NSX|v: Support more than 2 hostgroups
If edge_ha=True and ha_placement_random=True The user can configure more than 2 edge_host_groups globally or per availability zone. In this case 2 of those will be randomly selected for each deployed edge. Change-Id: Iaa673e5acf78ecdf8cbc942499cce70a2fe0546c
This commit is contained in:
parent
f02e3307be
commit
35d13ead0f
@ -484,8 +484,8 @@ nsxv_opts = [
|
|||||||
default=[],
|
default=[],
|
||||||
help=_('(Optional) If edge HA is used then this will ensure '
|
help=_('(Optional) If edge HA is used then this will ensure '
|
||||||
'that active/backup edges are placed in the listed '
|
'that active/backup edges are placed in the listed '
|
||||||
'host groups. 2 predefined host groups need to be '
|
'host groups. At least 2 predefined host groups need '
|
||||||
'configured.')),
|
'to be configured.')),
|
||||||
cfg.StrOpt('external_network',
|
cfg.StrOpt('external_network',
|
||||||
help=_('(Required) Network ID for physical network '
|
help=_('(Required) Network ID for physical network '
|
||||||
'connectivity')),
|
'connectivity')),
|
||||||
@ -709,8 +709,8 @@ nsxv_az_opts = [
|
|||||||
default=[],
|
default=[],
|
||||||
help=_('(Optional) If edge HA is used then this will ensure '
|
help=_('(Optional) If edge HA is used then this will ensure '
|
||||||
'that active/backup edges are placed in the listed '
|
'that active/backup edges are placed in the listed '
|
||||||
'host groups. 2 predefined host groups need to be '
|
'host groups. At least 2 predefined host groups need '
|
||||||
'configured.')),
|
'to be configured.')),
|
||||||
cfg.StrOpt('datacenter_moid',
|
cfg.StrOpt('datacenter_moid',
|
||||||
help=_('(Optional) Identifying the ID of datacenter to deploy '
|
help=_('(Optional) Identifying the ID of datacenter to deploy '
|
||||||
'NSX Edges')),
|
'NSX Edges')),
|
||||||
|
@ -161,7 +161,6 @@ class DvsManager(VCManagerBase):
|
|||||||
'vlan_tag': vlan_tag,
|
'vlan_tag': vlan_tag,
|
||||||
'dvs': dvs_moref.value})
|
'dvs': dvs_moref.value})
|
||||||
|
|
||||||
# DEBUG ADIT used only by the DVS plugin
|
|
||||||
def _net_id_to_moref(self, dvs_moref, net_id):
|
def _net_id_to_moref(self, dvs_moref, net_id):
|
||||||
"""Gets the moref for the specific neutron network."""
|
"""Gets the moref for the specific neutron network."""
|
||||||
# NOTE(garyk): return this from a cache if not found then invoke
|
# NOTE(garyk): return this from a cache if not found then invoke
|
||||||
@ -564,9 +563,9 @@ class ClusterManager(VCManagerBase):
|
|||||||
reconfig_task = session.invoke_api(
|
reconfig_task = session.invoke_api(
|
||||||
session.vim, "ReconfigureComputeResource_Task",
|
session.vim, "ReconfigureComputeResource_Task",
|
||||||
cluster, spec=config_spec, modify=True)
|
cluster, spec=config_spec, modify=True)
|
||||||
|
session.wait_for_task(reconfig_task)
|
||||||
except Exception as excep:
|
except Exception as excep:
|
||||||
LOG.exception('Failed to reconfigure cluster %s', excep)
|
LOG.exception('Failed to reconfigure cluster %s', excep)
|
||||||
session.wait_for_task(reconfig_task)
|
|
||||||
|
|
||||||
def _create_vm_group_spec(self, client_factory, name, vm_refs,
|
def _create_vm_group_spec(self, client_factory, name, vm_refs,
|
||||||
group=None):
|
group=None):
|
||||||
@ -605,7 +604,7 @@ class ClusterManager(VCManagerBase):
|
|||||||
rules_spec.info = rules_info
|
rules_spec.info = rules_info
|
||||||
return rules_spec
|
return rules_spec
|
||||||
|
|
||||||
def get_configured_vms(self, resource_id):
|
def get_configured_vms(self, resource_id, n_host_groups=2):
|
||||||
session = self._session
|
session = self._session
|
||||||
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
||||||
# TODO(garyk): cache the cluster details
|
# TODO(garyk): cache the cluster details
|
||||||
@ -616,7 +615,7 @@ class ClusterManager(VCManagerBase):
|
|||||||
vim_util, "get_object_property", self._session.vim, cluster,
|
vim_util, "get_object_property", self._session.vim, cluster,
|
||||||
"configurationEx")
|
"configurationEx")
|
||||||
configured_vms = []
|
configured_vms = []
|
||||||
for index in range(2):
|
for index in range(n_host_groups):
|
||||||
vm_group = None
|
vm_group = None
|
||||||
entry_id = index + 1
|
entry_id = index + 1
|
||||||
groups = []
|
groups = []
|
||||||
@ -632,8 +631,9 @@ class ClusterManager(VCManagerBase):
|
|||||||
return configured_vms
|
return configured_vms
|
||||||
|
|
||||||
def update_cluster_edge_failover(self, resource_id, vm_moids,
|
def update_cluster_edge_failover(self, resource_id, vm_moids,
|
||||||
edge_id, host_group_names):
|
host_group_names):
|
||||||
"""Updates cluster for vm placement using DRS"""
|
"""Updates cluster for vm placement using DRS"""
|
||||||
|
# DEBUG ADIT edge-id is never used
|
||||||
session = self._session
|
session = self._session
|
||||||
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
||||||
# TODO(garyk): cache the cluster details
|
# TODO(garyk): cache the cluster details
|
||||||
@ -643,12 +643,20 @@ class ClusterManager(VCManagerBase):
|
|||||||
cluster_config = session.invoke_api(
|
cluster_config = session.invoke_api(
|
||||||
vim_util, "get_object_property", self._session.vim, cluster,
|
vim_util, "get_object_property", self._session.vim, cluster,
|
||||||
"configurationEx")
|
"configurationEx")
|
||||||
vms = [vim_util.get_moref(vm_moid, 'VirtualMachine') for
|
vms = [vim_util.get_moref(vm_moid, 'VirtualMachine')
|
||||||
vm_moid in vm_moids]
|
if vm_moid else None
|
||||||
|
for vm_moid in vm_moids]
|
||||||
client_factory = session.vim.client.factory
|
client_factory = session.vim.client.factory
|
||||||
config_spec = client_factory.create('ns0:ClusterConfigSpecEx')
|
config_spec = client_factory.create('ns0:ClusterConfigSpecEx')
|
||||||
num_host_groups = len(host_group_names)
|
num_host_groups = len(host_group_names)
|
||||||
|
|
||||||
|
rules = []
|
||||||
|
if hasattr(cluster_config, 'rule'):
|
||||||
|
rules = cluster_config.rule
|
||||||
|
|
||||||
for index, vm in enumerate(vms, start=1):
|
for index, vm in enumerate(vms, start=1):
|
||||||
|
if not vm:
|
||||||
|
continue
|
||||||
vmGroup = None
|
vmGroup = None
|
||||||
groups = []
|
groups = []
|
||||||
if hasattr(cluster_config, 'group'):
|
if hasattr(cluster_config, 'group'):
|
||||||
@ -664,9 +672,6 @@ class ClusterManager(VCManagerBase):
|
|||||||
[vm], vmGroup)
|
[vm], vmGroup)
|
||||||
config_spec.groupSpec.append(groupSpec)
|
config_spec.groupSpec.append(groupSpec)
|
||||||
config_rule = None
|
config_rule = None
|
||||||
rules = []
|
|
||||||
if hasattr(cluster_config, 'rule'):
|
|
||||||
rules = cluster_config.rule
|
|
||||||
# Create the config rule if it does not exist
|
# Create the config rule if it does not exist
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if 'neutron-rule-%s' % index == rule.name:
|
if 'neutron-rule-%s' % index == rule.name:
|
||||||
@ -691,11 +696,11 @@ class ClusterManager(VCManagerBase):
|
|||||||
cluster_config = session.invoke_api(
|
cluster_config = session.invoke_api(
|
||||||
vim_util, "get_object_property", self._session.vim, cluster,
|
vim_util, "get_object_property", self._session.vim, cluster,
|
||||||
"configurationEx")
|
"configurationEx")
|
||||||
|
groups = []
|
||||||
|
if hasattr(cluster_config, 'group'):
|
||||||
|
groups = cluster_config.group
|
||||||
for host_group_name in host_group_names:
|
for host_group_name in host_group_names:
|
||||||
found = False
|
found = False
|
||||||
groups = []
|
|
||||||
if hasattr(cluster_config, 'group'):
|
|
||||||
groups = cluster_config.group
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if host_group_name == group.name:
|
if host_group_name == group.name:
|
||||||
found = True
|
found = True
|
||||||
@ -703,15 +708,16 @@ class ClusterManager(VCManagerBase):
|
|||||||
if not found:
|
if not found:
|
||||||
LOG.error("%s does not exist", host_group_name)
|
LOG.error("%s does not exist", host_group_name)
|
||||||
raise exceptions.NotFound()
|
raise exceptions.NotFound()
|
||||||
|
|
||||||
update_cluster = False
|
update_cluster = False
|
||||||
num_host_groups = len(host_group_names)
|
num_host_groups = len(host_group_names)
|
||||||
|
rules = []
|
||||||
|
if hasattr(cluster_config, 'rule'):
|
||||||
|
rules = cluster_config.rule
|
||||||
# Ensure that the VM groups are created
|
# Ensure that the VM groups are created
|
||||||
for index in range(2):
|
for index in range(num_host_groups):
|
||||||
entry_id = index + 1
|
entry_id = index + 1
|
||||||
vmGroup = None
|
vmGroup = None
|
||||||
groups = []
|
|
||||||
if hasattr(cluster_config, 'group'):
|
|
||||||
groups = cluster_config.group
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if 'neutron-group-%s' % entry_id == group.name:
|
if 'neutron-group-%s' % entry_id == group.name:
|
||||||
vmGroup = group
|
vmGroup = group
|
||||||
@ -725,9 +731,6 @@ class ClusterManager(VCManagerBase):
|
|||||||
update_cluster = True
|
update_cluster = True
|
||||||
|
|
||||||
config_rule = None
|
config_rule = None
|
||||||
rules = []
|
|
||||||
if hasattr(cluster_config, 'rule'):
|
|
||||||
rules = cluster_config.rule
|
|
||||||
# Create the config rule if it does not exist
|
# Create the config rule if it does not exist
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if 'neutron-rule-%s' % entry_id == rule.name:
|
if 'neutron-rule-%s' % entry_id == rule.name:
|
||||||
@ -744,8 +747,7 @@ class ClusterManager(VCManagerBase):
|
|||||||
try:
|
try:
|
||||||
self._reconfigure_cluster(session, cluster, config_spec)
|
self._reconfigure_cluster(session, cluster, config_spec)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error('Unable to update cluster for host groups %s',
|
LOG.error('Unable to update cluster for host groups %s', e)
|
||||||
e)
|
|
||||||
|
|
||||||
def _delete_vm_group_spec(self, client_factory, name):
|
def _delete_vm_group_spec(self, client_factory, name):
|
||||||
group_spec = client_factory.create('ns0:ClusterGroupSpec')
|
group_spec = client_factory.create('ns0:ClusterGroupSpec')
|
||||||
@ -768,7 +770,7 @@ class ClusterManager(VCManagerBase):
|
|||||||
rules_spec.info = rules_info
|
rules_spec.info = rules_info
|
||||||
return rules_spec
|
return rules_spec
|
||||||
|
|
||||||
def cluster_host_group_cleanup(self, resource_id):
|
def cluster_host_group_cleanup(self, resource_id, n_host_groups=2):
|
||||||
session = self._session
|
session = self._session
|
||||||
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
resource = vim_util.get_moref(resource_id, 'ResourcePool')
|
||||||
# TODO(garyk): cache the cluster details
|
# TODO(garyk): cache the cluster details
|
||||||
@ -780,21 +782,22 @@ class ClusterManager(VCManagerBase):
|
|||||||
cluster_config = session.invoke_api(
|
cluster_config = session.invoke_api(
|
||||||
vim_util, "get_object_property", self._session.vim, cluster,
|
vim_util, "get_object_property", self._session.vim, cluster,
|
||||||
"configurationEx")
|
"configurationEx")
|
||||||
|
groups = []
|
||||||
|
if hasattr(cluster_config, 'group'):
|
||||||
|
groups = cluster_config.group
|
||||||
|
rules = []
|
||||||
|
if hasattr(cluster_config, 'rule'):
|
||||||
|
rules = cluster_config.rule
|
||||||
|
|
||||||
groupSpec = []
|
groupSpec = []
|
||||||
ruleSpec = []
|
ruleSpec = []
|
||||||
for index in range(2):
|
for index in range(n_host_groups):
|
||||||
entry_id = index + 1
|
entry_id = index + 1
|
||||||
groups = []
|
|
||||||
if hasattr(cluster_config, 'group'):
|
|
||||||
groups = cluster_config.group
|
|
||||||
for group in groups:
|
for group in groups:
|
||||||
if 'neutron-group-%s' % entry_id == group.name:
|
if 'neutron-group-%s' % entry_id == group.name:
|
||||||
groupSpec.append(self._delete_vm_group_spec(
|
groupSpec.append(self._delete_vm_group_spec(
|
||||||
client_factory, group.name))
|
client_factory, group.name))
|
||||||
rules = []
|
# Delete the config rule if it exists
|
||||||
if hasattr(cluster_config, 'rule'):
|
|
||||||
rules = cluster_config.rule
|
|
||||||
# Create the config rule if it does not exist
|
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
if 'neutron-rule-%s' % entry_id == rule.name:
|
if 'neutron-rule-%s' % entry_id == rule.name:
|
||||||
ruleSpec.append(self._delete_cluster_rules_spec(
|
ruleSpec.append(self._delete_cluster_rules_spec(
|
||||||
|
@ -4193,6 +4193,18 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
|||||||
azs = self.get_azs_list()
|
azs = self.get_azs_list()
|
||||||
for az in azs:
|
for az in azs:
|
||||||
if az.edge_host_groups and az.edge_ha:
|
if az.edge_host_groups and az.edge_ha:
|
||||||
|
if len(az.edge_host_groups) < 2:
|
||||||
|
error = _("edge_host_groups must have at least 2 "
|
||||||
|
"names")
|
||||||
|
raise nsx_exc.NsxPluginException(err_msg=error)
|
||||||
|
if (not az.ha_placement_random and
|
||||||
|
len(az.edge_host_groups) > 2):
|
||||||
|
LOG.warning("Availability zone %(az)s has %(count)s "
|
||||||
|
"hostgroups. only the first 2 will be "
|
||||||
|
"used until ha_placement_random is "
|
||||||
|
"enabled",
|
||||||
|
{'az': az.name,
|
||||||
|
'count': len(az.edge_host_groups)})
|
||||||
self._vcm.validate_host_groups(az.resource_pool,
|
self._vcm.validate_host_groups(az.resource_pool,
|
||||||
az.edge_host_groups)
|
az.edge_host_groups)
|
||||||
|
|
||||||
|
@ -723,7 +723,6 @@ class EdgeManager(object):
|
|||||||
context, edge_id, lrouter['name'], lrouter['id'], dist,
|
context, edge_id, lrouter['name'], lrouter['id'], dist,
|
||||||
True, availability_zone=availability_zone,
|
True, availability_zone=availability_zone,
|
||||||
deploy_metadata=deploy_metadata)
|
deploy_metadata=deploy_metadata)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.nsxv_manager.rename_edge(edge_id, name)
|
self.nsxv_manager.rename_edge(edge_id, name)
|
||||||
except nsxapi_exc.VcnsApiException as e:
|
except nsxapi_exc.VcnsApiException as e:
|
||||||
@ -2603,22 +2602,26 @@ def update_edge_host_groups(vcns, edge_id, dvs, availability_zone,
|
|||||||
for appliance in appliances['appliances']]
|
for appliance in appliances['appliances']]
|
||||||
if validate:
|
if validate:
|
||||||
configured_vms = dvs.get_configured_vms(
|
configured_vms = dvs.get_configured_vms(
|
||||||
availability_zone.resource_pool)
|
availability_zone.resource_pool,
|
||||||
|
len(availability_zone.edge_host_groups))
|
||||||
for vm in vms:
|
for vm in vms:
|
||||||
if vm in configured_vms:
|
if vm in configured_vms:
|
||||||
LOG.info('Edge %s already configured', edge_id)
|
LOG.info('Edge %s already configured', edge_id)
|
||||||
return
|
return
|
||||||
|
LOG.info('Create DRS groups for %(vms)s on edge %(edge_id)s',
|
||||||
|
{'vms': vms, 'edge_id': edge_id})
|
||||||
# Ensure random distribution of the VMs
|
# Ensure random distribution of the VMs
|
||||||
if availability_zone.ha_placement_random:
|
if availability_zone.ha_placement_random:
|
||||||
|
if len(vms) < len(availability_zone.edge_host_groups):
|
||||||
|
# add some empty vms to the list, so it will randomize between
|
||||||
|
# all host groups
|
||||||
|
vms.extend([None] * (len(availability_zone.edge_host_groups) -
|
||||||
|
len(vms)))
|
||||||
random.shuffle(vms)
|
random.shuffle(vms)
|
||||||
try:
|
try:
|
||||||
LOG.info('Create DRS groups for '
|
|
||||||
'%(vms)s on edge %(edge_id)s',
|
|
||||||
{'vms': vms,
|
|
||||||
'edge_id': edge_id})
|
|
||||||
dvs.update_cluster_edge_failover(
|
dvs.update_cluster_edge_failover(
|
||||||
availability_zone.resource_pool,
|
availability_zone.resource_pool,
|
||||||
vms, edge_id, availability_zone.edge_host_groups)
|
vms, availability_zone.edge_host_groups)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error('Unable to create DRS groups for '
|
LOG.error('Unable to create DRS groups for '
|
||||||
'%(vms)s on edge %(edge_id)s. Error: %(e)s',
|
'%(vms)s on edge %(edge_id)s. Error: %(e)s',
|
||||||
@ -2632,7 +2635,8 @@ def clean_host_groups(dvs, availability_zone):
|
|||||||
LOG.info('Cleaning up host groups for AZ %s',
|
LOG.info('Cleaning up host groups for AZ %s',
|
||||||
availability_zone.name)
|
availability_zone.name)
|
||||||
dvs.cluster_host_group_cleanup(
|
dvs.cluster_host_group_cleanup(
|
||||||
availability_zone.resource_pool)
|
availability_zone.resource_pool,
|
||||||
|
len(availability_zone.edge_host_groups))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error('Unable to cleanup. Error: %s', e)
|
LOG.error('Unable to cleanup. Error: %s', e)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user