Example #1
0
    def delete(self, req, id):
        context = req.environ['patron.context']
        authorize(context)

        # get the floating ip object
        try:
            floating_ip = self.network_api.get_floating_ip(context, id)
        except (exception.NotFound, exception.FloatingIpNotFound):
            msg = _("Floating ip not found for id %s") % id
            raise webob.exc.HTTPNotFound(explanation=msg)
        except exception.InvalidID as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())

        address = floating_ip['address']

        # get the associated instance object (if any)
        instance = get_instance_by_floating_ip_addr(self, context, address)
        try:
            self.network_api.disassociate_and_release_floating_ip(
                context, instance, floating_ip)
        except exception.Forbidden:
            raise webob.exc.HTTPForbidden()
        except exception.CannotDisassociateAutoAssignedFloatingIP:
            msg = _('Cannot disassociate auto assigned floating ip')
            raise webob.exc.HTTPForbidden(explanation=msg)
Example #2
0
    def add_to_instance(self, context, instance, security_group_name):
        """Add security group to 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.NeutronClientNoUniqueMatch as e:
            raise exception.NoUniqueMatch(six.text_type(e))
        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:"))
                raise exc_info[0], exc_info[1], exc_info[2]
        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)

        for port in ports:
            if not self._has_security_group_requirements(port):
                LOG.warning(
                    _LW("Cannot add security group %(name)s to "
                        "%(instance)s since the port %(port_id)s "
                        "does not meet security requirements"), {
                            'name': security_group_name,
                            'instance': instance.uuid,
                            'port_id': port['id']
                        })
                raise exception.SecurityGroupCannotBeApplied()
            if 'security_groups' not in port:
                port['security_groups'] = []
            port['security_groups'].append(security_group_id)
            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})
            except Exception:
                with excutils.save_and_reraise_exception():
                    LOG.exception(_LE("Neutron Error:"))
Example #3
0
    def clone(self, context, image_id_or_uri):
        if not self.driver.supports_layering():
            reason = _('installed version of librbd does not support cloning')
            raise exception.ImageUnacceptable(image_id=image_id_or_uri,
                                              reason=reason)

        image_meta = IMAGE_API.get(context,
                                   image_id_or_uri,
                                   include_locations=True)
        locations = image_meta['locations']

        LOG.debug('Image locations are: %(locs)s' % {'locs': locations})

        if image_meta.get('disk_format') not in ['raw', 'iso']:
            reason = _('Image is not raw format')
            raise exception.ImageUnacceptable(image_id=image_id_or_uri,
                                              reason=reason)

        for location in locations:
            if self.driver.is_cloneable(location, image_meta):
                return self.driver.clone(location, self.rbd_name)

        reason = _('No image locations are accessible')
        raise exception.ImageUnacceptable(image_id=image_id_or_uri,
                                          reason=reason)
Example #4
0
    def _parse_white_list_from_config(self, whitelists):
        """Parse and validate the pci whitelist from the patron config."""
        specs = []
        for jsonspec in whitelists:
            try:
                dev_spec = jsonutils.loads(jsonspec)
            except ValueError:
                raise exception.PciConfigInvalidWhitelist(
                          reason=_("Invalid entry: '%s'") % jsonspec)
            if isinstance(dev_spec, dict):
                dev_spec = [dev_spec]
            elif not isinstance(dev_spec, list):
                raise exception.PciConfigInvalidWhitelist(
                          reason=_("Invalid entry: '%s'; "
                                   "Expecting list or dict") % jsonspec)

            for ds in dev_spec:
                if not isinstance(ds, dict):
                    raise exception.PciConfigInvalidWhitelist(
                              reason=_("Invalid entry: '%s'; "
                                       "Expecting dict") % ds)

                spec = devspec.PciDeviceSpec(ds)
                specs.append(spec)

        return specs
Example #5
0
    def create(self, req, body=None):
        context = req.environ['patron.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())

        return _translate_floating_ip_view(ip)
Example #6
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 #7
0
    def show(self, req, domain_id, id):
        """Return the DNS entry that corresponds to domain_id and id."""
        context = req.environ['patron.context']
        authorize(context)
        domain = _unquote_domain(domain_id)

        floating_ip = None
        # Check whether id is a valid ipv4/ipv6 address.
        if netutils.is_valid_ip(id):
            floating_ip = id

        try:
            if floating_ip:
                entries = self.network_api.get_dns_entries_by_address(
                    context, floating_ip, domain)
            else:
                entries = self.network_api.get_dns_entries_by_name(
                    context, id, domain)
        except NotImplementedError:
            msg = _("Unable to get dns entry")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        if not entries:
            explanation = _("DNS entries not found.")
            raise webob.exc.HTTPNotFound(explanation=explanation)

        if floating_ip:
            entrylist = [_create_dns_entry(floating_ip, entry, domain)
                         for entry in entries]
            dns_entries = _translate_dns_entries_view(entrylist)
            return wsgi.ResponseObject(dns_entries)

        entry = _create_dns_entry(entries[0], id, domain)
        return _translate_dns_entry_view(entry)
Example #8
0
    def from_api(cls, api_dict, image_uuid_specified):
        """Transform the API format of data to the internally used one.

        Only validate if the source_type field makes sense.
        """
        if not api_dict.get('no_device'):

            source_type = api_dict.get('source_type')
            device_uuid = api_dict.get('uuid')
            destination_type = api_dict.get('destination_type')

            if source_type not in ('volume', 'image', 'snapshot', 'blank'):
                raise exception.InvalidBDMFormat(
                    details=_("Invalid source_type field."))
            elif source_type == 'blank' and device_uuid:
                raise exception.InvalidBDMFormat(
                    details=_("Invalid device UUID."))
            elif source_type != 'blank':
                if not device_uuid:
                    raise exception.InvalidBDMFormat(
                        details=_("Missing device UUID."))
                api_dict[source_type + '_id'] = device_uuid
            if source_type == 'image' and destination_type == 'local':
                boot_index = api_dict.get('boot_index', -1)

                # if this bdm is generated from --image ,then
                # source_type = image and destination_type = local is allowed
                if not (image_uuid_specified and boot_index == 0):
                    raise exception.InvalidBDMFormat(
                        details=_("Mapping image to local is not supported."))

        api_dict.pop('uuid', None)
        return cls(api_dict)
Example #9
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 specs.iteritems():
            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, (int, long, float))):
                    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 #10
0
    def update(self, req, id, body):
        context = req.environ['patron.context']
        authorize(context)
        quota_class = id
        bad_keys = []

        if not self.is_valid_body(body, 'quota_class_set'):
            msg = _("quota_class_set not specified")
            raise webob.exc.HTTPBadRequest(explanation=msg)
        quota_class_set = body['quota_class_set']
        for key in quota_class_set.keys():
            if key not in self.supported_quotas:
                bad_keys.append(key)
                continue
            try:
                value = utils.validate_integer(body['quota_class_set'][key],
                                               key)
            except exception.InvalidInput as e:
                raise webob.exc.HTTPBadRequest(explanation=e.format_message())

        if bad_keys:
            msg = _("Bad key(s) %s in quota_set") % ",".join(bad_keys)
            raise webob.exc.HTTPBadRequest(explanation=msg)

        for key in quota_class_set.keys():
            value = utils.validate_integer(body['quota_class_set'][key], key)
            try:
                db.quota_class_update(context, quota_class, key, value)
            except exception.QuotaClassNotFound:
                db.quota_class_create(context, quota_class, key, value)
            except exception.AdminRequired:
                raise webob.exc.HTTPForbidden()

        values = QUOTAS.get_class_quotas(context, quota_class)
        return self._format_quota_set(None, values)
Example #11
0
    def sync_instances(self, req, body):
        """Tell all cells to sync instance info."""
        context = req.environ['patron.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 #12
0
    def get_image_vm_generation(self, root_vhd_path, image_meta):
        image_props = image_meta['properties']
        default_vm_gen = self._hostutils.get_default_vm_generation()
        image_prop_vm = image_props.get(constants.IMAGE_PROP_VM_GEN,
                                        default_vm_gen)
        if image_prop_vm not in self._hostutils.get_supported_vm_types():
            LOG.error(
                _LE('Requested VM Generation %s is not supported on '
                    ' this OS.'), image_prop_vm)
            raise vmutils.HyperVException(
                _('Requested VM Generation %s is not supported on this '
                  'OS.') % image_prop_vm)

        vm_gen = VM_GENERATIONS[image_prop_vm]

        if (vm_gen != constants.VM_GEN_1 and root_vhd_path
                and self._vhdutils.get_vhd_format(root_vhd_path)
                == constants.DISK_FORMAT_VHD):
            LOG.error(
                _LE('Requested VM Generation %s, but provided VHD '
                    'instead of VHDX.'), vm_gen)
            raise vmutils.HyperVException(
                _('Requested VM Generation %s, but provided VHD instead of '
                  'VHDX.') % vm_gen)

        return vm_gen
Example #13
0
    def _validate_input_body(self, body, entity_name):
        if not self.is_valid_body(body, entity_name):
            msg = _("the body is invalid.")
            raise patron.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 patron.exception.InvalidInput(reason=msg)
            if field == 'name':
                utils.check_string_length(value, field,
                                          min_length=1, max_length=255)
                if not common.VALID_NAME_REGEX.search(value):
                    msg = _("Invalid format for name: '%s'") % value
                    raise patron.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 patron.exception.InvalidInput(reason=msg)

        if subbody:
            msg = _("unsupported fields: %s") % subbody.keys()
            raise patron.exception.InvalidInput(reason=msg)
Example #14
0
    def show(self, req, id):
        """Checks a console auth token and returns the related connect info."""
        context = req.environ['patron.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 #15
0
    def get_vnc_console(self, req, id, body):
        """Get vnc connection information to access a server."""
        context = req.environ['patron.context']
        authorize(context)

        # If type is not supplied or unknown, get_vnc_console below will cope
        console_type = body['os-getVNCConsole'].get('type')
        instance = common.get_instance(self.compute_api, context, id)

        try:
            output = self.compute_api.get_vnc_console(context, instance,
                                                      console_type)
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(
                explanation=_('Instance not yet ready'))
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except (exception.ConsoleTypeUnavailable,
                exception.ConsoleTypeInvalid) as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Unable to get vnc console, functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return {'console': {'type': console_type, 'url': output['url']}}
Example #16
0
    def _lookup_torrent_url_fn():
        """Load a "fetcher" func to get the right torrent URL via
        entrypoints.
        """

        if CONF.xenserver.torrent_base_url:

            def _default_torrent_url_fn(image_id):
                return urlparse.urljoin(CONF.xenserver.torrent_base_url,
                                        "%s.torrent" % image_id)

            return _default_torrent_url_fn

        matches = [
            ep for ep in pkg_resources.iter_entry_points(
                'patron.virt.xenapi.vm_utils') if ep.name == 'torrent_url'
        ]

        if not matches:
            raise RuntimeError(
                _('Cannot create default bittorrent URL'
                  ' without torrent_base_url set or'
                  ' torrent URL fetcher extension'))
        elif len(matches) > 1:
            raise RuntimeError(
                _("Multiple torrent URL fetcher extensions"
                  " found. Failing."))
        else:
            ep = matches[0]
            LOG.debug(
                "Loading torrent URL fetcher from entry points"
                " %(ep)s", {'ep': ep})
            fn = ep.load()

        return fn
Example #17
0
 def check_attach(self, context, volume, instance=None):
     # TODO(vish): abstract status checking?
     if volume['status'] != "available":
         msg = _("volume '%(vol)s' status must be 'available'. Currently "
                 "in '%(status)s'") % {
                     'vol': volume['id'],
                     'status': volume['status']
                 }
         raise exception.InvalidVolume(reason=msg)
     if volume['attach_status'] == "attached":
         msg = _("volume %s already attached") % volume['id']
         raise exception.InvalidVolume(reason=msg)
     if instance and not CONF.cinder.cross_az_attach:
         # NOTE(sorrison): If instance is on a host we match against it's AZ
         #                 else we check the intended AZ
         if instance.get('host'):
             instance_az = az.get_instance_availability_zone(
                 context, instance)
         else:
             instance_az = instance['availability_zone']
         if instance_az != volume['availability_zone']:
             msg = _("Instance %(instance)s and volume %(vol)s are not in "
                     "the same availability_zone. Instance is in "
                     "%(ins_zone)s. Volume is in %(vol_zone)s") % {
                         "instance": instance['id'],
                         "vol": volume['id'],
                         'ins_zone': instance_az,
                         'vol_zone': volume['availability_zone']
                     }
             raise exception.InvalidVolume(reason=msg)
Example #18
0
    def from_api(cls, api_dict, image_uuid_specified):
        """Transform the API format of data to the internally used one.

        Only validate if the source_type field makes sense.
        """
        if not api_dict.get('no_device'):

            source_type = api_dict.get('source_type')
            device_uuid = api_dict.get('uuid')
            destination_type = api_dict.get('destination_type')

            if source_type not in ('volume', 'image', 'snapshot', 'blank'):
                raise exception.InvalidBDMFormat(
                    details=_("Invalid source_type field."))
            elif source_type == 'blank' and device_uuid:
                raise exception.InvalidBDMFormat(
                    details=_("Invalid device UUID."))
            elif source_type != 'blank':
                if not device_uuid:
                    raise exception.InvalidBDMFormat(
                        details=_("Missing device UUID."))
                api_dict[source_type + '_id'] = device_uuid
            if source_type == 'image' and destination_type == 'local':
                boot_index = api_dict.get('boot_index', -1)

                # if this bdm is generated from --image ,then
                # source_type = image and destination_type = local is allowed
                if not (image_uuid_specified and boot_index == 0):
                    raise exception.InvalidBDMFormat(
                        details=_("Mapping image to local is not supported."))

        api_dict.pop('uuid', None)
        return cls(api_dict)
Example #19
0
    def create(self, req, body):
        """Creates a new snapshot."""
        context = req.environ['patron.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 #20
0
    def _remove_floating_ip(self, req, id, body):
        """Dissociate floating_ip from an instance."""
        context = req.environ['patron.context']
        authorize(context)

        address = body['removeFloatingIp']['address']

        # get the floating ip object
        try:
            floating_ip = self.network_api.get_floating_ip_by_address(
                context, address)
        except exception.FloatingIpNotFoundForAddress:
            msg = _("floating ip not found")
            raise webob.exc.HTTPNotFound(explanation=msg)

        # get the associated instance object (if any)
        instance = get_instance_by_floating_ip_addr(self, context, address)

        # disassociate if associated
        if (instance and floating_ip.get('fixed_ip_id')
                and (uuidutils.is_uuid_like(id) and [instance.uuid == id]
                     or [instance.id == id])[0]):
            try:
                disassociate_floating_ip(self, context, instance, address)
            except exception.FloatingIpNotAssociated:
                msg = _('Floating ip is not associated')
                raise webob.exc.HTTPBadRequest(explanation=msg)
            return webob.Response(status_int=202)
        else:
            msg = _("Floating ip %(address)s is not associated with instance "
                    "%(id)s.") % {
                        'address': address,
                        'id': id
                    }
            raise webob.exc.HTTPConflict(explanation=msg)
Example #21
0
    def _update_instance_metadata(self, context, server_id, metadata,
                                  delete=False):
        try:
            server = common.get_instance(self.compute_api, context, server_id)
            return self.compute_api.update_instance_metadata(context,
                                                             server,
                                                             metadata,
                                                             delete)

        except exception.InstanceNotFound:
            msg = _('Server does not exist')
            raise exc.HTTPNotFound(explanation=msg)

        except (ValueError, AttributeError):
            msg = _("Malformed request body")
            raise exc.HTTPBadRequest(explanation=msg)

        except exception.InvalidMetadata as error:
            raise exc.HTTPBadRequest(explanation=error.format_message())

        except exception.InvalidMetadataSize as error:
            raise exc.HTTPRequestEntityTooLarge(
                explanation=error.format_message())

        except exception.QuotaError as error:
            raise exc.HTTPForbidden(explanation=error.format_message())

        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())

        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'update metadata', server_id)
Example #22
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.PatronException(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.PatronException(
                _('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.PatronException(
                _('Failed to decrypt image file '
                  '%(image_file)s: %(err)s') % {
                      'image_file': encrypted_filename,
                      'err': exc.stdout
                  })
Example #23
0
    def update(self, req, server_id, id, body):
        try:
            meta_item = body['meta']
        except (TypeError, KeyError):
            expl = _('Malformed request body')
            raise exc.HTTPBadRequest(explanation=expl)

        if not isinstance(meta_item, dict):
            msg = _("Malformed request body. meta item must be object")
            raise exc.HTTPBadRequest(explanation=msg)

        if id not in meta_item:
            expl = _('Request body and URI mismatch')
            raise exc.HTTPBadRequest(explanation=expl)

        if len(meta_item) > 1:
            expl = _('Request body contains too many items')
            raise exc.HTTPBadRequest(explanation=expl)

        context = req.environ['patron.context']
        self._update_instance_metadata(context,
                                       server_id,
                                       meta_item,
                                       delete=False)

        return {'meta': meta_item}
Example #24
0
    def show(self, req, id):
        """Checks a console auth token and returns the related connect info."""
        context = req.environ['patron.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 #25
0
    def show(self, req, server_id, id):
        """Return data about the given volume attachment."""
        context = req.environ['patron.context']
        authorize(context)
        authorize_attach(context, action='show')

        volume_id = id
        instance = common.get_instance(self.compute_api, context, server_id)

        bdms = objects.BlockDeviceMappingList.get_by_instance_uuid(
                context, instance.uuid)

        if not bdms:
            msg = _("Instance %s is not attached.") % server_id
            raise exc.HTTPNotFound(explanation=msg)

        assigned_mountpoint = None

        for bdm in bdms:
            if bdm.volume_id == volume_id:
                assigned_mountpoint = bdm.device_name
                break

        if assigned_mountpoint is None:
            msg = _("volume_id not found: %s") % volume_id
            raise exc.HTTPNotFound(explanation=msg)

        return {'volumeAttachment': _translate_attachment_detail_view(
            volume_id,
            instance.uuid,
            assigned_mountpoint)}
Example #26
0
    def create(self, req, body=None):
        context = req.environ['patron.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())

        return _translate_floating_ip_view(ip)
Example #27
0
    def _validate_quota_limit(self, resource, limit, minimum, maximum):
        # NOTE: -1 is a flag value for unlimited
        if limit < -1:
            msg = (_("Quota limit %(limit)s for %(resource)s "
                     "must be -1 or greater.") % {
                         'limit': limit,
                         'resource': resource
                     })
            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 #28
0
    def _remove_floating_ip(self, req, id, body):
        """Dissociate floating_ip from an instance."""
        context = req.environ['patron.context']
        authorize(context)

        address = body['removeFloatingIp']['address']

        # get the floating ip object
        try:
            floating_ip = self.network_api.get_floating_ip_by_address(context,
                                                                      address)
        except exception.FloatingIpNotFoundForAddress:
            msg = _("floating ip not found")
            raise webob.exc.HTTPNotFound(explanation=msg)

        # get the associated instance object (if any)
        instance = get_instance_by_floating_ip_addr(self, context, address)

        # disassociate if associated
        if (instance and
            floating_ip.get('fixed_ip_id') and
            (uuidutils.is_uuid_like(id) and
             [instance.uuid == id] or
             [instance.id == id])[0]):
            try:
                disassociate_floating_ip(self, context, instance, address)
            except exception.FloatingIpNotAssociated:
                msg = _('Floating ip is not associated')
                raise webob.exc.HTTPBadRequest(explanation=msg)
            return webob.Response(status_int=202)
        else:
            msg = _("Floating ip %(address)s is not associated with instance "
                    "%(id)s.") % {'address': address, 'id': id}
            raise webob.exc.HTTPConflict(explanation=msg)
Example #29
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:"))
                raise exc_info[0], exc_info[1], exc_info[2]
        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 patron 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 #30
0
    def get_vnc_console(self, req, id, body):
        """Get vnc connection information to access a server."""
        context = req.environ['patron.context']
        authorize(context)

        # If type is not supplied or unknown, get_vnc_console below will cope
        console_type = body['os-getVNCConsole'].get('type')
        instance = common.get_instance(self.compute_api, context, id)

        try:
            output = self.compute_api.get_vnc_console(context,
                                                      instance,
                                                      console_type)
        except exception.InstanceNotReady as e:
            raise webob.exc.HTTPConflict(
                    explanation=_('Instance not yet ready'))
        except exception.InstanceNotFound as e:
            raise webob.exc.HTTPNotFound(explanation=e.format_message())
        except (exception.ConsoleTypeUnavailable,
                exception.ConsoleTypeInvalid) as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())
        except NotImplementedError:
            msg = _("Unable to get vnc console, functionality not implemented")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return {'console': {'type': console_type, 'url': output['url']}}
Example #31
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 #32
0
    def _lookup_torrent_url_fn():
        """Load a "fetcher" func to get the right torrent URL via
        entrypoints.
        """

        if CONF.xenserver.torrent_base_url:
            def _default_torrent_url_fn(image_id):
                return urlparse.urljoin(CONF.xenserver.torrent_base_url,
                                        "%s.torrent" % image_id)

            return _default_torrent_url_fn

        matches = [ep for ep in
                   pkg_resources.iter_entry_points('patron.virt.xenapi.vm_utils')
                   if ep.name == 'torrent_url']

        if not matches:
            raise RuntimeError(_('Cannot create default bittorrent URL'
                                 ' without torrent_base_url set or'
                                 ' torrent URL fetcher extension'))
        elif len(matches) > 1:
            raise RuntimeError(_("Multiple torrent URL fetcher extensions"
                                 " found. Failing."))
        else:
            ep = matches[0]
            LOG.debug("Loading torrent URL fetcher from entry points"
                      " %(ep)s", {'ep': ep})
            fn = ep.load()

        return fn
Example #33
0
    def create(self, req, body):
        context = sg._authorize_context(req)
        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 #34
0
    def update(self, req, id, body):
        """Add or modify domain entry."""
        context = req.environ['patron.context']
        authorize(context)
        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:
            msg = _("Unable to create dns domain")
            raise webob.exc.HTTPNotImplemented(explanation=msg)

        return _translate_domain_entry_view({'domain': fqdomain,
                                             'scope': scope,
                                             area_name: area})
    def create(self, req, body):
        context = sg._authorize_context(req)
        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 #36
0
    def _validate(self, bdm_dict):
        """Basic data format validations."""
        dict_fields = set(key for key, _ in bdm_dict.iteritems())

        # 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 #37
0
def limited(items, request, max_limit=CONF.osapi_max_limit):
    """Return a slice of items according to requested offset and limit.

    :param items: A sliceable entity
    :param request: ``wsgi.Request`` possibly containing 'offset' and 'limit'
                    GET variables. 'offset' is where to start in the list,
                    and 'limit' is the maximum number of items to return. If
                    'limit' is not specified, 0, or > max_limit, we default
                    to max_limit. Negative values for either offset or limit
                    will cause exc.HTTPBadRequest() exceptions to be raised.
    :kwarg max_limit: The maximum number of items to return from 'items'
    """
    try:
        offset = int(request.GET.get('offset', 0))
    except ValueError:
        msg = _('offset param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    try:
        limit = int(request.GET.get('limit', max_limit))
    except ValueError:
        msg = _('limit param must be an integer')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    if limit < 0:
        msg = _('limit param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    if offset < 0:
        msg = _('offset param must be positive')
        raise webob.exc.HTTPBadRequest(explanation=msg)

    limit = min(max_limit, limit or max_limit)
    range_end = offset + limit
    return items[offset:range_end]
Example #38
0
    def _validate(self, bdm_dict):
        """Basic data format validations."""
        dict_fields = set(key for key, _ in bdm_dict.iteritems())

        # 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 #39
0
    def update(self, req, id, body):
        """Configure cloudpipe parameters for the project."""

        context = req.environ['patron.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 #40
0
    def delete(self, req, id):
        context = req.environ['patron.context']
        authorize(context)

        # get the floating ip object
        try:
            floating_ip = self.network_api.get_floating_ip(context, id)
        except (exception.NotFound, exception.FloatingIpNotFound):
            msg = _("Floating ip not found for id %s") % id
            raise webob.exc.HTTPNotFound(explanation=msg)
        except exception.InvalidID as e:
            raise webob.exc.HTTPBadRequest(explanation=e.format_message())

        address = floating_ip['address']

        # get the associated instance object (if any)
        instance = get_instance_by_floating_ip_addr(self, context, address)
        try:
            self.network_api.disassociate_and_release_floating_ip(
                context, instance, floating_ip)
        except exception.Forbidden:
            raise webob.exc.HTTPForbidden()
        except exception.CannotDisassociateAutoAssignedFloatingIP:
            msg = _('Cannot disassociate auto assigned floating ip')
            raise webob.exc.HTTPForbidden(explanation=msg)
Example #41
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['patron.context']
        instance = self._get_server(context, req, id)

        try:
            self.compute_api.reboot(context, instance, reboot_type)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(
                state_error, 'reboot', id)
        return webob.Response(status_int=202)
Example #42
0
    def sync_instances(self, req, body):
        """Tell all cells to sync instance info."""
        context = req.environ['patron.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 #43
0
 def check_attach(self, context, volume, instance=None):
     # TODO(vish): abstract status checking?
     if volume['status'] != "available":
         msg = _("volume '%(vol)s' status must be 'available'. Currently "
                 "in '%(status)s'") % {'vol': volume['id'],
                                       'status': volume['status']}
         raise exception.InvalidVolume(reason=msg)
     if volume['attach_status'] == "attached":
         msg = _("volume %s already attached") % volume['id']
         raise exception.InvalidVolume(reason=msg)
     if instance and not CONF.cinder.cross_az_attach:
         # NOTE(sorrison): If instance is on a host we match against it's AZ
         #                 else we check the intended AZ
         if instance.get('host'):
             instance_az = az.get_instance_availability_zone(
                 context, instance)
         else:
             instance_az = instance['availability_zone']
         if instance_az != volume['availability_zone']:
             msg = _("Instance %(instance)s and volume %(vol)s are not in "
                     "the same availability_zone. Instance is in "
                     "%(ins_zone)s. Volume is in %(vol_zone)s") % {
                         "instance": instance['id'],
                         "vol": volume['id'],
                         'ins_zone': instance_az,
                         'vol_zone': volume['availability_zone']}
             raise exception.InvalidVolume(reason=msg)
Example #44
0
    def update(self, req, id, body):
        """Configure cloudpipe parameters for the project."""

        context = req.environ['patron.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 #45
0
    def setup_os_root(self, root):
        LOG.debug("Inspecting guest OS root filesystem %s", root)
        mounts = self.handle.inspect_get_mountpoints(root)

        if len(mounts) == 0:
            raise exception.PatronException(
                _("No mount points found in %(root)s of %(imgfile)s") %
                {'root': root, 'imgfile': self.imgfile})

        # the root directory must be mounted first
        mounts.sort(key=lambda mount: mount[0])

        root_mounted = False
        for mount in mounts:
            LOG.debug("Mounting %(dev)s at %(dir)s",
                      {'dev': mount[1], 'dir': mount[0]})
            try:
                self.handle.mount_options("", mount[1], mount[0])
                root_mounted = True
            except RuntimeError as e:
                msg = _("Error mounting %(device)s to %(dir)s in image"
                        " %(imgfile)s with libguestfs (%(e)s)") % \
                      {'imgfile': self.imgfile, 'device': mount[1],
                       'dir': mount[0], 'e': e}
                if root_mounted:
                    LOG.debug(msg)
                else:
                    raise exception.PatronException(msg)
Example #46
0
File: s3.py Project: hsluoyz/patron
    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.PatronException(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.PatronException(_('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.PatronException(_('Failed to decrypt image file '
                                    '%(image_file)s: %(err)s') %
                                    {'image_file': encrypted_filename,
                                     'err': exc.stdout})
Example #47
0
    def update(self, req, image_id, id, body):
        context = req.environ['patron.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 #48
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['patron.context']
        instance = self._get_server(context, req, id)

        try:
            self.compute_api.reboot(context, instance, reboot_type)
        except exception.InstanceIsLocked as e:
            raise exc.HTTPConflict(explanation=e.format_message())
        except exception.InstanceInvalidState as state_error:
            common.raise_http_conflict_for_instance_invalid_state(state_error,
                    'reboot', id)
        return webob.Response(status_int=202)
Example #49
0
    def _reset_state(self, req, id, body):
        """Permit admins to reset the state of a server."""
        context = req.environ["patron.context"]
        authorize(context, 'resetState')

        # Identify the desired state from the body
        try:
            state = state_map[body["os-resetState"]["state"]]
        except (TypeError, KeyError):
            msg = _("Desired state must be specified.  Valid states "
                    "are: %s") % ', '.join(sorted(state_map.keys()))
            raise exc.HTTPBadRequest(explanation=msg)

        instance = common.get_instance(self.compute_api, context, id)
        try:
            instance.vm_state = state
            instance.task_state = None
            instance.save(admin_state_reset=True)
        except exception.InstanceNotFound:
            msg = _("Server not found")
            raise exc.HTTPNotFound(explanation=msg)
        except Exception:
            readable = traceback.format_exc()
            LOG.exception(_LE("Compute.api::resetState %s"), readable)
            raise exc.HTTPUnprocessableEntity()
        return webob.Response(status_int=202)
Example #50
0
    def setup_os_root(self, root):
        LOG.debug("Inspecting guest OS root filesystem %s", root)
        mounts = self.handle.inspect_get_mountpoints(root)

        if len(mounts) == 0:
            raise exception.PatronException(
                _("No mount points found in %(root)s of %(imgfile)s") % {
                    'root': root,
                    'imgfile': self.imgfile
                })

        # the root directory must be mounted first
        mounts.sort(key=lambda mount: mount[0])

        root_mounted = False
        for mount in mounts:
            LOG.debug("Mounting %(dev)s at %(dir)s", {
                'dev': mount[1],
                'dir': mount[0]
            })
            try:
                self.handle.mount_options("", mount[1], mount[0])
                root_mounted = True
            except RuntimeError as e:
                msg = _("Error mounting %(device)s to %(dir)s in image"
                        " %(imgfile)s with libguestfs (%(e)s)") % \
                      {'imgfile': self.imgfile, 'device': mount[1],
                       'dir': mount[0], 'e': e}
                if root_mounted:
                    LOG.debug(msg)
                else:
                    raise exception.PatronException(msg)
Example #51
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