def delete(self, req, replica_id, id):
     try:
         self._replica_tasks_execution_api.delete(
             req.environ['coriolis.context'], replica_id, id)
         raise exc.HTTPNoContent()
     except exception.NotFound as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 2
0
    def delete(self, req, replica_id, id):
        context = req.environ["coriolis.context"]
        context.can(
            schedules_policies.get_replica_schedules_policy_label("delete"))

        self._schedule_api.delete(context, replica_id, id)
        raise exc.HTTPNoContent()
Exemplo n.º 3
0
 def delete(self, req, application_id, id):
     try:
         self._session_api.delete(
             req.environ['vdibroker.context'], id)
         raise exc.HTTPNoContent()
     except exception.NotFound as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 4
0
    def update(self, req, id):
        """ Updates the server name or password """
        if len(req.body) == 0:
            raise exc.HTTPUnprocessableEntity()

        inst_dict = self._deserialize(req.body, req.get_content_type())
        if not inst_dict:
            return faults.Fault(exc.HTTPUnprocessableEntity())

        ctxt = req.environ['nova.context']
        update_dict = {}

        if 'name' in inst_dict['server']:
            name = inst_dict['server']['name']
            self._validate_server_name(name)
            update_dict['display_name'] = name.strip()

        self._parse_update(ctxt, id, inst_dict, update_dict)

        try:
            self.compute_api.update(ctxt, id, **update_dict)
        except exception.NotFound:
            return faults.Fault(exc.HTTPNotFound())

        return exc.HTTPNoContent()
Exemplo n.º 5
0
    def update(self, req, id, body):
        """ Updates the server name or password """
        if len(req.body) == 0:
            raise exc.HTTPUnprocessableEntity()

        if not body:
            return faults.Fault(exc.HTTPUnprocessableEntity())

        ctxt = req.environ['nova.context']
        update_dict = {}

        if 'name' in body['server']:
            name = body['server']['name']
            self.helper._validate_server_name(name)
            update_dict['display_name'] = name.strip()

        if 'description' in body['server']:
            description = body['server']['description']
            update_dict['display_description'] = description.strip()

        self._parse_update(ctxt, id, body, update_dict)

        try:
            self.compute_api.update(ctxt, id, **update_dict)
        except exception.NotFound:
            return faults.Fault(exc.HTTPNotFound())

        return exc.HTTPNoContent()
Exemplo n.º 6
0
    def delete(self, req, identity):
        """Delete the specified stack."""

        self.rpc_client.delete_stack(req.context,
                                     identity,
                                     cast=False)
        raise exc.HTTPNoContent()
Exemplo n.º 7
0
 def delete(self, req, id):
     try:
         self._migration_api.delete(req.environ['MigrationTool.context'],
                                    id)
         raise exc.HTTPNoContent()
     except exception.NotFound as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 8
0
    def delete(self, req, cluster_id):
        action = self.rpc_client.cluster_delete(req.context,
                                                cluster_id,
                                                cast=False)
        if action is not None:
            raise exc.HTTPNoContent()

        raise exc.HTTPInternalServerError(_('Failed deleting cluster.'))
Exemplo n.º 9
0
 def delete(self, req, id):
     context = req.environ["coriolis.context"]
     context.can(replica_policies.get_replicas_policy_label("delete"))
     try:
         self._replica_api.delete(context, id)
         raise exc.HTTPNoContent()
     except exception.NotFound as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 10
0
    def delete(self, req, config_id):
        """Delete an existing software config."""
        res = self.rpc_client.delete_software_config(req.context, config_id)

        if res is not None:
            raise exc.HTTPBadRequest(res['Error'])

        raise exc.HTTPNoContent()
Exemplo n.º 11
0
 def _cancel(self, req, id, body):
     try:
         self._migration_api.cancel(req.environ['coriolis.context'], id)
         raise exc.HTTPNoContent()
     except exception.NotFound as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
     except exception.InvalidParameterValue as ex:
         raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 12
0
    def delete(self, req, identity):
        """Delete the specified stack."""

        res = self.rpc_client.delete_stack(req.context, identity, cast=False)

        if res is not None:
            raise exc.HTTPBadRequest(res['Error'])

        raise exc.HTTPNoContent()
Exemplo n.º 13
0
    def delete(self, req, minion_pool_id, id):
        context = req.environ["coriolis.context"]
        context.can(
            pool_execution_policies.get_minion_pool_executions_policy_label(
                "delete"))

        try:
            self._pool_tasks_execution_api.delete(context, minion_pool_id, id)
            raise exc.HTTPNoContent()
        except exception.NotFound as ex:
            raise exc.HTTPNotFound(explanation=ex.msg)
    def delete(self, req, deployment_id):
        """
        Delete an existing software deployment
        """
        res = self.rpc_client.delete_software_deployment(
            req.context, deployment_id)

        if res is not None:
            raise exc.HTTPBadRequest(res['Error'])

        raise exc.HTTPNoContent()
Exemplo n.º 15
0
    def _cancel(self, req, replica_id, id, body):
        try:
            force = (body["cancel"] or {}).get("force", False)

            self._replica_tasks_execution_api.cancel(
                req.environ['coriolis.context'], replica_id, id, force)
            raise exc.HTTPNoContent()
        except exception.NotFound as ex:
            raise exc.HTTPNotFound(explanation=ex.msg)
        except exception.InvalidParameterValue as ex:
            raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 16
0
    def _cancel(self, req, id, body):
        context = req.environ['coriolis.context']
        context.can(migration_policies.get_migrations_policy_label("cancel"))
        try:
            force = (body["cancel"] or {}).get("force", False)

            self._migration_api.cancel(context, id, force)
            raise exc.HTTPNoContent()
        except exception.NotFound as ex:
            raise exc.HTTPNotFound(explanation=ex.msg)
        except exception.InvalidParameterValue as ex:
            raise exc.HTTPNotFound(explanation=ex.msg)
Exemplo n.º 17
0
    def update(self, req, server_id, id, body):
        context = req.environ["nova.context"]
        authorize(context, action='update')
        self._check_instance_in_valid_state(context, server_id, 'update tag')

        try:
            jsonschema.validate(id, schema.tag)
        except jsonschema.ValidationError as e:
            msg = (_("Tag '%(tag)s' is invalid. It must be a string without "
                     "characters '/' and ','. Validation error message: "
                     "%(err)s") % {
                         'tag': id,
                         'err': e.message
                     })
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            tags = objects.TagList.get_by_resource_id(context, server_id)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())

        if len(tags) >= objects.instance.MAX_TAG_COUNT:
            msg = (_("The number of tags exceeded the per-server limit %d") %
                   objects.instance.MAX_TAG_COUNT)
            raise exc.HTTPBadRequest(explanation=msg)

        if len(id) > objects.tag.MAX_TAG_LENGTH:
            msg = (_("Tag '%(tag)s' is too long. Maximum length of a tag "
                     "is %(length)d") % {
                         'tag': id,
                         'length': objects.tag.MAX_TAG_LENGTH
                     })
            raise exc.HTTPBadRequest(explanation=msg)

        if id in _get_tags_names(tags):
            # NOTE(snikitin): server already has specified tag
            return exc.HTTPNoContent()

        tag = objects.Tag(context=context, resource_id=server_id, tag=id)

        try:
            tag.create()
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())

        response = exc.HTTPCreated()
        response.headers['Location'] = self._view_builder.get_location(
            req, server_id, id)
        return response
Exemplo n.º 18
0
    def delete(self, req, identity):
        """
        Delete the specified stack
        """

        try:
            res = self.engine.delete_stack(req.context, identity, cast=False)

        except rpc_common.RemoteError as ex:
            return util.remote_error(ex)

        if res is not None:
            raise exc.HTTPBadRequest(res['Error'])

        raise exc.HTTPNoContent()
Exemplo n.º 19
0
 def device(self, request, controller, user_id, handle):
     try:
         if request.method == 'GET':
             return controller.get_descriptor(user_id, handle)
         elif request.method == 'POST':
             props = json.loads(request.body)
             controller.set_props(handle, props)
             return controller.get_descriptor(user_id, handle)
         elif request.method == 'DELETE':
             controller.unregister(handle)
             return exc.HTTPNoContent()
         else:
             raise exc.HTTPMethodNotAllowed
     except ValueError as e:
         raise exc.HTTPNotFound(e.message)
Exemplo n.º 20
0
    def user(self, request, controller, user_id):
        if request.path_info_peek():
            page = request.path_info_pop()
            if page == 'register':
                return self.register(request, controller, user_id)
            elif page == 'authenticate':
                return self.authenticate(request, controller, user_id)
            else:
                return self.device(request, controller, user_id, page)

        if request.method == 'GET':
            return controller.get_descriptors(user_id)
        elif request.method == 'DELETE':
            controller.delete_user(user_id)
            return exc.HTTPNoContent()
        else:
            raise exc.HTTPMethodNotAllowed
Exemplo n.º 21
0
    def delete_member(self, req, image_id, member):
        """
        Removes a membership from the image.
        """
        if req.context.read_only:
            raise exc.HTTPForbidden()
        elif req.context.owner is None:
            raise exc.HTTPUnauthorized(_("No authenticated user"))

        # Make sure the image exists
        try:
            image = db_api.image_get(req.context, image_id)
        except exception.NotFound:
            raise exc.HTTPNotFound()
        except exception.NotAuthorized:
            # If it's private and doesn't belong to them, don't let on
            # that it exists
            msg = _("Access by %(user)s to image %(id)s "
                    "denied") % ({
                        'user': req.context.user,
                        'id': image_id
                    })
            logger.info(msg)
            raise exc.HTTPNotFound()

        # Can they manipulate the membership?
        if not req.context.is_image_sharable(image):
            raise exc.HTTPForbidden(_("No permission to share that image"))

        # Look up an existing membership
        try:
            session = db_api.get_session()
            member_ref = db_api.image_member_find(req.context,
                                                  image_id,
                                                  member,
                                                  session=session)
            db_api.image_member_delete(req.context,
                                       member_ref,
                                       session=session)
        except exception.NotFound:
            pass

        # Make an appropriate result
        return exc.HTTPNoContent()
Exemplo n.º 22
0
class Controller(wsgi.Controller):
    """ The Server API base controller class for the OpenStack API """

    _view_builder_class = views_servers.ViewBuilder

    @staticmethod
    def _add_location(robj):
        # Just in case...
        if 'server' not in robj.obj:
            return robj

        link = filter(lambda l: l['rel'] == 'self',
                      robj.obj['server']['links'])
        if link:
            robj['Location'] = link[0]['href'].encode('utf-8')

        # Convenience return
        return robj

    def __init__(self, **kwargs):
        super(Controller, self).__init__(**kwargs)
        self.compute_api = compute.API()

    @wsgi.serializers(xml=MinimalServersTemplate)
    def index(self, req):
        """ Returns a list of server names and ids for a given user """
        try:
            servers = self._get_servers(req, is_detail=False)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound:
            raise exc.HTTPNotFound()
        return servers

    @wsgi.serializers(xml=ServersTemplate)
    def detail(self, req):
        """ Returns a list of server details for a given user """
        try:
            servers = self._get_servers(req, is_detail=True)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound as err:
            raise exc.HTTPNotFound()
        return servers

    def _get_block_device_mapping(self, data):
        """Get block_device_mapping from 'server' dictionary.
        Overridden by volumes controller.
        """
        return None

    def _add_instance_faults(self, ctxt, instances):
        faults = self.compute_api.get_instance_faults(ctxt, instances)
        if faults is not None:
            for instance in instances:
                faults_list = faults.get(instance['uuid'], [])
                try:
                    instance['fault'] = faults_list[0]
                except IndexError:
                    pass

        return instances

    def _get_servers(self, req, is_detail):
        """Returns a list of servers, taking into account any search
        options specified.
        """

        search_opts = {}
        search_opts.update(req.GET)

        context = req.environ['nova.context']
        remove_invalid_options(context, search_opts,
                               self._get_server_search_options())

        # Verify search by 'status' contains a valid status.
        # Convert it to filter by vm_state for compute_api.
        status = search_opts.pop('status', None)
        if status is not None:
            state = common.vm_state_from_status(status)
            if state is None:
                msg = _('Invalid server status: %(status)s') % locals()
                raise exc.HTTPBadRequest(explanation=msg)
            search_opts['vm_state'] = state

        if 'changes-since' in search_opts:
            try:
                parsed = utils.parse_isotime(search_opts['changes-since'])
            except ValueError:
                msg = _('Invalid changes-since value')
                raise exc.HTTPBadRequest(explanation=msg)
            search_opts['changes-since'] = parsed

        # By default, compute's get_all() will return deleted instances.
        # If an admin hasn't specified a 'deleted' search option, we need
        # to filter out deleted instances by setting the filter ourselves.
        # ... Unless 'changes-since' is specified, because 'changes-since'
        # should return recently deleted images according to the API spec.

        if 'deleted' not in search_opts:
            if 'changes-since' not in search_opts:
                # No 'changes-since', so we only want non-deleted servers
                search_opts['deleted'] = False

        # NOTE(dprince) This prevents computes' get_all() from returning
        # instances from multiple tenants when an admin accounts is used.
        # By default non-admin accounts are always limited to project/user
        # both here and in the compute API.
        if not context.is_admin or (context.is_admin
                                    and 'all_tenants' not in search_opts):
            if context.project_id:
                search_opts['project_id'] = context.project_id
            else:
                search_opts['user_id'] = context.user_id

        instance_list = self.compute_api.get_all(context,
                                                 search_opts=search_opts)

        limited_list = self._limit_items(instance_list, req)
        if is_detail:
            self._add_instance_faults(context, limited_list)
            return self._view_builder.detail(req, limited_list)
        else:
            return self._view_builder.index(req, limited_list)

    def _get_server(self, context, instance_uuid):
        """Utility function for looking up an instance by uuid"""
        try:
            return self.compute_api.get(context, instance_uuid)
        except exception.NotFound:
            raise exc.HTTPNotFound()

    def _handle_quota_error(self, error):
        """
        Reraise quota errors as api-specific http exceptions
        """

        code_mappings = {
            "OnsetFileLimitExceeded": _("Personality file limit exceeded"),
            "OnsetFilePathLimitExceeded": _("Personality file path too long"),
            "OnsetFileContentLimitExceeded":
            _("Personality file content too long"),

            # NOTE(bcwaldon): expose the message generated below in order
            # to better explain how the quota was exceeded
            "InstanceLimitExceeded": error.message,
        }

        code = error.kwargs['code']
        expl = code_mappings.get(code, error.message) % error.kwargs
        raise exc.HTTPRequestEntityTooLarge(explanation=expl,
                                            headers={'Retry-After': 0})

    def _validate_server_name(self, value):
        if not isinstance(value, basestring):
            msg = _("Server name is not a string or unicode")
            raise exc.HTTPBadRequest(explanation=msg)

        if value.strip() == '':
            msg = _("Server name is an empty string")
            raise exc.HTTPBadRequest(explanation=msg)

        if not len(value) < 256:
            msg = _("Server name must be less than 256 characters.")
            raise exc.HTTPBadRequest(explanation=msg)

    def _get_injected_files(self, personality):
        """
        Create a list of injected files from the personality attribute

        At this time, injected_files must be formatted as a list of
        (file_path, file_content) pairs for compatibility with the
        underlying compute service.
        """
        injected_files = []

        for item in personality:
            try:
                path = item['path']
                contents = item['contents']
            except KeyError as key:
                expl = _('Bad personality format: missing %s') % key
                raise exc.HTTPBadRequest(explanation=expl)
            except TypeError:
                expl = _('Bad personality format')
                raise exc.HTTPBadRequest(explanation=expl)
            try:
                contents = base64.b64decode(contents)
            except TypeError:
                expl = _('Personality content for %s cannot be decoded') % path
                raise exc.HTTPBadRequest(explanation=expl)
            injected_files.append((path, contents))
        return injected_files

    def _get_requested_networks(self, requested_networks):
        """
        Create a list of requested networks from the networks attribute
        """
        networks = []
        for network in requested_networks:
            try:
                network_uuid = network['uuid']

                if not utils.is_uuid_like(network_uuid):
                    msg = _("Bad networks format: network uuid is not in"
                            " proper format (%s)") % network_uuid
                    raise exc.HTTPBadRequest(explanation=msg)

                #fixed IP address is optional
                #if the fixed IP address is not provided then
                #it will use one of the available IP address from the network
                address = network.get('fixed_ip', None)
                if address is not None and not utils.is_valid_ipv4(address):
                    msg = _("Invalid fixed IP address (%s)") % address
                    raise exc.HTTPBadRequest(explanation=msg)
                # check if the network id is already present in the list,
                # we don't want duplicate networks to be passed
                # at the boot time
                for id, ip in networks:
                    if id == network_uuid:
                        expl = (_("Duplicate networks (%s) are not allowed") %
                                network_uuid)
                        raise exc.HTTPBadRequest(explanation=expl)

                networks.append((network_uuid, address))
            except KeyError as key:
                expl = _('Bad network format: missing %s') % key
                raise exc.HTTPBadRequest(explanation=expl)
            except TypeError:
                expl = _('Bad networks format')
                raise exc.HTTPBadRequest(explanation=expl)

        return networks

    def _validate_user_data(self, user_data):
        """Check if the user_data is encoded properly"""
        if not user_data:
            return
        try:
            user_data = base64.b64decode(user_data)
        except TypeError:
            expl = _('Userdata content cannot be decoded')
            raise exc.HTTPBadRequest(explanation=expl)

    def _validate_access_ipv4(self, address):
        try:
            socket.inet_aton(address)
        except socket.error:
            expl = _('accessIPv4 is not proper IPv4 format')
            raise exc.HTTPBadRequest(explanation=expl)

    def _validate_access_ipv6(self, address):
        try:
            socket.inet_pton(socket.AF_INET6, address)
        except socket.error:
            expl = _('accessIPv6 is not proper IPv6 format')
            raise exc.HTTPBadRequest(explanation=expl)

    @wsgi.serializers(xml=ServerTemplate)
    def show(self, req, id):
        """ Returns server details by server id """
        try:
            context = req.environ['nova.context']
            instance = self.compute_api.get(context, id)
            self._add_instance_faults(context, [instance])
            return self._view_builder.show(req, instance)
        except exception.NotFound:
            raise exc.HTTPNotFound()

    @wsgi.response(202)
    @wsgi.serializers(xml=FullServerTemplate)
    @wsgi.deserializers(xml=CreateDeserializer)
    def create(self, req, body):
        """ Creates a new server for a given user """
        if not body:
            raise exc.HTTPUnprocessableEntity()

        if not 'server' in body:
            raise exc.HTTPUnprocessableEntity()

        body['server']['key_name'] = self._get_key_name(req, body)

        context = req.environ['nova.context']
        server_dict = body['server']
        password = self._get_server_admin_password(server_dict)

        if not 'name' in server_dict:
            msg = _("Server name is not defined")
            raise exc.HTTPBadRequest(explanation=msg)

        name = server_dict['name']
        self._validate_server_name(name)
        name = name.strip()

        image_href = self._image_ref_from_req_data(body)
        image_href = self._image_uuid_from_href(image_href)

        personality = server_dict.get('personality')
        config_drive = server_dict.get('config_drive')

        injected_files = []
        if personality:
            injected_files = self._get_injected_files(personality)

        sg_names = []
        security_groups = server_dict.get('security_groups')
        if security_groups is not None:
            sg_names = [sg['name'] for sg in security_groups if sg.get('name')]
        if not sg_names:
            sg_names.append('default')

        sg_names = list(set(sg_names))

        requested_networks = server_dict.get('networks')
        if requested_networks is not None:
            requested_networks = self._get_requested_networks(
                requested_networks)

        (access_ip_v4, ) = server_dict.get('accessIPv4'),
        if access_ip_v4 is not None:
            self._validate_access_ipv4(access_ip_v4)

        (access_ip_v6, ) = server_dict.get('accessIPv6'),
        if access_ip_v6 is not None:
            self._validate_access_ipv6(access_ip_v6)

        try:
            flavor_id = self._flavor_id_from_req_data(body)
        except ValueError as error:
            msg = _("Invalid flavorRef provided.")
            raise exc.HTTPBadRequest(explanation=msg)

        # optional openstack extensions:
        key_name = server_dict.get('key_name')
        user_data = server_dict.get('user_data')
        self._validate_user_data(user_data)

        availability_zone = server_dict.get('availability_zone')
        name = server_dict['name']
        self._validate_server_name(name)
        name = name.strip()

        block_device_mapping = self._get_block_device_mapping(server_dict)

        ret_resv_id = server_dict.get('return_reservation_id', False)

        min_count = server_dict.get('min_count')
        max_count = server_dict.get('max_count')
        # min_count and max_count are optional.  If they exist, they come
        # in as strings.  We want to default 'min_count' to 1, and default
        # 'max_count' to be 'min_count'.
        min_count = int(min_count) if min_count else 1
        max_count = int(max_count) if max_count else min_count
        if min_count > max_count:
            min_count = max_count

        auto_disk_config = server_dict.get('auto_disk_config')
        scheduler_hints = server_dict.get('scheduler_hints', {})

        try:
            _get_inst_type = instance_types.get_instance_type_by_flavor_id
            inst_type = _get_inst_type(flavor_id)

            (instances, resv_id) = self.compute_api.create(
                context,
                inst_type,
                image_href,
                display_name=name,
                display_description=name,
                key_name=key_name,
                metadata=server_dict.get('metadata', {}),
                access_ip_v4=access_ip_v4,
                access_ip_v6=access_ip_v6,
                injected_files=injected_files,
                admin_password=password,
                min_count=min_count,
                max_count=max_count,
                requested_networks=requested_networks,
                security_group=sg_names,
                user_data=user_data,
                availability_zone=availability_zone,
                config_drive=config_drive,
                block_device_mapping=block_device_mapping,
                auto_disk_config=auto_disk_config,
                scheduler_hints=scheduler_hints)
        except exception.QuotaError as error:
            self._handle_quota_error(error)
        except exception.InstanceTypeMemoryTooSmall as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except exception.InstanceTypeDiskTooSmall as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except exception.ImageNotFound as error:
            msg = _("Can not find requested image")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.FlavorNotFound as error:
            msg = _("Invalid flavorRef provided.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.KeypairNotFound as error:
            msg = _("Invalid key_name provided.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.SecurityGroupNotFound as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except rpc_common.RemoteError as err:
            msg = "%(err_type)s: %(err_msg)s" % {
                'err_type': err.exc_type,
                'err_msg': err.value
            }
            raise exc.HTTPBadRequest(explanation=msg)
        # Let the caller deal with unhandled exceptions.

        # If the caller wanted a reservation_id, return it
        if ret_resv_id:
            return {'reservation_id': resv_id}

        server = self._view_builder.create(req, instances[0])

        if '_is_precooked' in server['server'].keys():
            del server['server']['_is_precooked']
        else:
            if FLAGS.enable_instance_password:
                server['server']['adminPass'] = password

        robj = wsgi.ResponseObject(server)

        return self._add_location(robj)

    def _delete(self, context, id):
        instance = self._get_server(context, id)
        if FLAGS.reclaim_instance_interval:
            self.compute_api.soft_delete(context, instance)
        else:
            self.compute_api.delete(context, instance)

    @wsgi.serializers(xml=ServerTemplate)
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller"""
        if len(req.body) == 0:
            raise exc.HTTPUnprocessableEntity()

        if not body:
            raise exc.HTTPUnprocessableEntity()

        ctxt = req.environ['nova.context']
        update_dict = {}

        if 'name' in body['server']:
            name = body['server']['name']
            self._validate_server_name(name)
            update_dict['display_name'] = name.strip()

        if 'accessIPv4' in body['server']:
            access_ipv4 = body['server']['accessIPv4']
            self._validate_access_ipv4(access_ipv4)
            update_dict['access_ip_v4'] = access_ipv4.strip()

        if 'accessIPv6' in body['server']:
            access_ipv6 = body['server']['accessIPv6']
            self._validate_access_ipv6(access_ipv6)
            update_dict['access_ip_v6'] = access_ipv6.strip()

        if 'auto_disk_config' in body['server']:
            auto_disk_config = utils.bool_from_str(
                body['server']['auto_disk_config'])
            update_dict['auto_disk_config'] = auto_disk_config

        try:
            instance = self.compute_api.get(ctxt, id)
            self.compute_api.update(ctxt, instance, **update_dict)
        except exception.NotFound:
            raise exc.HTTPNotFound()

        instance.update(update_dict)

        self._add_instance_faults(ctxt, [instance])
        return self._view_builder.show(req, instance)

    @wsgi.response(202)
    @wsgi.serializers(xml=FullServerTemplate)
    @wsgi.deserializers(xml=ActionDeserializer)
    @wsgi.action('confirmResize')
    def _action_confirm_resize(self, req, id, body):
        context = req.environ['nova.context']
        instance = self._get_server(context, id)
        try:
            self.compute_api.confirm_resize(context, instance)
        except exception.MigrationNotFound:
            msg = _("Instance has not been resized.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'confirmResize')
        except Exception, e:
            LOG.exception(_("Error in confirm-resize %s"), e)
            raise exc.HTTPBadRequest()
        return exc.HTTPNoContent()
Exemplo n.º 23
0
 def _update(self, context, req, id, inst_dict):
     if 'adminPass' in inst_dict['server']:
         self.compute_api.set_admin_password(
             context, id, inst_dict['server']['adminPass'])
     return exc.HTTPNoContent()
Exemplo n.º 24
0
class Controller(object):
    """ The Server API base controller class for the OpenStack API """
    def __init__(self):
        self.compute_api = compute.API()
        self.helper = helper.CreateInstanceHelper(self)

    def index(self, req):
        """ Returns a list of server names and ids for a given user """
        try:
            servers = self._get_servers(req, is_detail=False)
        except exception.Invalid as err:
            return exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound:
            return exc.HTTPNotFound()
        return servers

    def detail(self, req):
        """ Returns a list of server details for a given user """
        try:
            servers = self._get_servers(req, is_detail=True)
        except exception.Invalid as err:
            return exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound as err:
            return exc.HTTPNotFound()
        return servers

    def _build_view(self, req, instance, is_detail=False):
        raise NotImplementedError()

    def _limit_items(self, items, req):
        raise NotImplementedError()

    def _action_rebuild(self, info, request, instance_id):
        raise NotImplementedError()

    def _get_servers(self, req, is_detail):
        """Returns a list of servers, taking into account any search
        options specified.
        """

        search_opts = {}
        search_opts.update(req.str_GET)

        context = req.environ['nova.context']
        remove_invalid_options(context, search_opts,
                               self._get_server_search_options())

        # Convert recurse_zones into a boolean
        search_opts['recurse_zones'] = utils.bool_from_str(
            search_opts.get('recurse_zones', False))

        # If search by 'status', we need to convert it to 'vm_state'
        # to pass on to child zones.
        if 'status' in search_opts:
            status = search_opts['status']
            state = common.vm_state_from_status(status)
            if state is None:
                reason = _('Invalid server status: %(status)s') % locals()
                raise exception.InvalidInput(reason=reason)
            search_opts['vm_state'] = state

        if 'changes-since' in search_opts:
            try:
                parsed = utils.parse_isotime(search_opts['changes-since'])
            except ValueError:
                msg = _('Invalid changes-since value')
                raise exc.HTTPBadRequest(explanation=msg)
            search_opts['changes-since'] = parsed

        # By default, compute's get_all() will return deleted instances.
        # If an admin hasn't specified a 'deleted' search option, we need
        # to filter out deleted instances by setting the filter ourselves.
        # ... Unless 'changes-since' is specified, because 'changes-since'
        # should return recently deleted images according to the API spec.

        if 'deleted' not in search_opts:
            if 'changes-since' not in search_opts:
                # No 'changes-since', so we only want non-deleted servers
                search_opts['deleted'] = False

        instance_list = self.compute_api.get_all(context,
                                                 search_opts=search_opts)

        limited_list = self._limit_items(instance_list, req)
        servers = [
            self._build_view(req, inst, is_detail)['server']
            for inst in limited_list
        ]

        return dict(servers=servers)

    @scheduler_api.redirect_handler
    def show(self, req, id):
        """ Returns server details by server id """
        try:
            instance = self.compute_api.routing_get(
                req.environ['nova.context'], id)
            return self._build_view(req, instance, is_detail=True)
        except exception.NotFound:
            raise exc.HTTPNotFound()

    def _get_key_name(self, req, body):
        """ Get default keypair if not set """
        raise NotImplementedError()

    def create(self, req, body):
        """ Creates a new server for a given user """
        if 'server' in body:
            body['server']['key_name'] = self._get_key_name(req, body)

        extra_values = None
        extra_values, instances = self.helper.create_instance(
            req, body, self.compute_api.create)

        # We can only return 1 instance via the API, if we happen to
        # build more than one...  instances is a list, so we'll just
        # use the first one..
        inst = instances[0]
        for key in ['instance_type', 'image_ref']:
            inst[key] = extra_values[key]

        server = self._build_view(req, inst, is_detail=True)
        server['server']['adminPass'] = extra_values['password']
        return server

    @scheduler_api.redirect_handler
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller"""
        if len(req.body) == 0:
            raise exc.HTTPUnprocessableEntity()

        if not body:
            raise exc.HTTPUnprocessableEntity()

        ctxt = req.environ['nova.context']
        update_dict = {}

        if 'name' in body['server']:
            name = body['server']['name']
            self.helper._validate_server_name(name)
            update_dict['display_name'] = name.strip()

        if 'accessIPv4' in body['server']:
            access_ipv4 = body['server']['accessIPv4']
            update_dict['access_ip_v4'] = access_ipv4.strip()

        if 'accessIPv6' in body['server']:
            access_ipv6 = body['server']['accessIPv6']
            update_dict['access_ip_v6'] = access_ipv6.strip()

        try:
            self.compute_api.update(ctxt, id, **update_dict)
        except exception.NotFound:
            raise exc.HTTPNotFound()

        return self._update(ctxt, req, id, body)

    def _update(self, context, req, id, inst_dict):
        return exc.HTTPNotImplemented()

    @scheduler_api.redirect_handler
    def action(self, req, id, body):
        """Multi-purpose method used to take actions on a server"""

        self.actions = {
            'changePassword': self._action_change_password,
            'reboot': self._action_reboot,
            'resize': self._action_resize,
            'confirmResize': self._action_confirm_resize,
            'revertResize': self._action_revert_resize,
            'rebuild': self._action_rebuild,
            'createImage': self._action_create_image,
        }

        if FLAGS.allow_admin_api:
            admin_actions = {
                'createBackup': self._action_create_backup,
            }
            self.actions.update(admin_actions)

        for key in body:
            if key in self.actions:
                return self.actions[key](body, req, id)
            else:
                msg = _("There is no such server action: %s") % (key, )
                raise exc.HTTPBadRequest(explanation=msg)

        msg = _("Invalid request body")
        raise exc.HTTPBadRequest(explanation=msg)

    def _action_create_backup(self, input_dict, req, instance_id):
        """Backup a server instance.

        Images now have an `image_type` associated with them, which can be
        'snapshot' or the backup type, like 'daily' or 'weekly'.

        If the image_type is backup-like, then the rotation factor can be
        included and that will cause the oldest backups that exceed the
        rotation factor to be deleted.

        """
        entity = input_dict["createBackup"]

        try:
            image_name = entity["name"]
            backup_type = entity["backup_type"]
            rotation = entity["rotation"]

        except KeyError as missing_key:
            msg = _("createBackup entity requires %s attribute") % missing_key
            raise webob.exc.HTTPBadRequest(explanation=msg)

        except TypeError:
            msg = _("Malformed createBackup entity")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        try:
            rotation = int(rotation)
        except ValueError:
            msg = _("createBackup attribute 'rotation' must be an integer")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        # preserve link to server in image properties
        server_ref = os.path.join(req.application_url, 'servers',
                                  str(instance_id))
        props = {'instance_ref': server_ref}

        metadata = entity.get('metadata', {})
        context = req.environ["nova.context"]
        common.check_img_metadata_quota_limit(context, metadata)
        try:
            props.update(metadata)
        except ValueError:
            msg = _("Invalid metadata")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        image = self.compute_api.backup(context,
                                        instance_id,
                                        image_name,
                                        backup_type,
                                        rotation,
                                        extra_properties=props)

        # build location of newly-created image entity
        image_id = str(image['id'])
        image_ref = os.path.join(req.application_url, 'images', image_id)

        resp = webob.Response(status_int=202)
        resp.headers['Location'] = image_ref
        return resp

    @common.check_snapshots_enabled
    def _action_create_image(self, input_dict, req, id):
        return exc.HTTPNotImplemented()

    def _action_change_password(self, input_dict, req, id):
        return exc.HTTPNotImplemented()

    def _action_confirm_resize(self, input_dict, req, id):
        try:
            self.compute_api.confirm_resize(req.environ['nova.context'], id)
        except Exception, e:
            LOG.exception(_("Error in confirm-resize %s"), e)
            raise exc.HTTPBadRequest()
        return exc.HTTPNoContent()
Exemplo n.º 25
0
 def delete(self, req, policy_id):
     body = {'identity': policy_id}
     obj = util.parse_request('PolicyDeleteRequest', req, body)
     self.rpc_client.call2(req.context, 'policy_delete2', obj)
     raise exc.HTTPNoContent()
Exemplo n.º 26
0
 def delete_snapshot(self, req, identity, snapshot_id):
     self.rpc_client.delete_snapshot(req.context, identity, snapshot_id)
     raise exc.HTTPNoContent()
Exemplo n.º 27
0
class Controller(wsgi.Controller):
    """ The Server API base controller class for the OpenStack API """

    _view_builder_class = views_servers.ViewBuilder

    def __init__(self, **kwargs):
        super(Controller, self).__init__(**kwargs)
        self.compute_api = compute.API()
        self.network_api = network.API()

    def index(self, req):
        """ Returns a list of server names and ids for a given user """
        try:
            servers = self._get_servers(req, is_detail=False)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound:
            raise exc.HTTPNotFound()
        return servers

    def detail(self, req):
        """ Returns a list of server details for a given user """
        try:
            servers = self._get_servers(req, is_detail=True)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=str(err))
        except exception.NotFound as err:
            raise exc.HTTPNotFound()
        return servers

    def _get_block_device_mapping(self, data):
        """Get block_device_mapping from 'server' dictionary.
        Overridden by volumes controller.
        """
        return None

    def _add_instance_faults(self, ctxt, instances):
        faults = self.compute_api.get_instance_faults(ctxt, instances)
        if faults is not None:
            for instance in instances:
                faults_list = faults.get(instance['uuid'], [])
                try:
                    instance['fault'] = faults_list[0]
                except IndexError:
                    pass

        return instances

    def _get_servers(self, req, is_detail):
        """Returns a list of servers, taking into account any search
        options specified.
        """

        search_opts = {}
        search_opts.update(req.str_GET)

        context = req.environ['nova.context']
        remove_invalid_options(context, search_opts,
                self._get_server_search_options())

        # Convert local_zone_only into a boolean
        search_opts['local_zone_only'] = utils.bool_from_str(
                search_opts.get('local_zone_only', False))

        # If search by 'status', we need to convert it to 'vm_state'
        # to pass on to child zones.
        if 'status' in search_opts:
            status = search_opts['status']
            state = common.vm_state_from_status(status)
            if state is None:
                reason = _('Invalid server status: %(status)s') % locals()
                raise exception.InvalidInput(reason=reason)
            search_opts['vm_state'] = state

        if 'changes-since' in search_opts:
            try:
                parsed = utils.parse_isotime(search_opts['changes-since'])
            except ValueError:
                msg = _('Invalid changes-since value')
                raise exc.HTTPBadRequest(explanation=msg)
            search_opts['changes-since'] = parsed

        # By default, compute's get_all() will return deleted instances.
        # If an admin hasn't specified a 'deleted' search option, we need
        # to filter out deleted instances by setting the filter ourselves.
        # ... Unless 'changes-since' is specified, because 'changes-since'
        # should return recently deleted images according to the API spec.

        if 'deleted' not in search_opts:
            if 'changes-since' not in search_opts:
                # No 'changes-since', so we only want non-deleted servers
                search_opts['deleted'] = False

        instance_list = self.compute_api.get_all(context,
                                                 search_opts=search_opts)

        limited_list = self._limit_items(instance_list, req)
        if is_detail:
            self._add_instance_faults(context, limited_list)
            return self._view_builder.detail(req, limited_list)
        else:
            return self._view_builder.index(req, limited_list)

    def _get_server(self, context, instance_uuid):
        """Utility function for looking up an instance by uuid"""
        try:
            return self.compute_api.routing_get(context, instance_uuid)
        except exception.NotFound:
            raise exc.HTTPNotFound()

    def _handle_quota_error(self, error):
        """
        Reraise quota errors as api-specific http exceptions
        """

        code_mappings = {
            "OnsetFileLimitExceeded":
                    _("Personality file limit exceeded"),
            "OnsetFilePathLimitExceeded":
                    _("Personality file path too long"),
            "OnsetFileContentLimitExceeded":
                    _("Personality file content too long"),

            # NOTE(bcwaldon): expose the message generated below in order
            # to better explain how the quota was exceeded
            "InstanceLimitExceeded": error.message,
        }

        expl = code_mappings.get(error.code)
        if expl:
            raise exc.HTTPRequestEntityTooLarge(explanation=expl,
                                                headers={'Retry-After': 0})
        # if the original error is okay, just reraise it
        raise error

    def _validate_server_name(self, value):
        if not isinstance(value, basestring):
            msg = _("Server name is not a string or unicode")
            raise exc.HTTPBadRequest(explanation=msg)

        if value.strip() == '':
            msg = _("Server name is an empty string")
            raise exc.HTTPBadRequest(explanation=msg)

    def _get_injected_files(self, personality):
        """
        Create a list of injected files from the personality attribute

        At this time, injected_files must be formatted as a list of
        (file_path, file_content) pairs for compatibility with the
        underlying compute service.
        """
        injected_files = []

        for item in personality:
            try:
                path = item['path']
                contents = item['contents']
            except KeyError as key:
                expl = _('Bad personality format: missing %s') % key
                raise exc.HTTPBadRequest(explanation=expl)
            except TypeError:
                expl = _('Bad personality format')
                raise exc.HTTPBadRequest(explanation=expl)
            try:
                contents = base64.b64decode(contents)
            except TypeError:
                expl = _('Personality content for %s cannot be decoded') % path
                raise exc.HTTPBadRequest(explanation=expl)
            injected_files.append((path, contents))
        return injected_files

    def _get_requested_networks(self, requested_networks):
        """
        Create a list of requested networks from the networks attribute
        """
        networks = []
        for network in requested_networks:
            try:
                network_uuid = network['uuid']

                if not utils.is_uuid_like(network_uuid):
                    msg = _("Bad networks format: network uuid is not in"
                         " proper format (%s)") % network_uuid
                    raise exc.HTTPBadRequest(explanation=msg)

                #fixed IP address is optional
                #if the fixed IP address is not provided then
                #it will use one of the available IP address from the network
                address = network.get('fixed_ip', None)
                if address is not None and not utils.is_valid_ipv4(address):
                    msg = _("Invalid fixed IP address (%s)") % address
                    raise exc.HTTPBadRequest(explanation=msg)
                # check if the network id is already present in the list,
                # we don't want duplicate networks to be passed
                # at the boot time
                for id, ip in networks:
                    if id == network_uuid:
                        expl = _("Duplicate networks (%s) are not allowed")\
                                % network_uuid
                        raise exc.HTTPBadRequest(explanation=expl)

                networks.append((network_uuid, address))
            except KeyError as key:
                expl = _('Bad network format: missing %s') % key
                raise exc.HTTPBadRequest(explanation=expl)
            except TypeError:
                expl = _('Bad networks format')
                raise exc.HTTPBadRequest(explanation=expl)

        return networks

    def _validate_user_data(self, user_data):
        """Check if the user_data is encoded properly"""
        if not user_data:
            return
        try:
            user_data = base64.b64decode(user_data)
        except TypeError:
            expl = _('Userdata content cannot be decoded')
            raise exc.HTTPBadRequest(explanation=expl)

    @exception.novaclient_converter
    @scheduler_api.redirect_handler
    def show(self, req, id):
        """ Returns server details by server id """
        try:
            context = req.environ['nova.context']
            instance = self.compute_api.routing_get(context, id)
            self._add_instance_faults(context, [instance])
            return self._view_builder.show(req, instance)
        except exception.NotFound:
            raise exc.HTTPNotFound()

    def create(self, req, body):
        """ Creates a new server for a given user """
        if not body:
            raise exc.HTTPUnprocessableEntity()

        if not 'server' in body:
            raise exc.HTTPUnprocessableEntity()

        body['server']['key_name'] = self._get_key_name(req, body)

        context = req.environ['nova.context']
        server_dict = body['server']
        password = self._get_server_admin_password(server_dict)

        if not 'name' in server_dict:
            msg = _("Server name is not defined")
            raise exc.HTTPBadRequest(explanation=msg)

        name = server_dict['name']
        self._validate_server_name(name)
        name = name.strip()

        image_href = self._image_ref_from_req_data(body)

        # If the image href was generated by nova api, strip image_href
        # down to an id and use the default glance connection params
        if str(image_href).startswith(req.application_url):
            image_href = image_href.split('/').pop()

        personality = server_dict.get('personality')
        config_drive = server_dict.get('config_drive')

        injected_files = []
        if personality:
            injected_files = self._get_injected_files(personality)

        sg_names = []
        security_groups = server_dict.get('security_groups')
        if security_groups is not None:
            sg_names = [sg['name'] for sg in security_groups if sg.get('name')]
        if not sg_names:
            sg_names.append('default')

        sg_names = list(set(sg_names))

        requested_networks = server_dict.get('networks')
        if requested_networks is not None:
            requested_networks = self._get_requested_networks(
                                                    requested_networks)

        try:
            flavor_id = self._flavor_id_from_req_data(body)
        except ValueError as error:
            msg = _("Invalid flavorRef provided.")
            raise exc.HTTPBadRequest(explanation=msg)

        zone_blob = server_dict.get('blob')

        # optional openstack extensions:
        key_name = server_dict.get('key_name')
        user_data = server_dict.get('user_data')
        self._validate_user_data(user_data)

        availability_zone = server_dict.get('availability_zone')
        name = server_dict['name']
        self._validate_server_name(name)
        name = name.strip()

        block_device_mapping = self._get_block_device_mapping(server_dict)

        # Only allow admins to specify their own reservation_ids
        # This is really meant to allow zones to work.
        reservation_id = server_dict.get('reservation_id')
        if all([reservation_id is not None,
                reservation_id != '',
                not context.is_admin]):
            reservation_id = None

        ret_resv_id = server_dict.get('return_reservation_id', False)

        min_count = server_dict.get('min_count')
        max_count = server_dict.get('max_count')
        # min_count and max_count are optional.  If they exist, they come
        # in as strings.  We want to default 'min_count' to 1, and default
        # 'max_count' to be 'min_count'.
        min_count = int(min_count) if min_count else 1
        max_count = int(max_count) if max_count else min_count
        if min_count > max_count:
            min_count = max_count

        auto_disk_config = server_dict.get('auto_disk_config')

        try:
            inst_type = \
                    instance_types.get_instance_type_by_flavor_id(flavor_id)

            (instances, resv_id) = self.compute_api.create(context,
                            inst_type,
                            image_href,
                            display_name=name,
                            display_description=name,
                            key_name=key_name,
                            metadata=server_dict.get('metadata', {}),
                            access_ip_v4=server_dict.get('accessIPv4'),
                            access_ip_v6=server_dict.get('accessIPv6'),
                            injected_files=injected_files,
                            admin_password=password,
                            zone_blob=zone_blob,
                            reservation_id=reservation_id,
                            min_count=min_count,
                            max_count=max_count,
                            requested_networks=requested_networks,
                            security_group=sg_names,
                            user_data=user_data,
                            availability_zone=availability_zone,
                            config_drive=config_drive,
                            block_device_mapping=block_device_mapping,
                            auto_disk_config=auto_disk_config)
        except exception.QuotaError as error:
            self._handle_quota_error(error)
        except exception.InstanceTypeMemoryTooSmall as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except exception.InstanceTypeDiskTooSmall as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except exception.ImageNotFound as error:
            msg = _("Can not find requested image")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.FlavorNotFound as error:
            msg = _("Invalid flavorRef provided.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.KeypairNotFound as error:
            msg = _("Invalid key_name provided.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.SecurityGroupNotFound as error:
            raise exc.HTTPBadRequest(explanation=unicode(error))
        except rpc_common.RemoteError as err:
            msg = "%(err_type)s: %(err_msg)s" % \
                  {'err_type': err.exc_type, 'err_msg': err.value}
            raise exc.HTTPBadRequest(explanation=msg)
        # Let the caller deal with unhandled exceptions.

        # If the caller wanted a reservation_id, return it
        if ret_resv_id:
            return {'reservation_id': resv_id}

        server = self._view_builder.create(req, instances[0])

        if '_is_precooked' in server['server'].keys():
            del server['server']['_is_precooked']
        else:
            server['server']['adminPass'] = password

        return server

    def _delete(self, context, id):
        instance = self._get_server(context, id)
        if FLAGS.reclaim_instance_interval:
            self.compute_api.soft_delete(context, instance)
        else:
            self.compute_api.delete(context, instance)

    @scheduler_api.redirect_handler
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller"""
        if len(req.body) == 0:
            raise exc.HTTPUnprocessableEntity()

        if not body:
            raise exc.HTTPUnprocessableEntity()

        ctxt = req.environ['nova.context']
        update_dict = {}

        if 'name' in body['server']:
            name = body['server']['name']
            self._validate_server_name(name)
            update_dict['display_name'] = name.strip()

        if 'accessIPv4' in body['server']:
            access_ipv4 = body['server']['accessIPv4']
            update_dict['access_ip_v4'] = access_ipv4.strip()

        if 'accessIPv6' in body['server']:
            access_ipv6 = body['server']['accessIPv6']
            update_dict['access_ip_v6'] = access_ipv6.strip()

        if 'auto_disk_config' in body['server']:
            auto_disk_config = utils.bool_from_str(
                    body['server']['auto_disk_config'])
            update_dict['auto_disk_config'] = auto_disk_config

        instance = self.compute_api.routing_get(ctxt, id)

        try:
            self.compute_api.update(ctxt, instance, **update_dict)
        except exception.NotFound:
            raise exc.HTTPNotFound()

        instance.update(update_dict)

        self._add_instance_faults(ctxt, [instance])
        return self._view_builder.show(req, instance)

    @exception.novaclient_converter
    @scheduler_api.redirect_handler
    def action(self, req, id, body):
        """Multi-purpose method used to take actions on a server"""
        _actions = {
            'changePassword': self._action_change_password,
            'reboot': self._action_reboot,
            'resize': self._action_resize,
            'confirmResize': self._action_confirm_resize,
            'revertResize': self._action_revert_resize,
            'rebuild': self._action_rebuild,
            'createImage': self._action_create_image,
        }

        for key in body:
            if key in _actions:
                return _actions[key](body, req, id)
            else:
                msg = _("There is no such server action: %s") % (key,)
                raise exc.HTTPBadRequest(explanation=msg)

        msg = _("Invalid request body")
        raise exc.HTTPBadRequest(explanation=msg)

    def _action_confirm_resize(self, input_dict, req, id):
        context = req.environ['nova.context']
        instance = self._get_server(context, id)
        try:
            self.compute_api.confirm_resize(context, instance)
        except exception.MigrationNotFound:
            msg = _("Instance has not been resized.")
            raise exc.HTTPBadRequest(explanation=msg)
        except Exception, e:
            LOG.exception(_("Error in confirm-resize %s"), e)
            raise exc.HTTPBadRequest()
        return exc.HTTPNoContent()
Exemplo n.º 28
0
    def notify(self, req, receiver_id, body=None):

        obj = util.parse_request('ReceiverNotifyRequest', req,
                                 {'identity': receiver_id})
        self.rpc_client.call(req.context, 'receiver_notify', obj)
        raise exc.HTTPNoContent()
Exemplo n.º 29
0
    def delete(self, req, receiver_id):

        obj = util.parse_request('ReceiverDeleteRequest', req,
                                 {'identity': receiver_id})
        self.rpc_client.call(req.context, 'receiver_delete', obj)
        raise exc.HTTPNoContent()
Exemplo n.º 30
0
def no_content():
    return exc.HTTPNoContent()