Merge "NSX|V router create with availability zones hints"

This commit is contained in:
Jenkins 2016-05-30 12:23:44 +00:00 committed by Gerrit Code Review
commit 440c544b5a
17 changed files with 531 additions and 129 deletions

View File

@ -27,6 +27,7 @@ NSXV_PASSWORD # NSXv password.
NSXV_CLUSTER_MOID # clusters ids containing OpenStack hosts.
NSXV_DATACENTER_MOID # datacenter id for edge deployment.
NSXV_RESOURCE_POOL_ID # resource-pool id for edge deployment.
NSXV_AVAILABILITY_ZONES # alternative resource-pools ids for edge deployment
NSXV_DATASTORE_ID # datastore id for edge deployment.
NSXV_EXTERNAL_NETWORK # id of logic switch for physical network connectivity.
NSXV_VDN_SCOPE_ID # network scope id for VXLAN virtual-wires.

View File

@ -98,6 +98,7 @@ function neutron_plugin_configure_service {
_nsxv_ini_set datacenter_moid "$NSXV_DATACENTER_MOID"
_nsxv_ini_set datastore_id "$NSXV_DATASTORE_ID"
_nsxv_ini_set resource_pool_id "$NSXV_RESOURCE_POOL_ID"
_nsxv_ini_set availability_zones "$NSXV_AVAILABILITY_ZONES"
_nsxv_ini_set external_network "$NSXV_EXTERNAL_NETWORK"
_nsxv_ini_set cluster_moid "$NSXV_CLUSTER_MOID"
_nsxv_ini_set backup_edge_pool "$NSXV_BACKUP_POOL"

View File

@ -394,6 +394,10 @@ nsxv_opts = [
deprecated_group="vcns",
help=_('Optional parameter identifying the ID of resource to '
'deploy NSX Edges')),
cfg.ListOpt('availability_zones',
default=[],
help=_('Optional parameter identifying the IDs of alternative '
'resources to deploy NSX Edges')),
cfg.StrOpt('datastore_id',
deprecated_group="vcns",
help=_('Optional parameter identifying the ID of datastore to '

View File

@ -1 +1 @@
b7f41687cbad
c288bb6a7252

View File

@ -0,0 +1,36 @@
# Copyright 2016 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 add resource pool to the router bindings table
Revision ID: c288bb6a7252
Revises: b7f41687cbad
Create Date: 2016-05-15 06:12:09.450116
"""
# revision identifiers, used by Alembic.
revision = 'c288bb6a7252'
down_revision = 'b7f41687cbad'
from alembic import op
from oslo_config import cfg
import sqlalchemy as sa
from vmware_nsx.common import config # noqa
def upgrade():
op.add_column('nsxv_router_bindings',
sa.Column('resource_pool', sa.String(36), nullable=True,
server_default=cfg.CONF.nsxv.resource_pool_id))

View File

@ -53,7 +53,8 @@ def _apply_filters_to_query(query, model, filters, like_filters=None):
def add_nsxv_router_binding(session, router_id, vse_id, lswitch_id, status,
appliance_size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=None):
with session.begin(subtransactions=True):
binding = nsxv_models.NsxvRouterBinding(
router_id=router_id,
@ -61,7 +62,8 @@ def add_nsxv_router_binding(session, router_id, vse_id, lswitch_id, status,
lswitch_id=lswitch_id,
status=status,
appliance_size=appliance_size,
edge_type=edge_type)
edge_type=edge_type,
resource_pool=resource_pool)
session.add(binding)
return binding
@ -135,6 +137,12 @@ def delete_nsxv_router_binding(session, router_id):
session.delete(binding)
def get_edge_resource_pool(session, edge_id):
binding = get_nsxv_router_binding_by_edge(session, edge_id)
if binding:
return binding['resource_pool']
def get_edge_vnic_binding(session, edge_id, network_id):
return session.query(nsxv_models.NsxvEdgeVnicBinding).filter_by(
edge_id=edge_id, network_id=network_id).first()

View File

@ -48,6 +48,8 @@ class NsxvRouterBinding(model_base.BASEV2, models_v2.HasStatusDescription):
edge_type = sa.Column(sa.Enum(nsxv_constants.SERVICE_EDGE,
nsxv_constants.VDR_EDGE,
name='nsxv_router_bindings_edge_type'))
resource_pool = sa.Column(sa.String(36),
nullable=True)
class NsxvEdgeVnicBinding(model_base.BASEV2):

View File

@ -18,6 +18,7 @@ import six
from neutron.db import l3_db
from neutron.db import models_v2
from neutron.extensions import availability_zone as az_ext
from vmware_nsx._i18n import _
from vmware_nsx.common import exceptions as nsxv_exc
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
@ -120,3 +121,18 @@ class RouterBaseDriver(RouterAbstractDriver):
# Also update the nat rules
if is_uplink:
self.update_nat_rules(context, router, router_id)
def _get_resource_pool_from_hints_by_id(self, context, router_id):
lrouter = self.plugin.get_router(context, router_id)
return self._get_resource_pool_from_hints(lrouter)
def _get_resource_pools_from_hints(self, lrouter):
pools = []
if az_ext.AZ_HINTS in lrouter:
for hint in lrouter[az_ext.AZ_HINTS]:
pools.append(self.plugin.get_res_pool_id_by_name(hint))
return pools
def _get_resource_pool_from_hints(self, lrouter):
pools = self._get_resource_pools_from_hints(lrouter)
return pools[0] if len(pools) > 0 else None

View File

@ -94,7 +94,9 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
def create_router(self, context, lrouter, appliance_size=None,
allow_metadata=True):
self.edge_manager.create_lrouter(context, lrouter, dist=True)
res_pool = self._get_resource_pool_from_hints(lrouter)
self.edge_manager.create_lrouter(context, lrouter, dist=True,
res_pool=res_pool)
def update_router(self, context, router_id, router):
r = router['router']
@ -176,8 +178,10 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
else:
# Connecting plr to the tlr if new_ext_net_id is not None.
if not plr_id:
res_pool = self._get_resource_pool_from_hints_by_id(
context, router_id)
plr_id = self.edge_manager.create_plr_with_tlr_id(
context, router_id, router.get('name'))
context, router_id, router.get('name'), res_pool=res_pool)
if new_ext_net_id != org_ext_net_id and orgnexthop:
# network changed, so need to remove default gateway
# and all static routes before vnic can be configured

View File

@ -36,8 +36,10 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
def create_router(self, context, lrouter, appliance_size=None,
allow_metadata=True):
res_pool = self._get_resource_pool_from_hints(lrouter)
self.edge_manager.create_lrouter(
context, lrouter, dist=False, appliance_size=appliance_size)
context, lrouter, dist=False, appliance_size=appliance_size,
res_pool=res_pool)
if allow_metadata:
self.plugin.metadata_proxy_handler.configure_router_edge(
lrouter['id'])

View File

@ -568,9 +568,13 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
conflict_router_ids.extend(new_conflict_router_ids)
conflict_router_ids = list(set(conflict_router_ids))
res_pool = self._get_resource_pool_from_hints_by_id(
context, router_id)
new = self.edge_manager.bind_router_on_available_edge(
context, router_id, optional_router_ids,
conflict_router_ids, conflict_network_ids, intf_num)
conflict_router_ids, conflict_network_ids, intf_num,
res_pool)
# configure metadata service on the router.
metadata_proxy_handler = self.plugin.metadata_proxy_handler
if metadata_proxy_handler and new:

View File

@ -40,6 +40,7 @@ from neutron.common import rpc as n_rpc
from neutron import context as n_context
from neutron.db import agents_db
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db.availability_zone import router as router_az_db
from neutron.db import db_base_plugin_v2
from neutron.db import dns_db
from neutron.db import external_net_db
@ -52,6 +53,7 @@ from neutron.db import portsecurity_db
from neutron.db import quota_db # noqa
from neutron.db import securitygroups_db
from neutron.extensions import allowedaddresspairs as addr_pair
from neutron.extensions import availability_zone as az_ext
from neutron.extensions import external_net as ext_net_extn
from neutron.extensions import l3
from neutron.extensions import multiprovidernet as mpnet
@ -114,6 +116,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
rt_rtr.RouterType_mixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
router_az_db.RouterAvailabilityZoneMixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
@ -143,7 +146,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
"nsxv-router-size",
"vnic-index",
"advanced-service-providers",
"subnet_allocation"]
"subnet_allocation",
"availability_zone",
"router_availability_zone"]
supported_qos_rule_types = [qos_consts.RULE_TYPE_BANDWIDTH_LIMIT,
qos_consts.RULE_TYPE_DSCP_MARK]
@ -188,6 +193,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
self.nsx_sg_utils = securitygroup_utils.NsxSecurityGroupUtils(
self.nsx_v)
self._validate_config()
self._build_availability_zones_data()
self.sg_container_id = self._create_security_group_container()
self.default_section = self._create_cluster_default_fw_section()
self._process_security_groups_rules_logging()
@ -709,6 +715,42 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
# The vnic-id format which is expected by NSXv
return '%s.%03d' % (device_id, port_index)
def _list_availability_zones(self, context, filters=None):
#TODO(asarfaty): We may need to use the filters arg, but now it
# is here only for overriding the original api
result = {}
for az in self._availability_zones_data.keys():
# Add this availability zone as a router resource
resource = 'router'
key = (az, resource)
result[key] = True
return result
def _validate_availability_zones_in_obj(self, context, resource_type,
obj_data):
if az_ext.AZ_HINTS in obj_data:
self.validate_availability_zones(context, resource_type,
obj_data[az_ext.AZ_HINTS])
def validate_availability_zones(self, context, resource_type,
availability_zones):
"""Verify that the availability zones exist, and only 1 hint
was set.
"""
# For now we support only 1 hint per network/router
# TODO(asarfaty): support multiple hints
if len(availability_zones) > 1:
err_msg = _("Can't use multiple availability zone hints")
raise n_exc.InvalidInput(error_message=err_msg)
# check that all hints appear in the predefined list of availability
# zones
diff = (set(availability_zones) -
set(self._availability_zones_data.keys()))
if diff:
raise az_ext.AvailabilityZoneNotFound(
availability_zone=diff.pop())
def create_network(self, context, network):
net_data = network['network']
tenant_id = net_data['tenant_id']
@ -1793,14 +1835,20 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
r = router['router']
self._decide_router_type(context, r)
self._validate_router_size(router)
self._validate_availability_zones_in_obj(context, 'router', r)
# First extract the gateway info in case of updating
# gateway before edge is deployed.
# TODO(berlin): admin_state_up and routes update
gw_info = self._extract_external_gw(context, router)
lrouter = super(NsxVPluginV2, self).create_router(context, router)
with context.session.begin(subtransactions=True):
router_db = self._get_router(context, lrouter['id'])
self._process_extra_attr_router_create(context, router_db, r)
self._process_nsx_router_create(context, router_db, r)
lrouter = super(NsxVPluginV2, self).get_router(context,
lrouter['id'])
try:
router_driver = self._get_router_driver(context, router_db)
if router_driver.get_type() == nsxv_constants.EXCLUSIVE:
@ -1912,6 +1960,18 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
super(NsxVPluginV2, self).delete_router(context, id)
router_driver.delete_router(context, id)
def get_router_availability_zones(self, router):
"""Return availability zones which a router belongs to."""
context = n_context.get_admin_context()
edge_id = self._get_edge_id_by_rtr_id(context, router["id"])
if edge_id:
resource_pool = nsxv_db.get_edge_resource_pool(
context.session, edge_id)
if resource_pool:
av_zone = self.get_res_pool_name_by_id(resource_pool)
return [av_zone]
return []
def get_router(self, context, id, fields=None):
router = super(NsxVPluginV2, self).get_router(context, id, fields)
if router.get("distributed") and 'router_type' in router:
@ -2722,6 +2782,13 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
ver = self.nsx_v.vcns.get_version()
if version.LooseVersion(ver) < version.LooseVersion('6.2.0'):
# Do not support availability zones hints below 6.2
if (cfg.CONF.nsxv.availability_zones and
len(cfg.CONF.nsxv.availability_zones) > 0):
error = (_("Availability zones are not supported for version "
"%s") % ver)
raise nsx_exc.NsxPluginException(err_msg=error)
LOG.warning(_LW("Skipping validations. Not supported by version."))
return
# Validations below only supported by 6.2.0 and above
@ -2733,6 +2800,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
for cluster in cfg.CONF.nsxv.cluster_moid:
inventory.append((cluster, 'cluster_moid'))
# Add the availability zones resource pools
if cfg.CONF.nsxv.availability_zones:
for az in cfg.CONF.nsxv.availability_zones:
inventory.append((az, 'availability_zones'))
for moref, field in inventory:
if moref and not self.nsx_v.vcns.validate_inventory(moref):
error = _("Configured %s not found") % field
@ -2741,6 +2813,31 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
def _handle_qos_notification(self, qos_policy, event_type):
qos_utils.handle_qos_notification(qos_policy, event_type, self._dvs)
def _build_availability_zones_data(self):
self._availability_zones_data = {}
if not len(cfg.CONF.nsxv.availability_zones):
return
# Add the availability zones resource pools
if cfg.CONF.nsxv.availability_zones:
for az in cfg.CONF.nsxv.availability_zones:
name = self.nsx_v.vcns.get_inventory_name(az)
self._availability_zones_data[name] = az
# Add the default resource_pool_id too
az = cfg.CONF.nsxv.resource_pool_id
name = self.nsx_v.vcns.get_inventory_name(az)
self._availability_zones_data[name] = az
def get_res_pool_id_by_name(self, name):
if name in self._availability_zones_data.keys():
return self._availability_zones_data[name]
raise az_ext.AvailabilityZoneNotFound(availability_zone=name)
def get_res_pool_name_by_id(self, res_pool_id):
for name in self._availability_zones_data.keys():
if res_pool_id == self._availability_zones_data[name]:
return name
# Register the callback
def _validate_network_has_subnet(resource, event, trigger, **kwargs):

View File

@ -502,14 +502,16 @@ class EdgeApplianceDriver(object):
def deploy_edge(self, resource_id, name, internal_network, jobdata=None,
dist=False, wait_for_exec=False, loadbalancer_enable=True,
appliance_size=nsxv_constants.LARGE, async=True):
appliance_size=nsxv_constants.LARGE, async=True,
res_pool=None):
task_name = 'deploying-%s' % name
edge_name = name
edge = self._assemble_edge(
edge_name, datacenter_moid=self.datacenter_moid,
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist)
appliance = self._assemble_edge_appliance(self.resource_pool_id,
res_pool = res_pool or self.resource_pool_id
appliance = self._assemble_edge_appliance(res_pool,
self.datastore_id)
if appliance:
edge['appliances']['appliances'] = [appliance]
@ -590,7 +592,7 @@ class EdgeApplianceDriver(object):
def update_edge(self, router_id, edge_id, name, internal_network,
jobdata=None, dist=False, loadbalancer_enable=True,
appliance_size=nsxv_constants.LARGE,
set_errors=False):
set_errors=False, res_pool=None):
"""Update edge name."""
task_name = 'update-%s' % name
edge_name = name
@ -599,7 +601,8 @@ class EdgeApplianceDriver(object):
deployment_container_id=self.deployment_container_id,
appliance_size=appliance_size, remote_access=False, dist=dist)
edge['id'] = edge_id
appliance = self._assemble_edge_appliance(self.resource_pool_id,
res_pool = res_pool or self.resource_pool_id
appliance = self._assemble_edge_appliance(res_pool,
self.datastore_id)
if appliance:
edge['appliances']['appliances'] = [appliance]

View File

@ -101,6 +101,15 @@ def parse_backup_edge_pool_opt():
return edge_pool_dicts
def get_configured_res_pools():
pools = []
if cfg.CONF.nsxv.resource_pool_id:
pools.append(cfg.CONF.nsxv.resource_pool_id)
if cfg.CONF.nsxv.availability_zones:
pools.extend(cfg.CONF.nsxv.availability_zones)
return pools
class EdgeManager(object):
"""Edge Appliance Management.
EdgeManager provides a pool of edge appliances which we can use
@ -114,6 +123,7 @@ class EdgeManager(object):
self.edge_pool_dicts = parse_backup_edge_pool_opt()
self.nsxv_plugin = nsxv_manager.callbacks.plugin
self.plugin = plugin
self._resource_pools = get_configured_res_pools()
self.per_interface_rp_filter = self._get_per_edge_rp_filter_state()
self.worker_pool = eventlet.GreenPool(WORKER_POOL_SIZE)
self._check_backup_edge_pools()
@ -155,7 +165,8 @@ class EdgeManager(object):
def _deploy_edge(self, context, lrouter,
lswitch=None, appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE, async=True):
edge_type=nsxv_constants.SERVICE_EDGE, async=True,
res_pool=None):
"""Create an edge for logical router support."""
router_id = lrouter['id']
# deploy edge
@ -170,12 +181,14 @@ class EdgeManager(object):
lrouter['id'], lrouter['name'], internal_network=None,
jobdata=jobdata, wait_for_exec=True,
appliance_size=appliance_size,
dist=(edge_type == nsxv_constants.VDR_EDGE), async=async)
dist=(edge_type == nsxv_constants.VDR_EDGE), async=async,
res_pool=res_pool)
return task
def _deploy_backup_edges_on_db(self, context, num,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
res_pool=cfg.CONF.nsxv.resource_pool_id):
router_ids = [(vcns_const.BACKUP_ROUTER_PREFIX +
_uuid())[:vcns_const.EDGE_NAME_LEN]
for i in moves.range(num)]
@ -184,17 +197,20 @@ class EdgeManager(object):
nsxv_db.add_nsxv_router_binding(
context.session, router_id, None, None,
plugin_const.PENDING_CREATE,
appliance_size=appliance_size, edge_type=edge_type)
appliance_size=appliance_size, edge_type=edge_type,
resource_pool=res_pool)
return router_ids
def _deploy_backup_edges_at_backend(self, context, router_ids,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE):
def _deploy_backup_edges_at_backend(
self, context, router_ids,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE,
res_pool=cfg.CONF.nsxv.resource_pool_id):
eventlet.spawn_n(self._pool_creator, context, router_ids,
appliance_size, edge_type)
appliance_size, edge_type, res_pool)
def _pool_creator(self, context, router_ids, appliance_size, edge_type):
def _pool_creator(self, context, router_ids, appliance_size,
edge_type, res_pool):
pool = self.worker_pool
for router_id in router_ids:
fake_router = {
@ -202,7 +218,8 @@ class EdgeManager(object):
'name': router_id}
pool.spawn_n(self._deploy_edge, context, fake_router,
appliance_size=appliance_size,
edge_type=edge_type, async=False)
edge_type=edge_type, async=False,
res_pool=res_pool)
def _delete_edge(self, context, router_binding):
if router_binding['status'] == plugin_const.ERROR:
@ -237,8 +254,10 @@ class EdgeManager(object):
binding['router_id'], binding['edge_id'], jobdata=jobdata,
dist=(binding['edge_type'] == nsxv_constants.VDR_EDGE))
def _clean_all_error_edge_bindings(self, context):
filters = {'status': [plugin_const.ERROR]}
def _clean_all_error_edge_bindings(
self, context,
res_pool=cfg.CONF.nsxv.resource_pool_id):
filters = {'status': [plugin_const.ERROR], 'resource_pool': [res_pool]}
like_filters = {'router_id': vcns_const.BACKUP_ROUTER_PREFIX + "%"}
error_router_bindings = nsxv_db.get_nsxv_router_bindings(
context.session, filters=filters, like_filters=like_filters)
@ -250,9 +269,11 @@ class EdgeManager(object):
def _get_backup_edge_bindings(self, context,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE,
db_update_lock=False):
db_update_lock=False,
res_pool=cfg.CONF.nsxv.resource_pool_id):
filters = {'appliance_size': [appliance_size],
'edge_type': [edge_type],
'resource_pool': [res_pool],
'status': [plugin_const.PENDING_CREATE,
plugin_const.ACTIVE]}
like_filters = {'router_id': vcns_const.BACKUP_ROUTER_PREFIX + "%"}
@ -261,30 +282,34 @@ class EdgeManager(object):
def _check_backup_edge_pools(self):
admin_ctx = q_context.get_admin_context()
self._clean_all_error_edge_bindings(admin_ctx)
for edge_type, v in self.edge_pool_dicts.items():
for edge_size in vcns_const.ALLOWED_EDGE_SIZES:
if edge_size in v.keys():
edge_pool_range = v[edge_size]
self._check_backup_edge_pool(
edge_pool_range['minimum_pooled_edges'],
edge_pool_range['maximum_pooled_edges'],
appliance_size=edge_size, edge_type=edge_type)
else:
self._check_backup_edge_pool(
0, 0,
appliance_size=edge_size, edge_type=edge_type)
for res_pool in self._resource_pools:
self._clean_all_error_edge_bindings(admin_ctx, res_pool=res_pool)
for edge_type, v in self.edge_pool_dicts.items():
for edge_size in vcns_const.ALLOWED_EDGE_SIZES:
if edge_size in v.keys():
edge_pool_range = v[edge_size]
self._check_backup_edge_pool(
edge_pool_range['minimum_pooled_edges'],
edge_pool_range['maximum_pooled_edges'],
appliance_size=edge_size, edge_type=edge_type,
res_pool=res_pool)
else:
self._check_backup_edge_pool(
0, 0,
appliance_size=edge_size, edge_type=edge_type,
res_pool=res_pool)
def _check_backup_edge_pool(self,
minimum_pooled_edges,
maximum_pooled_edges,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
res_pool=cfg.CONF.nsxv.resource_pool_id):
"""Check edge pool's status and return one available edge for use."""
admin_ctx = q_context.get_admin_context()
backup_router_bindings = self._get_backup_edge_bindings(
admin_ctx, appliance_size=appliance_size, edge_type=edge_type,
db_update_lock=True)
db_update_lock=True, res_pool=res_pool)
backup_num = len(backup_router_bindings)
if backup_num > maximum_pooled_edges:
self._delete_backup_edges_on_db(
@ -297,12 +322,12 @@ class EdgeManager(object):
router_ids.extend(
self._deploy_backup_edges_on_db(
admin_ctx, 1, appliance_size=appliance_size,
edge_type=edge_type))
edge_type=edge_type, res_pool=res_pool))
new_backup_num = len(
self._get_backup_edge_bindings(
admin_ctx, appliance_size=appliance_size,
edge_type=edge_type, db_update_lock=True))
edge_type=edge_type, db_update_lock=True,
res_pool=res_pool))
if backup_num > maximum_pooled_edges:
self._delete_backup_edges_at_backend(
admin_ctx,
@ -311,7 +336,8 @@ class EdgeManager(object):
self._deploy_backup_edges_at_backend(admin_ctx,
router_ids,
appliance_size=appliance_size,
edge_type=edge_type)
edge_type=edge_type,
res_pool=res_pool)
def check_edge_active_at_backend(self, edge_id):
try:
@ -322,9 +348,13 @@ class EdgeManager(object):
def _get_available_router_binding(self, context,
appliance_size=nsxv_constants.COMPACT,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
res_pool=None):
if not res_pool:
res_pool = cfg.CONF.nsxv.resource_pool_id
backup_router_bindings = self._get_backup_edge_bindings(
context, appliance_size=appliance_size, edge_type=edge_type)
context, appliance_size=appliance_size, edge_type=edge_type,
res_pool=res_pool)
while backup_router_bindings:
router_binding = random.choice(backup_router_bindings)
if (router_binding['status'] == plugin_const.ACTIVE):
@ -534,9 +564,9 @@ class EdgeManager(object):
@vcns.retry_upon_exception(db_base_exc.OperationalError, max_delay=10)
def _allocate_edge_appliance(self, context, resource_id, name,
appliance_size=nsxv_constants.COMPACT,
dist=False):
dist=False,
res_pool=cfg.CONF.nsxv.resource_pool_id):
"""Try to allocate one available edge from pool."""
edge_type = (nsxv_constants.VDR_EDGE if dist else
nsxv_constants.SERVICE_EDGE)
lrouter = {'id': resource_id,
@ -547,33 +577,38 @@ class EdgeManager(object):
context.session, resource_id, None, None,
plugin_const.PENDING_CREATE,
appliance_size=appliance_size,
edge_type=edge_type)
edge_type=edge_type,
resource_pool=res_pool)
self._deploy_edge(context, lrouter,
appliance_size=appliance_size,
edge_type=edge_type, async=False)
edge_type=edge_type, async=False,
res_pool=res_pool)
return
with locking.LockManager.get_lock('nsx-edge-request'):
self._clean_all_error_edge_bindings(context)
self._clean_all_error_edge_bindings(context, res_pool=res_pool)
available_router_binding = self._get_available_router_binding(
context, appliance_size=appliance_size, edge_type=edge_type)
context, appliance_size=appliance_size, edge_type=edge_type,
res_pool=res_pool)
if available_router_binding:
# Update the status from ACTIVE to PENDING_UPDATE
# in case of other threads select the same router binding
nsxv_db.update_nsxv_router_binding(
context.session, available_router_binding['router_id'],
status=plugin_const.PENDING_UPDATE)
# Synchronously deploy an edge if no avaliable edge in pool.
# Synchronously deploy an edge if no available edge in pool.
if not available_router_binding:
# store router-edge mapping binding
nsxv_db.add_nsxv_router_binding(
context.session, resource_id, None, None,
plugin_const.PENDING_CREATE,
appliance_size=appliance_size,
edge_type=edge_type)
edge_type=edge_type,
resource_pool=res_pool)
self._deploy_edge(context, lrouter,
appliance_size=appliance_size,
edge_type=edge_type, async=False)
edge_type=edge_type, async=False,
res_pool=res_pool)
else:
LOG.debug("Select edge: %(edge_id)s from pool for %(name)s",
{'edge_id': available_router_binding['edge_id'],
@ -588,7 +623,8 @@ class EdgeManager(object):
None,
plugin_const.PENDING_CREATE,
appliance_size=appliance_size,
edge_type=edge_type)
edge_type=edge_type,
resource_pool=res_pool)
LOG.debug("Select edge: %(edge_id)s from pool for %(name)s",
{'edge_id': available_router_binding['edge_id'],
'name': name})
@ -611,18 +647,20 @@ class EdgeManager(object):
task = self.nsxv_manager.update_edge(
resource_id, available_router_binding['edge_id'],
name, None, appliance_size=appliance_size, dist=dist,
jobdata=jobdata, set_errors=True)
jobdata=jobdata, set_errors=True, res_pool=res_pool)
task.wait(task_const.TaskState.RESULT)
backup_num = len(self._get_backup_edge_bindings(
context, appliance_size=appliance_size, edge_type=edge_type,
db_update_lock=True))
db_update_lock=True, res_pool=res_pool))
router_ids = self._deploy_backup_edges_on_db(
context, edge_pool_range['minimum_pooled_edges'] - backup_num,
appliance_size=appliance_size, edge_type=edge_type)
appliance_size=appliance_size, edge_type=edge_type,
res_pool=res_pool)
self._deploy_backup_edges_at_backend(
context, router_ids,
appliance_size=appliance_size, edge_type=edge_type)
appliance_size=appliance_size, edge_type=edge_type,
res_pool=res_pool)
def _free_edge_appliance(self, context, router_id):
"""Try to collect one edge to pool."""
@ -632,10 +670,12 @@ class EdgeManager(object):
"not found"), router_id)
return
dist = (binding['edge_type'] == nsxv_constants.VDR_EDGE)
edge_id = binding['edge_id']
res_pool = nsxv_db.get_edge_resource_pool(context.session, edge_id)
edge_pool_range = self.edge_pool_dicts[binding['edge_type']].get(
binding['appliance_size'])
if (binding['status'] == plugin_const.ERROR or
not self.check_edge_active_at_backend(binding['edge_id']) or
not self.check_edge_active_at_backend(edge_id) or
not edge_pool_range):
nsxv_db.update_nsxv_router_binding(
context.session, router_id,
@ -646,14 +686,14 @@ class EdgeManager(object):
'router_id': router_id
}
self.nsxv_manager.delete_edge(
router_id, binding['edge_id'], jobdata=jobdata, dist=dist)
router_id, edge_id, jobdata=jobdata, dist=dist)
return
with locking.LockManager.get_lock('nsx-edge-request'):
self._clean_all_error_edge_bindings(context)
self._clean_all_error_edge_bindings(context, res_pool=res_pool)
backup_router_bindings = self._get_backup_edge_bindings(
context, appliance_size=binding['appliance_size'],
edge_type=binding['edge_type'])
edge_type=binding['edge_type'], res_pool=res_pool)
backup_num = len(backup_router_bindings)
# collect the edge to pool if pool not full
if backup_num < edge_pool_range['maximum_pooled_edges']:
@ -664,30 +704,30 @@ class EdgeManager(object):
nsxv_db.add_nsxv_router_binding(
context.session,
backup_router_id,
binding['edge_id'],
edge_id,
None,
plugin_const.PENDING_UPDATE,
appliance_size=binding['appliance_size'],
edge_type=binding['edge_type'])
edge_type=binding['edge_type'],
resource_pool=res_pool)
# change edge's name at backend
task = self.nsxv_manager.update_edge(
backup_router_id, binding['edge_id'], backup_router_id, None,
appliance_size=binding['appliance_size'], dist=dist)
backup_router_id, edge_id, backup_router_id, None,
appliance_size=binding['appliance_size'], dist=dist,
res_pool=res_pool)
task.wait(task_const.TaskState.RESULT)
# Clean all edge vnic bindings
nsxv_db.clean_edge_vnic_binding(
context.session, binding['edge_id'])
nsxv_db.clean_edge_vnic_binding(context.session, edge_id)
# Refresh edge_vnic_bindings for centralized router
if not dist and binding['edge_id']:
nsxv_db.init_edge_vnic_binding(
context.session, binding['edge_id'])
if not dist and edge_id:
nsxv_db.init_edge_vnic_binding(context.session, edge_id)
if task.status == task_const.TaskStatus.COMPLETED:
nsxv_db.update_nsxv_router_binding(
context.session, backup_router_id,
status=plugin_const.ACTIVE)
LOG.debug("Collect edge: %s to pool", binding['edge_id'])
LOG.debug("Collect edge: %s to pool", edge_id)
else:
nsxv_db.update_nsxv_router_binding(
context.session, router_id,
@ -698,7 +738,7 @@ class EdgeManager(object):
'router_id': router_id
}
self.nsxv_manager.delete_edge(
router_id, binding['edge_id'], jobdata=jobdata, dist=dist)
router_id, edge_id, jobdata=jobdata, dist=dist)
def _allocate_dhcp_edge_appliance(self, context, resource_id):
resource_name = (vcns_const.DHCP_EDGE_PREFIX +
@ -718,13 +758,16 @@ class EdgeManager(object):
def create_lrouter(
self, context, lrouter, lswitch=None, dist=False,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router']):
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router'],
res_pool=None):
"""Create an edge for logical router support."""
if not res_pool:
res_pool = cfg.CONF.nsxv.resource_pool_id
router_name = self._build_lrouter_name(lrouter['id'], lrouter['name'])
self._allocate_edge_appliance(
context, lrouter['id'], router_name,
appliance_size=appliance_size,
dist=dist)
dist=dist, res_pool=res_pool)
def delete_lrouter(self, context, router_id, dist=False):
self._free_edge_appliance(context, router_id)
@ -907,12 +950,15 @@ class EdgeManager(object):
else:
return new_id
def _get_available_edges(self, context, network_id, conflicting_nets):
def _get_available_edges(self, context, network_id, conflicting_nets,
res_pool=cfg.CONF.nsxv.resource_pool_id):
if conflicting_nets is None:
conflicting_nets = []
conflict_edge_ids = []
available_edge_ids = []
router_bindings = nsxv_db.get_nsxv_router_bindings(context.session)
filters = {'resource_pool': [res_pool]}
router_bindings = nsxv_db.get_nsxv_router_bindings(context.session,
filters=filters)
all_dhcp_edges = {binding['router_id']: binding['edge_id'] for
binding in router_bindings if (binding['router_id'].
startswith(vcns_const.DHCP_EDGE_PREFIX) and
@ -994,7 +1040,8 @@ class EdgeManager(object):
nsxv_db.add_nsxv_router_binding(
context.session, resource_id,
edge_id, None, plugin_const.ACTIVE,
appliance_size=app_size)
appliance_size=app_size,
resource_pool=cfg.CONF.nsxv.resource_pool_id)
nsxv_db.allocate_edge_vnic_with_tunnel_index(
context.session, edge_id, network_id)
@ -1394,7 +1441,8 @@ class EdgeManager(object):
if plr_router_id != router_id:
return plr_router_id
def create_plr_with_tlr_id(self, context, router_id, router_name):
def create_plr_with_tlr_id(self, context, router_id, router_name,
res_pool=None):
# Add an internal network preparing for connecting the VDR
# to a PLR
tlr_edge_id = nsxv_db.get_nsxv_router_binding(
@ -1424,7 +1472,7 @@ class EdgeManager(object):
# Handle plr relative op
plr_router = {'name': router_name,
'id': (vcns_const.PLR_EDGE_PREFIX + _uuid())[:36]}
self.create_lrouter(context, plr_router)
self.create_lrouter(context, plr_router, res_pool=res_pool)
binding = nsxv_db.get_nsxv_router_binding(
context.session, plr_router['id'])
plr_edge_id = binding['edge_id']
@ -1503,10 +1551,12 @@ class EdgeManager(object):
def bind_router_on_available_edge(
self, context, target_router_id,
optional_router_ids, conflict_router_ids,
conflict_network_ids, network_number):
conflict_network_ids, network_number, resource_pool):
"""Bind logical router on an available edge.
Return True if the logical router is bound to a new edge.
"""
if not resource_pool:
resource_pool = cfg.CONF.nsxv.resource_pool_id
with locking.LockManager.get_lock('nsx-edge-router'):
optional_edge_ids = []
conflict_edge_ids = []
@ -1514,6 +1564,7 @@ class EdgeManager(object):
binding = nsxv_db.get_nsxv_router_binding(
context.session, router_id)
if (binding and binding.status == plugin_const.ACTIVE and
binding.resource_pool == resource_pool and
binding.edge_id not in optional_edge_ids):
optional_edge_ids.append(binding.edge_id)
@ -1552,13 +1603,15 @@ class EdgeManager(object):
edge_binding.edge_id, None,
edge_binding.status,
edge_binding.appliance_size,
edge_binding.edge_type)
edge_binding.edge_type,
resource_pool=resource_pool)
else:
router_name = ('shared' + '-' + _uuid())[
:vcns_const.EDGE_NAME_LEN]
self._allocate_edge_appliance(
context, target_router_id, router_name,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router'])
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router'],
res_pool=resource_pool)
return True
def unbind_router_on_edge(self, context, router_id):
@ -1659,7 +1712,8 @@ class EdgeManager(object):
network_id)
def create_lrouter(nsxv_manager, context, lrouter, lswitch=None, dist=False):
def create_lrouter(nsxv_manager, context, lrouter, lswitch=None, dist=False,
res_pool=None):
"""Create an edge for logical router support."""
router_id = lrouter['id']
router_name = lrouter['name'] + '-' + router_id
@ -1668,7 +1722,8 @@ def create_lrouter(nsxv_manager, context, lrouter, lswitch=None, dist=False):
nsxv_db.add_nsxv_router_binding(
context.session, router_id, None, None,
plugin_const.PENDING_CREATE,
appliance_size=appliance_size)
appliance_size=appliance_size,
resource_pool=res_pool)
# deploy edge
jobdata = {
@ -1683,7 +1738,8 @@ def create_lrouter(nsxv_manager, context, lrouter, lswitch=None, dist=False):
# as we're not in a database transaction now
task = nsxv_manager.deploy_edge(
router_id, router_name, internal_network=None,
dist=dist, jobdata=jobdata, appliance_size=appliance_size)
dist=dist, jobdata=jobdata, appliance_size=appliance_size,
res_pool=res_pool)
task.wait(task_const.TaskState.RESULT)

View File

@ -827,6 +827,11 @@ class Vcns(object):
return False
return True
def get_inventory_name(self, object_id):
uri = '%s/inventory/%s/basicinfo' % (SERVICES_PREFIX, object_id)
h, c = self.do_request(HTTP_GET, uri, decode=True)
return c['name']
def _get_version(self):
uri = '/api/2.0/services/vsmconfig'
h, c = self.do_request(HTTP_GET, uri, decode=True)

View File

@ -132,10 +132,14 @@ class NsxVPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
mock_delete_dhcp_service = mock.patch("%s.%s" % (
vmware.EDGE_MANAGE_NAME, 'delete_dhcp_edge_service'))
mock_delete_dhcp_service.start()
self.default_res_pool = 'respool-28'
cfg.CONF.set_override("resource_pool_id", self.default_res_pool,
group="nsxv")
super(NsxVPluginV2TestCase, self).setUp(plugin=plugin,
ext_mgr=ext_mgr)
self.addCleanup(self.fc2.reset_all)
plugin_instance = manager.NeutronManager.get_plugin()
plugin_instance.real_get_edge = plugin_instance._get_edge_id_by_rtr_id
plugin_instance._get_edge_id_by_rtr_id = mock.Mock()
plugin_instance._get_edge_id_by_rtr_id.return_value = False
plugin_instance.edge_manager.is_dhcp_opt_enabled = True
@ -1890,7 +1894,8 @@ class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase):
data['router']['name'] = name
if admin_state_up:
data['router']['admin_state_up'] = admin_state_up
for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())):
for arg in (('admin_state_up', 'tenant_id')
+ (arg_list or ())):
# Arg must be present and not empty
if kwargs.get(arg):
data['router'][arg] = kwargs[arg]
@ -3003,6 +3008,40 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase,
returned_router['id'])
self.assertEqual(plugin_const.ERROR, new_router['status'])
def test_create_router_with_bad_az_hint(self):
p = manager.NeutronManager.get_plugin()
router = {'router': {'admin_state_up': True,
'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c',
'tenant_id': context.get_admin_context().tenant_id,
'router_type': 'exclusive',
'availability_zone_hints': ['bad_hint']}}
self.assertRaises(n_exc.NeutronException,
p.create_router,
context.get_admin_context(),
router)
def test_create_router_with_az_hint(self):
p = manager.NeutronManager.get_plugin()
alter_pool_id = 'respool-7'
alter_pool_name = 'rs-7'
p._availability_zones_data = {'default': self.default_res_pool,
alter_pool_name: alter_pool_id}
p._get_edge_id_by_rtr_id = p.real_get_edge
router = {'router': {'admin_state_up': True,
'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c',
'tenant_id': context.get_admin_context().tenant_id,
'router_type': 'exclusive',
'availability_zone_hints': [alter_pool_name]}}
# router creation should succeed
returned_router = p.create_router(context.get_admin_context(),
router)
self.assertEqual([alter_pool_name],
returned_router['availability_zone_hints'])
self.assertEqual([alter_pool_name],
returned_router['availability_zones'])
class ExtGwModeTestCase(NsxVPluginV2TestCase,
test_ext_gw_mode.ExtGwModeIntTestCase):
@ -3263,6 +3302,44 @@ class TestVdrTestCase(L3NatTest, L3NatTestCaseBase,
def test_router_create_distributed_unspecified(self):
self._test_router_create_with_distributed(None, False)
def _test_create_rotuer_with_az_hint(self, with_hint):
# init the availability zones in the plugin
p = manager.NeutronManager.get_plugin()
pool_id = 'respool-7'
pool_name = 'rs-7'
p._availability_zones_data = {'default': self.default_res_pool,
pool_name: pool_id}
# create a router with/without hints
router = {'router': {'admin_state_up': True,
'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c',
'tenant_id': context.get_admin_context().tenant_id,
'distributed': True}}
if with_hint:
router['router']['availability_zone_hints'] = [pool_name]
returned_router = p.create_router(context.get_admin_context(),
router)
# availability zones is still empty because the router is not attached
if with_hint:
self.assertEqual([pool_name],
returned_router['availability_zone_hints'])
else:
self.assertEqual([],
returned_router['availability_zone_hints'])
edge_id = edge_utils.get_router_edge_id(
context.get_admin_context(), returned_router['id'])
res_pool = nsxv_db.get_edge_resource_pool(
context.get_admin_context().session, edge_id)
expected_pool = pool_id if with_hint else self.default_res_pool
self.assertEqual(expected_pool, res_pool)
def test_create_rotuer_with_az_hint(self):
self._test_create_rotuer_with_az_hint(True)
def test_create_rotuer_without_az_hint(self):
self._test_create_rotuer_with_az_hint(False)
def test_floatingip_with_assoc_fails(self):
self._test_floatingip_with_assoc_fails(
self._plugin_name + '._check_and_get_fip_assoc')
@ -4109,3 +4186,50 @@ class TestSharedRouterTestCase(L3NatTest, L3NatTestCaseBase,
# get the updated router and check it's type
body = self._show('routers', router_id)
self.assertEqual('exclusive', body['router']['router_type'])
def _test_create_rotuer_with_az_hint(self, with_hint):
# init the availability zones in the plugin
p = manager.NeutronManager.get_plugin()
pool_id = 'respool-7'
pool_name = 'rs-7'
p._availability_zones_data = {'default': self.default_res_pool,
pool_name: pool_id}
# create a router with/without hints
router = {'router': {'admin_state_up': True,
'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c',
'tenant_id': context.get_admin_context().tenant_id,
'router_type': 'shared'}}
if with_hint:
router['router']['availability_zone_hints'] = [pool_name]
returned_router = p.create_router(context.get_admin_context(),
router)
# availability zones is still empty because the router is not attached
if with_hint:
self.assertEqual([pool_name],
returned_router['availability_zone_hints'])
else:
self.assertEqual([],
returned_router['availability_zone_hints'])
self.assertEqual([],
returned_router['availability_zones'])
# Add interface so the router will be attached to an edge
with self.subnet() as s1:
router_id = returned_router['id']
self._router_interface_action('add',
router_id,
s1['subnet']['id'],
None)
edge_id = edge_utils.get_router_edge_id(
context.get_admin_context(), router_id)
res_pool = nsxv_db.get_edge_resource_pool(
context.get_admin_context().session, edge_id)
expected_pool = pool_id if with_hint else self.default_res_pool
self.assertEqual(expected_pool, res_pool)
def test_create_rotuer_with_az_hint(self):
self._test_create_rotuer_with_az_hint(True)
def test_create_rotuer_without_az_hint(self):
self._test_create_rotuer_with_az_hint(False)

View File

@ -38,6 +38,7 @@ EDGE_CREATING = 'creating-'
EDGE_ERROR1 = 'error1-'
EDGE_ERROR2 = 'error2-'
EDGE_DELETING = 'deleting-'
DEFAULT_RES_POOL = 'respool-28'
class EdgeUtilsTestCaseMixin(testlib_api.SqlTestCase):
@ -56,6 +57,8 @@ class EdgeUtilsTestCaseMixin(testlib_api.SqlTestCase):
self.ctx = context.get_admin_context()
self.addCleanup(nsxv_manager_p.stop)
self.fake_jobdata = {'router_id': 'fake_id', 'context': self.ctx}
cfg.CONF.set_override("resource_pool_id", DEFAULT_RES_POOL,
group="nsxv")
def _create_router(self, name='router1'):
return {'name': name,
@ -77,7 +80,8 @@ class EdgeUtilsTestCaseMixin(testlib_api.SqlTestCase):
self.ctx.session, binding['router_id'],
binding['edge_id'], None, binding['status'],
appliance_size=binding['appliance_size'],
edge_type=binding['edge_type'])
edge_type=binding['edge_type'],
resource_pool=binding['resource_pool'])
class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
@ -94,17 +98,20 @@ class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
'edge_id': 'edge-1',
'router_id': 'backup-11111111-1111',
'appliance_size': 'compact',
'edge_type': 'service'},
'edge_type': 'service',
'resource_pool': DEFAULT_RES_POOL},
{'status': plugin_const.PENDING_DELETE,
'edge_id': 'edge-2',
'router_id': 'dhcp-22222222-2222',
'appliance_size': 'compact',
'edge_type': 'service'},
'edge_type': 'service',
'resource_pool': DEFAULT_RES_POOL},
{'status': plugin_const.PENDING_DELETE,
'edge_id': 'edge-3',
'router_id': 'backup-33333333-3333',
'appliance_size': 'compact',
'edge_type': 'service'}]
'edge_type': 'service',
'resource_pool': DEFAULT_RES_POOL}]
self._populate_vcns_router_binding(fake_edge_pool)
fake_network = self._create_network()
fake_subnet = self._create_subnet(fake_network['id'])
@ -118,7 +125,7 @@ class EdgeDHCPManagerTestCase(EdgeUtilsTestCaseMixin):
self.nsxv_manager.update_edge.assert_called_once_with(
resource_id, 'edge-1', mock.ANY, None, jobdata=jobdata,
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
dist=False, set_errors=True)
dist=False, set_errors=True, res_pool=None)
def test_get_random_available_edge(self):
available_edge_ids = ['edge-1', 'edge-2']
@ -185,10 +192,11 @@ class EdgeUtilsTestCase(EdgeUtilsTestCaseMixin):
lrouter = self._create_router()
self.nsxv_manager.deploy_edge.reset_mock()
edge_utils.create_lrouter(self.nsxv_manager, self.ctx, lrouter,
lswitch=None, dist=False)
lswitch=None, dist=False,
res_pool=DEFAULT_RES_POOL)
self.nsxv_manager.deploy_edge.assert_called_once_with(
lrouter['id'], (lrouter['name'] + '-' + lrouter['id']),
internal_network=None, dist=False,
internal_network=None, dist=False, res_pool=DEFAULT_RES_POOL,
jobdata={'router_id': lrouter['id'],
'lrouter': lrouter,
'lswitch': None,
@ -365,70 +373,81 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
def _create_available_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
id_prefix = EDGE_AVAIL + size + '-' + edge_type
return [{'status': plugin_const.ACTIVE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
'edge_type': edge_type,
'resource_pool': resource_pool}
for i in moves.range(num)]
def _create_creating_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
id_prefix = EDGE_CREATING + size + '-' + edge_type
return [{'status': plugin_const.PENDING_CREATE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
'edge_type': edge_type,
'resource_pool': resource_pool}
for i in moves.range(num)]
def _create_error_router_bindings(
self, num, status=plugin_const.ERROR,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
id_prefix = EDGE_ERROR1 + size + '-' + edge_type
return [{'status': status,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
'edge_type': edge_type,
'resource_pool': resource_pool}
for i in moves.range(num)]
def _create_error_router_bindings_at_backend(
self, num, status=plugin_const.ACTIVE,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
id_prefix = EDGE_ERROR2 + size + '-' + edge_type
return [{'status': status,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
'edge_type': edge_type,
'resource_pool': resource_pool}
for i in moves.range(num)]
def _create_deleting_router_bindings(
self, num, size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
id_prefix = EDGE_DELETING + size + '-' + edge_type
return [{'status': plugin_const.PENDING_DELETE,
'edge_id': id_prefix + '-edge-' + str(i),
'router_id': (vcns_const.BACKUP_ROUTER_PREFIX +
id_prefix + str(i)),
'appliance_size': size,
'edge_type': edge_type}
'edge_type': edge_type,
'resource_pool': resource_pool}
for i in moves.range(num)]
def _create_edge_pools(self, avail, creating, error,
error_at_backend, deleting,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
"""Create a backup edge pool with different status of edges.
Backup edges would be edges with avail, creating and error_at_backend,
@ -436,34 +455,45 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
"""
return (
self._create_error_router_bindings(
error, size=size, edge_type=edge_type) +
error, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_deleting_router_bindings(
deleting, size=size, edge_type=edge_type) +
deleting, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_error_router_bindings_at_backend(
error_at_backend, size=size, edge_type=edge_type) +
error_at_backend, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_creating_router_bindings(
creating, size=size, edge_type=edge_type) +
creating, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_available_router_bindings(
avail, size=size, edge_type=edge_type))
avail, size=size, edge_type=edge_type,
resource_pool=resource_pool))
def _create_backup_router_bindings(
self, avail, creating, error, error_at_backend, deleting,
error_status=plugin_const.PENDING_DELETE,
error_at_backend_status=plugin_const.PENDING_DELETE,
size=nsxv_constants.LARGE,
edge_type=nsxv_constants.SERVICE_EDGE):
edge_type=nsxv_constants.SERVICE_EDGE,
resource_pool=DEFAULT_RES_POOL):
return (
self._create_error_router_bindings(
error, status=error_status, size=size, edge_type=edge_type) +
error, status=error_status, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_error_router_bindings_at_backend(
error_at_backend, status=error_at_backend_status,
size=size, edge_type=edge_type) +
size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_creating_router_bindings(
creating, size=size, edge_type=edge_type) +
creating, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_available_router_bindings(
avail, size=size, edge_type=edge_type) +
avail, size=size, edge_type=edge_type,
resource_pool=resource_pool) +
self._create_deleting_router_bindings(
deleting, size=size, edge_type=edge_type))
deleting, size=size, edge_type=edge_type,
resource_pool=resource_pool))
def _verify_router_bindings(self, exp_bindings, act_db_bindings):
exp_dict = dict(zip([binding['router_id']
@ -472,7 +502,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
'edge_id': binding['edge_id'],
'status': binding['status'],
'appliance_size': binding['appliance_size'],
'edge_type': binding['edge_type']}
'edge_type': binding['edge_type'],
'resource_pool': binding['resource_pool']}
for binding in act_db_bindings]
act_dict = dict(zip([binding['router_id']
for binding in act_bindings], act_bindings))
@ -489,7 +520,7 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
error_at_backend_status=plugin_const.ACTIVE,
size=nsxv_constants.LARGE)
backup_bindings = self.edge_manager._get_backup_edge_bindings(self.ctx,
appliance_size=nsxv_constants.LARGE)
appliance_size=nsxv_constants.LARGE, res_pool=DEFAULT_RES_POOL)
self._verify_router_bindings(expect_backup_bindings, backup_bindings)
def test_get_available_router_bindings(self):
@ -508,7 +539,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
for binding_db in nsxv_db.get_nsxv_router_bindings(
self.ctx.session)
if (binding_db['appliance_size'] == appliance_size and
binding_db['edge_type'] == edge_type)]
binding_db['edge_type'] == edge_type and
binding_db['resource_pool'] == DEFAULT_RES_POOL)]
self._verify_router_bindings(expect_backup_bindings, router_bindings)
edge_id = (EDGE_AVAIL + appliance_size + '-' +
edge_type + '-edge-' + str(0))
@ -527,7 +559,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
error_at_backend_status=plugin_const.PENDING_DELETE)
self.edge_manager._check_backup_edge_pool(
0, 3,
appliance_size=appliance_size, edge_type=edge_type)
appliance_size=appliance_size, edge_type=edge_type,
res_pool=DEFAULT_RES_POOL)
router_bindings = [
binding
for binding in nsxv_db.get_nsxv_router_bindings(self.ctx.session)
@ -547,7 +580,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
edge_utils.eventlet.spawn_n.return_value = None
self.edge_manager._check_backup_edge_pool(
5, 10, appliance_size=appliance_size, edge_type=edge_type)
5, 10, appliance_size=appliance_size, edge_type=edge_type,
res_pool=DEFAULT_RES_POOL)
router_bindings = [
binding
for binding in nsxv_db.get_nsxv_router_bindings(self.ctx.session)
@ -557,7 +591,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
binding_ids = [bind.router_id for bind in router_bindings]
self.assertEqual(2, len(router_bindings))
edge_utils.eventlet.spawn_n.assert_called_with(
mock.ANY, mock.ANY, binding_ids, appliance_size, edge_type)
mock.ANY, mock.ANY, binding_ids, appliance_size,
edge_type, DEFAULT_RES_POOL)
def test_check_backup_edge_pools_with_empty_conf(self):
pool_edges = (self._create_edge_pools(1, 2, 3, 4, 5) +
@ -663,7 +698,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
jobdata=self.fake_jobdata, set_errors=True,
appliance_size=nsxv_constants.LARGE, dist=False)])
appliance_size=nsxv_constants.LARGE, dist=False,
res_pool=None)])
def test_allocate_compact_edge_appliance_with_default(self):
self.edge_manager.edge_pool_dicts = self.default_edge_pool_dicts
@ -681,7 +717,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
jobdata=self.fake_jobdata, set_errors=True,
appliance_size=nsxv_constants.COMPACT, dist=False)])
appliance_size=nsxv_constants.COMPACT, dist=False,
res_pool=None)])
def test_allocate_large_edge_appliance_with_vdr(self):
self.edge_manager.edge_pool_dicts = self.vdr_edge_pool_dicts
@ -699,7 +736,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call('fake_id', edge_id, 'fake_name', None,
jobdata=self.fake_jobdata, set_errors=True,
appliance_size=nsxv_constants.LARGE, dist=True)])
appliance_size=nsxv_constants.LARGE, dist=True,
res_pool=None)])
def test_free_edge_appliance_with_empty(self):
self.edge_manager._clean_all_error_edge_bindings = mock.Mock()
@ -718,7 +756,8 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
assert not self.nsxv_manager.delete_edge.called
self.nsxv_manager.update_edge.assert_has_calls(
[mock.call(mock.ANY, mock.ANY, mock.ANY, None,
appliance_size=nsxv_constants.COMPACT, dist=False)])
appliance_size=nsxv_constants.COMPACT, dist=False,
res_pool=None)])
def test_free_edge_appliance_with_default_with_full(self):
self.edge_pool_dicts = {