diff options
| author | Josh Kearney <josh@jk0.org> | 2011-09-19 10:25:00 -0500 |
|---|---|---|
| committer | Josh Kearney <josh@jk0.org> | 2011-09-19 10:25:00 -0500 |
| commit | 91664a2c07e4a5627558dbcaa2dd4a6719315561 (patch) | |
| tree | d18ac2781af9ebfa296bb9ae14d660207d94a94b /nova/virt | |
| parent | 90f01055a92153709a90115688a8fce3d3029976 (diff) | |
| parent | 0561c0e01822d81fc90fed00f41b8d469c6c7808 (diff) | |
Merged trunk.
Diffstat (limited to 'nova/virt')
| -rw-r--r-- | nova/virt/libvirt/connection.py | 136 | ||||
| -rw-r--r-- | nova/virt/libvirt/firewall.py | 4 | ||||
| -rw-r--r-- | nova/virt/xenapi/vmops.py | 64 |
3 files changed, 105 insertions, 99 deletions
diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 2ae1359bf..b3c8ebf6e 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -29,9 +29,9 @@ Supports KVM, LXC, QEMU, UML, and XEN. (default: kvm). :libvirt_uri: Override for the default libvirt URI (depends on libvirt_type). :libvirt_xml_template: Libvirt XML Template. -:rescue_image_id: Rescue ami image (default: ami-rescue). -:rescue_kernel_id: Rescue aki image (default: aki-rescue). -:rescue_ramdisk_id: Rescue ari image (default: ari-rescue). +:rescue_image_id: Rescue ami image (None = original image). +:rescue_kernel_id: Rescue aki image (None = original image). +:rescue_ramdisk_id: Rescue ari image (None = original image). :injected_network_template: Template file for injected network :allow_same_net_traffic: Whether to allow in project network traffic @@ -84,9 +84,9 @@ LOG = logging.getLogger('nova.virt.libvirt_conn') FLAGS = flags.FLAGS flags.DECLARE('live_migration_retry_count', 'nova.compute.manager') # TODO(vish): These flags should probably go into a shared location -flags.DEFINE_string('rescue_image_id', 'ami-rescue', 'Rescue ami image') -flags.DEFINE_string('rescue_kernel_id', 'aki-rescue', 'Rescue aki image') -flags.DEFINE_string('rescue_ramdisk_id', 'ari-rescue', 'Rescue ari image') +flags.DEFINE_string('rescue_image_id', None, 'Rescue ami image') +flags.DEFINE_string('rescue_kernel_id', None, 'Rescue aki image') +flags.DEFINE_string('rescue_ramdisk_id', None, 'Rescue ari image') flags.DEFINE_string('libvirt_xml_template', utils.abspath('virt/libvirt.xml.template'), 'Libvirt XML Template') @@ -125,8 +125,10 @@ flags.DEFINE_string('block_migration_flag', 'Define block migration behavior.') flags.DEFINE_integer('live_migration_bandwidth', 0, 'Define live migration behavior') -flags.DEFINE_string('qemu_img', 'qemu-img', - 'binary to use for qemu-img commands') +flags.DEFINE_string('snapshot_image_format', None, + 'Snapshot image format (valid options are : ' + 'raw, qcow2, vmdk, vdi).' + 'Defaults to same as source image') flags.DEFINE_string('libvirt_vif_type', 'bridge', 'Type of VIF to create.') flags.DEFINE_string('libvirt_vif_driver', @@ -391,10 +393,7 @@ class LibvirtConnection(driver.ComputeDriver): def snapshot(self, context, instance, image_href): """Create snapshot from a running VM instance. - This command only works with qemu 0.14+, the qemu_img flag is - provided so that a locally compiled binary of qemu-img can be used - to support this command. - + This command only works with qemu 0.14+ """ virt_dom = self._lookup_by_name(instance['name']) @@ -420,8 +419,11 @@ class LibvirtConnection(driver.ComputeDriver): arch = base['properties']['architecture'] metadata['properties']['architecture'] = arch - if 'disk_format' in base: - metadata['disk_format'] = base['disk_format'] + source_format = base.get('disk_format') or 'raw' + image_format = FLAGS.snapshot_image_format or source_format + if FLAGS.use_cow_images: + source_format = 'qcow2' + metadata['disk_format'] = image_format if 'container_format' in base: metadata['container_format'] = base['container_format'] @@ -444,12 +446,12 @@ class LibvirtConnection(driver.ComputeDriver): # Export the snapshot to a raw image temp_dir = tempfile.mkdtemp() out_path = os.path.join(temp_dir, snapshot_name) - qemu_img_cmd = (FLAGS.qemu_img, + qemu_img_cmd = ('qemu-img', 'convert', '-f', - 'qcow2', + source_format, '-O', - 'raw', + image_format, '-s', snapshot_name, disk_path, @@ -468,7 +470,7 @@ class LibvirtConnection(driver.ComputeDriver): snapshot_ptr.delete(0) @exception.wrap_exception() - def reboot(self, instance, network_info, reboot_type): + def reboot(self, instance, network_info, reboot_type=None, xml=None): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the @@ -479,7 +481,9 @@ class LibvirtConnection(driver.ComputeDriver): # NOTE(itoumsn): Use XML delived from the running instance # instead of using to_xml(instance, network_info). This is almost # the ultimate stupid workaround. - xml = virt_dom.XMLDesc(0) + if not xml: + xml = virt_dom.XMLDesc(0) + # NOTE(itoumsn): self.shutdown() and wait instead of self.destroy() is # better because we cannot ensure flushing dirty buffers # in the guest OS. But, in case of KVM, shutdown() does not work... @@ -543,43 +547,42 @@ class LibvirtConnection(driver.ComputeDriver): data recovery. """ - self.destroy(instance, network_info, cleanup=False) - - xml = self.to_xml(instance, network_info, rescue=True) - rescue_images = {'image_id': FLAGS.rescue_image_id, - 'kernel_id': FLAGS.rescue_kernel_id, - 'ramdisk_id': FLAGS.rescue_ramdisk_id} - self._create_image(context, instance, xml, '.rescue', rescue_images) - self._create_new_domain(xml) - - def _wait_for_rescue(): - """Called at an interval until the VM is running again.""" - instance_name = instance['name'] - try: - state = self.get_info(instance_name)['state'] - except exception.NotFound: - msg = _("During reboot, %s disappeared.") % instance_name - LOG.error(msg) - raise utils.LoopingCallDone - - if state == power_state.RUNNING: - msg = _("Instance %s rescued successfully.") % instance_name - LOG.info(msg) - raise utils.LoopingCallDone + virt_dom = self._conn.lookupByName(instance['name']) + unrescue_xml = virt_dom.XMLDesc(0) + unrescue_xml_path = os.path.join(FLAGS.instances_path, + instance['name'], + 'unrescue.xml') + f = open(unrescue_xml_path, 'w') + f.write(unrescue_xml) + f.close() - timer = utils.LoopingCall(_wait_for_rescue) - return timer.start(interval=0.5, now=True) + xml = self.to_xml(instance, network_info, rescue=True) + rescue_images = { + 'image_id': FLAGS.rescue_image_id or instance['image_ref'], + 'kernel_id': FLAGS.rescue_kernel_id or instance['kernel_id'], + 'ramdisk_id': FLAGS.rescue_ramdisk_id or instance['ramdisk_id'], + } + self._create_image(context, instance, xml, '.rescue', rescue_images, + network_info=network_info) + self.reboot(instance, network_info, xml=xml) @exception.wrap_exception() - def unrescue(self, instance, network_info): + def unrescue(self, instance, callback, network_info): """Reboot the VM which is being rescued back into primary images. Because reboot destroys and re-creates instances, unresue should simply call reboot. """ - self.reboot(instance, network_info) + unrescue_xml_path = os.path.join(FLAGS.instances_path, + instance['name'], + 'unrescue.xml') + f = open(unrescue_xml_path) + unrescue_xml = f.read() + f.close() + os.remove(unrescue_xml_path) + self.reboot(instance, network_info, xml=unrescue_xml) @exception.wrap_exception() def poll_rescued_instances(self, timeout): @@ -774,13 +777,13 @@ class LibvirtConnection(driver.ComputeDriver): if size: disk.extend(target, size) - def _create_local(self, target, local_size, prefix='G', fs_format=None): + def _create_local(self, target, local_size, unit='G', fs_format=None): """Create a blank image of specified size""" if not fs_format: fs_format = FLAGS.default_local_format - utils.execute('truncate', target, '-s', "%d%c" % (local_size, prefix)) + utils.execute('truncate', target, '-s', "%d%c" % (local_size, unit)) if fs_format: utils.execute('mkfs', '-t', fs_format, target) @@ -788,9 +791,9 @@ class LibvirtConnection(driver.ComputeDriver): self._create_local(target, local_size) disk.mkfs(os_type, fs_label, target) - def _create_swap(self, target, swap_gb): + def _create_swap(self, target, swap_mb): """Create a swap file of specified size""" - self._create_local(target, swap_gb) + self._create_local(target, swap_mb, unit='M') utils.execute('mkswap', target) def _create_image(self, context, inst, libvirt_xml, suffix='', @@ -818,8 +821,10 @@ class LibvirtConnection(driver.ComputeDriver): utils.execute('mkdir', '-p', container_dir) # NOTE(vish): No need add the suffix to console.log - os.close(os.open(basepath('console.log', ''), - os.O_CREAT | os.O_WRONLY, 0660)) + console_log = basepath('console.log', '') + if os.path.exists(console_log): + utils.execute('chown', os.getuid(), console_log, run_as_root=True) + os.close(os.open(console_log, os.O_CREAT | os.O_WRONLY, 0660)) if not disk_images: disk_images = {'image_id': inst['image_ref'], @@ -886,22 +891,22 @@ class LibvirtConnection(driver.ComputeDriver): cow=FLAGS.use_cow_images, local_size=eph['size']) - swap_gb = 0 + swap_mb = 0 swap = driver.block_device_info_get_swap(block_device_info) if driver.swap_is_usable(swap): - swap_gb = swap['swap_size'] + swap_mb = swap['swap_size'] elif (inst_type['swap'] > 0 and not self._volume_in_mapping(self.default_swap_device, block_device_info)): - swap_gb = inst_type['swap'] + swap_mb = inst_type['swap'] - if swap_gb > 0: + if swap_mb > 0: self._cache_image(fn=self._create_swap, target=basepath('disk.swap'), - fname="swap_%s" % swap_gb, + fname="swap_%s" % swap_mb, cow=FLAGS.use_cow_images, - swap_gb=swap_gb) + swap_mb=swap_mb) # For now, we assume that if we're not using a kernel, we're using a # partitioned disk image where the target partition is the first @@ -922,10 +927,10 @@ class LibvirtConnection(driver.ComputeDriver): target=basepath('disk.config'), fname=fname, image_id=config_drive_id, - user=user, - project=project) + user_id=inst['user_id'], + project_id=inst['project_id'],) elif config_drive: - self._create_local(basepath('disk.config'), 64, prefix="M", + self._create_local(basepath('disk.config'), 64, unit='M', fs_format='msdos') # 64MB if inst['key_data']: @@ -995,15 +1000,16 @@ class LibvirtConnection(driver.ComputeDriver): nbd=FLAGS.use_cow_images, tune2fs=tune2fs) - if FLAGS.libvirt_type == 'lxc': - disk.setup_container(basepath('disk'), - container_dir=container_dir, - nbd=FLAGS.use_cow_images) except Exception as e: # This could be a windows image, or a vmdk format disk LOG.warn(_('instance %(inst_name)s: ignoring error injecting' ' data into image %(img_id)s (%(e)s)') % locals()) + if FLAGS.libvirt_type == 'lxc': + disk.setup_container(basepath('disk'), + container_dir=container_dir, + nbd=FLAGS.use_cow_images) + if FLAGS.libvirt_type == 'uml': utils.execute('chown', 'root', basepath('disk'), run_as_root=True) diff --git a/nova/virt/libvirt/firewall.py b/nova/virt/libvirt/firewall.py index 0db10c7ce..c6253511e 100644 --- a/nova/virt/libvirt/firewall.py +++ b/nova/virt/libvirt/firewall.py @@ -663,7 +663,9 @@ class IptablesFirewallDriver(FirewallDriver): if version == 6 and rule.protocol == 'icmp': protocol = 'icmpv6' - args = ['-j ACCEPT', '-p', protocol] + args = ['-j ACCEPT'] + if protocol: + args += ['-p', protocol] if protocol in ['udp', 'tcp']: if rule.from_port == rule.to_port: diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 55a6a4a78..210b8fe65 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -49,9 +49,9 @@ XenAPI = None LOG = logging.getLogger("nova.virt.xenapi.vmops") FLAGS = flags.FLAGS -flags.DEFINE_integer('windows_version_timeout', 300, - 'number of seconds to wait for windows agent to be ' - 'fully operational') +flags.DEFINE_integer('agent_version_timeout', 300, + 'number of seconds to wait for agent to be fully ' + 'operational') flags.DEFINE_string('xenapi_vif_driver', 'nova.virt.xenapi.vif.XenAPIBridgeDriver', 'The XenAPI VIF driver using XenServer Network APIs.') @@ -324,15 +324,8 @@ class VMOps(object): def _check_agent_version(): LOG.debug(_("Querying agent version")) - if instance.os_type == 'windows': - # Windows will generally perform a setup process on first boot - # that can take a couple of minutes and then reboot. So we - # need to be more patient than normal as well as watch for - # domid changes - version = self.get_agent_version(instance, - timeout=FLAGS.windows_version_timeout) - else: - version = self.get_agent_version(instance) + + version = self.get_agent_version(instance) if not version: return @@ -639,9 +632,15 @@ class VMOps(object): self._session.wait_for_task(task, instance.id) - def get_agent_version(self, instance, timeout=None): + def get_agent_version(self, instance): """Get the version of the agent running on the VM instance.""" + # The agent can be slow to start for a variety of reasons. On Windows, + # it will generally perform a setup process on first boot that can + # take a couple of minutes and then reboot. On Linux, the system can + # also take a while to boot. So we need to be more patient than + # normal as well as watch for domid changes + def _call(): # Send the encrypted password transaction_id = str(uuid.uuid4()) @@ -655,27 +654,26 @@ class VMOps(object): # (ie CRLF escaped) for some reason. Strip that off. return resp['message'].replace('\\r\\n', '') - if timeout: - vm_ref = self._get_vm_opaque_ref(instance) - vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + vm_ref = self._get_vm_opaque_ref(instance) + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) - domid = vm_rec['domid'] - - expiration = time.time() + timeout - while time.time() < expiration: - ret = _call() - if ret: - return ret - - vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) - if vm_rec['domid'] != domid: - LOG.info(_('domid changed from %(olddomid)s to ' - '%(newdomid)s') % { - 'olddomid': domid, - 'newdomid': vm_rec['domid']}) - domid = vm_rec['domid'] - else: - return _call() + domid = vm_rec['domid'] + + expiration = time.time() + FLAGS.agent_version_timeout + while time.time() < expiration: + ret = _call() + if ret: + return ret + + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + if vm_rec['domid'] != domid: + LOG.info(_('domid changed from %(olddomid)s to ' + '%(newdomid)s') % { + 'olddomid': domid, + 'newdomid': vm_rec['domid']}) + domid = vm_rec['domid'] + + return None def agent_update(self, instance, url, md5sum): """Update agent on the VM instance.""" |
