示例#1
0
    def parse_headers(headers, default_version, latest_version):
        """Determine the API version requested based on the headers supplied.

        :param headers: webob headers
        :param default_version: version to use if not specified in headers
        :param latest_version: version to use if latest is requested
        :returns: a tuple of (major, minor) version numbers
        :raises: webob.HTTPNotAcceptable
        """

        version_hdr = headers.get(Version.string, default_version)

        try:
            version_service, version_str = version_hdr.split()
        except ValueError:
            raise exc.HTTPNotAcceptable(_(
                "Invalid service type for %s header") % Version.string)

        if version_str.lower() == 'latest':
            version_service, version_str = latest_version.split()

        if version_service != Version.service_string:
            raise exc.HTTPNotAcceptable(_(
                "Invalid service type for %s header") % Version.string)
        try:
            version = tuple(int(i) for i in version_str.split('.'))
        except ValueError:
            version = ()

        if len(version) != 2:
            raise exc.HTTPNotAcceptable(_(
                "Invalid value for %s header") % Version.string)
        return version
示例#2
0
    def search_image(self, context, repo, tag, exact_match):
        image_ref = docker_image.Reference.parse(repo)
        registry, image_name = image_ref.split_hostname()
        if registry and registry != 'docker.io':
            # Images searching is only supported in DockerHub
            msg = _('Image searching is not supported in registry: {0}')
            raise exception.OperationNotSupported(msg.format(registry))

        with docker_utils.docker_client() as docker:
            try:
                # TODO(hongbin): search image by both name and tag
                images = docker.search(image_name)
            except errors.APIError as api_error:
                raise exception.ZunException(six.text_type(api_error))
            except Exception as e:
                msg = _('Cannot search image in docker: {0}')
                raise exception.ZunException(msg.format(e))

        if exact_match:
            images = [i for i in images if i['name'] == image_name]

        for image in images:
            image['metadata'] = {}
            for key in ('is_official', 'star_count'):
                value = image.pop(key, None)
                if value is not None:
                    image['metadata'][key] = value

        # TODO(hongbin): convert images to a list of Zun Image object
        return images
示例#3
0
    def _parse_white_list_from_config(self, whitelists):
        """Parse and validate the pci whitelist from the zun 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
示例#4
0
 def _check_version(self, version, headers=None):
     if headers is None:
         headers = {}
     # ensure that major version in the URL matches the header
     if version.major != BASE_VERSION:
         raise http_error.HTTPNotAcceptableAPIVersion(_(
             "Mutually exclusive versions requested. Version %(ver)s "
             "requested but not supported by this service. "
             "The supported version range is: "
             "[%(min)s, %(max)s].") % {'ver': version,
                                       'min': MIN_VER_STR,
                                       'max': MAX_VER_STR},
             headers=headers,
             max_version=str(MAX_VER),
             min_version=str(MIN_VER))
     # ensure the minor version is within the supported range
     if version < MIN_VER or version > MAX_VER:
         raise http_error.HTTPNotAcceptableAPIVersion(_(
             "Version %(ver)s was requested but the minor version is not "
             "supported by this service. The supported version range is: "
             "[%(min)s, %(max)s].") % {'ver': version, 'min': MIN_VER_STR,
                                       'max': MAX_VER_STR},
             headers=headers,
             max_version=str(MAX_VER),
             min_version=str(MIN_VER))
示例#5
0
    def _verify_origin(self, access_url):
        # Verify Origin
        expected_origin_hostname = self.headers.get('Host')
        if ':' in expected_origin_hostname:
            e = expected_origin_hostname
            if '[' in e and ']' in e:
                expected_origin_hostname = e.split(']')[0][1:]
            else:
                expected_origin_hostname = e.split(':')[0]
        expected_origin_hostnames = CONF.websocket_proxy.allowed_origins
        expected_origin_hostnames.append(expected_origin_hostname)
        origin_url = self.headers.get('Origin')

        # missing origin header indicates non-browser client which is OK
        if origin_url is not None:
            origin = urlparse.urlparse(origin_url)
            origin_hostname = origin.hostname
            origin_scheme = origin.scheme
            if origin_hostname == '' or origin_scheme == '':
                detail = _("Origin header not valid.")
                raise exception.ValidationError(detail)
            if origin_hostname not in expected_origin_hostnames:
                detail = _("Origin header does not match this host.")
                raise exception.ValidationError(detail)
            if not self.verify_origin_proto(access_url, origin_scheme):
                detail = _("Origin header protocol does not match this host.")
                raise exception.ValidationError(detail)
示例#6
0
    def pull_image(self, context, repo, tag, image_pull_policy, registry):
        image_loaded = True
        image = self._search_image_on_host(repo, tag)
        if not utils.should_pull_image(image_pull_policy, bool(image)):
            if image:
                LOG.debug('Image  %s present locally', repo)
                return image, image_loaded
            else:
                message = _('Image %s not present with pull policy of Never'
                            ) % repo
                raise exception.ImageNotFound(message)

        try:
            LOG.debug('Pulling image from docker %(repo)s,'
                      ' context %(context)s',
                      {'repo': repo, 'context': context})
            self._pull_image(repo, tag, registry)
            return {'image': repo, 'path': None}, image_loaded
        except exception.ImageNotFound:
            with excutils.save_and_reraise_exception():
                LOG.error('Image %s was not found in docker repo', repo)
        except exception.DockerError:
            with excutils.save_and_reraise_exception():
                LOG.error('Docker API error occurred during downloading '
                          'image %s', repo)
        except Exception as e:
            msg = _('Cannot download image from docker: {0}')
            raise exception.ZunException(msg.format(e))
示例#7
0
def validate_limit(limit):
    try:
        if limit is not None and int(limit) <= 0:
            raise exception.InvalidValue(_("Limit must be positive integer"))
    except ValueError:
        raise exception.InvalidValue(_("Limit must be positive integer"))

    if limit is not None:
        return min(CONF.api.max_limit, int(limit))
    else:
        return CONF.api.max_limit
示例#8
0
文件: api.py 项目: openstack/higgins
    def container_create(self, context, new_container, extra_spec,
                         requested_networks, requested_volumes, run,
                         pci_requests=None):
        try:
            host_state = self._schedule_container(context, new_container,
                                                  extra_spec)
        except exception.NoValidHost:
            new_container.status = consts.ERROR
            new_container.status_reason = _(
                "There are not enough hosts available.")
            new_container.save(context)
            return
        except Exception:
            new_container.status = consts.ERROR
            new_container.status_reason = _("Unexpected exception occurred.")
            new_container.save(context)
            raise

        # NOTE(mkrai): Intent here is to check the existence of image
        # before proceeding to create container. If image is not found,
        # container create will fail with 400 status.
        if CONF.api.enable_image_validation:
            try:
                images = self.rpcapi.image_search(
                    context, new_container.image,
                    new_container.image_driver, True, new_container.registry,
                    host_state['host'])
                if not images:
                    raise exception.ImageNotFound(image=new_container.image)
                if len(images) > 1:
                    raise exception.Conflict('Multiple images exist with same '
                                             'name. Please use the container '
                                             'uuid instead.')
            except exception.OperationNotSupported:
                LOG.info("Skip validation since search is not supported for "
                         "image '%(image)s' and image driver '%(driver)s'.",
                         {'image': new_container.image,
                          'driver': new_container.image_driver})
            except exception.ReferenceInvalidFormat:
                raise exception.InvalidValue(_("The format of image name '%s' "
                                               "is invalid.")
                                             % new_container.image)
            except Exception as e:
                new_container.status = consts.ERROR
                new_container.status_reason = str(e)
                new_container.save(context)
                raise

        self._record_action_start(context, new_container,
                                  container_actions.CREATE)
        self.rpcapi.container_create(context, host_state['host'],
                                     new_container, host_state['limits'],
                                     requested_networks, requested_volumes,
                                     run, pci_requests)
示例#9
0
        def decorated_function(self, context, volume, **kwargs):
            provider = volume.volume_provider
            if provider not in supported_providers:
                msg = _("The volume provider '%s' is not supported") % provider
                raise exception.ZunException(msg)

            return function(self, context, volume, **kwargs)
示例#10
0
def load_image_driver(image_driver=None):
    """Load an image driver module.

    Load the container image driver module specified by the image_driver
    configuration option or, if supplied, the driver name supplied as an
    argument.
    :param image_driver: container image driver name to override config opt
    :returns: a ContainerImageDriver instance
    """
    if not image_driver:
        image_driver = CONF.default_image_driver
    if not image_driver:
        LOG.error("Container image driver option required, "
                  "but not specified")
        sys.exit(1)

    LOG.info("Loading container image driver '%s'", image_driver)
    try:
        driver = stevedore.driver.DriverManager(
            "zun.image.driver",
            image_driver,
            invoke_on_load=True).driver

        if not isinstance(driver, ContainerImageDriver):
            raise Exception(_('Expected driver of type: %s') %
                            six.text_type(ContainerImageDriver))

        return driver
    except Exception:
        LOG.exception("Unable to load the container image driver")
        sys.exit(1)
示例#11
0
    def read_mounts(self, filter_device=None, filter_fstype=None):
        """Read all mounted filesystems.

        Read all mounted filesystems except filtered option.

        :param filter_device: Filter for device, the result will not contain
                              the mounts whose device argument in it.
        :param filter_fstype: Filter for mount point.
        :return: All mounts.
        """
        if filter_device is None:
            filter_device = ()
        if filter_fstype is None:
            filter_fstype = ()

        try:
            (out, err) = utils.execute('cat', PROC_MOUNTS_PATH,
                                       check_exit_code=0)
        except exception.CommandError:
            msg = _("Failed to read mounts.")
            raise exception.FileNotFound(msg)

        lines = out.split('\n')
        mounts = []
        for line in lines:
            if not line:
                continue
            tokens = line.split()
            if len(tokens) < 4:
                continue
            if tokens[0] in filter_device or tokens[1] in filter_fstype:
                continue
            mounts.append(MountInfo(device=tokens[0], mountpoint=tokens[1],
                                    fstype=tokens[2], opts=tokens[3]))
        return mounts
示例#12
0
    def _test(self, type_, unit, total, used, requested, limit):
        """Test if the type resource needed for a claim can be allocated."""

        LOG.info('Total %(type)s: %(total)d %(unit)s, used: %(used).02f '
                 '%(unit)s',
                 {'type': type_, 'total': total, 'unit': unit, 'used': used})

        if limit is None:
            # treat resource as unlimited:
            LOG.info('%(type)s limit not specified, defaulting to '
                     'unlimited', {'type': type_})
            return

        free = limit - used

        # Oversubscribed resource policy info:
        LOG.info('%(type)s limit: %(limit).02f %(unit)s, '
                 'free: %(free).02f %(unit)s',
                 {'type': type_, 'limit': limit, 'free': free, 'unit': unit})

        if requested > free:
            return (_('Free %(type)s %(free).02f '
                      '%(unit)s < requested %(requested)s %(unit)s') %
                    {'type': type_, 'free': free, 'unit': unit,
                     'requested': requested})
示例#13
0
    def _new_websocket_client(self, container, token, uuid):
        if token != container.websocket_token:
            raise exception.InvalidWebsocketToken(token)

        access_url = '%s?token=%s&uuid=%s' % (CONF.websocket_proxy.base_url,
                                              token, uuid)

        self._verify_origin(access_url)

        if container.websocket_url:
            target_url = container.websocket_url
            escape = "~"
            close_wait = 0.5
            wscls = WebSocketClient(host_url=target_url, escape=escape,
                                    close_wait=close_wait)
            wscls.connect()
            self.target = wscls
        else:
            raise exception.InvalidWebsocketUrl()

        # Start proxying
        try:
            self.do_websocket_proxy(self.target.ws)
        except Exception:
            if self.target.ws:
                self.target.ws.close()
                self.vmsg(_("Websocket client or target closed"))
            raise
示例#14
0
def load_container_driver(container_driver=None):
    """Load a container driver module.

    Load the container driver module specified by the container_driver
    configuration option or, if supplied, the driver name supplied as an
    argument.
    :param container_driver: a container driver name to override the config opt
    :returns: a ContainerDriver instance
    """
    if not container_driver:
        container_driver = CONF.container_driver
        if not container_driver:
            LOG.error("Container driver option required, "
                      "but not specified")
            sys.exit(1)

    LOG.info("Loading container driver '%s'", container_driver)
    try:
        if not container_driver.startswith('zun.'):
            container_driver = 'zun.container.%s' % container_driver
        driver = importutils.import_object(container_driver)
        if not isinstance(driver, ContainerDriver):
            raise Exception(_('Expected driver of type: %s') %
                            str(ContainerDriver))

        return driver
    except ImportError:
        LOG.exception("Unable to load the container driver")
        sys.exit(1)
示例#15
0
    def new_websocket_client(self):
        """Called after a new WebSocket connection has been established."""
        # Reopen the eventlet hub to make sure we don't share an epoll
        # fd with parent and/or siblings, which would be bad
        from eventlet import hubs
        hubs.use_hub()

        # The zun expected behavior is to have token
        # passed to the method GET of the request
        parse = urlparse.urlparse(self.path)
        if parse.scheme not in ('http', 'https'):
            # From a bug in urlparse in Python < 2.7.4 we cannot support
            # special schemes (cf: https://bugs.python.org/issue9374)
            if sys.version_info < (2, 7, 4):
                raise exception.ZunException(
                    _("We do not support scheme '%s' under Python < 2.7.4, "
                      "please use http or https") % parse.scheme)

        query = parse.query
        token = urlparse.parse_qs(query).get("token", [""]).pop()
        uuid = urlparse.parse_qs(query).get("uuid", [""]).pop()
        exec_id = urlparse.parse_qs(query).get("exec_id", [""]).pop()

        ctx = context.get_admin_context(all_projects=True)

        if uuidutils.is_uuid_like(uuid):
            container = objects.Container.get_by_uuid(ctx, uuid)
        else:
            container = objects.Container.get_by_name(ctx, uuid)

        if exec_id:
            self._new_exec_client(container, token, uuid, exec_id)
        else:
            self._new_websocket_client(container, token, uuid)
示例#16
0
 def delete_volume(self, volmap):
     volume_id = volmap.cinder_volume_id
     try:
         self.cinder_api.delete_volume(volume_id)
     except cinder_exception as e:
         raise exception.Invalid(_("Delete Volume failed: %s") %
                                 six.text_type(e))
示例#17
0
    def obj_load_attr(self, attrname):
        if attrname not in CONTAINER_OPTIONAL_ATTRS:
            raise exception.ObjectActionError(
                action='obj_load_attr',
                reason=_('attribute %s not lazy-loadable') % attrname)

        if not self._context:
            raise exception.OrphanedObjectError(method='obj_load_attr',
                                                objtype=self.obj_name())

        LOG.debug("Lazy-loading '%(attr)s' on %(name)s uuid %(uuid)s",
                  {'attr': attrname,
                   'name': self.obj_name(),
                   'uuid': self.uuid,
                   })

        # NOTE(danms): We handle some fields differently here so that we
        # can be more efficient
        if attrname == 'pci_devices':
            self._load_pci_devices()

        if attrname == 'exec_instances':
            self._load_exec_instances()

        if attrname == 'registry':
            self._load_registry()

        self.obj_reset_changes([attrname])
示例#18
0
    def search(self, image, image_driver=None, exact_match=False):
        """Search a specific image

        :param image:  Name of the image.
        :param image_driver: Name of the image driver (glance, docker).
        :param exact_match: if True, exact match the image name.
        """
        context = pecan.request.context
        policy.enforce(context, "image:search",
                       action="image:search")
        LOG.debug('Calling compute.image_search with %s', image)
        try:
            exact_match = strutils.bool_from_string(exact_match, strict=True)
        except ValueError:
            bools = ', '.join(strutils.TRUE_STRINGS + strutils.FALSE_STRINGS)
            raise exception.InvalidValue(_('Valid exact_match values are: %s')
                                         % bools)
        # Valiadtion accepts 'None' so need to convert it to None
        image_driver = api_utils.string_or_none(image_driver)
        if not image_driver:
            image_driver = CONF.default_image_driver

        return pecan.request.compute_api.image_search(context, image,
                                                      image_driver,
                                                      exact_match)
示例#19
0
 def _test_disk(self, resources, limit):
     type_ = _("disk")
     unit = "GB"
     total = resources.disk_total
     used = resources.disk_used
     requested = self.disk
     return self._test(type_, unit, total, used, requested, limit)
示例#20
0
    def _schedule(self, context):
        """Picks a host that is up at random."""
        hosts = self.hosts_up(context)
        if not hosts:
            msg = _("Is the appropriate service running?")
            raise exception.NoValidHost(reason=msg)

        return random.choice(hosts)
示例#21
0
    def _test_memory(self, resources, limit):
        type_ = _("memory")
        unit = "MB"
        total = resources.mem_total
        used = resources.mem_used
        requested = self.memory

        return self._test(type_, unit, total, used, requested, limit)
示例#22
0
    def _test_cpu(self, resources, limit):
        type_ = _("vcpu")
        unit = "VCPU"
        total = resources.cpus
        used = resources.cpu_used
        requested = self.cpu

        return self._test(type_, unit, total, used, requested, limit)
示例#23
0
 def unmount(self, mountpoint):
     try:
         utils.execute('umount', mountpoint, run_as_root=True)
     except exception.CommandError as e:
         raise exception.UnmountException(_(
             "Unexpected err while unmount block device. "
             "Mountpoint: %(mountpoint)s, "
             "Error: %(error)s") %
             {'mountpoint': mountpoint, 'error': e})
示例#24
0
 def validate(self, *args, **kwargs):
     try:
         self.validator.validate(*args, **kwargs)
     except jsonschema.ValidationError as ex:
         if len(ex.path) > 0:
             if self.is_body:
                 detail = _("Invalid input for field '%(path)s'."
                            "Value: '%(value)s'. %(message)s")
             else:
                 detail = _("Invalid input for query parameters "
                            "'%(path)s'. Value: '%(value)s'. %(message)s")
             detail = detail % {
                 'path': ex.path.pop(), 'value': ex.instance,
                 'message': six.text_type(ex)
             }
         else:
             detail = six.text_type(ex)
         raise exception.SchemaValidationError(detail=detail)
示例#25
0
 def get_available_network(self):
     search_opts = {'tenant_id': self.context.project_id, 'shared': False}
     # NOTE(kiennt): Pick shared network if no tenant network
     nets = self.list_networks(**search_opts).get('networks', []) or \
         self.list_networks(**{'shared': True}).get('networks', [])
     if not nets:
         raise exception.Conflict(_(
             "There is no neutron network available"))
     nets.sort(key=lambda x: x['created_at'])
     return nets[0]
示例#26
0
 def _get_subnet(self, subnets, ip_version):
     subnets = [s for s in subnets if s['ip_version'] == ip_version]
     if len(subnets) == 0:
         return None
     elif len(subnets) == 1:
         return subnets[0]
     else:
         raise exception.ZunException(_(
             "Multiple Neutron subnets exist with ip version %s") %
             ip_version)
示例#27
0
 def make_filesystem(self, devpath, fstype):
     try:
         utils.execute('mkfs', '-t', fstype, '-F', devpath,
                       run_as_root=True)
     except exception.CommandError as e:
         raise exception.MakeFileSystemException(_(
             "Unexpected error while make filesystem. "
             "Devpath: %(devpath)s, "
             "Fstype: %(fstype)s, "
             "Error: %(error)s") %
             {'devpath': devpath, 'fstype': fstype, 'error': e})
示例#28
0
def driver(driver_name, *args, **kwargs):
    LOG.info("Loading volume driver '%s'", driver_name)
    volume_driver = stevedore_driver.DriverManager(
        "zun.volume.driver",
        driver_name,
        invoke_on_load=True,
        invoke_args=args,
        invoke_kwds=kwargs).driver
    if not isinstance(volume_driver, VolumeDriver):
        raise exception.ZunException(_("Invalid volume driver type"))
    return volume_driver
示例#29
0
 def exec_resize(self, exec_id, height=None, width=None):
     # NOTE(hongbin): This is a temporary work-around for a docker issue
     # See: https://github.com/moby/moby/issues/35561
     try:
         super(DockerHTTPClient, self).exec_resize(
             exec_id, height=height, width=width)
     except errors.APIError as e:
         if "process not found for container" in str(e):
             raise exception.Invalid(_(
                 "no such exec instance: %s") % six.text_type(e))
         raise
示例#30
0
 def mount(self, devpath, mountpoint, fstype=None):
     try:
         utils.execute('mount', '-t', fstype, devpath, mountpoint,
                       run_as_root=True)
     except exception.CommandError as e:
         raise exception.MountException(_(
             "Unexpected error while mount block device. "
             "Devpath: %(devpath)s, "
             "Mountpoint: %(mountpoint)s, "
             "Error: %(error)s") %
             {'devpath': devpath, 'mountpoint': mountpoint, 'error': e})
示例#31
0
class InvalidParameterValue(Invalid):
    message = _("%(err)s")
示例#32
0
class InvalidParam(Invalid):
    message = _('Invalid param %(param)s')
示例#33
0
class ContainerHostNotUp(ZunException):
    message = _("Container %(container)s host %(host)s is not up.")
示例#34
0
class InvalidDiscoveryURL(Invalid):
    message = _("Received invalid discovery URL '%(discovery_url)s' for "
                "discovery endpoint '%(discovery_endpoint)s'.")
示例#35
0
class InvalidUuidOrName(Invalid):
    message = _("Expected a name or uuid but received %(uuid)s.")
示例#36
0
class ResourceProviderNotFound(HTTPNotFound):
    message = _("Resource provider %(resource_provider)s could not be found.")
示例#37
0
class ResourceClassNotFound(HTTPNotFound):
    message = _("Resource class %(resource_class)s could not be found.")
示例#38
0
class InvalidName(Invalid):
    message = _("Expected a name but received %(uuid)s.")
示例#39
0
class InvalidValue(Invalid):
    message = _("Received value '%(value)s' is invalid for type %(type)s.")
示例#40
0
class NotAuthorized(ZunException):
    message = _("Not authorized.")
    code = 403
示例#41
0
class ConfigInvalid(ZunException):
    message = _("Invalid configuration file. %(error_msg)s")
示例#42
0
class PolicyNotAuthorized(NotAuthorized):
    message = _("Policy doesn't allow %(action)s to be performed.")
示例#43
0
class InvalidState(Conflict):
    message = _("Invalid resource state.")
示例#44
0
class InventoryNotFound(HTTPNotFound):
    message = _("Inventory %(inventory)s could not be found.")
示例#45
0
class Conflict(ZunException):
    message = _('Conflict.')
    code = 409
示例#46
0
class AllocationNotFound(HTTPNotFound):
    message = _("Allocation %(allocation)s could not be found.")
示例#47
0
class InvalidCsr(Invalid):
    message = _("Received invalid csr %(csr)s.")
示例#48
0
class CarrierNotFound(HTTPNotFound):
    message = _("Carrier account %(carrier)s could not be found.")
示例#49
0
class InvalidIdentity(Invalid):
    message = _("Expected an uuid or int but received %(identity)s.")
示例#50
0
class OrphanedObjectError(ZunException):
    message = _('Cannot call %(method)s on orphaned %(objtype)s object')
示例#51
0
class GetDiscoveryUrlFailed(ZunException):
    message = _("Failed to get discovery url from '%(discovery_endpoint)s'.")
示例#52
0
class PatchError(Invalid):
    message = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s")
示例#53
0
class InvalidUUID(Invalid):
    message = _("Expected a uuid but received %(uuid)s.")
示例#54
0
class ContainerNotFound(HTTPNotFound):
    message = _("Container %(container)s could not be found.")
示例#55
0
class ImageNotFound(HTTPNotFound):
    message = _("Image %(image)s could not be found.")
示例#56
0
class ZunServiceNotFound(HTTPNotFound):
    message = _("Zun service %(binary)s on host %(host)s could not be found.")
示例#57
0
class PortNotFound(HTTPNotFound):
    message = _("Neutron port %(port)s could not be found.")
示例#58
0
class Invalid(ZunException):
    message = _("Unacceptable parameters.")
    code = 400
示例#59
0
class ComputeNodeNotFound(HTTPNotFound):
    message = _("Compute node %(compute_node)s could not be found.")
示例#60
0
class NetworkNotFound(HTTPNotFound):
    message = _("Neutron network %(network)s could not be found.")