Example #1
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ['nova.context']
        context.can(ms_policies.POLICY_ROOT % 'migrate')

        host_name = None
        if (api_version_request.is_supported(req, min_version='2.56') and
            body['migrate'] is not None):
            host_name = body['migrate'].get('host')

        instance = common.get_instance(self.compute_api, context, id)
        try:
            self.compute_api.resize(req.environ['nova.context'], instance,
                                    host_name=host_name)
        except (exception.TooManyInstances, exception.QuotaError) as e:
            raise exc.HTTPForbidden(explanation=e.format_message())
        except (exception.InstanceIsLocked,
                exception.CannotMigrateWithTargetHost) as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'migrate', id)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except (exception.NoValidHost, exception.ComputeHostNotFound,
                exception.CannotMigrateToSameHost) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #2
0
    def _resize(self, req, instance_id, flavor_id, **kwargs):
        """Begin the resize process with given instance/flavor."""
        context = req.environ["nova.context"]
        instance = self._get_server(context, req, instance_id)

        try:
            self.compute_api.resize(context, instance, flavor_id, **kwargs)
        except exception.QuotaError as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message(),
                headers={'Retry-After': 0})
        except exception.FlavorNotFound:
            msg = _("Unable to locate requested flavor.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.CannotResizeToSameFlavor:
            msg = _("Resize requires a flavor change.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'resize')
        except exception.ImageNotAuthorized:
            msg = _("You are not authorized to access the image "
                    "the instance was started with.")
            raise exc.HTTPUnauthorized(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Image that the instance was started "
                    "with could not be found.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.Invalid:
            msg = _("Invalid instance image.")
            raise exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #3
0
    def attach(self, req, id, body):
        server_id = id
        context = req.environ['nova.context']
        authorize_attach(context)

        volume_id = body['attach']['volume_id']
        device = body['attach'].get('device')
        disk_bus = body['attach'].get('disk_bus')
        device_type = body['attach'].get('device_type')

        instance = common.get_instance(self.compute_api, context, server_id,
                                       want_objects=True)
        try:
            self.compute_api.attach_volume(context, instance,
                                           volume_id, device,
                                           disk_bus=disk_bus,
                                           device_type=device_type)
        except exception.VolumeNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'attach_volume', server_id)
        except exception.InvalidVolume as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InvalidDevicePath as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #4
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ['nova.context']
        authorize(context, 'migrate')

        instance = common.get_instance(self.compute_api, context, id,
                                       want_objects=True)
        try:
            self.compute_api.resize(req.environ['nova.context'], instance)
        except exception.TooManyInstances as e:
            raise exc.HTTPRequestEntityTooLarge(explanation=e.format_message())
        except exception.QuotaError as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message(),
                headers={'Retry-After': 0})
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'migrate')
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.NoValidHost as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())

        return webob.Response(status_int=202)
Example #5
0
    def _rescue(self, req, id, body):
        """Rescue an instance."""
        context = req.environ["nova.context"]
        authorize(context)

        if body['rescue'] and 'adminPass' in body['rescue']:
            password = body['rescue']['adminPass']
        else:
            password = utils.generate_password()

        instance = common.get_instance(self.compute_api, context, id)
        try:
            rescue_image_ref = None
            if self.ext_mgr.is_loaded("os-extended-rescue-with-image"):
                if body['rescue'] and 'rescue_image_ref' in body['rescue']:
                    rescue_image_ref = self._rescue_image_validation(
                       body['rescue']['rescue_image_ref'])
            self.compute_api.rescue(context, instance,
                rescue_password=password, rescue_image_ref=rescue_image_ref)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                                                                  'rescue', id)
        except exception.InvalidVolume as volume_error:
            raise exc.HTTPConflict(explanation=volume_error.format_message())
        except exception.InstanceNotRescuable as non_rescuable:
            raise exc.HTTPBadRequest(
                explanation=non_rescuable.format_message())

        return {'adminPass': password}
Example #6
0
    def _resize(self, req, instance_id, flavor_id, **kwargs):
        """Begin the resize process with given instance/flavor."""
        context = req.environ["nova.context"]
        authorize(context, action="resize")
        instance = self._get_server(context, req, instance_id)

        try:
            self.compute_api.resize(context, instance, flavor_id, **kwargs)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message(), headers={"Retry-After": 0})
        except exception.FlavorNotFound:
            msg = _("Unable to locate requested flavor.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.CannotResizeToSameFlavor:
            msg = _("Resize requires a flavor change.")
            raise exc.HTTPBadRequest(explanation=msg)
        except (exception.CannotResizeDisk, exception.AutoDiskConfigDisabledByImage) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "resize", instance_id)
        except exception.ImageNotAuthorized:
            msg = _("You are not authorized to access the image " "the instance was started with.")
            raise exc.HTTPUnauthorized(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Image that the instance was started " "with could not be found.")
            raise exc.HTTPBadRequest(explanation=msg)
        except (exception.NoValidHost, exception.AutoDiskConfigDisabledByImage) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.Invalid:
            msg = _("Invalid instance image.")
            raise exc.HTTPBadRequest(explanation=msg)
Example #7
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ["nova.context"]
        authorize(context, "migrate")

        # ADD by zhjh 2014-12-03 migrate instance to a selected host.
        host = body["migrate"]["host"] if (isinstance(body["migrate"], dict) and "host" in body["migrate"]) else None

        try:
            instance = self.compute_api.get(context, id, want_objects=True)
            # MOD by zhjh 2014-12-04 migrate instance to a selected host.
            # self.compute_api.resize(req.environ['nova.context'], instance)
            self.compute_api.resize(req.environ["nova.context"], instance, host=host)
        except exception.QuotaError as error:
            raise exc.HTTPRequestEntityTooLarge(explanation=error.format_message(), headers={"Retry-After": 0})
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "migrate")
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except Exception as e:
            LOG.exception(_("Error in migrate %s"), e)
            raise exc.HTTPBadRequest()
        return webob.Response(status_int=202)
Example #8
0
    def _action_reboot(self, req, id, body):
        if 'reboot' in body and 'type' in body['reboot']:
            if not isinstance(body['reboot']['type'], six.string_types):
                msg = _("Argument 'type' for reboot must be a string")
                LOG.error(msg)
                raise exc.HTTPBadRequest(explanation=msg)
            valid_reboot_types = ['HARD', 'SOFT']
            reboot_type = body['reboot']['type'].upper()
            if not valid_reboot_types.count(reboot_type):
                msg = _("Argument 'type' for reboot is not HARD or SOFT")
                LOG.error(msg)
                raise exc.HTTPBadRequest(explanation=msg)
        else:
            msg = _("Missing argument 'type' for reboot")
            LOG.error(msg)
            raise exc.HTTPBadRequest(explanation=msg)

        context = req.environ['nova.context']
        instance = self._get_server(context, req, id)

        try:
            self.compute_api.reboot(context, instance, reboot_type)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'reboot')
        return webob.Response(status_int=202)
Example #9
0
    def _update_instance_metadata(self, context, server_id, metadata,
                                  delete=False):
        try:
            server = common.get_instance(self.compute_api, context, server_id,
                                         want_objects=True)
            return self.compute_api.update_instance_metadata(context,
                                                             server,
                                                             metadata,
                                                             delete)

        except exception.InvalidMetadata as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())

        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'update metadata')
Example #10
0
    def _action_create_image(self, req, id, body):
        """Snapshot a server instance."""
        context = req.environ["nova.context"]
        entity = body.get("createImage", {})

        image_name = entity.get("name")

        if not image_name:
            msg = _("createImage entity requires name attribute")
            raise exc.HTTPBadRequest(explanation=msg)

        props = {}
        metadata = entity.get("metadata", {})
        common.check_img_metadata_quota_limit(context, metadata)
        try:
            props.update(metadata)
        except ValueError:
            msg = _("Invalid metadata")
            raise exc.HTTPBadRequest(explanation=msg)

        instance = self._get_server(context, id)

        try:
            image = self.compute_api.snapshot(context, instance, image_name, extra_properties=props)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "createImage")

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

        resp = webob.Response(status_int=202)
        resp.headers["Location"] = image_ref
        return resp
Example #11
0
    def _update_instance_metadata(self, context, server_id, metadata,
                                  delete=False):
        try:
            server = self.compute_api.get(context, server_id,
                                          want_objects=True)
            return self.compute_api.update_instance_metadata(context,
                                                             server,
                                                             metadata,
                                                             delete)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except (ValueError, AttributeError):
            msg = _("Malformed request body")
            raise exc.HTTPBadRequest(explanation=msg)

        except exception.InvalidMetadata as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())

        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'update metadata')
Example #12
0
    def delete(self, req, server_id, id):
        """Deletes an existing metadata."""
        context = req.environ['nova.context']

        metadata = self._get_metadata(context, server_id)

        if id not in metadata:
            msg = _("Metadata item was not found")
            raise exc.HTTPNotFound(explanation=msg)

        try:
            server = self.compute_api.get(context, server_id,
                                          want_objects=True)
            self.compute_api.delete_instance_metadata(context, server, id)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'delete metadata')
Example #13
0
    def index(self, req, server_id):
        context = req.environ["nova.context"]
        context.can(sd_policies.BASE_POLICY_NAME)

        instance = common.get_instance(self.compute_api, context, server_id)

        try:
            if api_version_request.is_supported(req, min_version='2.48'):
                diagnostics = self.compute_api.get_instance_diagnostics(
                    context, instance)
                return self._view_builder.instance_diagnostics(diagnostics)

            return self.compute_api.get_diagnostics(context, instance)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'get_diagnostics', server_id)
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceDiagnosticsNotSupported:
            # NOTE(snikitin): During upgrade we may face situation when env
            # has new API and old compute. New compute returns a
            # Diagnostics object. Old compute returns a dictionary. So we
            # can't perform a request correctly if compute is too old.
            msg = _('Compute node is too old. You must complete the '
                    'upgrade process to be able to get standardized '
                    'diagnostics data which is available since v2.48. However '
                    'you are still able to get diagnostics data in '
                    'non-standardized format which is available until v2.47.')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except NotImplementedError:
            common.raise_feature_not_supported()
Example #14
0
    def _migrate_live(self, req, id, body):
        """Permit admins to (live) migrate a server to a new host."""
        context = req.environ["nova.context"]
        authorize(context, 'migrate_live')

        try:
            block_migration = body["migrate_live"]["block_migration"]
            disk_over_commit = body["migrate_live"]["disk_over_commit"]
            host = body["migrate_live"]["host"]
        except (TypeError, KeyError):
            msg = _("host, block_migration and disk_over_commit must "
                    "be specified for live migration.")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            instance = self.compute_api.get(context, id)
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host)
        except (exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.NoValidHost,
                exception.InvalidLocalStorage,
                exception.InvalidSharedStorage,
                exception.MigrationPreCheckError) as ex:
            raise exc.HTTPBadRequest(explanation=ex.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'migrate_live')
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        return webob.Response(status_int=202)
Example #15
0
    def _rescue(self, req, id, body):
        """Rescue an instance."""
        context = req.environ["nova.context"]
        authorize(context)

        if body['rescue'] and 'adminPass' in body['rescue']:
            password = body['rescue']['adminPass']
        else:
            password = utils.generate_password()

        instance = self._get_instance(context, id, want_objects=True)
        try:
            self.compute_api.rescue(context, instance,
                                    rescue_password=password)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                                                                  'rescue')
        except exception.InvalidVolume as volume_error:
            raise exc.HTTPConflict(explanation=volume_error.format_message())
        except exception.InstanceNotRescuable as non_rescuable:
            raise exc.HTTPBadRequest(
                explanation=non_rescuable.format_message())
        except NotImplementedError:
                msg = _("The rescue operation is not implemented by this "
                        "cloud.")
                raise exc.HTTPNotImplemented(explanation=msg)

        return {'adminPass': password}
Example #16
0
    def attach(self, req, id, body):
        server_id = id
        context = req.environ["nova.context"]
        authorize_attach(context)

        volume_id = body["attach"]["volume_id"]
        device = body["attach"].get("device")
        disk_bus = body["attach"].get("disk_bus")
        device_type = body["attach"].get("device_type")

        LOG.audit(
            _("Attach volume %(volume_id)s to instance %(server_id)s " "at %(device)s"),
            {"volume_id": volume_id, "device": device, "server_id": server_id},
            context=context,
        )

        instance = common.get_instance(self.compute_api, context, server_id, want_objects=True)
        try:
            self.compute_api.attach_volume(
                context, instance, volume_id, device, disk_bus=disk_bus, device_type=device_type
            )
        except exception.VolumeNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "attach_volume")
        except exception.InvalidVolume as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InvalidDevicePath as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #17
0
    def _action_reboot(self, req, id, body):
        if "reboot" in body and "type" in body["reboot"]:
            if not isinstance(body["reboot"]["type"], six.string_types):
                msg = _("Argument 'type' for reboot must be a string")
                LOG.error(msg)
                raise exc.HTTPBadRequest(explanation=msg)
            valid_reboot_types = ["HARD", "SOFT"]
            reboot_type = body["reboot"]["type"].upper()
            if not valid_reboot_types.count(reboot_type):
                msg = _("Argument 'type' for reboot is not HARD or SOFT")
                LOG.error(msg)
                raise exc.HTTPBadRequest(explanation=msg)
        else:
            msg = _("Missing argument 'type' for reboot")
            LOG.error(msg)
            raise exc.HTTPBadRequest(explanation=msg)

        context = req.environ["nova.context"]
        instance = self._get_server(context, req, id)

        try:
            self.compute_api.reboot(context, instance, reboot_type)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "reboot", id)
Example #18
0
 def _migrate(self, req, id, body):
     """Permit admins to migrate a server to a new host."""
     context = req.environ['nova.context']
     authorize(context, 'migrate')
     instance = common.get_instance(self.compute_api, context, id,
                                    want_objects=True)
     host = None
     if self.ext_mgr.is_loaded('os-migrate-host'):
         migrate_body = body.get('migrate')
         host = migrate_body.get('host') if migrate_body else None
     LOG.debug("Going to try to cold migrate %(uuid)s to %(host)s",
               {"uuid":instance["uuid"], "host":(host or "another host")})
     try:
         self.compute_api.resize(req.environ['nova.context'], instance,
                                 migrate_host=host)
     except exception.QuotaError as error:
         raise exc.HTTPForbidden(explanation=error.format_message())
     except exception.InstanceIsLocked as e:
         raise exc.HTTPConflict(explanation=e.format_message())
     except exception.InstanceInvalidState as state_error:
         common.raise_http_conflict_for_instance_invalid_state(state_error,
                 'migrate')
     except exception.InstanceNotFound as e:
         raise exc.HTTPNotFound(explanation=e.format_message())
     except exception.NoValidHost as e:
         raise exc.HTTPBadRequest(explanation=e.format_message())
     except Exception as e:
         LOG.exception(_LE("Error in migrate %s"), e)
         raise exc.HTTPBadRequest()
     return webob.Response(status_int=202)
Example #19
0
    def _unshelve(self, req, id, body):
        """Restore an instance from shelved mode."""
        context = req.environ["nova.context"]
        context.can(shelve_policies.POLICY_ROOT % 'unshelve')
        instance = common.get_instance(self.compute_api, context, id)

        # We could potentially move this check to conductor and avoid the
        # extra API call to neutron when we support move operations with ports
        # having resource requests.
        if (instance.vm_state == vm_states.SHELVED_OFFLOADED
                and common.instance_has_port_with_resource_request(
                    context, instance.uuid, self.network_api)
                and not common.supports_port_resource_request_during_move(
                    req)):
            msg = _("The unshelve action on a server with ports having "
                    "resource requests, like a port with a QoS minimum "
                    "bandwidth policy, is not supported with this "
                    "microversion")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            self.compute_api.unshelve(context, instance)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                                                                  'unshelve',
                                                                  id)
Example #20
0
    def _action_rebuild(self, req, id, body):
        """Rebuild an instance with the given attributes."""
        rebuild_dict = body["rebuild"]

        image_href = rebuild_dict["imageRef"]
        image_href = self._image_uuid_from_href(image_href)

        password = self._get_server_admin_password(rebuild_dict)

        context = req.environ["nova.context"]
        authorize(context, action="rebuild")
        instance = self._get_server(context, req, id)

        attr_map = {"name": "display_name", "metadata": "metadata"}

        rebuild_kwargs = {}

        if list(self.rebuild_extension_manager):
            self.rebuild_extension_manager.map(self._rebuild_extension_point, rebuild_dict, rebuild_kwargs)

        for request_attribute, instance_attribute in attr_map.items():
            try:
                rebuild_kwargs[instance_attribute] = rebuild_dict[request_attribute]
            except (KeyError, TypeError):
                pass

        try:
            self.compute_api.rebuild(context, instance, image_href, password, **rebuild_kwargs)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "rebuild", id)
        except exception.InstanceNotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Cannot find image for rebuild")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())
        except (
            exception.ImageNotActive,
            exception.FlavorDiskTooSmall,
            exception.FlavorMemoryTooSmall,
            exception.InvalidMetadata,
            exception.AutoDiskConfigDisabledByImage,
        ) as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        instance = self._get_server(context, req, id)

        view = self._view_builder.show(req, instance, extend_address=False)

        # Add on the admin_password attribute since the view doesn't do it
        # unless instance passwords are disabled
        if CONF.enable_instance_password:
            view["server"]["adminPass"] = password

        robj = wsgi.ResponseObject(view)
        return self._add_location(robj)
Example #21
0
    def _action_create_image(self, req, id, body):
        """Snapshot a server instance."""
        context = req.environ['nova.context']
        entity = body.get("createImage", {})

        image_name = entity.get("name")

        if not image_name:
            msg = _("createImage entity requires name attribute")
            raise exc.HTTPBadRequest(explanation=msg)

        props = {}
        metadata = entity.get('metadata', {})
        common.check_img_metadata_properties_quota(context, metadata)
        try:
            props.update(metadata)
        except ValueError:
            msg = _("Invalid metadata")
            raise exc.HTTPBadRequest(explanation=msg)

        instance = self._get_server(context, req, id)

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
                    context, instance.uuid)

        try:
            if self.compute_api.is_volume_backed_instance(context, instance,
                                                          bdms):
                policy.enforce(context,
                        'compute:snapshot_volume_backed',
                        {'project_id': context.project_id,
                        'user_id': context.user_id})
                image = self.compute_api.snapshot_volume_backed(
                                                       context,
                                                       instance,
                                                       image_name,
                                                       extra_properties=props)
            else:
                image = self.compute_api.snapshot(context,
                                                  instance,
                                                  image_name,
                                                  extra_properties=props)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                        'createImage', id)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=err.format_message())

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

        resp = webob.Response(status_int=202)
        resp.headers['Location'] = image_ref
        return resp
Example #22
0
 def _check_instance_in_valid_state(self, context, server_id, action):
     instance = common.get_instance(self.compute_api, context, server_id)
     if instance.vm_state not in (vm_states.ACTIVE, vm_states.PAUSED, vm_states.SUSPENDED, vm_states.STOPPED):
         exc = exception.InstanceInvalidState(
             attr="vm_state", instance_uuid=instance.uuid, state=instance.vm_state, method=action
         )
         common.raise_http_conflict_for_instance_invalid_state(exc, action, server_id)
    def attach(self, req, id, body):
        server_id = id
        context = req.environ['nova.context']
        authorize_attach(context)

        volume_id = body['attach']['volume_id']
        device = body['attach'].get('device')

        LOG.audit(_("Attach volume %(volume_id)s to instance %(server_id)s "
                    "at %(device)s"),
                  {'volume_id': volume_id,
                   'device': device,
                   'server_id': server_id},
                  context=context)

        try:
            instance = self.compute_api.get(context, server_id)
            self.compute_api.attach_volume(context, instance,
                                           volume_id, device)
        except (exception.InstanceNotFound, exception.VolumeNotFound) as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'attach_volume')
        except exception.InvalidVolume as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InvalidDevicePath as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #24
0
    def _rescue(self, req, id, body):
        """Rescue an instance."""
        context = req.environ["nova.context"]
        authorize(context)

        if body['rescue'] and 'adminPass' in body['rescue']:
            password = body['rescue']['adminPass']
        else:
            password = utils.generate_password()

        instance = common.get_instance(self.compute_api, context, id,
                                       want_objects=True)
        rescue_image_ref = None
        if body['rescue'] and 'rescue_image_ref' in body['rescue']:
            rescue_image_ref = body['rescue']['rescue_image_ref']

        try:
            self.compute_api.rescue(context, instance,
                                    rescue_password=password,
                                    rescue_image_ref=rescue_image_ref)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                                                                  'rescue')
        except exception.InvalidVolume as volume_error:
            raise exc.HTTPConflict(explanation=volume_error.format_message())
        except exception.InstanceNotRescuable as non_rescuable:
            raise exc.HTTPBadRequest(
                explanation=non_rescuable.format_message())

        if CONF.enable_instance_password:
            return {'adminPass': password}
        else:
            return {}
Example #25
0
    def create(self, req, server_id, body):
        """Attach an interface to an instance."""
        context = req.environ['nova.context']
        authorize(context)

        network_id = None
        port_id = None
        req_ip = None
        if body:
            attachment = body['interfaceAttachment']
            network_id = attachment.get('net_id', None)
            port_id = attachment.get('port_id', None)
            try:
                req_ip = attachment['fixed_ips'][0]['ip_address']
            except Exception:
                pass

        if network_id and port_id:
            msg = _("Must not input both network_id and port_id")
            raise exc.HTTPBadRequest(explanation=msg)
        if req_ip and not network_id:
            msg = _("Must input network_id when request IP address")
            raise exc.HTTPBadRequest(explanation=msg)

        if req_ip:
            try:
                netaddr.IPAddress(req_ip)
            except netaddr.AddrFormatError as e:
                raise exc.HTTPBadRequest(explanation=six.text_type(e))

        try:
            instance = common.get_instance(self.compute_api,
                                           context, server_id)
            LOG.info(_LI("Attach interface"), instance=instance)
            vif = self.compute_api.attach_interface(context,
                instance, network_id, port_id, req_ip)
        except (exception.PortNotFound,
                exception.NetworkNotFound) as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except (exception.FixedIpAlreadyInUse,
                exception.InterfaceAttachFailedNoNetwork,
                exception.NoMoreFixedIps,
                exception.PortInUse,
                exception.NetworkDuplicated,
                exception.NetworkAmbiguous,
                exception.PortNotUsable) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Network driver does not support this function.")
            raise webob.exc.HTTPNotImplemented(explanation=msg)
        except exception.InterfaceAttachFailed:
            msg = _("Failed to attach interface")
            raise webob.exc.HTTPInternalServerError(explanation=msg)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'attach_interface', server_id)

        return self.show(req, server_id, vif['id'])
Example #26
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ['nova.context']
        authorize(context, 'migrate')

        #MOD by zhjh 2015-02-13 migrate instance to a selected host.
        host = body["migrate"]["host"] if (isinstance(body['migrate'], dict) and 'host' in body['migrate']) else None

        instance = common.get_instance(self.compute_api, context, id,
                                       want_objects=True)
        try:
            #MOD by zhjh 2015-02-13 migrate instance to a selected host.
            #self.compute_api.resize(req.environ['nova.context'], instance)
            self.compute_api.resize(req.environ['nova.context'], instance, host=host)

        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'migrate')
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.NoValidHost as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except Exception as e:
            LOG.exception(_LE("Error in migrate %s"), e)
            raise exc.HTTPBadRequest()
        return webob.Response(status_int=202)
Example #27
0
    def _action_create_image(self, req, id, body):
        """Snapshot a server instance."""
        context = req.environ["nova.context"]
        authorize(context, action="create_image")

        entity = body["createImage"]
        image_name = entity["name"]
        metadata = entity.get("metadata", {})

        common.check_img_metadata_properties_quota(context, metadata)

        instance = self._get_server(context, req, id)

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(context, instance.uuid)

        try:
            if self.compute_api.is_volume_backed_instance(context, instance, bdms):
                authorize(context, action="create_image:allow_volume_backed")
                image = self.compute_api.snapshot_volume_backed(
                    context, instance, image_name, extra_properties=metadata
                )
            else:
                image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error, "createImage", id)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=err.format_message())

        # build location of newly-created image entity
        image_id = str(image["id"])
        image_ref = glance.generate_image_url(image_id)

        resp = webob.Response(status_int=202)
        resp.headers["Location"] = image_ref
        return resp
Example #28
0
    def _migrate_live(self, req, id, body):
        """Permit admins to (live) migrate a server to a new host."""
        context = req.environ["nova.context"]
        authorize(context, action='migrate_live')

        block_migration = body["os-migrateLive"]["block_migration"]
        disk_over_commit = body["os-migrateLive"]["disk_over_commit"]
        host = body["os-migrateLive"]["host"]

        block_migration = strutils.bool_from_string(block_migration,
                                                    strict=True)
        disk_over_commit = strutils.bool_from_string(disk_over_commit,
                                                     strict=True)

        try:
            instance = common.get_instance(self.compute_api, context, id)
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host)
        except (exception.NoValidHost,
                exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType,
                exception.InvalidCPUInfo,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.InvalidLocalStorage,
                exception.InvalidSharedStorage,
                exception.HypervisorUnavailable,
                exception.MigrationPreCheckError,
                exception.LiveMigrationWithOldNovaNotSafe) as ex:
            raise exc.HTTPBadRequest(explanation=ex.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'os-migrateLive', id)
Example #29
0
 def _migrate(self, req, id, body):
     """Permit admins to migrate a server to a new host."""
     az=body.get('migrate')
     context = req.environ['nova.context']
     authorize(context, 'migrate')
     instance = common.get_instance(self.compute_api, context, id,
                                    want_objects=True)
     if az is not None:
         availability_zone = instance.availability_zone
         if az == availability_zone:
             msg = _("The target azone can't be the same one.")
             raise exc.HTTPBadRequest(explanation=msg)
             
         migrateThread = MigrateThread(context,instance,az)
         migrateThread.start()
         
     else:
         try:
             self.compute_api.resize(req.environ['nova.context'], instance)
         except exception.QuotaError as error:
             raise exc.HTTPForbidden(explanation=error.format_message())
         except exception.InstanceIsLocked as e:
             raise exc.HTTPConflict(explanation=e.format_message())
         except exception.InstanceInvalidState as state_error:
             common.raise_http_conflict_for_instance_invalid_state(state_error,
                     'migrate')
         except exception.InstanceNotFound as e:
             raise exc.HTTPNotFound(explanation=e.format_message())
         except exception.NoValidHost as e:
             raise exc.HTTPBadRequest(explanation=e.format_message())
         except Exception as e:
             LOG.exception(_LE("Error in migrate %s"), e)
             raise exc.HTTPBadRequest()
         return webob.Response(status_int=202)
Example #30
0
    def _update_instance_metadata(self, context, server_id, metadata,
                                  delete=False):
        try:
            server = self.compute_api.get(context, server_id)
            return self.compute_api.update_instance_metadata(context,
                                                             server,
                                                             metadata,
                                                             delete)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except exception.InvalidMetadata as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())

        except exception.QuotaError as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message(),
                headers={'Retry-After': 0})

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'update metadata')
Example #31
0
    def _unshelve(self, req, id, body):
        """Restore an instance from shelved mode."""
        context = req.environ["nova.context"]
        context.can(shelve_policies.POLICY_ROOT % 'unshelve')
        instance = common.get_instance(self.compute_api, context, id)

        new_az = None
        unshelve_dict = body['unshelve']
        support_az = api_version_request.is_supported(req, '2.77')
        if support_az and unshelve_dict:
            new_az = unshelve_dict['availability_zone']

        # We could potentially move this check to conductor and avoid the
        # extra API call to neutron when we support move operations with ports
        # having resource requests.
        if (instance.vm_state == vm_states.SHELVED_OFFLOADED
                and common.instance_has_port_with_resource_request(
                    instance.uuid, self.network_api) and
                not common.supports_port_resource_request_during_move(req)):
            msg = _("The unshelve action on a server with ports having "
                    "resource requests, like a port with a QoS minimum "
                    "bandwidth policy, is not supported with this "
                    "microversion")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            self.compute_api.unshelve(context, instance, new_az=new_az)
        except (exception.InstanceIsLocked,
                exception.UnshelveInstanceInvalidState,
                exception.MismatchVolumeAZException) as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'unshelve', id)
        except exception.InvalidRequest as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #32
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""
        context = req.environ['nova.context']
        authorize(context, 'migrate')

        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       want_objects=True)
        try:
            self.compute_api.resize(req.environ['nova.context'], instance)
        except exception.TooManyInstances as e:
            raise exc.HTTPRequestEntityTooLarge(explanation=e.format_message())
        except exception.QuotaError as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message(), headers={'Retry-After': 0})
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'migrate')
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        return webob.Response(status_int=202)
Example #33
0
    def _resize(self, req, instance_id, flavor_id, **kwargs):
        """Begin the resize process with given instance/flavor."""
        context = req.environ["nova.context"]
        context.can(server_policies.SERVERS % 'resize')
        instance = self._get_server(context, req, instance_id)

        try:
            self.compute_api.resize(context, instance, flavor_id, **kwargs)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(
                explanation=error.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'resize', instance_id)
        except exception.ImageNotAuthorized:
            msg = _("You are not authorized to access the image "
                    "the instance was started with.")
            raise exc.HTTPUnauthorized(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Image that the instance was started "
                    "with could not be found.")
            raise exc.HTTPBadRequest(explanation=msg)
        except (exception.AutoDiskConfigDisabledByImage,
                exception.CannotResizeDisk,
                exception.CannotResizeToSameFlavor,
                exception.FlavorNotFound,
                exception.NoValidHost,
                exception.PciRequestAliasNotDefined) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.Invalid:
            msg = _("Invalid instance image.")
            raise exc.HTTPBadRequest(explanation=msg)
    def delete(self, req, server_id, id):
        """Detach an interface from an instance."""
        context = req.environ['nova.context']
        context.can(ai_policies.BASE_POLICY_NAME)
        context.can(ai_policies.POLICY_ROOT % 'delete')
        port_id = id

        instance = common.get_instance(self.compute_api,
                                       context,
                                       server_id,
                                       expected_attrs=['device_metadata'])
        try:
            self.compute_api.detach_interface(context,
                                              instance,
                                              port_id=port_id)
        except exception.PortNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            common.raise_feature_not_supported()
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'detach_interface', server_id)
    def delete(self, req, server_id, id):
        """Detach an interface from an instance."""
        context = req.environ['nova.context']
        authorize(context)
        port_id = id
        instance = common.get_instance(self.compute_api,
                                       context, server_id,
                                       want_objects=True)
        LOG.audit(_("Detach interface %s"), port_id, instance=instance)
        try:
            self.compute_api.detach_interface(context,
                instance, port_id=port_id)
        except exception.PortNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Network driver does not support this function.")
            raise webob.exc.HTTPNotImplemented(explanation=msg)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'detach_interface', server_id)

        return webob.Response(status_int=202)
Example #36
0
    def _resize(self, req, instance_id, flavor_id, **kwargs):
        """Begin the resize process with given instance/flavor."""
        context = req.environ["nova.context"]
        instance = self._get_server(context, req, instance_id)

        try:
            self.compute_api.resize(context, instance, flavor_id, **kwargs)
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message(),
                                    headers={'Retry-After': 0})
        except exception.FlavorNotFound:
            msg = _("Unable to locate requested flavor.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.CannotResizeToSameFlavor:
            msg = _("Resize requires a flavor change.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.CannotResizeDisk as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'resize')
        except exception.ImageNotAuthorized:
            msg = _("You are not authorized to access the image "
                    "the instance was started with.")
            raise exc.HTTPUnauthorized(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Image that the instance was started "
                    "with could not be found.")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.Invalid:
            msg = _("Invalid instance image.")
            raise exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #37
0
    def _action_reboot(self, req, id, body):
        if 'reboot' in body and 'type' in body['reboot']:
            valid_reboot_types = ['HARD', 'SOFT']
            reboot_type = body['reboot']['type'].upper()
            if not valid_reboot_types.count(reboot_type):
                msg = _("Argument 'type' for reboot is not HARD or SOFT")
                LOG.exception(msg)
                raise exc.HTTPBadRequest(explanation=msg)
        else:
            msg = _("Missing argument 'type' for reboot")
            LOG.exception(msg)
            raise exc.HTTPBadRequest(explanation=msg)

        context = req.environ['nova.context']
        instance = self._get_server(context, id)

        try:
            self.compute_api.reboot(context, instance, reboot_type)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'reboot')
        except Exception, e:
            LOG.exception(_("Error in reboot %s"), e)
            raise exc.HTTPUnprocessableEntity()
Example #38
0
    def _migrate_live(self, req, id, body):
        """Permit admins to (live) migrate a server to a new host."""
        context = req.environ["nova.context"]
        authorize(context, 'migrate_live')

        block_migration = body["os-migrateLive"]["block_migration"]
        disk_over_commit = body["os-migrateLive"]["disk_over_commit"]
        host = body["os-migrateLive"]["host"]

        block_migration = strutils.bool_from_string(block_migration,
                                                    strict=True)
        disk_over_commit = strutils.bool_from_string(disk_over_commit,
                                                     strict=True)

        try:
            instance = common.get_instance(self.compute_api,
                                           context,
                                           id,
                                           want_objects=True)
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host)
        except (exception.NoValidHost, exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType, exception.InvalidCPUInfo,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.InvalidLocalStorage, exception.InvalidSharedStorage,
                exception.HypervisorUnavailable, exception.InstanceNotRunning,
                exception.MigrationPreCheckError,
                exception.LiveMigrationWithOldNovaNotSafe) as ex:
            raise exc.HTTPBadRequest(explanation=ex.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'os-migrateLive')
        return webob.Response(status_int=202)
Example #39
0
    def delete(self, req, server_id, id):
        """Deletes an existing metadata."""
        context = req.environ['nova.context']

        metadata = self._get_metadata(context, server_id)

        if id not in metadata:
            msg = _("Metadata item was not found")
            raise exc.HTTPNotFound(explanation=msg)

        server = common.get_instance(self.compute_api, context, server_id)
        try:
            self.compute_api.delete_instance_metadata(context, server, id)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'delete metadata', server_id)
Example #40
0
    def _rescue(self, req, id, body):
        """Rescue an instance."""
        context = req.environ["nova.context"]
        authorize(context)

        if body['rescue'] and 'adminPass' in body['rescue']:
            password = body['rescue']['adminPass']
        else:
            password = utils.generate_password()

        instance = self._get_instance(context, id, want_objects=True)
        try:
            self.compute_api.rescue(context, instance,
                                    rescue_password=password)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                                                                  'rescue')
        except exception.InvalidVolume as volume_error:
            raise exc.HTTPConflict(explanation=volume_error.format_message())
        except exception.InstanceNotRescuable as non_rescuable:
            raise exc.HTTPBadRequest(
                explanation=non_rescuable.format_message())

        return {'adminPass': password}
Example #41
0
    def _update_instance_metadata(self,
                                  context,
                                  server_id,
                                  metadata,
                                  delete=False):
        try:
            server = self.compute_api.get(context,
                                          server_id,
                                          want_objects=True)
            return self.compute_api.update_instance_metadata(
                context, server, metadata, delete)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except (ValueError, AttributeError):
            msg = _("Malformed request body")
            raise exc.HTTPBadRequest(explanation=msg)

        except exception.InvalidMetadata as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())

        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'update metadata', server_id)
    def change_password(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        password = body['changePassword']['adminPass']
        instance = common.get_instance(self.compute_api, context, id)
        try:
            self.compute_api.set_admin_password(context, instance, password)
        except exception.InstancePasswordSetFailed as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as e:
            raise common.raise_http_conflict_for_instance_invalid_state(
                e, 'changePassword', id)
        except NotImplementedError:
            msg = _("Unable to set password on instance")
            common.raise_feature_not_supported(msg=msg)
    def change_password(self, req, id, body):
        context = req.environ['nova.context']
        authorize(context)

        password = body['change_password']['admin_password']
        try:
            instance = self.compute_api.get(context, id, want_objects=True)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        try:
            self.compute_api.set_admin_password(context, instance, password)
        except exception.InstancePasswordSetFailed as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as e:
            raise common.raise_http_conflict_for_instance_invalid_state(
                e, 'change_password')
        except NotImplementedError:
            msg = _("Unable to set password on instance")
            raise exc.HTTPNotImplemented(explanation=msg)
Example #44
0
    def change_password(self, req, id, body):
        context = req.environ['nova.context']
        instance = common.get_instance(self.compute_api, context, id)
        context.can(ap_policies.BASE_POLICY_NAME,
                    target={'project_id': instance.project_id})

        password = body['changePassword']['adminPass']
        try:
            self.compute_api.set_admin_password(context, instance, password)
        except (exception.InstancePasswordSetFailed,
                exception.SetAdminPasswdNotSupported,
                exception.InstanceAgentNotEnabled) as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as e:
            raise common.raise_http_conflict_for_instance_invalid_state(
                e, 'changePassword', id)
        except NotImplementedError:
            msg = _("Unable to set password on instance")
            common.raise_feature_not_supported(msg=msg)
Example #45
0
    def _action_change_password(self, req, id, body):
        context = req.environ['nova.context']
        if (not body.get('changePassword')
                or 'adminPass' not in body['changePassword']):
            msg = _("No adminPass was specified")
            raise exc.HTTPBadRequest(explanation=msg)
        password = self._get_server_admin_password(body['changePassword'])

        server = self._get_server(context, req, id)
        try:
            self.compute_api.set_admin_password(context, server, password)
        except exception.InstancePasswordSetFailed as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as e:
            raise common.raise_http_conflict_for_instance_invalid_state(
                e, 'changePassword', id)
        except NotImplementedError:
            msg = _("Unable to set password on instance")
            raise exc.HTTPNotImplemented(explanation=msg)
        return webob.Response(status_int=202)
Example #46
0
 def change_password(self, req, id, body):
     context = req.environ['nova.context']
     authorize(context)
     if 'admin_password' not in body['change_password']:
         msg = _("No admin_password was specified")
         raise exc.HTTPBadRequest(explanation=msg)
     password = body['change_password']['admin_password']
     if not isinstance(password, basestring):
         msg = _("Invalid admin password")
         raise exc.HTTPBadRequest(explanation=msg)
     try:
         instance = self.compute_api.get(context, id)
     except exception.InstanceNotFound as e:
         raise exc.HTTPNotFound(explanation=e.format_message())
     try:
         self.compute_api.set_admin_password(context, instance, password)
     except exception.InstancePasswordSetFailed as e:
         raise exc.HTTPConflict(explanation=e.format_message())
     except exception.InstanceInvalidState as e:
         raise common.raise_http_conflict_for_instance_invalid_state(
             e, 'change_password')
     except NotImplementedError:
         msg = _("Unable to set password on instance")
         raise exc.HTTPNotImplemented(explanation=msg)
    def _action_rebuild(self, req, id, body):
        """Rebuild an instance with the given attributes"""
        try:
            body = body['rebuild']
        except (KeyError, TypeError):
            raise exc.HTTPBadRequest(_("Invalid request body"))

        try:
            image_href = body["imageRef"]
        except (KeyError, TypeError):
            msg = _("Could not parse imageRef from request.")
            raise exc.HTTPBadRequest(explanation=msg)

        image_href = self._image_uuid_from_href(image_href)

        try:
            password = body['adminPass']
        except (KeyError, TypeError):
            password = utils.generate_password(FLAGS.password_length)

        context = req.environ['nova.context']
        instance = self._get_server(context, id)

        attr_map = {
            'personality': 'files_to_inject',
            'name': 'display_name',
            'accessIPv4': 'access_ip_v4',
            'accessIPv6': 'access_ip_v6',
            'metadata': 'metadata',
            'auto_disk_config': 'auto_disk_config',
        }

        if 'accessIPv4' in body:
            self._validate_access_ipv4(body['accessIPv4'])

        if 'accessIPv6' in body:
            self._validate_access_ipv6(body['accessIPv6'])

        kwargs = {}

        for request_attribute, instance_attribute in attr_map.items():
            try:
                kwargs[instance_attribute] = body[request_attribute]
            except (KeyError, TypeError):
                pass

        self._validate_metadata(kwargs.get('metadata', {}))

        if 'files_to_inject' in kwargs:
            personality = kwargs['files_to_inject']
            kwargs['files_to_inject'] = self._get_injected_files(personality)

        try:
            self.compute_api.rebuild(context, instance, image_href, password,
                                     **kwargs)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'rebuild')
        except exception.InstanceNotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Cannot find image for rebuild")
            raise exc.HTTPBadRequest(explanation=msg)

        instance = self._get_server(context, id)

        self._add_instance_faults(context, [instance])
        view = self._view_builder.show(req, instance)

        # Add on the adminPass attribute since the view doesn't do it
        # unless instance passwords are disabled
        if FLAGS.enable_instance_password:
            view['server']['adminPass'] = password

        robj = wsgi.ResponseObject(view)
        return self._add_location(robj)
Example #48
0
    def _evacuate(self, req, id, body):
        """Permit admins to evacuate a server from a failed host
        to a new one.
        If host is empty, the scheduler will select one.
        """
        context = req.environ["nova.context"]
        authorize(context)

        if not self.is_valid_body(body, "evacuate"):
            raise exc.HTTPBadRequest(_("Malformed request body"))
        evacuate_body = body["evacuate"]

        host = evacuate_body.get("host")

        if (not host and
                not self.ext_mgr.is_loaded('os-extended-evacuate-find-host')):
            msg = _("host must be specified.")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            on_shared_storage = strutils.bool_from_string(
                evacuate_body["onSharedStorage"])
        except (TypeError, KeyError):
            msg = _("onSharedStorage must be specified.")
            raise exc.HTTPBadRequest(explanation=msg)

        password = None
        if 'adminPass' in evacuate_body:
            # check that if requested to evacuate server on shared storage
            # password not specified
            if on_shared_storage:
                msg = _("admin password can't be changed on existing disk")
                raise exc.HTTPBadRequest(explanation=msg)

            password = evacuate_body['adminPass']
        elif not on_shared_storage:
            password = utils.generate_password()

        if host is not None:
            try:
                self.host_api.service_get_by_compute_host(context, host)
            except exception.NotFound:
                msg = _("Compute host %s not found.") % host
                raise exc.HTTPNotFound(explanation=msg)

        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       want_objects=True)
        try:
            if instance.host == host:
                msg = _("The target host can't be the same one.")
                raise exc.HTTPBadRequest(explanation=msg)
            self.compute_api.evacuate(context, instance, host,
                                      on_shared_storage, password)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'evacuate', id)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.ComputeServiceInUse as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())

        if password:
            return {'adminPass': password}
Example #49
0
    def _migrate_live(self, req, id, body):
        """Permit admins to (live) migrate a server to a new host."""
        context = req.environ["nova.context"]
        context.can(ms_policies.POLICY_ROOT % 'migrate_live')

        host = body["os-migrateLive"]["host"]
        block_migration = body["os-migrateLive"]["block_migration"]
        force = None
        async_ = api_version_request.is_supported(req, min_version='2.34')
        if api_version_request.is_supported(req, min_version='2.30'):
            force = self._get_force_param_for_live_migration(body, host)
        if api_version_request.is_supported(req, min_version='2.25'):
            if block_migration == 'auto':
                block_migration = None
            else:
                block_migration = strutils.bool_from_string(block_migration,
                                                            strict=True)
            disk_over_commit = None
        else:
            disk_over_commit = body["os-migrateLive"]["disk_over_commit"]

            block_migration = strutils.bool_from_string(block_migration,
                                                        strict=True)
            disk_over_commit = strutils.bool_from_string(disk_over_commit,
                                                         strict=True)

        # NOTE(stephenfin): we need 'numa_topology' because of the
        # 'LiveMigrationTask._check_instance_has_no_numa' check in the
        # conductor
        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       expected_attrs=['numa_topology'])

        # We could potentially move this check to conductor and avoid the
        # extra API call to neutron when we support move operations with ports
        # having resource requests.
        if (common.instance_has_port_with_resource_request(
                context, instance.uuid, self.network_api) and
                not common.supports_port_resource_request_during_move(req)):
            msg = _("The os-migrateLive action on a server with ports having "
                    "resource requests, like a port with a QoS minimum "
                    "bandwidth policy, is not supported with this "
                    "microversion")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host, force,
                                          async_)
        except (exception.NoValidHost, exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType, exception.InvalidCPUInfo,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.InvalidLocalStorage, exception.InvalidSharedStorage,
                exception.HypervisorUnavailable,
                exception.MigrationPreCheckError) as ex:
            if async_:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        "Unexpected exception received from "
                        "conductor during pre-live-migration checks "
                        "'%(ex)s'", {'ex': ex})
            else:
                raise exc.HTTPBadRequest(explanation=ex.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.ComputeHostNotFound as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'os-migrateLive', id)
Example #50
0
    def _action_rebuild(self, req, id, body):
        """Rebuild an instance with the given attributes."""
        body = body['rebuild']

        try:
            image_href = body["imageRef"]
        except (KeyError, TypeError):
            msg = _("Could not parse imageRef from request.")
            raise exc.HTTPBadRequest(explanation=msg)

        image_href = self._image_uuid_from_href(image_href)

        password = self._get_server_admin_password(body)

        context = req.environ['nova.context']
        instance = self._get_server(context, req, id)

        attr_map = {
            'personality': 'files_to_inject',
            'name': 'display_name',
            'accessIPv4': 'access_ip_v4',
            'accessIPv6': 'access_ip_v6',
            'metadata': 'metadata',
            'auto_disk_config': 'auto_disk_config',
        }

        kwargs = {}

        # take the preserve_ephemeral value into account only when the
        # corresponding extension is active
        if (self.ext_mgr.is_loaded('os-preserve-ephemeral-rebuild')
                and 'preserve_ephemeral' in body):
            kwargs['preserve_ephemeral'] = strutils.bool_from_string(
                body['preserve_ephemeral'], strict=True)

        if 'accessIPv4' in body:
            self._validate_access_ipv4(body['accessIPv4'])

        if 'accessIPv6' in body:
            self._validate_access_ipv6(body['accessIPv6'])

        if 'name' in body:
            self._validate_server_name(body['name'])

        for request_attribute, instance_attribute in attr_map.items():
            try:
                kwargs[instance_attribute] = body[request_attribute]
            except (KeyError, TypeError):
                pass

        self._validate_metadata(kwargs.get('metadata', {}))

        if 'files_to_inject' in kwargs:
            personality = kwargs.pop('files_to_inject')
            files_to_inject = self._get_injected_files(personality)
        else:
            files_to_inject = None

        try:
            self.compute_api.rebuild(context,
                                     instance,
                                     image_href,
                                     password,
                                     files_to_inject=files_to_inject,
                                     **kwargs)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'rebuild', id)
        except exception.InstanceNotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())
        except exception.ImageNotFound:
            msg = _("Cannot find image for rebuild")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())
        except (exception.ImageNotActive, exception.FlavorDiskTooSmall,
                exception.FlavorMemoryTooSmall, exception.InvalidMetadata,
                exception.AutoDiskConfigDisabledByImage) as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        instance = self._get_server(context, req, id)

        view = self._view_builder.show(req, instance)

        # Add on the adminPass attribute since the view doesn't do it
        # unless instance passwords are disabled
        if CONF.enable_instance_password:
            view['server']['adminPass'] = password

        robj = wsgi.ResponseObject(view)
        return self._add_location(robj)
Example #51
0
    def create(self, req, server_id, body):
        """Attach an interface to an instance."""
        context = req.environ['nova.context']
        instance = common.get_instance(self.compute_api, context, server_id)

        context.can(ai_policies.POLICY_ROOT % 'create',
                    target={'project_id': instance.project_id})

        network_id = None
        port_id = None
        req_ip = None
        tag = None
        if body:
            attachment = body['interfaceAttachment']
            network_id = attachment.get('net_id', None)
            port_id = attachment.get('port_id', None)
            tag = attachment.get('tag', None)
            try:
                req_ip = attachment['fixed_ips'][0]['ip_address']
            except Exception:
                pass

        if network_id and port_id:
            msg = _("Must not input both network_id and port_id")
            raise exc.HTTPBadRequest(explanation=msg)
        if req_ip and not network_id:
            msg = _("Must input network_id when request IP address")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            vif = self.compute_api.attach_interface(context,
                instance, network_id, port_id, req_ip, tag=tag)
        except (exception.InterfaceAttachFailedNoNetwork,
                exception.NetworkAmbiguous,
                exception.NoMoreFixedIps,
                exception.PortNotUsable,
                exception.AttachInterfaceNotSupported,
                exception.SecurityGroupCannotBeApplied,
                exception.NetworkInterfaceTaggedAttachNotSupported,
                exception.NetworksWithQoSPolicyNotSupported,
                exception.InterfaceAttachPciClaimFailed,
                exception.InterfaceAttachResourceAllocationFailed,
                exception.ForbiddenPortsWithAccelerator,
                exception.ExtendedResourceRequestOldCompute,
                ) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except (
            exception.InstanceIsLocked,
            exception.FixedIpAlreadyInUse,
            exception.PortInUse,
        ) as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except (exception.PortNotFound,
                exception.NetworkNotFound) as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.PortLimitExceeded as e:
            raise exc.HTTPForbidden(explanation=e.format_message())
        except exception.InterfaceAttachFailed as e:
            raise webob.exc.HTTPInternalServerError(
                explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'attach_interface', server_id)

        return self.show(req, server_id, vif['id'])
Example #52
0
    def _action_rebuild(self, req, id, body):
        """Rebuild an instance with the given attributes."""
        rebuild_dict = body['rebuild']

        image_href = rebuild_dict["imageRef"]
        image_href = self._image_uuid_from_href(image_href)

        password = self._get_server_admin_password(rebuild_dict)

        context = req.environ['nova.context']
        instance = self._get_server(context, req, id)

        attr_map = {
            'name': 'display_name',
            'metadata': 'metadata',
        }

        rebuild_kwargs = {}

        if list(self.rebuild_extension_manager):
            self.rebuild_extension_manager.map(self._rebuild_extension_point,
                                               rebuild_dict, rebuild_kwargs)

        for request_attribute, instance_attribute in attr_map.items():
            try:
                rebuild_kwargs[instance_attribute] = rebuild_dict[
                    request_attribute]
            except (KeyError, TypeError):
                pass

        try:
            self.compute_api.rebuild(context, instance, image_href, password,
                                     **rebuild_kwargs)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'rebuild', id)
        except exception.InstanceNotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
        except exception.ImageNotFound:
            msg = _("Cannot find image for rebuild")
            raise exc.HTTPBadRequest(explanation=msg)
        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())
        except (exception.ImageNotActive, exception.FlavorDiskTooSmall,
                exception.FlavorMemoryTooSmall, exception.InvalidMetadata,
                exception.AutoDiskConfigDisabledByImage) as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        instance = self._get_server(context, req, id)

        view = self._view_builder.show(req, instance)

        # Add on the admin_password attribute since the view doesn't do it
        # unless instance passwords are disabled
        if CONF.enable_instance_password:
            view['server']['adminPass'] = password

        robj = wsgi.ResponseObject(view)
        return self._add_location(robj)
Example #53
0
    def _migrate_extend(self, req, id, body):
        """Permit admin to migrate a server to a new host lively."""
        if not self._get_ics_session():
            return dict(vms=[], error='CANNOT_CONNECT_ICS')

        if not id:
            return dict(vms=[], error='VM_ID_NULL')
        try:
            vm_info = self.ics_manager.vm.get_info(id)
        except exception as e:
            return {
                "success": False,
                "message": "Vm is not found and get vm_info has errors"
            }
        nodeTarget = body["migrateExtend"]["nodeTarget"]
        if vm_info:
            if vm_info['migratable'] == False:
                return {
                    'success': False,
                    'code': '300089',
                    "message": 'The vm is not allowed to migrate'
                }
            if vm_info['hostId'] == nodeTarget:
                return {
                    'success':
                    False,
                    'code':
                    '300090',
                    "message":
                    'The hostId which vm belongs is same as the target_hostId, Please check'
                }
        context = req.environ['nova.context']

        #        if not hostInfo or hostInfo['id']:
        #            return {'success': False, "vmId": id, "hostId": nodeTarget, "result": "HOST IS NULL"}
        #        instance = common.get_instance(self.compute_api, context, id)
        hostInfo = None
        try:
            # make sure the target host is exist or not
            hostInfo = self.ics_manager.host.get_host(nodeTarget)
            if hostInfo.get('code'):
                return {
                    'success': False,
                    "vmId": id,
                    "hostId": nodeTarget,
                    "result": hostInfo['message']
                }
            # do the migration
            result = self.ics_manager.vm.live_migrate(id, nodeTarget)
            res = {
                'success': True,
                "vmId": id,
                "hostId": nodeTarget,
                "result": result
            }
            return dict(migrateExtend=res)
#            body = self.ics_manager.vm.get_info(self, '0557ec0b_4e52_4228_a067_e6a7699ebe97')
#            result = self.ics_manager.host.get_host('5d85f39c-ef38-4bc3-991a-6f250b32221f')
#            print json.dumps(result) + "\n\n"
        except (exception.TooManyInstances, exception.QuotaError) as e:
            raise exc.HTTPForbidden(explanation=e.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'migrateExtend', id)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.NoValidHost as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
Example #54
0
    def _evacuate(self, req, id, body):
        """Permit admins to evacuate a server from a failed host
        to a new one.
        """
        context = req.environ["nova.context"]
        instance = common.get_instance(self.compute_api, context, id)
        context.can(evac_policies.BASE_POLICY_NAME,
                    target={
                        'user_id': instance.user_id,
                        'project_id': instance.project_id
                    })

        evacuate_body = body["evacuate"]
        host = evacuate_body.get("host")
        force = None

        on_shared_storage = self._get_on_shared_storage(req, evacuate_body)

        if api_version_request.is_supported(req, min_version='2.29'):
            force = body["evacuate"].get("force", False)
            force = strutils.bool_from_string(force, strict=True)
            if force is True and not host:
                message = _("Can't force to a non-provided destination")
                raise exc.HTTPBadRequest(explanation=message)
        if api_version_request.is_supported(req, min_version='2.14'):
            password = self._get_password_v214(req, evacuate_body)
        else:
            password = self._get_password(req, evacuate_body,
                                          on_shared_storage)

        if host is not None:
            try:
                self.host_api.service_get_by_compute_host(context, host)
            except (exception.ComputeHostNotFound,
                    exception.HostMappingNotFound):
                msg = _("Compute host %s not found.") % host
                raise exc.HTTPNotFound(explanation=msg)

        if instance.host == host:
            msg = _("The target host can't be the same one.")
            raise exc.HTTPBadRequest(explanation=msg)

        if (common.instance_has_port_with_resource_request(
                context, instance.uuid, self.network_api) and
                not common.supports_port_resource_request_during_move(req)):
            msg = _("The evacuate server operation with port having QoS "
                    "policy is not supported.")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            self.compute_api.evacuate(context, instance, host,
                                      on_shared_storage, password, force)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'evacuate', id)
        except exception.ComputeServiceInUse as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())

        if (not api_version_request.is_supported(req, min_version='2.14')
                and CONF.api.enable_instance_password):
            return {'adminPass': password}
        else:
            return None
Example #55
0
    def _evacuate(self, req, id, body):
        """Permit admins to evacuate a server from a failed host
        to a new one.
        """
        context = req.environ["nova.context"]
        instance = common.get_instance(self.compute_api, context, id)
        context.can(evac_policies.BASE_POLICY_NAME,
                    target={'user_id': instance.user_id,
                            'project_id': instance.project_id})

        evacuate_body = body["evacuate"]
        host = evacuate_body.get("host")
        force = None

        on_shared_storage = self._get_on_shared_storage(req, evacuate_body)

        if api_version_request.is_supported(req, min_version='2.29'):
            force = body["evacuate"].get("force", False)
            force = strutils.bool_from_string(force, strict=True)
            if force is True and not host:
                message = _("Can't force to a non-provided destination")
                raise exc.HTTPBadRequest(explanation=message)
        if api_version_request.is_supported(req, min_version='2.14'):
            password = self._get_password_v214(req, evacuate_body)
        else:
            password = self._get_password(req, evacuate_body,
                                          on_shared_storage)

        if host is not None:
            try:
                self.host_api.service_get_by_compute_host(context, host)
            except (exception.ComputeHostNotFound,
                    exception.HostMappingNotFound):
                msg = _("Compute host %s not found.") % host
                raise exc.HTTPNotFound(explanation=msg)

        if instance.host == host:
            msg = _("The target host can't be the same one.")
            raise exc.HTTPBadRequest(explanation=msg)

        # We could potentially move this check to conductor and avoid the
        # extra API call to neutron when we support move operations with ports
        # having resource requests.
        if (common.instance_has_port_with_resource_request(
                instance.uuid, self.network_api) and not
                common.supports_port_resource_request_during_move()):
            LOG.warning("The evacuate action on a server with ports "
                        "having resource requests, like a port with a QoS "
                        "minimum bandwidth policy, is not supported until "
                        "every nova-compute is upgraded to Ussuri")
            msg = _("The evacuate action on a server with ports having "
                    "resource requests, like a port with a QoS minimum "
                    "bandwidth policy, is not supported by this cluster right "
                    "now")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            self.compute_api.evacuate(context, instance, host,
                                      on_shared_storage, password, force)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'evacuate', id)
        except exception.ComputeServiceInUse as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.ForbiddenWithAccelerators as e:
            raise exc.HTTPForbidden(explanation=e.format_message())
        except exception.OperationNotSupportedForVTPM as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        if (not api_version_request.is_supported(req, min_version='2.14') and
                CONF.api.enable_instance_password):
            return {'adminPass': password}
        else:
            return None
Example #56
0
                                             state='fake_state',
                                             method='fake_method')
        try:
            common.raise_http_conflict_for_instance_invalid_state(exc, 'meow')
        except Exception, e:
            self.assertTrue(isinstance(e, webob.exc.HTTPConflict))
            msg = str(e)
            self.assertEqual(
                msg, "Cannot 'meow' while instance is in fake_attr fake_state")
        else:
            self.fail("webob.exc.HTTPConflict was not raised")

        # Incorrect args
        exc = exception.InstanceInvalidState()
        try:
            common.raise_http_conflict_for_instance_invalid_state(exc, 'meow')
        except Exception, e:
            self.assertTrue(isinstance(e, webob.exc.HTTPConflict))
            msg = str(e)
            self.assertEqual(msg, "Instance is in an invalid state for 'meow'")
        else:
            self.fail("webob.exc.HTTPConflict was not raised")

    def test_check_img_metadata_properties_quota_valid_metadata(self):
        ctxt = test_utils.get_test_admin_context()
        metadata1 = {"key": "value"}
        actual = common.check_img_metadata_properties_quota(ctxt, metadata1)
        self.assertEqual(actual, None)

        metadata2 = {"key": "v" * 260}
        actual = common.check_img_metadata_properties_quota(ctxt, metadata2)
Example #57
0
    def _migrate_live(self, req, id, body):
        """Permit admins to (live) migrate a server to a new host."""
        context = req.environ["nova.context"]

        # NOTE(stephenfin): we need 'numa_topology' because of the
        # 'LiveMigrationTask._check_instance_has_no_numa' check in the
        # conductor
        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       expected_attrs=['numa_topology'])

        context.can(ms_policies.POLICY_ROOT % 'migrate_live',
                    target={'project_id': instance.project_id})

        host = body["os-migrateLive"]["host"]
        block_migration = body["os-migrateLive"]["block_migration"]
        force = None
        async_ = api_version_request.is_supported(req, min_version='2.34')
        if api_version_request.is_supported(req, min_version='2.30'):
            force = self._get_force_param_for_live_migration(body, host)
        if api_version_request.is_supported(req, min_version='2.25'):
            if block_migration == 'auto':
                block_migration = None
            else:
                block_migration = strutils.bool_from_string(block_migration,
                                                            strict=True)
            disk_over_commit = None
        else:
            disk_over_commit = body["os-migrateLive"]["disk_over_commit"]

            block_migration = strutils.bool_from_string(block_migration,
                                                        strict=True)
            disk_over_commit = strutils.bool_from_string(disk_over_commit,
                                                         strict=True)

        try:
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host, force,
                                          async_)
        except (exception.NoValidHost, exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType, exception.InvalidCPUInfo,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.InvalidLocalStorage, exception.InvalidSharedStorage,
                exception.HypervisorUnavailable,
                exception.MigrationPreCheckError,
                exception.ForbiddenPortsWithAccelerator) as ex:
            if async_:
                with excutils.save_and_reraise_exception():
                    LOG.error(
                        "Unexpected exception received from "
                        "conductor during pre-live-migration checks "
                        "'%(ex)s'", {'ex': ex})
            else:
                raise exc.HTTPBadRequest(explanation=ex.format_message())
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except (
                exception.ComputeHostNotFound,
                exception.ExtendedResourceRequestOldCompute,
        ) as e:
            raise exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'os-migrateLive', id)
Example #58
0
    def _create_backup(self, req, id, body):
        """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.

        """
        context = req.environ["nova.context"]
        authorize(context, 'createBackup')
        entity = body["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 exc.HTTPBadRequest(explanation=msg)

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

        try:
            rotation = int(rotation)
        except ValueError:
            msg = _("createBackup attribute 'rotation' must be an integer")
            raise exc.HTTPBadRequest(explanation=msg)
        if rotation < 0:
            msg = _("createBackup attribute 'rotation' must be greater "
                    "than or equal to zero")
            raise exc.HTTPBadRequest(explanation=msg)

        props = {}
        metadata = entity.get('metadata', {})
        common.check_img_metadata_properties_quota(context, metadata)
        try:
            props.update(metadata)
        except ValueError:
            msg = _("Invalid metadata")
            raise exc.HTTPBadRequest(explanation=msg)

        try:
            instance = self.compute_api.get(context, id, want_objects=True)
        except exception.NotFound:
            msg = _("Instance not found")
            raise exc.HTTPNotFound(explanation=msg)

        try:
            image = self.compute_api.backup(context,
                                            instance,
                                            image_name,
                                            backup_type,
                                            rotation,
                                            extra_properties=props)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'createBackup')

        resp = webob.Response(status_int=202)

        # build location of newly-created image entity if rotation is not zero
        if rotation > 0:
            image_id = str(image['id'])
            image_ref = os.path.join(req.application_url, 'images', image_id)
            resp.headers['Location'] = image_ref

        return resp
Example #59
0
    def _action_create_image(self, req, id, body):
        """Snapshot a server instance."""
        context = req.environ['nova.context']
        entity = body.get("createImage", {})

        image_name = entity.get("name")

        if not image_name:
            msg = _("createImage entity requires name attribute")
            raise exc.HTTPBadRequest(explanation=msg)

        props = {}
        metadata = entity.get('metadata', {})
        common.check_img_metadata_properties_quota(context, metadata)
        try:
            props.update(metadata)
        except ValueError:
            msg = _("Invalid metadata")
            raise exc.HTTPBadRequest(explanation=msg)

        instance = self._get_server(context, req, id)

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
            context, instance.uuid)

        try:
            if self.compute_api.is_volume_backed_instance(
                    context, instance, bdms):
                img = instance.image_ref
                if not img:
                    properties = bdms.root_metadata(
                        context, self.compute_api.image_api,
                        self.compute_api.volume_api)
                    image_meta = {'properties': properties}
                else:
                    image_meta = self.compute_api.image_api.get(context, img)

                image = self.compute_api.snapshot_volume_backed(
                    context,
                    instance,
                    image_meta,
                    image_name,
                    extra_properties=props)
            else:
                image = self.compute_api.snapshot(context,
                                                  instance,
                                                  image_name,
                                                  extra_properties=props)
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'createImage', id)
        except exception.Invalid as err:
            raise exc.HTTPBadRequest(explanation=err.format_message())

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

        resp = webob.Response(status_int=202)
        resp.headers['Location'] = image_ref
        return resp
Example #60
0
    def detach(self, req, id, body):
        server_id = id
        context = req.environ['nova.context']
        authorize_detach(context)

        if not self.is_valid_body(body, 'detach'):
            raise exc.HTTPBadRequest(_("The request body invalid"))
        try:
            volume_id = body['detach']['volume_id']
        except KeyError:
            raise exc.HTTPBadRequest(
                _("Could not find volume_id from request"
                  "parameter"))
        self._validate_volume_id(volume_id)
        LOG.audit(
            _("Detach volume %(volume_id)s from "
              "instance %(server_id)s"), {
                  "volume_id": volume_id,
                  "server_id": id,
                  "context": context
              })
        try:
            instance = self.compute_api.get(context, server_id)
        except exception.InstanceNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())

        try:
            volume = self.volume_api.get(context, volume_id)
        except exception.VolumeNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())

        bdms = self.compute_api.get_instance_bdms(context, instance)
        if not bdms:
            msg = _("Volume %(volume_id)s is not attached to the "
                    "instance %(server_id)s") % {
                        'server_id': server_id,
                        'volume_id': volume_id
                    }
            LOG.debug(msg)
            raise exc.HTTPNotFound(explanation=msg)

        for bdm in bdms:
            if bdm['volume_id'] != volume_id:
                continue
            try:
                self.compute_api.detach_volume(context, instance, volume)
                break
            except exception.VolumeUnattached:
                # The volume is not attached.  Treat it as NotFound
                # by falling through.
                pass
            except exception.InvalidVolume as e:
                raise exc.HTTPBadRequest(explanation=e.format_message())
            except exception.InstanceInvalidState as state_error:
                common.raise_http_conflict_for_instance_invalid_state(
                    state_error, 'detach_volume')
        else:
            msg = _("Volume %(volume_id)s is not attached to the "
                    "instance %(server_id)s") % {
                        'server_id': server_id,
                        'volume_id': volume_id
                    }
            raise exc.HTTPNotFound(explanation=msg)