* 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:
parent
cd381ae3e1
commit
45ca7b71a8
@ -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.
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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})
|
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
=======================================
|
||||||
|
"""
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
"""
|
"""
|
||||||
|
@ -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 "
|
||||||
|
@ -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"))
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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')
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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"))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user