def call_director(self, method, post, data=None, use_certs=True): """Call the director API. Loads the director JSON response and returns it as a Python object. If the returned data can not be decoded it is returned as it is. 'method': a string representing the API method name. 'post': boolean value. True for POST method, false for GET. 'data': a dictionary representing the data to be sent to the director. TODO: use HTTPMethod.x instead of bool for post parameter... """ if self.director_url is None: raise Exception("Cannot call the ConPaaS director:" " the director URL address is not specified.") if data is None: data = {} if not "username" in data: data["username"] = self.username if data["username"] is None: raise Exception("Cannot call the ConPaaS director:" " user name is not specified.") if use_certs: # If certificates are used, the ssl context should already have # been initialized with the user's certificates in __init__ if not client.is_ssl_ctx_initialized(): raise Exception( "Cannot call the ConPaaS director: " "user certificates are not present.\n" "Try to run 'cps-user get_certificate' " "first." ) if self.debug: self.logger.debug("User certificates are present and will be used.") else: # If not, we need to send the user's password and initialize the # ssl context with one that does not use certificates if not "password" in data: if self.password is None: data["password"] = self._get_password() else: data["password"] = self.password client.conpaas_init_ssl_ctx_no_certs() if self.debug: self.logger.debug("User certificates will NOT be used.") url = "%s/%s" % (self.director_url, method) if self.debug: if "password" in data: data_log = dict(data) # hiding password from log if data_log["password"] == "": data_log["password"] = "******" else: data_log["password"] = "******" else: data_log = data self.logger.info("Requesting '%s' with data %s." % (url, data_log)) parsed_url = urlparse.urlparse(self.director_url) try: if post: status, body = client.https_post(parsed_url.hostname, parsed_url.port or 443, url, data) else: status, body = client.https_get(parsed_url.hostname, parsed_url.port or 443, url, data) except Exception as ex: if "certificate verify failed" in str(ex): raise Exception( "The ConPaaS director's SSL certificate " "failed verification.\n" "You may be the victim of a man-in-the-middle " "attack or, if you recently changed the " "ConPaaS deployment, you need to run " "'cps-user get_certificate' first." ) if self.debug: traceback.print_exc() raise Exception("Cannot contact the director at URL '%s': %s" % (url, ex)) if status != 200: raise Exception( "Call to method '%s' on '%s' failed: HTTP status %s.\n" "Params = %s" % (method, url, status, data) ) try: res = simplejson.loads(body) except simplejson.decoder.JSONDecodeError: # Not JSON, simply return what we got if self.debug: self.logger.info("Call succeeded, result is not json.") return body if type(res) is dict and "error" in res: if self.debug: self.logger.info("Call succeeded, result contains an error") raise Exception(res["error"]) self.logger.info("Call succeeded, result is: %s" % res) return res
def call_manager(self, app_id, service_id, method, post, data=None, files=None): """Call the manager API. Loads the manager JSON response and returns it as a Python object. 'service_id': an integer holding the service id of the manager. 'method': a string representing the API method name. 'post': boolean value. True for POST method, false for GET. 'data': a dictionary representing the data to be sent to the director. 'files': sequence of (name, filename, value) tuples for data to be uploaded as files. """ application = self.application_dict(app_id) if application["manager"] is None: raise Exception("Application %s has not started. Try to start it first." % app_id) if data is None: data = {} if files is None: files = [] url = "https://%s/" % application["manager"] # Certificates are always used, the ssl context should already have # been initialized with the user's certificates in __init__ if not client.is_ssl_ctx_initialized(): raise Exception( "Cannot call the manager: " "user certificates are not present.\n" "Try to run 'cps-user get_certificate' " "first." ) if self.debug: self.logger.debug("User certificates are present and will be used.") self.logger.info( "Requesting '%s' with aid %s, sid %s, method '%s', " "data %s and %s files." % (url, app_id, service_id, method, data, len(files)) ) try: # File upload if files: status, body = client.https_post(application["manager"], 443, "/", data, files) # POST elif post: status, body = client.jsonrpc_post(application["manager"], 443, "/", method, service_id, data) # GET else: status, body = client.jsonrpc_get(application["manager"], 443, "/", method, service_id, data) except Exception as ex: if "certificate verify failed" in str(ex): raise Exception( "The ConPaaS manager's SSL certificate " "failed verification.\n" "You may be the victim of a man-in-the-middle " "attack or, if you recently changed the " "ConPaaS deployment, you need to run " "'cps-user get_certificate' first." ) if self.debug: traceback.print_exc() raise Exception("Cannot contact the manager at URL '%s': %s" % (url, ex)) if status != 200: raise Exception( "Call to method '%s' on '%s' failed: HTTP status %s.\n" "Params = %s" % (method, application["manager"], status, data) ) try: data = simplejson.loads(body) except simplejson.decoder.JSONDecodeError: # Not JSON, simply return what we got if self.debug: self.logger.info("Call succeeded, result is not json.") return body res = data.get("result", data) if type(res) is dict and "error" in res: if self.debug: self.logger.info("Call succeeded, result contains an error") raise Exception(res["error"]) self.logger.info("Call succeeded, result is: %s" % res) return res