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 = "providers"
36 _AGREEMENTS_PATH = "agreements"
37 _TEMPLATES_PATH = "templates"
38 _VIOLATIONS_PATH = "violations"
39 _ENFORCEMENTJOBS_PATH = "enforcements"
41 rooturl = settings.SLA_MANAGER_URL
44 class Factory(object):
47 """Returns a REST client for Agreements
51 return Agreements(rooturl)
55 """Returns a REST client for Providers
59 return Providers(rooturl)
63 """Returns a REST client for Violations
67 return Violations(rooturl)
71 """Returns a REST client for Violations
75 return Templates(rooturl)
79 """Returns a REST client for Enforcements jobs
83 return Enforcements(rooturl)
88 def __init__(self, root_url):
90 """Generic rest client using requests library
92 Each operation mimics the corresponding "requests" operation (arguments
95 :param str root_url: this url is used as prefix in all subsequent
98 self.rooturl = root_url
100 def get(self, path, **kwargs):
101 """Just a wrapper over request.get, just in case.
103 Returns a requests.Response
105 :rtype : request.Response
106 :param str path: remaining path from root url;
107 empty if desired path equal to rooturl.
108 :param kwargs: arguments to requests.get
111 c = Client("http://localhost:8080/service")
112 c.get("/resource", headers = { "accept": "application/json" })
114 url = _buildpath_(self.rooturl, path)
115 url = url + "?testbed=iminds" # TODO remove hardcoded string
116 #kwargs['params']['testbed'] = 'iminds'
118 if "headers" not in kwargs:
119 kwargs["headers"] = {"accept": "application/xml"}
120 # kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER,
121 # settings.SLA_MANAGER_PASSWORD)
122 result = requests.get(url, **kwargs)
123 #print "GET {} {} {}".format(
124 # result.url, result.status_code, result.text[0:70])
128 def post(self, path, data=None, **kwargs):
129 """Just a wrapper over request.post, just in case
131 :rtype : request.Response
132 :param str path: remaining path from root url;
133 empty if desired path equal to rooturl.
134 :param dict[str, str] kwargs: arguments to requests.post
137 c = Client("http://localhost:8080/service")
140 '{ "id": "1", "name": "provider-a" }',
142 "content-type": "application/json",
143 "accept": "application/xml"
147 url = _buildpath_(self.rooturl, path)
148 url = url + "?testbed=iminds" # TODO remove hardcoded string
149 # kwargs["auth"] = HTTPBasicAuth(settings.SLA_MANAGER_USER,
150 # settings.SLA_MANAGER_PASSWORD)
151 if "headers" not in kwargs:
152 kwargs = {"accept": "application/xml",
153 "content-type": "application/xml"}
154 result = requests.post(url, data, **kwargs)
155 location = result.headers["location"] \
156 if "location" in result.headers else "<null>"
157 print "POST {} {} Location: {}".format(
158 result.url, result.status_code, location)
162 class _Resource(object):
164 def __init__(self, url, converter):
165 """Provides some common operations over resources.
167 The operations return a structured representation of the resource.
169 :param str url: url to the resource
170 :param Converter converter: resouce xml converter
172 Some attributes are initialized to be used from the owner if needed:
173 * client: Client instance
174 * converter: resource xml converter
175 * listconverter: list of resources xml converter
177 self.client = Client(url)
178 self.converter = converter
179 self.listconverter = xmlconverter.ListConverter(self.converter)
182 def _processresult(r, converter):
184 """Generic processing of the REST call.
186 If no errors, tries to convert the result to a destination entity.
189 :param converter Converter:
191 if r.status_code == 404:
194 content_type = r.headers.get('content-type', '')
196 #print("content-type = " + content_type)
197 if content_type == 'application/json':
199 elif content_type == 'application/xml':
201 result = xmlconverter.convertstring(converter, xml)
210 r = self.client.get("")
211 resources = self._processresult(r, self.listconverter)
214 def getbyid(self, id):
215 """Get resource 'id'"""
216 r = self.client.get(id)
217 resource = _Resource._processresult(r, self.converter)
220 def get(self, params):
221 """Generic query over resource: GET /resource?q1=v1&q2=v2...
223 :param dict[str,str] params: values to pass as get parameters
225 r = self.client.get("", params=params)
226 resources = self._processresult(r, self.listconverter)
229 def create(self, body, **kwargs):
230 """Creates (POST method) a resource.
232 It should be convenient to set content-type header.
235 resource.create(body, headers={'content-type': 'application/xml'})
237 r = self.client.post("", body, **kwargs)
242 class Agreements(object):
244 def __init__(self, root_url, path=_AGREEMENTS_PATH):
245 """Business methods for Agreement resource
246 :param str root_url: url to the root of resources
247 :param str path: path to resource from root_url
249 The final url to the resource is root_url + "/" + path
251 resourceurl = _buildpath_(root_url, path)
252 converter = xmlconverter.AgreementConverter()
253 self.res = _Resource(resourceurl, converter)
259 :rtype : list[wsag_model.Agreement]
261 return self.res.getall()
263 def getbyid(self, agreementid):
266 :rtype : wsag_model.Agreement
268 return self.res.getbyid(agreementid)
270 def getbyconsumer(self, consumerid):
271 """Get a consumer's agreements
273 :rtype : list[wsag_model.Agreement]
275 return self.res.get(dict(consumerId=consumerid))
277 def getbyprovider(self, providerid):
278 """Get the agreements served by a provider
280 :rtype : list[wsag_model.Agreement]
282 return self.res.get(dict(providerId=providerid))
284 def getstatus(self, agreementid):
285 """Get guarantee status of an agreement
287 :param str agreementid :
288 :rtype : wsag_model.AgreementStatus
290 path = _buildpath_(agreementid, "guaranteestatus")
291 r = self.res.client.get(path, headers={'accept': 'application/json'})
295 status = wsag_model.AgreementStatus.json_decode(json_obj)
299 def create(self, agreement):
300 """Create a new agreement
302 :param str agreement: sla template in ws-agreement format.
304 return self.res.create(agreement)
307 class Templates(object):
309 def __init__(self, root_url, path=_TEMPLATES_PATH):
310 """Business methods for Templates resource
311 :param str root_url: url to the root of resources
312 :param str path: path to resource from root_url
314 The final url to the resource is root_url + "/" + path
316 resourceurl = _buildpath_(root_url, path)
317 converter = xmlconverter.AgreementConverter()
318 self.res = _Resource(resourceurl, converter)
321 """ Get all templates
323 :rtype : list[wsag_model.Template]
325 return self.res.getall()
327 def getbyid(self, provider_id):
330 :rtype: wsag_model.Template
332 return self.res.getbyid(provider_id)
334 def create(self, template):
335 """Create a new template
337 :param str template: sla template in ws-agreement format.
339 self.res.create(template)
342 class Providers(object):
344 def __init__(self, root_url, path=_PROVIDERS_PATH):
345 """Business methods for Providers resource
346 :param str root_url: url to the root of resources
347 :param str path: path to resource from root_url
349 The final url to the resource is root_url + "/" + path
351 resourceurl = _buildpath_(root_url, path)
352 converter = xmlconverter.ProviderConverter()
353 self.res = _Resource(resourceurl, converter)
356 """ Get all providers
358 :rtype : list[wsag_model.Provider]
360 return self.res.getall()
362 def getbyid(self, provider_id):
365 :rtype: wsag_model.Provider
367 return self.res.getbyid(provider_id)
369 def create(self, provider):
370 """Create a new provider
372 :type provider: wsag_model.Provider
374 body = provider.to_xml()
375 return self.res.create(body)
378 class Violations(object):
380 def __init__(self, root_url, path=_VIOLATIONS_PATH):
381 """Business methods for Violation resource
382 :param str root_url: url to the root of resources
383 :param str path: path to resource from root_url
385 The final url to the resource is root_url + "/" + path
387 resourceurl = _buildpath_(root_url, path)
388 converter = xmlconverter.ViolationConverter()
389 self.res = _Resource(resourceurl, converter)
392 """ Get all violations
393 :rtype : list[wsag_model.Violation]
395 return self.res.getall()
397 def getbyid(self, violationid):
400 :rtype : wsag_model.Violation
402 return self.res.getbyid(violationid)
404 def getbyagreement(self, agreement_id, term=None):
405 """Get the violations of an agreement.
407 :param str agreement_id:
408 :param str term: optional GuaranteeTerm name. If not specified,
409 violations from all terms will be returned
410 :rtype: list[wsag_model.Violation]
414 {"agreementId": agreement_id, "guaranteeTerm": term})
417 class Enforcements(object):
419 def __init__(self, root_url, path=_ENFORCEMENTJOBS_PATH):
420 """Business methods for Violation resource
421 :param str root_url: url to the root of resources
422 :param str path: path to resource from root_url
424 The final url to the resource is root_url + "/" + path
426 resourceurl = _buildpath_(root_url, path)
427 converter = xmlconverter.EnforcementConverter()
428 self.res = _Resource(resourceurl, converter)
431 """ Get all Enforcements
432 :rtype : list[wsag_model.Violation]
434 return self.res.getall()
436 def getbyagreement(self, agreement_id):
437 """Get the enforcement of an agreement.
439 :param str agreement_id:
441 :rtype: list[wsag_model.Enforcement]
443 return self.res.getbyid(agreement_id)
446 def _buildpath_(*paths):
447 return "/".join(paths)
455 rooturl = "http://127.0.0.1:8080/sla-service"
457 c = Factory.templates()
459 #r = c.getbyid("noexiste")
460 #r = c.getstatus("agreement03")
463 #r = c.getbyconsumer('RandomClient')
464 r = c.getbyid("template02")
469 if __name__ == "__main__":