Merge "NSXv: Edge random placement"
This commit is contained in:
@@ -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.
|
||||||
@@ -454,6 +454,12 @@ nsxv_opts = [
|
|||||||
help=_('Optional parameter identifying the ID of datastore to '
|
help=_('Optional parameter identifying the ID of datastore to '
|
||||||
'deploy NSX Edges in addition to data_store_id in case'
|
'deploy NSX Edges in addition to data_store_id in case'
|
||||||
'edge_ha is True')),
|
'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',
|
cfg.StrOpt('external_network',
|
||||||
help=_('(Required) Network ID for physical network '
|
help=_('(Required) Network ID for physical network '
|
||||||
'connectivity')),
|
'connectivity')),
|
||||||
@@ -654,6 +660,12 @@ nsxv_az_opts = [
|
|||||||
help=_('Optional parameter identifying the ID of datastore to '
|
help=_('Optional parameter identifying the ID of datastore to '
|
||||||
'deploy NSX Edges in addition to data_store_id in case'
|
'deploy NSX Edges in addition to data_store_id in case'
|
||||||
'edge_ha is True')),
|
'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
|
# Register the configuration options
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ class ConfiguredAvailabilityZone(object):
|
|||||||
"enabled"))
|
"enabled"))
|
||||||
|
|
||||||
self.ha_datastore_id = values[4] if len(values) == 5 else None
|
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:
|
elif config_line:
|
||||||
# Newer configuration - the name of the availability zone can be
|
# Newer configuration - the name of the availability zone can be
|
||||||
# used to get the rest of the configuration for this AZ
|
# used to get the rest of the configuration for this AZ
|
||||||
@@ -89,6 +91,12 @@ class ConfiguredAvailabilityZone(object):
|
|||||||
# The HA datastore can be empty
|
# The HA datastore can be empty
|
||||||
self.ha_datastore_id = (az_info.get('ha_datastore_id')
|
self.ha_datastore_id = (az_info.get('ha_datastore_id')
|
||||||
if self.edge_ha else None)
|
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:
|
else:
|
||||||
# use the default configuration
|
# use the default configuration
|
||||||
self.name = DEFAULT_NAME
|
self.name = DEFAULT_NAME
|
||||||
@@ -96,6 +104,7 @@ class ConfiguredAvailabilityZone(object):
|
|||||||
self.datastore_id = cfg.CONF.nsxv.datastore_id
|
self.datastore_id = cfg.CONF.nsxv.datastore_id
|
||||||
self.edge_ha = cfg.CONF.nsxv.edge_ha
|
self.edge_ha = cfg.CONF.nsxv.edge_ha
|
||||||
self.ha_datastore_id = cfg.CONF.nsxv.ha_datastore_id
|
self.ha_datastore_id = cfg.CONF.nsxv.ha_datastore_id
|
||||||
|
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
||||||
|
|
||||||
|
|
||||||
class ConfiguredAvailabilityZones(object):
|
class ConfiguredAvailabilityZones(object):
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
from distutils import version
|
from distutils import version
|
||||||
|
import random
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from neutron.plugins.common import constants as plugin_const
|
from neutron.plugins.common import constants as plugin_const
|
||||||
@@ -45,6 +46,7 @@ class EdgeApplianceDriver(object):
|
|||||||
'nat': {},
|
'nat': {},
|
||||||
'route': {},
|
'route': {},
|
||||||
}
|
}
|
||||||
|
random.seed()
|
||||||
|
|
||||||
def _assemble_edge(self, name, appliance_size="compact",
|
def _assemble_edge(self, name, appliance_size="compact",
|
||||||
deployment_container_id=None, datacenter_moid=None,
|
deployment_container_id=None, datacenter_moid=None,
|
||||||
@@ -95,16 +97,34 @@ class EdgeApplianceDriver(object):
|
|||||||
|
|
||||||
return edge
|
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):
|
def _assemble_edge_appliances(self, availability_zone):
|
||||||
appliances = []
|
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(
|
appliances.append(self._assemble_edge_appliance(
|
||||||
availability_zone.resource_pool,
|
availability_zone.resource_pool,
|
||||||
availability_zone.datastore_id))
|
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
|
return appliances
|
||||||
|
|
||||||
def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
|
def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
self.az_name = 'zone1'
|
self.az_name = 'zone1'
|
||||||
self.group_name = 'az:%s' % self.az_name
|
self.group_name = 'az:%s' % self.az_name
|
||||||
config.register_nsxv_azs(cfg.CONF, [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",
|
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,
|
cfg.CONF.set_override("resource_pool_id", resource_pool_id,
|
||||||
group=self.group_name)
|
group=self.group_name)
|
||||||
cfg.CONF.set_override("datastore_id", datastore_id,
|
cfg.CONF.set_override("datastore_id", datastore_id,
|
||||||
@@ -41,6 +43,10 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
group=self.group_name)
|
group=self.group_name)
|
||||||
cfg.CONF.set_override("ha_datastore_id", ha_datastore_id,
|
cfg.CONF.set_override("ha_datastore_id", ha_datastore_id,
|
||||||
group=self.group_name)
|
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):
|
def test_simple_availability_zone(self):
|
||||||
self._config_az()
|
self._config_az()
|
||||||
@@ -50,6 +56,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual("datastore", az.datastore_id)
|
self.assertEqual("datastore", az.datastore_id)
|
||||||
self.assertEqual(True, az.edge_ha)
|
self.assertEqual(True, az.edge_ha)
|
||||||
self.assertEqual("hastore", az.ha_datastore_id)
|
self.assertEqual("hastore", az.ha_datastore_id)
|
||||||
|
self.assertEqual(False, az.ha_placement_random)
|
||||||
|
|
||||||
def test_availability_zone_no_edge_ha(self):
|
def test_availability_zone_no_edge_ha(self):
|
||||||
self._config_az(edge_ha=False)
|
self._config_az(edge_ha=False)
|
||||||
@@ -59,6 +66,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual("datastore", az.datastore_id)
|
self.assertEqual("datastore", az.datastore_id)
|
||||||
self.assertEqual(False, az.edge_ha)
|
self.assertEqual(False, az.edge_ha)
|
||||||
self.assertEqual(None, az.ha_datastore_id)
|
self.assertEqual(None, az.ha_datastore_id)
|
||||||
|
self.assertEqual(False, az.ha_placement_random)
|
||||||
|
|
||||||
def test_availability_zone_no_ha_datastore(self):
|
def test_availability_zone_no_ha_datastore(self):
|
||||||
self._config_az(ha_datastore_id=None)
|
self._config_az(ha_datastore_id=None)
|
||||||
@@ -68,6 +76,7 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual("datastore", az.datastore_id)
|
self.assertEqual("datastore", az.datastore_id)
|
||||||
self.assertEqual(True, az.edge_ha)
|
self.assertEqual(True, az.edge_ha)
|
||||||
self.assertEqual(None, az.ha_datastore_id)
|
self.assertEqual(None, az.ha_datastore_id)
|
||||||
|
self.assertEqual(False, az.ha_placement_random)
|
||||||
|
|
||||||
def test_missing_group_section(self):
|
def test_missing_group_section(self):
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
@@ -97,6 +106,18 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual("datastore", az.datastore_id)
|
self.assertEqual("datastore", az.datastore_id)
|
||||||
self.assertEqual(False, az.edge_ha)
|
self.assertEqual(False, az.edge_ha)
|
||||||
self.assertEqual(None, az.ha_datastore_id)
|
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):
|
class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||||
@@ -113,6 +134,7 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
|||||||
self.assertEqual("datastore", az.datastore_id)
|
self.assertEqual("datastore", az.datastore_id)
|
||||||
self.assertEqual(True, az.edge_ha)
|
self.assertEqual(True, az.edge_ha)
|
||||||
self.assertEqual("hastore", az.ha_datastore_id)
|
self.assertEqual("hastore", az.ha_datastore_id)
|
||||||
|
self.assertEqual(False, az.ha_placement_random)
|
||||||
|
|
||||||
def test_availability_zone_without_ha_datastore(self):
|
def test_availability_zone_without_ha_datastore(self):
|
||||||
az = nsx_az.ConfiguredAvailabilityZone(
|
az = nsx_az.ConfiguredAvailabilityZone(
|
||||||
|
|||||||
Reference in New Issue
Block a user