def show(self, req, server_id, id): """Return data about the given interface attachment.""" context = req.environ['patron.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.PortNotFound 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 _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 _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 _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 get_serial_console(self, req, id, body): """Get connection to a serial console.""" context = req.environ['patron.context'] authorize(context) # If type is not supplied or unknown get_serial_console below will cope console_type = body['os-getSerialConsole'].get('type') instance = common.get_instance(self.compute_api, context, id) try: 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.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 show(self, req, server_id, id): """Return data about the given volume attachment.""" context = req.environ['patron.context'] authorize(context) authorize_attach(context, action='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 _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 index(self, req, server_id): context = req.environ['patron.context'] authorize(context) instance = common.get_instance(self.compute_api, context, server_id) passw = password.extract_password(instance) return {'password': passw or ''}
def delete(self, req, server_id): context = req.environ['patron.context'] authorize(context) instance = common.get_instance(self.compute_api, context, server_id) meta = password.convert_password(context, None) instance.system_metadata.update(meta) instance.save()
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 get_console_output(self, req, id, body): """Get text console output.""" context = req.environ['patron.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: msg = _("Unable to get console log, functionality not implemented") raise webob.exc.HTTPNotImplemented(explanation=msg) # 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 update(self, req, id, body): """Update server then pass on to version-specific controller.""" ctxt = req.environ['patron.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 _reset_state(self, req, id, body): """Permit admins to reset the state of a server.""" context = req.environ["patron.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 get_rdp_console(self, req, id, body): """Get text console output.""" context = req.environ['patron.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: output = self.compute_api.get_rdp_console(context, instance, console_type) except (exception.ConsoleTypeUnavailable, exception.ConsoleTypeInvalid) 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 rdp console, functionality not implemented") raise webob.exc.HTTPNotImplemented(explanation=msg) return {'console': {'type': console_type, 'url': output['url']}}
def _add_floating_ip(self, req, id, body): """Associate floating_ip to an instance.""" context = req.environ['patron.context'] authorize(context) address = body['addFloatingIp']['address'] 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 '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 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 index(self, req, server_id): """Returns the list of actions recorded for a given instance.""" context = req.environ["patron.context"] instance = common.get_instance(self.compute_api, context, server_id) authorize_actions(context, target=instance) actions_raw = self.action_api.actions_get(context, instance) actions = [self._format_action(action) for action in actions_raw] return {'instanceActions': actions}
def _inject_network_info(self, req, id, body): """Permit admins to inject network info into a server.""" context = req.environ['patron.context'] authorize(context, action='inject_network_info') try: instance = common.get_instance(self.compute_api, context, id) self.compute_api.inject_network_info(context, instance) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message())
def _items(self, req, server_id, entity_maker): """Returns a list of VIFs, transformed through entity_maker.""" context = req.environ['patron.context'] instance = common.get_instance(self.compute_api, context, server_id) vifs = self.network_api.get_vifs_by_instance(context, instance) limited_list = common.limited(vifs, req) res = [entity_maker(context, vif) for vif in limited_list] return {'virtual_interfaces': res}
def show(self, req, id): """Returns server details by server id.""" context = req.environ['patron.context'] instance = common.get_instance(self.compute_api, context, id, expected_attrs=['pci_devices', 'flavor']) authorize(context, action="show") req.cache_db_instance(instance) return self._view_builder.show(req, instance)
def _force_delete(self, req, id, body): """Force delete of instance before deferred cleanup.""" context = req.environ["patron.context"] authorize(context) instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.force_delete(context, instance) except exception.InstanceIsLocked as e: raise webob.exc.HTTPConflict(explanation=e.format_message())
def show(self, req, server_id, id): context = req.environ["patron.context"] instance = common.get_instance(self._compute_api, context, server_id) networks = common.get_networks_for_instance(context, instance) if id not in networks: msg = _("Instance is not a member of specified network") raise exc.HTTPNotFound(explanation=msg) return self._view_builder.show(networks[id], 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 _add_fixed_ip(self, req, id, body): """Adds an IP on a given network to an instance.""" context = req.environ['patron.context'] authorize(context) instance = common.get_instance(self.compute_api, context, id) network_id = body['addFixedIp']['networkId'] try: self.compute_api.add_fixed_ip(context, instance, network_id) except exception.NoMoreFixedIps as e: raise exc.HTTPBadRequest(explanation=e.format_message())
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 _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 _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 get_instance_by_floating_ip_addr(self, context, address): try: instance_id =\ self.network_api.get_instance_id_by_floating_address( context, address) except exception.FloatingIpNotFoundForAddress as ex: raise webob.exc.HTTPNotFound(explanation=ex.format_message()) except exception.FloatingIpMultipleFoundForAddress as ex: raise webob.exc.HTTPConflict(explanation=ex.format_message()) if instance_id: return common.get_instance(self.compute_api, context, instance_id)
def _items(self, req, server_id, entity_maker): """Returns a list of attachments, transformed through entity_maker.""" context = req.environ['patron.context'] authorize(context) instance = common.get_instance(self.compute_api, context, server_id) results = [] search_opts = {'device_id': instance.uuid} 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', []) results = [entity_maker(port) for port in ports] return {'interfaceAttachments': results}
def _resume(self, req, id, body): """Permit admins to resume the server from suspend.""" context = req.environ['patron.context'] authorize(context, 'resume') server = common.get_instance(self.compute_api, context, id) try: 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) except exception.InstanceNotFound: msg = _("Server not found") raise exc.HTTPNotFound(explanation=msg) except Exception: readable = traceback.format_exc() LOG.exception(_LE("compute.api::resume %s"), readable) raise exc.HTTPUnprocessableEntity() return webob.Response(status_int=202)
def delete(self, req, server_id, id): """Deletes an existing metadata.""" context = req.environ['patron.context'] authorize(context, action='delete') metadata = self._get_metadata(context, server_id) if id not in metadata: msg = _("Metadata item was not found") raise exc.HTTPNotFound(explanation=msg) server = common.get_instance(self.compute_api, context, server_id) try: self.compute_api.delete_instance_metadata(context, server, id) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'delete metadata', server_id)
def index(self, req, server_id): """Returns a list of security groups for the given instance.""" context = _authorize_context(req) self.security_group_api.ensure_default(context) with translate_exceptions(): instance = common.get_instance(self.compute_api, context, server_id) groups = self.security_group_api.get_instance_security_groups( context, instance.uuid, True) result = [ self._format_security_group(context, group) for group in groups ] return { 'security_groups': list(sorted(result, key=lambda k: (k['tenant_id'], k['name']))) }
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') volume_id = body['volumeAttachment']['volumeId'] device = body['volumeAttachment'].get('device') instance = common.get_instance(self.compute_api, context, server_id) try: device = self.compute_api.attach_volume(context, instance, volume_id, device) except exception.VolumeNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'attach_volume', server_id) except (exception.InvalidVolume, exception.InvalidDevicePath) as e: raise exc.HTTPBadRequest(explanation=e.format_message()) # 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 _remove_fixed_ip(self, req, id, body): """Removes an IP from an instance.""" context = req.environ['patron.context'] authorize(context) # Validate the input entity if 'address' not in body['removeFixedIp']: msg = _("Missing 'address' argument for removeFixedIp") raise exc.HTTPBadRequest(explanation=msg) instance = common.get_instance(self.compute_api, context, id) address = body['removeFixedIp']['address'] try: self.compute_api.remove_fixed_ip(context, instance, address) except exception.FixedIpNotFoundForSpecificInstance: LOG.exception(_LE("Unable to find address %r"), address, instance=instance) raise exc.HTTPBadRequest() 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['patron.context'] authorize(context, 'migrate') instance = common.get_instance(self.compute_api, context, id) try: self.compute_api.resize(req.environ['patron.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', 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()) except Exception: LOG.exception(_LE("Error in migrate")) raise exc.HTTPBadRequest() return webob.Response(status_int=202)
def delete(self, req, server_id, id): """Detach an interface from an instance.""" context = req.environ['patron.context'] authorize(context) port_id = id instance = common.get_instance(self.compute_api, context, server_id) LOG.info(_LI("Detach interface %s"), port_id, instance=instance) try: self.compute_api.detach_interface(context, instance, port_id=port_id) except exception.PortNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except NotImplementedError: msg = _("Network driver does not support this function.") raise webob.exc.HTTPNotImplemented(explanation=msg) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state( state_error, 'detach_interface', server_id) return webob.Response(status_int=202)
def get_vnc_console(self, req, id, body): """Get text console output.""" context = req.environ['patron.context'] authorize(context) # If type is not supplied or unknown, get_vnc_console below will cope console_type = body['os-getVNCConsole'].get('type') try: instance = common.get_instance(self.compute_api, context, id) output = self.compute_api.get_vnc_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 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): """Returns a list of security groups for the given instance.""" context = _authorize_context(req) self.security_group_api.ensure_default(context) try: instance = common.get_instance(self.compute_api, context, server_id) groups = self.security_group_api.get_instance_security_groups( context, instance.uuid, True) except (exception.SecurityGroupNotFound, exception.InstanceNotFound) as exp: msg = exp.format_message() raise exc.HTTPNotFound(explanation=msg) result = [ self._format_security_group(context, group) for group in groups ] return { 'security_groups': list(sorted(result, key=lambda k: (k['tenant_id'], k['name']))) }
def _unlock(self, req, id, body): """Unlock a server instance.""" context = req.environ['patron.context'] authorize(context, action='unlock') instance = common.get_instance(self.compute_api, context, id) self.compute_api.unlock(context, instance)
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 _invoke(self, method, context, id, group_name): instance = common.get_instance(self.compute_api, context, id) method(context, instance, group_name)
def _add_floating_ip(self, req, id, body): """Associate floating_ip to an instance.""" context = req.environ['patron.context'] authorize(context) address = body['addFloatingIp']['address'] 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 '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 _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, 'createBackup') entity = body["createBackup"] try: image_name = entity["name"] backup_type = entity["backup_type"] rotation = entity["rotation"] except KeyError as missing_key: msg = _("createBackup entity requires %s attribute") % missing_key raise exc.HTTPBadRequest(explanation=msg) except TypeError: msg = _("Malformed createBackup entity") raise exc.HTTPBadRequest(explanation=msg) try: rotation = int(rotation) except ValueError: msg = _("createBackup attribute 'rotation' must be an integer") raise exc.HTTPBadRequest(explanation=msg) if rotation < 0: msg = _("createBackup attribute 'rotation' must be greater " "than or equal to zero") raise exc.HTTPBadRequest(explanation=msg) props = {} metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) try: props.update(metadata) except ValueError: msg = _("Invalid metadata") raise exc.HTTPBadRequest(explanation=msg) 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 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 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 index(self, req, server_id): context = req.environ["patron.context"] 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 _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["patron.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) 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}