summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorEd Leafe <ed@leafe.com>2010-12-28 16:02:46 -0600
committerEd Leafe <ed@leafe.com>2010-12-28 16:02:46 -0600
commitd531e873b97a8ff92d1534811f702e89a8cf60a7 (patch)
tree75d2c5e5a44baeb1ddb2ce93d3e61d32f1225095 /nova/virt
parentef8e4495f5ed195a08be6c02b3eb3326f6403bb6 (diff)
parent675ca7c5f38af0fa1150936e881482aa20fdaa45 (diff)
merge from trunk
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/fake.py12
-rw-r--r--nova/virt/libvirt_conn.py23
-rw-r--r--nova/virt/xenapi/fake.py1
-rw-r--r--nova/virt/xenapi/vm_utils.py88
-rw-r--r--nova/virt/xenapi/vmops.py51
-rw-r--r--nova/virt/xenapi/volume_utils.py6
-rw-r--r--nova/virt/xenapi_conn.py8
7 files changed, 154 insertions, 35 deletions
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index a948963f4..dc8b8c791 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -160,6 +160,18 @@ class FakeConnection(object):
"""
pass
+ def suspend(self, instance, callback):
+ """
+ suspend the specified instance
+ """
+ pass
+
+ def resume(self, instance, callback):
+ """
+ resume the specified instance
+ """
+ pass
+
def destroy(self, instance):
"""
Destroy (shutdown and delete) the specified instance.
diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py
index 651b2af93..65cf65098 100644
--- a/nova/virt/libvirt_conn.py
+++ b/nova/virt/libvirt_conn.py
@@ -280,6 +280,14 @@ class LibvirtConnection(object):
raise exception.APIError("unpause not supported for libvirt.")
@exception.wrap_exception
+ def suspend(self, instance, callback):
+ raise exception.APIError("suspend not supported for libvirt")
+
+ @exception.wrap_exception
+ def resume(self, instance, callback):
+ raise exception.APIError("resume not supported for libvirt")
+
+ @exception.wrap_exception
def rescue(self, instance):
self.destroy(instance, False)
@@ -512,9 +520,10 @@ class LibvirtConnection(object):
if FLAGS.allow_project_net_traffic:
net, mask = _get_net_and_mask(network['cidr'])
- extra_params = ("<parameter name=\"PROJNET\" value=\"%s\" />\n"
- "<parameter name=\"PROJMASK\" value=\"%s\" />\n"
- ) % (net, mask)
+ extra_params = ("<parameter name=\"PROJNET\" "
+ "value=\"%s\" />\n"
+ "<parameter name=\"PROJMASK\" "
+ "value=\"%s\" />\n") % (net, mask)
else:
extra_params = "\n"
@@ -800,8 +809,8 @@ class NWFilterFirewall(object):
the base filter are all in place.
"""
- nwfilter_xml = ("<filter name='nova-instance-%s' chain='root'>\n"
- ) % instance['name']
+ nwfilter_xml = ("<filter name='nova-instance-%s' "
+ "chain='root'>\n") % instance['name']
if instance['image_id'] == FLAGS.vpn_image_id:
nwfilter_xml += " <filterref filter='nova-vpn' />\n"
@@ -814,8 +823,8 @@ class NWFilterFirewall(object):
for security_group in instance.security_groups:
self.ensure_security_group_filter(security_group['id'])
- nwfilter_xml += (" <filterref filter='nova-secgroup-%d' />\n"
- ) % security_group['id']
+ nwfilter_xml += (" <filterref filter='nova-secgroup-%d' "
+ "/>\n") % security_group['id']
nwfilter_xml += "</filter>"
self._define_filter(nwfilter_xml)
diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py
index 7a6c9ee71..1eaf31c25 100644
--- a/nova/virt/xenapi/fake.py
+++ b/nova/virt/xenapi/fake.py
@@ -235,6 +235,7 @@ class SessionBase(object):
elif '.' in name:
impl = getattr(self, name.replace('.', '_'))
if impl is not None:
+
def callit(*params):
logging.warn('Calling %s %s', name, impl)
self._check_session(params)
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 89e02c917..47fb6db53 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -39,19 +39,35 @@ XENAPI_POWER_STATE = {
'Halted': power_state.SHUTDOWN,
'Running': power_state.RUNNING,
'Paused': power_state.PAUSED,
- 'Suspended': power_state.SHUTDOWN, # FIXME
+ 'Suspended': power_state.SUSPENDED,
'Crashed': power_state.CRASHED}
+class ImageType:
+ """
+ Enumeration class for distinguishing different image types
+ 0 - kernel/ramdisk image (goes on dom0's filesystem)
+ 1 - disk image (local SR, partitioned by objectstore plugin)
+ 2 - raw disk image (local SR, NOT partitioned by plugin)
+ """
+
+ KERNEL_RAMDISK = 0
+ DISK = 1
+ DISK_RAW = 2
+
+
class VMHelper(HelperBase):
"""
The class that wraps the helper methods together.
"""
@classmethod
- def create_vm(cls, session, instance, kernel, ramdisk):
+ def create_vm(cls, session, instance, kernel, ramdisk, pv_kernel=False):
"""Create a VM record. Returns a Deferred that gives the new
- VM reference."""
+ VM reference.
+ the pv_kernel flag indicates whether the guest is HVM or PV
+ """
+
instance_type = instance_types.INSTANCE_TYPES[instance.instance_type]
mem = str(long(instance_type['memory_mb']) * 1024 * 1024)
vcpus = str(instance_type['vcpus'])
@@ -70,9 +86,9 @@ class VMHelper(HelperBase):
'actions_after_reboot': 'restart',
'actions_after_crash': 'destroy',
'PV_bootloader': '',
- 'PV_kernel': kernel,
- 'PV_ramdisk': ramdisk,
- 'PV_args': 'root=/dev/xvda1',
+ 'PV_kernel': '',
+ 'PV_ramdisk': '',
+ 'PV_args': '',
'PV_bootloader_args': '',
'PV_legacy_args': '',
'HVM_boot_policy': '',
@@ -84,7 +100,25 @@ class VMHelper(HelperBase):
'user_version': '0',
'other_config': {},
}
- logging.debug(_('Created VM %s...'), instance.name)
+ #Complete VM configuration record according to the image type
+ #non-raw/raw with PV kernel/raw in HVM mode
+ if instance.kernel_id:
+ rec['PV_bootloader'] = ''
+ rec['PV_kernel'] = kernel
+ rec['PV_ramdisk'] = ramdisk
+ rec['PV_args'] = 'root=/dev/xvda1'
+ rec['PV_bootloader_args'] = ''
+ rec['PV_legacy_args'] = ''
+ else:
+ if pv_kernel:
+ rec['PV_args'] = 'noninteractive'
+ rec['PV_bootloader'] = 'pygrub'
+ else:
+ rec['HVM_boot_policy'] = 'BIOS order'
+ rec['HVM_boot_params'] = {'order': 'dc'}
+ rec['platform'] = {'acpi': 'true', 'apic': 'true',
+ 'pae': 'true', 'viridian': 'true'}
+ logging.debug('Created VM %s...', instance.name)
vm_ref = session.call_xenapi('VM.create', rec)
logging.debug(_('Created VM %s as %s.'), instance.name, vm_ref)
return vm_ref
@@ -170,22 +204,24 @@ class VMHelper(HelperBase):
return vif_ref
@classmethod
- def fetch_image(cls, session, image, user, project, use_sr):
- """use_sr: True to put the image as a VDI in an SR, False to place
- it on dom0's filesystem. The former is for VM disks, the latter for
- its kernel and ramdisk (if external kernels are being used).
- Returns a Deferred that gives the new VDI UUID."""
-
+ def fetch_image(cls, session, image, user, project, type):
+ """
+ type is interpreted as an ImageType instance
+ """
url = images.image_url(image)
access = AuthManager().get_access_key(user, project)
- logging.debug(_("Asking xapi to fetch %s as %s"), url, access)
- fn = use_sr and 'get_vdi' or 'get_kernel'
+ logging.debug("Asking xapi to fetch %s as %s", url, access)
+ fn = (type != ImageType.KERNEL_RAMDISK) and 'get_vdi' or 'get_kernel'
args = {}
args['src_url'] = url
args['username'] = access
args['password'] = user.secret
- if use_sr:
+ args['add_partition'] = 'false'
+ args['raw'] = 'false'
+ if type != ImageType.KERNEL_RAMDISK:
args['add_partition'] = 'true'
+ if type == ImageType.DISK_RAW:
+ args['raw'] = 'true'
task = session.async_call_plugin('objectstore', fn, args)
#FIXME(armando): find a solution to missing instance_id
#with Josh Kearney
@@ -193,6 +229,22 @@ class VMHelper(HelperBase):
return uuid
@classmethod
+ def lookup_image(cls, session, vdi_ref):
+ logging.debug("Looking up vdi %s for PV kernel", vdi_ref)
+ fn = "is_vdi_pv"
+ args = {}
+ args['vdi-ref'] = vdi_ref
+ #TODO: Call proper function in plugin
+ task = session.async_call_plugin('objectstore', fn, args)
+ pv_str = session.wait_for_task(task)
+ if pv_str.lower() == 'true':
+ pv = True
+ elif pv_str.lower() == 'false':
+ pv = False
+ logging.debug("PV Kernel in VDI:%d", pv)
+ return pv
+
+ @classmethod
def lookup(cls, session, i):
"""Look the instance i up, and returns it if available"""
vms = session.get_xenapi().VM.get_by_name_label(i)
@@ -231,6 +283,10 @@ class VMHelper(HelperBase):
@classmethod
def compile_info(cls, record):
"""Fill record with VM status information"""
+ logging.info(_("(VM_UTILS) xenserver vm state -> |%s|"),
+ record['power_state'])
+ logging.info(_("(VM_UTILS) xenapi power_state -> |%s|"),
+ XENAPI_POWER_STATE[record['power_state']])
return {'state': XENAPI_POWER_STATE[record['power_state']],
'max_mem': long(record['memory_static_max']) >> 10,
'mem': long(record['memory_dynamic_max']) >> 10,
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 0e22ce306..3f8f0da69 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -32,6 +32,7 @@ from nova.auth.manager import AuthManager
from nova.compute import power_state
from nova.virt.xenapi.network_utils import NetworkHelper
from nova.virt.xenapi.vm_utils import VMHelper
+from nova.virt.xenapi.vm_utils import ImageType
class VMOps(object):
@@ -65,16 +66,30 @@ class VMOps(object):
user = AuthManager().get_user(instance.user_id)
project = AuthManager().get_project(instance.project_id)
- vdi_uuid = VMHelper.fetch_image(
- self._session, instance.image_id, user, project, True)
- kernel = VMHelper.fetch_image(
- self._session, instance.kernel_id, user, project, False)
- ramdisk = VMHelper.fetch_image(
- self._session, instance.ramdisk_id, user, project, False)
+ #if kernel is not present we must download a raw disk
+ if instance.kernel_id:
+ disk_image_type = ImageType.DISK
+ else:
+ disk_image_type = ImageType.DISK_RAW
+ vdi_uuid = VMHelper.fetch_image(self._session,
+ instance.image_id, user, project, disk_image_type)
vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdi_uuid)
- vm_ref = VMHelper.create_vm(
- self._session, instance, kernel, ramdisk)
+ #Have a look at the VDI and see if it has a PV kernel
+ pv_kernel = False
+ if not instance.kernel_id:
+ pv_kernel = VMHelper.lookup_image(self._session, vdi_ref)
+ kernel = None
+ if instance.kernel_id:
+ kernel = VMHelper.fetch_image(self._session,
+ instance.kernel_id, user, project, ImageType.KERNEL_RAMDISK)
+ ramdisk = None
+ if instance.ramdisk_id:
+ ramdisk = VMHelper.fetch_image(self._session,
+ instance.ramdisk_id, user, project, ImageType.KERNEL_RAMDISK)
+ vm_ref = VMHelper.create_vm(self._session,
+ instance, kernel, ramdisk, pv_kernel)
VMHelper.create_vbd(self._session, vm_ref, vdi_ref, 0, True)
+
if network_ref:
VMHelper.create_vif(self._session, vm_ref,
network_ref, instance.mac_address)
@@ -181,6 +196,26 @@ class VMOps(object):
task = self._session.call_xenapi('Async.VM.unpause', vm)
self._wait_with_callback(instance.id, task, callback)
+ def suspend(self, instance, callback):
+ """suspend the specified instance"""
+ instance_name = instance.name
+ vm = VMHelper.lookup(self._session, instance_name)
+ if vm is None:
+ raise Exception(_("suspend: instance not present %s") %
+ instance_name)
+ task = self._session.call_xenapi('Async.VM.suspend', vm)
+ self._wait_with_callback(task, callback)
+
+ def resume(self, instance, callback):
+ """resume the specified instance"""
+ instance_name = instance.name
+ vm = VMHelper.lookup(self._session, instance_name)
+ if vm is None:
+ raise Exception(_("resume: instance not present %s") %
+ instance_name)
+ task = self._session.call_xenapi('Async.VM.resume', vm, False, True)
+ self._wait_with_callback(task, callback)
+
def get_info(self, instance_id):
"""Return data about VM instance"""
vm = VMHelper.lookup_blocking(self._session, instance_id)
diff --git a/nova/virt/xenapi/volume_utils.py b/nova/virt/xenapi/volume_utils.py
index a0c0a67d4..1ca813bcf 100644
--- a/nova/virt/xenapi/volume_utils.py
+++ b/nova/virt/xenapi/volume_utils.py
@@ -60,13 +60,11 @@ class VolumeHelper(HelperBase):
'port': info['targetPort'],
'targetIQN': info['targetIQN'],
'chapuser': info['chapuser'],
- 'chappassword': info['chappassword']
- }
+ 'chappassword': info['chappassword']}
else:
record = {'target': info['targetHost'],
'port': info['targetPort'],
- 'targetIQN': info['targetIQN']
- }
+ 'targetIQN': info['targetIQN']}
try:
sr_ref = session.get_xenapi().SR.create(
session.get_xenapi_host(),
diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py
index 57c9ea948..7fb7ff15d 100644
--- a/nova/virt/xenapi_conn.py
+++ b/nova/virt/xenapi_conn.py
@@ -151,6 +151,14 @@ class XenAPIConnection(object):
"""Unpause paused VM instance"""
self._vmops.unpause(instance, callback)
+ def suspend(self, instance, callback):
+ """suspend the specified instance"""
+ self._vmops.suspend(instance, callback)
+
+ def resume(self, instance, callback):
+ """resume the specified instance"""
+ self._vmops.resume(instance, callback)
+
def get_info(self, instance_id):
"""Return data about VM instance"""
return self._vmops.get_info(instance_id)