Example #1
0
    def show(self, req, server_id, id):
        """Return the migration of an instance in progress by id."""
        context = req.environ['nova.context']
        authorize(context, action="show")

        # NOTE(Shaohe Feng) just check the instance is available. To keep
        # consistency with other API, check it before get migrations.
        common.get_instance(self.compute_api, context, server_id)

        try:
            migration = self.compute_api.get_migration_by_id_and_instance(
                    context, id, server_id)
        except exception.MigrationNotFoundForInstance:
            msg = _("In-progress live migration %(id)s is not found for"
                    " server %(uuid)s.") % {"id": id, "uuid": server_id}
            raise exc.HTTPNotFound(explanation=msg)

        if migration.get("migration_type") != "live-migration":
            msg = _("Migration %(id)s for server %(uuid)s is not"
                    " live-migration.") % {"id": id, "uuid": server_id}
            raise exc.HTTPNotFound(explanation=msg)

        # TODO(Shaohe Feng) we should share the in-progress list.
        in_progress = ['queued', 'preparing', 'running', 'post-migrating']
        if migration.get("status") not in in_progress:
            msg = _("Live migration %(id)s for server %(uuid)s is not in"
                    " progress.") % {"id": id, "uuid": server_id}
            raise exc.HTTPNotFound(explanation=msg)

        return {'migration': output(migration)}
Example #2
0
    def show(self, req, server_id, id):
        """Return data about the given interface attachment."""
        context = req.environ['nova.context']
        authorize(context)

        port_id = id
        # NOTE(mriedem): We need to verify the instance actually exists from
        # the server_id even though we're not using the instance for anything,
        # just the port id.
        common.get_instance(self.compute_api, context, server_id)

        try:
            port_info = self.network_api.show_port(context, port_id)
        except exception.NotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except exception.Forbidden as e:
            raise exc.HTTPForbidden(explanation=e.format_message())

        if port_info['port']['device_id'] != server_id:
            msg = _("Instance %(instance)s does not have a port with id "
                    "%(port)s") % {'instance': server_id, 'port': port_id}
            raise exc.HTTPNotFound(explanation=msg)

        return {'interfaceAttachment': _translate_interface_attachment_view(
                port_info['port'])}
Example #3
0
    def index(self, req, server_id):
        """Return all migrations of an instance in progress."""
        context = req.environ['nova.context']
        authorize(context, action="index")

        # NOTE(Shaohe Feng) just check the instance is available. To keep
        # consistency with other API, check it before get migrations.
        common.get_instance(self.compute_api, context, server_id)

        migrations = self.compute_api.get_migrations_in_progress_by_instance(
                context, server_id, 'live-migration')

        return {'migrations': [output(migration) for migration in migrations]}
Example #4
0
    def index(self, req, server_id):
        """Return all migrations of an instance in progress."""
        context = req.environ['nova.context']
        context.can(sm_policies.POLICY_ROOT % 'index')

        # NOTE(Shaohe Feng) just check the instance is available. To keep
        # consistency with other API, check it before get migrations.
        common.get_instance(self.compute_api, context, server_id)

        migrations = self.compute_api.get_migrations_in_progress_by_instance(
                context, server_id, 'live-migration')

        include_uuid = api_version_request.is_supported(req, '2.59')
        return {'migrations': [output(
            migration, include_uuid) for migration in migrations]}
Example #5
0
    def get_rdp_console(self, req, id, body):
        """Get text console output."""
        context = req.environ['nova.context']
        authorize(context)

        # If type is not supplied or unknown, get_rdp_console below will cope
        console_type = body['os-getRDPConsole'].get('type')

        instance = common.get_instance(self.compute_api, context, id)
        try:
            # NOTE(mikal): get_rdp_console() can raise InstanceNotFound, so
            # we still need to catch it here.
            output = self.compute_api.get_rdp_console(context,
                                                      instance,
                                                      console_type)
        except exception.ConsoleTypeUnavailable as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            common.raise_feature_not_supported()

        return {'console': {'type': console_type, 'url': output['url']}}
Example #6
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 #7
0
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller."""
        if not self.is_valid_body(body, 'server'):
            raise exc.HTTPBadRequest(_("The request body is invalid"))

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

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

        if 'host_id' in body['server']:
            msg = _("host_id cannot be updated.")
            raise exc.HTTPBadRequest(explanation=msg)

        if list(self.update_extension_manager):
            self.update_extension_manager.map(self._update_extension_point,
                                              body['server'], update_dict)

        instance = common.get_instance(self.compute_api, ctxt, id,
                                       want_objects=True,
                                       expected_attrs=['pci_devices'])
        try:
            # NOTE(mikal): this try block needs to stay because save() still
            # might throw an exception.
            req.cache_db_instance(instance)
            policy.enforce(ctxt, 'compute:update', instance)
            instance.update(update_dict)
            instance.save()
            return self._view_builder.show(req, instance)
        except exception.NotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
    def _reset_state(self, req, id, body):
        """Permit admins to reset the state of a server."""
        context = req.environ["nova.context"]
        authorize(context, 'resetState')

        # Identify the desired state from the body
        try:
            state = state_map[body["os-resetState"]["state"]]
        except (TypeError, KeyError):
            msg = _("Desired state must be specified.  Valid states "
                    "are: %s") % ', '.join(sorted(state_map.keys()))
            raise exc.HTTPBadRequest(explanation=msg)

        instance = common.get_instance(self.compute_api, context, id)
        try:
            instance.vm_state = state
            instance.task_state = None
            instance.save(admin_state_reset=True)
        except exception.InstanceNotFound:
            msg = _("Server not found")
            raise exc.HTTPNotFound(explanation=msg)
        except Exception:
            readable = traceback.format_exc()
            LOG.exception(_LE("Compute.api::resetState %s"), readable)
            raise exc.HTTPUnprocessableEntity()
        return webob.Response(status_int=202)
Example #9
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 #10
0
    def get_serial_console(self, req, id, body):
        """Get connection to a serial console."""
        context = req.environ['nova.context']
        authorize(context)

        # If type is not supplied or unknown get_serial_console below will cope
        console_type = body['os-getSerialConsole'].get('type')
        try:
            instance = common.get_instance(self.compute_api, context, id)
            output = self.compute_api.get_serial_console(context,
                                                         instance,
                                                         console_type)
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except (exception.ConsoleTypeUnavailable,
                exception.ImageSerialPortNumberInvalid,
                exception.ImageSerialPortNumberExceedFlavorValue,
                exception.SocketPortRangeExhaustedException) as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except NotImplementedError:
            common.raise_feature_not_supported()

        return {'console': {'type': console_type, 'url': output['url']}}
Example #11
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 #12
0
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller."""

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

        if 'name' in body['server']:
            update_dict['display_name'] = body['server']['name']

        # TODO(oomichi): The following host_id validation code can be removed
        # when setting "'additionalProperties': False" in base_update schema.
        if 'host_id' in body['server']:
            msg = _("host_id cannot be updated.")
            raise exc.HTTPBadRequest(explanation=msg)

        if list(self.update_extension_manager):
            self.update_extension_manager.map(self._update_extension_point,
                                              body['server'], update_dict)

        instance = common.get_instance(self.compute_api, ctxt, id,
                                       want_objects=True,
                                       expected_attrs=['pci_devices'])
        try:
            # NOTE(mikal): this try block needs to stay because save() still
            # might throw an exception.
            req.cache_db_instance(instance)
            policy.enforce(ctxt, 'compute:update', instance)
            instance.update(update_dict)
            instance.save()
            return self._view_builder.show(req, instance)
        except exception.NotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
Example #13
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 #14
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 #15
0
    def get_spice_console(self, req, id, body):
        """Get text console output."""
        context = req.environ['nova.context']
        authorize(context)

        # If type is not supplied or unknown, get_spice_console below will cope
        console_type = body['os-getSPICEConsole'].get('type')

        try:
            instance = common.get_instance(self.compute_api, context, id)
            output = self.compute_api.get_spice_console(context,
                                                        instance,
                                                        console_type)
        except exception.ConsoleTypeUnavailable as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Unable to get spice console, "
                    "functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return {'console': {'type': console_type, 'url': output['url']}}
Example #16
0
    def update(self, req, id, body):
        """Update server then pass on to version-specific controller."""

        ctxt = req.environ['nova.context']
        update_dict = {}
        authorize(ctxt, action='update')

        if 'name' in body['server']:
            update_dict['display_name'] = body['server']['name']

        if list(self.update_extension_manager):
            self.update_extension_manager.map(self._update_extension_point,
                                              body['server'], update_dict)

        instance = common.get_instance(self.compute_api, ctxt, id,
                                       expected_attrs=['pci_devices'])
        try:
            # NOTE(mikal): this try block needs to stay because save() still
            # might throw an exception.
            req.cache_db_instance(instance)
            instance.update(update_dict)
            instance.save()
            return self._view_builder.show(req, instance,
                                           extend_address=False)
        except exception.InstanceNotFound:
            msg = _("Instance could not be found")
            raise exc.HTTPNotFound(explanation=msg)
Example #17
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 #18
0
    def show(self, req, server_id, id):
        """Return data about the given volume attachment."""
        context = req.environ['nova.context']
        authorize(context)
        authorize_attach(context, action='show')

        volume_id = id
        instance = common.get_instance(self.compute_api, context, server_id,
                                       want_objects=True)

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

        if not bdms:
            msg = _("Instance %s is not attached.") % server_id
            raise exc.HTTPNotFound(explanation=msg)

        assigned_mountpoint = None

        for bdm in bdms:
            if bdm.volume_id == volume_id:
                assigned_mountpoint = bdm.device_name
                break

        if assigned_mountpoint is None:
            msg = _("volume_id not found: %s") % volume_id
            raise exc.HTTPNotFound(explanation=msg)

        return {'volumeAttachment': _translate_attachment_detail_view(
            volume_id,
            instance['uuid'],
            assigned_mountpoint)}
Example #19
0
 def _get_server(self, context, req, instance_uuid):
     """Utility function for looking up an instance by uuid."""
     instance = common.get_instance(self.compute_api, context,
                                    instance_uuid,
                                    expected_attrs=['flavor'])
     req.cache_db_instance(instance)
     return instance
Example #20
0
    def index(self, req, server_id):
        context = req.environ['nova.context']
        authorize(context)
        instance = common.get_instance(self.compute_api, context, server_id)

        passw = password.extract_password(instance)
        return {'password': passw or ''}
Example #21
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 #22
0
    def get_vnc_console(self, req, id, body):
        """Get vnc connection information to access a server."""
        context = req.environ['nova.context']
        authorize(context)

        # If type is not supplied or unknown, get_vnc_console below will cope
        console_type = body['os-getVNCConsole'].get('type')
        instance = common.get_instance(self.compute_api, context, id)

        try:
            output = self.compute_api.get_vnc_console(context,
                                                      instance,
                                                      console_type)
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(
                    explanation=_('Instance not yet ready'))
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except (exception.ConsoleTypeUnavailable,
                exception.ConsoleTypeInvalid) as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Unable to get vnc console, functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return {'console': {'type': console_type, 'url': output['url']}}
Example #23
0
    def index(self, req, server_id):
        context = req.environ['nova.context']
        context.can(sp_policies.BASE_POLICY_NAME)
        instance = common.get_instance(self.compute_api, context, server_id)

        passw = password.extract_password(instance)
        return {'password': passw or ''}
Example #24
0
    def get_serial_console(self, req, id, body):
        """Get connection to a serial console."""
        context = req.environ['nova.context']
        authorize(context)

        # If type is not supplied or unknown get_serial_console below will cope
        key = 'os-getSerialConsole'
        if key not in body:
            key = 'os-getSerialPort'
        console_type = body[key].get('type', 'serial')
        console_index = int(body[key].get('serial_port', 0))
        instance = common.get_instance(self.compute_api, context, id)
        try:
            output = self.compute_api.get_serial_console(context,
                                                         instance,
                                                         console_type,
                                                         index=console_index)
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except (exception.ConsoleTypeUnavailable,
                exception.ConsoleTypeInvalid,
                exception.ImageSerialPortNumberInvalid,
                exception.ImageSerialPortNumberExceedFlavorValue,
                exception.SocketPortRangeExhaustedException) as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Unable to get serial console, "
                    "functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return {'console': {'type': console_type, 'url': output['url']}}
    def get_console_output(self, req, id, body):
        """Get text console output."""
        context = req.environ['nova.context']
        authorize(context)

        instance = common.get_instance(self.compute_api, context, id)
        length = body['os-getConsoleOutput'].get('length')
        # TODO(cyeoh): In a future API update accept a length of -1
        # as meaning unlimited length (convert to None)

        try:
            output = self.compute_api.get_console_output(context,
                                                         instance,
                                                         length)
        # NOTE(cyeoh): This covers race conditions where the instance is
        # deleted between common.get_instance and get_console_output
        # being called
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(explanation=e.format_message())
        except NotImplementedError:
            common.raise_feature_not_supported()

        # XML output is not correctly escaped, so remove invalid characters
        # NOTE(cyeoh): We don't support XML output with V2.1, but for
        # backwards compatibility reasons we continue to filter the output
        # We should remove this in the future
        remove_re = re.compile('[\x00-\x08\x0B-\x1F]')
        output = remove_re.sub('', output)

        return {'output': output}
Example #26
0
    def show(self, req, server_id, id):
        """Return data about the given volume attachment."""
        context = req.environ['nova.context']
        context.can(vol_policies.BASE_POLICY_NAME)
        context.can(va_policies.POLICY_ROOT % 'show')

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

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

        if not bdms:
            msg = _("Instance %s is not attached.") % server_id
            raise exc.HTTPNotFound(explanation=msg)

        assigned_mountpoint = None

        for bdm in bdms:
            if bdm.volume_id == volume_id:
                assigned_mountpoint = bdm.device_name
                break

        if assigned_mountpoint is None:
            msg = _("volume_id not found: %s") % volume_id
            raise exc.HTTPNotFound(explanation=msg)

        return {'volumeAttachment': _translate_attachment_detail_view(
            volume_id,
            instance.uuid,
            assigned_mountpoint)}
Example #27
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 #28
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 #29
0
 def _get_server(self, context, req, instance_uuid):
     """Utility function for looking up an instance by uuid."""
     instance = common.get_instance(self.compute_api, context,
                                    instance_uuid, want_objects=True,
                                    expected_attrs=['pci_devices'])
     req.cache_db_instance(instance)
     return instance
Example #30
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 #31
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)

        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,
            exception.OperationNotSupportedForVDPAInterface,
        ) 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 #32
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'])
        try:
            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host, force,
                                          async_)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        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 #33
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 the port has attached in this instance, raise
        port_info = {}
        if utils.is_neutron():
            if port_id:
                try:
                    port_info = self.network_api.show_port(context, port_id)
                except exception.NotFound as e:
                    raise exc.HTTPNotFound(explanation=e.format_message())
                if port_info['port']['device_id']:
                    raise exception.PortInUse(port_id=port_id)

        #check network is duplicated or not when allow_duplicate_networks is false
        if utils.is_neutron():
            if not cfg.CONF.neutron.allow_duplicate_networks:
                search_opts = {'device_id': server_id}
                try:
                    data = self.network_api.list_ports(context, **search_opts)
                except exception.NotFound as e:
                    raise exc.HTTPNotFound(explanation=e.format_message())
                except NotImplementedError:
                    msg = _("Network driver does not support this function.")
                    raise webob.exc.HTTPNotImplemented(explanation=msg)
                ports = data.get('ports', [])
                instance_networks = []
                for port in ports:
                    instance_networks.append(port.get('network_id'))
                if port_id:
                    network_id = port_info['port'].get('network_id')
                if network_id in instance_networks:
                    raise exception.NetworkDuplicated(network_id=network_id)

        try:
            instance = common.get_instance(self.compute_api,
                                           context, server_id,
                                           want_objects=True)
            LOG.audit(_("Attach interface"), instance=instance)
            vif = self.compute_api.attach_interface(context,
                instance, network_id, port_id, req_ip)
        except (exception.PortNotFound,
                exception.FixedIpAlreadyInUse,
                exception.PortInUse,
                exception.NetworkDuplicated,
                exception.NetworkAmbiguous,
                exception.NetworkNotFound,
                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 as e:
            LOG.exception(e)
            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')

        return self.show(req, server_id, vif['id'])
Example #34
0
    def _invoke(self, method, context, id, group_name):
        with translate_exceptions():
            instance = common.get_instance(self.compute_api, context, id)
            method(context, instance, group_name)

        return webob.Response(status_int=202)
Example #35
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)
        entity = body["create_backup"]

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

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

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

        try:
            rotation = int(rotation)
        except ValueError:
            msg = _("create_backup attribute 'rotation' must be an integer")
            raise exc.HTTPBadRequest(explanation=msg)
        if rotation < 0:
            msg = _("create_backup 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)

        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       want_objects=True)

        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, 'create_backup')

        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 #36
0
 def _invoke(self, method, context, id, group_name):
     instance = common.get_instance(self.compute_api, context, id)
     method(context, instance, group_name)
Example #37
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 #38
0
    def create(self, req, server_id, body):
        """Attach an interface to an instance."""
        context = req.environ['nova.context']
        context.can(ai_policies.BASE_POLICY_NAME)
        context.can(ai_policies.POLICY_ROOT % 'create')

        network_id = None
        port_id = None
        req_ip = None
        tag = None
        vif_model = 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)
            vif_model = attachment.get('wrs-if:vif_model')
            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)

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

        try:
            if hasattr(instance, 'info_cache'):
                instance_nic_count = len(instance.info_cache.network_info)
                if instance_nic_count >= wrs_server_if.MAXIMUM_VNICS:
                    msg = _("Already at %(max)d configured NICs, "
                            "which is the maximum amount supported") % {
                                "max": wrs_server_if.MAXIMUM_VNICS,
                           }
                    raise exc.HTTPBadRequest(explanation=msg)
            if hasattr(instance, 'host'):
                physkey = 'provider:physical_network'
                aggr_list = objects.AggregateList.get_by_metadata_key(
                    context, physkey, hosts=set([instance.host])
                )
                providernet_list = []
                for aggr_entry in aggr_list:
                    providernet_list.append(aggr_entry.metadata[physkey])

                neutron = neutronapi.get_client(context, admin=True)
                temp_network_id = None
                if port_id:
                    port = neutron.show_port(port_id)['port']
                    temp_network_id = port.get('network_id')
                    if not vif_model:
                        vif_model = port.get('wrs-binding:vif_model')
                else:
                    temp_network_id = network_id
                network = neutron.show_network(temp_network_id)['network']
                providernet = network[physkey]
                providernet_on_host = (providernet in providernet_list)
                if not providernet_on_host:
                    msg = _("Providernet %(pnet)s not on instance's "
                            "host %(host)s") % {
                                "pnet": providernet,
                                "host": instance.host,
                            }
                    raise exc.HTTPBadRequest(explanation=msg)
            if not vif_model:
                vif_model = network_model.VIF_MODEL_VIRTIO
            elif vif_model not in network_model.VIF_MODEL_HOTPLUGGABLE:
                msg = _("Interface attach not supported for vif_model "
                        "%(vif_model)s. Must be one of %(valid_vifs)s.") % {
                            'vif_model': vif_model,
                            'valid_vifs': network_model.VIF_MODEL_HOTPLUGGABLE,
                        }
                raise exception.InvalidInput(msg)
            vif = self.compute_api.attach_interface(context,
                instance, network_id, port_id, req_ip, vif_model, tag=tag)
        except (exception.InterfaceAttachFailedNoNetwork,
                exception.NetworkAmbiguous,
                exception.NoMoreFixedIps,
                exception.PortNotUsable,
                exception.AttachInterfaceNotSupported,
                exception.SecurityGroupCannotBeApplied,
                exception.InvalidInput,
                exception.TaggedAttachmentNotSupported) 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.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 #39
0
    def _add_floating_ip(self, req, id, body):
        """Associate floating_ip to an instance."""
        context = req.environ['nova.context']
        context.can(fi_policies.BASE_POLICY_NAME)

        address = body['addFloatingIp']['address']

        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       expected_attrs=['flavor'])
        cached_nwinfo = instance.get_network_info()
        if not cached_nwinfo:
            LOG.warning(
                'Info cache is %r during associate with no nw_info cache',
                instance.info_cache,
                instance=instance)
            msg = _('Instance network is not ready yet')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_ips = cached_nwinfo.fixed_ips()
        if not fixed_ips:
            msg = _('No fixed IPs associated to instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_address = None
        if 'fixed_address' in body['addFloatingIp']:
            fixed_address = body['addFloatingIp']['fixed_address']
            for fixed in fixed_ips:
                if fixed['address'] == fixed_address:
                    break
            else:
                msg = _('Specified fixed address not assigned to instance')
                raise webob.exc.HTTPBadRequest(explanation=msg)

        if not fixed_address:
            try:
                fixed_address = next(ip['address'] for ip in fixed_ips
                                     if netutils.is_valid_ipv4(ip['address']))
            except StopIteration:
                msg = _('Unable to associate floating IP %(address)s '
                        'to any fixed IPs for instance %(id)s. '
                        'Instance has no fixed IPv4 addresses to '
                        'associate.') % ({
                            'address': address,
                            'id': id
                        })
                raise webob.exc.HTTPBadRequest(explanation=msg)
            if len(fixed_ips) > 1:
                LOG.warning(
                    'multiple fixed_ips exist, using the first '
                    'IPv4 fixed_ip: %s', fixed_address)

        try:
            self.network_api.associate_floating_ip(context,
                                                   instance,
                                                   floating_address=address,
                                                   fixed_address=fixed_address)
        except exception.FloatingIpAssociated:
            msg = _('floating IP is already associated')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.FloatingIpAssociateFailed as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except exception.NoFloatingIpInterface:
            msg = _('l3driver call to add floating IP failed')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.FloatingIpNotFoundForAddress:
            msg = _('floating IP not found')
            raise webob.exc.HTTPNotFound(explanation=msg)
        except exception.Forbidden as e:
            raise webob.exc.HTTPForbidden(explanation=e.format_message())
        except Exception as e:
            msg = _('Unable to associate floating IP %(address)s to '
                    'fixed IP %(fixed_address)s for instance %(id)s. '
                    'Error: %(error)s') % ({
                        'address': address,
                        'fixed_address': fixed_address,
                        'id': id,
                        'error': e
                    })
            LOG.exception(msg)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #40
0
 def index(self, req, server_id):
     context = req.environ["nova.context"]
     authorize(context, action='index')
     instance = common.get_instance(self._compute_api, context, server_id)
     networks = common.get_networks_for_instance(context, instance)
     return self._view_builder.index(networks)
Example #41
0
 def _get_server(self, context, req, instance_uuid):
     """Utility function for looking up an instance by uuid."""
     instance = common.get_instance(self.compute_api, context,
                                    instance_uuid)
     return instance
Example #42
0
 def index(self, req, server_id):
     context = req.environ["nova.context"]
     context.can(ips_policies.POLICY_ROOT % 'index')
     instance = common.get_instance(self._compute_api, context, server_id)
     networks = common.get_networks_for_instance(context, instance)
     return self._view_builder.index(networks)
Example #43
0
    def update(self, req, server_id, id, body):
        if (not self.ext_mgr
                or not self.ext_mgr.is_loaded('os-volume-attachment-update')):
            raise exc.HTTPBadRequest()
        context = req.environ['nova.context']
        authorize(context)
        authorize_attach(context, action='update')

        if not self.is_valid_body(body, 'volumeAttachment'):
            msg = _("volumeAttachment not specified")
            raise exc.HTTPBadRequest(explanation=msg)

        old_volume_id = id
        old_volume = self.volume_api.get(context, old_volume_id)

        try:
            new_volume_id = body['volumeAttachment']['volumeId']
        except KeyError:
            msg = _("volumeId must be specified.")
            raise exc.HTTPBadRequest(explanation=msg)

        self._validate_volume_id(new_volume_id)
        try:
            new_volume = self.volume_api.get(context, new_volume_id)
        except exception.VolumeNotFound as e:
            # NOTE: This BadRequest is different from the above NotFound even
            # though the same VolumeNotFound exception. This is intentional
            # because new_volume_id is specified in a request body and if a
            # nonexistent resource in the body (not URI) the code should be
            # 400 Bad Request as API-WG guideline. On the other hand,
            # old_volume_id is specified with URI. So it is valid to return
            # NotFound response if that is not existent.
            raise exc.HTTPBadRequest(explanation=e.format_message())

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

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
            context, instance.uuid)
        found = False
        try:
            for bdm in bdms:
                if bdm.volume_id != old_volume_id:
                    continue
                try:
                    self.compute_api.swap_volume(context, instance, old_volume,
                                                 new_volume)
                    found = True
                    break
                except exception.VolumeUnattached:
                    # The volume is not attached.  Treat it as NotFound
                    # by falling through.
                    pass
        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, 'swap_volume', server_id)

        if not found:
            msg = _("volume_id not found: %s") % old_volume_id
            raise exc.HTTPNotFound(explanation=msg)
        else:
            return webob.Response(status_int=202)
Example #44
0
 def _get_instance(self, req, context, server_id):
     return common.get_instance(self.compute_api, context, server_id)
Example #45
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 #46
0
    def _add_floating_ip(self, req, id, body):
        """Associate floating_ip to an instance."""
        context = req.environ['nova.context']
        authorize(context)

        address = body['addFloatingIp']['address']

        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       want_objects=True)
        cached_nwinfo = compute_utils.get_nw_info_for_instance(instance)
        if not cached_nwinfo:
            msg = _('No nw_info cache associated with instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_ips = cached_nwinfo.fixed_ips()
        if not fixed_ips:
            msg = _('No fixed ips associated to instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_address = None
        if 'fixed_address' in body['addFloatingIp']:
            fixed_address = body['addFloatingIp']['fixed_address']
            for fixed in fixed_ips:
                if fixed['address'] == fixed_address:
                    break
            else:
                msg = _('Specified fixed address not assigned to instance')
                raise webob.exc.HTTPBadRequest(explanation=msg)

        if not fixed_address:
            fixed_address = fixed_ips[0]['address']
            if len(fixed_ips) > 1:
                LOG.warning(
                    _LW('multiple fixed_ips exist, using the first: '
                        '%s'), fixed_address)

        try:
            self.network_api.associate_floating_ip(context,
                                                   instance,
                                                   floating_address=address,
                                                   fixed_address=fixed_address)
        except exception.FloatingIpAssociated:
            msg = _('floating ip is already associated')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.NoFloatingIpInterface:
            msg = _('l3driver call to add floating ip failed')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.FloatingIpNotFoundForAddress:
            msg = _('floating ip not found')
            raise webob.exc.HTTPNotFound(explanation=msg)
        except exception.Forbidden as e:
            raise webob.exc.HTTPForbidden(explanation=e.format_message())
        except Exception as e:
            msg = _('Unable to associate floating ip %(address)s to '
                    'fixed ip %(fixed_address)s for instance %(id)s. '
                    'Error: %(error)s') % ({
                        'address': address,
                        'fixed_address': fixed_address,
                        'id': id,
                        'error': e
                    })
            LOG.exception(msg)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #47
0
 def _get_instance(self, req, context, server_id):
     with utils.temporary_mutation(context, read_deleted='yes'):
         return common.get_instance(self.compute_api, context, server_id)
Example #48
0
    def _add_floating_ip(self, req, id, body):
        """Associate floating_ip to an instance."""
        context = req.environ['nova.context']
        authorize(context)

        try:
            address = body['addFloatingIp']['address']
        except TypeError:
            msg = _("Missing parameter dict")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except KeyError:
            msg = _("Address not specified")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        instance = common.get_instance(self.compute_api, context, id)
        cached_nwinfo = compute_utils.get_nw_info_for_instance(instance)
        if not cached_nwinfo:
            LOG.warning(_LW('Info cache is %r during associate'),
                        instance.info_cache,
                        instance=instance)
            msg = _('No nw_info cache associated with instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_ips = cached_nwinfo.fixed_ips()
        if not fixed_ips:
            msg = _('No fixed IPs associated to instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_address = None
        if self.ext_mgr.is_loaded('os-extended-floating-ips'):
            if 'fixed_address' in body['addFloatingIp']:
                fixed_address = body['addFloatingIp']['fixed_address']
                for fixed in fixed_ips:
                    if fixed['address'] == fixed_address:
                        break
                else:
                    msg = _('Specified fixed address not assigned to instance')
                    raise webob.exc.HTTPBadRequest(explanation=msg)

        if not fixed_address:
            try:
                fixed_address = next(ip['address'] for ip in fixed_ips
                                     if netaddr.valid_ipv4(ip['address']))
            except StopIteration:
                msg = _('Unable to associate floating IP %(address)s '
                        'to any fixed IPs for instance %(id)s. '
                        'Instance has no fixed IPv4 addresses to '
                        'associate.') % ({
                            'address': address,
                            'id': id
                        })
                raise webob.exc.HTTPBadRequest(explanation=msg)
            if len(fixed_ips) > 1:
                LOG.warning(
                    _LW('multiple fixed_ips exist, using the first '
                        'IPv4 fixed_ip: %s'), fixed_address)

        try:
            self.network_api.associate_floating_ip(context,
                                                   instance,
                                                   floating_address=address,
                                                   fixed_address=fixed_address)
        except exception.FloatingIpAssociated:
            msg = _('floating IP is already associated')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.NoFloatingIpInterface:
            msg = _('l3driver call to add floating IP failed')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.FloatingIpNotFoundForAddress:
            msg = _('floating IP not found')
            raise webob.exc.HTTPNotFound(explanation=msg)
        except exception.Forbidden as e:
            raise webob.exc.HTTPForbidden(explanation=e.format_message())
        except Exception as e:
            msg = _('Unable to associate floating IP %(address)s to '
                    'fixed IP %(fixed_address)s for instance %(id)s. '
                    'Error: %(error)s') % ({
                        'address': address,
                        'fixed_address': fixed_address,
                        'id': id,
                        'error': e
                    })
            LOG.exception(msg)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #49
0
    def run(self):
        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
                self.context, self.instance['uuid'])
        is_boot_from_image = False
        
        #save the volume
        volume_dict_for_boot_index = {}
        volume_dict_for_image_id ={}
        volume_dict_for_mountpoint ={}
        block_device_mapping = None
        volume_ids = []
        system_volume_image_id = None
        #step1 get the source instance info
        instance = common.get_instance(self.compute_api, self.context, self.instance.uuid, want_objects=True) 
        for bdm in bdms:
            if bdm.image_id is not None and bdm.boot_index == 0 and bdm.destination_type =='local':
                is_boot_from_image =True
                system_volume_image_id = bdm.image_id
            if bdm.volume_id is not None:
                if bdm.boot_index == 0:
                    volume = self.volume_api.get(self.context, bdm.volume_id)
                    volume_image_metadata = volume.get('volume_metadata')
                    system_volume_image_id = volume_image_metadata['image_id'] 
                volume_dict_for_boot_index[bdm.volume_id]=bdm.boot_index
                volume_ids.append(bdm.volume_id)
                volume_dict_for_mountpoint[bdm.volume_id] =bdm.device_name
        #step2 stop the instance        
        self._stop_instance(instance)
        
        
        #step3 create image of vm and volume
        boot_image_uuid = None       
        if is_boot_from_image:
            if self.migrate_system_volume is False:
                boot_image_uuid = system_volume_image_id
            else:
                tmp_image_name = "%s@%s" % (uuid.uuid1(), self.instance.uuid)
                instance = common.get_instance(self.compute_api, self.context, self.instance.uuid, want_objects=True) 
                image_meta = self.compute_api.snapshot(self.context, instance, name=tmp_image_name, extra_properties=None)
                query_image_status_count=1800
                filters = {'name':tmp_image_name}
                imagelist = self.image_api.get_all(self.context,filters=filters)
                image = imagelist[0]
                while image['status'] != 'active':
                    time.sleep(1)
                    imagelist = self.image_api.get_all(self.context,filters=filters)
                    image = imagelist[0]
                    #image_uuid = image['id']
                    #image = self.image_api.get(self.context,image_uuid )
                    if image['status'] =='error':
                        msg = _("migrate vm failed.")
                        raise exc.HTTPBadRequest(explanation=msg)
                    query_image_status_count = query_image_status_count-1
                    if query_image_status_count == 0 and image['status'] != 'active':
                        msg = _("migrate vm failed.")
                        raise exc.HTTPBadRequest(explanation=msg)
                boot_image_uuid =image['id']

            #data_volume upload to glance
            #import pdb
            #pdb.set_trace()
            volume_dict_for_image_id= self._upload_volume_to_image(volume_ids,
                                                                    volume_dict_for_boot_index)
        else : 
            instance.task_state = task_states.IMAGE_SNAPSHOT
            instance.save() 
            if self.migrate_system_volume is False:
                boot_image_uuid = system_volume_image_id  
            volume_dict_for_image_id = self._upload_volume_to_image(volume_ids,
                                                                    volume_dict_for_boot_index)
           
          
        try:
            #step4 create the target volume
            source_target_vol_mapping = self._create_target_volume(volume_dict_for_image_id)  
            #step5 check the volume status
            self._check_volume_status(source_target_vol_mapping)
        except exc.HTTPBadRequest as e:
            #exception occurred,reset the instance task_state
            LOG.error('error occur when create target volume')
            instance.task_state = None
            instance.save()
            raise e
        #reset the instance task_state
        instance.task_state = None
        instance.save() 
        #step6 prepare the params of create vm
        block_device_mapping=self._create_bdm(source_target_vol_mapping, volume_dict_for_boot_index, volume_dict_for_mountpoint)  
        
        access_ip_v4 = instance.access_ip_v4
        if access_ip_v4 is not None:
            self._validate_access_ipv4(access_ip_v4)
            
        access_ip_v6 = instance.access_ip_v6
        if access_ip_v6 is not None:
            self._validate_access_ipv6(access_ip_v6)
            
        #networks = common.get_networks_for_instance(context, instance)
        min_count = 1
        max_count = 1
        
        name=instance.display_name
        key_name = None
        metadata = instance.metadata
        injected_files = []
        security_group=instance.security_groups
        user_data=instance.user_data
        
        flavor_id = instance.system_metadata['instance_type_flavorid']
        
        scheduler_hints = {}
         
        #check_server_group_quota = \
        #    self.ext_mgr.is_loaded('os-server-group-quotas')
        check_server_group_quota=True
        
        requested_networks = []
        nw_info = compute_utils.get_nw_info_for_instance(instance)
        for vif in nw_info:
            net_uuid = vif['network']['id']
            net_ip = vif['network']['subnets'][0]['ips'][0]['address']
            requested_networks.append({'fixed_ip':net_ip, 'uuid':net_uuid})
        
        requested_networks = self._get_requested_networks(requested_networks)
        #update the instance metadata the metadata use for vcloud delete vm
        self.compute_api.update_instance_metadata(self.context,instance,{'quick_delete_once': 'True'},delete=False) 
        #TODO detach port delete
        
        
        #step7 delete the vm
        self.compute_api.delete(self.context,instance)
        #import pdb
        #pdb.set_trace()
        #step8 create vm
        while True:
            time.sleep(3)
            try:
                _get_inst_type = flavors.get_flavor_by_flavor_id
                inst_type = _get_inst_type(flavor_id, ctxt=self.context,
                                           read_deleted="no")
                (instances, resv_id) = self.compute_api.create(self.context,
                            inst_type,
                            boot_image_uuid,
                            display_name=name,
                            display_description=name,
                            key_name=key_name,
                            metadata=metadata,
                            access_ip_v4=access_ip_v4,
                            access_ip_v6=access_ip_v6,
                            injected_files=injected_files,
                            admin_password=None,
                            min_count=min_count,
                            max_count=max_count,
                            requested_networks=requested_networks,
                            security_group=security_group,
                            user_data=user_data,
                            availability_zone=self.availability_zone,
                            config_drive=None,
                            block_device_mapping=block_device_mapping,
                            auto_disk_config=None,
                            scheduler_hints=scheduler_hints,
                            legacy_bdm=True,
                            check_server_group_quota=check_server_group_quota)
            except (exception.PortInUse,
                    exception.NoUniqueMatch) as error:
                readable = traceback.format_exc()
                LOG.exception('migrate exception10:%s', readable)
                continue
                raise exc.HTTPConflict(explanation=error.format_message())
            except exception.FixedIpAlreadyInUse as error:
                readable = traceback.format_exc()
                LOG.exception('migrate exception11:%s', readable)
                continue
                raise exc.HTTPBadRequest(explanation=error.format_message())
            break
        
        if instances is not None and len(instances) == 1:
            instance_new = instances[0]
            query_new_vm_status_count=1200
            while instance_new.vm_state != 'active':
                time.sleep(2)
                instance_new = common.get_instance(self.compute_api, self.context, instance_new.uuid,
                                       want_objects=True)
                if instance_new.vm_state == 'error' : 
                    LOG.error("bulid instance failed")
                    msg = _("migrate vm failed.")
                    raise exc.HTTPBadRequest(explanation=msg)
                query_new_vm_status_count =query_new_vm_status_count-1
                if query_new_vm_status_count ==0 and instance_new.vm_state != 'active':
                    msg = _("migrate vm failed.")
                    raise exc.HTTPBadRequest(explanation=msg)    
        #step 9 delete the image
        LOG.debug('begin clear the image and volume')
        self._delete_tmp_image(boot_image_uuid, volume_dict_for_image_id)
        #step 10 delete the volume
        self._delete_volume_after_migrate(volume_ids) 
Example #50
0
    def detach(self, req, id, body):
        server_id = id
        context = req.environ['nova.context']
        authorize_detach(context)

        volume_id = body['detach']['volume_id']

        LOG.audit(
            _("Detach volume %(volume_id)s from "
              "instance %(server_id)s"), {
                  "volume_id": volume_id,
                  "server_id": id,
                  "context": context
              })
        instance = common.get_instance(self.compute_api,
                                       context,
                                       server_id,
                                       want_objects=True)
        try:
            volume = self.volume_api.get(context, volume_id)
        except exception.VolumeNotFound as e:
            raise exc.HTTPNotFound(explanation=e.format_message())

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
            context, instance.uuid)
        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
            if bdm.is_root:
                msg = _("Can't detach root device volume")
                raise exc.HTTPForbidden(explanation=msg)
            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.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, '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)
Example #51
0
def get_instance_by_floating_ip_addr(self, context, address):
    snagiibfa = self.network_api.get_instance_id_by_floating_address
    instance_id = snagiibfa(context, address)
    if instance_id:
        return common.get_instance(self.compute_api, context, instance_id)
Example #52
0
    def _add_floating_ip(self, req, id, body):
        """Associate floating_ip to an instance."""
        context = req.environ['nova.context']
        authorize(context)

        try:
            address = body['addFloatingIp']['address']
        except TypeError:
            msg = _("Missing parameter dict")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except KeyError:
            msg = _("Address not specified")
            raise webob.exc.HTTPBadRequest(explanation=msg)

        instance = common.get_instance(self.compute_api, context, id)
        cached_nwinfo = compute_utils.get_nw_info_for_instance(instance)
        if not cached_nwinfo:
            msg = _('No nw_info cache associated with instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_ips = cached_nwinfo.fixed_ips()
        if not fixed_ips:
            msg = _('No fixed ips associated to instance')
            raise webob.exc.HTTPBadRequest(explanation=msg)

        fixed_address = None
        if self.ext_mgr.is_loaded('os-extended-floating-ips'):
            if 'fixed_address' in body['addFloatingIp']:
                fixed_address = body['addFloatingIp']['fixed_address']
                for fixed in fixed_ips:
                    if fixed['address'] == fixed_address:
                        break
                else:
                    msg = _('Specified fixed address not assigned to instance')
                    raise webob.exc.HTTPBadRequest(explanation=msg)

        if not fixed_address:
            fixed_address = fixed_ips[0]['address']
            if len(fixed_ips) > 1:
                msg = _('multiple fixed_ips exist, using the first: %s')
                LOG.warning(msg, fixed_address)

        try:
            self.network_api.associate_floating_ip(context,
                                                   instance,
                                                   floating_address=address,
                                                   fixed_address=fixed_address)
        except exception.FloatingIpAssociated:
            msg = _('floating ip is already associated')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except exception.NoFloatingIpInterface:
            msg = _('l3driver call to add floating ip failed')
            raise webob.exc.HTTPBadRequest(explanation=msg)
        except (exception.FloatingIpNotFoundForAddress, exception.Forbidden):
            msg = _('floating ip not found')
            raise webob.exc.HTTPNotFound(explanation=msg)
        except Exception:
            msg = _('Error. Unable to associate floating ip')
            LOG.exception(msg)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        return webob.Response(status_int=202)
Example #53
0
 def _lock(self, req, id, body):
     """Lock a server instance."""
     context = req.environ['nova.context']
     authorize(context, action='lock')
     instance = common.get_instance(self.compute_api, context, id)
     self.compute_api.lock(context, instance)
Example #54
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)

        instance = common.get_instance(self.compute_api, context, id)
        try:
            # WRS: Live migration with pci devices is only supported with
            # macvtap (which is currently not supported in Titanium Cloud).
            if instance.pci_devices:
                msg = _("Live migration of instance %s is not supported "
                        "with PCI devices attached.") % id
                raise exc.HTTPBadRequest(explanation=msg)

            self.compute_api.live_migrate(context, instance, block_migration,
                                          disk_over_commit, host, force, async)
        except exception.InstanceUnknownCell as e:
            raise exc.HTTPNotFound(explanation=e.format_message())
        except (exception.NoValidHost,
                exception.ComputeServiceUnavailable,
                exception.InvalidHypervisorType,
                exception.InvalidCPUInfo,
                exception.UnableToMigrateToSelf,
                exception.DestinationHypervisorTooOld,
                exception.InvalidLocalStorage,
                exception.InvalidSharedStorage,
                exception.HypervisorUnavailable,
                exception.MigrationPreCheckError,
                exception.MigrationPreCheckErrorNoRetry,
                exception.LiveMigrationWithOldNovaNotSupported) 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 #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(
                context, instance.uuid, self.network_api) and
                not common.supports_port_resource_request_during_move(req)):
            msg = _("The evacuate 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.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())

        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
    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 #57
0
    def _migrate(self, req, id, body):
        """Permit admins to migrate a server to a new host."""

        param_dict = body.get('migrate')
        no_sys_vol = param_dict.get('no_sys_vol', False)
        az = param_dict.get('az')
        boot_system_volume = not no_sys_vol
        context = req.environ['nova.context']
        authorize(context, 'migrate')
        instance = common.get_instance(self.compute_api,
                                       context,
                                       id,
                                       want_objects=True)
        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
            context, instance['uuid'])
        if az is not None:
            availability_zone = instance.availability_zone
            checkResut = self._check_migrate_conditions(
                context, az, instance, boot_system_volume)
            if checkResut is False:
                if 'vcloud' in az:
                    msg = _("The vm can't migrate to the az")
                    raise exc.HTTPBadRequest(explanation=msg)
                if 'aws' in az:
                    msg = _("The vm can only migrate data volume to the az")
                    raise exc.HTTPBadRequest(explanation=msg)
                if 'aws' in availability_zone:
                    msg = _("The vm can only migrate data volume from the az")
                    raise exc.HTTPBadRequest(explanation=msg)
            if az == availability_zone:
                msg = _("The target azone can't be the same one.")
                raise exc.HTTPBadRequest(explanation=msg)

            migrateThread = MigrateThread(context, instance, az,
                                          boot_system_volume)
            migrateThread.start()

        else:
            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)
            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)