multi-vendor-support-for-lbaas
BluePrint: multi-vendor-support-for-lbaas-step0 This is the first stage in a 3 stages BP Change-Id: Ic5b2c46c5a74338c3fa14cc991f4420cabd7798e
This commit is contained in:
parent
1c0c2cf1b1
commit
9e4b7355e6
@ -317,3 +317,9 @@ admin_tenant_name = %SERVICE_TENANT_NAME%
|
||||
admin_user = %SERVICE_USER%
|
||||
admin_password = %SERVICE_PASSWORD%
|
||||
signing_dir = /var/lib/quantum/keystone-signing
|
||||
|
||||
[LBAAS]
|
||||
# ==================================================================================================
|
||||
# driver_fqn is the fully qualified name of the lbaas driver that will be loaded by the lbass plugin
|
||||
# ==================================================================================================
|
||||
#driver_fqn = quantum.plugins.services.agent_loadbalancer.drivers.noop.noop_driver.NoopLbaaSDriver
|
||||
|
@ -449,15 +449,24 @@ class LoadBalancerPluginDb(LoadBalancerPluginBase,
|
||||
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _create_pool_stats(self, context, pool_id):
|
||||
def _update_pool_stats(self, context, pool_id, data=None):
|
||||
"""Update a pool with new stats structure."""
|
||||
with context.session.begin(subtransactions=True):
|
||||
pool_db = self._get_resource(context, Pool, pool_id)
|
||||
self.assert_modification_allowed(pool_db)
|
||||
pool_db.stats = self._create_pool_stats(context, pool_id, data)
|
||||
|
||||
def _create_pool_stats(self, context, pool_id, data=None):
|
||||
# This is internal method to add pool statistics. It won't
|
||||
# be exposed to API
|
||||
if not data:
|
||||
data = {}
|
||||
stats_db = PoolStatistics(
|
||||
pool_id=pool_id,
|
||||
bytes_in=0,
|
||||
bytes_out=0,
|
||||
active_connections=0,
|
||||
total_connections=0
|
||||
bytes_in=data.get("bytes_in", 0),
|
||||
bytes_out=data.get("bytes_out", 0),
|
||||
active_connections=data.get("active_connections", 0),
|
||||
total_connections=data.get("total_connections", 0)
|
||||
)
|
||||
return stats_db
|
||||
|
||||
|
@ -0,0 +1,131 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2013 Radware LTD.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @author: Avishay Balderman, Radware
|
||||
|
||||
import abc
|
||||
|
||||
|
||||
class LoadBalancerAbstractDriver(object):
|
||||
"""Abstract lbaas driver that expose ~same API as lbaas plugin.
|
||||
|
||||
The configuration elements (Vip,Member,etc) are the dicts that
|
||||
are returned to the tenant.
|
||||
Get operations are not part of the API - it will be handled
|
||||
by the lbaas plugin.
|
||||
"""
|
||||
__metaclass__ = abc.ABCMeta
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_vip(self, context, vip):
|
||||
"""A real driver would invoke a call to his backend
|
||||
and set the Vip status to ACTIVE/ERROR according
|
||||
to the backend call result
|
||||
self.plugin.update_status(context, Vip, vip["id"],
|
||||
constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_vip(self, context, old_vip, vip):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context, Vip, id, constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_vip(self, context, vip):
|
||||
"""A real driver would invoke a call to his backend
|
||||
and try to delete the Vip.
|
||||
if the deletion was successfull, delete the record from the database.
|
||||
if the deletion has failed, set the Vip status to ERROR.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_pool(self, context, pool):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context, Pool, pool["id"],
|
||||
constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_pool(self, context, old_pool, pool):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context,
|
||||
Pool,
|
||||
pool["id"], constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_pool(self, context, pool):
|
||||
"""Driver can call the code below in order to delete the pool.
|
||||
self.plugin._delete_db_pool(context, pool["id"])
|
||||
or set the status to ERROR if deletion failed
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def stats(self, context, pool_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_member(self, context, member):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context, Member, member["id"],
|
||||
constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_member(self, context, old_member, member):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context, Member,
|
||||
member["id"], constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_member(self, context, member):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_health_monitor(self, context, health_monitor):
|
||||
"""Driver may call the code below in order to update the status.
|
||||
self.plugin.update_status(context, HealthMonitor,
|
||||
health_monitor["id"],
|
||||
constants.ACTIVE)
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_health_monitor(self, context,
|
||||
old_health_monitor,
|
||||
health_monitor,
|
||||
pool_association):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_pool_health_monitor(self, context,
|
||||
health_monitor,
|
||||
pool_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_pool_health_monitor(self, context, health_monitor, pool_id):
|
||||
pass
|
@ -0,0 +1,16 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2013 OpenStack Foundation.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
@ -0,0 +1,112 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
#
|
||||
# Copyright 2013 Radware LTD.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @author: Avishay Balderman, Radware
|
||||
|
||||
|
||||
from quantum.openstack.common import log as logging
|
||||
from quantum.plugins.services.agent_loadbalancer.drivers import (
|
||||
abstract_driver
|
||||
)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def log(method):
|
||||
def wrapper(*args, **kwargs):
|
||||
data = {"method_name": method.__name__, "args": args, "kwargs": kwargs}
|
||||
LOG.debug(_('NoopLbaaSDriver method %(method_name)s'
|
||||
'called with arguments %(args)s %(kwargs)s ')
|
||||
% data)
|
||||
return method(*args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
|
||||
class NoopLbaaSDriver(abstract_driver.LoadBalancerAbstractDriver):
|
||||
|
||||
"""A dummy lbass driver that:
|
||||
1) Logs methods input
|
||||
2) Uses the plugin API in order to update
|
||||
the config elements status in DB
|
||||
"""
|
||||
|
||||
def __init__(self, plugin):
|
||||
self.plugin = plugin
|
||||
|
||||
@log
|
||||
def create_vip(self, context, vip):
|
||||
pass
|
||||
|
||||
@log
|
||||
def update_vip(self, context, old_vip, vip):
|
||||
pass
|
||||
|
||||
@log
|
||||
def delete_vip(self, context, vip):
|
||||
self.plugin._delete_db_vip(context, vip["id"])
|
||||
|
||||
@log
|
||||
def create_pool(self, context, pool):
|
||||
pass
|
||||
|
||||
@log
|
||||
def update_pool(self, context, old_pool, pool):
|
||||
pass
|
||||
|
||||
@log
|
||||
def delete_pool(self, context, pool):
|
||||
pass
|
||||
|
||||
@log
|
||||
def stats(self, context, pool_id):
|
||||
return {"bytes_in": 0,
|
||||
"bytes_out": 0,
|
||||
"active_connections": 0,
|
||||
"total_connections": 0}
|
||||
|
||||
@log
|
||||
def create_member(self, context, member):
|
||||
pass
|
||||
|
||||
@log
|
||||
def update_member(self, context, old_member, member):
|
||||
pass
|
||||
|
||||
@log
|
||||
def delete_member(self, context, member):
|
||||
self.plugin._delete_db_member(context, member["id"])
|
||||
|
||||
@log
|
||||
def create_health_monitor(self, context, health_monitor):
|
||||
pass
|
||||
|
||||
@log
|
||||
def update_health_monitor(self, context, old_health_monitor,
|
||||
health_monitor,
|
||||
pool_association):
|
||||
pass
|
||||
|
||||
@log
|
||||
def create_pool_health_monitor(self, context,
|
||||
health_monitor, pool_id):
|
||||
pass
|
||||
|
||||
@log
|
||||
def delete_pool_health_monitor(self, context, health_monitor, pool_id):
|
||||
self.plugin._delete_db_pool_health_monitor(
|
||||
context, health_monitor["id"],
|
||||
pool_id
|
||||
)
|
221
quantum/plugins/services/agent_loadbalancer/lbaas_plugin.py
Normal file
221
quantum/plugins/services/agent_loadbalancer/lbaas_plugin.py
Normal file
@ -0,0 +1,221 @@
|
||||
#
|
||||
# Copyright 2013 Radware LTD.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# @author: Avishay Balderman, Radware
|
||||
|
||||
from oslo.config import cfg
|
||||
|
||||
from quantum.db import api as qdbapi
|
||||
from quantum.db.loadbalancer import loadbalancer_db
|
||||
from quantum.openstack.common import importutils
|
||||
from quantum.openstack.common import log as logging
|
||||
from quantum.plugins.common import constants
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_DRIVER = ("quantum.plugins.services.agent_loadbalancer"
|
||||
".drivers.noop"
|
||||
".noop_driver.NoopLbaaSDriver")
|
||||
|
||||
lbaas_plugin_opts = [
|
||||
cfg.StrOpt('driver_fqn',
|
||||
default=DEFAULT_DRIVER,
|
||||
help=_('LBaaS driver Fully Qualified Name'))
|
||||
]
|
||||
|
||||
cfg.CONF.register_opts(lbaas_plugin_opts, "LBAAS")
|
||||
|
||||
|
||||
class LoadBalancerPlugin(loadbalancer_db.LoadBalancerPluginDb):
|
||||
|
||||
"""Implementation of the Quantum Loadbalancer Service Plugin.
|
||||
|
||||
This class manages the workflow of LBaaS request/response.
|
||||
Most DB related works are implemented in class
|
||||
loadbalancer_db.LoadBalancerPluginDb.
|
||||
"""
|
||||
supported_extension_aliases = ["lbaas"]
|
||||
|
||||
def __init__(self):
|
||||
"""Initialization for the loadbalancer service plugin."""
|
||||
|
||||
qdbapi.register_models()
|
||||
self.driver = importutils.import_object(
|
||||
cfg.CONF.LBAAS.driver_fqn, self)
|
||||
|
||||
def get_plugin_type(self):
|
||||
return constants.LOADBALANCER
|
||||
|
||||
def get_plugin_description(self):
|
||||
return "Quantum LoadBalancer Service Plugin"
|
||||
|
||||
def create_vip(self, context, vip):
|
||||
v = super(LoadBalancerPlugin, self).create_vip(context, vip)
|
||||
self.driver.create_vip(context, v)
|
||||
return v
|
||||
|
||||
def update_vip(self, context, id, vip):
|
||||
if 'status' not in vip['vip']:
|
||||
vip['vip']['status'] = constants.PENDING_UPDATE
|
||||
old_vip = self.get_vip(context, id)
|
||||
v = super(LoadBalancerPlugin, self).update_vip(context, id, vip)
|
||||
self.driver.update_vip(context, old_vip, v)
|
||||
return v
|
||||
|
||||
def _delete_db_vip(self, context, id):
|
||||
super(LoadBalancerPlugin, self).delete_vip(context, id)
|
||||
|
||||
def delete_vip(self, context, id):
|
||||
self.update_status(context, loadbalancer_db.Vip,
|
||||
id, constants.PENDING_DELETE)
|
||||
v = self.get_vip(context, id)
|
||||
self.driver.delete_vip(context, v)
|
||||
|
||||
def create_pool(self, context, pool):
|
||||
p = super(LoadBalancerPlugin, self).create_pool(context, pool)
|
||||
self.driver.create_pool(context, p)
|
||||
return p
|
||||
|
||||
def update_pool(self, context, id, pool):
|
||||
if 'status' not in pool['pool']:
|
||||
pool['pool']['status'] = constants.PENDING_UPDATE
|
||||
old_pool = self.get_pool(context, id)
|
||||
p = super(LoadBalancerPlugin, self).update_pool(context, id, pool)
|
||||
self.driver.update_pool(context, old_pool, p)
|
||||
return p
|
||||
|
||||
def _delete_db_pool(self, context, id):
|
||||
super(LoadBalancerPlugin, self).delete_pool(context, id)
|
||||
|
||||
def delete_pool(self, context, id):
|
||||
self.update_status(context, loadbalancer_db.Pool,
|
||||
id, constants.PENDING_DELETE)
|
||||
p = self.get_pool(context, id)
|
||||
self.driver.delete_pool(context, p)
|
||||
|
||||
def create_member(self, context, member):
|
||||
m = super(LoadBalancerPlugin, self).create_member(context, member)
|
||||
self.driver.create_member(context, m)
|
||||
return m
|
||||
|
||||
def update_member(self, context, id, member):
|
||||
if 'status' not in member['member']:
|
||||
member['member']['status'] = constants.PENDING_UPDATE
|
||||
old_member = self.get_member(context, id)
|
||||
m = super(LoadBalancerPlugin, self).update_member(context, id, member)
|
||||
self.driver.update_member(context, old_member, m)
|
||||
return m
|
||||
|
||||
def _delete_db_member(self, context, id):
|
||||
super(LoadBalancerPlugin, self).delete_member(context, id)
|
||||
|
||||
def delete_member(self, context, id):
|
||||
self.update_status(context, loadbalancer_db.Member,
|
||||
id, constants.PENDING_DELETE)
|
||||
m = self.get_member(context, id)
|
||||
self.driver.delete_member(context, m)
|
||||
|
||||
def create_health_monitor(self, context, health_monitor):
|
||||
hm = super(LoadBalancerPlugin, self).create_health_monitor(
|
||||
context,
|
||||
health_monitor
|
||||
)
|
||||
self.driver.create_health_monitor(context, hm)
|
||||
return hm
|
||||
|
||||
def update_health_monitor(self, context, id, health_monitor):
|
||||
if 'status' not in health_monitor['health_monitor']:
|
||||
health_monitor['health_monitor']['status'] = (
|
||||
constants.PENDING_UPDATE
|
||||
)
|
||||
old_hm = self.get_health_monitor(context, id)
|
||||
hm = super(LoadBalancerPlugin, self).update_health_monitor(
|
||||
context,
|
||||
id,
|
||||
health_monitor
|
||||
)
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
qry = context.session.query(
|
||||
loadbalancer_db.PoolMonitorAssociation
|
||||
)
|
||||
qry = qry.filter_by(monitor_id=hm['id'])
|
||||
assocs = qry.all()
|
||||
for assoc in assocs:
|
||||
self.driver.update_health_monitor(context, old_hm, hm, assoc)
|
||||
return hm
|
||||
|
||||
def _delete_db_pool_health_monitor(self, context, hm_id, pool_id):
|
||||
super(LoadBalancerPlugin, self).delete_pool_health_monitor(context,
|
||||
hm_id,
|
||||
pool_id)
|
||||
|
||||
def delete_health_monitor(self, context, id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
qry = context.session.query(
|
||||
loadbalancer_db.PoolMonitorAssociation
|
||||
)
|
||||
qry = qry.filter_by(monitor_id=id)
|
||||
assocs = qry.all()
|
||||
hm = self.get_health_monitor(context, id)
|
||||
for assoc in assocs:
|
||||
self.driver.delete_pool_health_monitor(context,
|
||||
hm,
|
||||
assoc['pool_id'])
|
||||
|
||||
def create_pool_health_monitor(self, context, health_monitor, pool_id):
|
||||
retval = super(LoadBalancerPlugin, self).create_pool_health_monitor(
|
||||
context,
|
||||
health_monitor,
|
||||
pool_id
|
||||
)
|
||||
# open issue: PoolMonitorAssociation has no status field
|
||||
# so we cant set the status to pending and let the driver
|
||||
# set the real status of the association
|
||||
self.driver.create_pool_health_monitor(
|
||||
context, health_monitor, pool_id)
|
||||
return retval
|
||||
|
||||
def delete_pool_health_monitor(self, context, id, pool_id):
|
||||
hm = self.get_health_monitor(context, id)
|
||||
self.driver.delete_pool_health_monitor(
|
||||
context, hm, pool_id)
|
||||
|
||||
def stats(self, context, pool_id):
|
||||
stats_data = self.driver.stats(context, pool_id)
|
||||
# if we get something from the driver -
|
||||
# update the db and return the value from db
|
||||
# else - return what we have in db
|
||||
if stats_data:
|
||||
super(LoadBalancerPlugin, self)._update_pool_stats(
|
||||
context,
|
||||
pool_id,
|
||||
stats_data
|
||||
)
|
||||
return super(LoadBalancerPlugin, self).stats(context,
|
||||
pool_id)
|
||||
|
||||
def populate_vip_graph(self, context, vip):
|
||||
"""Populate the vip with: pool, members, healthmonitors."""
|
||||
|
||||
pool = self.get_pool(context, vip['pool_id'])
|
||||
vip['pool'] = pool
|
||||
vip['members'] = [
|
||||
self.get_member(context, member_id)
|
||||
for member_id in pool['members']]
|
||||
vip['health_monitors'] = [
|
||||
self.get_health_monitor(context, hm_id)
|
||||
for hm_id in pool['health_monitors']]
|
||||
return vip
|
@ -38,7 +38,8 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
DB_CORE_PLUGIN_KLASS = 'quantum.db.db_base_plugin_v2.QuantumDbPluginV2'
|
||||
DB_LB_PLUGIN_KLASS = (
|
||||
"quantum.plugins.services.agent_loadbalancer.plugin.LoadBalancerPlugin"
|
||||
"quantum.plugins.services.agent_loadbalancer."
|
||||
"lbaas_plugin.LoadBalancerPlugin"
|
||||
)
|
||||
ROOTDIR = os.path.dirname(__file__) + '../../../..'
|
||||
ETCDIR = os.path.join(ROOTDIR, 'etc')
|
||||
@ -923,6 +924,31 @@ class TestLoadBalancer(LoadBalancerPluginDbTestCase):
|
||||
(m1, m2, m3),
|
||||
('delay', 'asc'), 2, 2)
|
||||
|
||||
def test_update_pool_stats_with_no_stats(self):
|
||||
keys = ["bytes_in", "bytes_out",
|
||||
"active_connections",
|
||||
"total_connections"]
|
||||
with self.pool() as pool:
|
||||
pool_id = pool['pool']['id']
|
||||
ctx = context.get_admin_context()
|
||||
self.plugin._update_pool_stats(ctx, pool_id)
|
||||
pool_obj = ctx.session.query(ldb.Pool).filter_by(id=pool_id).one()
|
||||
for key in keys:
|
||||
self.assertEqual(pool_obj.stats.__dict__[key], 0)
|
||||
|
||||
def test_update_pool_stats(self):
|
||||
stats_data = {"bytes_in": 1,
|
||||
"bytes_out": 2,
|
||||
"active_connections": 3,
|
||||
"total_connections": 4}
|
||||
with self.pool() as pool:
|
||||
pool_id = pool['pool']['id']
|
||||
ctx = context.get_admin_context()
|
||||
self.plugin._update_pool_stats(ctx, pool_id, stats_data)
|
||||
pool_obj = ctx.session.query(ldb.Pool).filter_by(id=pool_id).one()
|
||||
for k, v in stats_data.items():
|
||||
self.assertEqual(pool_obj.stats.__dict__[k], v)
|
||||
|
||||
def test_get_pool_stats(self):
|
||||
keys = [("bytes_in", 0),
|
||||
("bytes_out", 0),
|
||||
|
@ -22,6 +22,7 @@ import mock
|
||||
from quantum import context
|
||||
from quantum.db.loadbalancer import loadbalancer_db as ldb
|
||||
from quantum import manager
|
||||
from quantum.openstack.common import importutils
|
||||
from quantum.openstack.common import uuidutils
|
||||
from quantum.plugins.common import constants
|
||||
from quantum.plugins.services.agent_loadbalancer import plugin
|
||||
@ -40,6 +41,20 @@ class TestLoadBalancerPluginBase(
|
||||
|
||||
# we need access to loaded plugins to modify models
|
||||
loaded_plugins = manager.QuantumManager().get_service_plugins()
|
||||
# TODO(avishayb) - below is a little hack that helps the
|
||||
# test to pass :-)
|
||||
# the problem is the code below assumes the existance of 'callbacks'
|
||||
# on the plugin. So the bypass is to load the plugin that has
|
||||
# the callbacks as a member.The hack will be removed once we will
|
||||
# have one lbaas plugin. (we currently have 2 - (Grizzly and Havana))
|
||||
hack = True
|
||||
if hack:
|
||||
HACK_KLASS = (
|
||||
"quantum.plugins.services.agent_loadbalancer."
|
||||
"plugin.LoadBalancerPlugin"
|
||||
)
|
||||
self.plugin_instance = importutils.import_object(HACK_KLASS)
|
||||
else:
|
||||
self.plugin_instance = loaded_plugins[constants.LOADBALANCER]
|
||||
self.callbacks = self.plugin_instance.callbacks
|
||||
|
||||
@ -257,57 +272,3 @@ class TestLoadBalancerAgentApi(base.BaseTestCase):
|
||||
|
||||
def test_modify_pool(self):
|
||||
self._call_test_helper('modify_pool')
|
||||
|
||||
|
||||
class TestLoadBalancerPluginNotificationWrapper(TestLoadBalancerPluginBase):
|
||||
def setUp(self):
|
||||
self.log = mock.patch.object(plugin, 'LOG')
|
||||
api_cls = mock.patch.object(plugin, 'LoadBalancerAgentApi').start()
|
||||
super(TestLoadBalancerPluginNotificationWrapper, self).setUp()
|
||||
self.mock_api = api_cls.return_value
|
||||
|
||||
self.addCleanup(mock.patch.stopall)
|
||||
|
||||
def test_create_vip(self):
|
||||
with self.subnet() as subnet:
|
||||
with self.pool(subnet=subnet) as pool:
|
||||
with self.vip(pool=pool, subnet=subnet) as vip:
|
||||
self.mock_api.reload_pool.assert_called_once_with(
|
||||
mock.ANY,
|
||||
vip['vip']['pool_id']
|
||||
)
|
||||
|
||||
def test_update_vip(self):
|
||||
with self.subnet() as subnet:
|
||||
with self.pool(subnet=subnet) as pool:
|
||||
with self.vip(pool=pool, subnet=subnet) as vip:
|
||||
self.mock_api.reset_mock()
|
||||
ctx = context.get_admin_context()
|
||||
vip['vip'].pop('status')
|
||||
new_vip = self.plugin_instance.update_vip(
|
||||
ctx,
|
||||
vip['vip']['id'],
|
||||
vip
|
||||
)
|
||||
|
||||
self.mock_api.reload_pool.assert_called_once_with(
|
||||
mock.ANY,
|
||||
vip['vip']['pool_id']
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
new_vip['status'],
|
||||
constants.PENDING_UPDATE
|
||||
)
|
||||
|
||||
def test_delete_vip(self):
|
||||
with self.subnet() as subnet:
|
||||
with self.pool(subnet=subnet) as pool:
|
||||
with self.vip(pool=pool, subnet=subnet, no_delete=True) as vip:
|
||||
self.mock_api.reset_mock()
|
||||
ctx = context.get_admin_context()
|
||||
self.plugin_instance.delete_vip(ctx, vip['vip']['id'])
|
||||
self.mock_api.destroy_pool.assert_called_once_with(
|
||||
mock.ANY,
|
||||
vip['vip']['pool_id']
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user