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)}
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'])}
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]}
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]}
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']}}
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)
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)
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())
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']}}
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 {}
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)
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())
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)
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']}}
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)
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)
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)}
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
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 ''}
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}
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']}}
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 ''}
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}
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)}
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')
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()
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
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)
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
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)
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'])
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)
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
def _invoke(self, method, context, id, group_name): instance = common.get_instance(self.compute_api, context, id) method(context, instance, group_name)
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}
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'])
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)
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)
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
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)
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)
def _get_instance(self, req, context, server_id): return common.get_instance(self.compute_api, context, server_id)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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
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'])
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)