NSXv3: Refactor LBaaS driver to fix binding issue

Previously NSXv3 LBaaS driver only supports creating lb pool with
listener as LBaaS v2.0 spec. Since octavia api also allows
creating lb pool either with listener or loadbalancer, refactor
driver to support both cases.

Also in this patch, moved lb binding deletion from member_mgr to
loadbalancer_mgr. One loadbalancer can have multiple pools, the
lb binding cannot be deleted if there is other pools on the lb.

Fixing the unit tests as well.

Change-Id: Ia138eda4957f335c45ab4a9589a389baf0f7d676
This commit is contained in:
Tong Liu 2017-08-15 12:23:14 +00:00
parent 8304b2a28a
commit dcd5bdb0f3
9 changed files with 193 additions and 142 deletions

View File

@ -556,7 +556,7 @@ def delete_nsx_lbaas_listener_binding(session, loadbalancer_id, listener_id):
def add_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id, lb_pool_id,
lb_vs_id):
lb_vs_id=None):
with session.begin(subtransactions=True):
binding = nsx_models.NsxLbaasPool(loadbalancer_id=loadbalancer_id,
pool_id=pool_id,
@ -574,6 +574,19 @@ def get_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id):
return
def update_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id,
lb_vs_id):
try:
with session.begin(subtransactions=True):
binding = (session.query(nsx_models.NsxLbaasPool).
filter_by(loadbalancer_id=loadbalancer_id,
pool_id=pool_id).one())
binding.lb_vs_id = lb_vs_id
except exc.NoResultFound:
LOG.debug("Binding not found for pool %s", pool_id)
return
def delete_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id):
return (session.query(nsx_models.NsxLbaasPool).
filter_by(loadbalancer_id=loadbalancer_id,

View File

@ -56,7 +56,7 @@ def upgrade():
sa.Column('loadbalancer_id', sa.String(36), nullable=False),
sa.Column('pool_id', sa.String(36), nullable=False),
sa.Column('lb_pool_id', sa.String(36), nullable=False),
sa.Column('lb_vs_id', sa.String(36), nullable=False),
sa.Column('lb_vs_id', sa.String(36), nullable=True),
sa.Column('created_at', sa.DateTime(), nullable=True),
sa.Column('updated_at', sa.DateTime(), nullable=True),
sa.PrimaryKeyConstraint('loadbalancer_id', 'pool_id'))

View File

@ -433,7 +433,7 @@ class NsxLbaasPool(model_base.BASEV2, models.TimestampMixin):
ondelete="CASCADE"),
primary_key=True)
lb_pool_id = sa.Column(sa.String(36), nullable=False)
lb_vs_id = sa.Column(sa.String(36), nullable=False)
lb_vs_id = sa.Column(sa.String(36))
class NsxLbaasMonitor(model_base.BASEV2, models.TimestampMixin):

View File

@ -81,6 +81,7 @@ LB_POOL_TYPE = 'os-lbaas-pool-id'
LB_L7RULE_TYPE = 'os-lbaas-l7rule-id'
LB_HTTP_PROFILE = 'LbHttpProfile'
LB_TCP_PROFILE = 'LbFastTcpProfile'
LB_UDP_PROFILE = 'LbFastUdpProfile'
NSXV3_MONITOR_MAP = {LB_HEALTH_MONITOR_PING: 'LbIcmpMonitor',
LB_HEALTH_MONITOR_TCP: 'LbTcpMonitor',
LB_HEALTH_MONITOR_HTTP: 'LbHttpMonitor',

View File

@ -41,6 +41,7 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
load_balancer = self.core_plugin.nsxlib.load_balancer
app_client = load_balancer.application_profile
vs_client = load_balancer.virtual_server
service_client = load_balancer.service
vs_name = utils.get_name_and_uuid(listener.name, listener.id)
tags = lb_utils.get_tags(self.core_plugin, listener.id,
lb_const.LB_LISTENER_TYPE,
@ -76,6 +77,21 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
msg = _('Failed to create virtual server at NSX backend')
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
# If there is already lb:lb_service binding, add the virtual
# server to the lb service
binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if binding:
lb_service_id = binding['lb_service_id']
try:
service_client.add_virtual_server(lb_service_id,
virtual_server['id'])
except nsxlib_exc.ManagerError:
self.lbv2_driver.listener.failed_completion(context, listener)
msg = _('Failed to add virtual server to lb service '
'at NSX backend')
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
nsx_db.add_nsx_lbaas_listener_binding(
context.session, lb_id, listener.id, app_profile_id,
virtual_server['id'])
@ -90,6 +106,7 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
def delete(self, context, listener):
lb_id = listener.loadbalancer_id
load_balancer = self.core_plugin.nsxlib.load_balancer
service_client = load_balancer.service
vs_client = load_balancer.virtual_server
app_client = load_balancer.application_profile
@ -98,6 +115,22 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
if binding:
vs_id = binding['lb_vs_id']
app_profile_id = binding['app_profile_id']
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if lb_binding:
try:
lbs_id = lb_binding.get('lb_service_id')
lb_service = service_client.get(lbs_id)
vs_list = lb_service.get('virtual_server_ids')
if vs_list and vs_id in vs_list:
service_client.remove_virtual_server(lbs_id, vs_id)
except nsxlib_exc.ManagerError:
self.lbv2_driver.listener.failed_completion(context,
listener)
msg = (_('Failed to remove virtual server: %(listener)s '
'from lb service %(lbs)s') %
{'listener': listener.id, 'lbs': lbs_id})
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
try:
if listener.default_pool_id:
vs_client.update(vs_id, pool_id='')
@ -126,5 +159,6 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
nsx_db.delete_nsx_lbaas_listener_binding(
context.session, lb_id, listener.id)
self.lbv2_driver.listener.successful_completion(
context, listener, delete=True)

View File

@ -57,7 +57,24 @@ class EdgeLoadBalancerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
@log_helpers.log_method_call
def delete(self, context, lb):
# Discard any ports which are associated with LB
service_client = self.core_plugin.nsxlib.load_balancer.service
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb.id)
if lb_binding:
lb_service_id = lb_binding['lb_service_id']
lb_service = service_client.get(lb_service_id)
vs_list = lb_service.get('virtual_server_ids')
if not vs_list:
try:
service_client.delete(lb_service_id)
except nsxlib_exc.ManagerError:
self.lbv2_driver.pool.failed_completion(context, lb,
delete=True)
msg = (_('Failed to delete lb service %(lbs)s from nsx') %
{'lbs': lb_service_id})
raise n_exc.BadRequest(resource='lbaas-lb', msg=msg)
nsx_db.delete_nsx_lbaas_loadbalancer_binding(
context.session, lb.id)
self.lbv2_driver.load_balancer.successful_completion(
context, lb, delete=True)

View File

@ -65,8 +65,24 @@ class EdgeMemberManager(base_mgr.Nsxv3LoadbalancerBaseManager):
size=lb_size)
return lb_service
@log_helpers.log_method_call
def _add_loadbalancer_binding(self, context, lb_id, lbs_id,
nsx_router_id, vip_address):
# First check if there is already binding for the lb.
# If there is no binding for the lb, add the db binding.
binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if not binding:
nsx_db.add_nsx_lbaas_loadbalancer_binding(
context.session, lb_id, lbs_id,
nsx_router_id, vip_address)
else:
LOG.debug("LB binding has already been added, and no need "
"to add here.")
@log_helpers.log_method_call
def create(self, context, member):
lb_id = member.pool.loadbalancer_id
pool_id = member.pool.id
loadbalancer = member.pool.loadbalancer
if not lb_utils.validate_lb_subnet(context, self.core_plugin,
@ -92,12 +108,13 @@ class EdgeMemberManager(base_mgr.Nsxv3LoadbalancerBaseManager):
fixed_ip = member.address
binding = nsx_db.get_nsx_lbaas_pool_binding(context.session,
loadbalancer.id, pool_id)
lb_id, pool_id)
if binding:
vs_id = binding['lb_vs_id']
lb_pool_id = binding['lb_pool_id']
if len(pool_members) == 1:
vs_id = binding.get('lb_vs_id')
lb_pool_id = binding.get('lb_pool_id')
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if not lb_binding and len(pool_members) == 1:
nsx_router_id = nsx_db.get_nsx_router_id(context.session,
router_id)
lb_service = service_client.get_router_lb_service(
@ -110,16 +127,18 @@ class EdgeMemberManager(base_mgr.Nsxv3LoadbalancerBaseManager):
router_id, nsx_router_id, loadbalancer.id, lb_size)
if lb_service:
lb_service_id = lb_service['id']
nsx_db.add_nsx_lbaas_loadbalancer_binding(
context.session, loadbalancer.id, lb_service_id,
self._add_loadbalancer_binding(
context, loadbalancer.id, lb_service_id,
nsx_router_id, loadbalancer.vip_address)
if vs_id:
try:
service_client.add_virtual_server(lb_service_id, vs_id)
service_client.add_virtual_server(lb_service_id,
vs_id)
except nsxlib_exc.ManagerError:
self.lbv2_driver.member.failed_completion(context,
member)
msg = (_('Failed to attach virtual server %(vs)s to '
'lb service %(service)s') %
msg = (_('Failed to attach virtual server %(vs)s '
'to lb service %(service)s') %
{'vs': vs_id, 'service': lb_service_id})
raise n_exc.BadRequest(resource='lbaas-member',
msg=msg)
@ -159,45 +178,11 @@ class EdgeMemberManager(base_mgr.Nsxv3LoadbalancerBaseManager):
def delete(self, context, member):
lb_id = member.pool.loadbalancer_id
pool_id = member.pool.id
service_client = self.core_plugin.nsxlib.load_balancer.service
pool_client = self.core_plugin.nsxlib.load_balancer.pool
pool_members = self.lbv2_driver.plugin.get_pool_members(
context, pool_id)
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
context.session, lb_id, pool_id)
if pool_binding:
lb_pool_id = pool_binding['lb_pool_id']
lb_vs_id = pool_binding['lb_vs_id']
# If this is the last member of pool, detach virtual server from
# the lb service. If this is the last load balancer for this lb
# service, delete the lb service as well.
if len(pool_members) == 1:
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if lb_binding:
lb_service_id = lb_binding['lb_service_id']
try:
lb_service = service_client.get(lb_service_id)
vs_list = lb_service.get('virtual_server_ids')
if vs_list and lb_vs_id in vs_list:
vs_list.remove(lb_vs_id)
else:
LOG.error('virtual server id %s is not in the lb '
'service virtual server list %s',
lb_vs_id, vs_list)
service_client.update(lb_service_id,
virtual_server_ids=vs_list)
if not vs_list:
service_client.delete(lb_service_id)
nsx_db.delete_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
except nsxlib_exc.ManagerError:
self.lbv2_driver.member.failed_completion(context,
member)
msg = _('Failed to remove virtual server from lb '
'service on NSX backend')
raise n_exc.BadRequest(resource='lbaas-member',
msg=msg)
lb_pool_id = pool_binding.get('lb_pool_id')
try:
lb_pool = pool_client.get(lb_pool_id)
network = lb_utils.get_network_from_subnet(

View File

@ -37,7 +37,6 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
@log_helpers.log_method_call
def create(self, context, pool):
listener_id = pool.listener.id
lb_id = pool.loadbalancer_id
pool_client = self.core_plugin.nsxlib.load_balancer.pool
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
@ -51,12 +50,20 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
tags=tags,
algorithm=pool.lb_algorithm,
snat_translation=snat_translation)
nsx_db.add_nsx_lbaas_pool_binding(
context.session, lb_id, pool.id, lb_pool['id'])
except nsxlib_exc.ManagerError:
self.lbv2_driver.pool.failed_completion(context, pool)
msg = (_('Failed to create pool on NSX backend: %(pool)s') %
{'pool': pool.id})
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
# The pool object can be created with either --listener or
# --loadbalancer option. If listener is present, the virtual server
# will be updated with the pool. Otherwise, just return. The binding
# will be added later when the pool is associated with layer7 rule.
if pool.listener:
listener_id = pool.listener.id
binding = nsx_db.get_nsx_lbaas_listener_binding(
context.session, lb_id, listener_id)
if binding:
@ -66,10 +73,10 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
except nsxlib_exc.ManagerError:
with excutils.save_and_reraise_exception():
self.lbv2_driver.pool.failed_completion(context, pool)
LOG.error('Failed to attach pool %s to virtual server %s',
lb_pool['id'], vs_id)
nsx_db.add_nsx_lbaas_pool_binding(
context.session, lb_id, pool.id, lb_pool['id'], vs_id)
LOG.error('Failed to attach pool %s to virtual '
'server %s', lb_pool['id'], vs_id)
nsx_db.update_nsx_lbaas_pool_binding(
context.session, lb_id, pool.id, vs_id)
else:
msg = (_("Couldn't find binding on the listener: %s") %
listener_id)
@ -89,13 +96,13 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
lb_id = pool.loadbalancer_id
pool_client = self.core_plugin.nsxlib.load_balancer.pool
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
service_client = self.core_plugin.nsxlib.load_balancer.service
binding = nsx_db.get_nsx_lbaas_pool_binding(
context.session, lb_id, pool.id)
if binding:
vs_id = binding['lb_vs_id']
lb_pool_id = binding['lb_pool_id']
vs_id = binding.get('lb_vs_id')
lb_pool_id = binding.get('lb_pool_id')
if vs_id:
try:
vs_client.update(vs_id, pool_id='')
except nsxlib_exc.ManagerError:
@ -113,30 +120,6 @@ class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
nsx_db.delete_nsx_lbaas_pool_binding(context.session,
lb_id, pool.id)
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
if lb_binding:
lb_service_id = lb_binding['lb_service_id']
try:
lb_service = service_client.get(lb_service_id)
vs_list = lb_service.get('virtual_server_ids')
if vs_list and vs_id in vs_list:
vs_list.remove(vs_id)
else:
LOG.debug('virtual server id %s is not in the lb '
'service virtual server list %s',
vs_id, vs_list)
service_client.update(lb_service_id,
virtual_server_ids=vs_list)
if not vs_list:
service_client.delete(lb_service_id)
nsx_db.delete_nsx_lbaas_loadbalancer_binding(
context.session, lb_id)
except nsxlib_exc.ManagerError:
self.lbv2_driver.pool.failed_completion(context, pool)
msg = (_('Failed to delete lb pool from nsx: %(pool)s') %
{'pool': lb_pool_id})
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
self.lbv2_driver.pool.successful_completion(
context, pool, delete=True)

View File

@ -219,8 +219,22 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
mock_successful_completion.assert_called_with(self.context, new_lb)
def test_delete(self):
with mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_lb_binding, \
mock.patch.object(self.service_client, 'get'
) as mock_get_lb_service, \
mock.patch.object(self.service_client, 'delete'
) as mock_delete_lb_service, \
mock.patch.object(nsx_db, 'delete_nsx_lbaas_loadbalancer_binding'
) as mock_delete_lb_binding:
mock_get_lb_binding.return_value = LB_BINDING
mock_get_lb_service.return_value = {'id': LB_SERVICE_ID}
self.edge_driver.loadbalancer.delete(self.context, self.lb)
mock_delete_lb_service.assert_called_with(LB_SERVICE_ID)
mock_delete_lb_binding.assert_called_with(
self.context.session, LB_ID)
mock_successful_completion = (
self.lbv2_driver.load_balancer.successful_completion)
mock_successful_completion.assert_called_with(self.context,
@ -247,13 +261,20 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
) as mock_create_app_profile, \
mock.patch.object(self.vs_client, 'create'
) as mock_create_virtual_server, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_lb_binding, \
mock.patch.object(self.service_client, 'add_virtual_server'
) as mock_add_virtual_server, \
mock.patch.object(nsx_db, 'add_nsx_lbaas_listener_binding'
) as mock_add_listener_binding:
mock_create_app_profile.return_value = {'id': APP_PROFILE_ID}
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
mock_get_lb_binding.return_value = LB_BINDING
self.edge_driver.listener.create(self.context, self.listener)
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
LB_VS_ID)
mock_add_listener_binding.assert_called_with(
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
LB_VS_ID)
@ -280,6 +301,12 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
def test_delete(self):
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
) as mock_get_listener_binding, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_lb_binding, \
mock.patch.object(self.service_client, 'get'
) as mock_get_lb_service, \
mock.patch.object(self.service_client, 'remove_virtual_server'
) as mock_remove_virtual_server, \
mock.patch.object(self.app_client, 'delete'
) as mock_delete_app_profile, \
mock.patch.object(self.vs_client, 'delete'
@ -287,9 +314,15 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
mock.patch.object(nsx_db, 'delete_nsx_lbaas_listener_binding',
) as mock_delete_listener_binding:
mock_get_listener_binding.return_value = LISTENER_BINDING
mock_get_lb_binding.return_value = LB_BINDING
mock_get_lb_service.return_value = {
'id': LB_SERVICE_ID,
'virtual_server_ids': [LB_VS_ID]}
self.edge_driver.listener.delete(self.context, self.listener)
mock_remove_virtual_server.assert_called_with(LB_SERVICE_ID,
LB_VS_ID)
mock_delete_virtual_server.assert_called_with(LB_VS_ID)
mock_delete_app_profile.assert_called_with(APP_PROFILE_ID)
@ -314,18 +347,22 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
def test_create(self):
with mock.patch.object(self.pool_client, 'create'
) as mock_create_pool, \
mock.patch.object(nsx_db, 'add_nsx_lbaas_pool_binding'
) as mock_add_pool_binding, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
) as mock_get_listener_binding, \
mock.patch.object(self.vs_client, 'update', return_value=None), \
mock.patch.object(nsx_db, 'add_nsx_lbaas_pool_binding'
) as mock_add_pool_binding:
mock.patch.object(nsx_db, 'update_nsx_lbaas_pool_binding'
) as mock_update_pool_binding:
mock_create_pool.return_value = {'id': LB_POOL_ID}
mock_get_listener_binding.return_value = LISTENER_BINDING
self.edge_driver.pool.create(self.context, self.pool)
mock_add_pool_binding.assert_called_with(
self.context.session, LB_ID, POOL_ID, LB_POOL_ID, LB_VS_ID)
self.context.session, LB_ID, POOL_ID, LB_POOL_ID)
mock_update_pool_binding.assert_called_with(
self.context.session, LB_ID, POOL_ID, LB_VS_ID)
mock_successful_completion = (
self.lbv2_driver.pool.successful_completion)
mock_successful_completion.assert_called_with(self.context,
@ -389,6 +426,8 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
) as mock_get_router, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
) as mock_get_pool_binding, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_lb_binding, \
mock.patch.object(nsx_db, 'get_nsx_router_id'
) as mock_get_nsx_router_id, \
mock.patch.object(self.service_client, 'get_router_lb_service'
@ -407,6 +446,7 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
mock_get_network.return_value = LB_NETWORK
mock_get_router.return_value = LB_ROUTER_ID
mock_get_pool_binding.return_value = POOL_BINDING
mock_get_lb_binding.return_value = None
mock_get_nsx_router_id.return_value = LB_ROUTER_ID
mock_get_lb_service.return_value = {'id': LB_SERVICE_ID}
mock_get_pool.return_value = LB_POOL
@ -435,42 +475,20 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
mock_successful_completion.assert_called_with(self.context, new_member)
def test_delete(self):
with mock.patch.object(self.lbv2_driver.plugin, 'get_pool_members'
) as mock_get_pool_members, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
with mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
) as mock_get_pool_binding, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_loadbalancer_binding, \
mock.patch.object(self.service_client, 'get'
) as mock_get_lb_service, \
mock.patch.object(self.service_client, 'update'
) as mock_update_lb_service, \
mock.patch.object(self.service_client, 'delete'
) as mock_delete_lb_service, \
mock.patch.object(nsx_db, 'delete_nsx_lbaas_loadbalancer_binding'
) as mock_delete_loadbalancer_binding, \
mock.patch.object(self.pool_client, 'get'
) as mock_get_pool, \
mock.patch.object(lb_utils, 'get_network_from_subnet'
) as mock_get_network_from_subnet, \
mock.patch.object(self.pool_client, 'update_pool_with_members'
) as mock_update_pool_with_members:
mock_get_pool_members.return_value = [self.member]
mock_get_pool_binding.return_value = POOL_BINDING
mock_get_loadbalancer_binding.return_value = LB_BINDING
mock_get_lb_service.return_value = {
'id': LB_SERVICE_ID,
'virtual_server_ids': [LB_VS_ID]}
mock_get_pool.return_value = LB_POOL_WITH_MEMBER
mock_get_network_from_subnet.return_value = LB_NETWORK
self.edge_driver.member.delete(self.context, self.member)
mock_update_lb_service.assert_called_with(LB_SERVICE_ID,
virtual_server_ids=[])
mock_delete_lb_service.assert_called_with(LB_SERVICE_ID)
mock_delete_loadbalancer_binding.assert_called_with(
self.context.session, LB_ID)
mock_update_pool_with_members.assert_called_with(LB_POOL_ID, [])
mock_successful_completion = (