The patch introduces an API extension for LBaaS service
- API extension - abstract base class for plugin - some new validators were added to quantum/api/v2/attributes.py Implements: blueprint lbaas-restapi-tenant Change-Id: Ic2fd4debc4969389b395ce7352ab208c6854018b
This commit is contained in:
parent
b8607bb0c8
commit
1703047903
@ -233,6 +233,50 @@ def _validate_uuid(data, valid_values=None):
|
|||||||
return msg
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_uuid_or_none(data, valid_values=None):
|
||||||
|
if data is not None:
|
||||||
|
return _validate_uuid(data)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_uuid_list(data, valid_values=None):
|
||||||
|
if not isinstance(data, list):
|
||||||
|
msg = _("'%s' is not a list") % data
|
||||||
|
LOG.debug("validate_uuid_list: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
for item in data:
|
||||||
|
msg = _validate_uuid(item)
|
||||||
|
if msg:
|
||||||
|
LOG.debug("validate_uuid_list: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
if len(set(data)) != len(data):
|
||||||
|
msg = _("Duplicate items in the list: %s") % ', '.join(data)
|
||||||
|
LOG.debug("validate_uuid_list: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_dict(data, valid_values=None):
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
msg = _("'%s' is not a dictionary") % data
|
||||||
|
LOG.debug("validate_dict: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_non_negative(data, valid_values=None):
|
||||||
|
try:
|
||||||
|
data = int(data)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
msg = _("'%s' is not an integer") % data
|
||||||
|
LOG.debug("validate_non_negative: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
if data < 0:
|
||||||
|
msg = _("'%s' should be non-negative") % data
|
||||||
|
LOG.debug("validate_non_negative: %s", msg)
|
||||||
|
return msg
|
||||||
|
|
||||||
|
|
||||||
def convert_to_boolean(data):
|
def convert_to_boolean(data):
|
||||||
if isinstance(data, basestring):
|
if isinstance(data, basestring):
|
||||||
val = data.lower()
|
val = data.lower()
|
||||||
@ -294,6 +338,15 @@ def convert_none_to_empty_list(value):
|
|||||||
return [] if value is None else value
|
return [] if value is None else value
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_list(data):
|
||||||
|
if data is None:
|
||||||
|
return []
|
||||||
|
elif hasattr(data, '__iter__'):
|
||||||
|
return list(data)
|
||||||
|
else:
|
||||||
|
return [data]
|
||||||
|
|
||||||
|
|
||||||
HOSTNAME_PATTERN = ("(?=^.{1,254}$)(^(?:(?!\d+\.|-)[a-zA-Z0-9_\-]"
|
HOSTNAME_PATTERN = ("(?=^.{1,254}$)(^(?:(?!\d+\.|-)[a-zA-Z0-9_\-]"
|
||||||
"{1,63}(?<!-)\.?)+(?:[a-zA-Z]{2,})$)")
|
"{1,63}(?<!-)\.?)+(?:[a-zA-Z]{2,})$)")
|
||||||
|
|
||||||
@ -306,18 +359,22 @@ UUID_PATTERN = '-'.join([HEX_ELEM + '{8}', HEX_ELEM + '{4}',
|
|||||||
MAC_PATTERN = "^%s[aceACE02468](:%s{2}){5}$" % (HEX_ELEM, HEX_ELEM)
|
MAC_PATTERN = "^%s[aceACE02468](:%s{2}){5}$" % (HEX_ELEM, HEX_ELEM)
|
||||||
|
|
||||||
# Dictionary that maintains a list of validation functions
|
# Dictionary that maintains a list of validation functions
|
||||||
validators = {'type:fixed_ips': _validate_fixed_ips,
|
validators = {'type:dict': _validate_dict,
|
||||||
|
'type:fixed_ips': _validate_fixed_ips,
|
||||||
'type:hostroutes': _validate_hostroutes,
|
'type:hostroutes': _validate_hostroutes,
|
||||||
'type:ip_address': _validate_ip_address,
|
'type:ip_address': _validate_ip_address,
|
||||||
'type:ip_address_or_none': _validate_ip_address_or_none,
|
'type:ip_address_or_none': _validate_ip_address_or_none,
|
||||||
'type:ip_pools': _validate_ip_pools,
|
'type:ip_pools': _validate_ip_pools,
|
||||||
'type:mac_address': _validate_mac_address,
|
'type:mac_address': _validate_mac_address,
|
||||||
'type:nameservers': _validate_nameservers,
|
'type:nameservers': _validate_nameservers,
|
||||||
|
'type:non_negative': _validate_non_negative,
|
||||||
'type:range': _validate_range,
|
'type:range': _validate_range,
|
||||||
'type:regex': _validate_regex,
|
'type:regex': _validate_regex,
|
||||||
'type:string': _validate_string,
|
'type:string': _validate_string,
|
||||||
'type:subnet': _validate_subnet,
|
'type:subnet': _validate_subnet,
|
||||||
'type:uuid': _validate_uuid,
|
'type:uuid': _validate_uuid,
|
||||||
|
'type:uuid_or_none': _validate_uuid_or_none,
|
||||||
|
'type:uuid_list': _validate_uuid_list,
|
||||||
'type:values': _validate_values}
|
'type:values': _validate_values}
|
||||||
|
|
||||||
# Note: a default of ATTR_NOT_SPECIFIED indicates that an
|
# Note: a default of ATTR_NOT_SPECIFIED indicates that an
|
||||||
|
@ -165,8 +165,14 @@ class Controller(object):
|
|||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
if name in self._member_actions:
|
if name in self._member_actions:
|
||||||
def _handle_action(request, id, body=None):
|
def _handle_action(request, id, **kwargs):
|
||||||
return getattr(self._plugin, name)(request.context, id, body)
|
if 'body' in kwargs:
|
||||||
|
body = kwargs.pop('body')
|
||||||
|
return getattr(self._plugin, name)(request.context, id,
|
||||||
|
body, **kwargs)
|
||||||
|
else:
|
||||||
|
return getattr(self._plugin, name)(request.context, id,
|
||||||
|
**kwargs)
|
||||||
return _handle_action
|
return _handle_action
|
||||||
else:
|
else:
|
||||||
raise AttributeError
|
raise AttributeError
|
||||||
|
@ -86,13 +86,6 @@ class RouterExternalGatewayInUseByFloatingIp(qexception.InUse):
|
|||||||
"more floating IPs.")
|
"more floating IPs.")
|
||||||
|
|
||||||
|
|
||||||
def _validate_uuid_or_none(data, valid_values=None):
|
|
||||||
if data is None:
|
|
||||||
return None
|
|
||||||
return attr._validate_uuid(data)
|
|
||||||
|
|
||||||
attr.validators['type:uuid_or_none'] = _validate_uuid_or_none
|
|
||||||
|
|
||||||
# Attribute Map
|
# Attribute Map
|
||||||
RESOURCE_ATTRIBUTE_MAP = {
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
'routers': {
|
'routers': {
|
||||||
|
383
quantum/extensions/loadbalancer.py
Normal file
383
quantum/extensions/loadbalancer.py
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# 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 quantum.api import extensions
|
||||||
|
from quantum.api.v2 import attributes as attr
|
||||||
|
from quantum.api.v2 import base
|
||||||
|
from quantum import manager
|
||||||
|
from quantum.plugins.common import constants
|
||||||
|
from quantum.plugins.services.service_base import ServicePluginBase
|
||||||
|
|
||||||
|
|
||||||
|
RESOURCE_ATTRIBUTE_MAP = {
|
||||||
|
'vips': {
|
||||||
|
'id': {'allow_post': False, '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},
|
||||||
|
'name': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'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': {'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:string': None},
|
||||||
|
'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,
|
||||||
|
'default': {},
|
||||||
|
'validate': {'type:dict': None},
|
||||||
|
'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}
|
||||||
|
},
|
||||||
|
'pools': {
|
||||||
|
'id': {'allow_post': False, '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},
|
||||||
|
'vip_id': {'allow_post': False, 'allow_put': False,
|
||||||
|
'is_visible': True},
|
||||||
|
'name': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'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:string': None},
|
||||||
|
'is_visible': True},
|
||||||
|
'lb_method': {'allow_post': True, 'allow_put': True,
|
||||||
|
'validate': {'type:string': None},
|
||||||
|
'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},
|
||||||
|
'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}
|
||||||
|
},
|
||||||
|
'members': {
|
||||||
|
'id': {'allow_post': False, '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},
|
||||||
|
'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},
|
||||||
|
'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}
|
||||||
|
},
|
||||||
|
'health_monitors': {
|
||||||
|
'id': {'allow_post': False, '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},
|
||||||
|
'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,
|
||||||
|
'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 = {
|
||||||
|
'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},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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/Quantum/LBaaS/API_1.0"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_updated(cls):
|
||||||
|
return "2012-10-07T10:00:00-00:00"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_resources(cls):
|
||||||
|
resources = []
|
||||||
|
plugin = manager.QuantumManager.get_service_plugins()[
|
||||||
|
constants.LOADBALANCER]
|
||||||
|
for collection_name in RESOURCE_ATTRIBUTE_MAP:
|
||||||
|
# Special handling needed for resources with 'y' ending
|
||||||
|
# (e.g. proxies -> proxy)
|
||||||
|
resource_name = collection_name[:-1]
|
||||||
|
params = RESOURCE_ATTRIBUTE_MAP[collection_name]
|
||||||
|
|
||||||
|
member_actions = {}
|
||||||
|
if resource_name == 'pool':
|
||||||
|
member_actions = {'stats': 'GET'}
|
||||||
|
|
||||||
|
controller = base.create_resource(collection_name,
|
||||||
|
resource_name,
|
||||||
|
plugin, params,
|
||||||
|
member_actions=member_actions)
|
||||||
|
|
||||||
|
resource = extensions.ResourceExtension(
|
||||||
|
collection_name,
|
||||||
|
controller,
|
||||||
|
path_prefix=constants.COMMON_PREFIXES[constants.LOADBALANCER],
|
||||||
|
member_actions=member_actions)
|
||||||
|
resources.append(resource)
|
||||||
|
|
||||||
|
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])
|
||||||
|
resources.append(resource)
|
||||||
|
|
||||||
|
return resources
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_plugin_interface(cls):
|
||||||
|
return LoadBalancerPluginBase
|
||||||
|
|
||||||
|
|
||||||
|
class LoadBalancerPluginBase(ServicePluginBase):
|
||||||
|
__metaclass__ = abc.ABCMeta
|
||||||
|
|
||||||
|
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
|
@ -18,9 +18,11 @@
|
|||||||
# service type constants:
|
# service type constants:
|
||||||
CORE = "CORE"
|
CORE = "CORE"
|
||||||
DUMMY = "DUMMY"
|
DUMMY = "DUMMY"
|
||||||
|
LOADBALANCER = "LOADBALANCER"
|
||||||
|
|
||||||
|
|
||||||
COMMON_PREFIXES = {
|
COMMON_PREFIXES = {
|
||||||
CORE: "",
|
CORE: "",
|
||||||
DUMMY: "/dummy_svc",
|
DUMMY: "/dummy_svc",
|
||||||
|
LOADBALANCER: "/lb",
|
||||||
}
|
}
|
||||||
|
@ -17,8 +17,10 @@
|
|||||||
|
|
||||||
import abc
|
import abc
|
||||||
|
|
||||||
|
from quantum.api import extensions
|
||||||
|
|
||||||
class ServicePluginBase(object):
|
|
||||||
|
class ServicePluginBase(extensions.PluginInterface):
|
||||||
""" defines base interface for any Advanced Service plugin """
|
""" defines base interface for any Advanced Service plugin """
|
||||||
__metaclass__ = abc.ABCMeta
|
__metaclass__ = abc.ABCMeta
|
||||||
supported_extension_aliases = []
|
supported_extension_aliases = []
|
||||||
|
@ -371,6 +371,69 @@ class TestAttributes(unittest2.TestCase):
|
|||||||
msg = attributes._validate_uuid('00000000-ffff-ffff-ffff-000000000000')
|
msg = attributes._validate_uuid('00000000-ffff-ffff-ffff-000000000000')
|
||||||
self.assertIsNone(msg)
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
def test_validate_uuid_list(self):
|
||||||
|
# check not a list
|
||||||
|
uuids = [None,
|
||||||
|
123,
|
||||||
|
'e5069610-744b-42a7-8bd8-ceac1a229cd4',
|
||||||
|
'12345678123456781234567812345678',
|
||||||
|
{'uuid': 'e5069610-744b-42a7-8bd8-ceac1a229cd4'}]
|
||||||
|
for uuid in uuids:
|
||||||
|
msg = attributes._validate_uuid_list(uuid)
|
||||||
|
error = "'%s' is not a list" % uuid
|
||||||
|
self.assertEquals(msg, error)
|
||||||
|
|
||||||
|
# check invalid uuid in a list
|
||||||
|
invalid_uuid_lists = [[None],
|
||||||
|
[123],
|
||||||
|
[123, 'e5069610-744b-42a7-8bd8-ceac1a229cd4'],
|
||||||
|
['123', '12345678123456781234567812345678'],
|
||||||
|
['t5069610-744b-42a7-8bd8-ceac1a229cd4'],
|
||||||
|
['e5069610-744b-42a7-8bd8-ceac1a229cd44'],
|
||||||
|
['e50696100-744b-42a7-8bd8-ceac1a229cd4'],
|
||||||
|
['e5069610-744bb-42a7-8bd8-ceac1a229cd4']]
|
||||||
|
for uuid_list in invalid_uuid_lists:
|
||||||
|
msg = attributes._validate_uuid_list(uuid_list)
|
||||||
|
error = "'%s' is not a valid UUID" % uuid_list[0]
|
||||||
|
self.assertEquals(msg, error)
|
||||||
|
|
||||||
|
# check duplicate items in a list
|
||||||
|
duplicate_uuids = ['e5069610-744b-42a7-8bd8-ceac1a229cd4',
|
||||||
|
'f3eeab00-8367-4524-b662-55e64d4cacb5',
|
||||||
|
'e5069610-744b-42a7-8bd8-ceac1a229cd4']
|
||||||
|
msg = attributes._validate_uuid_list(duplicate_uuids)
|
||||||
|
error = "Duplicate items in the list: %s" % ', '.join(duplicate_uuids)
|
||||||
|
self.assertEquals(msg, error)
|
||||||
|
|
||||||
|
# check valid uuid lists
|
||||||
|
valid_uuid_lists = [['e5069610-744b-42a7-8bd8-ceac1a229cd4'],
|
||||||
|
['f3eeab00-8367-4524-b662-55e64d4cacb5'],
|
||||||
|
['e5069610-744b-42a7-8bd8-ceac1a229cd4',
|
||||||
|
'f3eeab00-8367-4524-b662-55e64d4cacb5']]
|
||||||
|
for uuid_list in valid_uuid_lists:
|
||||||
|
msg = attributes._validate_uuid_list(uuid_list)
|
||||||
|
self.assertEquals(msg, None)
|
||||||
|
|
||||||
|
def test_validate_dict(self):
|
||||||
|
for value in (None, True, '1', []):
|
||||||
|
self.assertEquals(attributes._validate_dict(value),
|
||||||
|
"'%s' is not a dictionary" % value)
|
||||||
|
|
||||||
|
msg = attributes._validate_dict({})
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
msg = attributes._validate_dict({'key': 'value'})
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
def test_validate_non_negative(self):
|
||||||
|
for value in (-1, '-2'):
|
||||||
|
self.assertEquals(attributes._validate_non_negative(value),
|
||||||
|
"'%s' should be non-negative" % value)
|
||||||
|
|
||||||
|
for value in (0, 1, '2', True, False):
|
||||||
|
msg = attributes._validate_non_negative(value)
|
||||||
|
self.assertIsNone(msg)
|
||||||
|
|
||||||
|
|
||||||
class TestConvertToBoolean(unittest2.TestCase):
|
class TestConvertToBoolean(unittest2.TestCase):
|
||||||
|
|
||||||
@ -457,3 +520,22 @@ class TestConvertKvp(unittest2.TestCase):
|
|||||||
def test_convert_kvp_str_to_list_succeeds_for_two_equals(self):
|
def test_convert_kvp_str_to_list_succeeds_for_two_equals(self):
|
||||||
result = attributes.convert_kvp_str_to_list('a=a=a')
|
result = attributes.convert_kvp_str_to_list('a=a=a')
|
||||||
self.assertEqual(['a', 'a=a'], result)
|
self.assertEqual(['a', 'a=a'], result)
|
||||||
|
|
||||||
|
|
||||||
|
class TestConvertToList(unittest2.TestCase):
|
||||||
|
|
||||||
|
def test_convert_to_empty_list(self):
|
||||||
|
for item in (None, [], (), {}):
|
||||||
|
self.assertEquals(attributes.convert_to_list(item), [])
|
||||||
|
|
||||||
|
def test_convert_to_list_string(self):
|
||||||
|
for item in ('', 'foo'):
|
||||||
|
self.assertEquals(attributes.convert_to_list(item), [item])
|
||||||
|
|
||||||
|
def test_convert_to_list_iterable(self):
|
||||||
|
for item in ([None], [1, 2, 3], (1, 2, 3), set([1, 2, 3]), ['foo']):
|
||||||
|
self.assertEquals(attributes.convert_to_list(item), list(item))
|
||||||
|
|
||||||
|
def test_convert_to_list_non_iterable(self):
|
||||||
|
for item in (True, False, 1, 1.2, object()):
|
||||||
|
self.assertEquals(attributes.convert_to_list(item), [item])
|
||||||
|
477
quantum/tests/unit/test_loadbalancer_plugin.py
Normal file
477
quantum/tests/unit/test_loadbalancer_plugin.py
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||||
|
|
||||||
|
# Copyright 2012 OpenStack LLC.
|
||||||
|
# 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 spec
|
||||||
|
|
||||||
|
import copy
|
||||||
|
import mock
|
||||||
|
from webob import exc
|
||||||
|
import webtest
|
||||||
|
import unittest2
|
||||||
|
|
||||||
|
from quantum.api import extensions
|
||||||
|
from quantum.common import config
|
||||||
|
from quantum.extensions import loadbalancer
|
||||||
|
from quantum import manager
|
||||||
|
from quantum.openstack.common import cfg
|
||||||
|
from quantum.openstack.common import uuidutils
|
||||||
|
from quantum.plugins.common import constants
|
||||||
|
from quantum.tests.unit import test_api_v2
|
||||||
|
from quantum.tests.unit import test_extensions
|
||||||
|
|
||||||
|
|
||||||
|
_uuid = uuidutils.generate_uuid
|
||||||
|
_get_path = test_api_v2._get_path
|
||||||
|
|
||||||
|
|
||||||
|
class LoadBalancerTestExtensionManager(object):
|
||||||
|
|
||||||
|
def get_resources(self):
|
||||||
|
return loadbalancer.Loadbalancer.get_resources()
|
||||||
|
|
||||||
|
def get_actions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_request_extensions(self):
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class LoadBalancerExtensionTestCase(unittest2.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
|
||||||
|
plugin = 'quantum.extensions.loadbalancer.LoadBalancerPluginBase'
|
||||||
|
# Ensure 'stale' patched copies of the plugin are never returned
|
||||||
|
manager.QuantumManager._instance = None
|
||||||
|
|
||||||
|
# Ensure existing ExtensionManager is not used
|
||||||
|
extensions.PluginAwareExtensionManager._instance = None
|
||||||
|
|
||||||
|
# Create the default configurations
|
||||||
|
args = ['--config-file', test_api_v2.etcdir('quantum.conf.test')]
|
||||||
|
config.parse(args)
|
||||||
|
|
||||||
|
#just stubbing core plugin with LoadBalancer plugin
|
||||||
|
cfg.CONF.set_override('core_plugin', plugin)
|
||||||
|
cfg.CONF.set_override('service_plugins', [plugin])
|
||||||
|
|
||||||
|
self._plugin_patcher = mock.patch(plugin, autospec=True)
|
||||||
|
self.plugin = self._plugin_patcher.start()
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_plugin_type.return_value = constants.LOADBALANCER
|
||||||
|
|
||||||
|
ext_mgr = LoadBalancerTestExtensionManager()
|
||||||
|
self.ext_mdw = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||||
|
self.api = webtest.TestApp(self.ext_mdw)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self._plugin_patcher.stop()
|
||||||
|
self.api = None
|
||||||
|
self.plugin = None
|
||||||
|
cfg.CONF.reset()
|
||||||
|
|
||||||
|
def test_vip_create(self):
|
||||||
|
vip_id = _uuid()
|
||||||
|
data = {'vip': {'name': 'vip1',
|
||||||
|
'description': 'descr_vip1',
|
||||||
|
'subnet_id': _uuid(),
|
||||||
|
'address': '127.0.0.1',
|
||||||
|
'port': 80,
|
||||||
|
'protocol': 'HTTP',
|
||||||
|
'pool_id': _uuid(),
|
||||||
|
'session_persistence': {'type': 'dummy'},
|
||||||
|
'connection_limit': 100,
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['vip'])
|
||||||
|
return_value.update({'status': "ACTIVE", 'id': vip_id})
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_vip.return_value = return_value
|
||||||
|
res = self.api.post_json(_get_path('lb/vips'), data)
|
||||||
|
instance.create_vip.assert_called_with(mock.ANY,
|
||||||
|
vip=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
self.assertTrue('vip' in res.json)
|
||||||
|
self.assertEqual(res.json['vip'], return_value)
|
||||||
|
|
||||||
|
def test_vip_list(self):
|
||||||
|
vip_id = _uuid()
|
||||||
|
return_value = [{'name': 'vip1',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'id': vip_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_vips.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/vips'))
|
||||||
|
|
||||||
|
instance.get_vips.assert_called_with(mock.ANY, fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_vip_update(self):
|
||||||
|
vip_id = _uuid()
|
||||||
|
update_data = {'vip': {'admin_state_up': False}}
|
||||||
|
return_value = {'name': 'vip1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': vip_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_vip.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put_json(_get_path('lb/vips', id=vip_id),
|
||||||
|
update_data)
|
||||||
|
|
||||||
|
instance.update_vip.assert_called_with(mock.ANY, vip_id,
|
||||||
|
vip=update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('vip' in res.json)
|
||||||
|
self.assertEqual(res.json['vip'], return_value)
|
||||||
|
|
||||||
|
def test_vip_get(self):
|
||||||
|
vip_id = _uuid()
|
||||||
|
return_value = {'name': 'vip1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': vip_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_vip.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/vips', id=vip_id))
|
||||||
|
|
||||||
|
instance.get_vip.assert_called_with(mock.ANY, vip_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('vip' in res.json)
|
||||||
|
self.assertEqual(res.json['vip'], return_value)
|
||||||
|
|
||||||
|
def test_vip_delete(self):
|
||||||
|
vip_id = _uuid()
|
||||||
|
|
||||||
|
res = self.api.delete(_get_path('lb/vips', id=vip_id))
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.delete_vip.assert_called_with(mock.ANY, vip_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_pool_create(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
hm_id = _uuid()
|
||||||
|
data = {'pool': {'name': 'pool1',
|
||||||
|
'description': 'descr_pool1',
|
||||||
|
'subnet_id': _uuid(),
|
||||||
|
'protocol': 'HTTP',
|
||||||
|
'lb_method': 'ROUND_ROBIN',
|
||||||
|
'health_monitors': [hm_id],
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['pool'])
|
||||||
|
return_value.update({'status': "ACTIVE", 'id': pool_id})
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_pool.return_value = return_value
|
||||||
|
res = self.api.post_json(_get_path('lb/pools'), data)
|
||||||
|
instance.create_pool.assert_called_with(mock.ANY,
|
||||||
|
pool=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
self.assertTrue('pool' in res.json)
|
||||||
|
self.assertEqual(res.json['pool'], return_value)
|
||||||
|
|
||||||
|
def test_pool_list(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
return_value = [{'name': 'pool1',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'id': pool_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_pools.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/pools'))
|
||||||
|
|
||||||
|
instance.get_pools.assert_called_with(mock.ANY, fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_pool_update(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
update_data = {'pool': {'admin_state_up': False}}
|
||||||
|
return_value = {'name': 'pool1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': pool_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_pool.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put_json(_get_path('lb/pools', id=pool_id),
|
||||||
|
update_data)
|
||||||
|
|
||||||
|
instance.update_pool.assert_called_with(mock.ANY, pool_id,
|
||||||
|
pool=update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('pool' in res.json)
|
||||||
|
self.assertEqual(res.json['pool'], return_value)
|
||||||
|
|
||||||
|
def test_pool_get(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
return_value = {'name': 'pool1',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': pool_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_pool.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/pools', id=pool_id))
|
||||||
|
|
||||||
|
instance.get_pool.assert_called_with(mock.ANY, pool_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('pool' in res.json)
|
||||||
|
self.assertEqual(res.json['pool'], return_value)
|
||||||
|
|
||||||
|
def test_pool_delete(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
|
||||||
|
res = self.api.delete(_get_path('lb/pools', id=pool_id))
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.delete_pool.assert_called_with(mock.ANY, pool_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_pool_stats(self):
|
||||||
|
pool_id = _uuid()
|
||||||
|
|
||||||
|
stats = {'stats': 'dummy'}
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.stats.return_value = stats
|
||||||
|
|
||||||
|
path = _get_path('lb/pools', id=pool_id,
|
||||||
|
action="stats")
|
||||||
|
res = self.api.get(path)
|
||||||
|
|
||||||
|
instance.stats.assert_called_with(mock.ANY, pool_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('stats' in res.json)
|
||||||
|
self.assertEqual(res.json['stats'], stats['stats'])
|
||||||
|
|
||||||
|
def test_member_create(self):
|
||||||
|
member_id = _uuid()
|
||||||
|
data = {'member': {'pool_id': _uuid(),
|
||||||
|
'address': '127.0.0.1',
|
||||||
|
'port': 80,
|
||||||
|
'weight': 1,
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['member'])
|
||||||
|
return_value.update({'status': "ACTIVE", 'id': member_id})
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_member.return_value = return_value
|
||||||
|
res = self.api.post_json(_get_path('lb/members'), data)
|
||||||
|
instance.create_member.assert_called_with(mock.ANY,
|
||||||
|
member=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
self.assertTrue('member' in res.json)
|
||||||
|
self.assertEqual(res.json['member'], return_value)
|
||||||
|
|
||||||
|
def test_member_list(self):
|
||||||
|
member_id = _uuid()
|
||||||
|
return_value = [{'name': 'member1',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'id': member_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_members.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/members'))
|
||||||
|
|
||||||
|
instance.get_members.assert_called_with(mock.ANY, fields=mock.ANY,
|
||||||
|
filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_member_update(self):
|
||||||
|
member_id = _uuid()
|
||||||
|
update_data = {'member': {'admin_state_up': False}}
|
||||||
|
return_value = {'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': member_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_member.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put_json(_get_path('lb/members', id=member_id),
|
||||||
|
update_data)
|
||||||
|
|
||||||
|
instance.update_member.assert_called_with(mock.ANY, member_id,
|
||||||
|
member=update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('member' in res.json)
|
||||||
|
self.assertEqual(res.json['member'], return_value)
|
||||||
|
|
||||||
|
def test_member_get(self):
|
||||||
|
member_id = _uuid()
|
||||||
|
return_value = {'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': member_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_member.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/members', id=member_id))
|
||||||
|
|
||||||
|
instance.get_member.assert_called_with(mock.ANY, member_id,
|
||||||
|
fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('member' in res.json)
|
||||||
|
self.assertEqual(res.json['member'], return_value)
|
||||||
|
|
||||||
|
def test_member_delete(self):
|
||||||
|
member_id = _uuid()
|
||||||
|
|
||||||
|
res = self.api.delete(_get_path('lb/members', id=member_id))
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.delete_member.assert_called_with(mock.ANY, member_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_health_monitor_create(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
data = {'health_monitor': {'type': 'HTTP',
|
||||||
|
'delay': 2,
|
||||||
|
'timeout': 1,
|
||||||
|
'max_retries': 3,
|
||||||
|
'http_method': 'GET',
|
||||||
|
'url_path': '/path',
|
||||||
|
'expected_codes': '200-300',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
return_value = copy.copy(data['health_monitor'])
|
||||||
|
return_value.update({'status': "ACTIVE", 'id': health_monitor_id})
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_health_monitor.return_value = return_value
|
||||||
|
res = self.api.post_json(_get_path('lb/health_monitors'), data)
|
||||||
|
instance.create_health_monitor.assert_called_with(mock.ANY,
|
||||||
|
health_monitor=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
self.assertTrue('health_monitor' in res.json)
|
||||||
|
self.assertEqual(res.json['health_monitor'], return_value)
|
||||||
|
|
||||||
|
def test_health_monitor_list(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
return_value = [{'type': 'HTTP',
|
||||||
|
'admin_state_up': True,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'id': health_monitor_id}]
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_health_monitors.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/health_monitors'))
|
||||||
|
|
||||||
|
instance.get_health_monitors.assert_called_with(
|
||||||
|
mock.ANY, fields=mock.ANY, filters=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
|
||||||
|
def test_health_monitor_update(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
update_data = {'health_monitor': {'admin_state_up': False}}
|
||||||
|
return_value = {'type': 'HTTP',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': health_monitor_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.update_health_monitor.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.put_json(_get_path('lb/health_monitors',
|
||||||
|
id=health_monitor_id),
|
||||||
|
update_data)
|
||||||
|
|
||||||
|
instance.update_health_monitor.assert_called_with(
|
||||||
|
mock.ANY, health_monitor_id, health_monitor=update_data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('health_monitor' in res.json)
|
||||||
|
self.assertEqual(res.json['health_monitor'], return_value)
|
||||||
|
|
||||||
|
def test_health_monitor_get(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
return_value = {'type': 'HTTP',
|
||||||
|
'admin_state_up': False,
|
||||||
|
'tenant_id': _uuid(),
|
||||||
|
'status': "ACTIVE",
|
||||||
|
'id': health_monitor_id}
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.get_health_monitor.return_value = return_value
|
||||||
|
|
||||||
|
res = self.api.get(_get_path('lb/health_monitors',
|
||||||
|
id=health_monitor_id))
|
||||||
|
|
||||||
|
instance.get_health_monitor.assert_called_with(
|
||||||
|
mock.ANY, health_monitor_id, fields=mock.ANY)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPOk.code)
|
||||||
|
self.assertTrue('health_monitor' in res.json)
|
||||||
|
self.assertEqual(res.json['health_monitor'], return_value)
|
||||||
|
|
||||||
|
def test_health_monitor_delete(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
|
||||||
|
res = self.api.delete(_get_path('lb/health_monitors',
|
||||||
|
id=health_monitor_id))
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.delete_health_monitor.assert_called_with(mock.ANY,
|
||||||
|
health_monitor_id)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
||||||
|
|
||||||
|
def test_create_pool_health_monitor(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
data = {'health_monitor': {'id': health_monitor_id,
|
||||||
|
'tenant_id': _uuid()}}
|
||||||
|
|
||||||
|
return_value = copy.copy(data['health_monitor'])
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.create_pool_health_monitor.return_value = return_value
|
||||||
|
res = self.api.post_json('/lb/pools/id1/health_monitors', data)
|
||||||
|
instance.create_pool_health_monitor.assert_called_with(
|
||||||
|
mock.ANY, pool_id='id1', health_monitor=data)
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPCreated.code)
|
||||||
|
self.assertTrue('health_monitor' in res.json)
|
||||||
|
self.assertEqual(res.json['health_monitor'], return_value)
|
||||||
|
|
||||||
|
def test_delete_pool_health_monitor(self):
|
||||||
|
health_monitor_id = _uuid()
|
||||||
|
|
||||||
|
res = self.api.delete('/lb/pools/id1/health_monitors/%s' %
|
||||||
|
health_monitor_id)
|
||||||
|
|
||||||
|
instance = self.plugin.return_value
|
||||||
|
instance.delete_pool_health_monitor.assert_called_with(
|
||||||
|
mock.ANY, health_monitor_id, pool_id='id1')
|
||||||
|
self.assertEqual(res.status_int, exc.HTTPNoContent.code)
|
Loading…
Reference in New Issue
Block a user