Example #1
0
    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)
Example #2
0
    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
Example #3
0
    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)
Example #4
0
    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)}
Example #5
0
    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}
Example #6
0
    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."))
Example #7
0
    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})
Example #8
0
    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
Example #9
0
    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}}
Example #10
0
    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
Example #11
0
    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)
Example #12
0
    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)
Example #13
0
    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)
Example #14
0
    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)
Example #15
0
    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)
Example #16
0
    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}
Example #18
0
    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})
Example #19
0
    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)
Example #20
0
    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']}}
Example #21
0
    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)
Example #22
0
    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)
Example #23
0
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)
Example #24
0
    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)}
Example #25
0
    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())
Example #26
0
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
Example #27
0
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)
Example #28
0
    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)
Example #29
0
    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}
Example #31
0
    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)
Example #32
0
    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'])
Example #33
0
 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)
Example #34
0
    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)
Example #35
0
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'))
Example #36
0
 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)}
Example #37
0
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)
Example #38
0
    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))
Example #39
0
    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()
Example #40
0
    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)
Example #41
0
    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}
Example #42
0
 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)
Example #43
0
 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.')
Example #44
0
 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)
Example #45
0
    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)
Example #46
0
    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)
Example #47
0
    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)
Example #48
0
 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)
Example #49
0
    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}
Example #50
0
    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
Example #51
0
    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})
Example #52
0
    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())
Example #53
0
    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)
Example #54
0
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)
Example #55
0
 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
Example #56
0
 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
Example #57
0
    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)
Example #58
0
    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)
Example #59
0
 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()
Example #60
0
    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