diff options
| author | sateesh <sateesh.chodapuneedi@citrix.com> | 2011-03-02 00:43:29 +0530 |
|---|---|---|
| committer | sateesh <sateesh.chodapuneedi@citrix.com> | 2011-03-02 00:43:29 +0530 |
| commit | f952992f035ec130b7608e9851ef9c3becc2047a (patch) | |
| tree | 661bf6bbe83fad06120fd7bbc5fe45e2743ba755 /nova | |
| parent | 4376b1add894aa6d9b5568865ffb07f921e7e525 (diff) | |
Updated the code to include support for guest consoles, VLAN networking for guest machines on ESX/ESXi servers as compute providers in OpenStack.
Removed dependency on ZSI and now using suds-0.4 to generate the required stubs for VMware Virtual Infrastructure API on the fly for calls by vmwareapi module.
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/virt/vmwareapi/__init__.py | 9 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/fake.py | 684 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/io_util.py | 52 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/network_utils.py | 117 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/read_write_util.py | 110 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/vim.py | 117 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/vim_util.py | 303 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/vm_util.py | 335 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/vmops.py | 435 | ||||
| -rw-r--r-- | nova/virt/vmwareapi/vmware_images.py | 96 | ||||
| -rw-r--r-- | nova/virt/vmwareapi_conn.py | 134 |
11 files changed, 1490 insertions, 902 deletions
diff --git a/nova/virt/vmwareapi/__init__.py b/nova/virt/vmwareapi/__init__.py index 0cf70150c..27e212a30 100644 --- a/nova/virt/vmwareapi/__init__.py +++ b/nova/virt/vmwareapi/__init__.py @@ -14,16 +14,7 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. - """ :mod:`vmwareapi` -- Nova support for VMware ESX/ESXi Server through vSphere API -=============================================================================== """ - -class HelperBase(object): - """The base for helper classes. This adds the VMwareAPI class attribute""" - VMwareAPI = None - - def __init__(self): - return diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py new file mode 100644 index 000000000..43a2f1943 --- /dev/null +++ b/nova/virt/vmwareapi/fake.py @@ -0,0 +1,684 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack LLC.
+#
+# 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.
+
+"""
+A fake VMWare VI API implementation.
+"""
+
+from pprint import pformat
+import uuid
+
+from nova import exception
+from nova import log as logging
+from nova.virt.vmwareapi import vim
+from nova.virt.vmwareapi.vim import SessionFaultyException
+
+_CLASSES = ['Datacenter', 'Datastore', 'ResourcePool', 'VirtualMachine',
+ 'Network', 'HostSystem', 'Task', 'session', 'files']
+
+_FAKE_FILE_SIZE = 1024
+
+_db_content = {}
+
+LOG = logging.getLogger("nova.virt.vmwareapi.fake")
+
+
+def log_db_contents(msg=None):
+ """ Log DB Contents"""
+ text = msg or ""
+ content = pformat(_db_content)
+ LOG.debug(_("%(text)s: _db_content => %(content)s") % locals())
+
+
+def reset():
+ """ Resets the db contents """
+ for c in _CLASSES:
+ #We fake the datastore by keeping the file references as a list of
+ #names in the db
+ if c == 'files':
+ _db_content[c] = []
+ else:
+ _db_content[c] = {}
+ create_network()
+ create_host()
+ create_datacenter()
+ create_datastore()
+ create_res_pool()
+
+
+def cleanup():
+ """ Clear the db contents """
+ for c in _CLASSES:
+ _db_content[c] = {}
+
+
+def _create_object(table, obj):
+ """ Create an object in the db """
+ _db_content[table][obj.obj] = obj
+
+
+def _get_objects(type):
+ """ Get objects of the type """
+ lst_objs = []
+ for key in _db_content[type]:
+ lst_objs.append(_db_content[type][key])
+ return lst_objs
+
+
+class Prop(object):
+ """ Property Object base class """
+
+ def __init__(self):
+ self.name = None
+ self.val = None
+
+ def setVal(self, val):
+ self.val = val
+
+ def setName(self, name):
+ self.name = name
+
+
+class ManagedObject(object):
+ """ Managed Data Object base class """
+
+ def __init__(self, name="ManagedObject", obj_ref=None):
+ """ Sets the obj property which acts as a reference to the object"""
+ object.__setattr__(self, 'objName', name)
+ if obj_ref is None:
+ obj_ref = str(uuid.uuid4())
+ object.__setattr__(self, 'obj', obj_ref)
+ object.__setattr__(self, 'propSet', [])
+
+ def set(self, attr, val):
+ """ Sets an attribute value. Not using the __setattr__ directly for we
+ want to set attributes of the type 'a.b.c' and using this function
+ class we set the same """
+ self.__setattr__(attr, val)
+
+ def get(self, attr):
+ """ Gets an attribute. Used as an intermediary to get nested
+ property like 'a.b.c' value """
+ return self.__getattr__(attr)
+
+ def __setattr__(self, attr, val):
+ for prop in self.propSet:
+ if prop.name == attr:
+ prop.val = val
+ return
+ elem = Prop()
+ elem.setName(attr)
+ elem.setVal(val)
+ self.propSet.append(elem)
+
+ def __getattr__(self, attr):
+ for elem in self.propSet:
+ if elem.name == attr:
+ return elem.val
+ raise Exception(_("Property %(attr)s not set for the managed "
+ "object %(objName)s") %
+ {'attr': attr,
+ 'objName': self.objName})
+
+
+class DataObject(object):
+ """ Data object base class """
+
+ def __init__(self):
+ pass
+
+ def __getattr__(self, attr):
+ return object.__getattribute__(self, attr)
+
+ def __setattr__(self, attr, value):
+ object.__setattr__(self, attr, value)
+
+
+class VirtualDisk(DataObject):
+ """ Virtual Disk class. Does nothing special except setting
+ __class__.__name__ to 'VirtualDisk'. Refer place where __class__.__name__
+ is used in the code """
+
+ def __init__(self):
+ DataObject.__init__(self)
+
+
+class VirtualDiskFlatVer2BackingInfo(DataObject):
+ """ VirtualDiskFlatVer2BackingInfo class """
+
+ def __init__(self):
+ DataObject.__init__(self)
+
+
+class VirtualLsiLogicController(DataObject):
+ """ VirtualLsiLogicController class """
+
+ def __init__(self):
+ DataObject.__init__(self)
+
+
+class VirtualMachine(ManagedObject):
+ """ Virtual Machine class """
+
+ def __init__(self, **kwargs):
+ ManagedObject.__init__(self, "VirtualMachine")
+ self.set("name", kwargs.get("name"))
+ self.set("runtime.connectionState",
+ kwargs.get("conn_state", "connected"))
+ self.set("summary.config.guestId", kwargs.get("guest", "otherGuest"))
+ ds_do = DataObject()
+ ds_do.ManagedObjectReference = [kwargs.get("ds").obj]
+ self.set("datastore", ds_do)
+ self.set("summary.guest.toolsStatus", kwargs.get("toolsstatus",
+ "toolsOk"))
+ self.set("runtime.powerState", kwargs.get("powerstate", "poweredOn"))
+ self.set("config.files.vmPathName", kwargs.get("vmPathName"))
+ self.set("summary.config.numCpu", kwargs.get("numCpu", 1))
+ self.set("summary.config.memorySizeMB", kwargs.get("mem", 1))
+ self.set("config.hardware.device", kwargs.get("virtual_disk", None))
+ self.set("config.extraConfig", kwargs.get("extra_config", None))
+
+ def reconfig(self, factory, val):
+ """ Called to reconfigure the VM. Actually customizes the property
+ setting of the Virtual Machine object """
+ try:
+ #Case of Reconfig of VM to attach disk
+ controller_key = val.deviceChange[1].device.controllerKey
+ filename = val.deviceChange[1].device.backing.fileName
+
+ disk = VirtualDisk()
+ disk.controllerKey = controller_key
+
+ disk_backing = VirtualDiskFlatVer2BackingInfo()
+ disk_backing.fileName = filename
+ disk_backing.key = -101
+ disk.backing = disk_backing
+
+ controller = VirtualLsiLogicController()
+ controller.key = controller_key
+
+ self.set("config.hardware.device", [disk, controller])
+ except Exception:
+ #Case of Reconfig of VM to set extra params
+ self.set("config.extraConfig", val.extraConfig)
+
+
+class Network(ManagedObject):
+ """ Network class """
+
+ def __init__(self):
+ ManagedObject.__init__(self, "Network")
+ self.set("summary.name", "vmnet0")
+
+
+class ResourcePool(ManagedObject):
+ """ Resource Pool class """
+
+ def __init__(self):
+ ManagedObject.__init__(self, "ResourcePool")
+ self.set("name", "ResPool")
+
+
+class Datastore(ManagedObject):
+ """ Datastore class """
+
+ def __init__(self):
+ ManagedObject.__init__(self, "Datastore")
+ self.set("summary.type", "VMFS")
+ self.set("summary.name", "fake-ds")
+
+
+class HostSystem(ManagedObject):
+ """ Host System class """
+
+ def __init__(self):
+ ManagedObject.__init__(self, "HostSystem")
+ self.set("name", "HostSystem")
+ self.set("configManager.networkSystem", "NetworkSystem")
+
+ vswitch_do = DataObject()
+ vswitch_do.pnic = ["vmnic0"]
+ vswitch_do.name = "vSwitch0"
+ vswitch_do.portgroup = ["PortGroup-vmnet0"]
+
+ net_swicth = DataObject()
+ net_swicth.HostVirtualSwitch = [vswitch_do]
+ self.set("config.network.vswitch", net_swicth)
+
+ host_pg_do = DataObject()
+ host_pg_do.key = "PortGroup-vmnet0"
+
+ pg_spec = DataObject()
+ pg_spec.vlanId = 0
+ pg_spec.name = "vmnet0"
+
+ host_pg_do.spec = pg_spec
+
+ host_pg = DataObject()
+ host_pg.HostPortGroup = [host_pg_do]
+ self.set("config.network.portgroup", host_pg)
+
+ def _add_port_group(self, spec):
+ """ Adds a port group to the host system object in the db """
+ pg_name = spec.name
+ vswitch_name = spec.vswitchName
+ vlanid = spec.vlanId
+
+ vswitch_do = DataObject()
+ vswitch_do.pnic = ["vmnic0"]
+ vswitch_do.name = vswitch_name
+ vswitch_do.portgroup = ["PortGroup-%s" % pg_name]
+
+ vswitches = self.get("config.network.vswitch").HostVirtualSwitch
+ vswitches.append(vswitch_do)
+
+ host_pg_do = DataObject()
+ host_pg_do.key = "PortGroup-%s" % pg_name
+
+ pg_spec = DataObject()
+ pg_spec.vlanId = vlanid
+ pg_spec.name = pg_name
+
+ host_pg_do.spec = pg_spec
+ host_pgrps = self.get("config.network.portgroup").HostPortGroup
+ host_pgrps.append(host_pg_do)
+
+
+class Datacenter(ManagedObject):
+ """ Datacenter class """
+
+ def __init__(self):
+ ManagedObject.__init__(self, "Datacenter")
+ self.set("name", "ha-datacenter")
+ self.set("vmFolder", "vm_folder_ref")
+ if _db_content.get("Network", None) is None:
+ create_network()
+ net_ref = _db_content["Network"][_db_content["Network"].keys()[0]].obj
+ network_do = DataObject()
+ network_do.ManagedObjectReference = [net_ref]
+ self.set("network", network_do)
+
+
+class Task(ManagedObject):
+ """ Task class """
+
+ def __init__(self, task_name, state="running"):
+ ManagedObject.__init__(self, "Task")
+ info = DataObject
+ info.name = task_name
+ info.state = state
+ self.set("info", info)
+
+
+def create_host():
+ host_system = HostSystem()
+ _create_object('HostSystem', host_system)
+
+
+def create_datacenter():
+ data_center = Datacenter()
+ _create_object('Datacenter', data_center)
+
+
+def create_datastore():
+ data_store = Datastore()
+ _create_object('Datastore', data_store)
+
+
+def create_res_pool():
+ res_pool = ResourcePool()
+ _create_object('ResourcePool', res_pool)
+
+
+def create_network():
+ network = Network()
+ _create_object('Network', network)
+
+
+def create_task(task_name, state="running"):
+ task = Task(task_name, state)
+ _create_object("Task", task)
+ return task
+
+
+def _add_file(file_path):
+ """ Adds a file reference to the db """
+ _db_content["files"].append(file_path)
+
+
+def _remove_file(file_path):
+ """ Removes a file reference from the db """
+ if _db_content.get("files", None) is None:
+ raise Exception(_("No files have been added yet"))
+ #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 Exception(_("File- '%s' is not there in the datastore") %\
+ file_path)
+ _db_content.get("files").remove(file_path)
+ else:
+ #Removes the files in the folder and the folder too from the db
+ for file in _db_content.get("files"):
+ if file.find(file_path) != -1:
+ try:
+ _db_content.get("files").remove(file)
+ except Exception:
+ pass
+
+
+def fake_fetch_image(image, instance, **kwargs):
+ """Fakes fetch image call. Just adds a reference to the db for the file """
+ ds_name = kwargs.get("datastore_name")
+ file_path = kwargs.get("file_path")
+ ds_file_path = "[" + ds_name + "] " + file_path
+ _add_file(ds_file_path)
+
+
+def fake_upload_image(image, instance, **kwargs):
+ """Fakes the upload of an image """
+ pass
+
+
+def fake_get_vmdk_size_and_properties(image_id, instance):
+ """ Fakes the file size and properties fetch for the image file """
+ props = {"vmware_ostype": "otherGuest",
+ "vmware_adaptertype": "lsiLogic"}
+ return _FAKE_FILE_SIZE, props
+
+
+def _get_vm_mdo(vm_ref):
+ """ Gets the Virtual Machine with the ref from the db """
+ if _db_content.get("VirtualMachine", None) is None:
+ raise Exception(_("There is no VM registered"))
+ if vm_ref not in _db_content.get("VirtualMachine"):
+ raise Exception(_("Virtual Machine with ref %s is not there") %\
+ vm_ref)
+ return _db_content.get("VirtualMachine")[vm_ref]
+
+
+class FakeFactory(object):
+ """ Fake factory class for the suds client """
+
+ def __init__(self):
+ pass
+
+ def create(self, obj_name):
+ """ Creates a namespace object """
+ return DataObject()
+
+
+class FakeVim(object):
+ """Fake VIM Class"""
+
+ def __init__(self, protocol="https", host="localhost", trace=None):
+ """ Initializes the suds client object, sets the service content
+ contents and the cookies for the session """
+ self._session = None
+ self.client = DataObject()
+ self.client.factory = FakeFactory()
+
+ transport = DataObject()
+ transport.cookiejar = "Fake-CookieJar"
+ options = DataObject()
+ options.transport = transport
+
+ self.client.options = options
+
+ service_content = self.client.factory.create('ns0:ServiceContent')
+ service_content.propertyCollector = "PropCollector"
+ service_content.virtualDiskManager = "VirtualDiskManager"
+ service_content.fileManager = "FileManager"
+ service_content.rootFolder = "RootFolder"
+ service_content.sessionManager = "SessionManager"
+ self._service_content = service_content
+
+ def get_service_content(self):
+ return self._service_content
+
+ def __repr__(self):
+ return "Fake VIM Object"
+
+ def __str__(self):
+ return "Fake VIM Object"
+
+ def _login(self):
+ """ Logs in and sets the session object in the db """
+ self._session = str(uuid.uuid4())
+ session = DataObject()
+ session.key = self._session
+ _db_content['session'][self._session] = session
+ return session
+
+ def _logout(self):
+ """ Logs out and remove the session object ref from the db """
+ s = self._session
+ self._session = None
+ if s not in _db_content['session']:
+ raise exception.Error(
+ _("Logging out a session that is invalid or already logged "
+ "out: %s") % s)
+ del _db_content['session'][s]
+
+ def _terminate(self, *args, **kwargs):
+ """ Terminates a session """
+ s = kwargs.get("sessionId")[0]
+ if s not in _db_content['session']:
+ return
+ del _db_content['session'][s]
+
+ def _check_session(self):
+ """ Checks if the session is active """
+ if (self._session is None or self._session not in
+ _db_content['session']):
+ LOG.debug(_("Session is faulty"))
+ raise SessionFaultyException(_("Session Invalid"))
+
+ def _create_vm(self, method, *args, **kwargs):
+ """ Creates and registers a VM object with the Host System """
+ config_spec = kwargs.get("config")
+ ds = _db_content["Datastore"][_db_content["Datastore"].keys()[0]]
+ vm_dict = {"name": config_spec.name,
+ "ds": ds,
+ "powerstate": "poweredOff",
+ "vmPathName": config_spec.files.vmPathName,
+ "numCpu": config_spec.numCPUs,
+ "mem": config_spec.memoryMB}
+ virtual_machine = VirtualMachine(**vm_dict)
+ _create_object("VirtualMachine", virtual_machine)
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _reconfig_vm(self, method, *args, **kwargs):
+ """ Reconfigures a VM and sets the properties supplied """
+ vm_ref = args[0]
+ vm_mdo = _get_vm_mdo(vm_ref)
+ vm_mdo.reconfig(self.client.factory, kwargs.get("spec"))
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _create_copy_disk(self, method, vmdk_file_path):
+ """ Creates/copies a vmdk file object in the datastore """
+ # We need to add/create both .vmdk and .-flat.vmdk files
+ flat_vmdk_file_path = \
+ vmdk_file_path.replace(".vmdk", "-flat.vmdk")
+ _add_file(vmdk_file_path)
+ _add_file(flat_vmdk_file_path)
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _snapshot_vm(self, method):
+ """ Snapshots a VM. Here we do nothing for faking sake """
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _delete_disk(self, method, *args, **kwargs):
+ """ Deletes .vmdk and -flat.vmdk files corresponding to the VM """
+ vmdk_file_path = kwargs.get("name")
+ flat_vmdk_file_path = \
+ vmdk_file_path.replace(".vmdk", "-flat.vmdk")
+ _remove_file(vmdk_file_path)
+ _remove_file(flat_vmdk_file_path)
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _delete_file(self, method, *args, **kwargs):
+ """ Deletes a file from the datastore """
+ _remove_file(kwargs.get("name"))
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _just_return(self):
+ """ Fakes a return """
+ return
+
+ def _unregister_vm(self, method, *args, **kwargs):
+ """ Unregisters a VM from the Host System """
+ vm_ref = args[0]
+ _get_vm_mdo(vm_ref)
+ del _db_content["VirtualMachine"][vm_ref]
+
+ def _search_ds(self, method, *args, **kwargs):
+ """ Searches the datastore for a file """
+ ds_path = kwargs.get("datastorePath")
+ if _db_content.get("files", None) is None:
+ raise Exception(_("No files have been added yet"))
+ for file in _db_content.get("files"):
+ if file.find(ds_path) != -1:
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+ task_mdo = create_task(method, "error")
+ return task_mdo.obj
+
+ def _make_dir(self, method, *args, **kwargs):
+ """ Creates a directory in the datastore """
+ ds_path = kwargs.get("name")
+ if _db_content.get("files", None) is None:
+ raise Exception(_("No files have been added yet"))
+ _db_content["files"].append(ds_path)
+
+ def _set_power_state(self, method, vm_ref, pwr_state="poweredOn"):
+ """ Sets power state for the VM """
+ if _db_content.get("VirtualMachine", None) is None:
+ raise Exception(_(" No Virtual Machine has been registered yet"))
+ if vm_ref not in _db_content.get("VirtualMachine"):
+ raise Exception(_("Virtual Machine with ref %s is not there") %\
+ vm_ref)
+ vm_mdo = _db_content.get("VirtualMachine").get(vm_ref)
+ vm_mdo.set("runtime.powerState", pwr_state)
+ task_mdo = create_task(method, "success")
+ return task_mdo.obj
+
+ def _retrieve_properties(self, method, *args, **kwargs):
+ """ Retrieves properties based on the type """
+ spec_set = kwargs.get("specSet")[0]
+ type = spec_set.propSet[0].type
+ properties = spec_set.propSet[0].pathSet
+ objs = spec_set.objectSet
+ lst_ret_objs = []
+ for obj in objs:
+ try:
+ obj_ref = obj.obj
+ #This means that we are doing a search for the managed
+ #dataobects of the type in the inventory
+ if obj_ref == "RootFolder":
+ for mdo_ref in _db_content[type]:
+ mdo = _db_content[type][mdo_ref]
+ #Create a temp Managed object which has the same ref
+ #as the parent object and copies just the properties
+ #asked for. We need .obj along with the propSet of
+ #just the properties asked for
+ temp_mdo = ManagedObject(mdo.objName, mdo.obj)
+ for prop in properties:
+ temp_mdo.set(prop, mdo.get(prop))
+ lst_ret_objs.append(temp_mdo)
+ else:
+ if obj_ref in _db_content[type]:
+ mdo = _db_content[type][obj_ref]
+ temp_mdo = ManagedObject(mdo.objName, obj_ref)
+ for prop in properties:
+ temp_mdo.set(prop, mdo.get(prop))
+ lst_ret_objs.append(temp_mdo)
+ except Exception:
+ continue
+ return lst_ret_objs
+
+ def _add_port_group(self, method, *args, **kwargs):
+ """ Adds a port group to the host system """
+ host_mdo = \
+ _db_content["HostSystem"][_db_content["HostSystem"].keys()[0]]
+ host_mdo._add_port_group(kwargs.get("portgrp"))
+
+ def __getattr__(self, attr_name):
+ if attr_name != "Login":
+ self._check_session()
+ if attr_name == "Login":
+ return lambda *args, **kwargs: self._login()
+ elif attr_name == "Logout":
+ self._logout()
+ elif attr_name == "Terminate":
+ return lambda *args, **kwargs: self._terminate(*args, **kwargs)
+ elif attr_name == "CreateVM_Task":
+ return lambda *args, **kwargs: self._create_vm(attr_name,
+ *args, **kwargs)
+ elif attr_name == "ReconfigVM_Task":
+ return lambda *args, **kwargs: self._reconfig_vm(attr_name,
+ *args, **kwargs)
+ elif attr_name == "CreateVirtualDisk_Task":
+ return lambda *args, **kwargs: self._create_copy_disk(attr_name,
+ kwargs.get("name"))
+ elif attr_name == "DeleteDatastoreFile_Task":
+ return lambda *args, **kwargs: self._delete_file(attr_name,
+ *args, **kwargs)
+ elif attr_name == "PowerOnVM_Task":
+ return lambda *args, **kwargs: self._set_power_state(attr_name,
+ args[0], "poweredOn")
+ elif attr_name == "PowerOffVM_Task":
+ return lambda *args, **kwargs: self._set_power_state(attr_name,
+ args[0], "poweredOff")
+ elif attr_name == "RebootGuest":
+ return lambda *args, **kwargs: self._just_return()
+ elif attr_name == "ResetVM_Task":
+ return lambda *args, **kwargs: self._set_power_state(attr_name,
+ args[0], "poweredOn")
+ elif attr_name == "SuspendVM_Task":
+ return lambda *args, **kwargs: self._set_power_state(attr_name,
+ args[0], "suspended")
+ elif attr_name == "CreateSnapshot_Task":
+ return lambda *args, **kwargs: self._snapshot_vm(attr_name)
+ elif attr_name == "CopyVirtualDisk_Task":
+ return lambda *args, **kwargs: self._create_copy_disk(attr_name,
+ kwargs.get("destName"))
+ elif attr_name == "DeleteVirtualDisk_Task":
+ return lambda *args, **kwargs: self._delete_disk(attr_name,
+ *args, **kwargs)
+ elif attr_name == "UnregisterVM":
+ return lambda *args, **kwargs: self._unregister_vm(attr_name,
+ *args, **kwargs)
+ elif attr_name == "SearchDatastore_Task":
+ return lambda *args, **kwargs: self._search_ds(attr_name,
+ *args, **kwargs)
+ elif attr_name == "MakeDirectory":
+ return lambda *args, **kwargs: self._make_dir(attr_name,
+ *args, **kwargs)
+ elif attr_name == "RetrieveProperties":
+ return lambda *args, **kwargs: self._retrieve_properties(
+ attr_name, *args, **kwargs)
+ elif attr_name == "AcquireCloneTicket":
+ return lambda *args, **kwargs: self._just_return()
+ elif attr_name == "AddPortGroup":
+ return lambda *args, **kwargs: self._add_port_group(attr_name,
+ *args, **kwargs)
diff --git a/nova/virt/vmwareapi/io_util.py b/nova/virt/vmwareapi/io_util.py index b9645e220..edec3eb34 100644 --- a/nova/virt/vmwareapi/io_util.py +++ b/nova/virt/vmwareapi/io_util.py @@ -16,13 +16,8 @@ # under the License.
"""
-Helper classes for multi-threaded I/O (read/write) in the basis of chunks.
-
-The class ThreadSafePipe queues the chunk data.
-
-The class IOThread reads chunks from input file and pipes it to output file
-till it reaches the transferable size
-
+Reads a chunk from input file and writes the same to the output file till
+it reaches the transferable size
"""
from Queue import Empty
@@ -32,27 +27,26 @@ from threading import Thread import time
import traceback
-THREAD_SLEEP_TIME = .01
+THREAD_SLEEP_TIME = 0.01
class ThreadSafePipe(Queue):
- """ThreadSafePipe class queue's the chunk data."""
+ """ThreadSafePipe class queues the chunk data"""
def __init__(self, max_size=None):
- """Initializes the queue"""
Queue.__init__(self, max_size)
self.eof = False
def write(self, data):
- """Writes the chunk data to the queue."""
+ """Writes the chunk data to the queue"""
self.put(data, block=False)
def read(self):
- """Retrieves the chunk data from the queue."""
+ """Retrieves the chunk data from the queue"""
return self.get(block=False)
def set_eof(self, eof):
- """Sets EOF to mark reading of input file finishes."""
+ """Sets EOF to mark reading of input file finishes"""
self.eof = eof
def get_eof(self):
@@ -61,16 +55,11 @@ class ThreadSafePipe(Queue): class IOThread(Thread):
- """
- IOThread reads chunks from input file and pipes it to output file till it
- reaches the transferable size
+ """IOThread reads chunks from input file and pipes it to output file till
+ it reaches the transferable size
"""
def __init__(self, input_file, output_file, chunk_size, transfer_size):
- """
- Initialize the thread.
- inputFile and outputFile should be file like objects.
- """
Thread.__init__(self)
self.input_file = input_file
self.output_file = output_file
@@ -83,9 +72,8 @@ class IOThread(Thread): self._exception = None
def run(self):
- """
- Pipes the input chunk read to the output file till it reaches
- transferable size
+ """Pipes the input chunk read to the output file till it reaches
+ a transferable size
"""
try:
if self.transfer_size and self.transfer_size <= self.chunk_size:
@@ -131,10 +119,10 @@ class IOThread(Thread): if not self.transfer_size is None:
if self.read_size < self.transfer_size:
- raise IOError(_("Not enough data (%(read_size)d of "
- "%(transfer_size)d bytes)") %
- {'read_size': self.read_size,
- 'transfer_size': self.transfer_size})
+ raise IOError(_("Not enough data (%(read_size)d "
+ "of %(transfer_size)d bytes)") \
+ % ({'read_size': self.read_size,
+ 'transfer_size': self.transfer_size}))
except Exception:
self._error = True
@@ -142,18 +130,20 @@ class IOThread(Thread): self._done = True
def stop_io_transfer(self):
- """Set stop flag to true, which causes the thread to stop safely."""
+ """Set the stop flag to true, which causes the thread to stop
+ safely
+ """
self._stop_transfer = True
self.join()
def get_error(self):
- """Returns the error string."""
+ """Returns the error string"""
return self._error
def get_exception(self):
- """Returns the traceback exception string."""
+ """Returns the traceback exception string"""
return self._exception
def is_done(self):
- """Checks whether transfer is complete."""
+ """Checks whether transfer is complete"""
return self._done
diff --git a/nova/virt/vmwareapi/network_utils.py b/nova/virt/vmwareapi/network_utils.py new file mode 100644 index 000000000..6927b15ca --- /dev/null +++ b/nova/virt/vmwareapi/network_utils.py @@ -0,0 +1,117 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 Citrix Systems, Inc.
+# Copyright 2011 OpenStack LLC.
+#
+# 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.
+
+"""
+Utility functions for ESX Networking
+"""
+
+from nova import log as logging
+from nova.virt.vmwareapi import vim_util
+from nova.virt.vmwareapi import vm_util
+from nova.virt.vmwareapi.vim import VimException
+
+LOG = logging.getLogger("nova.virt.vmwareapi.network_utils")
+
+PORT_GROUP_EXISTS_EXCEPTION = \
+ 'The specified key, name, or identifier already exists.'
+
+
+class NetworkHelper:
+
+ @classmethod
+ def get_network_with_the_name(cls, session, network_name="vmnet0"):
+ """ Gets reference to the network whose name is passed as the
+ argument. """
+ datacenters = session._call_method(vim_util, "get_objects",
+ "Datacenter", ["network"])
+ vm_networks = datacenters[0].propSet[0].val.ManagedObjectReference
+ networks = session._call_method(vim_util,
+ "get_properites_for_a_collection_of_objects",
+ "Network", vm_networks, ["summary.name"])
+ for network in networks:
+ if network.propSet[0].val == network_name:
+ return network.obj
+ return None
+
+ @classmethod
+ def get_vswitches_for_vlan_interface(cls, session, vlan_interface):
+ """ Gets the list of vswitches associated with the physical
+ network adapter with the name supplied"""
+ #Get the list of vSwicthes on the Host System
+ host_mor = session._call_method(vim_util, "get_objects",
+ "HostSystem")[0].obj
+ vswitches = session._call_method(vim_util,
+ "get_dynamic_property", host_mor,
+ "HostSystem", "config.network.vswitch").HostVirtualSwitch
+ vswicthes_conn_to_physical_nic = []
+ #For each vSwitch check if it is associated with the network adapter
+ for elem in vswitches:
+ try:
+ for nic_elem in elem.pnic:
+ if str(nic_elem).split('-')[-1].find(vlan_interface) != -1:
+ vswicthes_conn_to_physical_nic.append(elem.name)
+ except Exception:
+ pass
+ return vswicthes_conn_to_physical_nic
+
+ @classmethod
+ def check_if_vlan_id_is_proper(cls, session, pg_name, vlan_id):
+ """ Check if the vlan id associated with the port group matches the
+ vlan tag supplied """
+ host_mor = session._call_method(vim_util, "get_objects",
+ "HostSystem")[0].obj
+ port_grps_on_host = session._call_method(vim_util,
+ "get_dynamic_property", host_mor,
+ "HostSystem", "config.network.portgroup").HostPortGroup
+ for p_gp in port_grps_on_host:
+ if p_gp.spec.name == pg_name:
+ if p_gp.spec.vlanId == vlan_id:
+ return True, vlan_id
+ else:
+ return False, p_gp.spec.vlanId
+
+ @classmethod
+ def create_port_group(cls, session, pg_name, vswitch_name, vlan_id=0):
+ """ Creates a port group on the host system with the vlan tags
+ supplied. VLAN id 0 means no vlan id association """
+ client_factory = session._get_vim().client.factory
+ add_prt_grp_spec = vm_util.get_add_vswitch_port_group_spec(
+ client_factory,
+ vswitch_name,
+ pg_name,
+ vlan_id)
+ host_mor = session._call_method(vim_util, "get_objects",
+ "HostSystem")[0].obj
+ network_system_mor = session._call_method(vim_util,
+ "get_dynamic_property", host_mor,
+ "HostSystem", "configManager.networkSystem")
+ LOG.debug(_("Creating Port Group with name %s on "
+ "the ESX host") % pg_name)
+ try:
+ session._call_method(session._get_vim(),
+ "AddPortGroup", network_system_mor,
+ portgrp=add_prt_grp_spec)
+ except VimException, exc:
+ #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
+ #concerned with the port group being created, which is done
+ #by the other call, we can ignore the exception.
+ if str(exc).find(PORT_GROUP_EXISTS_EXCEPTION) == -1:
+ raise Exception(exc)
+ LOG.debug(_("Created Port Group with name %s on "
+ "the ESX host") % pg_name)
diff --git a/nova/virt/vmwareapi/read_write_util.py b/nova/virt/vmwareapi/read_write_util.py index 45214be04..37f80c133 100644 --- a/nova/virt/vmwareapi/read_write_util.py +++ b/nova/virt/vmwareapi/read_write_util.py @@ -20,20 +20,15 @@ Collection of classes to handle image upload/download to/from Image service
(like Glance image storage and retrieval service) from/to ESX/ESXi server.
-Also a class is available that acts as Fake image service. It uses local
-file system for storage.
-
"""
import httplib
-import json
-import logging
-import os
import urllib
import urllib2
import urlparse
from nova import flags
+from nova import log as logging
from nova import utils
from nova.auth.manager import AuthManager
@@ -47,10 +42,9 @@ LOG = logging.getLogger("nova.virt.vmwareapi.read_write_util") class ImageServiceFile:
- """The base image service Class"""
+ """The base image service class"""
def __init__(self, file_handle):
- """Initialize the file handle."""
self.eof = False
self.file_handle = file_handle
@@ -67,15 +61,15 @@ class ImageServiceFile: raise NotImplementedError
def set_eof(self, eof):
- """Set the end of file marker."""
+ """Set the end of file marker"""
self.eof = eof
def get_eof(self):
- """Check if the file end has been reached or not."""
+ """Check if the file end has been reached or not"""
return self.eof
def close(self):
- """Close the file handle."""
+ """Close the file handle"""
try:
self.file_handle.close()
except Exception:
@@ -86,16 +80,15 @@ class ImageServiceFile: raise NotImplementedError
def __del__(self):
- """Destructor. Close the file handle if the same has been forgotten."""
+ """Close the file handle on garbage collection"""
self.close()
class GlanceHTTPWriteFile(ImageServiceFile):
- """Glance file write handler Class"""
+ """Glance file write handler class"""
def __init__(self, host, port, image_id, file_size, os_type, adapter_type,
version=1, scheme="http"):
- """Initialize with the glance host specifics."""
base_url = "%s://%s:%s/images/%s" % (scheme, host, port, image_id)
(scheme, netloc, path, params, query, fragment) = \
urlparse.urlparse(base_url)
@@ -126,10 +119,9 @@ class GlanceHTTPWriteFile(ImageServiceFile): class GlanceHTTPReadFile(ImageServiceFile):
- """Glance file read handler Class"""
+ """Glance file read handler class"""
def __init__(self, host, port, image_id, scheme="http"):
- """Initialize with the glance host specifics."""
base_url = "%s://%s:%s/images/%s" % (scheme, host, port,
urllib.pathname2url(image_id))
headers = {'User-Agent': USER_AGENT}
@@ -138,15 +130,17 @@ class GlanceHTTPReadFile(ImageServiceFile): ImageServiceFile.__init__(self, conn)
def read(self, chunk_size=READ_CHUNKSIZE):
- """Read a chunk of data."""
+ """Read a chunk of data"""
return self.file_handle.read(chunk_size)
def get_size(self):
- """Get the size of the file to be read."""
+ """Get the size of the file to be read"""
return self.file_handle.headers.get("X-Image-Meta-Size", -1)
def get_image_properties(self):
- """Get the image properties like say OS Type and the Adapter Type"""
+ """Get the image properties like say OS Type and the
+ Adapter Type
+ """
return {"vmware_ostype":
self.file_handle.headers.get(
"X-Image-Meta-Property-Vmware_ostype"),
@@ -158,95 +152,58 @@ class GlanceHTTPReadFile(ImageServiceFile): "X-Image-Meta-Property-Vmware_image_version")}
-class FakeFileRead(ImageServiceFile):
- """Local file read handler class"""
-
- def __init__(self, path):
- """Initialize the file path"""
- self.path = path
- file_handle = open(path, "rb")
- ImageServiceFile.__init__(self, file_handle)
-
- def get_size(self):
- """Get size of the file to be read"""
- return os.path.getsize(os.path.abspath(self.path))
-
- def read(self, chunk_size=READ_CHUNKSIZE):
- """Read a chunk of data"""
- return self.file_handle.read(chunk_size)
-
- def get_image_properties(self):
- """Get the image properties like say OS Type and the Adapter Type"""
- return {"vmware_ostype": "otherGuest",
- "vmware_adaptertype": "lsiLogic",
- "vmware_image_version": "1"}
-
-
-class FakeFileWrite(ImageServiceFile):
- """Local file write handler Class"""
-
- def __init__(self, path):
- """Initialize the file path."""
- file_handle = open(path, "wb")
- ImageServiceFile.__init__(self, file_handle)
-
- def write(self, data):
- """Write data to the file."""
- self.file_handle.write(data)
-
-
class VMwareHTTPFile(object):
- """Base Class for HTTP file."""
+ """Base class for HTTP file"""
def __init__(self, file_handle):
- """Intialize the file handle."""
self.eof = False
self.file_handle = file_handle
def set_eof(self, eof):
- """Set the end of file marker."""
+ """Set the end of file marker"""
self.eof = eof
def get_eof(self):
- """Check if the end of file has been reached."""
+ """Check if the end of file has been reached"""
return self.eof
def close(self):
- """Close the file handle."""
+ """Close the file handle"""
try:
self.file_handle.close()
except Exception:
pass
def __del__(self):
- """Destructor. Close the file handle if the same has been forgotten."""
+ """Close the file handle on garbage collection"""
self.close()
def _build_vim_cookie_headers(self, vim_cookies):
- """Build ESX host session cookie headers."""
- cookie = str(vim_cookies).split(":")[1].strip()
- cookie = cookie[:cookie.find(';')]
- return cookie
+ """Build ESX host session cookie headers"""
+ cookie_header = ""
+ for vim_cookie in vim_cookies:
+ cookie_header = vim_cookie.name + "=" + vim_cookie.value
+ break
+ return cookie_header
def write(self, data):
- """Write data to the file."""
+ """Write data to the file"""
raise NotImplementedError
def read(self, chunk_size=READ_CHUNKSIZE):
- """Read a chunk of data."""
+ """Read a chunk of data"""
raise NotImplementedError
def get_size(self):
- """Get size of the file to be read."""
+ """Get size of the file to be read"""
raise NotImplementedError
class VMWareHTTPWriteFile(VMwareHTTPFile):
- """VMWare file write handler Class"""
+ """VMWare file write handler class"""
def __init__(self, host, data_center_name, datastore_name, cookies,
file_path, file_size, scheme="https"):
- """Initialize the file specifics."""
base_url = "%s://%s/folder/%s" % (scheme, host, file_path)
param_list = {"dcPath": data_center_name, "dsName": datastore_name}
base_url = base_url + "?" + urllib.urlencode(param_list)
@@ -265,7 +222,7 @@ class VMWareHTTPWriteFile(VMwareHTTPFile): VMwareHTTPFile.__init__(self, conn)
def write(self, data):
- """Write to the file."""
+ """Write to the file"""
self.file_handle.send(data)
def close(self):
@@ -273,17 +230,16 @@ class VMWareHTTPWriteFile(VMwareHTTPFile): try:
self.conn.getresponse()
except Exception, excep:
- LOG.debug(_("Exception during close of connection in "
+ LOG.debug(_("Exception during HTTP connection close in "
"VMWareHTTpWrite. Exception is %s") % excep)
super(VMWareHTTPWriteFile, self).close()
class VmWareHTTPReadFile(VMwareHTTPFile):
- """VMWare file read handler Class"""
+ """VMWare file read handler class"""
def __init__(self, host, data_center_name, datastore_name, cookies,
file_path, scheme="https"):
- """Initialize the file specifics."""
base_url = "%s://%s/folder/%s" % (scheme, host,
urllib.pathname2url(file_path))
param_list = {"dcPath": data_center_name, "dsName": datastore_name}
@@ -295,9 +251,9 @@ class VmWareHTTPReadFile(VMwareHTTPFile): VMwareHTTPFile.__init__(self, conn)
def read(self, chunk_size=READ_CHUNKSIZE):
- """Read a chunk of data."""
+ """Read a chunk of data"""
return self.file_handle.read(chunk_size)
def get_size(self):
- """Get size of the file to be read."""
+ """Get size of the file to be read"""
return self.file_handle.headers.get("Content-Length", -1)
diff --git a/nova/virt/vmwareapi/vim.py b/nova/virt/vmwareapi/vim.py index 9aca1b7ae..6a3e4b376 100644 --- a/nova/virt/vmwareapi/vim.py +++ b/nova/virt/vmwareapi/vim.py @@ -16,32 +16,39 @@ # under the License.
"""
-Class facilitating SOAP calls to ESX/ESXi server
-
+Classes for making VMware VI SOAP calls
"""
import httplib
-import ZSI
+from suds.client import Client
+from suds.plugin import MessagePlugin
+from suds.sudsobject import Property
-from nova.virt.vmwareapi import VimService_services
+from nova import flags
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'
+FLAGS = flags.FLAGS
+flags.DEFINE_string('vmwareapi_wsdl_loc',
+ None,
+ 'VIM Service WSDL Location'
+ 'E.g http://<server>/vimService.wsdl'
+ 'Due to a bug in vSphere ESX 4.1 default wsdl'
+ 'Read the readme for vmware to setup')
+
class VimException(Exception):
"""The VIM Exception class"""
def __init__(self, exception_summary, excep):
- """Initializer"""
Exception.__init__(self)
self.exception_summary = exception_summary
self.exception_obj = excep
def __str__(self):
- """The informal string representation of the object"""
return self.exception_summary + str(self.exception_obj)
@@ -56,38 +63,53 @@ class SessionFaultyException(VimException): class VimAttributeError(VimException):
- """Attribute Error"""
+ """VI Attribute Error"""
pass
+class VIMMessagePlugin(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",
- trace=None):
+ host="localhost"):
"""
- Initializer
-
protocol: http or https
host : ESX IPAddress[:port] or ESX Hostname[:port]
- trace : File handle (eg. sys.stdout, sys.stderr ,
- open("file.txt",w), Use it only for debugging
- SOAP Communication
Creates the necessary Communication interfaces, Gets the
ServiceContent for initiating SOAP transactions
"""
self._protocol = protocol
self._host_name = host
- service_locator = VimService_services.VimServiceLocator()
- connect_string = "%s://%s/sdk" % (self._protocol, self._host_name)
- if trace == None:
- self.proxy = \
- service_locator.getVimPortType(url=connect_string)
- else:
- self.proxy = service_locator.getVimPortType(url=connect_string,
- tracefile=trace)
+ wsdl_url = FLAGS.vmwareapi_wsdl_loc
+ if wsdl_url is None:
+ raise Exception(_("Must specify vmwareapi_wsdl_loc"))
+ #Use this when VMware fixes their faulty wsdl
+ #wsdl_url = '%s://%s/sdk/vimService.wsdl' % (self._protocol,
+ # self._host_name)
+ url = '%s://%s/sdk' % (self._protocol, self._host_name)
+ self.client = Client(wsdl_url, location=url,
+ plugins=[VIMMessagePlugin()])
self._service_content = \
self.RetrieveServiceContent("ServiceInstance")
@@ -102,45 +124,29 @@ class Vim: except AttributeError:
def vim_request_handler(managed_object, **kwargs):
- """
- managed_object : Managed Object Reference or Managed
+ """managed_object : Managed Object Reference or Managed
Object Name
**kw : Keyword arguments of the call
"""
#Dynamic handler for VI SDK Calls
- response = None
try:
- request_msg = \
- self._request_message_builder(attr_name,
- managed_object, **kwargs)
- request = getattr(self.proxy, attr_name)
- response = request(request_msg)
- if response == None:
- return None
- else:
- try:
- return getattr(response, "_returnval")
- except AttributeError, excep:
- return None
+ request_mo = \
+ self._request_managed_object_builder(managed_object)
+ request = getattr(self.client.service, attr_name)
+ return request(request_mo, **kwargs)
except AttributeError, excep:
raise VimAttributeError(_("No such SOAP method '%s'"
" provided by VI SDK") % (attr_name), excep)
- except ZSI.FaultException, excep:
- raise SessionFaultyException(_("<ZSI.FaultException> in"
- " %s:") % (attr_name), excep)
- except ZSI.EvaluateException, excep:
- raise SessionFaultyException(_("<ZSI.EvaluateException> in"
- " %s:") % (attr_name), excep)
except (httplib.CannotSendRequest,
httplib.ResponseNotReady,
httplib.CannotSendHeader), excep:
- raise SessionOverLoadException(_("httplib errror in"
+ raise SessionOverLoadException(_("httplib error in"
" %s: ") % (attr_name), excep)
except Exception, excep:
# Socket errors which need special handling for they
# might be caused by ESX API call overload
if (str(excep).find(ADDRESS_IN_USE_ERROR) != -1 or
- str(excep).find(CONN_ABORT_ERROR)):
+ str(excep).find(CONN_ABORT_ERROR)) != -1:
raise SessionOverLoadException(_("Socket error in"
" %s: ") % (attr_name), excep)
# Type error that needs special handling for it might be
@@ -153,25 +159,18 @@ class Vim: _("Exception in %s ") % (attr_name), excep)
return vim_request_handler
- def _request_message_builder(self, method_name, managed_object, **kwargs):
- """Builds the Request Message"""
- #Request Message Builder
- request_msg = getattr(VimService_services, \
- method_name + "RequestMsg")()
- element = request_msg.new__this(managed_object)
+ def _request_managed_object_builder(self, managed_object):
+ """Builds the request managed object"""
+ #Request Managed Object Builder
if type(managed_object) == type(""):
- element.set_attribute_type(managed_object)
+ mo = Property(managed_object)
+ mo._type = managed_object
else:
- element.set_attribute_type(managed_object.get_attribute_type())
- request_msg.set_element__this(element)
- for key in kwargs:
- getattr(request_msg, "set_element_" + key)(kwargs[key])
- return request_msg
+ mo = managed_object
+ return mo
def __repr__(self):
- """The official string representation"""
return "VIM Object"
def __str__(self):
- """The informal string representation"""
return "VIM Object"
diff --git a/nova/virt/vmwareapi/vim_util.py b/nova/virt/vmwareapi/vim_util.py index d07f7c278..619ad3c0b 100644 --- a/nova/virt/vmwareapi/vim_util.py +++ b/nova/virt/vmwareapi/vim_util.py @@ -17,178 +17,163 @@ """
The VMware API utility module
-
"""
-from nova.virt.vmwareapi.VimService_services_types import ns0
-
-MAX_CLONE_RETRIES = 1
-
-def build_recursive_traversal_spec():
+def build_recursive_traversal_spec(client_factory):
"""Builds the Traversal Spec"""
#Traversal through "hostFolder" branch
- visit_folders_select_spec = ns0.SelectionSpec_Def("visitFolders").pyclass()
- visit_folders_select_spec.set_element_name("visitFolders")
- select_set = [visit_folders_select_spec]
- dc_to_hf = ns0.TraversalSpec_Def("dc_to_hf").pyclass()
- dc_to_hf.set_element_name("dc_to_hf")
- dc_to_hf.set_element_type("Datacenter")
- dc_to_hf.set_element_path("hostFolder")
- dc_to_hf.set_element_skip(False)
- dc_to_hf.set_element_selectSet(select_set)
+ visit_folders_select_spec = client_factory.create('ns0:SelectionSpec')
+ visit_folders_select_spec.name = "visitFolders"
+ dc_to_hf = client_factory.create('ns0:TraversalSpec')
+ dc_to_hf.name = "dc_to_hf"
+ dc_to_hf.type = "Datacenter"
+ dc_to_hf.path = "hostFolder"
+ dc_to_hf.skip = False
+ dc_to_hf.selectSet = [visit_folders_select_spec]
#Traversal through "vmFolder" branch
- visit_folders_select_spec = ns0.SelectionSpec_Def("visitFolders").pyclass()
- visit_folders_select_spec.set_element_name("visitFolders")
- select_set = [visit_folders_select_spec]
- dc_to_vmf = ns0.TraversalSpec_Def("dc_to_vmf").pyclass()
- dc_to_vmf.set_element_name("dc_to_vmf")
- dc_to_vmf.set_element_type("Datacenter")
- dc_to_vmf.set_element_path("vmFolder")
- dc_to_vmf.set_element_skip(False)
- dc_to_vmf.set_element_selectSet(select_set)
+ visit_folders_select_spec = client_factory.create('ns0:SelectionSpec')
+ visit_folders_select_spec.name = "visitFolders"
+ dc_to_vmf = client_factory.create('ns0:TraversalSpec')
+ dc_to_vmf.name = "dc_to_vmf"
+ dc_to_vmf.type = "Datacenter"
+ dc_to_vmf.path = "vmFolder"
+ dc_to_vmf.skip = False
+ dc_to_vmf.selectSet = [visit_folders_select_spec]
#Traversal to the DataStore from the DataCenter
visit_folders_select_spec = \
- ns0.SelectionSpec_Def("traverseChild").pyclass()
- visit_folders_select_spec.set_element_name("traverseChild")
- select_set = [visit_folders_select_spec]
- dc_to_ds = ns0.TraversalSpec_Def("dc_to_ds").pyclass()
- dc_to_ds.set_element_name("dc_to_ds")
- dc_to_ds.set_element_type("Datacenter")
- dc_to_ds.set_element_path("datastore")
- dc_to_ds.set_element_skip(False)
- dc_to_ds.set_element_selectSet(select_set)
+ client_factory.create('ns0:SelectionSpec')
+ visit_folders_select_spec.name = "traverseChild"
+ dc_to_ds = client_factory.create('ns0:TraversalSpec')
+ dc_to_ds.name = "dc_to_ds"
+ dc_to_ds.type = "Datacenter"
+ dc_to_ds.path = "datastore"
+ dc_to_ds.skip = False
+ dc_to_ds.selectSet = [visit_folders_select_spec]
#Traversal through "vm" branch
visit_folders_select_spec = \
- ns0.SelectionSpec_Def("visitFolders").pyclass()
- visit_folders_select_spec.set_element_name("visitFolders")
- select_set = [visit_folders_select_spec]
- h_to_vm = ns0.TraversalSpec_Def("h_to_vm").pyclass()
- h_to_vm.set_element_name("h_to_vm")
- h_to_vm.set_element_type("HostSystem")
- h_to_vm.set_element_path("vm")
- h_to_vm.set_element_skip(False)
- h_to_vm.set_element_selectSet(select_set)
+ client_factory.create('ns0:SelectionSpec')
+ visit_folders_select_spec.name = "visitFolders"
+ h_to_vm = client_factory.create('ns0:TraversalSpec')
+ h_to_vm.name = "h_to_vm"
+ h_to_vm.type = "HostSystem"
+ h_to_vm.path = "vm"
+ h_to_vm.skip = False
+ h_to_vm.selectSet = [visit_folders_select_spec]
#Traversal through "host" branch
- cr_to_h = ns0.TraversalSpec_Def("cr_to_h").pyclass()
- cr_to_h.set_element_name("cr_to_h")
- cr_to_h.set_element_type("ComputeResource")
- cr_to_h.set_element_path("host")
- cr_to_h.set_element_skip(False)
- cr_to_h.set_element_selectSet([])
-
- cr_to_ds = ns0.TraversalSpec_Def("cr_to_ds").pyclass()
- cr_to_ds.set_element_name("cr_to_ds")
- cr_to_ds.set_element_type("ComputeResource")
- cr_to_ds.set_element_path("datastore")
- cr_to_ds.set_element_skip(False)
+ cr_to_h = client_factory.create('ns0:TraversalSpec')
+ cr_to_h.name = "cr_to_h"
+ cr_to_h.type = "ComputeResource"
+ cr_to_h.path = "host"
+ cr_to_h.skip = False
+ cr_to_h.selectSet = []
+
+ cr_to_ds = client_factory.create('ns0:TraversalSpec')
+ cr_to_ds.name = "cr_to_ds"
+ cr_to_ds.type = "ComputeResource"
+ cr_to_ds.path = "datastore"
+ cr_to_ds.skip = False
#Traversal through "resourcePool" branch
- rp_to_rp_select_spec = ns0.SelectionSpec_Def("rp_to_rp").pyclass()
- rp_to_rp_select_spec.set_element_name("rp_to_rp")
- rp_to_vm_select_spec = ns0.SelectionSpec_Def("rp_to_vm").pyclass()
- rp_to_vm_select_spec.set_element_name("rp_to_vm")
- select_set = [rp_to_rp_select_spec, rp_to_vm_select_spec]
- cr_to_rp = ns0.TraversalSpec_Def("cr_to_rp").pyclass()
- cr_to_rp.set_element_name("cr_to_rp")
- cr_to_rp.set_element_type("ComputeResource")
- cr_to_rp.set_element_path("resourcePool")
- cr_to_rp.set_element_skip(False)
- cr_to_rp.set_element_selectSet(select_set)
+ rp_to_rp_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_rp_select_spec.name = "rp_to_rp"
+ rp_to_vm_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_vm_select_spec.name = "rp_to_vm"
+ cr_to_rp = client_factory.create('ns0:TraversalSpec')
+ cr_to_rp.name = "cr_to_rp"
+ cr_to_rp.type = "ComputeResource"
+ cr_to_rp.path = "resourcePool"
+ cr_to_rp.skip = False
+ cr_to_rp.selectSet = [rp_to_rp_select_spec, rp_to_vm_select_spec]
#Traversal through all ResourcePools
- rp_to_rp_select_spec = ns0.SelectionSpec_Def("rp_to_rp").pyclass()
- rp_to_rp_select_spec.set_element_name("rp_to_rp")
- rp_to_vm_select_spec = ns0.SelectionSpec_Def("rp_to_vm").pyclass()
- rp_to_vm_select_spec.set_element_name("rp_to_vm")
- select_set = [rp_to_rp_select_spec, rp_to_vm_select_spec]
- rp_to_rp = ns0.TraversalSpec_Def("rp_to_rp").pyclass()
- rp_to_rp.set_element_name("rp_to_rp")
- rp_to_rp.set_element_type("ResourcePool")
- rp_to_rp.set_element_path("resourcePool")
- rp_to_rp.set_element_skip(False)
- rp_to_rp.set_element_selectSet(select_set)
+ rp_to_rp_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_rp_select_spec.name = "rp_to_rp"
+ rp_to_vm_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_vm_select_spec.name = "rp_to_vm"
+ rp_to_rp = client_factory.create('ns0:TraversalSpec')
+ rp_to_rp.name = "rp_to_rp"
+ rp_to_rp.type = "ResourcePool"
+ rp_to_rp.path = "resourcePool"
+ rp_to_rp.skip = False
+ rp_to_rp.selectSet = [rp_to_rp_select_spec, rp_to_vm_select_spec]
#Traversal through ResourcePools vm folders
- rp_to_rp_select_spec = ns0.SelectionSpec_Def("rp_to_rp").pyclass()
- rp_to_rp_select_spec.set_element_name("rp_to_rp")
- rp_to_vm_select_spec = ns0.SelectionSpec_Def("rp_to_vm").pyclass()
- rp_to_vm_select_spec.set_element_name("rp_to_vm")
- select_set = [rp_to_rp_select_spec, rp_to_vm_select_spec]
- rp_to_vm = ns0.TraversalSpec_Def("rp_to_vm").pyclass()
- rp_to_vm.set_element_name("rp_to_vm")
- rp_to_vm.set_element_type("ResourcePool")
- rp_to_vm.set_element_path("vm")
- rp_to_vm.set_element_skip(False)
- rp_to_vm.set_element_selectSet(select_set)
+ rp_to_rp_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_rp_select_spec.name = "rp_to_rp"
+ rp_to_vm_select_spec = client_factory.create('ns0:SelectionSpec')
+ rp_to_vm_select_spec.name = "rp_to_vm"
+ rp_to_vm = client_factory.create('ns0:TraversalSpec')
+ rp_to_vm.name = "rp_to_vm"
+ rp_to_vm.type = "ResourcePool"
+ rp_to_vm.path = "vm"
+ rp_to_vm.skip = False
+ rp_to_vm.selectSet = [rp_to_rp_select_spec, rp_to_vm_select_spec]
#Include all Traversals and Recurse into them
visit_folders_select_spec = \
- ns0.SelectionSpec_Def("visitFolders").pyclass()
- visit_folders_select_spec.set_element_name("visitFolders")
- select_set = [visit_folders_select_spec, dc_to_hf, dc_to_vmf,
+ client_factory.create('ns0:SelectionSpec')
+ visit_folders_select_spec.name = "visitFolders"
+ traversal_spec = client_factory.create('ns0:TraversalSpec')
+ traversal_spec.name = "visitFolders"
+ traversal_spec.type = "Folder"
+ traversal_spec.path = "childEntity"
+ traversal_spec.skip = False
+ traversal_spec.selectSet = [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]
- traversal_spec = ns0.TraversalSpec_Def("visitFolders").pyclass()
- traversal_spec.set_element_name("visitFolders")
- traversal_spec.set_element_type("Folder")
- traversal_spec.set_element_path("childEntity")
- traversal_spec.set_element_skip(False)
- traversal_spec.set_element_selectSet(select_set)
return traversal_spec
-def build_property_spec(type="VirtualMachine", properties_to_collect=["name"],
+def build_property_spec(client_factory, type="VirtualMachine",
+ properties_to_collect=["name"],
all_properties=False):
"""Builds the Property Spec"""
- property_spec = ns0.PropertySpec_Def("propertySpec").pyclass()
- property_spec.set_element_type(type)
- property_spec.set_element_all(all_properties)
- property_spec.set_element_pathSet(properties_to_collect)
+ 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(root_folder, traversal_specs):
+def build_object_spec(client_factory, root_folder, traversal_specs):
"""Builds the object Spec"""
- object_spec = ns0.ObjectSpec_Def("ObjectSpec").pyclass()
- object_spec.set_element_obj(root_folder)
- object_spec.set_element_skip(False)
- object_spec.set_element_selectSet(traversal_specs)
+ 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(property_specs, object_specs):
+def build_property_filter_spec(client_factory, property_specs, object_specs):
"""Builds the Property Filter Spec"""
- property_filter_spec = \
- ns0.PropertyFilterSpec_Def("PropertyFilterSpec").pyclass()
- property_filter_spec.set_element_propSet(property_specs)
- property_filter_spec.set_element_objectSet(object_specs)
+ 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_object_properties(vim, collector, mobj, type, properties):
"""Gets the properties of the Managed object specified"""
+ client_factory = vim.client.factory
if mobj is None:
return None
usecoll = collector
if usecoll is None:
- usecoll = vim.get_service_content().PropertyCollector
- property_filter_spec = \
- ns0.PropertyFilterSpec_Def("PropertyFilterSpec").pyclass()
- property_filter_spec._propSet = \
- [ns0.PropertySpec_Def("PropertySpec").pyclass()]
- property_filter_spec.PropSet[0]._all = \
- (properties == None or len(properties) == 0)
- property_filter_spec.PropSet[0]._type = type
- property_filter_spec.PropSet[0]._pathSet = properties
-
- property_filter_spec._objectSet = \
- [ns0.ObjectSpec_Def("ObjectSpec").pyclass()]
- property_filter_spec.ObjectSet[0]._obj = mobj
- property_filter_spec.ObjectSet[0]._skip = False
+ usecoll = vim.get_service_content().propertyCollector
+ property_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
+ property_spec = client_factory.create('ns0:PropertySpec')
+ property_spec.all = (properties == None or len(properties) == 0)
+ property_spec.pathSet = properties
+ property_spec.type = type
+ object_spec = client_factory.create('ns0:ObjectSpec')
+ object_spec.obj = mobj
+ object_spec.skip = False
+ property_filter_spec.propSet = [property_spec]
+ property_filter_spec.objectSet = [object_spec]
return vim.RetrieveProperties(usecoll, specSet=[property_filter_spec])
@@ -198,74 +183,68 @@ def get_dynamic_property(vim, mobj, type, property_name): get_object_properties(vim, None, mobj, type, [property_name])
property_value = None
if obj_content:
- dynamic_property = obj_content[0].PropSet
+ dynamic_property = obj_content[0].propSet
if dynamic_property:
- property_value = dynamic_property[0].Val
+ property_value = dynamic_property[0].val
return property_value
def get_objects(vim, type, properties_to_collect=["name"], all=False):
"""Gets the list of objects of the type specified"""
- object_spec = build_object_spec(vim.get_service_content().RootFolder,
- [build_recursive_traversal_spec()])
- property_spec = build_property_spec(type=type,
+ 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([property_spec],
+ property_filter_spec = build_property_filter_spec(client_factory,
+ [property_spec],
[object_spec])
- return vim.RetrieveProperties(vim.get_service_content().PropertyCollector,
+ return vim.RetrieveProperties(vim.get_service_content().propertyCollector,
specSet=[property_filter_spec])
-def get_traversal_spec(type, path, name="traversalSpec"):
- """Builds the traversal spec object"""
- t_spec = ns0.TraversalSpec_Def(name).pyclass()
- t_spec._name = name
- t_spec._type = type
- t_spec._path = path
- t_spec._skip = False
- return t_spec
-
-
-def get_prop_spec(type, properties):
+def get_prop_spec(client_factory, type, properties):
"""Builds the Property Spec Object"""
- prop_spec = ns0.PropertySpec_Def("PropertySpec").pyclass()
- prop_spec._type = type
- prop_spec._pathSet = properties
+ prop_spec = client_factory.create('ns0:PropertySpec')
+ prop_spec.type = type
+ prop_spec.pathSet = properties
return prop_spec
-def get_obj_spec(obj, select_set=None):
+def get_obj_spec(client_factory, obj, select_set=None):
"""Builds the Object Spec object"""
- obj_spec = ns0.ObjectSpec_Def("ObjectSpec").pyclass()
- obj_spec._obj = obj
- obj_spec._skip = False
+ obj_spec = client_factory.create('ns0:ObjectSpec')
+ obj_spec.obj = obj
+ obj_spec.skip = False
if select_set is not None:
- obj_spec._selectSet = select_set
+ obj_spec.selectSet = select_set
return obj_spec
-def get_prop_filter_spec(obj_spec, prop_spec):
+def get_prop_filter_spec(client_factory, obj_spec, prop_spec):
"""Builds the Property Filter Spec Object"""
prop_filter_spec = \
- ns0.PropertyFilterSpec_Def("PropertyFilterSpec").pyclass()
- prop_filter_spec._propSet = prop_spec
- prop_filter_spec._objectSet = obj_spec
+ client_factory.create('ns0:PropertyFilterSpec')
+ prop_filter_spec.propSet = prop_spec
+ prop_filter_spec.objectSet = obj_spec
return prop_filter_spec
def get_properites_for_a_collection_of_objects(vim, type,
obj_list, properties):
+ """Gets the list of properties for the collection of
+ objects of the type specified
"""
- Gets the list of properties for the collection of objects of the
- type specified
- """
+ client_factory = vim.client.factory
if len(obj_list) == 0:
return []
- prop_spec = get_prop_spec(type, properties)
+ prop_spec = get_prop_spec(client_factory, type, properties)
lst_obj_specs = []
for obj in obj_list:
- lst_obj_specs.append(get_obj_spec(obj))
- prop_filter_spec = get_prop_filter_spec(lst_obj_specs, [prop_spec])
- return vim.RetrieveProperties(vim.get_service_content().PropertyCollector,
+ lst_obj_specs.append(get_obj_spec(client_factory, obj))
+ prop_filter_spec = get_prop_filter_spec(client_factory,
+ lst_obj_specs, [prop_spec])
+ return vim.RetrieveProperties(vim.get_service_content().propertyCollector,
specSet=[prop_filter_spec])
diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py index 05e49de83..a46b4d10c 100644 --- a/nova/virt/vmwareapi/vm_util.py +++ b/nova/virt/vmwareapi/vm_util.py @@ -14,24 +14,19 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
"""
-Utility functions to handle virtual disks, virtual network adapters, VMs etc.
-
+The VMware API VM utility module to build SOAP object specs
"""
-from nova.virt.vmwareapi.VimService_services_types import ns0
-
def build_datastore_path(datastore_name, path):
- """Builds the datastore compliant path."""
+ """Build the datastore compliant path"""
return "[%s] %s" % (datastore_name, path)
def split_datastore_path(datastore_path):
- """
- Split the VMWare style datastore path to get the Datastore name and the
- entity path
+ """Split the VMWare style datastore path to get the Datastore
+ name and the entity path
"""
spl = datastore_path.split('[', 1)[1].split(']', 1)
path = ""
@@ -42,117 +37,95 @@ def split_datastore_path(datastore_path): return datastore_url, path.strip()
-def get_vm_create_spec(instance, data_store_name, network_name="vmnet0",
+def get_vm_create_spec(client_factory, instance, data_store_name,
+ network_name="vmnet0",
os_type="otherGuest"):
- """Builds the VM Create spec."""
- config_spec = ns0.VirtualMachineConfigSpec_Def(
- "VirtualMachineConfigSpec").pyclass()
-
- config_spec._name = instance.name
- config_spec._guestId = os_type
+ """Builds the VM Create spec"""
+ config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
+ config_spec.name = instance.name
+ config_spec.guestId = os_type
- vm_file_info = ns0.VirtualMachineFileInfo_Def(
- "VirtualMachineFileInfo").pyclass()
- vm_file_info._vmPathName = "[" + data_store_name + "]"
- config_spec._files = vm_file_info
+ vm_file_info = client_factory.create('ns0:VirtualMachineFileInfo')
+ vm_file_info.vmPathName = "[" + data_store_name + "]"
+ config_spec.files = vm_file_info
- tools_info = ns0.ToolsConfigInfo_Def("ToolsConfigInfo")
- tools_info._afterPowerOn = True
- tools_info._afterResume = True
- tools_info._beforeGuestStandby = True
- tools_info._bbeforeGuestShutdown = True
- tools_info._beforeGuestReboot = True
+ tools_info = client_factory.create('ns0:ToolsConfigInfo')
+ tools_info.afterPowerOn = True
+ tools_info.afterResume = True
+ tools_info.beforeGuestStandby = True
+ tools_info.beforeGuestShutdown = True
+ tools_info.beforeGuestReboot = True
- config_spec._tools = tools_info
- config_spec._numCPUs = int(instance.vcpus)
- config_spec._memoryMB = int(instance.memory_mb)
+ config_spec.tools = tools_info
+ config_spec.numCPUs = int(instance.vcpus)
+ config_spec.memoryMB = int(instance.memory_mb)
- nic_spec = create_network_spec(network_name, instance.mac_address)
+ nic_spec = create_network_spec(client_factory,
+ network_name, instance.mac_address)
device_config_spec = [nic_spec]
- config_spec._deviceChange = device_config_spec
+ config_spec.deviceChange = device_config_spec
return config_spec
-def create_controller_spec(key):
- """
- Builds a Config Spec for the LSI Logic Controller's addition which acts
- as the controller for the Virtual Hard disk to be attached to the VM
+def create_controller_spec(client_factory, key):
+ """Builds a Config Spec for the LSI Logic Controller's addition
+ which acts as the controller for the
+ Virtual Hard disk to be attached to the VM
"""
#Create a controller for the Virtual Hard Disk
virtual_device_config = \
- ns0.VirtualDeviceConfigSpec_Def("VirtualDeviceConfigSpec").pyclass()
- virtual_device_config._operation = "add"
+ client_factory.create('ns0:VirtualDeviceConfigSpec')
+ virtual_device_config.operation = "add"
virtual_lsi = \
- ns0.VirtualLsiLogicController_Def(
- "VirtualLsiLogicController").pyclass()
- virtual_lsi._key = key
- virtual_lsi._busNumber = 0
- virtual_lsi._sharedBus = "noSharing"
- virtual_device_config._device = virtual_lsi
-
+ client_factory.create('ns0:VirtualLsiLogicController')
+ virtual_lsi.key = key
+ virtual_lsi.busNumber = 0
+ virtual_lsi.sharedBus = "noSharing"
+ virtual_device_config.device = virtual_lsi
return virtual_device_config
-def create_network_spec(network_name, mac_address):
- """
- Builds a config spec for the addition of a new network adapter to
- the VM.
- """
+def create_network_spec(client_factory, network_name, mac_address):
+ """Builds a config spec for the addition of a new network
+ adapter to the VM"""
network_spec = \
- ns0.VirtualDeviceConfigSpec_Def("VirtualDeviceConfigSpec").pyclass()
- network_spec._operation = "add"
+ client_factory.create('ns0:VirtualDeviceConfigSpec')
+ network_spec.operation = "add"
#Get the recommended card type for the VM based on the guest OS of the VM
- net_device = ns0.VirtualPCNet32_Def("VirtualPCNet32").pyclass()
+ net_device = client_factory.create('ns0:VirtualPCNet32')
backing = \
- ns0.VirtualEthernetCardNetworkBackingInfo_Def(
- "VirtualEthernetCardNetworkBackingInfo").pyclass()
- backing._deviceName = network_name
+ client_factory.create('ns0:VirtualEthernetCardNetworkBackingInfo')
+ backing.deviceName = network_name
connectable_spec = \
- ns0.VirtualDeviceConnectInfo_Def("VirtualDeviceConnectInfo").pyclass()
- connectable_spec._startConnected = True
- connectable_spec._allowGuestControl = True
- connectable_spec._connected = True
+ client_factory.create('ns0:VirtualDeviceConnectInfo')
+ connectable_spec.startConnected = True
+ connectable_spec.allowGuestControl = True
+ connectable_spec.connected = True
- net_device._connectable = connectable_spec
- net_device._backing = backing
+ net_device.connectable = connectable_spec
+ net_device.backing = backing
#The Server assigns a Key to the device. Here we pass a -ve temporary key.
#-ve because actual keys are +ve numbers and we don't
#want a clash with the key that server might associate with the device
- net_device._key = -47
- net_device._addressType = "manual"
- net_device._macAddress = mac_address
- net_device._wakeOnLanEnabled = True
+ net_device.key = -47
+ net_device.addressType = "manual"
+ net_device.macAddress = mac_address
+ net_device.wakeOnLanEnabled = True
- network_spec._device = net_device
+ network_spec.device = net_device
return network_spec
-def get_datastore_search_sepc(pattern=None):
- """Builds the datastore search spec."""
- host_datastore_browser_search_spec = \
- ns0.HostDatastoreBrowserSearchSpec_Def(
- "HostDatastoreBrowserSearchSpec").pyclass()
- file_query_flags = ns0.FileQueryFlags_Def("FileQueryFlags").pyclass()
- file_query_flags._modification = False
- file_query_flags._fileSize = True
- file_query_flags._fileType = True
- file_query_flags._fileOwner = True
- host_datastore_browser_search_spec._details = file_query_flags
- if pattern is not None:
- host_datastore_browser_search_spec._matchPattern = pattern
- return host_datastore_browser_search_spec
-
-
-def get_vmdk_attach_config_sepc(disksize, file_path, adapter_type="lsiLogic"):
- """Builds the vmdk attach config spec."""
- config_spec = ns0.VirtualMachineConfigSpec_Def(
- "VirtualMachineConfigSpec").pyclass()
+def get_vmdk_attach_config_spec(client_factory,
+ disksize, file_path, adapter_type="lsiLogic"):
+ """Builds the vmdk attach config spec"""
+ config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
#The controller Key pertains to the Key of the LSI Logic Controller, which
#controls this Hard Disk
@@ -163,145 +136,165 @@ def get_vmdk_attach_config_sepc(disksize, file_path, adapter_type="lsiLogic"): controller_key = 200
else:
controller_key = -101
- controller_spec = create_controller_spec(controller_key)
+ controller_spec = create_controller_spec(client_factory,
+ controller_key)
device_config_spec.append(controller_spec)
- virtual_device_config_spec = create_virtual_disk_spec(disksize,
- controller_key, file_path)
+ virtual_device_config_spec = create_virtual_disk_spec(client_factory,
+ disksize, controller_key, file_path)
device_config_spec.append(virtual_device_config_spec)
- config_spec._deviceChange = device_config_spec
+ config_spec.deviceChange = device_config_spec
return config_spec
-def get_vmdk_file_path_and_adapter_type(hardware_devices):
- """Gets the vmdk file path and the storage adapter type."""
- if isinstance(hardware_devices.typecode, ns0.ArrayOfVirtualDevice_Def):
+def get_vmdk_file_path_and_adapter_type(client_factory, hardware_devices):
+ """Gets the vmdk file path and the storage adapter type"""
+ if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice":
hardware_devices = hardware_devices.VirtualDevice
vmdk_file_path = None
vmdk_controler_key = None
adapter_type_dict = {}
for device in hardware_devices:
- if (isinstance(device.typecode, ns0.VirtualDisk_Def) and
- isinstance(device.Backing.typecode,
- ns0.VirtualDiskFlatVer2BackingInfo_Def)):
- vmdk_file_path = device.Backing.FileName
- vmdk_controler_key = device.ControllerKey
- elif isinstance(device.typecode, ns0.VirtualLsiLogicController_Def):
- adapter_type_dict[device.Key] = "lsiLogic"
- elif isinstance(device.typecode, ns0.VirtualBusLogicController_Def):
- adapter_type_dict[device.Key] = "busLogic"
- elif isinstance(device.typecode, ns0.VirtualIDEController_Def):
- adapter_type_dict[device.Key] = "ide"
- elif isinstance(device.typecode, ns0.VirtualLsiLogicSASController_Def):
- adapter_type_dict[device.Key] = "lsiLogic"
+ if device.__class__.__name__ == "VirtualDisk" and \
+ device.backing.__class__.__name__ \
+ == "VirtualDiskFlatVer2BackingInfo":
+ vmdk_file_path = device.backing.fileName
+ vmdk_controler_key = device.controllerKey
+ elif device.__class__.__name__ == "VirtualLsiLogicController":
+ adapter_type_dict[device.key] = "lsiLogic"
+ elif device.__class__.__name__ == "VirtualBusLogicController":
+ adapter_type_dict[device.key] = "busLogic"
+ elif device.__class__.__name__ == "VirtualIDEController":
+ adapter_type_dict[device.key] = "ide"
+ elif device.__class__.__name__ == "VirtualLsiLogicSASController":
+ adapter_type_dict[device.key] = "lsiLogic"
adapter_type = adapter_type_dict.get(vmdk_controler_key, "")
return vmdk_file_path, adapter_type
-def get_copy_virtual_disk_spec(adapter_type="lsilogic"):
- """Builds the Virtual Disk copy spec."""
- dest_spec = ns0.VirtualDiskSpec_Def("VirtualDiskSpec").pyclass()
- dest_spec.AdapterType = adapter_type
- dest_spec.DiskType = "thick"
+def get_copy_virtual_disk_spec(client_factory, adapter_type="lsilogic"):
+ """Builds the Virtual Disk copy spec"""
+ dest_spec = client_factory.create('ns0:VirtualDiskSpec')
+ dest_spec.adapterType = adapter_type
+ dest_spec.diskType = "thick"
return dest_spec
-def get_vmdk_create_spec(size_in_kb, adapter_type="lsiLogic"):
- """Builds the virtual disk create sepc."""
+def get_vmdk_create_spec(client_factory, size_in_kb, adapter_type="lsiLogic"):
+ """Builds the virtual disk create spec"""
create_vmdk_spec = \
- ns0.FileBackedVirtualDiskSpec_Def("VirtualDiskSpec").pyclass()
- create_vmdk_spec._adapterType = adapter_type
- create_vmdk_spec._diskType = "thick"
- create_vmdk_spec._capacityKb = size_in_kb
+ client_factory.create('ns0:FileBackedVirtualDiskSpec')
+ create_vmdk_spec.adapterType = adapter_type
+ create_vmdk_spec.diskType = "thick"
+ create_vmdk_spec.capacityKb = size_in_kb
return create_vmdk_spec
-def create_virtual_disk_spec(disksize, controller_key, file_path=None):
- """Creates a Spec for the addition/attaching of a Virtual Disk to the VM"""
+def create_virtual_disk_spec(client_factory,
+ disksize, controller_key, file_path=None):
+ """Creates a Spec for the addition/attaching of a
+ Virtual Disk to the VM"""
virtual_device_config = \
- ns0.VirtualDeviceConfigSpec_Def("VirtualDeviceConfigSpec").pyclass()
- virtual_device_config._operation = "add"
+ client_factory.create('ns0:VirtualDeviceConfigSpec')
+ virtual_device_config.operation = "add"
if file_path is None:
- virtual_device_config._fileOperation = "create"
+ virtual_device_config.fileOperation = "create"
- virtual_disk = ns0.VirtualDisk_Def("VirtualDisk").pyclass()
+ virtual_disk = client_factory.create('ns0:VirtualDisk')
- disk_file_backing = ns0.VirtualDiskFlatVer2BackingInfo_Def(
- "VirtualDiskFlatVer2BackingInfo").pyclass()
- disk_file_backing._diskMode = "persistent"
- disk_file_backing._thinProvisioned = False
+ disk_file_backing = \
+ client_factory.create('ns0:VirtualDiskFlatVer2BackingInfo')
+ disk_file_backing.diskMode = "persistent"
+ disk_file_backing.thinProvisioned = False
if file_path is not None:
- disk_file_backing._fileName = file_path
+ disk_file_backing.fileName = file_path
else:
- disk_file_backing._fileName = ""
+ disk_file_backing.fileName = ""
- connectable_spec = ns0.VirtualDeviceConnectInfo_Def(
- "VirtualDeviceConnectInfo").pyclass()
- connectable_spec._startConnected = True
- connectable_spec._allowGuestControl = False
- connectable_spec._connected = True
+ connectable_spec = client_factory.create('ns0:VirtualDeviceConnectInfo')
+ connectable_spec.startConnected = True
+ connectable_spec.allowGuestControl = False
+ connectable_spec.connected = True
- virtual_disk._backing = disk_file_backing
- virtual_disk._connectable = connectable_spec
+ virtual_disk.backing = disk_file_backing
+ virtual_disk.connectable = connectable_spec
#The Server assigns a Key to the device. Here we pass a -ve temporary key.
#-ve because actual keys are +ve numbers and we don't
#want a clash with the key that server might associate with the device
- virtual_disk._key = -100
- virtual_disk._controllerKey = controller_key
- virtual_disk._unitNumber = 0
- virtual_disk._capacityInKB = disksize
+ virtual_disk.key = -100
+ virtual_disk.controllerKey = controller_key
+ virtual_disk.unitNumber = 0
+ virtual_disk.capacityInKB = disksize
- virtual_device_config._device = virtual_disk
+ virtual_device_config.device = virtual_disk
return virtual_device_config
-def get_dummy_vm_create_spec(name, data_store_name):
- """Builds the dummy VM create spec."""
- config_spec = ns0.VirtualMachineConfigSpec_Def(
- "VirtualMachineConfigSpec").pyclass()
+def get_dummy_vm_create_spec(client_factory, name, data_store_name):
+ """Builds the dummy VM create spec"""
+ config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
- config_spec._name = name
- config_spec._guestId = "otherGuest"
+ config_spec.name = name
+ config_spec.guestId = "otherGuest"
- vm_file_info = ns0.VirtualMachineFileInfo_Def(
- "VirtualMachineFileInfo").pyclass()
- vm_file_info._vmPathName = "[" + data_store_name + "]"
- config_spec._files = vm_file_info
+ vm_file_info = client_factory.create('ns0:VirtualMachineFileInfo')
+ vm_file_info.vmPathName = "[" + data_store_name + "]"
+ config_spec.files = vm_file_info
- tools_info = ns0.ToolsConfigInfo_Def("ToolsConfigInfo")
- tools_info._afterPowerOn = True
- tools_info._afterResume = True
- tools_info._beforeGuestStandby = True
- tools_info._bbeforeGuestShutdown = True
- tools_info._beforeGuestReboot = True
+ tools_info = client_factory.create('ns0:ToolsConfigInfo')
+ tools_info.afterPowerOn = True
+ tools_info.afterResume = True
+ tools_info.beforeGuestStandby = True
+ tools_info.beforeGuestShutdown = True
+ tools_info.beforeGuestReboot = True
- config_spec._tools = tools_info
- config_spec._numCPUs = 1
- config_spec._memoryMB = 4
+ config_spec.tools = tools_info
+ config_spec.numCPUs = 1
+ config_spec.memoryMB = 4
controller_key = -101
- controller_spec = create_controller_spec(controller_key)
- disk_spec = create_virtual_disk_spec(1024, controller_key)
+ controller_spec = create_controller_spec(client_factory, controller_key)
+ disk_spec = create_virtual_disk_spec(client_factory, 1024, controller_key)
device_config_spec = [controller_spec, disk_spec]
- config_spec._deviceChange = device_config_spec
+ config_spec.deviceChange = device_config_spec
return config_spec
-def get_machine_id_change_spec(mac, ip_addr, netmask, gateway):
- """Builds the machine id change config spec."""
+def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, gateway):
+ """Builds the machine id change config spec"""
machine_id_str = "%s;%s;%s;%s" % (mac, ip_addr, netmask, gateway)
- virtual_machine_config_spec = ns0.VirtualMachineConfigSpec_Def(
- "VirtualMachineConfigSpec").pyclass()
- opt = ns0.OptionValue_Def('OptionValue').pyclass()
- opt._key = "machine.id"
- opt._value = machine_id_str
- virtual_machine_config_spec._extraConfig = [opt]
+ virtual_machine_config_spec = \
+ client_factory.create('ns0:VirtualMachineConfigSpec')
+
+ opt = client_factory.create('ns0:OptionValue')
+ opt.key = "machine.id"
+ opt.value = machine_id_str
+ virtual_machine_config_spec.extraConfig = [opt]
return virtual_machine_config_spec
+
+
+def get_add_vswitch_port_group_spec(client_factory, vswitch_name,
+ port_group_name, vlan_id):
+ """Builds the virtual switch port group add spec"""
+ vswitch_port_group_spec = client_factory.create('ns0:HostPortGroupSpec')
+ vswitch_port_group_spec.name = port_group_name
+ vswitch_port_group_spec.vswitchName = vswitch_name
+
+ #VLAN ID of 0 means that VLAN tagging is not to be done for the network.
+ vswitch_port_group_spec.vlanId = int(vlan_id)
+
+ policy = client_factory.create('ns0:HostNetworkPolicy')
+ nicteaming = client_factory.create('ns0:HostNicTeamingPolicy')
+ nicteaming.notifySwitches = True
+ policy.nicTeaming = nicteaming
+
+ vswitch_port_group_spec.policy = policy
+ return vswitch_port_group_spec
diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index 3e32fceef..c2e6d9bf8 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -17,20 +17,27 @@ """
Class for VM tasks like spawn, snapshot, suspend, resume etc.
-
"""
-import logging
+
+import base64
import os
import time
+import urllib
+import urllib2
import uuid
-from nova import db
from nova import context
+from nova import db
+from nova import exception
+from nova import flags
+from nova import log as logging
from nova.compute import power_state
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi import vm_util
from nova.virt.vmwareapi import vmware_images
+from nova.virt.vmwareapi.network_utils import NetworkHelper
+FLAGS = flags.FLAGS
LOG = logging.getLogger("nova.virt.vmwareapi.vmops")
VMWARE_POWER_STATES = {
@@ -40,14 +47,14 @@ VMWARE_POWER_STATES = { class VMWareVMOps(object):
- """Management class for VM-related tasks"""
+ """ Management class for VM-related tasks """
def __init__(self, session):
- """Initializer"""
+ """ Initializer """
self._session = session
def _wait_with_callback(self, instance_id, task, callback):
- """Waits for the task to finish and does a callback after"""
+ """ Waits for the task to finish and does a callback after """
ret = None
try:
ret = self._session._wait_for_task(instance_id, task)
@@ -56,7 +63,7 @@ class VMWareVMOps(object): callback(ret)
def list_instances(self):
- """Lists the VM instances that are registered with the ESX host"""
+ """ Lists the VM instances that are registered with the ESX host """
LOG.debug(_("Getting list of instances"))
vms = self._session._call_method(vim_util, "get_objects",
"VirtualMachine",
@@ -65,11 +72,11 @@ class VMWareVMOps(object): for vm in vms:
vm_name = None
conn_state = None
- for prop in vm.PropSet:
- if prop.Name == "name":
- vm_name = prop.Val
- elif prop.Name == "runtime.connectionState":
- conn_state = prop.Val
+ for prop in vm.propSet:
+ if prop.name == "name":
+ vm_name = prop.val
+ elif prop.name == "runtime.connectionState":
+ conn_state = prop.val
# Ignoring the oprhaned or inaccessible VMs
if conn_state not in ["orphaned", "inaccessible"]:
lst_vm_names.append(vm_name)
@@ -93,18 +100,19 @@ class VMWareVMOps(object): """
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref:
- raise Exception('Attempted to create a VM with a name %s, '
- 'but that already exists on the host' % instance.name)
- bridge = db.network_get_by_instance(context.get_admin_context(),
- instance['id'])['bridge']
- #TODO(sateesh): Shouldn't we consider any public network in case
- #the network name supplied isn't there
+ raise Exception(_("Attempted to create a VM with a name %s, "
+ "but that already exists on the host") % instance.name)
+
+ client_factory = self._session._get_vim().client.factory
+
+ network = db.network_get_by_instance(context.get_admin_context(),
+ instance['id'])
+ net_name = network['bridge']
network_ref = \
- self._get_network_with_the_name(bridge)
+ NetworkHelper.get_network_with_the_name(self._session, net_name)
if network_ref is None:
- raise Exception("Network with the name '%s' doesn't exist on "
- "the ESX host" % bridge)
-
+ raise Exception(_("Network with the name '%s' doesn't exist on"
+ " the ESX host") % net_name)
#Get the Size of the flat vmdk file that is there on the storage
#repository.
image_size, image_properties = \
@@ -121,11 +129,11 @@ class VMWareVMOps(object): for elem in data_stores:
ds_name = None
ds_type = None
- for prop in elem.PropSet:
- if prop.Name == "summary.type":
- ds_type = prop.Val
- elif prop.Name == "summary.name":
- ds_name = prop.Val
+ for prop in elem.propSet:
+ if prop.name == "summary.type":
+ ds_type = prop.val
+ elif prop.name == "summary.name":
+ ds_name = prop.val
#Local storage identifier
if ds_type == "VMFS":
data_store_name = ds_name
@@ -135,22 +143,21 @@ class VMWareVMOps(object): msg = _("Couldn't get a local Datastore reference")
LOG.exception(msg)
raise Exception(msg)
-
- config_spec = vm_util.get_vm_create_spec(instance, data_store_name,
- bridge, os_type)
+ config_spec = vm_util.get_vm_create_spec(client_factory, instance,
+ data_store_name, net_name, os_type)
#Get the Vm folder ref from the datacenter
dc_objs = self._session._call_method(vim_util, "get_objects",
"Datacenter", ["vmFolder"])
#There is only one default datacenter in a standalone ESX host
- vm_folder_ref = dc_objs[0].PropSet[0].Val
+ vm_folder_ref = dc_objs[0].propSet[0].val
#Get the resource pool. Taking the first resource pool coming our way.
#Assuming that is the default resource pool.
res_pool_mor = self._session._call_method(vim_util, "get_objects",
- "ResourcePool")[0].Obj
+ "ResourcePool")[0].obj
- LOG.debug(_("Creating VM with the name %s on the ESX host") % \
+ LOG.debug(_("Creating VM with the name %s on the ESX host") %
instance.name)
#Create the VM on the ESX host
vm_create_task = self._session._call_method(self._session._get_vim(),
@@ -158,11 +165,11 @@ class VMWareVMOps(object): config=config_spec, pool=res_pool_mor)
self._session._wait_for_task(instance.id, vm_create_task)
- LOG.debug(_("Created VM with the name %s on the ESX host") % \
+ LOG.debug(_("Created VM with the name %s on the ESX host") %
instance.name)
# Set the machine id for the VM for setting the IP
- self._set_machine_id(instance)
+ self._set_machine_id(client_factory, instance)
#Naming the VM files in correspondence with the VM instance name
@@ -181,61 +188,56 @@ class VMWareVMOps(object): #depend on the size of the disk, thin/thick provisioning and the
#storage adapter type.
#Here we assume thick provisioning and lsiLogic for the adapter type
- LOG.debug(_("Creating Virtual Disk of size %(vmdk_file_size_in_kb)sKB"
- " and adapter type %(adapter_type)s on"
- " the ESX host local store %(data_store_name)s") %
- {'vmdk_file_size_in_kb': vmdk_file_size_in_kb,
- 'adapter_type': adapter_type,
- 'data_store_name': data_store_name})
- vmdk_create_spec = vm_util.get_vmdk_create_spec(vmdk_file_size_in_kb,
- adapter_type)
+ LOG.debug(_("Creating Virtual Disk of size %(vmdk_file_size_in_kb)s "
+ "KB and adapter type %(adapter_type)s on "
+ "the ESX host local store %(data_store_name)s") % locals())
+ vmdk_create_spec = vm_util.get_vmdk_create_spec(client_factory,
+ vmdk_file_size_in_kb, adapter_type)
vmdk_create_task = self._session._call_method(self._session._get_vim(),
"CreateVirtualDisk_Task",
- self._session._get_vim().get_service_content().VirtualDiskManager,
+ self._session._get_vim().get_service_content().virtualDiskManager,
name=uploaded_vmdk_path,
datacenter=self._get_datacenter_name_and_ref()[0],
spec=vmdk_create_spec)
self._session._wait_for_task(instance.id, vmdk_create_task)
- LOG.debug(_("Created Virtual Disk of size %(vmdk_file_size_in_kb)s KB"
- " on the ESX host local store %(data_store_name)s ") %
- {'vmdk_file_size_in_kb': vmdk_file_size_in_kb,
- 'data_store_name': data_store_name})
-
- LOG.debug(_("Deleting the file %(flat_uploaded_vmdk_path)s on "
- "the ESX host local store %(data_store_names)s") %
- {'flat_uploaded_vmdk_path': flat_uploaded_vmdk_path,
- 'data_store_name': data_store_name})
+ LOG.debug(_("Created Virtual Disk of size %(vmdk_file_size_in_kb)s "
+ "KB on the ESX host local store "
+ "%(data_store_name)s") % locals())
+
+ LOG.debug(_("Deleting the file %(flat_uploaded_vmdk_path)s "
+ "on the ESX host local"
+ "store %(data_store_name)s") % locals())
#Delete the -flat.vmdk file created. .vmdk file is retained.
vmdk_delete_task = self._session._call_method(self._session._get_vim(),
"DeleteDatastoreFile_Task",
- self._session._get_vim().get_service_content().FileManager,
+ self._session._get_vim().get_service_content().fileManager,
name=flat_uploaded_vmdk_path)
self._session._wait_for_task(instance.id, vmdk_delete_task)
- LOG.debug(_("Deleted the file %(flat_uploaded_vmdk_path)s on "
- "the ESX host local store %(data_store_name)s ") %
- {'flat_uploaded_vmdk_path': flat_uploaded_vmdk_path,
- 'data_store_name': data_store_name})
-
- LOG.debug(_("Downloading image file %(image_id)s to the "
- "ESX data store %(datastore_name)s ") %
- {'image_id': instance.image_id,
- 'data_store_name': data_store_name})
+ LOG.debug(_("Deleted the file %(flat_uploaded_vmdk_path)s on the "
+ "ESX host local store %(data_store_name)s") % locals())
+
+ LOG.debug(_("Downloading image file data %(image_id)s to the ESX "
+ "data store %(data_store_name)s") %
+ ({'image_id': instance.image_id,
+ 'data_store_name': data_store_name}))
+ cookies = self._session._get_vim().client.options.transport.cookiejar
# Upload the -flat.vmdk file whose meta-data file we just created above
vmware_images.fetch_image(
- instance.image_id,
- instance,
- host=self._session._host_ip,
- data_center_name=self._get_datacenter_name_and_ref()[1],
- datastore_name=data_store_name,
- cookies=self._session._get_vim().proxy.binding.cookies,
- file_path=flat_uploaded_vmdk_name)
- LOG.debug(_("Downloaded image file %(image_id)s to the ESX data "
- "store %(data_store_name)s ") %
- {'image_id': instance.image_id,
- 'data_store_name': data_store_name})
+ instance.image_id,
+ instance,
+ host=self._session._host_ip,
+ data_center_name=self._get_datacenter_name_and_ref()[1],
+ datastore_name=data_store_name,
+ cookies=cookies,
+ file_path=flat_uploaded_vmdk_name)
+ LOG.debug(_("Downloaded image file data %(image_id)s to the ESX "
+ "data store %(data_store_name)s") %
+ ({'image_id': instance.image_id,
+ 'data_store_name': data_store_name}))
#Attach the vmdk uploaded to the VM. VM reconfigure is done to do so.
- vmdk_attach_config_spec = vm_util.get_vmdk_attach_config_sepc(
+ vmdk_attach_config_spec = vm_util.get_vmdk_attach_config_spec(
+ client_factory,
vmdk_file_size_in_kb, uploaded_vmdk_path,
adapter_type)
vm_ref = self._get_vm_ref_from_the_name(instance.name)
@@ -248,12 +250,12 @@ class VMWareVMOps(object): LOG.debug(_("Reconfigured VM instance %s to attach the image "
"disk") % instance.name)
- LOG.debug(_("Powering on the VM instance %s ") % instance.name)
+ LOG.debug(_("Powering on the VM instance %s") % instance.name)
#Power On the VM
power_on_task = self._session._call_method(self._session._get_vim(),
"PowerOnVM_Task", vm_ref)
self._session._wait_for_task(instance.id, power_on_task)
- LOG.debug(_("Powered on the VM instance %s ") % instance.name)
+ LOG.debug(_("Powered on the VM instance %s") % instance.name)
def snapshot(self, instance, snapshot_name):
"""
@@ -277,14 +279,17 @@ class VMWareVMOps(object): hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device")
+ client_factory = self._session._get_vim().client.factory
vmdk_file_path_before_snapshot, adapter_type = \
- vm_util.get_vmdk_file_path_and_adapter_type(hardware_devices)
+ vm_util.get_vmdk_file_path_and_adapter_type(client_factory,
+ hardware_devices)
os_type = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
"VirtualMachine", "summary.config.guestId")
#Create a snapshot of the VM
- LOG.debug(_("Creating Snapshot of the VM instance %s") % instance.name)
+ LOG.debug(_("Creating Snapshot of the VM instance %s ") %
+ instance.name)
snapshot_task = self._session._call_method(self._session._get_vim(),
"CreateSnapshot_Task", vm_ref,
name="%s-snapshot" % instance.name,
@@ -313,7 +318,8 @@ class VMWareVMOps(object): self._mkdir(vm_util.build_datastore_path(datastore_name,
"vmware-tmp"))
- copy_spec = vm_util.get_copy_virtual_disk_spec(adapter_type)
+ copy_spec = vm_util.get_copy_virtual_disk_spec(client_factory,
+ adapter_type)
#Generate a random vmdk file name to which the coalesced vmdk content
#will be copied to. A random name is chosen so that we don't have
@@ -325,11 +331,11 @@ class VMWareVMOps(object): #Copy the contents of the disk ( or disks, if there were snapshots
#done earlier) to a temporary vmdk file.
- LOG.debug(_("Copying disk data before snapshot of "
- "the VM instance %s") % instance.name)
+ LOG.debug(_("Copying disk data before snapshot of the VM instance %s")
+ % instance.name)
copy_disk_task = self._session._call_method(self._session._get_vim(),
"CopyVirtualDisk_Task",
- self._session._get_vim().get_service_content().VirtualDiskManager,
+ self._session._get_vim().get_service_content().virtualDiskManager,
sourceName=vmdk_file_path_before_snapshot,
sourceDatacenter=dc_ref,
destName=dest_vmdk_file_location,
@@ -337,38 +343,39 @@ class VMWareVMOps(object): destSpec=copy_spec,
force=False)
self._session._wait_for_task(instance.id, copy_disk_task)
- LOG.debug(_("Copied disk data before snapshot of "
- "the VM instance %s") % instance.name)
+ LOG.debug(_("Copied disk data before snapshot of the VM instance %s")
+ % instance.name)
+ cookies = self._session._get_vim().client.options.transport.cookiejar
#Upload the contents of -flat.vmdk file which has the disk data.
LOG.debug(_("Uploading image %s") % snapshot_name)
vmware_images.upload_image(
- snapshot_name,
- instance,
- os_type=os_type,
- adapter_type=adapter_type,
- image_version=1,
- host=self._session._host_ip,
- data_center_name=self._get_datacenter_name_and_ref()[1],
- datastore_name=datastore_name,
- cookies=self._session._get_vim().proxy.binding.cookies,
- file_path="vmware-tmp/%s-flat.vmdk" % random_name)
+ snapshot_name,
+ instance,
+ os_type=os_type,
+ adapter_type=adapter_type,
+ image_version=1,
+ host=self._session._host_ip,
+ data_center_name=self._get_datacenter_name_and_ref()[1],
+ datastore_name=datastore_name,
+ cookies=cookies,
+ file_path="vmware-tmp/%s-flat.vmdk" % random_name)
LOG.debug(_("Uploaded image %s") % snapshot_name)
#Delete the temporary vmdk created above.
- LOG.debug(_("Deleting temporary vmdk file %s") % \
- dest_vmdk_file_location)
+ LOG.debug(_("Deleting temporary vmdk file %s")
+ % dest_vmdk_file_location)
remove_disk_task = self._session._call_method(self._session._get_vim(),
"DeleteVirtualDisk_Task",
- self._session._get_vim().get_service_content().VirtualDiskManager,
+ self._session._get_vim().get_service_content().virtualDiskManager,
name=dest_vmdk_file_location,
datacenter=dc_ref)
self._session._wait_for_task(instance.id, remove_disk_task)
- LOG.debug(_("Deleted temporary vmdk file %s") % \
- dest_vmdk_file_location)
+ LOG.debug(_("Deleted temporary vmdk file %s")
+ % dest_vmdk_file_location)
def reboot(self, instance):
- """Reboot a VM instance"""
+ """ Reboot a VM instance """
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
raise Exception(_("instance - %s not present") % instance.name)
@@ -379,11 +386,11 @@ class VMWareVMOps(object): for elem in props:
pwr_state = None
tools_status = None
- for prop in elem.PropSet:
- if prop.Name == "runtime.powerState":
- pwr_state = prop.Val
- elif prop.Name == "summary.guest.toolsStatus":
- tools_status = prop.Val
+ for prop in elem.propSet:
+ if prop.name == "runtime.powerState":
+ pwr_state = prop.val
+ elif prop.name == "summary.guest.toolsStatus":
+ tools_status = prop.val
#Raise an exception if the VM is not powered On.
if pwr_state not in ["poweredOn"]:
@@ -423,11 +430,11 @@ class VMWareVMOps(object): pwr_state = None
for elem in props:
vm_config_pathname = None
- for prop in elem.PropSet:
- if prop.Name == "runtime.powerState":
- pwr_state = prop.Val
- elif prop.Name == "config.files.vmPathName":
- vm_config_pathname = prop.Val
+ for prop in elem.propSet:
+ if prop.name == "runtime.powerState":
+ pwr_state = prop.val
+ elif prop.name == "config.files.vmPathName":
+ vm_config_pathname = prop.val
if vm_config_pathname:
datastore_name, vmx_file_path = \
vm_util.split_datastore_path(vm_config_pathname)
@@ -447,48 +454,49 @@ class VMWareVMOps(object): "UnregisterVM", vm_ref)
LOG.debug(_("Unregistered the VM %s") % instance.name)
except Exception, excep:
- LOG.warn(_("In vmwareapi:vmops:destroy, got this exception "
- "while un-registering the VM: ") + str(excep))
+ LOG.warn(_("In vmwareapi:vmops:destroy, got this exception"
+ " while un-registering the VM: %s") % str(excep))
#Delete the folder holding the VM related content on the datastore.
try:
dir_ds_compliant_path = vm_util.build_datastore_path(
datastore_name,
os.path.dirname(vmx_file_path))
- LOG.debug(_("Deleting contents of the VM %(instance.name)s "
- "from datastore %(datastore_name)s") %
- {('instance.name': instance.name,
- 'datastore_name': datastore_name)})
+ LOG.debug(_("Deleting contents of the VM %(name)s from "
+ "datastore %(datastore_name)s") %
+ ({'name': instance.name,
+ 'datastore_name': datastore_name}))
delete_task = self._session._call_method(
self._session._get_vim(),
"DeleteDatastoreFile_Task",
- self._session._get_vim().get_service_content().FileManager,
+ self._session._get_vim().get_service_content().fileManager,
name=dir_ds_compliant_path)
self._session._wait_for_task(instance.id, delete_task)
- LOG.debug(_("Deleted contents of the VM %(instance_name)s "
- "from datastore %(datastore_name)s") %
- {'instance_name': instance.name,
- 'datastore_name': datastore_name})
+ LOG.debug(_("Deleted contents of the VM %(name)s from "
+ "datastore %(datastore_name)s")
+ ({'name': instance.name,
+ 'datastore_name': datastore_name}))
except Exception, excep:
LOG.warn(_("In vmwareapi:vmops:destroy, "
"got this exception while deleting"
- " the VM contents from the disk: ") + str(excep))
+ " the VM contents from the disk: %s")
+ % str(excep))
except Exception, e:
LOG.exception(e)
def pause(self, instance, callback):
- """Pause a VM instance"""
- return "Not Implemented"
+ """ Pause a VM instance """
+ raise exception.APIError("pause not supported for vmwareapi")
def unpause(self, instance, callback):
- """Un-Pause a VM instance"""
- return "Not Implemented"
+ """ Un-Pause a VM instance """
+ raise exception.APIError("unpause not supported for vmwareapi")
def suspend(self, instance, callback):
- """Suspend the specified instance"""
+ """ Suspend the specified instance """
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
- raise Exception("instance - %s not present" % instance.name)
+ raise Exception(_("instance - %s not present") % instance.name)
pwr_state = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref,
@@ -505,10 +513,10 @@ class VMWareVMOps(object): raise Exception(_("instance - %s is poweredOff and hence can't "
"be suspended.") % instance.name)
LOG.debug(_("VM %s was already in suspended state. So returning "
- "without doing anything") % instance.name)
+ "without doing anything") % instance.name)
def resume(self, instance, callback):
- """Resume the specified instance"""
+ """ Resume the specified instance """
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
raise Exception(_("instance - %s not present") % instance.name)
@@ -517,7 +525,7 @@ class VMWareVMOps(object): "get_dynamic_property", vm_ref,
"VirtualMachine", "runtime.powerState")
if pwr_state.lower() == "suspended":
- LOG.debug(_("Resuming the VM %s ") % instance.name)
+ LOG.debug(_("Resuming the VM %s") % instance.name)
suspend_task = self._session._call_method(
self._session._get_vim(),
"PowerOnVM_Task", vm_ref)
@@ -528,7 +536,7 @@ class VMWareVMOps(object): "can't be Resumed.") % instance.name)
def get_info(self, instance_name):
- """Return data about the VM instance"""
+ """ Return data about the VM instance """
vm_ref = self._get_vm_ref_from_the_name(instance_name)
if vm_ref is None:
raise Exception(_("instance - %s not present") % instance_name)
@@ -543,14 +551,14 @@ class VMWareVMOps(object): pwr_state = None
num_cpu = None
for elem in vm_props:
- for prop in elem.PropSet:
- if prop.Name == "summary.config.numCpu":
- num_cpu = int(prop.Val)
- elif prop.Name == "summary.config..memorySizeMB":
+ for prop in elem.propSet:
+ if prop.name == "summary.config.numCpu":
+ num_cpu = int(prop.val)
+ elif prop.name == "summary.config.memorySizeMB":
# In MB, but we want in KB
- max_mem = int(prop.Val) * 1024
- elif prop.Name == "runtime.powerState":
- pwr_state = VMWARE_POWER_STATES[prop.Val]
+ max_mem = int(prop.val) * 1024
+ elif prop.name == "runtime.powerState":
+ pwr_state = VMWARE_POWER_STATES[prop.val]
return {'state': pwr_state,
'max_mem': max_mem,
@@ -559,22 +567,38 @@ class VMWareVMOps(object): 'cpu_time': 0}
def get_diagnostics(self, instance):
- """Return data about VM diagnostics"""
- return "Not Implemented"
+ """ Return data about VM diagnostics """
+ raise exception.APIError("get_diagnostics not implemented for "
+ "vmwareapi")
def get_console_output(self, instance):
- """Return snapshot of console"""
- return 'FAKE CONSOLE OUTPUT of instance'
+ """ Return snapshot of console """
+ vm_ref = self._get_vm_ref_from_the_name(instance.name)
+ if vm_ref is None:
+ raise Exception(_("instance - %s not present") % instance.name)
+ param_list = {"id": str(vm_ref)}
+ base_url = "%s://%s/screen?%s" % (self._session._scheme,
+ self._session._host_ip,
+ urllib.urlencode(param_list))
+ request = urllib2.Request(base_url)
+ base64string = base64.encodestring(
+ '%s:%s' % (
+ self._session._host_username,
+ self._session._host_password)).replace('\n', '')
+ request.add_header("Authorization", "Basic %s" % base64string)
+ result = urllib2.urlopen(request)
+ if result.code == 200:
+ return result.read()
+ else:
+ return ""
def get_ajax_console(self, instance):
- """Return link to instance's ajax console"""
+ """ Return link to instance's ajax console """
return 'http://fakeajaxconsole/fake_url'
- def _set_machine_id(self, instance):
- """
- Set the machine id of the VM for guest tools to pick up
- and change the IP
- """
+ def _set_machine_id(self, client_factory, instance):
+ """ Set the machine id of the VM for guest tools to pick up and change
+ the IP """
vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None:
raise Exception(_("instance - %s not present") % instance.name)
@@ -585,95 +609,30 @@ class VMWareVMOps(object): gateway = network["gateway"]
ip_addr = db.instance_get_fixed_address(context.get_admin_context(),
instance['id'])
- machine_id_chanfge_spec = vm_util.get_machine_id_change_spec(mac_addr,
+ machine_id_chanfge_spec = \
+ vm_util.get_machine_id_change_spec(client_factory, mac_addr,
ip_addr, net_mask, gateway)
- LOG.debug(_("Reconfiguring VM instance %(instance_name)s to set "
- "the machine id with ip - %(ip_addr)s") %
- {'instance_name': instance.name,
- 'ip_addr': ip_addr})
+ LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id "
+ "with ip - %(ip_addr)s") %
+ ({'name': instance.name,
+ 'ip_addr': ip_addr}))
reconfig_task = self._session._call_method(self._session._get_vim(),
"ReconfigVM_Task", vm_ref,
spec=machine_id_chanfge_spec)
self._session._wait_for_task(instance.id, reconfig_task)
- LOG.debug(_("Reconfigured VM instance %(instance_name)s to set "
- "the machine id with ip - %(ip_addr)s") %
- {'instance_name': instance.name,
- 'ip_addr': ip_addr})
-
- def _create_dummy_vm_for_test(self, instance):
- """Create a dummy VM for testing purpose"""
- vm_ref = self._get_vm_ref_from_the_name(instance.name)
- if vm_ref:
- raise Exception(_('Attempted to create a VM with a name %s, '
- 'but that already exists on the host') % instance.name)
-
- data_stores = self._session._call_method(vim_util, "get_objects",
- "Datastore", ["summary.type", "summary.name"])
- data_store_name = None
- for elem in data_stores:
- ds_name = None
- ds_type = None
- for prop in elem.PropSet:
- if prop.Name == "summary.type":
- ds_type = prop.Val
- elif prop.Name == "summary.name":
- ds_name = prop.Val
- #Local storage identifier
- if ds_type == "VMFS":
- data_store_name = ds_name
- break
-
- if data_store_name is None:
- msg = _("Couldn't get a local Datastore reference")
- LOG.exception(msg)
- raise Exception(msg)
-
- config_spec = vm_util.get_dummy_vm_create_spec(instance.name,
- data_store_name)
-
- #Get the Vm folder ref from the datacenter
- dc_objs = self._session._call_method(vim_util, "get_objects",
- "Datacenter", ["vmFolder"])
- #There is only one default datacenter in a standalone ESX host
- vm_folder_ref = dc_objs[0].PropSet[0].Val
-
- #Get the resource pool. Taking the first resource pool coming our way.
- #Assuming that is the default resource pool.
- res_pool_mor = self._session._call_method(vim_util, "get_objects",
- "ResourcePool")[0].Obj
-
- #Create the VM on the ESX host
- vm_create_task = self._session._call_method(self._session._get_vim(),
- "CreateVM_Task", vm_folder_ref,
- config=config_spec, pool=res_pool_mor)
- self._session._wait_for_task(instance.id, vm_create_task)
-
- vm_ref = self._get_vm_ref_from_the_name(instance.name)
- power_on_task = self._session._call_method(self._session._get_vim(),
- "PowerOnVM_Task", vm_ref)
- self._session._wait_for_task(instance.id, power_on_task)
-
- def _get_network_with_the_name(self, network_name="vmnet0"):
- """Gets reference to network whose name is passed as the argument."""
- datacenters = self._session._call_method(vim_util, "get_objects",
- "Datacenter", ["network"])
- vm_networks = datacenters[0].PropSet[0].Val.ManagedObjectReference
- networks = self._session._call_method(vim_util,
- "get_properites_for_a_collection_of_objects",
- "Network", vm_networks, ["summary.name"])
- for network in networks:
- if network.PropSet[0].Val == network_name:
- return network.Obj
- return None
+ LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id "
+ "with ip - %(ip_addr)s") %
+ ({'name': instance.name,
+ 'ip_addr': ip_addr}))
def _get_datacenter_name_and_ref(self):
- """Get the datacenter name and the reference."""
+ """ Get the datacenter name and the reference. """
dc_obj = self._session._call_method(vim_util, "get_objects",
"Datacenter", ["name"])
- return dc_obj[0].Obj, dc_obj[0].PropSet[0].Val
+ return dc_obj[0].obj, dc_obj[0].propSet[0].val
def _path_exists(self, ds_browser, ds_path):
- """Check if the path exists on the datastore."""
+ """Check if the path exists on the datastore"""
search_task = self._session._call_method(self._session._get_vim(),
"SearchDatastore_Task",
ds_browser,
@@ -684,31 +643,29 @@ class VMWareVMOps(object): task_info = self._session._call_method(vim_util,
"get_dynamic_property",
search_task, "Task", "info")
- if task_info.State in ['queued', 'running']:
+ if task_info.state in ['queued', 'running']:
time.sleep(2)
continue
break
- if task_info.State == "error":
+ if task_info.state == "error":
return False
return True
def _mkdir(self, ds_path):
- """
- Creates a directory at the path specified. If it is just "NAME", then a
- directory with this name is formed at the topmost level of the
- DataStore.
- """
+ """ Creates a directory at the path specified. If it is just "NAME",
+ then a directory with this name is formed at the topmost level of the
+ DataStore. """
LOG.debug(_("Creating directory with path %s") % ds_path)
self._session._call_method(self._session._get_vim(), "MakeDirectory",
- self._session._get_vim().get_service_content().FileManager,
+ self._session._get_vim().get_service_content().fileManager,
name=ds_path, createParentDirectories=False)
LOG.debug(_("Created directory with path %s") % ds_path)
def _get_vm_ref_from_the_name(self, vm_name):
- """Get reference to the VM with the name specified."""
+ """ Get reference to the VM with the name specified. """
vms = self._session._call_method(vim_util, "get_objects",
"VirtualMachine", ["name"])
for vm in vms:
- if vm.PropSet[0].Val == vm_name:
- return vm.Obj
+ if vm.propSet[0].val == vm_name:
+ return vm.obj
return None
diff --git a/nova/virt/vmwareapi/vmware_images.py b/nova/virt/vmwareapi/vmware_images.py index 4aad657e6..f2a7c3b33 100644 --- a/nova/virt/vmwareapi/vmware_images.py +++ b/nova/virt/vmwareapi/vmware_images.py @@ -14,19 +14,16 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-
"""
-Utility functions to handle vm images. Also include fake image handlers.
-
+Utility functions for Image transfer
"""
-import logging
-import os
import time
from nova import flags
-from nova.virt.vmwareapi import read_write_util
+from nova import log as logging
from nova.virt.vmwareapi import io_util
+from nova.virt.vmwareapi import read_write_util
FLAGS = flags.FLAGS
@@ -35,11 +32,11 @@ READ_CHUNKSIZE = 2 * 1024 * 1024 WRITE_CHUNKSIZE = 2 * 1024 * 1024
LOG = logging.getLogger("nova.virt.vmwareapi.vmware_images")
-TEST_IMAGE_PATH = "/tmp/vmware-test-images"
def start_transfer(read_file_handle, write_file_handle, data_size):
- """Start the data transfer from the read handle to the write handle."""
+ """ Start the data transfer from the read handle to the write handle. """
+
#The thread safe pipe
thread_safe_pipe = io_util.ThreadSafePipe(QUEUE_BUFFER_SIZE)
#The read thread
@@ -73,7 +70,7 @@ def start_transfer(read_file_handle, write_file_handle, data_size): def fetch_image(image, instance, **kwargs):
- """Fetch an image for attaching to the newly created VM."""
+ """ Fetch an image for attaching to the newly created VM """
#Depending upon the image service, make appropriate image service call
if FLAGS.image_service == "nova.image.glance.GlanceImageService":
func = _get_glance_image
@@ -81,8 +78,6 @@ def fetch_image(image, instance, **kwargs): func = _get_s3_image
elif FLAGS.image_service == "nova.image.local.LocalImageService":
func = _get_local_image
- elif FLAGS.image_service == "nova.FakeImageService":
- func = _get_fake_image
else:
raise NotImplementedError(_("The Image Service %s is not implemented")
% FLAGS.image_service)
@@ -90,7 +85,7 @@ def fetch_image(image, instance, **kwargs): def upload_image(image, instance, **kwargs):
- """Upload the newly snapshotted VM disk file."""
+ """ Upload the newly snapshotted VM disk file. """
#Depending upon the image service, make appropriate image service call
if FLAGS.image_service == "nova.image.glance.GlanceImageService":
func = _put_glance_image
@@ -98,8 +93,6 @@ def upload_image(image, instance, **kwargs): func = _put_s3_image
elif FLAGS.image_service == "nova.image.local.LocalImageService":
func = _put_local_image
- elif FLAGS.image_service == "nova.FakeImageService":
- func = _put_fake_image
else:
raise NotImplementedError(_("The Image Service %s is not implemented")
% FLAGS.image_service)
@@ -107,7 +100,7 @@ def upload_image(image, instance, **kwargs): def _get_glance_image(image, instance, **kwargs):
- """Download image from the glance image server."""
+ """ Download image from the glance image server. """
LOG.debug(_("Downloading image %s from glance image server") % image)
read_file_handle = read_write_util.GlanceHTTPReadFile(FLAGS.glance_host,
FLAGS.glance_port,
@@ -125,38 +118,17 @@ def _get_glance_image(image, instance, **kwargs): def _get_s3_image(image, instance, **kwargs):
- """Download image from the S3 image server."""
+ """ Download image from the S3 image server. """
raise NotImplementedError
def _get_local_image(image, instance, **kwargs):
- """Download image from the local nova compute node."""
+ """ Download image from the local nova compute node. """
raise NotImplementedError
-def _get_fake_image(image, instance, **kwargs):
- """ Download a fake image from the nova local file repository for testing
- purposes.
- """
- LOG.debug(_("Downloading image %s from fake image service") % image)
- image = str(image)
- file_path = os.path.join(TEST_IMAGE_PATH, image, image)
- file_path = os.path.abspath(file_path)
- read_file_handle = read_write_util.FakeFileRead(file_path)
- file_size = read_file_handle.get_size()
- write_file_handle = read_write_util.VMWareHTTPWriteFile(
- kwargs.get("host"),
- kwargs.get("data_center_name"),
- kwargs.get("datastore_name"),
- kwargs.get("cookies"),
- kwargs.get("file_path"),
- file_size)
- start_transfer(read_file_handle, write_file_handle, file_size)
- LOG.debug(_("Downloaded image %s from fake image service") % image)
-
-
def _put_glance_image(image, instance, **kwargs):
- """Upload the snapshotted vm disk file to Glance image server."""
+ """ Upload the snapshotted vm disk file to Glance image server """
LOG.debug(_("Uploading image %s to the Glance image server") % image)
read_file_handle = read_write_util.VmWareHTTPReadFile(
kwargs.get("host"),
@@ -178,48 +150,20 @@ def _put_glance_image(image, instance, **kwargs): def _put_local_image(image, instance, **kwargs):
- """Upload the snapshotted vm disk file to the local nova compute node."""
+ """ Upload the snapshotted vm disk file to the local nova compute node. """
raise NotImplementedError
def _put_s3_image(image, instance, **kwargs):
- """Upload the snapshotted vm disk file to S3 image server."""
+ """ Upload the snapshotted vm disk file to S3 image server. """
raise NotImplementedError
-def _put_fake_image(image, instance, **kwargs):
- """ Upload a dummy vmdk from the ESX host to the local file repository of
- the nova node for testing purposes.
- """
- LOG.debug(_("Uploading image %s to the Fake Image Service") % image)
- read_file_handle = read_write_util.VmWareHTTPReadFile(
- kwargs.get("host"),
- kwargs.get("data_center_name"),
- kwargs.get("datastore_name"),
- kwargs.get("cookies"),
- kwargs.get("file_path"))
- file_size = read_file_handle.get_size()
- image = str(image)
- image_dir_path = os.path.join(TEST_IMAGE_PATH, image)
- if not os.path.exists(TEST_IMAGE_PATH):
- os.mkdir(TEST_IMAGE_PATH)
- os.mkdir(image_dir_path)
- else:
- if not os.path.exists(image_dir_path):
- os.mkdir(image_dir_path)
- file_path = os.path.join(image_dir_path, image)
- file_path = os.path.abspath(file_path)
- write_file_handle = read_write_util.FakeFileWrite(file_path)
- start_transfer(read_file_handle, write_file_handle, file_size)
- LOG.debug(_("Uploaded image %s to the Fake Image Service") % image)
-
-
def get_vmdk_size_and_properties(image, instance):
- """
- Get size of the vmdk file that is to be downloaded for attach in spawn.
+ """ Get size of the vmdk file that is to be downloaded for attach in spawn.
Need this to create the dummy virtual disk for the meta-data file. The
- geometry of the disk created depends on the size.
- """
+ geometry of the disk created depends on the size."""
+
LOG.debug(_("Getting image size for the image %s") % image)
if FLAGS.image_service == "nova.image.glance.GlanceImageService":
read_file_handle = read_write_util.GlanceHTTPReadFile(
@@ -230,15 +174,9 @@ def get_vmdk_size_and_properties(image, instance): raise NotImplementedError
elif FLAGS.image_service == "nova.image.local.LocalImageService":
raise NotImplementedError
- elif FLAGS.image_service == "nova.FakeImageService":
- image = str(image)
- file_path = os.path.join(TEST_IMAGE_PATH, image, image)
- file_path = os.path.abspath(file_path)
- read_file_handle = read_write_util.FakeFileRead(file_path)
size = read_file_handle.get_size()
properties = read_file_handle.get_image_properties()
read_file_handle.close()
LOG.debug(_("Got image size of %(size)s for the image %(image)s") %
- {'size': size,
- 'image': image})
+ locals())
return size, properties
diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index 29748fe81..bd3ab4320 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -16,33 +16,30 @@ # under the License.
"""
-Connection class for VMware Infrastructure API in VMware ESX/ESXi platform
-
-Encapsulates the session management activties and acts as interface for VI API.
-The connection class sets up a session with the ESX/ESXi compute provider host
-and handles all the calls made to the host.
+A connection to the VMware ESX platform.
**Related Flags**
-:vmwareapi_host_ip: IP of VMware ESX/ESXi compute provider host
-:vmwareapi_host_username: ESX/ESXi server user to be used for API session
-:vmwareapi_host_password: Password for the user "vmwareapi_host_username"
-:vmwareapi_task_poll_interval: The interval used for polling of remote tasks
-:vmwareapi_api_retry_count: Max number of retry attempts upon API failures
-
+:vmwareapi_host_ip: IPAddress of VMware ESX server.
+:vmwareapi_host_username: Username for connection to VMware ESX Server.
+:vmwareapi_host_password: Password for connection to VMware ESX Server.
+:vmwareapi_task_poll_interval: The interval (seconds) used for polling of
+ remote tasks
+ (default: 1.0).
+:vmwareapi_api_retry_count: The API retry count in case of failure such as
+ network failures (socket errors etc.)
+ (default: 10).
"""
-import logging
import time
-import urlparse
from eventlet import event
from nova import context
from nova import db
from nova import flags
+from nova import log as logging
from nova import utils
-
from nova.virt.vmwareapi import vim
from nova.virt.vmwareapi import vim_util
from nova.virt.vmwareapi.vmops import VMWareVMOps
@@ -71,45 +68,34 @@ flags.DEFINE_float('vmwareapi_api_retry_count', 'The number of times we retry on failures, '
'e.g., socket error, etc.'
'Used only if connection_type is vmwareapi')
+flags.DEFINE_string('vmwareapi_vlan_interface',
+ 'vmnic0',
+ 'Physical ethernet adapter name for vlan networking')
TIME_BETWEEN_API_CALL_RETRIES = 2.0
-class TaskState:
- """Enumeration class for different states of task
- 0 - Task completed successfully
- 1 - Task is in queued state
- 2 - Task is in running state
- """
-
- TASK_SUCCESS = 0
- TASK_QUEUED = 1
- TASK_RUNNING = 2
-
-
class Failure(Exception):
"""Base Exception class for handling task failures"""
def __init__(self, details):
- """Initializer"""
self.details = details
def __str__(self):
- """The informal string representation of the object"""
return str(self.details)
def get_connection(_):
- """Sets up the ESX host connection"""
+ """Sets up the ESX host connection."""
host_ip = FLAGS.vmwareapi_host_ip
host_username = FLAGS.vmwareapi_host_username
host_password = FLAGS.vmwareapi_host_password
api_retry_count = FLAGS.vmwareapi_api_retry_count
- if not host_ip or host_username is None or host_password is None:
- raise Exception('Must specify vmwareapi_host_ip,'
- 'vmwareapi_host_username '
- 'and vmwareapi_host_password to use'
- 'connection_type=vmwareapi')
+ if not host_ip or host_username is None or host_password is None:
+ raise Exception(_("Must specify vmwareapi_host_ip,"
+ "vmwareapi_host_username "
+ "and vmwareapi_host_password to use"
+ "connection_type=vmwareapi"))
return VMWareESXConnection(host_ip, host_username, host_password,
api_retry_count)
@@ -119,7 +105,6 @@ class VMWareESXConnection(object): def __init__(self, host_ip, host_username, host_password,
api_retry_count, scheme="https"):
- """The Initializer"""
session = VMWareAPISession(host_ip, host_username, host_password,
api_retry_count, scheme=scheme)
self._vmops = VMWareVMOps(session)
@@ -191,22 +176,18 @@ class VMWareESXConnection(object): def get_console_pool_info(self, console_type):
"""Get info about the host on which the VM resides"""
- esx_url = urlparse.urlparse(FLAGS.vmwareapi_host_ip)
- return {'address': esx_url.netloc,
- 'username': FLAGS.vmwareapi_host_password,
- 'password': FLAGS.vmwareapi_host_password}
-
- def _create_dummy_vm_for_test(self, instance):
- """Creates a dummy VM with default parameters for testing purpose"""
- return self._vmops._create_dummy_vm_for_test(instance)
+ return {'address': FLAGS.vmwareapi_host_ip,
+ 'username': FLAGS.vmwareapi_host_username,
+ 'password': FLAGS.vmwareapi_host_password}
class VMWareAPISession(object):
- """Sets up a session with ESX host and handles all calls made to host"""
+ """Sets up a session with the ESX host and handles all
+ the calls made to the host
+ """
def __init__(self, host_ip, host_username, host_password,
api_retry_count, scheme="https"):
- """Set the connection credentials"""
self._host_ip = host_ip
self._host_username = host_username
self._host_password = host_password
@@ -216,15 +197,19 @@ class VMWareAPISession(object): 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)
+
def _create_session(self):
"""Creates a session with the ESX host"""
while True:
try:
# Login and setup the session with the ESX host for making
# API calls
- self.vim = vim.Vim(protocol=self._scheme, host=self._host_ip)
+ self.vim = self._get_vim_object()
session = self.vim.Login(
- self.vim.get_service_content().SessionManager,
+ self.vim.get_service_content().sessionManager,
userName=self._host_username,
password=self._host_password)
# Terminate the earlier session, if possible ( For the sake of
@@ -233,34 +218,40 @@ class VMWareAPISession(object): if self._session_id:
try:
self.vim.TerminateSession(
- self.vim.get_service_content().SessionManager,
+ self.vim.get_service_content().sessionManager,
sessionId=[self._session_id])
except Exception, excep:
LOG.exception(excep)
- self._session_id = session.Key
+ self._session_id = session.key
return
except Exception, excep:
- LOG.info(_("In vmwareapi:_create_session, "
+ LOG.critical(_("In vmwareapi:_create_session, "
"got this exception: %s") % excep)
raise Exception(excep)
def __del__(self):
- """The Destructor. Logs-out the session."""
+ """Logs-out the session."""
# Logout to avoid un-necessary increase in session count at the
# ESX host
try:
- self.vim.Logout(self.vim.get_service_content().SessionManager)
+ self.vim.Logout(self.vim.get_service_content().sessionManager)
except Exception:
pass
+ def _is_vim_object(self, module):
+ """Check if the module is a VIM Object instance"""
+ return isinstance(module, vim.Vim)
+
def _call_method(self, module, method, *args, **kwargs):
- """Calls a method within the module specified with args provided"""
+ """Calls a method within the module specified with
+ args provided
+ """
args = list(args)
retry_count = 0
exc = None
while True:
try:
- if not isinstance(module, vim.Vim):
+ 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:]
@@ -295,8 +286,8 @@ class VMWareAPISession(object): break
time.sleep(TIME_BETWEEN_API_CALL_RETRIES)
- LOG.info(_("In vmwareapi:_call_method, "
- "got this exception: ") % exc)
+ LOG.critical(_("In vmwareapi:_call_method, "
+ "got this exception: %s") % exc)
raise Exception(exc)
def _get_vim(self):
@@ -306,8 +297,7 @@ class VMWareAPISession(object): return self.vim
def _wait_for_task(self, instance_id, task_ref):
- """
- Return a Deferred that will give the result of the given task.
+ """Return a Deferred that will give the result of the given task.
The task is polled until it completes.
"""
done = event.Event()
@@ -319,36 +309,30 @@ class VMWareAPISession(object): return ret_val
def _poll_task(self, instance_id, task_ref, done):
- """
- Poll the given task, and fires the given Deferred if we
+ """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
+ task_name = task_info.name
action = dict(
instance_id=int(instance_id),
action=task_name[0:255],
error=None)
- if task_info.State in [TaskState.TASK_QUEUED,
- TaskState.TASK_RUNNING]:
+ if task_info.state in ['queued', 'running']:
return
- elif task_info.State == TaskState.TASK_SUCCESS:
- LOG.info(_("Task [%(taskname)s] %(taskref)s status: success") %
- {'taskname': task_name,
- 'taskref': str(task_ref)})
- done.send(TaskState.TASK_SUCCESS)
+ elif task_info.state == 'success':
+ LOG.info(_("Task [%(task_name)s] %(task_ref)s "
+ "status: success") % locals())
+ done.send("success")
else:
- error_info = str(task_info.Error.LocalizedMessage)
+ error_info = str(task_info.error.localizedMessage)
action["error"] = error_info
- LOG.info(_("Task [%(task_name)s] %(task_ref)s status: "
- "error [%(error_info)s]") %
- {'task_name': task_name,
- 'task_ref': str(task_ref),
- 'error_info': error_info})
+ LOG.warn(_("Task [%(task_name)s] %(task_ref)s "
+ "status: error %(error_info)s") % locals())
done.send_exception(Exception(error_info))
db.instance_action_create(context.get_admin_context(), action)
except Exception, excep:
- LOG.info(_("In vmwareapi:_poll_task, Got this error %s") % excep)
+ LOG.warn(_("In vmwareapi:_poll_task, Got this error %s") % excep)
done.send_exception(excep)
|
