Merge "VMware: Ensure compute_node.hypervisor_hostname is unique"
This commit is contained in:
commit
93610787de
|
@ -36,6 +36,7 @@ _CLASSES = ['Datacenter', 'Datastore', 'ResourcePool', 'VirtualMachine',
|
|||
'files', 'ClusterComputeResource', 'HostStorageSystem']
|
||||
|
||||
_FAKE_FILE_SIZE = 1024
|
||||
_FAKE_VCENTER_UUID = '497c514c-ef5e-4e7f-8d93-ec921993b93a'
|
||||
|
||||
_db_content = {}
|
||||
_array_types = {}
|
||||
|
@ -1195,6 +1196,8 @@ class FakeVim(object):
|
|||
about_info = DataObject()
|
||||
about_info.name = "VMware vCenter Server"
|
||||
about_info.version = "5.1.0"
|
||||
about_info.instanceUuid = _FAKE_VCENTER_UUID
|
||||
|
||||
service_content.about = about_info
|
||||
|
||||
self._service_content = service_content
|
||||
|
|
|
@ -220,7 +220,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
self._set_exception_vars()
|
||||
self.node_name = self.conn._resources.keys()[0]
|
||||
self.node_name2 = self.conn._resources.keys()[1]
|
||||
if cluster_name2 in self.node_name2:
|
||||
if self.conn._resources[self.node_name2]['name'] == cluster_name2:
|
||||
self.ds = 'ds1'
|
||||
else:
|
||||
self.ds = 'ds2'
|
||||
|
@ -2310,3 +2310,32 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
|
|||
self.conn._update_pbm_location()
|
||||
self.assertEqual('fira', self.conn._session._pbm_wsdl_loc)
|
||||
self.assertIsNone(self.conn._session._pbm)
|
||||
|
||||
def test_nodename(self):
|
||||
test_mor = "domain-26"
|
||||
self.assertEqual("%s.%s" % (test_mor,
|
||||
vmwareapi_fake._FAKE_VCENTER_UUID),
|
||||
self.conn._create_nodename(test_mor),
|
||||
"VC driver failed to create the proper node name")
|
||||
|
||||
def test_normalize_nodename_old(self):
|
||||
test_mor = "domain-26"
|
||||
sample_cluster_names = ["Cluster1",
|
||||
"Cluster:2",
|
||||
"Cluster:3)",
|
||||
"(Cluster:4",
|
||||
"(Cluster:5)",
|
||||
"Test Cluster"]
|
||||
|
||||
for cluster_name in sample_cluster_names:
|
||||
old_format = "%s(%s)" % (test_mor, cluster_name)
|
||||
self.assertEqual(self.conn._create_nodename(test_mor),
|
||||
self.conn._normalize_nodename(old_format),
|
||||
'VC driver failed to normalize cluster name %s' %
|
||||
cluster_name)
|
||||
|
||||
def test_normalize_nodename_new(self):
|
||||
# Assert that _normalize_nodename doesn't touch the new format
|
||||
test_mor = "domain-26"
|
||||
nodename = "%s.%s" % (test_mor, vmwareapi_fake._FAKE_VCENTER_UUID)
|
||||
self.assertEqual(nodename, self.conn._normalize_nodename(nodename))
|
||||
|
|
|
@ -37,6 +37,7 @@ from nova.virt import driver
|
|||
from nova.virt.vmwareapi import constants
|
||||
from nova.virt.vmwareapi import error_util
|
||||
from nova.virt.vmwareapi import host
|
||||
from nova.virt.vmwareapi import vim_util as nova_vim_util
|
||||
from nova.virt.vmwareapi import vm_util
|
||||
from nova.virt.vmwareapi import vmops
|
||||
from nova.virt.vmwareapi import volumeops
|
||||
|
@ -113,6 +114,13 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
"supports_migrate_to_same_host": True
|
||||
}
|
||||
|
||||
# Legacy nodename is of the form: <mo id>(<cluster name>)
|
||||
# e.g. domain-26(TestCluster)
|
||||
# We assume <mo id> consists of alphanumeric, _ and -.
|
||||
# We assume cluster name is everything between the first ( and the last ).
|
||||
# We pull out <mo id> for re-use.
|
||||
LEGACY_NODENAME = re.compile('([\w-]+)\(.+\)')
|
||||
|
||||
# The vCenter driver includes API that acts on ESX hosts or groups
|
||||
# of ESX hosts in clusters or non-cluster logical-groupings.
|
||||
#
|
||||
|
@ -171,6 +179,7 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
LOG.warning(_LW("The following clusters could not be found in the "
|
||||
"vCenter %s"), list(missing_clusters))
|
||||
|
||||
self._vcenter_uuid = self._get_vcenter_uuid()
|
||||
# The _resources is used to maintain the vmops, volumeops and vcstate
|
||||
# objects per cluster
|
||||
self._resources = {}
|
||||
|
@ -330,14 +339,16 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
The VMwareVMOps, VMwareVolumeOps and VCState object is for each
|
||||
cluster/rp. The dictionary is of the form
|
||||
{
|
||||
domain-1000 : {'vmops': vmops_obj,
|
||||
'volumeops': volumeops_obj,
|
||||
'vcstate': vcstate_obj,
|
||||
'name': MyCluster},
|
||||
resgroup-1000 : {'vmops': vmops_obj,
|
||||
'volumeops': volumeops_obj,
|
||||
'vcstate': vcstate_obj,
|
||||
'name': MyRP},
|
||||
'domain-1000.497c514c-ef5e-4e7f-8d93-ec921993b93a' : {
|
||||
'vmops': vmops_obj,
|
||||
'volumeops': volumeops_obj,
|
||||
'vcstate': vcstate_obj,
|
||||
'name': MyCluster},
|
||||
'resgroup-1000.497c514c-ef5e-4e7f-8d93-ec921993b93a' : {
|
||||
'vmops': vmops_obj,
|
||||
'volumeops': volumeops_obj,
|
||||
'vcstate': vcstate_obj,
|
||||
'name': MyRP},
|
||||
}
|
||||
"""
|
||||
added_nodes = set(self.dict_mors.keys()) - set(self._resource_keys)
|
||||
|
@ -349,7 +360,7 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
self.dict_mors[node]['cluster_mor'],
|
||||
datastore_regex=self._datastore_regex)
|
||||
name = self.dict_mors.get(node)['name']
|
||||
nodename = self._create_nodename(node, name)
|
||||
nodename = self._create_nodename(node)
|
||||
_vc_state = host.VCState(self._session, nodename,
|
||||
self.dict_mors.get(node)['cluster_mor'],
|
||||
self._datastore_regex)
|
||||
|
@ -363,22 +374,52 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
deleted_nodes = (set(self._resource_keys) -
|
||||
set(self.dict_mors.keys()))
|
||||
for node in deleted_nodes:
|
||||
name = self.dict_mors.get(node)['name']
|
||||
nodename = self._create_nodename(node, name)
|
||||
nodename = self._create_nodename(node)
|
||||
del self._resources[nodename]
|
||||
self._resource_keys.discard(node)
|
||||
|
||||
def _create_nodename(self, mo_id, display_name):
|
||||
"""Creates the name that is stored in hypervisor_hostname column.
|
||||
def _get_vcenter_uuid(self):
|
||||
"""Retrieves the vCenter UUID."""
|
||||
|
||||
The name will be of the form similar to
|
||||
domain-1000(MyCluster)
|
||||
resgroup-1000(MyResourcePool)
|
||||
about = self._session._call_method(nova_vim_util, 'get_about_info')
|
||||
return about.instanceUuid
|
||||
|
||||
def _create_nodename(self, mo_id):
|
||||
"""Return a nodename which uniquely describes a cluster.
|
||||
|
||||
The name will be of the form:
|
||||
<mo id>.<vcenter uuid>
|
||||
e.g.
|
||||
domain-26.9d51f082-58a4-4449-beed-6fd205a5726b
|
||||
"""
|
||||
return mo_id + '(' + display_name + ')'
|
||||
|
||||
return '%s.%s' % (mo_id, self._vcenter_uuid)
|
||||
|
||||
def _normalize_nodename(self, nodename):
|
||||
"""Change I2f3b5d224cc653d0465598de0788116e71d1ca0d altered the format
|
||||
of nodename to <mo id>.<vCenter UUID>. This function matches legacy
|
||||
nodenames and translates them to the new format.
|
||||
|
||||
Note that the legacy format did not contain the vCenter UUID, which we
|
||||
are adding here. We can safely assume that we are adding the correct
|
||||
vCenter UUID because instance.host has caused it to be scheduled to
|
||||
this compute, which can only be configured with a single vCenter.
|
||||
"""
|
||||
|
||||
match = self.LEGACY_NODENAME.match(nodename)
|
||||
|
||||
# Return it unmodified if it's not in the legacy format
|
||||
if match is None:
|
||||
return nodename
|
||||
|
||||
mo_id = match.group(1)
|
||||
return self._create_nodename(mo_id)
|
||||
|
||||
def _get_resource_for_node(self, nodename):
|
||||
"""Gets the resource information for the specific node."""
|
||||
|
||||
nodename = self._normalize_nodename(nodename)
|
||||
|
||||
resource = self._resources.get(nodename)
|
||||
if not resource:
|
||||
msg = _("The resource %s does not exist") % nodename
|
||||
|
@ -386,26 +427,17 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
return resource
|
||||
|
||||
def _get_vmops_for_compute_node(self, nodename):
|
||||
"""Retrieve vmops object from mo_id stored in the node name.
|
||||
|
||||
Node name is of the form domain-1000(MyCluster)
|
||||
"""
|
||||
"""Retrieve vmops object for this node."""
|
||||
resource = self._get_resource_for_node(nodename)
|
||||
return resource['vmops']
|
||||
|
||||
def _get_volumeops_for_compute_node(self, nodename):
|
||||
"""Retrieve vmops object from mo_id stored in the node name.
|
||||
|
||||
Node name is of the form domain-1000(MyCluster)
|
||||
"""
|
||||
"""Retrieve vmops object for this node."""
|
||||
resource = self._get_resource_for_node(nodename)
|
||||
return resource['volumeops']
|
||||
|
||||
def _get_vc_state_for_compute_node(self, nodename):
|
||||
"""Retrieve VCState object from mo_id stored in the node name.
|
||||
|
||||
Node name is of the form domain-1000(MyCluster)
|
||||
"""
|
||||
"""Retrieve VCState object for this node."""
|
||||
resource = self._get_resource_for_node(nodename)
|
||||
return resource['vcstate']
|
||||
|
||||
|
@ -467,8 +499,7 @@ class VMwareVCDriver(driver.ComputeDriver):
|
|||
node_list = []
|
||||
self._update_resources()
|
||||
for node in self.dict_mors.keys():
|
||||
nodename = self._create_nodename(node,
|
||||
self.dict_mors.get(node)['name'])
|
||||
nodename = self._create_nodename(node)
|
||||
node_list.append(nodename)
|
||||
LOG.debug("The available nodes are: %s", node_list)
|
||||
return node_list
|
||||
|
|
Loading…
Reference in New Issue