Merge "LBaaS new object model logging no-op driver"

This commit is contained in:
Jenkins 2014-07-01 18:32:25 +00:00 committed by Gerrit Code Review
commit 0e032e20b3
8 changed files with 436 additions and 0 deletions

View File

@ -577,3 +577,5 @@ service_provider=VPN:openswan:neutron.services.vpn.service_drivers.ipsec.IPsecVP
# service_provider=VPN:cisco:neutron.services.vpn.service_drivers.cisco_ipsec.CiscoCsrIPsecVPNDriver:default
# Uncomment the line below to use Embrane heleos as Load Balancer service provider.
# service_provider=LOADBALANCER:Embrane:neutron.services.loadbalancer.drivers.embrane.driver.EmbraneLbaas:default
# Uncomment the following line to test the LBaaS v2 API _WITHOUT_ a real backend
# service_provider = LOADBALANCER:LoggingNoop:neutron.services.loadbalancer.drivers.logging_noop.driver.LoggingNoopLoadBalancerDriver:default

View File

@ -18,6 +18,14 @@ import abc
import six
#
# DEPRECATION WARNING. THIS ABSTRACT DRIVER IS FOR THE LBAAS V1 OBJECT
# MODEL AND SHOULD NO LONGER BE USED TO CREATE DRIVERS.
#
# PLEASE REFER TO driver_base.py and driver_mixins.py for the newest
# lbaas driver base classes.
#
@six.add_metaclass(abc.ABCMeta)
class LoadBalancerAbstractDriver(object):

View File

@ -0,0 +1,87 @@
# Copyright 2014 A10 Networks
#
# 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.
from neutron.db.loadbalancer import loadbalancer_db as lb_db
from neutron.services.loadbalancer.drivers import driver_mixins
class NotImplementedManager(object):
"""Helper class to make any subclass of LBAbstractDriver explode if it
is missing any of the required object managers.
"""
def create(self, context, obj):
raise NotImplementedError()
def update(self, context, old_obj, obj):
raise NotImplementedError()
def delete(self, context, obj):
raise NotImplementedError()
class LoadBalancerBaseDriver(object):
"""LBaaSv2 object model drivers should subclass LBAbstractDriver, and
initialize the following manager classes to create, update, and delete
the various load balancer objects.
"""
load_balancer = NotImplementedManager()
listener = NotImplementedManager()
pool = NotImplementedManager()
member = NotImplementedManager()
health_monitor = NotImplementedManager()
def __init__(self, plugin):
self.plugin = plugin
class BaseLoadBalancerManager(driver_mixins.BaseRefreshMixin,
driver_mixins.BaseStatsMixin,
driver_mixins.BaseStatusUpdateMixin,
driver_mixins.BaseManagerMixin):
def __init__(self, driver):
super(BaseLoadBalancerManager, self).__init__(driver)
# TODO(dougw), use lb_db.LoadBalancer when v2 lbaas
# TODO(dougw), get rid of __init__() in StatusHelperManager, and
# the if is not None clauses; after fixing this next line,
# it can become a mandatory variable for that subclass.
self.model_class = None
class BaseListenerManager(driver_mixins.BaseManagerMixin):
pass
class BasePoolManager(driver_mixins.BaseStatusUpdateMixin,
driver_mixins.BaseManagerMixin):
def __init__(self, driver):
super(BasePoolManager, self).__init__(driver)
self.model_class = lb_db.Pool
class BaseMemberManager(driver_mixins.BaseStatusUpdateMixin,
driver_mixins.BaseManagerMixin):
def __init__(self, driver):
super(BaseMemberManager, self).__init__(driver)
self.model_class = lb_db.Member
class BaseHealthMonitorManager(
driver_mixins.BaseHealthMonitorStatusUpdateMixin,
driver_mixins.BaseManagerMixin):
pass

View File

@ -0,0 +1,85 @@
# Copyright 2014 A10 Networks
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import abc
import six
from neutron.plugins.common import constants
@six.add_metaclass(abc.ABCMeta)
class BaseManagerMixin(object):
def __init__(self, driver):
self.driver = driver
@abc.abstractmethod
def create(self, context, obj):
pass
@abc.abstractmethod
def update(self, context, obj_old, obj):
pass
@abc.abstractmethod
def delete(self, context, obj):
pass
@six.add_metaclass(abc.ABCMeta)
class BaseRefreshMixin(object):
@abc.abstractmethod
def refresh(self, context, obj):
pass
@six.add_metaclass(abc.ABCMeta)
class BaseStatsMixin(object):
@abc.abstractmethod
def stats(self, context, obj):
pass
class BaseStatusUpdateMixin(object):
# Status update helpers
# Note: You must set self.model_class to an appropriate neutron model
# in your base manager class.
def active(self, context, model_id):
if self.model_class is not None:
self.driver.plugin.update_status(context, self.model_class,
model_id, constants.ACTIVE)
def failed(self, context, model_id):
if self.model_class is not None:
self.driver.plugin.update_status(context, self.model_class,
model_id, constants.ERROR)
class BaseHealthMonitorStatusUpdateMixin(object):
def active(self, context, health_monitor_id, pool_id):
self.driver.plugin.update_pool_health_monitor(context,
health_monitor_id,
pool_id,
constants.ACTIVE)
def failed(self, context, health_monitor_id, pool_id):
self.driver.plugin.update_pool_health_monitor(context,
health_monitor_id,
pool_id,
constants.ERROR)

View File

@ -0,0 +1,106 @@
# Copyright 2014, Doug Wiegley (dougwig), A10 Networks
#
# 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.
from neutron.openstack.common import log as logging
from neutron.services.loadbalancer.drivers import driver_base
LOG = logging.getLogger(__name__)
class LoggingNoopLoadBalancerDriver(driver_base.LoadBalancerBaseDriver):
def __init__(self, plugin):
self.plugin = plugin
# Each of the major LBaaS objects in the neutron database
# need a corresponding manager/handler class.
#
# Put common things that are shared across the entire driver, like
# config or a rest client handle, here.
#
# This function is executed when neutron-server starts.
self.load_balancer = LoggingNoopLoadBalancerManager(self)
self.listener = LoggingNoopListenerManager(self)
self.pool = LoggingNoopPoolManager(self)
self.member = LoggingNoopMemberManager(self)
self.health_monitor = LoggingNoopHealthMonitorManager(self)
class LoggingNoopCommonManager(object):
def create(self, context, obj):
LOG.debug("LB %s no-op, create %s", self.__class__.__name__, obj.id)
self.active(context, obj.id)
def update(self, context, old_obj, obj):
LOG.debug("LB %s no-op, update %s", self.__class__.__name__, obj.id)
self.active(context, obj.id)
def delete(self, context, obj):
LOG.debug("LB %s no-op, delete %s", self.__class__.__name__, obj.id)
class LoggingNoopLoadBalancerManager(LoggingNoopCommonManager,
driver_base.BaseLoadBalancerManager):
def refresh(self, context, lb_obj, force=False):
# This is intended to trigger the backend to check and repair
# the state of this load balancer and all of its dependent objects
LOG.debug("LB pool refresh %s, force=%s", lb_obj.id, force)
def stats(self, context, lb_obj):
LOG.debug("LB stats %s", lb_obj.id)
return {
"bytes_in": 0,
"bytes_out": 0,
"active_connections": 0,
"total_connections": 0
}
class LoggingNoopListenerManager(LoggingNoopCommonManager,
driver_base.BaseListenerManager):
def create(self, context, obj):
LOG.debug("LB listener no-op, create %s", self.__class__.__name__,
obj.id)
def update(self, context, old_obj, obj):
LOG.debug("LB listener no-op, update %s", self.__class__.__name__,
obj.id)
class LoggingNoopPoolManager(LoggingNoopCommonManager,
driver_base.BasePoolManager):
pass
class LoggingNoopMemberManager(LoggingNoopCommonManager,
driver_base.BaseMemberManager):
pass
class LoggingNoopHealthMonitorManager(LoggingNoopCommonManager,
driver_base.BaseHealthMonitorManager):
def create(self, context, obj):
LOG.debug("LB health monitor no-op, create %s",
self.__class__.__name__, obj.id)
self.active(context, obj.id, obj.id)
def update(self, context, old_obj, obj):
LOG.debug("LB health monitor no-op, update %s",
self.__class__.__name__, obj.id)
self.active(context, obj.id, obj.id)

View File

@ -0,0 +1,148 @@
# Copyright 2014, Doug Wiegley (dougwig), A10 Networks
#
# 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 neutron import context
from neutron.services.loadbalancer.drivers.logging_noop import driver
from neutron.tests.unit.db.loadbalancer import test_db_loadbalancer
log_path = 'neutron.services.loadbalancer.drivers.logging_noop.driver.LOG'
class FakeModel(object):
def __init__(self, id):
self.id = id
def patch_manager(func):
@mock.patch(log_path)
def wrapper(*args):
log_mock = args[-1]
manager_test = args[0]
model = args[1]
parent = manager_test.parent
driver = parent.driver
driver.plugin.reset_mock()
func(*args[:-1])
s = str(log_mock.mock_calls[0])
parent.assertEqual(s[:11], "call.debug(")
parent.assertTrue(s.index(model.id) != -1,
msg="Model ID not found in log")
return wrapper
class ManagerTest(object):
def __init__(self, parent, manager, model):
self.parent = parent
self.manager = manager
self.create(model)
self.update(model, model)
self.delete(model)
@patch_manager
def create(self, model):
self.manager.create(self.parent.context, model)
@patch_manager
def update(self, old_model, model):
self.manager.update(self.parent.context, old_model, model)
@patch_manager
def delete(self, model):
self.manager.delete(self.parent.context, model)
class ManagerTestWithUpdates(ManagerTest):
def __init__(self, parent, manager, model):
self.parent = parent
self.manager = manager
self.create(model)
self.update(model, model)
self.delete(model)
@patch_manager
def create(self, model):
self.manager.create(self.parent.context, model)
if self.manager.model_class is not None:
self.parent.assertEqual(
str(self.parent.driver.plugin.mock_calls[0])[:18],
"call.update_status")
@patch_manager
def update(self, old_model, model):
self.manager.update(self.parent.context, old_model, model)
if self.manager.model_class is not None:
self.parent.assertEqual(
str(self.parent.driver.plugin.mock_calls[0])[:18],
"call.update_status")
@patch_manager
def delete(self, model):
self.manager.delete(self.parent.context, model)
class LoadBalancerManagerTest(ManagerTestWithUpdates):
def __init__(self, parent, manager, model):
super(LoadBalancerManagerTest, self).__init__(parent, manager, model)
self.refresh(model)
self.stats(model)
@patch_manager
def refresh(self, model):
self.manager.refresh(self.parent.context, model)
@patch_manager
def stats(self, model):
dummy_stats = {
"bytes_in": 0,
"bytes_out": 0,
"active_connections": 0,
"total_connections": 0
}
h = self.manager.stats(self.parent.context, model)
self.parent.assertEqual(h, dummy_stats)
class TestLoggingNoopLoadBalancerDriver(
test_db_loadbalancer.LoadBalancerPluginDbTestCase):
def setUp(self):
super(TestLoggingNoopLoadBalancerDriver, self).setUp()
self.context = context.get_admin_context()
self.plugin = mock.Mock()
self.driver = driver.LoggingNoopLoadBalancerDriver(self.plugin)
def test_load_balancer_ops(self):
LoadBalancerManagerTest(self, self.driver.load_balancer,
FakeModel("loadbalancer-001"))
def test_listener_ops(self):
ManagerTest(self, self.driver.listener, FakeModel("listener-001"))
def test_pool_ops(self):
ManagerTestWithUpdates(self, self.driver.pool, FakeModel("pool-001"))
def test_member_ops(self):
ManagerTestWithUpdates(self, self.driver.member,
FakeModel("member-001"))
def test_health_monitor_ops(self):
ManagerTest(self, self.driver.health_monitor, FakeModel("hm-001"))