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())
26 # Much faster and lighter library (C implementation)
27 from xml.etree import cElementTree as ElementTree
29 from xml.etree import ElementTree
31 from xml.etree.ElementTree import QName
33 import dateutil.parser
35 from wsag_model import Agreement
36 from wsag_model import Template
37 from wsag_model import Violation
38 from wsag_model import Provider
39 from wsag_model import Enforcement
42 def convertfile(converter, f):
43 """Reads and converts a xml file
46 :param Converter converter:
47 :param str f: file to read
49 tree = ElementTree.parse(f)
50 result = converter.convert(tree.getroot())
54 def convertstring(converter, string):
58 :param Converter converter:
59 :param str string: contains the xml to convert
61 root = ElementTree.fromstring(string)
62 result = converter.convert(root)
66 class Converter(object):
69 """Base class for converters
73 def convert(self, xmlroot):
74 """Converts the given xml in an object
76 :rtype : Object that represents the xml
77 :param Element xmlroot: root element of xml to convert.
82 class ListConverter(Converter):
83 def __init__(self, innerconverter):
84 super(ListConverter, self).__init__()
85 self.innerconverter = innerconverter
87 def convert(self, xmlroot):
90 # Converter for the old xml structure
91 # for item in xmlroot.find("items"): # loop through "items" children
92 # inner = self.innerconverter.convert(item)
93 # result.append(inner)
96 for item in xmlroot: # loop through children
97 inner = self.innerconverter.convert(item)
102 class ProviderConverter(Converter):
103 """Converter for a provider.
107 <uuid>1ad9acb9-8dbc-4fe6-9a0b-4244ab6455da</uuid>
108 <name>Provider2</name>
116 super(ProviderConverter, self).__init__()
118 def convert(self, xmlroot):
120 result.uuid = xmlroot.find("uuid").text
121 result.name = xmlroot.find("name").text
125 class EnforcementConverter(Converter):
126 """Converter for an Enforcement job.
130 <agreement_id>agreement03</agreement_id>
131 <enabled>false</enabled>
135 wsag_model.Enforcement
139 super(EnforcementConverter, self).__init__()
141 def convert(self, xmlroot):
142 result = Enforcement()
143 result.agreement_id = xmlroot.find("agreement_id").text
144 result.enabled = xmlroot.find("enabled").text
148 class ViolationConverter(Converter):
149 """Converter for a violation.
153 <uuid>1d94627e-c318-41ba-9c45-42c95b67cc32</uuid>
154 <contract_uuid>26e5d5b6-f5a1-4eb3-bc91-606e8f24fb09</contract_uuid>
155 <service_name>servicename1</service_name>
156 <service_scope>test1</service_scope>
157 <metric_name>UpTime</metric_name>
158 <datetime>2014-07-17T09:32:00+02:00</datetime>
159 <actual_value>0.0</actual_value>
166 super(ViolationConverter, self).__init__()
168 def convert(self, xmlroot):
170 result.uuid = xmlroot.find("uuid").text
171 result.contract_uuid = xmlroot.find("contract_uuid").text
172 result.service_name = xmlroot.find("service_name").text
173 result.service_scope = xmlroot.find("service_scope").text
174 result.metric_name = xmlroot.find("metric_name").text
175 result.actual_value = xmlroot.find("actual_value").text
176 dt_str = xmlroot.find("datetime").text
177 result.datetime = dateutil.parser.parse(dt_str)
182 class AgreementConverter(Converter):
184 """Converter for an ws-agreement agreement or template.
186 super(AgreementConverter, self).__init__()
188 "wsag": "http://www.ggf.org/namespaces/ws-agreement",
189 "sla": "http://sla.atos.eu",
191 self.agreement_tags = (
192 "{{{}}}Agreement".format(self._namespaces["wsag"]),
194 self.template_tags = (
195 "{{{}}}Template".format(self._namespaces["wsag"]),
198 def convert(self, xmlroot):
200 :param Element xmlroot: root element of xml to convert.
201 :rtype: wsag_model.Agreement
203 for name, value in xmlroot.attrib.items():
204 print '{0}="{1}"'.format(name, value)
206 if xmlroot.tag in self.agreement_tags:
208 agreementId = str(QName(self._namespaces["wsag"], "AgreementId"))
209 result.agreement_id = xmlroot.attrib[agreementId]
210 elif xmlroot.tag in self.template_tags:
212 templateId = str(QName(self._namespaces["wsag"], "TemplateId"))
213 result.template_id = xmlroot.attrib[templateId]
215 raise ValueError("Not valid root element name: " + xmlroot.tag)
217 context = xmlroot.find("wsag:Context", self._namespaces)
218 result.context = self._parse_context(context)
220 terms = xmlroot.find("wsag:Terms/wsag:All", self._namespaces)
222 properties = terms.findall("wsag:ServiceProperties", self._namespaces)
223 result.variables = self._parse_properties(properties)
225 guarantees = terms.findall("wsag:GuaranteeTerm", self._namespaces)
226 result.guaranteeterms = self._parse_guarantees(guarantees)
230 def _parse_context(self, element):
231 nss = self._namespaces
232 result = Agreement.Context()
234 result.template_id = self._find_text(element, "wsag:TemplateId")
235 result.expirationtime = self._find_text(element, "wsag:ExpirationTime")
237 service_elem = element.find("sla:Service", nss)
239 service_elem.text if service_elem is not None else "<servicename>"
241 initiator = self._find_text(element, "wsag:AgreementInitiator")
242 responder = self._find_text(element, "wsag:AgreementResponder")
243 serviceprovider_elem = self._find_text(element, "wsag:ServiceProvider")
246 # Deloop the initiator-responder indirection.
248 if serviceprovider_elem == "AgreementResponder":
251 elif serviceprovider_elem == "AgreementInitiator":
256 "Invalid value for wsag:ServiceProvider : " +
257 serviceprovider_elem)
259 result.initiator = initiator
260 result.responder = responder
261 result.provider = provider
262 result.consumer = consumer
266 def _parse_property(self, element, servicename):
267 nss = self._namespaces
269 key = _get_attribute(element, "Name")
270 value = Agreement.Property()
271 value.servicename = servicename
273 value.metric = _get_attribute(element, "Metric")
274 value.location = element.find("wsag:Location", nss).text
278 def _parse_properties(self, elements):
280 nss = self._namespaces
281 for element in elements:
282 servicename = _get_attribute(element, "ServiceName")
283 for var in element.findall("wsag:Variables/wsag:Variable", nss):
284 key, value = self._parse_property(var, servicename)
289 def _parse_guarantee_scope(self, element):
290 result = Agreement.GuaranteeTerm.GuaranteeScope()
291 result.servicename = _get_attribute(element, "ServiceName")
292 result.scope = element.text
295 def _parse_guarantee_scopes(self, elements):
297 for scope in elements:
298 result.append(self._parse_guarantee_scope(scope))
301 def _parse_guarantee(self, element):
302 nss = self._namespaces
304 result = Agreement.GuaranteeTerm()
305 name = _get_attribute(element, "Name")
307 scopes = element.findall("wsag:ServiceScope", nss)
308 result.scopes = self._parse_guarantee_scopes(scopes)
310 kpitarget = element.find(
311 "wsag:ServiceLevelObjective/wsag:KPITarget", nss)
312 slo = Agreement.GuaranteeTerm.ServiceLevelObjective()
313 result.servicelevelobjective = slo
314 slo.kpiname = kpitarget.find("wsag:KPIName", nss).text
315 slo.customservicelevel = kpitarget.find(
316 "wsag:CustomServiceLevel", nss).text
320 def _parse_guarantees(self, elements):
322 for element in elements:
323 key, value = self._parse_guarantee(element)
327 def _find_text(self, src, path):
328 """Returns the inner text of the element located in path from the src
329 element; None if no elements were found.
336 text = _find_text(root, "wsag:Context/ExpirationTime")
338 dst = src.find(path, self._namespaces)
344 def _get_attribute(element, attrname):
346 Get attribute from an element.
348 Wrapper over Element.attrib, as this doesn't fallback to the element
349 namespace if the attribute is qnamed and the requested attribute name
353 <ns:elem attr1="value1" ns:attr2="value2"/>
355 _get_attribute(elem, "attr1") -> value1
356 _get_attribute(elem, "attr2") -> value2
357 _get_attribute(elem, "{uri}:attr1") -> Error
358 _get_attribute(elem, "{uri}:attr2") -> value2
360 isns = (attrname[0] == '{')
363 # Handle qnamed request:
364 # attrname = {uri}name
367 return element.attrib[attrname]
370 # Handle non-qnamed request and non-qnamed actual_attr
374 if attrname in element.attrib:
375 return element.attrib[attrname]
378 # Handle non-qnamed request but qnamed actualAttr
380 # actual_attr = {uri}name
382 tag_uri = element.tag[0: element.tag.find('}') + 1]
383 return element.attrib[tag_uri + attrname]