def add_node(self, node_list, lb_id, current_timestamp): """ Returns the canned response for add nodes """ if lb_id in self.lbs: _verify_and_update_lb_state(self, lb_id, False, current_timestamp) if self.lbs[lb_id]["status"] != "ACTIVE": resource = invalid_resource( "Load Balancer '{0}' has a status of {1} and is considered " "immutable.".format(lb_id, self.lbs[lb_id]["status"]), 422) return (resource, 422) nodes = _format_nodes_on_lb(node_list) if self.lbs[lb_id].get("nodes"): for existing_node in self.lbs[lb_id]["nodes"]: for new_node in node_list: if (existing_node["address"] == new_node["address"] and existing_node["port"] == new_node["port"]): resource = invalid_resource( "Duplicate nodes detected. One or more nodes " "already configured on load balancer.", 413) return (resource, 413) self.lbs[lb_id]["nodes"] = self.lbs[lb_id]["nodes"] + nodes else: self.lbs[lb_id]["nodes"] = nodes self.lbs[lb_id]["nodeCount"] = len(self.lbs[lb_id]["nodes"]) _verify_and_update_lb_state(self, lb_id, current_timestamp=current_timestamp) return {"nodes": nodes}, 202 return not_found_response("loadbalancer"), 404
def del_load_balancer(self, lb_id, current_timestamp): """ Returns response for a load balancer is in building status for 20 seconds and response code 202, and adds the new lb to ``self.lbs``. A loadbalancer, on delete, goes into PENDING-DELETE and remains in DELETED status until a nightly job(maybe?) """ if lb_id in self.lbs: if self.lbs[lb_id]["status"] == "PENDING-DELETE": msg = ("Must provide valid load balancers: {0} are immutable and " "could not be processed.".format(lb_id)) # Dont doubt this to be 422, it is 400! return invalid_resource(msg, 400), 400 _verify_and_update_lb_state(self, lb_id, True, current_timestamp) if any([self.lbs[lb_id]["status"] == "ACTIVE", self.lbs[lb_id]["status"] == "ERROR", self.lbs[lb_id]["status"] == "PENDING-UPDATE"]): del self.lbs[lb_id] return EMPTY_RESPONSE, 202 if self.lbs[lb_id]["status"] == "PENDING-DELETE": return EMPTY_RESPONSE, 202 if self.lbs[lb_id]["status"] == "DELETED": _verify_and_update_lb_state(self, lb_id, current_timestamp=current_timestamp) msg = "Must provide valid load balancers: {0} could not be found.".format(lb_id) # Dont doubt this to be 422, it is 400! return invalid_resource(msg, 400), 400 return not_found_response("loadbalancer"), 404
def add_node(self, node_list, lb_id): """ Add one or more nodes to a load balancer. Fails if one or more of the nodes provided has the same address/port as an existing node. Also fails if adding the nodes would exceed the maximum number of nodes on the CLB. :param list node_list: a `list` of `dict` containing specification for nodes :return: a `tuple` of (json response as a dict, http status code) """ if lb_id in self.lbs: current_timestamp = self.clock.seconds() self._verify_and_update_lb_state(lb_id, False, current_timestamp) if self.lbs[lb_id]["status"] != "ACTIVE": return considered_immutable_error( self.lbs[lb_id]["status"], lb_id) nodes = [Node.from_json(blob) for blob in node_list] for existing_node in self.lbs[lb_id].nodes: for new_node in nodes: if existing_node.same_as(new_node): resource = invalid_resource( "Duplicate nodes detected. One or more nodes " "already configured on load balancer.", 413) return (resource, 413) # If there were no duplicates new_nodeCount = len(self.lbs[lb_id].nodes) + len(nodes) if new_nodeCount <= self.node_limit: self.lbs[lb_id].nodes = self.lbs[lb_id].nodes + nodes else: resource = invalid_resource( "Nodes must not exceed {0} " "per load balancer.".format(self.node_limit), 413) return (resource, 413) # Node status will be OFFLINE if health monitor is enabled in CLB # ONLINE if health monitor is disabled if self.lbs[lb_id].health_monitor != {}: for node in nodes: node.status = "OFFLINE" self._add_node_created_feeds(nodes) self._verify_and_update_lb_state( lb_id, current_timestamp=current_timestamp) return {"nodes": [node.as_json() for node in nodes]}, 202 return not_found_response("loadbalancer"), 404
def get_token_and_service_catalog(self, request): """ Return a service catalog consisting of all plugin endpoints and an api token. """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) tenant_id = (content['auth'].get('tenantName', None) or content['auth'].get('tenantId', None)) if content['auth'].get('passwordCredentials'): username = content['auth']['passwordCredentials']['username'] password = content['auth']['passwordCredentials']['password'] session = self.core.sessions.session_for_username_password( username, password, tenant_id) elif content['auth'].get('RAX-KSKEY:apiKeyCredentials'): username = content['auth']['RAX-KSKEY:apiKeyCredentials']['username'] api_key = content['auth']['RAX-KSKEY:apiKeyCredentials']['apiKey'] session = self.core.sessions.session_for_api_key( username, api_key, tenant_id) elif content['auth'].get('token') and tenant_id: session = self.core.sessions.session_for_token( content['auth']['token']['id'], tenant_id) else: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) request.setResponseCode(200) prefix_map = { # map of entry to URI prefix for that entry } def lookup(entry): return prefix_map[entry] return json.dumps( get_token( session.tenant_id, entry_generator=lambda tenant_id: list(self.core.entries_for_tenant( tenant_id, prefix_map, base_uri_from_request(request))), prefix_for_endpoint=lookup, response_token=session.token, response_user_id=session.user_id, response_user_name=session.username, ) )
def delete_node(store, lb_id, node_id, current_timestamp): """ Determines whether the node to be deleted exists in mimic store and returns the response code. """ if lb_id in store.lbs: _verify_and_update_lb_state(store, lb_id, False, current_timestamp) if store.lbs[lb_id]["status"] != "ACTIVE": resource = invalid_resource( "Load Balancer '{0}' has a status of {1} and is considered " "immutable.".format(lb_id, store.lbs[lb_id]["status"]), 422) return (resource, 422) _verify_and_update_lb_state(store, lb_id, current_timestamp=current_timestamp) if store.lbs[lb_id].get("nodes"): for each in store.lbs[lb_id]["nodes"]: if each["id"] == node_id: index = store.lbs[lb_id]["nodes"].index(each) del store.lbs[lb_id]["nodes"][index] if not store.lbs[lb_id]["nodes"]: del store.lbs[lb_id]["nodes"] store.lbs[lb_id].update({"nodeCount": len(store.lbs[lb_id].get("nodes", []))}) return None, 202 return not_found_response("node"), 404 return not_found_response("loadbalancer"), 404
def get_token_and_service_catalog(self, request): """ Return a service catalog consisting of all plugin endpoints and an api token. """ try: content = json_from_request(request) except ValueError: pass else: for cred_type in (PasswordCredentials, APIKeyCredentials, TokenCredentials): if cred_type.type_key in content['auth']: try: cred = cred_type.from_json(content) except (KeyError, TypeError): pass else: registry = self.registry_collection.registry_by_event( authentication) behavior = registry.behavior_for_attributes( attr.asdict(cred)) return behavior(self.core, request, cred) request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body"))
def delete_node(self, lb_id, node_id, current_timestamp): """ Determines whether the node to be deleted exists in the session store, deletes the node, and returns the response code. """ if lb_id in self.lbs: _verify_and_update_lb_state(self, lb_id, False, current_timestamp) if self.lbs[lb_id]["status"] != "ACTIVE": # Error message verified as of 2015-04-22 resource = invalid_resource( "Load Balancer '{0}' has a status of '{1}' and is considered " "immutable.".format(lb_id, self.lbs[lb_id]["status"]), 422) return (resource, 422) _verify_and_update_lb_state(self, lb_id, current_timestamp=current_timestamp) if _delete_node(self, lb_id, node_id): return None, 202 else: return not_found_response("node"), 404 return not_found_response("loadbalancer"), 404
def create_server(tenant_id, server_info, server_id, compute_uri_prefix): """ Canned response for create server and adds the server to the server cache. """ status = "ACTIVE" if 'metadata' in server_info: if 'create_server_failure' in server_info['metadata']: dict_meta = json.loads(server_info['metadata']['create_server_failure']) return invalid_resource(dict_meta['message'], dict_meta['code']), dict_meta['code'] if 'server_building' in server_info['metadata']: status = "BUILD" if 'server_error' in server_info['metadata']: status = "ERROR" s_cache[server_id] = server_template( tenant_id, server_info, server_id, status, compute_uri_prefix=compute_uri_prefix, ) return { 'server': {"OS-DCF:diskConfig": s_cache[server_id]['OS-DCF:diskConfig'], "id": s_cache[server_id]['id'], "links": s_cache[server_id]['links'], "adminPass": "******"}}, 202
def set_attributes(self, request, tenant_id, clb_id): """ Alters the supported attributes of the CLB to supported values. To return things back to normal, you'll first need to list the CLB to get any original values yourself. """ regional_lbs = self._collection_from_tenant(tenant_id) if not regional_lbs.lb_in_region(clb_id): request.setResponseCode(404) return json.dumps({ "message": "Tenant {0} doesn't own load balancer {1}".format( tenant_id, clb_id ), "code": 404, }) try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) try: regional_lbs.set_attributes(clb_id, content) except BadKeysError, bke: request.setResponseCode(400) return json.dumps({ "message": str(bke), "code": 400, })
def get_image(image_id): """ Canned response for get image. The image id provided is substituted in the response, if not one of the invalid image ids specified in mimic_presets. """ if any([image_id in get_presets['servers']['invalid_image_ref'], image_id.endswith('Z')]): return invalid_resource('Invalid imageRef provided.', 400), 400 return {'image': {'status': 'ACTIVE', 'id': image_id}}, 200
def get_flavor(flavor_id): """ Canned response for get flavor. The flavor id provided is substituted in the response """ if flavor_id in get_presets['servers']['invalid_flavor_ref']: return invalid_resource('Invalid flavorRef provided.', 400), 400 return {'flavor': {'name': '512MB Standard Instance', 'id': flavor_id}}, 200
def update_node_status(self, request, tenant_id, clb_id, node_id): """ Update given node's status. The request will be like:: {"status": "ONLINE"} """ regional_lbs = self._collection_from_tenant(tenant_id) clb = regional_lbs.lbs.get(clb_id) if clb is None: request.setResponseCode(404) return json.dumps({ "message": "Tenant {0} doesn't own load balancer {1}".format( tenant_id, clb_id ), "code": 404, }) node = next((node for node in clb.nodes if node.id == node_id), None) if node is None: request.setResponseCode(404) return json.dumps({ "message": "Load balancer {1} on tenant {0} does not have node {2}".format( tenant_id, clb_id, node_id), "code": 404, }) try: content = json_from_request(request) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) if content.get("status") not in ("ONLINE", "OFFLINE"): request.setResponseCode(400) return json.dumps(invalid_resource( "status key not found or it must have ONLINE or OFFLINE value")) node.status = content["status"] request.setResponseCode(200) return b""
def add_node_to_load_balancer(self, request, tenant_id, lb_id): """ Return a successful add node response with code 200 """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) node_list = content['nodes'] response_data = self.session(tenant_id).add_node(node_list, lb_id) request.setResponseCode(response_data[1]) return json.dumps(response_data[0])
def update_health_monitor(self, request, tenant_id, lb_id): """ Update health monitor setting of given LB. https://developer.rackspace.com/docs/cloud-load-balancers/v1/developer-guide/#update-health-monitor """ try: content = json_from_request(request) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) body, code = self.session(tenant_id).update_health_monitor( lb_id, content) request.setResponseCode(code) return json_dump(body)
def delete_server(server_id): """ Returns True if the server was deleted from the cache, else returns false. """ if server_id in s_cache: if 'delete_server_failure' in s_cache[server_id]['metadata']: del_meta = json.loads(s_cache[server_id]['metadata']['delete_server_failure']) if del_meta['times'] != 0: del_meta['times'] = del_meta['times'] - 1 s_cache[server_id]['metadata']['delete_server_failure'] = json.dumps(del_meta) return invalid_resource('server error', del_meta['code']), del_meta['code'] del s_cache[server_id] return True, 204 else: return not_found_response(), 404
def add_load_balancer(self, request, tenant_id): """ Creates a load balancer and adds it to the load balancer store. Returns the newly created load balancer with response code 202 """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) lb_id = randrange(99999) response_data = self.session(tenant_id).add_load_balancer( content['loadBalancer'], lb_id ) request.setResponseCode(response_data[1]) return json.dumps(response_data[0])
def get_impersonation_token(self, request): """ Return a token id with expiration. """ request.setResponseCode(200) try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) cred = ImpersonationCredentials.from_json(content, request.getHeader("x-auth-token")) registry = self.registry_collection.registry_by_event(authentication) behavior = registry.behavior_for_attributes( {"token": cred.impersonator_token, "username": cred.impersonated_username} ) return behavior(self.core, request, cred)
def list_nodes(self, lb_id, current_timestamp): """ Returns the list of nodes remaining on the load balancer """ if lb_id in self.lbs: _verify_and_update_lb_state(self, lb_id, False, current_timestamp) if lb_id not in self.lbs: return not_found_response("loadbalancer"), 404 if self.lbs[lb_id]["status"] == "DELETED": return invalid_resource("The loadbalancer is marked as deleted.", 410), 410 node_list = [] if self.lbs[lb_id].get("nodes"): node_list = self.lbs[lb_id]["nodes"] return {"nodes": node_list}, 200 else: return not_found_response("loadbalancer"), 404
def list_nodes(self, lb_id): """ Returns the list of nodes remaining on the load balancer """ if lb_id in self.lbs: self._verify_and_update_lb_state(lb_id, False, self.clock.seconds()) if lb_id not in self.lbs: return not_found_response("loadbalancer"), 404 if self.lbs[lb_id]["status"] == "DELETED": return invalid_resource("The loadbalancer is marked as deleted.", 410), 410 node_list = [node.as_json() for node in self.lbs[lb_id].nodes] return {"nodes": node_list}, 200 else: return not_found_response("loadbalancer"), 404
def add_node(node_list, lb_id): """ Returns the canned response for add nodes """ if lb_id in lb_cache: nodes = _format_nodes_on_lb(node_list) if lb_cache[lb_id].get("nodes"): for existing_node in lb_cache[lb_id]["nodes"]: for new_node in node_list: if (existing_node["address"] == new_node["address"] and existing_node["port"] == new_node["port"]): return invalid_resource("Duplicate nodes detected. One or more nodes " "already configured on load balancer.", 413), 413 lb_cache[lb_id]["nodes"] = lb_cache[lb_id]["nodes"] + nodes else: lb_cache[lb_id]["nodes"] = nodes return {"nodes": nodes}, 200 else: return not_found_response("loadbalancer"), 404
def get_node(self, lb_id, node_id): """ Returns the node on the load balancer """ if lb_id in self.lbs: self._verify_and_update_lb_state(lb_id, False, self.clock.seconds()) if self.lbs[lb_id]["status"] == "DELETED": return (invalid_resource( "The loadbalancer is marked as deleted.", 410), 410) for each in self.lbs[lb_id].nodes: if node_id == each.id: return {"node": each.as_json()}, 200 return not_found_response("node"), 404 return not_found_response("loadbalancer"), 404
def get_node(self, lb_id, node_id): """ Returns the node on the load balancer """ if lb_id in self.lbs: self._verify_and_update_lb_state(lb_id, False, self.clock.seconds()) if self.lbs[lb_id]["status"] == "DELETED": return ( invalid_resource( "The loadbalancer is marked as deleted.", 410), 410) for each in self.lbs[lb_id].nodes: if node_id == each.id: return {"node": each.as_json()}, 200 return not_found_response("node"), 404 return not_found_response("loadbalancer"), 404
def create_server(self, request, tenant_id): """ Returns a generic create server response, with status 'ACTIVE'. """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) server_id = 'test-server{0}-id-{0}'.format(str(randrange(9999999999))) response_data = create_server( tenant_id, content['server'], server_id, self.uri_prefix, s_cache=self._server_cache_for_tenant(tenant_id), current_time=seconds_to_timestamp( self._session_store.clock.seconds()) ) request.setResponseCode(response_data[1]) return json.dumps(response_data[0])
def get_impersonation_token(self, request): """ Return a token id with expiration. """ request.setResponseCode(200) try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) expires_in = content['RAX-AUTH:impersonation']['expire-in-seconds'] username = content['RAX-AUTH:impersonation']['user']['username'] session = self.core.sessions.session_for_impersonation(username, expires_in) return json.dumps({"access": { "token": {"id": session.token, "expires": format_timestamp(session.expires)} }})
def get_nodes(self, lb_id, node_id, current_timestamp): """ Returns the node on the load balancer """ if lb_id in self.lbs: _verify_and_update_lb_state(self, lb_id, False, current_timestamp) if self.lbs[lb_id]["status"] == "DELETED": return ( invalid_resource( "The loadbalancer is marked as deleted.", 410), 410) if self.lbs[lb_id].get("nodes"): for each in self.lbs[lb_id]["nodes"]: if node_id == each["id"]: return {"node": each}, 200 return not_found_response("node"), 404 return not_found_response("loadbalancer"), 404
def add_node(node_list, lb_id): """ Returns the canned response for add nodes """ if lb_id in lb_cache: nodes = _format_nodes_on_lb(node_list) if lb_cache[lb_id].get("nodes"): for existing_node in lb_cache[lb_id]["nodes"]: for new_node in node_list: if (existing_node["address"] == new_node["address"] and existing_node["port"] == new_node["port"]): return invalid_resource( "Duplicate nodes detected. One or more nodes " "already configured on load balancer.", 413), 413 lb_cache[lb_id]["nodes"] = lb_cache[lb_id]["nodes"] + nodes else: lb_cache[lb_id]["nodes"] = nodes return {"nodes": nodes}, 200 else: return not_found_response("loadbalancer"), 404
def create_server(self, request, tenant_id): """ Returns a generic create server response, with status 'ACTIVE'. """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) server_id = 'test-server{0}-id-{0}'.format(str(randrange(9999999999))) response_data = create_server( tenant_id, content['server'], server_id, self.uri_prefix, s_cache=self._server_cache_for_tenant(tenant_id), current_time=seconds_to_timestamp( self._session_store.clock.seconds())) request.setResponseCode(response_data[1]) return json.dumps(response_data[0])
def get_impersonation_token(self, request): """ Return a token id with expiration. """ request.setResponseCode(200) try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) cred = ImpersonationCredentials.from_json( content, request.getHeader("x-auth-token")) registry = self.registry_collection.registry_by_event(authentication) behavior = registry.behavior_for_attributes({ "token": cred.impersonator_token, "username": cred.impersonated_username }) return behavior(self.core, request, cred)
def get_impersonation_token(self, request): """ Return a token id with expiration. """ request.setResponseCode(200) try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) expires_in = content['RAX-AUTH:impersonation']['expire-in-seconds'] username = content['RAX-AUTH:impersonation']['user']['username'] session = self.core.sessions.session_for_impersonation( username, expires_in) return json.dumps({ "access": { "token": { "id": session.token, "expires": format_timestamp(session.expires) } } })
def fail_without_creating(collection, http, json, absolutize_url): # behavior for failing to even start to build http.setResponseCode(status_code) return dumps(invalid_resource(failure_message, status_code))
def fail_and_dont_do_anything(collection, http, json, absolutize_url): # behavior for failing to even start to build http.setResponseCode(failure['code']) return dumps(invalid_resource(failure['message'], failure['code']))
def get_token_and_service_catalog(self, request): """ Return a service catalog consisting of all plugin endpoints and an api token. """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) tenant_id = (content['auth'].get('tenantName', None) or content['auth'].get('tenantId', None)) def format_response(callable_returning_session, nonmatching_tenant_message_generator): try: session = callable_returning_session() except NonMatchingTenantError as e: request.setResponseCode(401) return json.dumps({ "unauthorized": { "code": 401, "message": nonmatching_tenant_message_generator(e) } }) else: request.setResponseCode(200) prefix_map = { # map of entry to URI prefix for that entry } def lookup(entry): return prefix_map[entry] result = get_token( session.tenant_id, entry_generator=lambda tenant_id: list(self.core.entries_for_tenant( tenant_id, prefix_map, base_uri_from_request(request))), prefix_for_endpoint=lookup, response_token=session.token, response_user_id=session.user_id, response_user_name=session.username, ) return json.dumps(result) username_generator = ( lambda exception: "Tenant with Name/Id: '{0}' is not valid for " "User '{1}' (id: '{2}')".format( exception.desired_tenant, exception.session.username, exception.session.user_id)) if content['auth'].get('passwordCredentials'): username = content['auth']['passwordCredentials']['username'] password = content['auth']['passwordCredentials']['password'] return format_response( lambda: self.core.sessions.session_for_username_password( username, password, tenant_id), username_generator) elif content['auth'].get('RAX-KSKEY:apiKeyCredentials'): username = content['auth']['RAX-KSKEY:apiKeyCredentials'][ 'username'] api_key = content['auth']['RAX-KSKEY:apiKeyCredentials'][ 'apiKey'] return format_response( lambda: self.core.sessions.session_for_api_key( username, api_key, tenant_id), username_generator) elif content['auth'].get('token') and tenant_id: token = content['auth']['token']['id'] return format_response( lambda: self.core.sessions.session_for_token( token, tenant_id), lambda e: "Token doesn't belong to Tenant with Id/Name: " "'{0}'".format(e.desired_tenant)) else: request.setResponseCode(400) return json.dumps( invalid_resource("Invalid JSON request body"))
def get_token_and_service_catalog(self, request): """ Return a service catalog consisting of all plugin endpoints and an api token. """ try: content = json.loads(request.content.read()) except ValueError: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body")) tenant_id = (content['auth'].get('tenantName', None) or content['auth'].get('tenantId', None)) def format_response(callable_returning_session, nonmatching_tenant_message_generator): try: session = callable_returning_session() except NonMatchingTenantError as e: request.setResponseCode(401) return json.dumps({ "unauthorized": { "code": 401, "message": nonmatching_tenant_message_generator(e) } }) else: request.setResponseCode(200) prefix_map = { # map of entry to URI prefix for that entry } def lookup(entry): return prefix_map[entry] result = get_token( session.tenant_id, entry_generator=lambda tenant_id: list( self.core.entries_for_tenant( tenant_id, prefix_map, base_uri_from_request(request))), prefix_for_endpoint=lookup, response_token=session.token, response_user_id=session.user_id, response_user_name=session.username, ) return json.dumps(result) username_generator = ( lambda exception: "Tenant with Name/Id: '{0}' is not valid for " "User '{1}' (id: '{2}')".format(exception.desired_tenant, exception .session.username, exception. session.user_id)) if content['auth'].get('passwordCredentials'): username = content['auth']['passwordCredentials']['username'] password = content['auth']['passwordCredentials']['password'] return format_response( lambda: self.core.sessions.session_for_username_password( username, password, tenant_id), username_generator) elif content['auth'].get('RAX-KSKEY:apiKeyCredentials'): username = content['auth']['RAX-KSKEY:apiKeyCredentials'][ 'username'] api_key = content['auth']['RAX-KSKEY:apiKeyCredentials']['apiKey'] return format_response( lambda: self.core.sessions.session_for_api_key( username, api_key, tenant_id), username_generator) elif content['auth'].get('token') and tenant_id: token = content['auth']['token']['id'] return format_response( lambda: self.core.sessions.session_for_token(token, tenant_id), lambda e: "Token doesn't belong to Tenant with Id/Name: " "'{0}'".format(e.desired_tenant)) else: request.setResponseCode(400) return json.dumps(invalid_resource("Invalid JSON request body"))