Merge "K8s Services support: LBaaSv2Driver"

This commit is contained in:
Jenkins 2017-03-15 09:23:00 +00:00 committed by Gerrit Code Review
commit 3ea54ef501
3 changed files with 1124 additions and 0 deletions

View File

@ -251,3 +251,112 @@ class PodVIFDriver(DriverBase):
:param vif: VIF object as returned by `PodVIFDriver.request_vif`
"""
raise NotImplementedError()
@six.add_metaclass(abc.ABCMeta)
class LBaaSDriver(DriverBase):
"""Manages Neutron/Octavia load balancer to support Kubernetes Services."""
ALIAS = 'lbaas'
@abc.abstractmethod
def ensure_loadbalancer(self, endpoints, project_id, subnet_id, ip,
security_groups_ids):
"""Get or create load balancer.
:param endpoints: dict containing K8s Endpoints object
:param project_id: OpenStack project ID
:param subnet_id: Neutron subnet ID to host load balancer
:param ip: IP of the load balancer
:param security_groups_ids: security groups that should be allowed
access to the load balancer
"""
raise NotImplementedError()
@abc.abstractmethod
def release_loadbalancer(self, endpoints, loadbalancer):
"""Release load balancer.
Should return without errors if load balancer does not exist (e.g.
already deleted).
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
"""
raise NotImplementedError()
@abc.abstractmethod
def ensure_listener(self, endpoints, loadbalancer, protocol, port):
"""Get or create listener.
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param protocol: listener's protocol (only TCP is supported for now)
:param port: listener's port
"""
raise NotImplementedError()
@abc.abstractmethod
def release_listener(self, endpoints, loadbalancer, listener):
"""Release listener.
Should return without errors if listener or load balancer does not
exist (e.g. already deleted).
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param listener: `LBaaSListener` object
"""
raise NotImplementedError()
@abc.abstractmethod
def ensure_pool(self, endpoints, loadbalancer, listener):
"""Get or create pool.
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param listener: `LBaaSListener` object
"""
raise NotImplementedError()
@abc.abstractmethod
def release_pool(self, endpoints, loadbalancer, pool):
"""Release pool.
Should return without errors if pool or load balancer does not exist
(e.g. already deleted).
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param pool: `LBaaSPool` object
"""
raise NotImplementedError()
@abc.abstractmethod
def ensure_member(self, endpoints, loadbalancer, pool,
subnet_id, ip, port, target_ref):
"""Get or create member.
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param pool: `LBaaSPool` object
:param subnet_id: Neutron subnet ID of the target
:param ip: target's IP (e.g. Pod's IP)
:param port: target port
:param target_ref: Kubernetes ObjectReference of the target (e.g.
Pod reference)
"""
raise NotImplementedError()
@abc.abstractmethod
def release_member(self, endpoints, loadbalancer, member):
"""Release member.
Should return without errors if memberor load balancer does not exist
(e.g. already deleted).
:param endpoints: dict containing K8s Endpoints object
:param loadbalancer: `LBaaSLoadBalancer` object
:param member: `LBaaSMember` object
"""
raise NotImplementedError()

View File

@ -0,0 +1,320 @@
# Copyright (c) 2016 Mirantis, 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 random
import time
from neutronclient.common import exceptions as n_exc
from oslo_log import log as logging
from oslo_utils import excutils
from oslo_utils import timeutils
from kuryr_kubernetes import clients
from kuryr_kubernetes.controller.drivers import base
from kuryr_kubernetes import exceptions as k_exc
from kuryr_kubernetes.objects import lbaas as obj_lbaas
LOG = logging.getLogger(__name__)
_ACTIVATION_TIMEOUT = 300
class LBaaSv2Driver(base.LBaaSDriver):
"""LBaaSv2Driver implements LBaaSDriver for Neutron LBaaSv2 API."""
def ensure_loadbalancer(self, endpoints, project_id, subnet_id, ip,
security_groups_ids):
name = "%(namespace)s/%(name)s" % endpoints['metadata']
request = obj_lbaas.LBaaSLoadBalancer(name=name,
project_id=project_id,
subnet_id=subnet_id,
ip=ip)
response = self._ensure(request,
self._create_loadbalancer,
self._find_loadbalancer)
if not response:
# NOTE(ivc): load balancer was present before 'create', but got
# deleted externally between 'create' and 'find'
raise k_exc.ResourceNotReady(request)
# TODO(ivc): handle security groups
return response
def release_loadbalancer(self, endpoints, loadbalancer):
neutron = clients.get_neutron_client()
self._release(loadbalancer, loadbalancer,
neutron.delete_loadbalancer, loadbalancer.id)
def ensure_listener(self, endpoints, loadbalancer, protocol, port):
name = "%(namespace)s/%(name)s" % endpoints['metadata']
name += ":%s:%s" % (protocol, port)
listener = obj_lbaas.LBaaSListener(name=name,
project_id=loadbalancer.project_id,
loadbalancer_id=loadbalancer.id,
protocol=protocol,
port=port)
return self._ensure_provisioned(loadbalancer, listener,
self._create_listener,
self._find_listener)
def release_listener(self, endpoints, loadbalancer, listener):
neutron = clients.get_neutron_client()
self._release(loadbalancer, listener,
neutron.delete_listener,
listener.id)
def ensure_pool(self, endpoints, loadbalancer, listener):
pool = obj_lbaas.LBaaSPool(name=listener.name,
project_id=loadbalancer.project_id,
loadbalancer_id=loadbalancer.id,
listener_id=listener.id,
protocol=listener.protocol)
return self._ensure_provisioned(loadbalancer, pool,
self._create_pool,
self._find_pool)
def release_pool(self, endpoints, loadbalancer, pool):
neutron = clients.get_neutron_client()
self._release(loadbalancer, pool,
neutron.delete_lbaas_pool,
pool.id)
def ensure_member(self, endpoints, loadbalancer, pool,
subnet_id, ip, port, target_ref):
name = "%(namespace)s/%(name)s" % target_ref
name += ":%s" % port
member = obj_lbaas.LBaaSMember(name=name,
project_id=pool.project_id,
pool_id=pool.id,
subnet_id=subnet_id,
ip=ip,
port=port)
return self._ensure_provisioned(loadbalancer, member,
self._create_member,
self._find_member)
def release_member(self, endpoints, loadbalancer, member):
neutron = clients.get_neutron_client()
self._release(loadbalancer, member,
neutron.delete_lbaas_member,
member.id, member.pool_id)
def _create_loadbalancer(self, loadbalancer):
neutron = clients.get_neutron_client()
response = neutron.create_loadbalancer({'loadbalancer': {
'name': loadbalancer.name,
'project_id': loadbalancer.project_id,
'tenant_id': loadbalancer.project_id,
'vip_address': str(loadbalancer.ip),
'vip_subnet_id': loadbalancer.subnet_id}})
loadbalancer.id = response['loadbalancer']['id']
return loadbalancer
def _find_loadbalancer(self, loadbalancer):
neutron = clients.get_neutron_client()
response = neutron.list_loadbalancers(
name=loadbalancer.name,
project_id=loadbalancer.project_id,
tenant_id=loadbalancer.project_id,
vip_address=str(loadbalancer.ip),
vip_subnet_id=loadbalancer.subnet_id)
try:
loadbalancer.id = response['loadbalancers'][0]['id']
except (KeyError, IndexError):
return None
return loadbalancer
def _create_listener(self, listener):
neutron = clients.get_neutron_client()
response = neutron.create_listener({'listener': {
'name': listener.name,
'project_id': listener.project_id,
'tenant_id': listener.project_id,
'loadbalancer_id': listener.loadbalancer_id,
'protocol': listener.protocol,
'protocol_port': listener.port}})
listener.id = response['listener']['id']
return listener
def _find_listener(self, listener):
neutron = clients.get_neutron_client()
response = neutron.list_listeners(
name=listener.name,
project_id=listener.project_id,
tenant_id=listener.project_id,
loadbalancer_id=listener.loadbalancer_id,
protocol=listener.protocol,
protocol_port=listener.port)
try:
listener.id = response['listeners'][0]['id']
except (KeyError, IndexError):
return None
return listener
def _create_pool(self, pool):
# TODO(ivc): make lb_algorithm configurable
lb_algorithm = 'ROUND_ROBIN'
neutron = clients.get_neutron_client()
try:
response = neutron.create_lbaas_pool({'pool': {
'name': pool.name,
'project_id': pool.project_id,
'tenant_id': pool.project_id,
'listener_id': pool.listener_id,
'loadbalancer_id': pool.loadbalancer_id,
'protocol': pool.protocol,
'lb_algorithm': lb_algorithm}})
pool.id = response['pool']['id']
return pool
except n_exc.StateInvalidClient:
with excutils.save_and_reraise_exception():
self._cleanup_bogus_pool(neutron, pool, lb_algorithm)
def _cleanup_bogus_pool(self, neutron, pool, lb_algorithm):
# REVISIT(ivc): LBaaSv2 creates pool object despite raising an
# exception. The created pool is not bound to listener, but
# it is bound to loadbalancer and will cause an error on
# 'release_loadbalancer'.
pools = neutron.list_lbaas_pools(
name=pool.name, project_id=pool.project_id,
loadbalancer_id=pool.loadbalancer_id,
protocol=pool.protocol, lb_algorithm=lb_algorithm)
bogus_pool_ids = [p['id'] for p in pools.get('pools')
if not p['listeners']]
for pool_id in bogus_pool_ids:
try:
LOG.debug("Removing bogus pool %(id)s %(pool)s", {
'id': pool_id, 'pool': pool})
neutron.delete_lbaas_pool(pool_id)
except (n_exc.NotFound, n_exc.StateInvalidClient):
pass
def _find_pool(self, pool):
neutron = clients.get_neutron_client()
response = neutron.list_lbaas_pools(
name=pool.name,
project_id=pool.project_id,
tenant_id=pool.project_id,
loadbalancer_id=pool.loadbalancer_id,
protocol=pool.protocol)
try:
pools = [p for p in response['pools']
if pool.listener_id in {l['id'] for l in p['listeners']}]
pool.id = pools[0]['id']
except (KeyError, IndexError):
return None
return pool
def _create_member(self, member):
neutron = clients.get_neutron_client()
response = neutron.create_lbaas_member(member.pool_id, {'member': {
'name': member.name,
'project_id': member.project_id,
'tenant_id': member.project_id,
'subnet_id': member.subnet_id,
'address': str(member.ip),
'protocol_port': member.port}})
member.id = response['member']['id']
return member
def _find_member(self, member):
neutron = clients.get_neutron_client()
response = neutron.list_lbaas_members(
member.pool_id,
name=member.name,
project_id=member.project_id,
tenant_id=member.project_id,
subnet_id=member.subnet_id,
address=member.ip,
protocol_port=member.port)
try:
member.id = response['members'][0]['id']
except (KeyError, IndexError):
return None
return member
def _ensure(self, obj, create, find):
try:
result = create(obj)
LOG.debug("Created %(obj)s", {'obj': result})
except n_exc.Conflict:
result = find(obj)
if result:
LOG.debug("Found %(obj)s", {'obj': result})
return result
def _ensure_provisioned(self, loadbalancer, obj, create, find):
for remaining in self._provisioning_timer(_ACTIVATION_TIMEOUT):
self._wait_for_provisioning(loadbalancer, remaining)
try:
result = self._ensure(obj, create, find)
if result:
return result
except n_exc.StateInvalidClient:
continue
raise k_exc.ResourceNotReady(obj)
def _release(self, loadbalancer, obj, delete, *args, **kwargs):
for remaining in self._provisioning_timer(_ACTIVATION_TIMEOUT):
try:
try:
delete(*args, **kwargs)
return
except n_exc.StateInvalidClient:
self._wait_for_provisioning(loadbalancer, remaining)
except n_exc.NotFound:
return
raise k_exc.ResourceNotReady(obj)
def _wait_for_provisioning(self, loadbalancer, timeout):
neutron = clients.get_neutron_client()
for remaining in self._provisioning_timer(timeout):
response = neutron.show_loadbalancer(loadbalancer.id)
status = response['loadbalancer']['provisioning_status']
if status == 'ACTIVE':
LOG.debug("Provisioning complete for %(lb)s", {
'lb': loadbalancer})
return
else:
LOG.debug("Provisioning status %(status)s for %(lb)s, "
"%(rem).3gs remaining until timeout",
{'status': status, 'lb': loadbalancer,
'rem': remaining})
raise k_exc.ResourceNotReady(loadbalancer)
def _provisioning_timer(self, timeout):
# REVISIT(ivc): consider integrating with Retry
interval = 3
max_interval = 15
with timeutils.StopWatch(duration=timeout) as timer:
while not timer.expired():
yield timer.leftover()
interval = interval * 2 * random.gauss(0.8, 0.05)
interval = min(interval, max_interval)
interval = min(interval, timer.leftover())
if interval:
time.sleep(interval)

View File

@ -0,0 +1,695 @@
# Copyright (c) 2016 Mirantis, 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 mock
from neutronclient.common import exceptions as n_exc
from kuryr_kubernetes.controller.drivers import lbaasv2 as d_lbaasv2
from kuryr_kubernetes import exceptions as k_exc
from kuryr_kubernetes.objects import lbaas as obj_lbaas
from kuryr_kubernetes.tests import base as test_base
from kuryr_kubernetes.tests.unit import kuryr_fixtures as k_fix
class TestLBaaSv2Driver(test_base.TestCase):
def test_ensure_loadbalancer(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
expected_resp = mock.sentinel.expected_resp
namespace = 'TEST_NAMESPACE'
name = 'TEST_NAME'
project_id = 'TEST_PROJECT'
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
ip = '1.2.3.4'
# TODO(ivc): handle security groups
sg_ids = []
endpoints = {'metadata': {'namespace': namespace, 'name': name}}
m_driver._ensure.return_value = expected_resp
resp = cls.ensure_loadbalancer(m_driver, endpoints, project_id,
subnet_id, ip, sg_ids)
m_driver._ensure.assert_called_once_with(mock.ANY,
m_driver._create_loadbalancer,
m_driver._find_loadbalancer)
req = m_driver._ensure.call_args[0][0]
self.assertEqual("%s/%s" % (namespace, name), req.name)
self.assertEqual(project_id, req.project_id)
self.assertEqual(subnet_id, req.subnet_id)
self.assertEqual(ip, str(req.ip))
self.assertEqual(expected_resp, resp)
def test_ensure_loadbalancer_not_ready(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
namespace = 'TEST_NAMESPACE'
name = 'TEST_NAME'
project_id = 'TEST_PROJECT'
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
ip = '1.2.3.4'
# TODO(ivc): handle security groups
sg_ids = []
endpoints = {'metadata': {'namespace': namespace, 'name': name}}
m_driver._ensure.return_value = None
self.assertRaises(k_exc.ResourceNotReady, cls.ensure_loadbalancer,
m_driver, endpoints, project_id, subnet_id, ip,
sg_ids)
def test_release_loadbalancer(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
endpoints = mock.sentinel.endpoints
loadbalancer = mock.Mock()
cls.release_loadbalancer(m_driver, endpoints, loadbalancer)
m_driver._release.assert_called_once_with(loadbalancer, loadbalancer,
neutron.delete_loadbalancer,
loadbalancer.id)
def test_ensure_listener(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
expected_resp = mock.sentinel.expected_resp
namespace = 'TEST_NAMESPACE'
name = 'TEST_NAME'
project_id = 'TEST_PROJECT'
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
ip = '1.2.3.4'
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
protocol = 'TCP'
port = 1234
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
id=loadbalancer_id, name=name, project_id=project_id,
subnet_id=subnet_id, ip=ip)
# TODO(ivc): handle security groups
endpoints = {'metadata': {'namespace': namespace, 'name': name}}
m_driver._ensure_provisioned.return_value = expected_resp
resp = cls.ensure_listener(m_driver, endpoints, loadbalancer,
protocol, port)
m_driver._ensure_provisioned.assert_called_once_with(
loadbalancer, mock.ANY, m_driver._create_listener,
m_driver._find_listener)
listener = m_driver._ensure_provisioned.call_args[0][1]
self.assertEqual("%s/%s:%s:%s" % (namespace, name, protocol, port),
listener.name)
self.assertEqual(project_id, listener.project_id)
self.assertEqual(loadbalancer_id, listener.loadbalancer_id)
self.assertEqual(protocol, listener.protocol)
self.assertEqual(port, listener.port)
self.assertEqual(expected_resp, resp)
def test_release_listener(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
endpoints = mock.sentinel.endpoints
loadbalancer = mock.Mock()
listener = mock.Mock()
cls.release_listener(m_driver, endpoints, loadbalancer, listener)
m_driver._release.assert_called_once_with(loadbalancer, listener,
neutron.delete_listener,
listener.id)
def test_ensure_pool(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
expected_resp = mock.sentinel.expected_resp
endpoints = mock.sentinel.endpoints
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C',
project_id='TEST_PROJECT')
listener = obj_lbaas.LBaaSListener(
id='A57B7771-6050-4CA8-A63C-443493EC98AB',
name='TEST_LISTENER_NAME',
protocol='TCP')
m_driver._ensure_provisioned.return_value = expected_resp
resp = cls.ensure_pool(m_driver, endpoints, loadbalancer, listener)
m_driver._ensure_provisioned.assert_called_once_with(
loadbalancer, mock.ANY, m_driver._create_pool,
m_driver._find_pool)
pool = m_driver._ensure_provisioned.call_args[0][1]
self.assertEqual(listener.name, pool.name)
self.assertEqual(loadbalancer.project_id, pool.project_id)
self.assertEqual(listener.id, pool.listener_id)
self.assertEqual(listener.protocol, pool.protocol)
self.assertEqual(expected_resp, resp)
def test_release_pool(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
endpoints = mock.sentinel.endpoints
loadbalancer = mock.Mock()
pool = mock.Mock()
cls.release_pool(m_driver, endpoints, loadbalancer, pool)
m_driver._release.assert_called_once_with(loadbalancer, pool,
neutron.delete_lbaas_pool,
pool.id)
def test_ensure_member(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
expected_resp = mock.sentinel.expected_resp
endpoints = mock.sentinel.endpoints
loadbalancer = mock.sentinel.loadbalancer
pool = obj_lbaas.LBaaSPool(project_id='TEST_PROJECT',
id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
subnet_id = 'D3FA400A-F543-4B91-9CD3-047AF0CE42D1'
ip = '1.2.3.4'
port = 1234
namespace = 'TEST_NAMESPACE'
name = 'TEST_NAME'
target_ref = {'namespace': namespace, 'name': name}
m_driver._ensure_provisioned.return_value = expected_resp
resp = cls.ensure_member(m_driver, endpoints, loadbalancer, pool,
subnet_id, ip, port, target_ref)
m_driver._ensure_provisioned.assert_called_once_with(
loadbalancer, mock.ANY, m_driver._create_member,
m_driver._find_member)
member = m_driver._ensure_provisioned.call_args[0][1]
self.assertEqual("%s/%s:%s" % (namespace, name, port), member.name)
self.assertEqual(pool.project_id, member.project_id)
self.assertEqual(pool.id, member.pool_id)
self.assertEqual(subnet_id, member.subnet_id)
self.assertEqual(ip, str(member.ip))
self.assertEqual(port, member.port)
self.assertEqual(expected_resp, resp)
def test_release_member(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
endpoints = mock.sentinel.endpoints
loadbalancer = mock.Mock()
member = mock.Mock()
cls.release_member(m_driver, endpoints, loadbalancer, member)
m_driver._release.assert_called_once_with(loadbalancer, member,
neutron.delete_lbaas_member,
member.id, member.pool_id)
def test_create_loadbalancer(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
req = {'loadbalancer': {
'name': loadbalancer.name,
'project_id': loadbalancer.project_id,
'tenant_id': loadbalancer.project_id,
'vip_address': str(loadbalancer.ip),
'vip_subnet_id': loadbalancer.subnet_id}}
resp = {'loadbalancer': {'id': loadbalancer_id}}
neutron.create_loadbalancer.return_value = resp
ret = cls._create_loadbalancer(m_driver, loadbalancer)
neutron.create_loadbalancer.assert_called_once_with(req)
for attr in loadbalancer.obj_fields:
self.assertEqual(getattr(loadbalancer, attr),
getattr(ret, attr))
self.assertEqual(loadbalancer_id, ret.id)
def test_find_loadbalancer(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
loadbalancer_id = '00EE9E11-91C2-41CF-8FD4-7970579E5C4C'
resp = {'loadbalancers': [{'id': loadbalancer_id}]}
neutron.list_loadbalancers.return_value = resp
ret = cls._find_loadbalancer(m_driver, loadbalancer)
neutron.list_loadbalancers.assert_called_once_with(
name=loadbalancer.name,
project_id=loadbalancer.project_id,
tenant_id=loadbalancer.project_id,
vip_address=str(loadbalancer.ip),
vip_subnet_id=loadbalancer.subnet_id)
for attr in loadbalancer.obj_fields:
self.assertEqual(getattr(loadbalancer, attr),
getattr(ret, attr))
self.assertEqual(loadbalancer_id, ret.id)
def test_find_loadbalancer_not_found(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = obj_lbaas.LBaaSLoadBalancer(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1')
resp = {'loadbalancers': []}
neutron.list_loadbalancers.return_value = resp
ret = cls._find_loadbalancer(m_driver, loadbalancer)
neutron.list_loadbalancers.assert_called_once_with(
name=loadbalancer.name,
project_id=loadbalancer.project_id,
tenant_id=loadbalancer.project_id,
vip_address=str(loadbalancer.ip),
vip_subnet_id=loadbalancer.subnet_id)
self.assertEqual(None, ret)
def test_create_listener(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
listener = obj_lbaas.LBaaSListener(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
req = {'listener': {
'name': listener.name,
'project_id': listener.project_id,
'tenant_id': listener.project_id,
'loadbalancer_id': listener.loadbalancer_id,
'protocol': listener.protocol,
'protocol_port': listener.port}}
resp = {'listener': {'id': listener_id}}
neutron.create_listener.return_value = resp
ret = cls._create_listener(m_driver, listener)
neutron.create_listener.assert_called_once_with(req)
for attr in listener.obj_fields:
self.assertEqual(getattr(listener, attr),
getattr(ret, attr))
self.assertEqual(listener_id, ret.id)
def test_find_listener(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
listener = obj_lbaas.LBaaSListener(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
listener_id = 'A57B7771-6050-4CA8-A63C-443493EC98AB'
resp = {'listeners': [{'id': listener_id}]}
neutron.list_listeners.return_value = resp
ret = cls._find_listener(m_driver, listener)
neutron.list_listeners.assert_called_once_with(
name=listener.name,
project_id=listener.project_id,
tenant_id=listener.project_id,
loadbalancer_id=listener.loadbalancer_id,
protocol=listener.protocol,
protocol_port=listener.port)
for attr in listener.obj_fields:
self.assertEqual(getattr(listener, attr),
getattr(ret, attr))
self.assertEqual(listener_id, ret.id)
def test_find_listener_not_found(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
listener = obj_lbaas.LBaaSListener(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
port=1234, loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
resp = {'listeners': []}
neutron.list_listeners.return_value = resp
ret = cls._find_listener(m_driver, listener)
neutron.list_listeners.assert_called_once_with(
name=listener.name,
project_id=listener.project_id,
tenant_id=listener.project_id,
loadbalancer_id=listener.loadbalancer_id,
protocol=listener.protocol,
protocol_port=listener.port)
self.assertEqual(None, ret)
def test_create_pool(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
lb_algorithm = 'ROUND_ROBIN'
pool = obj_lbaas.LBaaSPool(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
req = {'pool': {
'name': pool.name,
'project_id': pool.project_id,
'tenant_id': pool.project_id,
'listener_id': pool.listener_id,
'loadbalancer_id': pool.loadbalancer_id,
'protocol': pool.protocol,
'lb_algorithm': lb_algorithm}}
resp = {'pool': {'id': pool_id}}
neutron.create_lbaas_pool.return_value = resp
ret = cls._create_pool(m_driver, pool)
neutron.create_lbaas_pool.assert_called_once_with(req)
for attr in pool.obj_fields:
self.assertEqual(getattr(pool, attr),
getattr(ret, attr))
self.assertEqual(pool_id, ret.id)
def test_create_pool_conflict(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
lb_algorithm = 'ROUND_ROBIN'
pool = obj_lbaas.LBaaSPool(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
req = {'pool': {
'name': pool.name,
'project_id': pool.project_id,
'tenant_id': pool.project_id,
'listener_id': pool.listener_id,
'loadbalancer_id': pool.loadbalancer_id,
'protocol': pool.protocol,
'lb_algorithm': lb_algorithm}}
neutron.create_lbaas_pool.side_effect = n_exc.StateInvalidClient
self.assertRaises(n_exc.StateInvalidClient, cls._create_pool, m_driver,
pool)
neutron.create_lbaas_pool.assert_called_once_with(req)
m_driver._cleanup_bogus_pool.assert_called_once_with(neutron, pool,
lb_algorithm)
def test_cleanup_bogus_pool(self):
# TODO(ivc): add unit test or get rid of _cleanup_bogus_pool
self.skipTest("not implemented")
def test_find_pool(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
pool = obj_lbaas.LBaaSPool(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
pool_id = 'D4F35594-27EB-4F4C-930C-31DD40F53B77'
resp = {'pools': [{'id': pool_id,
'listeners': [{'id': pool.listener_id}]}]}
neutron.list_lbaas_pools.return_value = resp
ret = cls._find_pool(m_driver, pool)
neutron.list_lbaas_pools.assert_called_once_with(
name=pool.name,
project_id=pool.project_id,
tenant_id=pool.project_id,
loadbalancer_id=pool.loadbalancer_id,
protocol=pool.protocol)
for attr in pool.obj_fields:
self.assertEqual(getattr(pool, attr),
getattr(ret, attr))
self.assertEqual(pool_id, ret.id)
def test_find_pool_not_found(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
pool = obj_lbaas.LBaaSPool(
name='TEST_NAME', project_id='TEST_PROJECT', protocol='TCP',
listener_id='A57B7771-6050-4CA8-A63C-443493EC98AB',
loadbalancer_id='00EE9E11-91C2-41CF-8FD4-7970579E5C4C')
resp = {'pools': []}
neutron.list_lbaas_pools.return_value = resp
ret = cls._find_pool(m_driver, pool)
neutron.list_lbaas_pools.assert_called_once_with(
name=pool.name,
project_id=pool.project_id,
tenant_id=pool.project_id,
loadbalancer_id=pool.loadbalancer_id,
protocol=pool.protocol)
self.assertEqual(None, ret)
def test_create_member(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
member = obj_lbaas.LBaaSMember(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
req = {'member': {
'name': member.name,
'project_id': member.project_id,
'tenant_id': member.project_id,
'subnet_id': member.subnet_id,
'address': str(member.ip),
'protocol_port': member.port}}
resp = {'member': {'id': member_id}}
neutron.create_lbaas_member.return_value = resp
ret = cls._create_member(m_driver, member)
neutron.create_lbaas_member.assert_called_once_with(
member.pool_id, req)
for attr in member.obj_fields:
self.assertEqual(getattr(member, attr),
getattr(ret, attr))
self.assertEqual(member_id, ret.id)
def test_find_member(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
member = obj_lbaas.LBaaSMember(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
member_id = '3A70CEC0-392D-4BC1-A27C-06E63A0FD54F'
resp = {'members': [{'id': member_id}]}
neutron.list_lbaas_members.return_value = resp
ret = cls._find_member(m_driver, member)
neutron.list_lbaas_members.assert_called_once_with(
member.pool_id,
name=member.name,
project_id=member.project_id,
tenant_id=member.project_id,
subnet_id=member.subnet_id,
address=member.ip,
protocol_port=member.port)
for attr in member.obj_fields:
self.assertEqual(getattr(member, attr),
getattr(ret, attr))
self.assertEqual(member_id, ret.id)
def test_find_member_not_found(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
member = obj_lbaas.LBaaSMember(
name='TEST_NAME', project_id='TEST_PROJECT', ip='1.2.3.4',
port=1234, subnet_id='D3FA400A-F543-4B91-9CD3-047AF0CE42D1',
pool_id='D4F35594-27EB-4F4C-930C-31DD40F53B77')
resp = {'members': []}
neutron.list_lbaas_members.return_value = resp
ret = cls._find_member(m_driver, member)
neutron.list_lbaas_members.assert_called_once_with(
member.pool_id,
name=member.name,
project_id=member.project_id,
tenant_id=member.project_id,
subnet_id=member.subnet_id,
address=member.ip,
protocol_port=member.port)
self.assertEqual(None, ret)
def test_ensure(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
obj = mock.Mock()
m_create = mock.Mock()
m_find = mock.Mock()
expected_result = mock.sentinel.expected_result
m_create.return_value = expected_result
ret = cls._ensure(m_driver, obj, m_create, m_find)
m_create.assert_called_once_with(obj)
self.assertEqual(expected_result, ret)
def test_ensure_with_conflict(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
obj = mock.Mock()
m_create = mock.Mock()
m_find = mock.Mock()
expected_result = mock.sentinel.expected_result
m_create.side_effect = n_exc.Conflict
m_find.return_value = expected_result
ret = cls._ensure(m_driver, obj, m_create, m_find)
m_create.assert_called_once_with(obj)
m_find.assert_called_once_with(obj)
self.assertEqual(expected_result, ret)
def test_request(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
create = mock.sentinel.create
find = mock.sentinel.find
expected_result = mock.sentinel.expected_result
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
m_driver._ensure.side_effect = [n_exc.StateInvalidClient,
expected_result]
ret = cls._ensure_provisioned(m_driver, loadbalancer, obj, create,
find)
m_driver._wait_for_provisioning.assert_has_calls(
[mock.call(loadbalancer, t) for t in timer])
m_driver._ensure.assert_has_calls(
[mock.call(obj, create, find) for _ in timer])
self.assertEqual(expected_result, ret)
def test_ensure_not_ready(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
create = mock.sentinel.create
find = mock.sentinel.find
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
m_driver._ensure.return_value = None
self.assertRaises(k_exc.ResourceNotReady, cls._ensure_provisioned,
m_driver,
loadbalancer, obj, create, find)
m_driver._wait_for_provisioning.assert_has_calls(
[mock.call(loadbalancer, t) for t in timer])
m_driver._ensure.assert_has_calls(
[mock.call(obj, create, find) for _ in timer])
def test_release(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
m_delete = mock.Mock()
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
cls._release(m_driver, loadbalancer, obj, m_delete)
m_driver._wait_for_provisioning.assert_not_called()
m_delete.assert_called_once()
def test_release_with_wait(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
m_delete = mock.Mock()
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
m_delete.side_effect = [n_exc.StateInvalidClient, None]
cls._release(m_driver, loadbalancer, obj, m_delete)
m_driver._wait_for_provisioning.assert_called_once_with(loadbalancer,
mock.ANY)
self.assertEqual(2, m_delete.call_count)
def test_release_not_found(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
m_delete = mock.Mock()
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
m_delete.side_effect = n_exc.NotFound
cls._release(m_driver, loadbalancer, obj, m_delete)
m_driver._wait_for_provisioning.assert_not_called()
self.assertEqual(1, m_delete.call_count)
def test_release_not_ready(self):
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.sentinel.loadbalancer
obj = mock.sentinel.obj
m_delete = mock.Mock()
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
m_delete.side_effect = n_exc.StateInvalidClient
self.assertRaises(k_exc.ResourceNotReady, cls._release, m_driver,
loadbalancer, obj, m_delete)
call_count = len(timer)
self.assertEqual(call_count,
m_driver._wait_for_provisioning.call_count)
self.assertEqual(call_count, m_delete.call_count)
def test_wait_for_provisioning(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.Mock()
timeout = mock.sentinel.timeout
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
resp = {'loadbalancer': {'provisioning_status': 'ACTIVE'}}
neutron.show_loadbalancer.return_value = resp
cls._wait_for_provisioning(m_driver, loadbalancer, timeout)
neutron.show_loadbalancer.assert_called_once_with(loadbalancer.id)
def test_wait_for_provisioning_not_ready(self):
neutron = self.useFixture(k_fix.MockNeutronClient()).client
cls = d_lbaasv2.LBaaSv2Driver
m_driver = mock.Mock(spec=d_lbaasv2.LBaaSv2Driver)
loadbalancer = mock.Mock()
timeout = mock.sentinel.timeout
timer = [mock.sentinel.t0, mock.sentinel.t1]
m_driver._provisioning_timer.return_value = timer
resp = {'loadbalancer': {'provisioning_status': 'NOT_ACTIVE'}}
neutron.show_loadbalancer.return_value = resp
self.assertRaises(k_exc.ResourceNotReady, cls._wait_for_provisioning,
m_driver, loadbalancer, timeout)
self.assertEqual(len(timer), neutron.show_loadbalancer.call_count)
def test_provisioning_timer(self):
# REVISIT(ivc): add test if _provisioning_timer is to stay
self.skipTest("not implemented")