Пример #1
0
    def change_attributes(self, request, tenant_id):
        """
        Modify the specified attributes on existing servers.

        The request looks like this::

            {
                "status": {
                    "test_server_id_8482197407": "ERROR",
                    "test_server_id_0743289146": "BUILD"
                }
            }

        As more attributes are added, they should be additional top-level keys
        where "status" goes in this request.
        """
        region_collection = self._collection_from_tenant(tenant_id)
        attributes_description = json_from_request(request)
        statuses_description = attributes_description["status"]
        servers = [
            region_collection.server_by_id(server_id)
            for server_id in statuses_description
        ]
        if None in servers:
            request.setResponseCode(BAD_REQUEST)
            return b''
        for server in servers:
            server.update_status(statuses_description[server.server_id])
        request.setResponseCode(CREATED)
        return b''
Пример #2
0
    def create_endpoint_for_tenant(self, request, tenant_id):
        """
        Enable a given endpoint template for a given tenantid.

        `OpenStack Identity v2 OS-KSCATALOG Create Endpoint for Tenant
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body", request))

        try:
            template_id = content["OS-KSCATALOG:endpointTemplate"]["id"]
        except KeyError:
            return json.dumps(bad_request("Invalid Content. OS-KSCATALOG:endpointTemplate:id is " "required.", request))

        for api_id in self.core.get_external_apis():
            api = self.core.get_external_api(api_id)
            if api.has_template(template_id):
                api.enable_endpoint_for_tenant(tenant_id, template_id)
                request.setResponseCode(201)
                return b""

        return json.dumps(not_found("Unable to locate an External API with the given Template ID.", request))
Пример #3
0
    def create_image(self, http_create_request):
        """
        Creates a new image with the given request json and returns the image.

        Note: This is more like a control plane API as I dint find seem
        to find documentation for add image under the Glance admin API.
        """
        try:
            content = json_from_request(http_create_request)
            image_name = content.get('name')
            if image_name is None:
                raise KeyError("no name supplied")
            image_distro = content.get('distro')
            if image_distro is None:
                raise KeyError("no distro supplied")
        except Exception as e:
            http_create_request.setResponseCode(400)
            return dumps({"Error": text_type(e)})
        image_id = text_type(uuid4())
        new_image = self.add_to_glance_admin_image_store(
            image_id=image_id,
            name=image_name,
            distro=image_distro)
        http_create_request.setResponseCode(201)
        return new_image.get_glance_admin_image_json()
Пример #4
0
    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_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(invalid_resource("Invalid JSON request body"))

        try:
            regional_lbs.set_attributes(clb_id, content)
        except (BadKeysError, BadValueError) as err:
            request.setResponseCode(err.code)
            return json.dumps(err.to_json())
        else:
            request.setResponseCode(204)
            return b''
Пример #5
0
    def create_image(self, http_create_request):
        """
        Creates a new image with the given request json and returns the image.

        Note: This is more like a control plane API as I dint find seem
        to find documentation for add image under the Glance admin API.
        """
        try:
            content = json_from_request(http_create_request)
            image_name = content.get('name')
            if image_name is None:
                raise KeyError("no name supplied")
            image_distro = content.get('distro')
            if image_distro is None:
                raise KeyError("no distro supplied")
        except Exception as e:
            http_create_request.setResponseCode(400)
            return dumps({"Error": text_type(e)})
        image_id = text_type(uuid4())
        new_image = self.add_to_glance_admin_image_store(
            image_id=image_id,
            name=image_name,
            distro=image_distro)
        http_create_request.setResponseCode(201)
        return new_image.get_glance_admin_image_json()
Пример #6
0
    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"))
Пример #7
0
    def create_endpoint_for_tenant(self, request, tenant_id):
        """
        Enable a given endpoint template for a given tenantid.

        `OpenStack Identity v2 OS-KSCATALOG Create Endpoint for Tenant
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body",
                                          request))

        try:
            template_id = content['OS-KSCATALOG:endpointTemplate']['id']
        except KeyError:
            return json.dumps(
                bad_request(
                    "Invalid Content. OS-KSCATALOG:endpointTemplate:id is "
                    "required.", request))

        for api_id in self.core.get_external_apis():
            api = self.core.get_external_api(api_id)
            if api.has_template(template_id):
                api.enable_endpoint_for_tenant(tenant_id, template_id)
                request.setResponseCode(201)
                return b''

        return json.dumps(
            not_found(
                "Unable to locate an External API with the given Template ID.",
                request))
Пример #8
0
    def change_attributes(self, request, tenant_id):
        """
        Modify the specified attributes on existing servers.

        The request looks like this::

            {
                "status": {
                    "test_server_id_8482197407": "ERROR",
                    "test_server_id_0743289146": "BUILD"
                }
            }

        As more attributes are added, they should be additional top-level keys
        where "status" goes in this request.
        """
        region_collection = self._collection_from_tenant(tenant_id)
        attributes_description = json_from_request(request)
        statuses_description = attributes_description["status"]
        servers = [region_collection.server_by_id(server_id)
                   for server_id in statuses_description]
        if None in servers:
            request.setResponseCode(BAD_REQUEST)
            return b''
        for server in servers:
            server.update_status(statuses_description[server.server_id])
        request.setResponseCode(CREATED)
        return b''
Пример #9
0
    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"))
Пример #10
0
    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_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(invalid_resource("Invalid JSON request body"))

        try:
            regional_lbs.set_attributes(clb_id, content)
        except (BadKeysError, BadValueError) as err:
            request.setResponseCode(err.code)
            return json.dumps(err.to_json())
        else:
            request.setResponseCode(204)
            return b''
Пример #11
0
    def update_endpoint_templates(self, request, template_id):
        """
        Update an API endpoint template already in the system.

        .. note:: A template by the same id must already exist in the system.

        .. note:: Either the service-id must be specified in the header or
            a Service Name by the same name must already exist. Otherwise
            a Not Found (404) will be returned.

        `OpenStack Identity v2 OS-KSCATALOG Update Endpoint Template
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body", request))

        try:
            if content["id"] != template_id:
                return json.dumps(conflict("Template ID in URL does not match that of the JSON body", request))

            endpoint_template_instance = EndpointTemplateStore.deserialize(content)
        except (InvalidEndpointTemplateMissingKey, KeyError) as ex:
            # KeyError is for the content['id'] line
            return json.dumps(
                bad_request("JSON body does not contain the required parameters: " + text_type(ex), request)
            )

        service_id = request.getHeader(b"serviceid")
        if service_id is None:
            for api_id in self.core.get_external_apis():
                api = self.core.get_external_api(api_id)
                if api.has_template(template_id):
                    service_id = api.uuid_key
        else:
            service_id = service_id.decode("utf-8")

        try:
            service = self.core.get_external_api(service_id)
        except ServiceDoesNotExist:
            return json.dumps(not_found("Service API for endoint template not found", request))

        try:
            service.update_template(endpoint_template_instance)
        except (InvalidEndpointTemplateServiceType, InvalidEndpointTemplateId):
            return json.dumps(
                conflict("Endpoint already exists and service id or service type " "does not match.", request)
            )
        except EndpointTemplateDoesNotExist:
            return json.dumps(
                not_found(
                    "Unable to update non-existent template. Template must " "first be added before it can be updated.",
                    request,
                )
            )
        else:
            request.setResponseCode(201)
            return b""
Пример #12
0
    def create_external_api_service(self, request):
        """
        Create a new external api service that endpoint templates
        may be added to.

        .. note:: Only requires 'name' and 'type' fields in the JSON. If the 'id'
            or 'description' fields are present, then they will be used;
            otherwise a UUID4 will be assigned to the 'id' field and the
            'description' will be given a generic value.
        `OpenStack Identity v2 OS-KSADM Create Service
        <http://developer.openstack.org/api-ref/identity/v2-ext/index.html#create-service-admin-extension>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body",
                                          request))

        try:
            service_name = content['name']
            service_type = content['type']
        except KeyError:
            return json.dumps(
                bad_request(
                    "Invalid Content. 'name' and 'type' fields are required.",
                    request))

        try:
            service_id = content['id']
        except KeyError:
            service_id = text_type(uuid.uuid4())

        try:
            service_description = content['description']
        except KeyError:
            service_description = u"External API referenced by Mimic"

        if service_id in self.core.get_external_apis():
            return json.dumps(
                conflict(
                    "Conflict: Service with the same uuid already exists.",
                    request))

        try:
            self.core.add_api(
                ExternalApiStore(service_id,
                                 service_name,
                                 service_type,
                                 description=service_description))
        except ServiceNameExists:
            return json.dumps(
                conflict(
                    "Conflict: Service with the same name already exists.",
                    request))
        else:
            request.setResponseCode(201)
            return b''
Пример #13
0
 def create_stack(self, request, tenant_id):
     """
     Creates a stack.
     See http://api.rackspace.com/api-ref-orchestration.html#stack_create
     """
     region_collection = self._region_collection_for_tenant(tenant_id)
     content = json_from_request(request)
     return region_collection.request_creation(request, content,
                                               absolutize_url=self.url)
Пример #14
0
 def create_stack(self, request, tenant_id):
     """
     Creates a stack.
     See http://api.rackspace.com/api-ref-orchestration.html#stack_create
     """
     region_collection = self._region_collection_for_tenant(tenant_id)
     content = json_from_request(request)
     return region_collection.request_creation(request, content,
                                               absolutize_url=self.url)
Пример #15
0
    def bulk_add_nodes_to_load_balancer_pools(self, request):
        """
        Add multiple nodes to multiple load balancer pools.

        Returns a 400 if the lb pool_id is not a uuid.
        Returns a 409 if the lb pool_id does not exist or the cloud server already exists
        on the lb pool.

        http://docs.rcv3.apiary.io/#post-%2Fv3%2F%7Btenant_id%7D%2Fload_balancer_pools%2Fnodes

        TODO: blow up with a 500 and verify if the given server exists in nova.
        """
        body = json_from_request(request)
        added_nodes = []
        error_response = {"errors": []}

        for each in body:
            pool_id = each['load_balancer_pool']['id']
            try:
                UUID(pool_id, version=4)
            except (ValueError, AttributeError):
                request.setResponseCode(400)
                return json.dumps(
                    'The input was not in the correct format. Please reference '
                    'the documentation at http://docs.rcv3.apiary.io for '
                    'further assistance.')
            pool = self._pool_by_id(pool_id)
            if pool is None:
                response_code = 409
                error_response["errors"].append("Load Balancer Pool {0} does "
                                                "not exist".format(pool_id))
            elif pool.node_by_cloud_server(each['cloud_server']['id']):
                response_code = 409
                error_response["errors"].append(
                    "Cloud Server {0} is already a "
                    "member of Load Balancer Pool "
                    "{1}".format(each['cloud_server']['id'], pool_id))
        if not error_response['errors']:
            for add in body:
                node = LoadBalancerPoolNode(
                    created=seconds_to_timestamp(self.clock.seconds(),
                                                 timestamp_format),
                    load_balancer_pool=pool,
                    cloud_server=add['cloud_server']['id'])

                pool.nodes.append(node)
                added_nodes.append(node)
                response_code = 201

        request.setResponseCode(response_code)
        if response_code == 201:
            return json.dumps([n.short_json() for n in added_nodes])
        else:
            return json.dumps(error_response)
Пример #16
0
    def bulk_add_nodes_to_load_balancer_pools(self, request):
        """
        Add multiple nodes to multiple load balancer pools.

        Returns a 400 if the lb pool_id is not a uuid.
        Returns a 409 if the lb pool_id does not exist or the cloud server already exists
        on the lb pool.

        http://docs.rcv3.apiary.io/#post-%2Fv3%2F%7Btenant_id%7D%2Fload_balancer_pools%2Fnodes

        TODO: blow up with a 500 and verify if the given server exists in nova.
        """
        body = json_from_request(request)
        added_nodes = []
        error_response = {"errors": []}

        for each in body:
            pool_id = each['load_balancer_pool']['id']
            try:
                UUID(pool_id, version=4)
            except (ValueError, AttributeError):
                request.setResponseCode(400)
                return json.dumps('The input was not in the correct format. Please reference '
                                  'the documentation at http://docs.rcv3.apiary.io for '
                                  'further assistance.')
            pool = self._pool_by_id(pool_id)
            if pool is None:
                response_code = 409
                error_response["errors"].append("Load Balancer Pool {0} does "
                                                "not exist".format(pool_id))
            elif pool.node_by_cloud_server(each['cloud_server']['id']):
                response_code = 409
                error_response["errors"].append("Cloud Server {0} is already a "
                                                "member of Load Balancer Pool "
                                                "{1}".format(each['cloud_server']['id'],
                                                             pool_id))
        if not error_response['errors']:
            for add in body:
                node = LoadBalancerPoolNode(
                    created=seconds_to_timestamp(self.clock.seconds(),
                                                 timestamp_format),
                    load_balancer_pool=pool,
                    cloud_server=add['cloud_server']['id'])

                pool.nodes.append(node)
                added_nodes.append(node)
                response_code = 201

        request.setResponseCode(response_code)
        if response_code == 201:
            return json.dumps([n.short_json() for n in added_nodes])
        else:
            return json.dumps(error_response)
Пример #17
0
 def advance_time(self, request):
     """
     Advance time by the given number of seconds.
     """
     body = json_from_request(request)
     amount = body['amount']
     self.clock.advance(amount)
     request.setResponseCode(200)
     return json.dumps({
         "advanced": amount,
         "now": seconds_to_timestamp(self.clock.seconds())
     })
Пример #18
0
 def advance_time(self, request):
     """
     Advance time by the given number of seconds.
     """
     body = json_from_request(request)
     amount = body['amount']
     self.clock.advance(amount)
     request.setResponseCode(200)
     return json.dumps({
         "advanced": amount,
         "now": seconds_to_timestamp(self.clock.seconds())
     })
Пример #19
0
    def add_customer_contacts_for_tenant(self, request, tenant_id):
        """
        Adds new contacts to a tenant and responds with a 200.

        Note: If there is a GET on the tenant before this `POST` call, the default
        contacts would have been listed. This POST will overwrite the existing contacts
        and only set the contacts provided.
        """
        content = json_from_request(request)
        contact_list = [(each_contact["email"], each_contact["role"]) for each_contact in content]
        self.core.contacts_store.add_to_contacts_store(tenant_id, contact_list)
        return b''
Пример #20
0
    def add_customer_contacts_for_tenant(self, request, tenant_id):
        """
        Adds new contacts to a tenant and responds with a 200.

        Note: If there is a GET on the tenant before this `POST` call, the default
        contacts would have been listed. This POST will overwrite the existing contacts
        and only set the contacts provided.
        """
        content = json_from_request(request)
        contact_list = [(each_contact["email"], each_contact["role"])
                        for each_contact in content]
        self.core.contacts_store.add_to_contacts_store(tenant_id, contact_list)
        return b''
Пример #21
0
    def add_node_to_load_balancer(self, request, tenant_id, lb_id):
        """
        Return a successful add node response with code 200
        """
        try:
            content = json_from_request(request)
        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])
Пример #22
0
    def add_node_to_load_balancer(self, request, tenant_id, lb_id):
        """
        Return a successful add node response with code 200
        """
        try:
            content = json_from_request(request)
        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])
Пример #23
0
    def bulk_delete_nodes_to_load_balancer_pools(self, request):
        """
        Delete multiple nodes from multiple load balancer pools.

        Returns a 400 if the lb pool_id is not a uuid.
        Returns a 409 if the lb pool_id does not exist or the cloud server does not exist
        on the lb pool.

        http://docs.rcv3.apiary.io/#delete-%2Fv3%2F%7Btenant_id%7D%2Fload_balancer_pools%2Fnodes

        TODO: For now, blow up with a 500 and verify if the given server exists in nova.
        """
        body = json_from_request(request)
        error_response = {"errors": []}

        for each in body:
            pool_id = each['load_balancer_pool']['id']
            try:
                UUID(pool_id, version=4)
            except (ValueError, AttributeError):
                request.setResponseCode(400)
                return json.dumps(
                    'The input was not in the correct format. Please reference '
                    'the documentation at http://docs.rcv3.apiary.io for '
                    'further assistance.')
            pool = self._pool_by_id(pool_id)

            if pool is None:
                response_code = 409
                error_response["errors"].append("Load Balancer Pool {0} does "
                                                "not exist".format(pool_id))
            elif pool.node_by_cloud_server(each['cloud_server']['id']) is None:
                response_code = 409
                error_response["errors"].append(
                    ("Cloud Server {0} is not a "
                     "member of Load Balancer Pool "
                     "{1}").format(each['cloud_server']['id'], pool_id))
        if not error_response['errors']:
            for add in body:
                pool = self._pool_by_id(add['load_balancer_pool']['id'])
                node = pool.node_by_cloud_server(add['cloud_server']['id'])
                pool.nodes.remove(node)
                response_code = 204

        request.setResponseCode(response_code)
        if response_code == 204:
            return b""
        else:
            return json.dumps(error_response)
Пример #24
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)
Пример #25
0
    def bulk_delete_nodes_to_load_balancer_pools(self, request):
        """
        Delete multiple nodes from multiple load balancer pools.

        Returns a 400 if the lb pool_id is not a uuid.
        Returns a 409 if the lb pool_id does not exist or the cloud server does not exist
        on the lb pool.

        http://docs.rcv3.apiary.io/#delete-%2Fv3%2F%7Btenant_id%7D%2Fload_balancer_pools%2Fnodes

        TODO: For now, blow up with a 500 and verify if the given server exists in nova.
        """
        body = json_from_request(request)
        error_response = {"errors": []}

        for each in body:
            pool_id = each['load_balancer_pool']['id']
            try:
                UUID(pool_id, version=4)
            except (ValueError, AttributeError):
                request.setResponseCode(400)
                return json.dumps('The input was not in the correct format. Please reference '
                                  'the documentation at http://docs.rcv3.apiary.io for '
                                  'further assistance.')
            pool = self._pool_by_id(pool_id)

            if pool is None:
                response_code = 409
                error_response["errors"].append("Load Balancer Pool {0} does "
                                                "not exist".format(pool_id))
            elif pool.node_by_cloud_server(each['cloud_server']['id']) is None:
                response_code = 409
                error_response["errors"].append(("Cloud Server {0} is not a "
                                                 "member of Load Balancer Pool "
                                                 "{1}").format(each['cloud_server']['id'],
                                                               pool_id))
        if not error_response['errors']:
            for add in body:
                pool = self._pool_by_id(add['load_balancer_pool']['id'])
                node = pool.node_by_cloud_server(add['cloud_server']['id'])
                pool.nodes.remove(node)
                response_code = 204

        request.setResponseCode(response_code)
        if response_code == 204:
            return b""
        else:
            return json.dumps(error_response)
Пример #26
0
    def validate_template(self, request, tenant_id):
        """
        Validates a template.
        See http://api.rackspace.com/api-ref-orchestration.html#template_validate
        """
        content = json_from_request(request)

        if 'template' in content or 'template_url' in content:
            request.setResponseCode(200)
            response = json.dumps({"Parameters": "parameters would go here"})
        else:
            request.setResponseCode(400)
            response = ("Bad request! template or template_url should be in "
                        "the request.")

        return response
Пример #27
0
    def validate_template(self, request, tenant_id):
        """
        Validates a template.
        See http://api.rackspace.com/api-ref-orchestration.html#template_validate
        """
        content = json_from_request(request)

        if 'template' in content or 'template_url' in content:
            request.setResponseCode(200)
            response = json.dumps({"Parameters": "parameters would go here"})
        else:
            request.setResponseCode(400)
            response = ("Bad request! template or template_url should be in "
                        "the request.")

        return response
Пример #28
0
    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_from_request(request)
        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])
Пример #29
0
    def create_key_pair(self, request, tenant_id):
        """
        Returns a newly created key pair with the specified name.
        http://docs.rackspace.com/servers/api/v2/cs-devguide/content/UploadKeyPair.html
        """
        try:
            content = json_from_request(request)
            keypair = content["keypair"]
            keypair_from_request = KeyPair(name=keypair["name"],
                                           public_key=keypair["public_key"])
        except (ValueError or KeyError):
            request.setResponseCode(400)
            return json.dumps(bad_request("Malformed request body", request))

        keypair_response = self._keypair_collection_for_tenant(
            tenant_id).create_keypair(keypair=keypair_from_request)
        return json.dumps(keypair_response)
Пример #30
0
    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_from_request(request)
        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])
Пример #31
0
    def create_key_pair(self, request, tenant_id):
        """
        Returns a newly created key pair with the specified name.
        http://docs.rackspace.com/servers/api/v2/cs-devguide/content/UploadKeyPair.html
        """
        try:
            content = json_from_request(request)
            keypair = content["keypair"]
            keypair_from_request = KeyPair(
                name=keypair["name"], public_key=keypair["public_key"])
        except (ValueError or KeyError):
            request.setResponseCode(400)
            return json.dumps(bad_request("Malformed request body", request))

        keypair_response = self._keypair_collection_for_tenant(
            tenant_id).create_keypair(keypair=keypair_from_request)
        return json.dumps(keypair_response)
Пример #32
0
 def cache_image_using_vendor_passthru(self, http_request, node_id, method):
     """
     Cache the image on the node.
     """
     content = json_from_request(http_request)
     node = self.node_by_id(node_id)
     if not node:
         http_request.setResponseCode(404)
         return self.node_not_found(node_id)
     if method != 'cache_image':
         http_request.setResponseCode(400)
         return b''
     if content.get('image_info') and content['image_info'].get('id'):
         node.cache_image_id = content['image_info']['id']
         http_request.setResponseCode(202)
         return dumps('')
     http_request.setResponseCode(400)
     return b''
Пример #33
0
 def cache_image_using_vendor_passthru(self, http_request, node_id, method):
     """
     Cache the image on the node.
     """
     content = json_from_request(http_request)
     node = self.node_by_id(node_id)
     if not node:
         http_request.setResponseCode(404)
         return self.node_not_found(node_id)
     if method != 'cache_image':
         http_request.setResponseCode(400)
         return b''
     if content.get('image_info') and content['image_info'].get('id'):
         node.cache_image_id = content['image_info']['id']
         http_request.setResponseCode(202)
         return dumps('')
     http_request.setResponseCode(400)
     return b''
Пример #34
0
    def set_metadata(self, request):
        """
        Set the metadata for the specified server - this replaces whatever
        metadata was there.  The resulting metadata is not a union of the
        previous metadata and the new metadata - it is *just* the new
        metadata.

        The body must look like:

        ``{"metadata": {...}}``

        although

        ``{"metadata": {...}, "other": "garbage", "keys": "included"}``

        is ok too.

        All the response messages and codes have been verified as of
        2015-04-23 against Rackspace Nova.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Malformed request body", request))

        # more than one key is ok, non-"meta" keys are just ignored
        if 'metadata' not in content:
            return json.dumps(bad_request("Malformed request body", request))

        # When setting metadata, None is special for some reason
        if content['metadata'] is None:
            return json.dumps(
                bad_request("Malformed request body. metadata must be object",
                            request))

        try:
            Server.validate_metadata(content['metadata'])
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        self._server.set_metadata(content['metadata'])
        return json.dumps({'metadata': content['metadata']})
Пример #35
0
    def set_metadata_item(self, request, key):
        """
        Set a metadata item.  The body must look like:

        ``{"meta": {<key>: value}}``

        although

        ``{"meta": {<key>: value}, "other": "garbage", "keys": "included"}``

        is ok too.

        All the response messages and codes have been verified as of
        2015-04-23 against Rackspace Nova.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(bad_request("Malformed request body", request))

        # more than one key is ok, non-"meta" keys are just ignored
        if 'meta' not in content or not isinstance(content['meta'], dict):
            return json.dumps(bad_request("Malformed request body", request))

        if len(content['meta']) > 1:
            return json.dumps(bad_request(
                "Request body contains too many items", request))

        if key not in content['meta']:
            return json.dumps(bad_request(
                "Request body and URI mismatch", request))

        try:
            self._server.set_metadata_item(key, content['meta'][key])
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        # no matter how many keys were passed in, only the meta key is
        # returned
        return json.dumps({'meta': content['meta']})
Пример #36
0
    def create_server(self, request, tenant_id):
        """
        Returns a generic create server response, with status 'ACTIVE'.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(
                bad_request("Invalid JSON request body", request))

        try:
            creation = (self._region_collection_for_tenant(tenant_id)
                        .request_creation(request, content, self.url))
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        return creation
Пример #37
0
    def set_metadata_item(self, request, key):
        """
        Set a metadata item.  The body must look like:

        ``{"meta": {<key>: value}}``

        although

        ``{"meta": {<key>: value}, "other": "garbage", "keys": "included"}``

        is ok too.

        All the response messages and codes have been verified as of
        2015-04-23 against Rackspace Nova.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(bad_request("Malformed request body", request))

        # more than one key is ok, non-"meta" keys are just ignored
        if 'meta' not in content or not isinstance(content['meta'], dict):
            return json.dumps(bad_request("Malformed request body", request))

        if len(content['meta']) > 1:
            return json.dumps(
                bad_request("Request body contains too many items", request))

        if key not in content['meta']:
            return json.dumps(
                bad_request("Request body and URI mismatch", request))

        try:
            self._server.set_metadata_item(key, content['meta'][key])
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        # no matter how many keys were passed in, only the meta key is
        # returned
        return json.dumps({'meta': content['meta']})
Пример #38
0
    def set_metadata(self, request):
        """
        Set the metadata for the specified server - this replaces whatever
        metadata was there.  The resulting metadata is not a union of the
        previous metadata and the new metadata - it is *just* the new
        metadata.

        The body must look like:

        ``{"metadata": {...}}``

        although

        ``{"metadata": {...}, "other": "garbage", "keys": "included"}``

        is ok too.

        All the response messages and codes have been verified as of
        2015-04-23 against Rackspace Nova.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Malformed request body", request))

        # more than one key is ok, non-"meta" keys are just ignored
        if 'metadata' not in content:
            return json.dumps(bad_request("Malformed request body", request))

        # When setting metadata, None is special for some reason
        if content['metadata'] is None:
            return json.dumps(bad_request(
                "Malformed request body. metadata must be object", request))

        try:
            Server.validate_metadata(content['metadata'])
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        self._server.set_metadata(content['metadata'])
        return json.dumps({'metadata': content['metadata']})
Пример #39
0
    def create_external_api_service(self, request):
        """
        Create a new external api service that endpoint templates
        may be added to.

        .. note:: Only requires 'name' and 'type' fields in the JSON. If the 'id'
            or 'description' fields are present, then they will be used;
            otherwise a UUID4 will be assigned to the 'id' field and the
            'description' will be given a generic value.
        `OpenStack Identity v2 OS-KSADM Create Service
        <http://developer.openstack.org/api-ref/identity/v2-ext/index.html#create-service-admin-extension>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body", request))

        try:
            service_name = content["name"]
            service_type = content["type"]
        except KeyError:
            return json.dumps(bad_request("Invalid Content. 'name' and 'type' fields are required.", request))

        try:
            service_id = content["id"]
        except KeyError:
            service_id = text_type(uuid.uuid4())

        try:
            service_description = content["description"]
        except KeyError:
            service_description = "External API referenced by Mimic"

        if service_id in self.core.get_external_apis():
            return json.dumps(conflict("Conflict: Service with the same uuid already exists.", request))

        try:
            self.core.add_api(ExternalApiStore(service_id, service_name, service_type, description=service_description))
        except ServiceNameExists:
            return json.dumps(conflict("Conflict: Service with the same name already exists.", request))
        else:
            request.setResponseCode(201)
            return b""
Пример #40
0
 def update_node(self, request, tenant_id, lb_id, node_id):
     """
     Return a 202 response code to updating a node, if successful.
     """
     try:
         content = json_from_request(request)
         assert (isinstance(content, dict) and
                 list(content.keys()) == ["node"])
         content = content["node"]
         assert isinstance(content, dict)
     except (ValueError, AssertionError):
         resp_body, resp_code = invalid_json_schema()
     else:
         resp_body, resp_code = self.session(tenant_id).update_node(
             lb_id, node_id, content
         )
     request.setResponseCode(resp_code)
     if isinstance(resp_body, string_types):
         return resp_body
     return json.dumps(resp_body)
Пример #41
0
    def get_impersonation_token(self, request):
        """
        Return a token id with expiration.
        """
        request.setResponseCode(200)
        try:
            content = json_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(invalid_resource("Invalid JSON request body"))

        x_auth_token = request.getHeader(b"x-auth-token")
        if x_auth_token is not None:
            x_auth_token = x_auth_token.decode("utf-8")
        cred = ImpersonationCredentials.from_json(content, 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)
Пример #42
0
    def create_server(self, request, tenant_id):
        """
        Returns a generic create server response, with status 'ACTIVE'.
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body",
                                          request))

        try:
            creation = (
                self._region_collection_for_tenant(tenant_id).request_creation(
                    request, content, self.url))
        except BadRequestError as e:
            return json.dumps(bad_request(e.nova_message, request))
        except LimitError as e:
            return json.dumps(forbidden(e.nova_message, request))

        return creation
Пример #43
0
 def update_node(self, request, tenant_id, lb_id, node_id):
     """
     Return a 202 response code to updating a node, if successful.
     """
     try:
         content = json_from_request(request)
         assert (isinstance(content, dict) and
                 list(content.keys()) == ["node"])
         content = content["node"]
         assert isinstance(content, dict)
     except (ValueError, AssertionError):
         resp_body, resp_code = invalid_json_schema()
     else:
         resp_body, resp_code = self.session(tenant_id).update_node(
             lb_id, node_id, content
         )
     request.setResponseCode(resp_code)
     if isinstance(resp_body, string_types):
         return resp_body
     return json.dumps(resp_body)
Пример #44
0
    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""
Пример #45
0
        def register_behavior(kl_self, request):
            """
            Register the specified behavior to cause a future event
            operation to behave in the described way.

            The request looks like this::

                {
                    # list of criteria for which requests will behave
                    # in the described way
                    "criteria": [
                        {"criteria1": "regex_pattern.*"},
                        {"criteria2": "regex_pattern.*"},
                    ],
                    # what kind of behavior: in this case,
                    # "fail the request"
                    "name": "fail",
                    # parameters for the behavior: in this case,
                    # "return a 404 with a message".
                    "parameters": {
                        "code": 404,
                        "message": "Stuff is broken, what"
                    }
                }

            The response looks like::

                {
                    "id": "this-is-a-uuid-here"
                }
            """
            reg = kl_self.registry_collection.registry_by_event(event)
            try:
                behavior_description = json_from_request(request)
                behavior_id = reg.register_from_json(behavior_description)
            except (ValueError, KeyError):
                request.setResponseCode(BAD_REQUEST)
                return b''

            request.setResponseCode(CREATED)
            return json.dumps({'id': text_type(behavior_id)})
Пример #46
0
        def register_behavior(kl_self, request):
            """
            Register the specified behavior to cause a future event
            operation to behave in the described way.

            The request looks like this::

                {
                    # list of criteria for which requests will behave
                    # in the described way
                    "criteria": [
                        {"criteria1": "regex_pattern.*"},
                        {"criteria2": "regex_pattern.*"},
                    ],
                    # what kind of behavior: in this case,
                    # "fail the request"
                    "name": "fail",
                    # parameters for the behavior: in this case,
                    # "return a 404 with a message".
                    "parameters": {
                        "code": 404,
                        "message": "Stuff is broken, what"
                    }
                }

            The response looks like::

                {
                    "id": "this-is-a-uuid-here"
                }
            """
            reg = kl_self.registry_collection.registry_by_event(event)
            try:
                behavior_description = json_from_request(request)
                behavior_id = reg.register_from_json(behavior_description)
            except (ValueError, KeyError):
                request.setResponseCode(BAD_REQUEST)
                return b""

            request.setResponseCode(CREATED)
            return json.dumps({"id": text_type(behavior_id)})
Пример #47
0
 def create_node(self, http_create_request):
     """
     Create a node
     http://bit.ly/1N0O9KM
     """
     content = json_from_request(http_create_request)
     try:
         memory_mb = None
         if content.get('properties'):
             memory_mb = content['properties'].get('memory_mb')
         node = self.add_to_ironic_node_store(
             node_id=str(uuid4()),
             memory_mb=memory_mb,
             chassis_uuid=content.get('chassis_uuid'),
             driver=content.get('driver'),
             properties=content.get('properties'),
             driver_info=content.get('driver_info'),
             name=content.get('name'))
         http_create_request.setResponseCode(201)
         return dumps(node.detail_json())
     except:
         http_create_request.setResponseCode(400)
         return b''
Пример #48
0
    def perform_action(self, request, tenant_id, stack_name, stack_id):
        """
        Performs an action on a stack. Only action-check is enabled at
        Rackspace.
        http://developer.openstack.org/api-ref-orchestration-v1.html#stack-actions
        http://developer.openstack.org/api-ref-orchestration-v1.html#stack_action_check
        """
        region_collection = self._region_collection_for_tenant(tenant_id)

        body = json_from_request(request)
        valid_actions = ('cancel_update', 'check', 'resume', 'suspend')

        if len(body.keys()) != 1 or list(body.keys())[0] not in valid_actions:
            request.setResponseCode(400)
            return "Action in request must be one of {}".format(
                ", ".join(valid_actions))

        if 'check' in body:
            return region_collection.request_check(
                request, stack_name, stack_id)

        request.setResponseCode(405)
        return "Only action-check is allowed."
Пример #49
0
 def set_node_provision_state(self, http_put_request, node_id):
     """
     Sets the provision state on the node and returns 202.
     If the `node_id` does not exist returns 404.
     Note: When the provision_state is set to `provide` the
     node is made 'available'.
     Docs: http://bit.ly/1ElELdU
     """
     content = json_from_request(http_put_request)
     node = self.node_by_id(node_id)
     if node:
         http_put_request.setResponseCode(202)
         node.provision_state = content.get('target', 'available')
         if node.provision_state == 'provide':
             node.provision_state = 'available'
         if node.provision_state != 'active':
             node.instance_uuid = None
             node.cache_image_id = None
         if node.provision_state == 'active':
             node.instance_uuid = str(uuid4())
         return dumps('')
     http_put_request.setResponseCode(404)
     return self.node_not_found(node_id)
Пример #50
0
    def get_impersonation_token(self, request):
        """
        Return a token id with expiration.
        """
        request.setResponseCode(200)
        try:
            content = json_from_request(request)
        except ValueError:
            request.setResponseCode(400)
            return json.dumps(invalid_resource("Invalid JSON request body"))

        x_auth_token = request.getHeader(b"x-auth-token")
        if x_auth_token is not None:
            x_auth_token = x_auth_token.decode("utf-8")
        cred = ImpersonationCredentials.from_json(content, 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)
Пример #51
0
 def create_node(self, http_create_request):
     """
     Create a node
     http://bit.ly/1N0O9KM
     """
     content = json_from_request(http_create_request)
     try:
         memory_mb = None
         if content.get('properties'):
             memory_mb = content['properties'].get('memory_mb')
         node = self.add_to_ironic_node_store(
             node_id=str(uuid4()),
             memory_mb=memory_mb,
             chassis_uuid=content.get('chassis_uuid'),
             driver=content.get('driver'),
             properties=content.get('properties'),
             driver_info=content.get('driver_info'),
             name=content.get('name'))
         http_create_request.setResponseCode(201)
         return dumps(node.detail_json())
     except:
         http_create_request.setResponseCode(400)
         return b''
Пример #52
0
 def set_node_provision_state(self, http_put_request, node_id):
     """
     Sets the provision state on the node and returns 202.
     If the `node_id` does not exist returns 404.
     Note: When the provision_state is set to `provide` the
     node is made 'available'.
     Docs: http://bit.ly/1ElELdU
     """
     content = json_from_request(http_put_request)
     node = self.node_by_id(node_id)
     if node:
         http_put_request.setResponseCode(202)
         node.provision_state = content.get('target', 'available')
         if node.provision_state == 'provide':
             node.provision_state = 'available'
         if node.provision_state != 'active':
             node.instance_uuid = None
             node.cache_image_id = None
         if node.provision_state == 'active':
             node.instance_uuid = str(uuid4())
         return dumps('')
     http_put_request.setResponseCode(404)
     return self.node_not_found(node_id)
Пример #53
0
    def request_action(self, http_action_request, server_id, absolutize_url,
                       regional_image_collection, image_store):
        """
        Perform the requested action on the provided server
        """
        server = self.server_by_id(server_id)
        if server is None:
            return dumps(
                not_found("Instance " + server_id + " could not be found",
                          http_action_request))
        action_json = json_from_request(http_action_request)
        if 'resize' in action_json:
            flavor = action_json['resize'].get('flavorRef')
            if not flavor:
                return dumps(
                    bad_request(
                        "Resize requests require 'flavorRef' attribute",
                        http_action_request))

            server.status = 'VERIFY_RESIZE'
            server.oldFlavor = server.flavor_ref
            server.flavor_ref = flavor
            http_action_request.setResponseCode(202)
            return b''

        elif 'confirmResize' in action_json or 'revertResize' in action_json:
            if server.status == 'VERIFY_RESIZE' and 'confirmResize' in action_json:
                server.status = 'ACTIVE'
                http_action_request.setResponseCode(204)
                return b''
            elif server.status == 'VERIFY_RESIZE' and 'revertResize' in action_json:
                server.status = 'ACTIVE'
                server.flavor_ref = server.oldFlavor
                http_action_request.setResponseCode(202)
                return b''
            else:
                return dumps(
                    conflicting(
                        "Cannot '" + list(action_json.keys())[0] +
                        "' instance " + server_id +
                        " while it is in vm_state active",
                        http_action_request))
        elif 'rescue' in action_json:
            if server.status != 'ACTIVE':
                return dumps(
                    conflicting(
                        "Cannot 'rescue' instance " + server_id +
                        " while it is in task state other than active",
                        http_action_request))
            else:
                server.status = 'RESCUE'
                http_action_request.setResponseCode(200)
                password = random_string(12)
                return dumps({"adminPass": password})

        elif 'unrescue' in action_json:
            if server.status == 'RESCUE':
                server.status = 'ACTIVE'
                http_action_request.setResponseCode(200)
                return b''
            else:
                return dumps(
                    conflicting(
                        "Cannot 'unrescue' instance " + server_id +
                        " while it is in task state other than rescue",
                        http_action_request))

        elif 'reboot' in action_json:
            reboot_type = action_json['reboot'].get('type')
            if not reboot_type:
                return dumps(
                    bad_request("Missing argument 'type' for reboot",
                                http_action_request))
            if reboot_type == 'HARD':
                server.status = 'HARD_REBOOT'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(6.0, server.update_status,
                                                  u"ACTIVE")
                return b''
            elif reboot_type == 'SOFT':
                server.status = 'REBOOT'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(3.0, server.update_status,
                                                  u"ACTIVE")
                return b''
            else:
                return dumps(
                    bad_request(
                        "Argument 'type' for reboot is not HARD or SOFT",
                        http_action_request))

        elif 'changePassword' in action_json:
            password = action_json['changePassword'].get('adminPass')
            if not password:
                return dumps(
                    bad_request("No adminPass was specified",
                                http_action_request))
            if server.status == 'ACTIVE':
                http_action_request.setResponseCode(202)
                return b''
            else:
                return dumps(
                    conflicting(
                        "Cannot 'changePassword' instance " + server_id +
                        " while it is in task state other than active",
                        http_action_request))

        elif 'rebuild' in action_json:
            image_ref = action_json['rebuild'].get('imageRef')
            if not image_ref:
                return dumps(
                    bad_request("Could not parse imageRef from request.",
                                http_action_request))
            if server.status == 'ACTIVE':
                server.image_ref = image_ref
                server.status = 'REBUILD'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(5.0, server.update_status,
                                                  u"ACTIVE")
                server_details = server.detail_json(absolutize_url)
                server_details['adminPass'] = '******'
                return dumps({"server": server_details})
            else:
                return dumps(
                    conflicting(
                        "Cannot 'rebuild' instance " + server_id +
                        " while it is in task state other than active",
                        http_action_request))

        elif 'createImage' in action_json:
            image_name = action_json['createImage'].get('name')
            server == self.server_by_id(server_id)
            links = server.links_json(absolutize_url)
            server_id = server.server_id
            image_ref = server.image_ref
            image = image_store.get_image_by_id(image_ref)
            image_json = regional_image_collection.get_image(
                http_action_request, image_ref, absolutize_url)
            image_dict = loads(image_json)
            flavor_classes = image_dict['image']['metadata']['flavor_classes']
            os_type = image_dict['image']['metadata']['os_type']
            os_distro = image_dict['image']['metadata'][
                'org.openstack__1__os_distro']
            vm_mode = image_dict['image']['metadata']['vm_mode']
            disk_config = image_dict['image']['metadata']['auto_disk_config']
            image_id = text_type(uuid.uuid4())
            image_size = image.image_size
            minRam = image.minRam
            minDisk = image.minDisk
            saved_image = RackspaceSavedImage(image_id=image_id,
                                              tenant_id=self.tenant_id,
                                              image_size=image_size,
                                              name=image_name,
                                              minRam=minRam,
                                              minDisk=minDisk,
                                              links=links,
                                              server_id=server_id,
                                              flavor_classes=flavor_classes,
                                              os_type=os_type,
                                              os_distro=os_distro,
                                              vm_mode=vm_mode,
                                              disk_config=disk_config)

            image_store.add_image_to_store(saved_image)
            http_action_request.setHeader(b"Location", b"www.someurl.com")
            http_action_request.setResponseCode(202)
            return b''

        else:
            return dumps(
                bad_request("There is no such action currently supported",
                            http_action_request))
Пример #54
0
    def add_endpoint_templates(self, request):
        """
        Add an API endpoint template to the system. By default the API
        described by the template will disabled for all users.

        .. note:: Either the service-id must be specified in the header or
            a Service Name by the same name must already exist. Otherwise
            a Not Found (404) will be returned.

        .. note:: A template has certain required parametes. For Mimic the
            id, name, type, and region parameters are required. See
            EndpointTemplateStore.required_mapping for details. Other
            implementations may have different requirements.

        `OpenStack Identity v2 OS-KSCATALOG Create Endpoint Template
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body", request))

        try:
            endpoint_template_instance = EndpointTemplateStore.deserialize(content)
        except InvalidEndpointTemplateMissingKey as ex:
            return json.dumps(
                bad_request("JSON body does not contain the required parameters: " + text_type(ex), request)
            )

        # Access the Service ID that tells which External API
        # is to support this template.
        service_id = request.getHeader(b"serviceid")
        if service_id is not None:
            service_id = service_id.decode("utf-8")

        # Check all existing External APIs for the API ID
        # to ensure that none of them contain it already. The
        # value must be unique.
        for api_id in self.core.get_external_apis():
            api = self.core.get_external_api(api_id)
            if api.has_template(endpoint_template_instance.id_key):
                return json.dumps(conflict("ID value is already assigned to an existing template", request))

            # While we're at it, if we need to look up the service ID
            # and find the External API that will ultimately provide it
            # then grab that too instead of repeating the search.
            elif api.name_key == endpoint_template_instance.name_key:
                if service_id is None:
                    service_id = api.uuid_key

        try:
            service = self.core.get_external_api(service_id)
        except ServiceDoesNotExist:
            return json.dumps(not_found("Service API for endoint template not found", request))

        try:
            service.add_template(endpoint_template_instance)
        except (EndpointTemplateAlreadyExists, InvalidEndpointTemplateServiceType):
            return json.dumps(conflict("Endpoint already exists or service type does not match.", request))
        else:
            request.setResponseCode(201)
            return b""
Пример #55
0
    def update_endpoint_templates(self, request, template_id):
        """
        Update an API endpoint template already in the system.

        .. note:: A template by the same id must already exist in the system.

        .. note:: Either the service-id must be specified in the header or
            a Service Name by the same name must already exist. Otherwise
            a Not Found (404) will be returned.

        `OpenStack Identity v2 OS-KSCATALOG Update Endpoint Template
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body",
                                          request))

        try:
            if content['id'] != template_id:
                return json.dumps(
                    conflict(
                        "Template ID in URL does not match that of the JSON body",
                        request))

            endpoint_template_instance = EndpointTemplateStore.deserialize(
                content)
        except (InvalidEndpointTemplateMissingKey, KeyError) as ex:
            # KeyError is for the content['id'] line
            return json.dumps(
                bad_request(
                    "JSON body does not contain the required parameters: " +
                    text_type(ex), request))

        service_id = request.getHeader(b'serviceid')
        if service_id is None:
            for api_id in self.core.get_external_apis():
                api = self.core.get_external_api(api_id)
                if api.has_template(template_id):
                    service_id = api.uuid_key
        else:
            service_id = service_id.decode('utf-8')

        try:
            service = self.core.get_external_api(service_id)
        except ServiceDoesNotExist:
            return json.dumps(
                not_found("Service API for endoint template not found",
                          request))

        try:
            service.update_template(endpoint_template_instance)
        except (InvalidEndpointTemplateServiceType, InvalidEndpointTemplateId):
            return json.dumps(
                conflict(
                    "Endpoint already exists and service id or service type "
                    "does not match.", request))
        except EndpointTemplateDoesNotExist:
            return json.dumps(
                not_found(
                    "Unable to update non-existent template. Template must "
                    "first be added before it can be updated.", request))
        else:
            request.setResponseCode(201)
            return b''
Пример #56
0
    def add_endpoint_templates(self, request):
        """
        Add an API endpoint template to the system. By default the API
        described by the template will disabled for all users.

        .. note:: Either the service-id must be specified in the header or
            a Service Name by the same name must already exist. Otherwise
            a Not Found (404) will be returned.

        .. note:: A template has certain required parametes. For Mimic the
            id, name, type, and region parameters are required. See
            EndpointTemplateStore.required_mapping for details. Other
            implementations may have different requirements.

        `OpenStack Identity v2 OS-KSCATALOG Create Endpoint Template
        <http://developer.openstack.org/api-ref-identity-v2-ext.html>`_
        """
        try:
            content = json_from_request(request)
        except ValueError:
            return json.dumps(bad_request("Invalid JSON request body",
                                          request))

        try:
            endpoint_template_instance = EndpointTemplateStore.deserialize(
                content)
        except InvalidEndpointTemplateMissingKey as ex:
            return json.dumps(
                bad_request(
                    "JSON body does not contain the required parameters: " +
                    text_type(ex), request))

        # Access the Service ID that tells which External API
        # is to support this template.
        service_id = request.getHeader(b'serviceid')
        if service_id is not None:
            service_id = service_id.decode('utf-8')

        # Check all existing External APIs for the API ID
        # to ensure that none of them contain it already. The
        # value must be unique.
        for api_id in self.core.get_external_apis():
            api = self.core.get_external_api(api_id)
            if api.has_template(endpoint_template_instance.id_key):
                return json.dumps(
                    conflict(
                        "ID value is already assigned to an existing template",
                        request))

            # While we're at it, if we need to look up the service ID
            # and find the External API that will ultimately provide it
            # then grab that too instead of repeating the search.
            elif api.name_key == endpoint_template_instance.name_key:
                if service_id is None:
                    service_id = api.uuid_key

        try:
            service = self.core.get_external_api(service_id)
        except ServiceDoesNotExist:
            return json.dumps(
                not_found("Service API for endoint template not found",
                          request))

        try:
            service.add_template(endpoint_template_instance)
        except (EndpointTemplateAlreadyExists,
                InvalidEndpointTemplateServiceType):
            return json.dumps(
                conflict(
                    "Endpoint already exists or service type does not match.",
                    request))
        else:
            request.setResponseCode(201)
            return b''
Пример #57
0
    def request_action(self, http_action_request, server_id, absolutize_url,
                       regional_image_collection, image_store):
        """
        Perform the requested action on the provided server
        """
        server = self.server_by_id(server_id)
        if server is None:
            return dumps(not_found("Instance " + server_id + " could not be found",
                                   http_action_request))
        action_json = json_from_request(http_action_request)
        if 'resize' in action_json:
            flavor = action_json['resize'].get('flavorRef')
            if not flavor:
                return dumps(bad_request("Resize requests require 'flavorRef' attribute",
                                         http_action_request))

            server.status = 'VERIFY_RESIZE'
            server.oldFlavor = server.flavor_ref
            server.flavor_ref = flavor
            http_action_request.setResponseCode(202)
            return b''

        elif 'confirmResize' in action_json or 'revertResize' in action_json:
            if server.status == 'VERIFY_RESIZE' and 'confirmResize' in action_json:
                server.status = 'ACTIVE'
                http_action_request.setResponseCode(204)
                return b''
            elif server.status == 'VERIFY_RESIZE' and 'revertResize' in action_json:
                server.status = 'ACTIVE'
                server.flavor_ref = server.oldFlavor
                http_action_request.setResponseCode(202)
                return b''
            else:
                return dumps(conflicting(
                    "Cannot '" + list(action_json.keys())[0] + "' instance " +
                    server_id + " while it is in vm_state active",
                    http_action_request)
                )
        elif 'rescue' in action_json:
            if server.status != 'ACTIVE':
                return dumps(conflicting("Cannot 'rescue' instance " + server_id +
                                         " while it is in task state other than active",
                                         http_action_request))
            else:
                server.status = 'RESCUE'
                http_action_request.setResponseCode(200)
                password = random_string(12)
                return dumps({"adminPass": password})

        elif 'unrescue' in action_json:
            if server.status == 'RESCUE':
                server.status = 'ACTIVE'
                http_action_request.setResponseCode(200)
                return b''
            else:
                return dumps(conflicting("Cannot 'unrescue' instance " + server_id +
                                         " while it is in task state other than rescue",
                                         http_action_request))

        elif 'reboot' in action_json:
            reboot_type = action_json['reboot'].get('type')
            if not reboot_type:
                return dumps(bad_request("Missing argument 'type' for reboot",
                                         http_action_request))
            if reboot_type == 'HARD':
                server.status = 'HARD_REBOOT'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(
                    6.0,
                    server.update_status,
                    u"ACTIVE")
                return b''
            elif reboot_type == 'SOFT':
                server.status = 'REBOOT'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(
                    3.0,
                    server.update_status,
                    u"ACTIVE")
                return b''
            else:
                return dumps(bad_request("Argument 'type' for reboot is not HARD or SOFT",
                                         http_action_request))

        elif 'changePassword' in action_json:
            password = action_json['changePassword'].get('adminPass')
            if not password:
                return dumps(bad_request("No adminPass was specified",
                                         http_action_request))
            if server.status == 'ACTIVE':
                http_action_request.setResponseCode(202)
                return b''
            else:
                return dumps(conflicting("Cannot 'changePassword' instance " + server_id +
                                         " while it is in task state other than active",
                                         http_action_request))

        elif 'rebuild' in action_json:
            image_ref = action_json['rebuild'].get('imageRef')
            if not image_ref:
                return dumps(bad_request("Could not parse imageRef from request.", http_action_request))
            if server.status == 'ACTIVE':
                server.image_ref = image_ref
                server.status = 'REBUILD'
                http_action_request.setResponseCode(202)
                server.collection.clock.callLater(
                    5.0,
                    server.update_status,
                    u"ACTIVE")
                server_details = server.detail_json(absolutize_url)
                server_details['adminPass'] = '******'
                return dumps({"server": server_details})
            else:
                return dumps(conflicting("Cannot 'rebuild' instance " + server_id +
                                         " while it is in task state other than active",
                                         http_action_request))

        elif 'createImage' in action_json:
            image_name = action_json['createImage'].get('name')
            server == self.server_by_id(server_id)
            links = server.links_json(absolutize_url)
            server_id = server.server_id
            image_ref = server.image_ref
            image = image_store.get_image_by_id(image_ref)
            image_json = regional_image_collection.get_image(http_action_request,
                                                             image_ref, absolutize_url)
            image_dict = loads(image_json)
            flavor_classes = image_dict['image']['metadata']['flavor_classes']
            os_type = image_dict['image']['metadata']['os_type']
            os_distro = image_dict['image']['metadata']['org.openstack__1__os_distro']
            vm_mode = image_dict['image']['metadata']['vm_mode']
            disk_config = image_dict['image']['metadata']['auto_disk_config']
            image_id = text_type(uuid.uuid4())
            image_size = image.image_size
            minRam = image.minRam
            minDisk = image.minDisk
            saved_image = RackspaceSavedImage(image_id=image_id, tenant_id=self.tenant_id,
                                              image_size=image_size, name=image_name, minRam=minRam,
                                              minDisk=minDisk, links=links, server_id=server_id,
                                              flavor_classes=flavor_classes, os_type=os_type,
                                              os_distro=os_distro, vm_mode=vm_mode,
                                              disk_config=disk_config)

            image_store.add_image_to_store(saved_image)
            http_action_request.setHeader(b"Location", b"www.someurl.com")
            http_action_request.setResponseCode(202)
            return b''

        else:
            return dumps(bad_request("There is no such action currently supported", http_action_request))