* Updated document vmware_readme.rst to mention VLAN networking

* Corrected docstrings as per pep0257 recommentations.
* Stream-lined the comments.
* Updated code with locals() where ever applicable.
* VIM : It stands for VMware Virtual Infrastructure Methodology. We have used the terminology from VMware.  we have added a question in FAQ inside vmware_readme.rst in doc/source
* New fake db: vmwareapi fake module uses a different set of fields and hence the structures required are different. Ex: bridge : 'xenbr0' does not hold good for VMware environment and bridge : 'vmnic0' is used instead. Also return values varies, hence went for implementing separate fake db.
* Now using eventlet library instead and removed io_utils.py from branch.
* Now using glance.client.Client instead of homegrown code to talk to Glance server to handle images.
* Corrected all mis-spelled function names and corresponding calls. Yeah, an auto-complete side-effect!
This commit is contained in:
sateesh 2011-03-16 21:54:02 +05:30
parent cd381ae3e1
commit 45ca7b71a8
20 changed files with 500 additions and 545 deletions

View File

@ -26,7 +26,7 @@ The basic requirement is to support VMware vSphere 4.1 as a compute provider wit
The 'vmwareapi' module is integrated with Glance, so that VM images can be streamed from there for boot on ESXi using Glance server for image storage & retrieval. The 'vmwareapi' module is integrated with Glance, so that VM images can be streamed from there for boot on ESXi using Glance server for image storage & retrieval.
Currently supports Nova's flat networking model (Flat Manager). Currently supports Nova's flat networking model (Flat Manager) & VLAN networking model.
.. image:: images/vmwareapi_blockdiagram.jpg .. image:: images/vmwareapi_blockdiagram.jpg
@ -213,3 +213,7 @@ FAQ
* VMware VMRC based consoles are supported. There are 2 options for credentials one is OTP (Secure but creates multiple session entries in DB for each OpenStack console create request.) & other is host based credentials (It may not be secure as ESX credentials are transmitted as clear text). * VMware VMRC based consoles are supported. There are 2 options for credentials one is OTP (Secure but creates multiple session entries in DB for each OpenStack console create request.) & other is host based credentials (It may not be secure as ESX credentials are transmitted as clear text).
5. What does 'Vim' refer to as far as vmwareapi module is concerned?
* Vim refers to VMware Virtual Infrastructure Methodology. This is not to be confused with "VIM" editor.

View File

@ -65,11 +65,13 @@ class VMRCConsole(object):
def fix_pool_password(self, password): def fix_pool_password(self, password):
"""Encode password.""" """Encode password."""
#TODO:Encrypt pool password # TODO(sateesh): Encrypt pool password
return password return password
def generate_password(self, vim_session, pool, instance_name): def generate_password(self, vim_session, pool, instance_name):
"""Returns a VMRC Connection credentials """
Returns VMRC Connection credentials.
Return string is of the form '<VM PATH>:<ESX Username>@<ESX Password>'. Return string is of the form '<VM PATH>:<ESX Username>@<ESX Password>'.
""" """
username, password = pool['username'], pool['password'] username, password = pool['username'], pool['password']
@ -98,12 +100,12 @@ class VMRCConsole(object):
return base64.b64encode(json_data) return base64.b64encode(json_data)
def is_otp(self): def is_otp(self):
"""Is one time password.""" """Is one time password or not."""
return False return False
class VMRCSessionConsole(VMRCConsole): class VMRCSessionConsole(VMRCConsole):
"""VMRC console driver with VMRC One Time Sessions""" """VMRC console driver with VMRC One Time Sessions."""
def __init__(self): def __init__(self):
super(VMRCSessionConsole, self).__init__() super(VMRCSessionConsole, self).__init__()
@ -113,7 +115,9 @@ class VMRCSessionConsole(VMRCConsole):
return 'vmrc+session' return 'vmrc+session'
def generate_password(self, vim_session, pool, instance_name): def generate_password(self, vim_session, pool, instance_name):
"""Returns a VMRC Session """
Returns a VMRC Session.
Return string is of the form '<VM MOID>:<VMRC Ticket>'. Return string is of the form '<VM MOID>:<VMRC Ticket>'.
""" """
vms = vim_session._call_method(vim_util, "get_objects", vms = vim_session._call_method(vim_util, "get_objects",
@ -136,5 +140,5 @@ class VMRCSessionConsole(VMRCConsole):
return base64.b64encode(json_data) return base64.b64encode(json_data)
def is_otp(self): def is_otp(self):
"""Is one time password.""" """Is one time password or not."""
return True return True

View File

@ -16,7 +16,7 @@
# under the License. # under the License.
""" """
VMRC Console Manager VMRC Console Manager.
""" """
from nova import exception from nova import exception
@ -25,6 +25,7 @@ from nova import log as logging
from nova import manager from nova import manager
from nova import rpc from nova import rpc
from nova import utils from nova import utils
from nova.virt.vmwareapi_conn import VMWareAPISession
LOG = logging.getLogger("nova.console.vmrc_manager") LOG = logging.getLogger("nova.console.vmrc_manager")
@ -39,8 +40,8 @@ flags.DEFINE_string('console_driver',
class ConsoleVMRCManager(manager.Manager): class ConsoleVMRCManager(manager.Manager):
"""Manager to handle VMRC connections needed for accessing """
instance consoles Manager to handle VMRC connections needed for accessing instance consoles.
""" """
def __init__(self, console_driver=None, *args, **kwargs): def __init__(self, console_driver=None, *args, **kwargs):
@ -48,15 +49,29 @@ class ConsoleVMRCManager(manager.Manager):
super(ConsoleVMRCManager, self).__init__(*args, **kwargs) super(ConsoleVMRCManager, self).__init__(*args, **kwargs)
def init_host(self): def init_host(self):
self.sessions = {}
self.driver.init_host() self.driver.init_host()
def _get_vim_session(self, pool):
"""Get VIM session for the pool specified."""
vim_session = None
if pool['id'] not in self.sessions.keys():
vim_session = VMWareAPISession(pool['address'],
pool['username'],
pool['password'],
FLAGS.console_vmrc_error_retries)
self.sessions[pool['id']] = vim_session
return self.sessions[pool['id']]
def _generate_console(self, context, pool, name, instance_id, instance): def _generate_console(self, context, pool, name, instance_id, instance):
"""Sets up console for the instance."""
LOG.debug(_("Adding console")) LOG.debug(_("Adding console"))
password = self.driver.generate_password( password = self.driver.generate_password(
pool['address'], self._get_vim_session(pool),
pool['username'], pool,
pool['password'],
instance.name) instance.name)
console_data = {'instance_name': name, console_data = {'instance_name': name,
'instance_id': instance_id, 'instance_id': instance_id,
'password': password, 'password': password,
@ -69,6 +84,10 @@ class ConsoleVMRCManager(manager.Manager):
@exception.wrap_exception @exception.wrap_exception
def add_console(self, context, instance_id, password=None, def add_console(self, context, instance_id, password=None,
port=None, **kwargs): port=None, **kwargs):
"""
Adds a console for the instance. If it is one time password, then we
generate new console credentials.
"""
instance = self.db.instance_get(context, instance_id) instance = self.db.instance_get(context, instance_id)
host = instance['host'] host = instance['host']
name = instance['name'] name = instance['name']
@ -95,6 +114,7 @@ class ConsoleVMRCManager(manager.Manager):
@exception.wrap_exception @exception.wrap_exception
def remove_console(self, context, console_id, **_kwargs): def remove_console(self, context, console_id, **_kwargs):
"""Removes a console entry."""
try: try:
console = self.db.console_get(context, console_id) console = self.db.console_get(context, console_id)
except exception.NotFound: except exception.NotFound:
@ -109,6 +129,7 @@ class ConsoleVMRCManager(manager.Manager):
self.driver.teardown_console(context, console) self.driver.teardown_console(context, console)
def get_pool_for_instance_host(self, context, instance_host): def get_pool_for_instance_host(self, context, instance_host):
"""Gets console pool info for the instance."""
context = context.elevated() context = context.elevated()
console_type = self.driver.console_type console_type = self.driver.console_type
try: try:
@ -126,7 +147,7 @@ class ConsoleVMRCManager(manager.Manager):
pool_info['password'] = self.driver.fix_pool_password( pool_info['password'] = self.driver.fix_pool_password(
pool_info['password']) pool_info['password'])
pool_info['host'] = self.host pool_info['host'] = self.host
#ESX Address or Proxy Address # ESX Address or Proxy Address
public_host_name = pool_info['address'] public_host_name = pool_info['address']
if FLAGS.console_public_hostname: if FLAGS.console_public_hostname:
public_host_name = FLAGS.console_public_hostname public_host_name = FLAGS.console_public_hostname

View File

@ -16,7 +16,7 @@
# under the License. # under the License.
""" """
Implements vlans for vmwareapi Implements vlans for vmwareapi.
""" """
from nova import db from nova import db
@ -36,8 +36,8 @@ flags.DEFINE_string('vlan_interface', 'vmnic0',
def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None): def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None):
"""Create a vlan and bridge unless they already exist""" """Create a vlan and bridge unless they already exist."""
#open vmwareapi session # Open vmwareapi session
host_ip = FLAGS.vmwareapi_host_ip host_ip = FLAGS.vmwareapi_host_ip
host_username = FLAGS.vmwareapi_host_username host_username = FLAGS.vmwareapi_host_username
host_password = FLAGS.vmwareapi_host_password host_password = FLAGS.vmwareapi_host_password
@ -49,49 +49,43 @@ def ensure_vlan_bridge(vlan_num, bridge, net_attrs=None):
session = VMWareAPISession(host_ip, host_username, host_password, session = VMWareAPISession(host_ip, host_username, host_password,
FLAGS.vmwareapi_api_retry_count) FLAGS.vmwareapi_api_retry_count)
vlan_interface = FLAGS.vlan_interface vlan_interface = FLAGS.vlan_interface
#Check if the vlan_interface physical network adapter exists on the host # Check if the vlan_interface physical network adapter exists on the host
if not NetworkHelper.check_if_vlan_interface_exists(session, if not NetworkHelper.check_if_vlan_interface_exists(session,
vlan_interface): vlan_interface):
raise exception.NotFound(_("There is no physical network adapter with " raise exception.NotFound(_("There is no physical network adapter with "
"the name %s on the ESX host") % vlan_interface) "the name %s on the ESX host") % vlan_interface)
#Get the vSwitch associated with the Physical Adapter # Get the vSwitch associated with the Physical Adapter
vswitch_associated = NetworkHelper.get_vswitch_for_vlan_interface( vswitch_associated = NetworkHelper.get_vswitch_for_vlan_interface(
session, vlan_interface) session, vlan_interface)
if vswitch_associated is None: if vswitch_associated is None:
raise exception.NotFound(_("There is no virtual switch associated " raise exception.NotFound(_("There is no virtual switch associated "
"with the physical network adapter with name %s") % "with the physical network adapter with name %s") %
vlan_interface) vlan_interface)
#check whether bridge already exists and retrieve the the ref of the # Check whether bridge already exists and retrieve the the ref of the
#network whose name_label is "bridge" # network whose name_label is "bridge"
network_ref = NetworkHelper.get_network_with_the_name(session, bridge) network_ref = NetworkHelper.get_network_with_the_name(session, bridge)
if network_ref == None: if network_ref == None:
#Create a port group on the vSwitch associated with the vlan_interface # Create a port group on the vSwitch associated with the vlan_interface
#corresponding physical network adapter on the ESX host # corresponding physical network adapter on the ESX host
NetworkHelper.create_port_group(session, bridge, vswitch_associated, NetworkHelper.create_port_group(session, bridge, vswitch_associated,
vlan_num) vlan_num)
else: else:
#Get the vlan id and vswitch corresponding to the port group # Get the vlan id and vswitch corresponding to the port group
pg_vlanid, pg_vswitch = \ pg_vlanid, pg_vswitch = \
NetworkHelper.get_vlanid_and_vswicth_for_portgroup(session, bridge) NetworkHelper.get_vlanid_and_vswitch_for_portgroup(session, bridge)
#Check if the vsiwtch associated is proper # Check if the vsiwtch associated is proper
if pg_vswitch != vswitch_associated: if pg_vswitch != vswitch_associated:
raise exception.Invalid(_("vSwitch which contains the port group " raise exception.Invalid(_("vSwitch which contains the port group "
"%(bridge)s is not associated with the desired " "%(bridge)s is not associated with the desired "
"physical adapter. Expected vSwitch is " "physical adapter. Expected vSwitch is "
"%(vswitch_associated)s, but the one associated" "%(vswitch_associated)s, but the one associated"
" is %(pg_vswitch)s") %\ " is %(pg_vswitch)s") % locals())
{"bridge": bridge,
"vswitch_associated": vswitch_associated,
"pg_vswitch": pg_vswitch})
#Check if the vlan id is proper for the port group # Check if the vlan id is proper for the port group
if pg_vlanid != vlan_num: if pg_vlanid != vlan_num:
raise exception.Invalid(_("VLAN tag is not appropriate for the " raise exception.Invalid(_("VLAN tag is not appropriate for the "
"port group %(bridge)s. Expected VLAN tag is " "port group %(bridge)s. Expected VLAN tag is "
"%(vlan_num)s, but the one associated with the " "%(vlan_num)s, but the one associated with the "
"port group is %(pg_vlanid)s") %\ "port group is %(pg_vlanid)s") % locals())
{"bridge": bridge,
"vlan_num": vlan_num,
"pg_vlanid": pg_vlanid})

View File

@ -16,8 +16,9 @@
# under the License. # under the License.
""" """
Test suite for VMWareAPI Test suite for VMWareAPI.
""" """
import stubout import stubout
from nova import context from nova import context
@ -38,9 +39,7 @@ FLAGS = flags.FLAGS
class VMWareAPIVMTestCase(test.TestCase): class VMWareAPIVMTestCase(test.TestCase):
""" """Unit tests for Vmware API connection calls."""
Unit tests for Vmware API connection calls
"""
def setUp(self): def setUp(self):
super(VMWareAPIVMTestCase, self).setUp() super(VMWareAPIVMTestCase, self).setUp()
@ -61,7 +60,7 @@ class VMWareAPIVMTestCase(test.TestCase):
self.conn = vmwareapi_conn.get_connection(False) self.conn = vmwareapi_conn.get_connection(False)
def _create_vm(self): def _create_vm(self):
""" Create and spawn the VM """ """Create and spawn the VM."""
values = {'name': 1, values = {'name': 1,
'id': 1, 'id': 1,
'project_id': self.project.id, 'project_id': self.project.id,
@ -78,15 +77,17 @@ class VMWareAPIVMTestCase(test.TestCase):
self._check_vm_record() self._check_vm_record()
def _check_vm_record(self): def _check_vm_record(self):
""" Check if the spawned VM's properties corresponds to the instance in """
the db """ Check if the spawned VM's properties correspond to the instance in
the db.
"""
instances = self.conn.list_instances() instances = self.conn.list_instances()
self.assertEquals(len(instances), 1) self.assertEquals(len(instances), 1)
# Get Nova record for VM # Get Nova record for VM
vm_info = self.conn.get_info(1) vm_info = self.conn.get_info(1)
# Get record for VMs # Get record for VM
vms = vmwareapi_fake._get_objects("VirtualMachine") vms = vmwareapi_fake._get_objects("VirtualMachine")
vm = vms[0] vm = vms[0]
@ -106,8 +107,10 @@ class VMWareAPIVMTestCase(test.TestCase):
self.assertEquals(vm.get("runtime.powerState"), 'poweredOn') self.assertEquals(vm.get("runtime.powerState"), 'poweredOn')
def _check_vm_info(self, info, pwr_state=power_state.RUNNING): def _check_vm_info(self, info, pwr_state=power_state.RUNNING):
""" Check if the get_info returned values correspond to the instance """
object in the db """ Check if the get_info returned values correspond to the instance
object in the db.
"""
mem_kib = long(self.type_data['memory_mb']) << 10 mem_kib = long(self.type_data['memory_mb']) << 10
self.assertEquals(info["state"], pwr_state) self.assertEquals(info["state"], pwr_state)
self.assertEquals(info["max_mem"], mem_kib) self.assertEquals(info["max_mem"], mem_kib)
@ -194,8 +197,9 @@ class VMWareAPIVMTestCase(test.TestCase):
pass pass
def dummy_callback_handler(self, ret): def dummy_callback_handler(self, ret):
""" Dummy callback function to be passed to suspend, resume, etc. """
calls """ Dummy callback function to be passed to suspend, resume, etc., calls.
"""
pass pass
def tearDown(self): def tearDown(self):

View File

@ -14,3 +14,8 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
"""
:mod:`vmwareapi` -- Stubs for VMware API
=======================================
"""

View File

@ -26,7 +26,7 @@ from nova import utils
def stub_out_db_instance_api(stubs): def stub_out_db_instance_api(stubs):
""" Stubs out the db API for creating Instances """ """Stubs out the db API for creating Instances."""
INSTANCE_TYPES = { INSTANCE_TYPES = {
'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1), 'm1.tiny': dict(memory_mb=512, vcpus=1, local_gb=0, flavorid=1),
@ -38,7 +38,7 @@ def stub_out_db_instance_api(stubs):
dict(memory_mb=16384, vcpus=8, local_gb=160, flavorid=5)} dict(memory_mb=16384, vcpus=8, local_gb=160, flavorid=5)}
class FakeModel(object): class FakeModel(object):
""" Stubs out for model """ """Stubs out for model."""
def __init__(self, values): def __init__(self, values):
self.values = values self.values = values
@ -53,7 +53,7 @@ def stub_out_db_instance_api(stubs):
raise NotImplementedError() raise NotImplementedError()
def fake_instance_create(values): def fake_instance_create(values):
""" Stubs out the db.instance_create method """ """Stubs out the db.instance_create method."""
type_data = INSTANCE_TYPES[values['instance_type']] type_data = INSTANCE_TYPES[values['instance_type']]
@ -77,7 +77,7 @@ def stub_out_db_instance_api(stubs):
return FakeModel(base_options) return FakeModel(base_options)
def fake_network_get_by_instance(context, instance_id): def fake_network_get_by_instance(context, instance_id):
""" Stubs out the db.network_get_by_instance method """ """Stubs out the db.network_get_by_instance method."""
fields = { fields = {
'bridge': 'vmnet0', 'bridge': 'vmnet0',
@ -87,11 +87,11 @@ def stub_out_db_instance_api(stubs):
return FakeModel(fields) return FakeModel(fields)
def fake_instance_action_create(context, action): def fake_instance_action_create(context, action):
""" Stubs out the db.instance_action_create method """ """Stubs out the db.instance_action_create method."""
pass pass
def fake_instance_get_fixed_address(context, instance_id): def fake_instance_get_fixed_address(context, instance_id):
""" Stubs out the db.instance_get_fixed_address method """ """Stubs out the db.instance_get_fixed_address method."""
return '10.10.10.10' return '10.10.10.10'
def fake_instance_type_get_all(context, inactive=0): def fake_instance_type_get_all(context, inactive=0):

View File

@ -25,17 +25,17 @@ from nova.virt.vmwareapi import vmware_images
def fake_get_vim_object(arg): def fake_get_vim_object(arg):
""" Stubs out the VMWareAPISession's get_vim_object method """ """Stubs out the VMWareAPISession's get_vim_object method."""
return fake.FakeVim() return fake.FakeVim()
def fake_is_vim_object(arg, module): def fake_is_vim_object(arg, module):
""" Stubs out the VMWareAPISession's is_vim_object method """ """Stubs out the VMWareAPISession's is_vim_object method."""
return isinstance(module, fake.FakeVim) return isinstance(module, fake.FakeVim)
def set_stubs(stubs): def set_stubs(stubs):
""" Set the stubs """ """Set the stubs."""
stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image) stubs.Set(vmware_images, 'fetch_image', fake.fake_fetch_image)
stubs.Set(vmware_images, 'get_vmdk_size_and_properties', stubs.Set(vmware_images, 'get_vmdk_size_and_properties',
fake.fake_get_vmdk_size_and_properties) fake.fake_get_vmdk_size_and_properties)

View File

@ -15,5 +15,5 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
""" """
:mod:`vmwareapi` -- Nova support for VMware ESX/ESXi Server through vSphere API :mod:`vmwareapi` -- Nova support for VMware ESX/ESXi Server through VMware API.
""" """

View File

@ -16,7 +16,7 @@
# under the License. # under the License.
""" """
Exception classes and SOAP response error checking module Exception classes and SOAP response error checking module.
""" """
FAULT_NOT_AUTHENTICATED = "NotAuthenticated" FAULT_NOT_AUTHENTICATED = "NotAuthenticated"
@ -24,7 +24,7 @@ FAULT_ALREADY_EXISTS = "AlreadyExists"
class VimException(Exception): class VimException(Exception):
"""The VIM Exception class""" """The VIM Exception class."""
def __init__(self, exception_summary, excep): def __init__(self, exception_summary, excep):
Exception.__init__(self) Exception.__init__(self)
@ -36,17 +36,17 @@ class VimException(Exception):
class SessionOverLoadException(VimException): class SessionOverLoadException(VimException):
"""Session Overload Exception""" """Session Overload Exception."""
pass pass
class VimAttributeError(VimException): class VimAttributeError(VimException):
"""VI Attribute Error""" """VI Attribute Error."""
pass pass
class VimFaultException(Exception): class VimFaultException(Exception):
"""The VIM Fault exception class""" """The VIM Fault exception class."""
def __init__(self, fault_list, excep): def __init__(self, fault_list, excep):
Exception.__init__(self) Exception.__init__(self)
@ -58,23 +58,37 @@ class VimFaultException(Exception):
class FaultCheckers: class FaultCheckers:
"""Methods for fault checking of SOAP response. Per Method error handlers """
Methods for fault checking of SOAP response. Per Method error handlers
for which we desire error checking are defined. SOAP faults are for which we desire error checking are defined. SOAP faults are
embedded in the SOAP as a property and not as a SOAP fault.""" embedded in the SOAP messages as properties and not as SOAP faults.
"""
@classmethod @classmethod
def retrieveproperties_fault_checker(self, resp_obj): def retrieveproperties_fault_checker(self, resp_obj):
"""Checks the RetrieveProperties response for errors. Certain faults """
are sent as a part of the SOAP body as property of missingSet. Checks the RetrieveProperties response for errors. Certain faults
For example NotAuthenticated fault""" are sent as part of the SOAP body as property of missingSet.
For example NotAuthenticated fault.
"""
fault_list = [] fault_list = []
for obj_cont in resp_obj: if not resp_obj:
if hasattr(obj_cont, "missingSet"): # This is the case when the session has timed out. ESX SOAP server
for missing_elem in obj_cont.missingSet: # sends an empty RetrievePropertiesResponse. Normally missingSet in
fault_type = missing_elem.fault.fault.__class__.__name__ # the returnval field has the specifics about the error, but that's
#Fault needs to be added to the type of fault for # not the case with a timed out idle session. It is as bad as a
#uniformity in error checking as SOAP faults define # terminated session for we cannot use the session. So setting
fault_list.append(fault_type) # fault to NotAuthenticated fault.
fault_list = ["NotAuthenticated"]
else:
for obj_cont in resp_obj:
if hasattr(obj_cont, "missingSet"):
for missing_elem in obj_cont.missingSet:
fault_type = \
missing_elem.fault.fault.__class__.__name__
# Fault needs to be added to the type of fault for
# uniformity in error checking as SOAP faults define
fault_list.append(fault_type)
if fault_list: if fault_list:
exc_msg_list = ', '.join(fault_list) exc_msg_list = ', '.join(fault_list)
raise VimFaultException(fault_list, Exception(_("Error(s) %s " raise VimFaultException(fault_list, Exception(_("Error(s) %s "

View File

@ -39,14 +39,14 @@ LOG = logging.getLogger("nova.virt.vmwareapi.fake")
def log_db_contents(msg=None): def log_db_contents(msg=None):
""" Log DB Contents""" """Log DB Contents."""
text = msg or "" text = msg or ""
content = pformat(_db_content) content = pformat(_db_content)
LOG.debug(_("%(text)s: _db_content => %(content)s") % locals()) LOG.debug(_("%(text)s: _db_content => %(content)s") % locals())
def reset(): def reset():
""" Resets the db contents """ """Resets the db contents."""
for c in _CLASSES: for c in _CLASSES:
#We fake the datastore by keeping the file references as a list of #We fake the datastore by keeping the file references as a list of
#names in the db #names in the db
@ -63,18 +63,18 @@ def reset():
def cleanup(): def cleanup():
""" Clear the db contents """ """Clear the db contents."""
for c in _CLASSES: for c in _CLASSES:
_db_content[c] = {} _db_content[c] = {}
def _create_object(table, obj): def _create_object(table, obj):
""" Create an object in the db """ """Create an object in the db."""
_db_content[table][obj.obj] = obj _db_content[table][obj.obj] = obj
def _get_objects(type): def _get_objects(type):
""" Get objects of the type """ """Get objects of the type."""
lst_objs = [] lst_objs = []
for key in _db_content[type]: for key in _db_content[type]:
lst_objs.append(_db_content[type][key]) lst_objs.append(_db_content[type][key])
@ -82,7 +82,7 @@ def _get_objects(type):
class Prop(object): class Prop(object):
""" Property Object base class """ """Property Object base class."""
def __init__(self): def __init__(self):
self.name = None self.name = None
@ -96,10 +96,10 @@ class Prop(object):
class ManagedObject(object): class ManagedObject(object):
""" Managed Data Object base class """ """Managed Data Object base class."""
def __init__(self, name="ManagedObject", obj_ref=None): def __init__(self, name="ManagedObject", obj_ref=None):
""" Sets the obj property which acts as a reference to the object""" """Sets the obj property which acts as a reference to the object."""
object.__setattr__(self, 'objName', name) object.__setattr__(self, 'objName', name)
if obj_ref is None: if obj_ref is None:
obj_ref = str(uuid.uuid4()) obj_ref = str(uuid.uuid4())
@ -107,14 +107,18 @@ class ManagedObject(object):
object.__setattr__(self, 'propSet', []) object.__setattr__(self, 'propSet', [])
def set(self, attr, val): def set(self, attr, val):
""" Sets an attribute value. Not using the __setattr__ directly for we """
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 want to set attributes of the type 'a.b.c' and using this function
class we set the same """ class we set the same.
"""
self.__setattr__(attr, val) self.__setattr__(attr, val)
def get(self, attr): def get(self, attr):
""" Gets an attribute. Used as an intermediary to get nested """
property like 'a.b.c' value """ Gets an attribute. Used as an intermediary to get nested
property like 'a.b.c' value.
"""
return self.__getattr__(attr) return self.__getattr__(attr)
def __setattr__(self, attr, val): def __setattr__(self, attr, val):
@ -138,7 +142,7 @@ class ManagedObject(object):
class DataObject(object): class DataObject(object):
""" Data object base class """ """Data object base class."""
def __init__(self): def __init__(self):
pass pass
@ -151,30 +155,32 @@ class DataObject(object):
class VirtualDisk(DataObject): class VirtualDisk(DataObject):
""" Virtual Disk class. Does nothing special except setting """
Virtual Disk class. Does nothing special except setting
__class__.__name__ to 'VirtualDisk'. Refer place where __class__.__name__ __class__.__name__ to 'VirtualDisk'. Refer place where __class__.__name__
is used in the code """ is used in the code.
"""
def __init__(self): def __init__(self):
DataObject.__init__(self) DataObject.__init__(self)
class VirtualDiskFlatVer2BackingInfo(DataObject): class VirtualDiskFlatVer2BackingInfo(DataObject):
""" VirtualDiskFlatVer2BackingInfo class """ """VirtualDiskFlatVer2BackingInfo class."""
def __init__(self): def __init__(self):
DataObject.__init__(self) DataObject.__init__(self)
class VirtualLsiLogicController(DataObject): class VirtualLsiLogicController(DataObject):
""" VirtualLsiLogicController class """ """VirtualLsiLogicController class."""
def __init__(self): def __init__(self):
DataObject.__init__(self) DataObject.__init__(self)
class VirtualMachine(ManagedObject): class VirtualMachine(ManagedObject):
""" Virtual Machine class """ """Virtual Machine class."""
def __init__(self, **kwargs): def __init__(self, **kwargs):
ManagedObject.__init__(self, "VirtualMachine") ManagedObject.__init__(self, "VirtualMachine")
@ -195,8 +201,10 @@ class VirtualMachine(ManagedObject):
self.set("config.extraConfig", kwargs.get("extra_config", None)) self.set("config.extraConfig", kwargs.get("extra_config", None))
def reconfig(self, factory, val): def reconfig(self, factory, val):
""" Called to reconfigure the VM. Actually customizes the property """
setting of the Virtual Machine object """ Called to reconfigure the VM. Actually customizes the property
setting of the Virtual Machine object.
"""
try: try:
#Case of Reconfig of VM to attach disk #Case of Reconfig of VM to attach disk
controller_key = val.deviceChange[1].device.controllerKey controller_key = val.deviceChange[1].device.controllerKey
@ -220,7 +228,7 @@ class VirtualMachine(ManagedObject):
class Network(ManagedObject): class Network(ManagedObject):
""" Network class """ """Network class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "Network") ManagedObject.__init__(self, "Network")
@ -228,7 +236,7 @@ class Network(ManagedObject):
class ResourcePool(ManagedObject): class ResourcePool(ManagedObject):
""" Resource Pool class """ """Resource Pool class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "ResourcePool") ManagedObject.__init__(self, "ResourcePool")
@ -236,7 +244,7 @@ class ResourcePool(ManagedObject):
class Datastore(ManagedObject): class Datastore(ManagedObject):
""" Datastore class """ """Datastore class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "Datastore") ManagedObject.__init__(self, "Datastore")
@ -245,7 +253,7 @@ class Datastore(ManagedObject):
class HostNetworkSystem(ManagedObject): class HostNetworkSystem(ManagedObject):
""" HostNetworkSystem class """ """HostNetworkSystem class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "HostNetworkSystem") ManagedObject.__init__(self, "HostNetworkSystem")
@ -261,7 +269,7 @@ class HostNetworkSystem(ManagedObject):
class HostSystem(ManagedObject): class HostSystem(ManagedObject):
""" Host System class """ """Host System class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "HostSystem") ManagedObject.__init__(self, "HostSystem")
@ -302,7 +310,7 @@ class HostSystem(ManagedObject):
self.set("config.network.portgroup", host_pg) self.set("config.network.portgroup", host_pg)
def _add_port_group(self, spec): def _add_port_group(self, spec):
""" Adds a port group to the host system object in the db """ """Adds a port group to the host system object in the db."""
pg_name = spec.name pg_name = spec.name
vswitch_name = spec.vswitchName vswitch_name = spec.vswitchName
vlanid = spec.vlanId vlanid = spec.vlanId
@ -328,7 +336,7 @@ class HostSystem(ManagedObject):
class Datacenter(ManagedObject): class Datacenter(ManagedObject):
""" Datacenter class """ """Datacenter class."""
def __init__(self): def __init__(self):
ManagedObject.__init__(self, "Datacenter") ManagedObject.__init__(self, "Datacenter")
@ -343,7 +351,7 @@ class Datacenter(ManagedObject):
class Task(ManagedObject): class Task(ManagedObject):
""" Task class """ """Task class."""
def __init__(self, task_name, state="running"): def __init__(self, task_name, state="running"):
ManagedObject.__init__(self, "Task") ManagedObject.__init__(self, "Task")
@ -390,12 +398,12 @@ def create_task(task_name, state="running"):
def _add_file(file_path): def _add_file(file_path):
""" Adds a file reference to the db """ """Adds a file reference to the db."""
_db_content["files"].append(file_path) _db_content["files"].append(file_path)
def _remove_file(file_path): def _remove_file(file_path):
""" Removes a file reference from the db """ """Removes a file reference from the db."""
if _db_content.get("files", None) is None: if _db_content.get("files", None) is None:
raise exception.NotFound(_("No files have been added yet")) raise exception.NotFound(_("No files have been added yet"))
#Check if the remove is for a single file object or for a folder #Check if the remove is for a single file object or for a folder
@ -415,7 +423,7 @@ def _remove_file(file_path):
def fake_fetch_image(image, instance, **kwargs): def fake_fetch_image(image, instance, **kwargs):
"""Fakes fetch image call. Just adds a reference to the db for the file """ """Fakes fetch image call. Just adds a reference to the db for the file."""
ds_name = kwargs.get("datastore_name") ds_name = kwargs.get("datastore_name")
file_path = kwargs.get("file_path") file_path = kwargs.get("file_path")
ds_file_path = "[" + ds_name + "] " + file_path ds_file_path = "[" + ds_name + "] " + file_path
@ -423,19 +431,19 @@ def fake_fetch_image(image, instance, **kwargs):
def fake_upload_image(image, instance, **kwargs): def fake_upload_image(image, instance, **kwargs):
"""Fakes the upload of an image """ """Fakes the upload of an image."""
pass pass
def fake_get_vmdk_size_and_properties(image_id, instance): def fake_get_vmdk_size_and_properties(image_id, instance):
""" Fakes the file size and properties fetch for the image file """ """Fakes the file size and properties fetch for the image file."""
props = {"vmware_ostype": "otherGuest", props = {"vmware_ostype": "otherGuest",
"vmware_adaptertype": "lsiLogic"} "vmware_adaptertype": "lsiLogic"}
return _FAKE_FILE_SIZE, props return _FAKE_FILE_SIZE, props
def _get_vm_mdo(vm_ref): def _get_vm_mdo(vm_ref):
""" Gets the Virtual Machine with the ref from the db """ """Gets the Virtual Machine with the ref from the db."""
if _db_content.get("VirtualMachine", None) is None: if _db_content.get("VirtualMachine", None) is None:
raise exception.NotFound(_("There is no VM registered")) raise exception.NotFound(_("There is no VM registered"))
if vm_ref not in _db_content.get("VirtualMachine"): if vm_ref not in _db_content.get("VirtualMachine"):
@ -445,22 +453,24 @@ def _get_vm_mdo(vm_ref):
class FakeFactory(object): class FakeFactory(object):
""" Fake factory class for the suds client """ """Fake factory class for the suds client."""
def __init__(self): def __init__(self):
pass pass
def create(self, obj_name): def create(self, obj_name):
""" Creates a namespace object """ """Creates a namespace object."""
return DataObject() return DataObject()
class FakeVim(object): class FakeVim(object):
"""Fake VIM Class""" """Fake VIM Class."""
def __init__(self, protocol="https", host="localhost", trace=None): 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 """ Initializes the suds client object, sets the service content
contents and the cookies for the session.
"""
self._session = None self._session = None
self.client = DataObject() self.client = DataObject()
self.client.factory = FakeFactory() self.client.factory = FakeFactory()
@ -490,7 +500,7 @@ class FakeVim(object):
return "Fake VIM Object" return "Fake VIM Object"
def _login(self): def _login(self):
""" Logs in and sets the session object in the db """ """Logs in and sets the session object in the db."""
self._session = str(uuid.uuid4()) self._session = str(uuid.uuid4())
session = DataObject() session = DataObject()
session.key = self._session session.key = self._session
@ -498,7 +508,7 @@ class FakeVim(object):
return session return session
def _logout(self): def _logout(self):
""" Logs out and remove the session object ref from the db """ """Logs out and remove the session object ref from the db."""
s = self._session s = self._session
self._session = None self._session = None
if s not in _db_content['session']: if s not in _db_content['session']:
@ -508,14 +518,14 @@ class FakeVim(object):
del _db_content['session'][s] del _db_content['session'][s]
def _terminate_session(self, *args, **kwargs): def _terminate_session(self, *args, **kwargs):
""" Terminates a session """ """Terminates a session."""
s = kwargs.get("sessionId")[0] s = kwargs.get("sessionId")[0]
if s not in _db_content['session']: if s not in _db_content['session']:
return return
del _db_content['session'][s] del _db_content['session'][s]
def _check_session(self): def _check_session(self):
""" Checks if the session is active """ """Checks if the session is active."""
if (self._session is None or self._session not in if (self._session is None or self._session not in
_db_content['session']): _db_content['session']):
LOG.debug(_("Session is faulty")) LOG.debug(_("Session is faulty"))
@ -524,7 +534,7 @@ class FakeVim(object):
_("Session Invalid")) _("Session Invalid"))
def _create_vm(self, method, *args, **kwargs): def _create_vm(self, method, *args, **kwargs):
""" Creates and registers a VM object with the Host System """ """Creates and registers a VM object with the Host System."""
config_spec = kwargs.get("config") config_spec = kwargs.get("config")
ds = _db_content["Datastore"][_db_content["Datastore"].keys()[0]] ds = _db_content["Datastore"][_db_content["Datastore"].keys()[0]]
vm_dict = {"name": config_spec.name, vm_dict = {"name": config_spec.name,
@ -539,7 +549,7 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _reconfig_vm(self, method, *args, **kwargs): def _reconfig_vm(self, method, *args, **kwargs):
""" Reconfigures a VM and sets the properties supplied """ """Reconfigures a VM and sets the properties supplied."""
vm_ref = args[0] vm_ref = args[0]
vm_mdo = _get_vm_mdo(vm_ref) vm_mdo = _get_vm_mdo(vm_ref)
vm_mdo.reconfig(self.client.factory, kwargs.get("spec")) vm_mdo.reconfig(self.client.factory, kwargs.get("spec"))
@ -547,7 +557,7 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _create_copy_disk(self, method, vmdk_file_path): def _create_copy_disk(self, method, vmdk_file_path):
""" Creates/copies a vmdk file object in the datastore """ """Creates/copies a vmdk file object in the datastore."""
# We need to add/create both .vmdk and .-flat.vmdk files # We need to add/create both .vmdk and .-flat.vmdk files
flat_vmdk_file_path = \ flat_vmdk_file_path = \
vmdk_file_path.replace(".vmdk", "-flat.vmdk") vmdk_file_path.replace(".vmdk", "-flat.vmdk")
@ -557,12 +567,12 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _snapshot_vm(self, method): def _snapshot_vm(self, method):
""" Snapshots a VM. Here we do nothing for faking sake """ """Snapshots a VM. Here we do nothing for faking sake."""
task_mdo = create_task(method, "success") task_mdo = create_task(method, "success")
return task_mdo.obj return task_mdo.obj
def _delete_disk(self, method, *args, **kwargs): def _delete_disk(self, method, *args, **kwargs):
""" Deletes .vmdk and -flat.vmdk files corresponding to the VM """ """Deletes .vmdk and -flat.vmdk files corresponding to the VM."""
vmdk_file_path = kwargs.get("name") vmdk_file_path = kwargs.get("name")
flat_vmdk_file_path = \ flat_vmdk_file_path = \
vmdk_file_path.replace(".vmdk", "-flat.vmdk") vmdk_file_path.replace(".vmdk", "-flat.vmdk")
@ -572,23 +582,23 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _delete_file(self, method, *args, **kwargs): def _delete_file(self, method, *args, **kwargs):
""" Deletes a file from the datastore """ """Deletes a file from the datastore."""
_remove_file(kwargs.get("name")) _remove_file(kwargs.get("name"))
task_mdo = create_task(method, "success") task_mdo = create_task(method, "success")
return task_mdo.obj return task_mdo.obj
def _just_return(self): def _just_return(self):
""" Fakes a return """ """Fakes a return."""
return return
def _unregister_vm(self, method, *args, **kwargs): def _unregister_vm(self, method, *args, **kwargs):
""" Unregisters a VM from the Host System """ """Unregisters a VM from the Host System."""
vm_ref = args[0] vm_ref = args[0]
_get_vm_mdo(vm_ref) _get_vm_mdo(vm_ref)
del _db_content["VirtualMachine"][vm_ref] del _db_content["VirtualMachine"][vm_ref]
def _search_ds(self, method, *args, **kwargs): def _search_ds(self, method, *args, **kwargs):
""" Searches the datastore for a file """ """Searches the datastore for a file."""
ds_path = kwargs.get("datastorePath") ds_path = kwargs.get("datastorePath")
if _db_content.get("files", None) is None: if _db_content.get("files", None) is None:
raise exception.NotFound(_("No files have been added yet")) raise exception.NotFound(_("No files have been added yet"))
@ -600,14 +610,14 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _make_dir(self, method, *args, **kwargs): def _make_dir(self, method, *args, **kwargs):
""" Creates a directory in the datastore """ """Creates a directory in the datastore."""
ds_path = kwargs.get("name") ds_path = kwargs.get("name")
if _db_content.get("files", None) is None: if _db_content.get("files", None) is None:
raise exception.NotFound(_("No files have been added yet")) raise exception.NotFound(_("No files have been added yet"))
_db_content["files"].append(ds_path) _db_content["files"].append(ds_path)
def _set_power_state(self, method, vm_ref, pwr_state="poweredOn"): def _set_power_state(self, method, vm_ref, pwr_state="poweredOn"):
""" Sets power state for the VM """ """Sets power state for the VM."""
if _db_content.get("VirtualMachine", None) is None: if _db_content.get("VirtualMachine", None) is None:
raise exception.NotFound(_(" No Virtual Machine has been " raise exception.NotFound(_(" No Virtual Machine has been "
"registered yet")) "registered yet"))
@ -620,7 +630,7 @@ class FakeVim(object):
return task_mdo.obj return task_mdo.obj
def _retrieve_properties(self, method, *args, **kwargs): def _retrieve_properties(self, method, *args, **kwargs):
""" Retrieves properties based on the type """ """Retrieves properties based on the type."""
spec_set = kwargs.get("specSet")[0] spec_set = kwargs.get("specSet")[0]
type = spec_set.propSet[0].type type = spec_set.propSet[0].type
properties = spec_set.propSet[0].pathSet properties = spec_set.propSet[0].pathSet
@ -654,7 +664,7 @@ class FakeVim(object):
return lst_ret_objs return lst_ret_objs
def _add_port_group(self, method, *args, **kwargs): def _add_port_group(self, method, *args, **kwargs):
""" Adds a port group to the host system """ """Adds a port group to the host system."""
host_mdo = \ host_mdo = \
_db_content["HostSystem"][_db_content["HostSystem"].keys()[0]] _db_content["HostSystem"][_db_content["HostSystem"].keys()[0]]
host_mdo._add_port_group(kwargs.get("portgrp")) host_mdo._add_port_group(kwargs.get("portgrp"))

View File

@ -16,7 +16,7 @@
# under the License. # under the License.
""" """
Utility functions for ESX Networking Utility functions for ESX Networking.
""" """
from nova import exception from nova import exception
@ -32,8 +32,10 @@ class NetworkHelper:
@classmethod @classmethod
def get_network_with_the_name(cls, session, network_name="vmnet0"): def get_network_with_the_name(cls, session, network_name="vmnet0"):
""" Gets reference to the network whose name is passed as the """
argument. """ Gets reference to the network whose name is passed as the
argument.
"""
hostsystems = session._call_method(vim_util, "get_objects", hostsystems = session._call_method(vim_util, "get_objects",
"HostSystem", ["network"]) "HostSystem", ["network"])
vm_networks_ret = hostsystems[0].propSet[0].val vm_networks_ret = hostsystems[0].propSet[0].val
@ -44,7 +46,7 @@ class NetworkHelper:
return None return None
vm_networks = vm_networks_ret.ManagedObjectReference vm_networks = vm_networks_ret.ManagedObjectReference
networks = session._call_method(vim_util, networks = session._call_method(vim_util,
"get_properites_for_a_collection_of_objects", "get_properties_for_a_collection_of_objects",
"Network", vm_networks, ["summary.name"]) "Network", vm_networks, ["summary.name"])
for network in networks: for network in networks:
if network.propSet[0].val == network_name: if network.propSet[0].val == network_name:
@ -53,8 +55,10 @@ class NetworkHelper:
@classmethod @classmethod
def get_vswitch_for_vlan_interface(cls, session, vlan_interface): def get_vswitch_for_vlan_interface(cls, session, vlan_interface):
""" Gets the vswitch associated with the physical """
network adapter with the name supplied""" Gets the vswitch associated with the physical network adapter
with the name supplied.
"""
#Get the list of vSwicthes on the Host System #Get the list of vSwicthes on the Host System
host_mor = session._call_method(vim_util, "get_objects", host_mor = session._call_method(vim_util, "get_objects",
"HostSystem")[0].obj "HostSystem")[0].obj
@ -77,7 +81,7 @@ class NetworkHelper:
@classmethod @classmethod
def check_if_vlan_interface_exists(cls, session, vlan_interface): def check_if_vlan_interface_exists(cls, session, vlan_interface):
""" Checks if the vlan_inteface exists on the esx host """ """Checks if the vlan_inteface exists on the esx host."""
host_net_system_mor = session._call_method(vim_util, "get_objects", host_net_system_mor = session._call_method(vim_util, "get_objects",
"HostSystem", ["configManager.networkSystem"])[0].propSet[0].val "HostSystem", ["configManager.networkSystem"])[0].propSet[0].val
physical_nics_ret = session._call_method(vim_util, physical_nics_ret = session._call_method(vim_util,
@ -93,8 +97,8 @@ class NetworkHelper:
return False return False
@classmethod @classmethod
def get_vlanid_and_vswicth_for_portgroup(cls, session, pg_name): def get_vlanid_and_vswitch_for_portgroup(cls, session, pg_name):
""" Get the vlan id and vswicth associated with the port group """ """Get the vlan id and vswicth associated with the port group."""
host_mor = session._call_method(vim_util, "get_objects", host_mor = session._call_method(vim_util, "get_objects",
"HostSystem")[0].obj "HostSystem")[0].obj
port_grps_on_host_ret = session._call_method(vim_util, port_grps_on_host_ret = session._call_method(vim_util,
@ -113,8 +117,10 @@ class NetworkHelper:
@classmethod @classmethod
def create_port_group(cls, session, pg_name, vswitch_name, vlan_id=0): 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 """ 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 client_factory = session._get_vim().client.factory
add_prt_grp_spec = vm_util.get_add_vswitch_port_group_spec( add_prt_grp_spec = vm_util.get_add_vswitch_port_group_spec(
client_factory, client_factory,

View File

@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
""" Classes to handle image files """Classes to handle image files.
Collection of classes to handle image upload/download to/from Image service Collection of classes to handle image upload/download to/from Image service
(like Glance image storage and retrieval service) from/to ESX/ESXi server. (like Glance image storage and retrieval service) from/to ESX/ESXi server.
@ -29,8 +29,6 @@ import urlparse
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova import utils
from nova.auth.manager import AuthManager
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@ -41,145 +39,34 @@ USER_AGENT = "OpenStack-ESX-Adapter"
LOG = logging.getLogger("nova.virt.vmwareapi.read_write_util") LOG = logging.getLogger("nova.virt.vmwareapi.read_write_util")
class ImageServiceFile:
"""The base image service class"""
def __init__(self, file_handle):
self.eof = False
self.file_handle = file_handle
def write(self, data):
"""Write data to the file"""
raise NotImplementedError
def read(self, chunk_size=READ_CHUNKSIZE):
"""Read a chunk of data from the file"""
raise NotImplementedError
def get_size(self):
"""Get the size of the file whose data is to be read"""
raise NotImplementedError
def set_eof(self, eof):
"""Set the end of file marker"""
self.eof = eof
def get_eof(self):
"""Check if the file end has been reached or not"""
return self.eof
def close(self):
"""Close the file handle"""
try:
self.file_handle.close()
except Exception:
pass
def get_image_properties(self):
"""Get the image properties"""
raise NotImplementedError
def __del__(self):
"""Close the file handle on garbage collection"""
self.close()
class GlanceHTTPWriteFile(ImageServiceFile):
"""Glance file write handler class"""
def __init__(self, host, port, image_id, file_size, os_type, adapter_type,
version=1, scheme="http"):
base_url = "%s://%s:%s/images/%s" % (scheme, host, port, image_id)
(scheme, netloc, path, params, query, fragment) = \
urlparse.urlparse(base_url)
if scheme == "http":
conn = httplib.HTTPConnection(netloc)
elif scheme == "https":
conn = httplib.HTTPSConnection(netloc)
conn.putrequest("PUT", path)
conn.putheader("User-Agent", USER_AGENT)
conn.putheader("Content-Length", file_size)
conn.putheader("Content-Type", "application/octet-stream")
conn.putheader("x-image-meta-store", "file")
conn.putheader("x-image-meta-is_public", "True")
conn.putheader("x-image-meta-type", "raw")
conn.putheader("x-image-meta-size", file_size)
conn.putheader("x-image-meta-property-kernel_id", "")
conn.putheader("x-image-meta-property-ramdisk_id", "")
conn.putheader("x-image-meta-property-vmware_ostype", os_type)
conn.putheader("x-image-meta-property-vmware_adaptertype",
adapter_type)
conn.putheader("x-image-meta-property-vmware_image_version", version)
conn.endheaders()
ImageServiceFile.__init__(self, conn)
def write(self, data):
"""Write data to the file"""
self.file_handle.send(data)
class GlanceHTTPReadFile(ImageServiceFile):
"""Glance file read handler class"""
def __init__(self, host, port, image_id, scheme="http"):
base_url = "%s://%s:%s/images/%s" % (scheme, host, port,
urllib.pathname2url(image_id))
headers = {'User-Agent': USER_AGENT}
request = urllib2.Request(base_url, None, headers)
conn = urllib2.urlopen(request)
ImageServiceFile.__init__(self, conn)
def read(self, chunk_size=READ_CHUNKSIZE):
"""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"""
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
"""
return {"vmware_ostype":
self.file_handle.headers.get(
"X-Image-Meta-Property-Vmware_ostype"),
"vmware_adaptertype":
self.file_handle.headers.get(
"X-Image-Meta-Property-Vmware_adaptertype"),
"vmware_image_version":
self.file_handle.headers.get(
"X-Image-Meta-Property-Vmware_image_version")}
class VMwareHTTPFile(object): class VMwareHTTPFile(object):
"""Base class for HTTP file""" """Base class for HTTP file."""
def __init__(self, file_handle): def __init__(self, file_handle):
self.eof = False self.eof = False
self.file_handle = file_handle self.file_handle = file_handle
def set_eof(self, eof): def set_eof(self, eof):
"""Set the end of file marker""" """Set the end of file marker."""
self.eof = eof self.eof = eof
def get_eof(self): 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 return self.eof
def close(self): def close(self):
"""Close the file handle""" """Close the file handle."""
try: try:
self.file_handle.close() self.file_handle.close()
except Exception: except Exception:
pass pass
def __del__(self): def __del__(self):
"""Close the file handle on garbage collection""" """Close the file handle on garbage collection."""
self.close() self.close()
def _build_vim_cookie_headers(self, vim_cookies): def _build_vim_cookie_headers(self, vim_cookies):
"""Build ESX host session cookie headers""" """Build ESX host session cookie headers."""
cookie_header = "" cookie_header = ""
for vim_cookie in vim_cookies: for vim_cookie in vim_cookies:
cookie_header = vim_cookie.name + "=" + vim_cookie.value cookie_header = vim_cookie.name + "=" + vim_cookie.value
@ -187,20 +74,20 @@ class VMwareHTTPFile(object):
return cookie_header return cookie_header
def write(self, data): def write(self, data):
"""Write data to the file""" """Write data to the file."""
raise NotImplementedError raise NotImplementedError
def read(self, chunk_size=READ_CHUNKSIZE): def read(self, chunk_size=READ_CHUNKSIZE):
"""Read a chunk of data""" """Read a chunk of data."""
raise NotImplementedError raise NotImplementedError
def get_size(self): def get_size(self):
"""Get size of the file to be read""" """Get size of the file to be read."""
raise NotImplementedError raise NotImplementedError
class VMWareHTTPWriteFile(VMwareHTTPFile): class VMWareHTTPWriteFile(VMwareHTTPFile):
"""VMWare file write handler class""" """VMWare file write handler class."""
def __init__(self, host, data_center_name, datastore_name, cookies, def __init__(self, host, data_center_name, datastore_name, cookies,
file_path, file_size, scheme="https"): file_path, file_size, scheme="https"):
@ -222,11 +109,11 @@ class VMWareHTTPWriteFile(VMwareHTTPFile):
VMwareHTTPFile.__init__(self, conn) VMwareHTTPFile.__init__(self, conn)
def write(self, data): def write(self, data):
"""Write to the file""" """Write to the file."""
self.file_handle.send(data) self.file_handle.send(data)
def close(self): def close(self):
"""Get the response and close the connection""" """Get the response and close the connection."""
try: try:
self.conn.getresponse() self.conn.getresponse()
except Exception, excep: except Exception, excep:
@ -236,7 +123,7 @@ class VMWareHTTPWriteFile(VMwareHTTPFile):
class VmWareHTTPReadFile(VMwareHTTPFile): class VmWareHTTPReadFile(VMwareHTTPFile):
"""VMWare file read handler class""" """VMWare file read handler class."""
def __init__(self, host, data_center_name, datastore_name, cookies, def __init__(self, host, data_center_name, datastore_name, cookies,
file_path, scheme="https"): file_path, scheme="https"):
@ -251,9 +138,9 @@ class VmWareHTTPReadFile(VMwareHTTPFile):
VMwareHTTPFile.__init__(self, conn) VMwareHTTPFile.__init__(self, conn)
def read(self, chunk_size=READ_CHUNKSIZE): def read(self, chunk_size=READ_CHUNKSIZE):
"""Read a chunk of data""" """Read a chunk of data."""
return self.file_handle.read(chunk_size) return self.file_handle.read(chunk_size)
def get_size(self): 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) return self.file_handle.headers.get("Content-Length", -1)

View File

@ -16,7 +16,7 @@
# under the License. # under the License.
""" """
Classes for making VMware VI SOAP calls Classes for making VMware VI SOAP calls.
""" """
import httplib import httplib
@ -37,49 +37,50 @@ FLAGS = flags.FLAGS
flags.DEFINE_string('vmwareapi_wsdl_loc', flags.DEFINE_string('vmwareapi_wsdl_loc',
None, None,
'VIM Service WSDL Location' 'VIM Service WSDL Location'
'E.g http://<server>/vimService.wsdl' 'e.g http://<server>/vimService.wsdl'
'Due to a bug in vSphere ESX 4.1 default wsdl' 'Due to a bug in vSphere ESX 4.1 default wsdl'
'Read the readme for vmware to setup') 'Refer readme-vmware to setup')
class VIMMessagePlugin(MessagePlugin): class VIMMessagePlugin(MessagePlugin):
def addAttributeForValue(self, node): def addAttributeForValue(self, node):
#suds does not handle AnyType properly # suds does not handle AnyType properly.
#VI SDK requires type attribute to be set when AnyType is used # VI SDK requires type attribute to be set when AnyType is used
if node.name == 'value': if node.name == 'value':
node.set('xsi:type', 'xsd:string') node.set('xsi:type', 'xsd:string')
def marshalled(self, context): def marshalled(self, context):
"""Suds will send the specified soap envelope. """suds will send the specified soap envelope.
Provides the plugin with the opportunity to prune empty Provides the plugin with the opportunity to prune empty
nodes and fixup nodes before sending it to the server nodes and fixup nodes before sending it to the server.
""" """
#suds builds the entire request object based on the wsdl schema # suds builds the entire request object based on the wsdl schema.
#VI SDK throws server errors if optional SOAP nodes are sent without # VI SDK throws server errors if optional SOAP nodes are sent without
#values. E.g <test/> as opposed to <test>test</test> # values, e.g. <test/> as opposed to <test>test</test>
context.envelope.prune() context.envelope.prune()
context.envelope.walk(self.addAttributeForValue) context.envelope.walk(self.addAttributeForValue)
class Vim: class Vim:
"""The VIM Object""" """The VIM Object."""
def __init__(self, def __init__(self,
protocol="https", protocol="https",
host="localhost"): host="localhost"):
""" """
Creates the necessary Communication interfaces and gets the
ServiceContent for initiating SOAP transactions.
protocol: http or https protocol: http or https
host : ESX IPAddress[:port] or ESX Hostname[:port] host : ESX IPAddress[:port] or ESX Hostname[:port]
Creates the necessary Communication interfaces, Gets the
ServiceContent for initiating SOAP transactions
""" """
self._protocol = protocol self._protocol = protocol
self._host_name = host self._host_name = host
wsdl_url = FLAGS.vmwareapi_wsdl_loc wsdl_url = FLAGS.vmwareapi_wsdl_loc
if wsdl_url is None: if wsdl_url is None:
raise Exception(_("Must specify vmwareapi_wsdl_loc")) raise Exception(_("Must specify vmwareapi_wsdl_loc"))
#Use this when VMware fixes their faulty wsdl # Use this when VMware fixes their faulty wsdl
#wsdl_url = '%s://%s/sdk/vimService.wsdl' % (self._protocol, #wsdl_url = '%s://%s/sdk/vimService.wsdl' % (self._protocol,
# self._host_name) # self._host_name)
url = '%s://%s/sdk' % (self._protocol, self._host_name) url = '%s://%s/sdk' % (self._protocol, self._host_name)
@ -89,37 +90,41 @@ class Vim:
self.RetrieveServiceContent("ServiceInstance") self.RetrieveServiceContent("ServiceInstance")
def get_service_content(self): def get_service_content(self):
"""Gets the service content object""" """Gets the service content object."""
return self._service_content return self._service_content
def __getattr__(self, attr_name): def __getattr__(self, attr_name):
"""Makes the API calls and gets the result""" """Makes the API calls and gets the result."""
try: try:
return object.__getattr__(self, attr_name) return object.__getattr__(self, attr_name)
except AttributeError: except AttributeError:
def vim_request_handler(managed_object, **kwargs): def vim_request_handler(managed_object, **kwargs):
"""managed_object : Managed Object Reference or Managed
Object Name
**kw : Keyword arguments of the call
""" """
#Dynamic handler for VI SDK Calls Builds the SOAP message and parses the response for fault
checking and other errors.
managed_object : Managed Object Reference or Managed
Object Name
**kwargs : Keyword arguments of the call
"""
# Dynamic handler for VI SDK Calls
try: try:
request_mo = \ request_mo = \
self._request_managed_object_builder(managed_object) self._request_managed_object_builder(managed_object)
request = getattr(self.client.service, attr_name) request = getattr(self.client.service, attr_name)
response = request(request_mo, **kwargs) response = request(request_mo, **kwargs)
#To check for the faults that are part of the message body # To check for the faults that are part of the message body
#and not returned as Fault object response from the ESX # and not returned as Fault object response from the ESX
#SOAP server # SOAP server
if hasattr(error_util.FaultCheckers, if hasattr(error_util.FaultCheckers,
attr_name.lower() + "_fault_checker"): attr_name.lower() + "_fault_checker"):
fault_checker = getattr(error_util.FaultCheckers, fault_checker = getattr(error_util.FaultCheckers,
attr_name.lower() + "_fault_checker") attr_name.lower() + "_fault_checker")
fault_checker(response) fault_checker(response)
return response return response
#Catch the VimFaultException that is raised by the fault # Catch the VimFaultException that is raised by the fault
#check of the SOAP response # check of the SOAP response
except error_util.VimFaultException, excep: except error_util.VimFaultException, excep:
raise raise
except WebFault, excep: except WebFault, excep:
@ -155,8 +160,8 @@ class Vim:
return vim_request_handler return vim_request_handler
def _request_managed_object_builder(self, managed_object): def _request_managed_object_builder(self, managed_object):
"""Builds the request managed object""" """Builds the request managed object."""
#Request Managed Object Builder # Request Managed Object Builder
if type(managed_object) == type(""): if type(managed_object) == type(""):
mo = Property(managed_object) mo = Property(managed_object)
mo._type = managed_object mo._type = managed_object

View File

@ -16,19 +16,19 @@
# under the License. # under the License.
""" """
The VMware API utility module The VMware API utility module.
""" """
def build_selcetion_spec(client_factory, name): def build_selection_spec(client_factory, name):
""" Builds the selection spec """ """Builds the selection spec."""
sel_spec = client_factory.create('ns0:SelectionSpec') sel_spec = client_factory.create('ns0:SelectionSpec')
sel_spec.name = name sel_spec.name = name
return sel_spec return sel_spec
def build_traversal_spec(client_factory, name, type, path, skip, select_set): def build_traversal_spec(client_factory, name, type, path, skip, select_set):
""" Builds the traversal spec object """ """Builds the traversal spec object."""
traversal_spec = client_factory.create('ns0:TraversalSpec') traversal_spec = client_factory.create('ns0:TraversalSpec')
traversal_spec.name = name traversal_spec.name = name
traversal_spec.type = type traversal_spec.type = type
@ -39,9 +39,11 @@ def build_traversal_spec(client_factory, name, type, path, skip, select_set):
def build_recursive_traversal_spec(client_factory): def build_recursive_traversal_spec(client_factory):
""" Builds the Recursive Traversal Spec to traverse the object managed """
object hierarchy """ Builds the Recursive Traversal Spec to traverse the object managed
visit_folders_select_spec = build_selcetion_spec(client_factory, object hierarchy.
"""
visit_folders_select_spec = build_selection_spec(client_factory,
"visitFolders") "visitFolders")
#For getting to hostFolder from datacnetr #For getting to hostFolder from datacnetr
dc_to_hf = build_traversal_spec(client_factory, "dc_to_hf", "Datacenter", dc_to_hf = build_traversal_spec(client_factory, "dc_to_hf", "Datacenter",
@ -64,8 +66,8 @@ def build_recursive_traversal_spec(client_factory):
cr_to_ds = build_traversal_spec(client_factory, "cr_to_ds", cr_to_ds = build_traversal_spec(client_factory, "cr_to_ds",
"ComputeResource", "datastore", False, []) "ComputeResource", "datastore", False, [])
rp_to_rp_select_spec = build_selcetion_spec(client_factory, "rp_to_rp") rp_to_rp_select_spec = build_selection_spec(client_factory, "rp_to_rp")
rp_to_vm_select_spec = build_selcetion_spec(client_factory, "rp_to_vm") rp_to_vm_select_spec = build_selection_spec(client_factory, "rp_to_vm")
#For getting to resource pool from Compute Resource #For getting to resource pool from Compute Resource
cr_to_rp = build_traversal_spec(client_factory, "cr_to_rp", cr_to_rp = build_traversal_spec(client_factory, "cr_to_rp",
"ComputeResource", "resourcePool", False, "ComputeResource", "resourcePool", False,
@ -94,7 +96,7 @@ def build_recursive_traversal_spec(client_factory):
def build_property_spec(client_factory, type="VirtualMachine", def build_property_spec(client_factory, type="VirtualMachine",
properties_to_collect=["name"], properties_to_collect=["name"],
all_properties=False): all_properties=False):
"""Builds the Property Spec""" """Builds the Property Spec."""
property_spec = client_factory.create('ns0:PropertySpec') property_spec = client_factory.create('ns0:PropertySpec')
property_spec.all = all_properties property_spec.all = all_properties
property_spec.pathSet = properties_to_collect property_spec.pathSet = properties_to_collect
@ -103,7 +105,7 @@ def build_property_spec(client_factory, type="VirtualMachine",
def build_object_spec(client_factory, root_folder, traversal_specs): def build_object_spec(client_factory, root_folder, traversal_specs):
"""Builds the object Spec""" """Builds the object Spec."""
object_spec = client_factory.create('ns0:ObjectSpec') object_spec = client_factory.create('ns0:ObjectSpec')
object_spec.obj = root_folder object_spec.obj = root_folder
object_spec.skip = False object_spec.skip = False
@ -112,7 +114,7 @@ def build_object_spec(client_factory, root_folder, traversal_specs):
def build_property_filter_spec(client_factory, property_specs, object_specs): def build_property_filter_spec(client_factory, property_specs, object_specs):
"""Builds the Property Filter Spec""" """Builds the Property Filter Spec."""
property_filter_spec = client_factory.create('ns0:PropertyFilterSpec') property_filter_spec = client_factory.create('ns0:PropertyFilterSpec')
property_filter_spec.propSet = property_specs property_filter_spec.propSet = property_specs
property_filter_spec.objectSet = object_specs property_filter_spec.objectSet = object_specs
@ -120,7 +122,7 @@ def build_property_filter_spec(client_factory, property_specs, object_specs):
def get_object_properties(vim, collector, mobj, type, properties): def get_object_properties(vim, collector, mobj, type, properties):
"""Gets the properties of the Managed object specified""" """Gets the properties of the Managed object specified."""
client_factory = vim.client.factory client_factory = vim.client.factory
if mobj is None: if mobj is None:
return None return None
@ -141,7 +143,7 @@ def get_object_properties(vim, collector, mobj, type, properties):
def get_dynamic_property(vim, mobj, type, property_name): def get_dynamic_property(vim, mobj, type, property_name):
"""Gets a particular property of the Managed Object""" """Gets a particular property of the Managed Object."""
obj_content = \ obj_content = \
get_object_properties(vim, None, mobj, type, [property_name]) get_object_properties(vim, None, mobj, type, [property_name])
property_value = None property_value = None
@ -153,7 +155,7 @@ def get_dynamic_property(vim, mobj, type, property_name):
def get_objects(vim, type, properties_to_collect=["name"], all=False): def get_objects(vim, type, properties_to_collect=["name"], all=False):
"""Gets the list of objects of the type specified""" """Gets the list of objects of the type specified."""
client_factory = vim.client.factory client_factory = vim.client.factory
object_spec = build_object_spec(client_factory, object_spec = build_object_spec(client_factory,
vim.get_service_content().rootFolder, vim.get_service_content().rootFolder,
@ -169,7 +171,7 @@ def get_objects(vim, type, properties_to_collect=["name"], all=False):
def get_prop_spec(client_factory, type, properties): def get_prop_spec(client_factory, type, properties):
"""Builds the Property Spec Object""" """Builds the Property Spec Object."""
prop_spec = client_factory.create('ns0:PropertySpec') prop_spec = client_factory.create('ns0:PropertySpec')
prop_spec.type = type prop_spec.type = type
prop_spec.pathSet = properties prop_spec.pathSet = properties
@ -177,7 +179,7 @@ def get_prop_spec(client_factory, type, properties):
def get_obj_spec(client_factory, obj, select_set=None): def get_obj_spec(client_factory, obj, select_set=None):
"""Builds the Object Spec object""" """Builds the Object Spec object."""
obj_spec = client_factory.create('ns0:ObjectSpec') obj_spec = client_factory.create('ns0:ObjectSpec')
obj_spec.obj = obj obj_spec.obj = obj
obj_spec.skip = False obj_spec.skip = False
@ -187,7 +189,7 @@ def get_obj_spec(client_factory, obj, select_set=None):
def get_prop_filter_spec(client_factory, obj_spec, prop_spec): def get_prop_filter_spec(client_factory, obj_spec, prop_spec):
"""Builds the Property Filter Spec Object""" """Builds the Property Filter Spec Object."""
prop_filter_spec = \ prop_filter_spec = \
client_factory.create('ns0:PropertyFilterSpec') client_factory.create('ns0:PropertyFilterSpec')
prop_filter_spec.propSet = prop_spec prop_filter_spec.propSet = prop_spec
@ -195,10 +197,11 @@ def get_prop_filter_spec(client_factory, obj_spec, prop_spec):
return prop_filter_spec return prop_filter_spec
def get_properites_for_a_collection_of_objects(vim, type, def get_properties_for_a_collection_of_objects(vim, type,
obj_list, properties): 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 client_factory = vim.client.factory
if len(obj_list) == 0: if len(obj_list) == 0:

View File

@ -15,18 +15,19 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
""" """
The VMware API VM utility module to build SOAP object specs The VMware API VM utility module to build SOAP object specs.
""" """
def build_datastore_path(datastore_name, path): def build_datastore_path(datastore_name, path):
"""Build the datastore compliant path""" """Build the datastore compliant path."""
return "[%s] %s" % (datastore_name, path) return "[%s] %s" % (datastore_name, path)
def split_datastore_path(datastore_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) spl = datastore_path.split('[', 1)[1].split(']', 1)
path = "" path = ""
@ -40,7 +41,7 @@ def split_datastore_path(datastore_path):
def get_vm_create_spec(client_factory, instance, data_store_name, def get_vm_create_spec(client_factory, instance, data_store_name,
network_name="vmnet0", network_name="vmnet0",
os_type="otherGuest"): os_type="otherGuest"):
"""Builds the VM Create spec""" """Builds the VM Create spec."""
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec') config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
config_spec.name = instance.name config_spec.name = instance.name
config_spec.guestId = os_type config_spec.guestId = os_type
@ -70,11 +71,12 @@ def get_vm_create_spec(client_factory, instance, data_store_name,
def create_controller_spec(client_factory, key): 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 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 = \ virtual_device_config = \
client_factory.create('ns0:VirtualDeviceConfigSpec') client_factory.create('ns0:VirtualDeviceConfigSpec')
virtual_device_config.operation = "add" virtual_device_config.operation = "add"
@ -88,13 +90,15 @@ def create_controller_spec(client_factory, key):
def create_network_spec(client_factory, network_name, mac_address): 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""" Builds a config spec for the addition of a new network
adapter to the VM.
"""
network_spec = \ network_spec = \
client_factory.create('ns0:VirtualDeviceConfigSpec') client_factory.create('ns0:VirtualDeviceConfigSpec')
network_spec.operation = "add" network_spec.operation = "add"
#Get the recommended card type for the VM based on the guest OS of the VM # Get the recommended card type for the VM based on the guest OS of the VM
net_device = client_factory.create('ns0:VirtualPCNet32') net_device = client_factory.create('ns0:VirtualPCNet32')
backing = \ backing = \
@ -110,9 +114,9 @@ def create_network_spec(client_factory, network_name, mac_address):
net_device.connectable = connectable_spec net_device.connectable = connectable_spec
net_device.backing = backing net_device.backing = backing
#The Server assigns a Key to the device. Here we pass a -ve temporary key. # 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 # -ve because actual keys are +ve numbers and we don't
#want a clash with the key that server might associate with the device # want a clash with the key that server might associate with the device
net_device.key = -47 net_device.key = -47
net_device.addressType = "manual" net_device.addressType = "manual"
net_device.macAddress = mac_address net_device.macAddress = mac_address
@ -124,14 +128,14 @@ def create_network_spec(client_factory, network_name, mac_address):
def get_vmdk_attach_config_spec(client_factory, def get_vmdk_attach_config_spec(client_factory,
disksize, file_path, adapter_type="lsiLogic"): disksize, file_path, adapter_type="lsiLogic"):
"""Builds the vmdk attach config spec""" """Builds the vmdk attach config spec."""
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec') config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
#The controller Key pertains to the Key of the LSI Logic Controller, which # The controller Key pertains to the Key of the LSI Logic Controller, which
#controls this Hard Disk # controls this Hard Disk
device_config_spec = [] device_config_spec = []
#For IDE devices, there are these two default controllers created in the # For IDE devices, there are these two default controllers created in the
#VM having keys 200 and 201 # VM having keys 200 and 201
if adapter_type == "ide": if adapter_type == "ide":
controller_key = 200 controller_key = 200
else: else:
@ -149,7 +153,7 @@ def get_vmdk_attach_config_spec(client_factory,
def get_vmdk_file_path_and_adapter_type(client_factory, hardware_devices): def get_vmdk_file_path_and_adapter_type(client_factory, hardware_devices):
"""Gets the vmdk file path and the storage adapter type""" """Gets the vmdk file path and the storage adapter type."""
if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice": if hardware_devices.__class__.__name__ == "ArrayOfVirtualDevice":
hardware_devices = hardware_devices.VirtualDevice hardware_devices = hardware_devices.VirtualDevice
vmdk_file_path = None vmdk_file_path = None
@ -177,7 +181,7 @@ def get_vmdk_file_path_and_adapter_type(client_factory, hardware_devices):
def get_copy_virtual_disk_spec(client_factory, adapter_type="lsilogic"): def get_copy_virtual_disk_spec(client_factory, adapter_type="lsilogic"):
"""Builds the Virtual Disk copy spec""" """Builds the Virtual Disk copy spec."""
dest_spec = client_factory.create('ns0:VirtualDiskSpec') dest_spec = client_factory.create('ns0:VirtualDiskSpec')
dest_spec.adapterType = adapter_type dest_spec.adapterType = adapter_type
dest_spec.diskType = "thick" dest_spec.diskType = "thick"
@ -185,7 +189,7 @@ def get_copy_virtual_disk_spec(client_factory, adapter_type="lsilogic"):
def get_vmdk_create_spec(client_factory, size_in_kb, adapter_type="lsiLogic"): def get_vmdk_create_spec(client_factory, size_in_kb, adapter_type="lsiLogic"):
"""Builds the virtual disk create spec""" """Builds the virtual disk create spec."""
create_vmdk_spec = \ create_vmdk_spec = \
client_factory.create('ns0:FileBackedVirtualDiskSpec') client_factory.create('ns0:FileBackedVirtualDiskSpec')
create_vmdk_spec.adapterType = adapter_type create_vmdk_spec.adapterType = adapter_type
@ -196,8 +200,10 @@ def get_vmdk_create_spec(client_factory, size_in_kb, adapter_type="lsiLogic"):
def create_virtual_disk_spec(client_factory, def create_virtual_disk_spec(client_factory,
disksize, controller_key, file_path=None): disksize, controller_key, file_path=None):
"""Creates a Spec for the addition/attaching of a """
Virtual Disk to the VM""" Builds spec for the creation of a new/ attaching of an already existing
Virtual Disk to the VM.
"""
virtual_device_config = \ virtual_device_config = \
client_factory.create('ns0:VirtualDeviceConfigSpec') client_factory.create('ns0:VirtualDeviceConfigSpec')
virtual_device_config.operation = "add" virtual_device_config.operation = "add"
@ -223,9 +229,9 @@ def create_virtual_disk_spec(client_factory,
virtual_disk.backing = disk_file_backing virtual_disk.backing = disk_file_backing
virtual_disk.connectable = connectable_spec virtual_disk.connectable = connectable_spec
#The Server assigns a Key to the device. Here we pass a -ve temporary key. # The Server assigns a Key to the device. Here we pass a -ve random key.
#-ve because actual keys are +ve numbers and we don't # -ve because actual keys are +ve numbers and we don't
#want a clash with the key that server might associate with the device # want a clash with the key that server might associate with the device
virtual_disk.key = -100 virtual_disk.key = -100
virtual_disk.controllerKey = controller_key virtual_disk.controllerKey = controller_key
virtual_disk.unitNumber = 0 virtual_disk.unitNumber = 0
@ -237,7 +243,7 @@ def create_virtual_disk_spec(client_factory,
def get_dummy_vm_create_spec(client_factory, name, data_store_name): def get_dummy_vm_create_spec(client_factory, name, data_store_name):
"""Builds the dummy VM create spec""" """Builds the dummy VM create spec."""
config_spec = client_factory.create('ns0:VirtualMachineConfigSpec') config_spec = client_factory.create('ns0:VirtualMachineConfigSpec')
config_spec.name = name config_spec.name = name
@ -269,7 +275,7 @@ def get_dummy_vm_create_spec(client_factory, name, data_store_name):
def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, gateway): def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, gateway):
"""Builds the machine id change config spec""" """Builds the machine id change config spec."""
machine_id_str = "%s;%s;%s;%s" % (mac, ip_addr, netmask, gateway) machine_id_str = "%s;%s;%s;%s" % (mac, ip_addr, netmask, gateway)
virtual_machine_config_spec = \ virtual_machine_config_spec = \
client_factory.create('ns0:VirtualMachineConfigSpec') client_factory.create('ns0:VirtualMachineConfigSpec')
@ -283,12 +289,12 @@ def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, gateway):
def get_add_vswitch_port_group_spec(client_factory, vswitch_name, def get_add_vswitch_port_group_spec(client_factory, vswitch_name,
port_group_name, vlan_id): port_group_name, vlan_id):
"""Builds the virtual switch port group add spec""" """Builds the virtual switch port group add spec."""
vswitch_port_group_spec = client_factory.create('ns0:HostPortGroupSpec') vswitch_port_group_spec = client_factory.create('ns0:HostPortGroupSpec')
vswitch_port_group_spec.name = port_group_name vswitch_port_group_spec.name = port_group_name
vswitch_port_group_spec.vswitchName = vswitch_name vswitch_port_group_spec.vswitchName = vswitch_name
#VLAN ID of 0 means that VLAN tagging is not to be done for the network. # VLAN ID of 0 means that VLAN tagging is not to be done for the network.
vswitch_port_group_spec.vlanId = int(vlan_id) vswitch_port_group_spec.vlanId = int(vlan_id)
policy = client_factory.create('ns0:HostNetworkPolicy') policy = client_factory.create('ns0:HostNetworkPolicy')

View File

@ -47,14 +47,14 @@ VMWARE_POWER_STATES = {
class VMWareVMOps(object): class VMWareVMOps(object):
""" Management class for VM-related tasks """ """Management class for VM-related tasks."""
def __init__(self, session): def __init__(self, session):
""" Initializer """ """Initializer."""
self._session = session self._session = session
def _wait_with_callback(self, instance_id, task, callback): 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 ret = None
try: try:
ret = self._session._wait_for_task(instance_id, task) ret = self._session._wait_for_task(instance_id, task)
@ -63,7 +63,7 @@ class VMWareVMOps(object):
callback(ret) callback(ret)
def list_instances(self): 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")) LOG.debug(_("Getting list of instances"))
vms = self._session._call_method(vim_util, "get_objects", vms = self._session._call_method(vim_util, "get_objects",
"VirtualMachine", "VirtualMachine",
@ -96,7 +96,7 @@ class VMWareVMOps(object):
the metadata .vmdk file. the metadata .vmdk file.
4. Upload the disk file. 4. Upload the disk file.
5. Attach the disk to the VM by reconfiguring the same. 5. Attach the disk to the VM by reconfiguring the same.
6. Power on the VM 6. Power on the VM.
""" """
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref: if vm_ref:
@ -122,7 +122,7 @@ class VMWareVMOps(object):
_check_if_network_bridge_exists() _check_if_network_bridge_exists()
def _get_datastore_ref(): def _get_datastore_ref():
# Get the datastore list and choose the first local storage """Get the datastore list and choose the first local storage."""
data_stores = self._session._call_method(vim_util, "get_objects", data_stores = self._session._call_method(vim_util, "get_objects",
"Datastore", ["summary.type", "summary.name"]) "Datastore", ["summary.type", "summary.name"])
for elem in data_stores: for elem in data_stores:
@ -133,7 +133,7 @@ class VMWareVMOps(object):
ds_type = prop.val ds_type = prop.val
elif prop.name == "summary.name": elif prop.name == "summary.name":
ds_name = prop.val ds_name = prop.val
#Local storage identifier # Local storage identifier
if ds_type == "VMFS": if ds_type == "VMFS":
data_store_name = ds_name data_store_name = ds_name
return data_store_name return data_store_name
@ -146,8 +146,10 @@ class VMWareVMOps(object):
data_store_name = _get_datastore_ref() data_store_name = _get_datastore_ref()
def _get_image_properties(): def _get_image_properties():
#Get the Size of the flat vmdk file that is there on the storage """
#repository. Get the Size of the flat vmdk file that is there on the storage
repository.
"""
image_size, image_properties = \ image_size, image_properties = \
vmware_images.get_vmdk_size_and_properties( vmware_images.get_vmdk_size_and_properties(
instance.image_id, instance) instance.image_id, instance)
@ -160,28 +162,29 @@ class VMWareVMOps(object):
vmdk_file_size_in_kb, os_type, adapter_type = _get_image_properties() vmdk_file_size_in_kb, os_type, adapter_type = _get_image_properties()
def _get_vmfolder_and_res_pool_mors(): def _get_vmfolder_and_res_pool_mors():
#Get the Vm folder ref from the datacenter """Get the Vm folder ref from the datacenter."""
dc_objs = self._session._call_method(vim_util, "get_objects", dc_objs = self._session._call_method(vim_util, "get_objects",
"Datacenter", ["vmFolder"]) "Datacenter", ["vmFolder"])
#There is only one default datacenter in a standalone ESX host # There is only one default datacenter in a standalone ESX host
vm_folder_mor = dc_objs[0].propSet[0].val vm_folder_mor = dc_objs[0].propSet[0].val
#Get the resource pool. Taking the first resource pool coming our # Get the resource pool. Taking the first resource pool coming our
#way. Assuming that is the default resource pool. # way. Assuming that is the default resource pool.
res_pool_mor = self._session._call_method(vim_util, "get_objects", res_pool_mor = self._session._call_method(vim_util, "get_objects",
"ResourcePool")[0].obj "ResourcePool")[0].obj
return vm_folder_mor, res_pool_mor return vm_folder_mor, res_pool_mor
vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors() vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors()
#Get the create vm config spec # Get the create vm config spec
config_spec = vm_util.get_vm_create_spec(client_factory, instance, config_spec = vm_util.get_vm_create_spec(client_factory, instance,
data_store_name, net_name, os_type) data_store_name, net_name, os_type)
def _execute_create_vm(): def _execute_create_vm():
"""Create VM on ESX host."""
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) instance.name)
#Create the VM on the ESX host # Create the VM on the ESX host
vm_create_task = self._session._call_method( vm_create_task = self._session._call_method(
self._session._get_vim(), self._session._get_vim(),
"CreateVM_Task", vm_folder_mor, "CreateVM_Task", vm_folder_mor,
@ -196,11 +199,11 @@ class VMWareVMOps(object):
# Set the machine id for the VM for setting the IP # Set the machine id for the VM for setting the IP
self._set_machine_id(client_factory, instance) self._set_machine_id(client_factory, instance)
#Naming the VM files in correspondence with the VM instance name # Naming the VM files in correspondence with the VM instance name
# The flat vmdk file name # The flat vmdk file name
flat_uploaded_vmdk_name = "%s/%s-flat.vmdk" % (instance.name, flat_uploaded_vmdk_name = "%s/%s-flat.vmdk" % (instance.name,
instance.name) instance.name)
#The vmdk meta-data file # The vmdk meta-data file
uploaded_vmdk_name = "%s/%s.vmdk" % (instance.name, instance.name) uploaded_vmdk_name = "%s/%s.vmdk" % (instance.name, instance.name)
flat_uploaded_vmdk_path = vm_util.build_datastore_path(data_store_name, flat_uploaded_vmdk_path = vm_util.build_datastore_path(data_store_name,
flat_uploaded_vmdk_name) flat_uploaded_vmdk_name)
@ -208,12 +211,13 @@ class VMWareVMOps(object):
uploaded_vmdk_name) uploaded_vmdk_name)
def _create_virtual_disk(): def _create_virtual_disk():
#Create a Virtual Disk of the size of the flat vmdk file. This is """Create a virtual disk of the size of flat vmdk file."""
#done just to generate the meta-data file whose specifics # Create a Virtual Disk of the size of the flat vmdk file. This is
#depend on the size of the disk, thin/thick provisioning and the # done just to generate the meta-data file whose specifics
#storage adapter type. # depend on the size of the disk, thin/thick provisioning and the
#Here we assume thick provisioning and lsiLogic for the adapter # storage adapter type.
#type # Here we assume thick provisioning and lsiLogic for the adapter
# type
LOG.debug(_("Creating Virtual Disk of size " LOG.debug(_("Creating Virtual Disk of size "
"%(vmdk_file_size_in_kb)s KB and adapter type " "%(vmdk_file_size_in_kb)s KB and adapter type "
"%(adapter_type)s on the ESX host local store" "%(adapter_type)s on the ESX host local store"
@ -245,7 +249,7 @@ class VMWareVMOps(object):
"store %(data_store_name)s") % "store %(data_store_name)s") %
{"flat_uploaded_vmdk_path": flat_uploaded_vmdk_path, {"flat_uploaded_vmdk_path": flat_uploaded_vmdk_path,
"data_store_name": data_store_name}) "data_store_name": data_store_name})
#Delete the -flat.vmdk file created. .vmdk file is retained. # Delete the -flat.vmdk file created. .vmdk file is retained.
vmdk_delete_task = self._session._call_method( vmdk_delete_task = self._session._call_method(
self._session._get_vim(), self._session._get_vim(),
"DeleteDatastoreFile_Task", "DeleteDatastoreFile_Task",
@ -262,12 +266,13 @@ class VMWareVMOps(object):
cookies = self._session._get_vim().client.options.transport.cookiejar cookies = self._session._get_vim().client.options.transport.cookiejar
def _fetch_image_on_esx_datastore(): def _fetch_image_on_esx_datastore():
"""Fetch image from Glance to ESX datastore."""
LOG.debug(_("Downloading image file data %(image_id)s to the ESX " LOG.debug(_("Downloading image file data %(image_id)s to the ESX "
"data store %(data_store_name)s") % "data store %(data_store_name)s") %
({'image_id': instance.image_id, ({'image_id': instance.image_id,
'data_store_name': data_store_name})) 'data_store_name': data_store_name}))
#Upload the -flat.vmdk file whose meta-data file we just created # Upload the -flat.vmdk file whose meta-data file we just created
#above # above
vmware_images.fetch_image( vmware_images.fetch_image(
instance.image_id, instance.image_id,
instance, instance,
@ -285,8 +290,10 @@ class VMWareVMOps(object):
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
def _attach_vmdk_to_the_vm(): def _attach_vmdk_to_the_vm():
#Attach the vmdk uploaded to the VM. VM reconfigure is done """
#to do so. Attach the vmdk uploaded to the VM. VM reconfigure is done
to do so.
"""
vmdk_attach_config_spec = vm_util.get_vmdk_attach_config_spec( vmdk_attach_config_spec = vm_util.get_vmdk_attach_config_spec(
client_factory, client_factory,
vmdk_file_size_in_kb, uploaded_vmdk_path, vmdk_file_size_in_kb, uploaded_vmdk_path,
@ -304,8 +311,9 @@ class VMWareVMOps(object):
_attach_vmdk_to_the_vm() _attach_vmdk_to_the_vm()
def _power_on_vm(): def _power_on_vm():
"""Power on the VM."""
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 the VM
power_on_task = self._session._call_method( power_on_task = self._session._call_method(
self._session._get_vim(), self._session._get_vim(),
"PowerOnVM_Task", vm_ref) "PowerOnVM_Task", vm_ref)
@ -325,7 +333,7 @@ class VMWareVMOps(object):
3. Call CopyVirtualDisk which coalesces the disk chain to form a single 3. Call CopyVirtualDisk which coalesces the disk chain to form a single
vmdk, rather a .vmdk metadata file and a -flat.vmdk disk data file. vmdk, rather a .vmdk metadata file and a -flat.vmdk disk data file.
4. Now upload the -flat.vmdk file to the image store. 4. Now upload the -flat.vmdk file to the image store.
5. Delete the coalesced .vmdk and -flat.vmdk created 5. Delete the coalesced .vmdk and -flat.vmdk created.
""" """
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
@ -336,7 +344,7 @@ class VMWareVMOps(object):
service_content = self._session._get_vim().get_service_content() service_content = self._session._get_vim().get_service_content()
def _get_vm_and_vmdk_attribs(): def _get_vm_and_vmdk_attribs():
#Get the vmdk file name that the VM is pointing to # Get the vmdk file name that the VM is pointing to
hardware_devices = self._session._call_method(vim_util, hardware_devices = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref, "get_dynamic_property", vm_ref,
"VirtualMachine", "config.hardware.device") "VirtualMachine", "config.hardware.device")
@ -355,7 +363,7 @@ class VMWareVMOps(object):
os_type = _get_vm_and_vmdk_attribs() os_type = _get_vm_and_vmdk_attribs()
def _create_vm_snapshot(): def _create_vm_snapshot():
#Create a snapshot of the VM # Create a snapshot of the VM
LOG.debug(_("Creating Snapshot of the VM instance %s ") % LOG.debug(_("Creating Snapshot of the VM instance %s ") %
instance.name) instance.name)
snapshot_task = self._session._call_method( snapshot_task = self._session._call_method(
@ -372,8 +380,8 @@ class VMWareVMOps(object):
_create_vm_snapshot() _create_vm_snapshot()
def _check_if_tmp_folder_exists(): def _check_if_tmp_folder_exists():
#Copy the contents of the VM that were there just before the # Copy the contents of the VM that were there just before the
#snapshot was taken # snapshot was taken
ds_ref_ret = vim_util.get_dynamic_property( ds_ref_ret = vim_util.get_dynamic_property(
self._session._get_vim(), self._session._get_vim(),
vm_ref, vm_ref,
@ -388,7 +396,7 @@ class VMWareVMOps(object):
ds_ref, ds_ref,
"Datastore", "Datastore",
"browser") "browser")
#Check if the vmware-tmp folder exists or not. If not, create one # Check if the vmware-tmp folder exists or not. If not, create one
tmp_folder_path = vm_util.build_datastore_path(datastore_name, tmp_folder_path = vm_util.build_datastore_path(datastore_name,
"vmware-tmp") "vmware-tmp")
if not self._path_exists(ds_browser, tmp_folder_path): if not self._path_exists(ds_browser, tmp_folder_path):
@ -397,17 +405,17 @@ class VMWareVMOps(object):
_check_if_tmp_folder_exists() _check_if_tmp_folder_exists()
#Generate a random vmdk file name to which the coalesced vmdk content # 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 # will be copied to. A random name is chosen so that we don't have
#name clashes. # name clashes.
random_name = str(uuid.uuid4()) random_name = str(uuid.uuid4())
dest_vmdk_file_location = vm_util.build_datastore_path(datastore_name, dest_vmdk_file_location = vm_util.build_datastore_path(datastore_name,
"vmware-tmp/%s.vmdk" % random_name) "vmware-tmp/%s.vmdk" % random_name)
dc_ref = self._get_datacenter_name_and_ref()[0] dc_ref = self._get_datacenter_name_and_ref()[0]
def _copy_vmdk_content(): def _copy_vmdk_content():
#Copy the contents of the disk ( or disks, if there were snapshots # Copy the contents of the disk ( or disks, if there were snapshots
#done earlier) to a temporary vmdk file. # done earlier) to a temporary vmdk file.
copy_spec = vm_util.get_copy_virtual_disk_spec(client_factory, copy_spec = vm_util.get_copy_virtual_disk_spec(client_factory,
adapter_type) adapter_type)
LOG.debug(_("Copying disk data before snapshot of the VM " LOG.debug(_("Copying disk data before snapshot of the VM "
@ -431,7 +439,7 @@ class VMWareVMOps(object):
cookies = self._session._get_vim().client.options.transport.cookiejar cookies = self._session._get_vim().client.options.transport.cookiejar
def _upload_vmdk_to_image_repository(): def _upload_vmdk_to_image_repository():
#Upload the contents of -flat.vmdk file which has the disk data. # Upload the contents of -flat.vmdk file which has the disk data.
LOG.debug(_("Uploading image %s") % snapshot_name) LOG.debug(_("Uploading image %s") % snapshot_name)
vmware_images.upload_image( vmware_images.upload_image(
snapshot_name, snapshot_name,
@ -449,7 +457,11 @@ class VMWareVMOps(object):
_upload_vmdk_to_image_repository() _upload_vmdk_to_image_repository()
def _clean_temp_data(): def _clean_temp_data():
#Delete the temporary vmdk created above. """
Delete temporary vmdk files generated in image handling
operations.
"""
# Delete the temporary vmdk created above.
LOG.debug(_("Deleting temporary vmdk file %s") LOG.debug(_("Deleting temporary vmdk file %s")
% dest_vmdk_file_location) % dest_vmdk_file_location)
remove_disk_task = self._session._call_method( remove_disk_task = self._session._call_method(
@ -465,7 +477,7 @@ class VMWareVMOps(object):
_clean_temp_data() _clean_temp_data()
def reboot(self, instance): def reboot(self, instance):
""" Reboot a VM instance """ """Reboot a VM instance."""
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -483,13 +495,13 @@ class VMWareVMOps(object):
elif prop.name == "summary.guest.toolsStatus": elif prop.name == "summary.guest.toolsStatus":
tools_status = prop.val tools_status = prop.val
#Raise an exception if the VM is not powered On. # Raise an exception if the VM is not powered On.
if pwr_state not in ["poweredOn"]: if pwr_state not in ["poweredOn"]:
raise exception.Invalid(_("instance - %s not poweredOn. So can't " raise exception.Invalid(_("instance - %s not poweredOn. So can't "
"be rebooted.") % instance.name) "be rebooted.") % instance.name)
#If vmware tools are installed in the VM, then do a guest reboot. # If vmware tools are installed in the VM, then do a guest reboot.
#Otherwise do a hard reset. # Otherwise do a hard reset.
if tools_status not in ['toolsNotInstalled', 'toolsNotRunning']: if tools_status not in ['toolsNotInstalled', 'toolsNotRunning']:
LOG.debug(_("Rebooting guest OS of VM %s") % instance.name) LOG.debug(_("Rebooting guest OS of VM %s") % instance.name)
self._session._call_method(self._session._get_vim(), "RebootGuest", self._session._call_method(self._session._get_vim(), "RebootGuest",
@ -507,7 +519,7 @@ class VMWareVMOps(object):
Destroy a VM instance. Steps followed are: Destroy a VM instance. Steps followed are:
1. Power off the VM, if it is in poweredOn state. 1. Power off the VM, if it is in poweredOn state.
2. Un-register a VM. 2. Un-register a VM.
3. Delete the contents of the folder holding the VM related data 3. Delete the contents of the folder holding the VM related data.
""" """
try: try:
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
@ -529,7 +541,7 @@ class VMWareVMOps(object):
if vm_config_pathname: if vm_config_pathname:
datastore_name, vmx_file_path = \ datastore_name, vmx_file_path = \
vm_util.split_datastore_path(vm_config_pathname) vm_util.split_datastore_path(vm_config_pathname)
#Power off the VM if it is in PoweredOn state. # Power off the VM if it is in PoweredOn state.
if pwr_state == "poweredOn": if pwr_state == "poweredOn":
LOG.debug(_("Powering off the VM %s") % instance.name) LOG.debug(_("Powering off the VM %s") % instance.name)
poweroff_task = self._session._call_method( poweroff_task = self._session._call_method(
@ -538,7 +550,7 @@ class VMWareVMOps(object):
self._session._wait_for_task(instance.id, poweroff_task) self._session._wait_for_task(instance.id, poweroff_task)
LOG.debug(_("Powered off the VM %s") % instance.name) LOG.debug(_("Powered off the VM %s") % instance.name)
#Un-register the VM # Un-register the VM
try: try:
LOG.debug(_("Unregistering the VM %s") % instance.name) LOG.debug(_("Unregistering the VM %s") % instance.name)
self._session._call_method(self._session._get_vim(), self._session._call_method(self._session._get_vim(),
@ -548,7 +560,8 @@ class VMWareVMOps(object):
LOG.warn(_("In vmwareapi:vmops:destroy, got this exception" LOG.warn(_("In vmwareapi:vmops:destroy, got this exception"
" while un-registering the VM: %s") % str(excep)) " while un-registering the VM: %s") % str(excep))
#Delete the folder holding the VM related content on the datastore. # Delete the folder holding the VM related content on
# the datastore.
try: try:
dir_ds_compliant_path = vm_util.build_datastore_path( dir_ds_compliant_path = vm_util.build_datastore_path(
datastore_name, datastore_name,
@ -564,7 +577,7 @@ class VMWareVMOps(object):
name=dir_ds_compliant_path) name=dir_ds_compliant_path)
self._session._wait_for_task(instance.id, delete_task) self._session._wait_for_task(instance.id, delete_task)
LOG.debug(_("Deleted contents of the VM %(name)s from " LOG.debug(_("Deleted contents of the VM %(name)s from "
"datastore %(datastore_name)s") "datastore %(datastore_name)s") %
({'name': instance.name, ({'name': instance.name,
'datastore_name': datastore_name})) 'datastore_name': datastore_name}))
except Exception, excep: except Exception, excep:
@ -576,15 +589,15 @@ class VMWareVMOps(object):
LOG.exception(e) LOG.exception(e)
def pause(self, instance, callback): def pause(self, instance, callback):
""" Pause a VM instance """ """Pause a VM instance."""
raise exception.APIError("pause not supported for vmwareapi") raise exception.APIError("pause not supported for vmwareapi")
def unpause(self, instance, callback): def unpause(self, instance, callback):
""" Un-Pause a VM instance """ """Un-Pause a VM instance."""
raise exception.APIError("unpause not supported for vmwareapi") raise exception.APIError("unpause not supported for vmwareapi")
def suspend(self, instance, callback): def suspend(self, instance, callback):
""" Suspend the specified instance """ """Suspend the specified instance."""
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -593,14 +606,14 @@ class VMWareVMOps(object):
pwr_state = self._session._call_method(vim_util, pwr_state = self._session._call_method(vim_util,
"get_dynamic_property", vm_ref, "get_dynamic_property", vm_ref,
"VirtualMachine", "runtime.powerState") "VirtualMachine", "runtime.powerState")
#Only PoweredOn VMs can be suspended. # Only PoweredOn VMs can be suspended.
if pwr_state == "poweredOn": if pwr_state == "poweredOn":
LOG.debug(_("Suspending the VM %s ") % instance.name) LOG.debug(_("Suspending the VM %s ") % instance.name)
suspend_task = self._session._call_method(self._session._get_vim(), suspend_task = self._session._call_method(self._session._get_vim(),
"SuspendVM_Task", vm_ref) "SuspendVM_Task", vm_ref)
self._wait_with_callback(instance.id, suspend_task, callback) self._wait_with_callback(instance.id, suspend_task, callback)
LOG.debug(_("Suspended the VM %s ") % instance.name) LOG.debug(_("Suspended the VM %s ") % instance.name)
#Raise Exception if VM is poweredOff # Raise Exception if VM is poweredOff
elif pwr_state == "poweredOff": elif pwr_state == "poweredOff":
raise exception.Invalid(_("instance - %s is poweredOff and hence " raise exception.Invalid(_("instance - %s is poweredOff and hence "
" can't be suspended.") % instance.name) " can't be suspended.") % instance.name)
@ -608,7 +621,7 @@ class VMWareVMOps(object):
"without doing anything") % instance.name) "without doing anything") % instance.name)
def resume(self, instance, callback): def resume(self, instance, callback):
""" Resume the specified instance """ """Resume the specified instance."""
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -629,7 +642,7 @@ class VMWareVMOps(object):
"and hence can't be Resumed.") % instance.name) "and hence can't be Resumed.") % instance.name)
def get_info(self, 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) vm_ref = self._get_vm_ref_from_the_name(instance_name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -661,12 +674,12 @@ class VMWareVMOps(object):
'cpu_time': 0} 'cpu_time': 0}
def get_diagnostics(self, instance): def get_diagnostics(self, instance):
""" Return data about VM diagnostics """ """Return data about VM diagnostics."""
raise exception.APIError("get_diagnostics not implemented for " raise exception.APIError("get_diagnostics not implemented for "
"vmwareapi") "vmwareapi")
def get_console_output(self, instance): def get_console_output(self, instance):
""" Return snapshot of console """ """Return snapshot of console."""
vm_ref = self._get_vm_ref_from_the_name(instance.name) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -688,12 +701,14 @@ class VMWareVMOps(object):
return "" return ""
def get_ajax_console(self, instance): 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' return 'http://fakeajaxconsole/fake_url'
def _set_machine_id(self, client_factory, instance): 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 """ 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) vm_ref = self._get_vm_ref_from_the_name(instance.name)
if vm_ref is None: if vm_ref is None:
raise exception.NotFound(_("instance - %s not present") % raise exception.NotFound(_("instance - %s not present") %
@ -722,19 +737,19 @@ class VMWareVMOps(object):
'ip_addr': ip_addr})) 'ip_addr': ip_addr}))
def _get_datacenter_name_and_ref(self): 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", dc_obj = self._session._call_method(vim_util, "get_objects",
"Datacenter", ["name"]) "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): 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(), search_task = self._session._call_method(self._session._get_vim(),
"SearchDatastore_Task", "SearchDatastore_Task",
ds_browser, ds_browser,
datastorePath=ds_path) datastorePath=ds_path)
#Wait till the state changes from queued or running. # Wait till the state changes from queued or running.
#If an error state is returned, it means that the path doesn't exist. # If an error state is returned, it means that the path doesn't exist.
while True: while True:
task_info = self._session._call_method(vim_util, task_info = self._session._call_method(vim_util,
"get_dynamic_property", "get_dynamic_property",
@ -748,9 +763,11 @@ class VMWareVMOps(object):
return True return True
def _mkdir(self, ds_path): 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 Creates a directory at the path specified. If it is just "NAME",
DataStore. """ then a directory with this name is created at the topmost level of the
DataStore.
"""
LOG.debug(_("Creating directory with path %s") % ds_path) LOG.debug(_("Creating directory with path %s") % ds_path)
self._session._call_method(self._session._get_vim(), "MakeDirectory", 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,
@ -758,7 +775,7 @@ class VMWareVMOps(object):
LOG.debug(_("Created directory with path %s") % ds_path) LOG.debug(_("Created directory with path %s") % ds_path)
def _get_vm_ref_from_the_name(self, vm_name): 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", vms = self._session._call_method(vim_util, "get_objects",
"VirtualMachine", ["name"]) "VirtualMachine", ["name"])
for vm in vms: for vm in vms:

View File

@ -15,15 +15,14 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
""" """
Utility functions for Image transfer Utility functions for Image transfer.
""" """
import time import glance.client
from nova import exception from nova import exception
from nova import flags from nova import flags
from nova import log as logging from nova import log as logging
from nova.virt.vmwareapi import io_util
from nova.virt.vmwareapi import read_write_util from nova.virt.vmwareapi import read_write_util
FLAGS = flags.FLAGS FLAGS = flags.FLAGS
@ -35,44 +34,9 @@ WRITE_CHUNKSIZE = 2 * 1024 * 1024
LOG = logging.getLogger("nova.virt.vmwareapi.vmware_images") LOG = logging.getLogger("nova.virt.vmwareapi.vmware_images")
def start_transfer(read_file_handle, write_file_handle, data_size):
""" 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
read_thread = io_util.IOThread(read_file_handle, thread_safe_pipe,
READ_CHUNKSIZE, long(data_size))
#The write thread
write_thread = io_util.IOThread(thread_safe_pipe, write_file_handle,
WRITE_CHUNKSIZE, long(data_size))
read_thread.start()
write_thread.start()
LOG.debug(_("Starting image file transfer"))
#Wait till both the read thread and the write thread are done
while not (read_thread.is_done() and write_thread.is_done()):
if read_thread.get_error() or write_thread.get_error():
read_thread.stop_io_transfer()
write_thread.stop_io_transfer()
# If there was an exception in reading or writing, raise the same.
read_excep = read_thread.get_exception()
write_excep = write_thread.get_exception()
if read_excep is not None:
LOG.exception(str(read_excep))
raise exception.Error(read_excep)
if write_excep is not None:
LOG.exception(str(write_excep))
raise exception.Error(write_excep)
time.sleep(2)
LOG.debug(_("Finished image file transfer and closing the file handles"))
#Close the file handles
read_file_handle.close()
write_file_handle.close()
def fetch_image(image, instance, **kwargs): 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 # Depending upon the image service, make appropriate image service call
if FLAGS.image_service == "nova.image.glance.GlanceImageService": if FLAGS.image_service == "nova.image.glance.GlanceImageService":
func = _get_glance_image func = _get_glance_image
elif FLAGS.image_service == "nova.image.s3.S3ImageService": elif FLAGS.image_service == "nova.image.s3.S3ImageService":
@ -86,8 +50,8 @@ def fetch_image(image, instance, **kwargs):
def upload_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 # Depending upon the image service, make appropriate image service call
if FLAGS.image_service == "nova.image.glance.GlanceImageService": if FLAGS.image_service == "nova.image.glance.GlanceImageService":
func = _put_glance_image func = _put_glance_image
elif FLAGS.image_service == "nova.image.s3.S3ImageService": elif FLAGS.image_service == "nova.image.s3.S3ImageService":
@ -101,12 +65,11 @@ def upload_image(image, instance, **kwargs):
def _get_glance_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) LOG.debug(_("Downloading image %s from glance image server") % image)
read_file_handle = read_write_util.GlanceHTTPReadFile(FLAGS.glance_host, glance_client = glance.client.Client(FLAGS.glance_host, FLAGS.glance_port)
FLAGS.glance_port, metadata, read_file_handle = glance_client.get_image(image)
image) file_size = int(metadata['size'])
file_size = read_file_handle.get_size()
write_file_handle = read_write_util.VMWareHTTPWriteFile( write_file_handle = read_write_util.VMWareHTTPWriteFile(
kwargs.get("host"), kwargs.get("host"),
kwargs.get("data_center_name"), kwargs.get("data_center_name"),
@ -114,22 +77,23 @@ def _get_glance_image(image, instance, **kwargs):
kwargs.get("cookies"), kwargs.get("cookies"),
kwargs.get("file_path"), kwargs.get("file_path"),
file_size) file_size)
start_transfer(read_file_handle, write_file_handle, file_size) for chunk in read_file_handle:
write_file_handle.write(chunk)
LOG.debug(_("Downloaded image %s from glance image server") % image) LOG.debug(_("Downloaded image %s from glance image server") % image)
def _get_s3_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 raise NotImplementedError
def _get_local_image(image, instance, **kwargs): 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 raise NotImplementedError
def _put_glance_image(image, instance, **kwargs): 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) LOG.debug(_("Uploading image %s to the Glance image server") % image)
read_file_handle = read_write_util.VmWareHTTPReadFile( read_file_handle = read_write_util.VmWareHTTPReadFile(
kwargs.get("host"), kwargs.get("host"),
@ -137,47 +101,48 @@ def _put_glance_image(image, instance, **kwargs):
kwargs.get("datastore_name"), kwargs.get("datastore_name"),
kwargs.get("cookies"), kwargs.get("cookies"),
kwargs.get("file_path")) kwargs.get("file_path"))
file_size = read_file_handle.get_size() glance_client = glance.client.Client(FLAGS.glance_host, FLAGS.glance_port)
write_file_handle = read_write_util.GlanceHTTPWriteFile( image_metadata = {"is_public": True,
FLAGS.glance_host, "disk_format": "vmdk",
FLAGS.glance_port, "container_format": "bare",
image, "type": "vmdk",
file_size, "properties": {"vmware_adaptertype":
kwargs.get("os_type"), kwargs.get("adapter_type"),
kwargs.get("adapter_type"), "vmware_ostype": kwargs.get("os_type"),
kwargs.get("image_version")) "vmware_image_version":
start_transfer(read_file_handle, write_file_handle, file_size) kwargs.get("image_version")}}
glance_client.update_image(image, image_meta=image_metadata,
image_data=read_file_handle)
LOG.debug(_("Uploaded image %s to the Glance image server") % image) LOG.debug(_("Uploaded image %s to the Glance image server") % image)
def _put_local_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 raise NotImplementedError
def _put_s3_image(image, instance, **kwargs): 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 raise NotImplementedError
def get_vmdk_size_and_properties(image, instance): 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 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) LOG.debug(_("Getting image size for the image %s") % image)
if FLAGS.image_service == "nova.image.glance.GlanceImageService": if FLAGS.image_service == "nova.image.glance.GlanceImageService":
read_file_handle = read_write_util.GlanceHTTPReadFile( glance_client = glance.client.Client(FLAGS.glance_host,
FLAGS.glance_host, FLAGS.glance_port)
FLAGS.glance_port, meta_data = glance_client.get_image_meta(image)
image) size, properties = meta_data["size"], meta_data["properties"]
elif FLAGS.image_service == "nova.image.s3.S3ImageService": elif FLAGS.image_service == "nova.image.s3.S3ImageService":
raise NotImplementedError raise NotImplementedError
elif FLAGS.image_service == "nova.image.local.LocalImageService": elif FLAGS.image_service == "nova.image.local.LocalImageService":
raise NotImplementedError raise NotImplementedError
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") % LOG.debug(_("Got image size of %(size)s for the image %(image)s") %
locals()) locals())
return size, properties return size, properties

View File

@ -29,6 +29,7 @@ A connection to the VMware ESX platform.
:vmwareapi_api_retry_count: The API retry count in case of failure such as :vmwareapi_api_retry_count: The API retry count in case of failure such as
network failures (socket errors etc.) network failures (socket errors etc.)
(default: 10). (default: 10).
""" """
import time import time
@ -78,7 +79,7 @@ TIME_BETWEEN_API_CALL_RETRIES = 2.0
class Failure(Exception): class Failure(Exception):
"""Base Exception class for handling task failures""" """Base Exception class for handling task failures."""
def __init__(self, details): def __init__(self, details):
self.details = details self.details = details
@ -103,7 +104,7 @@ def get_connection(_):
class VMWareESXConnection(object): class VMWareESXConnection(object):
"""The ESX host connection object""" """The ESX host connection object."""
def __init__(self, host_ip, host_username, host_password, def __init__(self, host_ip, host_username, host_password,
api_retry_count, scheme="https"): api_retry_count, scheme="https"):
@ -112,80 +113,85 @@ class VMWareESXConnection(object):
self._vmops = VMWareVMOps(session) self._vmops = VMWareVMOps(session)
def init_host(self, host): def init_host(self, host):
"""Do the initialization that needs to be done""" """Do the initialization that needs to be done."""
#FIXME(sateesh): implement this # FIXME(sateesh): implement this
pass pass
def list_instances(self): def list_instances(self):
"""List VM instances""" """List VM instances."""
return self._vmops.list_instances() return self._vmops.list_instances()
def spawn(self, instance): def spawn(self, instance):
"""Create VM instance""" """Create VM instance."""
self._vmops.spawn(instance) self._vmops.spawn(instance)
def snapshot(self, instance, name): def snapshot(self, instance, name):
"""Create snapshot from a running VM instance""" """Create snapshot from a running VM instance."""
self._vmops.snapshot(instance, name) self._vmops.snapshot(instance, name)
def reboot(self, instance): def reboot(self, instance):
"""Reboot VM instance""" """Reboot VM instance."""
self._vmops.reboot(instance) self._vmops.reboot(instance)
def destroy(self, instance): def destroy(self, instance):
"""Destroy VM instance""" """Destroy VM instance."""
self._vmops.destroy(instance) self._vmops.destroy(instance)
def pause(self, instance, callback): def pause(self, instance, callback):
"""Pause VM instance""" """Pause VM instance."""
self._vmops.pause(instance, callback) self._vmops.pause(instance, callback)
def unpause(self, instance, callback): def unpause(self, instance, callback):
"""Unpause paused VM instance""" """Unpause paused VM instance."""
self._vmops.unpause(instance, callback) self._vmops.unpause(instance, callback)
def suspend(self, instance, callback): def suspend(self, instance, callback):
"""Suspend the specified instance""" """Suspend the specified instance."""
self._vmops.suspend(instance, callback) self._vmops.suspend(instance, callback)
def resume(self, instance, callback): def resume(self, instance, callback):
"""Resume the suspended VM instance""" """Resume the suspended VM instance."""
self._vmops.resume(instance, callback) self._vmops.resume(instance, callback)
def get_info(self, instance_id): def get_info(self, instance_id):
"""Return info about the VM instance""" """Return info about the VM instance."""
return self._vmops.get_info(instance_id) return self._vmops.get_info(instance_id)
def get_diagnostics(self, instance): def get_diagnostics(self, instance):
"""Return data about VM diagnostics""" """Return data about VM diagnostics."""
return self._vmops.get_info(instance) return self._vmops.get_info(instance)
def get_console_output(self, instance): def get_console_output(self, instance):
"""Return snapshot of console""" """Return snapshot of console."""
return self._vmops.get_console_output(instance) return self._vmops.get_console_output(instance)
def get_ajax_console(self, instance): def get_ajax_console(self, instance):
"""Return link to instance's ajax console""" """Return link to instance's ajax console."""
return self._vmops.get_ajax_console(instance) return self._vmops.get_ajax_console(instance)
def attach_volume(self, instance_name, device_path, mountpoint): def attach_volume(self, instance_name, device_path, mountpoint):
"""Attach volume storage to VM instance""" """Attach volume storage to VM instance."""
pass pass
def detach_volume(self, instance_name, mountpoint): def detach_volume(self, instance_name, mountpoint):
"""Detach volume storage to VM instance""" """Detach volume storage to VM instance."""
pass pass
def get_console_pool_info(self, console_type): def get_console_pool_info(self, console_type):
"""Get info about the host on which the VM resides""" """Get info about the host on which the VM resides."""
return {'address': FLAGS.vmwareapi_host_ip, return {'address': FLAGS.vmwareapi_host_ip,
'username': FLAGS.vmwareapi_host_username, 'username': FLAGS.vmwareapi_host_username,
'password': FLAGS.vmwareapi_host_password} 'password': FLAGS.vmwareapi_host_password}
def update_available_resource(self, ctxt, host):
"""This method is supported only by libvirt."""
return
class VMWareAPISession(object): class VMWareAPISession(object):
"""Sets up a session with the ESX host and handles all """
the calls made to the 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, def __init__(self, host_ip, host_username, host_password,
@ -200,11 +206,11 @@ class VMWareAPISession(object):
self._create_session() self._create_session()
def _get_vim_object(self): def _get_vim_object(self):
"""Create the VIM Object instance""" """Create the VIM Object instance."""
return vim.Vim(protocol=self._scheme, host=self._host_ip) return vim.Vim(protocol=self._scheme, host=self._host_ip)
def _create_session(self): def _create_session(self):
"""Creates a session with the ESX host""" """Creates a session with the ESX host."""
while True: while True:
try: try:
# Login and setup the session with the ESX host for making # Login and setup the session with the ESX host for making
@ -241,12 +247,13 @@ class VMWareAPISession(object):
pass pass
def _is_vim_object(self, module): def _is_vim_object(self, module):
"""Check if the module is a VIM Object instance""" """Check if the module is a VIM Object instance."""
return isinstance(module, vim.Vim) return isinstance(module, vim.Vim)
def _call_method(self, module, method, *args, **kwargs): 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) args = list(args)
retry_count = 0 retry_count = 0
@ -254,7 +261,8 @@ class VMWareAPISession(object):
while True: while True:
try: try:
if not self._is_vim_object(module): if not self._is_vim_object(module):
#If it is not the first try, then get the latest vim object # If it is not the first try, then get the latest
# vim object
if retry_count > 0: if retry_count > 0:
args = args[1:] args = args[1:]
args = [self.vim] + args args = [self.vim] + args
@ -264,8 +272,7 @@ class VMWareAPISession(object):
for method_elem in method.split("."): for method_elem in method.split("."):
temp_module = getattr(temp_module, method_elem) temp_module = getattr(temp_module, method_elem)
ret_val = temp_module(*args, **kwargs) return temp_module(*args, **kwargs)
return ret_val
except error_util.VimFaultException, excep: except error_util.VimFaultException, excep:
# If it is a Session Fault Exception, it may point # If it is a Session Fault Exception, it may point
# to a session gone bad. So we try re-creating a session # to a session gone bad. So we try re-creating a session
@ -274,9 +281,9 @@ class VMWareAPISession(object):
if error_util.FAULT_NOT_AUTHENTICATED in excep.fault_list: if error_util.FAULT_NOT_AUTHENTICATED in excep.fault_list:
self._create_session() self._create_session()
else: else:
#No re-trying for errors for API call has gone through # No re-trying for errors for API call has gone through
#and is the caller's fault. Caller should handle these # and is the caller's fault. Caller should handle these
#errors. e.g, InvalidArgument fault. # errors. e.g, InvalidArgument fault.
break break
except error_util.SessionOverLoadException, excep: except error_util.SessionOverLoadException, excep:
# For exceptions which may come because of session overload, # For exceptions which may come because of session overload,
@ -299,13 +306,14 @@ class VMWareAPISession(object):
raise raise
def _get_vim(self): def _get_vim(self):
"""Gets the VIM object reference""" """Gets the VIM object reference."""
if self.vim is None: if self.vim is None:
self._create_session() self._create_session()
return self.vim return self.vim
def _wait_for_task(self, instance_id, task_ref): 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. The task is polled until it completes.
""" """
done = event.Event() done = event.Event()
@ -317,7 +325,8 @@ class VMWareAPISession(object):
return ret_val return ret_val
def _poll_task(self, instance_id, task_ref, done): 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. get a result.
""" """
try: try:
@ -331,7 +340,7 @@ class VMWareAPISession(object):
if task_info.state in ['queued', 'running']: if task_info.state in ['queued', 'running']:
return return
elif task_info.state == 'success': elif task_info.state == 'success':
LOG.info(_("Task [%(task_name)s] %(task_ref)s " LOG.debug(_("Task [%(task_name)s] %(task_ref)s "
"status: success") % locals()) "status: success") % locals())
done.send("success") done.send("success")
else: else:

View File

@ -36,7 +36,7 @@ ARCH_32_BIT = '32bit'
ARCH_64_BIT = '64bit' ARCH_64_BIT = '64bit'
NO_MACHINE_ID = 'No machine id' NO_MACHINE_ID = 'No machine id'
#Logging # Logging
FORMAT = "%(asctime)s - %(levelname)s - %(message)s" FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
if sys.platform == PLATFORM_WIN: if sys.platform == PLATFORM_WIN:
LOG_DIR = os.path.join(os.environ.get('ALLUSERSPROFILE'), 'openstack') LOG_DIR = os.path.join(os.environ.get('ALLUSERSPROFILE'), 'openstack')
@ -56,7 +56,7 @@ else:
class ProcessExecutionError: class ProcessExecutionError:
"""Process Execution Error Class""" """Process Execution Error Class."""
def __init__(self, exit_code, stdout, stderr, cmd): def __init__(self, exit_code, stdout, stderr, cmd):
self.exit_code = exit_code self.exit_code = exit_code
@ -77,7 +77,8 @@ def _bytes2int(bytes):
def _parse_network_details(machine_id): def _parse_network_details(machine_id):
"""Parse the machine.id field to get MAC, IP, Netmask and Gateway fields """
Parse the machine.id field to get MAC, IP, Netmask and Gateway fields
machine.id is of the form MAC;IP;Netmask;Gateway;Broadcast;DNS1,DNS2 machine.id is of the form MAC;IP;Netmask;Gateway;Broadcast;DNS1,DNS2
where ';' is the separator. where ';' is the separator.
""" """
@ -103,7 +104,7 @@ def _parse_network_details(machine_id):
def _get_windows_network_adapters(): def _get_windows_network_adapters():
"""Get the list of windows network adapters""" """Get the list of windows network adapters."""
import win32com.client import win32com.client
wbem_locator = win32com.client.Dispatch('WbemScripting.SWbemLocator') wbem_locator = win32com.client.Dispatch('WbemScripting.SWbemLocator')
wbem_service = wbem_locator.ConnectServer('.', 'root\cimv2') wbem_service = wbem_locator.ConnectServer('.', 'root\cimv2')
@ -132,7 +133,7 @@ def _get_windows_network_adapters():
def _get_linux_network_adapters(): def _get_linux_network_adapters():
"""Get the list of Linux network adapters""" """Get the list of Linux network adapters."""
import fcntl import fcntl
max_bytes = 8096 max_bytes = 8096
arch = platform.architecture()[0] arch = platform.architecture()[0]
@ -177,7 +178,7 @@ def _get_linux_network_adapters():
def _get_adapter_name_and_ip_address(network_adapters, mac_address): def _get_adapter_name_and_ip_address(network_adapters, mac_address):
"""Get the adapter name based on the MAC address""" """Get the adapter name based on the MAC address."""
adapter_name = None adapter_name = None
ip_address = None ip_address = None
for network_adapter in network_adapters: for network_adapter in network_adapters:
@ -189,19 +190,19 @@ def _get_adapter_name_and_ip_address(network_adapters, mac_address):
def _get_win_adapter_name_and_ip_address(mac_address): def _get_win_adapter_name_and_ip_address(mac_address):
"""Get Windows network adapter name""" """Get Windows network adapter name."""
network_adapters = _get_windows_network_adapters() network_adapters = _get_windows_network_adapters()
return _get_adapter_name_and_ip_address(network_adapters, mac_address) return _get_adapter_name_and_ip_address(network_adapters, mac_address)
def _get_linux_adapter_name_and_ip_address(mac_address): def _get_linux_adapter_name_and_ip_address(mac_address):
"""Get Linux network adapter name""" """Get Linux network adapter name."""
network_adapters = _get_linux_network_adapters() network_adapters = _get_linux_network_adapters()
return _get_adapter_name_and_ip_address(network_adapters, mac_address) return _get_adapter_name_and_ip_address(network_adapters, mac_address)
def _execute(cmd_list, process_input=None, check_exit_code=True): def _execute(cmd_list, process_input=None, check_exit_code=True):
"""Executes the command with the list of arguments specified""" """Executes the command with the list of arguments specified."""
cmd = ' '.join(cmd_list) cmd = ' '.join(cmd_list)
logging.debug(_("Executing command: '%s'") % cmd) logging.debug(_("Executing command: '%s'") % cmd)
env = os.environ.copy() env = os.environ.copy()
@ -226,7 +227,7 @@ def _execute(cmd_list, process_input=None, check_exit_code=True):
def _windows_set_networking(): def _windows_set_networking():
"""Set IP address for the windows VM""" """Set IP address for the windows VM."""
program_files = os.environ.get('PROGRAMFILES') program_files = os.environ.get('PROGRAMFILES')
program_files_x86 = os.environ.get('PROGRAMFILES(X86)') program_files_x86 = os.environ.get('PROGRAMFILES(X86)')
vmware_tools_bin = None vmware_tools_bin = None
@ -256,7 +257,7 @@ def _windows_set_networking():
'name="%s"' % adapter_name, 'source=static', ip_address, 'name="%s"' % adapter_name, 'source=static', ip_address,
subnet_mask, gateway, '1'] subnet_mask, gateway, '1']
_execute(cmd) _execute(cmd)
#Windows doesn't let you manually set the broadcast address # Windows doesn't let you manually set the broadcast address
for dns_server in dns_servers: for dns_server in dns_servers:
if dns_server: if dns_server:
cmd = ['netsh', 'interface', 'ip', 'add', 'dns', cmd = ['netsh', 'interface', 'ip', 'add', 'dns',
@ -285,9 +286,9 @@ def _set_rhel_networking(network_details=[]):
if adapter_name and not ip_address == current_ip_address: if adapter_name and not ip_address == current_ip_address:
interface_file_name = \ interface_file_name = \
'/etc/sysconfig/network-scripts/ifcfg-%s' % adapter_name '/etc/sysconfig/network-scripts/ifcfg-%s' % adapter_name
#Remove file # Remove file
os.remove(interface_file_name) os.remove(interface_file_name)
#Touch file # Touch file
_execute(['touch', interface_file_name]) _execute(['touch', interface_file_name])
interface_file = open(interface_file_name, 'w') interface_file = open(interface_file_name, 'w')
interface_file.write('\nDEVICE=%s' % adapter_name) interface_file.write('\nDEVICE=%s' % adapter_name)
@ -315,7 +316,7 @@ def _set_rhel_networking(network_details=[]):
def _linux_set_networking(): def _linux_set_networking():
"""Set IP address for the Linux VM""" """Set IP address for the Linux VM."""
vmware_tools_bin = None vmware_tools_bin = None
if os.path.exists('/usr/sbin/vmtoolsd'): if os.path.exists('/usr/sbin/vmtoolsd'):
vmware_tools_bin = '/usr/sbin/vmtoolsd' vmware_tools_bin = '/usr/sbin/vmtoolsd'
@ -329,7 +330,7 @@ def _linux_set_networking():
cmd = [vmware_tools_bin, '--cmd', 'machine.id.get'] cmd = [vmware_tools_bin, '--cmd', 'machine.id.get']
network_details = _parse_network_details(_execute(cmd, network_details = _parse_network_details(_execute(cmd,
check_exit_code=False)) check_exit_code=False))
#TODO: For other distros like ubuntu, suse, debian, BSD, etc. # TODO(sateesh): For other distros like ubuntu, suse, debian, BSD, etc.
_set_rhel_networking(network_details) _set_rhel_networking(network_details)
else: else:
logging.warn(_("VMware Tools is not installed")) logging.warn(_("VMware Tools is not installed"))