Ejemplo n.º 1
0
 def _validate_with_subnet(self, subnet_cidr):
     if self.allocation_pools:
         if subnet_cidr.version != self.allocation_pools[0].version:
             raise ipam_exc.IpamValueInvalid(_("allocation_pools use the wrong ip version"))
         for pool in self.allocation_pools:
             if pool not in subnet_cidr:
                 raise ipam_exc.IpamValueInvalid(_("allocation_pools are not in the subnet"))
Ejemplo n.º 2
0
 def _validate_floatingip_dns(self, dns_name, dns_domain):
     if dns_domain and not dns_name:
         msg = _("dns_domain cannot be specified without a dns_name")
         raise n_exc.BadRequest(resource='floatingip', msg=msg)
     if dns_name and not dns_domain:
         msg = _("dns_name cannot be specified without a dns_domain")
         raise n_exc.BadRequest(resource='floatingip', msg=msg)
Ejemplo n.º 3
0
def load_class_by_alias_or_classname(namespace, name):
    """Load class using stevedore alias or the class name

    :param namespace: namespace where the alias is defined
    :param name: alias or class name of the class to be loaded
    :returns: class if calls can be loaded
    :raises ImportError if class cannot be loaded
    """

    if not name:
        LOG.error(_LE("Alias or class name is not set"))
        raise ImportError(_("Class not found."))
    try:
        # Try to resolve class by alias
        mgr = driver.DriverManager(
            namespace, name, warn_on_missing_entrypoint=False)
        class_to_load = mgr.driver
    except RuntimeError:
        e1_info = sys.exc_info()
        # Fallback to class name
        try:
            class_to_load = importutils.import_class(name)
        except (ImportError, ValueError):
            LOG.error(_LE("Error loading class by alias"),
                      exc_info=e1_info)
            LOG.error(_LE("Error loading class by class name"),
                      exc_info=True)
            raise ImportError(_("Class not found."))
    return class_to_load
Ejemplo n.º 4
0
    def _validate(self, context, subport):
        # Check that the subport doesn't reference the same port_id as a
        # trunk we may be in the middle of trying to create, in other words
        # make the validation idiot proof.
        if subport['port_id'] == self.trunk_port_id:
            raise trunk_exc.ParentPortInUse(port_id=subport['port_id'])

        # If the segmentation details are missing, we will need to
        # figure out defaults when the time comes to support Ironic.
        # We can reasonably expect segmentation details to be provided
        # in all other cases for now.
        segmentation_id = subport.get("segmentation_id")
        segmentation_type = subport.get("segmentation_type")
        if not segmentation_id or not segmentation_type:
            msg = _("Invalid subport details '%s': missing segmentation "
                    "information. Must specify both segmentation_id and "
                    "segmentation_type") % subport
            raise n_exc.InvalidInput(error_message=msg)

        if segmentation_type not in self._segmentation_types:
            msg = _("Invalid segmentation_type '%s'") % segmentation_type
            raise n_exc.InvalidInput(error_message=msg)

        if not self._segmentation_types[segmentation_type](segmentation_id):
            msg = _("Invalid segmentation id '%s'") % segmentation_id
            raise n_exc.InvalidInput(error_message=msg)

        trunk_validator = TrunkPortValidator(subport['port_id'])
        trunk_validator.validate(context)
        return subport
Ejemplo n.º 5
0
    def validate_provider_segment(self, segment):
        physical_network = segment.get(api.PHYSICAL_NETWORK)
        segmentation_id = segment.get(api.SEGMENTATION_ID)
        if physical_network:
            if physical_network not in self.network_vlan_ranges:
                msg = (_("physical_network '%s' unknown "
                         "for VLAN provider network") % physical_network)
                raise exc.InvalidInput(error_message=msg)
            if segmentation_id:
                if not plugin_utils.is_valid_vlan_tag(segmentation_id):
                    msg = (_("segmentation_id out of range (%(min)s through "
                             "%(max)s)") %
                           {'min': p_const.MIN_VLAN_TAG,
                            'max': p_const.MAX_VLAN_TAG})
                    raise exc.InvalidInput(error_message=msg)
            else:
                if not self.network_vlan_ranges.get(physical_network):
                    msg = (_("Physical network %s requires segmentation_id "
                             "to be specified when creating a provider "
                             "network") % physical_network)
                    raise exc.InvalidInput(error_message=msg)
        elif segmentation_id:
            msg = _("segmentation_id requires physical_network for VLAN "
                    "provider network")
            raise exc.InvalidInput(error_message=msg)

        for key, value in segment.items():
            if value and key not in [api.NETWORK_TYPE,
                                     api.PHYSICAL_NETWORK,
                                     api.SEGMENTATION_ID]:
                msg = _("%s prohibited for VLAN provider network") % key
                raise exc.InvalidInput(error_message=msg)
Ejemplo n.º 6
0
def get_sorts(request, attr_info):
    """Extract sort_key and sort_dir from request.

    Return as: [(key1, value1), (key2, value2)]
    """
    sort_keys = list_args(request, "sort_key")
    sort_dirs = list_args(request, "sort_dir")
    if len(sort_keys) != len(sort_dirs):
        msg = _("The number of sort_keys and sort_dirs must be same")
        raise exc.HTTPBadRequest(explanation=msg)
    valid_dirs = [constants.SORT_DIRECTION_ASC, constants.SORT_DIRECTION_DESC]
    absent_keys = [x for x in sort_keys if x not in attr_info]
    if absent_keys:
        msg = _("%s is invalid attribute for sort_keys") % absent_keys
        raise exc.HTTPBadRequest(explanation=msg)
    invalid_dirs = [x for x in sort_dirs if x not in valid_dirs]
    if invalid_dirs:
        msg = (_("%(invalid_dirs)s is invalid value for sort_dirs, "
                 "valid value is '%(asc)s' and '%(desc)s'") %
               {'invalid_dirs': invalid_dirs,
                'asc': constants.SORT_DIRECTION_ASC,
                'desc': constants.SORT_DIRECTION_DESC})
        raise exc.HTTPBadRequest(explanation=msg)
    return list(zip(sort_keys,
                    [x == constants.SORT_DIRECTION_ASC for x in sort_dirs]))
Ejemplo n.º 7
0
def _validate_range(data, valid_values=None):
    """Check that integer value is within a range provided.

    Test is inclusive. Allows either limit to be ignored, to allow
    checking ranges where only the lower or upper limit matter.
    It is expected that the limits provided are valid integers or
    the value None.
    """

    min_value = valid_values[0]
    max_value = valid_values[1]
    try:
        data = int(data)
    except (ValueError, TypeError):
        msg = _("'%s' is not an integer") % data
        LOG.debug(msg)
        return msg
    if min_value is not UNLIMITED and data < min_value:
        msg = _("'%(data)s' is too small - must be at least "
                "'%(limit)d'") % {'data': data, 'limit': min_value}
        LOG.debug(msg)
        return msg
    if max_value is not UNLIMITED and data > max_value:
        msg = _("'%(data)s' is too large - must be no larger than "
                "'%(limit)d'") % {'data': data, 'limit': max_value}
        LOG.debug(msg)
        return msg
Ejemplo n.º 8
0
 def _validate_value(self, value):
     if not isinstance(value, six.integer_types):
         msg = _("Field value %s is not an integer") % value
         raise ValueError(msg)
     if not self._start <= value <= self._end:
         msg = _("Field value %s is invalid") % value
         raise ValueError(msg)
Ejemplo n.º 9
0
    def _validate_router_migration(self, context, router_db, router_res):
        """Allow centralized -> distributed state transition only."""
        if (router_db.extra_attributes.distributed and
            router_res.get('distributed') is False):
            LOG.info(_LI("Centralizing distributed router %s "
                         "is not supported"), router_db['id'])
            raise n_exc.BadRequest(
                resource='router',
                msg=_("Migration from distributed router to centralized is "
                      "not supported"))
        elif (not router_db.extra_attributes.distributed and
              router_res.get('distributed')):
            # router should be disabled in order for upgrade
            if router_db.admin_state_up:
                msg = _('Cannot upgrade active router to distributed. Please '
                        'set router admin_state_up to False prior to upgrade.')
                raise n_exc.BadRequest(resource='router', msg=msg)

            # Notify advanced services of the imminent state transition
            # for the router.
            try:
                kwargs = {'context': context, 'router': router_db}
                registry.notify(
                    resources.ROUTER, events.BEFORE_UPDATE, self, **kwargs)
            except exceptions.CallbackFailure as e:
                with excutils.save_and_reraise_exception():
                    # NOTE(armax): preserve old check's behavior
                    if len(e.errors) == 1:
                        raise e.errors[0].error
                    raise l3.RouterInUse(router_id=router_db['id'],
                                         reason=e)
Ejemplo n.º 10
0
def _validate_ip_address(data, valid_values=None):
    msg = None
    try:
        # netaddr.core.ZEROFILL is only applicable to IPv4.
        # it will remove leading zeros from IPv4 address octets.
        ip = netaddr.IPAddress(_validate_no_whitespace(data),
                               flags=netaddr.core.ZEROFILL)
        # The followings are quick checks for IPv6 (has ':') and
        # IPv4.  (has 3 periods like 'xx.xx.xx.xx')
        # NOTE(yamamoto): netaddr uses libraries provided by the underlying
        # platform to convert addresses.  For example, inet_aton(3).
        # Some platforms, including NetBSD and OS X, have inet_aton
        # implementation which accepts more varying forms of addresses than
        # we want to accept here.  The following check is to reject such
        # addresses.  For Example:
        #   >>> netaddr.IPAddress('1' * 59)
        #   IPAddress('199.28.113.199')
        #   >>> netaddr.IPAddress(str(int('1' * 59) & 0xffffffff))
        #   IPAddress('199.28.113.199')
        #   >>>
        if ':' not in data and data.count('.') != 3:
            msg = _("'%s' is not a valid IP address") % data
        # A leading '0' in IPv4 address may be interpreted as an octal number,
        # e.g. 011 octal is 9 decimal. Since there is no standard saying
        # whether IP address with leading '0's should be interpreted as octal
        # or decimal, hence we reject leading '0's to avoid ambiguity.
        if ip.version == 4 and str(ip) != data:
            msg = _("'%(data)s' is not an accepted IP address, "
                    "'%(ip)s' is recommended") % {"data": data, "ip": ip}
    except Exception:
        msg = _("'%s' is not a valid IP address") % data
    if msg:
        LOG.debug(msg)
    return msg
Ejemplo n.º 11
0
    def __init__(self, conf):
        LOG.debug("Initializing firewall agent")
        self.conf = conf
        fwaas_driver_class_path = provconf.get_provider_driver_class(
            cfg.CONF.fwaas.driver)
        self.fwaas_enabled = cfg.CONF.fwaas.enabled

        # None means l3-agent has no information on the server
        # configuration due to the lack of RPC support.
        if self.neutron_service_plugins is not None:
            fwaas_plugin_configured = (constants.FIREWALL
                                       in self.neutron_service_plugins)
            if fwaas_plugin_configured and not self.fwaas_enabled:
                msg = _("FWaaS plugin is configured in the server side, but "
                        "FWaaS is disabled in L3-agent.")
                LOG.error(msg)
                raise SystemExit(1)
            self.fwaas_enabled = self.fwaas_enabled and fwaas_plugin_configured

        if self.fwaas_enabled:
            try:
                self.fwaas_driver = importutils.import_object(
                    fwaas_driver_class_path)
                LOG.debug("FWaaS Driver Loaded: '%s'", fwaas_driver_class_path)
            except ImportError:
                msg = _('Error importing FWaaS device driver: %s')
                raise ImportError(msg % fwaas_driver_class_path)
        self.services_sync = False
        # setup RPC to msg fwaas plugin
        self.fwplugin_rpc = FWaaSL3PluginApi(topics.FIREWALL_PLUGIN,
                                             conf.host)
        super(FWaaSL3AgentRpcCallback, self).__init__(host=conf.host)
Ejemplo n.º 12
0
    def blacklist_supported_vnic_types(self, vnic_types, blacklist):
        """Validate the blacklist and blacklist the supported_vnic_types

        :param vnic_types: The supported_vnic_types list
        :param blacklist: The blacklist as in vnic_type_blacklist
        :return The blacklisted vnic_types
        """
        if not blacklist:
            return vnic_types

        # Not valid values in the blacklist:
        if not all(bl in vnic_types for bl in blacklist):
            raise ValueError(_("Not all of the items from vnic_type_blacklist "
                               "are valid vnic_types for %(agent)s mechanism "
                               "driver. The valid values are: "
                               "%(valid_vnics)s.") %
                             {'agent': self.agent_type,
                              'valid_vnics': vnic_types})

        supported_vnic_types = [vnic_t for vnic_t in vnic_types if
                                vnic_t not in blacklist]

        # Nothing left in the supported vnict types list:
        if len(supported_vnic_types) < 1:
            raise ValueError(_("All possible vnic_types were blacklisted for "
                               "%s mechanism driver!") % self.agent_type)
        return supported_vnic_types
Ejemplo n.º 13
0
    def __init__(self, connection=None, timeout=None, schema_name=None, idl_class=None, idl_factory=None):
        """Create a connection to an OVSDB server using the OVS IDL

        :param connection: (deprecated) An OVSDB connection string
        :param timeout: The timeout value for OVSDB operations (required)
        :param schema_name: (deprecated) The name ovs the OVSDB schema to use
        :param idl_class: (deprecated) An Idl subclass. Defaults to idl.Idl
        :param idl_factory: A factory function that produces an Idl instance

        The signature of this class is changing. It is recommended to pass in
        a timeout and idl_factory
        """
        assert timeout is not None
        self.idl = None
        self.timeout = timeout
        self.txns = TransactionQueue(1)
        self.lock = threading.Lock()
        if idl_factory:
            if connection or schema_name:
                raise TypeError(_("Connection: Takes either idl_factory, or " "connection and schema_name. Both given"))
            self.idl_factory = idl_factory
        else:
            if not connection or not schema_name:
                raise TypeError(
                    _("Connection: Takes either idl_factory, or " "connection and schema_name. Neither given")
                )
            self.idl_factory = self._idl_factory
            self.connection = connection
            self.schema_name = schema_name
            self.idl_class = idl_class or idl.Idl
            self._schema_filter = None
Ejemplo n.º 14
0
    def scan_vf_devices(cls, dev_name):
        """Scan os directories to get VF devices

        @param dev_name: pf network device name
        @return: list of virtual functions
        """
        vf_list = []
        dev_path = cls.DEVICE_PATH % dev_name
        if not os.path.isdir(dev_path):
            LOG.error(_LE("Failed to get devices for %s"), dev_name)
            raise exc.InvalidDeviceError(dev_name=dev_name,
                                         reason=_("Device not found"))
        file_list = os.listdir(dev_path)
        for file_name in file_list:
            pattern_match = cls.VIRTFN_REG_EX.match(file_name)
            if pattern_match:
                vf_index = int(pattern_match.group("vf_index"))
                file_path = os.path.join(dev_path, file_name)
                if os.path.islink(file_path):
                    file_link = os.readlink(file_path)
                    pci_slot = os.path.basename(file_link)
                    vf_list.append((pci_slot, vf_index))
        if not vf_list:
            raise exc.InvalidDeviceError(
                dev_name=dev_name,
                reason=_("Device has no virtual functions"))
        return vf_list
Ejemplo n.º 15
0
    def _get_subnet_for_fixed_ip(self, context, fixed, network_id):
        if 'subnet_id' in fixed:
            subnet = self._get_subnet(context, fixed['subnet_id'])
            if subnet['network_id'] != network_id:
                msg = (_("Failed to create port on network %(network_id)s"
                         ", because fixed_ips included invalid subnet "
                         "%(subnet_id)s") %
                       {'network_id': network_id,
                        'subnet_id': fixed['subnet_id']})
                raise n_exc.InvalidInput(error_message=msg)
            # Ensure that the IP is valid on the subnet
            if ('ip_address' in fixed and
                not ipam_utils.check_subnet_ip(subnet['cidr'],
                                               fixed['ip_address'])):
                raise n_exc.InvalidIpForSubnet(ip_address=fixed['ip_address'])
            return subnet

        if 'ip_address' not in fixed:
            msg = _('IP allocation requires subnet_id or ip_address')
            raise n_exc.InvalidInput(error_message=msg)

        filter = {'network_id': [network_id]}
        subnets = self._get_subnets(context, filters=filter)

        for subnet in subnets:
            if ipam_utils.check_subnet_ip(subnet['cidr'],
                                          fixed['ip_address']):
                return subnet
        raise n_exc.InvalidIpForNetwork(ip_address=fixed['ip_address'])
Ejemplo n.º 16
0
def parse_exclude_devices(exclude_list):
    """Parse Exclude devices list

    parses excluded device list in the form:
    dev_name:pci_dev_1;pci_dev_2
    @param exclude list: list of string pairs in "key:value" format
                        the key part represents the network device name
                        the value part is a list of PCI slots separated by ";"
    """
    exclude_mapping = {}
    for dev_mapping in exclude_list:
        try:
            dev_name, exclude_devices = dev_mapping.split(":", 1)
        except ValueError:
            raise ValueError(_("Invalid mapping: '%s'") % dev_mapping)
        dev_name = dev_name.strip()
        if not dev_name:
            raise ValueError(_("Missing key in mapping: '%s'") % dev_mapping)
        if dev_name in exclude_mapping:
            raise ValueError(_("Device %(dev_name)s in mapping: %(mapping)s "
                               "not unique") % {'dev_name': dev_name,
                                                'mapping': dev_mapping})
        exclude_devices_list = exclude_devices.split(";")
        exclude_devices_set = set()
        for dev in exclude_devices_list:
            dev = dev.strip()
            if dev:
                exclude_devices_set.add(dev)
        exclude_mapping[dev_name] = exclude_devices_set
    return exclude_mapping
Ejemplo n.º 17
0
def _build_flow_expr_str(flow_dict, cmd):
    flow_expr_arr = []
    actions = None

    if cmd == 'add':
        flow_expr_arr.append("hard_timeout=%s" %
                             flow_dict.pop('hard_timeout', '0'))
        flow_expr_arr.append("idle_timeout=%s" %
                             flow_dict.pop('idle_timeout', '0'))
        flow_expr_arr.append("priority=%s" %
                             flow_dict.pop('priority', '1'))
    elif 'priority' in flow_dict:
        msg = _("Cannot match priority on flow deletion or modification")
        raise exceptions.InvalidInput(error_message=msg)

    if cmd != 'del':
        if "actions" not in flow_dict:
            msg = _("Must specify one or more actions on flow addition"
                    " or modification")
            raise exceptions.InvalidInput(error_message=msg)
        actions = "actions=%s" % flow_dict.pop('actions')

    for key, value in six.iteritems(flow_dict):
        if key == 'proto':
            flow_expr_arr.append(value)
        else:
            flow_expr_arr.append("%s=%s" % (key, str(value)))

    if actions:
        flow_expr_arr.append(actions)

    return ','.join(flow_expr_arr)
Ejemplo n.º 18
0
def row_by_record(idl_, table, record):
    t = idl_.tables[table]
    try:
        if isinstance(record, uuid.UUID):
            return t.rows[record]
        uuid_ = uuid.UUID(record)
        return t.rows[uuid_]
    except ValueError:
        # Not a UUID string, continue lookup by other means
        pass
    except KeyError:
        raise RowNotFound(table=table, col='uuid', match=record)

    rl = _LOOKUP_TABLE.get(table, RowLookup(table, get_index_column(t), None))
    # no table means uuid only, no column is just SSL which we don't need
    if rl.table is None:
        raise ValueError(_("Table %s can only be queried by UUID") % table)
    if rl.column is None:
        raise NotImplementedError(_("'.' searches are not implemented"))
    row = row_by_value(idl_, rl.table, rl.column, record)
    if rl.uuid_column:
        rows = getattr(row, rl.uuid_column)
        if len(rows) != 1:
            raise RowNotFound(table=table, col=_('record'), match=record)
        row = rows[0]
    return row
Ejemplo n.º 19
0
 def _send_msg(self, msg, reply_cls=None, reply_multi=False,
               active_bundle=None):
     timeout_sec = cfg.CONF.OVS.of_request_timeout
     timeout = eventlet.Timeout(seconds=timeout_sec)
     if active_bundle is not None:
         (dp, ofp, ofpp) = self._get_dp()
         msg = ofpp.ONFBundleAddMsg(dp, active_bundle['id'],
                                    active_bundle['bundle_flags'], msg, [])
     try:
         result = ofctl_api.send_msg(self._app, msg, reply_cls, reply_multi)
     except ryu_exc.RyuException as e:
         m = _("ofctl request %(request)s error %(error)s") % {
             "request": msg,
             "error": e,
         }
         LOG.error(m)
         # NOTE(yamamoto): use RuntimeError for compat with ovs_lib
         raise RuntimeError(m)
     except eventlet.Timeout as e:
         with excutils.save_and_reraise_exception() as ctx:
             if e is timeout:
                 ctx.reraise = False
                 m = _("ofctl request %(request)s timed out") % {
                     "request": msg,
                 }
                 LOG.error(m)
                 # NOTE(yamamoto): use RuntimeError for compat with ovs_lib
                 raise RuntimeError(m)
     finally:
         timeout.cancel()
     LOG.debug("ofctl request %(request)s result %(result)s",
               {"request": msg, "result": result})
     return result
Ejemplo n.º 20
0
def _build_flow_expr_str(flow_dict, cmd):
    flow_expr_arr = []
    actions = None

    if cmd == "add":
        flow_expr_arr.append("hard_timeout=%s" % flow_dict.pop("hard_timeout", "0"))
        flow_expr_arr.append("idle_timeout=%s" % flow_dict.pop("idle_timeout", "0"))
        flow_expr_arr.append("priority=%s" % flow_dict.pop("priority", "1"))
    elif "priority" in flow_dict:
        msg = _("Cannot match priority on flow deletion or modification")
        raise exceptions.InvalidInput(error_message=msg)

    if cmd != "del":
        if "actions" not in flow_dict:
            msg = _("Must specify one or more actions on flow addition" " or modification")
            raise exceptions.InvalidInput(error_message=msg)
        actions = "actions=%s" % flow_dict.pop("actions")

    for key, value in six.iteritems(flow_dict):
        if key == "proto":
            flow_expr_arr.append(value)
        else:
            flow_expr_arr.append("%s=%s" % (key, str(value)))

    if actions:
        flow_expr_arr.append(actions)

    return ",".join(flow_expr_arr)
Ejemplo n.º 21
0
def _validate_dns_name_with_dns_domain(request_dns_name):
    # If a PQDN was passed, make sure the FQDN that will be generated is of
    # legal size
    dns_domain = _get_dns_domain()
    higher_labels = dns_domain
    if dns_domain:
        higher_labels = '.%s' % dns_domain
    higher_labels_len = len(higher_labels)
    dns_name_len = len(request_dns_name)
    if not request_dns_name.endswith('.'):
        if dns_name_len + higher_labels_len > FQDN_MAX_LEN:
            msg = _("The dns_name passed is a PQDN and its size is "
                    "'%(dns_name_len)s'. The dns_domain option in "
                    "neutron.conf is set to %(dns_domain)s, with a "
                    "length of '%(higher_labels_len)s'. When the two are "
                    "concatenated to form a FQDN (with a '.' at the end), "
                    "the resulting length exceeds the maximum size "
                    "of '%(fqdn_max_len)s'"
                    ) % {'dns_name_len': dns_name_len,
                         'dns_domain': cfg.CONF.dns_domain,
                         'higher_labels_len': higher_labels_len,
                         'fqdn_max_len': FQDN_MAX_LEN}
            return msg
        return

    # A FQDN was passed
    if (dns_name_len <= higher_labels_len or not
        request_dns_name.endswith(higher_labels)):
        msg = _("The dns_name passed is a FQDN. Its higher level labels "
                "must be equal to the dns_domain option in neutron.conf, "
                "that has been set to '%(dns_domain)s'. It must also "
                "include one or more valid DNS labels to the left "
                "of '%(dns_domain)s'") % {'dns_domain':
                                          cfg.CONF.dns_domain}
        return msg
Ejemplo n.º 22
0
def parse_mappings(mapping_list, unique_values=True):
    """Parse a list of mapping strings into a dictionary.

    :param mapping_list: a list of strings of the form '<key>:<value>'
    :param unique_values: values must be unique if True
    :returns: a dict mapping keys to values
    """
    mappings = {}
    for mapping in mapping_list:
        mapping = mapping.strip()
        if not mapping:
            continue
        split_result = mapping.split(':')
        if len(split_result) != 2:
            raise ValueError(_("Invalid mapping: '%s'") % mapping)
        key = split_result[0].strip()
        if not key:
            raise ValueError(_("Missing key in mapping: '%s'") % mapping)
        value = split_result[1].strip()
        if not value:
            raise ValueError(_("Missing value in mapping: '%s'") % mapping)
        if key in mappings:
            raise ValueError(_("Key %(key)s in mapping: '%(mapping)s' not "
                               "unique") % {'key': key, 'mapping': mapping})
        if unique_values and value in mappings.values():
            raise ValueError(_("Value %(value)s in mapping: '%(mapping)s' "
                               "not unique") % {'value': value,
                                                'mapping': mapping})
        mappings[key] = value
    return mappings
Ejemplo n.º 23
0
    def run_idl(self, txn):
        try:
            port = idlutils.row_by_value(self.api.idl, 'Port', 'name',
                                         self.port)
        except idlutils.RowNotFound:
            if self.if_exists:
                return
            msg = _("Port %s does not exist") % self.port
            raise RuntimeError(msg)
        if self.bridge:
            br = idlutils.row_by_value(self.api.idl, 'Bridge', 'name',
                                       self.bridge)
        else:
            br = next(b for b in self.api._tables['Bridge'].rows.values()
                      if port in b.ports)

        if port.uuid not in br.ports and not self.if_exists:
            # TODO(twilson) Make real errors across both implementations
            msg = _("Port %(port)s does not exist on %(bridge)s!") % {
                'port': self.name, 'bridge': self.bridge
            }
            LOG.error(msg)
            raise RuntimeError(msg)

        br.verify('ports')
        ports = br.ports
        ports.remove(port)
        br.ports = ports

        # Also remove port/interface directly for indexing?
        port.verify('interfaces')
        for iface in port.interfaces:
            self.api._tables['Interface'].rows[iface.uuid].delete()
        self.api._tables['Port'].rows[port.uuid].delete()
Ejemplo n.º 24
0
    def _proxy_request(self, instance_id, tenant_id, req):
        headers = {
            'X-Forwarded-For': req.headers.get('X-Forwarded-For'),
            'X-Instance-ID': instance_id,
            'X-Tenant-ID': tenant_id,
            'X-Instance-ID-Signature': self._sign_instance_id(instance_id)
        }

        nova_host_port = '%s:%s' % (self.conf.nova_metadata_host,
                                    self.conf.nova_metadata_port)
        url = urlparse.urlunsplit((
            self.conf.nova_metadata_protocol,
            nova_host_port,
            req.path_info,
            req.query_string,
            ''))

        disable_ssl_certificate_validation = self.conf.nova_metadata_insecure
        if self.conf.auth_ca_cert and not disable_ssl_certificate_validation:
            verify_cert = self.conf.auth_ca_cert
        else:
            verify_cert = not disable_ssl_certificate_validation

        client_cert = None
        if self.conf.nova_client_cert and self.conf.nova_client_priv_key:
            client_cert = (self.conf.nova_client_cert,
                           self.conf.nova_client_priv_key)

        resp = requests.request(method=req.method, url=url,
                                headers=headers,
                                data=req.body,
                                cert=client_cert,
                                verify=verify_cert)

        if resp.status_code == 200:
            req.response.content_type = resp.headers['content-type']
            req.response.body = resp.content
            LOG.debug(str(resp))
            return req.response
        elif resp.status_code == 403:
            LOG.warning(
                'The remote metadata server responded with Forbidden. This '
                'response usually occurs when shared secrets do not match.'
            )
            return webob.exc.HTTPForbidden()
        elif resp.status_code == 400:
            return webob.exc.HTTPBadRequest()
        elif resp.status_code == 404:
            return webob.exc.HTTPNotFound()
        elif resp.status_code == 409:
            return webob.exc.HTTPConflict()
        elif resp.status_code == 500:
            msg = _(
                'Remote metadata server experienced an internal server error.'
            )
            LOG.warning(msg)
            explanation = six.text_type(msg)
            return webob.exc.HTTPInternalServerError(explanation=explanation)
        else:
            raise Exception(_('Unexpected response code: %s') % resp.status)
Ejemplo n.º 25
0
def _verify_dict_keys(expected_keys, target_dict, strict=True):
    """Allows to verify keys in a dictionary.

    :param expected_keys: A list of keys expected to be present.
    :param target_dict: The dictionary which should be verified.
    :param strict: Specifies whether additional keys are allowed to be present.
    :return: True, if keys in the dictionary correspond to the specification.
    """
    if not isinstance(target_dict, dict):
        msg = (_("Invalid input. '%(target_dict)s' must be a dictionary "
                 "with keys: %(expected_keys)s") %
               {'target_dict': target_dict, 'expected_keys': expected_keys})
        LOG.debug(msg)
        return msg

    expected_keys = set(expected_keys)
    provided_keys = set(target_dict.keys())

    predicate = expected_keys.__eq__ if strict else expected_keys.issubset

    if not predicate(provided_keys):
        msg = (_("Validation of dictionary's keys failed. "
                 "Expected keys: %(expected_keys)s "
                 "Provided keys: %(provided_keys)s") %
               {'expected_keys': expected_keys,
                'provided_keys': provided_keys})
        LOG.debug(msg)
        return msg
Ejemplo n.º 26
0
    def external_network_bridge_check(checker):
        if not cfg.CONF.database.connection:
            return upgradecheck.Result(
                upgradecheck.Code.WARNING,
                _("Database connection string is not set. Check of usage of "
                  "'external_network_bridge' config option in L3 agents "
                  "can't be done"))

        agents_with_external_bridge = []
        for agent in get_l3_agents():
            config_string = agent.get('configurations')
            if not config_string:
                continue
            config = jsonutils.loads(config_string)
            if config.get("external_network_bridge"):
                agents_with_external_bridge.append(agent.get("host"))

        if agents_with_external_bridge:
            return upgradecheck.Result(
                upgradecheck.Code.WARNING,
                _("L3 agents on hosts %s are still using "
                  "'external_network_bridge' config option to provide "
                  "gateway connectivity. This option is now removed. "
                  "Migration of routers from those L3 agents will be "
                  "required to connect them to external network through "
                  "integration bridge.") % agents_with_external_bridge)
        else:
            return upgradecheck.Result(
                upgradecheck.Code.SUCCESS,
                _("L3 agents are using integration bridge to connect external "
                  "gateways"))
Ejemplo n.º 27
0
def _validate_fixed_ips(data, valid_values=None):
    if not isinstance(data, list):
        msg = _("Invalid data format for fixed IP: '%s'") % data
        LOG.debug(msg)
        return msg

    ips = []
    for fixed_ip in data:
        if not isinstance(fixed_ip, dict):
            msg = _("Invalid data format for fixed IP: '%s'") % fixed_ip
            LOG.debug(msg)
            return msg
        if 'ip_address' in fixed_ip:
            # Ensure that duplicate entries are not set - just checking IP
            # suffices. Duplicate subnet_id's are legitimate.
            fixed_ip_address = fixed_ip['ip_address']
            if fixed_ip_address in ips:
                msg = _("Duplicate IP address '%s'") % fixed_ip_address
                LOG.debug(msg)
            else:
                msg = _validate_ip_address(fixed_ip_address)
            if msg:
                return msg
            ips.append(fixed_ip_address)
        if 'subnet_id' in fixed_ip:
            msg = _validate_uuid(fixed_ip['subnet_id'])
            if msg:
                return msg
Ejemplo n.º 28
0
def main():

    class SimpleDaemon(daemon.Daemon):
        """The purpose of this daemon is to serve as an example, and also as
        a dummy daemon, which can be invoked by functional testing, it
        does nothing but setting the pid file, and staying detached in the
        background.
        """

        def run(self):
            while True:
                time.sleep(10)

    opts = [
        cfg.StrOpt('uuid',
                   help=_('uuid provided from the command line '
                          'so external_process can track us via /proc/'
                          'cmdline interface.'),
                   required=True),
        cfg.StrOpt('pid_file',
                   help=_('Location of pid file of this process.'),
                   required=True)
    ]

    cfg.CONF.register_cli_opts(opts)
    # Don't get the default configuration file
    cfg.CONF(project='neutron', default_config_files=[])
    simple_daemon = SimpleDaemon(cfg.CONF.pid_file,
                                 uuid=cfg.CONF.uuid)
    simple_daemon.start()
Ejemplo n.º 29
0
    def _prepare_request_body(self, body, params):
        """Verifies required parameters are in request body.

        Sets default value for missing optional parameters.
        Body argument must be the deserialized body.
        """
        try:
            if body is None:
                # Initialize empty resource for setting default value
                body = {self._resource_name: {}}
            data = body[self._resource_name]
        except KeyError:
            # raise if _resource_name is not in req body.
            raise exc.HTTPBadRequest(_("Unable to find '%s' in request body") %
                                     self._resource_name)
        for param in params:
            param_name = param['param-name']
            param_value = data.get(param_name)
            # If the parameter wasn't found and it was required, return 400
            if param_value is None and param['required']:
                msg = (_("Failed to parse request. "
                         "Parameter '%s' not specified") % param_name)
                LOG.error(msg)
                raise exc.HTTPBadRequest(msg)
            data[param_name] = param_value or param.get('default-value')
        return body
Ejemplo n.º 30
0
 def coerce(self, obj, attr, value):
     if not isinstance(value, six.integer_types):
         msg = _("Field value %s is not an integer") % value
         raise ValueError(msg)
     if not self._start <= value <= self._end:
         msg = _("Field value %s is invalid") % value
         raise ValueError(msg)
     return super(RangeConstrainedInteger, self).coerce(obj, attr, value)
Ejemplo n.º 31
0
class HostConnectedToMultipleSegments(exceptions.Conflict):
    message = _("Host %(host)s is connected to multiple segments on routed "
                "provider network '%(network_id)s'.  It should be connected "
                "to one.")
Ejemplo n.º 32
0
class HostNotCompatibleWithFixedIps(exceptions.Conflict):
    message = _("Host %(host)s is not connected to a segment where the "
                "existing fixed_ips on port %(port_id)s will function given "
                "the routed network topology.")
Ejemplo n.º 33
0
class HostNotConnectedToAnySegment(exceptions.Conflict):
    message = _("Host %(host)s is not connected to any segments on routed "
                "provider network '%(network_id)s'.  It should be connected "
                "to one.")
Ejemplo n.º 34
0
class VersionsCallbackNotFound(exceptions.NeutronException):
    message = _("No versions callback provided in ResourceVersionsManager")
Ejemplo n.º 35
0
class CallbacksMaxLimitReached(exceptions.NeutronException):
    message = _("Cannot add multiple callbacks for %(resource_type)s")
Ejemplo n.º 36
0
class SubnetCantAssociateToDynamicSegment(exceptions.BadRequest):
    message = _("A subnet cannot be associated with a dynamic segment.")
Ejemplo n.º 37
0
class NoUpdateSubnetWhenMultipleSegmentsOnNetwork(exceptions.BadRequest):
    message = _("The network '%(network_id)s' has multiple segments, it is "
                "only possible to associate an existing subnet with a segment "
                "on networks with a single segment.")
Ejemplo n.º 38
0
 def get_name(cls):
     return _("Neutron Service Type Management")
Ejemplo n.º 39
0
class OvsdbConnectionUnavailable(n_exc.ServiceUnavailable):
    message = _("OVS database connection to %(db_schema)s failed with error: "
                "'%(error)s'. Verify that the OVS and OVN services are "
                "available and that the 'ovn_nb_connection' and "
                "'ovn_sb_connection' configuration options are correct.")
Ejemplo n.º 40
0
    def _update(self, request, id, body, **kwargs):
        try:
            body = Controller.prepare_request_body(
                request.context, body, False, self._resource, self._attr_info,
                allow_bulk=self._allow_bulk)
        except Exception as e:
            LOG.warning("An exception happened while processing the request "
                        "body. The exception message is [%s].", e)
            raise e

        action = self._plugin_handlers[self.UPDATE]
        # Load object to check authz
        # but pass only attributes in the original body and required
        # by the policy engine to the policy 'brain'
        field_list = [name for (name, value) in self._attr_info.items()
                      if (value.get('required_by_policy') or
                          value.get('primary_key') or
                          'default' not in value)]
        # Ensure policy engine is initialized
        policy.init()
        parent_id = kwargs.get(self._parent_id_name)
        # If the parent_id exist, we should get orig_obj with
        # self._parent_id_name field.
        if parent_id and self._parent_id_name not in field_list:
            field_list.append(self._parent_id_name)
        orig_obj = self._item(request, id, field_list=field_list,
                              parent_id=parent_id)
        orig_object_copy = copy.copy(orig_obj)
        orig_obj.update(body[self._resource])
        # Make a list of attributes to be updated to inform the policy engine
        # which attributes are set explicitly so that it can distinguish them
        # from the ones that are set to their default values.
        orig_obj[constants.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys()
        # Then get the ext_parent_id, format to ext_parent_parent_resource_id
        if self._parent_id_name in orig_obj:
            self._set_parent_id_into_ext_resources_request(
                request, orig_obj, parent_id)
        try:
            policy.enforce(request.context,
                           action,
                           orig_obj,
                           pluralized=self._collection)
        except oslo_policy.PolicyNotAuthorized:
            # To avoid giving away information, pretend that it
            # doesn't exist if policy does not authorize SHOW
            with excutils.save_and_reraise_exception() as ctxt:
                if not policy.check(request.context,
                                    self._plugin_handlers[self.SHOW],
                                    orig_obj,
                                    pluralized=self._collection):
                    ctxt.reraise = False
            msg = _('The resource could not be found.')
            raise webob.exc.HTTPNotFound(msg)

        if self._native_bulk and hasattr(self._plugin, "%s_bulk" % action):
            obj_updater = getattr(self._plugin, "%s_bulk" % action)
        else:
            obj_updater = getattr(self._plugin, action)

        kwargs = {self._resource: body}
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj = obj_updater(request.context, id, **kwargs)
        # Usually an update operation does not alter resource usage, but as
        # there might be side effects it might be worth checking for changes
        # in resource usage here as well (e.g: a tenant port is created when a
        # router interface is added)
        resource_registry.set_resources_dirty(request.context)

        result = {self._resource: self._view(request.context, obj)}
        notifier_method = self._resource + '.update.end'
        self._notifier.info(request.context, notifier_method, result)
        registry.publish(self._resource, events.BEFORE_RESPONSE, self,
                         payload=events.APIEventPayload(
                             request.context, notifier_method, action,
                             request_body=body,
                             states=(orig_object_copy, result,),
                             collection_name=self._collection))
        return result
Ejemplo n.º 41
0
 def get_description(cls):
     return _("API for retrieving service providers for "
              "Neutron advanced services")
Ejemplo n.º 42
0
    def prepare_request_body(context, body, is_create, resource, attr_info,
                             allow_bulk=False):
        """Verifies required attributes are in request body.

        Also checking that an attribute is only specified if it is allowed
        for the given operation (create/update).

        Attribute with default values are considered to be optional.

        body argument must be the deserialized body.
        """
        collection = resource + "s"
        if not body:
            raise webob.exc.HTTPBadRequest(_("Resource body required"))

        LOG.debug("Request body: %(body)s", {'body': body})
        try:
            if collection in body:
                if not allow_bulk:
                    raise webob.exc.HTTPBadRequest(_("Bulk operation "
                                                     "not supported"))
                if not body[collection]:
                    raise webob.exc.HTTPBadRequest(_("Resources required"))
                try:
                    bulk_body = [
                        Controller.prepare_request_body(
                            context, item if resource in item
                            else {resource: item}, is_create, resource,
                            attr_info, allow_bulk) for item in body[collection]
                    ]
                    return {collection: bulk_body}
                except Exception as e:
                    LOG.warning(
                        "An exception happened while processing the request "
                        "body. The exception message is [%s].", e)
                    raise e

            res_dict = body.get(resource)
        except (AttributeError, TypeError):
            msg = _("Body contains invalid data")
            raise webob.exc.HTTPBadRequest(msg)
        if res_dict is None:
            msg = _("Unable to find '%s' in request body") % resource
            raise webob.exc.HTTPBadRequest(msg)
        if not isinstance(res_dict, dict):
            msg = _("Object '%s' contains invalid data") % resource
            raise webob.exc.HTTPBadRequest(msg)

        attr_ops = attributes.AttributeInfo(attr_info)
        attr_ops.populate_project_id(context, res_dict, is_create)
        attributes.populate_project_info(attr_info)
        attr_ops.verify_attributes(res_dict)

        if is_create:  # POST
            attr_ops.fill_post_defaults(
                res_dict, exc_cls=webob.exc.HTTPBadRequest)
        else:  # PUT
            for attr, attr_vals in attr_info.items():
                if attr in res_dict and not attr_vals['allow_put']:
                    msg = _("Cannot update read-only attribute %s") % attr
                    raise webob.exc.HTTPBadRequest(msg)

        attr_ops.convert_values(res_dict, exc_cls=webob.exc.HTTPBadRequest)
        return body
Ejemplo n.º 43
0
 def validate_existing_attrs(cls_name, dct):
     if 'shared' not in dct['fields']:
         raise KeyError(_('No shared key in %s fields') % cls_name)
     if 'rbac_db_cls' not in dct:
         raise AttributeError(_('rbac_db_cls not found in %s') % cls_name)
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
import six

from neutron._i18n import _, _LE
from neutron.agent.common import utils
from neutron.common import constants
from neutron.common import exceptions

LOG = logging.getLogger(__name__)

OPTS = [
    cfg.BoolOpt('ip_lib_force_root',
                default=False,
                help=_('Force ip_lib calls to use the root helper')),
]

LOOPBACK_DEVNAME = 'lo'

IP_NETNS_PATH = '/var/run/netns'
SYS_NET_PATH = '/sys/class/net'
DEFAULT_GW_PATTERN = re.compile(r"via (\S+)")
METRIC_PATTERN = re.compile(r"metric (\S+)")
DEVICE_NAME_PATTERN = re.compile(r"(\d+?): (\S+?):.*")
BRIDGE_PATH_FOR_DEVICE = SYS_NET_PATH + '/%s/brport/bridge'


def remove_interface_suffix(interface):
    """Remove a possible "<if>@<endpoint>" suffix from an interface' name.
Ejemplo n.º 45
0
class NetworkIdsDontMatch(exceptions.BadRequest):
    message = _("The subnet's network id, '%(subnet_network)s', doesn't match "
                "the network_id of segment '%(segment_id)s'")
Ejemplo n.º 46
0
 def agent_updated(self, context, payload):
     """Handle the agent_updated notification event."""
     self.schedule_resync(
         _("Agent updated: %(payload)s") % {"payload": payload})
     LOG.info("agent_updated by server side %s!", payload)
Ejemplo n.º 47
0
class SubnetSegmentAssociationChangeNotAllowed(exceptions.BadRequest):
    message = _("A subnet that is already associated with a segment cannot "
                "have its segment association changed.")
Ejemplo n.º 48
0
from oslo_log import log
import sqlalchemy as sa
from sqlalchemy import sql

from neutron._i18n import _, _LE
from neutron.db import model_base
from neutron.plugins.common import constants as p_const
from neutron.plugins.ml2.drivers import type_tunnel

LOG = log.getLogger(__name__)

gre_opts = [
    cfg.ListOpt('tunnel_id_ranges',
                default=[],
                help=_("Comma-separated list of <tun_min>:<tun_max> tuples "
                       "enumerating ranges of GRE tunnel IDs that are "
                       "available for tenant network allocation"))
]

cfg.CONF.register_opts(gre_opts, "ml2_type_gre")


class GreAllocation(model_base.BASEV2):

    __tablename__ = 'ml2_gre_allocations'

    gre_id = sa.Column(sa.Integer,
                       nullable=False,
                       primary_key=True,
                       autoincrement=False)
    allocated = sa.Column(sa.Boolean,
Ejemplo n.º 49
0
class SubnetsNotAllAssociatedWithSegments(exceptions.BadRequest):
    message = _("All of the subnets on network '%(network_id)s' must either "
                "all be associated with segments or all not associated with "
                "any segment.")
Ejemplo n.º 50
0
class FixedIpsSubnetsNotOnSameSegment(exceptions.BadRequest):
    message = _("Cannot allocate addresses from different segments.")
Ejemplo n.º 51
0
class SegmentNotFound(exceptions.NotFound):
    message = _("Segment %(segment_id)s could not be found.")
Ejemplo n.º 52
0
class SegmentInUse(exceptions.InUse):
    message = _("Segment '%(segment_id)s' cannot be deleted: %(reason)s.")
Ejemplo n.º 53
0
class CallbackWrongResourceType(exceptions.NeutronException):
    message = _('Callback for %(resource_type)s returned wrong resource type')
class AddressNotReady(exceptions.NeutronException):
    message = _("Failure waiting for address %(address)s to "
                "become ready: %(reason)s")
Ejemplo n.º 55
0
class MultipleAgentFoundByTypeHost(exceptions.Conflict):
    message = _("Multiple agents with agent_type=%(agent_type)s and "
                "host=%(host)s found")
Ejemplo n.º 56
0
class CallbackNotFound(exceptions.NeutronException):
    message = _('Callback for %(resource_type)s not found')
Ejemplo n.º 57
0
class AgentNotFound(exceptions.NotFound):
    message = _("Agent %(id)s could not be found")
Ejemplo n.º 58
0
    def _update(self, request, id, body, **kwargs):
        body = Controller.prepare_request_body(request.context,
                                               body,
                                               False,
                                               self._resource,
                                               self._attr_info,
                                               allow_bulk=self._allow_bulk)
        action = self._plugin_handlers[self.UPDATE]
        # Load object to check authz
        # but pass only attributes in the original body and required
        # by the policy engine to the policy 'brain'
        field_list = [
            name for (name, value) in six.iteritems(self._attr_info)
            if (value.get('required_by_policy') or value.get('primary_key')
                or 'default' not in value)
        ]
        # Ensure policy engine is initialized
        policy.init()
        parent_id = kwargs.get(self._parent_id_name)
        orig_obj = self._item(request,
                              id,
                              field_list=field_list,
                              parent_id=parent_id)
        orig_object_copy = copy.copy(orig_obj)
        orig_obj.update(body[self._resource])
        # Make a list of attributes to be updated to inform the policy engine
        # which attributes are set explicitly so that it can distinguish them
        # from the ones that are set to their default values.
        orig_obj[n_const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys()
        try:
            policy.enforce(request.context,
                           action,
                           orig_obj,
                           pluralized=self._collection)
        except oslo_policy.PolicyNotAuthorized:
            with excutils.save_and_reraise_exception() as ctxt:
                # If a tenant is modifying its own object, it's safe to return
                # a 403. Otherwise, pretend that it doesn't exist to avoid
                # giving away information.
                orig_obj_tenant_id = orig_obj.get("tenant_id")
                if (request.context.tenant_id != orig_obj_tenant_id
                        or orig_obj_tenant_id is None):
                    ctxt.reraise = False
            msg = _('The resource could not be found.')
            raise webob.exc.HTTPNotFound(msg)

        obj_updater = getattr(self._plugin, action)
        kwargs = {self._resource: body}
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj = obj_updater(request.context, id, **kwargs)
        # Usually an update operation does not alter resource usage, but as
        # there might be side effects it might be worth checking for changes
        # in resource usage here as well (e.g: a tenant port is created when a
        # router interface is added)
        resource_registry.set_resources_dirty(request.context)

        result = {self._resource: self._view(request.context, obj)}
        notifier_method = self._resource + '.update.end'
        self._notifier.info(request.context, notifier_method, result)
        registry.notify(self._resource,
                        events.BEFORE_RESPONSE,
                        self,
                        context=request.context,
                        data=result,
                        method_name=notifier_method,
                        action=action,
                        original=orig_object_copy)
        return result
Ejemplo n.º 59
0
from neutron.db import api as db_api
from neutron.db.models import dvr as dvr_models
from neutron.db import models_v2
from neutron.extensions import dvr as ext_dvr
from neutron.extensions import portbindings

LOG = logging.getLogger(__name__)

dvr_mac_address_opts = [
    cfg.StrOpt('dvr_base_mac',
               default="fa:16:3f:00:00:00",
               help=_("The base mac address used for unique "
                      "DVR instances by Neutron. The first 3 octets will "
                      "remain unchanged. If the 4th octet is not 00, it will "
                      "also be used. The others will be randomly generated. "
                      "The 'dvr_base_mac' *must* be different from "
                      "'base_mac' to avoid mixing them up with MAC's "
                      "allocated for tenant ports. A 4 octet example would be "
                      "dvr_base_mac = fa:16:3f:4f:00:00. The default is 3 "
                      "octet")),
]
cfg.CONF.register_opts(dvr_mac_address_opts)


@registry.has_registry_receivers
class DVRDbMixin(ext_dvr.DVRMacAddressPluginBase):
    """Mixin class to add dvr mac address to db_plugin_base_v2."""
    @property
    def plugin(self):
        try:
            if self._plugin is not None:
Ejemplo n.º 60
0
class AgentNotFoundByTypeHost(exceptions.NotFound):
    message = _("Agent with agent_type=%(agent_type)s and host=%(host)s "
                "could not be found")