1 # -*- coding: utf-8 -*-
5 from requests.auth import HTTPBasicAuth
10 from django.conf import settings
13 """REST client to SLA Manager.
15 Contains a generic rest client and wrappers over this generic client
18 Each resource client implements business-like() functions, but
19 returns a tuple (output, requests.Response)
21 The resource clients are initialized with the rooturl and a path, which
22 are combined to build the resource url. The path is defaulted to the known
23 resource path. So, for example, to create a agreements client:
25 c = Agreements("http://localhost/slagui-service")
27 A Factory facility is provided to create resource client instances. The
28 Factory uses "rooturl" module variable to use as rooturl parameter.
30 restclient.rooturl = "http://localhost/slagui-service"
31 c = restclient.Factory.agreements()
35 _PROVIDERS_PATH = "providerso"
36 _AGREEMENTS_PATH = "agreementso"
37 _TEMPLATES_PATH = "templateso"
38 _VIOLATIONS_PATH = "violationso"
39 _ENFORCEMENTJOBS_PATH = "enforcements"
41 rooturl = settings.SLA_MANAGER_URL
43 # SLA_MANAGER_USER = "normal_user"
44 # SLA_MANAGER_PASSWORD = "password"
46 class Factory(object):
49 """Returns aREST client for Agreements
53 return Agreements(rooturl)
57 """Returns aREST client for Providers
61 return Providers(rooturl)
65 """Returns aREST client for Violations
69 return Violations(rooturl)
73 """Returns aREST client for Violations
77 return Templates(rooturl)
81 """Returns aREST client for Enforcements jobs
85 return Enforcements(rooturl)
89 def __init__(self, root_url):
91 """Generic rest client using requests library
93 Each operation mimics the corresponding "requests" operation (arguments
96 :param str root_url: this url is used as prefix in all subsequent
99 self.rooturl = root_url
101 def get(self, path, **kwargs):
102 """Just a wrapper over request.get, just in case.
104 Returns a requests.Response
106 :rtype : request.Response
107 :param str path: remaining path from root url;
108 empty if desired path equal to rooturl.
109 :param kwargs: arguments to requests.get
112 c = Client("http://localhost:8080/service")
113 c.get("/resource", headers = { "accept": "application/json" })
115 url = _buildpath_(self.rooturl, path)
116 kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER, settings.SLA_MANAGER_PASSWORD)
117 result = requests.get(url, **kwargs)
118 print "GET {} {} {}".format(
119 result.url, result.status_code, result.text[0:70])
123 def post(self, path, data=None, **kwargs):
124 """Just a wrapper over request.post, just in case
126 :rtype : request.Response
127 :param str path: remaining path from root url;
128 empty if desired path equal to rooturl.
129 :param dict[str, str] kwargs: arguments to requests.post
132 c = Client("http://localhost:8080/service")
135 '{ "id": "1", "name": "provider-a" }',
137 "content-type": "application/json",
138 "accept": "application/xml"
142 url = _buildpath_(self.rooturl, path)
143 kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER, settings.SLA_MANAGER_PASSWORD)
144 result = requests.post(url, data, **kwargs)
145 location = result.headers["location"] \
146 if "location" in result.headers else "<null>"
147 print "POST {} {} Location: {}".format(
148 result.url, result.status_code, location)
153 class _Resource(object):
155 def __init__(self, url, converter):
156 """Provides some common operations over resources.
158 The operations return a structured representation of the resource.
160 :param str url: url to the resource
161 :param Converter converter: resouce xml converter
163 Some attributes are initialized to be used from the owner if needed:
164 * client: Client instance
165 * converter: resource xml converter
166 * listconverter: list of resources xml converter
168 self.client = Client(url)
169 self.converter = converter
170 self.listconverter = xmlconverter.ListConverter(self.converter)
173 def _processresult(r, converter):
175 """Generic processing of the REST call.
177 If no errors, tries to convert the result to a destination entity.
180 :param converter Converter:
182 if r.status_code == 404:
185 content_type = r.headers.get('content-type', '')
187 print("content-type = " + content_type)
188 if content_type == 'application/json':
190 elif content_type == 'application/xml':
192 result = xmlconverter.convertstring(converter, xml)
201 r = self.client.get("")
202 resources = self._processresult(r, self.listconverter)
205 def getbyid(self, id):
206 """Get resource 'id'"""
207 r = self.client.get(id)
208 resource = _Resource._processresult(r, self.converter)
211 def get(self, params):
212 """Generic query over resource: GET /resource?q1=v1&q2=v2...
214 :param dict[str,str] params: values to pass as get parameters
216 r = self.client.get("", params=params)
217 resources = self._processresult(r, self.listconverter)
220 def create(self, body, **kwargs):
221 """Creates (POST method) a resource.
223 It should be convenient to set content-type header.
226 resource.create(body, headers={'content-type': 'application/xml'})
228 r = self.client.post("", body, **kwargs)
233 class Agreements(object):
235 def __init__(self, root_url, path=_AGREEMENTS_PATH):
236 """Business methods for Agreement resource
237 :param str root_url: url to the root of resources
238 :param str path: path to resource from root_url
240 The final url to the resource is root_url + "/" + path
242 resourceurl = _buildpath_(root_url, path)
243 converter = xmlconverter.AgreementConverter()
244 self.res = _Resource(resourceurl, converter)
250 :rtype : list[wsag_model.Agreement]
252 return self.res.getall()
254 def getbyid(self, agreementid):
257 :rtype : wsag_model.Agreement
259 return self.res.getbyid(agreementid)
261 def getbyconsumer(self, consumerid):
262 """Get a consumer's agreements
264 :rtype : list[wsag_model.Agreement]
266 return self.res.get(dict(consumerId=consumerid))
268 def getbyprovider(self, providerid):
269 """Get the agreements served by a provider
271 :rtype : list[wsag_model.Agreement]
273 return self.res.get(dict(providerId=providerid))
275 def getstatus(self, agreementid):
276 """Get guarantee status of an agreement
278 :param str agreementid :
279 :rtype : wsag_model.AgreementStatus
281 path = _buildpath_(agreementid, "guaranteestatus")
282 r = self.res.client.get(path, headers={'accept': 'application/json'})
286 status = wsag_model.AgreementStatus.json_decode(json_obj)
290 def create(self, agreement):
291 """Create a new agreement
293 :param str agreement: sla template in ws-agreement format.
295 return self.res.create(agreement)
297 class Templates(object):
299 def __init__(self, root_url, path=_TEMPLATES_PATH):
300 """Business methods for Templates resource
301 :param str root_url: url to the root of resources
302 :param str path: path to resource from root_url
304 The final url to the resource is root_url + "/" + path
306 resourceurl = _buildpath_(root_url, path)
307 converter = xmlconverter.AgreementConverter()
308 self.res = _Resource(resourceurl, converter)
311 """ Get all templates
313 :rtype : list[wsag_model.Template]
315 return self.res.getall()
317 def getbyid(self, provider_id):
320 :rtype: wsag_model.Template
322 return self.res.getbyid(provider_id)
324 def create(self, template):
325 """Create a new template
327 :param str template: sla template in ws-agreement format.
329 self.res.create(template)
331 class Providers(object):
333 def __init__(self, root_url, path=_PROVIDERS_PATH):
334 """Business methods for Providers resource
335 :param str root_url: url to the root of resources
336 :param str path: path to resource from root_url
338 The final url to the resource is root_url + "/" + path
340 resourceurl = _buildpath_(root_url, path)
341 converter = xmlconverter.ProviderConverter()
342 self.res = _Resource(resourceurl, converter)
345 """ Get all providers
347 :rtype : list[wsag_model.Provider]
349 return self.res.getall()
351 def getbyid(self, provider_id):
354 :rtype: wsag_model.Provider
356 return self.res.getbyid(provider_id)
358 def create(self, provider):
359 """Create a new provider
361 :type provider: wsag_model.Provider
363 body = provider.to_xml()
364 return self.res.create(body)
366 class Violations(object):
368 def __init__(self, root_url, path=_VIOLATIONS_PATH):
369 """Business methods for Violation resource
370 :param str root_url: url to the root of resources
371 :param str path: path to resource from root_url
373 The final url to the resource is root_url + "/" + path
375 resourceurl = _buildpath_(root_url, path)
376 converter = xmlconverter.ViolationConverter()
377 self.res = _Resource(resourceurl, converter)
380 """ Get all violations
381 :rtype : list[wsag_model.Violation]
383 return self.res.getall()
385 def getbyid(self, violationid):
388 :rtype : wsag_model.Violation
390 return self.res.getbyid(violationid)
392 def getbyagreement(self, agreement_id, term=None):
393 """Get the violations of an agreement.
395 :param str agreement_id:
396 :param str term: optional GuaranteeTerm name. If not specified,
397 violations from all terms will be returned
398 :rtype: list[wsag_model.Violation]
401 {"agreementId": agreement_id, "guaranteeTerm": term})
404 class Enforcements(object):
406 def __init__(self, root_url, path=_ENFORCEMENTJOBS_PATH):
407 """Business methods for Violation resource
408 :param str root_url: url to the root of resources
409 :param str path: path to resource from root_url
411 The final url to the resource is root_url + "/" + path
413 resourceurl = _buildpath_(root_url, path)
414 converter = xmlconverter.EnforcementConverter()
415 self.res = _Resource(resourceurl, converter)
418 """ Get all Enforcements
419 :rtype : list[wsag_model.Violation]
421 return self.res.getall()
423 def getbyagreement(self, agreement_id):
424 """Get the enforcement of an agreement.
426 :param str agreement_id:
428 :rtype: list[wsag_model.Enforcement]
430 return self.res.getbyid(agreement_id)
433 def _buildpath_(*paths):
434 return "/".join(paths)
442 rooturl = "http://127.0.0.1:8080/sla-service"
445 c = Factory.templates()
447 #r = c.getbyid("noexiste")
448 #r = c.getstatus("agreement03")
451 #r = c.getbyconsumer('RandomClient')
452 r = c.getbyid("template02")
458 if __name__ == "__main__":