VMware: Relocate volume to compliant datastore

During attach to a nova instance, the backing VM corresponding to the
volume is relocated only if the nova instance's ESX host cannot access
the backing's current datastore. The storage profile is ignored and
the volume's virtual disk might end up in a non-compliant datastore.
This patch fixes the problem by checking storage profile compliance of
the current datastore.

Change-Id: I3865654e219c05dcec3aaab07c4cee0658fe181e
Closes-Bug: #1301348
This commit is contained in:
Vipin Balachandran 2014-08-27 20:26:34 +05:30
parent 86591a24d4
commit 4be8913520
5 changed files with 336 additions and 184 deletions

View File

@ -375,30 +375,97 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
m.UnsetStubs()
m.VerifyAll()
def test_init_conn_with_instance_and_backing(self):
"""Test initialize_connection with instance and backing."""
m = self.mox
m.StubOutWithMock(self._driver.__class__, 'volumeops')
self._driver.volumeops = self._volumeops
m.StubOutWithMock(self._volumeops, 'get_backing')
volume = FakeObject()
volume['name'] = 'volume_name'
volume['id'] = 'volume_id'
volume['size'] = 1
connector = {'instance': 'my_instance'}
backing = FakeMor('VirtualMachine', 'my_back')
self._volumeops.get_backing(volume['name']).AndReturn(backing)
m.StubOutWithMock(self._volumeops, 'get_host')
host = FakeMor('HostSystem', 'my_host')
self._volumeops.get_host(mox.IgnoreArg()).AndReturn(host)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing')
def test_initialize_connection_with_instance_and_backing(
self, create_backing, relocate_backing, vops):
self._test_initialize_connection_with_instance_and_backing(
create_backing, relocate_backing, vops)
m.ReplayAll()
def _test_initialize_connection_with_instance_and_backing(
self, create_backing, relocate_backing, vops):
instance = mock.sentinel.instance
connector = {'instance': instance}
backing = mock.Mock(value=mock.sentinel.backing_value)
vops.get_backing.return_value = backing
host = mock.sentinel.host
vops.get_host.return_value = host
volume = {'name': 'vol-1', 'id': 1}
conn_info = self._driver.initialize_connection(volume, connector)
self.assertEqual(conn_info['driver_volume_type'], 'vmdk')
self.assertEqual(conn_info['data']['volume'], 'my_back')
self.assertEqual(conn_info['data']['volume_id'], 'volume_id')
m.UnsetStubs()
m.VerifyAll()
relocate_backing.assert_called_once_with(volume, backing, host)
self.assertFalse(create_backing.called)
self.assertEqual('vmdk', conn_info['driver_volume_type'])
self.assertEqual(backing.value, conn_info['data']['volume'])
self.assertEqual(volume['id'],
conn_info['data']['volume_id'])
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing')
def test_initialize_connection_with_instance_and_no_backing(
self, create_backing, relocate_backing, vops):
self._test_initialize_connection_with_instance_and_no_backing(
create_backing, relocate_backing, vops)
def _test_initialize_connection_with_instance_and_no_backing(
self, create_backing, relocate_backing, vops):
instance = mock.sentinel.instance
connector = {'instance': instance}
vops.get_backing.return_value = None
host = mock.sentinel.host
vops.get_host.return_value = host
backing = mock.Mock(value=mock.sentinel.backing_value)
create_backing.return_value = backing
volume = {'name': 'vol-1', 'id': 1}
conn_info = self._driver.initialize_connection(volume, connector)
create_backing.assert_called_once_with(volume, host)
self.assertFalse(relocate_backing.called)
self.assertEqual('vmdk', conn_info['driver_volume_type'])
self.assertEqual(backing.value, conn_info['data']['volume'])
self.assertEqual(volume['id'],
conn_info['data']['volume_id'])
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing_in_inventory')
def test_initialize_connection_with_no_instance_and_no_backing(
self, create_backing_in_inventory, relocate_backing, vops):
self._test_initialize_connection_with_no_instance_and_no_backing(
create_backing_in_inventory, relocate_backing, vops)
def _test_initialize_connection_with_no_instance_and_no_backing(
self, create_backing_in_inventory, relocate_backing, vops):
vops.get_backing.return_value = None
host = mock.sentinel.host
vops.get_host.return_value = host
backing = mock.Mock(value=mock.sentinel.backing_value)
create_backing_in_inventory.return_value = backing
connector = {}
volume = {'name': 'vol-1', 'id': 1}
conn_info = self._driver.initialize_connection(volume, connector)
create_backing_in_inventory.assert_called_once_with(volume)
self.assertFalse(relocate_backing.called)
self.assertEqual('vmdk', conn_info['driver_volume_type'])
self.assertEqual(backing.value, conn_info['data']['volume'])
self.assertEqual(volume['id'],
conn_info['data']['volume_id'])
def test_get_volume_group_folder(self):
"""Test _get_volume_group_folder."""
@ -529,71 +596,6 @@ class VMwareEsxVmdkDriverTestCase(test.TestCase):
vmdk.VMwareEsxVmdkDriver._get_disk_type,
volume)
def test_init_conn_with_instance_no_backing(self):
"""Test initialize_connection with instance and without backing."""
m = self.mox
m.StubOutWithMock(self._driver.__class__, 'volumeops')
self._driver.volumeops = self._volumeops
m.StubOutWithMock(self._volumeops, 'get_backing')
volume = FakeObject()
volume['name'] = 'volume_name'
volume['id'] = 'volume_id'
volume['size'] = 1
volume['volume_type_id'] = None
connector = {'instance': 'my_instance'}
self._volumeops.get_backing(volume['name'])
m.StubOutWithMock(self._volumeops, 'get_host')
host = FakeMor('HostSystem', 'my_host')
self._volumeops.get_host(mox.IgnoreArg()).AndReturn(host)
m.StubOutWithMock(self._volumeops, 'get_dss_rp')
resource_pool = FakeMor('ResourcePool', 'my_rp')
datastores = [FakeMor('Datastore', 'my_ds')]
self._volumeops.get_dss_rp(host).AndReturn((datastores, resource_pool))
m.StubOutWithMock(self._driver, '_get_folder_ds_summary')
folder = FakeMor('Folder', 'my_fol')
summary = FakeDatastoreSummary(1, 1)
self._driver._get_folder_ds_summary(volume, resource_pool,
datastores).AndReturn((folder,
summary))
backing = FakeMor('VirtualMachine', 'my_back')
m.StubOutWithMock(self._volumeops, 'create_backing')
self._volumeops.create_backing(volume['name'],
volume['size'] * units.Mi,
mox.IgnoreArg(), folder,
resource_pool, host,
mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg()).AndReturn(backing)
m.ReplayAll()
conn_info = self._driver.initialize_connection(volume, connector)
self.assertEqual(conn_info['driver_volume_type'], 'vmdk')
self.assertEqual(conn_info['data']['volume'], 'my_back')
self.assertEqual(conn_info['data']['volume_id'], 'volume_id')
m.UnsetStubs()
m.VerifyAll()
def test_init_conn_without_instance(self):
"""Test initialize_connection without instance and a backing."""
m = self.mox
m.StubOutWithMock(self._driver.__class__, 'volumeops')
self._driver.volumeops = self._volumeops
m.StubOutWithMock(self._volumeops, 'get_backing')
backing = FakeMor('VirtualMachine', 'my_back')
volume = FakeObject()
volume['name'] = 'volume_name'
volume['id'] = 'volume_id'
connector = {}
self._volumeops.get_backing(volume['name']).AndReturn(backing)
m.ReplayAll()
conn_info = self._driver.initialize_connection(volume, connector)
self.assertEqual(conn_info['driver_volume_type'], 'vmdk')
self.assertEqual(conn_info['data']['volume'], 'my_back')
self.assertEqual(conn_info['data']['volume_id'], 'volume_id')
m.UnsetStubs()
m.VerifyAll()
def test_create_snapshot_without_backing(self):
"""Test vmdk.create_snapshot without backing."""
m = self.mox
@ -2003,37 +2005,29 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
self._test_create_backing_by_copying(volumeops, create_backing,
extend_virtual_disk)
def test_init_conn_with_instance_and_backing(self):
"""Test initialize_connection with instance and backing."""
m = self.mox
m.StubOutWithMock(self._driver.__class__, 'volumeops')
self._driver.volumeops = self._volumeops
m.StubOutWithMock(self._volumeops, 'get_backing')
volume = FakeObject()
volume['name'] = 'volume_name'
volume['id'] = 'volume_id'
volume['size'] = 1
connector = {'instance': 'my_instance'}
backing = FakeMor('VirtualMachine', 'my_back')
self._volumeops.get_backing(volume['name']).AndReturn(backing)
m.StubOutWithMock(self._volumeops, 'get_host')
host = FakeMor('HostSystem', 'my_host')
self._volumeops.get_host(mox.IgnoreArg()).AndReturn(host)
datastore = FakeMor('Datastore', 'my_ds')
resource_pool = FakeMor('ResourcePool', 'my_rp')
m.StubOutWithMock(self._volumeops, 'get_dss_rp')
self._volumeops.get_dss_rp(host).AndReturn(([datastore],
resource_pool))
m.StubOutWithMock(self._volumeops, 'get_datastore')
self._volumeops.get_datastore(backing).AndReturn(datastore)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing')
def test_initialize_connection_with_instance_and_backing(
self, create_backing, relocate_backing, vops):
self._test_initialize_connection_with_instance_and_backing(
create_backing, relocate_backing, vops)
m.ReplayAll()
conn_info = self._driver.initialize_connection(volume, connector)
self.assertEqual(conn_info['driver_volume_type'], 'vmdk')
self.assertEqual(conn_info['data']['volume'], 'my_back')
self.assertEqual(conn_info['data']['volume_id'], 'volume_id')
m.UnsetStubs()
m.VerifyAll()
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing')
def test_initialize_connection_with_instance_and_no_backing(
self, create_backing, relocate_backing, vops):
self._test_initialize_connection_with_instance_and_no_backing(
create_backing, relocate_backing, vops)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_relocate_backing')
@mock.patch.object(VMDK_DRIVER, '_create_backing_in_inventory')
def test_initialize_connection_with_no_instance_and_no_backing(
self, create_backing_in_inventory, relocate_backing, vops):
self._test_initialize_connection_with_no_instance_and_no_backing(
create_backing_in_inventory, relocate_backing, vops)
def test_get_volume_group_folder(self):
"""Test _get_volume_group_folder."""
@ -2052,50 +2046,6 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
m.UnsetStubs()
m.VerifyAll()
def test_init_conn_with_instance_and_backing_and_relocation(self):
"""Test initialize_connection with backing being relocated."""
m = self.mox
m.StubOutWithMock(self._driver.__class__, 'volumeops')
self._driver.volumeops = self._volumeops
m.StubOutWithMock(self._volumeops, 'get_backing')
volume = FakeObject()
volume['name'] = 'volume_name'
volume['id'] = 'volume_id'
volume['size'] = 1
connector = {'instance': 'my_instance'}
backing = FakeMor('VirtualMachine', 'my_back')
self._volumeops.get_backing(volume['name']).AndReturn(backing)
m.StubOutWithMock(self._volumeops, 'get_host')
host = FakeMor('HostSystem', 'my_host')
self._volumeops.get_host(mox.IgnoreArg()).AndReturn(host)
datastore1 = FakeMor('Datastore', 'my_ds_1')
datastore2 = FakeMor('Datastore', 'my_ds_2')
resource_pool = FakeMor('ResourcePool', 'my_rp')
m.StubOutWithMock(self._volumeops, 'get_dss_rp')
self._volumeops.get_dss_rp(host).AndReturn(([datastore1],
resource_pool))
m.StubOutWithMock(self._volumeops, 'get_datastore')
self._volumeops.get_datastore(backing).AndReturn(datastore2)
m.StubOutWithMock(self._driver, '_get_folder_ds_summary')
folder = FakeMor('Folder', 'my_fol')
summary = FakeDatastoreSummary(1, 1, datastore1)
self._driver._get_folder_ds_summary(volume, resource_pool,
[datastore1]).AndReturn((folder,
summary))
m.StubOutWithMock(self._volumeops, 'relocate_backing')
self._volumeops.relocate_backing(backing, datastore1,
resource_pool, host)
m.StubOutWithMock(self._volumeops, 'move_backing_to_folder')
self._volumeops.move_backing_to_folder(backing, folder)
m.ReplayAll()
conn_info = self._driver.initialize_connection(volume, connector)
self.assertEqual(conn_info['driver_volume_type'], 'vmdk')
self.assertEqual(conn_info['data']['volume'], 'my_back')
self.assertEqual(conn_info['data']['volume_id'], 'volume_id')
m.UnsetStubs()
m.VerifyAll()
@mock.patch.object(VMDK_DRIVER, '_extend_vmdk_virtual_disk')
@mock.patch.object(VMDK_DRIVER, 'volumeops')
def test_clone_backing_linked(self, volume_ops, _extend_vmdk_virtual_disk):
@ -2691,6 +2641,86 @@ class VMwareVcVmdkDriverTestCase(VMwareEsxVmdkDriverTestCase):
close.assert_called_once_with(fd)
delete_if_exists.assert_called_once_with(tmp)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, 'ds_sel')
def test_relocate_backing_nop(self, ds_sel, vops):
volume = {'name': 'vol-1', 'size': 1}
datastore = mock.sentinel.datastore
vops.get_datastore.return_value = datastore
profile = mock.sentinel.profile
vops.get_profile.return_value = profile
vops.is_datastore_accessible.return_value = True
ds_sel.is_datastore_compliant.return_value = True
backing = mock.sentinel.backing
host = mock.sentinel.host
self._driver._relocate_backing(volume, backing, host)
vops.is_datastore_accessible.assert_called_once_with(datastore, host)
ds_sel.is_datastore_compliant.assert_called_once_with(datastore,
profile)
self.assertFalse(vops.relocate_backing.called)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, 'ds_sel')
def test_relocate_backing_with_no_datastore(
self, ds_sel, vops):
volume = {'name': 'vol-1', 'size': 1}
profile = mock.sentinel.profile
vops.get_profile.return_value = profile
vops.is_datastore_accessible.return_value = True
ds_sel.is_datastore_compliant.return_value = False
ds_sel.select_datastore.return_value = []
backing = mock.sentinel.backing
host = mock.sentinel.host
self.assertRaises(error_util.NoValidDatastoreException,
self._driver._relocate_backing,
volume,
backing,
host)
ds_sel.select_datastore.assert_called_once_with(
{hub.DatastoreSelector.SIZE_BYTES: volume['size'] * units.Gi,
hub.DatastoreSelector.PROFILE_NAME: profile}, hosts=[host])
self.assertFalse(vops.relocate_backing.called)
@mock.patch.object(VMDK_DRIVER, 'volumeops')
@mock.patch.object(VMDK_DRIVER, '_get_volume_group_folder')
@mock.patch.object(VMDK_DRIVER, 'ds_sel')
def test_relocate_backing(
self, ds_sel, get_volume_group_folder, vops):
volume = {'name': 'vol-1', 'size': 1}
vops.is_datastore_accessible.return_value = False
ds_sel.is_datastore_compliant.return_value = True
backing = mock.sentinel.backing
host = mock.sentinel.host
rp = mock.sentinel.rp
datastore = mock.sentinel.datastore
summary = mock.Mock(datastore=datastore)
ds_sel.select_datastore.return_value = (host, rp, summary)
folder = mock.sentinel.folder
get_volume_group_folder.return_value = folder
self._driver._relocate_backing(volume, backing, host)
vops.relocate_backing.assert_called_once_with(backing,
datastore,
rp,
host)
vops.move_backing_to_folder.assert_called_once_with(backing,
folder)
class ImageDiskTypeTest(test.TestCase):
"""Unit tests for ImageDiskType."""

View File

@ -237,6 +237,30 @@ class VolumeOpsTestCase(test.TestCase):
hosts = self.vops.get_connected_hosts(datastore)
self.assertEqual([], hosts)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'get_connected_hosts')
def test_is_datastore_accessible(self, get_connected_hosts):
host_1 = mock.Mock(value=mock.sentinel.host_1)
host_2 = mock.Mock(value=mock.sentinel.host_2)
get_connected_hosts.return_value = [host_1, host_2]
ds = mock.sentinel.datastore
host = mock.Mock(value=mock.sentinel.host_1)
self.assertTrue(self.vops.is_datastore_accessible(ds, host))
get_connected_hosts.assert_called_once_with(ds)
@mock.patch('cinder.volume.drivers.vmware.volumeops.VMwareVolumeOps.'
'get_connected_hosts')
def test_is_datastore_accessible_with_inaccessible(self,
get_connected_hosts):
host_1 = mock.Mock(value=mock.sentinel.host_1)
get_connected_hosts.return_value = [host_1]
ds = mock.sentinel.datastore
host = mock.Mock(value=mock.sentinel.host_2)
self.assertFalse(self.vops.is_datastore_accessible(ds, host))
get_connected_hosts.assert_called_once_with(ds)
def test_is_valid(self):
with mock.patch.object(self.vops, 'get_summary') as get_summary:
summary = mock.Mock(spec=object)
@ -1229,6 +1253,52 @@ class VolumeOpsTestCase(test.TestCase):
datacenter=dc_ref)
self.session.wait_for_task.assert_called_once_with(task)
def test_get_profile(self):
server_obj = mock.Mock()
self.session.pbm.client.factory.create.return_value = server_obj
profile_ids = [mock.sentinel.profile_id]
profile_name = mock.sentinel.profile_name
profile = mock.Mock()
profile.name = profile_name
self.session.invoke_api.side_effect = [profile_ids, [profile]]
value = mock.sentinel.value
backing = mock.Mock(value=value)
self.assertEqual(profile_name, self.vops.get_profile(backing))
pbm = self.session.pbm
profile_manager = pbm.service_content.profileManager
exp_calls = [mock.call(pbm, 'PbmQueryAssociatedProfile',
profile_manager, entity=server_obj),
mock.call(pbm, 'PbmRetrieveContent', profile_manager,
profileIds=profile_ids)]
self.assertEqual(exp_calls, self.session.invoke_api.call_args_list)
self.assertEqual(value, server_obj.key)
self.assertEqual('virtualMachine', server_obj.objectType)
self.session.invoke_api.side_effect = None
def test_get_profile_with_no_profile(self):
server_obj = mock.Mock()
self.session.pbm.client.factory.create.return_value = server_obj
self.session.invoke_api.side_effect = [[]]
value = mock.sentinel.value
backing = mock.Mock(value=value)
self.assertIsNone(self.vops.get_profile(backing))
pbm = self.session.pbm
profile_manager = pbm.service_content.profileManager
exp_calls = [mock.call(pbm, 'PbmQueryAssociatedProfile',
profile_manager, entity=server_obj)]
self.assertEqual(exp_calls, self.session.invoke_api.call_args_list)
self.assertEqual(value, server_obj.key)
self.assertEqual('virtualMachine', server_obj.objectType)
self.session.invoke_api.side_effect = None
def test_extend_virtual_disk(self):
"""Test volumeops.extend_virtual_disk."""
task = mock.sentinel.task

View File

@ -93,3 +93,8 @@ class VirtualDiskNotFoundException(VMwareDriverException):
class ProfileNotFoundException(VMwareDriverException):
"""Thrown when the given storage profile cannot be found."""
message = _("Storage profile: %(storage_profile)s not found.")
class NoValidDatastoreException(VMwareDriverException):
"""Thrown when there are no valid datastores."""
message = _("There are no valid datastores.")

View File

@ -1916,38 +1916,52 @@ class VMwareVcVmdkDriver(VMwareEsxVmdkDriver):
return self.volumeops.create_folder(vm_folder, volume_folder)
def _relocate_backing(self, volume, backing, host):
"""Relocate volume backing under host and move to volume_group folder.
"""Relocate volume backing to a datastore accessible to the given host.
If the volume backing is on a datastore that is visible to the host,
then need not do any operation.
The backing is not relocated if the current datastore is already
accessible to the host and compliant with the backing's storage
profile.
:param volume: volume to be relocated
:param volume: Volume to be relocated
:param backing: Reference to the backing
:param host: Reference to the host
"""
# Check if volume's datastore is visible to host managing
# the instance
(datastores, resource_pool) = self.volumeops.get_dss_rp(host)
# Check if current datastore is visible to host managing
# the instance and compliant with the storage profile.
datastore = self.volumeops.get_datastore(backing)
visible_to_host = False
for _datastore in datastores:
if _datastore.value == datastore.value:
visible_to_host = True
break
if visible_to_host:
backing_profile = self.volumeops.get_profile(backing)
if (self.volumeops.is_datastore_accessible(datastore, host) and
self.ds_sel.is_datastore_compliant(datastore,
backing_profile)):
LOG.debug("Datastore: %(datastore)s of backing: %(backing)s is "
"already accessible to instance's host: %(host)s and "
"compliant with storage profile: %(profile)s.",
{'backing': backing,
'datastore': datastore,
'host': host,
'profile': backing_profile})
return
# The volume's backing is on a datastore that is not visible to the
# host managing the instance. We relocate the volume's backing.
# We need to relocate the backing to an accessible and profile
# compliant datastore.
req = {}
req[hub.DatastoreSelector.SIZE_BYTES] = (volume['size'] *
units.Gi)
req[hub.DatastoreSelector.PROFILE_NAME] = backing_profile
# Select datastore satisfying the requirements.
best_candidate = self.ds_sel.select_datastore(req, hosts=[host])
if not best_candidate:
# No candidate datastore to relocate.
msg = _("There are no datastores matching volume requirements;"
" can't relocate volume: %s.") % volume['name']
LOG.error(msg)
raise error_util.NoValidDatastoreException(msg)
(host, resource_pool, summary) = best_candidate
dc = self.volumeops.get_dc(resource_pool)
folder = self._get_volume_group_folder(dc)
# Pick a folder and datastore to relocate volume backing to
(folder, summary) = self._get_folder_ds_summary(volume,
resource_pool,
datastores)
LOG.info(_("Relocating volume: %(backing)s to %(ds)s and %(rp)s.") %
{'backing': backing, 'ds': summary, 'rp': resource_pool})
# Relocate the backing to the datastore and folder
self.volumeops.relocate_backing(backing, summary.datastore,
resource_pool, host)
self.volumeops.move_backing_to_folder(backing, folder)

View File

@ -386,6 +386,15 @@ class VMwareVolumeOps(object):
return connected_hosts
def is_datastore_accessible(self, datastore, host):
"""Check if the datastore is accessible to the given host.
:param datastore: datastore reference
:return: True if the datastore is accessible
"""
hosts = self.get_connected_hosts(datastore)
return host.value in [host_ref.value for host_ref in hosts]
def _in_maintenance(self, summary):
"""Check if a datastore is entering maintenance or in maintenance.
@ -1379,3 +1388,27 @@ class VMwareVolumeOps(object):
profile=profile_id)
LOG.debug("Filtered hubs: %s", filtered_hubs)
return filtered_hubs
def get_profile(self, backing):
"""Query storage profile associated with the given backing.
:param backing: backing reference
:return: profile name
"""
pbm = self._session.pbm
profile_manager = pbm.service_content.profileManager
object_ref = pbm.client.factory.create('ns0:PbmServerObjectRef')
object_ref.key = backing.value
object_ref.objectType = 'virtualMachine'
profile_ids = self._session.invoke_api(pbm,
'PbmQueryAssociatedProfile',
profile_manager,
entity=object_ref)
if profile_ids:
profiles = self._session.invoke_api(pbm,
'PbmRetrieveContent',
profile_manager,
profileIds=profile_ids)
return profiles[0].name