summaryrefslogtreecommitdiffstats
path: root/nova/virt
diff options
context:
space:
mode:
authordanwent@gmail.com <>2011-08-28 20:06:55 -0700
committerdanwent@gmail.com <>2011-08-28 20:06:55 -0700
commita4bd14f86f31ea82daad8e194b26e86e6dd37398 (patch)
tree3807a1131dc6a7ba7119782f356eb365f28d8b6c /nova/virt
parent605fe4f19af3af830a2a8c82809e9ce5909c602d (diff)
parent0ef2581749f39fa4fd41c2376186418e730f0afb (diff)
merge trunk
Diffstat (limited to 'nova/virt')
-rw-r--r--nova/virt/disk.py32
-rw-r--r--nova/virt/driver.py18
-rw-r--r--nova/virt/fake.py13
-rw-r--r--nova/virt/libvirt.xml.template11
-rw-r--r--nova/virt/libvirt/connection.py77
-rw-r--r--nova/virt/xenapi/vm_utils.py15
-rw-r--r--nova/virt/xenapi/vmops.py2
7 files changed, 124 insertions, 44 deletions
diff --git a/nova/virt/disk.py b/nova/virt/disk.py
index 19f3ec185..52b2881e8 100644
--- a/nova/virt/disk.py
+++ b/nova/virt/disk.py
@@ -2,6 +2,9 @@
# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
+#
+# Copyright 2011, Piston Cloud Computing, Inc.
+#
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -22,6 +25,7 @@ Includes injection of SSH PGP keys into authorized_keys file.
"""
+import json
import os
import tempfile
import time
@@ -60,7 +64,8 @@ def extend(image, size):
utils.execute('resize2fs', image, check_exit_code=False)
-def inject_data(image, key=None, net=None, partition=None, nbd=False):
+def inject_data(image, key=None, net=None, metadata=None,
+ partition=None, nbd=False, tune2fs=True):
"""Injects a ssh key and optionally net data into a disk image.
it will mount the image as a fully partitioned disk and attempt to inject
@@ -89,10 +94,10 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False):
' only inject raw disk images): %s' %
mapped_device)
- # Configure ext2fs so that it doesn't auto-check every N boots
- out, err = utils.execute('tune2fs', '-c', 0, '-i', 0,
- mapped_device, run_as_root=True)
-
+ if tune2fs:
+ # Configure ext2fs so that it doesn't auto-check every N boots
+ out, err = utils.execute('tune2fs', '-c', 0, '-i', 0,
+ mapped_device, run_as_root=True)
tmpdir = tempfile.mkdtemp()
try:
# mount loopback to dir
@@ -103,7 +108,8 @@ def inject_data(image, key=None, net=None, partition=None, nbd=False):
% err)
try:
- inject_data_into_fs(tmpdir, key, net, utils.execute)
+ inject_data_into_fs(tmpdir, key, net, metadata,
+ utils.execute)
finally:
# unmount device
utils.execute('umount', mapped_device, run_as_root=True)
@@ -155,6 +161,7 @@ def destroy_container(target, instance, nbd=False):
def _link_device(image, nbd):
"""Link image to device using loopback or nbd"""
+
if nbd:
device = _allocate_device()
utils.execute('qemu-nbd', '-c', device, image, run_as_root=True)
@@ -190,6 +197,7 @@ def _allocate_device():
# NOTE(vish): This assumes no other processes are allocating nbd devices.
# It may race cause a race condition if multiple
# workers are running on a given machine.
+
while True:
if not _DEVICES:
raise exception.Error(_('No free nbd devices'))
@@ -203,7 +211,7 @@ def _free_device(device):
_DEVICES.append(device)
-def inject_data_into_fs(fs, key, net, execute):
+def inject_data_into_fs(fs, key, net, metadata, execute):
"""Injects data into a filesystem already mounted by the caller.
Virt connections can call this directly if they mount their fs
in a different way to inject_data
@@ -212,6 +220,16 @@ def inject_data_into_fs(fs, key, net, execute):
_inject_key_into_fs(key, fs, execute=execute)
if net:
_inject_net_into_fs(net, fs, execute=execute)
+ if metadata:
+ _inject_metadata_into_fs(metadata, fs, execute=execute)
+
+
+def _inject_metadata_into_fs(metadata, fs, execute=None):
+ metadata_path = os.path.join(fs, "meta.js")
+ metadata = dict([(m.key, m.value) for m in metadata])
+
+ utils.execute('sudo', 'tee', metadata_path,
+ process_input=json.dumps(metadata))
def _inject_key_into_fs(key, fs, execute=None):
diff --git a/nova/virt/driver.py b/nova/virt/driver.py
index 93290aba7..d05b51bd9 100644
--- a/nova/virt/driver.py
+++ b/nova/virt/driver.py
@@ -140,7 +140,7 @@ class ComputeDriver(object):
that it was before this call began.
:param context: security context
- :param instance: Instance of {nova.compute.service.Instance}.
+ :param instance: Instance object as returned by DB layer.
This function should use the data there to guide
the creation of the new instance.
:param network_info:
@@ -152,14 +152,11 @@ class ComputeDriver(object):
def destroy(self, instance, network_info, cleanup=True):
"""Destroy (shutdown and delete) the specified instance.
- The given parameter is an instance of nova.compute.service.Instance,
-
If the instance is not found (for example if networking failed), this
function should still succeed. It's probably a good idea to log a
warning in that case.
- :param instance: Instance of {nova.compute.service.Instance} and so
- the instance is being specified as instance.name.
+ :param instance: Instance object as returned by DB layer.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
:param cleanup:
@@ -171,8 +168,7 @@ class ComputeDriver(object):
def reboot(self, instance, network_info):
"""Reboot the specified instance.
- :param instance: Instance of {nova.compute.service.Instance} and so
- the instance is being specified as instance.name.
+ :param instance: Instance object as returned by DB layer.
:param network_info:
:py:meth:`~nova.network.manager.NetworkManager.get_instance_nw_info`
"""
@@ -240,10 +236,10 @@ class ComputeDriver(object):
"""
Snapshots the specified instance.
- The given parameter is an instance of nova.compute.service.Instance,
- and so the instance is being specified as instance.name.
-
- The second parameter is the name of the snapshot.
+ :param context: security context
+ :param instance: Instance object as returned by DB layer.
+ :param image_id: Reference to a pre-created image that will
+ hold the snapshot.
"""
raise NotImplementedError()
diff --git a/nova/virt/fake.py b/nova/virt/fake.py
index 13b7aeab5..d5e2bf31b 100644
--- a/nova/virt/fake.py
+++ b/nova/virt/fake.py
@@ -67,6 +67,7 @@ class FakeConnection(driver.ComputeDriver):
'disk_used': 100000000000,
'host_uuid': 'cedb9b39-9388-41df-8891-c5c9a0c0fe5f',
'host_name_label': 'fake-mini'}
+ self._mounts = {}
@classmethod
def instance(cls):
@@ -99,7 +100,8 @@ class FakeConnection(driver.ComputeDriver):
self.instances[name] = fake_instance
def snapshot(self, context, instance, name):
- pass
+ if not instance['name'] in self.instances:
+ raise exception.InstanceNotRunning()
def reboot(self, instance, network_info):
pass
@@ -144,7 +146,7 @@ class FakeConnection(driver.ComputeDriver):
pass
def destroy(self, instance, network_info, cleanup=True):
- key = instance.name
+ key = instance['name']
if key in self.instances:
del self.instances[key]
else:
@@ -152,9 +154,16 @@ class FakeConnection(driver.ComputeDriver):
(key, self.instances))
def attach_volume(self, instance_name, device_path, mountpoint):
+ if not instance_name in self._mounts:
+ self._mounts[instance_name] = {}
+ self._mounts[instance_name][mountpoint] = device_path
return True
def detach_volume(self, instance_name, mountpoint):
+ try:
+ del self._mounts[instance_name][mountpoint]
+ except KeyError:
+ pass
return True
def get_info(self, instance_name):
diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template
index 210e2b0fb..d3aeadda4 100644
--- a/nova/virt/libvirt.xml.template
+++ b/nova/virt/libvirt.xml.template
@@ -106,6 +106,13 @@
</disk>
#end for
#end if
+ #if $getVar('config_drive', False)
+ <disk type='file'>
+ <driver type='raw' />
+ <source file='${basepath}/disk.config' />
+ <target dev='${disk_prefix}z' bus='${disk_bus}' />
+ </disk>
+ #end if
#end if
#for $nic in $nics
@@ -128,7 +135,9 @@
<interface type='bridge'>
<source bridge='${nic.bridge_name}'/>
<mac address='${nic.mac_address}'/>
- <!-- <model type='virtio'/> CANT RUN virtio network right now -->
+#if $getVar('use_virtio_for_bridges', True)
+ <model type='virtio'/>
+#end if
<filterref filter="nova-instance-${name}-${nic.id}">
<parameter name="IP" value="${nic.ip_address}" />
<parameter name="DHCPSERVER" value="${nic.dhcp_server}" />
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py
index e8a657bac..363a20ed0 100644
--- a/nova/virt/libvirt/connection.py
+++ b/nova/virt/libvirt/connection.py
@@ -4,6 +4,7 @@
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
# Copyright (c) 2010 Citrix Systems, Inc.
+# Copyright (c) 2011 Piston Cloud Computing, Inc
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -130,6 +131,13 @@ flags.DEFINE_string('libvirt_vif_type', 'bridge',
flags.DEFINE_string('libvirt_vif_driver',
'nova.virt.libvirt.vif.LibvirtBridgeDriver',
'The libvirt VIF driver to configure the VIFs.')
+flags.DEFINE_string('default_local_format',
+ None,
+ 'The default format a local_volume will be formatted with '
+ 'on creation.')
+flags.DEFINE_bool('libvirt_use_virtio_for_bridges',
+ False,
+ 'Use virtio for bridge interfaces')
def get_connection(read_only):
@@ -586,6 +594,7 @@ class LibvirtConnection(driver.ComputeDriver):
self.firewall_driver.prepare_instance_filter(instance, network_info)
self._create_image(context, instance, xml, network_info=network_info,
block_device_info=block_device_info)
+
domain = self._create_new_domain(xml)
LOG.debug(_("instance %s: is running"), instance['name'])
self.firewall_driver.apply_instance_filter(instance, network_info)
@@ -759,10 +768,15 @@ class LibvirtConnection(driver.ComputeDriver):
if size:
disk.extend(target, size)
- def _create_local(self, target, local_gb):
+ def _create_local(self, target, local_size, prefix='G', fs_format=None):
"""Create a blank image of specified size"""
- utils.execute('truncate', target, '-s', "%dG" % local_gb)
- # TODO(vish): should we format disk by default?
+
+ if not fs_format:
+ fs_format = FLAGS.default_local_format
+
+ utils.execute('truncate', target, '-s', "%d%c" % (local_size, prefix))
+ if fs_format:
+ utils.execute('mkfs', '-t', fs_format, target)
def _create_swap(self, target, swap_gb):
"""Create a swap file of specified size"""
@@ -849,14 +863,14 @@ class LibvirtConnection(driver.ComputeDriver):
target=basepath('disk.local'),
fname="local_%s" % local_gb,
cow=FLAGS.use_cow_images,
- local_gb=local_gb)
+ local_size=local_gb)
for eph in driver.block_device_info_get_ephemerals(block_device_info):
self._cache_image(fn=self._create_local,
target=basepath(_get_eph_disk(eph)),
fname="local_%s" % eph['size'],
cow=FLAGS.use_cow_images,
- local_gb=eph['size'])
+ local_size=eph['size'])
swap_gb = 0
@@ -882,9 +896,24 @@ class LibvirtConnection(driver.ComputeDriver):
if not inst['kernel_id']:
target_partition = "1"
- if FLAGS.libvirt_type == 'lxc':
+ config_drive_id = inst.get('config_drive_id')
+ config_drive = inst.get('config_drive')
+
+ if any((FLAGS.libvirt_type == 'lxc', config_drive, config_drive_id)):
target_partition = None
+ if config_drive_id:
+ fname = '%08x' % int(config_drive_id)
+ self._cache_image(fn=self._fetch_image,
+ target=basepath('disk.config'),
+ fname=fname,
+ image_id=config_drive_id,
+ user=user,
+ project=project)
+ elif config_drive:
+ self._create_local(basepath('disk.config'), 64, prefix="M",
+ fs_format='msdos') # 64MB
+
if inst['key_data']:
key = str(inst['key_data'])
else:
@@ -928,19 +957,29 @@ class LibvirtConnection(driver.ComputeDriver):
searchList=[{'interfaces': nets,
'use_ipv6': FLAGS.use_ipv6}]))
- if key or net:
+ metadata = inst.get('metadata')
+ if any((key, net, metadata)):
inst_name = inst['name']
- img_id = inst.image_ref
- if key:
- LOG.info(_('instance %(inst_name)s: injecting key into'
- ' image %(img_id)s') % locals())
- if net:
- LOG.info(_('instance %(inst_name)s: injecting net into'
- ' image %(img_id)s') % locals())
+
+ if config_drive: # Should be True or None by now.
+ injection_path = basepath('disk.config')
+ img_id = 'config-drive'
+ tune2fs = False
+ else:
+ injection_path = basepath('disk')
+ img_id = inst.image_ref
+ tune2fs = True
+
+ for injection in ('metadata', 'key', 'net'):
+ if locals()[injection]:
+ LOG.info(_('instance %(inst_name)s: injecting '
+ '%(injection)s into image %(img_id)s'
+ % locals()))
try:
- disk.inject_data(basepath('disk'), key, net,
+ disk.inject_data(injection_path, key, net, metadata,
partition=target_partition,
- nbd=FLAGS.use_cow_images)
+ nbd=FLAGS.use_cow_images,
+ tune2fs=tune2fs)
if FLAGS.libvirt_type == 'lxc':
disk.setup_container(basepath('disk'),
@@ -1047,6 +1086,8 @@ class LibvirtConnection(driver.ComputeDriver):
'ebs_root': ebs_root,
'local_device': local_device,
'volumes': block_device_mapping,
+ 'use_virtio_for_bridges':
+ FLAGS.libvirt_use_virtio_for_bridges,
'ephemerals': ephemerals}
root_device_name = driver.block_device_info_get_root(block_device_info)
@@ -1070,6 +1111,10 @@ class LibvirtConnection(driver.ComputeDriver):
block_device_info)):
xml_info['swap_device'] = self.default_swap_device
+ config_drive = False
+ if instance.get('config_drive') or instance.get('config_drive_id'):
+ xml_info['config_drive'] = xml_info['basepath'] + "/disk.config"
+
if FLAGS.vnc_enabled and FLAGS.libvirt_type not in ('lxc', 'uml'):
xml_info['vncserver_host'] = FLAGS.vncserver_host
xml_info['vnc_keymap'] = FLAGS.vnc_keymap
diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py
index 4a1f07bb1..efbea7076 100644
--- a/nova/virt/xenapi/vm_utils.py
+++ b/nova/virt/xenapi/vm_utils.py
@@ -1,6 +1,7 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright (c) 2010 Citrix Systems, Inc.
+# Copyright 2011 Piston Cloud Computing, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
@@ -740,13 +741,14 @@ class VMHelper(HelperBase):
# if at all, so determine whether it's required first, and then do
# everything
mount_required = False
- key, net = _prepare_injectables(instance, network_info)
- mount_required = key or net
+ key, net, metadata = _prepare_injectables(instance, network_info)
+ mount_required = key or net or metadata
if not mount_required:
return
with_vdi_attached_here(session, vdi_ref, False,
- lambda dev: _mounted_processing(dev, key, net))
+ lambda dev: _mounted_processing(dev, key, net,
+ metadata))
@classmethod
def lookup_kernel_ramdisk(cls, session, vm):
@@ -1198,7 +1200,7 @@ def _find_guest_agent(base_dir, agent_rel_path):
return False
-def _mounted_processing(device, key, net):
+def _mounted_processing(device, key, net, metadata):
"""Callback which runs with the image VDI attached"""
dev_path = '/dev/' + device + '1' # NB: Partition 1 hardcoded
@@ -1212,7 +1214,7 @@ def _mounted_processing(device, key, net):
if not _find_guest_agent(tmpdir, FLAGS.xenapi_agent_path):
LOG.info(_('Manipulating interface files '
'directly'))
- disk.inject_data_into_fs(tmpdir, key, net,
+ disk.inject_data_into_fs(tmpdir, key, net, metadata,
utils.execute)
finally:
utils.execute('umount', dev_path, run_as_root=True)
@@ -1235,6 +1237,7 @@ def _prepare_injectables(inst, networks_info):
template = t.Template
template_data = open(FLAGS.injected_network_template).read()
+ metadata = inst['metadata']
key = str(inst['key_data'])
net = None
if networks_info:
@@ -1272,4 +1275,4 @@ def _prepare_injectables(inst, networks_info):
net = str(template(template_data,
searchList=[{'interfaces': interfaces_info,
'use_ipv6': FLAGS.use_ipv6}]))
- return key, net
+ return key, net, metadata
diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py
index 9a6215f88..c5f105f40 100644
--- a/nova/virt/xenapi/vmops.py
+++ b/nova/virt/xenapi/vmops.py
@@ -239,7 +239,7 @@ class VMOps(object):
self._attach_disks(instance, disk_image_type, vm_ref, first_vdi_ref,
vdis)
- # Alter the image before VM start for, e.g. network injection
+ # Alter the image before VM start for network injection.
if FLAGS.flat_injected:
VMHelper.preconfigure_instance(self._session, instance,
first_vdi_ref, network_info)