summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authorEwan Mellor <ewan.mellor@citrix.com>2010-08-03 00:52:06 +0100
committerEwan Mellor <ewan.mellor@citrix.com>2010-08-03 00:52:06 +0100
commit4c8ae5e0a5b30039075a87ba39aec6da64fdd138 (patch)
tree1ddbc9fc2a03550e7de113678cf86cd25f07081b /nova/virt
parent40b2bbcfe6274aca9fd4361c56b2b042ba22e3c2 (diff)
Added a xapi plugin that can pull images from nova-objectstore, and use that
to get a disk, kernel, and ramdisk for the VM. The VM actually boots!
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/xenapi.py105
1 files changed, 98 insertions, 7 deletions
diff --git a/nova/virt/xenapi.py b/nova/virt/xenapi.py
index dc372e3e3..b84e55138 100644
--- a/nova/virt/xenapi.py
+++ b/nova/virt/xenapi.py
@@ -19,6 +19,7 @@ A connection to XenServer or Xen Cloud Platform.
"""
import logging
+import xmlrpclib
from twisted.internet import defer
from twisted.internet import task
@@ -26,7 +27,9 @@ from twisted.internet import task
from nova import exception
from nova import flags
from nova import process
+from nova.auth.manager import AuthManager
from nova.compute import power_state
+from nova.virt import images
XenAPI = None
@@ -71,10 +74,26 @@ class XenAPIConnection(object):
@defer.inlineCallbacks
@exception.wrap_exception
def spawn(self, instance):
- vm = self.lookup(instance.name)
+ vm = yield self.lookup(instance.name)
if vm is not None:
raise Exception('Attempted to create non-unique name %s' %
instance.name)
+
+ user = AuthManager().get_user(instance.datamodel['user_id'])
+ vdi_uuid = yield self.fetch_image(
+ instance.datamodel['image_id'], user, True)
+ kernel = yield self.fetch_image(
+ instance.datamodel['kernel_id'], user, False)
+ ramdisk = yield self.fetch_image(
+ instance.datamodel['ramdisk_id'], user, False)
+ vdi_ref = yield self._conn.xenapi.VDI.get_by_uuid(vdi_uuid)
+
+ vm_ref = yield self.create_vm(instance, kernel, ramdisk)
+ yield self.create_vbd(vm_ref, vdi_ref, 0, True)
+ yield self._conn.xenapi.VM.start(vm_ref, False, False)
+
+
+ def create_vm(self, instance, kernel, ramdisk):
mem = str(long(instance.datamodel['memory_kb']) * 1024)
vcpus = str(instance.datamodel['vcpus'])
rec = {
@@ -92,9 +111,9 @@ class XenAPIConnection(object):
'actions_after_reboot': 'restart',
'actions_after_crash': 'destroy',
'PV_bootloader': '',
- 'PV_kernel': instance.datamodel['kernel_id'],
- 'PV_ramdisk': instance.datamodel['ramdisk_id'],
- 'PV_args': '',
+ 'PV_kernel': kernel,
+ 'PV_ramdisk': ramdisk,
+ 'PV_args': 'root=/dev/xvda1',
'PV_bootloader_args': '',
'PV_legacy_args': '',
'HVM_boot_policy': '',
@@ -106,8 +125,48 @@ class XenAPIConnection(object):
'user_version': '0',
'other_config': {},
}
- vm = yield self._conn.xenapi.VM.create(rec)
- #yield self._conn.xenapi.VM.start(vm, False, False)
+ logging.debug('Created VM %s...', instance.name)
+ vm_ref = self._conn.xenapi.VM.create(rec)
+ logging.debug('Created VM %s as %s.', instance.name, vm_ref)
+ return vm_ref
+
+
+ def create_vbd(self, vm_ref, vdi_ref, userdevice, bootable):
+ vbd_rec = {}
+ vbd_rec['VM'] = vm_ref
+ vbd_rec['VDI'] = vdi_ref
+ vbd_rec['userdevice'] = str(userdevice)
+ vbd_rec['bootable'] = bootable
+ vbd_rec['mode'] = 'RW'
+ vbd_rec['type'] = 'disk'
+ vbd_rec['unpluggable'] = True
+ vbd_rec['empty'] = False
+ vbd_rec['other_config'] = {}
+ vbd_rec['qos_algorithm_type'] = ''
+ vbd_rec['qos_algorithm_params'] = {}
+ vbd_rec['qos_supported_algorithms'] = []
+ logging.debug('Creating VBD for VM %s, VDI %s ... ', vm_ref, vdi_ref)
+ vbd_ref = self._conn.xenapi.VBD.create(vbd_rec)
+ logging.debug('Created VBD %s for VM %s, VDI %s.', vbd_ref, vm_ref,
+ vdi_ref)
+ return vbd_ref
+
+
+ def fetch_image(self, image, user, 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)."""
+
+ url = images.image_url(image)
+ logging.debug("Asking xapi to fetch %s as %s" % (url, user.access))
+ fn = use_sr and 'get_vdi' or 'get_kernel'
+ args = {}
+ args['src_url'] = url
+ args['username'] = user.access
+ args['password'] = user.secret
+ if use_sr:
+ args['add_partition'] = 'true'
+ return self._call_plugin('objectstore', fn, args)
def reboot(self, instance):
@@ -143,10 +202,42 @@ class XenAPIConnection(object):
else:
return vms[0]
+
+ def _call_plugin(self, plugin, fn, args):
+ return _unwrap_plugin_exceptions(
+ self._conn.xenapi.host.call_plugin,
+ self._get_xenapi_host(), plugin, fn, args)
+
+
+ def _get_xenapi_host(self):
+ return self._conn.xenapi.session.get_this_host(self._conn.handle)
+
+
power_state_from_xenapi = {
- 'Halted' : power_state.RUNNING, #FIXME
+ 'Halted' : power_state.SHUTDOWN,
'Running' : power_state.RUNNING,
'Paused' : power_state.PAUSED,
'Suspended': power_state.SHUTDOWN, # FIXME
'Crashed' : power_state.CRASHED
}
+
+
+def _unwrap_plugin_exceptions(func, *args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except XenAPI.Failure, exn:
+ logging.debug("Got exception: %s", exn)
+ if (len(exn.details) == 4 and
+ exn.details[0] == 'XENAPI_PLUGIN_EXCEPTION' and
+ exn.details[2] == 'Failure'):
+ params = None
+ try:
+ params = eval(exn.details[3])
+ except:
+ raise exn
+ raise XenAPI.Failure(params)
+ else:
+ raise
+ except xmlrpclib.ProtocolError, exn:
+ logging.debug("Got exception: %s", exn)
+ raise