def _rescue(self, req, id, body): """Rescue an instance.""" context = req.environ["patron.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 = 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 _update_instance_metadata(self, context, server_id, metadata, delete=False): try: server = common.get_instance(self.compute_api, context, server_id) return self.compute_api.update_instance_metadata(context, server, metadata, delete) except exception.InstanceNotFound: msg = _('Server does not exist') raise exc.HTTPNotFound(explanation=msg) except (ValueError, AttributeError): msg = _("Malformed request body") raise exc.HTTPBadRequest(explanation=msg) except exception.InvalidMetadata as error: raise exc.HTTPBadRequest(explanation=error.format_message()) except exception.InvalidMetadataSize as error: raise exc.HTTPRequestEntityTooLarge( explanation=error.format_message()) except exception.QuotaError as error: raise exc.HTTPForbidden(explanation=error.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'update metadata', server_id)
def _action_reboot(self, req, id, body): if 'reboot' in body and 'type' in body['reboot']: if not isinstance(body['reboot']['type'], six.string_types): msg = _("Argument 'type' for reboot must be a string") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) valid_reboot_types = ['HARD', 'SOFT'] reboot_type = body['reboot']['type'].upper() if not valid_reboot_types.count(reboot_type): msg = _("Argument 'type' for reboot is not HARD or SOFT") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) else: msg = _("Missing argument 'type' for reboot") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.reboot(context, instance, reboot_type) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'reboot', id) return webob.Response(status_int=202)
def _rescue(self, req, id, body): """Rescue an instance.""" context = req.environ["patron.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) 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', 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()) if CONF.enable_instance_password: return {'adminPass': password} else: return {}
def _migrate_live(self, req, id, body): """Permit admins to (live) migrate a server to a new host.""" context = req.environ["patron.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 _rescue(self, req, id, body): """Rescue an instance.""" context = req.environ["patron.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) 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', 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()) if CONF.enable_instance_password: return {'adminPass': password} else: return {}
def _migrate_live(self, req, id, body): """Permit admins to (live) migrate a server to a new host.""" context = req.environ["patron.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 _action_reboot(self, req, id, body): if 'reboot' in body and 'type' in body['reboot']: if not isinstance(body['reboot']['type'], six.string_types): msg = _("Argument 'type' for reboot must be a string") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) valid_reboot_types = ['HARD', 'SOFT'] reboot_type = body['reboot']['type'].upper() if not valid_reboot_types.count(reboot_type): msg = _("Argument 'type' for reboot is not HARD or SOFT") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) else: msg = _("Missing argument 'type' for reboot") LOG.error(msg) raise exc.HTTPBadRequest(explanation=msg) context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.reboot(context, instance, reboot_type) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'reboot', id) return webob.Response(status_int=202)
def create(self, req, server_id, body): """Attach an interface to an instance.""" context = req.environ['patron.context'] authorize(context) network_id = None port_id = None req_ip = None if body: attachment = body['interfaceAttachment'] network_id = attachment.get('net_id', None) port_id = attachment.get('port_id', None) try: req_ip = attachment['fixed_ips'][0]['ip_address'] except Exception: pass if network_id and port_id: msg = _("Must not input both network_id and port_id") raise exc.HTTPBadRequest(explanation=msg) if req_ip and not network_id: msg = _("Must input network_id when request IP address") raise exc.HTTPBadRequest(explanation=msg) if req_ip: try: netaddr.IPAddress(req_ip) except netaddr.AddrFormatError as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) try: instance = common.get_instance(self.compute_api, context, server_id) LOG.info(_LI("Attach interface"), instance=instance) vif = self.compute_api.attach_interface(context, instance, network_id, port_id, req_ip) except (exception.PortNotFound, exception.NetworkNotFound) as e: raise exc.HTTPNotFound(explanation=e.format_message()) except (exception.FixedIpAlreadyInUse, exception.NoMoreFixedIps, exception.PortInUse, exception.NetworkDuplicated, exception.NetworkAmbiguous, exception.PortNotUsable) as e: raise exc.HTTPBadRequest(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except NotImplementedError: msg = _("Network driver does not support this function.") raise webob.exc.HTTPNotImplemented(explanation=msg) except exception.InterfaceAttachFailed as 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', server_id) return self.show(req, server_id, vif['id'])
def _migrate_live(self, req, id, body): """Permit admins to (live) migrate a server to a new host.""" context = req.environ["patron.context"] authorize(context, 'migrateLive') try: block_migration = body["os-migrateLive"]["block_migration"] disk_over_commit = body["os-migrateLive"]["disk_over_commit"] host = body["os-migrateLive"]["host"] except (TypeError, KeyError): msg = _("host, block_migration and disk_over_commit must " "be specified for live migration.") raise exc.HTTPBadRequest(explanation=msg) try: block_migration = strutils.bool_from_string(block_migration, strict=True) disk_over_commit = strutils.bool_from_string(disk_over_commit, strict=True) except ValueError as err: raise exc.HTTPBadRequest(explanation=six.text_type(err)) instance = common.get_instance(self.compute_api, context, id) try: 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.InstanceNotFound 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, 'os-migrateLive', id) except Exception: if host is None: msg = _("Live migration of instance %s to another host " "failed") % id else: msg = _("Live migration of instance %(id)s to host %(host)s " "failed") % {'id': id, 'host': host} LOG.exception(msg) # Return messages from scheduler raise exc.HTTPInternalServerError(explanation=msg) return webob.Response(status_int=202)
def create(self, req, server_id, body): """Attach an interface to an instance.""" context = req.environ['patron.context'] authorize(context) network_id = None port_id = None req_ip = None if body: attachment = body['interfaceAttachment'] network_id = attachment.get('net_id', None) port_id = attachment.get('port_id', None) try: req_ip = attachment['fixed_ips'][0]['ip_address'] except Exception: pass if network_id and port_id: msg = _("Must not input both network_id and port_id") raise exc.HTTPBadRequest(explanation=msg) if req_ip and not network_id: msg = _("Must input network_id when request IP address") raise exc.HTTPBadRequest(explanation=msg) if req_ip: try: netaddr.IPAddress(req_ip) except netaddr.AddrFormatError as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) try: instance = common.get_instance(self.compute_api, context, server_id) LOG.info(_LI("Attach interface"), instance=instance) vif = self.compute_api.attach_interface(context, instance, network_id, port_id, req_ip) except (exception.PortNotFound, exception.NetworkNotFound) as e: raise exc.HTTPNotFound(explanation=e.format_message()) except (exception.FixedIpAlreadyInUse, exception.NoMoreFixedIps, exception.PortInUse, exception.NetworkDuplicated, exception.NetworkAmbiguous, exception.PortNotUsable) as e: raise exc.HTTPBadRequest(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except NotImplementedError: msg = _("Network driver does not support this function.") raise webob.exc.HTTPNotImplemented(explanation=msg) except exception.InterfaceAttachFailed as 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', server_id) return self.show(req, server_id, vif['id'])
def _unshelve(self, req, id, body): """Restore an instance from shelved mode.""" context = req.environ["patron.context"] authorize(context, action="unshelve") instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.unshelve(context, instance) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, "unshelve", id)
def create(self, req, server_id, body): """Attach a volume to an instance.""" context = req.environ['patron.context'] authorize(context) authorize_attach(context, action='create') if not self.is_valid_body(body, 'volumeAttachment'): msg = _("volumeAttachment not specified") raise exc.HTTPBadRequest(explanation=msg) try: volume_id = body['volumeAttachment']['volumeId'] except KeyError: msg = _("volumeId must be specified.") raise exc.HTTPBadRequest(explanation=msg) device = body['volumeAttachment'].get('device') self._validate_volume_id(volume_id) LOG.info(_LI("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) try: device = self.compute_api.attach_volume(context, instance, volume_id, device) except exception.NotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'attach_volume', server_id) # The attach is async attachment = {} attachment['id'] = volume_id attachment['serverId'] = server_id attachment['volumeId'] = volume_id attachment['device'] = device # NOTE(justinsb): And now, we have a problem... # The attach is async, so there's a window in which we don't see # the attachment (until the attachment completes). We could also # get problems with concurrent requests. I think we need an # attachment state, and to write to the DB here, but that's a bigger # change. # For now, we'll probably have to rely on libraries being smart # TODO(justinsb): How do I return "accepted" here? return {'volumeAttachment': attachment}
def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['patron.context'] authorize(context, action='create_image') entity = body["createImage"] image_name = entity["name"] metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if self.compute_api.is_volume_backed_instance(context, instance, bdms): img = instance.image_ref if not img: properties = bdms.root_metadata( context, self.compute_api.image_api, self.compute_api.volume_api) image_meta = {'properties': properties} else: image_meta = self.compute_api.image_api.get(context, img) image = self.compute_api.snapshot_volume_backed( context, instance, image_meta, image_name, extra_properties= metadata) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) image_ref = glance.generate_image_url(image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def _restore(self, req, id, body): """Restore a previously deleted instance.""" context = req.environ["patron.context"] authorize(context) instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.restore(context, instance) except exception.QuotaError as error: raise webob.exc.HTTPForbidden(explanation=error.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'restore', id)
def _resume(self, req, id, body): """Permit admins to resume the server from suspend.""" context = req.environ['patron.context'] authorize(context, action='resume') try: server = common.get_instance(self.compute_api, context, id) self.compute_api.resume(context, server) 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, 'resume', id)
def _restore(self, req, id, body): """Restore a previously deleted instance.""" context = req.environ["patron.context"] authorize(context) instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.restore(context, instance) except exception.QuotaError as error: raise webob.exc.HTTPForbidden(explanation=error.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'restore', id)
def delete(self, req, id): """Destroys a server.""" try: self._delete(req.environ['patron.context'], req, id) except exception.NotFound: msg = _("Instance could not be found") raise exc.HTTPNotFound(explanation=msg) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'delete', id)
def _unshelve(self, req, id, body): """Restore an instance from shelved mode.""" context = req.environ["patron.context"] authorize(context, action='unshelve') instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.unshelve(context, instance) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'unshelve', id)
def delete(self, req, id): """Destroys a server.""" try: self._delete(req.environ['patron.context'], req, id) except exception.NotFound: msg = _("Instance could not be found") raise exc.HTTPNotFound(explanation=msg) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'delete', id)
def _resume(self, req, id, body): """Permit admins to resume the server from suspend.""" context = req.environ['patron.context'] authorize(context, action='resume') try: server = common.get_instance(self.compute_api, context, id) self.compute_api.resume(context, server) 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, 'resume', id)
def _shelve_offload(self, req, id, body): """Force removal of a shelved instance from the compute node.""" context = req.environ["patron.context"] authorize(context, action="shelve_offload") instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.shelve_offload(context, instance) 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, "shelveOffload", id)
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['patron.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) new_volume = self.volume_api.get(context, new_volume_id) 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 _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['patron.context'] authorize(context, action='create_image') entity = body["createImage"] image_name = entity["name"] metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if self.compute_api.is_volume_backed_instance( context, instance, bdms): img = instance.image_ref if not img: properties = bdms.root_metadata( context, self.compute_api.image_api, self.compute_api.volume_api) image_meta = {'properties': properties} else: image_meta = self.compute_api.image_api.get(context, img) image = self.compute_api.snapshot_volume_backed( context, instance, image_meta, image_name, extra_properties=metadata) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=metadata) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) image_ref = glance.generate_image_url(image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def _action_confirm_resize(self, req, id, body): context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.confirm_resize(context, instance) except exception.MigrationNotFound: msg = _("Instance has not been resized.") raise exc.HTTPBadRequest(explanation=msg) except exception.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, 'confirmResize', id)
def _shelve_offload(self, req, id, body): """Force removal of a shelved instance from the compute node.""" context = req.environ["patron.context"] authorize(context, action='shelve_offload') instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.shelve_offload(context, instance) 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, 'shelveOffload', id)
def _stop_server(self, req, id, body): """Stop an instance.""" context = req.environ['patron.context'] instance = self._get_instance(context, id) authorize(context, instance, 'stop') LOG.debug('stop instance', instance=instance) try: self.compute_api.stop(context, instance) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'stop', id) except (exception.InstanceNotReady, exception.InstanceIsLocked) as e: raise webob.exc.HTTPConflict(explanation=e.format_message())
def _action_confirm_resize(self, req, id, body): context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.confirm_resize(context, instance) except exception.MigrationNotFound: msg = _("Instance has not been resized.") raise exc.HTTPBadRequest(explanation=msg) except exception.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, 'confirmResize', id)
def test_raise_http_conflict_for_instance_invalid_state(self): exc = exception.InstanceInvalidState(attr='fake_attr', state='fake_state', method='fake_method', instance_uuid='fake') try: common.raise_http_conflict_for_instance_invalid_state(exc, 'meow', 'fake_server_id') except webob.exc.HTTPConflict as e: self.assertEqual(six.text_type(e), "Cannot 'meow' instance fake_server_id while it is in " "fake_attr fake_state") else: self.fail("webob.exc.HTTPConflict was not raised")
def _stop_server(self, req, id, body): """Stop an instance.""" context = req.environ['patron.context'] instance = self._get_instance(context, id) authorize(context, instance, 'stop') LOG.debug('stop instance', instance=instance) try: self.compute_api.stop(context, instance) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'stop', id) except (exception.InstanceNotReady, exception.InstanceIsLocked) as e: raise webob.exc.HTTPConflict(explanation=e.format_message())
def _unrescue(self, req, id, body): """Unrescue an instance.""" context = req.environ["patron.context"] authorize(context) instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.unrescue(context, instance) 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, "unrescue", id) return webob.Response(status_int=202)
def _action_reboot(self, req, id, body): reboot_type = body['reboot']['type'].upper() context = req.environ['patron.context'] authorize(context, action='reboot') instance = self._get_server(context, req, id) try: self.compute_api.reboot(context, instance, reboot_type) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'reboot', id)
def _stop_server(self, req, id, body): """Stop an instance.""" context = req.environ['patron.context'] instance = self._get_instance(context, id) extensions.check_compute_policy(context, 'stop', instance) try: self.compute_api.stop(context, instance) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'stop', id) except (exception.InstanceNotReady, exception.InstanceIsLocked) as e: raise webob.exc.HTTPConflict(explanation=e.format_message()) return webob.Response(status_int=202)
def _stop_server(self, req, id, body): """Stop an instance.""" context = req.environ['patron.context'] instance = self._get_instance(context, id) extensions.check_compute_policy(context, 'stop', instance) try: self.compute_api.stop(context, instance) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'stop', id) except (exception.InstanceNotReady, exception.InstanceIsLocked) as e: raise webob.exc.HTTPConflict(explanation=e.format_message()) return webob.Response(status_int=202)
def _action_reboot(self, req, id, body): reboot_type = body['reboot']['type'].upper() context = req.environ['patron.context'] authorize(context, action='reboot') instance = self._get_server(context, req, id) try: self.compute_api.reboot(context, instance, reboot_type) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'reboot', id)
def index(self, req, server_id): context = req.environ["patron.context"] authorize(context) instance = common.get_instance(self.compute_api, context, server_id) try: 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 NotImplementedError: msg = _("Unable to get diagnostics, functionality not implemented") raise webob.exc.HTTPNotImplemented(explanation=msg)
def delete(self, req, server_id, id): """Detach a volume from an instance.""" context = req.environ['patron.context'] authorize(context) authorize_attach(context, action='delete') volume_id = id instance = common.get_instance(self.compute_api, context, server_id) 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 = _("Instance %s is not attached.") % server_id raise exc.HTTPNotFound(explanation=msg) found = False try: 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) found = True 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', server_id) if not found: msg = _("volume_id not found: %s") % volume_id raise exc.HTTPNotFound(explanation=msg)
def _evacuate(self, req, id, body): """Permit admins to evacuate a server from a failed host to a new one. """ context = req.environ["patron.context"] authorize(context) evacuate_body = body["evacuate"] host = evacuate_body.get("host") on_shared_storage = strutils.bool_from_string( evacuate_body["onSharedStorage"]) 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.ComputeHostNotFound: msg = _("Compute host %s not found.") % host raise exc.HTTPNotFound(explanation=msg) instance = common.get_instance(self.compute_api, context, id) 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) 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 CONF.enable_instance_password: return {'adminPass': password} else: return {}
def _evacuate(self, req, id, body): """Permit admins to evacuate a server from a failed host to a new one. """ context = req.environ["patron.context"] authorize(context) evacuate_body = body["evacuate"] host = evacuate_body.get("host") on_shared_storage = strutils.bool_from_string( evacuate_body["onSharedStorage"]) 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.ComputeHostNotFound: msg = _("Compute host %s not found.") % host raise exc.HTTPNotFound(explanation=msg) instance = common.get_instance(self.compute_api, context, id) 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) 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 CONF.enable_instance_password: return {'adminPass': password} else: return {}
def _shelve(self, req, id, body): """Move an instance into shelved mode.""" context = req.environ["patron.context"] auth_shelve(context) instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.shelve(context, instance) 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, 'shelve', id) return webob.Response(status_int=202)
def test_raise_http_conflict_for_instance_invalid_state(self): exc = exception.InstanceInvalidState(attr='fake_attr', state='fake_state', method='fake_method', instance_uuid='fake') try: common.raise_http_conflict_for_instance_invalid_state( exc, 'meow', 'fake_server_id') except webob.exc.HTTPConflict as e: self.assertEqual( six.text_type(e), "Cannot 'meow' instance fake_server_id while it is in " "fake_attr fake_state") else: self.fail("webob.exc.HTTPConflict was not raised")
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["patron.context"] authorize(context) entity = body["createBackup"] image_name = entity["name"] backup_type = entity["backup_type"] rotation = int(entity["rotation"]) props = {} metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) props.update(metadata) instance = common.get_instance(self.compute_api, context, id) try: image = self.compute_api.backup(context, instance, image_name, backup_type, rotation, extra_properties=props) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'createBackup', id) except exception.InvalidRequest as e: raise webob.exc.HTTPBadRequest(explanation=e.format_message()) 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 _action_revert_resize(self, req, id, body): context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.revert_resize(context, instance) except exception.MigrationNotFound: msg = _("Instance has not been resized.") raise exc.HTTPBadRequest(explanation=msg) except exception.FlavorNotFound: msg = _("Flavor used by the instance could not be found.") raise exc.HTTPBadRequest(explanation=msg) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'revertResize', id) return webob.Response(status_int=202)
def _unpause(self, req, id, body): """Permit Admins to unpause the server.""" ctxt = req.environ['patron.context'] authorize(ctxt, action='unpause') server = common.get_instance(self.compute_api, ctxt, id) try: self.compute_api.unpause(ctxt, server) 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, 'unpause', id) except exception.InstanceNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except NotImplementedError: msg = _("Virt driver does not implement pause function.") raise exc.HTTPNotImplemented(explanation=msg)
def _action_revert_resize(self, req, id, body): context = req.environ['patron.context'] instance = self._get_server(context, req, id) try: self.compute_api.revert_resize(context, instance) except exception.MigrationNotFound: msg = _("Instance has not been resized.") raise exc.HTTPBadRequest(explanation=msg) except exception.FlavorNotFound: msg = _("Flavor used by the instance could not be found.") raise exc.HTTPBadRequest(explanation=msg) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'revertResize', id) return webob.Response(status_int=202)
def _unpause(self, req, id, body): """Permit Admins to unpause the server.""" ctxt = req.environ['patron.context'] authorize(ctxt, action='unpause') server = common.get_instance(self.compute_api, ctxt, id) try: self.compute_api.unpause(ctxt, server) 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, 'unpause', id) except exception.InstanceNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except NotImplementedError: msg = _("Virt driver does not implement pause function.") raise exc.HTTPNotImplemented(explanation=msg)
def _update_instance_metadata(self, context, server_id, metadata, delete=False): try: server = common.get_instance(self.compute_api, context, server_id) return self.compute_api.update_instance_metadata(context, server, metadata, delete) except exception.QuotaError as error: raise exc.HTTPForbidden(explanation=error.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'update metadata', server_id)
def update(self, req, server_id, id, body): context = req.environ['patron.context'] authorize(context) authorize_attach(context, action='update') old_volume_id = id try: old_volume = self.volume_api.get(context, old_volume_id) new_volume_id = body['volumeAttachment']['volumeId'] new_volume = self.volume_api.get(context, new_volume_id) except exception.VolumeNotFound as e: raise exc.HTTPNotFound(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.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, 'swap_volume', server_id) if not found: msg = _("The volume was either invalid or not attached to the " "instance.") raise exc.HTTPNotFound(explanation=msg)
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["patron.context"] authorize(context) entity = body["createBackup"] image_name = entity["name"] backup_type = entity["backup_type"] rotation = int(entity["rotation"]) props = {} metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) props.update(metadata) instance = common.get_instance(self.compute_api, context, id) try: image = self.compute_api.backup(context, instance, image_name, backup_type, rotation, extra_properties=props) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createBackup', id) except exception.InvalidRequest as e: raise webob.exc.HTTPBadRequest(explanation=e.format_message()) 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 _update_instance_metadata(self, context, server_id, metadata, delete=False): try: server = common.get_instance(self.compute_api, context, server_id) return self.compute_api.update_instance_metadata( context, server, metadata, delete) except exception.QuotaError as error: raise exc.HTTPForbidden(explanation=error.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'update metadata', server_id)
def _migrate(self, req, id, body): """Permit admins to migrate a server to a new host.""" context = req.environ['patron.context'] authorize(context, action='migrate') instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.resize(req.environ['patron.context'], instance) except (exception.TooManyInstances, exception.QuotaError) as e: raise exc.HTTPForbidden(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'migrate', id) except exception.InstanceNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.NoValidHost as e: raise exc.HTTPBadRequest(explanation=e.format_message())
def _migrate(self, req, id, body): """Permit admins to migrate a server to a new host.""" context = req.environ['patron.context'] authorize(context, action='migrate') instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.resize(req.environ['patron.context'], instance) except (exception.TooManyInstances, exception.QuotaError) as e: raise exc.HTTPForbidden(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'migrate', id) except exception.InstanceNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.NoValidHost as e: raise exc.HTTPBadRequest(explanation=e.format_message())
def _suspend(self, req, id, body): """Permit admins to suspend the server.""" context = req.environ['patron.context'] authorize(context, 'suspend') server = common.get_instance(self.compute_api, context, id) try: self.compute_api.suspend(context, server) 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, 'suspend', id) except exception.InstanceNotFound: msg = _("Server not found") raise exc.HTTPNotFound(explanation=msg) except Exception: readable = traceback.format_exc() LOG.exception(_LE("compute.api::suspend %s"), readable) raise exc.HTTPUnprocessableEntity() return webob.Response(status_int=202)