def details(s): ''' A collection of detailed information about all of the nodes in a particular nodegroup. ''' center(s.__class__.__name__) #from client import MCA # Will probably produce a Nodes object but for now just return what comes # back from the rest interface. # response = s.__maas.post(u'/nodegroups/%s/' % s['uuid'], op='details') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) data = bson.BSON.decode(response.data) cdebug(json.dumps(data, sort_keys=True, indent=4)) retval = response.data cleave(s.__class__.__name__) return retval
def call(cls, uri, op, method, creds, data=[]): center('RestClient.call') # TODO: this is el-cheapo URI Template # <http://tools.ietf.org/html/rfc6570> support; use uritemplate-py # <https://github.com/uri-templates/uritemplate-py> here? #uri = self.uri.format(**vars(options)) # Bundle things up ready to throw over the wire. uri, body, headers = cls.prepare_payload(op, method, uri, data) # Headers are returned as a list, but they must be a dict for # the signing machinery. headers = dict(headers) # Sign request if credentials have been provided. credentials = creds.split(':') if credentials is not None: cls.sign(uri, headers, credentials) # Use httplib2 instead of urllib2 (or MAASDispatcher, which is based # on urllib2) so that we get full control over HTTP method. TODO: # create custom MAASDispatcher to use httplib2 so that MAASClient can # be used. response, content = http_request(uri, method, body=body, headers=headers, insecure=False) # Compare API hashes to see if our version of the API is old. #self.compare_api_hashes(self.profile, response) # Output. #cdebug('response.status: %d' % response.status) #cls.print_debug(response) #cls.print_response(response, content) # 2xx status codes are all okay. if response.status // 100 != 2: cleave('MaiClient.call') if response.status == 500: raise MaasApiHttpInternalServerError(response.status, content) elif response.status == 503: raise MaasApiHttpServiceUnavailable(response.status, content) elif response.status == 400: raise MaasApiHttpBadRequest(response.status, content) elif response.status == 409: raise MaasApiHttpConflict(response.status, content) else: raise MaasApiUnknownError(response.status, content) if is_response_textual(response): try: retval = Response(True, json.loads(content)) if Clog.dbg: cdebug('content: %s' % content) except ValueError: # The content is not a json string. Just assume it's a plain string. # retval = Response(True, content) else: retval = Response(True, content) cleave('RestClient.call') return retval
def __init__(s, url, creds): center(s.__class__.__name__) cdebug(' url: %s' % url) cdebug(' creds: %s' % creds) s.root = url s.creds = creds cleave(s.__class__.__name__)
def __init__(s, maas, group): center('Nodegroup.__init__') s.__maas = maas cdebug('group: %s' % group) dict.__init__(s, group) cleave('Nodegroup.__init__')
def is_response_textual(response): """Is the response body text?""" center('api.is_response_textual') content_type = get_response_content_type(response) cdebug('content_type: %s' % content_type) retval = (content_type.endswith("/json") or content_type.startswith("text/")) cleave('api.is_response_textual (%s)' % retval) return retval
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__boot_images is None: response = s.__maas.get(u'/nodegroups/%s/boot-images/' % s.__uuid) if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__boot_images = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__zones is None: response = s.__maas.get(u'/zones/') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__zones = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center('Interfaces.__fetch_if_needed') if s.__interfaces is None: response = s.__maas.get(u'/nodegroups/%s/interfaces/' % s.__uuid, op='list') if not response.ok: if type(response.data) == str: cleave('Interfaces.__fetch_if_needed') raise MapiError(response.data) s.__interfaces = response.data cdebug(' fetched') cleave('Interfaces.__fetch_if_needed')
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__groups is None: response = s.__maas.get(u'/nodes/%s/volume-groups/' % s.__system_id) if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__groups = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__resources is None: response = s.__maas.get(u'/boot-sources/') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__resources = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__nodegroups is None: response = s.__maas.get(u'/nodegroups/', op='list') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__nodegroups = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__keys is None: response = s.__maas.get(u'/account/prefs/sslkeys/', op='list') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__keys = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__power_types is None: response = s.__maas.get(u'/nodegroups/', op='describe_power_types') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__power_types = response.data cdebug(' fetched') cleave(s.__class__.__name__)
def __fetch_if_needed(s): center(s.__class__.__name__) if s.__events is None: response = s.__maas.get(u'/events/', op='query') if not response.ok: if type(response.data) == str: cleave(s.__class__.__name__) raise MapiError(response.data) s.__prev_uri = response.data['prev_uri'] s.__next_uri = response.data['next_uri'] s.__count = response.data['count'] s.__events = response.data['events'] cdebug(' fetched') cleave(s.__class__.__name__)
def http_request(url, method, body=None, headers=None, insecure=False): """Issue an http request.""" center('api.http_request') cdebug(' url: %s' % url) cdebug(' method: %s' % method) cdebug(' body: %s' % body) cdebug(' headers: %s' % headers) cdebug(' insecure: %s' % insecure) http = httplib2.Http(disable_ssl_certificate_validation=insecure) try: cleave('api.http_request') return http.request(url, method, body=body, headers=headers) except httplib2.SSLHandshakeError: cleave('api.http_request') raise MaasApiCertificateVerificationError( 0, "Certificate verification failed, use --insecure/-k to " "disable the certificate check.")
def http_request(url, method, body=None, headers=None, insecure=False): """Issue an http request.""" center('api.http_request') cdebug(' url: %s' % url) cdebug(' method: %s' % method) cdebug(' body: %s' % body) cdebug(' headers: %s' % headers) cdebug(' insecure: %s' % insecure) http = httplib2.Http(disable_ssl_certificate_validation=insecure) try: cleave('api.http_request') return http.request(url, method, body=body, headers=headers) except httplib2.SSLHandshakeError: cleave('api.http_request') raise MaasApiCertificateVerificationError(0, "Certificate verification failed, use --insecure/-k to " "disable the certificate check.")
def __init__(s, url, creds): center(s.__class__.__name__) cdebug(' url: %s' % url) cdebug(' creds: %s' % creds) super(MapiClient, s).__init__(url, creds) cleave(s.__class__.__name__)
def prepare_payload(cls, op, method, uri, data): """Return the URI (modified perhaps) and body and headers. - For GET requests, encode parameters in the query string. - Otherwise always encode parameters in the request body. - Except op; this can always go in the query string. :param method: The HTTP method. :param uri: The URI of the action. :param data: An iterable of ``name, value`` or ``name, opener`` tuples (see `name_value_pair`) to pack into the body or query, depending on the type of request. """ center('RestClient.prepare_payload') cdebug(' op : %s' % op) cdebug('method : %s' % method) cdebug(' uri : %s' % uri) cdebug(' data : %s' % data) query = [] if op is None else [("op", op)] def slurp(opener): with opener() as fd: return fd.read() if method == "GET": query.extend((name, slurp(value) if callable(value) else value) for name, value in data) body, headers = None, [] else: if data is None or len(data) == 0: body, headers = None, [] else: cdebug('encode multipart') message = build_multipart_message(data) headers, body = encode_multipart_message(message) uri = urlparse(uri)._replace(query=urlencode(query)).geturl() cleave('RestClient.prepare_payload') cdebug(' uri : %s' % uri) cdebug(' body : %s' % body) cdebug('headers : %s' % headers) return uri, body, headers
def prepare_payload(cls, op, method, uri, data): """Return the URI (modified perhaps) and body and headers. - For GET requests, encode parameters in the query string. - Otherwise always encode parameters in the request body. - Except op; this can always go in the query string. :param method: The HTTP method. :param uri: The URI of the action. :param data: An iterable of ``name, value`` or ``name, opener`` tuples (see `name_value_pair`) to pack into the body or query, depending on the type of request. """ center('RestClient.prepare_payload') cdebug(' op : %s' % op) cdebug('method : %s' % method) cdebug(' uri : %s' % uri) cdebug(' data : %s' % data) query = [] if op is None else [("op", op)] def slurp(opener): with opener() as fd: return fd.read() if method == "GET": query.extend( (name, slurp(value) if callable(value) else value) for name, value in data) body, headers = None, [] else: if data is None or len(data) == 0: body, headers = None, [] else: cdebug('encode multipart') message = build_multipart_message(data) headers, body = encode_multipart_message(message) uri = urlparse(uri)._replace(query=urlencode(query)).geturl() cleave('RestClient.prepare_payload') cdebug(' uri : %s' % uri) cdebug(' body : %s' % body) cdebug('headers : %s' % headers) return uri, body, headers
def dump(s, d=None, title=None, key=None, more=False): if d is None: d = dict(s) if title: cdebug(title) cdebug('-------------------------------------------------------------------------------------------') if type(d) == dict: if key is not None: cdebug('%s : {' % key) else: cdebug('{') for k in d: if type(d[k]) == dict or type(d[k]) == list: Clog.indent += 4 s.dump(d[k], key=k, more=True) Clog.indent -= 4 else: cdebug(' %s : %s,' % (k, d[k])) if more: cdebug('},') else: cdebug('}') elif type(d) == list: if key is not None: cdebug('%s : [' % key) else: cdebug('[') for k in d: if type(k) == dict : Clog.indent += 4 s.dump(k, more=True) Clog.indent -= 4 elif type(k) == list: Clog.indent += 4 s.dump(k, key=k, more=True) Clog.indent -= 4 else: cdebug(' %s,' % (k)) if more: cdebug('],') else: cdebug(']') else: cdebug(' %s,' % (d))
def dump(s, d=None, title=None, key=None, more=False): if d is None: d = dict(s) if title: cdebug(title) cdebug( '-------------------------------------------------------------------------------------------' ) if type(d) == dict: if key is not None: cdebug('%s : {' % key) else: cdebug('{') for k in d: if type(d[k]) == dict or type(d[k]) == list: Clog.indent += 4 s.dump(d[k], key=k, more=True) Clog.indent -= 4 else: cdebug(' %s : %s,' % (k, d[k])) if more: cdebug('},') else: cdebug('}') elif type(d) == list: if key is not None: cdebug('%s : [' % key) else: cdebug('[') for k in d: if type(k) == dict: Clog.indent += 4 s.dump(k, more=True) Clog.indent -= 4 elif type(k) == list: Clog.indent += 4 s.dump(k, key=k, more=True) Clog.indent -= 4 else: cdebug(' %s,' % (k)) if more: cdebug('],') else: cdebug(']') else: cdebug(' %s,' % (d))