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):
|
||||
return (session.query(nsx_models.NsxCertificateRepository).
|
||||
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)
|
||||
certificate = sa.Column(sa.String(9216), 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 utils as v3_utils
|
||||
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.nsx_v3 import driver as qos_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.nsxlib = v3_utils.get_nsxlib_wrapper()
|
||||
self.lbv2_driver = self._init_lbv2_driver()
|
||||
# reinitialize the cluster upon fork for api workers to ensure each
|
||||
# process has its own keepalive loops + state
|
||||
registry.subscribe(
|
||||
@ -269,6 +271,18 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# Bind FWaaS callbacks to the driver
|
||||
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):
|
||||
# availability zones are supported only with native dhcp
|
||||
# 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'])
|
||||
|
||||
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:
|
||||
nsx_rpc.handle_router_metadata_access(self, context, router_id,
|
||||
interface=None)
|
||||
|
@ -15,11 +15,15 @@
|
||||
|
||||
from neutron_lib.plugins import constants as plugin_const
|
||||
from neutron_lib.plugins import directory
|
||||
from oslo_log import log as logging
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LoadbalancerBaseManager(object):
|
||||
_lbv2_driver = None
|
||||
_core_plugin = None
|
||||
_flavor_plugin = None
|
||||
|
||||
def __init__(self):
|
||||
super(LoadbalancerBaseManager, self).__init__()
|
||||
@ -45,6 +49,14 @@ class LoadbalancerBaseManager(object):
|
||||
|
||||
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):
|
||||
|
||||
@ -55,3 +67,9 @@ class EdgeLoadbalancerBaseManager(LoadbalancerBaseManager):
|
||||
@property
|
||||
def vcns(self):
|
||||
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_CONTAINS = 'CONTAINS'
|
||||
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