Merge "NSXv3: Neutron LBaaS nsxv3 support"
This commit is contained in:
commit
48e46e4c03
@ -484,3 +484,112 @@ def save_certificate(session, purpose, cert, pk):
|
|||||||
def delete_certificate(session, purpose):
|
def delete_certificate(session, purpose):
|
||||||
return (session.query(nsx_models.NsxCertificateRepository).
|
return (session.query(nsx_models.NsxCertificateRepository).
|
||||||
filter_by(purpose=purpose).delete())
|
filter_by(purpose=purpose).delete())
|
||||||
|
|
||||||
|
|
||||||
|
def add_nsx_lbaas_loadbalancer_binding(session, loadbalancer_id,
|
||||||
|
lb_service_id, lb_router_id,
|
||||||
|
vip_address):
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
binding = nsx_models.NsxLbaasLoadbalancer(
|
||||||
|
loadbalancer_id=loadbalancer_id, lb_service_id=lb_service_id,
|
||||||
|
lb_router_id=lb_router_id, vip_address=vip_address)
|
||||||
|
session.add(binding)
|
||||||
|
return binding
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_lbaas_loadbalancer_binding(session, loadbalancer_id):
|
||||||
|
try:
|
||||||
|
return session.query(
|
||||||
|
nsx_models.NsxLbaasLoadbalancer).filter_by(
|
||||||
|
loadbalancer_id=loadbalancer_id).one()
|
||||||
|
except exc.NoResultFound:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_lbaas_loadbalancer_binding_by_service(session, lb_service_id):
|
||||||
|
return session.query(
|
||||||
|
nsx_models.NsxLbaasLoadbalancer).filter_by(
|
||||||
|
lb_service_id=lb_service_id).all()
|
||||||
|
|
||||||
|
|
||||||
|
def delete_nsx_lbaas_loadbalancer_binding(session, loadbalancer_id):
|
||||||
|
return (session.query(nsx_models.NsxLbaasLoadbalancer).
|
||||||
|
filter_by(loadbalancer_id=loadbalancer_id).delete())
|
||||||
|
|
||||||
|
|
||||||
|
def add_nsx_lbaas_listener_binding(session, loadbalancer_id, listener_id,
|
||||||
|
app_profile_id, lb_vs_id):
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
binding = nsx_models.NsxLbaasListener(
|
||||||
|
loadbalancer_id=loadbalancer_id, listener_id=listener_id,
|
||||||
|
app_profile_id=app_profile_id,
|
||||||
|
lb_vs_id=lb_vs_id)
|
||||||
|
session.add(binding)
|
||||||
|
return binding
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_lbaas_listener_binding(session, loadbalancer_id, listener_id):
|
||||||
|
try:
|
||||||
|
return session.query(
|
||||||
|
nsx_models.NsxLbaasListener).filter_by(
|
||||||
|
loadbalancer_id=loadbalancer_id,
|
||||||
|
listener_id=listener_id).one()
|
||||||
|
except exc.NoResultFound:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def delete_nsx_lbaas_listener_binding(session, loadbalancer_id, listener_id):
|
||||||
|
return (session.query(nsx_models.NsxLbaasListener).
|
||||||
|
filter_by(loadbalancer_id=loadbalancer_id,
|
||||||
|
listener_id=listener_id).delete())
|
||||||
|
|
||||||
|
|
||||||
|
def add_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id, lb_pool_id,
|
||||||
|
lb_vs_id):
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
binding = nsx_models.NsxLbaasPool(loadbalancer_id=loadbalancer_id,
|
||||||
|
pool_id=pool_id,
|
||||||
|
lb_pool_id=lb_pool_id,
|
||||||
|
lb_vs_id=lb_vs_id)
|
||||||
|
session.add(binding)
|
||||||
|
return binding
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id):
|
||||||
|
try:
|
||||||
|
return session.query(nsx_models.NsxLbaasPool).filter_by(
|
||||||
|
loadbalancer_id=loadbalancer_id, pool_id=pool_id).one()
|
||||||
|
except exc.NoResultFound:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def delete_nsx_lbaas_pool_binding(session, loadbalancer_id, pool_id):
|
||||||
|
return (session.query(nsx_models.NsxLbaasPool).
|
||||||
|
filter_by(loadbalancer_id=loadbalancer_id,
|
||||||
|
pool_id=pool_id).delete())
|
||||||
|
|
||||||
|
|
||||||
|
def add_nsx_lbaas_monitor_binding(session, loadbalancer_id, pool_id, hm_id,
|
||||||
|
lb_monitor_id, lb_pool_id):
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
binding = nsx_models.NsxLbaasMonitor(
|
||||||
|
loadbalancer_id=loadbalancer_id, pool_id=pool_id, hm_id=hm_id,
|
||||||
|
lb_monitor_id=lb_monitor_id, lb_pool_id=lb_pool_id)
|
||||||
|
session.add(binding)
|
||||||
|
return binding
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_lbaas_monitor_binding(session, loadbalancer_id, pool_id, hm_id):
|
||||||
|
try:
|
||||||
|
return session.query(nsx_models.NsxLbaasMonitor).filter_by(
|
||||||
|
loadbalancer_id=loadbalancer_id,
|
||||||
|
pool_id=pool_id, hm_id=hm_id).one()
|
||||||
|
except exc.NoResultFound:
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def delete_nsx_lbaas_monitor_binding(session, loadbalancer_id, pool_id,
|
||||||
|
hm_id):
|
||||||
|
return (session.query(nsx_models.NsxLbaasMonitor).
|
||||||
|
filter_by(loadbalancer_id=loadbalancer_id,
|
||||||
|
pool_id=pool_id, hm_id=hm_id).delete())
|
||||||
|
@ -1 +1 @@
|
|||||||
53eb497903a4
|
ea7a72ab9643
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
# Copyright 2017 VMware, Inc.
|
||||||
|
#
|
||||||
|
# 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 alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from neutron.db import migration
|
||||||
|
|
||||||
|
"""nsxv3_lbaas_mapping
|
||||||
|
|
||||||
|
Revision ID: ea7a72ab9643
|
||||||
|
Revises: 53eb497903a4
|
||||||
|
Create Date: 2017-06-12 16:59:48.021909
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'ea7a72ab9643'
|
||||||
|
down_revision = '53eb497903a4'
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
'nsxv3_lbaas_loadbalancers',
|
||||||
|
sa.Column('loadbalancer_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('lb_router_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('lb_service_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('vip_address', sa.String(36), nullable=False),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('loadbalancer_id'))
|
||||||
|
op.create_table(
|
||||||
|
'nsxv3_lbaas_listeners',
|
||||||
|
sa.Column('loadbalancer_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('listener_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('app_profile_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('lb_vs_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('loadbalancer_id', 'listener_id'))
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'nsxv3_lbaas_pools',
|
||||||
|
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('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('loadbalancer_id', 'pool_id'))
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
'nsxv3_lbaas_monitors',
|
||||||
|
sa.Column('loadbalancer_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('pool_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('hm_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('lb_monitor_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('lb_pool_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||||
|
sa.PrimaryKeyConstraint('loadbalancer_id', 'pool_id', 'hm_id'))
|
||||||
|
|
||||||
|
if migration.schema_has_table('lbaas_loadbalancers'):
|
||||||
|
op.create_foreign_key(
|
||||||
|
'fk_nsxv3_lbaas_loadbalancers_id', 'nsxv3_lbaas_loadbalancers',
|
||||||
|
'lbaas_loadbalancers', ['loadbalancer_id'], ['id'],
|
||||||
|
ondelete='CASCADE')
|
||||||
|
|
||||||
|
if migration.schema_has_table('lbaas_listeners'):
|
||||||
|
op.create_foreign_key(
|
||||||
|
'fk_nsxv3_lbaas_listeners_id', 'nsxv3_lbaas_listeners',
|
||||||
|
'lbaas_listeners', ['listener_id'], ['id'], ondelete='CASCADE')
|
||||||
|
|
||||||
|
if migration.schema_has_table('lbaas_pools'):
|
||||||
|
op.create_foreign_key(
|
||||||
|
'fk_nsxv3_lbaas_pools_id', 'nsxv3_lbaas_pools',
|
||||||
|
'lbaas_pools', ['pool_id'], ['id'], ondelete='CASCADE')
|
||||||
|
|
||||||
|
if migration.schema_has_table('lbaas_healthmonitors'):
|
||||||
|
op.create_foreign_key(
|
||||||
|
'fk_nsxv3_lbaas_healthmonitors_id', 'nsxv3_lbaas_monitors',
|
||||||
|
'lbaas_healthmonitors', ['hm_id'], ['id'], ondelete='CASCADE')
|
@ -388,3 +388,63 @@ class NsxCertificateRepository(model_base.BASEV2, models.TimestampMixin):
|
|||||||
primary_key=True)
|
primary_key=True)
|
||||||
certificate = sa.Column(sa.String(9216), nullable=False)
|
certificate = sa.Column(sa.String(9216), nullable=False)
|
||||||
private_key = sa.Column(sa.String(5120), nullable=False)
|
private_key = sa.Column(sa.String(5120), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class NsxLbaasLoadbalancer(model_base.BASEV2, models.TimestampMixin):
|
||||||
|
"""Stores mapping of LBaaS loadbalancer and NSX LB service and router
|
||||||
|
|
||||||
|
Since in NSXv3, multiple loadbalancers may share the same LB service
|
||||||
|
on NSX backend. And the in turn LB service attaches to a logical router.
|
||||||
|
This stores the mapping between LBaaS loadbalancer and NSX LB service id
|
||||||
|
and NSX logical router id.
|
||||||
|
"""
|
||||||
|
__tablename__ = 'nsxv3_lbaas_loadbalancers'
|
||||||
|
fk_name = 'fk_nsxv3_lbaas_loadbalancers_id'
|
||||||
|
loadbalancer_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('lbaas_loadbalancers.id',
|
||||||
|
name=fk_name,
|
||||||
|
ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
lb_router_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
lb_service_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
vip_address = sa.Column(sa.String(36), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class NsxLbaasListener(model_base.BASEV2, models.TimestampMixin):
|
||||||
|
"""Stores the mapping between LBaaS listener and NSX LB virtual server"""
|
||||||
|
__tablename__ = 'nsxv3_lbaas_listeners'
|
||||||
|
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
listener_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('lbaas_listeners.id',
|
||||||
|
name='fk_nsxv3_lbaas_listeners_id',
|
||||||
|
ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
app_profile_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class NsxLbaasPool(model_base.BASEV2, models.TimestampMixin):
|
||||||
|
"""Stores the mapping between LBaaS pool and NSX LB Pool"""
|
||||||
|
__tablename__ = 'nsxv3_lbaas_pools'
|
||||||
|
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
pool_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('lbaas_pools.id',
|
||||||
|
name='fk_nsxv3_lbaas_pools_id',
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
class NsxLbaasMonitor(model_base.BASEV2, models.TimestampMixin):
|
||||||
|
"""Stores the mapping between LBaaS monitor and NSX LB monitor"""
|
||||||
|
__tablename__ = 'nsxv3_lbaas_monitors'
|
||||||
|
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
pool_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
hm_id = sa.Column(sa.String(36),
|
||||||
|
sa.ForeignKey('lbaas_healthmonitors.id',
|
||||||
|
name='fk_nsxv3_lbaas_healthmonitors_id',
|
||||||
|
ondelete="CASCADE"),
|
||||||
|
primary_key=True)
|
||||||
|
lb_monitor_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
lb_pool_id = sa.Column(sa.String(36), nullable=False)
|
||||||
|
@ -96,6 +96,7 @@ from vmware_nsx.plugins.common import plugin as nsx_plugin_common
|
|||||||
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
|
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
|
||||||
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
|
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
|
||||||
from vmware_nsx.services.fwaas.nsx_v3 import fwaas_callbacks
|
from vmware_nsx.services.fwaas.nsx_v3 import fwaas_callbacks
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_driver_v2
|
||||||
from vmware_nsx.services.qos.common import utils as qos_com_utils
|
from vmware_nsx.services.qos.common import utils as qos_com_utils
|
||||||
from vmware_nsx.services.qos.nsx_v3 import driver as qos_driver
|
from vmware_nsx.services.qos.nsx_v3 import driver as qos_driver
|
||||||
from vmware_nsx.services.trunk.nsx_v3 import driver as trunk_driver
|
from vmware_nsx.services.trunk.nsx_v3 import driver as trunk_driver
|
||||||
@ -187,6 +188,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
self._extension_manager.extension_aliases())
|
self._extension_manager.extension_aliases())
|
||||||
|
|
||||||
self.nsxlib = v3_utils.get_nsxlib_wrapper()
|
self.nsxlib = v3_utils.get_nsxlib_wrapper()
|
||||||
|
self.lbv2_driver = self._init_lbv2_driver()
|
||||||
# reinitialize the cluster upon fork for api workers to ensure each
|
# reinitialize the cluster upon fork for api workers to ensure each
|
||||||
# process has its own keepalive loops + state
|
# process has its own keepalive loops + state
|
||||||
registry.subscribe(
|
registry.subscribe(
|
||||||
@ -269,6 +271,18 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
# Bind FWaaS callbacks to the driver
|
# Bind FWaaS callbacks to the driver
|
||||||
self.fwaas_callbacks = fwaas_callbacks.Nsxv3FwaasCallbacks(self.nsxlib)
|
self.fwaas_callbacks = fwaas_callbacks.Nsxv3FwaasCallbacks(self.nsxlib)
|
||||||
|
|
||||||
|
def _init_lbv2_driver(self):
|
||||||
|
# Get LBaaSv2 driver during plugin initialization. If the platform
|
||||||
|
# has a version that doesn't support native loadbalancing, the driver
|
||||||
|
# will return a NotImplementedManager class.
|
||||||
|
LOG.debug("Initializing LBaaSv2.0 nsxv3 driver")
|
||||||
|
if self.nsxlib.feature_supported(nsxlib_consts.FEATURE_LOAD_BALANCER):
|
||||||
|
return lb_driver_v2.EdgeLoadbalancerDriverV2()
|
||||||
|
else:
|
||||||
|
LOG.warning("Current NSX version %(ver)s doesn't support LBaaS",
|
||||||
|
{'ver': self.nsxlib.get_version()})
|
||||||
|
return lb_driver_v2.DummyLoadbalancerDriverV2()
|
||||||
|
|
||||||
def init_availability_zones(self):
|
def init_availability_zones(self):
|
||||||
# availability zones are supported only with native dhcp
|
# availability zones are supported only with native dhcp
|
||||||
# if not - the default az will be loaded and used internally only
|
# if not - the default az will be loaded and used internally only
|
||||||
@ -2834,6 +2848,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
return self.get_router(context, router['id'])
|
return self.get_router(context, router['id'])
|
||||||
|
|
||||||
def delete_router(self, context, router_id):
|
def delete_router(self, context, router_id):
|
||||||
|
# TODO(tongl) Prevent router deletion if router still has load
|
||||||
|
# balancer attachment. Raise exception if router has lb attachment.
|
||||||
if not cfg.CONF.nsx_v3.native_dhcp_metadata:
|
if not cfg.CONF.nsx_v3.native_dhcp_metadata:
|
||||||
nsx_rpc.handle_router_metadata_access(self, context, router_id,
|
nsx_rpc.handle_router_metadata_access(self, context, router_id,
|
||||||
interface=None)
|
interface=None)
|
||||||
|
@ -15,11 +15,15 @@
|
|||||||
|
|
||||||
from neutron_lib.plugins import constants as plugin_const
|
from neutron_lib.plugins import constants as plugin_const
|
||||||
from neutron_lib.plugins import directory
|
from neutron_lib.plugins import directory
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class LoadbalancerBaseManager(object):
|
class LoadbalancerBaseManager(object):
|
||||||
_lbv2_driver = None
|
_lbv2_driver = None
|
||||||
_core_plugin = None
|
_core_plugin = None
|
||||||
|
_flavor_plugin = None
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(LoadbalancerBaseManager, self).__init__()
|
super(LoadbalancerBaseManager, self).__init__()
|
||||||
@ -45,6 +49,14 @@ class LoadbalancerBaseManager(object):
|
|||||||
|
|
||||||
return LoadbalancerBaseManager._core_plugin
|
return LoadbalancerBaseManager._core_plugin
|
||||||
|
|
||||||
|
@property
|
||||||
|
def flavor_plugin(self):
|
||||||
|
if not LoadbalancerBaseManager._flavor_plugin:
|
||||||
|
LoadbalancerBaseManager._flavor_plugin = (
|
||||||
|
self._get_plugin(plugin_const.FLAVORS))
|
||||||
|
|
||||||
|
return LoadbalancerBaseManager._flavor_plugin
|
||||||
|
|
||||||
|
|
||||||
class EdgeLoadbalancerBaseManager(LoadbalancerBaseManager):
|
class EdgeLoadbalancerBaseManager(LoadbalancerBaseManager):
|
||||||
|
|
||||||
@ -55,3 +67,9 @@ class EdgeLoadbalancerBaseManager(LoadbalancerBaseManager):
|
|||||||
@property
|
@property
|
||||||
def vcns(self):
|
def vcns(self):
|
||||||
return self.vcns_driver.vcns
|
return self.vcns_driver.vcns
|
||||||
|
|
||||||
|
|
||||||
|
class Nsxv3LoadbalancerBaseManager(LoadbalancerBaseManager):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(Nsxv3LoadbalancerBaseManager, self).__init__()
|
||||||
|
@ -72,3 +72,23 @@ L7_RULE_COMPARE_TYPE_STARTS_WITH = 'STARTS_WITH'
|
|||||||
L7_RULE_COMPARE_TYPE_ENDS_WITH = 'ENDS_WITH'
|
L7_RULE_COMPARE_TYPE_ENDS_WITH = 'ENDS_WITH'
|
||||||
L7_RULE_COMPARE_TYPE_CONTAINS = 'CONTAINS'
|
L7_RULE_COMPARE_TYPE_CONTAINS = 'CONTAINS'
|
||||||
L7_RULE_COMPARE_TYPE_EQUAL_TO = 'EQUAL_TO'
|
L7_RULE_COMPARE_TYPE_EQUAL_TO = 'EQUAL_TO'
|
||||||
|
|
||||||
|
# Resource type for resources created on NSX backend
|
||||||
|
LB_LB_TYPE = 'os-lbaas-lb-id'
|
||||||
|
LB_LISTENER_TYPE = 'os-lbaas-listener-id'
|
||||||
|
LB_HM_TYPE = 'os-lbaas-hm-id'
|
||||||
|
LB_POOL_TYPE = 'os-lbaas-pool-type'
|
||||||
|
LB_HTTP_PROFILE = 'LbHttpProfile'
|
||||||
|
LB_TCP_PROFILE = 'LbFastTcpProfile'
|
||||||
|
NSXV3_MONITOR_MAP = {LB_HEALTH_MONITOR_PING: 'LbIcmpMonitor',
|
||||||
|
LB_HEALTH_MONITOR_TCP: 'LbTcpMonitor',
|
||||||
|
LB_HEALTH_MONITOR_HTTP: 'LbHttpMonitor',
|
||||||
|
LB_HEALTH_MONITOR_HTTPS: 'LbHttpsMonitor'}
|
||||||
|
LB_STATS_MAP = {'active_connections': 'current_sessions',
|
||||||
|
'bytes_in': 'bytes_in',
|
||||||
|
'bytes_out': 'bytes_out',
|
||||||
|
'total_connections': 'total_sessions'}
|
||||||
|
LR_ROUTER_TYPE = 'os-neutron-router-id'
|
||||||
|
LR_PORT_TYPE = 'os-neutron-rport-id'
|
||||||
|
DEFAULT_LB_SIZE = 'SMALL'
|
||||||
|
LB_FLAVOR_SIZES = ['SMALL', 'MEDIUM', 'LARGE', 'small', 'medium', 'large']
|
||||||
|
0
vmware_nsx/services/lbaas/nsx_v3/__init__.py
Normal file
0
vmware_nsx/services/lbaas/nsx_v3/__init__.py
Normal file
138
vmware_nsx/services/lbaas/nsx_v3/healthmonitor_mgr.py
Normal file
138
vmware_nsx/services/lbaas/nsx_v3/healthmonitor_mgr.py
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeHealthMonitorManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgeHealthMonitorManager, self).__init__()
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def _build_monitor_args(self, hm):
|
||||||
|
if hm.type in lb_const.NSXV3_MONITOR_MAP:
|
||||||
|
monitor_type = lb_const.NSXV3_MONITOR_MAP.get(hm.type)
|
||||||
|
else:
|
||||||
|
msg = (_('Cannot create health monitor %(monitor)s with '
|
||||||
|
'type %(type)s') % {'monitor': hm.id, 'type': hm.type})
|
||||||
|
raise n_exc.InvalidInput(error_message=msg)
|
||||||
|
body = {'resource_type': monitor_type,
|
||||||
|
'interval': hm.delay,
|
||||||
|
'fall_count': hm.max_retries,
|
||||||
|
'timeout': hm.timeout}
|
||||||
|
if monitor_type in [lb_const.LB_HEALTH_MONITOR_HTTP,
|
||||||
|
lb_const.LB_HEALTH_MONITOR_HTTPS]:
|
||||||
|
if hm.http_method:
|
||||||
|
body['request_method'] = hm.http_method
|
||||||
|
if hm.url_path:
|
||||||
|
body['request_url'] = hm.url_path
|
||||||
|
# TODO(tongl): nsxv3 backend doesn't support granular control
|
||||||
|
# of expected_codes. So we ignore it and use default for now.
|
||||||
|
# Once backend supports it, we can add it back.
|
||||||
|
# if hm.expected_codes:
|
||||||
|
# body['response_status'] = hm.expected_codes
|
||||||
|
return body
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def create(self, context, hm):
|
||||||
|
lb_id = hm.pool.loadbalancer_id
|
||||||
|
pool_id = hm.pool.id
|
||||||
|
pool_client = self.core_plugin.nsxlib.load_balancer.pool
|
||||||
|
monitor_client = self.core_plugin.nsxlib.load_balancer.monitor
|
||||||
|
monitor_name = utils.get_name_and_uuid(hm.name, hm.id)
|
||||||
|
tags = lb_utils.get_tags(self.core_plugin, hm.id, lb_const.LB_HM_TYPE,
|
||||||
|
hm.tenant_id, context.project_name)
|
||||||
|
monitor_body = self._build_monitor_args(hm)
|
||||||
|
|
||||||
|
try:
|
||||||
|
lb_monitor = monitor_client.create(
|
||||||
|
display_name=monitor_name, tags=tags, **monitor_body)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
self.lbv2_driver.health_monitor.failed_completion(context, hm)
|
||||||
|
|
||||||
|
binding = nsx_db.get_nsx_lbaas_pool_binding(
|
||||||
|
context.session, lb_id, pool_id)
|
||||||
|
if binding:
|
||||||
|
lb_pool_id = binding['lb_pool_id']
|
||||||
|
try:
|
||||||
|
pool_client.add_monitor_to_pool(lb_pool_id,
|
||||||
|
lb_monitor['id'])
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.health_monitor.failed_completion(
|
||||||
|
context, hm)
|
||||||
|
msg = _('Failed to attach monitor %(monitor)s to pool '
|
||||||
|
'%(pool)s') % {'monitor': lb_monitor['id'],
|
||||||
|
'pool': lb_pool_id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-hm', msg=msg)
|
||||||
|
nsx_db.add_nsx_lbaas_monitor_binding(
|
||||||
|
context.session, lb_id, pool_id, hm.id, lb_monitor['id'],
|
||||||
|
lb_pool_id)
|
||||||
|
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion(context, hm)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def update(self, context, old_hm, new_hm):
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion(context, new_hm)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def delete(self, context, hm):
|
||||||
|
lb_id = hm.pool.loadbalancer_id
|
||||||
|
pool_id = hm.pool.id
|
||||||
|
pool_client = self.core_plugin.nsxlib.load_balancer.pool
|
||||||
|
monitor_client = self.core_plugin.nsxlib.load_balancer.monitor
|
||||||
|
|
||||||
|
binding = nsx_db.get_nsx_lbaas_monitor_binding(
|
||||||
|
context.session, lb_id, pool_id, hm.id)
|
||||||
|
if binding:
|
||||||
|
lb_monitor_id = binding['lb_monitor_id']
|
||||||
|
lb_pool_id = binding['lb_pool_id']
|
||||||
|
try:
|
||||||
|
pool_client.remove_monitor_from_pool(lb_pool_id,
|
||||||
|
lb_monitor_id)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.health_monitor.failed_completion(
|
||||||
|
context, hm)
|
||||||
|
msg = _('Failed to remove monitor %(monitor)s from pool '
|
||||||
|
'%(pool)s') % {'monitor': lb_monitor_id,
|
||||||
|
'pool': lb_pool_id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-hm', msg=msg)
|
||||||
|
try:
|
||||||
|
monitor_client.delete(lb_monitor_id)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.health_monitor.failed_completion(
|
||||||
|
context, hm)
|
||||||
|
msg = _('Failed to delete monitor %(monitor)s from '
|
||||||
|
'backend') % {'monitor': lb_monitor_id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-hm', msg=msg)
|
||||||
|
nsx_db.delete_nsx_lbaas_monitor_binding(context.session, lb_id,
|
||||||
|
pool_id, hm.id)
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion(
|
||||||
|
context, hm, delete=True)
|
64
vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py
Normal file
64
vmware_nsx/services/lbaas/nsx_v3/lb_driver_v2.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import healthmonitor_mgr as hm_mgr
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import listener_mgr
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import loadbalancer_mgr as lb_mgr
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import member_mgr
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import pool_mgr
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class NotImplementedManager(object):
|
||||||
|
"""Helper class to make any subclass of LoadBalancerBaseDriver 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 EdgeLoadbalancerDriverV2(object):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgeLoadbalancerDriverV2, self).__init__()
|
||||||
|
|
||||||
|
self.loadbalancer = lb_mgr.EdgeLoadBalancerManager()
|
||||||
|
self.listener = listener_mgr.EdgeListenerManager()
|
||||||
|
self.pool = pool_mgr.EdgePoolManager()
|
||||||
|
self.member = member_mgr.EdgeMemberManager()
|
||||||
|
self.healthmonitor = hm_mgr.EdgeHealthMonitorManager()
|
||||||
|
|
||||||
|
|
||||||
|
class DummyLoadbalancerDriverV2(object):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
self.load_balancer = NotImplementedManager()
|
||||||
|
self.listener = NotImplementedManager()
|
||||||
|
self.pool = NotImplementedManager()
|
||||||
|
self.member = NotImplementedManager()
|
||||||
|
self.health_monitor = NotImplementedManager()
|
||||||
|
self.l7policy = NotImplementedManager()
|
||||||
|
self.l7rule = NotImplementedManager()
|
107
vmware_nsx/services/lbaas/nsx_v3/lb_utils.py
Normal file
107
vmware_nsx/services/lbaas/nsx_v3/lb_utils.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from neutron.db import l3_db
|
||||||
|
from neutron.services.flavors import flavors_plugin
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
|
||||||
|
def get_tags(plugin, resource_id, resource_type, project_id, project_name):
|
||||||
|
resource = {'project_id': project_id,
|
||||||
|
'id': resource_id}
|
||||||
|
tags = plugin.nsxlib.build_v3_tags_payload(
|
||||||
|
resource, resource_type=resource_type,
|
||||||
|
project_name=project_name)
|
||||||
|
return tags
|
||||||
|
|
||||||
|
|
||||||
|
def get_nsx_resource_binding(client, name, id):
|
||||||
|
"""
|
||||||
|
:param client: nsx resource client
|
||||||
|
:param name: name of neutron object
|
||||||
|
:param id: id of neutron object
|
||||||
|
:return: return the nsx resource id
|
||||||
|
"""
|
||||||
|
nsx_name = utils.get_name_and_uuid(name, id)
|
||||||
|
nsx_resource = client.find_by_display_name(nsx_name)
|
||||||
|
if nsx_resource:
|
||||||
|
return nsx_resource[0]['id']
|
||||||
|
|
||||||
|
|
||||||
|
def get_network_from_subnet(context, plugin, subnet_id):
|
||||||
|
subnet = plugin.get_subnet(context, subnet_id)
|
||||||
|
if subnet:
|
||||||
|
return plugin.get_network(context, subnet['network_id'])
|
||||||
|
|
||||||
|
|
||||||
|
def get_router_from_network(context, plugin, subnet_id):
|
||||||
|
subnet = plugin.get_subnet(context, subnet_id)
|
||||||
|
network_id = subnet['network_id']
|
||||||
|
port_filters = {'device_owner': [l3_db.DEVICE_OWNER_ROUTER_INTF],
|
||||||
|
'network_id': [network_id]}
|
||||||
|
ports = plugin.get_ports(context, filters=port_filters)
|
||||||
|
if ports:
|
||||||
|
return ports[0]['device_id']
|
||||||
|
|
||||||
|
|
||||||
|
def get_lb_router_id(context, plugin, lb):
|
||||||
|
router_client = plugin.nsxlib.logical_router
|
||||||
|
name = utils.get_name_and_uuid(lb.name, lb.id)
|
||||||
|
tags = get_tags(plugin, lb.id, lb_const.LB_LB_TYPE, lb.tenant_id,
|
||||||
|
context.project_name)
|
||||||
|
edge_cluster_uuid = plugin._get_edge_cluster(plugin._default_tier0_router)
|
||||||
|
lb_router = router_client.create(name, tags, edge_cluster_uuid)
|
||||||
|
return lb_router
|
||||||
|
|
||||||
|
|
||||||
|
def get_lb_flavor_size(flavor_plugin, context, flavor_id):
|
||||||
|
if not flavor_id:
|
||||||
|
return lb_const.DEFAULT_LB_SIZE
|
||||||
|
else:
|
||||||
|
flavor = flavors_plugin.FlavorsPlugin.get_flavor(
|
||||||
|
flavor_plugin, context, flavor_id)
|
||||||
|
flavor_size = flavor['name']
|
||||||
|
if flavor_size in lb_const.LB_FLAVOR_SIZES:
|
||||||
|
return flavor_size.upper()
|
||||||
|
else:
|
||||||
|
err_msg = (_("Invalid flavor size %(flavor)s, only 'small', "
|
||||||
|
"'medium', or 'large' are supported") %
|
||||||
|
{'flavor': flavor_size})
|
||||||
|
raise n_exc.InvalidInput(error_message=err_msg)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_lb_subnet(context, plugin, subnet_id):
|
||||||
|
'''Validate LB subnet before creating loadbalancer on it.
|
||||||
|
|
||||||
|
To create a loadbalancer, the network has to be either an external
|
||||||
|
network or private network that connects to a tenant router. It will
|
||||||
|
throw exception if the network doesn't meet this requirement.
|
||||||
|
|
||||||
|
:param context: context
|
||||||
|
:param plugin: core plugin
|
||||||
|
:param subnet_id: loadbalancer's subnet id
|
||||||
|
:return: True if subnet meet requirement, otherwise return False
|
||||||
|
'''
|
||||||
|
network = get_network_from_subnet(context, plugin, subnet_id)
|
||||||
|
router_id = get_router_from_network(
|
||||||
|
context, plugin, subnet_id)
|
||||||
|
if network.get('router:external') or router_id:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
124
vmware_nsx/services/lbaas/nsx_v3/listener_mgr.py
Normal file
124
vmware_nsx/services/lbaas/nsx_v3/listener_mgr.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.common import exceptions as nsx_exc
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgeListenerManager, self).__init__()
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def create(self, context, listener, certificate=None):
|
||||||
|
lb_id = listener.loadbalancer_id
|
||||||
|
vip_address = listener.loadbalancer.vip_address
|
||||||
|
load_balancer = self.core_plugin.nsxlib.load_balancer
|
||||||
|
app_client = load_balancer.application_profile
|
||||||
|
vs_client = load_balancer.virtual_server
|
||||||
|
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,
|
||||||
|
listener.tenant_id,
|
||||||
|
context.project_name)
|
||||||
|
if listener.protocol == 'HTTP' or listener.protocol == 'HTTPS':
|
||||||
|
profile_type = lb_const.LB_HTTP_PROFILE
|
||||||
|
elif listener.protocol == 'TCP':
|
||||||
|
profile_type = lb_const.LB_TCP_PROFILE
|
||||||
|
else:
|
||||||
|
msg = (_('Cannot create listener %(listener)s with '
|
||||||
|
'protocol %(protocol)s') %
|
||||||
|
{'listener': listener.id,
|
||||||
|
'protocol': listener.protocol})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||||
|
try:
|
||||||
|
app_profile = app_client.create(
|
||||||
|
display_name=vs_name, resource_type=profile_type, tags=tags)
|
||||||
|
app_profile_id = app_profile['id']
|
||||||
|
virtual_server = vs_client.create(
|
||||||
|
display_name=vs_name,
|
||||||
|
tags=tags,
|
||||||
|
enabled=listener.admin_state_up,
|
||||||
|
ip_address=vip_address,
|
||||||
|
port=listener.protocol_port,
|
||||||
|
application_profile_id=app_profile_id)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.listener.failed_completion(context, listener)
|
||||||
|
msg = _('Failed to create virtual server 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'])
|
||||||
|
self.lbv2_driver.listener.successful_completion(
|
||||||
|
context, listener)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def update(self, context, old_listener, new_listener, certificate=None):
|
||||||
|
self.lbv2_driver.listener.successful_completion(context, new_listener)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def delete(self, context, listener):
|
||||||
|
lb_id = listener.loadbalancer_id
|
||||||
|
load_balancer = self.core_plugin.nsxlib.load_balancer
|
||||||
|
vs_client = load_balancer.virtual_server
|
||||||
|
app_client = load_balancer.application_profile
|
||||||
|
|
||||||
|
binding = nsx_db.get_nsx_lbaas_listener_binding(
|
||||||
|
context.session, lb_id, listener.id)
|
||||||
|
if binding:
|
||||||
|
vs_id = binding['lb_vs_id']
|
||||||
|
app_profile_id = binding['app_profile_id']
|
||||||
|
try:
|
||||||
|
vs_client.delete(vs_id)
|
||||||
|
except nsx_exc.NsxResourceNotFound:
|
||||||
|
msg = (_("virtual server not found on nsx: %(vs)s") %
|
||||||
|
{'vs': vs_id})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.listener.failed_completion(context,
|
||||||
|
listener)
|
||||||
|
msg = (_('Failed to delete virtual server: %(listener)s') %
|
||||||
|
{'listener': listener.id})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||||
|
try:
|
||||||
|
app_client.delete(app_profile_id)
|
||||||
|
except nsx_exc.NsxResourceNotFound:
|
||||||
|
msg = (_("application profile not found on nsx: %s") %
|
||||||
|
app_profile_id)
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.listener.failed_completion(context,
|
||||||
|
listener)
|
||||||
|
msg = (_('Failed to delete application profile: %(app)s') %
|
||||||
|
{'app': app_profile_id})
|
||||||
|
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)
|
110
vmware_nsx/services/lbaas/nsx_v3/loadbalancer_mgr.py
Normal file
110
vmware_nsx/services/lbaas/nsx_v3/loadbalancer_mgr.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
|
||||||
|
from neutron_lib.callbacks import events
|
||||||
|
from neutron_lib.callbacks import registry
|
||||||
|
from neutron_lib.callbacks import resources
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeLoadBalancerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgeLoadBalancerManager, self).__init__()
|
||||||
|
registry.subscribe(
|
||||||
|
self._handle_subnet_gw_change,
|
||||||
|
resources.SUBNET, events.AFTER_UPDATE)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def create(self, context, lb):
|
||||||
|
if lb_utils.validate_lb_subnet(context, self.core_plugin,
|
||||||
|
lb.vip_subnet_id):
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion(context, lb)
|
||||||
|
else:
|
||||||
|
msg = _('Cannot create lb on subnet %(sub)s for '
|
||||||
|
'loadbalancer %(lb)s as it does not connect '
|
||||||
|
'to router') % {'sub': lb.vip_subnet_id,
|
||||||
|
'lb': lb.id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-subnet', msg=msg)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def update(self, context, old_lb, new_lb):
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion(context, new_lb)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def delete(self, context, lb):
|
||||||
|
# Discard any ports which are associated with LB
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion(
|
||||||
|
context, lb, delete=True)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def refresh(self, context, lb):
|
||||||
|
# TODO(tongl): implememnt
|
||||||
|
pass
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def stats(self, context, lb):
|
||||||
|
# Since multiple LBaaS loadbalancer can share the same LB service,
|
||||||
|
# get the corresponding virtual servers' stats instead of LB service.
|
||||||
|
stats = {'active_connections': 0,
|
||||||
|
'bytes_in': 0,
|
||||||
|
'bytes_out': 0,
|
||||||
|
'total_connections': 0}
|
||||||
|
|
||||||
|
service_client = self.core_plugin.nsxlib.load_balancer.service
|
||||||
|
for listener in lb.listeners:
|
||||||
|
lb_binding = nsx_db.get_nsx_lbaas_loadbalancer_binding(
|
||||||
|
context.session, lb.id)
|
||||||
|
vs_binding = nsx_db.get_nsx_lbaas_listener_binding(
|
||||||
|
context.session, lb.id, listener.id)
|
||||||
|
if lb_binding and vs_binding:
|
||||||
|
lb_service_id = lb_binding.get('lb_service_id')
|
||||||
|
vs_id = vs_binding.get('lb_vs_id')
|
||||||
|
try:
|
||||||
|
rsp = service_client.get_stats(lb_service_id)
|
||||||
|
if rsp:
|
||||||
|
|
||||||
|
vs_stats = rsp['virtual_servers'][vs_id]['statistics']
|
||||||
|
for stat in lb_const.LB_STATS_MAP:
|
||||||
|
lb_stat = lb_const.LB_STATS_MAP[stat]
|
||||||
|
if lb_stat in vs_stats:
|
||||||
|
stats[stat] += stats[stat] + vs_stats[lb_stat]
|
||||||
|
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
msg = _('Failed to retrieve stats from LB service '
|
||||||
|
'for loadbalancer %(lb)s') % {'lb': lb.id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-lb', msg=msg)
|
||||||
|
return stats
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def _handle_subnet_gw_change(self, *args, **kwargs):
|
||||||
|
# As the Edge appliance doesn't use DHCP, we should change the
|
||||||
|
# default gateway here when the subnet GW changes.
|
||||||
|
orig = kwargs['original_subnet']
|
||||||
|
updated = kwargs['subnet']
|
||||||
|
if orig['gateway_ip'] == updated['gateway_ip']:
|
||||||
|
return
|
222
vmware_nsx/services/lbaas/nsx_v3/member_mgr.py
Normal file
222
vmware_nsx/services/lbaas/nsx_v3/member_mgr.py
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.common import exceptions as nsx_exc
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EdgeMemberManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgeMemberManager, self).__init__()
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def _get_info_from_fip(self, context, fip):
|
||||||
|
filters = {'floating_ip_address': [fip]}
|
||||||
|
floating_ips = self.core_plugin.get_floatingips(context,
|
||||||
|
filters=filters)
|
||||||
|
if floating_ips:
|
||||||
|
return (floating_ips[0]['fixed_ip_address'],
|
||||||
|
floating_ips[0]['router_id'])
|
||||||
|
else:
|
||||||
|
msg = (_('Cannot get floating ip %(fip)s provided from '
|
||||||
|
'neutron db') % {'fip': fip})
|
||||||
|
raise nsx_exc.BadRequest(resource='lbaas-vip', msg=msg)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def _create_lb_service(self, context, service_client, tenant_id,
|
||||||
|
router_id, nsx_router_id, lb_id, lb_size):
|
||||||
|
router = self.core_plugin.get_router(context, router_id)
|
||||||
|
lb_name = utils.get_name_and_uuid(router['name'],
|
||||||
|
router_id)
|
||||||
|
tags = lb_utils.get_tags(self.core_plugin, router_id,
|
||||||
|
lb_const.LR_ROUTER_TYPE,
|
||||||
|
tenant_id, context.project_name)
|
||||||
|
tags.append({'scope': 'os-lbaas-lb-id', 'tag': lb_id})
|
||||||
|
attachment = {'target_id': nsx_router_id,
|
||||||
|
'target_type': 'LogicalRouter'}
|
||||||
|
lb_service = service_client.create(display_name=lb_name,
|
||||||
|
tags=tags,
|
||||||
|
attachment=attachment,
|
||||||
|
size=lb_size)
|
||||||
|
return lb_service
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def create(self, context, member):
|
||||||
|
pool_id = member.pool.id
|
||||||
|
loadbalancer = member.pool.loadbalancer
|
||||||
|
if not lb_utils.validate_lb_subnet(context, self.core_plugin,
|
||||||
|
member.subnet_id):
|
||||||
|
msg = (_('Cannot add member %(member)s to pool as member subnet '
|
||||||
|
'%(subnet)s is neither public nor connected to router') %
|
||||||
|
{'member': member.id, 'subnet': member.subnet_id})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-subnet', msg=msg)
|
||||||
|
|
||||||
|
pool_client = self.core_plugin.nsxlib.load_balancer.pool
|
||||||
|
service_client = self.core_plugin.nsxlib.load_balancer.service
|
||||||
|
pool_members = self.lbv2_driver.plugin.get_pool_members(
|
||||||
|
context, pool_id)
|
||||||
|
|
||||||
|
network = lb_utils.get_network_from_subnet(
|
||||||
|
context, self.core_plugin, member.subnet_id)
|
||||||
|
if network.get('router:external'):
|
||||||
|
router_id, fixed_ip = self._get_info_from_fip(
|
||||||
|
context, member.address)
|
||||||
|
else:
|
||||||
|
router_id = lb_utils.get_router_from_network(
|
||||||
|
context, self.core_plugin, member.subnet_id)
|
||||||
|
fixed_ip = member.address
|
||||||
|
|
||||||
|
binding = nsx_db.get_nsx_lbaas_pool_binding(context.session,
|
||||||
|
loadbalancer.id, pool_id)
|
||||||
|
if binding:
|
||||||
|
vs_id = binding['lb_vs_id']
|
||||||
|
lb_pool_id = binding['lb_pool_id']
|
||||||
|
|
||||||
|
if 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(
|
||||||
|
nsx_router_id)
|
||||||
|
if not lb_service:
|
||||||
|
lb_size = lb_utils.get_lb_flavor_size(
|
||||||
|
self.flavor_plugin, context, loadbalancer.flavor_id)
|
||||||
|
lb_service = self._create_lb_service(
|
||||||
|
context, service_client, member.tenant_id,
|
||||||
|
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,
|
||||||
|
nsx_router_id, loadbalancer.vip_address)
|
||||||
|
try:
|
||||||
|
service_client.add_virtual_server_to_service(
|
||||||
|
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') %
|
||||||
|
{'vs': vs_id, 'service': lb_service_id})
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-member',
|
||||||
|
msg=msg)
|
||||||
|
else:
|
||||||
|
msg = (_('Failed to get lb service to attach virtual '
|
||||||
|
'server %(vs)s for member %(member)s') %
|
||||||
|
{'vs': vs_id, 'member': member['id']})
|
||||||
|
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||||
|
|
||||||
|
lb_pool = pool_client.get(lb_pool_id)
|
||||||
|
old_m = lb_pool.get('members', None)
|
||||||
|
new_m = [{'display_name': member.name,
|
||||||
|
'ip_address': fixed_ip,
|
||||||
|
'port': member.protocol_port,
|
||||||
|
'weight': member.weight}]
|
||||||
|
members = (old_m + new_m) if old_m else new_m
|
||||||
|
pool_client.update_pool_with_members(lb_pool_id, members)
|
||||||
|
else:
|
||||||
|
msg = (_('Failed to get pool binding to add member %s') %
|
||||||
|
member['id'])
|
||||||
|
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||||
|
|
||||||
|
self.lbv2_driver.member.successful_completion(context, member)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def update(self, context, old_member, new_member):
|
||||||
|
try:
|
||||||
|
self.lbv2_driver.member.successful_completion(
|
||||||
|
context, new_member)
|
||||||
|
|
||||||
|
except nsx_exc.NsxPluginException:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
self.lbv2_driver.member.failed_completion(
|
||||||
|
context, new_member)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
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)
|
||||||
|
try:
|
||||||
|
lb_pool = pool_client.get(lb_pool_id)
|
||||||
|
network = lb_utils.get_network_from_subnet(
|
||||||
|
context, self.core_plugin, member.subnet_id)
|
||||||
|
if network.get('router:external'):
|
||||||
|
fixed_ip, router_id = self._get_info_from_fip(
|
||||||
|
context, member.address)
|
||||||
|
else:
|
||||||
|
fixed_ip = member.address
|
||||||
|
if 'members' in lb_pool:
|
||||||
|
m_list = lb_pool['members']
|
||||||
|
members = [m for m in m_list
|
||||||
|
if m['ip_address'] != fixed_ip]
|
||||||
|
pool_client.update_pool_with_members(lb_pool_id, members)
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.member.failed_completion(context, member)
|
||||||
|
msg = _('Failed to remove member from pool on NSX backend')
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-member', msg=msg)
|
||||||
|
self.lbv2_driver.member.successful_completion(
|
||||||
|
context, member, delete=True)
|
115
vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py
Normal file
115
vmware_nsx/services/lbaas/nsx_v3/pool_mgr.py
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
# Copyright 2017 VMware, 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.
|
||||||
|
|
||||||
|
from neutron_lib import exceptions as n_exc
|
||||||
|
from oslo_log import helpers as log_helpers
|
||||||
|
from oslo_log import log as logging
|
||||||
|
from oslo_utils import excutils
|
||||||
|
|
||||||
|
from vmware_nsx._i18n import _
|
||||||
|
from vmware_nsx.common import exceptions as nsx_exc
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas import lb_const
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
|
||||||
|
from vmware_nsxlib.v3 import utils
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class EdgePoolManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def __init__(self):
|
||||||
|
super(EdgePoolManager, self).__init__()
|
||||||
|
|
||||||
|
@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
|
||||||
|
pool_name = utils.get_name_and_uuid(pool.name, pool.id)
|
||||||
|
tags = lb_utils.get_tags(self.core_plugin, pool.id,
|
||||||
|
lb_const.LB_POOL_TYPE, pool.tenant_id,
|
||||||
|
context.project_name)
|
||||||
|
try:
|
||||||
|
lb_pool = pool_client.create(display_name=pool_name,
|
||||||
|
tags=tags,
|
||||||
|
algorithm=pool.lb_algorithm)
|
||||||
|
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)
|
||||||
|
|
||||||
|
binding = nsx_db.get_nsx_lbaas_listener_binding(
|
||||||
|
context.session, lb_id, listener_id)
|
||||||
|
if binding:
|
||||||
|
vs_id = binding['lb_vs_id']
|
||||||
|
try:
|
||||||
|
vs_client.update(vs_id, pool_id=lb_pool['id'])
|
||||||
|
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)
|
||||||
|
else:
|
||||||
|
msg = (_("Couldn't find binding on the listener: %s") %
|
||||||
|
listener_id)
|
||||||
|
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||||
|
self.lbv2_driver.pool.successful_completion(context, pool)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def update(self, context, old_pool, new_pool):
|
||||||
|
try:
|
||||||
|
self.lbv2_driver.pool.successful_completion(context, new_pool)
|
||||||
|
except Exception:
|
||||||
|
with excutils.save_and_reraise_exception():
|
||||||
|
self.lbv2_driver.pool.failed_completion(context, new_pool)
|
||||||
|
|
||||||
|
@log_helpers.log_method_call
|
||||||
|
def delete(self, context, pool):
|
||||||
|
lb_id = pool.loadbalancer_id
|
||||||
|
pool_client = self.core_plugin.nsxlib.load_balancer.pool
|
||||||
|
vs_client = self.core_plugin.nsxlib.load_balancer.virtual_server
|
||||||
|
|
||||||
|
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']
|
||||||
|
try:
|
||||||
|
vs_client.update(vs_id, pool_id='')
|
||||||
|
except nsxlib_exc.ManagerError:
|
||||||
|
self.lbv2_driver.pool.failed_completion(context, pool)
|
||||||
|
msg = _('Failed to remove lb pool %(pool)s from virtual '
|
||||||
|
'server %(vs)s') % {'pool': lb_pool_id,
|
||||||
|
'vs': vs_id}
|
||||||
|
raise n_exc.BadRequest(resource='lbaas-pool', msg=msg)
|
||||||
|
try:
|
||||||
|
pool_client.delete(lb_pool_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)
|
||||||
|
nsx_db.delete_nsx_lbaas_pool_binding(context.session,
|
||||||
|
lb_id, pool.id)
|
||||||
|
|
||||||
|
self.lbv2_driver.pool.successful_completion(
|
||||||
|
context, pool, delete=True)
|
0
vmware_nsx/tests/unit/services/lbaas/__init__.py
Normal file
0
vmware_nsx/tests/unit/services/lbaas/__init__.py
Normal file
519
vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py
Normal file
519
vmware_nsx/tests/unit/services/lbaas/test_nsxv3_driver.py
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
# Copyright (c) 2017 VMware, Inc.
|
||||||
|
#
|
||||||
|
# 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.tests import base
|
||||||
|
from neutron_lbaas.services.loadbalancer import data_models as lb_models
|
||||||
|
from neutron_lib import context
|
||||||
|
|
||||||
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.services.lbaas import base_mgr
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_driver_v2
|
||||||
|
from vmware_nsx.services.lbaas.nsx_v3 import lb_utils
|
||||||
|
|
||||||
|
|
||||||
|
LB_VIP = '10.0.0.10'
|
||||||
|
LB_ROUTER_ID = 'router-x'
|
||||||
|
LB_ID = 'xxx-xxx'
|
||||||
|
LB_TENANT_ID = 'yyy-yyy'
|
||||||
|
LB_SERVICE_ID = 'service-1'
|
||||||
|
LB_BINDING = {'loadbalancer_id': LB_ID,
|
||||||
|
'lb_service_id': LB_SERVICE_ID,
|
||||||
|
'lb_router_id': LB_ROUTER_ID,
|
||||||
|
'vip_address': LB_VIP}
|
||||||
|
LB_NETWORK = {'router:external': False,
|
||||||
|
'id': 'xxxxx',
|
||||||
|
'name': 'network-1'}
|
||||||
|
LISTENER_ID = 'listener-x'
|
||||||
|
APP_PROFILE_ID = 'appp-x'
|
||||||
|
LB_VS_ID = 'vs-x'
|
||||||
|
LB_APP_PROFILE = {
|
||||||
|
"resource_type": "LbHttpProfile",
|
||||||
|
"description": "my http profile",
|
||||||
|
"id": APP_PROFILE_ID,
|
||||||
|
"display_name": "httpprofile1",
|
||||||
|
"ntlm": False,
|
||||||
|
"request_header_size": 1024,
|
||||||
|
"http_redirect_to_https": False,
|
||||||
|
"idle_timeout": 1800,
|
||||||
|
"x_forwarded_for": "INSERT",
|
||||||
|
}
|
||||||
|
LISTENER_BINDING = {'loadbalancer_id': LB_ID,
|
||||||
|
'listener_id': LISTENER_ID,
|
||||||
|
'app_profile_id': APP_PROFILE_ID,
|
||||||
|
'lb_vs_id': LB_VS_ID}
|
||||||
|
POOL_ID = 'ppp-qqq'
|
||||||
|
LB_POOL_ID = 'pool-xx'
|
||||||
|
LB_POOL = {
|
||||||
|
"display_name": "httppool1",
|
||||||
|
"description": "my http pool",
|
||||||
|
"id": LB_POOL_ID,
|
||||||
|
"algorithm": "ROUND_ROBIN",
|
||||||
|
}
|
||||||
|
POOL_BINDING = {'loadbalancer_id': LB_ID,
|
||||||
|
'pool_id': POOL_ID,
|
||||||
|
'lb_pool_id': LB_POOL_ID,
|
||||||
|
'lb_vs_id': LB_VS_ID}
|
||||||
|
MEMBER_ID = 'mmm-mmm'
|
||||||
|
MEMBER_ADDRESS = '10.0.0.200'
|
||||||
|
LB_MEMBER = {'display_name': 'member-' + MEMBER_ID,
|
||||||
|
'weight': 1, 'ip_address': MEMBER_ADDRESS, 'port': 80}
|
||||||
|
LB_POOL_WITH_MEMBER = {
|
||||||
|
"display_name": "httppool1",
|
||||||
|
"description": "my http pool",
|
||||||
|
"id": LB_POOL_ID,
|
||||||
|
"algorithm": "ROUND_ROBIN",
|
||||||
|
"members": [
|
||||||
|
{
|
||||||
|
"display_name": "http-member1",
|
||||||
|
"ip_address": MEMBER_ADDRESS,
|
||||||
|
"port": "80",
|
||||||
|
"weight": "1",
|
||||||
|
"admin_state": "ENABLED"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
HM_ID = 'hhh-mmm'
|
||||||
|
LB_MONITOR_ID = 'mmm-ddd'
|
||||||
|
|
||||||
|
HM_BINDING = {'loadbalancer_id': LB_ID,
|
||||||
|
'pool_id': POOL_ID,
|
||||||
|
'hm_id': HM_ID,
|
||||||
|
'lb_monitor_id': LB_MONITOR_ID,
|
||||||
|
'lb_pool_id': LB_POOL_ID}
|
||||||
|
|
||||||
|
|
||||||
|
class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
||||||
|
def _tested_entity(self):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(BaseTestEdgeLbaasV2, self).setUp()
|
||||||
|
|
||||||
|
self.context = context.get_admin_context()
|
||||||
|
self.edge_driver = lb_driver_v2.EdgeLoadbalancerDriverV2()
|
||||||
|
|
||||||
|
self.lbv2_driver = mock.Mock()
|
||||||
|
self.core_plugin = mock.Mock()
|
||||||
|
base_mgr.LoadbalancerBaseManager._lbv2_driver = self.lbv2_driver
|
||||||
|
base_mgr.LoadbalancerBaseManager._core_plugin = self.core_plugin
|
||||||
|
self._patch_lb_plugin(self.lbv2_driver, self._tested_entity)
|
||||||
|
self._patch_nsxlib_lb_clients(self.core_plugin)
|
||||||
|
|
||||||
|
self.lb = lb_models.LoadBalancer(LB_ID, LB_TENANT_ID, 'lb1', '',
|
||||||
|
'some-subnet', 'port-id', LB_VIP)
|
||||||
|
self.listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1', '', None, LB_ID,
|
||||||
|
'HTTP', protocol_port=80,
|
||||||
|
loadbalancer=self.lb)
|
||||||
|
self.pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
|
||||||
|
None, 'HTTP', 'ROUND_ROBIN',
|
||||||
|
loadbalancer_id=LB_ID,
|
||||||
|
listener=self.listener,
|
||||||
|
listeners=[self.listener],
|
||||||
|
loadbalancer=self.lb)
|
||||||
|
self.member = lb_models.Member(MEMBER_ID, LB_TENANT_ID, POOL_ID,
|
||||||
|
MEMBER_ADDRESS, 80, 1, pool=self.pool,
|
||||||
|
name='member-mmm-mmm')
|
||||||
|
self.hm = lb_models.HealthMonitor(HM_ID, LB_TENANT_ID, 'PING', 3, 3,
|
||||||
|
1, pool=self.pool, name='hm1')
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self._unpatch_lb_plugin(self.lbv2_driver, self._tested_entity)
|
||||||
|
super(BaseTestEdgeLbaasV2, self).tearDown()
|
||||||
|
|
||||||
|
def _patch_lb_plugin(self, lb_plugin, manager):
|
||||||
|
self.real_manager = getattr(lb_plugin, manager)
|
||||||
|
lb_manager = mock.patch.object(lb_plugin, manager).start()
|
||||||
|
mock.patch.object(lb_manager, 'create').start()
|
||||||
|
mock.patch.object(lb_manager, 'update').start()
|
||||||
|
mock.patch.object(lb_manager, 'delete').start()
|
||||||
|
mock.patch.object(lb_manager, 'successful_completion').start()
|
||||||
|
|
||||||
|
def _patch_nsxlib_lb_clients(self, core_plugin):
|
||||||
|
nsxlib = mock.patch.object(core_plugin, 'nsxlib').start()
|
||||||
|
load_balancer = mock.patch.object(nsxlib, 'load_balancer').start()
|
||||||
|
self.service_client = mock.patch.object(load_balancer,
|
||||||
|
'service').start()
|
||||||
|
self.app_client = mock.patch.object(load_balancer,
|
||||||
|
'application_profile').start()
|
||||||
|
self.vs_client = mock.patch.object(load_balancer,
|
||||||
|
'virtual_server').start()
|
||||||
|
self.pool_client = mock.patch.object(load_balancer,
|
||||||
|
'pool').start()
|
||||||
|
self.monitor_client = mock.patch.object(load_balancer,
|
||||||
|
'monitor').start()
|
||||||
|
|
||||||
|
def _unpatch_lb_plugin(self, lb_plugin, manager):
|
||||||
|
setattr(lb_plugin, manager, self.real_manager)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestEdgeLbaasV2Loadbalancer, self).setUp()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tested_entity(self):
|
||||||
|
return 'load_balancer'
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
with mock.patch.object(lb_utils, 'validate_lb_subnet'
|
||||||
|
) as mock_validate_lb_subnet:
|
||||||
|
mock_validate_lb_subnet.return_value = True
|
||||||
|
|
||||||
|
self.edge_driver.loadbalancer.create(self.context, self.lb)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.lb)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
new_lb = lb_models.LoadBalancer(LB_ID, 'yyy-yyy', 'lb1-new',
|
||||||
|
'new-description', 'some-subnet',
|
||||||
|
'port-id', LB_VIP)
|
||||||
|
|
||||||
|
self.edge_driver.loadbalancer.update(self.context, self.lb, new_lb)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context, new_lb)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
self.edge_driver.loadbalancer.delete(self.context, self.lb)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.load_balancer.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.lb,
|
||||||
|
delete=True)
|
||||||
|
|
||||||
|
def test_stats(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_refresh(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestEdgeLbaasV2Listener, self).setUp()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tested_entity(self):
|
||||||
|
return 'listener'
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
with mock.patch.object(self.app_client, 'create'
|
||||||
|
) as mock_create_app_profile, \
|
||||||
|
mock.patch.object(self.vs_client, 'create'
|
||||||
|
) as mock_create_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}
|
||||||
|
|
||||||
|
self.edge_driver.listener.create(self.context, self.listener)
|
||||||
|
|
||||||
|
mock_add_listener_binding.assert_called_with(
|
||||||
|
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
|
||||||
|
LB_VS_ID)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.listener.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.listener)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
'listener1-new', 'new-description',
|
||||||
|
None, LB_ID, protocol_port=8000,
|
||||||
|
loadbalancer=self.lb)
|
||||||
|
|
||||||
|
self.edge_driver.listener.update(self.context, self.listener,
|
||||||
|
new_listener)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.listener.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
new_listener)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
with mock.patch.object(nsx_db, 'get_nsx_lbaas_listener_binding'
|
||||||
|
) as mock_get_listener_binding, \
|
||||||
|
mock.patch.object(self.app_client, 'delete'
|
||||||
|
) as mock_delete_app_profile, \
|
||||||
|
mock.patch.object(self.vs_client, 'delete'
|
||||||
|
) as mock_delete_virtual_server, \
|
||||||
|
mock.patch.object(nsx_db, 'delete_nsx_lbaas_listener_binding',
|
||||||
|
) as mock_delete_listener_binding:
|
||||||
|
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||||
|
|
||||||
|
self.edge_driver.listener.delete(self.context, self.listener)
|
||||||
|
|
||||||
|
mock_delete_virtual_server.assert_called_with(LB_VS_ID)
|
||||||
|
mock_delete_app_profile.assert_called_with(APP_PROFILE_ID)
|
||||||
|
|
||||||
|
mock_delete_listener_binding.assert_called_with(
|
||||||
|
self.context.session, LB_ID, LISTENER_ID)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.listener.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.listener,
|
||||||
|
delete=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestEdgeLbaasV2Pool, self).setUp()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tested_entity(self):
|
||||||
|
return 'pool'
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
with mock.patch.object(self.pool_client, 'create'
|
||||||
|
) as mock_create_pool, \
|
||||||
|
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_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)
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.pool.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.pool)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
new_pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool-name', '',
|
||||||
|
None, 'HTTP', 'LEAST_CONNECTIONS',
|
||||||
|
listener=self.listener)
|
||||||
|
self.edge_driver.pool.update(self.context, self.pool, new_pool)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.pool.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context, new_pool)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
with mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||||
|
) as mock_get_pool_binding, \
|
||||||
|
mock.patch.object(self.vs_client, 'update', return_value=None
|
||||||
|
) as mock_update_virtual_server, \
|
||||||
|
mock.patch.object(self.pool_client, 'delete'
|
||||||
|
) as mock_delete_pool, \
|
||||||
|
mock.patch.object(nsx_db, 'delete_nsx_lbaas_pool_binding'
|
||||||
|
) as mock_delete_pool_binding:
|
||||||
|
mock_get_pool_binding.return_value = POOL_BINDING
|
||||||
|
|
||||||
|
self.edge_driver.pool.delete(self.context, self.pool)
|
||||||
|
|
||||||
|
mock_update_virtual_server.assert_called_with(LB_VS_ID,
|
||||||
|
pool_id='')
|
||||||
|
mock_delete_pool.assert_called_with(LB_POOL_ID)
|
||||||
|
mock_delete_pool_binding.assert_called_with(
|
||||||
|
self.context.session, LB_ID, POOL_ID)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.pool.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.pool,
|
||||||
|
delete=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestEdgeLbaasV2Member, self).setUp()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tested_entity(self):
|
||||||
|
return 'member'
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
with mock.patch.object(lb_utils, 'validate_lb_subnet'
|
||||||
|
) as mock_validate_lb_subnet, \
|
||||||
|
mock.patch.object(self.lbv2_driver.plugin, 'get_pool_members'
|
||||||
|
) as mock_get_pool_members, \
|
||||||
|
mock.patch.object(lb_utils, 'get_network_from_subnet'
|
||||||
|
) as mock_get_network, \
|
||||||
|
mock.patch.object(lb_utils, 'get_router_from_network'
|
||||||
|
) 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_router_id'
|
||||||
|
) as mock_get_nsx_router_id, \
|
||||||
|
mock.patch.object(self.service_client, 'get_router_lb_service'
|
||||||
|
) as mock_get_lb_service, \
|
||||||
|
mock.patch.object(nsx_db, 'add_nsx_lbaas_loadbalancer_binding'
|
||||||
|
) as mock_add_loadbalancer_bidning, \
|
||||||
|
mock.patch.object(self.service_client,
|
||||||
|
'add_virtual_server_to_service'
|
||||||
|
) as mock_add_vs_to_service, \
|
||||||
|
mock.patch.object(self.pool_client, 'get'
|
||||||
|
) as mock_get_pool, \
|
||||||
|
mock.patch.object(self.pool_client, 'update_pool_with_members'
|
||||||
|
) as mock_update_pool_with_members:
|
||||||
|
mock_validate_lb_subnet.return_value = True
|
||||||
|
mock_get_pool_members.return_value = [self.member]
|
||||||
|
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_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
|
||||||
|
|
||||||
|
self.edge_driver.member.create(self.context, self.member)
|
||||||
|
|
||||||
|
mock_add_loadbalancer_bidning.assert_called_with(
|
||||||
|
self.context.session, LB_ID, LB_SERVICE_ID, LB_ROUTER_ID,
|
||||||
|
LB_VIP)
|
||||||
|
mock_add_vs_to_service.assert_called_with(LB_SERVICE_ID, LB_VS_ID)
|
||||||
|
mock_update_pool_with_members.assert_called_with(LB_POOL_ID,
|
||||||
|
[LB_MEMBER])
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.member.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.member)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
new_member = lb_models.Member(MEMBER_ID, LB_TENANT_ID, POOL_ID,
|
||||||
|
MEMBER_ADDRESS, 80, 1, pool=self.pool,
|
||||||
|
name='member-nnn-nnn')
|
||||||
|
self.edge_driver.member.update(self.context, self.pool, new_member)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.member.successful_completion)
|
||||||
|
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'
|
||||||
|
) 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 = (
|
||||||
|
self.lbv2_driver.member.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.member,
|
||||||
|
delete=True)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEdgeLbaasV2HealthMonitor(BaseTestEdgeLbaasV2):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestEdgeLbaasV2HealthMonitor, self).setUp()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _tested_entity(self):
|
||||||
|
return 'health_monitor'
|
||||||
|
|
||||||
|
def test_create(self):
|
||||||
|
with mock.patch.object(self.monitor_client, 'create'
|
||||||
|
) as mock_create_monitor, \
|
||||||
|
mock.patch.object(nsx_db, 'get_nsx_lbaas_pool_binding'
|
||||||
|
) as mock_get_pool_binding, \
|
||||||
|
mock.patch.object(self.pool_client, 'add_monitor_to_pool'
|
||||||
|
) as mock_add_monitor_to_pool, \
|
||||||
|
mock.patch.object(nsx_db, 'add_nsx_lbaas_monitor_binding'
|
||||||
|
) as mock_add_monitor_binding:
|
||||||
|
mock_create_monitor.return_value = {'id': LB_MONITOR_ID}
|
||||||
|
mock_get_pool_binding.return_value = POOL_BINDING
|
||||||
|
|
||||||
|
self.edge_driver.healthmonitor.create(self.context, self.hm)
|
||||||
|
|
||||||
|
mock_add_monitor_to_pool.assert_called_with(LB_POOL_ID,
|
||||||
|
LB_MONITOR_ID)
|
||||||
|
mock_add_monitor_binding.assert_called_with(
|
||||||
|
self.context.session, LB_ID, POOL_ID, HM_ID, LB_MONITOR_ID,
|
||||||
|
LB_POOL_ID)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.hm)
|
||||||
|
|
||||||
|
def test_update(self):
|
||||||
|
new_hm = lb_models.HealthMonitor(HM_ID, LB_TENANT_ID, 'PING', 3, 3,
|
||||||
|
3, pool=self.pool)
|
||||||
|
self.edge_driver.healthmonitor.update(self.context, self.pool, new_hm)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context, new_hm)
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
with mock.patch.object(nsx_db, 'get_nsx_lbaas_monitor_binding'
|
||||||
|
) as mock_get_monitor_binding, \
|
||||||
|
mock.patch.object(self.pool_client, 'remove_monitor_from_pool'
|
||||||
|
) as mock_remove_monitor_from_pool, \
|
||||||
|
mock.patch.object(self.monitor_client, 'delete'
|
||||||
|
) as mock_delete_monitor, \
|
||||||
|
mock.patch.object(nsx_db, 'delete_nsx_lbaas_monitor_binding'
|
||||||
|
) as mock_delete_monitor_binding:
|
||||||
|
mock_get_monitor_binding.return_value = HM_BINDING
|
||||||
|
|
||||||
|
self.edge_driver.healthmonitor.delete(self.context, self.hm)
|
||||||
|
|
||||||
|
mock_remove_monitor_from_pool.assert_called_with(LB_POOL_ID,
|
||||||
|
LB_MONITOR_ID)
|
||||||
|
mock_delete_monitor.assert_called_with(LB_MONITOR_ID)
|
||||||
|
mock_delete_monitor_binding.assert_called_with(
|
||||||
|
self.context.session, LB_ID, POOL_ID, HM_ID)
|
||||||
|
|
||||||
|
mock_successful_completion = (
|
||||||
|
self.lbv2_driver.health_monitor.successful_completion)
|
||||||
|
mock_successful_completion.assert_called_with(self.context,
|
||||||
|
self.hm,
|
||||||
|
delete=True)
|
Loading…
Reference in New Issue
Block a user