NSXv: Add backup pools ranges to each AZ config

A new optional parameter was added to the availability zone section:
backup_edge_pool.
If not set - the global one will be used.

Change-Id: Ib6cad8cf0b31128fe7e68eaecc902e17303efd41
This commit is contained in:
Adit Sarfaty 2017-01-31 12:44:24 +02:00 committed by garyk
parent c4354d31b2
commit a4ed08ec1a
5 changed files with 93 additions and 27 deletions

View File

@ -659,6 +659,8 @@ nsxv_opts = [
# define the configuration of each availability zone.
# the list of expected zones in under nsxv group: availability_zones
# Note: if any of the optional arguments is missing - the global one will be
# used instead.
nsxv_az_opts = [
cfg.StrOpt('resource_pool_id',
help=_('Identifying the ID of resource to deploy NSX Edges')),
@ -677,6 +679,10 @@ nsxv_az_opts = [
'active and the other half will be placed in the '
'ha_datastore. If this value is not set, the global '
'one will be used')),
cfg.ListOpt('backup_edge_pool',
help=_("(Optional) Defines edge pool's management range for "
"the availability zone. If not defined, the global one "
"will be used")),
]
# Register the configuration options

View File

@ -66,12 +66,22 @@ class ConfiguredAvailabilityZone(object):
"enabled"))
self.ha_datastore_id = values[4] if len(values) == 5 else None
# Use the global configuration for ha_placement_random
# Some parameters are not supported in this format.
# using the global ones instead.
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
elif config_line:
# Newer configuration - the name of the availability zone can be
# used to get the rest of the configuration for this AZ
self.name = config_line
# field name size in the DB is 36
if len(self.name) > 36:
raise nsx_exc.NsxInvalidConfiguration(
opt_name="availability_zones",
opt_value=config_line,
reason=_("Maximum name length is 36"))
az_info = config.get_nsxv_az_opts(self.name)
self.resource_pool = az_info.get('resource_pool_id')
if not self.resource_pool:
@ -92,11 +102,17 @@ class ConfiguredAvailabilityZone(object):
self.ha_datastore_id = (az_info.get('ha_datastore_id')
if self.edge_ha else None)
# Use the global config for ha_placement_random if not set
# The optional parameters will get the global values if not
# defined for this AZ
self.ha_placement_random = az_info.get('ha_placement_random')
if self.ha_placement_random is None:
self.ha_placement_random = (
cfg.CONF.nsxv.ha_placement_random)
self.backup_edge_pool = az_info.get('backup_edge_pool', [])
if not self.backup_edge_pool:
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
else:
# use the default configuration
self.name = DEFAULT_NAME
@ -105,6 +121,7 @@ class ConfiguredAvailabilityZone(object):
self.edge_ha = cfg.CONF.nsxv.edge_ha
self.ha_datastore_id = cfg.CONF.nsxv.ha_datastore_id
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
class ConfiguredAvailabilityZones(object):

View File

@ -122,9 +122,9 @@ def is_overlapping_reserved_subnets(cidr, reserved_subnets):
return False
def parse_backup_edge_pool_opt():
"""Parse edge pool opts and returns result."""
edge_pool_opts = cfg.CONF.nsxv.backup_edge_pool
def parse_backup_edge_pool_opt_per_az(az):
"""Parse edge pool opts per AZ and returns result."""
edge_pool_opts = az.backup_edge_pool
res = []
for edge_pool_def in edge_pool_opts:
split = edge_pool_def.split(':')
@ -132,20 +132,25 @@ def parse_backup_edge_pool_opt():
(edge_type, edge_size, minimum_pooled_edges,
maximum_pooled_edges) = split[:4]
except ValueError:
raise n_exc.Invalid(_("Invalid edge pool format"))
raise n_exc.Invalid(_("Invalid edge pool format for availability"
" zone %s") % az.name)
if edge_type not in vcns_const.ALLOWED_EDGE_TYPES:
msg = (_("edge type '%(edge_type)s' is not allowed, "
"allowed types: %(allowed)s") %
"allowed types: %(allowed)s for availability zone "
"%(name)s") %
{'edge_type': edge_type,
'allowed': vcns_const.ALLOWED_EDGE_TYPES})
'allowed': vcns_const.ALLOWED_EDGE_TYPES,
'name': az.name})
LOG.error(msg)
raise n_exc.Invalid(msg)
edge_size = edge_size or nsxv_constants.COMPACT
if edge_size not in vcns_const.ALLOWED_EDGE_SIZES:
msg = (_("edge size '%(edge_size)s' is not allowed, "
"allowed types: %(allowed)s") %
"allowed types: %(allowed)s for availability zone "
"%(name)s") %
{'edge_type': edge_size,
'allowed': vcns_const.ALLOWED_EDGE_SIZES})
'allowed': vcns_const.ALLOWED_EDGE_SIZES,
'name': az.name})
LOG.error(msg)
raise n_exc.Invalid(msg)
res.append({'edge_type': edge_type,
@ -159,7 +164,8 @@ def parse_backup_edge_pool_opt():
for r in res:
edge_pool_dict = edge_pool_dicts[r['edge_type']]
if r['edge_size'] in edge_pool_dict.keys():
raise n_exc.Invalid(_("Duplicate edge pool configuration"))
raise n_exc.Invalid(_("Duplicate edge pool configuration for "
"availability zone %s") % az.name)
else:
edge_pool_dict[r['edge_size']] = {
'minimum_pooled_edges': r['minimum_pooled_edges'],
@ -179,14 +185,26 @@ class EdgeManager(object):
self._worker_pool = None
self.nsxv_manager = nsxv_manager
self.dvs_id = cfg.CONF.nsxv.dvs_id
self.edge_pool_dicts = parse_backup_edge_pool_opt()
self._availability_zones = nsx_az.ConfiguredAvailabilityZones()
self.edge_pool_dicts = self._parse_backup_edge_pool_opt()
self.nsxv_plugin = nsxv_manager.callbacks.plugin
self.plugin = plugin
self._availability_zones = nsx_az.ConfiguredAvailabilityZones()
self.per_interface_rp_filter = self._get_per_edge_rp_filter_state()
self._check_backup_edge_pools()
self._validate_new_features()
def _parse_backup_edge_pool_opt(self):
"""Parse edge pool opts for all availability zones."""
az_list = self._availability_zones.list_availability_zones()
az_pools = {}
for az_name in az_list:
az = self._availability_zones.get_availability_zone(az_name)
az_pools[az.name] = parse_backup_edge_pool_opt_per_az(az)
return az_pools
def _get_az_pool(self, az_name):
return self.edge_pool_dicts[az_name]
def _get_worker_pool(self):
if self._worker_pool_pid != os.getpid():
self._worker_pool_pid = os.getpid()
@ -337,7 +355,7 @@ class EdgeManager(object):
for az_name in self._availability_zones.list_availability_zones():
az = self._availability_zones.get_availability_zone(az_name)
self._clean_all_error_edge_bindings(admin_ctx, az)
for edge_type, v in self.edge_pool_dicts.items():
for edge_type, v in self._get_az_pool(az.name).items():
for edge_size in vcns_const.ALLOWED_EDGE_SIZES:
if edge_size in v.keys():
edge_pool_range = v[edge_size]
@ -626,7 +644,8 @@ class EdgeManager(object):
nsxv_constants.SERVICE_EDGE)
lrouter = {'id': resource_id,
'name': name}
edge_pool_range = self.edge_pool_dicts[edge_type].get(appliance_size)
az_pool = self._get_az_pool(availability_zone.name)
edge_pool_range = az_pool[edge_type].get(appliance_size)
if edge_pool_range is None:
nsxv_db.add_nsxv_router_binding(
context.session, resource_id, None, None,
@ -717,7 +736,8 @@ class EdgeManager(object):
edge_id = binding['edge_id']
availability_zone_name = nsxv_db.get_edge_availability_zone(
context.session, edge_id)
edge_pool_range = self.edge_pool_dicts[binding['edge_type']].get(
az_pool = self._get_az_pool(availability_zone_name)
edge_pool_range = az_pool[binding['edge_type']].get(
binding['appliance_size'])
nsxv_db.delete_nsxv_router_binding(

View File

@ -22,6 +22,10 @@ from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.plugins.nsx_v import availability_zones as nsx_az
DEF_AZ_POOL = ['service:compact:1:2', 'vdr:compact:1:2']
DEF_GLOBAL_POOL = ['service:compact:4:10', 'vdr:compact:4:10']
class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
def setUp(self):
@ -33,7 +37,8 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
def _config_az(self, resource_pool_id="respool", datastore_id="datastore",
edge_ha=True, ha_datastore_id="hastore",
ha_placement_random=False):
ha_placement_random=False,
backup_edge_pool=DEF_AZ_POOL):
cfg.CONF.set_override("resource_pool_id", resource_pool_id,
group=self.group_name)
cfg.CONF.set_override("datastore_id", datastore_id,
@ -47,6 +52,9 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
cfg.CONF.set_override("ha_placement_random",
ha_placement_random,
group=self.group_name)
if backup_edge_pool is not None:
cfg.CONF.set_override("backup_edge_pool", backup_edge_pool,
group=self.group_name)
def test_simple_availability_zone(self):
self._config_az()
@ -57,6 +65,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
self.assertEqual(True, az.edge_ha)
self.assertEqual("hastore", az.ha_datastore_id)
self.assertEqual(False, az.ha_placement_random)
self.assertEqual(DEF_AZ_POOL, az.backup_edge_pool)
def test_availability_zone_no_edge_ha(self):
self._config_az(edge_ha=False)
@ -119,6 +128,13 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
# ha_placement_random should have the global value
self.assertEqual(True, az.ha_placement_random)
def test_availability_zone_missing_backup_pool(self):
self._config_az(backup_edge_pool=None)
az = nsx_az.ConfiguredAvailabilityZone(self.az_name)
self.assertEqual(self.az_name, az.name)
# Should use the global configuration instead
self.assertEqual(DEF_GLOBAL_POOL, az.backup_edge_pool)
class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
"""Test old way of configuring the availability zones
@ -135,6 +151,7 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
self.assertEqual(True, az.edge_ha)
self.assertEqual("hastore", az.ha_datastore_id)
self.assertEqual(False, az.ha_placement_random)
self.assertEqual(DEF_GLOBAL_POOL, az.backup_edge_pool)
def test_availability_zone_without_ha_datastore(self):
az = nsx_az.ConfiguredAvailabilityZone(

View File

@ -327,18 +327,18 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
self.check = mock.patch.object(self.edge_manager,
'check_edge_active_at_backend').start()
self.check.side_effect = self.check_edge_active_at_backend
self.default_edge_pool_dicts = {
self.default_edge_pool_dicts = {'default': {
nsxv_constants.SERVICE_EDGE: {
nsxv_constants.LARGE: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3},
nsxv_constants.COMPACT: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3}},
nsxv_constants.VDR_EDGE: {}}
self.vdr_edge_pool_dicts = {
nsxv_constants.VDR_EDGE: {}}}
self.vdr_edge_pool_dicts = {'default': {
nsxv_constants.SERVICE_EDGE: {},
nsxv_constants.VDR_EDGE: {
nsxv_constants.LARGE: {'minimum_pooled_edges': 1,
'maximum_pooled_edges': 3}}}
'maximum_pooled_edges': 3}}}}
def check_edge_active_at_backend(self, edge_id):
# workaround to let edge_id None pass since we wrapped router binding
@ -352,12 +352,15 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
cfg.CONF.set_override('backup_edge_pool',
['service:large:1:3', 'service:compact:1:3'],
'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
self.assertEqual(self.default_edge_pool_dicts, edge_pool_dicts)
az = nsx_az.ConfiguredAvailabilityZone(None)
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt_per_az(az)
self.assertEqual(self.default_edge_pool_dicts['default'],
edge_pool_dicts)
def test_backup_edge_pool_with_empty_conf(self):
cfg.CONF.set_override('backup_edge_pool', [], 'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
az = nsx_az.ConfiguredAvailabilityZone(None)
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt_per_az(az)
expect_edge_pool_dicts = {
nsxv_constants.SERVICE_EDGE: {},
nsxv_constants.VDR_EDGE: {}}
@ -365,15 +368,18 @@ class EdgeManagerTestCase(EdgeUtilsTestCaseMixin):
def test_backup_edge_pool_with_vdr_conf(self):
cfg.CONF.set_override('backup_edge_pool', ['vdr:large:1:3'], 'nsxv')
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt()
expect_edge_pool_dicts = self.vdr_edge_pool_dicts
az = nsx_az.ConfiguredAvailabilityZone(None)
edge_pool_dicts = edge_utils.parse_backup_edge_pool_opt_per_az(az)
expect_edge_pool_dicts = self.vdr_edge_pool_dicts['default']
self.assertEqual(expect_edge_pool_dicts, edge_pool_dicts)
def test_backup_edge_pool_with_duplicate_conf(self):
cfg.CONF.set_override('backup_edge_pool',
['service:compact:1:3', 'service::3:4'],
'nsxv')
self.assertRaises(n_exc.Invalid, edge_utils.parse_backup_edge_pool_opt)
az = nsx_az.ConfiguredAvailabilityZone(None)
self.assertRaises(n_exc.Invalid,
edge_utils.parse_backup_edge_pool_opt_per_az, az)
def _create_router_bindings(self, num, status, id_prefix, size,
edge_type, availability_zone):