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['compute.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 _get_barbican_client(self, ctxt): """Creates a client to connect to the Barbican service. :param ctxt: the user context for authentication :return: a Barbican Client object :raises Forbidden: if the ctxt is None """ # Confirm context is provided, if not raise forbidden if not ctxt: msg = _("User is not authorized to use key manager.") LOG.error(msg) raise exception.Forbidden(msg) if not hasattr(ctxt, 'project_id') or ctxt.project_id is None: msg = _("Unable to create Barbican Client without project_id.") LOG.error(msg) raise exception.KeyManagerError(msg) # If same context, return cached barbican client if self._barbican_client and self._current_context == ctxt: return self._barbican_client try: _SESSION = ks_loading.load_session_from_conf_options( CONF, BARBICAN_OPT_GROUP) auth = ctxt.get_auth_plugin() service_type, service_name, interface = (CONF. barbican. catalog_info. split(':')) region_name = CONF.barbican.os_region_name service_parameters = {'service_type': service_type, 'service_name': service_name, 'interface': interface, 'region_name': region_name} if CONF.barbican.endpoint_template: self._base_url = (CONF.barbican.endpoint_template % ctxt.to_dict()) else: self._base_url = _SESSION.get_endpoint( auth, **service_parameters) # the barbican endpoint can't have the '/v1' on the end self._barbican_endpoint = self._base_url.rpartition('/')[0] sess = session.Session(auth=auth) self._barbican_client = barbican_client.Client( session=sess, endpoint=self._barbican_endpoint) self._current_context = ctxt except Exception as e: with excutils.save_and_reraise_exception(): LOG.error(_LE("Error creating Barbican client: %s"), e) return self._barbican_client
def _wait_for_active(self, instance): """Wait for the node to be marked as ACTIVE in Ironic.""" instance.refresh() if (instance.task_state == task_states.DELETING or instance.vm_state in (vm_states.ERROR, vm_states.DELETED)): raise exception.InstanceDeployFailure( _("Instance %s provisioning was aborted") % instance.uuid) node = self._validate_instance_and_node(instance) if node.provision_state == ironic_states.ACTIVE: # job is done LOG.debug("Ironic node %(node)s is now ACTIVE", dict(node=node.uuid), instance=instance) raise loopingcall.LoopingCallDone() if node.target_provision_state in (ironic_states.DELETED, ironic_states.AVAILABLE): # ironic is trying to delete it now raise exception.InstanceNotFound(instance_id=instance.uuid) if node.provision_state in (ironic_states.NOSTATE, ironic_states.AVAILABLE): # ironic already deleted it raise exception.InstanceNotFound(instance_id=instance.uuid) if node.provision_state == ironic_states.DEPLOYFAIL: # ironic failed to deploy msg = (_("Failed to provision instance %(inst)s: %(reason)s") % {'inst': instance.uuid, 'reason': node.last_error}) raise exception.InstanceDeployFailure(msg) _log_ironic_polling('become ACTIVE', node, instance)
def show(self, req, server_id, id): """Return the migration of an instance in progress by id.""" context = req.environ['compute.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 create(self, req, body): """Creates a new snapshot.""" context = req.environ['compute.context'] authorize(context) if not self.is_valid_body(body, 'snapshot'): msg = _("snapshot not specified") raise exc.HTTPBadRequest(explanation=msg) snapshot = body['snapshot'] volume_id = snapshot['volume_id'] LOG.info(_LI("Create snapshot from volume %s"), volume_id, context=context) force = snapshot.get('force', False) try: force = strutils.bool_from_string(force, strict=True) except ValueError: msg = _("Invalid value '%s' for force.") % force raise exc.HTTPBadRequest(explanation=msg) if force: create_func = self.volume_api.create_snapshot_force else: create_func = self.volume_api.create_snapshot new_snapshot = create_func(context, volume_id, snapshot.get('display_name'), snapshot.get('display_description')) retval = _translate_snapshot_detail_view(context, new_snapshot) return {'snapshot': retval}
def _validate(self, bdm_dict): """Basic data format validations.""" dict_fields = set(key for key, _ in six.iteritems(bdm_dict)) # Check that there are no bogus fields if not (dict_fields <= (self._fields | self._db_only_fields)): raise exception.InvalidBDMFormat( details=_("Some fields are invalid.")) if bdm_dict.get('no_device'): return # Check that all required fields are there if (self._required_fields and not ((dict_fields & self._required_fields) == self._required_fields)): raise exception.InvalidBDMFormat( details=_("Some required fields are missing")) if 'delete_on_termination' in bdm_dict: bdm_dict['delete_on_termination'] = strutils.bool_from_string( bdm_dict['delete_on_termination']) if bdm_dict.get('device_name') is not None: validate_device_name(bdm_dict['device_name']) validate_and_default_volume_size(bdm_dict) if bdm_dict.get('boot_index'): try: bdm_dict['boot_index'] = int(bdm_dict['boot_index']) except ValueError: raise exception.InvalidBDMFormat( details=_("Boot index is invalid."))
def update(self, req, id, body): """Add or modify domain entry.""" context = req.environ['compute.context'] authorize(context, action="domain:update") fqdomain = _unquote_domain(id) entry = body['domain_entry'] scope = entry['scope'] project = entry.get('project', None) av_zone = entry.get('availability_zone', None) if scope == 'private' and project: msg = _("you can not pass project if the scope is private") raise webob.exc.HTTPBadRequest(explanation=msg) if scope == 'public' and av_zone: msg = _("you can not pass av_zone if the scope is public") raise webob.exc.HTTPBadRequest(explanation=msg) if scope == 'private': create_dns_domain = self.network_api.create_private_dns_domain area_name, area = 'availability_zone', av_zone else: create_dns_domain = self.network_api.create_public_dns_domain area_name, area = 'project', project try: create_dns_domain(context, fqdomain, area) except NotImplementedError: common.raise_feature_not_supported() return _translate_domain_entry_view({'domain': fqdomain, 'scope': scope, area_name: area})
def _test_numa_topology(self, resources, limit): host_topology = resources.get('numa_topology') requested_topology = self.numa_topology if host_topology: host_topology = objects.NUMATopology.obj_from_db_obj( host_topology) pci_requests = objects.InstancePCIRequests.get_by_instance_uuid( self.context, self.instance.uuid) pci_stats = None if pci_requests.requests: pci_stats = self.tracker.pci_tracker.stats instance_topology = ( hardware.numa_fit_instance_to_host( host_topology, requested_topology, limits=limit, pci_requests=pci_requests.requests, pci_stats=pci_stats)) if requested_topology and not instance_topology: if pci_requests.requests: return (_("Requested instance NUMA topology together with" " requested PCI devices cannot fit the given" " host NUMA topology")) else: return (_("Requested instance NUMA topology cannot fit " "the given host NUMA topology")) elif instance_topology: self.claimed_numa_topology = instance_topology
def show(self, req, id): """Checks a console auth token and returns the related connect info.""" context = req.environ['compute.context'] authorize(context) token = id if not token: msg = _("token not provided") raise webob.exc.HTTPBadRequest(explanation=msg) connect_info = self._consoleauth_rpcapi.check_token(context, token) if not connect_info: raise webob.exc.HTTPNotFound(explanation=_("Token not found")) console_type = connect_info.get('console_type') # This is currently required only for RDP consoles if console_type != "rdp-html5": raise webob.exc.HTTPUnauthorized( explanation=_("The requested console type details are not " "accessible")) return {'console': {i: connect_info[i] for i in ['instance_uuid', 'host', 'port', 'internal_access_path'] if i in connect_info}}
def _action_create_image(self, req, id, body): """Snapshot a server instance.""" context = req.environ['compute.context'] entity = body.get("createImage", {}) image_name = entity.get("name") if not image_name: msg = _("createImage entity requires name attribute") raise exc.HTTPBadRequest(explanation=msg) props = {} metadata = entity.get('metadata', {}) common.check_img_metadata_properties_quota(context, metadata) try: props.update(metadata) except ValueError: msg = _("Invalid metadata") raise exc.HTTPBadRequest(explanation=msg) instance = self._get_server(context, req, id) bdms = objects.BlockDeviceMappingList.get_by_instance_uuid( context, instance.uuid) try: if self.compute_api.is_volume_backed_instance(context, instance, bdms): policy.enforce(context, 'cloud:snapshot_volume_backed', {'project_id': context.project_id, 'user_id': context.user_id}) image = self.compute_api.snapshot_volume_backed( context, instance, image_name, extra_properties=props) else: image = self.compute_api.snapshot(context, instance, image_name, extra_properties=props) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'createImage', id) except exception.Invalid as err: raise exc.HTTPBadRequest(explanation=err.format_message()) # build location of newly-created image entity image_id = str(image['id']) url_prefix = self._view_builder._update_glance_link_prefix( req.application_url) image_ref = common.url_join(url_prefix, context.project_id, 'images', image_id) resp = webob.Response(status_int=202) resp.headers['Location'] = image_ref return resp
def _reset_state(self, req, id, body): """Permit admins to reset the state of a server.""" context = req.environ["compute.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 create(self, req, body=None): context = req.environ['compute.context'] authorize(context) pool = None if body and 'pool' in body: pool = body['pool'] try: address = self.network_api.allocate_floating_ip(context, pool) ip = self.network_api.get_floating_ip_by_address(context, address) except exception.NoMoreFloatingIps: if pool: msg = _("No more floating IPs in pool %s.") % pool else: msg = _("No more floating IPs available.") raise webob.exc.HTTPNotFound(explanation=msg) except exception.FloatingIpLimitExceeded: if pool: msg = _("IP allocation over quota in pool %s.") % pool else: msg = _("IP allocation over quota.") raise webob.exc.HTTPForbidden(explanation=msg) except exception.FloatingIpPoolNotFound as e: raise webob.exc.HTTPNotFound(explanation=e.format_message()) except exception.FloatingIpBadRequest as e: raise webob.exc.HTTPBadRequest(explanation=e.format_message()) return _translate_floating_ip_view(ip)
def update(self, req, image_id, id, body): context = req.environ['compute.context'] try: meta = body['meta'] except KeyError: expl = _('Incorrect request body format') raise exc.HTTPBadRequest(explanation=expl) if id not in meta: expl = _('Request body and URI mismatch') raise exc.HTTPBadRequest(explanation=expl) if len(meta) > 1: expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) image = self._get_image(context, image_id) image['properties'][id] = meta[id] common.check_img_metadata_properties_quota(context, image['properties']) try: self.image_api.update(context, image_id, image, data=None, purge_props=True) except exception.ImageNotAuthorized as e: raise exc.HTTPForbidden(explanation=e.format_message()) return dict(meta=meta)
def _handle_instance_id_request(self, req): instance_id = req.headers.get('X-Instance-ID') tenant_id = req.headers.get('X-Tenant-ID') signature = req.headers.get('X-Instance-ID-Signature') remote_address = req.headers.get('X-Forwarded-For') # Ensure that only one header was passed if instance_id is None: msg = _('X-Instance-ID header is missing from request.') elif signature is None: msg = _('X-Instance-ID-Signature header is missing from request.') elif tenant_id is None: msg = _('X-Tenant-ID header is missing from request.') elif not isinstance(instance_id, six.string_types): msg = _('Multiple X-Instance-ID headers found within request.') elif not isinstance(tenant_id, six.string_types): msg = _('Multiple X-Tenant-ID headers found within request.') else: msg = None if msg: raise webob.exc.HTTPBadRequest(explanation=msg) self._validate_shared_secret(instance_id, signature, remote_address) return self._get_meta_by_instance_id(instance_id, tenant_id, remote_address)
def update(self, req, id, body): """Configure cloudpipe parameters for the project.""" context = req.environ['compute.context'] authorize(context) if id != "configure-project": msg = _("Unknown action %s") % id raise webob.exc.HTTPBadRequest(explanation=msg) project_id = context.project_id networks = objects.NetworkList.get_by_project(context, project_id) try: params = body['configure_project'] vpn_ip = params['vpn_ip'] vpn_port = params['vpn_port'] for network in networks: network.vpn_public_address = vpn_ip network.vpn_public_port = vpn_port network.save() except (TypeError, KeyError, ValueError) as ex: msg = _("Invalid request body: %s") % ex raise webob.exc.HTTPBadRequest(explanation=msg) return webob.Response(status_int=202)
def _validate_input_body(self, body, entity_name): if not self.is_valid_body(body, entity_name): msg = _("the body is invalid.") raise jacket.compute.exception.InvalidInput(reason=msg) subbody = dict(body[entity_name]) expected_fields = ['name', 'policies'] for field in expected_fields: value = subbody.pop(field, None) if not value: msg = _("'%s' is either missing or empty.") % field raise jacket.compute.exception.InvalidInput(reason=msg) if field == 'name': utils.check_string_length(value, field, min_length=1, max_length=255) if not parameter_types.valid_name_regex_obj.search(value): msg = _("Invalid format for name: '%s'") % value raise jacket.compute.exception.InvalidInput(reason=msg) elif field == 'policies': if isinstance(value, list): [utils.check_string_length(v, field, min_length=1, max_length=255) for v in value] self._validate_policies(value) else: msg = _("'%s' is not a list") % value raise jacket.compute.exception.InvalidInput(reason=msg) if subbody: msg = _("unsupported fields: %s") % subbody.keys() raise jacket.compute.exception.InvalidInput(reason=msg)
def create(self, req, body): context = req.environ['compute.context'] authorize(context) sg_rule = self._from_body(body, 'security_group_default_rule') try: values = self._rule_args_to_dict(to_port=sg_rule.get('to_port'), from_port=sg_rule.get('from_port'), ip_protocol=sg_rule.get('ip_protocol'), cidr=sg_rule.get('cidr')) except (exception.InvalidCidr, exception.InvalidInput, exception.InvalidIpProtocol, exception.InvalidPortRange) as ex: raise exc.HTTPBadRequest(explanation=ex.format_message()) if values is None: msg = _('Not enough parameters to build a valid rule.') raise exc.HTTPBadRequest(explanation=msg) if self.security_group_api.default_rule_exists(context, values): msg = _('This default rule already exists.') raise exc.HTTPConflict(explanation=msg) security_group_rule = self.security_group_api.add_default_rules( context, [values])[0] fmt_rule = self._format_security_group_default_rule( security_group_rule) return {'security_group_default_rule': fmt_rule}
def _decrypt_image(self, context, encrypted_filename, encrypted_key, encrypted_iv, decrypted_filename): elevated = context.elevated() try: key = self.cert_rpcapi.decrypt_text(elevated, project_id=context.project_id, text=base64.b64encode(encrypted_key)) except Exception as exc: msg = _('Failed to decrypt private key: %s') % exc raise exception.NovaException(msg) try: iv = self.cert_rpcapi.decrypt_text(elevated, project_id=context.project_id, text=base64.b64encode(encrypted_iv)) except Exception as exc: raise exception.NovaException(_('Failed to decrypt initialization ' 'vector: %s') % exc) try: utils.execute('openssl', 'enc', '-d', '-aes-128-cbc', '-in', '%s' % (encrypted_filename,), '-K', '%s' % (key,), '-iv', '%s' % (iv,), '-out', '%s' % (decrypted_filename,)) except processutils.ProcessExecutionError as exc: raise exception.NovaException(_('Failed to decrypt image file ' '%(image_file)s: %(err)s') % {'image_file': encrypted_filename, 'err': exc.stdout})
def _validate_quota_limit(self, resource, limit, minimum, maximum): # NOTE: -1 is a flag value for unlimited, maximum value is limited # by SQL standard integer type `INT` which is `0x7FFFFFFF`, it's a # general value for SQL, using a hardcoded value here is not a # `nice` way, but it seems like the only way for now: # http://dev.mysql.com/doc/refman/5.0/en/integer-types.html # http://www.postgresql.org/docs/9.1/static/datatype-numeric.html if limit < -1 or limit > db.MAX_INT: msg = (_("Quota limit %(limit)s for %(resource)s " "must be in the range of -1 and %(max)s.") % {'limit': limit, 'resource': resource, 'max': db.MAX_INT}) raise webob.exc.HTTPBadRequest(explanation=msg) def conv_inf(value): return float("inf") if value == -1 else value if conv_inf(limit) < conv_inf(minimum): msg = (_("Quota limit %(limit)s for %(resource)s must " "be greater than or equal to already used and " "reserved %(minimum)s.") % {'limit': limit, 'resource': resource, 'minimum': minimum}) raise webob.exc.HTTPBadRequest(explanation=msg) if conv_inf(limit) > conv_inf(maximum): msg = (_("Quota limit %(limit)s for %(resource)s must be " "less than or equal to %(maximum)s.") % {'limit': limit, 'resource': resource, 'maximum': maximum}) raise webob.exc.HTTPBadRequest(explanation=msg)
def get_vnc_console(self, req, id, body): """Get vnc connection information to access a server.""" context = req.environ['compute.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: 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 sync_instances(self, req, body): """Tell all cells to sync instance info.""" context = req.environ['compute.context'] authorize(context) authorize(context, action="sync_instances") project_id = body.pop('project_id', None) deleted = body.pop('deleted', False) updated_since = body.pop('updated_since', None) if body: msg = _("Only 'updated_since', 'project_id' and 'deleted' are " "understood.") raise exc.HTTPBadRequest(explanation=msg) if isinstance(deleted, six.string_types): try: deleted = strutils.bool_from_string(deleted, strict=True) except ValueError as err: raise exc.HTTPBadRequest(explanation=six.text_type(err)) if updated_since: try: timeutils.parse_isotime(updated_since) except ValueError: msg = _('Invalid changes-since value') raise exc.HTTPBadRequest(explanation=msg) self.cells_rpcapi.sync_instances(context, project_id=project_id, updated_since=updated_since, deleted=deleted)
def remove_from_instance(self, context, instance, security_group_name): """Remove the security group associated with the instance.""" neutron = neutronapi.get_client(context) try: security_group_id = neutronv20.find_resourceid_by_name_or_id( neutron, 'security_group', security_group_name, context.project_id) except n_exc.NeutronClientException as e: exc_info = sys.exc_info() if e.status_code == 404: msg = (_("Security group %(name)s is not found for " "project %(project)s") % {'name': security_group_name, 'project': context.project_id}) self.raise_not_found(msg) else: LOG.exception(_LE("Neutron Error:")) six.reraise(*exc_info) params = {'device_id': instance.uuid} try: ports = neutron.list_ports(**params).get('ports') except n_exc.NeutronClientException: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Neutron Error:")) if not ports: msg = (_("instance_id %s could not be found as device id on" " any ports") % instance.uuid) self.raise_not_found(msg) found_security_group = False for port in ports: try: port.get('security_groups', []).remove(security_group_id) except ValueError: # When removing a security group from an instance the security # group should be on both ports since it was added this way if # done through the compute api. In case it is not a 404 is only # raised if the security group is not found on any of the # ports on the instance. continue updated_port = {'security_groups': port['security_groups']} try: LOG.info(_LI("Adding security group %(security_group_id)s to " "port %(port_id)s"), {'security_group_id': security_group_id, 'port_id': port['id']}) neutron.update_port(port['id'], {'port': updated_port}) found_security_group = True except Exception: with excutils.save_and_reraise_exception(): LOG.exception(_LE("Neutron Error:")) if not found_security_group: msg = (_("Security group %(security_group_name)s not associated " "with the instance %(instance)s") % {'security_group_name': security_group_name, 'instance': instance.uuid}) self.raise_not_found(msg)
def check_string_length(value, name=None, min_length=0, max_length=None): """Check the length of specified string :param value: the value of the string :param name: the name of the string :param min_length: the min_length of the string :param max_length: the max_length of the string """ if not isinstance(value, six.string_types): if name is None: msg = _("The input is not a string or unicode") else: msg = _("%s is not a string or unicode") % name raise exception.InvalidInput(message=msg) if name is None: name = value if len(value) < min_length: msg = _("%(name)s has a minimum character requirement of " "%(min_length)s.") % {'name': name, 'min_length': min_length} raise exception.InvalidInput(message=msg) if max_length and len(value) > max_length: msg = _("%(name)s has more than %(max_length)s " "characters.") % {'name': name, 'max_length': max_length} raise exception.InvalidInput(message=msg)
def show(self, req, server_id, id): """Return data about the given volume attachment.""" context = req.environ['compute.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 _check_extra_specs(self, specs): if type(specs) is not dict: msg = _('Bad extra_specs provided') raise exc.HTTPBadRequest(explanation=msg) try: flavors.validate_extra_spec_keys(specs.keys()) except TypeError: msg = _("Fail to validate provided extra specs keys. " "Expected string") raise exc.HTTPBadRequest(explanation=msg) except exception.InvalidInput as error: raise exc.HTTPBadRequest(explanation=error.format_message()) for key, value in six.iteritems(specs): try: utils.check_string_length(key, 'extra_specs key', min_length=1, max_length=255) # NOTE(dims): The following check was added for backwards # compatibility. if (isinstance(value, float) or type(value) in six.integer_types): value = six.text_type(value) utils.check_string_length(value, 'extra_specs value', max_length=255) except exception.InvalidInput as error: raise exc.HTTPBadRequest(explanation=error.format_message())
def check_shadow_table(migrate_engine, table_name): """This method checks that table with ``table_name`` and corresponding shadow table have same columns. """ meta = MetaData() meta.bind = migrate_engine table = Table(table_name, meta, autoload=True) shadow_table = Table(db._SHADOW_TABLE_PREFIX + table_name, meta, autoload=True) columns = {c.name: c for c in table.columns} shadow_columns = {c.name: c for c in shadow_table.columns} for name, column in columns.items(): if name not in shadow_columns: raise exception.NovaException( _("Missing column %(table)s.%(column)s in shadow table") % {'column': name, 'table': shadow_table.name}) shadow_column = shadow_columns[name] if not isinstance(shadow_column.type, type(column.type)): raise exception.NovaException( _("Different types in %(table)s.%(column)s and shadow table: " "%(c_type)s %(shadow_c_type)s") % {'column': name, 'table': table.name, 'c_type': column.type, 'shadow_c_type': shadow_column.type}) for name, column in shadow_columns.items(): if name not in columns: raise exception.NovaException( _("Extra column %(table)s.%(column)s in shadow table") % {'column': name, 'table': shadow_table.name}) return True
def qemu_img_info(path, format=None): """Return an object containing the parsed output from qemu-img info.""" # TODO(mikal): this code should not be referring to a libvirt specific # flag. # NOTE(sirp): The config option import must go here to avoid an import # cycle CONF.import_opt('images_type', 'jacket.compute.virt.libvirt.imagebackend', group='libvirt') if not os.path.exists(path) and CONF.libvirt.images_type != 'rbd': raise exception.DiskNotFound(location=path) try: cmd = ('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) if format is not None: cmd = cmd + ('-f', format) out, err = utils.execute(*cmd, prlimit=QEMU_IMG_LIMITS) except processutils.ProcessExecutionError as exp: msg = (_("qemu-img failed to execute on %(path)s : %(exp)s") % {'path': path, 'exp': exp}) raise exception.InvalidDiskInfo(reason=msg) if not out: msg = (_("Failed to run qemu-img info on %(path)s : %(error)s") % {'path': path, 'error': err}) raise exception.InvalidDiskInfo(reason=msg) return imageutils.QemuImgInfo(out)
def _set_metadata(self, req, id, body): """Replaces the aggregate's existing metadata with new metadata.""" context = _get_context(req) authorize(context) if len(body) != 1: raise exc.HTTPBadRequest() try: metadata = body["metadata"] except KeyError: raise exc.HTTPBadRequest() # The metadata should be a dict if not isinstance(metadata, dict): msg = _('The value of metadata must be a dict') raise exc.HTTPBadRequest(explanation=msg) try: for key, value in metadata.items(): utils.check_string_length(key, "metadata.key", 1, 255) if value is not None: utils.check_string_length(value, "metadata.value", 0, 255) except exception.InvalidInput as e: raise exc.HTTPBadRequest(explanation=e.format_message()) try: aggregate = self.api.update_aggregate_metadata(context, id, metadata) except exception.AggregateNotFound: msg = _('Cannot set metadata %(metadata)s in aggregate' ' %(id)s') % {'metadata': metadata, 'id': id} raise exc.HTTPNotFound(explanation=msg) except exception.InvalidAggregateAction as e: raise exc.HTTPBadRequest(explanation=e.format_message()) return self._marshall_aggregate(aggregate)
def create(self, req, server_id, body): """Attach an interface to an instance.""" context = req.environ['compute.context'] authorize(context) network_id = None port_id = None req_ip = None if body: attachment = body['interfaceAttachment'] network_id = attachment.get('net_id', None) port_id = attachment.get('port_id', None) try: req_ip = attachment['fixed_ips'][0]['ip_address'] except Exception: pass if network_id and port_id: msg = _("Must not input both network_id and port_id") raise exc.HTTPBadRequest(explanation=msg) if req_ip and not network_id: msg = _("Must input network_id when request IP address") raise exc.HTTPBadRequest(explanation=msg) if req_ip: try: netaddr.IPAddress(req_ip) except netaddr.AddrFormatError as e: raise exc.HTTPBadRequest(explanation=six.text_type(e)) try: instance = common.get_instance(self.compute_api, context, server_id) LOG.info(_LI("Attach interface"), instance=instance) vif = self.compute_api.attach_interface(context, instance, network_id, port_id, req_ip) except (exception.PortNotFound, exception.NetworkNotFound) as e: raise exc.HTTPNotFound(explanation=e.format_message()) except (exception.FixedIpAlreadyInUse, exception.InterfaceAttachFailedNoNetwork, exception.NoMoreFixedIps, exception.PortInUse, exception.NetworkDuplicated, exception.NetworkAmbiguous, exception.PortNotUsable) as e: raise exc.HTTPBadRequest(explanation=e.format_message()) except exception.InstanceIsLocked as e: raise exc.HTTPConflict(explanation=e.format_message()) except NotImplementedError: msg = _("Network driver does not support this function.") raise webob.exc.HTTPNotImplemented(explanation=msg) except exception.InterfaceAttachFailed: msg = _("Failed to attach interface") raise webob.exc.HTTPInternalServerError(explanation=msg) except exception.InstanceInvalidState as state_error: common.raise_http_conflict_for_instance_invalid_state(state_error, 'attach_interface', server_id) return self.show(req, server_id, vif['id'])
def create(self, req, body): context = sg._authorize_context(req) authorize(context) # NOTE(shaohe-feng): back-compatible with db layer hard-code # admin permission checks. nova_context.require_admin_context(context) sg_rule = self._from_body(body, 'security_group_default_rule') try: values = self._rule_args_to_dict(to_port=sg_rule.get('to_port'), from_port=sg_rule.get('from_port'), ip_protocol=sg_rule.get('ip_protocol'), cidr=sg_rule.get('cidr')) except Exception as exp: raise exc.HTTPBadRequest(explanation=six.text_type(exp)) if values is None: msg = _('Not enough parameters to build a valid rule.') raise exc.HTTPBadRequest(explanation=msg) if self.security_group_api.default_rule_exists(context, values): msg = _('This default rule already exists.') raise exc.HTTPConflict(explanation=msg) security_group_rule = self.security_group_api.add_default_rules( context, [values])[0] fmt_rule = self._format_security_group_default_rule( security_group_rule) return {'security_group_default_rule': fmt_rule}
def _disassociate_host_and_project(self, req, id, body): context = req.environ['compute.context'] authorize(context) # NOTE(shaohe-feng): back-compatible with db layer hard-code # admin permission checks. call db API objects.Network.associate nova_context.require_admin_context(context) try: self.network_api.associate(context, id, host=None, project=None) except exception.NetworkNotFound: msg = _("Network not found") raise exc.HTTPNotFound(explanation=msg) except NotImplementedError: msg = _('Disassociate network is not implemented by the ' 'configured Network API') raise exc.HTTPNotImplemented(explanation=msg) return webob.Response(status_int=202)
def check_detach(self, context, volume, instance=None): # TODO(vish): abstract status checking? if volume['status'] == "available": msg = _("volume %s already detached") % volume['id'] raise exception.InvalidVolume(reason=msg) if volume['attach_status'] == 'detached': msg = _("Volume must be attached in order to detach.") raise exception.InvalidVolume(reason=msg) # NOTE(ildikov):Preparation for multiattach support, when a volume # can be attached to multiple hosts and/or instances, # so just check the attachment specific to this instance if instance is not None and instance.uuid not in volume['attachments']: # TODO(ildikov): change it to a better exception, when enable # multi-attach. raise exception.VolumeUnattached(volume_id=volume['id'])
def check_attached(self, context, volume): if volume['status'] != "in-use": msg = _("volume '%(vol)s' status must be 'in-use'. Currently in " "'%(status)s' status") % { "vol": volume['id'], "status": volume['status'] } raise exception.InvalidVolume(reason=msg)
def create_cloned_volume(self, volume, src_vref): """Create a clone of the specified volume.""" context = req_context.RequestContext(is_admin=True, project_id=volume.project_id) snapshot = None try: src_vol = self._get_provider_volume_id(context, src_vref) snapshot = self._aws_client.get_aws_client(context).\ create_snapshot(VolumeId=src_vol) provider_vol = self._create_volume(volume, context, snapshot=snapshot['SnapshotId']) except Exception as ex: LOG.error( _LE("create_cloned_volume failed! volume:%(id)s," "ex: %(ex)s"), { 'id': volume.id, 'ex': ex }) msg = (_("create_cloned_volume failed! volume:%s") % volume.id) raise cinder_ex.VolumeBackendAPIException(data=msg) finally: if snapshot: self._aws_client.get_aws_client(context).\ delete_snapshot( SnapshotId=snapshot['SnapshotId'] ) # create local volume mapper try: values = {'provider_volume_id': provider_vol['VolumeId']} self.caa_db_api.volume_mapper_create(context, volume.id, context.project_id, values) except Exception as ex: LOG.error( _LE("volume_mapper_create failed! vol:%(id)s," " ex = %(ex)s"), { 'id': volume.id, 'ex': ex }) self._aws_client.get_aws_client(context).\ delete_volume(VolumeId=provider_vol['VolumeId']) msg = (_("volume_mapper_create failed! volume:%s") % volume.id) raise cinder_ex.VolumeBackendAPIException(data=msg) LOG.debug('create volume %s success.' % volume.id)
def get_verifier(context, img_signature_certificate_uuid, img_signature_hash_method, img_signature, img_signature_key_type): """Instantiate signature properties and use them to create a verifier. :param context: the user context for authentication :param img_signature_certificate_uuid: uuid of signing certificate stored in key manager :param img_signature_hash_method: string denoting hash method used to compute signature :param img_signature: string of base64 encoding of signature :param img_signature_key_type: string denoting type of keypair used to compute signature :returns: instance of cryptography.hazmat.primitives.asymmetric.AsymmetricVerificationContext :raises: SignatureVerificationError if we fail to build the verifier """ image_meta_props = {'img_signature_uuid': img_signature_certificate_uuid, 'img_signature_hash_method': img_signature_hash_method, 'img_signature': img_signature, 'img_signature_key_type': img_signature_key_type} for key in image_meta_props.keys(): if image_meta_props[key] is None: raise exception.SignatureVerificationError( reason=_('Required image properties for signature verification' ' do not exist. Cannot verify signature. Missing' ' property: %s') % key) signature = get_signature(img_signature) hash_method = get_hash_method(img_signature_hash_method) signature_key_type = SignatureKeyType.lookup(img_signature_key_type) public_key = get_public_key(context, img_signature_certificate_uuid, signature_key_type) # create the verifier based on the signature key type verifier = signature_key_type.create_verifier(signature, hash_method, public_key) if verifier: return verifier else: # Error creating the verifier raise exception.SignatureVerificationError( reason=_('Error occurred while creating the verifier'))
def show(self, req, id): context = req.environ['compute.context'] authorize(context) try: network = self.network_api.get(context, id) except exception.NetworkNotFound: msg = _("Network not found") raise exc.HTTPNotFound(explanation=msg) return {'network': network_dict(network)}
def to_global(prefix, mac, project_id): project_hash = netaddr.IPAddress( int(hashlib.sha1(project_id).hexdigest()[:8], 16) << 32) static_num = netaddr.IPAddress(0xff << 24) try: mac_suffix = netaddr.EUI(mac).words[3:] int_addr = int(''.join(['%02x' % i for i in mac_suffix]), 16) mac_addr = netaddr.IPAddress(int_addr) maskIP = netaddr.IPNetwork(prefix).ip return (project_hash ^ static_num ^ mac_addr | maskIP).format() except netaddr.AddrFormatError: raise TypeError(_('Bad mac for to_global_ipv6: %s') % mac) except TypeError: raise TypeError(_('Bad prefix for to_global_ipv6: %s') % prefix) except NameError: raise TypeError( _('Bad project_id for to_global_ipv6: %s') % project_id)
def create(self, req, body): """Creates a new volume.""" context = req.environ['compute.context'] authorize(context) if not self.is_valid_body(body, 'volume'): msg = _("volume not specified") raise exc.HTTPBadRequest(explanation=msg) vol = body['volume'] vol_type = vol.get('volume_type', None) metadata = vol.get('metadata', None) snapshot_id = vol.get('snapshot_id') if snapshot_id is not None: try: snapshot = self.volume_api.get_snapshot(context, snapshot_id) except exception.SnapshotNotFound as e: raise exc.HTTPNotFound(explanation=e.format_message()) else: snapshot = None size = vol.get('size', None) if size is None and snapshot is not None: size = snapshot['volume_size'] LOG.info(_LI("Create volume of %s GB"), size, context=context) availability_zone = vol.get('availability_zone', None) try: new_volume = self.volume_api.create( context, size, vol.get('display_name'), vol.get('display_description'), snapshot=snapshot, volume_type=vol_type, metadata=metadata, availability_zone=availability_zone ) except exception.InvalidInput as err: raise exc.HTTPBadRequest(explanation=err.format_message()) except exception.OverQuota as err: raise exc.HTTPForbidden(explanation=err.format_message()) # TODO(vish): Instance should be None at db layer instead of # trying to lazy load, but for now we turn it into # a dict to avoid an error. retval = _translate_volume_detail_view(context, dict(new_volume)) result = {'volume': retval} location = '%s/%s' % (req.url, new_volume['id']) return wsgi.ResponseObject(result, headers=dict(location=location))
def delete(self, req, id): """Delete an image, if allowed. :param req: `wsgi.Request` object :param id: Image identifier (integer) """ context = req.environ['compute.context'] try: self._image_api.delete(context, id) except exception.ImageNotFound: explanation = _("Image not found.") raise webob.exc.HTTPNotFound(explanation=explanation) except exception.ImageNotAuthorized: # The image service raises this exception on delete if glanceclient # raises HTTPForbidden. explanation = _("You are not allowed to delete the image.") raise webob.exc.HTTPForbidden(explanation=explanation) return webob.exc.HTTPNoContent()
def _remove_host(self, req, id, body): """Removes a host from the specified aggregate.""" host = body['remove_host']['host'] context = _get_context(req) authorize(context, action='remove_host') try: aggregate = self.api.remove_host_from_aggregate(context, id, host) except (exception.AggregateNotFound, exception.AggregateHostNotFound, exception.ComputeHostNotFound): msg = _('Cannot remove host %(host)s in aggregate %(id)s') % { 'host': host, 'id': id} raise exc.HTTPNotFound(explanation=msg) except exception.InvalidAggregateAction: msg = _('Cannot remove host %(host)s in aggregate %(id)s') % { 'host': host, 'id': id} raise exc.HTTPConflict(explanation=msg) return self._marshall_aggregate(aggregate)
def update_all(self, req, server_id, body): try: metadata = body['metadata'] except (TypeError, KeyError): expl = _('Malformed request body') raise exc.HTTPBadRequest(explanation=expl) if not isinstance(metadata, dict): msg = _("Malformed request body. metadata must be object") raise exc.HTTPBadRequest(explanation=msg) context = req.environ['compute.context'] new_metadata = self._update_instance_metadata(context, server_id, metadata, delete=True) return {'metadata': new_metadata}
def _call_livem_checks_on_host(self, destination): try: self.migrate_data = self.compute_rpcapi.\ check_can_live_migrate_destination(self.context, self.instance, destination, self.block_migration, self.disk_over_commit) except messaging.MessagingTimeout: msg = _("Timeout while checking if we can live migrate to host: " "%s") % destination raise exception.MigrationPreCheckError(msg)
def _test_pci(self): pci_requests = objects.InstancePCIRequests.\ get_by_instance_uuid_and_newness( self.context, self.instance.uuid, True) if pci_requests.requests: claim = self.tracker.pci_tracker.stats.support_requests( pci_requests.requests) if not claim: return _('Claim pci failed.')
def _get_instance(self, context, instance_uuid): try: attrs = ['system_metadata', 'metadata'] return objects.Instance.get_by_uuid(context, instance_uuid, expected_attrs=attrs) except exception.NotFound: msg = _("Instance not found") raise webob.exc.HTTPNotFound(explanation=msg)
def _disable_log_reason(self, body, context): """Disable scheduling for a service with a log.""" try: reason = body['disabled_reason'] except KeyError: msg = _('Missing disabled reason field') raise webob.exc.HTTPBadRequest(explanation=msg) return self._disable(body, context, reason)
def purge(self, age_in_days): """Purge deleted rows older than a given age from jacket tables.""" age_in_days = int(age_in_days) if age_in_days <= 0: print(_("Must supply a positive, non-zero value for age")) sys.exit(1) if age_in_days >= (int(time.time()) / 86400): print(_("Maximum age is count of days since epoch.")) sys.exit(1) ctxt = context.get_admin_context() try: db.purge_deleted_rows(ctxt, age_in_days) except db_exc.DBReferenceError: print( _("Purge command failed, check jacket-manage " "logs for more details.")) sys.exit(1)
def delete_key(self, ctxt, key_id, **kwargs): if ctxt is None: raise exception.Forbidden() if key_id != self.key_id: raise exception.KeyManagerError( reason=_("cannot delete non-existent key")) LOG.warning(_LW("Not deleting key %s"), key_id)
def coerce(obj, attr, value): if isinstance(value, network_model.NetworkInfo): return value elif isinstance(value, six.string_types): # Hmm, do we need this? return network_model.NetworkInfo.hydrate(value) else: raise ValueError( _('A NetworkModel is required in field %s') % attr)
def get_console_output(self, req, id, body): """Get text console output.""" context = req.environ['compute.context'] authorize(context) instance = common.get_instance(self.compute_api, context, id) try: length = body['os-getConsoleOutput'].get('length') except (TypeError, KeyError): raise webob.exc.HTTPBadRequest( _('os-getConsoleOutput malformed ' 'or missing from request body')) if length is not None: try: # NOTE(maurosr): cast length into a string before cast into an # integer to avoid thing like: int(2.5) which is 2 instead of # raise ValueError like it would when we try int("2.5"). This # can be removed once we have api validation landed. int(str(length)) except ValueError: raise webob.exc.HTTPBadRequest( _('Length in request body must ' 'be an integer value')) try: output = self.compute_api.get_console_output( context, instance, length) except exception.ConsoleNotAvailable as e: raise webob.exc.HTTPNotFound(explanation=e.format_message()) except exception.NotFound: msg = _('Unable to get console') raise webob.exc.HTTPNotFound(explanation=msg) 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 remove_re = re.compile('[\x00-\x08\x0B-\x1F]') output = remove_re.sub('', output) return {'output': output}
def _get_flavors(self, req): """Helper function that returns a list of flavor dicts.""" filters = {} sort_key = req.params.get('sort_key') or 'flavorid' sort_dir = req.params.get('sort_dir') or 'asc' limit, marker = common.get_limit_and_marker(req) context = req.environ['compute.context'] if context.is_admin: # Only admin has query access to all flavor types filters['is_public'] = self._parse_is_public( req.params.get('is_public', None)) else: filters['is_public'] = True filters['disabled'] = False if 'minRam' in req.params: try: filters['min_memory_mb'] = int(req.params['minRam']) except ValueError: msg = _('Invalid min_ram filter [%s]') % req.params['minRam'] raise webob.exc.HTTPBadRequest(explanation=msg) if 'minDisk' in req.params: try: filters['min_root_gb'] = int(req.params['minDisk']) except ValueError: msg = (_('Invalid minDisk filter [%s]') % req.params['minDisk']) raise webob.exc.HTTPBadRequest(explanation=msg) try: limited_flavors = flavors.get_all_flavors_sorted_list( context, filters=filters, sort_key=sort_key, sort_dir=sort_dir, limit=limit, marker=marker) except exception.MarkerNotFound: msg = _('marker [%s] not found') % marker raise webob.exc.HTTPBadRequest(explanation=msg) return limited_flavors
def __init__(self, name, app, host='0.0.0.0', port=0, pool_size=None, protocol=eventlet.wsgi.HttpProtocol, backlog=128, use_ssl=False, max_url_len=None): """Initialize, but do not start, a WSGI server. :param name: Pretty name for logging. :param app: The WSGI application to serve. :param host: IP address to serve the application. :param port: Port number to server the application. :param pool_size: Maximum number of eventlets to spawn concurrently. :param backlog: Maximum number of queued connections. :param max_url_len: Maximum length of permitted URLs. :returns: None :raises: compute.exception.InvalidInput """ # Allow operators to customize http requests max header line size. eventlet.wsgi.MAX_HEADER_LINE = CONF.max_header_line self.name = name self.app = app self._server = None self._protocol = protocol self.pool_size = pool_size or self.default_pool_size self._pool = eventlet.GreenPool(self.pool_size) self._logger = logging.getLogger("compute.%s.wsgi.server" % self.name) self._use_ssl = use_ssl self._max_url_len = max_url_len self.client_socket_timeout = CONF.client_socket_timeout or None if backlog < 1: raise exception.InvalidInput( reason=_('The backlog must be more than 0')) bind_addr = (host, port) # TODO(dims): eventlet's green dns/socket module does not actually # support IPv6 in getaddrinfo(). We need to get around this in the # future or monitor upstream for a fix try: info = socket.getaddrinfo(bind_addr[0], bind_addr[1], socket.AF_UNSPEC, socket.SOCK_STREAM)[0] family = info[0] bind_addr = info[-1] except Exception: family = socket.AF_INET try: self._socket = eventlet.listen(bind_addr, family, backlog=backlog) except EnvironmentError: LOG.error(_LE("Could not bind to %(host)s:%(port)s"), {'host': host, 'port': port}) raise (self.host, self.port) = self._socket.getsockname()[0:2] LOG.info(_LI("%(name)s listening on %(host)s:%(port)s"), {'name': self.name, 'host': self.host, 'port': self.port})
def create(self, req, body): """Create or import keypair. Sending name will generate a key and return private_key and fingerprint. You can send a public_key to add an existing ssh key params: keypair object with: name (required) - string public_key (optional) - string """ context = req.environ['compute.context'] authorize(context, action='create') try: params = body['keypair'] name = params['name'] except KeyError: msg = _("Invalid request body") raise webob.exc.HTTPBadRequest(explanation=msg) try: if 'public_key' in params: keypair = self.api.import_key_pair(context, context.user_id, name, params['public_key']) keypair = self._filter_keypair(keypair, user_id=True) else: keypair, private_key = self.api.create_key_pair( context, context.user_id, name) keypair = self._filter_keypair(keypair, user_id=True) keypair['private_key'] = private_key return {'keypair': keypair} except exception.KeypairLimitExceeded: msg = _("Quota exceeded, too many key pairs.") raise webob.exc.HTTPForbidden(explanation=msg) except exception.InvalidKeypair as exc: raise webob.exc.HTTPBadRequest(explanation=exc.format_message()) except exception.KeyPairExists as exc: raise webob.exc.HTTPConflict(explanation=exc.format_message())
def show(self, req, server_id, id): """Return a single metadata item.""" context = req.environ['compute.context'] data = self._get_metadata(context, server_id) try: return {'meta': {id: data[id]}} except KeyError: msg = _("Metadata item was not found") raise exc.HTTPNotFound(explanation=msg)
def verify_certificate(certificate): """Verify that the certificate has not expired. :param certificate: the cryptography certificate object :raises: SignatureVerificationError if the certificate valid time range does not include now """ # Get now in UTC, since certificate returns times in UTC now = timeutils.utcnow() # Confirm the certificate valid time range includes now if now < certificate.not_valid_before: raise exception.SignatureVerificationError( reason=_('Certificate is not valid before: %s UTC') % certificate.not_valid_before) elif now > certificate.not_valid_after: raise exception.SignatureVerificationError( reason=_('Certificate is not valid after: %s UTC') % certificate.not_valid_after)
def coerce(obj, attr, value): result = IPAddress.coerce(obj, attr, value) if result.version != 4 and result.version != 6: raise ValueError( _('Network "%(val)s" is not valid ' 'in field %(attr)s') % { 'val': value, 'attr': attr }) return result
def update(self, req, flavor_id, id, body): context = req.environ['compute.context'] authorize(context, action='update') self._check_extra_specs(body) if id not in body: expl = _('Request body and URI mismatch') raise exc.HTTPBadRequest(explanation=expl) if len(body) > 1: expl = _('Request body contains too many items') raise exc.HTTPBadRequest(explanation=expl) flavor = common.get_flavor(context, flavor_id) try: flavor.extra_specs = dict(flavor.extra_specs, **body) flavor.save() except exception.FlavorExtraSpecUpdateCreateFailed as e: raise exc.HTTPConflict(explanation=e.format_message()) except exception.FlavorNotFound as error: raise exc.HTTPNotFound(explanation=error.format_message()) return body
def show(self, req, server_id, id): context = req.environ["compute.context"] authorize(context, action='show') 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 _verify_resources(self, resources): resource_keys = [ "vcpus", "memory_mb", "local_gb", "cpu_info", "vcpus_used", "memory_mb_used", "local_gb_used", "numa_topology" ] missing_keys = [k for k in resource_keys if k not in resources] if missing_keys: reason = _("Missing keys: %s") % missing_keys raise exception.InvalidInput(reason=reason)
def _disassociate_project_only(self, req, id, body): context = req.environ['compute.context'] authorize(context) try: self.network_api.associate(context, id, project=None) except exception.NetworkNotFound: msg = _("Network not found") raise exc.HTTPNotFound(explanation=msg) except NotImplementedError: common.raise_feature_not_supported()
def __call__(self, req): user_id = req.headers.get('X_USER') user_id = req.headers.get('X_USER_ID', user_id) if user_id is None: LOG.debug("Neither X_USER_ID nor X_USER found in request") return webob.exc.HTTPUnauthorized() roles = self._get_roles(req) if 'X_TENANT_ID' in req.headers: # This is the new header since Keystone went to ID/Name project_id = req.headers['X_TENANT_ID'] else: # This is for legacy compatibility project_id = req.headers['X_TENANT'] project_name = req.headers.get('X_TENANT_NAME') user_name = req.headers.get('X_USER_NAME') req_id = req.environ.get(request_id.ENV_REQUEST_ID) # Get the auth token auth_token = req.headers.get('X_AUTH_TOKEN', req.headers.get('X_STORAGE_TOKEN')) # Build a context, including the auth_token... remote_address = req.remote_addr if CONF.use_forwarded_for: remote_address = req.headers.get('X-Forwarded-For', remote_address) service_catalog = None if req.headers.get('X_SERVICE_CATALOG') is not None: try: catalog_header = req.headers.get('X_SERVICE_CATALOG') service_catalog = jsonutils.loads(catalog_header) except ValueError: raise webob.exc.HTTPInternalServerError( _('Invalid service catalog json.')) # NOTE(jamielennox): This is a full auth plugin set by auth_token # middleware in newer versions. user_auth_plugin = req.environ.get('keystone.token_auth') ctx = context.RequestContext(user_id, project_id, user_name=user_name, project_name=project_name, roles=roles, auth_token=auth_token, remote_address=remote_address, service_catalog=service_catalog, request_id=req_id, user_auth_plugin=user_auth_plugin) req.environ['compute.context'] = ctx return self.application