1 # -*- coding: utf-8 -*-
3 """Converts from XML to objects for ws-agreement agreements/templates or any
4 other xml returned by SLA Manager.
6 This module offers a set of converters from xml formats returned by SLA Manager
7 to a more-friendly POJO instances.
9 The converters are designed to be pluggable: see ListConverter.
14 c = ListConverter(AnyOtherConverter())
16 convertstring(c, "<?xml ... </>")
18 convertfile(c, "file.xml")
20 root = ElementTree.parse("file.xml")
21 c.convert(root.getroot())
24 from myslice.settings import logger
27 # Much faster and lighter library (C implementation)
28 from xml.etree import cElementTree as ElementTree
30 from xml.etree import ElementTree
32 from xml.etree.ElementTree import QName
34 import dateutil.parser
36 from wsag_model import Agreement
37 from wsag_model import Template
38 from wsag_model import Violation
39 from wsag_model import Provider
40 from wsag_model import Enforcement
43 def convertfile(converter, f):
44 """Reads and converts a xml file
47 :param Converter converter:
48 :param str f: file to read
50 tree = ElementTree.parse(f)
51 result = converter.convert(tree.getroot())
55 def convertstring(converter, string):
59 :param Converter converter:
60 :param str string: contains the xml to convert
62 root = ElementTree.fromstring(string)
63 result = converter.convert(root)
67 class Converter(object):
70 """Base class for converters
74 def convert(self, xmlroot):
75 """Converts the given xml in an object
77 :rtype : Object that represents the xml
78 :param Element xmlroot: root element of xml to convert.
83 class ListConverter(Converter):
84 def __init__(self, innerconverter):
85 super(ListConverter, self).__init__()
86 self.innerconverter = innerconverter
88 def convert(self, xmlroot):
91 # Converter for the old xml structure
92 # for item in xmlroot.find("items"): # loop through "items" children
93 # inner = self.innerconverter.convert(item)
94 # result.append(inner)
97 for item in xmlroot: # loop through children
98 inner = self.innerconverter.convert(item)
103 class ProviderConverter(Converter):
104 """Converter for a provider.
108 <uuid>1ad9acb9-8dbc-4fe6-9a0b-4244ab6455da</uuid>
109 <name>Provider2</name>
117 super(ProviderConverter, self).__init__()
119 def convert(self, xmlroot):
121 result.uuid = xmlroot.find("uuid").text
122 result.name = xmlroot.find("name").text
126 class EnforcementConverter(Converter):
127 """Converter for an Enforcement job.
131 <agreement_id>agreement03</agreement_id>
132 <enabled>false</enabled>
136 wsag_model.Enforcement
140 super(EnforcementConverter, self).__init__()
142 def convert(self, xmlroot):
143 result = Enforcement()
144 result.agreement_id = xmlroot.find("agreement_id").text
145 result.enabled = xmlroot.find("enabled").text
149 class ViolationConverter(Converter):
150 """Converter for a violation.
154 <uuid>1d94627e-c318-41ba-9c45-42c95b67cc32</uuid>
155 <contract_uuid>26e5d5b6-f5a1-4eb3-bc91-606e8f24fb09</contract_uuid>
156 <service_name>servicename1</service_name>
157 <service_scope>test1</service_scope>
158 <metric_name>UpTime</metric_name>
159 <datetime>2014-07-17T09:32:00+02:00</datetime>
160 <actual_value>0.0</actual_value>
167 super(ViolationConverter, self).__init__()
169 def convert(self, xmlroot):
171 result.uuid = xmlroot.find("uuid").text
172 result.contract_uuid = xmlroot.find("contract_uuid").text
173 result.service_name = xmlroot.find("service_name").text
174 result.service_scope = xmlroot.find("service_scope").text
175 result.metric_name = xmlroot.find("metric_name").text
176 result.actual_value = xmlroot.find("actual_value").text
177 dt_str = xmlroot.find("datetime").text
178 result.datetime = dateutil.parser.parse(dt_str)
183 class AgreementConverter(Converter):
185 """Converter for an ws-agreement agreement or template.
187 super(AgreementConverter, self).__init__()
189 "wsag": "http://www.ggf.org/namespaces/ws-agreement",
190 "sla": "http://sla.atos.eu",
192 self.agreement_tags = (
193 "{{{}}}Agreement".format(self._namespaces["wsag"]),
195 self.template_tags = (
196 "{{{}}}Template".format(self._namespaces["wsag"]),
199 def convert(self, xmlroot):
201 :param Element xmlroot: root element of xml to convert.
202 :rtype: wsag_model.Agreement
204 # for name, value in xmlroot.attrib.items():
205 # logger.debug('SLA xmlconverter: {} = {}'.format(name, value))
207 if xmlroot.tag in self.agreement_tags:
209 agreementId = str(QName(self._namespaces["wsag"], "AgreementId"))
210 result.agreement_id = xmlroot.attrib[agreementId]
211 elif xmlroot.tag in self.template_tags:
213 templateId = str(QName(self._namespaces["wsag"], "TemplateId"))
214 result.template_id = xmlroot.attrib[templateId]
216 raise ValueError("Not valid root element name: " + xmlroot.tag)
218 context = xmlroot.find("wsag:Context", self._namespaces)
219 result.context = self._parse_context(context)
221 terms = xmlroot.find("wsag:Terms/wsag:All", self._namespaces)
223 properties = terms.findall("wsag:ServiceProperties", self._namespaces)
224 result.variables = self._parse_properties(properties)
226 guarantees = terms.findall("wsag:GuaranteeTerm", self._namespaces)
227 result.guaranteeterms = self._parse_guarantees(guarantees)
231 def _parse_context(self, element):
232 nss = self._namespaces
233 result = Agreement.Context()
235 result.template_id = self._find_text(element, "wsag:TemplateId")
236 result.expirationtime = self._find_text(element, "wsag:ExpirationTime")
238 service_elem = element.find("sla:Service", nss)
240 service_elem.text if service_elem is not None else "<servicename>"
242 initiator = self._find_text(element, "wsag:AgreementInitiator")
243 responder = self._find_text(element, "wsag:AgreementResponder")
244 serviceprovider_elem = self._find_text(element, "wsag:ServiceProvider")
247 # Deloop the initiator-responder indirection.
249 if serviceprovider_elem == "AgreementResponder":
252 elif serviceprovider_elem == "AgreementInitiator":
257 "Invalid value for wsag:ServiceProvider : " +
258 serviceprovider_elem)
260 result.initiator = initiator
261 result.responder = responder
262 result.provider = provider
263 result.consumer = consumer
267 def _parse_property(self, element, servicename):
268 nss = self._namespaces
270 key = _get_attribute(element, "Name")
271 value = Agreement.Property()
272 value.servicename = servicename
274 value.metric = _get_attribute(element, "Metric")
275 value.location = element.find("wsag:Location", nss).text
279 def _parse_properties(self, elements):
281 nss = self._namespaces
282 for element in elements:
283 servicename = _get_attribute(element, "ServiceName")
284 for var in element.findall("wsag:VariableSet/wsag:Variable", nss):
285 key, value = self._parse_property(var, servicename)
290 def _parse_guarantee_scope(self, element):
291 result = Agreement.GuaranteeTerm.GuaranteeScope()
292 result.servicename = _get_attribute(element, "ServiceName")
293 result.scope = element.text
296 def _parse_guarantee_scopes(self, elements):
298 for scope in elements:
299 result.append(self._parse_guarantee_scope(scope))
302 def _parse_guarantee(self, element):
303 nss = self._namespaces
305 result = Agreement.GuaranteeTerm()
306 name = _get_attribute(element, "Name")
308 scopes = element.findall("wsag:ServiceScope", nss)
309 result.scopes = self._parse_guarantee_scopes(scopes)
311 kpitarget = element.find(
312 "wsag:ServiceLevelObjective/wsag:KPITarget", nss)
313 slo = Agreement.GuaranteeTerm.ServiceLevelObjective()
314 result.servicelevelobjective = slo
315 slo.kpiname = kpitarget.find("wsag:KPIName", nss).text
316 slo.customservicelevel = kpitarget.find(
317 "wsag:CustomServiceLevel", nss).text
321 def _parse_guarantees(self, elements):
323 for element in elements:
324 key, value = self._parse_guarantee(element)
328 def _find_text(self, src, path):
329 """Returns the inner text of the element located in path from the src
330 element; None if no elements were found.
337 text = _find_text(root, "wsag:Context/ExpirationTime")
339 dst = src.find(path, self._namespaces)
345 def _get_attribute(element, attrname):
347 Get attribute from an element.
349 Wrapper over Element.attrib, as this doesn't fallback to the element
350 namespace if the attribute is qnamed and the requested attribute name
354 <ns:elem attr1="value1" ns:attr2="value2"/>
356 _get_attribute(elem, "attr1") -> value1
357 _get_attribute(elem, "attr2") -> value2
358 _get_attribute(elem, "{uri}:attr1") -> Error
359 _get_attribute(elem, "{uri}:attr2") -> value2
361 isns = (attrname[0] == '{')
364 # Handle qnamed request:
365 # attrname = {uri}name
368 return element.attrib[attrname]
371 # Handle non-qnamed request and non-qnamed actual_attr
375 if attrname in element.attrib:
376 return element.attrib[attrname]
379 # Handle non-qnamed request but qnamed actualAttr
381 # actual_attr = {uri}name
383 tag_uri = element.tag[0: element.tag.find('}') + 1]
384 return element.attrib[tag_uri + attrname]