NSXv: Edge random placement
Support randomly selecting which will be the primary datastore and which will be the secondary one when deplying an edge, in order to balance the load. This new option is available globally as well as per availability_zone via a new configuration parameter edge_placement_random which will be False by default. Change-Id: I5bf8f8999100c4c6da4645bda6e74165575c3818
This commit is contained in:
parent
dd1923005c
commit
3ac633ec68
@ -0,0 +1,9 @@
|
||||
---
|
||||
prelude: >
|
||||
Support randomly selecting which will be the primary datastore and which
|
||||
will be the secondary one when deplying an edge, in order to balance the load.
|
||||
This new option is available globally as well as per availability_zone.
|
||||
features:
|
||||
- |
|
||||
Support randomly selecting which will be the primary datastore and which
|
||||
will be the secondary one when deplying an edge, in order to balance the load.
|
@ -461,6 +461,12 @@ nsxv_opts = [
|
||||
help=_('Optional parameter identifying the ID of datastore to '
|
||||
'deploy NSX Edges in addition to data_store_id in case'
|
||||
'edge_ha is True')),
|
||||
cfg.BoolOpt('ha_placement_random',
|
||||
default=False,
|
||||
help=_('When True and in case edge_ha is True, half of the '
|
||||
'edges will be placed in the primary datastore as '
|
||||
'active and the other half will be placed in the '
|
||||
'ha_datastore')),
|
||||
cfg.StrOpt('external_network',
|
||||
deprecated_group="vcns",
|
||||
help=_('(Required) Network ID for physical network '
|
||||
@ -663,6 +669,12 @@ nsxv_az_opts = [
|
||||
help=_('Optional parameter identifying the ID of datastore to '
|
||||
'deploy NSX Edges in addition to data_store_id in case'
|
||||
'edge_ha is True')),
|
||||
cfg.BoolOpt('ha_placement_random',
|
||||
help=_('When True and in case edge_ha is True, half of the '
|
||||
'edges will be placed in the primary datastore as '
|
||||
'active and the other half will be placed in the '
|
||||
'ha_datastore. If this value is not set, the global '
|
||||
'one will be used')),
|
||||
]
|
||||
|
||||
# Register the configuration options
|
||||
|
@ -66,6 +66,8 @@ class ConfiguredAvailabilityZone(object):
|
||||
"enabled"))
|
||||
|
||||
self.ha_datastore_id = values[4] if len(values) == 5 else None
|
||||
# Use the global configuration for ha_placement_random
|
||||
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
||||
elif config_line:
|
||||
# Newer configuration - the name of the availability zone can be
|
||||
# used to get the rest of the configuration for this AZ
|
||||
@ -89,6 +91,12 @@ class ConfiguredAvailabilityZone(object):
|
||||
# The HA datastore can be empty
|
||||
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
|
||||
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)
|
||||
else:
|
||||
# use the default configuration
|
||||
self.name = DEFAULT_NAME
|
||||
@ -96,6 +104,7 @@ class ConfiguredAvailabilityZone(object):
|
||||
self.datastore_id = cfg.CONF.nsxv.datastore_id
|
||||
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
|
||||
|
||||
|
||||
class ConfiguredAvailabilityZones(object):
|
||||
|
@ -13,6 +13,7 @@
|
||||
# under the License.
|
||||
|
||||
from distutils import version
|
||||
import random
|
||||
import time
|
||||
|
||||
from neutron.plugins.common import constants as plugin_const
|
||||
@ -45,6 +46,7 @@ class EdgeApplianceDriver(object):
|
||||
'nat': {},
|
||||
'route': {},
|
||||
}
|
||||
random.seed()
|
||||
|
||||
def _assemble_edge(self, name, appliance_size="compact",
|
||||
deployment_container_id=None, datacenter_moid=None,
|
||||
@ -95,16 +97,34 @@ class EdgeApplianceDriver(object):
|
||||
|
||||
return edge
|
||||
|
||||
def _select_datastores(self, availability_zone):
|
||||
primary_ds = availability_zone.datastore_id
|
||||
secondary_ds = availability_zone.ha_datastore_id
|
||||
if availability_zone.ha_placement_random:
|
||||
# we want to switch primary and secondary datastores
|
||||
# half of the times, to balance it
|
||||
if random.random() > 0.5:
|
||||
primary_ds = availability_zone.ha_datastore_id
|
||||
secondary_ds = availability_zone.datastore_id
|
||||
return primary_ds, secondary_ds
|
||||
|
||||
def _assemble_edge_appliances(self, availability_zone):
|
||||
appliances = []
|
||||
if availability_zone.datastore_id:
|
||||
if availability_zone.ha_datastore_id and availability_zone.edge_ha:
|
||||
# create appliance with HA
|
||||
primary_ds, secondary_ds = self._select_datastores(
|
||||
availability_zone)
|
||||
appliances.append(self._assemble_edge_appliance(
|
||||
availability_zone.resource_pool,
|
||||
primary_ds))
|
||||
appliances.append(self._assemble_edge_appliance(
|
||||
availability_zone.resource_pool,
|
||||
secondary_ds))
|
||||
elif availability_zone.datastore_id:
|
||||
# Single datastore
|
||||
appliances.append(self._assemble_edge_appliance(
|
||||
availability_zone.resource_pool,
|
||||
availability_zone.datastore_id))
|
||||
if availability_zone.ha_datastore_id and availability_zone.edge_ha:
|
||||
appliances.append(self._assemble_edge_appliance(
|
||||
availability_zone.resource_pool,
|
||||
availability_zone.ha_datastore_id))
|
||||
return appliances
|
||||
|
||||
def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
|
||||
|
@ -29,9 +29,11 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.az_name = 'zone1'
|
||||
self.group_name = 'az:%s' % self.az_name
|
||||
config.register_nsxv_azs(cfg.CONF, [self.az_name])
|
||||
cfg.CONF.set_override("ha_placement_random", True, group="nsxv")
|
||||
|
||||
def _config_az(self, resource_pool_id="respool", datastore_id="datastore",
|
||||
edge_ha=True, ha_datastore_id="hastore"):
|
||||
edge_ha=True, ha_datastore_id="hastore",
|
||||
ha_placement_random=False):
|
||||
cfg.CONF.set_override("resource_pool_id", resource_pool_id,
|
||||
group=self.group_name)
|
||||
cfg.CONF.set_override("datastore_id", datastore_id,
|
||||
@ -41,6 +43,10 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
group=self.group_name)
|
||||
cfg.CONF.set_override("ha_datastore_id", ha_datastore_id,
|
||||
group=self.group_name)
|
||||
if ha_placement_random is not None:
|
||||
cfg.CONF.set_override("ha_placement_random",
|
||||
ha_placement_random,
|
||||
group=self.group_name)
|
||||
|
||||
def test_simple_availability_zone(self):
|
||||
self._config_az()
|
||||
@ -50,6 +56,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_no_edge_ha(self):
|
||||
self._config_az(edge_ha=False)
|
||||
@ -59,6 +66,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(False, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_no_ha_datastore(self):
|
||||
self._config_az(ha_datastore_id=None)
|
||||
@ -68,6 +76,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
|
||||
def test_missing_group_section(self):
|
||||
self.assertRaises(
|
||||
@ -97,6 +106,18 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(False, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_missing_edge_placement(self):
|
||||
self._config_az(ha_placement_random=None)
|
||||
az = nsx_az.ConfiguredAvailabilityZone(self.az_name)
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
# ha_placement_random should have the global value
|
||||
self.assertEqual(True, az.ha_placement_random)
|
||||
|
||||
|
||||
class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
@ -113,6 +134,7 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_without_ha_datastore(self):
|
||||
az = nsx_az.ConfiguredAvailabilityZone(
|
||||
|
Loading…
Reference in New Issue
Block a user