Browse Source

LBaaSv2 driver

Implement LBaaSv2 driver for NSXv Edge appliance load balancer.
Includes TLS support for Edge appliance, and certificate management
For SSL termination.

Change-Id: I60093c0186cce3e99fb26e1fc6bd5175cbd1a560
changes/06/199106/49
Kobi Samoray 6 years ago
parent
commit
9b6d3b1b47
  1. 10
      tools/tox_install.sh
  2. 2
      vmware_nsx/db/migration/alembic_migrations/versions/HEADS
  3. 68
      vmware_nsx/db/migration/alembic_migrations/versions/mitaka/expand/312211a5725f_nsxv_lbv2.py
  4. 150
      vmware_nsx/db/nsxv_db.py
  5. 56
      vmware_nsx/db/nsxv_models.py
  6. 5
      vmware_nsx/plugins/nsx_v/vshield/vcns.py
  7. 6
      vmware_nsx/plugins/nsx_v/vshield/vcns_driver.py
  8. 0
      vmware_nsx/services/lbaas/__init__.py
  9. 0
      vmware_nsx/services/lbaas/nsx_v/__init__.py
  10. 250
      vmware_nsx/services/lbaas/nsx_v/lbaas_common.py
  11. 56
      vmware_nsx/services/lbaas/nsx_v/lbaas_const.py
  12. 0
      vmware_nsx/services/lbaas/nsx_v/v1/__init__.py
  13. 493
      vmware_nsx/services/lbaas/nsx_v/v1/edge_loadbalancer_driver.py
  14. 0
      vmware_nsx/services/lbaas/nsx_v/v2/__init__.py
  15. 52
      vmware_nsx/services/lbaas/nsx_v/v2/base_mgr.py
  16. 36
      vmware_nsx/services/lbaas/nsx_v/v2/edge_loadbalancer_driver_v2.py
  17. 186
      vmware_nsx/services/lbaas/nsx_v/v2/healthmon_mgr.py
  18. 278
      vmware_nsx/services/lbaas/nsx_v/v2/listener_mgr.py
  19. 89
      vmware_nsx/services/lbaas/nsx_v/v2/loadbalancer_mgr.py
  20. 173
      vmware_nsx/services/lbaas/nsx_v/v2/member_mgr.py
  21. 143
      vmware_nsx/services/lbaas/nsx_v/v2/pool_mgr.py
  22. 247
      vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver.py
  23. 611
      vmware_nsx/tests/unit/nsx_v/test_edge_loadbalancer_driver_v2.py
  24. 173
      vmware_nsx/tests/unit/nsx_v/test_lbaas_common.py

10
tools/tox_install.sh

@ -16,6 +16,7 @@
ZUUL_CLONER=/usr/zuul-env/bin/zuul-cloner
neutron_installed=$(echo "import neutron" | python 2>/dev/null ; echo $?)
networking_l2gw_installed=$(echo "import networking_l2gw" | python 2>/dev/null ; echo $?)
neutron_lbaas_installed=$(echo "import neutron_lbaas" | python 2>/dev/null ; echo $?)
set -ex
@ -56,5 +57,14 @@ else
pip_hardcode openstack/networking-l2gw#egg=networking-l2gw
fi
if [ $neutron_lbaas_installed -eq 0 ]; then
echo "NEUTRON_LBAAS ALREADY INSTALLED" >> /tmp/tox_install.txt
echo "Neutron_lbaas already installed; using existing package"
elif [ -x "$ZUUL_CLONER" ]; then
zuul_cloner openstack/neutron-lbaas
else
pip_hardcode openstack/neutron-lbaas#egg=neutron-lbaas
fi
pip install -U $*
exit $?

2
vmware_nsx/db/migration/alembic_migrations/versions/HEADS

@ -1,2 +1,2 @@
279b70ac3ae8
312211a5725f
3c88bdea3054

68
vmware_nsx/db/migration/alembic_migrations/versions/mitaka/expand/312211a5725f_nsxv_lbv2.py

@ -0,0 +1,68 @@
# Copyright 2015 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.
#
"""nsxv_lbv2
Revision ID: 312211a5725f
Revises: 279b70ac3ae8
Create Date: 2015-09-09 02:02:59.990122
"""
# revision identifiers, used by Alembic.
revision = '312211a5725f'
down_revision = '279b70ac3ae8'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.create_table(
'nsxv_lbaas_loadbalancer_bindings',
sa.Column('loadbalancer_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=False),
sa.Column('edge_fw_rule_id', sa.String(length=36), nullable=False),
sa.Column('vip_address', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('loadbalancer_id'))
op.create_table(
'nsxv_lbaas_listener_bindings',
sa.Column('loadbalancer_id', sa.String(length=36), nullable=False),
sa.Column('listener_id', sa.String(length=36), nullable=False),
sa.Column('app_profile_id', sa.String(length=36), nullable=False),
sa.Column('vse_id', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('loadbalancer_id', 'listener_id'))
op.create_table(
'nsxv_lbaas_pool_bindings',
sa.Column('loadbalancer_id', sa.String(length=36), nullable=False),
sa.Column('listener_id', sa.String(length=36), nullable=False),
sa.Column('pool_id', sa.String(length=36), nullable=False),
sa.Column('edge_pool_id', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('loadbalancer_id', 'listener_id', 'pool_id'))
op.create_table(
'nsxv_lbaas_monitor_bindings',
sa.Column('loadbalancer_id', sa.String(length=36), nullable=False),
sa.Column('listener_id', sa.String(length=36), nullable=False),
sa.Column('pool_id', sa.String(length=36), nullable=False),
sa.Column('hm_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=False),
sa.Column('edge_mon_id', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('loadbalancer_id', 'listener_id', 'pool_id',
'hm_id', 'edge_id'))
op.create_table(
'nsxv_lbaas_certificate_bindings',
sa.Column('cert_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=False),
sa.Column('edge_cert_id', sa.String(length=36), nullable=False),
sa.PrimaryKeyConstraint('cert_id', 'edge_id'))

150
vmware_nsx/db/nsxv_db.py

@ -536,3 +536,153 @@ def get_vdr_dhcp_binding_by_vdr(session, vdr_router_id):
def delete_vdr_dhcp_binding(session, vdr_router_id):
return (session.query(nsxv_models.NsxvVdrDhcpBinding).
filter_by(vdr_router_id=vdr_router_id).delete())
def add_nsxv_lbaas_loadbalancer_binding(
session, loadbalancer_id, edge_id, edge_fw_rule_id, vip_address):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvLbaasLoadbalancerBinding(
loadbalancer_id=loadbalancer_id,
edge_id=edge_id,
edge_fw_rule_id=edge_fw_rule_id,
vip_address=vip_address)
session.add(binding)
return binding
def get_nsxv_lbaas_loadbalancer_binding(session, loadbalancer_id):
try:
return session.query(
nsxv_models.NsxvLbaasLoadbalancerBinding).filter_by(
loadbalancer_id=loadbalancer_id).one()
except exc.NoResultFound:
return
def del_nsxv_lbaas_loadbalancer_binding(session, loadbalancer_id):
return (session.query(nsxv_models.NsxvLbaasLoadbalancerBinding).
filter_by(loadbalancer_id=loadbalancer_id).delete())
def add_nsxv_lbaas_listener_binding(session, loadbalancer_id, listener_id,
app_profile_id, vse_id):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvLbaasListenerBinding(
loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
app_profile_id=app_profile_id,
vse_id=vse_id)
session.add(binding)
return binding
def get_nsxv_lbaas_listener_binding(session, loadbalancer_id, listener_id):
try:
return session.query(
nsxv_models.NsxvLbaasListenerBinding).filter_by(
loadbalancer_id=loadbalancer_id, listener_id=listener_id).one()
except exc.NoResultFound:
return
def del_nsxv_lbaas_listener_binding(session, loadbalancer_id, listener_id):
return (session.query(nsxv_models.NsxvLbaasListenerBinding).
filter_by(loadbalancer_id=loadbalancer_id,
listener_id=listener_id).delete())
def add_nsxv_lbaas_pool_binding(session, loadbalancer_id, listener_id,
pool_id, edge_pool_id):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvLbaasPoolBinding(
loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id,
edge_pool_id=edge_pool_id)
session.add(binding)
return binding
def get_nsxv_lbaas_pool_binding(session, loadbalancer_id, listener_id,
pool_id):
try:
return session.query(
nsxv_models.NsxvLbaasPoolBinding).filter_by(
loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id).one()
except exc.NoResultFound:
return
def del_nsxv_lbaas_pool_binding(session, loadbalancer_id, listener_id,
pool_id):
return (session.query(nsxv_models.NsxvLbaasPoolBinding).
filter_by(loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id).delete())
def add_nsxv_lbaas_monitor_binding(session, loadbalancer_id, listener_id,
pool_id, hm_id, edge_id, edge_mon_id):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvLbaasMonitorBinding(
loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id,
hm_id=hm_id,
edge_id=edge_id,
edge_mon_id=edge_mon_id)
session.add(binding)
return binding
def get_nsxv_lbaas_monitor_binding(session, loadbalancer_id, listener_id,
pool_id, hm_id, edge_id):
try:
return session.query(
nsxv_models.NsxvLbaasMonitorBinding).filter_by(
loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id,
hm_id=hm_id,
edge_id=edge_id).one()
except exc.NoResultFound:
return
def del_nsxv_lbaas_monitor_binding(session, loadbalancer_id, listener_id,
pool_id, hm_id, edge_id):
return (session.query(nsxv_models.NsxvLbaasMonitorBinding).
filter_by(loadbalancer_id=loadbalancer_id,
listener_id=listener_id,
pool_id=pool_id,
hm_id=hm_id,
edge_id=edge_id).delete())
def add_nsxv_lbaas_certificate_binding(session, cert_id, edge_id,
edge_cert_id):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvLbaasCertificateBinding(
cert_id=cert_id,
edge_id=edge_id,
edge_cert_id=edge_cert_id)
session.add(binding)
return binding
def get_nsxv_lbaas_certificate_binding(session, cert_id, edge_id):
try:
return session.query(
nsxv_models.NsxvLbaasCertificateBinding).filter_by(
cert_id=cert_id,
edge_id=edge_id).one()
except exc.NoResultFound:
return
def del_nsxv_lbaas_certificate_binding(session, cert_id, edge_id):
return (session.query(nsxv_models.NsxvLbaasCertificateBinding).
filter_by(cert_id=cert_id,
edge_id=edge_id).delete())

56
vmware_nsx/db/nsxv_models.py

@ -254,3 +254,59 @@ class NsxvVdrDhcpBinding(model_base.BASEV2):
dhcp_edge_id,
name='unique_nsxv_vdr_dhcp_bindings0dhcp_edge_id'),
model_base.BASEV2.__table_args__)
class NsxvLbaasLoadbalancerBinding(model_base.BASEV2):
"""Mapping between Edge LB and LBaaSv2"""
__tablename__ = 'nsxv_lbaas_loadbalancer_bindings'
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)
class NsxvLbaasListenerBinding(model_base.BASEV2):
"""Mapping between Edge VSE and LBaaSv2"""
__tablename__ = 'nsxv_lbaas_listener_bindings'
loadbalancer_id = sa.Column(sa.String(36), 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)
class NsxvLbaasPoolBinding(model_base.BASEV2):
"""Mapping between Edge Pool and LBaaSv2"""
__tablename__ = 'nsxv_lbaas_pool_bindings'
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
listener_id = sa.Column(sa.String(36), primary_key=True)
pool_id = sa.Column(sa.String(36), primary_key=True)
edge_pool_id = sa.Column(sa.String(36), nullable=False)
class NsxvLbaasMonitorBinding(model_base.BASEV2):
"""Mapping between Edge Monitor and LBaaSv2"""
__tablename__ = 'nsxv_lbaas_monitor_bindings'
loadbalancer_id = sa.Column(sa.String(36), primary_key=True)
listener_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), primary_key=True)
edge_id = sa.Column(sa.String(36), primary_key=True)
edge_mon_id = sa.Column(sa.String(36), nullable=False)
class NsxvLbaasCertificateBinding(model_base.BASEV2):
"""Mapping between Edge certificate and LBaaSv2 object"""
__tablename__ = 'nsxv_lbaas_certificate_bindings'
cert_id = sa.Column(sa.String(36), primary_key=True)
edge_id = sa.Column(sa.String(36), primary_key=True)
edge_cert_id = sa.Column(sa.String(36), nullable=False)

5
vmware_nsx/plugins/nsx_v/vshield/vcns.py

@ -792,3 +792,8 @@ class Vcns(object):
"""Enable HA in the given edge."""
uri = "/api/4.0/edges/%s/highavailability/config?async=true" % edge_id
return self.do_request(HTTP_PUT, uri, request_config)
def upload_edge_certificate(self, edge_id, request):
"""Creates a certificate on the specified Edge appliance."""
uri = '/api/2.0/services/truststore/certificate/%s' % edge_id
return self.do_request(HTTP_POST, uri, request, decode=True)

6
vmware_nsx/plugins/nsx_v/vshield/vcns_driver.py

@ -19,18 +19,20 @@ import os
from oslo_config import cfg
from oslo_log import log as logging
from vmware_nsx.common import config # noqa
from vmware_nsx.plugins.nsx_v.vshield import edge_appliance_driver
from vmware_nsx.plugins.nsx_v.vshield import edge_firewall_driver
from vmware_nsx.plugins.nsx_v.vshield import edge_loadbalancer_driver
from vmware_nsx.plugins.nsx_v.vshield.tasks import tasks
from vmware_nsx.plugins.nsx_v.vshield import vcns
from vmware_nsx.services.lbaas.nsx_v.v1 import edge_loadbalancer_driver
from vmware_nsx.services.lbaas.nsx_v.v2 import (
edge_loadbalancer_driver_v2 as lbaas_v2)
LOG = logging.getLogger(__name__)
class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
edge_loadbalancer_driver.EdgeLbDriver,
lbaas_v2.EdgeLoadbalancerDriverV2,
edge_firewall_driver.EdgeFirewallDriver):
def __init__(self, callbacks):

0
vmware_nsx/services/lbaas/__init__.py

0
vmware_nsx/services/lbaas/nsx_v/__init__.py

250
vmware_nsx/services/lbaas/nsx_v/lbaas_common.py

@ -0,0 +1,250 @@
# Copyright 2015 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 netaddr
import xml.etree.ElementTree as et
from neutron.common import exceptions as n_exc
from vmware_nsx.common import locking
from vmware_nsx.db import nsxv_db
from vmware_nsx.plugins.nsx_v.vshield import vcns as nsxv_api
MEMBER_ID_PFX = 'member-'
LBAAS_FW_SECTION_NAME = 'LBaaS FW Rules'
def get_member_id(member_id):
return MEMBER_ID_PFX + member_id
def get_lbaas_edge_id_for_subnet(context, plugin, subnet_id):
"""
Grab the id of an Edge appliance that is connected to subnet_id.
"""
subnet = plugin.get_subnet(context, subnet_id)
net_id = subnet.get('network_id')
filters = {'network_id': [net_id],
'device_owner': ['network:router_interface']}
attached_routers = plugin.get_ports(context.elevated(),
filters=filters,
fields=['device_id'])
for attached_router in attached_routers:
router = plugin.get_router(context, attached_router['device_id'])
if router['router_type'] == 'exclusive':
rtr_bindings = nsxv_db.get_nsxv_router_binding(context.session,
router['id'])
return rtr_bindings['edge_id']
def find_address_in_same_subnet(ip_addr, address_groups):
"""
Lookup an address group with a matching subnet to ip_addr.
If found, return address_group.
"""
for address_group in address_groups['addressGroups']:
net_addr = '%(primaryAddress)s/%(subnetPrefixLength)s' % address_group
if netaddr.IPAddress(ip_addr) in netaddr.IPNetwork(net_addr):
return address_group
def add_address_to_address_groups(ip_addr, address_groups):
"""
Add ip_addr as a secondary IP address to an address group which belongs to
the same subnet.
"""
address_group = find_address_in_same_subnet(
ip_addr, address_groups)
if address_group:
sec_addr = address_group.get('secondaryAddresses')
if not sec_addr:
sec_addr = {
'type': 'secondary_addresses',
'ipAddress': [ip_addr]}
else:
sec_addr['ipAddress'].append(ip_addr)
address_group['secondaryAddresses'] = sec_addr
return True
return False
def del_address_from_address_groups(ip_addr, address_groups):
"""
Delete ip_addr from secondary address list in address groups.
"""
address_group = find_address_in_same_subnet(ip_addr, address_groups)
if address_group:
sec_addr = address_group.get('secondaryAddresses')
if sec_addr and ip_addr in sec_addr['ipAddress']:
sec_addr['ipAddress'].remove(ip_addr)
return True
return False
def vip_as_secondary_ip(vcns, edge_id, vip, handler):
with locking.LockManager.get_lock(edge_id, external=True):
r = vcns.get_interfaces(edge_id)[1]
vnics = r.get('vnics', [])
for vnic in vnics:
if vnic['type'] == 'trunk':
for sub_interface in vnic.get('subInterfaces', {}).get(
'subInterfaces', []):
address_groups = sub_interface.get('addressGroups')
if handler(vip, address_groups):
vcns.update_interface(edge_id, vnic)
return True
else:
address_groups = vnic.get('addressGroups')
if handler(vip, address_groups):
vcns.update_interface(edge_id, vnic)
return True
return False
def add_vip_as_secondary_ip(vcns, edge_id, vip):
"""
Edge appliance requires that a VIP will be configured as a primary
or a secondary IP address on an interface.
To do so, we locate an interface which is connected to the same subnet
that vip belongs to.
This can be a regular interface, on a sub-interface on a trunk.
"""
if not vip_as_secondary_ip(vcns, edge_id, vip,
add_address_to_address_groups):
msg = _('Failed to add VIP %(vip)s as secondary IP on '
'Edge %(edge_id)s') % {'vip': vip, 'edge_id': edge_id}
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
def del_vip_as_secondary_ip(vcns, edge_id, vip):
"""
While removing vip, delete the secondary interface from Edge config.
"""
if not vip_as_secondary_ip(vcns, edge_id, vip,
del_address_from_address_groups):
msg = _('Failed to delete VIP %(vip)s as secondary IP on '
'Edge %(edge_id)s') % {'vip': vip, 'edge_id': edge_id}
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
def extract_resource_id(location_uri):
"""
Edge assigns an ID for each resource that is being created:
it is postfixes the uri specified in the Location header.
This ID should be used while updating/deleting this resource.
"""
uri_elements = location_uri.split('/')
return uri_elements[-1]
def add_vip_fw_rule(vcns, edge_id, vip_id, ip_address):
fw_rule = {
'firewallRules': [
{'action': 'accept', 'destination': {
'ipAddress': [ip_address]},
'enabled': True,
'name': vip_id}]}
with locking.LockManager.get_lock(edge_id, external=True):
h = vcns.add_firewall_rule(edge_id, fw_rule)[0]
fw_rule_id = extract_resource_id(h['location'])
return fw_rule_id
def del_vip_fw_rule(vcns, edge_id, vip_fw_rule_id):
with locking.LockManager.get_lock(edge_id, external=True):
vcns.delete_firewall_rule(edge_id, vip_fw_rule_id)
def get_edge_ip_addresses(vcns, edge_id):
edge_ips = []
r = vcns.get_interfaces(edge_id)[1]
vnics = r.get('vnics', [])
for vnic in vnics:
if vnic['type'] == 'trunk':
for sub_interface in vnic.get('subInterfaces', {}).get(
'subInterfaces', []):
address_groups = sub_interface.get('addressGroups')
for address_group in address_groups['addressGroups']:
edge_ips.append(address_group['primaryAddress'])
else:
address_groups = vnic.get('addressGroups')
for address_group in address_groups['addressGroups']:
edge_ips.append(address_group['primaryAddress'])
return edge_ips
def update_pool_fw_rule(vcns, pool_id, edge_id, section_id, member_ips):
edge_ips = get_edge_ip_addresses(vcns, edge_id)
with locking.LockManager.get_lock('lbaas-fw-section', external=True):
section_uri = '%s/%s/%s' % (nsxv_api.FIREWALL_PREFIX,
'layer3sections',
section_id)
xml_section = vcns.get_section(section_uri)[1]
section = et.fromstring(xml_section)
pool_rule = None
for rule in section.iter('rule'):
if rule.find('name').text == pool_id:
pool_rule = rule
if member_ips:
pool_rule.find('sources').find('source').find(
'value').text = (','.join(edge_ips))
pool_rule.find('destinations').find(
'destination').find('value').text = ','.join(
member_ips)
else:
section.remove(pool_rule)
break
if member_ips and pool_rule is None:
pool_rule = et.SubElement(section, 'rule')
et.SubElement(pool_rule, 'name').text = pool_id
et.SubElement(pool_rule, 'action').text = 'allow'
sources = et.SubElement(pool_rule, 'sources')
sources.attrib['excluded'] = 'false'
source = et.SubElement(sources, 'source')
et.SubElement(source, 'type').text = 'Ipv4Address'
et.SubElement(source, 'value').text = ','.join(edge_ips)
destinations = et.SubElement(pool_rule, 'destinations')
destinations.attrib['excluded'] = 'false'
destination = et.SubElement(destinations, 'destination')
et.SubElement(destination, 'type').text = 'Ipv4Address'
et.SubElement(destination, 'value').text = ','.join(member_ips)
vcns.update_section(section_uri,
et.tostring(section, encoding="us-ascii"),
None)
def get_lbaas_fw_section_id(vcns):
# Avoid concurrent creation of section by multiple neutron
# instances
with locking.LockManager.get_lock('lbaas-fw-section',
external=True):
fw_section_id = vcns.get_section_id(LBAAS_FW_SECTION_NAME)
if not fw_section_id:
section = et.Element('section')
section.attrib['name'] = LBAAS_FW_SECTION_NAME
sect = vcns.create_section('ip', et.tostring(section))[1]
fw_section_id = et.fromstring(sect).attrib['id']
return fw_section_id

56
vmware_nsx/services/lbaas/nsx_v/lbaas_const.py

@ -0,0 +1,56 @@
# Copyright 2015 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.
LB_METHOD_ROUND_ROBIN = 'ROUND_ROBIN'
LB_METHOD_LEAST_CONNECTIONS = 'LEAST_CONNECTIONS'
LB_METHOD_SOURCE_IP = 'SOURCE_IP'
BALANCE_MAP = {
LB_METHOD_ROUND_ROBIN: 'round-robin',
LB_METHOD_LEAST_CONNECTIONS: 'leastconn',
LB_METHOD_SOURCE_IP: 'ip-hash'}
LB_PROTOCOL_TCP = 'TCP'
LB_PROTOCOL_HTTP = 'HTTP'
LB_PROTOCOL_HTTPS = 'HTTPS'
PROTOCOL_MAP = {
LB_PROTOCOL_TCP: 'tcp',
LB_PROTOCOL_HTTP: 'http',
LB_PROTOCOL_HTTPS: 'tcp'}
LB_HEALTH_MONITOR_PING = 'PING'
LB_HEALTH_MONITOR_TCP = 'TCP'
LB_HEALTH_MONITOR_HTTP = 'HTTP'
LB_HEALTH_MONITOR_HTTPS = 'HTTPS'
HEALTH_MONITOR_MAP = {
LB_HEALTH_MONITOR_PING: 'icmp',
LB_HEALTH_MONITOR_TCP: 'tcp',
LB_HEALTH_MONITOR_HTTP: 'http',
LB_HEALTH_MONITOR_HTTPS: 'tcp'}
LB_SESSION_PERSISTENCE_SOURCE_IP = 'SOURCE_IP'
LB_SESSION_PERSISTENCE_HTTP_COOKIE = 'HTTP_COOKIE'
LB_SESSION_PERSISTENCE_APP_COOKIE = 'APP_COOKIE'
SESSION_PERSISTENCE_METHOD_MAP = {
LB_SESSION_PERSISTENCE_SOURCE_IP: 'sourceip',
LB_SESSION_PERSISTENCE_APP_COOKIE: 'cookie',
LB_SESSION_PERSISTENCE_HTTP_COOKIE: 'cookie'}
SESSION_PERSISTENCE_COOKIE_MAP = {
LB_SESSION_PERSISTENCE_APP_COOKIE: 'app',
LB_SESSION_PERSISTENCE_HTTP_COOKIE: 'insert'}

0
vmware_nsx/services/lbaas/nsx_v/v1/__init__.py

493
vmware_nsx/plugins/nsx_v/vshield/edge_loadbalancer_driver.py → vmware_nsx/services/lbaas/nsx_v/v1/edge_loadbalancer_driver.py

@ -13,71 +13,20 @@
# License for the specific language governing permissions and limitations
# under the License.
import xml.etree.ElementTree as et
import netaddr
from oslo_log import log as logging
from oslo_utils import excutils
from neutron.common import exceptions as n_exc
from neutron.i18n import _LE
from neutron import manager
from neutron.plugins.common import constants
from vmware_nsx.common import locking
from vmware_nsx.db import nsxv_db
from vmware_nsx.plugins.nsx_v.vshield.common import (
exceptions as nsxv_exc)
from vmware_nsx.plugins.nsx_v.vshield import vcns as nsxv_api
from oslo_log import log as logging
from oslo_utils import excutils
from vmware_nsx.common import locking
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as nsxv_exc
from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_common
from vmware_nsx.services.lbaas.nsx_v import lbaas_const as lb_const
LOG = logging.getLogger(__name__)
LB_METHOD_ROUND_ROBIN = 'ROUND_ROBIN'
LB_METHOD_LEAST_CONNECTIONS = 'LEAST_CONNECTIONS'
LB_METHOD_SOURCE_IP = 'SOURCE_IP'
LB_PROTOCOL_TCP = 'TCP'
LB_PROTOCOL_HTTP = 'HTTP'
LB_PROTOCOL_HTTPS = 'HTTPS'
LB_HEALTH_MONITOR_PING = 'PING'
LB_HEALTH_MONITOR_TCP = 'TCP'
LB_HEALTH_MONITOR_HTTP = 'HTTP'
LB_HEALTH_MONITOR_HTTPS = 'HTTPS'
LB_SESSION_PERSISTENCE_SOURCE_IP = 'SOURCE_IP'
LB_SESSION_PERSISTENCE_HTTP_COOKIE = 'HTTP_COOKIE'
LB_SESSION_PERSISTENCE_APP_COOKIE = 'APP_COOKIE'
BALANCE_MAP = {
LB_METHOD_ROUND_ROBIN: 'round-robin',
LB_METHOD_LEAST_CONNECTIONS: 'leastconn',
LB_METHOD_SOURCE_IP: 'ip-hash'}
PROTOCOL_MAP = {
LB_PROTOCOL_TCP: 'tcp',
LB_PROTOCOL_HTTP: 'http',
LB_PROTOCOL_HTTPS: 'tcp'}
HEALTH_MONITOR_MAP = {
LB_HEALTH_MONITOR_PING: 'icmp',
LB_HEALTH_MONITOR_TCP: 'tcp',
LB_HEALTH_MONITOR_HTTP: 'http',
LB_HEALTH_MONITOR_HTTPS: 'tcp'}
SESSION_PERSISTENCE_METHOD_MAP = {
LB_SESSION_PERSISTENCE_SOURCE_IP: 'sourceip',
LB_SESSION_PERSISTENCE_APP_COOKIE: 'cookie',
LB_SESSION_PERSISTENCE_HTTP_COOKIE: 'cookie'}
SESSION_PERSISTENCE_COOKIE_MAP = {
LB_SESSION_PERSISTENCE_APP_COOKIE: 'app',
LB_SESSION_PERSISTENCE_HTTP_COOKIE: 'insert'}
LBAAS_FW_SECTION_NAME = 'LBaaS FW Rules'
MEMBER_ID_PFX = 'member-'
def convert_lbaas_pool(lbaas_pool):
"""
@ -87,7 +36,7 @@ def convert_lbaas_pool(lbaas_pool):
'name': 'pool_' + lbaas_pool['id'],
'description': lbaas_pool.get('description',
lbaas_pool.get('name')),
'algorithm': BALANCE_MAP.get(
'algorithm': lb_const.BALANCE_MAP.get(
lbaas_pool.get('lb_method'), 'round-robin'),
'transparent': False
}
@ -110,25 +59,27 @@ def convert_lbaas_app_profile(name, sess_persist, protocol):
}
# Since SSL Termination is not supported right now, so just use
# sslPassthrough method if the protocol is HTTPS.
if protocol == LB_PROTOCOL_HTTPS:
if protocol == lb_const.LB_PROTOCOL_HTTPS:
vcns_app_profile['sslPassthrough'] = True
persist_type = sess_persist.get('type')
if persist_type:
# If protocol is not HTTP, only source_ip is supported
if (protocol != LB_PROTOCOL_HTTP and
persist_type != LB_SESSION_PERSISTENCE_SOURCE_IP):
if (protocol != lb_const.LB_PROTOCOL_HTTP and
persist_type != lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP):
msg = (_('Invalid %(protocol)s persistence method: %(type)s') %
{'protocol': protocol,
'type': persist_type})
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
persistence = {
'method': SESSION_PERSISTENCE_METHOD_MAP.get(persist_type)}
if persist_type in SESSION_PERSISTENCE_COOKIE_MAP:
'method':
lb_const.SESSION_PERSISTENCE_METHOD_MAP.get(persist_type)}
if persist_type in lb_const.SESSION_PERSISTENCE_COOKIE_MAP:
persistence.update({
'cookieName': sess_persist.get('cookie_name',
'default_cookie_name'),
'cookieMode': SESSION_PERSISTENCE_COOKIE_MAP[persist_type]})
'cookieMode':
lb_const.SESSION_PERSISTENCE_COOKIE_MAP[persist_type]})
vcns_app_profile['persistence'] = persistence
return vcns_app_profile
@ -159,7 +110,7 @@ def convert_lbaas_member(member):
'weight': member['weight'],
'port': member['protocol_port'],
'monitorPort': member['protocol_port'],
'name': get_member_id(member['id']),
'name': lb_common.get_member_id(member['id']),
'condition': 'enabled' if member['admin_state_up'] else 'disabled'}
@ -168,8 +119,7 @@ def convert_lbaas_monitor(monitor):
Transform OpenStack health monitor dict to NSXv health monitor dict.
"""
mon = {
'type': HEALTH_MONITOR_MAP.get(
monitor['type'], 'icmp'),
'type': lb_const.HEALTH_MONITOR_MAP.get(monitor['type'], 'icmp'),
'interval': monitor['delay'],
'timeout': monitor['timeout'],
'maxRetries': monitor['max_retries'],
@ -183,72 +133,6 @@ def convert_lbaas_monitor(monitor):
return mon
def extract_resource_id(location_uri):
"""
Edge assigns an ID for each resource that is being created:
it is postfixes the uri specified in the Location header.
This ID should be used while updating/deleting this resource.
"""
uri_elements = location_uri.split('/')
return uri_elements[-1]
def get_subnet_primary_ip(ip_addr, address_groups):
"""
Retrieve the primary IP of an interface that's attached to the same subnet.
"""
addr_group = find_address_in_same_subnet(ip_addr, address_groups)
return addr_group['primaryAddress'] if addr_group else None
def find_address_in_same_subnet(ip_addr, address_groups):
"""
Lookup an address group with a matching subnet to ip_addr.
If found, return address_group.
"""
for address_group in address_groups['addressGroups']:
net_addr = '%(primaryAddress)s/%(subnetPrefixLength)s' % address_group
if netaddr.IPAddress(ip_addr) in netaddr.IPNetwork(net_addr):
return address_group
def add_address_to_address_groups(ip_addr, address_groups):
"""
Add ip_addr as a secondary IP address to an address group which belongs to
the same subnet.
"""
address_group = find_address_in_same_subnet(
ip_addr, address_groups)
if address_group:
sec_addr = address_group.get('secondaryAddresses')
if not sec_addr:
sec_addr = {
'type': 'secondary_addresses',
'ipAddress': [ip_addr]}
else:
sec_addr['ipAddress'].append(ip_addr)
address_group['secondaryAddresses'] = sec_addr
return True
return False
def del_address_from_address_groups(ip_addr, address_groups):
"""
Delete ip_addr from secondary address list in address groups.
"""
address_group = find_address_in_same_subnet(ip_addr, address_groups)
if address_group:
sec_addr = address_group.get('secondaryAddresses')
if sec_addr and ip_addr in sec_addr['ipAddress']:
sec_addr['ipAddress'].remove(ip_addr)
return True
return False
def get_member_id(member_id):
return MEMBER_ID_PFX + member_id
class EdgeLbDriver(object):
def __init__(self):
super(EdgeLbDriver, self).__init__()
@ -257,7 +141,7 @@ class EdgeLbDriver(object):
self.vcns = None
self._fw_section_id = None
self._lb_plugin = None
self._lb_driver_prop = None
self._lbv1_driver_prop = None
def _get_lb_plugin(self):
if not self._lb_plugin:
@ -266,220 +150,70 @@ class EdgeLbDriver(object):
return self._lb_plugin
@property
def _lb_driver(self):
if not self._lb_driver_prop:
def lbv1_driver(self):
if not self._lbv1_driver_prop:
plugin = self._get_lb_plugin()
self._lb_driver_prop = plugin.drivers['vmwareedge']
self._lbv1_driver_prop = plugin.drivers['vmwareedge']
return self._lb_driver_prop
return self._lbv1_driver_prop
def _get_lbaas_fw_section_id(self):
if not self._fw_section_id:
# Avoid concurrent creation of section by multiple neutron
# instances
with locking.LockManager.get_lock('lbaas-section-creation'):
fw_section_id = self.vcns.get_section_id(LBAAS_FW_SECTION_NAME)
if not fw_section_id:
section = et.Element('section')
section.attrib['name'] = LBAAS_FW_SECTION_NAME
sect = self.vcns.create_section('ip',
et.tostring(section))[1]
fw_section_id = et.fromstring(sect).attrib['id']
self._fw_section_id = fw_section_id
self._fw_section_id = lb_common.get_lbaas_fw_section_id(self.vcns)
return self._fw_section_id
def _get_lb_edge_id(self, context, subnet_id):
"""
Grab the id of an Edge appliance that is connected to subnet_id.
"""
subnet = self.callbacks.plugin.get_subnet(context, subnet_id)
net_id = subnet.get('network_id')
filters = {'network_id': [net_id],
'device_owner': ['network:router_interface']}
attached_routers = self.callbacks.plugin.get_ports(
context.elevated(), filters=filters,
fields=['device_id'])
for attached_router in attached_routers:
router = self.callbacks.plugin.get_router(
context, attached_router['device_id'])
if router['router_type'] == 'exclusive':
rtr_bindings = nsxv_db.get_nsxv_router_binding(
context.session, router['id'])
return rtr_bindings['edge_id']
def _vip_as_secondary_ip(self, edge_id, vip, handler):
with locking.LockManager.get_lock(edge_id):
r = self.vcns.get_interfaces(edge_id)[1]
vnics = r.get('vnics', [])
for vnic in vnics:
if vnic['type'] == 'trunk':
for sub_interface in vnic.get('subInterfaces').get(
'subInterfaces'):
address_groups = sub_interface.get('addressGroups')
if handler(vip, address_groups):
self.vcns.update_interface(edge_id, vnic)
return True
else:
address_groups = vnic.get('addressGroups')
if handler(vip, address_groups):
self.vcns.update_interface(edge_id, vnic)
return True
return False
def _add_vip_as_secondary_ip(self, edge_id, vip):
"""
Edge appliance requires that a VIP will be configured as a primary
or a secondary IP address on an interface.
To do so, we locate an interface which is connected to the same subnet
that vip belongs to.
This can be a regular interface, on a sub-interface on a trunk.
"""
if not self._vip_as_secondary_ip(
edge_id, vip, add_address_to_address_groups):
msg = _('Failed to add VIP %(vip)s as secondary IP on '
'Edge %(edge_id)s') % {'vip': vip, 'edge_id': edge_id}
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
def _del_vip_as_secondary_ip(self, edge_id, vip):
"""
While removing vip, delete the secondary interface from Edge config.
"""
if not self._vip_as_secondary_ip(
edge_id, vip, del_address_from_address_groups):
msg = _('Failed to delete VIP %(vip)s as secondary IP on '
'Edge %(edge_id)s') % {'vip': vip, 'edge_id': edge_id}
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
def _get_edge_ips(self, edge_id):
edge_ips = []
r = self.vcns.get_interfaces(edge_id)[1]
vnics = r.get('vnics', [])
for vnic in vnics:
if vnic['type'] == 'trunk':
for sub_interface in vnic.get('subInterfaces').get(
'subInterfaces'):
address_groups = sub_interface.get('addressGroups')
for address_group in address_groups['addressGroups']:
edge_ips.append(address_group['primaryAddress'])
else:
address_groups = vnic.get('addressGroups')
for address_group in address_groups['addressGroups']:
edge_ips.append(address_group['primaryAddress'])
return edge_ips
def _update_pool_fw_rule(self, context, pool_id, edge_id,
operation=None, address=None):
edge_ips = self._get_edge_ips(edge_id)
def _get_pool_member_ips(self, context, pool_id, operation, address):
plugin = self._get_lb_plugin()
with locking.LockManager.get_lock('lbaas-fw-section'):
members = plugin.get_members(
context,
filters={'pool_id': [pool_id]},
fields=['address'])
member_ips = [member['address'] for member in members]
if operation == 'add' and address not in member_ips:
member_ips.append(address)
elif operation == 'del' and address in member_ips:
member_ips.remove(address)
section_uri = '%s/%s/%s' % (nsxv_api.FIREWALL_PREFIX,
'layer3sections',
self._get_lbaas_fw_section_id())
xml_section = self.vcns.get_section(section_uri)[1]
section = et.fromstring(xml_section)
pool_rule = None
for rule in section.iter('rule'):
if rule.find('name').text == pool_id:
pool_rule = rule
if member_ips:
pool_rule.find('sources').find('source').find(
'value').text = (','.join(edge_ips))
pool_rule.find('destinations').find(
'destination').find('value').text = ','.join(
member_ips)
else:
section.remove(pool_rule)
break
members = plugin.get_members(
context,
filters={'pool_id': [pool_id]},
fields=['address'])
member_ips = {member['address'] for member in members}
if operation == 'add':
member_ips.add(address)
elif operation == 'del' and address in member_ips:
member_ips.remove(address)
if member_ips and pool_rule is None:
pool_rule = et.SubElement(section, 'rule')
et.SubElement(pool_rule, 'name').text = pool_id
et.SubElement(pool_rule, 'action').text = 'allow'
sources = et.SubElement(pool_rule, 'sources')
sources.attrib['excluded'] = 'false'
source = et.SubElement(sources, 'source')
et.SubElement(source, 'type').text = 'Ipv4Address'
et.SubElement(source, 'value').text = ','.join(edge_ips)
destinations = et.SubElement(pool_rule, 'destinations')
destinations.attrib['excluded'] = 'false'
destination = et.SubElement(destinations, 'destination')
et.SubElement(destination, 'type').text = 'Ipv4Address'
et.SubElement(destination, 'value').text = ','.join(member_ips)
self.vcns.update_section(section_uri,
et.tostring(section, encoding="us-ascii"),
None)
def _add_vip_fw_rule(self, edge_id, vip_id, ip_address):
fw_rule = {
'firewallRules': [
{'action': 'accept', 'destination': {
'ipAddress': [ip_address]},
'enabled': True,
'name': vip_id}]}
with locking.LockManager.get_lock(edge_id):
h = self.vcns.add_firewall_rule(edge_id, fw_rule)[0]
fw_rule_id = extract_resource_id(h['location'])
return fw_rule_id
def _del_vip_fw_rule(self, edge_id, vip_fw_rule_id):
with locking.LockManager.get_lock(edge_id):
self.vcns.delete_firewall_rule(edge_id, vip_fw_rule_id)
return list(member_ips)
def create_pool(self, context, pool):
LOG.debug('Creating pool %s', pool)
edge_id = self._get_lb_edge_id(context, pool['subnet_id'])
edge_id = lb_common.get_lbaas_edge_id_for_subnet(
context, self.callbacks.plugin, pool['subnet_id'])
if edge_id is None:
self._lb_driver.pool_failed(context, pool)
self.lbv1_driver.pool_failed(context, pool)
msg = _(
'No suitable Edge found for subnet %s') % pool['subnet_id']
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
edge_pool = convert_lbaas_pool(pool)
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
h = self.vcns.create_pool(edge_id, edge_pool)[0]
edge_pool_id = extract_resource_id(h['location'])
self._lb_driver.create_pool_successful(
edge_pool_id = lb_common.extract_resource_id(h['location'])
self.lbv1_driver.create_pool_successful(
context, pool, edge_id, edge_pool_id)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.pool_failed(context, pool)
self.lbv1_driver.pool_failed(context, pool)
LOG.error(_LE('Failed to create pool %s'), pool['id'])
def update_pool(self, context, old_pool, pool, pool_mapping):
LOG.debug('Updating pool %s to %s', old_pool, pool)
edge_pool = convert_lbaas_pool(pool)
try:
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
self.vcns.update_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'],
edge_pool)
self._lb_driver.pool_successful(context, pool)
self.lbv1_driver.pool_successful(context, pool)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.pool_failed(context, pool)
self.lbv1_driver.pool_failed(context, pool)
LOG.error(_LE('Failed to update pool %s'), pool['id'])
def delete_pool(self, context, pool, pool_mapping):
@ -487,23 +221,24 @@ class EdgeLbDriver(object):
if pool_mapping:
try:
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
self.vcns.delete_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'])
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.pool_failed(context, pool)
self.lbv1_driver.pool_failed(context, pool)
LOG.error(_LE('Failed to delete pool %s'), pool['id'])
else:
LOG.error(_LE('No mapping found for pool %s'), pool['id'])
self._lb_driver.delete_pool_successful(context, pool)
self.lbv1_driver.delete_pool_successful(context, pool)
def create_vip(self, context, vip, pool_mapping):
LOG.debug('Create VIP %s', vip)
app_profile = convert_lbaas_app_profile(
vip['id'], vip.get('session_persistence') or {},
vip['id'], vip.get('session_persistence', {}),
vip.get('protocol'))
if not pool_mapping:
@ -512,34 +247,35 @@ class EdgeLbDriver(object):
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
edge_id = pool_mapping['edge_id']
app_profile_id = None
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
h = (self.vcns.create_app_profile(edge_id, app_profile))[0]
app_profile_id = extract_resource_id(h['location'])
app_profile_id = lb_common.extract_resource_id(h['location'])
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(_LE('Failed to create app profile on edge: %s'),
edge_id)
edge_vip = convert_lbaas_vip(vip, app_profile_id, pool_mapping)
try:
self._add_vip_as_secondary_ip(edge_id, vip['address'])
with locking.LockManager.get_lock(edge_id):
lb_common.add_vip_as_secondary_ip(self.vcns, edge_id,
vip['address'])
with locking.LockManager.get_lock(edge_id, external=True):
h = self.vcns.create_vip(edge_id, edge_vip)[0]
edge_vip_id = extract_resource_id(h['location'])
edge_fw_rule_id = self._add_vip_fw_rule(edge_id, vip['id'],
vip['address'])
self._lb_driver.create_vip_successful(
edge_vip_id = lb_common.extract_resource_id(h['location'])
edge_fw_rule_id = lb_common.add_vip_fw_rule(self.vcns,
edge_id, vip['id'],
vip['address'])
self.lbv1_driver.create_vip_successful(
context, vip, edge_id, app_profile_id, edge_vip_id,
edge_fw_rule_id)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(_LE('Failed to create vip on Edge: %s'), edge_id)
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
self.vcns.delete_app_profile(edge_id, app_profile_id)
def update_vip(self, context, old_vip, vip, pool_mapping, vip_mapping):
@ -549,26 +285,26 @@ class EdgeLbDriver(object):
edge_vip_id = vip_mapping['edge_vse_id']
app_profile_id = vip_mapping['edge_app_profile_id']
app_profile = convert_lbaas_app_profile(
vip['name'], vip.get('session_persistence') or {},
vip['name'], vip.get('session_persistence', {}),
vip.get('protocol'))
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
self.vcns.update_app_profile(edge_id, app_profile_id,
app_profile)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(_LE('Failed to update app profile on edge: %s'),
edge_id)
edge_vip = convert_lbaas_vip(vip, app_profile_id, pool_mapping)
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
self.vcns.update_vip(edge_id, edge_vip_id, edge_vip)
self._lb_driver.vip_successful(context, vip)
self.lbv1_driver.vip_successful(context, vip)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(_LE('Failed to update vip on edge: %s'), edge_id)
def delete_vip(self, context, vip, vip_mapping):
@ -582,36 +318,40 @@ class EdgeLbDriver(object):
app_profile_id = vip_mapping['edge_app_profile_id']
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
self.vcns.delete_vip(edge_id, edge_vse_id)
self._del_vip_as_secondary_ip(edge_id, vip['address'])
self._del_vip_fw_rule(edge_id, vip_mapping['edge_fw_rule_id'])
lb_common.del_vip_as_secondary_ip(self.vcns, edge_id,
vip['address'])
lb_common.del_vip_fw_rule(self.vcns, edge_id,
vip_mapping['edge_fw_rule_id'])
except nsxv_exc.ResourceNotFound:
LOG.error(_LE('vip not found on edge: %s'), edge_id)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(
_LE('Failed to delete vip on edge: %s'), edge_id)
try:
with locking.LockManager.get_lock(edge_id):
with locking.LockManager.get_lock(edge_id, external=True):
self.vcns.delete_app_profile(edge_id, app_profile_id)
except nsxv_exc.ResourceNotFound:
LOG.error(_LE('app profile not found on edge: %s'), edge_id)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.vip_failed(context, vip)
self.lbv1_driver.vip_failed(context, vip)
LOG.error(
_LE('Failed to delete app profile on Edge: %s'),
edge_id)
self._lb_driver.delete_vip_successful(context, vip)
self.lbv1_driver.delete_vip_successful(context, vip)
def create_member(self, context, member, pool_mapping):
LOG.debug('Creating member %s', member)
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
edge_pool = self.vcns.get_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'])[1]
edge_member = convert_lbaas_member(member)
@ -627,28 +367,31 @@ class EdgeLbDriver(object):
pool_mapping['edge_pool_id'],
edge_pool)
self._update_pool_fw_rule(context, member['pool_id'],
pool_mapping['edge_id'],
'add',
member['address'])
self._lb_driver.member_successful(context, member)
member_ips = self._get_pool_member_ips(
context, member['pool_id'], 'add', member['address'])
lb_common.update_pool_fw_rule(
self.vcns, member['pool_id'], pool_mapping['edge_id'],
self._get_lbaas_fw_section_id(), member_ips)
self.lbv1_driver.member_successful(context, member)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.member_failed(context, member)
self.lbv1_driver.member_failed(context, member)
LOG.error(_LE('Failed to create member on edge: %s'),
pool_mapping['edge_id'])
def update_member(self, context, old_member, member, pool_mapping):
LOG.debug('Updating member %s to %s', old_member, member)
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
edge_pool = self.vcns.get_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'])[1]
edge_member = convert_lbaas_member(member)
for i, m in enumerate(edge_pool['member']):
if m['name'] == get_member_id(member['id']):
if m['name'] == lb_common.get_member_id(member['id']):
edge_pool['member'][i] = edge_member
break
@ -656,10 +399,10 @@ class EdgeLbDriver(object):
self.vcns.update_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'],
edge_pool)
self._lb_driver.member_successful(context, member)
self.lbv1_driver.member_successful(context, member)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.member_failed(context, member)
self.lbv1_driver.member_failed(context, member)
LOG.error(_LE('Failed to update member on edge: %s'),
pool_mapping['edge_id'])
@ -667,13 +410,14 @@ class EdgeLbDriver(object):
LOG.debug('Deleting member %s', member)
if pool_mapping:
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
edge_pool = self.vcns.get_pool(
pool_mapping['edge_id'],
pool_mapping['edge_pool_id'])[1]
for i, m in enumerate(edge_pool['member']):
if m['name'] == get_member_id(member['id']):
if m['name'] == lb_common.get_member_id(member['id']):
edge_pool['member'].pop(i)
break
@ -681,13 +425,15 @@ class EdgeLbDriver(object):
self.vcns.update_pool(pool_mapping['edge_id'],
pool_mapping['edge_pool_id'],
edge_pool)
self._update_pool_fw_rule(context, member['pool_id'],
pool_mapping['edge_id'],
'del',
member['address'])
member_ips = self._get_pool_member_ips(
context, member['pool_id'], 'del', member['address'])
lb_common.update_pool_fw_rule(
self.vcns, member['pool_id'], pool_mapping['edge_id'],
self._get_lbaas_fw_section_id(), member_ips)
except nsxv_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
self._lb_driver.member_failed(context, member)
self.lbv1_driver.member_failed(context, member)
LOG.error(_LE('Failed to update member on edge: %s'),
pool_mapping['edge_id'])
@ -699,7 +445,8 @@ class EdgeLbDriver(object):
LOG.debug('Create HM %s', health_monitor)
edge_mon_id = None
with locking.LockManager.get_lock(pool_mapping['edge_id']):
with locking.LockManager.get_lock(pool_mapping['edge_id'],
external=True):
# 1st, we find if we already have a pool with the same monitor, on
# the same Edge appliance.
# If there is no pool on this Edge which is already associated with
@ -711,10 +458,10 @@ class EdgeLbDriver(object):
try:
h = self.vcns.create_health_monitor(
pool_mapping['edge_id'], edge_monitor)[0]
edge_mon_id = extract_resource_id(h['location'])
edge_mon_id = lb_common.extract_resource_id(h['location'])
except nsxv_exc.VcnsApiException: