Nuke remaining service config and extensions from main repo
Change-Id: Ic8ab865a387808c925cc311d9b70ac53f5c2c5b8 Partially-implements: blueprint services-split
This commit is contained in:
parent
014b4be568
commit
3cd60de8f5
@ -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=<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
|
||||
|
@ -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
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
ini_path = '/etc/neutron/%s.conf' % module
|
||||
if neutron_dir is None:
|
||||
neutron_dir = '/etc/neutron'
|
||||
|
||||
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
|
||||
|
@ -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 = [
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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)
|
||||
|
||||
|
@ -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))
|
Loading…
Reference in New Issue
Block a user