New extension for version 2 of LBaaS API
Also added some constants for supported protocols, algorithms, health monitor types, and session persistence types. Partially-implements: blueprint lbaas-api-and-objmodel-improvement Change-Id: I43270fdf9cd52a57274575ecea502f660ff0d5a9 Co-authored-by: Brandon Logan <brandon.logan@rackspace.com> Co-authored-by: Vijayendra Bhamidipati <vbhamidipati@paypal.com>
This commit is contained in:
parent
ad595d25fc
commit
4ed88624b1
|
@ -522,6 +522,16 @@ lock_path = $state_path/lock
|
|||
# and that is the reason why quota is possible.
|
||||
# quota_health_monitor = -1
|
||||
|
||||
# Number of loadbalancers allowed per tenant. A negative value means unlimited.
|
||||
# quota_loadbalancer = 10
|
||||
|
||||
# Number of listeners allowed per tenant. A negative value means unlimited.
|
||||
# quota_listener = -1
|
||||
|
||||
# Number of v2 health monitors allowed per tenant. A negative value means
|
||||
# unlimited. These health monitors exist under the lbaas v2 API
|
||||
# quota_healthmonitor = -1
|
||||
|
||||
# Number of routers allowed per tenant. A negative value means unlimited.
|
||||
# quota_router = 10
|
||||
|
||||
|
|
|
@ -0,0 +1,536 @@
|
|||
# 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 qexception
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.services.loadbalancer import constants as lb_const
|
||||
from neutron.services import service_base
|
||||
|
||||
|
||||
# Loadbalancer Exceptions
|
||||
# This exception is only for a workaround when having v1 and v2 lbaas extension
|
||||
# and plugins enabled
|
||||
class RequiredAttributeNotSpecified(qexception.BadRequest):
|
||||
message = _("Required attribute %(attr_name)s not specified")
|
||||
|
||||
|
||||
class EntityNotFound(qexception.NotFound):
|
||||
message = _("%(name)s %(id)s could not be found")
|
||||
|
||||
|
||||
class DelayOrTimeoutInvalid(qexception.BadRequest):
|
||||
message = _("Delay must be greater than or equal to timeout")
|
||||
|
||||
|
||||
class EntityInUse(qexception.InUse):
|
||||
message = _("%(entity_using)s %(id)s is using this %(entity_in_use)s")
|
||||
|
||||
|
||||
class LoadBalancerListenerProtocolPortExists(qexception.Conflict):
|
||||
message = _("Load Balancer %(lb_id)s already has a listener with "
|
||||
"protocol_port of %(protocol_port)s")
|
||||
|
||||
|
||||
class ListenerPoolProtocolMismatch(qexception.Conflict):
|
||||
message = _("Listener protocol %(listener_proto)s and pool protocol "
|
||||
"%(pool_proto)s are not compatible.")
|
||||
|
||||
|
||||
class AttributeIDImmutable(qexception.NeutronException):
|
||||
message = _("Cannot change %(attribute)s if one already exists")
|
||||
|
||||
|
||||
class StateInvalid(qexception.NeutronException):
|
||||
message = _("Invalid state %(state)s of loadbalancer resource %(id)s")
|
||||
|
||||
|
||||
class MemberNotFoundForPool(qexception.NotFound):
|
||||
message = _("Member %(member_id)s could not be found in pool %(pool_id)s")
|
||||
|
||||
|
||||
class MemberExists(qexception.Conflict):
|
||||
message = _("Member with address %(address)s and protocol_port %(port)s "
|
||||
"already present in pool %(pool)s")
|
||||
|
||||
|
||||
class MemberAddressTypeSubnetTypeMismatch(qexception.NeutronException):
|
||||
message = _("Member with address %(address)s and subnet %(subnet_id) "
|
||||
" have mismatched IP versions")
|
||||
|
||||
|
||||
class DriverError(qexception.NeutronException):
|
||||
message = _("An error happened in the driver: %(message)s")
|
||||
|
||||
|
||||
class LBConfigurationUnsupported(qexception.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': lb_const.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': lb_const.SUPPORTED_PROTOCOLS},
|
||||
'is_visible': True},
|
||||
'lb_algorithm': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {
|
||||
'type:values': lb_const.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': lb_const.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': lb_const.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': '^(\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
|
|
@ -17,6 +17,7 @@
|
|||
CORE = "CORE"
|
||||
DUMMY = "DUMMY"
|
||||
LOADBALANCER = "LOADBALANCER"
|
||||
LOADBALANCERV2 = "LOADBALANCERV2"
|
||||
FIREWALL = "FIREWALL"
|
||||
VPN = "VPN"
|
||||
METERING = "METERING"
|
||||
|
@ -27,6 +28,7 @@ L3_ROUTER_NAT = "L3_ROUTER_NAT"
|
|||
EXT_TO_SERVICE_MAPPING = {
|
||||
'dummy': DUMMY,
|
||||
'lbaas': LOADBALANCER,
|
||||
'lbaasv2': LOADBALANCERV2,
|
||||
'fwaas': FIREWALL,
|
||||
'vpnaas': VPN,
|
||||
'metering': METERING,
|
||||
|
@ -35,12 +37,13 @@ EXT_TO_SERVICE_MAPPING = {
|
|||
|
||||
# TODO(salvatore-orlando): Move these (or derive them) from conf file
|
||||
ALLOWED_SERVICES = [CORE, DUMMY, LOADBALANCER, FIREWALL, VPN, METERING,
|
||||
L3_ROUTER_NAT]
|
||||
L3_ROUTER_NAT, LOADBALANCERV2]
|
||||
|
||||
COMMON_PREFIXES = {
|
||||
CORE: "",
|
||||
DUMMY: "/dummy_svc",
|
||||
LOADBALANCER: "/lb",
|
||||
LOADBALANCERV2: "/lbaas",
|
||||
FIREWALL: "/fw",
|
||||
VPN: "/vpn",
|
||||
METERING: "/metering",
|
||||
|
|
|
@ -13,22 +13,31 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
#FIXME(brandon-logan): change these to LB_ALGORITHM
|
||||
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)
|
||||
|
||||
STATS_ACTIVE_CONNECTIONS = 'active_connections'
|
||||
STATS_MAX_CONNECTIONS = 'max_connections'
|
||||
|
|
|
@ -30,7 +30,8 @@ class LBaaSQuotaExtensionTestCase(
|
|||
super(LBaaSQuotaExtensionTestCase, self).setUp()
|
||||
cfg.CONF.set_override(
|
||||
'quota_items',
|
||||
['vip', 'pool', 'member', 'health_monitor', 'extra1'],
|
||||
['vip', 'pool', 'member', 'health_monitor', 'extra1',
|
||||
'loadbalancer', 'listener', 'healthmonitor'],
|
||||
group='QUOTAS')
|
||||
quota.register_resources_from_config()
|
||||
|
||||
|
@ -62,6 +63,9 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.assertEqual(-1, quota['quota']['member'])
|
||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||
self.assertEqual(-1, quota['quota']['extra1'])
|
||||
self.assertEqual(10, quota['quota']['loadbalancer'])
|
||||
self.assertEqual(-1, quota['quota']['listener'])
|
||||
self.assertEqual(-1, quota['quota']['healthmonitor'])
|
||||
|
||||
def test_show_quotas_with_admin(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -75,6 +79,9 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.assertEqual(10, quota['quota']['pool'])
|
||||
self.assertEqual(-1, quota['quota']['member'])
|
||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||
self.assertEqual(10, quota['quota']['loadbalancer'])
|
||||
self.assertEqual(-1, quota['quota']['listener'])
|
||||
self.assertEqual(-1, quota['quota']['healthmonitor'])
|
||||
|
||||
def test_show_quotas_with_owner_tenant(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -88,6 +95,9 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.assertEqual(10, quota['quota']['pool'])
|
||||
self.assertEqual(-1, quota['quota']['member'])
|
||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||
self.assertEqual(10, quota['quota']['loadbalancer'])
|
||||
self.assertEqual(-1, quota['quota']['listener'])
|
||||
self.assertEqual(-1, quota['quota']['healthmonitor'])
|
||||
|
||||
def test_update_quotas_to_unlimited(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -98,6 +108,11 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.serialize(quotas), extra_environ=env,
|
||||
expect_errors=False)
|
||||
self.assertEqual(200, res.status_int)
|
||||
quotas = {'quota': {'loadbalancer': -1}}
|
||||
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
self.serialize(quotas), extra_environ=env,
|
||||
expect_errors=False)
|
||||
self.assertEqual(200, res.status_int)
|
||||
|
||||
def test_update_quotas_exceeding_current_limit(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -108,6 +123,11 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.serialize(quotas), extra_environ=env,
|
||||
expect_errors=False)
|
||||
self.assertEqual(200, res.status_int)
|
||||
quotas = {'quota': {'loadbalancer': 120}}
|
||||
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
self.serialize(quotas), extra_environ=env,
|
||||
expect_errors=False)
|
||||
self.assertEqual(200, res.status_int)
|
||||
|
||||
def test_update_quotas_with_admin(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -117,6 +137,10 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
self.serialize(quotas), extra_environ=env)
|
||||
self.assertEqual(200, res.status_int)
|
||||
quotas = {'quota': {'loadbalancer': 100}}
|
||||
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
self.serialize(quotas), extra_environ=env)
|
||||
self.assertEqual(200, res.status_int)
|
||||
env2 = {'neutron.context': context.Context('', tenant_id)}
|
||||
res = self.api.get(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
extra_environ=env2)
|
||||
|
@ -125,6 +149,9 @@ class LBaaSQuotaExtensionDbTestCase(LBaaSQuotaExtensionTestCase):
|
|||
self.assertEqual(100, quota['quota']['pool'])
|
||||
self.assertEqual(-1, quota['quota']['member'])
|
||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||
self.assertEqual(100, quota['quota']['loadbalancer'])
|
||||
self.assertEqual(-1, quota['quota']['listener'])
|
||||
self.assertEqual(-1, quota['quota']['healthmonitor'])
|
||||
|
||||
|
||||
class LBaaSQuotaExtensionDbTestCaseXML(LBaaSQuotaExtensionDbTestCase):
|
||||
|
@ -152,6 +179,9 @@ class LBaaSQuotaExtensionCfgTestCase(
|
|||
self.assertEqual(-1, quota['quota']['member'])
|
||||
self.assertEqual(-1, quota['quota']['health_monitor'])
|
||||
self.assertEqual(-1, quota['quota']['extra1'])
|
||||
self.assertEqual(10, quota['quota']['loadbalancer'])
|
||||
self.assertEqual(-1, quota['quota']['listener'])
|
||||
self.assertEqual(-1, quota['quota']['healthmonitor'])
|
||||
|
||||
def test_update_quotas_forbidden(self):
|
||||
tenant_id = 'tenant_id1'
|
||||
|
@ -160,6 +190,11 @@ class LBaaSQuotaExtensionCfgTestCase(
|
|||
self.serialize(quotas),
|
||||
expect_errors=True)
|
||||
self.assertEqual(403, res.status_int)
|
||||
quotas = {'quota': {'loadbalancer': 100}}
|
||||
res = self.api.put(_get_path('quotas', id=tenant_id, fmt=self.fmt),
|
||||
self.serialize(quotas),
|
||||
expect_errors=True)
|
||||
self.assertEqual(403, res.status_int)
|
||||
|
||||
|
||||
class LBaaSQuotaExtensionCfgTestCaseXML(LBaaSQuotaExtensionCfgTestCase):
|
||||
|
|
Loading…
Reference in New Issue