Changes for supporting fast cloning on Xenserver.
Implements blueprint fast-cloning-for-xenserver 1. use_cow_images flag is reused for xenserver to check if copy on write images should be used. 2. image-id is used to tag an image which has already been streamed from glance. 3. If cow is true, when an instance of an image is created for the first time on a given xenserver, the image is streamed from glance and copy on write disk is created for the instance. 4. For subsequent instance creation requests (of the same image), a copy on write disk is created from the base image that is already present on the host. 5. If cow is false, when an instance of an image is created for the first time on a host, the image is streamed from glance and its copy is made to create a virtual disk for the instance. 6. For subsequent instance creation requests, a copy of disk is made for creating the disk for the instance. 7. Snapshot creation code was updated to handle cow=true. Now there can be upto 3 disks in the chain. The base disk needs to be uploaded too. 8. Also added a cache_images flag. Depending on whether the flag is turned on on not, images will be cached on the host. Change-Id: I54838a24b061c134877f3479c925c6ee78da14bc
This commit is contained in:
parent
d8f8bad0f2
commit
6c3bc216c1
1
Authors
1
Authors
@ -43,6 +43,7 @@ David Subiros <david.perez5@hp.com>
|
||||
Dean Troyer <dtroyer@gmail.com>
|
||||
Deepak Garg <deepak.garg@citrix.com>
|
||||
Derek Higgins <higginsd@gmail.com>
|
||||
Devdeep Singh <devdeep.singh@citrix.com>
|
||||
Devendra Modium <dmodium@isi.edu>
|
||||
Devin Carlen <devin.carlen@gmail.com>
|
||||
Donal Lafferty <donal.lafferty@citrix.com>
|
||||
|
@ -445,6 +445,12 @@ global_opts = [
|
||||
cfg.ListOpt('isolated_hosts',
|
||||
default=[],
|
||||
help='Host reserved for specific images'),
|
||||
cfg.BoolOpt('cache_images',
|
||||
default=True,
|
||||
help='Cache glance images locally'),
|
||||
cfg.BoolOpt('use_cow_images',
|
||||
default=True,
|
||||
help='Whether to use cow images')
|
||||
]
|
||||
|
||||
FLAGS.register_opts(global_opts)
|
||||
|
@ -399,7 +399,14 @@ class XenAPIVMTestCase(test.TestCase):
|
||||
def _check_vdis(self, start_list, end_list):
|
||||
for vdi_ref in end_list:
|
||||
if not vdi_ref in start_list:
|
||||
self.fail('Found unexpected VDI:%s' % vdi_ref)
|
||||
vdi_rec = xenapi_fake.get_record('VDI', vdi_ref)
|
||||
# If the cache is turned on then the base disk will be
|
||||
# there even after the cleanup
|
||||
if 'other_config' in vdi_rec:
|
||||
if vdi_rec['other_config']['image-id'] is None:
|
||||
self.fail('Found unexpected VDI:%s' % vdi_ref)
|
||||
else:
|
||||
self.fail('Found unexpected VDI:%s' % vdi_ref)
|
||||
|
||||
def _test_spawn(self, image_ref, kernel_id, ramdisk_id,
|
||||
instance_type_id="3", os_type="linux",
|
||||
|
@ -46,7 +46,7 @@ def stubout_instance_snapshot(stubs):
|
||||
|
||||
def fake_wait_for_vhd_coalesce(*args):
|
||||
#TODO(sirp): Should we actually fake out the data here
|
||||
return "fakeparent"
|
||||
return "fakeparent", "fakebase"
|
||||
|
||||
stubs.Set(vm_utils, '_wait_for_vhd_coalesce', fake_wait_for_vhd_coalesce)
|
||||
|
||||
|
@ -99,9 +99,6 @@ libvirt_opts = [
|
||||
default='',
|
||||
help='Override the default libvirt URI '
|
||||
'(which is dependent on libvirt_type)'),
|
||||
cfg.BoolOpt('use_cow_images',
|
||||
default=True,
|
||||
help='Whether to use cow images'),
|
||||
cfg.StrOpt('cpuinfo_xml_template',
|
||||
default=utils.abspath('virt/cpuinfo.xml.template'),
|
||||
help='CpuInfo XML Template (Used only live migration now)'),
|
||||
|
@ -446,6 +446,35 @@ class SessionBase(object):
|
||||
db_ref['xenstore_data'] = {}
|
||||
db_ref['xenstore_data'][key] = value
|
||||
|
||||
def VDI_remove_from_other_config(self, _1, vdi_ref, key):
|
||||
db_ref = _db_content['VDI'][vdi_ref]
|
||||
if not 'other_config' in db_ref:
|
||||
return
|
||||
db_ref['other_config'][key] = None
|
||||
|
||||
def VDI_add_to_other_config(self, _1, vdi_ref, key, value):
|
||||
db_ref = _db_content['VDI'][vdi_ref]
|
||||
if not 'other_config' in db_ref:
|
||||
db_ref['other_config'] = {}
|
||||
db_ref['other_config'][key] = value
|
||||
|
||||
def VDI_copy(self, _1, vdi_to_copy_ref, sr_ref):
|
||||
db_ref = _db_content['VDI'][vdi_to_copy_ref]
|
||||
name_label = db_ref['name_label']
|
||||
read_only = db_ref['read_only']
|
||||
sharable = db_ref['sharable']
|
||||
vdi_ref = create_vdi(name_label, read_only, sr_ref, sharable)
|
||||
return vdi_ref
|
||||
|
||||
def VDI_clone(self, _1, vdi_to_clone_ref):
|
||||
db_ref = _db_content['VDI'][vdi_to_clone_ref]
|
||||
name_label = db_ref['name_label']
|
||||
read_only = db_ref['read_only']
|
||||
sr_ref = db_ref['SR']
|
||||
sharable = db_ref['sharable']
|
||||
vdi_ref = create_vdi(name_label, read_only, sr_ref, sharable)
|
||||
return vdi_ref
|
||||
|
||||
def host_compute_free_memory(self, _1, ref):
|
||||
#Always return 12GB available
|
||||
return 12 * 1024 * 1024 * 1024
|
||||
@ -457,6 +486,8 @@ class SessionBase(object):
|
||||
return ''
|
||||
elif (plugin, method) == ('glance', 'upload_vhd'):
|
||||
return ''
|
||||
elif (plugin, method) == ('glance', 'create_kernel_ramdisk'):
|
||||
return ''
|
||||
elif (plugin, method) == ('migration', 'move_vhds_into_sr'):
|
||||
return ''
|
||||
elif (plugin, method) == ('migration', 'transfer_vhd'):
|
||||
|
@ -314,6 +314,22 @@ class VMHelper(HelperBase):
|
||||
% locals())
|
||||
return vdi_ref
|
||||
|
||||
@classmethod
|
||||
def copy_vdi(cls, session, sr_ref, vdi_to_copy_ref):
|
||||
"""Copy a VDI and return the new VDIs reference."""
|
||||
vdi_ref = session.call_xenapi('VDI.copy', vdi_to_copy_ref, sr_ref)
|
||||
LOG.debug(_('Copied VDI %(vdi_ref)s from VDI '
|
||||
'%(vdi_to_copy_ref)s on %(sr_ref)s.') % locals())
|
||||
return vdi_ref
|
||||
|
||||
@classmethod
|
||||
def clone_vdi(cls, session, vdi_to_clone_ref):
|
||||
"""Clones a VDI and return the new VDIs reference."""
|
||||
vdi_ref = session.call_xenapi('VDI.clone', vdi_to_clone_ref)
|
||||
LOG.debug(_('Cloned VDI %(vdi_ref)s from VDI '
|
||||
'%(vdi_to_clone_ref)s') % locals())
|
||||
return vdi_ref
|
||||
|
||||
@classmethod
|
||||
def set_vdi_name_label(cls, session, vdi_uuid, name_label):
|
||||
vdi_ref = session.call_xenapi("VDI.get_by_uuid", vdi_uuid)
|
||||
@ -353,11 +369,11 @@ class VMHelper(HelperBase):
|
||||
LOG.debug(_('Created snapshot %(template_vm_ref)s from'
|
||||
' VM %(vm_ref)s.') % locals())
|
||||
|
||||
parent_uuid = _wait_for_vhd_coalesce(
|
||||
parent_uuid, base_uuid = _wait_for_vhd_coalesce(
|
||||
session, instance, sr_ref, vm_vdi_ref, original_parent_uuid)
|
||||
|
||||
#TODO(sirp): we need to assert only one parent, not parents two deep
|
||||
template_vdi_uuids = {'image': parent_uuid,
|
||||
template_vdi_uuids = {'base': base_uuid,
|
||||
'image': parent_uuid,
|
||||
'snap': template_vdi_uuid}
|
||||
return template_vm_ref, template_vdi_uuids
|
||||
|
||||
@ -373,6 +389,15 @@ class VMHelper(HelperBase):
|
||||
sr_uuid = sr_rec["uuid"]
|
||||
return os.path.join(FLAGS.xenapi_sr_base_path, sr_uuid)
|
||||
|
||||
@classmethod
|
||||
def find_cached_image(cls, session, image_id, sr_ref):
|
||||
"""Returns the vdi-ref of the cached image."""
|
||||
for vdi_ref, vdi_rec in _get_all_vdis_in_sr(session, sr_ref):
|
||||
if ('image-id' in vdi_rec['other_config'] and
|
||||
vdi_rec['other_config']['image-id'] == image_id):
|
||||
return vdi_ref
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def upload_image(cls, context, session, instance, vdi_uuids, image_id):
|
||||
""" Requests that the Glance plugin bundle the specified VDIs and
|
||||
@ -544,6 +569,108 @@ class VMHelper(HelperBase):
|
||||
vdi_ref = cls.create_vdi(session, sr_ref, 'blank HD', vdi_size, False)
|
||||
return vdi_ref
|
||||
|
||||
@classmethod
|
||||
def create_kernel_image(cls, context, session, instance, image, user_id,
|
||||
project_id, image_type):
|
||||
"""Creates kernel/ramdisk file from the image stored in the cache.
|
||||
If the image is not present in the cache, it streams it from glance.
|
||||
|
||||
Returns: A list of dictionaries that describe VDIs
|
||||
"""
|
||||
filename = ""
|
||||
if FLAGS.cache_images:
|
||||
args = {}
|
||||
args['cached-image'] = image
|
||||
args['new-image-uuid'] = str(uuid.uuid4())
|
||||
task = session.async_call_plugin('glance', "create_kernel_ramdisk",
|
||||
args)
|
||||
filename = session.wait_for_task(task, instance.id)
|
||||
|
||||
if filename == "":
|
||||
return cls.fetch_image(context, session, instance, image,
|
||||
user_id, project_id, image_type)
|
||||
else:
|
||||
return [dict(vdi_type=ImageType.to_string(image_type),
|
||||
vdi_uuid=None,
|
||||
file=filename)]
|
||||
|
||||
@classmethod
|
||||
def create_image(cls, context, session, instance, image, user_id,
|
||||
project_id, image_type):
|
||||
"""Creates VDI from the image stored in the local cache. If the image
|
||||
is not present in the cache, it streams it from glance.
|
||||
|
||||
Returns: A list of dictionaries that describe VDIs
|
||||
"""
|
||||
if FLAGS.cache_images == False or image_type == ImageType.DISK_ISO:
|
||||
# If caching is disabled, we do not have to keep a copy of the
|
||||
# image. Fetch the image from glance.
|
||||
return cls.fetch_image(context, session,
|
||||
instance, instance.image_ref,
|
||||
instance.user_id, instance.project_id,
|
||||
image_type)
|
||||
|
||||
sr_ref = cls.safe_find_sr(session)
|
||||
sr_type = session.call_xenapi('SR.get_record', sr_ref)["type"]
|
||||
vdi_return_list = []
|
||||
|
||||
if FLAGS.use_cow_images and sr_type != "ext":
|
||||
LOG.warning(_("Fast cloning is only supported on default local SR "
|
||||
"of type ext. SR on this system was found to be of "
|
||||
"type %(sr_type)s. Ignoring the cow flag.")
|
||||
% locals())
|
||||
|
||||
vdi_ref = cls.find_cached_image(session, image, sr_ref)
|
||||
if vdi_ref is None:
|
||||
vdis = cls.fetch_image(context, session, instance, image, user_id,
|
||||
project_id, image_type)
|
||||
vdi_ref = session.call_xenapi('VDI.get_by_uuid',
|
||||
vdis[0]['vdi_uuid'])
|
||||
session.call_xenapi('VDI.add_to_other_config',
|
||||
vdi_ref, "image-id", str(image))
|
||||
session.call_xenapi('VDI.set_name_label',
|
||||
vdi_ref, "Cached glance image")
|
||||
|
||||
for vdi in vdis:
|
||||
if vdi["vdi_type"] == "swap":
|
||||
session.call_xenapi('VDI.add_to_other_config',
|
||||
vdi_ref, "swap-disk",
|
||||
str(vdi['vdi_uuid']))
|
||||
|
||||
if FLAGS.use_cow_images and sr_type == 'ext':
|
||||
new_vdi_ref = cls.clone_vdi(session, vdi_ref)
|
||||
else:
|
||||
new_vdi_ref = cls.copy_vdi(session, sr_ref, vdi_ref)
|
||||
|
||||
# Set the name label for the image we just created and remove image id
|
||||
# field from other-config.
|
||||
session.call_xenapi('VDI.set_name_label', new_vdi_ref, instance.name)
|
||||
session.call_xenapi('VDI.remove_from_other_config',
|
||||
new_vdi_ref, "image-id")
|
||||
|
||||
vdi_return_list.append(dict(
|
||||
vdi_type=("os" if image_type == ImageType.DISK_VHD
|
||||
else ImageType.to_string(image_type)),
|
||||
vdi_uuid=session.call_xenapi('VDI.get_uuid', new_vdi_ref),
|
||||
file=None))
|
||||
|
||||
# Create a swap disk if the glance image had one associated with it.
|
||||
vdi_rec = session.call_xenapi('VDI.get_record', vdi_ref)
|
||||
if 'swap-disk' in vdi_rec['other_config']:
|
||||
swap_disk_uuid = vdi_rec['other_config']['swap-disk']
|
||||
swap_vdi_ref = session.call_xenapi('VDI.get_by_uuid',
|
||||
swap_disk_uuid)
|
||||
new_swap_vdi_ref = cls.copy_vdi(session, sr_ref, swap_vdi_ref)
|
||||
new_swap_vdi_uuid = session.call_xenapi('VDI.get_uuid',
|
||||
new_swap_vdi_ref)
|
||||
session.call_xenapi('VDI.set_name_label', new_swap_vdi_ref,
|
||||
instance.name + "-swap")
|
||||
vdi_return_list.append(dict(vdi_type="swap",
|
||||
vdi_uuid=new_swap_vdi_uuid,
|
||||
file=None))
|
||||
|
||||
return vdi_return_list
|
||||
|
||||
@classmethod
|
||||
def fetch_image(cls, context, session, instance, image, user_id,
|
||||
project_id, image_type):
|
||||
@ -575,7 +702,7 @@ class VMHelper(HelperBase):
|
||||
# which does not have the `uuid` module. To work around this,
|
||||
# we generate the uuids here (under Python 2.6+) and
|
||||
# pass them as arguments
|
||||
uuid_stack = [str(uuid.uuid4()) for i in xrange(2)]
|
||||
uuid_stack = [str(uuid.uuid4()) for i in xrange(3)]
|
||||
|
||||
glance_host, glance_port = glance.pick_glance_api_server()
|
||||
params = {'image_id': image,
|
||||
@ -712,6 +839,8 @@ class VMHelper(HelperBase):
|
||||
args['vdi-ref'] = vdi_ref
|
||||
# Let the plugin copy the correct number of bytes.
|
||||
args['image-size'] = str(vdi_size)
|
||||
if FLAGS.cache_images:
|
||||
args['cached-image'] = image
|
||||
task = session.async_call_plugin('glance', fn, args)
|
||||
filename = session.wait_for_task(task, instance['uuid'])
|
||||
# Remove the VDI as it is not needed anymore.
|
||||
@ -1156,6 +1285,15 @@ def integrate_series(data, col, start, until=None):
|
||||
return total.quantize(Decimal('1.0000'))
|
||||
|
||||
|
||||
def _get_all_vdis_in_sr(session, sr_ref):
|
||||
for vdi_ref in session.call_xenapi('SR.get_VDIs', sr_ref):
|
||||
try:
|
||||
vdi_rec = session.call_xenapi('VDI.get_record', vdi_ref)
|
||||
yield vdi_ref, vdi_rec
|
||||
except VMHelper.XenAPI.Failure:
|
||||
continue
|
||||
|
||||
|
||||
#TODO(sirp): This code comes from XS5.6 pluginlib.py, we should refactor to
|
||||
# use that implmenetation
|
||||
def get_vhd_parent(session, vdi_rec):
|
||||
@ -1208,10 +1346,35 @@ def _wait_for_vhd_coalesce(session, instance, sr_ref, vdi_ref,
|
||||
* parent_vhd
|
||||
snapshot
|
||||
|
||||
Atter coalesce:
|
||||
After coalesce:
|
||||
* parent_vhd
|
||||
snapshot
|
||||
"""
|
||||
def _another_child_vhd():
|
||||
if not original_parent_uuid:
|
||||
return False
|
||||
|
||||
# Search for any other vdi which parents to original parent and is not
|
||||
# in the active vm/instance vdi chain.
|
||||
vdi_uuid = session.call_xenapi('VDI.get_record', vdi_ref)['uuid']
|
||||
parent_vdi_uuid = get_vhd_parent_uuid(session, vdi_ref)
|
||||
for ref, rec in _get_all_vdis_in_sr(session, sr_ref):
|
||||
if ((rec['uuid'] != vdi_uuid) and
|
||||
(rec['uuid'] != parent_vdi_uuid) and
|
||||
(rec['sm_config'].get('vhd-parent') == original_parent_uuid)):
|
||||
# Found another vhd which too parents to original parent.
|
||||
return True
|
||||
# Found no other vdi with the same parent.
|
||||
return False
|
||||
|
||||
# Check if original parent has any other child. If so, coalesce will
|
||||
# not take place.
|
||||
if _another_child_vhd():
|
||||
parent_uuid = get_vhd_parent_uuid(session, vdi_ref)
|
||||
parent_ref = session.call_xenapi("VDI.get_by_uuid", parent_uuid)
|
||||
base_uuid = get_vhd_parent_uuid(session, parent_ref)
|
||||
return parent_uuid, base_uuid
|
||||
|
||||
max_attempts = FLAGS.xenapi_vhd_coalesce_max_attempts
|
||||
for i in xrange(max_attempts):
|
||||
VMHelper.scan_sr(session, instance, sr_ref)
|
||||
@ -1221,7 +1384,9 @@ def _wait_for_vhd_coalesce(session, instance, sr_ref, vdi_ref,
|
||||
" %(original_parent_uuid)s, waiting for coalesce...")
|
||||
% locals())
|
||||
else:
|
||||
return parent_uuid
|
||||
parent_ref = session.call_xenapi("VDI.get_by_uuid", parent_uuid)
|
||||
base_uuid = get_vhd_parent_uuid(session, parent_ref)
|
||||
return parent_uuid, base_uuid
|
||||
|
||||
greenthread.sleep(FLAGS.xenapi_vhd_coalesce_poll_interval)
|
||||
|
||||
|
@ -186,7 +186,7 @@ class VMOps(object):
|
||||
|
||||
def _create_disks(self, context, instance, image_meta):
|
||||
disk_image_type = VMHelper.determine_disk_image_type(image_meta)
|
||||
vdis = VMHelper.fetch_image(context, self._session,
|
||||
vdis = VMHelper.create_image(context, self._session,
|
||||
instance, instance.image_ref,
|
||||
instance.user_id, instance.project_id,
|
||||
disk_image_type)
|
||||
@ -279,11 +279,11 @@ class VMOps(object):
|
||||
ramdisk = None
|
||||
try:
|
||||
if instance.kernel_id:
|
||||
kernel = VMHelper.fetch_image(context, self._session,
|
||||
kernel = VMHelper.create_kernel_image(context, self._session,
|
||||
instance, instance.kernel_id, instance.user_id,
|
||||
instance.project_id, vm_utils.ImageType.KERNEL)[0]
|
||||
if instance.ramdisk_id:
|
||||
ramdisk = VMHelper.fetch_image(context, self._session,
|
||||
ramdisk = VMHelper.create_kernel_image(context, self._session,
|
||||
instance, instance.ramdisk_id, instance.user_id,
|
||||
instance.project_id, vm_utils.ImageType.RAMDISK)[0]
|
||||
|
||||
|
@ -54,6 +54,7 @@ class RetryException(Exception):
|
||||
def _copy_kernel_vdi(dest, copy_args):
|
||||
vdi_uuid = copy_args['vdi_uuid']
|
||||
vdi_size = copy_args['vdi_size']
|
||||
cached_image = copy_args['cached-image']
|
||||
logging.debug("copying kernel/ramdisk file from %s to /boot/guest/%s",
|
||||
dest, vdi_uuid)
|
||||
filename = KERNEL_DIR + '/' + vdi_uuid
|
||||
@ -67,6 +68,17 @@ def _copy_kernel_vdi(dest, copy_args):
|
||||
#copy only vdi_size bytes
|
||||
data = f.read(vdi_size)
|
||||
of.write(data)
|
||||
if cached_image:
|
||||
#create a cache file. If caching is enabled, kernel images do not have
|
||||
#to be fetched from glance.
|
||||
cached_image = KERNEL_DIR + '/' + cached_image
|
||||
logging.debug("copying kernel/ramdisk file from %s to /boot/guest/%s",
|
||||
dest, cached_image)
|
||||
cache_file = open(cached_image, 'wb')
|
||||
cache_file.write(data)
|
||||
cache_file.close()
|
||||
logging.debug("Done. Filename: %s", cached_image)
|
||||
|
||||
f.close()
|
||||
of.close()
|
||||
logging.debug("Done. Filename: %s", filename)
|
||||
@ -264,11 +276,17 @@ def _import_vhds(sr_path, staging_path, uuid_stack):
|
||||
vdi_return_list = []
|
||||
paths_to_move = []
|
||||
|
||||
image_info = prepare_if_exists(staging_path, 'image.vhd')
|
||||
image_parent = None
|
||||
base_info = prepare_if_exists(staging_path, 'base.vhd')
|
||||
if base_info:
|
||||
paths_to_move.append(base_info[0])
|
||||
image_parent = base_info[0]
|
||||
|
||||
image_info = prepare_if_exists(staging_path, 'image.vhd', image_parent)
|
||||
if not image_info:
|
||||
raise Exception("Invalid image: image.vhd not present")
|
||||
|
||||
paths_to_move.append(image_info[0])
|
||||
paths_to_move.insert(0, image_info[0])
|
||||
|
||||
snap_info = prepare_if_exists(staging_path, 'snap.vhd',
|
||||
image_info[0])
|
||||
@ -302,9 +320,10 @@ def _prepare_staging_area_for_upload(sr_path, staging_path, vdi_uuids):
|
||||
('snap' or 'image.vhd')
|
||||
"""
|
||||
for name, uuid in vdi_uuids.items():
|
||||
source = os.path.join(sr_path, "%s.vhd" % uuid)
|
||||
link_name = os.path.join(staging_path, "%s.vhd" % name)
|
||||
os.link(source, link_name)
|
||||
if uuid:
|
||||
source = os.path.join(sr_path, "%s.vhd" % uuid)
|
||||
link_name = os.path.join(staging_path, "%s.vhd" % name)
|
||||
os.link(source, link_name)
|
||||
|
||||
|
||||
def _upload_tarball(staging_path, image_id, glance_host, glance_port,
|
||||
@ -439,6 +458,24 @@ def _finish_subprocess(proc, cmdline):
|
||||
return out, err
|
||||
|
||||
|
||||
def create_kernel_ramdisk(session, args):
|
||||
"""Creates a copy of the kernel/ramdisk image if it is present in the
|
||||
cache. If the image is not present in the cache, it does nothing.
|
||||
"""
|
||||
cached_image = exists(args, 'cached-image')
|
||||
image_uuid = exists(args, 'new-image-uuid')
|
||||
cached_image_filename = KERNEL_DIR + '/' + cached_image
|
||||
filename = KERNEL_DIR + '/' + image_uuid
|
||||
|
||||
if os.path.isfile(cached_image_filename):
|
||||
shutil.copyfile(cached_image_filename, filename)
|
||||
logging.debug("Done. Filename: %s", filename)
|
||||
else:
|
||||
filename = ""
|
||||
logging.debug("Cached kernel/ramdisk image not found")
|
||||
return filename
|
||||
|
||||
|
||||
def download_vhd(session, args):
|
||||
"""Download an image from Glance, unbundle it, and then deposit the VHDs
|
||||
into the storage repository
|
||||
@ -491,9 +528,12 @@ def upload_vhd(session, args):
|
||||
def copy_kernel_vdi(session, args):
|
||||
vdi = exists(args, 'vdi-ref')
|
||||
size = exists(args, 'image-size')
|
||||
cached_image = optional(args, 'cached-image')
|
||||
#Use the uuid as a filename
|
||||
vdi_uuid = session.xenapi.VDI.get_uuid(vdi)
|
||||
copy_args = {'vdi_uuid': vdi_uuid, 'vdi_size': int(size)}
|
||||
copy_args = {'vdi_uuid': vdi_uuid,
|
||||
'vdi_size': int(size),
|
||||
'cached-image': cached_image}
|
||||
filename = with_vdi_in_dom0(session, vdi, False,
|
||||
lambda dev:
|
||||
_copy_kernel_vdi('/dev/%s' % dev, copy_args))
|
||||
@ -515,4 +555,5 @@ if __name__ == '__main__':
|
||||
XenAPIPlugin.dispatch({'upload_vhd': upload_vhd,
|
||||
'download_vhd': download_vhd,
|
||||
'copy_kernel_vdi': copy_kernel_vdi,
|
||||
'create_kernel_ramdisk': create_kernel_ramdisk,
|
||||
'remove_kernel_ramdisk': remove_kernel_ramdisk})
|
||||
|
Loading…
Reference in New Issue
Block a user