From 3cd60de8f5631d714e86b0a7d8c00a688c08083e Mon Sep 17 00:00:00 2001 From: Doug Wiegley Date: Thu, 29 Jan 2015 22:57:55 -0700 Subject: [PATCH] Nuke remaining service config and extensions from main repo Change-Id: Ic8ab865a387808c925cc311d9b70ac53f5c2c5b8 Partially-implements: blueprint services-split --- etc/neutron.conf | 29 - etc/services.conf | 43 -- neutron/api/extensions.py | 14 +- neutron/common/repos.py | 50 +- neutron/db/migration/cli.py | 8 +- neutron/extensions/firewall.py | 470 --------------- neutron/extensions/lbaas_agentscheduler.py | 137 ----- neutron/extensions/loadbalancer.py | 508 ---------------- neutron/extensions/loadbalancerv2.py | 566 ------------------ neutron/extensions/vpnaas.py | 484 --------------- neutron/services/provider_configuration.py | 18 +- neutron/tests/unit/test_extension_firewall.py | 486 --------------- 12 files changed, 48 insertions(+), 2765 deletions(-) delete mode 100644 etc/services.conf delete mode 100644 neutron/extensions/firewall.py delete mode 100644 neutron/extensions/lbaas_agentscheduler.py delete mode 100644 neutron/extensions/loadbalancer.py delete mode 100644 neutron/extensions/loadbalancerv2.py delete mode 100644 neutron/extensions/vpnaas.py delete mode 100644 neutron/tests/unit/test_extension_firewall.py diff --git a/etc/neutron.conf b/etc/neutron.conf index 6ff5f06cb..0fa172671 100644 --- a/etc/neutron.conf +++ b/etc/neutron.conf @@ -663,32 +663,3 @@ admin_password = %SERVICE_PASSWORD% # If set, use this value for pool_timeout with sqlalchemy # pool_timeout = 10 - -# TODO(dougwig) - remove these lines once service repos have them -[service_providers] -# Specify service providers (drivers) for advanced services like loadbalancer, VPN, Firewall. -# Must be in form: -# service_provider=::[:default] -# List of allowed service types includes LOADBALANCER, FIREWALL, VPN -# Combination of and must be unique; must also be unique -# This is multiline option, example for default provider: -# service_provider=LOADBALANCER:name:lbaas_plugin_driver_path:default -# example of non-default provider: -# service_provider=FIREWALL:name2:firewall_driver_path -# --- Reference implementations --- -service_provider=LOADBALANCER:Haproxy:neutron_lbaas.services.loadbalancer.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default -service_provider=VPN:openswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default -# In order to activate Radware's lbaas driver you need to uncomment the next line. -# If you want to keep the HA Proxy as the default lbaas driver, remove the attribute default from the line below. -# Otherwise comment the HA Proxy line -# service_provider = LOADBALANCER:Radware:neutron_lbaas.services.loadbalancer.drivers.radware.driver.LoadBalancerDriver:default -# uncomment the following line to make the 'netscaler' LBaaS provider available. -# service_provider=LOADBALANCER:NetScaler:neutron_lbaas.services.loadbalancer.drivers.netscaler.netscaler_driver.NetScalerPluginDriver -# Uncomment the following line (and comment out the OpenSwan VPN line) to enable Cisco's VPN driver. -# service_provider=VPN:cisco:neutron_vpnaas.services.vpn.service_drivers.cisco_ipsec.CiscoCsrIPsecVPNDriver:default -# Uncomment the line below to use Embrane heleos as Load Balancer service provider. -# service_provider=LOADBALANCER:Embrane:neutron_lbaas.services.loadbalancer.drivers.embrane.driver.EmbraneLbaas:default -# Uncomment the line below to use the A10 Networks LBaaS driver. Requires 'pip install a10-neutron-lbaas'. -# service_provider = LOADBALANCER:A10Networks:neutron_lbaas.services.loadbalancer.drivers.a10networks.driver_v1.ThunderDriver:default -# Uncomment the following line to test the LBaaS v2 API _WITHOUT_ a real backend -# service_provider = LOADBALANCERV2:LoggingNoop:neutron_lbaas.services.loadbalancer.drivers.logging_noop.driver.LoggingNoopLoadBalancerDriver:default diff --git a/etc/services.conf b/etc/services.conf deleted file mode 100644 index 262c12082..000000000 --- a/etc/services.conf +++ /dev/null @@ -1,43 +0,0 @@ -[radware] -#vdirect_address = 0.0.0.0 -#ha_secondary_address= -#vdirect_user = vDirect -#vdirect_password = radware -#service_ha_pair = False -#service_throughput = 1000 -#service_ssl_throughput = 200 -#service_compression_throughput = 100 -#service_cache = 20 -#service_adc_type = VA -#service_adc_version= -#service_session_mirroring_enabled = False -#service_isl_vlan = -1 -#service_resource_pool_ids = [] -#actions_to_skip = 'setup_l2_l3' -#l4_action_name = 'BaseCreate' -#l2_l3_workflow_name = openstack_l2_l3 -#l4_workflow_name = openstack_l4 -#l2_l3_ctor_params = service: _REPLACE_, ha_network_name: HA-Network, ha_ip_pool_name: default, allocate_ha_vrrp: True, allocate_ha_ips: True -#l2_l3_setup_params = data_port: 1, data_ip_address: 192.168.200.99, data_ip_mask: 255.255.255.0, gateway: 192.168.200.1, ha_port: 2 - -[netscaler_driver] -#netscaler_ncc_uri = https://ncc_server.acme.org/ncc/v1/api -#netscaler_ncc_username = admin -#netscaler_ncc_password = secret - -[heleoslb] -#esm_mgmt = -#admin_username = -#admin_password = -#lb_image = -#inband_id = -#oob_id = -#mgmt_id = -#dummy_utif_id = -#resource_pool_id = -#async_requests = -#lb_flavor = small -#sync_interval = 60 - -[haproxy] -#jinja_config_template = /opt/stack/neutron/neutron/services/drivers/haproxy/templates/haproxy_v1.4.template diff --git a/neutron/api/extensions.py b/neutron/api/extensions.py index b889c0a32..dd0e71a8a 100644 --- a/neutron/api/extensions.py +++ b/neutron/api/extensions.py @@ -520,18 +520,13 @@ class ExtensionManager(object): implementation. """ - # TODO(dougwig) - remove this after the service extensions move out - # While moving the extensions out of neutron into the service repos, - # don't double-load the same thing. - loaded = [] - for path in self.path.split(':'): if os.path.exists(path): - self._load_all_extensions_from_path(path, loaded) + self._load_all_extensions_from_path(path) else: LOG.error(_LE("Extension path '%s' doesn't exist!"), path) - def _load_all_extensions_from_path(self, path, loaded): + def _load_all_extensions_from_path(self, path): # Sorting the extension list makes the order in which they # are loaded predictable across a cluster of load-balanced # Neutron Servers @@ -541,12 +536,7 @@ class ExtensionManager(object): mod_name, file_ext = os.path.splitext(os.path.split(f)[-1]) ext_path = os.path.join(path, f) if file_ext.lower() == '.py' and not mod_name.startswith('_'): - if mod_name in loaded: - LOG.warn(_LW("Extension already loaded, skipping: %s"), - mod_name) - continue mod = imp.load_source(mod_name, ext_path) - loaded.append(mod_name) ext_name = mod_name[0].upper() + mod_name[1:] new_ext_class = getattr(mod, ext_name, None) if not new_ext_class: diff --git a/neutron/common/repos.py b/neutron/common/repos.py index bf848c5a7..7ce32175a 100644 --- a/neutron/common/repos.py +++ b/neutron/common/repos.py @@ -17,6 +17,8 @@ import ConfigParser import importlib import os +from oslo.config import cfg + from neutron.openstack.common import log as logging LOG = logging.getLogger(__name__) @@ -24,15 +26,21 @@ LOG = logging.getLogger(__name__) class NeutronModules(object): - MODULES = [ - 'neutron_fwaas', - 'neutron_lbaas', - 'neutron_vpnaas' - ] + MODULES = { + 'neutron_fwaas': { + 'alembic-name': 'fwaas', + }, + 'neutron_lbaas': { + 'alembic-name': 'lbaas', + }, + 'neutron_vpnaas': { + 'alembic-name': 'vpnaas', + }, + } def __init__(self): self.repos = {} - for repo in self.MODULES: + for repo in self.MODULES.iterkeys(): self.repos[repo] = {} self.repos[repo]['mod'] = self._import_or_none(repo) self.repos[repo]['ini'] = None @@ -51,18 +59,42 @@ class NeutronModules(object): def module(self, module): return self.repos[module]['mod'] + def alembic_name(self, module): + return self.MODULES[module]['alembic-name'] + # Return an INI parser for the child module. oslo.conf is a bit too # magical in its INI loading, and in one notable case, we need to merge - # together the [service_providers] section for across at least four + # together the [service_providers] section across at least four # repositories. def ini(self, module): if self.repos[module]['ini'] is None: - ini = ConfigParser.SafeConfigParser() + neutron_dir = None + try: + neutron_dir = cfg.CONF.config_dir + except cfg.NoSuchOptError: + pass + + if neutron_dir is None: + neutron_dir = '/etc/neutron' - ini_path = '/etc/neutron/%s.conf' % module + ini = ConfigParser.SafeConfigParser() + ini_path = os.path.join(neutron_dir, '%s.conf' % module) if os.path.exists(ini_path): ini.read(ini_path) self.repos[module]['ini'] = ini return self.repos[module]['ini'] + + def service_providers(self, module): + ini = self.ini(module) + + sp = [] + try: + for name, value in ini.items('service_providers'): + if name == 'service_provider': + sp.append(value) + except ConfigParser.NoSectionError: + pass + + return sp diff --git a/neutron/db/migration/cli.py b/neutron/db/migration/cli.py index 7ed083b79..8312d96e8 100644 --- a/neutron/db/migration/cli.py +++ b/neutron/db/migration/cli.py @@ -23,12 +23,12 @@ from alembic import util as alembic_util from oslo.config import cfg from oslo.utils import importutils +from neutron.common import repos HEAD_FILENAME = 'HEAD' -LBAAS_SERVICE = 'lbaas' -FWAAS_SERVICE = 'fwaas' -VPNAAS_SERVICE = 'vpnaas' -VALID_SERVICES = (LBAAS_SERVICE, FWAAS_SERVICE, VPNAAS_SERVICE) + +mods = repos.NeutronModules() +VALID_SERVICES = map(lambda x: mods.alembic_name(x), mods.installed_list()) _core_opts = [ diff --git a/neutron/extensions/firewall.py b/neutron/extensions/firewall.py deleted file mode 100644 index 4e76c9a49..000000000 --- a/neutron/extensions/firewall.py +++ /dev/null @@ -1,470 +0,0 @@ -# Copyright 2013 Big Switch Networks, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from oslo.config import cfg -import six - -from neutron.api import extensions -from neutron.api.v2 import attributes as attr -from neutron.api.v2 import resource_helper -from neutron.common import exceptions as nexception -from neutron.openstack.common import log as logging -from neutron.plugins.common import constants -from neutron.services import service_base - - -LOG = logging.getLogger(__name__) - - -# Firewall Exceptions -class FirewallNotFound(nexception.NotFound): - message = _("Firewall %(firewall_id)s could not be found.") - - -class FirewallInUse(nexception.InUse): - message = _("Firewall %(firewall_id)s is still active.") - - -class FirewallInPendingState(nexception.Conflict): - message = _("Operation cannot be performed since associated Firewall " - "%(firewall_id)s is in %(pending_state)s.") - - -class FirewallPolicyNotFound(nexception.NotFound): - message = _("Firewall Policy %(firewall_policy_id)s could not be found.") - - -class FirewallPolicyInUse(nexception.InUse): - message = _("Firewall Policy %(firewall_policy_id)s is being used.") - - -class FirewallRuleSharingConflict(nexception.Conflict): - - """FWaaS exception for firewall rules - - When a shared policy is created or updated with unshared rules, - this exception will be raised. - """ - message = _("Operation cannot be performed since Firewall Policy " - "%(firewall_policy_id)s is shared but Firewall Rule " - "%(firewall_rule_id)s is not shared") - - -class FirewallPolicySharingConflict(nexception.Conflict): - - """FWaaS exception for firewall policy - - When a policy is shared without sharing its associated rules, - this exception will be raised. - """ - message = _("Operation cannot be performed. Before sharing Firewall " - "Policy %(firewall_policy_id)s, share associated Firewall " - "Rule %(firewall_rule_id)s") - - -class FirewallRuleNotFound(nexception.NotFound): - message = _("Firewall Rule %(firewall_rule_id)s could not be found.") - - -class FirewallRuleInUse(nexception.InUse): - message = _("Firewall Rule %(firewall_rule_id)s is being used.") - - -class FirewallRuleNotAssociatedWithPolicy(nexception.InvalidInput): - message = _("Firewall Rule %(firewall_rule_id)s is not associated " - " with Firewall Policy %(firewall_policy_id)s.") - - -class FirewallRuleInvalidProtocol(nexception.InvalidInput): - message = _("Firewall Rule protocol %(protocol)s is not supported. " - "Only protocol values %(values)s and their integer " - "representation (0 to 255) are supported.") - - -class FirewallRuleInvalidAction(nexception.InvalidInput): - message = _("Firewall rule action %(action)s is not supported. " - "Only action values %(values)s are supported.") - - -class FirewallRuleInvalidICMPParameter(nexception.InvalidInput): - message = _("%(param)s are not allowed when protocol " - "is set to ICMP.") - - -class FirewallRuleWithPortWithoutProtocolInvalid(nexception.InvalidInput): - message = _("Source/destination port requires a protocol") - - -class FirewallInvalidPortValue(nexception.InvalidInput): - message = _("Invalid value for port %(port)s.") - - -class FirewallRuleInfoMissing(nexception.InvalidInput): - message = _("Missing rule info argument for insert/remove " - "rule operation.") - - -class FirewallInternalDriverError(nexception.NeutronException): - """Fwaas exception for all driver errors. - - On any failure or exception in the driver, driver should log it and - raise this exception to the agent - """ - message = _("%(driver)s: Internal driver error.") - - -class FirewallRuleConflict(nexception.Conflict): - - """Firewall rule conflict exception. - - Occurs when admin policy tries to use another tenant's unshared - rule. - """ - - message = _("Operation cannot be performed since Firewall Rule " - "%(firewall_rule_id)s is not shared and belongs to " - "another tenant %(tenant_id)s") - - -fw_valid_protocol_values = [None, constants.TCP, constants.UDP, constants.ICMP] -fw_valid_action_values = [constants.FWAAS_ALLOW, constants.FWAAS_DENY] - - -def convert_protocol(value): - if value is None: - return - if value.isdigit(): - val = int(value) - if 0 <= val <= 255: - return val - else: - raise FirewallRuleInvalidProtocol( - protocol=value, - values=fw_valid_protocol_values) - elif value.lower() in fw_valid_protocol_values: - return value.lower() - else: - raise FirewallRuleInvalidProtocol( - protocol=value, - values=fw_valid_protocol_values) - - -def convert_action_to_case_insensitive(value): - if value is None: - return - else: - return value.lower() - - -def convert_port_to_string(value): - if value is None: - return - else: - return str(value) - - -def _validate_port_range(data, key_specs=None): - if data is None: - return - data = str(data) - ports = data.split(':') - for p in ports: - try: - val = int(p) - except (ValueError, TypeError): - msg = _("Port '%s' is not a valid number") % p - LOG.debug(msg) - return msg - if val <= 0 or val > 65535: - msg = _("Invalid port '%s'") % p - LOG.debug(msg) - return msg - - -def _validate_ip_or_subnet_or_none(data, valid_values=None): - if data is None: - return None - msg_ip = attr._validate_ip_address(data, valid_values) - if not msg_ip: - return - msg_subnet = attr._validate_subnet(data, valid_values) - if not msg_subnet: - return - return _("%(msg_ip)s and %(msg_subnet)s") % {'msg_ip': msg_ip, - 'msg_subnet': msg_subnet} - - -attr.validators['type:port_range'] = _validate_port_range -attr.validators['type:ip_or_subnet_or_none'] = _validate_ip_or_subnet_or_none - - -RESOURCE_ATTRIBUTE_MAP = { - 'firewall_rules': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'firewall_policy_id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid_or_none': None}, - 'is_visible': True}, - 'shared': {'allow_post': True, 'allow_put': True, - 'default': False, 'convert_to': attr.convert_to_boolean, - 'is_visible': True, 'required_by_policy': True, - 'enforce_policy': True}, - 'protocol': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': None, - 'convert_to': convert_protocol, - 'validate': {'type:values': fw_valid_protocol_values}}, - 'ip_version': {'allow_post': True, 'allow_put': True, - 'default': 4, 'convert_to': attr.convert_to_int, - 'validate': {'type:values': [4, 6]}, - 'is_visible': True}, - 'source_ip_address': {'allow_post': True, 'allow_put': True, - 'validate': {'type:ip_or_subnet_or_none': None}, - 'is_visible': True, 'default': None}, - 'destination_ip_address': {'allow_post': True, 'allow_put': True, - 'validate': {'type:ip_or_subnet_or_none': - None}, - 'is_visible': True, 'default': None}, - 'source_port': {'allow_post': True, 'allow_put': True, - 'validate': {'type:port_range': None}, - 'convert_to': convert_port_to_string, - 'default': None, 'is_visible': True}, - 'destination_port': {'allow_post': True, 'allow_put': True, - 'validate': {'type:port_range': None}, - 'convert_to': convert_port_to_string, - 'default': None, 'is_visible': True}, - 'position': {'allow_post': False, 'allow_put': False, - 'default': None, 'is_visible': True}, - 'action': {'allow_post': True, 'allow_put': True, - 'convert_to': convert_action_to_case_insensitive, - 'validate': {'type:values': fw_valid_action_values}, - 'is_visible': True, 'default': 'deny'}, - 'enabled': {'allow_post': True, 'allow_put': True, - 'default': True, 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - }, - 'firewall_policies': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'shared': {'allow_post': True, 'allow_put': True, - 'default': False, 'convert_to': attr.convert_to_boolean, - 'is_visible': True, 'required_by_policy': True, - 'enforce_policy': True}, - 'firewall_rules': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid_list': None}, - 'convert_to': attr.convert_none_to_empty_list, - 'default': None, 'is_visible': True}, - 'audited': {'allow_post': True, 'allow_put': True, - 'default': False, 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - }, - 'firewalls': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'shared': {'allow_post': True, 'allow_put': True, - 'default': False, 'convert_to': attr.convert_to_boolean, - 'is_visible': False, 'required_by_policy': True, - 'enforce_policy': True}, - 'firewall_policy_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid_or_none': None}, - 'is_visible': True}, - }, -} - -firewall_quota_opts = [ - cfg.IntOpt('quota_firewall', - default=1, - help=_('Number of firewalls allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_firewall_policy', - default=1, - help=_('Number of firewall policies allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_firewall_rule', - default=100, - help=_('Number of firewall rules allowed per tenant. ' - 'A negative value means unlimited.')), -] -cfg.CONF.register_opts(firewall_quota_opts, 'QUOTAS') - - -class Firewall(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "Firewall service" - - @classmethod - def get_alias(cls): - return "fwaas" - - @classmethod - def get_description(cls): - return "Extension for Firewall service" - - @classmethod - def get_namespace(cls): - return "http://wiki.openstack.org/Neutron/FWaaS/API_1.0" - - @classmethod - def get_updated(cls): - return "2013-02-25T10:00:00-00:00" - - @classmethod - def get_resources(cls): - special_mappings = {'firewall_policies': 'firewall_policy'} - plural_mappings = resource_helper.build_plural_mappings( - special_mappings, RESOURCE_ATTRIBUTE_MAP) - attr.PLURALS.update(plural_mappings) - action_map = {'firewall_policy': {'insert_rule': 'PUT', - 'remove_rule': 'PUT'}} - return resource_helper.build_resource_info(plural_mappings, - RESOURCE_ATTRIBUTE_MAP, - constants.FIREWALL, - action_map=action_map) - - @classmethod - def get_plugin_interface(cls): - return FirewallPluginBase - - def update_attributes_map(self, attributes): - super(Firewall, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} - - -@six.add_metaclass(abc.ABCMeta) -class FirewallPluginBase(service_base.ServicePluginBase): - - def get_plugin_name(self): - return constants.FIREWALL - - def get_plugin_type(self): - return constants.FIREWALL - - def get_plugin_description(self): - return 'Firewall service plugin' - - @abc.abstractmethod - def get_firewalls(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_firewall(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_firewall(self, context, firewall): - pass - - @abc.abstractmethod - def update_firewall(self, context, id, firewall): - pass - - @abc.abstractmethod - def delete_firewall(self, context, id): - pass - - @abc.abstractmethod - def get_firewall_rules(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_firewall_rule(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_firewall_rule(self, context, firewall_rule): - pass - - @abc.abstractmethod - def update_firewall_rule(self, context, id, firewall_rule): - pass - - @abc.abstractmethod - def delete_firewall_rule(self, context, id): - pass - - @abc.abstractmethod - def get_firewall_policy(self, context, id, fields=None): - pass - - @abc.abstractmethod - def get_firewall_policies(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def create_firewall_policy(self, context, firewall_policy): - pass - - @abc.abstractmethod - def update_firewall_policy(self, context, id, firewall_policy): - pass - - @abc.abstractmethod - def delete_firewall_policy(self, context, id): - pass - - @abc.abstractmethod - def insert_rule(self, context, id, rule_info): - pass - - @abc.abstractmethod - def remove_rule(self, context, id, rule_info): - pass diff --git a/neutron/extensions/lbaas_agentscheduler.py b/neutron/extensions/lbaas_agentscheduler.py deleted file mode 100644 index a821cb6e8..000000000 --- a/neutron/extensions/lbaas_agentscheduler.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from neutron.api import extensions -from neutron.api.v2 import base -from neutron.api.v2 import resource -from neutron.common import constants -from neutron.extensions import agent -from neutron.extensions import loadbalancer -from neutron import manager -from neutron.plugins.common import constants as plugin_const -from neutron import policy -from neutron import wsgi - -LOADBALANCER_POOL = 'loadbalancer-pool' -LOADBALANCER_POOLS = LOADBALANCER_POOL + 's' -LOADBALANCER_AGENT = 'loadbalancer-agent' - - -class PoolSchedulerController(wsgi.Controller): - def index(self, request, **kwargs): - lbaas_plugin = manager.NeutronManager.get_service_plugins().get( - plugin_const.LOADBALANCER) - if not lbaas_plugin: - return {'pools': []} - - policy.enforce(request.context, - "get_%s" % LOADBALANCER_POOLS, - {}, - plugin=lbaas_plugin) - return lbaas_plugin.list_pools_on_lbaas_agent( - request.context, kwargs['agent_id']) - - -class LbaasAgentHostingPoolController(wsgi.Controller): - def index(self, request, **kwargs): - lbaas_plugin = manager.NeutronManager.get_service_plugins().get( - plugin_const.LOADBALANCER) - if not lbaas_plugin: - return - - policy.enforce(request.context, - "get_%s" % LOADBALANCER_AGENT, - {}, - plugin=lbaas_plugin) - return lbaas_plugin.get_lbaas_agent_hosting_pool( - request.context, kwargs['pool_id']) - - -class Lbaas_agentscheduler(extensions.ExtensionDescriptor): - """Extension class supporting LBaaS agent scheduler. - """ - - @classmethod - def get_name(cls): - return "Loadbalancer Agent Scheduler" - - @classmethod - def get_alias(cls): - return constants.LBAAS_AGENT_SCHEDULER_EXT_ALIAS - - @classmethod - def get_description(cls): - return "Schedule pools among lbaas agents" - - @classmethod - def get_namespace(cls): - return "http://docs.openstack.org/ext/lbaas_agent_scheduler/api/v1.0" - - @classmethod - def get_updated(cls): - return "2013-02-07T10:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Ext Resources.""" - exts = [] - parent = dict(member_name="agent", - collection_name="agents") - - controller = resource.Resource(PoolSchedulerController(), - base.FAULT_MAP) - exts.append(extensions.ResourceExtension( - LOADBALANCER_POOLS, controller, parent)) - - parent = dict(member_name="pool", - collection_name="pools") - - controller = resource.Resource(LbaasAgentHostingPoolController(), - base.FAULT_MAP) - exts.append(extensions.ResourceExtension( - LOADBALANCER_AGENT, controller, parent, - path_prefix=plugin_const. - COMMON_PREFIXES[plugin_const.LOADBALANCER])) - return exts - - def get_extended_resources(self, version): - return {} - - -class NoEligibleLbaasAgent(loadbalancer.NoEligibleBackend): - message = _("No eligible loadbalancer agent found " - "for pool %(pool_id)s.") - - -class NoActiveLbaasAgent(agent.AgentNotFound): - message = _("No active loadbalancer agent found " - "for pool %(pool_id)s.") - - -class LbaasAgentSchedulerPluginBase(object): - """REST API to operate the lbaas agent scheduler. - - All of method must be in an admin context. - """ - - @abc.abstractmethod - def list_pools_on_lbaas_agent(self, context, id): - pass - - @abc.abstractmethod - def get_lbaas_agent_hosting_pool(self, context, pool_id): - pass diff --git a/neutron/extensions/loadbalancer.py b/neutron/extensions/loadbalancer.py deleted file mode 100644 index 54650cfd3..000000000 --- a/neutron/extensions/loadbalancer.py +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright 2012 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from oslo.config import cfg -import six - -from neutron.api import extensions -from neutron.api.v2 import attributes as attr -from neutron.api.v2 import base -from neutron.api.v2 import resource_helper -from neutron.common import exceptions as nexception -from neutron import manager -from neutron.plugins.common import constants -from neutron.services import service_base - - -# Loadbalancer Exceptions -class DelayOrTimeoutInvalid(nexception.BadRequest): - message = _("Delay must be greater than or equal to timeout") - - -class NoEligibleBackend(nexception.NotFound): - message = _("No eligible backend for pool %(pool_id)s") - - -class VipNotFound(nexception.NotFound): - message = _("Vip %(vip_id)s could not be found") - - -class VipExists(nexception.NeutronException): - message = _("Another Vip already exists for pool %(pool_id)s") - - -class PoolNotFound(nexception.NotFound): - message = _("Pool %(pool_id)s could not be found") - - -class MemberNotFound(nexception.NotFound): - message = _("Member %(member_id)s could not be found") - - -class HealthMonitorNotFound(nexception.NotFound): - message = _("Health_monitor %(monitor_id)s could not be found") - - -class PoolMonitorAssociationNotFound(nexception.NotFound): - message = _("Monitor %(monitor_id)s is not associated " - "with Pool %(pool_id)s") - - -class PoolMonitorAssociationExists(nexception.Conflict): - message = _('health_monitor %(monitor_id)s is already associated ' - 'with pool %(pool_id)s') - - -class StateInvalid(nexception.NeutronException): - message = _("Invalid state %(state)s of Loadbalancer resource %(id)s") - - -class PoolInUse(nexception.InUse): - message = _("Pool %(pool_id)s is still in use") - - -class HealthMonitorInUse(nexception.InUse): - message = _("Health monitor %(monitor_id)s still has associations with " - "pools") - - -class PoolStatsNotFound(nexception.NotFound): - message = _("Statistics of Pool %(pool_id)s could not be found") - - -class ProtocolMismatch(nexception.BadRequest): - message = _("Protocol %(vip_proto)s does not match " - "pool protocol %(pool_proto)s") - - -class MemberExists(nexception.NeutronException): - message = _("Member with address %(address)s and port %(port)s " - "already present in pool %(pool)s") - - -RESOURCE_ATTRIBUTE_MAP = { - 'vips': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '', - 'is_visible': True}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'subnet_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'address': {'allow_post': True, 'allow_put': False, - 'default': attr.ATTR_NOT_SPECIFIED, - 'validate': {'type:ip_address_or_none': None}, - 'is_visible': True}, - 'port_id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'protocol_port': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': [0, 65535]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'protocol': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': ['TCP', 'HTTP', 'HTTPS']}, - 'is_visible': True}, - 'pool_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'session_persistence': {'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_none_to_empty_dict, - 'default': {}, - 'validate': { - 'type:dict_or_empty': { - 'type': {'type:values': ['APP_COOKIE', - 'HTTP_COOKIE', - 'SOURCE_IP'], - 'required': True}, - 'cookie_name': {'type:string': None, - 'required': False}}}, - 'is_visible': True}, - 'connection_limit': {'allow_post': True, 'allow_put': True, - 'default': -1, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'status_description': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'pools': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'vip_id': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '', - 'is_visible': True}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'subnet_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'protocol': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': ['TCP', 'HTTP', 'HTTPS']}, - 'is_visible': True}, - 'provider': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': attr.ATTR_NOT_SPECIFIED}, - 'lb_method': {'allow_post': True, 'allow_put': True, - 'validate': {'type:values': ['ROUND_ROBIN', - 'LEAST_CONNECTIONS', - 'SOURCE_IP']}, - 'is_visible': True}, - 'members': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'health_monitors': {'allow_post': True, 'allow_put': True, - 'default': None, - 'validate': {'type:uuid_list': None}, - 'convert_to': attr.convert_to_list, - 'is_visible': True}, - 'health_monitors_status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'status_description': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'members': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'pool_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'address': {'allow_post': True, 'allow_put': False, - 'validate': {'type:ip_address': None}, - 'is_visible': True}, - 'protocol_port': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': [0, 65535]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'weight': {'allow_post': True, 'allow_put': True, - 'default': 1, - 'validate': {'type:range': [0, 256]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'status_description': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'health_monitors': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'type': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': ['PING', 'TCP', 'HTTP', 'HTTPS']}, - 'is_visible': True}, - 'delay': {'allow_post': True, 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'timeout': {'allow_post': True, 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'max_retries': {'allow_post': True, 'allow_put': True, - 'validate': {'type:range': [1, 10]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'http_method': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': 'GET', - 'is_visible': True}, - 'url_path': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '/', - 'is_visible': True}, - 'expected_codes': {'allow_post': True, 'allow_put': True, - 'validate': { - 'type:regex': - r'^(\d{3}(\s*,\s*\d{3})*)$|^(\d{3}-\d{3})$'}, - 'default': '200', - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'status_description': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'pools': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - } -} - -SUB_RESOURCE_ATTRIBUTE_MAP = { - 'health_monitors': { - 'parent': {'collection_name': 'pools', - 'member_name': 'pool'}, - 'parameters': {'id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - } - } -} - -lbaas_quota_opts = [ - cfg.IntOpt('quota_vip', - default=10, - help=_('Number of vips allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_pool', - default=10, - help=_('Number of pools allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_member', - default=-1, - help=_('Number of pool members allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_health_monitor', - default=-1, - help=_('Number of health monitors allowed per tenant. ' - 'A negative value means unlimited.')) -] -cfg.CONF.register_opts(lbaas_quota_opts, 'QUOTAS') - - -class Loadbalancer(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "LoadBalancing service" - - @classmethod - def get_alias(cls): - return "lbaas" - - @classmethod - def get_description(cls): - return "Extension for LoadBalancing service" - - @classmethod - def get_namespace(cls): - return "http://wiki.openstack.org/neutron/LBaaS/API_1.0" - - @classmethod - def get_updated(cls): - return "2012-10-07T10:00:00-00:00" - - @classmethod - def get_resources(cls): - plural_mappings = resource_helper.build_plural_mappings( - {}, RESOURCE_ATTRIBUTE_MAP) - plural_mappings['health_monitors_status'] = 'health_monitor_status' - attr.PLURALS.update(plural_mappings) - action_map = {'pool': {'stats': 'GET'}} - resources = resource_helper.build_resource_info(plural_mappings, - RESOURCE_ATTRIBUTE_MAP, - constants.LOADBALANCER, - action_map=action_map, - register_quota=True) - plugin = manager.NeutronManager.get_service_plugins()[ - constants.LOADBALANCER] - for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP: - # Special handling needed for sub-resources with 'y' ending - # (e.g. proxies -> proxy) - resource_name = collection_name[:-1] - parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get('parent') - params = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( - 'parameters') - - controller = base.create_resource(collection_name, resource_name, - plugin, params, - allow_bulk=True, - parent=parent) - - resource = extensions.ResourceExtension( - collection_name, - controller, parent, - path_prefix=constants.COMMON_PREFIXES[constants.LOADBALANCER], - attr_map=params) - resources.append(resource) - - return resources - - @classmethod - def get_plugin_interface(cls): - return LoadBalancerPluginBase - - def update_attributes_map(self, attributes): - super(Loadbalancer, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} - - -@six.add_metaclass(abc.ABCMeta) -class LoadBalancerPluginBase(service_base.ServicePluginBase): - - def get_plugin_name(self): - return constants.LOADBALANCER - - def get_plugin_type(self): - return constants.LOADBALANCER - - def get_plugin_description(self): - return 'LoadBalancer service plugin' - - @abc.abstractmethod - def get_vips(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_vip(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_vip(self, context, vip): - pass - - @abc.abstractmethod - def update_vip(self, context, id, vip): - pass - - @abc.abstractmethod - def delete_vip(self, context, id): - pass - - @abc.abstractmethod - def get_pools(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_pool(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_pool(self, context, pool): - pass - - @abc.abstractmethod - def update_pool(self, context, id, pool): - pass - - @abc.abstractmethod - def delete_pool(self, context, id): - pass - - @abc.abstractmethod - def stats(self, context, pool_id): - pass - - @abc.abstractmethod - def create_pool_health_monitor(self, context, health_monitor, pool_id): - pass - - @abc.abstractmethod - def get_pool_health_monitor(self, context, id, pool_id, fields=None): - pass - - @abc.abstractmethod - def delete_pool_health_monitor(self, context, id, pool_id): - pass - - @abc.abstractmethod - def get_members(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_member(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_member(self, context, member): - pass - - @abc.abstractmethod - def update_member(self, context, id, member): - pass - - @abc.abstractmethod - def delete_member(self, context, id): - pass - - @abc.abstractmethod - def get_health_monitors(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_health_monitor(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_health_monitor(self, context, health_monitor): - pass - - @abc.abstractmethod - def update_health_monitor(self, context, id, health_monitor): - pass - - @abc.abstractmethod - def delete_health_monitor(self, context, id): - pass diff --git a/neutron/extensions/loadbalancerv2.py b/neutron/extensions/loadbalancerv2.py deleted file mode 100644 index 79c954219..000000000 --- a/neutron/extensions/loadbalancerv2.py +++ /dev/null @@ -1,566 +0,0 @@ -# Copyright 2014 OpenStack Foundation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import abc - -from oslo.config import cfg -import six - -from neutron.api import extensions -from neutron.api.v2 import attributes as attr -from neutron.api.v2 import base -from neutron.api.v2 import resource_helper -from neutron.common import exceptions as nexception -from neutron import manager -from neutron.plugins.common import constants -from neutron.services import service_base - -# TODO(dougw) - stop hard-coding these constants when this extension moves -# to the neutron-lbaas repo -#from neutron.services.loadbalancer import constants as lb_const - -LB_METHOD_ROUND_ROBIN = 'ROUND_ROBIN' -LB_METHOD_LEAST_CONNECTIONS = 'LEAST_CONNECTIONS' -LB_METHOD_SOURCE_IP = 'SOURCE_IP' -SUPPORTED_LB_ALGORITHMS = (LB_METHOD_LEAST_CONNECTIONS, LB_METHOD_ROUND_ROBIN, - LB_METHOD_SOURCE_IP) - -PROTOCOL_TCP = 'TCP' -PROTOCOL_HTTP = 'HTTP' -PROTOCOL_HTTPS = 'HTTPS' -SUPPORTED_PROTOCOLS = (PROTOCOL_TCP, PROTOCOL_HTTPS, PROTOCOL_HTTP) - - -HEALTH_MONITOR_PING = 'PING' -HEALTH_MONITOR_TCP = 'TCP' -HEALTH_MONITOR_HTTP = 'HTTP' -HEALTH_MONITOR_HTTPS = 'HTTPS' -SUPPORTED_HEALTH_MONITOR_TYPES = (HEALTH_MONITOR_HTTP, HEALTH_MONITOR_HTTPS, - HEALTH_MONITOR_PING, HEALTH_MONITOR_TCP) - - -SESSION_PERSISTENCE_SOURCE_IP = 'SOURCE_IP' -SESSION_PERSISTENCE_HTTP_COOKIE = 'HTTP_COOKIE' -SESSION_PERSISTENCE_APP_COOKIE = 'APP_COOKIE' -SUPPORTED_SP_TYPES = (SESSION_PERSISTENCE_SOURCE_IP, - SESSION_PERSISTENCE_HTTP_COOKIE, - SESSION_PERSISTENCE_APP_COOKIE) - - -# Loadbalancer Exceptions -# This exception is only for a workaround when having v1 and v2 lbaas extension -# and plugins enabled -class RequiredAttributeNotSpecified(nexception.BadRequest): - message = _("Required attribute %(attr_name)s not specified") - - -class EntityNotFound(nexception.NotFound): - message = _("%(name)s %(id)s could not be found") - - -class DelayOrTimeoutInvalid(nexception.BadRequest): - message = _("Delay must be greater than or equal to timeout") - - -class EntityInUse(nexception.InUse): - message = _("%(entity_using)s %(id)s is using this %(entity_in_use)s") - - -class LoadBalancerListenerProtocolPortExists(nexception.Conflict): - message = _("Load Balancer %(lb_id)s already has a listener with " - "protocol_port of %(protocol_port)s") - - -class ListenerPoolProtocolMismatch(nexception.Conflict): - message = _("Listener protocol %(listener_proto)s and pool protocol " - "%(pool_proto)s are not compatible.") - - -class AttributeIDImmutable(nexception.NeutronException): - message = _("Cannot change %(attribute)s if one already exists") - - -class StateInvalid(nexception.NeutronException): - message = _("Invalid state %(state)s of loadbalancer resource %(id)s") - - -class MemberNotFoundForPool(nexception.NotFound): - message = _("Member %(member_id)s could not be found in pool %(pool_id)s") - - -class MemberExists(nexception.Conflict): - message = _("Member with address %(address)s and protocol_port %(port)s " - "already present in pool %(pool)s") - - -class MemberAddressTypeSubnetTypeMismatch(nexception.NeutronException): - message = _("Member with address %(address)s and subnet %(subnet_id) " - " have mismatched IP versions") - - -class DriverError(nexception.NeutronException): - message = _("An error happened in the driver") - - -class LBConfigurationUnsupported(nexception.NeutronException): - message = _("Load balancer %(load_balancer_id)s configuration is not" - "supported by driver %(driver_name)s") - - -RESOURCE_ATTRIBUTE_MAP = { - 'loadbalancers': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '', - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'vip_subnet_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'vip_address': {'allow_post': True, 'allow_put': False, - 'default': attr.ATTR_NOT_SPECIFIED, - 'validate': {'type:ip_address_or_none': None}, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'listeners': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '', - 'is_visible': True}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'loadbalancer_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid_or_none': None}, - 'default': attr.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - 'default_pool_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:uuid_or_none': None}, - 'default': attr.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - 'connection_limit': {'allow_post': True, 'allow_put': True, - 'default': -1, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'protocol': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': SUPPORTED_PROTOCOLS}, - 'is_visible': True}, - 'protocol_port': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': [0, 65535]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'pools': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'healthmonitor_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string_or_none': None}, - 'is_visible': True, - 'default': attr.ATTR_NOT_SPECIFIED}, - 'protocol': {'allow_post': True, 'allow_put': False, - 'validate': {'type:values': SUPPORTED_PROTOCOLS}, - 'is_visible': True}, - 'lb_algorithm': {'allow_post': True, 'allow_put': True, - 'validate': { - 'type:values': SUPPORTED_LB_ALGORITHMS}, - # TODO(brandon-logan) remove when old API is removed - # because this is a required attribute) - 'default': attr.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - 'session_persistence': { - 'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_none_to_empty_dict, - 'default': {}, - 'validate': { - 'type:dict_or_empty': { - 'type': { - 'type:values': SUPPORTED_SP_TYPES, - 'required': True}, - 'cookie_name': {'type:string': None, - 'required': False}}}, - 'is_visible': True}, - 'members': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - 'healthmonitors': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'type': {'allow_post': True, 'allow_put': False, - 'validate': { - 'type:values': SUPPORTED_HEALTH_MONITOR_TYPES}, - 'is_visible': True}, - 'delay': {'allow_post': True, 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'timeout': {'allow_post': True, 'allow_put': True, - 'validate': {'type:non_negative': None}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'max_retries': {'allow_post': True, 'allow_put': True, - 'validate': {'type:range': [1, 10]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'http_method': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': 'GET', - 'is_visible': True}, - 'url_path': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'default': '/', - 'is_visible': True}, - 'expected_codes': { - 'allow_post': True, - 'allow_put': True, - 'validate': { - 'type:regex': r'^(\d{3}(\s*,\s*\d{3})*)$|^(\d{3}-\d{3})$' - }, - 'default': '200', - 'is_visible': True - }, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - } -} - -SUB_RESOURCE_ATTRIBUTE_MAP = { - 'members': { - 'parent': {'collection_name': 'pools', - 'member_name': 'pool'}, - 'parameters': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'address': {'allow_post': True, 'allow_put': False, - 'validate': {'type:ip_address': None}, - 'is_visible': True}, - 'protocol_port': {'allow_post': True, 'allow_put': False, - 'validate': {'type:range': [0, 65535]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'weight': {'allow_post': True, 'allow_put': True, - 'default': 1, - 'validate': {'type:range': [0, 256]}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'subnet_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - - } - } -} - - -lbaasv2_quota_opts = [ - cfg.IntOpt('quota_loadbalancer', - default=10, - help=_('Number of LoadBalancers allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_listener', - default=-1, - help=_('Number of Loadbalancer Listeners allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_pool', - default=10, - help=_('Number of pools allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_member', - default=-1, - help=_('Number of pool members allowed per tenant. ' - 'A negative value means unlimited.')), - cfg.IntOpt('quota_healthmonitor', - default=-1, - help=_('Number of health monitors allowed per tenant. ' - 'A negative value means unlimited.')) -] -cfg.CONF.register_opts(lbaasv2_quota_opts, 'QUOTAS') - - -class Loadbalancerv2(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "LoadBalancing service v2" - - @classmethod - def get_alias(cls): - return "lbaasv2" - - @classmethod - def get_description(cls): - return "Extension for LoadBalancing service v2" - - @classmethod - def get_namespace(cls): - return "http://wiki.openstack.org/neutron/LBaaS/API_2.0" - - @classmethod - def get_updated(cls): - return "2014-06-18T10:00:00-00:00" - - @classmethod - def get_resources(cls): - plural_mappings = resource_helper.build_plural_mappings( - {}, RESOURCE_ATTRIBUTE_MAP) - action_map = {'loadbalancer': {'stats': 'GET'}} - plural_mappings['members'] = 'member' - attr.PLURALS.update(plural_mappings) - resources = resource_helper.build_resource_info( - plural_mappings, - RESOURCE_ATTRIBUTE_MAP, - constants.LOADBALANCERV2, - action_map=action_map, - register_quota=True) - plugin = manager.NeutronManager.get_service_plugins()[ - constants.LOADBALANCERV2] - for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP: - # Special handling needed for sub-resources with 'y' ending - # (e.g. proxies -> proxy) - resource_name = collection_name[:-1] - parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get('parent') - params = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name].get( - 'parameters') - - controller = base.create_resource(collection_name, resource_name, - plugin, params, - allow_bulk=True, - parent=parent, - allow_pagination=True, - allow_sorting=True) - - resource = extensions.ResourceExtension( - collection_name, - controller, parent, - path_prefix=constants.COMMON_PREFIXES[ - constants.LOADBALANCERV2], - attr_map=params) - resources.append(resource) - - return resources - - @classmethod - def get_plugin_interface(cls): - return LoadBalancerPluginBaseV2 - - def update_attributes_map(self, attributes, extension_attrs_map=None): - super(Loadbalancerv2, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} - - -@six.add_metaclass(abc.ABCMeta) -class LoadBalancerPluginBaseV2(service_base.ServicePluginBase): - - def get_plugin_name(self): - return constants.LOADBALANCERV2 - - def get_plugin_type(self): - return constants.LOADBALANCERV2 - - def get_plugin_description(self): - return 'LoadBalancer service plugin v2' - - @abc.abstractmethod - def get_loadbalancers(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_loadbalancer(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_loadbalancer(self, context, loadbalancer): - pass - - @abc.abstractmethod - def update_loadbalancer(self, context, id, loadbalancer): - pass - - @abc.abstractmethod - def delete_loadbalancer(self, context, id): - pass - - @abc.abstractmethod - def create_listener(self, context, listener): - pass - - @abc.abstractmethod - def get_listener(self, context, id, fields=None): - pass - - @abc.abstractmethod - def get_listeners(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def update_listener(self, context, id, listener): - pass - - @abc.abstractmethod - def delete_listener(self, context, id): - pass - - @abc.abstractmethod - def get_pools(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_pool(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_pool(self, context, pool): - pass - - @abc.abstractmethod - def update_pool(self, context, id, pool): - pass - - @abc.abstractmethod - def delete_pool(self, context, id): - pass - - @abc.abstractmethod - def stats(self, context, loadbalancer_id): - pass - - @abc.abstractmethod - def get_pool_members(self, context, pool_id, - filters=None, - fields=None): - pass - - @abc.abstractmethod - def get_pool_member(self, context, id, pool_id, - fields=None): - pass - - @abc.abstractmethod - def create_pool_member(self, context, member, - pool_id): - pass - - @abc.abstractmethod - def update_pool_member(self, context, member, id, - pool_id): - pass - - @abc.abstractmethod - def delete_pool_member(self, context, id, pool_id): - pass - - @abc.abstractmethod - def get_healthmonitors(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_healthmonitor(self, context, id, fields=None): - pass - - @abc.abstractmethod - def create_healthmonitor(self, context, healthmonitor): - pass - - @abc.abstractmethod - def update_healthmonitor(self, context, id, healthmonitor): - pass - - @abc.abstractmethod - def delete_healthmonitor(self, context, id): - pass - - @abc.abstractmethod - def get_members(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_member(self, context, id, fields=None): - pass diff --git a/neutron/extensions/vpnaas.py b/neutron/extensions/vpnaas.py deleted file mode 100644 index 22768249a..000000000 --- a/neutron/extensions/vpnaas.py +++ /dev/null @@ -1,484 +0,0 @@ -# (c) Copyright 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -import six - -from neutron.api import extensions -from neutron.api.v2 import attributes as attr -from neutron.api.v2 import resource_helper -from neutron.common import exceptions as nexception -from neutron.plugins.common import constants -from neutron.services import service_base - - -class VPNServiceNotFound(nexception.NotFound): - message = _("VPNService %(vpnservice_id)s could not be found") - - -class IPsecSiteConnectionNotFound(nexception.NotFound): - message = _("ipsec_site_connection %(ipsec_site_conn_id)s not found") - - -class IPsecSiteConnectionDpdIntervalValueError(nexception.InvalidInput): - message = _("ipsec_site_connection %(attr)s is " - "equal to or less than dpd_interval") - - -class IPsecSiteConnectionMtuError(nexception.InvalidInput): - message = _("ipsec_site_connection MTU %(mtu)d is too small " - "for ipv%(version)s") - - -class IKEPolicyNotFound(nexception.NotFound): - message = _("IKEPolicy %(ikepolicy_id)s could not be found") - - -class IPsecPolicyNotFound(nexception.NotFound): - message = _("IPsecPolicy %(ipsecpolicy_id)s could not be found") - - -class IKEPolicyInUse(nexception.InUse): - message = _("IKEPolicy %(ikepolicy_id)s is in use by existing " - "IPsecSiteConnection and can't be updated or deleted") - - -class VPNServiceInUse(nexception.InUse): - message = _("VPNService %(vpnservice_id)s is still in use") - - -class RouterInUseByVPNService(nexception.InUse): - message = _("Router %(router_id)s is used by VPNService %(vpnservice_id)s") - - -class SubnetInUseByVPNService(nexception.InUse): - message = _("Subnet %(subnet_id)s is used by VPNService %(vpnservice_id)s") - - -class VPNStateInvalidToUpdate(nexception.BadRequest): - message = _("Invalid state %(state)s of vpnaas resource %(id)s" - " for updating") - - -class IPsecPolicyInUse(nexception.InUse): - message = _("IPsecPolicy %(ipsecpolicy_id)s is in use by existing " - "IPsecSiteConnection and can't be updated or deleted") - - -class DeviceDriverImportError(nexception.NeutronException): - message = _("Can not load driver :%(device_driver)s") - - -class SubnetIsNotConnectedToRouter(nexception.BadRequest): - message = _("Subnet %(subnet_id)s is not " - "connected to Router %(router_id)s") - - -class RouterIsNotExternal(nexception.BadRequest): - message = _("Router %(router_id)s has no external network gateway set") - - -vpn_supported_initiators = ['bi-directional', 'response-only'] -vpn_supported_encryption_algorithms = ['3des', 'aes-128', - 'aes-192', 'aes-256'] -vpn_dpd_supported_actions = [ - 'hold', 'clear', 'restart', 'restart-by-peer', 'disabled' -] -vpn_supported_transform_protocols = ['esp', 'ah', 'ah-esp'] -vpn_supported_encapsulation_mode = ['tunnel', 'transport'] -#TODO(nati) add kilobytes when we support it -vpn_supported_lifetime_units = ['seconds'] -vpn_supported_pfs = ['group2', 'group5', 'group14'] -vpn_supported_ike_versions = ['v1', 'v2'] -vpn_supported_auth_mode = ['psk'] -vpn_supported_auth_algorithms = ['sha1'] -vpn_supported_phase1_negotiation_mode = ['main'] - -vpn_lifetime_limits = (60, attr.UNLIMITED) -positive_int = (0, attr.UNLIMITED) - -RESOURCE_ATTRIBUTE_MAP = { - - 'vpnservices': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'subnet_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'router_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True} - }, - - 'ipsec_site_connections': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'peer_address': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True}, - 'peer_id': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True}, - 'peer_cidrs': {'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_to_list, - 'validate': {'type:subnet_list': None}, - 'is_visible': True}, - 'route_mode': {'allow_post': False, 'allow_put': False, - 'default': 'static', - 'is_visible': True}, - 'mtu': {'allow_post': True, 'allow_put': True, - 'default': '1500', - 'validate': {'type:range': positive_int}, - 'convert_to': attr.convert_to_int, - 'is_visible': True}, - 'initiator': {'allow_post': True, 'allow_put': True, - 'default': 'bi-directional', - 'validate': {'type:values': vpn_supported_initiators}, - 'is_visible': True}, - 'auth_mode': {'allow_post': False, 'allow_put': False, - 'default': 'psk', - 'validate': {'type:values': vpn_supported_auth_mode}, - 'is_visible': True}, - 'psk': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True}, - 'dpd': {'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_none_to_empty_dict, - 'is_visible': True, - 'default': {}, - 'validate': { - 'type:dict_or_empty': { - 'actions': { - 'type:values': vpn_dpd_supported_actions, - }, - 'interval': { - 'type:range': positive_int - }, - 'timeout': { - 'type:range': positive_int - }}}}, - 'admin_state_up': {'allow_post': True, 'allow_put': True, - 'default': True, - 'convert_to': attr.convert_to_boolean, - 'is_visible': True}, - 'status': {'allow_post': False, 'allow_put': False, - 'is_visible': True}, - 'vpnservice_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'ikepolicy_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True}, - 'ipsecpolicy_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True} - }, - - 'ipsecpolicies': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'transform_protocol': { - 'allow_post': True, - 'allow_put': True, - 'default': 'esp', - 'validate': { - 'type:values': vpn_supported_transform_protocols}, - 'is_visible': True}, - 'auth_algorithm': { - 'allow_post': True, - 'allow_put': True, - 'default': 'sha1', - 'validate': { - 'type:values': vpn_supported_auth_algorithms - }, - 'is_visible': True}, - 'encryption_algorithm': { - 'allow_post': True, - 'allow_put': True, - 'default': 'aes-128', - 'validate': { - 'type:values': vpn_supported_encryption_algorithms - }, - 'is_visible': True}, - 'encapsulation_mode': { - 'allow_post': True, - 'allow_put': True, - 'default': 'tunnel', - 'validate': { - 'type:values': vpn_supported_encapsulation_mode - }, - 'is_visible': True}, - 'lifetime': {'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_none_to_empty_dict, - 'default': {}, - 'validate': { - 'type:dict_or_empty': { - 'units': { - 'type:values': vpn_supported_lifetime_units, - }, - 'value': { - 'type:range': vpn_lifetime_limits - }}}, - 'is_visible': True}, - 'pfs': {'allow_post': True, 'allow_put': True, - 'default': 'group5', - 'validate': {'type:values': vpn_supported_pfs}, - 'is_visible': True} - }, - - 'ikepolicies': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:uuid': None}, - 'is_visible': True, - 'primary_key': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'validate': {'type:string': None}, - 'required_by_policy': True, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'description': {'allow_post': True, 'allow_put': True, - 'validate': {'type:string': None}, - 'is_visible': True, 'default': ''}, - 'auth_algorithm': {'allow_post': True, 'allow_put': True, - 'default': 'sha1', - 'validate': { - 'type:values': vpn_supported_auth_algorithms}, - 'is_visible': True}, - 'encryption_algorithm': { - 'allow_post': True, 'allow_put': True, - 'default': 'aes-128', - 'validate': {'type:values': vpn_supported_encryption_algorithms}, - 'is_visible': True}, - 'phase1_negotiation_mode': { - 'allow_post': True, 'allow_put': True, - 'default': 'main', - 'validate': { - 'type:values': vpn_supported_phase1_negotiation_mode - }, - 'is_visible': True}, - 'lifetime': {'allow_post': True, 'allow_put': True, - 'convert_to': attr.convert_none_to_empty_dict, - 'default': {}, - 'validate': { - 'type:dict_or_empty': { - 'units': { - 'type:values': vpn_supported_lifetime_units, - }, - 'value': { - 'type:range': vpn_lifetime_limits, - }}}, - 'is_visible': True}, - 'ike_version': {'allow_post': True, 'allow_put': True, - 'default': 'v1', - 'validate': { - 'type:values': vpn_supported_ike_versions}, - 'is_visible': True}, - 'pfs': {'allow_post': True, 'allow_put': True, - 'default': 'group5', - 'validate': {'type:values': vpn_supported_pfs}, - 'is_visible': True} - } -} - - -class Vpnaas(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "VPN service" - - @classmethod - def get_alias(cls): - return "vpnaas" - - @classmethod - def get_description(cls): - return "Extension for VPN service" - - @classmethod - def get_namespace(cls): - return "https://wiki.openstack.org/Neutron/VPNaaS" - - @classmethod - def get_updated(cls): - return "2013-05-29T10:00:00-00:00" - - @classmethod - def get_resources(cls): - special_mappings = {'ikepolicies': 'ikepolicy', - 'ipsecpolicies': 'ipsecpolicy'} - plural_mappings = resource_helper.build_plural_mappings( - special_mappings, RESOURCE_ATTRIBUTE_MAP) - plural_mappings['peer_cidrs'] = 'peer_cidr' - attr.PLURALS.update(plural_mappings) - return resource_helper.build_resource_info(plural_mappings, - RESOURCE_ATTRIBUTE_MAP, - constants.VPN, - register_quota=True, - translate_name=True) - - @classmethod - def get_plugin_interface(cls): - return VPNPluginBase - - def update_attributes_map(self, attributes): - super(Vpnaas, self).update_attributes_map( - attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP) - - def get_extended_resources(self, version): - if version == "2.0": - return RESOURCE_ATTRIBUTE_MAP - else: - return {} - - -@six.add_metaclass(abc.ABCMeta) -class VPNPluginBase(service_base.ServicePluginBase): - - def get_plugin_name(self): - return constants.VPN - - def get_plugin_type(self): - return constants.VPN - - def get_plugin_description(self): - return 'VPN service plugin' - - @abc.abstractmethod - def get_vpnservices(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_vpnservice(self, context, vpnservice_id, fields=None): - pass - - @abc.abstractmethod - def create_vpnservice(self, context, vpnservice): - pass - - @abc.abstractmethod - def update_vpnservice(self, context, vpnservice_id, vpnservice): - pass - - @abc.abstractmethod - def delete_vpnservice(self, context, vpnservice_id): - pass - - @abc.abstractmethod - def get_ipsec_site_connections(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_ipsec_site_connection(self, context, - ipsecsite_conn_id, fields=None): - pass - - @abc.abstractmethod - def create_ipsec_site_connection(self, context, ipsec_site_connection): - pass - - @abc.abstractmethod - def update_ipsec_site_connection(self, context, - ipsecsite_conn_id, ipsec_site_connection): - pass - - @abc.abstractmethod - def delete_ipsec_site_connection(self, context, ipsecsite_conn_id): - pass - - @abc.abstractmethod - def get_ikepolicy(self, context, ikepolicy_id, fields=None): - pass - - @abc.abstractmethod - def get_ikepolicies(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def create_ikepolicy(self, context, ikepolicy): - pass - - @abc.abstractmethod - def update_ikepolicy(self, context, ikepolicy_id, ikepolicy): - pass - - @abc.abstractmethod - def delete_ikepolicy(self, context, ikepolicy_id): - pass - - @abc.abstractmethod - def get_ipsecpolicies(self, context, filters=None, fields=None): - pass - - @abc.abstractmethod - def get_ipsecpolicy(self, context, ipsecpolicy_id, fields=None): - pass - - @abc.abstractmethod - def create_ipsecpolicy(self, context, ipsecpolicy): - pass - - @abc.abstractmethod - def update_ipsecpolicy(self, context, ipsecpolicy_id, ipsecpolicy): - pass - - @abc.abstractmethod - def delete_ipsecpolicy(self, context, ipsecpolicy_id): - pass diff --git a/neutron/services/provider_configuration.py b/neutron/services/provider_configuration.py index 6bc0ed730..0d43d0018 100644 --- a/neutron/services/provider_configuration.py +++ b/neutron/services/provider_configuration.py @@ -79,23 +79,7 @@ def parse_service_provider_opt(): # Add in entries from the *aas conf files neutron_mods = repos.NeutronModules() for x in neutron_mods.installed_list(): - ini = neutron_mods.ini(x) - if ini is None: - continue - - try: - sp = ini.items('service_providers') - for name, value in sp: - if name == 'service_provider': - svc_providers_opt.append(value) - except Exception: - continue - - # TODO(dougwig) - remove this next bit after we've migrated all entries - # to the service repo config files. Some tests require a default driver - # to be present, but not two, which leads to a cross-repo breakage - # issue. uniq the list as a short-term workaround. - svc_providers_opt = list(set(svc_providers_opt)) + svc_providers_opt += neutron_mods.service_providers(x) LOG.debug("Service providers = %s", svc_providers_opt) diff --git a/neutron/tests/unit/test_extension_firewall.py b/neutron/tests/unit/test_extension_firewall.py deleted file mode 100644 index 6771c6339..000000000 --- a/neutron/tests/unit/test_extension_firewall.py +++ /dev/null @@ -1,486 +0,0 @@ -# Copyright 2013 Big Switch Networks, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock -from webob import exc -import webtest - -from neutron.extensions import firewall -from neutron.openstack.common import uuidutils -from neutron.plugins.common import constants -from neutron.tests import base -from neutron.tests.unit import test_api_v2 -from neutron.tests.unit import test_api_v2_extension - - -_uuid = uuidutils.generate_uuid -_get_path = test_api_v2._get_path - - -class FirewallExtensionTestCase(test_api_v2_extension.ExtensionTestCase): - fmt = 'json' - - def setUp(self): - super(FirewallExtensionTestCase, self).setUp() - plural_mappings = {'firewall_policy': 'firewall_policies'} - self._setUpExtension( - 'neutron.extensions.firewall.FirewallPluginBase', - constants.FIREWALL, firewall.RESOURCE_ATTRIBUTE_MAP, - firewall.Firewall, 'fw', plural_mappings=plural_mappings) - - def test_create_firewall(self): - fw_id = _uuid() - data = {'firewall': {'description': 'descr_firewall1', - 'name': 'firewall1', - 'admin_state_up': True, - 'firewall_policy_id': _uuid(), - 'shared': False, - 'tenant_id': _uuid()}} - return_value = copy.copy(data['firewall']) - return_value.update({'id': fw_id}) - # since 'shared' is hidden - del return_value['shared'] - - instance = self.plugin.return_value - instance.create_firewall.return_value = return_value - res = self.api.post(_get_path('fw/firewalls', fmt=self.fmt), - self.serialize(data), - content_type='application/%s' % self.fmt) - instance.create_firewall.assert_called_with(mock.ANY, - firewall=data) - self.assertEqual(res.status_int, exc.HTTPCreated.code) - res = self.deserialize(res) - self.assertIn('firewall', res) - self.assertEqual(res['firewall'], return_value) - - def test_firewall_list(self): - fw_id = _uuid() - return_value = [{'tenant_id': _uuid(), - 'id': fw_id}] - - instance = self.plugin.return_value - instance.get_firewalls.return_value = return_value - - res = self.api.get(_get_path('fw/firewalls', fmt=self.fmt)) - - instance.get_firewalls.assert_called_with(mock.ANY, - fields=mock.ANY, - filters=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - - def test_firewall_get(self): - fw_id = _uuid() - return_value = {'tenant_id': _uuid(), - 'id': fw_id} - - instance = self.plugin.return_value - instance.get_firewall.return_value = return_value - - res = self.api.get(_get_path('fw/firewalls', - id=fw_id, fmt=self.fmt)) - - instance.get_firewall.assert_called_with(mock.ANY, - fw_id, - fields=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall', res) - self.assertEqual(res['firewall'], return_value) - - def test_firewall_update(self): - fw_id = _uuid() - update_data = {'firewall': {'name': 'new_name'}} - return_value = {'tenant_id': _uuid(), - 'id': fw_id} - - instance = self.plugin.return_value - instance.update_firewall.return_value = return_value - - res = self.api.put(_get_path('fw/firewalls', id=fw_id, - fmt=self.fmt), - self.serialize(update_data)) - - instance.update_firewall.assert_called_with(mock.ANY, fw_id, - firewall=update_data) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall', res) - self.assertEqual(res['firewall'], return_value) - - def test_firewall_delete(self): - self._test_entity_delete('firewall') - - def _test_create_firewall_rule(self, src_port, dst_port): - rule_id = _uuid() - data = {'firewall_rule': {'description': 'descr_firewall_rule1', - 'name': 'rule1', - 'shared': False, - 'protocol': 'tcp', - 'ip_version': 4, - 'source_ip_address': '192.168.0.1', - 'destination_ip_address': '127.0.0.1', - 'source_port': src_port, - 'destination_port': dst_port, - 'action': 'allow', - 'enabled': True, - 'tenant_id': _uuid()}} - expected_ret_val = copy.copy(data['firewall_rule']) - expected_ret_val['source_port'] = str(src_port) - expected_ret_val['destination_port'] = str(dst_port) - expected_call_args = copy.copy(expected_ret_val) - expected_ret_val['id'] = rule_id - instance = self.plugin.return_value - instance.create_firewall_rule.return_value = expected_ret_val - res = self.api.post(_get_path('fw/firewall_rules', fmt=self.fmt), - self.serialize(data), - content_type='application/%s' % self.fmt) - instance.create_firewall_rule.assert_called_with( - mock.ANY, - firewall_rule={'firewall_rule': expected_call_args}) - self.assertEqual(res.status_int, exc.HTTPCreated.code) - res = self.deserialize(res) - self.assertIn('firewall_rule', res) - self.assertEqual(res['firewall_rule'], expected_ret_val) - - def test_create_firewall_rule_with_integer_ports(self): - self._test_create_firewall_rule(1, 10) - - def test_create_firewall_rule_with_string_ports(self): - self._test_create_firewall_rule('1', '10') - - def test_create_firewall_rule_with_port_range(self): - self._test_create_firewall_rule('1:20', '30:40') - - def test_firewall_rule_list(self): - rule_id = _uuid() - return_value = [{'tenant_id': _uuid(), - 'id': rule_id}] - - instance = self.plugin.return_value - instance.get_firewall_rules.return_value = return_value - - res = self.api.get(_get_path('fw/firewall_rules', fmt=self.fmt)) - - instance.get_firewall_rules.assert_called_with(mock.ANY, - fields=mock.ANY, - filters=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - - def test_firewall_rule_get(self): - rule_id = _uuid() - return_value = {'tenant_id': _uuid(), - 'id': rule_id} - - instance = self.plugin.return_value - instance.get_firewall_rule.return_value = return_value - - res = self.api.get(_get_path('fw/firewall_rules', - id=rule_id, fmt=self.fmt)) - - instance.get_firewall_rule.assert_called_with(mock.ANY, - rule_id, - fields=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall_rule', res) - self.assertEqual(res['firewall_rule'], return_value) - - def test_firewall_rule_update(self): - rule_id = _uuid() - update_data = {'firewall_rule': {'action': 'deny'}} - return_value = {'tenant_id': _uuid(), - 'id': rule_id} - - instance = self.plugin.return_value - instance.update_firewall_rule.return_value = return_value - - res = self.api.put(_get_path('fw/firewall_rules', id=rule_id, - fmt=self.fmt), - self.serialize(update_data)) - - instance.update_firewall_rule.assert_called_with( - mock.ANY, - rule_id, - firewall_rule=update_data) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall_rule', res) - self.assertEqual(res['firewall_rule'], return_value) - - def test_firewall_rule_delete(self): - self._test_entity_delete('firewall_rule') - - def test_create_firewall_policy(self): - policy_id = _uuid() - data = {'firewall_policy': {'description': 'descr_firewall_policy1', - 'name': 'new_fw_policy1', - 'shared': False, - 'firewall_rules': [_uuid(), _uuid()], - 'audited': False, - 'tenant_id': _uuid()}} - return_value = copy.copy(data['firewall_policy']) - return_value.update({'id': policy_id}) - - instance = self.plugin.return_value - instance.create_firewall_policy.return_value = return_value - res = self.api.post(_get_path('fw/firewall_policies', - fmt=self.fmt), - self.serialize(data), - content_type='application/%s' % self.fmt) - instance.create_firewall_policy.assert_called_with( - mock.ANY, - firewall_policy=data) - self.assertEqual(res.status_int, exc.HTTPCreated.code) - res = self.deserialize(res) - self.assertIn('firewall_policy', res) - self.assertEqual(res['firewall_policy'], return_value) - - def test_firewall_policy_list(self): - policy_id = _uuid() - return_value = [{'tenant_id': _uuid(), - 'id': policy_id}] - - instance = self.plugin.return_value - instance.get_firewall_policies.return_value = return_value - - res = self.api.get(_get_path('fw/firewall_policies', - fmt=self.fmt)) - - instance.get_firewall_policies.assert_called_with(mock.ANY, - fields=mock.ANY, - filters=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - - def test_firewall_policy_get(self): - policy_id = _uuid() - return_value = {'tenant_id': _uuid(), - 'id': policy_id} - - instance = self.plugin.return_value - instance.get_firewall_policy.return_value = return_value - - res = self.api.get(_get_path('fw/firewall_policies', - id=policy_id, fmt=self.fmt)) - - instance.get_firewall_policy.assert_called_with(mock.ANY, - policy_id, - fields=mock.ANY) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall_policy', res) - self.assertEqual(res['firewall_policy'], return_value) - - def test_firewall_policy_update(self): - policy_id = _uuid() - update_data = {'firewall_policy': {'audited': True}} - return_value = {'tenant_id': _uuid(), - 'id': policy_id} - - instance = self.plugin.return_value - instance.update_firewall_policy.return_value = return_value - - res = self.api.put(_get_path('fw/firewall_policies', - id=policy_id, - fmt=self.fmt), - self.serialize(update_data)) - - instance.update_firewall_policy.assert_called_with( - mock.ANY, - policy_id, - firewall_policy=update_data) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertIn('firewall_policy', res) - self.assertEqual(res['firewall_policy'], return_value) - - def test_firewall_policy_update_malformed_rules(self): - # emulating client request when no rule uuids are provided for - # --firewall_rules parameter - update_data = {'firewall_policy': {'firewall_rules': True}} - # have to check for generic AppError - self.assertRaises( - webtest.AppError, - self.api.put, - _get_path('fw/firewall_policies', id=_uuid(), fmt=self.fmt), - self.serialize(update_data)) - - def test_firewall_policy_delete(self): - self._test_entity_delete('firewall_policy') - - def test_firewall_policy_insert_rule(self): - firewall_policy_id = _uuid() - firewall_rule_id = _uuid() - ref_firewall_rule_id = _uuid() - - insert_data = {'firewall_rule_id': firewall_rule_id, - 'insert_before': ref_firewall_rule_id, - 'insert_after': None} - return_value = {'firewall_policy': - {'tenant_id': _uuid(), - 'id': firewall_policy_id, - 'firewall_rules': [ref_firewall_rule_id, - firewall_rule_id]}} - - instance = self.plugin.return_value - instance.insert_rule.return_value = return_value - - path = _get_path('fw/firewall_policies', id=firewall_policy_id, - action="insert_rule", - fmt=self.fmt) - res = self.api.put(path, self.serialize(insert_data)) - instance.insert_rule.assert_called_with(mock.ANY, firewall_policy_id, - insert_data) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertEqual(res, return_value) - - def test_firewall_policy_remove_rule(self): - firewall_policy_id = _uuid() - firewall_rule_id = _uuid() - - remove_data = {'firewall_rule_id': firewall_rule_id} - return_value = {'firewall_policy': - {'tenant_id': _uuid(), - 'id': firewall_policy_id, - 'firewall_rules': []}} - - instance = self.plugin.return_value - instance.remove_rule.return_value = return_value - - path = _get_path('fw/firewall_policies', id=firewall_policy_id, - action="remove_rule", - fmt=self.fmt) - res = self.api.put(path, self.serialize(remove_data)) - instance.remove_rule.assert_called_with(mock.ANY, firewall_policy_id, - remove_data) - self.assertEqual(res.status_int, exc.HTTPOk.code) - res = self.deserialize(res) - self.assertEqual(res, return_value) - - -class TestFirewallAttributeValidators(base.BaseTestCase): - - def test_validate_port_range(self): - msg = firewall._validate_port_range(None) - self.assertIsNone(msg) - - msg = firewall._validate_port_range('10') - self.assertIsNone(msg) - - msg = firewall._validate_port_range(10) - self.assertIsNone(msg) - - msg = firewall._validate_port_range(-1) - self.assertEqual(msg, "Invalid port '-1'") - - msg = firewall._validate_port_range('66000') - self.assertEqual(msg, "Invalid port '66000'") - - msg = firewall._validate_port_range('10:20') - self.assertIsNone(msg) - - msg = firewall._validate_port_range('1:65535') - self.assertIsNone(msg) - - msg = firewall._validate_port_range('0:65535') - self.assertEqual(msg, "Invalid port '0'") - - msg = firewall._validate_port_range('1:65536') - self.assertEqual(msg, "Invalid port '65536'") - - msg = firewall._validate_port_range('abc:efg') - self.assertEqual(msg, "Port 'abc' is not a valid number") - - msg = firewall._validate_port_range('1:efg') - self.assertEqual(msg, "Port 'efg' is not a valid number") - - msg = firewall._validate_port_range('-1:10') - self.assertEqual(msg, "Invalid port '-1'") - - msg = firewall._validate_port_range('66000:10') - self.assertEqual(msg, "Invalid port '66000'") - - msg = firewall._validate_port_range('10:66000') - self.assertEqual(msg, "Invalid port '66000'") - - msg = firewall._validate_port_range('1:-10') - self.assertEqual(msg, "Invalid port '-10'") - - def test_validate_ip_or_subnet_or_none(self): - msg = firewall._validate_ip_or_subnet_or_none(None) - self.assertIsNone(msg) - - msg = firewall._validate_ip_or_subnet_or_none('1.1.1.1') - self.assertIsNone(msg) - - msg = firewall._validate_ip_or_subnet_or_none('1.1.1.0/24') - self.assertIsNone(msg) - - ip_addr = '1111.1.1.1' - msg = firewall._validate_ip_or_subnet_or_none(ip_addr) - self.assertEqual(msg, ("'%s' is not a valid IP address and " - "'%s' is not a valid IP subnet") % (ip_addr, - ip_addr)) - - ip_addr = '1.1.1.1 has whitespace' - msg = firewall._validate_ip_or_subnet_or_none(ip_addr) - self.assertEqual(msg, ("'%s' is not a valid IP address and " - "'%s' is not a valid IP subnet") % (ip_addr, - ip_addr)) - - ip_addr = '111.1.1.1\twhitespace' - msg = firewall._validate_ip_or_subnet_or_none(ip_addr) - self.assertEqual(msg, ("'%s' is not a valid IP address and " - "'%s' is not a valid IP subnet") % (ip_addr, - ip_addr)) - - ip_addr = '111.1.1.1\nwhitespace' - msg = firewall._validate_ip_or_subnet_or_none(ip_addr) - self.assertEqual(msg, ("'%s' is not a valid IP address and " - "'%s' is not a valid IP subnet") % (ip_addr, - ip_addr)) - - # Valid - IPv4 - cidr = "10.0.2.0/24" - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertIsNone(msg) - - # Valid - IPv6 without final octets - cidr = "fe80::/24" - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertIsNone(msg) - - # Valid - IPv6 with final octets - cidr = "fe80::0/24" - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertIsNone(msg) - - cidr = "fe80::" - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertIsNone(msg) - - # Invalid - IPv6 with final octets, missing mask - cidr = "fe80::0" - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertIsNone(msg) - - # Invalid - Address format error - cidr = 'invalid' - msg = firewall._validate_ip_or_subnet_or_none(cidr, None) - self.assertEqual(msg, ("'%s' is not a valid IP address and " - "'%s' is not a valid IP subnet") % (cidr, - cidr)) -- 2.45.2