SLA and Service Directory code added
[unfold.git] / sla / slaclient / templates / fed4fire / fed4fire.py
1 # -*- coding: utf-8 -*-\r
2 """Template system for xifi project.\r
3 \r
4 The specific template system is configured with the factory module variable.\r
5 \r
6 By default, it is set to use django.\r
7 \r
8 Each implementation must define a factory module/object, defining:\r
9 * slaagreement()\r
10 * slatemplate()\r
11 \r
12 that returns a slaclient.templates.Template-compliant object that performs\r
13 the actual render.\r
14 \r
15 This module defines two facade methods:\r
16 * render_slaagreement(data)\r
17 * render_slatemplate(data)\r
18 \r
19 and the corresponding input classes:\r
20 * AgreementInput\r
21 * TemplateInput\r
22 \r
23 Usage:\r
24     # Thread safe\r
25     import sla.slaclient.templates.fed4fire\r
26     data = sla.slaclient.templates.fed4fire.TemplateInput(template_id="template-test")\r
27     t = sla.slaclient.templates.fed4fire.django.Factory().slatemplate()\r
28     slatemplate_xml = t.render(data)\r
29 \r
30     # Non thread safe\r
31     import sla.slaclient.templates.fed4fire\r
32     data = sla.slaclient.templates.fed4fire.TemplateInput(template_id="template-test")\r
33     slatemplate_xml = sla.slaclient.templates.fed4fire.render_slatemplate(data)\r
34 \r
35 Notes about agreements in XiFi:\r
36     The ws-agreement specification does not address where to place the name/id\r
37     of the service (as known outside SLA) being defined in the\r
38     agreement/template xml. So, it has been defined an element\r
39     wsag:Context/sla:Service, whose text is the name/id of the service. This\r
40     is known here as serviceId.\r
41 \r
42     An agreement/template can represent zero or more than one existing services.\r
43     The guarantee terms, service description terms, etc, use the attribute\r
44     serviceName to reference (internally in the xml) the service. So, there\r
45     could be more than one serviceName in a xml (as opposed to the former\r
46     serviceId). In Xifi, there is only one service per agreement, so we\r
47     can give serviceId and serviceName the same value.\r
48 \r
49     A ServiceReference defines how a serviceName is known externally: a\r
50     service reference can be a name, a location, a structure containing both...\r
51 \r
52     The service properties are a set of variables that are used in the guarantee\r
53     terms contraints. So, for example, if a constraint is : "uptime < 90", we\r
54     can have 2 service properties: ActualUptime and DesiredUptime. And the\r
55     constraint will be "ActualUptime < DesiredUptime". This is the theory. But\r
56     we're not going to use the service properties this way. We will not use the\r
57     thresholds as service properties; only the actual metric. So, in this case,\r
58     the service property is defined in ws-agreement as:\r
59 \r
60         <wsag:Variable Name="Uptime" Metric="xs:double">\r
61             <wsag:Location>service-ping/Uptime</wsag:Location>\r
62         </wsag:Variable>\r
63 \r
64     The "location" is the strange value here. Ws-agreement says that it is a\r
65     "structural reference" to the place where to find the actual value of the\r
66     metric. The examples I've found are references to the\r
67     ServiceDescriptionTerms in the agreement itself. We are not using SDTs\r
68     (they are used to describe the service to be instantiated), so we can\r
69     extrapolate the location as the "abstract location of the metric".\r
70 \r
71     In summary, in XiFi, the service properties will hold the metrics being\r
72     monitored for a service.\r
73 \r
74     And the guarantee terms hold the constraints that are being enforced for\r
75     the service in this agreement (maybe we are only interested in enforcing\r
76     one of the metrics).\r
77 \r
78     A guarantee term is defined as:\r
79         <wsag:GuaranteeTerm Name="GT_ResponseTime">\r
80             <wsag:ServiceScope ServiceName="service-ping"/>\r
81             <wsag:ServiceLevelObjective>\r
82                 <wsag:KPITarget>\r
83                     <wsag:KPIName>Uptime</wsag:KPIName>\r
84                     <wsag:CustomServiceLevel>\r
85                         {"constraint" : "Uptime BETWEEN (90, 100)"}\r
86                     </wsag:CustomServiceLevel>\r
87                 </wsag:KPITarget>\r
88             </wsag:ServiceLevelObjective>\r
89         </wsag:GuaranteeTerm>\r
90 \r
91     * Name is a name for the guarantee term. In Xifi, the name will have the\r
92       value "GT_<metric_name>"\r
93     * ServiceName is an internal reference in the agreement to the service\r
94       being enforced, as an agreement can created for more than one service.\r
95       In Xifi, to my knowledge, one service: one agreement, so this service\r
96       name is not really important.\r
97     * KpiName is a name given to the constraint, and I am using the same name\r
98       as the service property used in the constraint. This makes more sense\r
99       when using thresholds as service properties (e.g., a kpi called\r
100       "uptime" could be defined as :\r
101       "actual_uptime BETWEEN(lower_uptime, upper_uptime)").\r
102 \r
103     The CustomServiceLevel is not specified by ws-agreement, so it's something\r
104       to be defined by the implementation.\r
105 \r
106 """\r
107 \r
108 from sla.slaclient import wsag_model\r
109 import pdb\r
110 \r
111 from sla.slaclient.templates.fed4fire.django.factory import Factory\r
112 factory = Factory()\r
113 \r
114 \r
115 def _getfactory():\r
116     #\r
117     # Hardwired above to avoid multheading issues. This will need some\r
118     # refactoring if the factory really needs to be configurable.\r
119     #\r
120 \r
121     global factory\r
122     #if factory is None:\r
123     #    from slaclient.templates.fed4fire.django.factory import Factory\r
124     #    factory = Factory()\r
125     return factory\r
126 \r
127 \r
128 def render_slaagreement(data):\r
129     """Generate a sla agreement based on the supplied data.\r
130 \r
131     :type data: AgreementInput\r
132     """\r
133     print "render_slaagreement"\r
134     template = _getfactory().slaagreement()\r
135     #pdb.set_trace()\r
136     rendered = template.render(data) \r
137     return rendered\r
138 \r
139 \r
140 def render_slatemplate(data):\r
141     """Generate a sla template based on the supplied data.\r
142 \r
143     :type data: TemplateInput\r
144     """\r
145     template = _getfactory().slatemplate()\r
146     return template.render(data)\r
147 \r
148 \r
149 class TemplateInput(object):\r
150 \r
151     def __init__(self,\r
152                  template_id="",\r
153                  template_name="",\r
154                  provider="",\r
155                  service_id="",\r
156                  expiration_time=None,\r
157                  service_properties=()):\r
158         """Input data to the template for generating a sla-template.\r
159 \r
160         :param str template_id: optional TemplateId. If not specified, the\r
161           SlaManager should provide one.\r
162         :param str template_name: optional name for the template.\r
163         :param str service_id: Domain id/name of the service.\r
164         :param str provider: optional Resource Id of the provider party in the\r
165           agreement. The provider must exist previously in the SlaManager.\r
166         :param expiration_time: optional expiration time of this template.\r
167         :type expiration_time: datetime.datetime\r
168         :param service_properties: Metrics that the provider is able to\r
169           monitor for this service.\r
170         :type service_properties: list[slaclient.wsag_model.Agreement.Property]\r
171         """\r
172         self.template_id = template_id\r
173         self.template_name = template_name\r
174         self.service_id = service_id\r
175         self.provider = provider\r
176         self.expiration_time = expiration_time\r
177         self.expiration_time_iso = \\r
178             expiration_time.isoformat() if expiration_time else None\r
179         self.service_properties = service_properties\r
180 \r
181     def __repr__(self):\r
182         s = "<TemplateInput(template_id={}, template_name={})" \\r
183             "service_id={}, provider={}, expiration_time={}, " \\r
184             "service_properties={}>"\r
185         return s.format(\r
186             self.template_id,\r
187             self.template_name,\r
188             self.service_id,\r
189             self.provider,\r
190             self.expiration_time_iso,\r
191             repr(self.service_properties)\r
192         )\r
193 \r
194 \r
195 class AgreementInput(object):\r
196 \r
197     class GuaranteeTerm(object):\r
198 \r
199         def __init__(self,\r
200                      metric_name="",\r
201                      bounds=(0, 0)):\r
202             """Creates a GuaranteeTerm.\r
203 \r
204             Take into account that the GT's name is based on the metric_name.\r
205             :param str metric_name: name of the service property being enforced.\r
206             :param bounds: (lower, upper) bounds of the metric values.\r
207             :type bounds: (float, float)\r
208             """\r
209             self.name = "GT_{}".format(metric_name)\r
210             self.metric_name = metric_name\r
211             self.kpiname = metric_name\r
212             self.bounds = bounds\r
213 \r
214     def __init__(self,\r
215                  agreement_id="",\r
216                  agreement_name="",\r
217                  service_id="",\r
218                  consumer="",\r
219                  provider="",\r
220                  template_id="",\r
221                  expiration_time=None,\r
222                  service_properties=(),\r
223                  guarantee_terms=()):\r
224         """Input data to the template for generating a sla-agreement\r
225 \r
226         :param str agreement_id: optional agreement id. If not supplied,\r
227             the SlaManager should create one.\r
228         :param str agreement_name: optional agreement name\r
229         :param str service_id: Domain id/name of the service.\r
230         :param str consumer: Id of the consumer party in the agreement.\r
231         :param str provider: Resource Id of the provider party in the agreement.\r
232           The provider must exist previously in the SlaManager.\r
233         :param str template_id: TemplateId of the template this agreement is\r
234           based on.\r
235         :param expiration_time: Expiration time of this agreement.\r
236         :type expiration_time: datetime.datetime\r
237         :param service_properties: Should be the same of the template.\r
238         :type service_properties: list[slaclient.wsag_model.Agreement.Property]\r
239         :param guarantee_terms: Guarantee terms to be enforced in this\r
240           agreement.\r
241         :type guarantee_terms: list(AgreementInput.GuaranteeTerm)\r
242         """\r
243         self.agreement_id = agreement_id\r
244         self.agreement_name = agreement_name\r
245         self.service_id = service_id\r
246         self.consumer = consumer\r
247         self.provider = provider\r
248         self.template_id = template_id\r
249         self.expiration_time = expiration_time\r
250         self.expiration_time_iso = \\r
251             expiration_time.isoformat() if expiration_time else None\r
252         self.service_properties = service_properties\r
253         self.guarantee_terms = guarantee_terms\r
254 \r
255     def __repr__(self):\r
256         s = "<AgreementInput(agreement_id={}, agreement_name={}, " \\r
257             "service_id={}, consumer={}, provider={}, template_id={}, " \\r
258             "expiration_time={}, service_properties={}, guarantee_terms={}>"\r
259         return s.format(\r
260             self.agreement_id,\r
261             self.agreement_name,\r
262             self.service_id,\r
263             self.consumer,\r
264             self.provider,\r
265             self.template_id,\r
266             self.expiration_time,\r
267             repr(self.service_properties),\r
268             repr(self.guarantee_terms)\r
269         )\r
270 \r
271     def from_template(self, slatemplate):\r
272         """Return a new agreement based on this agreement and copying info\r
273         (overriding if necessary) from a slatemplate.\r
274 \r
275         :type slatemplate: wsag_model.Template\r
276         :rtype: AgreementInput\r
277         """\r
278         #\r
279         # NOTE: templateinput does not address guaranteeterms (yet)\r
280         #\r
281         result = AgreementInput(\r
282             agreement_id=self.agreement_id,\r
283             agreement_name=self.agreement_name,\r
284             service_id=slatemplate.context.service,\r
285             consumer=self.consumer,\r
286             provider=slatemplate.context.provider or self.provider,\r
287             template_id=slatemplate.template_id,\r
288             expiration_time=self.expiration_time,\r
289             service_properties=slatemplate.variables.values(),\r
290             guarantee_terms=slatemplate.guaranteeterms.values()\r
291         )\r
292         print result.guarantee_terms[0]\r
293         return result\r