Merge "vmwareapi oslo.vmware library integration"

This commit is contained in:
Jenkins 2014-09-02 17:06:44 +00:00 committed by Gerrit Code Review
commit 1dcdfd1d2b
22 changed files with 282 additions and 1309 deletions

View File

@ -22,6 +22,8 @@ A fake VMware VI API implementation.
import collections
import pprint
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
from nova.openstack.common import jsonutils
@ -30,7 +32,6 @@ from nova.openstack.common import units
from nova.openstack.common import uuidutils
from nova.virt.vmwareapi import constants
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
_CLASSES = ['Datacenter', 'Datastore', 'ResourcePool', 'VirtualMachine',
'Network', 'HostSystem', 'HostNetworkSystem', 'Task', 'session',
@ -40,6 +41,7 @@ _FAKE_FILE_SIZE = 1024
_db_content = {}
_array_types = {}
_vim_map = {}
LOG = logging.getLogger(__name__)
@ -296,7 +298,7 @@ class FileAlreadyExists(DataObject):
def __init__(self):
super(FileAlreadyExists, self).__init__()
self.__name__ = error_util.FILE_ALREADY_EXISTS
self.__name__ = vexc.FILE_ALREADY_EXISTS
class FileNotFound(DataObject):
@ -304,7 +306,7 @@ class FileNotFound(DataObject):
def __init__(self):
super(FileNotFound, self).__init__()
self.__name__ = error_util.FILE_NOT_FOUND
self.__name__ = vexc.FILE_NOT_FOUND
class FileFault(DataObject):
@ -312,7 +314,7 @@ class FileFault(DataObject):
def __init__(self):
super(FileFault, self).__init__()
self.__name__ = error_util.FILE_FAULT
self.__name__ = vexc.FILE_FAULT
class CannotDeleteFile(DataObject):
@ -320,7 +322,7 @@ class CannotDeleteFile(DataObject):
def __init__(self):
super(CannotDeleteFile, self).__init__()
self.__name__ = error_util.CANNOT_DELETE_FILE
self.__name__ = vexc.CANNOT_DELETE_FILE
class FileLocked(DataObject):
@ -328,7 +330,7 @@ class FileLocked(DataObject):
def __init__(self):
super(FileLocked, self).__init__()
self.__name__ = error_util.FILE_LOCKED
self.__name__ = vexc.FILE_LOCKED
class VirtualDisk(DataObject):
@ -965,7 +967,7 @@ def _remove_file(file_path):
# Check if the remove is for a single file object or for a folder
if file_path.find(".vmdk") != -1:
if file_path not in _db_content.get("files"):
raise error_util.FileNotFoundException(file_path)
raise vexc.FileNotFoundException(file_path)
_db_content.get("files").remove(file_path)
else:
# Removes the files in the folder and the folder too from the db
@ -999,6 +1001,13 @@ def fake_upload_image(context, image, instance, **kwargs):
pass
def fake_fetch_image(context, instance, host, dc_name, ds_name, file_path,
cookies=None):
"""Fakes the fetch of an image."""
ds_file_path = "[" + ds_name + "] " + file_path
_add_file(ds_file_path)
def _get_vm_mdo(vm_ref):
"""Gets the Virtual Machine with the ref from the db."""
if _db_content.get("VirtualMachine", None) is None:
@ -1079,6 +1088,13 @@ class FakeObjectRetrievalSession(FakeSession):
return self.ret[self.ind - 1]
def get_fake_vim_object(vmware_api_session):
key = vmware_api_session.__repr__()
if key not in _vim_map:
_vim_map[key] = FakeVim()
return _vim_map[key]
class FakeVim(object):
"""Fake VIM Class."""
@ -1112,7 +1128,8 @@ class FakeVim(object):
self._service_content = service_content
def get_service_content(self):
@property
def service_content(self):
return self._service_content
def __repr__(self):
@ -1142,8 +1159,8 @@ class FakeVim(object):
if (self._session is None or self._session not in
_db_content['session']):
LOG.debug("Session is faulty")
raise error_util.VimFaultException(
[error_util.NOT_AUTHENTICATED],
raise vexc.VimFaultException(
[vexc.NOT_AUTHENTICATED],
_("Session Invalid"))
def _session_is_active(self, *args, **kwargs):
@ -1360,7 +1377,7 @@ class FakeVim(object):
if _db_content.get("files", None) is None:
raise exception.NoFilesFound()
if get_file(ds_path):
raise error_util.FileAlreadyExistsException()
raise vexc.FileAlreadyExistsException()
_db_content["files"].append('%s/' % ds_path)
def _set_power_state(self, method, vm_ref, pwr_state="poweredOn"):

View File

@ -20,13 +20,14 @@ Stubouts for the test suite
import contextlib
import mock
from oslo.vmware import exceptions as vexc
from nova import db
from nova.tests import test_flavors
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import driver
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import network_util
from nova.virt.vmwareapi import vmware_images
def fake_get_vim_object(arg):
@ -34,32 +35,39 @@ def fake_get_vim_object(arg):
return fake.FakeVim()
@property
def fake_vim_prop(arg):
"""Stubs out the VMwareAPISession's vim property access method."""
return fake.get_fake_vim_object(arg)
def fake_is_vim_object(arg, module):
"""Stubs out the VMwareAPISession's is_vim_object method."""
return isinstance(module, fake.FakeVim)
def fake_temp_method_exception():
raise error_util.VimFaultException(
[error_util.NOT_AUTHENTICATED],
raise vexc.VimFaultException(
[vexc.NOT_AUTHENTICATED],
"Session Empty/Not Authenticated")
def fake_temp_session_exception():
raise error_util.SessionConnectionException("it's a fake!",
raise vexc.VimConnectionException("it's a fake!",
"Session Exception")
def fake_session_file_exception():
fault_list = [error_util.FILE_ALREADY_EXISTS]
raise error_util.VimFaultException(fault_list, 'fake')
fault_list = [vexc.FILE_ALREADY_EXISTS]
raise vexc.VimFaultException(fault_list,
Exception('fake'))
def fake_session_permission_exception():
fault_list = [error_util.NO_PERMISSION]
fault_list = [vexc.NO_PERMISSION]
fault_string = 'Permission to perform this operation was denied.'
details = {'privilegeId': 'Resource.AssignVMToPool', 'object': 'domain-c7'}
raise error_util.VimFaultException(fault_list, fault_string, details)
raise vexc.VimFaultException(fault_list, fault_string, details=details)
def _fake_flavor_get(context, id):
@ -78,8 +86,9 @@ def set_stubs(stubs):
"""Set the stubs."""
stubs.Set(network_util, 'get_network_with_the_name',
fake.fake_get_network)
stubs.Set(driver.VMwareAPISession, "_get_vim_object",
fake_get_vim_object)
stubs.Set(vmware_images, 'upload_image', fake.fake_upload_image)
stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image)
stubs.Set(driver.VMwareAPISession, "vim", fake_vim_prop)
stubs.Set(driver.VMwareAPISession, "_is_vim_object",
fake_is_vim_object)
stubs.Set(db, 'flavor_get', _fake_flavor_get)

View File

@ -13,10 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import contextlib
import fixtures
import mock
import mox
from nova import context
@ -29,7 +26,6 @@ from nova.tests.virt.vmwareapi import fake as vmwareapi_fake
from nova.tests.virt.vmwareapi import stubs
from nova.virt import fake
from nova.virt.vmwareapi import driver
from nova.virt.vmwareapi import read_write_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmops
from nova.virt.vmwareapi import vmware_images
@ -123,42 +119,11 @@ class ConfigDriveTestCase(test.NoDBTestCase):
block_device_info=None):
injected_files = injected_files or []
read_file_handle = mock.MagicMock()
write_file_handle = mock.MagicMock()
self.image_ref = self.test_instance.image_ref
def fake_read_handle(read_iter):
return read_file_handle
def fake_write_handle(host, dc_name, ds_name, cookies,
file_path, file_size, scheme="https"):
self.assertEqual('dc1', dc_name)
self.assertEqual('ds1', ds_name)
self.assertEqual('Fake-CookieJar', cookies)
split_file_path = file_path.split('/')
self.assertEqual('vmware_temp', split_file_path[0])
self.assertEqual(self.image_ref, split_file_path[2])
self.assertEqual(('%s-flat.vmdk' % self.image_ref),
split_file_path[3])
self.assertEqual(int(self.image['size']), file_size)
return write_file_handle
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
side_effect=fake_write_handle),
mock.patch.object(read_write_util, 'GlanceFileRead',
side_effect=fake_read_handle),
mock.patch.object(vmware_images, 'start_transfer')
) as (fake_http_write, fake_glance_read, fake_start_transfer):
self.conn.spawn(self.context, self.test_instance, self.image,
self.conn.spawn(self.context, self.test_instance, self.image,
injected_files=injected_files,
admin_password=admin_password,
network_info=self.network_info,
block_device_info=block_device_info)
fake_start_transfer.assert_called_once_with(self.context,
read_file_handle, self.image['size'],
write_file_handle=write_file_handle)
def test_create_vm_with_config_drive_verify_method_invocation(self):
self.test_instance.config_drive = 'True'

View File

@ -23,12 +23,13 @@ import collections
import contextlib
import copy
import datetime
import time
from eventlet import greenthread
import mock
import mox
from oslo.config import cfg
import six
from oslo.vmware import exceptions as vexc
from oslo.vmware import vim
import suds
from nova import block_device
@ -60,9 +61,7 @@ from nova.virt.vmwareapi import driver
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import imagecache
from nova.virt.vmwareapi import read_write_util
from nova.virt.vmwareapi import vif
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmops
@ -100,18 +99,17 @@ class VMwareSudsTest(test.NoDBTestCase):
self.vim = self._vim_create()
self.addCleanup(mock.patch.stopall)
def _mock_getattr(self, attr_name):
self.assertEqual("RetrieveServiceContent", attr_name)
return lambda obj, **kwargs: fake_service_content()
def _vim_create(self):
def fake_retrieve_service_content(fake):
return fake_service_content()
self.stubs.Set(vim.Vim, 'retrieve_service_content',
fake_retrieve_service_content)
return vim.Vim()
with mock.patch.object(vim.Vim, '__getattr__', self._mock_getattr):
return vim.Vim()
def test_exception_with_deepcopy(self):
self.assertIsNotNone(self.vim)
self.assertRaises(error_util.VimException,
self.assertRaises(vexc.VimException,
copy.deepcopy, self.vim)
@ -161,187 +159,38 @@ class VMwareDriverStartupTestCase(test.NoDBTestCase):
class VMwareSessionTestCase(test.NoDBTestCase):
def _fake_is_vim_object(self, module):
return True
@mock.patch('time.sleep')
def test_call_method_vim_fault(self, mock_sleep):
def _fake_session_is_active(self):
return False
@mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
return_value=False)
def test_call_method(self, mock_is_vim):
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
self._fake_is_vim_object),
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
mock.patch.object(driver.VMwareAPISession, '_session_is_active',
_fake_session_is_active)
) as (_fake_vim, _fake_create, _fake_is_active):
api_session = driver.VMwareAPISession()
args = ()
kwargs = {}
self.assertRaises(error_util.VimFaultException,
api_session._call_method,
stubs, 'fake_temp_method_exception',
*args, **kwargs)
def test_call_method_vim_empty(self):
def _fake_session_is_active(self):
return True
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
mock.patch.object(driver.VMwareAPISession, 'invoke_api'),
) as (fake_create, fake_invoke):
session = driver.VMwareAPISession()
session._vim = mock.Mock()
module = mock.Mock()
session._call_method(module, 'fira')
fake_invoke.assert_called_once_with(module, 'fira', session._vim)
@mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
return_value=True)
def test_call_method_vim(self, mock_is_vim):
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
self._fake_is_vim_object),
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
mock.patch.object(driver.VMwareAPISession, '_session_is_active',
_fake_session_is_active)
) as (_fake_vim, _fake_create, _fake_is_active):
api_session = driver.VMwareAPISession()
args = ()
kwargs = {}
res = api_session._call_method(stubs, 'fake_temp_method_exception',
*args, **kwargs)
self.assertEqual([], res)
@mock.patch('time.sleep')
def test_call_method_session_exception(self, mock_sleep):
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
self._fake_is_vim_object),
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
) as (_fake_vim, _fake_create):
api_session = driver.VMwareAPISession()
args = ()
kwargs = {}
self.assertRaises(error_util.SessionConnectionException,
api_session._call_method,
stubs, 'fake_temp_session_exception',
*args, **kwargs)
def test_call_method_session_file_exists_exception(self):
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
self._fake_is_vim_object),
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
) as (_fake_vim, _fake_create):
api_session = driver.VMwareAPISession()
args = ()
kwargs = {}
self.assertRaises(error_util.FileAlreadyExistsException,
api_session._call_method,
stubs, 'fake_session_file_exception',
*args, **kwargs)
def test_call_method_session_no_permission_exception(self):
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_is_vim_object',
self._fake_is_vim_object),
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
) as (_fake_vim, _fake_create):
api_session = driver.VMwareAPISession()
args = ()
kwargs = {}
e = self.assertRaises(error_util.NoPermissionException,
api_session._call_method,
stubs, 'fake_session_permission_exception',
*args, **kwargs)
fault_string = 'Permission to perform this operation was denied.'
details = {'privilegeId': 'Resource.AssignVMToPool',
'object': 'domain-c7'}
exception_string = '%s %s' % (fault_string, details)
self.assertEqual(exception_string, six.text_type(e))
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
mock.patch.object(driver.VMwareAPISession, 'invoke_api'),
) as (fake_create, fake_invoke):
session = driver.VMwareAPISession()
module = mock.Mock()
session._call_method(module, 'fira')
fake_invoke.assert_called_once_with(module, 'fira')
class VMwareAPIConfTestCase(test.NoDBTestCase):
"""Unit tests for VMWare API configurations."""
def setUp(self):
super(VMwareAPIConfTestCase, self).setUp()
vm_util.vm_refs_cache_reset()
def tearDown(self):
super(VMwareAPIConfTestCase, self).tearDown()
def test_configure_without_wsdl_loc_override(self):
# Test the default configuration behavior. By default,
# use the WSDL sitting on the host we are talking to in
# order to bind the SOAP client.
wsdl_loc = cfg.CONF.vmware.wsdl_location
self.assertIsNone(wsdl_loc)
wsdl_url = vim.Vim.get_wsdl_url("https", "www.example.com", 443)
url = vim.Vim.get_soap_url("https", "www.example.com", 443)
self.assertEqual("https://www.example.com:443/sdk/vimService.wsdl",
wsdl_url)
self.assertEqual("https://www.example.com:443/sdk", url)
def test_configure_without_wsdl_loc_override_using_ipv6(self):
# Same as above but with ipv6 based host ip
wsdl_loc = cfg.CONF.vmware.wsdl_location
self.assertIsNone(wsdl_loc)
wsdl_url = vim.Vim.get_wsdl_url("https", "::1", 443)
url = vim.Vim.get_soap_url("https", "::1", 443)
self.assertEqual("https://[::1]:443/sdk/vimService.wsdl",
wsdl_url)
self.assertEqual("https://[::1]:443/sdk", url)
def test_configure_with_wsdl_loc_override(self):
# Use the setting vmwareapi_wsdl_loc to override the
# default path to the WSDL.
#
# This is useful as a work-around for XML parsing issues
# found when using some WSDL in combination with some XML
# parsers.
#
# The wsdl_url should point to a different host than the one we
# are actually going to send commands to.
fake_wsdl = "https://www.test.com:443/sdk/foo.wsdl"
self.flags(wsdl_location=fake_wsdl, group='vmware')
wsdl_loc = cfg.CONF.vmware.wsdl_location
self.assertIsNotNone(wsdl_loc)
self.assertEqual(fake_wsdl, wsdl_loc)
wsdl_url = vim.Vim.get_wsdl_url("https", "www.example.com", 443)
url = vim.Vim.get_soap_url("https", "www.example.com", 443)
self.assertEqual(fake_wsdl, wsdl_url)
self.assertEqual("https://www.example.com:443/sdk", url)
def test_configure_non_default_host_port(self):
def _fake_create_session(self):
pass
def _fake_retrieve_service_content(self):
return None
with contextlib.nested(
mock.patch.object(driver.VMwareAPISession, '_create_session',
_fake_create_session),
mock.patch.object(vim.Vim, 'retrieve_service_content',
_fake_retrieve_service_content),
mock.patch('suds.client.Client')
):
self.flags(host_ip='www.test.com',
host_port=12345, group='vmware')
host_ip = cfg.CONF.vmware.host_ip
host_port = cfg.CONF.vmware.host_port
self.assertEqual('www.test.com', host_ip)
self.assertEqual(12345, host_port)
api_session = driver.VMwareAPISession(host_ip=host_ip,
host_port=host_port)
vim_obj = api_session._get_vim_object()
self.assertEqual("https://www.test.com:12345/sdk/vimService.wsdl",
vim_obj.wsdl_url)
self.assertEqual("https://www.test.com:12345/sdk", vim_obj.url)
@mock.patch.object(driver, 'TIME_BETWEEN_API_CALL_RETRIES', 0)
class VMwareAPIVMTestCase(test.NoDBTestCase):
"""Unit tests for Vmware API connection calls."""
def setUp(self):
def setUp(self, create_connection=True):
super(VMwareAPIVMTestCase, self).setUp()
vm_util.vm_refs_cache_reset()
self.context = context.RequestContext('fake', 'fake', is_admin=False)
@ -362,13 +211,16 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
stubs.set_stubs(self.stubs)
vmwareapi_fake.reset()
nova.tests.image.fake.stub_out_image_service(self.stubs)
self.conn = driver.VMwareVCDriver(None, False)
self.node_name = self.conn._resources.keys()[0]
self.node_name2 = self.conn._resources.keys()[1]
if cluster_name2 in self.node_name2:
self.ds = 'ds1'
else:
self.ds = 'ds2'
if create_connection:
self.conn = driver.VMwareVCDriver(None, False)
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:
self.ds = 'ds1'
else:
self.ds = 'ds2'
self.vim = vmwareapi_fake.FakeVim()
# NOTE(vish): none of the network plugging code is actually
@ -386,7 +238,6 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.fake_image_uuid = self.image['id']
nova.tests.image.fake.stub_out_image_service(self.stubs)
self.vnc_host = 'ha-host'
self._set_exception_vars()
self.instance_without_compute = {'node': None,
'vm_state': 'building',
'project_id': 'fake',
@ -450,9 +301,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
vcdriver = driver.VMwareVCDriver(None, False)
vcdriver._session = mock.Mock()
vcdriver.cleanup_host("foo")
vcdriver._session.vim.get_service_content.assert_called_once_with()
vcdriver._session.vim.client.service.Logout.assert_called_once_with(
vcdriver._session.vim.get_service_content().sessionManager
vcdriver._session.vim.service_content.sessionManager
)
@mock.patch('nova.virt.vmwareapi.driver.VMwareVCDriver.__init__')
@ -475,45 +325,20 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def _fake_login(_self):
self.attempts += 1
if self.attempts == 1:
raise exception.NovaException('Here is my fake exception')
raise vexc.VimConnectionException('Here is my fake exception')
return self.login_session
def _fake_check_session(_self):
return True
self.stubs.Set(vmwareapi_fake.FakeVim, '_login', _fake_login)
self.stubs.Set(time, 'sleep', lambda x: None)
self.stubs.Set(vmwareapi_fake.FakeVim, '_check_session',
_fake_check_session)
self.conn = driver.VMwareAPISession()
with mock.patch.object(greenthread, 'sleep'):
self.conn = driver.VMwareAPISession()
self.assertEqual(self.attempts, 2)
def test_wait_for_task_exception(self):
self.flags(task_poll_interval=1, group='vmware')
self.login_session = vmwareapi_fake.FakeVim()._login()
self.stop_called = 0
def _fake_login(_self):
return self.login_session
self.stubs.Set(vmwareapi_fake.FakeVim, '_login', _fake_login)
def fake_poll_task(task_ref, done):
done.send_exception(exception.NovaException('fake exception'))
def fake_stop_loop(loop):
self.stop_called += 1
return loop.stop()
self.conn = driver.VMwareAPISession()
self.stubs.Set(self.conn, "_poll_task",
fake_poll_task)
self.stubs.Set(self.conn, "_stop_loop",
fake_stop_loop)
self.assertRaises(exception.NovaException,
self.conn._wait_for_task, 'fake-ref')
self.assertEqual(self.stop_called, 1)
def _get_instance_type_by_name(self, type):
for instance_type in test_flavors.DEFAULT_FLAVORS:
if instance_type['name'] == type:
@ -559,48 +384,17 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
def _create_vm(self, node=None, num_instances=1, uuid=None,
instance_type='m1.large', powered_on=True):
"""Create and spawn the VM."""
read_file_handle = mock.MagicMock()
write_file_handle = mock.MagicMock()
def fake_read_handle(read_iter):
return read_file_handle
def _fake_write_mock(host, dc_name, ds_name, cookies,
file_path, file_size, scheme="https"):
self.vim.fake_transfer_file(ds_name=ds_name,
file_path=file_path)
image_ref = self.image['id']
self.assertIn(dc_name, ['dc1', 'dc2'])
self.assertIn(ds_name, ['ds1', 'ds2'])
self.assertEqual('Fake-CookieJar', cookies)
split_file_path = file_path.split('/')
self.assertEqual('vmware_temp', split_file_path[0])
self.assertEqual(image_ref, split_file_path[2])
self.assertEqual(int(self.image['size']), file_size)
return write_file_handle
if not node:
node = self.node_name
self._create_instance(node=node, uuid=uuid,
instance_type=instance_type)
self.assertIsNone(vm_util.vm_ref_cache_get(self.uuid))
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
_fake_write_mock),
mock.patch.object(read_write_util, 'GlanceFileRead',
fake_read_handle),
mock.patch.object(vmware_images, 'start_transfer')
) as (fake_http_write, fake_glance_read, fake_start_transfer):
self.conn.spawn(self.context, self.instance, self.image,
injected_files=[], admin_password=None,
network_info=self.network_info,
block_device_info=None)
fake_start_transfer.assert_called_once_with(self.context,
read_file_handle, self.image['size'],
write_file_handle=write_file_handle)
self._check_vm_record(num_instances=num_instances,
powered_on=powered_on)
self.conn.spawn(self.context, self.instance, self.image,
injected_files=[], admin_password=None,
network_info=self.network_info,
block_device_info=None)
self._check_vm_record(num_instances=num_instances,
powered_on=powered_on)
self.assertIsNotNone(vm_util.vm_ref_cache_get(self.uuid))
def _get_vm_record(self):
@ -914,8 +708,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
'node': self.instance_node})
self._check_vm_info(info, power_state.RUNNING)
else:
self.assertRaises(error_util.VMwareDriverException,
self._create_vm)
self.assertRaises(vexc.VMwareDriverException, self._create_vm)
self.assertTrue(self.exception)
def test_spawn_with_delete_exception_not_found(self):
@ -994,10 +787,8 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
#
# Expect the copy error to be raised
self.flags(use_linked_clone=True, group='vmware')
self.wait_task = self.conn._session._wait_for_task
self.call_method = self.conn._session._call_method
CopyError = error_util.FileFaultException
CopyError = vexc.FileFaultException
def fake_wait_for_task(task_ref):
if task_ref == 'fake-copy-task':
@ -1024,14 +815,12 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
# Expect the file to be cleaned up
# Expect the copy error to be raised
self.flags(use_linked_clone=True, group='vmware')
self.wait_task = self.conn._session._wait_for_task
self.call_method = self.conn._session._call_method
self.task_ref = None
uuid = self.fake_image_uuid
cached_image = '[%s] vmware_base/%s/%s.80.vmdk' % (self.ds,
uuid, uuid)
CopyError = error_util.FileFaultException
CopyError = vexc.FileFaultException
def fake_wait_for_task(task_ref):
if task_ref == self.task_ref:
@ -1064,15 +853,13 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
# Expect file to be left behind
# Expect file cleanup error to be raised
self.flags(use_linked_clone=True, group='vmware')
self.wait_task = self.conn._session._wait_for_task
self.call_method = self.conn._session._call_method
self.task_ref = None
uuid = self.fake_image_uuid
cached_image = '[%s] vmware_base/%s/%s.80.vmdk' % (self.ds,
uuid, uuid)
CopyError = error_util.FileFaultException
DeleteError = error_util.CannotDeleteFileException
CopyError = vexc.FileFaultException
DeleteError = vexc.CannotDeleteFileException
def fake_wait_for_task(task_ref):
if task_ref == self.task_ref:
@ -1136,7 +923,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
'%s.80-flat.vmdk' %
self.fake_image_uuid)
NoDiskSpace = error_util.get_fault_class('NoDiskSpace')
NoDiskSpace = vexc.get_fault_class('NoDiskSpace')
def fake_wait_for_task(task_ref):
if task_ref == self.task_ref:
@ -1171,7 +958,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
if task_ref == self.task_ref:
self.task_ref = None
self.exception = True
raise error_util.FileAlreadyExistsException()
raise vexc.FileAlreadyExistsException()
return self.wait_task(task_ref)
def fake_call_method(module, method, *args, **kwargs):
@ -1203,7 +990,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
if task_ref == self.task_ref:
self.task_ref = None
self.exception = True
raise error_util.VMwareDriverException('Exception!')
raise vexc.VMwareDriverException('Exception!')
return self.wait_task(task_ref)
def fake_call_method(module, method, *args, **kwargs):
@ -1218,7 +1005,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
mock.patch.object(self.conn._session, '_call_method',
fake_call_method)
) as (_wait_for_task, _call_method):
self.assertRaises(error_util.VMwareDriverException,
self.assertRaises(vexc.VMwareDriverException,
self._create_vm)
self.assertTrue(self.exception)
@ -1236,7 +1023,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
mock.patch.object(self.conn._session, '_call_method',
fake_call_method)
):
self.assertRaises(error_util.VMwareDriverException,
self.assertRaises(vexc.VMwareDriverException,
self._create_vm)
def test_spawn_with_move_file_exists_poll_exception(self):
@ -1426,7 +1213,7 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
with contextlib.nested(
mock.patch.object(self.conn._session, '_wait_for_task',
side_effect=exception),
mock.patch.object(time, 'sleep')
mock.patch.object(vmops, '_time_sleep_wrapper')
) as (_fake_wait, _fake_sleep):
if exception != error_util.TaskInProgress:
self.assertRaises(exception,
@ -1737,20 +1524,9 @@ class VMwareAPIVMTestCase(test.NoDBTestCase):
self.stubs.Set(self.conn._volumeops, "attach_disk_to_vm",
fake_attach_disk_to_vm)
def _fake_http_write(host, data_center_name, datastore_name,
cookies, file_path, file_size, scheme="https"):
self.vim.fake_transfer_file(ds_name=datastore_name,
file_path=file_path)
with contextlib.nested(
mock.patch.object(read_write_util, 'VMwareHTTPWriteFile',
_fake_http_write),
mock.patch.object(read_write_util, 'GlanceFileRead'),
mock.patch.object(vmware_images, 'start_transfer')
) as (http_write, glance_read, fake_start_transfer):
self.conn.rescue(self.context, self.instance, self.network_info,
self.conn.rescue(self.context, self.instance, self.network_info,
self.image, 'fake-password')
info = self.conn.get_info({'name': '1-rescue',
'uuid': '%s-rescue' % self.uuid,
'node': self.instance_node})
@ -2212,8 +1988,8 @@ class VMwareAPIVCDriverTestCase(VMwareAPIVMTestCase,
test_driver.DriverAPITestHelper):
def setUp(self):
super(VMwareAPIVCDriverTestCase, self).setUp()
super(VMwareAPIVCDriverTestCase, self).setUp(create_connection=False)
cluster_name = 'test_cluster'
cluster_name2 = 'test_cluster2'
self.flags(cluster_name=[cluster_name, cluster_name2],
@ -2223,6 +1999,7 @@ class VMwareAPIVCDriverTestCase(VMwareAPIVMTestCase,
image_cache_subdirectory_name='vmware_base')
vmwareapi_fake.reset()
self.conn = driver.VMwareVCDriver(None, False)
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:
@ -2579,7 +2356,7 @@ class VMwareAPIVCDriverTestCase(VMwareAPIVMTestCase,
"Original VM name should be with suffix -backup")
self.assertEqual(cloned_vm_obj.name, self.instance['uuid'],
"VM name does not match instance['uuid']")
self.assertRaises(error_util.MissingParameter,
self.assertRaises(vexc.MissingParameter,
vm_util.clone_vmref_for_instance, self.conn._session,
self.instance, None, host_ref, ds_ref,
dc_obj.get("vmFolder"))

View File

@ -16,6 +16,7 @@ import contextlib
import re
import mock
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
@ -23,7 +24,6 @@ from nova.openstack.common import units
from nova import test
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
class DsUtilTestCase(test.NoDBTestCase):
@ -146,7 +146,7 @@ class DsUtilTestCase(test.NoDBTestCase):
def fake_wait_for_task(task_ref):
if task_ref == 'fake_exists_task':
raise error_util.FileNotFoundException()
raise vexc.FileNotFoundException()
# Should never get here
self.fail()

View File

@ -1,84 +0,0 @@
# Copyright 2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
from nova import test
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import error_util
class ExpectedMethodFault:
pass
class ErrorUtilTestCase(test.NoDBTestCase):
def setUp(self):
super(ErrorUtilTestCase, self).setUp()
def test_fault_checker_empty_response(self):
# assertRaises as a Context Manager would have been a good choice to
# perform additional checks on the exception raised, instead of
# try/catch block in the below tests, but it's available
# only from Py 2.7.
exp_fault_list = [error_util.NOT_AUTHENTICATED]
try:
error_util.FaultCheckers.retrievepropertiesex_fault_checker(None)
except error_util.VimFaultException as e:
self.assertEqual(exp_fault_list, e.fault_list)
else:
self.fail("VimFaultException was not raised.")
def test_fault_checker_missing_props(self):
fake_objects = fake.FakeRetrieveResult()
ml = [fake.MissingProperty(method_fault=ExpectedMethodFault())]
fake_objects.add_object(fake.ObjectContent(None, missing_list=ml))
exp_fault_list = ['ExpectedMethodFault']
try:
error_util.FaultCheckers.retrievepropertiesex_fault_checker(
fake_objects)
except error_util.VimFaultException as e:
self.assertEqual(exp_fault_list, e.fault_list)
else:
self.fail("VimFaultException was not raised.")
def test_fault_checker_no_missing_props(self):
fake_objects = fake.FakeRetrieveResult()
fake_objects.add_object(fake.ObjectContent(None))
self.assertIsNone(
error_util.FaultCheckers.retrievepropertiesex_fault_checker(
fake_objects))
def test_exception_summary_exception_as_list(self):
# assert that if a list is fed to the VimException object
# that it will error.
self.assertRaises(ValueError,
error_util.VimException,
[], ValueError('foo'))
def test_exception_summary_string(self):
e = error_util.VimException("string", ValueError("foo"))
string = six.text_type(e)
self.assertEqual("string: foo", string)
def test_vim_fault_exception_string(self):
self.assertRaises(ValueError,
error_util.VimFaultException,
"bad", ValueError("argument"))
def test_vim_fault_exception(self):
vfe = error_util.VimFaultException([ValueError("example")], "cause")
string = six.text_type(vfe)
self.assertEqual("cause", string)

View File

@ -17,6 +17,7 @@ import contextlib
import mock
from oslo.config import cfg
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.network import model as network_model
@ -24,7 +25,6 @@ from nova import test
from nova.tests import matchers
from nova.tests import utils
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import network_util
from nova.virt.vmwareapi import vif
from nova.virt.vmwareapi import vim_util
@ -280,7 +280,7 @@ class VMwareVifTestCase(test.NoDBTestCase):
def test_create_port_group_already_exists(self):
def fake_call_method(module, method, *args, **kwargs):
if method == 'AddPortGroup':
raise error_util.AlreadyExistsException()
raise vexc.AlreadyExistsException()
with contextlib.nested(
mock.patch.object(vm_util, 'get_add_vswitch_port_group_spec'),
@ -295,7 +295,7 @@ class VMwareVifTestCase(test.NoDBTestCase):
def test_create_port_group_exception(self):
def fake_call_method(module, method, *args, **kwargs):
if method == 'AddPortGroup':
raise error_util.VMwareDriverException()
raise vexc.VMwareDriverException()
with contextlib.nested(
mock.patch.object(vm_util, 'get_add_vswitch_port_group_spec'),
@ -303,7 +303,7 @@ class VMwareVifTestCase(test.NoDBTestCase):
mock.patch.object(self.session, '_call_method',
fake_call_method)
) as (_add_vswitch, _get_host, _call_method):
self.assertRaises(error_util.VMwareDriverException,
self.assertRaises(vexc.VMwareDriverException,
network_util.create_port_group,
self.session, 'pg_name',
'vswitch_name', vlan_id=0,
@ -312,7 +312,7 @@ class VMwareVifTestCase(test.NoDBTestCase):
def test_get_neutron_network_invalid_property(self):
def fake_call_method(module, method, *args, **kwargs):
if method == 'get_dynamic_property':
raise error_util.InvalidPropertyException()
raise vexc.InvalidPropertyException()
with contextlib.nested(
mock.patch.object(vm_util, 'get_host_ref'),

View File

@ -85,11 +85,10 @@ class VMwareVIMUtilTestCase(test.NoDBTestCase):
retrievePropertiesEx.return_value = result
calls = {'RetrievePropertiesEx': retrievePropertiesEx}
with stubs.fake_suds_context(calls):
session = driver.VMwareAPISession()
session = driver.VMwareAPISession(host_ip='localhost')
service_content = session.vim.get_service_content()
service_content = session.vim.service_content
props = session._call_method(vim_util, "get_dynamic_properties",
service_content.propertyCollector,
'fake_type', None)

View File

@ -19,13 +19,13 @@ import contextlib
import re
import mock
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.network import model as network_model
from nova.openstack.common import uuidutils
from nova import test
from nova.tests.virt.vmwareapi import fake
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vm_util
@ -815,7 +815,7 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
return_value='fake-task'),
mock.patch.object(
session, "_wait_for_task",
side_effect=error_util.InvalidPowerStateException),
side_effect=vexc.InvalidPowerStateException),
) as (fake_call_method, fake_wait_for_task):
vm_util.power_on_instance(session, fake_instance,
vm_ref='fake-vm-ref')
@ -826,7 +826,7 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
def test_create_virtual_disk(self):
session = fake.FakeSession()
dm = session._get_vim().get_service_content().virtualDiskManager
dm = session._get_vim().service_content.virtualDiskManager
with contextlib.nested(
mock.patch.object(vm_util, "get_vmdk_create_spec",
return_value='fake-spec'),
@ -852,7 +852,7 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
def test_copy_virtual_disk(self):
session = fake.FakeSession()
dm = session._get_vim().get_service_content().virtualDiskManager
dm = session._get_vim().service_content.virtualDiskManager
with contextlib.nested(
mock.patch.object(session, "_call_method",
return_value='fake-task'),
@ -1052,7 +1052,7 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
return_value='fake-task'),
mock.patch.object(
session, '_wait_for_task',
side_effect=error_util.InvalidPowerStateException)
side_effect=vexc.InvalidPowerStateException)
) as (fake_call_method, fake_wait_for_task):
vm_util.power_off_instance(session, fake_instance, 'fake-vm-ref')
fake_call_method.assert_called_once_with(session._get_vim(),

View File

@ -16,6 +16,7 @@ import contextlib
import copy
import mock
from oslo.vmware import exceptions as vexc
from nova.compute import power_state
from nova import context
@ -33,7 +34,6 @@ from nova.tests.virt.vmwareapi import stubs
from nova.virt.vmwareapi import constants
from nova.virt.vmwareapi import driver
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmops
@ -158,7 +158,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
def test_create_folder_if_missing_exception(self):
ds_name, ds_ref, ops, path, dc = self._setup_create_folder_mocks()
ds_util.mkdir.side_effect = error_util.FileAlreadyExistsException()
ds_util.mkdir.side_effect = vexc.FileAlreadyExistsException()
ops._create_folder_if_missing(ds_name, ds_ref, 'folder')
ds_util.mkdir.assert_called_with(ops._session, path, dc)
@ -716,7 +716,7 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
_fetch_image.assert_called_once_with(
self._context,
self._instance,
self._session._host_ip,
self._session._host,
self._dc_info.name,
self._ds.name,
upload_file_name,
@ -803,17 +803,11 @@ class VMwareVMOpsTestCase(test.NoDBTestCase):
}
self._test_spawn(block_device_info=block_device_info)
@mock.patch('nova.virt.vmwareapi.driver.VMwareAPISession._get_vim_object')
def test_build_virtual_machine(self, mock_get_vim_object):
mock_get_vim_object.return_value = vmwareapi_fake.FakeVim()
fake_session = driver.VMwareAPISession()
fake_vmops = vmops.VMwareVCVMOps(fake_session, None, None)
def test_build_virtual_machine(self):
image_id = nova.tests.image.fake.get_valid_image_id()
image = vmware_images.VMwareImage(image_id=image_id)
vm_ref = fake_vmops.build_virtual_machine(self._instance,
vm_ref = self._vmops.build_virtual_machine(self._instance,
'fake-instance-name',
image, self._dc_info,
self._ds, self.network_info)

View File

@ -20,30 +20,24 @@ A connection to the VMware vCenter platform.
"""
import re
import sys
import time
from eventlet import event
from oslo.config import cfg
import six
from oslo.vmware import api
from oslo.vmware import vim
import suds
from nova import exception
from nova.i18n import _, _LC, _LW
from nova.i18n import _, _LW
from nova.openstack.common import jsonutils
from nova.openstack.common import log as logging
from nova.openstack.common import loopingcall
from nova.openstack.common import uuidutils
from nova.virt import driver
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import host
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmops
from nova.virt.vmwareapi import volumeops
LOG = logging.getLogger(__name__)
vmwareapi_opts = [
@ -78,6 +72,11 @@ vmwareapi_opts = [
cfg.BoolOpt('use_linked_clone',
default=True,
help='Whether to use linked clone'),
cfg.StrOpt('wsdl_location',
help='Optional VIM Service WSDL Location '
'e.g http://<server>/vimService.wsdl. '
'Optional over-ride to default location for bug '
'work-arounds')
]
CONF = cfg.CONF
@ -181,7 +180,7 @@ class VMwareVCDriver(driver.ComputeDriver):
# NOTE(hartsocks): we lean on the init_host to force the vim object
# to not be None.
vim = self._session.vim
service_content = vim.get_service_content()
service_content = vim.service_content
session_manager = service_content.sessionManager
try:
vim.client.service.Logout(session_manager)
@ -630,227 +629,47 @@ class VMwareVCDriver(driver.ComputeDriver):
_vmops.detach_interface(instance, vif)
class VMwareAPISession(object):
"""Sets up a session with the VC host and handles all
class VMwareAPISession(api.VMwareAPISession):
"""Sets up a session with the VC/ESX host and handles all
the calls made to the host.
"""
def __init__(self, host_ip=CONF.vmware.host_ip,
host_port=CONF.vmware.host_port,
username=CONF.vmware.host_username,
password=CONF.vmware.host_password,
retry_count=CONF.vmware.api_retry_count,
scheme="https"):
self._host_ip = host_ip
self._host_port = host_port
self._host_username = username
self._host_password = password
self._api_retry_count = retry_count
self._scheme = scheme
self._session = None
self.vim = None
self._create_session()
def _get_vim_object(self):
"""Create the VIM Object instance."""
return vim.Vim(protocol=self._scheme, host=self._host_ip,
port=self._host_port)
def _create_session(self):
"""Creates a session with the VC host."""
delay = 1
while True:
try:
# Login and setup the session with the host for making
# API calls
self.vim = self._get_vim_object()
session = self.vim.Login(
self.vim.get_service_content().sessionManager,
userName=self._host_username,
password=self._host_password)
# Terminate the earlier session, if possible ( For the sake of
# preserving sessions as there is a limit to the number of
# sessions we can have )
if self._session:
try:
self.vim.TerminateSession(
self.vim.get_service_content().sessionManager,
sessionId=[self._session.key])
except Exception:
# This exception is something we can live with. It is
# just an extra caution on our side. The session may
# have been cleared. We could have made a call to
# SessionIsActive, but that is an overhead because we
# anyway would have to call TerminateSession.
LOG.debug("TerminateSession failed", exc_info=True)
self._session = session
return
except Exception:
LOG.critical(_LC("Unable to connect to server at %(server)s, "
"sleeping for %(seconds)s seconds"),
{'server': self._host_ip, 'seconds': delay},
exc_info=True)
# exc_info logs the exception with the message
time.sleep(delay)
delay = min(2 * delay, 60)
super(VMwareAPISession, self).__init__(
host=host_ip,
port=host_port,
server_username=username,
server_password=password,
api_retry_count=retry_count,
task_poll_interval=CONF.vmware.task_poll_interval,
scheme=scheme,
create_session=True,
wsdl_loc=CONF.vmware.wsdl_location
)
def _is_vim_object(self, module):
"""Check if the module is a VIM Object instance."""
return isinstance(module, vim.Vim)
def _session_is_active(self):
active = False
try:
active = self.vim.SessionIsActive(
self.vim.get_service_content().sessionManager,
sessionID=self._session.key,
userName=self._session.userName)
except Exception:
LOG.warning(_("Unable to validate session %s!"),
self._session.key)
LOG.debug("Unable to validate session %s", self._session.key,
exc_info=True)
return active
def _call_method(self, module, method, *args, **kwargs):
"""Calls a method within the module specified with
args provided.
"""
args = list(args)
retry_count = 0
while True:
exc_info = False
try:
if not self._is_vim_object(module):
# If it is not the first try, then get the latest
# vim object
if retry_count > 0:
args = args[1:]
args = [self.vim] + args
retry_count += 1
temp_module = module
for method_elem in method.split("."):
temp_module = getattr(temp_module, method_elem)
return temp_module(*args, **kwargs)
except error_util.VimFaultException as excep:
# If it is a Session Fault Exception, it may point
# to a session gone bad. So we try re-creating a session
# and then proceeding ahead with the call.
exc_info = sys.exc_info()
if error_util.NOT_AUTHENTICATED in excep.fault_list:
# Because of the idle session returning an empty
# RetrievePropertiesResponse and also the same is returned
# when there is say empty answer to the query for
# VMs on the host ( as in no VMs on the host), we have no
# way to differentiate. We thus check if the session is
# active
if self._session_is_active():
return []
LOG.warning(_("Session %s is inactive!"),
self._session.key)
self._create_session()
else:
# No re-trying for errors for API call has gone through
# and is the caller's fault. Caller should handle these
# errors. e.g, InvalidArgument fault.
# Raise specific exceptions here if possible
if excep.fault_list:
fault = excep.fault_list[0]
msg_excep = six.text_type(excep)
raise error_util.get_fault_class(fault)(msg_excep)
break
except error_util.SessionOverLoadException:
# For exceptions which may come because of session overload,
# we retry
exc_info = sys.exc_info()
except error_util.SessionConnectionException:
# For exceptions with connections we create the session
exc_info = sys.exc_info()
self._create_session()
except Exception:
# If it is a proper exception, say not having furnished
# proper data in the SOAP call or the retry limit having
# exceeded, we raise the exception
exc_info = sys.exc_info()
break
LOG.debug("_call_method(session=%(key)s) failed. "
"Module: %(module)s. "
"Method: %(method)s. "
"args: %(args)s. "
"kwargs: %(kwargs)s. "
"Iteration: %(n)s. ",
{'key': self._session.key,
'module': module,
'method': method,
'args': args,
'kwargs': kwargs,
'n': retry_count},
exc_info=exc_info)
# If retry count has been reached then break and
# raise the exception
if retry_count > self._api_retry_count:
break
time.sleep(TIME_BETWEEN_API_CALL_RETRIES)
LOG.critical(_LC("In vmwareapi: _call_method (session=%s)"),
self._session.key, exc_info=True)
raise
if not self._is_vim_object(module):
return self.invoke_api(module, method, self.vim, *args, **kwargs)
else:
return self.invoke_api(module, method, *args, **kwargs)
def _get_vim(self):
"""Gets the VIM object reference."""
if self.vim is None:
self._create_session()
"""Create the VIM Object instance."""
return self.vim
def _stop_loop(self, loop):
loop.stop()
def _wait_for_task(self, task_ref):
"""Return a Deferred that will give the result of the given task.
The task is polled until it completes.
"""
done = event.Event()
loop = loopingcall.FixedIntervalLoopingCall(self._poll_task,
task_ref, done)
loop.start(CONF.vmware.task_poll_interval)
try:
ret_val = done.wait()
finally:
self._stop_loop(loop)
return ret_val
def _poll_task(self, task_ref, done):
"""Poll the given task, and fires the given Deferred if we
get a result.
"""
try:
task_info = self._call_method(vim_util, "get_dynamic_property",
task_ref, "Task", "info")
task_name = task_info.name
if task_info.state in ['queued', 'running']:
return
elif task_info.state == 'success':
LOG.debug("Task [%(task_name)s] %(task_ref)s "
"status: success",
{'task_name': task_name, 'task_ref': task_ref})
done.send(task_info)
else:
error_info = six.text_type(task_info.error.localizedMessage)
LOG.warn(_("Task [%(task_name)s] %(task_ref)s "
"status: error %(error_info)s"),
{'task_name': task_name, 'task_ref': task_ref,
'error_info': error_info})
# Check if we can raise a specific exception
error = task_info.error
name = error.fault.__class__.__name__
task_ex = error_util.get_fault_class(name)(error_info)
done.send_exception(task_ex)
except Exception as excep:
LOG.warn(_("In vmwareapi:_poll_task, Got this error %s") % excep)
done.send_exception(excep)
return self.wait_for_task(task_ref)

View File

@ -17,10 +17,11 @@ Datastore utility functions
"""
import posixpath
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
from nova.openstack.common import log as logging
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@ -338,7 +339,7 @@ def file_delete(session, ds_path, dc_ref):
file_delete_task = session._call_method(
session._get_vim(),
"DeleteDatastoreFile_Task",
vim.get_service_content().fileManager,
vim.service_content.fileManager,
name=str(ds_path),
datacenter=dc_ref)
session._wait_for_task(file_delete_task)
@ -375,7 +376,7 @@ def file_move(session, dc_ref, src_file, dst_file):
move_task = session._call_method(
session._get_vim(),
"MoveDatastoreFile_Task",
vim.get_service_content().fileManager,
vim.service_content.fileManager,
sourceName=str(src_file),
sourceDatacenter=dc_ref,
destinationName=str(dst_file),
@ -402,7 +403,7 @@ def file_exists(session, ds_browser, ds_path, file_name):
searchSpec=search_spec)
try:
task_info = session._wait_for_task(search_task)
except error_util.FileNotFoundException:
except vexc.FileNotFoundException:
return False
file_exists = (getattr(task_info.result, 'file', False) and
@ -417,7 +418,7 @@ def mkdir(session, ds_path, dc_ref):
"""
LOG.debug("Creating directory with path %s", ds_path)
session._call_method(session._get_vim(), "MakeDirectory",
session._get_vim().get_service_content().fileManager,
session._get_vim().service_content.fileManager,
name=str(ds_path), datacenter=dc_ref,
createParentDirectories=True)
LOG.debug("Created directory with path %s", ds_path)
@ -435,7 +436,7 @@ def get_sub_folders(session, ds_browser, ds_path):
datastorePath=str(ds_path))
try:
task_info = session._wait_for_task(search_task)
except error_util.FileNotFoundException:
except vexc.FileNotFoundException:
return set()
# populate the folder entries
if hasattr(task_info.result, 'file'):

View File

@ -14,132 +14,19 @@
# under the License.
"""
Exception classes and SOAP response error checking module.
Exception classes specific for the VMware driver.
"""
import six
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
from nova.openstack.common import log as logging
LOG = logging.getLogger(__name__)
ALREADY_EXISTS = 'AlreadyExists'
CANNOT_DELETE_FILE = 'CannotDeleteFile'
FILE_ALREADY_EXISTS = 'FileAlreadyExists'
FILE_FAULT = 'FileFault'
FILE_LOCKED = 'FileLocked'
FILE_NOT_FOUND = 'FileNotFound'
INVALID_POWER_STATE = 'InvalidPowerState'
INVALID_PROPERTY = 'InvalidProperty'
NO_PERMISSION = 'NoPermission'
NOT_AUTHENTICATED = 'NotAuthenticated'
TASK_IN_PROGRESS = 'TaskInProgress'
# Most VMware-specific exception classes are now centrally defined in
# oslo.vmware.
# Note(vui):
# - map back to NovaException?
class VimException(Exception):
"""The VIM Exception class."""
def __init__(self, exception_summary, excep):
Exception.__init__(self)
if isinstance(exception_summary, list):
# we need this to protect against developers using
# this method like VimFaultException
raise ValueError(_("exception_summary must not be a list"))
self.exception_summary = six.text_type(exception_summary)
self.exception_obj = excep
def __str__(self):
return (self.exception_summary + ": " +
six.text_type(self.exception_obj))
class SessionOverLoadException(VimException):
"""Session Overload Exception."""
pass
class SessionConnectionException(VimException):
"""Session Connection Exception."""
pass
class VimAttributeError(VimException):
"""VI Attribute Error."""
pass
class VimFaultException(Exception):
"""The VIM Fault exception class."""
def __init__(self, fault_list, fault_string, details=None):
Exception.__init__(self)
if not isinstance(fault_list, list):
raise ValueError(_("fault_list must be a list"))
self.fault_list = fault_list
self.fault_string = fault_string
self.details = details
def __str__(self):
if self.details:
return '%s %s' % (self.fault_string, self.details)
return self.fault_string
class FaultCheckers(object):
"""Methods for fault checking of SOAP response. Per Method error handlers
for which we desire error checking are defined. SOAP faults are
embedded in the SOAP messages as properties and not as SOAP faults.
"""
@staticmethod
def retrievepropertiesex_fault_checker(resp_obj):
"""Checks the RetrievePropertiesEx response for errors. Certain faults
are sent as part of the SOAP body as property of missingSet.
For example NotAuthenticated fault.
"""
fault_list = []
details = {}
if not resp_obj:
# This is the case when the session has timed out. ESX SOAP server
# sends an empty RetrievePropertiesResponse. Normally missingSet in
# the returnval field has the specifics about the error, but that's
# not the case with a timed out idle session. It is as bad as a
# terminated session for we cannot use the session. So setting
# fault to NotAuthenticated fault.
fault_list = [NOT_AUTHENTICATED]
else:
for obj_cont in resp_obj.objects:
if hasattr(obj_cont, "missingSet"):
for missing_elem in obj_cont.missingSet:
fault_type = missing_elem.fault.fault
# Fault needs to be added to the type of fault for
# uniformity in error checking as SOAP faults define
fault_list.append(fault_type.__class__.__name__)
if fault_type.__class__.__name__ == NO_PERMISSION:
details['object'] = fault_type.object.value
details['privilegeId'] = fault_type.privilegeId
if fault_list:
exc_msg_list = ', '.join(fault_list)
fault_string = _("Error(s) %s occurred in the call to "
"RetrievePropertiesEx") % exc_msg_list
raise VimFaultException(fault_list, fault_string, details)
class VMwareDriverException(exception.NovaException):
"""Base class for all exceptions raised by the VMware Driver.
All exceptions raised by the VMwareAPI drivers should raise
an exception descended from this class as a root. This will
allow the driver to potentially trap problems related to its
own internal configuration before halting the nova-compute
node.
"""
msg_fmt = _("VMware Driver fault.")
class VMwareDriverConfigurationException(VMwareDriverException):
class VMwareDriverConfigurationException(vexc.VMwareDriverException):
"""Base class for all configuration exceptions.
"""
msg_fmt = _("VMware Driver configuration fault.")
@ -149,90 +36,9 @@ class UseLinkedCloneConfigurationFault(VMwareDriverConfigurationException):
msg_fmt = _("No default value for use_linked_clone found.")
class MissingParameter(VMwareDriverException):
msg_fmt = _("Missing parameter : %(param)s")
class NoRootDiskDefined(VMwareDriverException):
class NoRootDiskDefined(vexc.VMwareDriverException):
msg_fmt = _("No root disk defined.")
class AlreadyExistsException(VMwareDriverException):
msg_fmt = _("Resource already exists.")
code = 409
class CannotDeleteFileException(VMwareDriverException):
msg_fmt = _("Cannot delete file.")
code = 403
class FileAlreadyExistsException(VMwareDriverException):
msg_fmt = _("File already exists.")
code = 409
class FileFaultException(VMwareDriverException):
msg_fmt = _("File fault.")
code = 409
class FileLockedException(VMwareDriverException):
msg_fmt = _("File locked.")
code = 403
class FileNotFoundException(VMwareDriverException):
msg_fmt = _("File not found.")
code = 404
class InvalidPropertyException(VMwareDriverException):
msg_fmt = _("Invalid property.")
code = 400
class NoPermissionException(VMwareDriverException):
msg_fmt = _("No Permission.")
code = 403
class NotAuthenticatedException(VMwareDriverException):
msg_fmt = _("Not Authenticated.")
code = 403
class InvalidPowerStateException(VMwareDriverException):
msg_fmt = _("Invalid Power State.")
code = 409
class TaskInProgress(VMwareDriverException):
class TaskInProgress(vexc.VMwareDriverException):
msg_fmt = _("Virtual machine is busy.")
# Populate the fault registry with the exceptions that have
# special treatment.
_fault_classes_registry = {
ALREADY_EXISTS: AlreadyExistsException,
CANNOT_DELETE_FILE: CannotDeleteFileException,
FILE_ALREADY_EXISTS: FileAlreadyExistsException,
FILE_FAULT: FileFaultException,
FILE_LOCKED: FileLockedException,
FILE_NOT_FOUND: FileNotFoundException,
INVALID_POWER_STATE: InvalidPowerStateException,
INVALID_PROPERTY: InvalidPropertyException,
NO_PERMISSION: NoPermissionException,
NOT_AUTHENTICATED: NotAuthenticatedException,
TASK_IN_PROGRESS: TaskInProgress,
}
def get_fault_class(name):
"""Get a named subclass of VMwareDriverException."""
name = str(name)
fault_class = _fault_classes_registry.get(name)
if not fault_class:
LOG.warning(_('Fault %s not matched.'), name)
fault_class = VMwareDriverException
return fault_class

View File

@ -36,6 +36,7 @@ This will ensure that a image is not deleted during the spawn.
"""
from oslo.config import cfg
from oslo.vmware import exceptions as vexc
from nova.i18n import _
from nova.openstack.common import lockutils
@ -43,7 +44,6 @@ from nova.openstack.common import log as logging
from nova.openstack.common import timeutils
from nova.virt import imagecache
from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
LOG = logging.getLogger(__name__)
@ -66,14 +66,14 @@ class ImageCacheManager(imagecache.ImageCacheManager):
def _folder_delete(self, ds_path, dc_ref):
try:
ds_util.file_delete(self._session, ds_path, dc_ref)
except (error_util.CannotDeleteFileException,
error_util.FileFaultException,
error_util.FileLockedException) as e:
except (vexc.CannotDeleteFileException,
vexc.FileFaultException,
vexc.FileLockedException) as e:
# There may be more than one process or thread that tries
# to delete the file.
LOG.warning(_("Unable to delete %(file)s. Exception: %(ex)s"),
{'file': ds_path, 'ex': e})
except error_util.FileNotFoundException:
except vexc.FileNotFoundException:
LOG.debug("File not found: %s", ds_path)
def timestamp_folder_get(self, ds_path, image_id):
@ -142,7 +142,7 @@ class ImageCacheManager(imagecache.ImageCacheManager):
ts_path = path.join(self._get_timestamp_filename())
try:
ds_util.mkdir(self._session, ts_path, dc_info.ref)
except error_util.FileAlreadyExistsException:
except vexc.FileAlreadyExistsException:
LOG.debug("Timestamp already exists.")
LOG.info(_("Image %s is no longer used by this node. "
"Pending deletion!"), image)

View File

@ -17,11 +17,11 @@
"""
Utility functions for ESX Networking.
"""
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
from nova.openstack.common import log as logging
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@ -162,7 +162,7 @@ def create_port_group(session, pg_name, vswitch_name, vlan_id=0, cluster=None):
session._call_method(session._get_vim(),
"AddPortGroup", network_system_mor,
portgrp=add_prt_grp_spec)
except error_util.AlreadyExistsException:
except vexc.AlreadyExistsException:
# There can be a race condition when two instances try
# adding port groups at the same time. One succeeds, then
# the other one will get an exception. Since we are

View File

@ -16,11 +16,11 @@
"""VIF drivers for VMware."""
from oslo.config import cfg
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
from nova.openstack.common import log as logging
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import network_util
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@ -126,7 +126,7 @@ def get_neutron_network(session, network_name, cluster, vif):
opaque = session._call_method(vim_util, "get_dynamic_property", host,
"HostSystem",
"config.network.opaqueNetwork")
except error_util.InvalidPropertyException:
except vexc.InvalidPropertyException:
opaque = None
if opaque:
bridge = vif['network']['id']

View File

@ -1,269 +0,0 @@
# Copyright (c) 2012 VMware, Inc.
# Copyright (c) 2011 Citrix Systems, Inc.
# Copyright 2011 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Classes for making VMware VI SOAP calls.
"""
import httplib
import time
import urllib2
import decorator
from oslo.config import cfg
import six
import suds
from nova.i18n import _
from nova import utils
from nova.virt.vmwareapi import error_util
RESP_NOT_XML_ERROR = 'Response is "text/html", not "text/xml"'
CONN_ABORT_ERROR = 'Software caused connection abort'
ADDRESS_IN_USE_ERROR = 'Address already in use'
vmwareapi_wsdl_loc_opt = cfg.StrOpt('wsdl_location',
help='Optional VIM Service WSDL Location '
'e.g http://<server>/vimService.wsdl. '
'Optional over-ride to default location for bug work-arounds')
CONF = cfg.CONF
CONF.register_opt(vmwareapi_wsdl_loc_opt, 'vmware')
@decorator.decorator
def retry_if_task_in_progress(f, *args, **kwargs):
retries = max(CONF.vmware.api_retry_count, 1)
delay = 1
for attempt in range(1, retries + 1):
if attempt != 1:
time.sleep(delay)
delay = min(2 * delay, 60)
try:
f(*args, **kwargs)
return
except error_util.TaskInProgress:
pass
def get_moref(value, type):
"""Get managed object reference."""
moref = suds.sudsobject.Property(value)
moref._type = type
return moref
def object_to_dict(obj, list_depth=1):
"""Convert Suds object into serializable format.
The calling function can limit the amount of list entries that
are converted.
"""
d = {}
for k, v in suds.sudsobject.asdict(obj).iteritems():
if hasattr(v, '__keylist__'):
d[k] = object_to_dict(v, list_depth=list_depth)
elif isinstance(v, list):
d[k] = []
used = 0
for item in v:
used = used + 1
if used > list_depth:
break
if hasattr(item, '__keylist__'):
d[k].append(object_to_dict(item, list_depth=list_depth))
else:
d[k].append(item)
else:
d[k] = v
return d
class VIMMessagePlugin(suds.plugin.MessagePlugin):
def addAttributeForValue(self, node):
# suds does not handle AnyType properly.
# VI SDK requires type attribute to be set when AnyType is used
if node.name == 'value':
node.set('xsi:type', 'xsd:string')
def marshalled(self, context):
"""suds will send the specified soap envelope.
Provides the plugin with the opportunity to prune empty
nodes and fixup nodes before sending it to the server.
"""
# suds builds the entire request object based on the wsdl schema.
# VI SDK throws server errors if optional SOAP nodes are sent
# without values, e.g. <test/> as opposed to <test>test</test>
context.envelope.prune()
context.envelope.walk(self.addAttributeForValue)
class Vim:
"""The VIM Object."""
def __init__(self,
protocol="https",
host="localhost",
port=443):
"""Creates the necessary Communication interfaces and gets the
ServiceContent for initiating SOAP transactions.
protocol: http or https
host : ESX IPAddress or Hostname
port : port for connection
"""
if not suds:
raise Exception(_("Unable to import suds."))
self._protocol = protocol
self._host_name = host
self.wsdl_url = Vim.get_wsdl_url(protocol, host, port)
self.url = Vim.get_soap_url(protocol, host, port)
self.client = suds.client.Client(self.wsdl_url, location=self.url,
plugins=[VIMMessagePlugin()])
self._service_content = self.retrieve_service_content()
def retrieve_service_content(self):
return self.RetrieveServiceContent("ServiceInstance")
@staticmethod
def get_wsdl_url(protocol, host_name, port):
"""Allows override of the wsdl location, making this static
means we can test the logic outside of the constructor
without forcing the test environment to have multiple valid
wsdl locations to test against.
:param protocol: https or http
:param host_name: localhost or other server name
:param port: port for connection
:return: string to WSDL location for vSphere WS Management API
"""
# optional WSDL location over-ride for work-arounds
if CONF.vmware.wsdl_location:
return CONF.vmware.wsdl_location
# calculate default WSDL location if no override supplied
return Vim.get_soap_url(protocol, host_name, port) + "/vimService.wsdl"
@staticmethod
def get_soap_url(protocol, host_name, port):
"""Calculates the location of the SOAP services
for a particular server. Created as a static
method for testing.
:param protocol: https or http
:param host_name: localhost or other vSphere server name
:param port: port for connection
:return: the url to the active vSphere WS Management API
"""
if utils.is_valid_ipv6(host_name):
return '%s://[%s]:%d/sdk' % (protocol, host_name, port)
return '%s://%s:%d/sdk' % (protocol, host_name, port)
def get_service_content(self):
"""Gets the service content object."""
return self._service_content
def __getattr__(self, attr_name):
"""Makes the API calls and gets the result."""
def vim_request_handler(managed_object, **kwargs):
"""Builds the SOAP message and parses the response for fault
checking and other errors.
managed_object : Managed Object Reference or Managed
Object Name
**kwargs : Keyword arguments of the call
"""
# Dynamic handler for VI SDK Calls
try:
request_mo = self._request_managed_object_builder(
managed_object)
request = getattr(self.client.service, attr_name)
response = request(request_mo, **kwargs)
# To check for the faults that are part of the message body
# and not returned as Fault object response from the ESX
# SOAP server
if hasattr(error_util.FaultCheckers,
attr_name.lower() + "_fault_checker"):
fault_checker = getattr(error_util.FaultCheckers,
attr_name.lower() + "_fault_checker")
fault_checker(response)
return response
# Catch the VimFaultException that is raised by the fault
# check of the SOAP response
except error_util.VimFaultException:
raise
except suds.MethodNotFound:
raise
except suds.WebFault as excep:
doc = excep.document
fault_string = doc.childAtPath("/Envelope/Body/Fault/"
"faultstring").getText()
detail = doc.childAtPath("/Envelope/Body/Fault/detail")
fault_list = []
details = {}
if detail:
for fault in detail.getChildren():
fault_list.append(fault.get("type"))
for child in fault.getChildren():
details[child.name] = child.getText()
raise error_util.VimFaultException(fault_list, fault_string,
details)
except AttributeError as excep:
raise error_util.VimAttributeError(_("No such SOAP method "
"'%s' provided by VI SDK") % (attr_name), excep)
except (httplib.CannotSendRequest,
httplib.ResponseNotReady,
httplib.CannotSendHeader) as excep:
raise error_util.SessionOverLoadException(_("httplib "
"error in %s: ") % (attr_name), excep)
except (urllib2.URLError,
urllib2.HTTPError) as excep:
raise error_util.SessionConnectionException(_("urllib2 "
"error in %s: ") % (attr_name), excep)
except Exception as excep:
# Socket errors which need special handling for they
# might be caused by ESX API call overload
msg_excep = six.text_type(excep)
if (msg_excep.find(ADDRESS_IN_USE_ERROR) != -1 or
msg_excep.find(CONN_ABORT_ERROR)) != -1:
raise error_util.SessionOverLoadException(_("Socket "
"error in %s: ") % (attr_name), excep)
# Type error that needs special handling for it might be
# caused by ESX host API call overload
elif six.text_type(excep).find(RESP_NOT_XML_ERROR) != -1:
raise error_util.SessionOverLoadException(_("Type "
"error in %s: ") % (attr_name), excep)
else:
raise error_util.VimException(
_("Exception in %s ") % (attr_name), excep)
return vim_request_handler
def _request_managed_object_builder(self, managed_object):
"""Builds the request managed object."""
# Request Managed Object Builder
if isinstance(managed_object, str):
mo = suds.sudsobject.Property(managed_object)
mo._type = managed_object
else:
mo = managed_object
return mo
def __repr__(self):
return "VIM Object"
def __str__(self):
return "VIM Object"

View File

@ -18,6 +18,8 @@ The VMware API utility module.
"""
from oslo.config import cfg
from oslo.vmware import vim_util as vutil
import suds
from nova.i18n import _
from nova.openstack.common import log as logging
@ -37,108 +39,34 @@ CONF.register_opt(vmware_opts, 'vmware')
LOG = logging.getLogger(__name__)
def build_selection_spec(client_factory, name):
"""Builds the selection spec."""
sel_spec = client_factory.create('ns0:SelectionSpec')
sel_spec.name = name
return sel_spec
def object_to_dict(obj, list_depth=1):
"""Convert Suds object into serializable format.
def build_traversal_spec(client_factory, name, spec_type, path, skip,
select_set):
"""Builds the traversal spec object."""
traversal_spec = client_factory.create('ns0:TraversalSpec')
traversal_spec.name = name
traversal_spec.type = spec_type
traversal_spec.path = path
traversal_spec.skip = skip
traversal_spec.selectSet = select_set
return traversal_spec
def build_recursive_traversal_spec(client_factory):
"""Builds the Recursive Traversal Spec to traverse the object managed
object hierarchy.
The calling function can limit the amount of list entries that
are converted.
"""
visit_folders_select_spec = build_selection_spec(client_factory,
"visitFolders")
# For getting to hostFolder from datacenter
dc_to_hf = build_traversal_spec(client_factory, "dc_to_hf", "Datacenter",
"hostFolder", False,
[visit_folders_select_spec])
# For getting to vmFolder from datacenter
dc_to_vmf = build_traversal_spec(client_factory, "dc_to_vmf", "Datacenter",
"vmFolder", False,
[visit_folders_select_spec])
# For getting Host System to virtual machine
h_to_vm = build_traversal_spec(client_factory, "h_to_vm", "HostSystem",
"vm", False,
[visit_folders_select_spec])
# For getting to Host System from Compute Resource
cr_to_h = build_traversal_spec(client_factory, "cr_to_h",
"ComputeResource", "host", False, [])
# For getting to datastore from Compute Resource
cr_to_ds = build_traversal_spec(client_factory, "cr_to_ds",
"ComputeResource", "datastore", False, [])
rp_to_rp_select_spec = build_selection_spec(client_factory, "rp_to_rp")
rp_to_vm_select_spec = build_selection_spec(client_factory, "rp_to_vm")
# For getting to resource pool from Compute Resource
cr_to_rp = build_traversal_spec(client_factory, "cr_to_rp",
"ComputeResource", "resourcePool", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# For getting to child res pool from the parent res pool
rp_to_rp = build_traversal_spec(client_factory, "rp_to_rp", "ResourcePool",
"resourcePool", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# For getting to Virtual Machine from the Resource Pool
rp_to_vm = build_traversal_spec(client_factory, "rp_to_vm", "ResourcePool",
"vm", False,
[rp_to_rp_select_spec, rp_to_vm_select_spec])
# Get the assorted traversal spec which takes care of the objects to
# be searched for from the root folder
traversal_spec = build_traversal_spec(client_factory, "visitFolders",
"Folder", "childEntity", False,
[visit_folders_select_spec, dc_to_hf,
dc_to_vmf, cr_to_ds, cr_to_h, cr_to_rp,
rp_to_rp, h_to_vm, rp_to_vm])
return traversal_spec
d = {}
for k, v in suds.sudsobject.asdict(obj).iteritems():
if hasattr(v, '__keylist__'):
d[k] = object_to_dict(v, list_depth=list_depth)
elif isinstance(v, list):
d[k] = []
used = 0
for item in v:
used = used + 1
if used > list_depth:
break
if hasattr(item, '__keylist__'):
d[k].append(object_to_dict(item, list_depth=list_depth))
else:
d[k].append(item)
else:
d[k] = v
return d
def build_property_spec(client_factory, type="VirtualMachine",
properties_to_collect=None,
all_properties=False):
"""Builds the Property Spec."""
if not properties_to_collect:
properties_to_collect = ["name"]
property_spec = client_factory.create('ns0:PropertySpec')
property_spec.all = all_properties
property_spec.pathSet = properties_to_collect
property_spec.type = type
return property_spec
def build_object_spec(client_factory, root_folder, traversal_specs):
"""Builds the object Spec."""
object_spec = client_factory.create('ns0:ObjectSpec')
object_spec.obj = root_folder
object_spec.skip = False
object_spec.selectSet = traversal_specs
return object_spec
def build_property_filter_spec(client_factory, property_specs, object_specs):
"""Builds the Property Filter Spec."""
property_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
property_filter_spec.propSet = property_specs
property_filter_spec.objectSet = object_specs
return property_filter_spec
def get_moref(value, type):
return vutil.get_moref(value, type)
def get_object_properties(vim, collector, mobj, type, properties):
@ -148,7 +76,7 @@ def get_object_properties(vim, collector, mobj, type, properties):
return None
usecoll = collector
if usecoll is None:
usecoll = vim.get_service_content().propertyCollector
usecoll = vim.service_content.propertyCollector
property_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
property_spec = client_factory.create('ns0:PropertySpec')
property_spec.all = (properties is None or len(properties) == 0)
@ -197,24 +125,8 @@ def get_dynamic_properties(vim, mobj, type, property_names):
def get_objects(vim, type, properties_to_collect=None, all=False):
"""Gets the list of objects of the type specified."""
if not properties_to_collect:
properties_to_collect = ["name"]
client_factory = vim.client.factory
object_spec = build_object_spec(client_factory,
vim.get_service_content().rootFolder,
[build_recursive_traversal_spec(client_factory)])
property_spec = build_property_spec(client_factory, type=type,
properties_to_collect=properties_to_collect,
all_properties=all)
property_filter_spec = build_property_filter_spec(client_factory,
[property_spec],
[object_spec])
options = client_factory.create('ns0:RetrieveOptions')
options.maxObjects = CONF.vmware.maximum_objects
return vim.RetrievePropertiesEx(
vim.get_service_content().propertyCollector,
specSet=[property_filter_spec], options=options)
return vutil.get_objects(vim, type, CONF.vmware.maximum_objects,
properties_to_collect, all)
def get_inner_objects(vim, base_obj, path, inner_type,
@ -222,32 +134,34 @@ def get_inner_objects(vim, base_obj, path, inner_type,
"""Gets the list of inner objects of the type specified."""
client_factory = vim.client.factory
base_type = base_obj._type
traversal_spec = build_traversal_spec(client_factory, 'inner', base_type,
path, False, [])
object_spec = build_object_spec(client_factory, base_obj, [traversal_spec])
property_spec = build_property_spec(client_factory, type=inner_type,
traversal_spec = vutil.build_traversal_spec(client_factory, 'inner',
base_type, path, False, [])
object_spec = vutil.build_object_spec(client_factory,
base_obj,
[traversal_spec])
property_spec = vutil.build_property_spec(client_factory, type_=inner_type,
properties_to_collect=properties_to_collect,
all_properties=all)
property_filter_spec = build_property_filter_spec(client_factory,
property_filter_spec = vutil.build_property_filter_spec(client_factory,
[property_spec], [object_spec])
options = client_factory.create('ns0:RetrieveOptions')
options.maxObjects = CONF.vmware.maximum_objects
return vim.RetrievePropertiesEx(
vim.get_service_content().propertyCollector,
vim.service_content.propertyCollector,
specSet=[property_filter_spec], options=options)
def cancel_retrieve(vim, token):
"""Cancels the retrieve operation."""
return vim.CancelRetrievePropertiesEx(
vim.get_service_content().propertyCollector,
vim.service_content.propertyCollector,
token=token)
def continue_to_get_objects(vim, token):
"""Continues to get the list of objects of the type specified."""
return vim.ContinueRetrievePropertiesEx(
vim.get_service_content().propertyCollector,
vim.service_content.propertyCollector,
token=token)
@ -294,10 +208,10 @@ def get_properties_for_a_collection_of_objects(vim, type,
options = client_factory.create('ns0:RetrieveOptions')
options.maxObjects = CONF.vmware.maximum_objects
return vim.RetrievePropertiesEx(
vim.get_service_content().propertyCollector,
vim.service_content.propertyCollector,
specSet=[prop_filter_spec], options=options)
def get_about_info(vim):
"""Get the About Info from the service content."""
return vim.get_service_content().about
return vim.service_content.about

View File

@ -22,6 +22,7 @@ import copy
import functools
from oslo.config import cfg
from oslo.vmware import exceptions as vexc
from nova import exception
from nova.i18n import _
@ -30,7 +31,6 @@ from nova.openstack.common import log as logging
from nova.openstack.common import units
from nova import utils
from nova.virt.vmwareapi import constants
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import vim_util
CONF = cfg.CONF
@ -854,7 +854,7 @@ def _get_vm_ref_from_vm_uuid(session, instance_uuid):
vm_refs = session._call_method(
session._get_vim(),
"FindAllByUuid",
session._get_vim().get_service_content().searchIndex,
session._get_vim().service_content.searchIndex,
uuid=instance_uuid,
vmSearch=True,
instanceUuid=True)
@ -1298,7 +1298,7 @@ def create_virtual_disk(session, dc_ref, adapter_type, disk_type,
vmdk_create_task = session._call_method(
session._get_vim(),
"CreateVirtualDisk_Task",
session._get_vim().get_service_content().virtualDiskManager,
session._get_vim().service_content.virtualDiskManager,
name=virtual_disk_path,
datacenter=dc_ref,
spec=vmdk_create_spec)
@ -1328,7 +1328,7 @@ def copy_virtual_disk(session, dc_ref, source, dest, copy_spec=None):
vmdk_copy_task = session._call_method(
vim,
"CopyVirtualDisk_Task",
vim.get_service_content().virtualDiskManager,
vim.service_content.virtualDiskManager,
sourceName=source,
sourceDatacenter=dc_ref,
destName=dest,
@ -1356,7 +1356,7 @@ def clone_vmref_for_instance(session, instance, vm_ref, host_ref, ds_ref,
if vm_ref is None:
LOG.warn(_("vmwareapi:vm_util:clone_vmref_for_instance, called "
"with vm_ref=None"))
raise error_util.MissingParameter(param="vm_ref")
raise vexc.MissingParameter(param="vm_ref")
# Get the clone vm spec
client_factory = session._get_vim().client.factory
rel_spec = relocate_vm_spec(client_factory, ds_ref, host_ref,
@ -1449,7 +1449,7 @@ def power_on_instance(session, instance, vm_ref=None):
"PowerOnVM_Task", vm_ref)
session._wait_for_task(poweron_task)
LOG.debug("Powered on the VM", instance=instance)
except error_util.InvalidPowerStateException:
except vexc.InvalidPowerStateException:
LOG.debug("VM already powered on", instance=instance)
@ -1528,5 +1528,5 @@ def power_off_instance(session, instance, vm_ref=None):
"PowerOffVM_Task", vm_ref)
session._wait_for_task(poweroff_task)
LOG.debug("Powered off the VM", instance=instance)
except error_util.InvalidPowerStateException:
except vexc.InvalidPowerStateException:
LOG.debug("VM already powered off", instance=instance)

View File

@ -22,8 +22,11 @@ Class for VM tasks like spawn, snapshot, suspend, resume etc.
import collections
import copy
import os
import time
import decorator
from oslo.config import cfg
from oslo.vmware import exceptions as vexc
from nova.api.metadata import base as instance_metadata
from nova import compute
@ -49,7 +52,6 @@ from nova.virt.vmwareapi import ds_util
from nova.virt.vmwareapi import error_util
from nova.virt.vmwareapi import imagecache
from nova.virt.vmwareapi import vif as vmwarevif
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmware_images
@ -111,6 +113,29 @@ class VirtualMachineInstanceConfigInfo(object):
return self.cache_image_folder.join(cached_image_file_name)
# Note(vui): See https://bugs.launchpad.net/nova/+bug/1363349
# for cases where mocking time.sleep() can have unintended effects on code
# not under test. For now, unblock the affected test cases by providing
# a wrapper function to work around needing to mock time.sleep()
def _time_sleep_wrapper(delay):
time.sleep(delay)
@decorator.decorator
def retry_if_task_in_progress(f, *args, **kwargs):
retries = max(CONF.vmware.api_retry_count, 1)
delay = 1
for attempt in range(1, retries + 1):
if attempt != 1:
_time_sleep_wrapper(delay)
delay = min(2 * delay, 60)
try:
f(*args, **kwargs)
return
except error_util.TaskInProgress:
pass
class VMwareVMOps(object):
"""Management class for VM-related tasks."""
@ -151,7 +176,7 @@ class VMwareVMOps(object):
return lst_vm_names
def _extend_virtual_disk(self, instance, requested_size, name, dc_ref):
service_content = self._session._get_vim().get_service_content()
service_content = self._session._get_vim().service_content
LOG.debug("Extending root virtual disk to %s", requested_size)
vmdk_extend_task = self._session._call_method(
self._session._get_vim(),
@ -178,10 +203,10 @@ class VMwareVMOps(object):
def _delete_datastore_file(self, instance, datastore_path, dc_ref):
try:
ds_util.file_delete(self._session, datastore_path, dc_ref)
except (error_util.CannotDeleteFileException,
error_util.FileFaultException,
error_util.FileLockedException,
error_util.FileNotFoundException):
except (vexc.CannotDeleteFileException,
vexc.FileFaultException,
vexc.FileLockedException,
vexc.FileNotFoundException):
LOG.debug("Unable to delete %(ds)s. There may be more than "
"one process or thread trying to delete the file",
{'ds': datastore_path},
@ -428,7 +453,7 @@ class VMwareVMOps(object):
vmware_images.fetch_image(context,
instance,
self._session._host_ip,
self._session._host,
dc_info.name,
datastore.name,
upload_rel_path,
@ -454,7 +479,7 @@ class VMwareVMOps(object):
try:
ds_util.file_move(self._session, dc_info.ref,
src_folder, dest_folder)
except error_util.FileAlreadyExistsException:
except vexc.FileAlreadyExistsException:
# File move has failed. This may be due to the fact that a
# process or thread has already completed the opertaion.
# In the event of a FileAlreadyExists we continue,
@ -564,7 +589,7 @@ class VMwareVMOps(object):
ds_util.file_delete(self._session,
root_vmdk_path,
dc_info.ref)
except error_util.FileNotFoundException:
except vexc.FileNotFoundException:
# File was never created: cleanup not
# required
pass
@ -624,7 +649,7 @@ class VMwareVMOps(object):
upload_folder)
vmware_images.upload_iso_to_datastore(
tmp_file, instance,
host=self._session._host_ip,
host=self._session._host,
data_center_name=dc_name,
datastore_name=data_store_name,
cookies=cookies,
@ -682,7 +707,7 @@ class VMwareVMOps(object):
snapshot = task_info.result
return snapshot
@vim.retry_if_task_in_progress
@retry_if_task_in_progress
def _delete_vm_snapshot(self, instance, vm_ref, snapshot):
LOG.debug("Deleting Snapshot of the VM instance", instance=instance)
delete_snapshot_task = self._session._call_method(
@ -709,7 +734,7 @@ class VMwareVMOps(object):
"""
vm_ref = vm_util.get_vm_ref(self._session, instance)
client_factory = self._session._get_vim().client.factory
service_content = self._session._get_vim().get_service_content()
service_content = self._session._get_vim().service_content
def _get_vm_and_vmdk_attribs():
# Get the vmdk file name that the VM is pointing to
@ -801,7 +826,7 @@ class VMwareVMOps(object):
disk_type=constants.DEFAULT_DISK_TYPE,
adapter_type=adapter_type,
image_version=1,
host=self._session._host_ip,
host=self._session._host,
data_center_name=dc_info.name,
datastore_name=datastore_name,
cookies=cookies,
@ -1269,7 +1294,7 @@ class VMwareVMOps(object):
data = {}
# All of values received are objects. Convert them to dictionaries
for value in query.values():
prop_dict = vim.object_to_dict(value, list_depth=1)
prop_dict = vim_util.object_to_dict(value, list_depth=1)
data.update(prop_dict)
return data
@ -1437,7 +1462,7 @@ class VMwareVMOps(object):
try:
ds_util.mkdir(self._session, path, dc_info.ref)
LOG.debug("Folder %s created.", path)
except error_util.FileAlreadyExistsException:
except vexc.FileAlreadyExistsException:
# NOTE(hartsocks): if the folder already exists, that
# just means the folder was prepped by another process.
pass

View File

@ -22,7 +22,6 @@ from oslo.config import cfg
from nova import exception
from nova.i18n import _
from nova.openstack.common import log as logging
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
@ -300,7 +299,7 @@ class VMwareVolumeOps(object):
def _get_volume_ref(self, volume_ref_name):
"""Get the volume moref from the ref name."""
return vim.get_moref(volume_ref_name, 'VirtualMachine')
return vim_util.get_moref(volume_ref_name, 'VirtualMachine')
def _get_vmdk_base_volume_device(self, volume_ref):
# Get the vmdk file name that the VM is pointing to

View File

@ -38,3 +38,4 @@ oslo.messaging>=1.4.0.0a3
oslo.i18n>=0.2.0 # Apache-2.0
lockfile>=0.8
rfc3986>=0.2.0 # Apache-2.0
oslo.vmware>=0.5.0