NSX|V+V3: Octavia driver
Implementing the Octavia support for NSX-V & NSX-T. Follow up patches will handle the TVD plugin, Status updates, and migration. Since Octavia is not (yet?) in the requirements, using a hack to allow unittests to be skipped. Co-Authored-by: Adit Sarfaty <asarfaty@vmware.com> Change-Id: Iadb24e7eadcab658faf3e646cc528c2a8a6976e5
This commit is contained in:
parent
759f015542
commit
83d9b3abdd
@ -131,3 +131,4 @@
|
||||
- openstack/neutron-dynamic-routing
|
||||
- openstack/neutron-vpnaas
|
||||
- openstack/tap-as-a-service
|
||||
- openstack/octavia
|
||||
|
@ -30,7 +30,7 @@ function _nsxv_ini_set {
|
||||
}
|
||||
|
||||
function install_neutron_projects {
|
||||
pkg_list="networking-l2gw networking-sfc neutron-lbaas neutron-fwaas neutron-dynamic-routing neutron-vpnaas vmware-nsxlib"
|
||||
pkg_list="networking-l2gw networking-sfc neutron-lbaas neutron-fwaas neutron-dynamic-routing neutron-vpnaas octavia vmware-nsxlib"
|
||||
for pkg in `echo $pkg_list`
|
||||
do
|
||||
if is_plugin_enabled $pkg; then
|
||||
|
@ -238,6 +238,30 @@ Add neutron-vpnaas repo as an external repository and configure following flags
|
||||
[DEFAULT]
|
||||
api_extensions_path = $DEST/neutron-vpnaas/neutron_vpnaas/extensions
|
||||
|
||||
Octavia
|
||||
~~~~~~~
|
||||
|
||||
Add octavia repo as an external repository and configure following flags in ``local.conf``::
|
||||
|
||||
[[local|localrc]]
|
||||
OCTAVIA_NODE=api
|
||||
DISABLE_AMP_IMAGE_BUILD=True
|
||||
enable_plugin octavia $GIT_BASE/openstack/octavia.git
|
||||
enable_plugin octavia-dashboard $GIT_BASE/openstack/octavia-dashboard
|
||||
enable_service octavia
|
||||
enable_service o-api
|
||||
|
||||
[[post-config|$OCTAVIA_CONF]]
|
||||
[DEFAULT]
|
||||
verbose = True
|
||||
debug = True
|
||||
|
||||
[api_settings]
|
||||
default_provider_driver=vmwareedge
|
||||
enabled_provider_drivers=vmwareedge:NSX
|
||||
|
||||
[oslo_messaging]
|
||||
topic=vmwarensxv_edge_lb
|
||||
|
||||
NSX-TVD
|
||||
-------
|
||||
|
@ -55,6 +55,7 @@ munch==2.1.0
|
||||
netaddr==0.7.18
|
||||
netifaces==0.10.4
|
||||
neutron-lib==1.18.0
|
||||
octavia==3.0.0
|
||||
openstackdocstheme==1.18.1
|
||||
openstacksdk==0.11.2
|
||||
os-client-config==1.28.0
|
||||
|
6
releasenotes/notes/octavia-support-2fa83d464dbc4e52.yaml
Normal file
6
releasenotes/notes/octavia-support-2fa83d464dbc4e52.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
prelude: >
|
||||
Support Octavia loadbalancer support in NSXv and NSXv3 plugins.
|
||||
features:
|
||||
- |
|
||||
NSXv and NSXv3 plugins now support Octavia loadbalancer.
|
@ -38,6 +38,7 @@ neutron-fwaas>=12.0.0 # Apache-2.0
|
||||
neutron-vpnaas>=12.0.0 # Apache-2.0
|
||||
neutron-dynamic-routing>=12.0.0 # Apache-2.0
|
||||
vmware-nsxlib>=12.0.0 # Apache-2.0
|
||||
#octavia>=3.0.0 # Apache-2.0
|
||||
|
||||
# The comment below indicates this project repo is current with neutron-lib
|
||||
# and should receive neutron-lib consumption patches as they are released
|
||||
|
@ -94,7 +94,8 @@ vmware_nsx.neutron.nsxv3.housekeeper.jobs =
|
||||
orphaned_logical_router = vmware_nsx.plugins.nsx_v3.housekeeper.orphaned_logical_router:OrphanedLogicalRouterJob
|
||||
orphaned_firewall_section = vmware_nsx.plugins.nsx_v3.housekeeper.orphaned_firewall_section:OrphanedFirewallSectionJob
|
||||
mismatch_logical_port = vmware_nsx.plugins.nsx_v3.housekeeper.mismatch_logical_port:MismatchLogicalportJob
|
||||
|
||||
octavia.api.drivers =
|
||||
vmwareedge = vmware_nsx.services.lbaas.octavia.octavia_driver:NSXOctaviaDriver
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
build-dir = doc/build
|
||||
|
1
tox.ini
1
tox.ini
@ -34,6 +34,7 @@ commands =
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/neutron-fwaas#egg=neutron_fwaas"
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/neutron-dynamic-routing#egg=neutron_dynamic_routing"
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/neutron-vpnaas#egg=neutron_vpnaas"
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/octavia#egg=octavia"
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/vmware-nsxlib#egg=vmware_nsxlib"
|
||||
pip install -q -e "git+https://git.openstack.org/openstack/neutron#egg=neutron"
|
||||
|
||||
|
@ -262,6 +262,10 @@ nsx_common_opts = [
|
||||
default=[],
|
||||
help=_("(Optional) List of email addresses for "
|
||||
"notifications.")),
|
||||
cfg.IntOpt('octavia_stats_interval',
|
||||
default=10,
|
||||
help=_("Interval in seconds for Octavia statistics reporting. "
|
||||
"0 means no reporting")),
|
||||
]
|
||||
|
||||
nsx_v3_and_p = [
|
||||
|
@ -559,6 +559,10 @@ def get_nsx_lbaas_loadbalancer_binding(session, loadbalancer_id):
|
||||
return
|
||||
|
||||
|
||||
def get_nsx_lbaas_loadbalancer_bindings(session):
|
||||
return session.query(nsx_models.NsxLbaasLoadbalancer).all()
|
||||
|
||||
|
||||
def get_nsx_lbaas_loadbalancer_binding_by_service(session, lb_service_id):
|
||||
return session.query(
|
||||
nsx_models.NsxLbaasLoadbalancer).filter_by(
|
||||
@ -591,7 +595,8 @@ def get_nsx_lbaas_listener_binding(session, loadbalancer_id, listener_id):
|
||||
return
|
||||
|
||||
|
||||
def get_nsx_lbaas_listener_binding_by_vs(session, loadbalancer_id, lb_vs_id):
|
||||
def get_nsx_lbaas_listener_binding_by_lb_and_vs(session, loadbalancer_id,
|
||||
lb_vs_id):
|
||||
try:
|
||||
return session.query(
|
||||
nsx_models.NsxLbaasListener).filter_by(
|
||||
@ -601,6 +606,15 @@ def get_nsx_lbaas_listener_binding_by_vs(session, loadbalancer_id, lb_vs_id):
|
||||
return
|
||||
|
||||
|
||||
def get_nsx_lbaas_listener_binding_by_vs_id(session, lb_vs_id):
|
||||
try:
|
||||
return session.query(
|
||||
nsx_models.NsxLbaasListener).filter_by(
|
||||
lb_vs_id=lb_vs_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,
|
||||
|
@ -1 +1 @@
|
||||
0dbeda408e41
|
||||
fc6308289aca
|
||||
|
@ -0,0 +1,51 @@
|
||||
# Copyright 2018 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.
|
||||
|
||||
"""lbaas_no_foreign_key
|
||||
|
||||
Revision ID: fc6308289aca
|
||||
Revises: 0dbeda408e41
|
||||
Create Date: 2018-06-04 13:47:09.450116
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
from sqlalchemy.engine import reflection
|
||||
|
||||
from neutron.db import migration
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'fc6308289aca'
|
||||
down_revision = '0dbeda408e41'
|
||||
depends_on = ('717f7f63a219')
|
||||
|
||||
|
||||
def upgrade():
|
||||
for table_name in ['nsxv3_lbaas_loadbalancers',
|
||||
'nsxv3_lbaas_listeners',
|
||||
'nsxv3_lbaas_pools',
|
||||
'nsxv3_lbaas_monitors',
|
||||
'nsxv3_lbaas_l7rules',
|
||||
'nsxv3_lbaas_l7policies',
|
||||
'nsxv_lbaas_loadbalancer_bindings',
|
||||
'nsxv_lbaas_listener_bindings',
|
||||
'nsxv_lbaas_pool_bindings',
|
||||
'nsxv_lbaas_monitor_bindings',
|
||||
'nsxv_lbaas_l7policy_bindings']:
|
||||
|
||||
if migration.schema_has_table(table_name):
|
||||
inspector = reflection.Inspector.from_engine(op.get_bind())
|
||||
fk_constraint = inspector.get_foreign_keys(table_name)[0]
|
||||
op.drop_constraint(fk_constraint.get('name'), table_name,
|
||||
type_='foreignkey')
|
@ -399,12 +399,7 @@ class NsxLbaasLoadbalancer(model_base.BASEV2, models.TimestampMixin):
|
||||
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)
|
||||
loadbalancer_id = sa.Column(sa.String(36), 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)
|
||||
@ -414,11 +409,7 @@ 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)
|
||||
listener_id = sa.Column(sa.String(36), primary_key=True)
|
||||
app_profile_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
@ -427,11 +418,7 @@ 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)
|
||||
pool_id = sa.Column(sa.String(36), primary_key=True)
|
||||
lb_pool_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36))
|
||||
|
||||
@ -441,11 +428,7 @@ class NsxLbaasMonitor(model_base.BASEV2, models.TimestampMixin):
|
||||
__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)
|
||||
hm_id = sa.Column(sa.String(36), primary_key=True)
|
||||
lb_monitor_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_pool_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
@ -462,11 +445,7 @@ class NsxLbaasL7Rule(model_base.BASEV2, models.TimestampMixin):
|
||||
__tablename__ = 'nsxv3_lbaas_l7rules'
|
||||
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||
l7policy_id = sa.Column(sa.String(36), primary_key=True)
|
||||
l7rule_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_l7rules.id',
|
||||
name='fk_nsxv3_lbaas_l7rules_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
l7rule_id = sa.Column(sa.String(36), primary_key=True)
|
||||
lb_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
@ -474,11 +453,7 @@ class NsxLbaasL7Rule(model_base.BASEV2, models.TimestampMixin):
|
||||
class NsxLbaasL7Policy(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Stores the mapping between LBaaS l7policy and NSX LB rule"""
|
||||
__tablename__ = 'nsxv3_lbaas_l7policies'
|
||||
l7policy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_l7policies.id',
|
||||
name='fk_nsxv3_lbaas_l7policies_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
l7policy_id = sa.Column(sa.String(36), primary_key=True)
|
||||
lb_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
@ -684,6 +684,15 @@ def add_nsxv_lbaas_loadbalancer_binding(
|
||||
return binding
|
||||
|
||||
|
||||
def get_nsxv_lbaas_loadbalancer_bindings(session, filters=None,
|
||||
like_filters=None):
|
||||
session = db_api.get_reader_session()
|
||||
query = session.query(nsxv_models.NsxvLbaasLoadbalancerBinding)
|
||||
return nsx_db._apply_filters_to_query(
|
||||
query, nsxv_models.NsxvLbaasLoadbalancerBinding, filters,
|
||||
like_filters).all()
|
||||
|
||||
|
||||
def get_nsxv_lbaas_loadbalancer_binding(session, loadbalancer_id):
|
||||
try:
|
||||
return session.query(
|
||||
@ -731,6 +740,15 @@ def del_nsxv_lbaas_listener_binding(session, loadbalancer_id, listener_id):
|
||||
listener_id=listener_id).delete())
|
||||
|
||||
|
||||
def get_nsxv_lbaas_listener_binding_by_vse(session, loadbalancer_id, vse_id):
|
||||
try:
|
||||
return session.query(
|
||||
nsxv_models.NsxvLbaasListenerBinding).filter_by(
|
||||
loadbalancer_id=loadbalancer_id, vse_id=vse_id).one()
|
||||
except exc.NoResultFound:
|
||||
return
|
||||
|
||||
|
||||
def add_nsxv_lbaas_pool_binding(session, loadbalancer_id, pool_id,
|
||||
edge_pool_id):
|
||||
with session.begin(subtransactions=True):
|
||||
|
@ -252,11 +252,7 @@ class NsxvLbaasLoadbalancerBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
|
||||
__tablename__ = 'nsxv_lbaas_loadbalancer_bindings'
|
||||
|
||||
loadbalancer_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_loadbalancers.id',
|
||||
name='fk_lbaas_loadbalancers_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||
edge_id = sa.Column(sa.String(36), nullable=False)
|
||||
edge_fw_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
vip_address = sa.Column(sa.String(36), nullable=False)
|
||||
@ -268,11 +264,7 @@ class NsxvLbaasListenerBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
__tablename__ = 'nsxv_lbaas_listener_bindings'
|
||||
|
||||
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||
listener_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_listeners.id',
|
||||
name='fk_lbaas_listeners_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
listener_id = sa.Column(sa.String(36), primary_key=True)
|
||||
app_profile_id = sa.Column(sa.String(36), nullable=False)
|
||||
vse_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
@ -283,11 +275,7 @@ class NsxvLbaasPoolBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
__tablename__ = 'nsxv_lbaas_pool_bindings'
|
||||
|
||||
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
|
||||
pool_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_pools.id',
|
||||
name='fk_lbaas_pools_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
pool_id = sa.Column(sa.String(36), primary_key=True)
|
||||
edge_pool_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
||||
@ -298,11 +286,7 @@ class NsxvLbaasMonitorBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
|
||||
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_lbaas_healthmonitors_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
hm_id = sa.Column(sa.String(36), primary_key=True)
|
||||
edge_id = sa.Column(sa.String(36), primary_key=True)
|
||||
edge_mon_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
@ -322,11 +306,7 @@ class NsxvLbaasL7PolicyBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
|
||||
__tablename__ = 'nsxv_lbaas_l7policy_bindings'
|
||||
|
||||
policy_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('lbaas_l7policies.id',
|
||||
name='fk_lbaas_l7policies_id',
|
||||
ondelete="CASCADE"),
|
||||
primary_key=True)
|
||||
policy_id = sa.Column(sa.String(36), primary_key=True)
|
||||
edge_id = sa.Column(sa.String(36), nullable=False)
|
||||
edge_app_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
@ -16,7 +16,6 @@ from oslo_log import log as logging
|
||||
|
||||
from neutron_lib import constants as n_consts
|
||||
from neutron_lib.db import api as db_api
|
||||
from neutron_lib.plugins import constants as plugin_const
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
from vmware_nsx.common import exceptions as nsxv_exc
|
||||
@ -26,6 +25,7 @@ from vmware_nsx.plugins.nsx_v.drivers import (
|
||||
abstract_router_driver as router_driver)
|
||||
from vmware_nsx.plugins.nsx_v import plugin as nsx_v
|
||||
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
|
||||
from vmware_nsx.services.lbaas.octavia import constants as oct_const
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -279,9 +279,10 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
|
||||
|
||||
def _check_lb_on_subnet(self, context, subnet_id, router_id):
|
||||
# Check lbaas
|
||||
dev_owner_v1 = 'neutron:' + plugin_const.LOADBALANCER
|
||||
dev_owner_v2 = 'neutron:' + plugin_const.LOADBALANCERV2
|
||||
filters = {'device_owner': [dev_owner_v1, dev_owner_v2],
|
||||
dev_owner_v1 = n_consts.DEVICE_OWNER_LOADBALANCER
|
||||
dev_owner_v2 = n_consts.DEVICE_OWNER_LOADBALANCERV2
|
||||
dev_owner_oct = oct_const.DEVICE_OWNER_OCTAVIA
|
||||
filters = {'device_owner': [dev_owner_v1, dev_owner_v2, dev_owner_oct],
|
||||
'fixed_ips': {'subnet_id': [subnet_id]}}
|
||||
ports = super(nsx_v.NsxVPluginV2, self.plugin).get_ports(
|
||||
context, filters=filters)
|
||||
|
@ -143,6 +143,15 @@ from vmware_nsx.plugins.nsx_v.vshield import securitygroup_utils
|
||||
from vmware_nsx.plugins.nsx_v.vshield import vcns_driver
|
||||
from vmware_nsx.services.flowclassifier.nsx_v import utils as fc_utils
|
||||
from vmware_nsx.services.fwaas.nsx_v import fwaas_callbacks
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import healthmon_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import l7policy_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import l7rule_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import listener_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import loadbalancer_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import member_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v.implementation import pool_mgr
|
||||
from vmware_nsx.services.lbaas.octavia import constants as oct_const
|
||||
from vmware_nsx.services.lbaas.octavia import octavia_listener
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
PORTGROUP_PREFIX = 'dvportgroup'
|
||||
@ -226,6 +235,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
def __init__(self):
|
||||
self._is_sub_plugin = tvd_utils.is_tvd_core_plugin()
|
||||
self.init_is_complete = False
|
||||
self.octavia_listener = None
|
||||
self.octavia_stats_collector = None
|
||||
self.housekeeper = None
|
||||
super(NsxVPluginV2, self).__init__()
|
||||
if self._is_sub_plugin:
|
||||
@ -321,6 +332,10 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Bind QoS notifications
|
||||
qos_driver.register(self)
|
||||
|
||||
registry.subscribe(self.spawn_complete,
|
||||
resources.PROCESS,
|
||||
events.AFTER_SPAWN)
|
||||
|
||||
# subscribe the init complete method last, so it will be called only
|
||||
# if init was successful
|
||||
registry.subscribe(self.init_complete,
|
||||
@ -335,6 +350,16 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
def is_tvd_plugin():
|
||||
return False
|
||||
|
||||
def spawn_complete(self, resource, event, trigger, payload=None):
|
||||
# This method should run only once, but after init_complete
|
||||
if not self.init_is_complete:
|
||||
self.init_complete(None, None, None)
|
||||
|
||||
self.octavia_stats_collector = (
|
||||
octavia_listener.NSXOctaviaStatisticsCollector(
|
||||
self,
|
||||
listener_mgr.stats_getter))
|
||||
|
||||
def init_complete(self, resource, event, trigger, payload=None):
|
||||
with locking.LockManager.get_lock('plugin-init-complete'):
|
||||
if self.init_is_complete:
|
||||
@ -362,6 +387,18 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
hk_readonly=cfg.CONF.nsxv.housekeeping_readonly,
|
||||
hk_readonly_jobs=cfg.CONF.nsxv.housekeeping_readonly_jobs)
|
||||
|
||||
# Init octavia listener and endpoints
|
||||
self.octavia_listener = octavia_listener.NSXOctaviaListener(
|
||||
loadbalancer=loadbalancer_mgr.EdgeLoadBalancerManagerFromDict(
|
||||
self.nsx_v),
|
||||
listener=listener_mgr.EdgeListenerManagerFromDict(self.nsx_v),
|
||||
pool=pool_mgr.EdgePoolManagerFromDict(self.nsx_v),
|
||||
member=member_mgr.EdgeMemberManagerFromDict(self.nsx_v),
|
||||
healthmonitor=healthmon_mgr.EdgeHealthMonitorManagerFromDict(
|
||||
self.nsx_v),
|
||||
l7policy=l7policy_mgr.EdgeL7PolicyManagerFromDict(self.nsx_v),
|
||||
l7rule=l7rule_mgr.EdgeL7RuleManagerFromDict(self.nsx_v))
|
||||
|
||||
self.init_is_complete = True
|
||||
|
||||
def _validate_nsx_version(self):
|
||||
@ -1851,7 +1888,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
|
||||
def _assert_on_lb_port_admin_state(self, port_data, original_port,
|
||||
device_owner):
|
||||
if device_owner == constants.DEVICE_OWNER_LOADBALANCERV2:
|
||||
if device_owner in [constants.DEVICE_OWNER_LOADBALANCERV2,
|
||||
oct_const.DEVICE_OWNER_OCTAVIA]:
|
||||
orig_state = original_port.get("admin_state_up")
|
||||
new_state = port_data.get("admin_state_up")
|
||||
if new_state is not None and (orig_state != new_state) and (
|
||||
|
@ -116,7 +116,16 @@ from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
|
||||
from vmware_nsx.services.fwaas.common import utils as fwaas_utils
|
||||
from vmware_nsx.services.fwaas.nsx_v3 import fwaas_callbacks_v1
|
||||
from vmware_nsx.services.fwaas.nsx_v3 import fwaas_callbacks_v2
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import healthmonitor_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import l7policy_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import l7rule_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import listener_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import loadbalancer_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import member_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import pool_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.v2 import lb_driver_v2
|
||||
from vmware_nsx.services.lbaas.octavia import constants as oct_const
|
||||
from vmware_nsx.services.lbaas.octavia import octavia_listener
|
||||
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
|
||||
@ -211,6 +220,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self.fwaas_callbacks = None
|
||||
self._is_sub_plugin = tvd_utils.is_tvd_core_plugin()
|
||||
self.init_is_complete = False
|
||||
self.octavia_listener = None
|
||||
self.octavia_stats_collector = None
|
||||
nsxlib_utils.set_is_attr_callback(validators.is_attr_set)
|
||||
self._extend_fault_map()
|
||||
if self._is_sub_plugin:
|
||||
@ -293,6 +304,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# Register NSXv3 trunk driver to support trunk extensions
|
||||
self.trunk_driver = trunk_driver.NsxV3TrunkDriver.create(self)
|
||||
|
||||
registry.subscribe(self.spawn_complete,
|
||||
resources.PROCESS,
|
||||
events.AFTER_SPAWN)
|
||||
|
||||
# subscribe the init complete method last, so it will be called only
|
||||
# if init was successful
|
||||
registry.subscribe(self.init_complete,
|
||||
@ -430,6 +445,16 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
def is_tvd_plugin():
|
||||
return False
|
||||
|
||||
def spawn_complete(self, resource, event, trigger, payload=None):
|
||||
# This method should run only once, but after init_complete
|
||||
if not self.init_is_complete:
|
||||
self.init_complete(None, None, None)
|
||||
|
||||
self.octavia_stats_collector = (
|
||||
octavia_listener.NSXOctaviaStatisticsCollector(
|
||||
self,
|
||||
listener_mgr.stats_getter))
|
||||
|
||||
def init_complete(self, resource, event, trigger, payload=None):
|
||||
with locking.LockManager.get_lock('plugin-init-complete'):
|
||||
if self.init_is_complete:
|
||||
@ -451,8 +476,25 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
hk_readonly=cfg.CONF.nsx_v3.housekeeping_readonly,
|
||||
hk_readonly_jobs=cfg.CONF.nsx_v3.housekeeping_readonly_jobs)
|
||||
|
||||
# Init octavia listener and endpoints
|
||||
self._init_octavia()
|
||||
|
||||
self.init_is_complete = True
|
||||
|
||||
def _init_octavia(self):
|
||||
if not self.nsxlib.feature_supported(
|
||||
nsxlib_consts.FEATURE_LOAD_BALANCER):
|
||||
return
|
||||
|
||||
self.octavia_listener = octavia_listener.NSXOctaviaListener(
|
||||
loadbalancer=loadbalancer_mgr.EdgeLoadBalancerManagerFromDict(),
|
||||
listener=listener_mgr.EdgeListenerManagerFromDict(),
|
||||
pool=pool_mgr.EdgePoolManagerFromDict(),
|
||||
member=member_mgr.EdgeMemberManagerFromDict(),
|
||||
healthmonitor=healthmonitor_mgr.EdgeHealthMonitorManagerFromDict(),
|
||||
l7policy=l7policy_mgr.EdgeL7PolicyManagerFromDict(),
|
||||
l7rule=l7rule_mgr.EdgeL7RuleManagerFromDict())
|
||||
|
||||
def _extend_fault_map(self):
|
||||
"""Extends the Neutron Fault Map.
|
||||
|
||||
@ -4479,7 +4521,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
port_data = self.get_port(context, port_id)
|
||||
device_owner = port_data.get('device_owner')
|
||||
fip_address = new_fip['floating_ip_address']
|
||||
if device_owner == const.DEVICE_OWNER_LOADBALANCERV2:
|
||||
if (device_owner == const.DEVICE_OWNER_LOADBALANCERV2 or
|
||||
device_owner == oct_const.DEVICE_OWNER_OCTAVIA):
|
||||
try:
|
||||
self._update_lb_vip(port_data, fip_address)
|
||||
except nsx_lib_exc.ManagerError:
|
||||
@ -4508,7 +4551,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
port_data = self.get_port(context, port_id)
|
||||
device_owner = port_data.get('device_owner')
|
||||
fixed_ip_address = fip['fixed_ip_address']
|
||||
if device_owner == const.DEVICE_OWNER_LOADBALANCERV2:
|
||||
if (device_owner == const.DEVICE_OWNER_LOADBALANCERV2 or
|
||||
device_owner == oct_const.DEVICE_OWNER_OCTAVIA):
|
||||
# If the port is LB VIP port, after deleting the FIP,
|
||||
# update the virtual server VIP back to fixed IP.
|
||||
is_lb_port = True
|
||||
@ -4551,7 +4595,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
old_port_data = self.get_port(context, old_port_id)
|
||||
old_device_owner = old_port_data['device_owner']
|
||||
old_fixed_ip = old_fip['fixed_ip_address']
|
||||
if old_device_owner == const.DEVICE_OWNER_LOADBALANCERV2:
|
||||
if (old_device_owner == const.DEVICE_OWNER_LOADBALANCERV2 or
|
||||
old_device_owner == oct_const.DEVICE_OWNER_OCTAVIA):
|
||||
is_lb_port = True
|
||||
self._update_lb_vip(old_port_data, old_fixed_ip)
|
||||
|
||||
@ -4578,7 +4623,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
new_port_data = self.get_port(context, new_port_id)
|
||||
new_dev_own = new_port_data['device_owner']
|
||||
new_fip_address = new_fip['floating_ip_address']
|
||||
if new_dev_own == const.DEVICE_OWNER_LOADBALANCERV2:
|
||||
if (new_dev_own == const.DEVICE_OWNER_LOADBALANCERV2 or
|
||||
new_dev_own == oct_const.DEVICE_OWNER_OCTAVIA):
|
||||
is_lb_port = True
|
||||
self._update_lb_vip(new_port_data, new_fip_address)
|
||||
|
||||
|
@ -96,6 +96,10 @@ LB_STATS_MAP = {'active_connections': 'current_sessions',
|
||||
'bytes_in': 'bytes_in',
|
||||
'bytes_out': 'bytes_out',
|
||||
'total_connections': 'total_sessions'}
|
||||
LB_EMPTY_STATS = {'active_connections': 0,
|
||||
'bytes_in': 0,
|
||||
'bytes_out': 0,
|
||||
'total_connections': 0}
|
||||
LR_ROUTER_TYPE = 'os-neutron-router-id'
|
||||
LR_PORT_TYPE = 'os-neutron-rport-id'
|
||||
LB_CERT_RESOURCE_TYPE = ['certificate_signed', 'certificate_self_signed']
|
||||
|
@ -32,12 +32,14 @@ def lb_listener_obj_to_dict(listener):
|
||||
# Translate the LBaaS listener to a dictionary skipping the some objects
|
||||
# to avoid recursions
|
||||
listener_dict = listener.to_dict(loadbalancer=False, default_pool=False)
|
||||
|
||||
# Translate the default pool separately without it's internal objects
|
||||
if listener.default_pool:
|
||||
listener_dict['default_pool'] = lb_pool_obj_to_dict(
|
||||
listener.default_pool, with_listeners=False)
|
||||
else:
|
||||
listener_dict['default_pool'] = None
|
||||
|
||||
if listener.loadbalancer:
|
||||
listener_dict['loadbalancer'] = lb_loadbalancer_obj_to_dict(
|
||||
listener.loadbalancer)
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
@ -297,3 +299,45 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
listener['id'])
|
||||
|
||||
completor(success=True)
|
||||
|
||||
|
||||
def stats_getter(context, core_plugin, ignore_list=None):
|
||||
"""Update Octavia statistics for each listener (virtual server)"""
|
||||
stat_list = []
|
||||
vcns = core_plugin.nsx_v.vcns
|
||||
# go over all LB edges
|
||||
bindings = nsxv_db.get_nsxv_lbaas_loadbalancer_bindings(context.session)
|
||||
for binding in bindings:
|
||||
lb_id = binding['loadbalancer_id']
|
||||
if ignore_list and lb_id in ignore_list:
|
||||
continue
|
||||
edge_id = binding['edge_id']
|
||||
|
||||
try:
|
||||
lb_stats = vcns.get_loadbalancer_statistics(edge_id)
|
||||
|
||||
virtual_servers_stats = lb_stats[1].get('virtualServer', [])
|
||||
for vs_stats in virtual_servers_stats:
|
||||
# Get the stats of the virtual server
|
||||
stats = copy.copy(lb_const.LB_EMPTY_STATS)
|
||||
stats['bytes_in'] += vs_stats.get('bytesIn', 0)
|
||||
stats['bytes_out'] += vs_stats.get('bytesOut', 0)
|
||||
stats['active_connections'] += vs_stats.get('curSessions', 0)
|
||||
stats['total_connections'] += vs_stats.get('totalSessions', 0)
|
||||
stats['request_errors'] = 0 # currently unsupported
|
||||
|
||||
# Find the listener Id
|
||||
vs_id = vs_stats.get('virtualServerId')
|
||||
list_bind = nsxv_db.get_nsxv_lbaas_listener_binding_by_vse(
|
||||
context.session, lb_id, vs_id)
|
||||
if not list_bind:
|
||||
continue
|
||||
stats['id'] = list_bind['listener_id']
|
||||
|
||||
stat_list.append(stats)
|
||||
|
||||
except vcns_exc.VcnsApiException as e:
|
||||
LOG.warning('Failed to read load balancer statistics for %s: %s',
|
||||
edge_id, e)
|
||||
|
||||
return stat_list
|
||||
|
@ -31,6 +31,7 @@ from vmware_nsx.plugins.nsx_v.vshield.common import (
|
||||
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as nsxv_exc
|
||||
from vmware_nsx.services.lbaas import base_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_common
|
||||
from vmware_nsx.services.lbaas.octavia import constants as oct_const
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -159,33 +160,15 @@ class EdgeLoadBalancerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
completor(success=True)
|
||||
|
||||
def refresh(self, context, lb):
|
||||
# TODO(kobis): implememnt
|
||||
# TODO(kobis): implement
|
||||
pass
|
||||
|
||||
def stats(self, context, lb):
|
||||
stats = {'bytes_in': 0,
|
||||
'bytes_out': 0,
|
||||
'active_connections': 0,
|
||||
'total_connections': 0}
|
||||
|
||||
binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(context.session,
|
||||
lb['id'])
|
||||
|
||||
try:
|
||||
lb_stats = self.vcns.get_loadbalancer_statistics(
|
||||
binding['edge_id'])
|
||||
|
||||
except nsxv_exc.VcnsApiException:
|
||||
msg = (_('Failed to read load balancer statistics, edge: %s') %
|
||||
binding['edge_id'])
|
||||
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
||||
|
||||
pools_stats = lb_stats[1].get('pool', [])
|
||||
for pool_stats in pools_stats:
|
||||
stats['bytes_in'] += pool_stats.get('bytesIn', 0)
|
||||
stats['bytes_out'] += pool_stats.get('bytesOut', 0)
|
||||
stats['active_connections'] += pool_stats.get('curSessions', 0)
|
||||
stats['total_connections'] += pool_stats.get('totalSessions', 0)
|
||||
stats = _get_edge_loadbalancer_statistics(self.vcns,
|
||||
binding['edge_id'])
|
||||
|
||||
return stats
|
||||
|
||||
@ -208,12 +191,15 @@ class EdgeLoadBalancerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
subnet = self.core_plugin.get_subnet(context.elevated(), subnet_id)
|
||||
|
||||
filters = {'fixed_ips': {'subnet_id': [subnet_id]},
|
||||
'device_owner': [constants.DEVICE_OWNER_LOADBALANCERV2]}
|
||||
'device_owner': [constants.DEVICE_OWNER_LOADBALANCERV2,
|
||||
oct_const.DEVICE_OWNER_OCTAVIA]}
|
||||
lb_ports = self.core_plugin.get_ports(context.elevated(),
|
||||
filters=filters)
|
||||
|
||||
if lb_ports:
|
||||
for lb_port in lb_ports:
|
||||
# TODO(asarfaty): for Octavia this code might need to change
|
||||
# as the device_id is different
|
||||
if lb_port['device_id']:
|
||||
edge_bind = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
||||
context.session, lb_port['device_id'])
|
||||
@ -238,3 +224,27 @@ class EdgeLoadBalancerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
if not found:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _get_edge_loadbalancer_statistics(vcns, edge_id):
|
||||
stats = {'bytes_in': 0,
|
||||
'bytes_out': 0,
|
||||
'active_connections': 0,
|
||||
'total_connections': 0}
|
||||
|
||||
try:
|
||||
lb_stats = vcns.get_loadbalancer_statistics(edge_id)
|
||||
|
||||
except nsxv_exc.VcnsApiException:
|
||||
msg = (_('Failed to read load balancer statistics, edge: %s') %
|
||||
edge_id)
|
||||
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
||||
|
||||
pools_stats = lb_stats[1].get('pool', [])
|
||||
for pool_stats in pools_stats:
|
||||
stats['bytes_in'] += pool_stats.get('bytesIn', 0)
|
||||
stats['bytes_out'] += pool_stats.get('bytesOut', 0)
|
||||
stats['active_connections'] += pool_stats.get('curSessions', 0)
|
||||
stats['total_connections'] += pool_stats.get('totalSessions', 0)
|
||||
|
||||
return stats
|
||||
|
@ -46,6 +46,8 @@ class EdgeL7RuleManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
lb_rule_id = binding['lb_rule_id']
|
||||
if delete:
|
||||
lb_utils.remove_rule_from_policy(rule)
|
||||
else:
|
||||
lb_utils.update_rule_in_policy(rule)
|
||||
rule_body = lb_utils.convert_l7policy_to_lb_rule(
|
||||
context, rule['policy'])
|
||||
try:
|
||||
|
@ -203,3 +203,8 @@ def convert_l7policy_to_lb_rule(context, policy):
|
||||
def remove_rule_from_policy(rule):
|
||||
l7rules = rule['policy']['rules']
|
||||
rule['policy']['rules'] = [r for r in l7rules if r['id'] != rule['id']]
|
||||
|
||||
|
||||
def update_rule_in_policy(rule):
|
||||
remove_rule_from_policy(rule)
|
||||
rule['policy']['rules'].append(rule)
|
||||
|
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
@ -281,3 +283,42 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
context.session, lb_id, listener['id'])
|
||||
|
||||
completor(success=True)
|
||||
|
||||
|
||||
def stats_getter(context, core_plugin, ignore_list=None):
|
||||
"""Update Octavia statistics for each listener (virtual server)"""
|
||||
stat_list = []
|
||||
lb_service_client = core_plugin.nsxlib.load_balancer.service
|
||||
# Go over all the loadbalancers & services
|
||||
lb_bindings = nsx_db.get_nsx_lbaas_loadbalancer_bindings(
|
||||
context.session)
|
||||
for lb_binding in lb_bindings:
|
||||
if ignore_list and lb_binding['loadbalancer_id'] in ignore_list:
|
||||
continue
|
||||
|
||||
lb_service_id = lb_binding.get('lb_service_id')
|
||||
LOG.debug("Getting listeners statistics for NSX lb service %s",
|
||||
lb_service_id)
|
||||
try:
|
||||
# get the NSX statistics for this LB service
|
||||
rsp = lb_service_client.get_stats(lb_service_id)
|
||||
if rsp and 'virtual_servers' in rsp:
|
||||
# Go over each virtual server in the response
|
||||
for vs in rsp['virtual_servers']:
|
||||
# look up the virtual server in the DB
|
||||
vs_bind = nsx_db.get_nsx_lbaas_listener_binding_by_vs_id(
|
||||
context.session, vs['virtual_server_id'])
|
||||
if vs_bind:
|
||||
vs_stats = vs['statistics']
|
||||
stats = copy.copy(lb_const.LB_EMPTY_STATS)
|
||||
stats['id'] = vs_bind.listener_id
|
||||
stats['request_errors'] = 0 # currently unsupported
|
||||
for stat in lb_const.LB_STATS_MAP:
|
||||
lb_stat = lb_const.LB_STATS_MAP[stat]
|
||||
stats[stat] += vs_stats[lb_stat]
|
||||
stat_list.append(stats)
|
||||
|
||||
except nsxlib_exc.ManagerError:
|
||||
pass
|
||||
|
||||
return stat_list
|
||||
|
@ -192,10 +192,10 @@ class EdgeLoadBalancerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
for vs in vs_statuses.get('results', []):
|
||||
vs_status = self._nsx_status_to_lb_status(vs.get('status'))
|
||||
vs_id = vs.get('virtual_server_id')
|
||||
listener_binding = nsx_db.get_nsx_lbaas_listener_binding_by_vs(
|
||||
list_binding = nsx_db.get_nsx_lbaas_listener_binding_by_lb_and_vs(
|
||||
context.session, id, vs_id)
|
||||
if listener_binding:
|
||||
listener_id = listener_binding['listener_id']
|
||||
if list_binding:
|
||||
listener_id = list_binding['listener_id']
|
||||
statuses[lb_const.LISTENERS].append(
|
||||
{'id': listener_id, 'status': vs_status})
|
||||
|
||||
|
@ -65,10 +65,15 @@ class EdgeMemberManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
|
||||
tenant_id, context.project_name)
|
||||
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)
|
||||
try:
|
||||
lb_service = service_client.create(display_name=lb_name,
|
||||
tags=tags,
|
||||
attachment=attachment,
|
||||
size=lb_size)
|
||||
except nsxlib_exc.ManagerError as e:
|
||||
LOG.error("Failed to create LB service: %s", e)
|
||||
return
|
||||
|
||||
# Update router to enable advertise_lb_vip flag
|
||||
self.core_plugin.nsxlib.logical_router.update_advertisement(
|
||||
nsx_router_id, advertise_lb_vip=True)
|
||||
|
@ -16,8 +16,8 @@
|
||||
from neutron_lib.callbacks import events
|
||||
from neutron_lib.callbacks import registry
|
||||
from neutron_lib.callbacks import resources
|
||||
from neutron_lib import constants as n_consts
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from neutron_lib.plugins import constants as plugin_const
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
|
||||
@ -33,6 +33,7 @@ from vmware_nsx.services.lbaas.nsx_v3.implementation import listener_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import loadbalancer_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import member_mgr
|
||||
from vmware_nsx.services.lbaas.nsx_v3.implementation import pool_mgr
|
||||
from vmware_nsx.services.lbaas.octavia import constants as oct_const
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
@ -108,6 +109,9 @@ class EdgeLoadbalancerDriverV2(base_mgr.LoadbalancerBaseManager):
|
||||
# Check if there is any LB attachment for the NSX router.
|
||||
# This callback is subscribed here to prevent router/GW/interface
|
||||
# deletion if it still has LB service attached to it.
|
||||
|
||||
#Note(asarfaty): Those callbacks are used by Octavia as well even
|
||||
# though they are bound only here
|
||||
registry.subscribe(self._check_lb_service_on_router,
|
||||
resources.ROUTER, events.BEFORE_DELETE)
|
||||
registry.subscribe(self._check_lb_service_on_router,
|
||||
@ -124,8 +128,9 @@ class EdgeLoadbalancerDriverV2(base_mgr.LoadbalancerBaseManager):
|
||||
resources.ROUTER_INTERFACE, events.BEFORE_DELETE)
|
||||
|
||||
def _get_lb_ports(self, context, subnet_ids):
|
||||
dev_owner = 'neutron:' + plugin_const.LOADBALANCERV2
|
||||
filters = {'device_owner': [dev_owner],
|
||||
dev_owner_v2 = n_consts.DEVICE_OWNER_LOADBALANCERV2
|
||||
dev_owner_oct = oct_const.DEVICE_OWNER_OCTAVIA
|
||||
filters = {'device_owner': [dev_owner_v2, dev_owner_oct],
|
||||
'fixed_ips': {'subnet_id': subnet_ids}}
|
||||
return self.loadbalancer.core_plugin.get_ports(
|
||||
context, filters=filters)
|
||||
|
0
vmware_nsx/services/lbaas/octavia/__init__.py
Normal file
0
vmware_nsx/services/lbaas/octavia/__init__.py
Normal file
45
vmware_nsx/services/lbaas/octavia/constants.py
Normal file
45
vmware_nsx/services/lbaas/octavia/constants.py
Normal file
@ -0,0 +1,45 @@
|
||||
# Copyright 2018 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.
|
||||
|
||||
OCTAVIA_TO_DRIVER_TOPIC = 'vmware_nsx__lb_listener'
|
||||
DRIVER_TO_OCTAVIA_TOPIC = 'vmware_nsx__driver_listener'
|
||||
|
||||
LOADBALANCER = 'loadbalancer'
|
||||
LISTENER = 'listener'
|
||||
POOL = 'pool'
|
||||
HEALTHMONITOR = 'healthmonitor'
|
||||
MEMBER = 'member'
|
||||
L7POLICY = 'l7policy'
|
||||
L7RULE = 'l7rule'
|
||||
|
||||
LOADBALANCERS = 'loadbalancers'
|
||||
LISTENERS = 'listeners'
|
||||
POOLS = 'pools'
|
||||
HEALTHMONITORS = 'healthmonitors'
|
||||
MEMBERS = 'members'
|
||||
L7POLICIES = 'l7policies'
|
||||
L7RULES = 'l7rules'
|
||||
|
||||
ONLINE = 'ONLINE'
|
||||
OFFLINE = 'OFFLINE'
|
||||
ERROR = 'ERROR'
|
||||
ACTIVE = 'ACTIVE'
|
||||
DELETED = 'DELETED'
|
||||
ERROR = 'ERROR'
|
||||
|
||||
OPERATING_STATUS = 'operating_status'
|
||||
PROVISIONING_STATUS = 'provisioning_status'
|
||||
|
||||
DEVICE_OWNER_OCTAVIA = 'Octavia'
|
507
vmware_nsx/services/lbaas/octavia/octavia_driver.py
Normal file
507
vmware_nsx/services/lbaas/octavia/octavia_driver.py
Normal file
@ -0,0 +1,507 @@
|
||||
# Copyright 2018 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.
|
||||
|
||||
import copy
|
||||
import socket
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
import oslo_messaging as messaging
|
||||
from oslo_messaging.rpc import dispatcher
|
||||
import pecan
|
||||
from stevedore import driver as stevedore_driver
|
||||
|
||||
from octavia.api.drivers import driver_lib
|
||||
from octavia.api.drivers import exceptions
|
||||
from octavia.api.drivers import provider_base as driver_base
|
||||
from octavia.api.drivers import utils as oct_utils
|
||||
from octavia.db import api as db_apis
|
||||
from octavia.db import repositories
|
||||
|
||||
from vmware_nsx.services.lbaas.octavia import constants as d_const
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
cfg.CONF.import_group('oslo_messaging', 'octavia.common.config')
|
||||
|
||||
# List of keys per object type that will not be sent to the listener
|
||||
unsupported_keys = {'Loadbalancer': ['vip_qos_policy_id'],
|
||||
'Listener': ['sni_container_refs',
|
||||
'insert_headers',
|
||||
'timeout_client_data',
|
||||
'timeout_member_connect',
|
||||
'timeout_member_data',
|
||||
'timeout_tcp_inspect'],
|
||||
'HealthMonitor': ['expected_codes', 'max_retries_down'],
|
||||
'Member': ['monitor_address', 'monitor_port', 'backup']}
|
||||
|
||||
|
||||
class NSXOctaviaDriver(driver_base.ProviderDriver):
|
||||
@log_helpers.log_method_call
|
||||
def __init__(self):
|
||||
super(NSXOctaviaDriver, self).__init__()
|
||||
self._init_rpc_messaging()
|
||||
self._init_rpc_listener()
|
||||
self._init_cert_manager()
|
||||
self.repositories = repositories.Repositories()
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _init_rpc_messaging(self):
|
||||
topic = d_const.OCTAVIA_TO_DRIVER_TOPIC
|
||||
transport = messaging.get_rpc_transport(cfg.CONF)
|
||||
target = messaging.Target(topic=topic, exchange="common",
|
||||
namespace='control', fanout=False,
|
||||
version='1.0')
|
||||
self.client = messaging.RPCClient(transport, target)
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _init_rpc_listener(self):
|
||||
# Initialize RPC listener
|
||||
topic = d_const.DRIVER_TO_OCTAVIA_TOPIC
|
||||
server = socket.gethostname()
|
||||
transport = messaging.get_rpc_transport(cfg.CONF)
|
||||
target = messaging.Target(topic=topic, server=server,
|
||||
exchange="common", fanout=False)
|
||||
endpoints = [NSXOctaviaDriverEndpoint()]
|
||||
access_policy = dispatcher.DefaultRPCAccessPolicy
|
||||
self.octavia_server = messaging.get_rpc_server(
|
||||
transport, target, endpoints, executor='threading',
|
||||
access_policy=access_policy)
|
||||
self.octavia_server.start()
|
||||
|
||||
@log_helpers.log_method_call
|
||||
def _init_cert_manager(self):
|
||||
self.cert_manager = stevedore_driver.DriverManager(
|
||||
namespace='octavia.cert_manager',
|
||||
name=cfg.CONF.certificates.cert_manager,
|
||||
invoke_on_load=True).driver
|
||||
|
||||
def get_obj_project_id(self, obj_type, obj_dict):
|
||||
if obj_dict.get('project_id'):
|
||||
return obj_dict['project_id']
|
||||
if obj_dict.get('tenant_id'):
|
||||
return obj_dict['tenant_id']
|
||||
|
||||
# look for the project id of the attached objects
|
||||
project_id = None
|
||||
if obj_dict.get('loadbalancer_id'):
|
||||
db_lb = self.repositories.load_balancer.get(
|
||||
db_apis.get_session(), id=obj_dict['loadbalancer_id'])
|
||||
if db_lb:
|
||||
project_id = db_lb.project_id
|
||||
if not project_id and obj_dict.get('pool_id'):
|
||||
db_pool = self.repositories.pool.get(
|
||||
db_apis.get_session(), id=obj_dict['pool_id'])
|
||||
if db_pool:
|
||||
project_id = db_pool.load_balancer.project_id
|
||||
if not project_id and obj_dict.get('listener_id'):
|
||||
db_list = self.repositories.listener.get(
|
||||
db_apis.get_session(), id=obj_dict['listener_id'])
|
||||
if db_list:
|
||||
project_id = db_list.load_balancer.project_id
|
||||
if not project_id and obj_dict.get('l7policy_id'):
|
||||
db_policy = self.repositories.l7policy.get(
|
||||
db_apis.get_session(), id=obj_dict['l7policy_id'])
|
||||
if db_policy:
|
||||
if db_policy.listener:
|
||||
db_lb = db_policy.listener.load_balancer
|
||||
elif db_policy.redirect_pool:
|
||||
db_lb = db_policy.redirect_pool.load_balancer
|
||||
if db_lb:
|
||||
project_id = db_lb.project_id
|
||||
|
||||
if not project_id:
|
||||
LOG.warning("Could bot find the tenant id for %(type)s "
|
||||
"%(obj)s", {'type': obj_type, 'obj': obj_dict})
|
||||
return project_id
|
||||
|
||||
def _get_load_balancer_dict(self, loadbalancer_id):
|
||||
if not loadbalancer_id:
|
||||
return
|
||||
db_lb = self.repositories.load_balancer.get(
|
||||
db_apis.get_session(), id=loadbalancer_id)
|
||||
if not db_lb:
|
||||
return
|
||||
lb_dict = {'name': db_lb.name, 'id': loadbalancer_id}
|
||||
if db_lb.vip:
|
||||
lb_dict['vip_port_id'] = db_lb.vip.port_id
|
||||
lb_dict['vip_address'] = db_lb.vip.ip_address
|
||||
lb_dict['vip_port_id'] = db_lb.vip.port_id
|
||||
lb_dict['vip_network_id'] = db_lb.vip.network_id
|
||||
lb_dict['vip_subnet_id'] = db_lb.vip.subnet_id
|
||||
return lb_dict
|
||||
|
||||
def _get_listener_in_pool_dict(self, pool_dict):
|
||||
if 'listener' not in pool_dict:
|
||||
if pool_dict.get('listener_id'):
|
||||
db_listener = self.repositories.listener.get(
|
||||
db_apis.get_session(), id=pool_dict['listener_id'])
|
||||
listener_obj = oct_utils.db_listener_to_provider_listener(
|
||||
db_listener)
|
||||
listener_dict = listener_obj.to_dict(
|
||||
recurse=False, render_unsets=True)
|
||||
listener_dict['id'] = listener_dict['listener_id']
|
||||
listener_dict['l7_policies'] = listener_dict['l7policies']
|
||||
pool_dict['listener'] = listener_dict
|
||||
if 'listeners' not in pool_dict:
|
||||
# multiple listeners is not really supported yet
|
||||
pool_dict['listeners'] = [listener_dict]
|
||||
else:
|
||||
pool_dict['listener'] = None
|
||||
if 'listeners' not in pool_dict:
|
||||
pool_dict['listeners'] = []
|
||||
|
||||
def _get_pool_dict(self, pool_id):
|
||||
if not pool_id:
|
||||
return
|
||||
db_pool = self.repositories.pool.get(db_apis.get_session(), id=pool_id)
|
||||
if not db_pool:
|
||||
return
|
||||
pool_obj = oct_utils.db_pool_to_provider_pool(db_pool)
|
||||
pool_dict = pool_obj.to_dict(recurse=True, render_unsets=True)
|
||||
pool_dict['id'] = pool_id
|
||||
# Get the load balancer object
|
||||
if pool_dict.get('loadbalancer_id'):
|
||||
# Generate a loadbalancer object
|
||||
pool_dict['loadbalancer'] = self._get_load_balancer_dict(
|
||||
pool_dict['loadbalancer_id'])
|
||||
if 'listener' not in pool_dict:
|
||||
self._get_listener_in_pool_dict(pool_dict)
|
||||
return pool_dict
|
||||
|
||||
def update_policy_dict(self, policy_dict, policy_obj, is_update=False):
|
||||
if policy_dict.get('listener_id'):
|
||||
db_list = self.repositories.listener.get(
|
||||
db_apis.get_session(), id=policy_dict['listener_id'])
|
||||
list_obj = oct_utils.db_listener_to_provider_listener(db_list)
|
||||
list_dict = list_obj.to_dict(recurse=True, render_unsets=True)
|
||||
list_dict['id'] = policy_dict['listener_id']
|
||||
policy_dict[ |