From 6930c62a02a39f64506a7b2d2ec5b04dbff5fe3a Mon Sep 17 00:00:00 2001 From: sateesh Date: Mon, 5 Sep 2011 12:51:07 +0530 Subject: Multi-NIC support for vmwareapi virt driver in nova. Does injection of Multi-NIC information to instances with Operating system flavors Ubuntu, Windows and RHEL. vmwareapi virt driver now relies on calls to network manager instead of nova db calls for network configuration information of instance. Ensure if port group is properly associated with vlan_interface specified in case of VLAN networking for instances. Re-oranized VMWareVlanBridgeDriver and added session parmeter to methods to use existing session. Also removed session creation code as session comes as argument. Added check for flat_inject flag before attempting an inject operation. Removed stale code from vmwareapi stubs. Also updated some comments to be more meaningful. Did pep8 and pylint checks. Tried to improve pylint score for newly added lines of code. --- nova/virt/vmwareapi/fake.py | 2 +- nova/virt/vmwareapi/vif.py | 27 +++++------ nova/virt/vmwareapi/vm_util.py | 26 +++++----- nova/virt/vmwareapi/vmops.py | 106 ++++++++++++++++++++++++----------------- 4 files changed, 84 insertions(+), 77 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/vmwareapi/fake.py b/nova/virt/vmwareapi/fake.py index 4c62d18bb..f47ffdf1c 100644 --- a/nova/virt/vmwareapi/fake.py +++ b/nova/virt/vmwareapi/fake.py @@ -409,7 +409,7 @@ def fake_plug_vifs(*args, **kwargs): def fake_get_network(*args, **kwargs): """Fake get network.""" - return [{'type': 'fake'}] + return {'type': 'fake'} def fake_fetch_image(image, instance, **kwargs): diff --git a/nova/virt/vmwareapi/vif.py b/nova/virt/vmwareapi/vif.py index fb6548b34..9906b89e1 100644 --- a/nova/virt/vmwareapi/vif.py +++ b/nova/virt/vmwareapi/vif.py @@ -17,42 +17,35 @@ """VIF drivers for VMWare.""" -from nova import db from nova import exception from nova import flags from nova import log as logging -from nova import utils from nova.virt.vif import VIFDriver -from nova.virt.vmwareapi_conn import VMWareAPISession from nova.virt.vmwareapi import network_utils LOG = logging.getLogger("nova.virt.vmwareapi.vif") FLAGS = flags.FLAGS +FLAGS['vmwareapi_vlan_interface'].SetDefault('vmnic0') class VMWareVlanBridgeDriver(VIFDriver): """VIF Driver to setup bridge/VLAN networking using VMWare API.""" def plug(self, instance, network, mapping): + """Plug the VIF to specified instance using information passed. + Currently we are plugging the VIF(s) during instance creation itself. + We can use this method when we add support to add additional NIC to + an existing instance.""" + pass + + def ensure_vlan_bridge(self, session, network): """Create a vlan and bridge unless they already exist.""" vlan_num = network['vlan'] bridge = network['bridge'] - bridge_interface = network['bridge_interface'] + vlan_interface = FLAGS.vmwareapi_vlan_interface - # Open vmwareapi session - host_ip = FLAGS.vmwareapi_host_ip - host_username = FLAGS.vmwareapi_host_username - host_password = FLAGS.vmwareapi_host_password - if not host_ip or host_username is None or host_password is None: - raise Exception(_('Must specify vmwareapi_host_ip, ' - 'vmwareapi_host_username ' - 'and vmwareapi_host_password to use ' - 'connection_type=vmwareapi')) - session = VMWareAPISession(host_ip, host_username, host_password, - FLAGS.vmwareapi_api_retry_count) - vlan_interface = bridge_interface # Check if the vlan_interface physical network adapter exists on the # host. if not network_utils.check_if_vlan_interface_exists(session, @@ -92,4 +85,6 @@ class VMWareVlanBridgeDriver(VIFDriver): pgroup=pg_vlanid) def unplug(self, instance, network, mapping): + """Cleanup operations like deleting port group if no instance + is associated with it.""" pass diff --git a/nova/virt/vmwareapi/vm_util.py b/nova/virt/vmwareapi/vm_util.py index 82b5f7214..dd1c81196 100644 --- a/nova/virt/vmwareapi/vm_util.py +++ b/nova/virt/vmwareapi/vm_util.py @@ -39,8 +39,7 @@ def split_datastore_path(datastore_path): def get_vm_create_spec(client_factory, instance, data_store_name, - network_name="vmnet0", - os_type="otherGuest", network_ref=None): + vif_infos, os_type="otherGuest"): """Builds the VM Create spec.""" config_spec = client_factory.create('ns0:VirtualMachineConfigSpec') config_spec.name = instance.name @@ -61,14 +60,12 @@ def get_vm_create_spec(client_factory, instance, data_store_name, config_spec.numCPUs = int(instance.vcpus) config_spec.memoryMB = int(instance.memory_mb) - mac_address = None - if instance['mac_addresses']: - mac_address = instance['mac_addresses'][0]['address'] + vif_spec_list = [] + for vif_info in vif_infos: + vif_spec = create_network_spec(client_factory, vif_info) + vif_spec_list.append(vif_spec) - nic_spec = create_network_spec(client_factory, - network_name, mac_address) - - device_config_spec = [nic_spec] + device_config_spec = vif_spec_list config_spec.deviceChange = device_config_spec return config_spec @@ -93,8 +90,7 @@ def create_controller_spec(client_factory, key): return virtual_device_config -def create_network_spec(client_factory, network_name, mac_address, - network_ref=None): +def create_network_spec(client_factory, vif_info): """ Builds a config spec for the addition of a new network adapter to the VM. @@ -109,6 +105,9 @@ def create_network_spec(client_factory, network_name, mac_address, # NOTE(asomya): Only works on ESXi if the portgroup binding is set to # ephemeral. Invalid configuration if set to static and the NIC does # not come up on boot if set to dynamic. + network_ref = vif_info['network_ref'] + network_name = vif_info['network_name'] + mac_address = vif_info['mac_address'] backing = None if (network_ref and network_ref['type'] == "DistributedVirtualPortgroup"): @@ -295,11 +294,8 @@ def get_dummy_vm_create_spec(client_factory, name, data_store_name): return config_spec -def get_machine_id_change_spec(client_factory, mac, ip_addr, netmask, - gateway, broadcast, dns): +def get_machine_id_change_spec(client_factory, machine_id_str): """Builds the machine id change config spec.""" - machine_id_str = "%s;%s;%s;%s;%s;%s" % (mac, ip_addr, netmask, - gateway, broadcast, dns) virtual_machine_config_spec = \ client_factory.create('ns0:VirtualMachineConfigSpec') diff --git a/nova/virt/vmwareapi/vmops.py b/nova/virt/vmwareapi/vmops.py index 07a6ba6ab..3ac99f923 100644 --- a/nova/virt/vmwareapi/vmops.py +++ b/nova/virt/vmwareapi/vmops.py @@ -27,7 +27,6 @@ import urllib2 import uuid from nova import context as nova_context -from nova import db from nova import exception from nova import flags from nova import log as logging @@ -111,22 +110,6 @@ class VMWareVMOps(object): client_factory = self._session._get_vim().client.factory service_content = self._session._get_vim().get_service_content() - network = db.network_get_by_instance(nova_context.get_admin_context(), - instance['id']) - - net_name = network['bridge'] - - def _check_if_network_bridge_exists(): - network_ref = \ - network_utils.get_network_with_the_name(self._session, - net_name) - if network_ref is None: - raise exception.NetworkNotFoundForBridge(bridge=net_name) - return network_ref - - self.plug_vifs(instance, network_info) - network_obj = _check_if_network_bridge_exists() - def _get_datastore_ref(): """Get the datastore list and choose the first local storage.""" data_stores = self._session._call_method(vim_util, "get_objects", @@ -182,11 +165,36 @@ class VMWareVMOps(object): vm_folder_mor, res_pool_mor = _get_vmfolder_and_res_pool_mors() + def _check_if_network_bridge_exists(network_name): + network_ref = \ + network_utils.get_network_with_the_name(self._session, + network_name) + if network_ref is None: + raise exception.NetworkNotFoundForBridge(bridge=network_name) + return network_ref + + def _get_vif_infos(): + vif_infos = [] + for (network, mapping) in network_info: + mac_address = mapping['mac'] + network_name = network['bridge'] + if mapping.get('should_create_vlan'): + network_ref = self._vif_driver.ensure_vlan_bridge( + self._session, network) + else: + network_ref = _check_if_network_bridge_exists(network_name) + vif_infos.append({'network_name': network_name, + 'mac_address': mac_address, + 'network_ref': network_ref, + }) + return vif_infos + + vif_infos = _get_vif_infos() + # Get the create vm config spec config_spec = vm_util.get_vm_create_spec( client_factory, instance, - data_store_name, net_name, os_type, - network_obj) + data_store_name, vif_infos, os_type) def _execute_create_vm(): """Create VM on ESX host.""" @@ -204,8 +212,10 @@ class VMWareVMOps(object): _execute_create_vm() - # Set the machine id for the VM for setting the IP - self._set_machine_id(client_factory, instance) + # Set the machine.id parameter of the instance to inject + # the NIC configuration inside the VM + if FLAGS.flat_injected: + self._set_machine_id(client_factory, instance, network_info) # Naming the VM files in correspondence with the VM instance name # The flat vmdk file name @@ -716,39 +726,45 @@ class VMWareVMOps(object): """Return link to instance's ajax console.""" return 'http://fakeajaxconsole/fake_url' - def _set_machine_id(self, client_factory, instance): + def _set_machine_id(self, client_factory, instance, network_info): """ - Set the machine id of the VM for guest tools to pick up and change - the IP. + Set the machine id of the VM for guest tools to pick up and reconfigure + the network interfaces. """ - admin_context = nova_context.get_admin_context() vm_ref = self._get_vm_ref_from_the_name(instance.name) if vm_ref is None: raise exception.InstanceNotFound(instance_id=instance.id) - network = db.network_get_by_instance(nova_context.get_admin_context(), - instance['id']) - mac_address = None - if instance['mac_addresses']: - mac_address = instance['mac_addresses'][0]['address'] - - net_mask = network["netmask"] - gateway = network["gateway"] - broadcast = network["broadcast"] - # TODO(vish): add support for dns2 - dns = network["dns1"] - - addresses = db.instance_get_fixed_addresses(admin_context, - instance['id']) - ip_addr = addresses[0] if addresses else None + + machine_id_str = '' + for (network, info) in network_info: + # TODO(vish): add support for dns2 + # TODO(sateesh): add support for injection of ipv6 configuration + ip_v4 = ip_v6 = None + if 'ips' in info and len(info['ips']) > 0: + ip_v4 = info['ips'][0] + if 'ip6s' in info and len(info['ip6s']) > 0: + ip_v6 = info['ip6s'][0] + if len(info['dns']) > 0: + dns = info['dns'][0] + else: + dns = '' + + interface_str = "%s;%s;%s;%s;%s;%s" % \ + (info['mac'], + ip_v4 and ip_v4['ip'] or '', + ip_v4 and ip_v4['netmask'] or '', + info['gateway'], + info['broadcast'], + dns) + machine_id_str = machine_id_str + interface_str + '#' machine_id_change_spec = \ - vm_util.get_machine_id_change_spec(client_factory, mac_address, - ip_addr, net_mask, gateway, - broadcast, dns) + vm_util.get_machine_id_change_spec(client_factory, machine_id_str) + LOG.debug(_("Reconfiguring VM instance %(name)s to set the machine id " "with ip - %(ip_addr)s") % ({'name': instance.name, - 'ip_addr': ip_addr})) + 'ip_addr': ip_v4['ip']})) reconfig_task = self._session._call_method(self._session._get_vim(), "ReconfigVM_Task", vm_ref, spec=machine_id_change_spec) @@ -756,7 +772,7 @@ class VMWareVMOps(object): LOG.debug(_("Reconfigured VM instance %(name)s to set the machine id " "with ip - %(ip_addr)s") % ({'name': instance.name, - 'ip_addr': ip_addr})) + 'ip_addr': ip_v4['ip']})) def _get_datacenter_name_and_ref(self): """Get the datacenter name and the reference.""" -- cgit From e1d38ca90c259a44035cf3bd5ad17d9ca5d93472 Mon Sep 17 00:00:00 2001 From: Thuleau Édouard Date: Fri, 9 Sep 2011 15:21:00 +0200 Subject: Authorize to start a LXC instance withour, key, network file to inject or metadata. --- nova/virt/libvirt/connection.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..fc060703a 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -981,15 +981,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) -- cgit From 248787462473195ab35591946ed6e3f0e2a818b0 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sat, 10 Sep 2011 17:08:43 +0900 Subject: virt/libvirt: format ephemeral device and add fs label when formating ext3 fs his patch fixes the but reported by ttps://bugs.launchpad.net/bugs/827590 ttps://bugs.launchpad.net/nova/+bug/828357 The ephemeral device is formated as ext3 on Amazon ec2. The new options, vir_mkfs, is introduced. virt_mkfs use the format of = --- nova/virt/disk.py | 41 +++++++++++++++++++++++++++++++++++++++++ nova/virt/libvirt/connection.py | 13 +++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/disk.py b/nova/virt/disk.py index 52b2881e8..2c994626c 100644 --- a/nova/virt/disk.py +++ b/nova/virt/disk.py @@ -52,6 +52,47 @@ flags.DEFINE_integer('timeout_nbd', 10, flags.DEFINE_integer('max_nbd_devices', 16, 'maximum number of possible nbd devices') +# NOTE(yamahata): DEFINE_list() doesn't work because the command may +# include ','. For example, +# mkfs.ext3 -O dir_index,extent -E stride=8,stripe-width=16 +# --label %(fs_label)s %(target)s +# +# DEFINE_list() parses its argument by +# [s.strip() for s in argument.split(self._token)] +# where self._token = ',' +# No escape nor exceptional handling for ','. +# DEFINE_list() doesn't give us what we need. +flags.DEFINE_multistring('virt_mkfs', + ['windows=mkfs.ntfs --fast --label %(fs_label)s ' + '%(target)s', + # NOTE(yamahata): vfat case + #'windows=mkfs.vfat -n %(fs_label)s %(target)s', + 'linux=mkfs.ext3 -L %(fs_label)s -F %(target)s', + 'default=mkfs.ext3 -L %(fs_label)s -F %(target)s'], + 'mkfs commands for ephemeral device. The format is' + '=') + + +_MKFS_COMMAND = {} +_DEFAULT_MKFS_COMMAND = None + + +for s in FLAGS.virt_mkfs: + # NOTE(yamahata): mkfs command may includes '=' for its options. + # So item.partition('=') doesn't work here + os_type, mkfs_command = s.split('=', 1) + if os_type: + _MKFS_COMMAND[os_type] = mkfs_command + if os_type == 'default': + _DEFAULT_MKFS_COMMAND = mkfs_command + + +def mkfs(os_type, fs_label, target): + mkfs_command = (_MKFS_COMMAND.get(os_type, _DEFAULT_MKFS_COMMAND) or + '') % locals() + if mkfs_command: + utils.execute(*mkfs_command.split()) + def extend(image, size): """Increase image to size""" diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 19cef5ad7..6b740d995 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -38,6 +38,7 @@ Supports KVM, LXC, QEMU, UML, and XEN. """ import hashlib +import functools import multiprocessing import netaddr import os @@ -778,6 +779,10 @@ class LibvirtConnection(driver.ComputeDriver): if fs_format: utils.execute('mkfs', '-t', fs_format, target) + def _create_ephemeral(self, target, local_size, fs_label, os_type): + self._create_local(target, local_size) + disk.mkfs(os_type, fs_label, target) + def _create_swap(self, target, swap_gb): """Create a swap file of specified size""" self._create_local(target, swap_gb) @@ -866,9 +871,13 @@ class LibvirtConnection(driver.ComputeDriver): local_size=local_gb) for eph in driver.block_device_info_get_ephemerals(block_device_info): - self._cache_image(fn=self._create_local, + fn = functools.partial(self._create_ephemeral, + fs_label='ephemeral%d' % eph['num'], + os_type=inst.os_type) + self._cache_image(fn=fn, target=basepath(_get_eph_disk(eph)), - fname="local_%s" % eph['size'], + fname="ephemeral_%s_%s_%s" % + (eph['num'], eph['size'], inst.os_type), cow=FLAGS.use_cow_images, local_size=eph['size']) -- cgit From d8abe79da8dde2667936ee97d88d30d5cf0e6d7f Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Sat, 10 Sep 2011 17:11:31 +0900 Subject: api/ec2/ebs: make metadata returns correct swap and ephemeral0 --- nova/virt/libvirt/connection.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 6b740d995..2a6f75d35 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -1111,6 +1111,11 @@ class LibvirtConnection(driver.ComputeDriver): nova_context.get_admin_context(), instance['id'], {'root_device_name': '/dev/' + self.default_root_device}) + if local_device: + db.instance_update( + nova_context.get_admin_context(), instance['id'], + {'default_local_device': '/dev/' + self.default_local_device}) + swap = driver.block_device_info_get_swap(block_device_info) if driver.swap_is_usable(swap): xml_info['swap_device'] = block_device.strip_dev( @@ -1119,6 +1124,9 @@ class LibvirtConnection(driver.ComputeDriver): not self._volume_in_mapping(self.default_swap_device, block_device_info)): xml_info['swap_device'] = self.default_swap_device + db.instance_update( + nova_context.get_admin_context(), instance['id'], + {'default_swap_device': '/dev/' + self.default_swap_device}) config_drive = False if instance.get('config_drive') or instance.get('config_drive_id'): -- cgit From 7ac94ccf7dbb5838ef877b9d954ea96bf1412b4b Mon Sep 17 00:00:00 2001 From: Anthony Young Date: Mon, 12 Sep 2011 00:16:49 -0700 Subject: fix for lp847604 to unbreak instance rebooting --- nova/virt/libvirt/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 19cef5ad7..fb2aed651 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -466,7 +466,7 @@ class LibvirtConnection(driver.ComputeDriver): shutil.rmtree(temp_dir) @exception.wrap_exception() - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, reboot_type): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the -- cgit From 3f92fc99c23b0cc17f31ff9d988733abac98028a Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 13 Sep 2011 12:33:09 -0500 Subject: Inject hostname to xenstore upon creation. --- nova/virt/xenapi/vmops.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index fb9c602d9..15b942a82 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -253,6 +253,8 @@ class VMOps(object): self.create_vifs(vm_ref, instance, network_info) self.inject_network_info(instance, network_info, vm_ref) + self.inject_hostname(vm_ref, instance['hostname']) + return vm_ref def _attach_disks(self, instance, disk_image_type, vm_ref, first_vdi_ref, @@ -1158,6 +1160,12 @@ class VMOps(object): resp = self._make_plugin_call('agent', 'resetnetwork', instance, '', args, vm_ref) + def inject_hostname(self, vm_ref, hostname): + """Inject the hostname of the instance into the xenstore.""" + logging.debug(_("injecting hostname to xs for vm: |%s|"), vm_ref) + self._session.call_xenapi_request("VM.add_to_xenstore_data", + (vm_ref, "vm-data/hostname", hostname)) + def list_from_xenstore(self, vm, path): """ Runs the xenstore-ls command to get a listing of all records -- cgit From 98e2fd764b33fa5a3af6ca982a171717a12ee206 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Tue, 13 Sep 2011 15:33:34 -0500 Subject: Only allow up to 15 chars for a Windows hostname. --- nova/virt/xenapi/vmops.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 15b942a82..6b56d668e 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -253,7 +253,7 @@ class VMOps(object): self.create_vifs(vm_ref, instance, network_info) self.inject_network_info(instance, network_info, vm_ref) - self.inject_hostname(vm_ref, instance['hostname']) + self.inject_hostname(instance, vm_ref, instance['hostname']) return vm_ref @@ -1160,8 +1160,12 @@ class VMOps(object): resp = self._make_plugin_call('agent', 'resetnetwork', instance, '', args, vm_ref) - def inject_hostname(self, vm_ref, hostname): + def inject_hostname(self, instance, vm_ref, hostname): """Inject the hostname of the instance into the xenstore.""" + if instance.os_type == "windows": + # NOTE(jk0): Windows hostnames can only be <= 15 chars. + hostname = hostname[:15] + logging.debug(_("injecting hostname to xs for vm: |%s|"), vm_ref) self._session.call_xenapi_request("VM.add_to_xenstore_data", (vm_ref, "vm-data/hostname", hostname)) -- cgit From 3d88e123624694b557f44cad44335bcadc404631 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 14 Sep 2011 14:38:07 -0700 Subject: fix rescue to use the base image, reset firewall rules, and accept network_info --- nova/virt/libvirt/connection.py | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..c7445fe50 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 @@ -83,9 +83,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') @@ -466,18 +466,22 @@ class LibvirtConnection(driver.ComputeDriver): shutil.rmtree(temp_dir) @exception.wrap_exception() - def reboot(self, instance, network_info): + def reboot(self, instance, network_info, regenerate_xml=False): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the reboot happens, as the guest OS cannot ignore this action. """ + # NOTE(vish): this should accept block device info virt_dom = self._conn.lookupByName(instance['name']) # 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 regenerate_xml: + xml = self.to_xml(instance, network_info, False) + else: + 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... @@ -544,11 +548,17 @@ class LibvirtConnection(driver.ComputeDriver): 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) + 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.firewall_driver.setup_basic_filtering(instance, network_info) + self.firewall_driver.prepare_instance_filter(instance, network_info) self._create_new_domain(xml) + self.firewall_driver.apply_instance_filter(instance, network_info) def _wait_for_rescue(): """Called at an interval until the VM is running again.""" @@ -557,7 +567,7 @@ class LibvirtConnection(driver.ComputeDriver): try: state = self.get_info(instance_name)['state'] except exception.NotFound: - msg = _("During reboot, %s disappeared.") % instance_name + msg = _("During rescue, %s disappeared.") % instance_name LOG.error(msg) raise utils.LoopingCallDone @@ -570,14 +580,15 @@ class LibvirtConnection(driver.ComputeDriver): return timer.start(interval=0.5, now=True) @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) + # NOTE(vish): this should accept block device info + self.reboot(instance, network_info, regenerate_xml=True) @exception.wrap_exception() def poll_rescued_instances(self, timeout): -- cgit From d0daaaa320ecb408e721d5e856676a87d7e98ea6 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Wed, 14 Sep 2011 15:28:22 -0700 Subject: write out xml for rescue --- nova/virt/libvirt/connection.py | 52 +++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 31 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index c7445fe50..56a0f3bb0 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -466,22 +466,20 @@ class LibvirtConnection(driver.ComputeDriver): shutil.rmtree(temp_dir) @exception.wrap_exception() - def reboot(self, instance, network_info, regenerate_xml=False): + def reboot(self, instance, network_info, xml=None): """Reboot a virtual machine, given an instance reference. This method actually destroys and re-creates the domain to ensure the reboot happens, as the guest OS cannot ignore this action. """ - # NOTE(vish): this should accept block device info virt_dom = self._conn.lookupByName(instance['name']) # NOTE(itoumsn): Use XML delived from the running instance # instead of using to_xml(instance, network_info). This is almost # the ultimate stupid workaround. - if regenerate_xml: - xml = self.to_xml(instance, network_info, False) - else: + 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... @@ -545,7 +543,15 @@ class LibvirtConnection(driver.ComputeDriver): data recovery. """ - self.destroy(instance, network_info, cleanup=False) + + 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() xml = self.to_xml(instance, network_info, rescue=True) rescue_images = { @@ -555,29 +561,7 @@ class LibvirtConnection(driver.ComputeDriver): } self._create_image(context, instance, xml, '.rescue', rescue_images, network_info=network_info) - self.firewall_driver.setup_basic_filtering(instance, network_info) - self.firewall_driver.prepare_instance_filter(instance, network_info) - self._create_new_domain(xml) - self.firewall_driver.apply_instance_filter(instance, network_info) - - 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 rescue, %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 - - timer = utils.LoopingCall(_wait_for_rescue) - return timer.start(interval=0.5, now=True) + self.reboot(instance, network_info, xml=xml) @exception.wrap_exception() def unrescue(self, instance, callback, network_info): @@ -587,8 +571,14 @@ class LibvirtConnection(driver.ComputeDriver): simply call reboot. """ - # NOTE(vish): this should accept block device info - self.reboot(instance, network_info, regenerate_xml=True) + 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): -- cgit From 19736d4991ff55f300fddd0ab48af40a081f2272 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Thu, 15 Sep 2011 11:27:16 -0700 Subject: delete the internal libvirt snapshot after it is saved to glance --- nova/virt/libvirt/connection.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 363a20ed0..47e43a7c2 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -464,6 +464,7 @@ class LibvirtConnection(driver.ComputeDriver): # Clean up shutil.rmtree(temp_dir) + snapshot_ptr.delete(0) @exception.wrap_exception() def reboot(self, instance, network_info): -- cgit From e09b3d70e5a4aaa00f5ba62d1eab5d6d57a800e1 Mon Sep 17 00:00:00 2001 From: Vishvananda Ishaya Date: Fri, 16 Sep 2011 08:44:25 -0700 Subject: fix permissions --- nova/virt/libvirt/connection.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 31b08be68..4e91415a7 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -814,8 +814,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'], -- cgit