diff options
| author | danwent@gmail.com <> | 2011-08-28 20:06:55 -0700 |
|---|---|---|
| committer | danwent@gmail.com <> | 2011-08-28 20:06:55 -0700 |
| commit | a4bd14f86f31ea82daad8e194b26e86e6dd37398 (patch) | |
| tree | 3807a1131dc6a7ba7119782f356eb365f28d8b6c /nova/virt | |
| parent | 605fe4f19af3af830a2a8c82809e9ce5909c602d (diff) | |
| parent | 0ef2581749f39fa4fd41c2376186418e730f0afb (diff) | |
merge trunk
Diffstat (limited to 'nova/virt')
| -rw-r--r-- | nova/virt/disk.py | 32 | ||||
| -rw-r--r-- | nova/virt/driver.py | 18 | ||||
| -rw-r--r-- | nova/virt/fake.py | 13 | ||||
| -rw-r--r-- | nova/virt/libvirt.xml.template | 11 | ||||
| -rw-r--r-- | nova/virt/libvirt/connection.py | 77 | ||||
| -rw-r--r-- | nova/virt/xenapi/vm_utils.py | 15 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 2 |
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) |
