Support advanced NVP LBaaS Service

The patch adds NVP advanced LBaaS service support for NVP with
VCNS:
        * NVP LBaaS is an advanced Service of NVP depending on NVP
          advanced service router
            - Once an advanced router id created, one corresponding
              vshield edge will be deployed, and then we can configure
              LB service On the vshield edge
        * NVP LBaaS service plugin still uses LBaaS DB service logic,
          while finally calling vShield Edge to support FWaaS service
            - When creating VIP object, service attaches the object to
              the advanced router with routedserviceinsertion service.
              Then before pushing VIP VCNS call, the server would first
              pushing associated POOL VCNS call and associated Monitor
              VCNS call to vShield Edge. Deleting VIP is opposite
              operation
            - Refering to CUD operation of other objects, service would
              first find the associated VIP object and then find the edge bound to
              the router which vip inserted. Then service would push corresponding
              VCNS call to Vshield Edge
        * on driver part, the driver will first convert the object
          to VSM known object input, and then send a synchronous JSON
          calling to VSM, and receive the result

Implements: blueprint nvp-lbaas-plugin
Change-Id: Iec41f2dc103daddf3bed4d09c147df3865b3dccd
This commit is contained in:
linb 2013-08-20 13:35:10 +08:00 committed by Salvatore Orlando
parent db9c24a519
commit 18d991a6b2
17 changed files with 2075 additions and 25 deletions

View File

@ -0,0 +1,82 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 OpenStack Foundation
#
# 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.
#
"""nvp lbaas plugin
Revision ID: 3d6fae8b70b0
Revises: 3ed8f075e38a
Create Date: 2013-09-13 19:34:41.522665
"""
# revision identifiers, used by Alembic.
revision = '3d6fae8b70b0'
down_revision = '3ed8f075e38a'
# Change to ['*'] if this migration applies to all plugins
migration_for_plugins = [
'neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin'
]
from alembic import op
import sqlalchemy as sa
from neutron.db import migration
def upgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.create_table(
'vcns_edge_pool_bindings',
sa.Column('pool_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=False),
sa.Column('pool_vseid', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['pool_id'], ['pools.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('pool_id', 'edge_id')
)
op.create_table(
'vcns_edge_monitor_bindings',
sa.Column('monitor_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=False),
sa.Column('monitor_vseid', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['monitor_id'], ['healthmonitors.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('monitor_id', 'edge_id')
)
op.create_table(
'vcns_edge_vip_bindings',
sa.Column('vip_id', sa.String(length=36), nullable=False),
sa.Column('edge_id', sa.String(length=36), nullable=True),
sa.Column('vip_vseid', sa.String(length=36), nullable=True),
sa.Column('app_profileid', sa.String(length=36), nullable=True),
sa.ForeignKeyConstraint(['vip_id'], ['vips.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('vip_id')
)
def downgrade(active_plugins=None, options=None):
if not migration.should_run(active_plugins, migration_for_plugins):
return
op.drop_table('vcns_edge_vip_bindings')
op.drop_table('vcns_edge_monitor_bindings')
op.drop_table('vcns_edge_pool_bindings')

View File

@ -22,8 +22,10 @@ from oslo.config import cfg
from neutron.common import exceptions as q_exc
from neutron.db.firewall import firewall_db
from neutron.db import l3_db
from neutron.db.loadbalancer import loadbalancer_db
from neutron.db import routedserviceinsertion_db as rsi_db
from neutron.extensions import firewall as fw_ext
from neutron.openstack.common import excutils
from neutron.openstack.common import log as logging
from neutron.plugins.common import constants as service_constants
from neutron.plugins.nicira.common import config # noqa
@ -39,6 +41,7 @@ from neutron.plugins.nicira.vshield.common import (
constants as vcns_const)
from neutron.plugins.nicira.vshield.common.constants import RouterStatus
from neutron.plugins.nicira.vshield.common import exceptions
from neutron.plugins.nicira.vshield.tasks.constants import TaskState
from neutron.plugins.nicira.vshield.tasks.constants import TaskStatus
from neutron.plugins.nicira.vshield import vcns_driver
from sqlalchemy.orm import exc as sa_exc
@ -73,12 +76,15 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
NeutronPlugin.NvpPluginV2,
rsi_db.RoutedServiceInsertionDbMixin,
firewall_db.Firewall_db_mixin,
loadbalancer_db.LoadBalancerPluginDb
):
supported_extension_aliases = (
NeutronPlugin.NvpPluginV2.supported_extension_aliases + [
"service-router",
"routed-service-insertion",
"fwaas"
"fwaas",
"lbaas"
])
def __init__(self):
@ -257,7 +263,7 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
binding['edge_id'],
snat, dnat)
def _update_interface(self, context, router):
def _update_interface(self, context, router, sync=False):
addr, mask, nexthop = self._get_external_attachment_info(
context, router)
@ -267,14 +273,20 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
for fip in fip_db:
if fip.fixed_port_id:
secondary.append(fip.floating_ip_address)
#Add all vip addresses bound on the router
vip_addrs = self._get_all_vip_addrs_by_router_id(context,
router['id'])
secondary.extend(vip_addrs)
binding = vcns_db.get_vcns_router_binding(context.session,
router['id'])
self.vcns_driver.update_interface(
task = self.vcns_driver.update_interface(
router['id'], binding['edge_id'],
vcns_const.EXTERNAL_VNIC_INDEX,
self.vcns_driver.external_network,
addr, mask, secondary=secondary)
if sync:
task.wait(TaskState.RESULT)
def _update_router_gw_info(self, context, router_id, info):
if not self._is_advanced_service_router(context, router_id):
@ -1006,6 +1018,483 @@ class NvpAdvancedPlugin(sr_db.ServiceRouter_mixin,
context, fwr['id'], edge_id)
return fwp
#
# LBAAS service plugin implementation
#
def _get_edge_id_by_vip_id(self, context, vip_id):
try:
router_binding = self._get_resource_router_id_bindings(
context, loadbalancer_db.Vip, resource_ids=[vip_id])[0]
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to find the edge with "
"vip_id: %s"), vip_id)
service_binding = vcns_db.get_vcns_router_binding(
context.session, router_binding.router_id)
return service_binding.edge_id
def _get_all_vip_addrs_by_router_id(
self, context, router_id):
vip_bindings = self._get_resource_router_id_bindings(
context, loadbalancer_db.Vip, router_ids=[router_id])
vip_addrs = []
for vip_binding in vip_bindings:
vip = self.get_vip(context, vip_binding.resource_id)
vip_addrs.append(vip.get('address'))
return vip_addrs
def _add_router_service_insertion_binding(self, context, resource_id,
router_id,
model):
res = {
'id': resource_id,
'router_id': router_id
}
self._process_create_resource_router_id(context, res,
model)
def _resource_set_status(self, context, model, id, status, obj=None,
pool_id=None):
with context.session.begin(subtransactions=True):
try:
qry = context.session.query(model)
if issubclass(model, loadbalancer_db.PoolMonitorAssociation):
res = qry.filter_by(monitor_id=id,
pool_id=pool_id).one()
else:
res = qry.filter_by(id=id).one()
if status == service_constants.PENDING_UPDATE and (
res.get('status') == service_constants.PENDING_DELETE):
msg = (_("Operation can't be performed, Since resource "
"%(model)s : %(id)s is in DELETEing status!") %
{'model': model,
'id': id})
LOG.error(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
else:
res.status = status
except sa_exc.NoResultFound:
msg = (_("Resource %(model)s : %(id)s not found!") %
{'model': model,
'id': id})
LOG.exception(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
if obj:
obj['status'] = status
def _vcns_create_pool_and_monitors(self, context, pool_id, **kwargs):
pool = self.get_pool(context, pool_id)
edge_id = kwargs.get('edge_id')
if not edge_id:
edge_id = self._get_edge_id_by_vip_id(
context, pool['vip_id'])
#Check wheter the pool is already created on the router
#in case of future's M:N relation between Pool and Vip
#Check associated HealthMonitors and then create them
for monitor_id in pool.get('health_monitors'):
hm = self.get_health_monitor(context, monitor_id)
try:
self.vcns_driver.create_health_monitor(
context, edge_id, hm)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create healthmonitor "
"associated with pool id: %s!") % pool_id)
for monitor_ide in pool.get('health_monitors'):
if monitor_ide == monitor_id:
break
self.vcns_driver.delete_health_monitor(
context, monitor_ide, edge_id)
#Create the pool on the edge
members = [
super(NvpAdvancedPlugin, self).get_member(
context, member_id)
for member_id in pool.get('members')
]
try:
self.vcns_driver.create_pool(context, edge_id, pool, members)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create pool on vshield edge"))
self.vcns_driver.delete_pool(
context, pool_id, edge_id)
for monitor_id in pool.get('health_monitors'):
self.vcns_driver.delete_health_monitor(
context, monitor_id, edge_id)
def _vcns_update_pool(self, context, pool, **kwargs):
edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id'])
members = kwargs.get('members')
if not members:
members = [
super(NvpAdvancedPlugin, self).get_member(
context, member_id)
for member_id in pool.get('members')
]
self.vcns_driver.update_pool(context, edge_id, pool, members)
def create_vip(self, context, vip):
LOG.debug(_("create_vip() called"))
router_id = vip['vip'].get(vcns_const.ROUTER_ID)
if not router_id:
msg = _("router_id is not provided!")
LOG.error(msg)
raise q_exc.BadRequest(resource='router', msg=msg)
if not self._is_advanced_service_router(context, router_id):
msg = _("router_id: %s is not an advanced router!") % router_id
LOG.error(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
#Check whether the vip port is an external port
subnet_id = vip['vip']['subnet_id']
network_id = self.get_subnet(context, subnet_id)['network_id']
ext_net = self._get_network(context, network_id)
if not ext_net.external:
msg = (_("Network '%s' is not a valid external "
"network") % network_id)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
v = super(NvpAdvancedPlugin, self).create_vip(context, vip)
#Get edge_id for the resource
router_binding = vcns_db.get_vcns_router_binding(
context.session,
router_id)
edge_id = router_binding.edge_id
#Add vip_router binding
self._add_router_service_insertion_binding(context, v['id'],
router_id,
loadbalancer_db.Vip)
#Create the vip port on vShield Edge
router = self._get_router(context, router_id)
self._update_interface(context, router, sync=True)
#Create the vip and associated pool/monitor on the corresponding edge
try:
self._vcns_create_pool_and_monitors(
context, v['pool_id'], edge_id=edge_id)
self.vcns_driver.create_vip(context, edge_id, v)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create vip!"))
self._delete_resource_router_id_binding(
context, v['id'], loadbalancer_db.Vip)
super(NvpAdvancedPlugin, self).delete_vip(context, v['id'])
self._resource_set_status(context, loadbalancer_db.Vip,
v['id'], service_constants.ACTIVE, v)
return v
def update_vip(self, context, id, vip):
edge_id = self._get_edge_id_by_vip_id(context, id)
old_vip = self.get_vip(context, id)
vip['vip']['status'] = service_constants.PENDING_UPDATE
v = super(NvpAdvancedPlugin, self).update_vip(context, id, vip)
if old_vip['pool_id'] != v['pool_id']:
self.vcns_driver.delete_vip(context, id)
#Delete old pool/monitor on the edge
#TODO(linb): Factor out procedure for removing pool and health
#separate method
old_pool = self.get_pool(context, old_vip['pool_id'])
self.vcns_driver.delete_pool(
context, old_vip['pool_id'], edge_id)
for monitor_id in old_pool.get('health_monitors'):
self.vcns_driver.delete_health_monitor(
context, monitor_id, edge_id)
#Create new pool/monitor object on the edge
#TODO(linb): add exception handle if error
self._vcns_create_pool_and_monitors(
context, v['pool_id'], edge_id=edge_id)
self.vcns_driver.create_vip(context, edge_id, v)
return v
try:
self.vcns_driver.update_vip(context, v)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update vip with id: %s!"), id)
self._resource_set_status(context, loadbalancer_db.Vip,
id, service_constants.ERROR, v)
self._resource_set_status(context, loadbalancer_db.Vip,
v['id'], service_constants.ACTIVE, v)
return v
def delete_vip(self, context, id):
v = self.get_vip(context, id)
self._resource_set_status(
context, loadbalancer_db.Vip,
id, service_constants.PENDING_DELETE)
try:
self.vcns_driver.delete_vip(context, id)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to delete vip with id: %s!"), id)
self._resource_set_status(context, loadbalancer_db.Vip,
id, service_constants.ERROR)
edge_id = self._get_edge_id_by_vip_id(context, id)
#Check associated HealthMonitors and then delete them
pool = self.get_pool(context, v['pool_id'])
self.vcns_driver.delete_pool(context, v['pool_id'], edge_id)
for monitor_id in pool.get('health_monitors'):
#TODO(linb): do exception handle if error
self.vcns_driver.delete_health_monitor(
context, monitor_id, edge_id)
router_binding = self._get_resource_router_id_binding(
context, loadbalancer_db.Vip, resource_id=id)
router = self._get_router(context, router_binding.router_id)
self._delete_resource_router_id_binding(
context, id, loadbalancer_db.Vip)
super(NvpAdvancedPlugin, self).delete_vip(context, id)
self._update_interface(context, router, sync=True)
def update_pool(self, context, id, pool):
pool['pool']['status'] = service_constants.PENDING_UPDATE
p = super(NvpAdvancedPlugin, self).update_pool(context, id, pool)
#Check whether the pool is already associated with the vip
if not p.get('vip_id'):
self._resource_set_status(context, loadbalancer_db.Pool,
p['id'], service_constants.ACTIVE, p)
return p
try:
self._vcns_update_pool(context, p)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool with id: %s!"), id)
self._resource_set_status(context, loadbalancer_db.Pool,
p['id'], service_constants.ERROR, p)
self._resource_set_status(context, loadbalancer_db.Pool,
p['id'], service_constants.ACTIVE, p)
return p
def create_member(self, context, member):
m = super(NvpAdvancedPlugin, self).create_member(context, member)
pool_id = m.get('pool_id')
pool = self.get_pool(context, pool_id)
if not pool.get('vip_id'):
self._resource_set_status(context, loadbalancer_db.Member,
m['id'], service_constants.ACTIVE, m)
return m
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id,
service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool with the member"))
super(NvpAdvancedPlugin, self).delete_member(context, m['id'])
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
self._resource_set_status(context, loadbalancer_db.Member,
m['id'], service_constants.ACTIVE, m)
return m
def update_member(self, context, id, member):
member['member']['status'] = service_constants.PENDING_UPDATE
old_member = self.get_member(context, id)
m = super(NvpAdvancedPlugin, self).update_member(
context, id, member)
if m['pool_id'] != old_member['pool_id']:
old_pool_id = old_member['pool_id']
old_pool = self.get_pool(context, old_pool_id)
if old_pool.get('vip_id'):
self._resource_set_status(
context, loadbalancer_db.Pool,
old_pool_id, service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, old_pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update old pool "
"with the member"))
super(NvpAdvancedPlugin, self).delete_member(
context, m['id'])
self._resource_set_status(
context, loadbalancer_db.Pool,
old_pool_id, service_constants.ACTIVE)
pool_id = m['pool_id']
pool = self.get_pool(context, pool_id)
if not pool.get('vip_id'):
self._resource_set_status(context, loadbalancer_db.Member,
m['id'], service_constants.ACTIVE, m)
return m
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id,
service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool with the member"))
super(NvpAdvancedPlugin, self).delete_member(
context, m['id'])
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
self._resource_set_status(context, loadbalancer_db.Member,
m['id'], service_constants.ACTIVE, m)
return m
def delete_member(self, context, id):
m = self.get_member(context, id)
super(NvpAdvancedPlugin, self).delete_member(context, id)
pool_id = m['pool_id']
pool = self.get_pool(context, pool_id)
if not pool.get('vip_id'):
return
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id, service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool with the member"))
self._resource_set_status(context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
def update_health_monitor(self, context, id, health_monitor):
old_hm = super(NvpAdvancedPlugin, self).get_health_monitor(
context, id)
hm = super(NvpAdvancedPlugin, self).update_health_monitor(
context, id, health_monitor)
for hm_pool in hm.get('pools'):
pool_id = hm_pool['pool_id']
pool = self.get_pool(context, pool_id)
if pool.get('vip_id'):
edge_id = self._get_edge_id_by_vip_id(
context, pool['vip_id'])
try:
self.vcns_driver.update_health_monitor(
context, edge_id, old_hm, hm)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update monitor "
"with id: %s!"), id)
return hm
def delete_health_monitor(self, context, id):
with context.session.begin(subtransactions=True):
qry = context.session.query(
loadbalancer_db.PoolMonitorAssociation
).filter_by(monitor_id=id)
for assoc in qry:
pool_id = assoc['pool_id']
super(NvpAdvancedPlugin,
self).delete_pool_health_monitor(context,
id,
pool_id)
pool = self.get_pool(context, pool_id)
if not pool.get('vip_id'):
continue
edge_id = self._get_edge_id_by_vip_id(
context, pool['vip_id'])
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool with monitor!"))
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
try:
self.vcns_driver.delete_health_monitor(
context, id, edge_id)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to delete monitor "
"with id: %s!"), id)
super(NvpAdvancedPlugin,
self).delete_health_monitor(context, id)
self._delete_resource_router_id_binding(
context, id, loadbalancer_db.HealthMonitor)
super(NvpAdvancedPlugin, self).delete_health_monitor(context, id)
self._delete_resource_router_id_binding(
context, id, loadbalancer_db.HealthMonitor)
def create_pool_health_monitor(self, context,
health_monitor, pool_id):
monitor_id = health_monitor['health_monitor']['id']
pool = self.get_pool(context, pool_id)
monitors = pool.get('health_monitors')
if len(monitors) > 0:
msg = _("Vcns right now can only support "
"one monitor per pool")
LOG.error(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
#Check whether the pool is already associated with the vip
if not pool.get('vip_id'):
res = super(NvpAdvancedPlugin,
self).create_pool_health_monitor(context,
health_monitor,
pool_id)
return res
#Get the edge_id
edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id'])
res = super(NvpAdvancedPlugin,
self).create_pool_health_monitor(context,
health_monitor,
pool_id)
monitor = self.get_health_monitor(context, monitor_id)
#TODO(linb)Add Exception handle if error
self.vcns_driver.create_health_monitor(context, edge_id, monitor)
#Get updated pool
pool['health_monitors'].append(monitor['id'])
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to associate monitor with pool!"))
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.ERROR)
super(NvpAdvancedPlugin, self).delete_pool_health_monitor(
context, monitor_id, pool_id)
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
self._resource_set_status(
context, loadbalancer_db.PoolMonitorAssociation,
monitor_id, service_constants.ACTIVE, res,
pool_id=pool_id)
return res
def delete_pool_health_monitor(self, context, id, pool_id):
super(NvpAdvancedPlugin, self).delete_pool_health_monitor(
context, id, pool_id)
pool = self.get_pool(context, pool_id)
#Check whether the pool is already associated with the vip
if pool.get('vip_id'):
#Delete the monitor on vshield edge
edge_id = self._get_edge_id_by_vip_id(context, pool['vip_id'])
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.PENDING_UPDATE)
try:
self._vcns_update_pool(context, pool)
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(
_("Failed to update pool with pool_monitor!"))
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.ERROR)
#TODO(linb): Add exception handle if error
self.vcns_driver.delete_health_monitor(context, id, edge_id)
self._resource_set_status(
context, loadbalancer_db.Pool,
pool_id, service_constants.ACTIVE)
class VcnsCallbacks(object):
"""Edge callback implementation Callback functions for

View File

@ -67,7 +67,7 @@ class MaintenanceInProgress(NvpPluginException):
class NvpServicePluginException(q_exc.NeutronException):
"""NVP Service Plugin exceptions."""
message = _("An unexpected error happened "
"in the NVP Service Plugin:%(err_msg)s")
"in the NVP Service Plugin: %(err_msg)s")
class NvpServiceOverQuota(q_exc.Conflict):

View File

@ -17,8 +17,13 @@
from sqlalchemy.orm import exc
from neutron.openstack.common import log as logging
from neutron.plugins.nicira.common import exceptions as nvp_exc
from neutron.plugins.nicira.dbexts import vcns_models
from neutron.plugins.nicira.vshield.common import (
exceptions as vcns_exc)
LOG = logging.getLogger(__name__)
def add_vcns_router_binding(session, router_id, vse_id, lswitch_id, status):
@ -55,6 +60,7 @@ def delete_vcns_router_binding(session, router_id):
#
# Edge Firewall binding methods
#
def add_vcns_edge_firewallrule_binding(session, map_info):
with session.begin(subtransactions=True):
binding = vcns_models.VcnsEdgeFirewallRuleBinding(
@ -95,3 +101,103 @@ def cleanup_vcns_edge_firewallrule_binding(session, edge_id):
session.query(
vcns_models.VcnsEdgeFirewallRuleBinding).filter_by(
edge_id=edge_id).delete()
def add_vcns_edge_vip_binding(session, map_info):
with session.begin(subtransactions=True):
binding = vcns_models.VcnsEdgeVipBinding(
vip_id=map_info['vip_id'],
edge_id=map_info['edge_id'],
vip_vseid=map_info['vip_vseid'],
app_profileid=map_info['app_profileid'])
session.add(binding)
return binding
def get_vcns_edge_vip_binding(session, id):
with session.begin(subtransactions=True):
try:
qry = session.query(vcns_models.VcnsEdgeVipBinding)
return qry.filter_by(vip_id=id).one()
except exc.NoResultFound:
msg = _("VIP Resource binding with id:%s not found!") % id
LOG.exception(msg)
raise vcns_exc.VcnsNotFound(
resource='router_service_binding', msg=msg)
def delete_vcns_edge_vip_binding(session, id):
with session.begin(subtransactions=True):
qry = session.query(vcns_models.VcnsEdgeVipBinding)
if not qry.filter_by(vip_id=id).delete():
msg = _("VIP Resource binding with id:%s not found!") % id
LOG.exception(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
def add_vcns_edge_pool_binding(session, map_info):
with session.begin(subtransactions=True):
binding = vcns_models.VcnsEdgePoolBinding(
pool_id=map_info['pool_id'],
edge_id=map_info['edge_id'],
pool_vseid=map_info['pool_vseid'])
session.add(binding)
return binding
def get_vcns_edge_pool_binding(session, id, edge_id):
with session.begin(subtransactions=True):
return (session.query(vcns_models.VcnsEdgePoolBinding).
filter_by(pool_id=id, edge_id=edge_id).first())
def get_vcns_edge_pool_binding_by_vseid(session, edge_id, pool_vseid):
with session.begin(subtransactions=True):
try:
qry = session.query(vcns_models.VcnsEdgePoolBinding)
binding = qry.filter_by(edge_id=edge_id,
pool_vseid=pool_vseid).one()
except exc.NoResultFound:
msg = (_("Pool Resource binding with edge_id:%(edge_id)s "
"pool_vseid:%(pool_vseid)s not found!") %
{'edge_id': edge_id, 'pool_vseid': pool_vseid})
LOG.exception(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
return binding
def delete_vcns_edge_pool_binding(session, id, edge_id):
with session.begin(subtransactions=True):
qry = session.query(vcns_models.VcnsEdgePoolBinding)
if not qry.filter_by(pool_id=id, edge_id=edge_id).delete():
msg = _("Pool Resource binding with id:%s not found!") % id
LOG.exception(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)
def add_vcns_edge_monitor_binding(session, map_info):
with session.begin(subtransactions=True):
binding = vcns_models.VcnsEdgeMonitorBinding(
monitor_id=map_info['monitor_id'],
edge_id=map_info['edge_id'],
monitor_vseid=map_info['monitor_vseid'])
session.add(binding)
return binding
def get_vcns_edge_monitor_binding(session, id, edge_id):
with session.begin(subtransactions=True):
return (session.query(vcns_models.VcnsEdgeMonitorBinding).
filter_by(monitor_id=id, edge_id=edge_id).first())
def delete_vcns_edge_monitor_binding(session, id, edge_id):
with session.begin(subtransactions=True):
qry = session.query(vcns_models.VcnsEdgeMonitorBinding)
if not qry.filter_by(monitor_id=id, edge_id=edge_id).delete():
msg = _("Monitor Resource binding with id:%s not found!") % id
LOG.exception(msg)
raise nvp_exc.NvpServicePluginException(err_msg=msg)

View File

@ -51,3 +51,41 @@ class VcnsEdgeFirewallRuleBinding(model_base.BASEV2):
primary_key=True)
edge_id = sa.Column(sa.String(36), primary_key=True)
rule_vseid = sa.Column(sa.String(36))
class VcnsEdgePoolBinding(model_base.BASEV2):
"""Represents the mapping between neutron pool and Edge pool."""
__tablename__ = 'vcns_edge_pool_bindings'
pool_id = sa.Column(sa.String(36),
sa.ForeignKey("pools.id", ondelete="CASCADE"),
primary_key=True)
edge_id = sa.Column(sa.String(36), primary_key=True)
pool_vseid = sa.Column(sa.String(36))
class VcnsEdgeVipBinding(model_base.BASEV2):
"""Represents the mapping between neutron vip and Edge vip."""
__tablename__ = 'vcns_edge_vip_bindings'
vip_id = sa.Column(sa.String(36),
sa.ForeignKey("vips.id", ondelete="CASCADE"),
primary_key=True)
edge_id = sa.Column(sa.String(36))
vip_vseid = sa.Column(sa.String(36))
app_profileid = sa.Column(sa.String(36))
class VcnsEdgeMonitorBinding(model_base.BASEV2):
"""Represents the mapping between neutron monitor and Edge monitor."""
__tablename__ = 'vcns_edge_monitor_bindings'
monitor_id = sa.Column(sa.String(36),
sa.ForeignKey("healthmonitors.id",
ondelete="CASCADE"),
primary_key=True)
edge_id = sa.Column(sa.String(36), primary_key=True)
monitor_vseid = sa.Column(sa.String(36))

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 VMware, Inc,
# Copyright 2013 VMware, Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may

View File

@ -1,6 +1,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation.
# Copyright 2013 VMware, Inc
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may

View File

@ -17,6 +17,7 @@
# @author: Kaiwei Fan, VMware, Inc.
# @author: Bo Link, VMware, Inc.
from neutron.openstack.common import excutils
from neutron.openstack.common import jsonutils
from neutron.openstack.common import log as logging
from neutron.plugins.nicira.vshield.common import (
@ -118,6 +119,14 @@ class EdgeApplianceDriver(object):
status_level = RouterStatus.ROUTER_STATUS_ERROR
return status_level
def _enable_loadbalancer(self, edge):
if not edge.get('featureConfigs') or (
not edge['featureConfigs'].get('features')):
edge['featureConfigs'] = {'features': []}
edge['featureConfigs']['features'].append(
{'featureType': 'loadbalancer_4.0',
'enabled': True})
def get_edge_status(self, edge_id):
try:
response = self.vcns.get_edge_status(edge_id)[1]
@ -295,7 +304,7 @@ class EdgeApplianceDriver(object):
raise e
def deploy_edge(self, router_id, name, internal_network, jobdata=None,
wait_for_exec=False):
wait_for_exec=False, loadbalancer_enable=True):
task_name = 'deploying-%s' % name
edge_name = name
edge = self._assemble_edge(
@ -318,6 +327,8 @@ class EdgeApplianceDriver(object):
vcns_const.INTEGRATION_SUBNET_NETMASK,
type="internal")
edge['vnics']['vnics'].append(vnic_inside)
if loadbalancer_enable:
self._enable_loadbalancer(edge)
userdata = {
'request': edge,
'router_name': name,
@ -628,3 +639,24 @@ class EdgeApplianceDriver(object):
def delete_lswitch(self, lswitch_id):
self.vcns.delete_lswitch(lswitch_id)
def get_loadbalancer_config(self, edge_id):
try:
header, response = self.vcns.get_loadbalancer_config(
edge_id)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to get service config"))
return response
def enable_service_loadbalancer(self, edge_id):
config = self.get_loadbalancer_config(
edge_id)
if not config['enabled']:
config['enabled'] = True
try:
self.vcns.enable_service_loadbalancer(edge_id, config)
except exceptions.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to enable loadbalancer "
"service config"))

View File

@ -0,0 +1,338 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 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.
#
# @author: Leon Cui, VMware
from neutron.openstack.common import excutils
from neutron.openstack.common import log as logging
from neutron.plugins.nicira.dbexts import vcns_db
from neutron.plugins.nicira.vshield.common import (
constants as vcns_const)
from neutron.plugins.nicira.vshield.common import (
exceptions as vcns_exc)
from neutron.services.loadbalancer import constants as lb_constants
LOG = logging.getLogger(__name__)
BALANCE_MAP = {
lb_constants.LB_METHOD_ROUND_ROBIN: 'round-robin',
lb_constants.LB_METHOD_LEAST_CONNECTIONS: 'leastconn',
lb_constants.LB_METHOD_SOURCE_IP: 'source'
}
PROTOCOL_MAP = {
lb_constants.PROTOCOL_TCP: 'tcp',
lb_constants.PROTOCOL_HTTP: 'http',
lb_constants.PROTOCOL_HTTPS: 'tcp'
}
class EdgeLbDriver():
"""Implementation of driver APIs for
Edge Loadbalancer feature configuration
"""
def _convert_lb_vip(self, context, edge_id, vip, app_profileid):
pool_id = vip.get('pool_id')
poolid_map = vcns_db.get_vcns_edge_pool_binding(
context.session, pool_id, edge_id)
pool_vseid = poolid_map['pool_vseid']
return {
'name': vip.get('name'),
'ipAddress': vip.get('address'),
'protocol': vip.get('protocol'),
'port': vip.get('protocol_port'),
'defaultPoolId': pool_vseid,
'applicationProfileId': app_profileid
}
def _restore_lb_vip(self, context, edge_id, vip_vse):
pool_binding = vcns_db.get_vcns_edge_pool_binding_by_vseid(
context.session,
edge_id,
vip_vse['defaultPoolId'])
return {
'name': vip_vse['name'],
'address': vip_vse['ipAddress'],
'protocol': vip_vse['protocol'],
'protocol_port': vip_vse['port'],
'pool_id': pool_binding['pool_id']
}
def _convert_lb_pool(self, context, edge_id, pool, members):
vsepool = {
'name': pool.get('name'),
'algorithm': BALANCE_MAP.get(
pool.get('lb_method'),
'round-robin'),
'member': [],
'monitorId': []
}
for member in members:
vsepool['member'].append({
'ipAddress': member['address'],
'port': member['protocol_port']
})
##TODO(linb) right now, vse only accept at most one monitor per pool
monitors = pool.get('health_monitors')
if not monitors:
return vsepool
monitorid_map = vcns_db.get_vcns_edge_monitor_binding(
context.session,
monitors[0],
edge_id)
vsepool['monitorId'].append(monitorid_map['monitor_vseid'])
return vsepool
def _restore_lb_pool(self, context, edge_id, pool_vse):
#TODO(linb): Get more usefule info
return {
'name': pool_vse['name'],
}
def _convert_lb_monitor(self, context, monitor):
return {
'type': PROTOCOL_MAP.get(
monitor.get('type'), 'http'),
'interval': monitor.get('delay'),
'timeout': monitor.get('timeout'),
'maxRetries': monitor.get('max_retries'),
'name': monitor.get('id')
}
def _restore_lb_monitor(self, context, edge_id, monitor_vse):
return {
'delay': monitor_vse['interval'],
'timeout': monitor_vse['timeout'],
'max_retries': monitor_vse['maxRetries'],
'id': monitor_vse['name']
}
def _convert_app_profile(self, name, app_profile):
#TODO(linb): convert the session_persistence to
#corresponding app_profile
return {
"insertXForwardedFor": False,
"name": name,
"persistence": {
"method": "sourceip"
},
"serverSslEnabled": False,
"sslPassthrough": False,
"template": "HTTP"
}
def create_vip(self, context, edge_id, vip):
app_profile = self._convert_app_profile(
vip['name'], vip.get('session_persistence'))
try:
header, response = self.vcns.create_app_profile(
edge_id, app_profile)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create app profile on edge: %s"),
edge_id)
objuri = header['location']
app_profileid = objuri[objuri.rfind("/") + 1:]
vip_new = self._convert_lb_vip(context, edge_id, vip, app_profileid)
try:
header, response = self.vcns.create_vip(
edge_id, vip_new)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create vip on vshield edge: %s"),
edge_id)
objuri = header['location']
vip_vseid = objuri[objuri.rfind("/") + 1:]
# Add the vip mapping
map_info = {
"vip_id": vip['id'],
"vip_vseid": vip_vseid,
"edge_id": edge_id,
"app_profileid": app_profileid
}
vcns_db.add_vcns_edge_vip_binding(context.session, map_info)
def get_vip(self, context, id):
vip_binding = vcns_db.get_vcns_edge_vip_binding(context.session, id)
edge_id = vip_binding[vcns_const.EDGE_ID]
vip_vseid = vip_binding['vip_vseid']
try:
response = self.vcns.get_vip(edge_id, vip_vseid)[1]
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to get vip on edge"))
return self._restore_lb_vip(context, edge_id, response)
def update_vip(self, context, vip):
vip_binding = vcns_db.get_vcns_edge_vip_binding(
context.session, vip['id'])
edge_id = vip_binding[vcns_const.EDGE_ID]
vip_vseid = vip_binding.get('vip_vseid')
app_profileid = vip_binding.get('app_profileid')
vip_new = self._convert_lb_vip(context, edge_id, vip, app_profileid)
try:
self.vcns.update_vip(edge_id, vip_vseid, vip_new)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update vip on edge: %s"), edge_id)
def delete_vip(self, context, id):
vip_binding = vcns_db.get_vcns_edge_vip_binding(
context.session, id)
edge_id = vip_binding[vcns_const.EDGE_ID]
vip_vseid = vip_binding['vip_vseid']
app_profileid = vip_binding['app_profileid']
try:
self.vcns.delete_vip(edge_id, vip_vseid)
self.vcns.delete_app_profile(edge_id, app_profileid)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to delete vip on edge: %s"), edge_id)
vcns_db.delete_vcns_edge_vip_binding(context.session, id)
def create_pool(self, context, edge_id, pool, members):
pool_new = self._convert_lb_pool(context, edge_id, pool, members)
try:
header = self.vcns.create_pool(edge_id, pool_new)[0]
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create pool"))
objuri = header['location']
pool_vseid = objuri[objuri.rfind("/") + 1:]
# update the pool mapping table
map_info = {
"pool_id": pool['id'],
"pool_vseid": pool_vseid,
"edge_id": edge_id
}
vcns_db.add_vcns_edge_pool_binding(context.session, map_info)
def get_pool(self, context, id, edge_id):
pool_binding = vcns_db.get_vcns_edge_pool_binding(
context.session, id, edge_id)
if not pool_binding:
msg = (_("pool_binding not found with id: %(id)s "
"edge_id: %(edge_id)s") % {
'id': id,
'edge_id': edge_id})
LOG.error(msg)
raise vcns_exc.VcnsNotFound(
resource='router_service_binding', msg=msg)
pool_vseid = pool_binding['pool_vseid']
try:
response = self.vcns.get_pool(edge_id, pool_vseid)[1]
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to get pool on edge"))
return self._restore_lb_pool(context, edge_id, response)
def update_pool(self, context, edge_id, pool, members):
pool_binding = vcns_db.get_vcns_edge_pool_binding(
context.session, pool['id'], edge_id)
pool_vseid = pool_binding['pool_vseid']
pool_new = self._convert_lb_pool(context, edge_id, pool, members)
try:
self.vcns.update_pool(edge_id, pool_vseid, pool_new)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update pool"))
def delete_pool(self, context, id, edge_id):
pool_binding = vcns_db.get_vcns_edge_pool_binding(
context.session, id, edge_id)
pool_vseid = pool_binding['pool_vseid']
try:
self.vcns.delete_pool(edge_id, pool_vseid)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to delete pool"))
vcns_db.delete_vcns_edge_pool_binding(
context.session, id, edge_id)
def create_health_monitor(self, context, edge_id, health_monitor):
monitor_new = self._convert_lb_monitor(context, health_monitor)
try:
header = self.vcns.create_health_monitor(edge_id, monitor_new)[0]
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to create monitor on edge: %s"),
edge_id)
objuri = header['location']
monitor_vseid = objuri[objuri.rfind("/") + 1:]
# update the health_monitor mapping table
map_info = {
"monitor_id": health_monitor['id'],
"monitor_vseid": monitor_vseid,
"edge_id": edge_id
}
vcns_db.add_vcns_edge_monitor_binding(context.session, map_info)
def get_health_monitor(self, context, id, edge_id):
monitor_binding = vcns_db.get_vcns_edge_monitor_binding(
context.session, id, edge_id)
if not monitor_binding:
msg = (_("monitor_binding not found with id: %(id)s "
"edge_id: %(edge_id)s") % {
'id': id,
'edge_id': edge_id})
LOG.error(msg)
raise vcns_exc.VcnsNotFound(
resource='router_service_binding', msg=msg)
monitor_vseid = monitor_binding['monitor_vseid']
try:
response = self.vcns.get_health_monitor(edge_id, monitor_vseid)[1]
except vcns_exc.VcnsApiException as e:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to get monitor on edge: %s"),
e.response)
return self._restore_lb_monitor(context, edge_id, response)
def update_health_monitor(self, context, edge_id,
old_health_monitor, health_monitor):
monitor_binding = vcns_db.get_vcns_edge_monitor_binding(
context.session,
old_health_monitor['id'], edge_id)
monitor_vseid = monitor_binding['monitor_vseid']
monitor_new = self._convert_lb_monitor(
context, health_monitor)
try:
self.vcns.update_health_monitor(
edge_id, monitor_vseid, monitor_new)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to update monitor on edge: %s"),
edge_id)
def delete_health_monitor(self, context, id, edge_id):
monitor_binding = vcns_db.get_vcns_edge_monitor_binding(
context.session, id, edge_id)
monitor_vseid = monitor_binding['monitor_vseid']
try:
self.vcns.delete_health_monitor(edge_id, monitor_vseid)
except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception():
LOG.exception(_("Failed to delete monitor"))
vcns_db.delete_vcns_edge_monitor_binding(
context.session, id, edge_id)

View File

@ -32,6 +32,13 @@ URI_PREFIX = "/api/4.0/edges"
FIREWALL_SERVICE = "firewall/config"
FIREWALL_RULE_RESOURCE = "rules"
#LbaaS Constants
LOADBALANCER_SERVICE = "loadbalancer/config"
VIP_RESOURCE = "virtualservers"
POOL_RESOURCE = "pools"
MONITOR_RESOURCE = "monitors"
APP_PROFILE_RESOURCE = "applicationprofiles"
class Vcns(object):
@ -111,6 +118,14 @@ class Vcns(object):
uri = "/api/ws.v1/lswitch/%s" % lswitch_id
return self.do_request(HTTP_DELETE, uri)
def get_loadbalancer_config(self, edge_id):
uri = self._build_uri_path(edge_id, LOADBALANCER_SERVICE)
return self.do_request(HTTP_GET, uri, decode=True)
def enable_service_loadbalancer(self, edge_id, config):
uri = self._build_uri_path(edge_id, LOADBALANCER_SERVICE)
return self.do_request(HTTP_PUT, uri, config)
def update_firewall(self, edge_id, fw_req):
uri = self._build_uri_path(
edge_id, FIREWALL_SERVICE)
@ -159,6 +174,96 @@ class Vcns(object):
vcns_rule_id)
return self.do_request(HTTP_GET, uri, decode=True)
#
#Edge LBAAS call helper
#
def create_vip(self, edge_id, vip_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
VIP_RESOURCE)
return self.do_request(HTTP_POST, uri, vip_new)
def get_vip(self, edge_id, vip_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
VIP_RESOURCE, vip_vseid)
return self.do_request(HTTP_GET, uri, decode=True)
def update_vip(self, edge_id, vip_vseid, vip_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
VIP_RESOURCE, vip_vseid)
return self.do_request(HTTP_PUT, uri, vip_new)
def delete_vip(self, edge_id, vip_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
VIP_RESOURCE, vip_vseid)
return self.do_request(HTTP_DELETE, uri)
def create_pool(self, edge_id, pool_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
POOL_RESOURCE)
return self.do_request(HTTP_POST, uri, pool_new)
def get_pool(self, edge_id, pool_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
POOL_RESOURCE, pool_vseid)
return self.do_request(HTTP_GET, uri, decode=True)
def update_pool(self, edge_id, pool_vseid, pool_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
POOL_RESOURCE, pool_vseid)
return self.do_request(HTTP_PUT, uri, pool_new)
def delete_pool(self, edge_id, pool_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
POOL_RESOURCE, pool_vseid)
return self.do_request(HTTP_DELETE, uri)
def create_health_monitor(self, edge_id, monitor_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
MONITOR_RESOURCE)
return self.do_request(HTTP_POST, uri, monitor_new)
def get_health_monitor(self, edge_id, monitor_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
MONITOR_RESOURCE, monitor_vseid)
return self.do_request(HTTP_GET, uri, decode=True)
def update_health_monitor(self, edge_id, monitor_vseid, monitor_new):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
MONITOR_RESOURCE,
monitor_vseid)
return self.do_request(HTTP_PUT, uri, monitor_new)
def delete_health_monitor(self, edge_id, monitor_vseid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
MONITOR_RESOURCE,
monitor_vseid)
return self.do_request(HTTP_DELETE, uri)
def create_app_profile(self, edge_id, app_profile):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
APP_PROFILE_RESOURCE)
return self.do_request(HTTP_POST, uri, app_profile)
def delete_app_profile(self, edge_id, app_profileid):
uri = self._build_uri_path(
edge_id, LOADBALANCER_SERVICE,
APP_PROFILE_RESOURCE,
app_profileid)
return self.do_request(HTTP_DELETE, uri)
def _build_uri_path(self, edge_id,
service,
resource=None,

View File

@ -18,15 +18,21 @@
from oslo.config import cfg
from neutron.plugins.nicira.common import config # noqa
from neutron.openstack.common import log as logging
from neutron.plugins.nicira.common import config as nicira_cfg # noqa
from neutron.plugins.nicira.vshield import edge_appliance_driver
from neutron.plugins.nicira.vshield import edge_firewall_driver
from neutron.plugins.nicira.vshield import edge_loadbalancer_driver
from neutron.plugins.nicira.vshield.tasks import tasks
from neutron.plugins.nicira.vshield import vcns
LOG = logging.getLogger(__name__)
class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
edge_firewall_driver.EdgeFirewallDriver):
edge_firewall_driver.EdgeFirewallDriver,
edge_loadbalancer_driver.EdgeLbDriver):
def __init__(self, callbacks):
super(VcnsDriver, self).__init__()

View File

@ -64,6 +64,10 @@ class LoadBalancerTestMixin(object):
for k in loadbalancer.RESOURCE_ATTRIBUTE_MAP.keys()
)
def _get_vip_optional_args(self):
return ('description', 'subnet_id', 'address',
'session_persistence', 'connection_limit')
def _create_vip(self, fmt, name, pool_id, protocol, protocol_port,
admin_state_up, expected_res_status=None, **kwargs):
data = {'vip': {'name': name,
@ -72,8 +76,8 @@ class LoadBalancerTestMixin(object):
'protocol_port': protocol_port,
'admin_state_up': admin_state_up,
'tenant_id': self._tenant_id}}
for arg in ('description', 'subnet_id', 'address',
'session_persistence', 'connection_limit'):
args = self._get_vip_optional_args()
for arg in args:
if arg in kwargs and kwargs[arg] is not None:
data['vip'][arg] = kwargs[arg]
@ -255,7 +259,8 @@ class LoadBalancerTestMixin(object):
class LoadBalancerPluginDbTestCase(LoadBalancerTestMixin,
test_db_plugin.NeutronDbPluginV2TestCase):
def setUp(self, core_plugin=None, lb_plugin=None, lbaas_provider=None):
def setUp(self, core_plugin=None, lb_plugin=None, lbaas_provider=None,
ext_mgr=None):
service_plugins = {'lb_plugin_name': DB_LB_PLUGIN_KLASS}
if not lbaas_provider:
lbaas_provider = (
@ -269,12 +274,18 @@ class LoadBalancerPluginDbTestCase(LoadBalancerTestMixin,
sdb.ServiceTypeManager._instance = None
super(LoadBalancerPluginDbTestCase, self).setUp(
ext_mgr=ext_mgr,
service_plugins=service_plugins
)
self._subnet_id = _subnet_id
self.plugin = loadbalancer_plugin.LoadBalancerPlugin()
if not ext_mgr:
self.plugin = loadbalancer_plugin.LoadBalancerPlugin()
ext_mgr = PluginAwareExtensionManager(
extensions_path,
{constants.LOADBALANCER: self.plugin}
)
app = config.load_paste_app('extensions_test_app')
self.ext_api = ExtensionMiddleware(app, ext_mgr=ext_mgr)
get_lbaas_agent_patcher = mock.patch(
'neutron.services.loadbalancer.agent_scheduler'
@ -285,12 +296,7 @@ class LoadBalancerPluginDbTestCase(LoadBalancerTestMixin,
self.addCleanup(mock.patch.stopall)
self.addCleanup(cfg.CONF.reset)
ext_mgr = PluginAwareExtensionManager(
extensions_path,
{constants.LOADBALANCER: self.plugin}
)
app = config.load_paste_app('extensions_test_app')
self.ext_api = ExtensionMiddleware(app, ext_mgr=ext_mgr)
self._subnet_id = _subnet_id
class TestLoadBalancer(LoadBalancerPluginDbTestCase):

View File

@ -31,6 +31,7 @@ from neutron.tests.unit.nicira import SERVICE_PLUGIN_NAME
from neutron.tests.unit.nicira import test_nicira_plugin
from neutron.tests.unit.nicira import VCNS_NAME
from neutron.tests.unit.nicira.vshield import fake_vcns
from neutron.tests.unit import test_l3_plugin
_uuid = uuidutils.generate_uuid
@ -67,7 +68,8 @@ class NvpRouterTestCase(test_nicira_plugin.TestNiciraL3NatTestCase):
service_plugins=service_plugins)
class ServiceRouterTest(test_nicira_plugin.NiciraL3NatTest):
class ServiceRouterTest(test_nicira_plugin.NiciraL3NatTest,
test_l3_plugin.L3NatTestCaseMixin):
def vcns_patch(self):
instance = self.mock_vcns.start()
@ -94,6 +96,10 @@ class ServiceRouterTest(test_nicira_plugin.NiciraL3NatTest):
self.fc2.create_lswitch)
instance.return_value.delete_lswitch.side_effect = (
self.fc2.delete_lswitch)
instance.return_value.get_loadbalancer_config.side_effect = (
self.fc2.get_loadbalancer_config)
instance.return_value.enable_service_loadbalancer.side_effect = (
self.fc2.enable_service_loadbalancer)
def setUp(self, ext_mgr=None, service_plugins=None):
cfg.CONF.set_override('api_extensions_path', NVPEXT_PATH)
@ -113,7 +119,7 @@ class ServiceRouterTest(test_nicira_plugin.NiciraL3NatTest):
self.fc2.set_fake_nvpapi(self.fc)
self.addCleanup(self.fc2.reset_all)
self.addCleanup(self.mock_vcns.stop)
self.addCleanup(mock.patch.stopall)
def tearDown(self):
plugin = NeutronManager.get_plugin()

View File

@ -0,0 +1,433 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 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.
#
# @author: linb, VMware
import contextlib
from webob import exc as web_exc
from neutron.api.v2 import attributes
from neutron import context
from neutron.db.loadbalancer import loadbalancer_db as ldb
from neutron.extensions import loadbalancer as lb
from neutron import manager
from neutron.openstack.common import uuidutils
from neutron.tests.unit.db.loadbalancer import test_db_loadbalancer
from neutron.tests.unit.nicira import test_edge_router
_uuid = uuidutils.generate_uuid
LBAAS_PLUGIN_CLASS = (
"neutron.plugins.nicira.NeutronServicePlugin.NvpAdvancedPlugin"
)
class LoadBalancerTestExtensionManager(
test_edge_router.ServiceRouterTestExtensionManager):
def get_resources(self):
# If l3 resources have been loaded and updated by main API
# router, update the map in the l3 extension so it will load
# the same attributes as the API router
resources = super(LoadBalancerTestExtensionManager,
self).get_resources()
lb_attr_map = lb.RESOURCE_ATTRIBUTE_MAP.copy()
for res in lb.RESOURCE_ATTRIBUTE_MAP.keys():
attr_info = attributes.RESOURCE_ATTRIBUTE_MAP.get(res)
if attr_info:
lb.RESOURCE_ATTRIBUTE_MAP[res] = attr_info
lb_resources = lb.Loadbalancer.get_resources()
# restore the original resources once the controllers are created
lb.RESOURCE_ATTRIBUTE_MAP = lb_attr_map
resources.extend(lb_resources)
return resources
class TestLoadbalancerPlugin(
test_db_loadbalancer.LoadBalancerPluginDbTestCase,
test_edge_router.ServiceRouterTest):
def vcns_loadbalancer_patch(self):
instance = self.vcns_instance
instance.return_value.create_vip.side_effect = (
self.fc2.create_vip)
instance.return_value.get_vip.side_effect = (
self.fc2.get_vip)
instance.return_value.update_vip.side_effect = (
self.fc2.update_vip)
instance.return_value.delete_vip.side_effect = (
self.fc2.delete_vip)
instance.return_value.create_pool.side_effect = (
self.fc2.create_pool)
instance.return_value.get_pool.side_effect = (
self.fc2.get_pool)
instance.return_value.update_pool.side_effect = (
self.fc2.update_pool)
instance.return_value.delete_pool.side_effect = (
self.fc2.delete_pool)
instance.return_value.create_health_monitor.side_effect = (
self.fc2.create_health_monitor)
instance.return_value.get_health_monitor.side_effect = (
self.fc2.get_health_monitor)
instance.return_value.update_health_monitor.side_effect = (
self.fc2.update_health_monitor)
instance.return_value.delete_health_monitor.side_effect = (
self.fc2.delete_health_monitor)
instance.return_value.create_app_profile.side_effect = (
self.fc2.create_app_profile)
instance.return_value.delete_app_profile.side_effect = (
self.fc2.delete_app_profile)
def setUp(self):
# Save the global RESOURCE_ATTRIBUTE_MAP
self.saved_attr_map = {}
for resource, attrs in attributes.RESOURCE_ATTRIBUTE_MAP.iteritems():
self.saved_attr_map[resource] = attrs.copy()
super(TestLoadbalancerPlugin, self).setUp(
ext_mgr=LoadBalancerTestExtensionManager(),
lb_plugin=LBAAS_PLUGIN_CLASS)
self.vcns_loadbalancer_patch()
self.plugin = manager.NeutronManager.get_plugin()
self.router_id = None
def tearDown(self):
super(TestLoadbalancerPlugin, self).tearDown()
# Restore the global RESOURCE_ATTRIBUTE_MAP
attributes.RESOURCE_ATTRIBUTE_MAP = self.saved_attr_map
self.ext_api = None
self.plugin = None
def _fake_router_edge_mapping(self):
req = self._create_router(self.fmt, self._tenant_id)
res = self.deserialize(self.fmt, req)
self.router_id = res['router']['id']
def _get_vip_optional_args(self):
args = super(TestLoadbalancerPlugin, self)._get_vip_optional_args()
return args + ('router_id',)
def test_update_healthmonitor(self):
self._fake_router_edge_mapping()
keys = [('type', "TCP"),
('tenant_id', self._tenant_id),
('delay', 20),
('timeout', 20),
('max_retries', 2),
('admin_state_up', False)]
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, health_mon):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
with self.vip(
router_id=self.router_id, pool=pool,
subnet=subnet):
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
health_mon, pool['pool']['id']
)
data = {'health_monitor': {'delay': 20,
'timeout': 20,
'max_retries': 2,
'admin_state_up': False}}
req = self.new_update_request(
"health_monitors",
data,
health_mon['health_monitor']['id'])
res = self.deserialize(
self.fmt, req.get_response(self.ext_api))
for k, v in keys:
self.assertEqual(res['health_monitor'][k], v)
def test_delete_healthmonitor(self):
ctx = context.get_admin_context()
self._fake_router_edge_mapping()
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor(no_delete=True)
) as (subnet, pool, health_mon):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
with self.vip(
router_id=self.router_id, pool=pool,
subnet=subnet):
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
health_mon, pool['pool']['id']
)
req = self.new_delete_request('health_monitors',
health_mon['health_monitor']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 204)
qry = ctx.session.query(ldb.HealthMonitor)
qry = qry.filter_by(id=health_mon['health_monitor']['id'])
self.assertIsNone(qry.first())
def test_create_vip(self, **extras):
self._fake_router_edge_mapping()
expected = {
'name': 'vip1',
'description': '',
'protocol_port': 80,
'protocol': 'HTTP',
'connection_limit': -1,
'admin_state_up': True,
'status': 'PENDING_CREATE',
'tenant_id': self._tenant_id,
}
expected.update(extras)
name = expected['name']
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
expected['pool_id'] = pool['pool']['id']
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id, name=name,
pool=pool, subnet=subnet, **extras) as vip:
for k in ('id', 'address', 'port_id', 'pool_id'):
self.assertTrue(vip['vip'].get(k, None))
expected['status'] = 'ACTIVE'
self.assertEqual(
dict((k, v)
for k, v in vip['vip'].items() if k in expected),
expected
)
def test_update_vip(self):
self._fake_router_edge_mapping()
name = 'new_vip'
keys = [('name', name),
('address', "10.0.0.2"),
('protocol_port', 80),
('connection_limit', 100),
('admin_state_up', False),
('status', 'ACTIVE')]
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id, name=name,
pool=pool, subnet=subnet) as vip:
keys.append(('subnet_id', vip['vip']['subnet_id']))
data = {'vip': {'name': name,
'connection_limit': 100,
'session_persistence':
{'type': "APP_COOKIE",
'cookie_name': "jesssionId"},
'admin_state_up': False}}
req = self.new_update_request(
'vips', data, vip['vip']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
for k, v in keys:
self.assertEqual(res['vip'][k], v)
def test_delete_vip(self):
self._fake_router_edge_mapping()
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id,
pool=pool, subnet=subnet, no_delete=True) as vip:
req = self.new_delete_request('vips',
vip['vip']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 204)
def test_update_pool(self):
self._fake_router_edge_mapping()
data = {'pool': {'name': "new_pool",
'admin_state_up': False}}
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id,
pool=pool, subnet=subnet):
req = self.new_update_request(
'pools', data, pool['pool']['id'])
res = self.deserialize(self.fmt,
req.get_response(self.ext_api))
for k, v in data['pool'].items():
self.assertEqual(res['pool'][k], v)
def test_create_member(self):
self._fake_router_edge_mapping()
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
pool_id = pool['pool']['id']
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id,
pool=pool, subnet=subnet):
with contextlib.nested(
self.member(address='192.168.1.100',
protocol_port=80,
pool_id=pool_id),
self.member(router_id=self.router_id,
address='192.168.1.101',
protocol_port=80,
pool_id=pool_id)) as (member1, member2):
req = self.new_show_request('pools',
pool_id,
fmt=self.fmt)
pool_update = self.deserialize(
self.fmt,
req.get_response(self.ext_api)
)
self.assertIn(member1['member']['id'],
pool_update['pool']['members'])
self.assertIn(member2['member']['id'],
pool_update['pool']['members'])
def _show_pool(self, pool_id):
req = self.new_show_request('pools', pool_id, fmt=self.fmt)
res = req.get_response(self.ext_api)
self.assertEqual(web_exc.HTTPOk.code, res.status_int)
return self.deserialize(self.fmt, res)
def test_update_member(self):
self._fake_router_edge_mapping()
with contextlib.nested(
self.subnet(),
self.pool(name="pool1"),
self.pool(name="pool2"),
self.health_monitor()
) as (subnet, pool1, pool2, monitor):
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool1['pool']['id']
)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool2['pool']['id']
)
with self.vip(
router_id=self.router_id,
pool=pool1, subnet=subnet):
keys = [('address', "192.168.1.100"),
('tenant_id', self._tenant_id),
('protocol_port', 80),
('weight', 10),
('pool_id', pool2['pool']['id']),
('admin_state_up', False),
('status', 'ACTIVE')]
with self.member(
pool_id=pool1['pool']['id']) as member:
pool1_update = self._show_pool(pool1['pool']['id'])
self.assertEqual(len(pool1_update['pool']['members']), 1)
pool2_update = self._show_pool(pool2['pool']['id'])
self.assertEqual(len(pool1_update['pool']['members']), 1)
self.assertFalse(pool2_update['pool']['members'])
data = {'member': {'pool_id': pool2['pool']['id'],
'weight': 10,
'admin_state_up': False}}
req = self.new_update_request('members',
data,
member['member']['id'])
raw_res = req.get_response(self.ext_api)
self.assertEquals(web_exc.HTTPOk.code, raw_res.status_int)
res = self.deserialize(self.fmt, raw_res)
for k, v in keys:
self.assertEqual(res['member'][k], v)
pool1_update = self._show_pool(pool1['pool']['id'])
pool2_update = self._show_pool(pool2['pool']['id'])
self.assertEqual(len(pool2_update['pool']['members']), 1)
self.assertFalse(pool1_update['pool']['members'])
def test_delete_member(self):
self._fake_router_edge_mapping()
with contextlib.nested(
self.subnet(),
self.pool(),
self.health_monitor()
) as (subnet, pool, monitor):
pool_id = pool['pool']['id']
net_id = subnet['subnet']['network_id']
self._set_net_external(net_id)
self.plugin.create_pool_health_monitor(
context.get_admin_context(),
monitor, pool['pool']['id']
)
with self.vip(
router_id=self.router_id,
pool=pool, subnet=subnet):
with self.member(pool_id=pool_id,
no_delete=True) as member:
req = self.new_delete_request('members',
member['member']['id'])
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, 204)
pool_update = self._show_pool(pool['pool']['id'])
self.assertFalse(pool_update['pool']['members'])

View File

@ -124,8 +124,7 @@ class NiciraPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
ext_mgr=ext_mgr)
cfg.CONF.set_override('metadata_mode', None, 'NVP')
self.addCleanup(self.fc.reset_all)
self.addCleanup(self.mock_nvpapi.stop)
self.addCleanup(patch_sync.stop)
self.addCleanup(mock.patch.stopall)
class TestNiciraBasicGet(test_plugin.TestBasicGet, NiciraPluginV2TestCase):

View File

@ -48,6 +48,11 @@ class FakeVcns(object):
"firewallRules": []
}
}
self._fake_virtualservers_dict = {}
self._fake_pools_dict = {}
self._fake_monitors_dict = {}
self._fake_app_profiles_dict = {}
self._fake_loadbalancer_config = {}
def set_fake_nvpapi(self, fake_nvpapi):
self._fake_nvpapi = fake_nvpapi
@ -363,6 +368,173 @@ class FakeVcns(object):
break
return self.return_helper(header, response)
#
#Fake Edge LBAAS call
#
def create_vip(self, edge_id, vip_new):
if not self._fake_virtualservers_dict.get(edge_id):
self._fake_virtualservers_dict[edge_id] = {}
vip_vseid = uuidutils.generate_uuid()
self._fake_virtualservers_dict[edge_id][vip_vseid] = vip_new
header = {
'status': 204,
'location': "https://host/api/4.0/edges/edge_id"
"/loadbalancer/config/%s" % vip_vseid}
response = ""
return self.return_helper(header, response)
def get_vip(self, edge_id, vip_vseid):
header = {'status': 404}
response = ""
if not self._fake_virtualservers_dict.get(edge_id) or (
not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
response = self._fake_virtualservers_dict[edge_id][vip_vseid]
return self.return_helper(header, response)
def update_vip(self, edge_id, vip_vseid, vip_new):
header = {'status': 404}
response = ""
if not self._fake_virtualservers_dict.get(edge_id) or (
not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
self._fake_virtualservers_dict[edge_id][vip_vseid].update(
vip_new)
return self.return_helper(header, response)
def delete_vip(self, edge_id, vip_vseid):
header = {'status': 404}
response = ""
if not self._fake_virtualservers_dict.get(edge_id) or (
not self._fake_virtualservers_dict[edge_id].get(vip_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
del self._fake_virtualservers_dict[edge_id][vip_vseid]
return self.return_helper(header, response)
def create_pool(self, edge_id, pool_new):
if not self._fake_pools_dict.get(edge_id):
self._fake_pools_dict[edge_id] = {}
pool_vseid = uuidutils.generate_uuid()
self._fake_pools_dict[edge_id][pool_vseid] = pool_new
header = {
'status': 204,
'location': "https://host/api/4.0/edges/edge_id"
"/loadbalancer/config/%s" % pool_vseid}
response = ""
return self.return_helper(header, response)
def get_pool(self, edge_id, pool_vseid):
header = {'status': 404}
response = ""
if not self._fake_pools_dict.get(edge_id) or (
not self._fake_pools_dict[edge_id].get(pool_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
response = self._fake_pools_dict[edge_id][pool_vseid]
return self.return_helper(header, response)
def update_pool(self, edge_id, pool_vseid, pool_new):
header = {'status': 404}
response = ""
if not self._fake_pools_dict.get(edge_id) or (
not self._fake_pools_dict[edge_id].get(pool_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
self._fake_pools_dict[edge_id][pool_vseid].update(
pool_new)
return self.return_helper(header, response)
def delete_pool(self, edge_id, pool_vseid):
header = {'status': 404}
response = ""
if not self._fake_pools_dict.get(edge_id) or (
not self._fake_pools_dict[edge_id].get(pool_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
del self._fake_pools_dict[edge_id][pool_vseid]
return self.return_helper(header, response)
def create_health_monitor(self, edge_id, monitor_new):
if not self._fake_monitors_dict.get(edge_id):
self._fake_monitors_dict[edge_id] = {}
monitor_vseid = uuidutils.generate_uuid()
self._fake_monitors_dict[edge_id][monitor_vseid] = monitor_new
header = {
'status': 204,
'location': "https://host/api/4.0/edges/edge_id"
"/loadbalancer/config/%s" % monitor_vseid}
response = ""
return self.return_helper(header, response)
def get_health_monitor(self, edge_id, monitor_vseid):
header = {'status': 404}
response = ""
if not self._fake_monitors_dict.get(edge_id) or (
not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
response = self._fake_monitors_dict[edge_id][monitor_vseid]
return self.return_helper(header, response)
def update_health_monitor(self, edge_id, monitor_vseid, monitor_new):
header = {'status': 404}
response = ""
if not self._fake_monitors_dict.get(edge_id) or (
not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
self._fake_monitors_dict[edge_id][monitor_vseid].update(
monitor_new)
return self.return_helper(header, response)
def delete_health_monitor(self, edge_id, monitor_vseid):
header = {'status': 404}
response = ""
if not self._fake_monitors_dict.get(edge_id) or (
not self._fake_monitors_dict[edge_id].get(monitor_vseid)):
return self.return_helper(header, response)
header = {'status': 204}
del self._fake_monitors_dict[edge_id][monitor_vseid]
return self.return_helper(header, response)
def create_app_profile(self, edge_id, app_profile):
if not self._fake_app_profiles_dict.get(edge_id):
self._fake_app_profiles_dict[edge_id] = {}
app_profileid = uuidutils.generate_uuid()
self._fake_app_profiles_dict[edge_id][app_profileid] = app_profile
header = {
'status': 204,
'location': "https://host/api/4.0/edges/edge_id"
"/loadbalancer/config/%s" % app_profileid}
response = ""
return self.return_helper(header, response)
def delete_app_profile(self, edge_id, app_profileid):
header = {'status': 404}
response = ""
if not self._fake_app_profiles_dict.get(edge_id) or (
not self._fake_app_profiles_dict[edge_id].get(app_profileid)):
return self.return_helper(header, response)
header = {'status': 204}
del self._fake_app_profiles_dict[edge_id][app_profileid]
return self.return_helper(header, response)
def get_loadbalancer_config(self, edge_id):
header = {'status': 204}
response = {'config': False}
if self._fake_loadbalancer_config[edge_id]:
response['config'] = self._fake_loadbalancer_config[edge_id]
return self.return_helper(header, response)
def enable_service_loadbalancer(self, edge_id, config):
header = {'status': 204}
response = ""
self._fake_loadbalancer_config[edge_id] = True
return self.return_helper(header, response)
def return_helper(self, header, response):
status = int(header['status'])
if 200 <= status <= 300:
@ -379,3 +551,8 @@ class FakeVcns(object):
self._edges.clear()
self._lswitches.clear()
self.fake_firewall_dict = {}
self._fake_virtualservers_dict = {}
self._fake_pools_dict = {}
self._fake_monitors_dict = {}
self._fake_app_profiles_dict = {}
self._fake_loadbalancer_config = {}

View File

@ -0,0 +1,233 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright 2013 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.
#
# @author: linb, VMware
import mock
from neutron.common import config as n_config
from neutron import context
from neutron.openstack.common import uuidutils
from neutron.plugins.nicira.dbexts import vcns_db
from neutron.plugins.nicira.vshield import (
vcns_driver)
from neutron.plugins.nicira.vshield.common import (
exceptions as vcns_exc)
from neutron.tests.unit.db.loadbalancer import test_db_loadbalancer
from neutron.tests.unit.nicira import get_fake_conf
from neutron.tests.unit.nicira import VCNS_NAME
from neutron.tests.unit.nicira.vshield import fake_vcns
_uuid = uuidutils.generate_uuid
VSE_ID = 'edge-1'
POOL_MAP_INFO = {
'pool_id': None,
'edge_id': VSE_ID,
'pool_vseid': 'pool-1'}
VCNS_CONFIG_FILE = get_fake_conf("vcns.ini.test")
class VcnsDriverTestCase(test_db_loadbalancer.LoadBalancerPluginDbTestCase):
def vcns_loadbalancer_patch(self):
instance = self.mock_vcns.start()
instance.return_value.create_vip.side_effect = (
self.fc2.create_vip)
instance.return_value.get_vip.side_effect = (
self.fc2.get_vip)
instance.return_value.update_vip.side_effect = (
self.fc2.update_vip)
instance.return_value.delete_vip.side_effect = (
self.fc2.delete_vip)
instance.return_value.create_pool.side_effect = (
self.fc2.create_pool)
instance.return_value.get_pool.side_effect = (
self.fc2.get_pool)
instance.return_value.update_pool.side_effect = (
self.fc2.update_pool)
instance.return_value.delete_pool.side_effect = (
self.fc2.delete_pool)
instance.return_value.create_health_monitor.side_effect = (
self.fc2.create_health_monitor)
instance.return_value.get_health_monitor.side_effect = (
self.fc2.get_health_monitor)
instance.return_value.update_health_monitor.side_effect = (
self.fc2.update_health_monitor)
instance.return_value.delete_health_monitor.side_effect = (
self.fc2.delete_health_monitor)
instance.return_value.create_app_profile.side_effect = (
self.fc2.create_app_profile)
instance.return_value.delete_app_profile.side_effect = (
self.fc2.delete_app_profile)
self.pool_id = None
self.vip_id = None
def setUp(self):
n_config.parse(['--config-file', VCNS_CONFIG_FILE])
# mock vcns
self.fc2 = fake_vcns.FakeVcns(unique_router_name=False)
self.mock_vcns = mock.patch(VCNS_NAME, autospec=True)
self.vcns_loadbalancer_patch()
self.nvp_service_plugin_callback = mock.Mock()
self.driver = vcns_driver.VcnsDriver(self.nvp_service_plugin_callback)
super(VcnsDriverTestCase, self).setUp()
self.addCleanup(self.fc2.reset_all)
self.addCleanup(self.mock_vcns.stop)
def tearDown(self):
super(VcnsDriverTestCase, self).tearDown()
class TestEdgeLbDriver(VcnsDriverTestCase):
def test_create_and_get_vip(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as pool:
self.pool_id = pool['pool']['id']
POOL_MAP_INFO['pool_id'] = pool['pool']['id']
vcns_db.add_vcns_edge_pool_binding(ctx.session, POOL_MAP_INFO)
with self.vip(pool=pool) as res:
vip_create = res['vip']
self.driver.create_vip(ctx, VSE_ID, vip_create)
vip_get = self.driver.get_vip(ctx, vip_create['id'])
for k, v in vip_get.iteritems():
self.assertEqual(vip_create[k], v)
def test_update_vip(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as pool:
self.pool_id = pool['pool']['id']
POOL_MAP_INFO['pool_id'] = pool['pool']['id']
vcns_db.add_vcns_edge_pool_binding(ctx.session, POOL_MAP_INFO)
with self.vip(pool=pool) as res:
vip_create = res['vip']
self.driver.create_vip(ctx, VSE_ID, vip_create)
vip_update = {'id': vip_create['id'],
'pool_id': pool['pool']['id'],
'name': 'update_name',
'description': 'description',
'address': 'update_address',
'port_id': 'update_port_id',
'protocol_port': 'protocol_port',
'protocol': 'update_protocol'}
self.driver.update_vip(ctx, vip_update)
vip_get = self.driver.get_vip(ctx, vip_create['id'])
for k, v in vip_get.iteritems():
if k in vip_update:
self.assertEqual(vip_update[k], v)
def test_delete_vip(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as pool:
self.pool_id = pool['pool']['id']
POOL_MAP_INFO['pool_id'] = pool['pool']['id']
vcns_db.add_vcns_edge_pool_binding(ctx.session, POOL_MAP_INFO)
with self.vip(pool=pool) as res:
vip_create = res['vip']
self.driver.create_vip(ctx, VSE_ID, vip_create)
self.driver.delete_vip(ctx, vip_create['id'])
self.assertRaises(vcns_exc.VcnsNotFound,
self.driver.get_vip,
ctx,
vip_create['id'])
#Test Pool Operation
def test_create_and_get_pool(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as p:
self.pool_id = p['pool']['id']
pool_create = p['pool']
self.driver.create_pool(ctx, VSE_ID, pool_create, [])
pool_get = self.driver.get_pool(ctx, pool_create['id'], VSE_ID)
for k, v in pool_get.iteritems():
self.assertEqual(pool_create[k], v)
def test_update_pool(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as p:
self.pool_id = p['pool']['id']
pool_create = p['pool']
self.driver.create_pool(ctx, VSE_ID, pool_create, [])
pool_update = {'id': pool_create['id'],
'lb_method': 'lb_method',
'name': 'update_name',
'members': [],
'health_monitors': []}
self.driver.update_pool(ctx, VSE_ID, pool_update, [])
pool_get = self.driver.get_pool(ctx, pool_create['id'], VSE_ID)
for k, v in pool_get.iteritems():
if k in pool_update:
self.assertEqual(pool_update[k], v)
def test_delete_pool(self):
ctx = context.get_admin_context()
with self.pool(no_delete=True) as p:
self.pool_id = p['pool']['id']
pool_create = p['pool']
self.driver.create_pool(ctx, VSE_ID, pool_create, [])
self.driver.delete_pool(ctx, pool_create['id'], VSE_ID)
self.assertRaises(vcns_exc.VcnsNotFound,
self.driver.get_pool,
ctx,
pool_create['id'],
VSE_ID)
def test_create_and_get_monitor(self):
ctx = context.get_admin_context()
with self.health_monitor(no_delete=True) as m:
monitor_create = m['health_monitor']
self.driver.create_health_monitor(ctx, VSE_ID, monitor_create)
monitor_get = self.driver.get_health_monitor(
ctx, monitor_create['id'], VSE_ID)
for k, v in monitor_get.iteritems():
self.assertEqual(monitor_create[k], v)
def test_update_health_monitor(self):
ctx = context.get_admin_context()
with self.health_monitor(no_delete=True) as m:
monitor_create = m['health_monitor']
self.driver.create_health_monitor(
ctx, VSE_ID, monitor_create)
monitor_update = {'id': monitor_create['id'],
'delay': 'new_delay',
'timeout': "new_timeout",
'type': 'type',
'max_retries': "max_retries"}
self.driver.update_health_monitor(
ctx, VSE_ID, monitor_create, monitor_update)
monitor_get = self.driver.get_health_monitor(
ctx, monitor_create['id'], VSE_ID)
for k, v in monitor_get.iteritems():
if k in monitor_update:
self.assertEqual(monitor_update[k], v)
def test_delete_health_monitor(self):
ctx = context.get_admin_context()
with self.health_monitor(no_delete=True) as m:
monitor_create = m['health_monitor']
self.driver.create_health_monitor(ctx, VSE_ID, monitor_create)
self.driver.delete_health_monitor(
ctx, monitor_create['id'], VSE_ID)
self.assertRaises(vcns_exc.VcnsNotFound,
self.driver.get_health_monitor,
ctx,
monitor_create['id'],
VSE_ID)