# 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=<service_type>:<name>:<driver>[:default]
-# List of allowed service types includes LOADBALANCER, FIREWALL, VPN
-# Combination of <service type> and <name> must be unique; <driver> 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
+++ /dev/null
-[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
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
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:
import importlib
import os
+from oslo.config import cfg
+
from neutron.openstack.common import log as logging
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
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
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 = [
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-# 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
+++ /dev/null
-# (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
# 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)
+++ /dev/null
-# 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))