From 945d566c10877aeaf4d75bc26e161ba3a5f9c4b9 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 27 May 2011 11:10:03 +0900 Subject: compute, virt: support boot-from-volume without ephemeral device and no device This patch implements basic ebs boot support. ephemeral device/no device isn't supported yet. --- nova/virt/driver.py | 2 +- nova/virt/fake.py | 2 +- nova/virt/hyperv.py | 2 +- nova/virt/libvirt.xml.template | 9 ++++++ nova/virt/libvirt_conn.py | 69 +++++++++++++++++++++++++++++++----------- nova/virt/vmwareapi_conn.py | 2 +- nova/virt/xenapi_conn.py | 2 +- 7 files changed, 65 insertions(+), 23 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/driver.py b/nova/virt/driver.py index eb9626d08..773d60855 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -61,7 +61,7 @@ class ComputeDriver(object): """Return a list of InstanceInfo for all registered VMs""" raise NotImplementedError() - def spawn(self, instance, network_info=None): + def spawn(self, instance, network_info=None, block_device_mapping=[]): """Launch a VM for the specified instance""" raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 5ac376e46..093c0f5d2 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -114,7 +114,7 @@ class FakeConnection(driver.ComputeDriver): info_list.append(self._map_to_instance_info(instance)) return info_list - def spawn(self, instance): + def spawn(self, instance, network_info=None, block_device_mapping=[]): """ Create a new instance/VM/domain on the virtualization platform. diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 1142e97a4..216e90016 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -139,7 +139,7 @@ class HyperVConnection(driver.ComputeDriver): return instance_infos - def spawn(self, instance): + def spawn(self, instance, network_info=None, block_device_mapping=[]): """ Create a new VM and start it.""" vm = self._lookup(instance.name) if vm is not None: diff --git a/nova/virt/libvirt.xml.template b/nova/virt/libvirt.xml.template index de2497a76..f7d699a15 100644 --- a/nova/virt/libvirt.xml.template +++ b/nova/virt/libvirt.xml.template @@ -67,11 +67,13 @@ #else + #if not ($getVar('ebs_root', False)) + #end if #if $getVar('local', False) @@ -79,6 +81,13 @@ #end if + #for $vol in $volumes + + + + + + #end for #end if #end if diff --git a/nova/virt/libvirt_conn.py b/nova/virt/libvirt_conn.py index fa918b0a3..3290be603 100644 --- a/nova/virt/libvirt_conn.py +++ b/nova/virt/libvirt_conn.py @@ -39,6 +39,7 @@ Supports KVM, LXC, QEMU, UML, and XEN. import multiprocessing import os import random +import re import shutil import subprocess import sys @@ -207,6 +208,8 @@ def _get_network_info(instance): network_info.append((network, mapping)) return network_info +def _strip_dev(mount_path): + return re.sub(r'^/dev/', '', mount_path) class LibvirtConnection(driver.ComputeDriver): @@ -619,11 +622,13 @@ class LibvirtConnection(driver.ComputeDriver): # NOTE(ilyaalekseyev): Implementation like in multinics # for xenapi(tr3buchet) @exception.wrap_exception - def spawn(self, instance, network_info=None): - xml = self.to_xml(instance, False, network_info) + def spawn(self, instance, network_info=None, block_device_mapping=[]): + xml = self.to_xml(instance, False, network_info=network_info, + block_device_mapping=block_device_mapping) self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) - self._create_image(instance, xml, network_info=network_info) + self._create_image(instance, xml, network_info=network_info, + block_device_mapping=block_device_mapping) domain = self._create_new_domain(xml) LOG.debug(_("instance %s: is running"), instance['name']) self.firewall_driver.apply_instance_filter(instance) @@ -805,7 +810,7 @@ class LibvirtConnection(driver.ComputeDriver): # TODO(vish): should we format disk by default? def _create_image(self, inst, libvirt_xml, suffix='', disk_images=None, - network_info=None): + network_info=None, block_device_mapping=[]): if not network_info: network_info = _get_network_info(inst) @@ -868,16 +873,19 @@ class LibvirtConnection(driver.ComputeDriver): size = None root_fname += "_sm" - self._cache_image(fn=self._fetch_image, - target=basepath('disk'), - fname=root_fname, - cow=FLAGS.use_cow_images, - image_id=disk_images['image_id'], - user=user, - project=project, - size=size) + if not self._volume_in_mapping(self.root_mount_device, + block_device_mapping): + self._cache_image(fn=self._fetch_image, + target=basepath('disk'), + fname=root_fname, + cow=FLAGS.use_cow_images, + image_id=disk_images['image_id'], + user=user, + project=project, + size=size) - if inst_type['local_gb']: + if inst_type['local_gb'] and not self._volume_in_mapping( + self.local_mount_device, block_device_mapping): self._cache_image(fn=self._create_local, target=basepath('disk.local'), fname="local_%s" % inst_type['local_gb'], @@ -992,7 +1000,18 @@ class LibvirtConnection(driver.ComputeDriver): return result - def _prepare_xml_info(self, instance, rescue=False, network_info=None): + root_mount_device = 'vda' # FIXME for now. it's hard coded. + local_mount_device = 'vdb' # FIXME for now. it's hard coded. + def _volume_in_mapping(self, mount_device, block_device_mapping): + mount_device_ = _strip_dev(mount_device) + for vol in block_device_mapping: + vol_mount_device = _strip_dev(vol['mount_device']) + if vol_mount_device == mount_device_: + return True + return False + + def _prepare_xml_info(self, instance, rescue=False, network_info=None, + block_device_mapping=[]): # TODO(adiantum) remove network_info creation code # when multinics will be completed if not network_info: @@ -1010,6 +1029,16 @@ class LibvirtConnection(driver.ComputeDriver): else: driver_type = 'raw' + for vol in block_device_mapping: + vol['mount_device'] = _strip_dev(vol['mount_device']) + ebs_root = self._volume_in_mapping(self.root_mount_device, + block_device_mapping) + if self._volume_in_mapping(self.local_mount_device, + block_device_mapping): + local_gb = False + else: + local_gb = inst_type['local_gb'] + xml_info = {'type': FLAGS.libvirt_type, 'name': instance['name'], 'basepath': os.path.join(FLAGS.instances_path, @@ -1017,9 +1046,11 @@ class LibvirtConnection(driver.ComputeDriver): 'memory_kb': inst_type['memory_mb'] * 1024, 'vcpus': inst_type['vcpus'], 'rescue': rescue, - 'local': inst_type['local_gb'], + 'local': local_gb, 'driver_type': driver_type, - 'nics': nics} + 'nics': nics, + 'ebs_root': ebs_root, + 'volumes': block_device_mapping} if FLAGS.vnc_enabled: if FLAGS.libvirt_type != 'lxc': @@ -1034,10 +1065,12 @@ class LibvirtConnection(driver.ComputeDriver): xml_info['disk'] = xml_info['basepath'] + "/disk" return xml_info - def to_xml(self, instance, rescue=False, network_info=None): + def to_xml(self, instance, rescue=False, network_info=None, + block_device_mapping=[]): # TODO(termie): cache? LOG.debug(_('instance %s: starting toXML method'), instance['name']) - xml_info = self._prepare_xml_info(instance, rescue, network_info) + xml_info = self._prepare_xml_info(instance, rescue, network_info, + block_device_mapping) xml = str(Template(self.libvirt_xml, searchList=[xml_info])) LOG.debug(_('instance %s: finished toXML method'), instance['name']) return xml diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index 1c6d2572d..a36b45d80 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -124,7 +124,7 @@ class VMWareESXConnection(driver.ComputeDriver): """List VM instances.""" return self._vmops.list_instances() - def spawn(self, instance): + def spawn(self, instance, network_info=None, block_device_mapping=[]): """Create VM instance.""" self._vmops.spawn(instance) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 6d828e109..8c5e2201e 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -194,7 +194,7 @@ class XenAPIConnection(driver.ComputeDriver): def list_instances_detail(self): return self._vmops.list_instances_detail() - def spawn(self, instance): + def spawn(self, instance, network_info=None, block_device_mapping=[]): """Create VM instance""" self._vmops.spawn(instance) -- cgit From 25104b5e8570003f82ee1b4d2e5678715cdcc551 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Fri, 27 May 2011 11:11:30 +0900 Subject: unittest: make unit tests happy various fixes to make unit tests pass. --- nova/virt/fake.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 093c0f5d2..498c5ecbb 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -222,6 +222,10 @@ class FakeConnection(driver.ComputeDriver): """ pass + def poll_rescued_instances(self, timeout): + """Poll for rescued instances""" + pass + def migrate_disk_and_power_off(self, instance, dest): """ Transfers the disk of a running instance in multiple phases, turning -- cgit From a66ae006e0a6103ee6db49ad2b8dc4506969178e Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 8 Jun 2011 15:45:23 +0000 Subject: Look for vm_mode property on images and use that if it exists to determine if image should be run in PV or HVM mode. If it doesn't exist, fall back to existing logic --- nova/virt/xenapi/vmops.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 32dae97c2..3b793113f 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -160,9 +160,14 @@ class VMOps(object): # Create the VM ref and attach the first disk first_vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdis[0]['vdi_uuid']) - use_pv_kernel = VMHelper.determine_is_pv(self._session, - instance.id, first_vdi_ref, disk_image_type, - instance.os_type) + if instance.vm_mode in ('pv', 'PV'): + use_pv_kernel = True + elif instance.vm_mode in ('hv', 'HV', 'hvm', 'HVM'): + use_pv_kernel = False + else: + use_pv_kernel = VMHelper.determine_is_pv(self._session, + instance.id, first_vdi_ref, disk_image_type, + instance.os_type) vm_ref = VMHelper.create_vm(self._session, instance, kernel, ramdisk, use_pv_kernel) VMHelper.create_vbd(session=self._session, vm_ref=vm_ref, -- cgit From f20c73bbe395a93c087562966b10ade3c9f32afc Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 8 Jun 2011 22:28:28 +0000 Subject: Normalize and update database with used vm_mode --- nova/virt/xenapi/vmops.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 3b793113f..99d2dc758 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -160,14 +160,24 @@ class VMOps(object): # Create the VM ref and attach the first disk first_vdi_ref = self._session.call_xenapi('VDI.get_by_uuid', vdis[0]['vdi_uuid']) - if instance.vm_mode in ('pv', 'PV'): + + vm_mode = instance.vm_mode and instance.vm_mode.lower() + if vm_mode == 'pv': use_pv_kernel = True - elif instance.vm_mode in ('hv', 'HV', 'hvm', 'HVM'): + elif vm_mode in ('hv', 'hvm'): use_pv_kernel = False + vm_mode = 'hvm' # Normalize else: use_pv_kernel = VMHelper.determine_is_pv(self._session, instance.id, first_vdi_ref, disk_image_type, instance.os_type) + vm_mode = use_pv_kernel and 'pv' or 'hvm' + + if instance.vm_mode != vm_mode: + # Update database with normalized (or determined) value + db.instance_update(context.get_admin_context(), + instance['id'], {'vm_mode': vm_mode}) + vm_ref = VMHelper.create_vm(self._session, instance, kernel, ramdisk, use_pv_kernel) VMHelper.create_vbd(session=self._session, vm_ref=vm_ref, -- cgit From 249279cd7c70a7306ed28a62939477ef94ecbc91 Mon Sep 17 00:00:00 2001 From: Brian Waldon Date: Thu, 9 Jun 2011 15:31:10 -0400 Subject: further changes --- nova/virt/vmwareapi/vmware_images.py | 6 ------ 1 file changed, 6 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/vmwareapi/vmware_images.py b/nova/virt/vmwareapi/vmware_images.py index 48edc5384..70adba74f 100644 --- a/nova/virt/vmwareapi/vmware_images.py +++ b/nova/virt/vmwareapi/vmware_images.py @@ -90,8 +90,6 @@ def fetch_image(image, instance, **kwargs): func = _get_glance_image elif FLAGS.image_service == "nova.image.s3.S3ImageService": func = _get_s3_image - elif FLAGS.image_service == "nova.image.local.LocalImageService": - func = _get_local_image else: raise NotImplementedError(_("The Image Service %s is not implemented") % FLAGS.image_service) @@ -105,8 +103,6 @@ def upload_image(image, instance, **kwargs): func = _put_glance_image elif FLAGS.image_service == "nova.image.s3.S3ImageService": func = _put_s3_image - elif FLAGS.image_service == "nova.image.local.LocalImageService": - func = _put_local_image else: raise NotImplementedError(_("The Image Service %s is not implemented") % FLAGS.image_service) @@ -192,8 +188,6 @@ def get_vmdk_size_and_properties(image, instance): size, properties = meta_data["size"], meta_data["properties"] elif FLAGS.image_service == "nova.image.s3.S3ImageService": raise NotImplementedError - elif FLAGS.image_service == "nova.image.local.LocalImageService": - raise NotImplementedError LOG.debug(_("Got image size of %(size)s for the image %(image)s") % locals()) return size, properties -- cgit From f732831bf4f0c5581b28322d76fb13a17cd65839 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 9 Jun 2011 20:11:55 +0000 Subject: Record architecture of image for matching to agent build later. Add code to automatically update agent running on instance on instance creation. --- nova/virt/xenapi/vmops.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c6d2b0936..f45912867 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -47,6 +47,18 @@ LOG = logging.getLogger("nova.virt.xenapi.vmops") FLAGS = flags.FLAGS +def _cmp_version(a, b): + a = a.split('.') + b = b.split('.') + + for va, vb in zip(a, b): + ret = int(va) - int(vb) + if ret: + return ret + + return len(a) - len(b) + + class VMOps(object): """ Management class for VM-related tasks @@ -203,6 +215,33 @@ class VMOps(object): LOG.info(_('Spawning VM %(instance_name)s created %(vm_ref)s.') % locals()) + ctx = context.get_admin_context() + agent_build = db.agent_build_get_by_triple(ctx, 'xen', + instance.os_type, instance.architecture) + if agent_build: + LOG.info(_('Latest agent build for %s/%s/%s is %s') % ( + agent_build['hypervisor'], agent_build['os'], + agent_build['architecture'], agent_build['version'])) + else: + LOG.info(_('No agent build found for %s/%s/%s') % ( + 'xen', instance.os_type, instance.architecture)) + + def _check_agent_version(): + version = self.get_agent_version(instance) + if not version: + LOG.info(_('No agent version returned by instance')) + return + + LOG.info(_('Instance agent version: %s') % version) + if not agent_build: + return + + if _cmp_version(version, agent_build['version']) < 0: + LOG.info(_('Updating Agent to %s') % agent_build['version']) + ret = self.agent_update(instance, agent_build['url'], + agent_build['md5hash']) + LOG.info('Agent Update returned: %s' % ret) + def _inject_files(): injected_files = instance.injected_files if injected_files: @@ -237,6 +276,7 @@ class VMOps(object): if state == power_state.RUNNING: LOG.debug(_('Instance %s: booted'), instance_name) timer.stop() + _check_agent_version() _inject_files() _set_admin_password() return True @@ -443,6 +483,34 @@ class VMOps(object): task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) self._session.wait_for_task(task, instance.id) + def get_agent_version(self, instance): + """Get the version of the agent running on the VM instance.""" + + # Send the encrypted password + transaction_id = str(uuid.uuid4()) + args = {'id': transaction_id} + resp = self._make_agent_call('version', instance, '', args) + if resp is None: + # No response from the agent + return + resp_dict = json.loads(resp) + return resp_dict['message'] + + def agent_update(self, instance, url, md5sum): + """Update agent on the VM instance.""" + + # Send the encrypted password + transaction_id = str(uuid.uuid4()) + args = {'id': transaction_id, 'url': url, 'md5sum': md5sum} + resp = self._make_agent_call('agentupdate', instance, '', args) + if resp is None: + # No response from the agent + return + resp_dict = json.loads(resp) + if resp_dict['returncode'] != '0': + raise RuntimeError(resp_dict['message']) + return resp_dict['message'] + def set_admin_password(self, instance, new_pass): """Set the root/admin password on the VM instance. -- cgit From fdb1e0e788398e1a29d08d6030709280ca93185c Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 9 Jun 2011 21:52:05 +0000 Subject: Multiple position dependent formats and internationalization don't work well together --- nova/virt/xenapi/vmops.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index f45912867..deebfd9ae 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -219,12 +219,14 @@ class VMOps(object): agent_build = db.agent_build_get_by_triple(ctx, 'xen', instance.os_type, instance.architecture) if agent_build: - LOG.info(_('Latest agent build for %s/%s/%s is %s') % ( - agent_build['hypervisor'], agent_build['os'], - agent_build['architecture'], agent_build['version'])) + LOG.info(_('Latest agent build for %(hypervisor)s/%(os)s' + \ + '/%(architecture)s is %(version)s') % agent_build) else: - LOG.info(_('No agent build found for %s/%s/%s') % ( - 'xen', instance.os_type, instance.architecture)) + LOG.info(_('No agent build found for %(hypervisor)s/%(os)s' + \ + '/%(architecture)s') % { + 'hypervisor': 'xen', + 'os': instance.os_type, + 'architecture': instance.architecture}) def _check_agent_version(): version = self.get_agent_version(instance) -- cgit From fa0b64b500f3a196044459ba4bf8ed0dea214e92 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 9 Jun 2011 22:04:32 +0000 Subject: Add test for agent update --- nova/virt/driver.py | 4 ++++ nova/virt/fake.py | 15 +++++++++++++++ 2 files changed, 19 insertions(+) (limited to 'nova/virt') diff --git a/nova/virt/driver.py b/nova/virt/driver.py index eb9626d08..2229291f2 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -234,6 +234,10 @@ class ComputeDriver(object): """ raise NotImplementedError() + def agent_update(self, instance, url, md5hash): + """Update agent on the VM instance.""" + raise NotImplementedError() + def inject_network_info(self, instance): """inject network info for specified instance""" raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 0225797d7..22fbeefd2 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -225,6 +225,21 @@ class FakeConnection(driver.ComputeDriver): """ pass + def agent_update(self, instance, url, md5hash): + """ + Update agent on the specified instance. + + The first parameter is an instance of nova.compute.service.Instance, + and so the instance is being specified as instance.name. The second + parameter is the URL of the agent to be fetched and updated on the + instance; the third is the md5 hash of the file for verification + purposes. + + The work will be done asynchronously. This function returns a + task that allows the caller to detect when it is complete. + """ + pass + def rescue(self, instance): """ Rescue the specified instance. -- cgit From 2ee3d49e6c35515b9ef9d78365c3bc0ec9236b4b Mon Sep 17 00:00:00 2001 From: Dan Prince Date: Mon, 13 Jun 2011 11:06:25 -0400 Subject: Update xenapi/vm_utils.py so that it calls find_sr instead of get_sr. Remove the old get_sr function which by default looked for an SR named 'slices'. --- nova/virt/xenapi/vm_utils.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index b9d4346e4..cb4da7fdb 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -329,12 +329,6 @@ class VMHelper(HelperBase): 'snap': template_vdi_uuid} return template_vm_ref, template_vdi_uuids - @classmethod - def get_sr(cls, session, sr_label='slices'): - """Finds the SR named by the given name label and returns - the UUID""" - return session.call_xenapi('SR.get_by_name_label', sr_label)[0] - @classmethod def get_sr_path(cls, session): """Return the path to our storage repository @@ -790,8 +784,7 @@ class VMHelper(HelperBase): @classmethod def scan_default_sr(cls, session): """Looks for the system default SR and triggers a re-scan""" - #FIXME(sirp/mdietz): refactor scan_default_sr in there - sr_ref = cls.get_sr(session) + sr_ref = find_sr(session) session.call_xenapi('SR.scan', sr_ref) -- cgit From bebeaa6b0bf69c0a4017d429e79174401df28550 Mon Sep 17 00:00:00 2001 From: Josh Kearney Date: Mon, 13 Jun 2011 15:20:43 -0500 Subject: Removed clocksource=jiffies from PV_args. --- nova/virt/xenapi/vm_utils.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index b9d4346e4..11da221f2 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -157,7 +157,6 @@ class VMHelper(HelperBase): rec['PV_ramdisk'] = ramdisk else: # 2. Use kernel within the image - rec['PV_args'] = 'clocksource=jiffies' rec['PV_bootloader'] = 'pygrub' else: # 3. Using hardware virtualization -- cgit From e89aad7ca0ba7ab5e9b83fa6fd9cde7fb22924bf Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Tue, 14 Jun 2011 17:22:33 +0000 Subject: Really PEP8? A tab is inferior to 2 spaces? --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 624588b6b..d105cf300 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -166,7 +166,7 @@ class VMOps(object): use_pv_kernel = True elif vm_mode in ('hv', 'hvm'): use_pv_kernel = False - vm_mode = 'hvm' # Normalize + vm_mode = 'hvm' # Normalize else: use_pv_kernel = VMHelper.determine_is_pv(self._session, instance.id, first_vdi_ref, disk_image_type, -- cgit From c7e8f9ff46758ddbeecd049083bece013301bb59 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Wed, 15 Jun 2011 14:47:18 +0900 Subject: block_device_mapping: don't use [] as default argument --- nova/virt/driver.py | 2 +- nova/virt/fake.py | 2 +- nova/virt/hyperv.py | 2 +- nova/virt/libvirt/connection.py | 12 ++++++++---- nova/virt/vmwareapi_conn.py | 2 +- nova/virt/xenapi_conn.py | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/driver.py b/nova/virt/driver.py index 773d60855..6341e81d2 100644 --- a/nova/virt/driver.py +++ b/nova/virt/driver.py @@ -61,7 +61,7 @@ class ComputeDriver(object): """Return a list of InstanceInfo for all registered VMs""" raise NotImplementedError() - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): """Launch a VM for the specified instance""" raise NotImplementedError() diff --git a/nova/virt/fake.py b/nova/virt/fake.py index 498c5ecbb..ab85de2e4 100644 --- a/nova/virt/fake.py +++ b/nova/virt/fake.py @@ -114,7 +114,7 @@ class FakeConnection(driver.ComputeDriver): info_list.append(self._map_to_instance_info(instance)) return info_list - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): """ Create a new instance/VM/domain on the virtualization platform. diff --git a/nova/virt/hyperv.py b/nova/virt/hyperv.py index 216e90016..23e25e457 100644 --- a/nova/virt/hyperv.py +++ b/nova/virt/hyperv.py @@ -139,7 +139,7 @@ class HyperVConnection(driver.ComputeDriver): return instance_infos - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): """ Create a new VM and start it.""" vm = self._lookup(instance.name) if vm is not None: diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 0d22d6c41..6300d00a8 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -562,9 +562,10 @@ class LibvirtConnection(driver.ComputeDriver): # NOTE(ilyaalekseyev): Implementation like in multinics # for xenapi(tr3buchet) @exception.wrap_exception - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): xml = self.to_xml(instance, False, network_info=network_info, block_device_mapping=block_device_mapping) + block_device_mapping = block_device_mapping or [] self.firewall_driver.setup_basic_filtering(instance, network_info) self.firewall_driver.prepare_instance_filter(instance, network_info) self._create_image(instance, xml, network_info=network_info, @@ -750,7 +751,8 @@ class LibvirtConnection(driver.ComputeDriver): # TODO(vish): should we format disk by default? def _create_image(self, inst, libvirt_xml, suffix='', disk_images=None, - network_info=None, block_device_mapping=[]): + network_info=None, block_device_mapping=None): + block_device_mapping = block_device_mapping or [] if not network_info: network_info = netutils.get_network_info(inst) @@ -951,7 +953,8 @@ class LibvirtConnection(driver.ComputeDriver): return False def _prepare_xml_info(self, instance, rescue=False, network_info=None, - block_device_mapping=[]): + block_device_mapping=None): + block_device_mapping = block_device_mapping or [] # TODO(adiantum) remove network_info creation code # when multinics will be completed if not network_info: @@ -1006,7 +1009,8 @@ class LibvirtConnection(driver.ComputeDriver): return xml_info def to_xml(self, instance, rescue=False, network_info=None, - block_device_mapping=[]): + block_device_mapping=None): + block_device_mapping = block_device_mapping or [] # TODO(termie): cache? LOG.debug(_('instance %s: starting toXML method'), instance['name']) xml_info = self._prepare_xml_info(instance, rescue, network_info, diff --git a/nova/virt/vmwareapi_conn.py b/nova/virt/vmwareapi_conn.py index a36b45d80..3c6345ec8 100644 --- a/nova/virt/vmwareapi_conn.py +++ b/nova/virt/vmwareapi_conn.py @@ -124,7 +124,7 @@ class VMWareESXConnection(driver.ComputeDriver): """List VM instances.""" return self._vmops.list_instances() - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): """Create VM instance.""" self._vmops.spawn(instance) diff --git a/nova/virt/xenapi_conn.py b/nova/virt/xenapi_conn.py index 8c5e2201e..5fcec1715 100644 --- a/nova/virt/xenapi_conn.py +++ b/nova/virt/xenapi_conn.py @@ -194,7 +194,7 @@ class XenAPIConnection(driver.ComputeDriver): def list_instances_detail(self): return self._vmops.list_instances_detail() - def spawn(self, instance, network_info=None, block_device_mapping=[]): + def spawn(self, instance, network_info=None, block_device_mapping=None): """Create VM instance""" self._vmops.spawn(instance) -- cgit From f48f35183f6bc30c0e053ea9569f5348799ed451 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Wed, 15 Jun 2011 23:11:03 +0900 Subject: pep8 --- nova/virt/libvirt/connection.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/libvirt/connection.py b/nova/virt/libvirt/connection.py index 6300d00a8..a877749e9 100644 --- a/nova/virt/libvirt/connection.py +++ b/nova/virt/libvirt/connection.py @@ -942,8 +942,9 @@ class LibvirtConnection(driver.ComputeDriver): return result - root_mount_device = 'vda' # FIXME for now. it's hard coded. - local_mount_device = 'vdb' # FIXME for now. it's hard coded. + root_mount_device = 'vda' # FIXME for now. it's hard coded. + local_mount_device = 'vdb' # FIXME for now. it's hard coded. + def _volume_in_mapping(self, mount_device, block_device_mapping): mount_device_ = _strip_dev(mount_device) for vol in block_device_mapping: -- cgit From a9eb3a0416b465145ddf765da08bd6d94b191595 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 15 Jun 2011 21:46:22 +0000 Subject: Windows instances will often take a few minutes setting up the image on first boot and then reboot. We should be more patient for those systems as well check if the domid changes so we can send agent requests to the current domid --- nova/virt/xenapi/vmops.py | 60 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 49 insertions(+), 11 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6b61ca9b5..190bf7c20 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -25,6 +25,7 @@ import M2Crypto import os import pickle import subprocess +import time import uuid from nova import context @@ -44,7 +45,10 @@ from nova.virt.xenapi.vm_utils import ImageType XenAPI = None LOG = logging.getLogger("nova.virt.xenapi.vmops") + FLAGS = flags.FLAGS +flags.DEFINE_integer('windows_version_timeout', 300, + 'time to wait for windows agent to be fully operational') def _cmp_version(a, b): @@ -244,7 +248,16 @@ class VMOps(object): 'architecture': instance.architecture}) def _check_agent_version(): - version = self.get_agent_version(instance) + 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, + check_domid_changes=True) + else: + version = self.get_agent_version(instance) if not version: LOG.info(_('No agent version returned by instance')) return @@ -500,18 +513,43 @@ class VMOps(object): task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) self._session.wait_for_task(task, instance.id) - def get_agent_version(self, instance): + def get_agent_version(self, instance, timeout=None, + check_domid_changes=False): """Get the version of the agent running on the VM instance.""" - # Send the encrypted password - transaction_id = str(uuid.uuid4()) - args = {'id': transaction_id} - resp = self._make_agent_call('version', instance, '', args) - if resp is None: - # No response from the agent - return - resp_dict = json.loads(resp) - return resp_dict['message'] + def _call(): + # Send the encrypted password + transaction_id = str(uuid.uuid4()) + args = {'id': transaction_id} + resp = self._make_agent_call('version', instance, '', args) + if resp is None: + # No response from the agent + return + resp_dict = json.loads(resp) + return resp_dict['message'] + + if timeout: + vm_ref = self._get_vm_opaque_ref(instance) + vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) + + domid = vm_rec['domid'] + + timeout = time.time() + timeout + while time.time() < timeout: + ret = _call() + if ret: + return ret + + if check_domid_changes: + 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() def agent_update(self, instance, url, md5sum): """Update agent on the VM instance.""" -- cgit From 357556ce52af91cc4273597c6576bd9da8e5b388 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Wed, 15 Jun 2011 22:18:54 +0000 Subject: Split patch off to new branch instead --- nova/virt/xenapi/vmops.py | 60 +++++++++-------------------------------------- 1 file changed, 11 insertions(+), 49 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 190bf7c20..6b61ca9b5 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -25,7 +25,6 @@ import M2Crypto import os import pickle import subprocess -import time import uuid from nova import context @@ -45,10 +44,7 @@ from nova.virt.xenapi.vm_utils import ImageType XenAPI = None LOG = logging.getLogger("nova.virt.xenapi.vmops") - FLAGS = flags.FLAGS -flags.DEFINE_integer('windows_version_timeout', 300, - 'time to wait for windows agent to be fully operational') def _cmp_version(a, b): @@ -248,16 +244,7 @@ class VMOps(object): 'architecture': instance.architecture}) def _check_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, - check_domid_changes=True) - else: - version = self.get_agent_version(instance) + version = self.get_agent_version(instance) if not version: LOG.info(_('No agent version returned by instance')) return @@ -513,43 +500,18 @@ class VMOps(object): task = self._session.call_xenapi('Async.VM.clean_reboot', vm_ref) self._session.wait_for_task(task, instance.id) - def get_agent_version(self, instance, timeout=None, - check_domid_changes=False): + def get_agent_version(self, instance): """Get the version of the agent running on the VM instance.""" - def _call(): - # Send the encrypted password - transaction_id = str(uuid.uuid4()) - args = {'id': transaction_id} - resp = self._make_agent_call('version', instance, '', args) - if resp is None: - # No response from the agent - return - resp_dict = json.loads(resp) - return resp_dict['message'] - - if timeout: - vm_ref = self._get_vm_opaque_ref(instance) - vm_rec = self._session.get_xenapi().VM.get_record(vm_ref) - - domid = vm_rec['domid'] - - timeout = time.time() + timeout - while time.time() < timeout: - ret = _call() - if ret: - return ret - - if check_domid_changes: - 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() + # Send the encrypted password + transaction_id = str(uuid.uuid4()) + args = {'id': transaction_id} + resp = self._make_agent_call('version', instance, '', args) + if resp is None: + # No response from the agent + return + resp_dict = json.loads(resp) + return resp_dict['message'] def agent_update(self, instance, url, md5sum): """Update agent on the VM instance.""" -- cgit From fb5cc193cfbd9f92ba777bdbcdaae045c982b05a Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Thu, 16 Jun 2011 12:50:55 -0500 Subject: Attempting to retrieve the correct VDI for snapshotting --- nova/virt/xenapi/vm_utils.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 11da221f2..c91a9bab7 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -283,19 +283,16 @@ class VMHelper(HelperBase): @classmethod def get_vdi_for_vm_safely(cls, session, vm_ref): - vdi_refs = VMHelper.lookup_vm_vdis(session, vm_ref) - if vdi_refs is None: - raise Exception(_("No VDIs found for VM %s") % vm_ref) - else: - num_vdis = len(vdi_refs) - if num_vdis != 1: - raise Exception( - _("Unexpected number of VDIs (%(num_vdis)s) found" - " for VM %(vm_ref)s") % locals()) - - vdi_ref = vdi_refs[0] - vdi_rec = session.get_xenapi().VDI.get_record(vdi_ref) - return vdi_ref, vdi_rec + """Retrieves the primary VDI for a VM""" + vbd_refs = session.get_xenapi().VM.get_VBDs(vm_ref) + for vbd in vbd_refs: + vbd_rec = session.get_xenapi().VBD.get_record(vbd) + # Convention dictates the primary VDI will be userdevice 0 + if vbd_rec['userdevice'] == '0': + vdi_rec = session.get_xenapi().VDI.get_record(vbd_rec['VDI']) + return vbd_rec['VDI'], vdi_rec + raise exception.Error(_("No primary VDI found for" + "%(vm_ref)s") % locals()) @classmethod def create_snapshot(cls, session, instance_id, vm_ref, label): -- cgit From 9f62def7b578fc85f85e174a031592a5c4750751 Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Thu, 16 Jun 2011 13:45:55 -0500 Subject: Unit tests pass again --- nova/virt/xenapi/fake.py | 1 + 1 file changed, 1 insertion(+) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/fake.py b/nova/virt/xenapi/fake.py index 113198689..d5ac39473 100644 --- a/nova/virt/xenapi/fake.py +++ b/nova/virt/xenapi/fake.py @@ -146,6 +146,7 @@ def create_vdi(name_label, read_only, sr_ref, sharable): def create_vbd(vm_ref, vdi_ref): vbd_rec = {'VM': vm_ref, 'VDI': vdi_ref, + 'userdevice': '0', 'currently_attached': False} vbd_ref = _create_object('VBD', vbd_rec) after_VBD_create(vbd_ref, vbd_rec) -- cgit From 83df657360fe32315d6a55488de7dccdffa25c90 Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Thu, 16 Jun 2011 13:56:52 -0500 Subject: Added a new test for confirming failure when no primary VDI is present --- nova/virt/xenapi/vm_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index c91a9bab7..7597a0e82 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -879,7 +879,7 @@ def get_vdi_for_vm_safely(session, vm_ref): else: num_vdis = len(vdi_refs) if num_vdis != 1: - raise Exception(_("Unexpected number of VDIs (%(num_vdis)s) found" + raise exception.Exception(_("Unexpected number of VDIs (%(num_vdis)s) found" " for VM %(vm_ref)s") % locals()) vdi_ref = vdi_refs[0] -- cgit From 9ff7bf3c379a3c10ab34c50951cad54659433d65 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 16 Jun 2011 22:30:56 +0000 Subject: Remove debugging statement --- nova/virt/xenapi/vmops.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 6b61ca9b5..e638808c3 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -257,7 +257,6 @@ class VMOps(object): LOG.info(_('Updating Agent to %s') % agent_build['version']) ret = self.agent_update(instance, agent_build['url'], agent_build['md5hash']) - LOG.info('Agent Update returned: %s' % ret) def _inject_files(): injected_files = instance.injected_files -- cgit From a6687f56e0ebb23d59fc4b4097b5877f57312a95 Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Thu, 16 Jun 2011 22:31:14 +0000 Subject: We don't check result in caller, so don't set variable to return value --- nova/virt/xenapi/vmops.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index e638808c3..c3a8fb70e 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -255,7 +255,7 @@ class VMOps(object): if _cmp_version(version, agent_build['version']) < 0: LOG.info(_('Updating Agent to %s') % agent_build['version']) - ret = self.agent_update(instance, agent_build['url'], + self.agent_update(instance, agent_build['url'], agent_build['md5hash']) def _inject_files(): -- cgit From 716e0f8c9c1ee41551e82154de386dfec653218b Mon Sep 17 00:00:00 2001 From: Johannes Erdfelt Date: Fri, 17 Jun 2011 17:32:45 +0000 Subject: Add some documentation for cmp_version Add test cases for cmp_version --- nova/virt/xenapi/vmops.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index c3a8fb70e..2f4286184 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -47,15 +47,18 @@ LOG = logging.getLogger("nova.virt.xenapi.vmops") FLAGS = flags.FLAGS -def _cmp_version(a, b): +def cmp_version(a, b): + """Compare two version strings (eg 0.0.1.10 > 0.0.1.9)""" a = a.split('.') b = b.split('.') + # Compare each individual portion of both version strings for va, vb in zip(a, b): ret = int(va) - int(vb) if ret: return ret + # Fallback to comparing length last return len(a) - len(b) @@ -253,7 +256,7 @@ class VMOps(object): if not agent_build: return - if _cmp_version(version, agent_build['version']) < 0: + if cmp_version(version, agent_build['version']) < 0: LOG.info(_('Updating Agent to %s') % agent_build['version']) self.agent_update(instance, agent_build['url'], agent_build['md5hash']) -- cgit From c5d23693500448b85c727deac364471743363406 Mon Sep 17 00:00:00 2001 From: "matt.dietz@rackspace.com" <> Date: Fri, 17 Jun 2011 12:33:18 -0500 Subject: Missed a pep8 fix --- nova/virt/xenapi/vm_utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/virt') diff --git a/nova/virt/xenapi/vm_utils.py b/nova/virt/xenapi/vm_utils.py index 7597a0e82..5d6aa9ba3 100644 --- a/nova/virt/xenapi/vm_utils.py +++ b/nova/virt/xenapi/vm_utils.py @@ -879,7 +879,8 @@ def get_vdi_for_vm_safely(session, vm_ref): else: num_vdis = len(vdi_refs) if num_vdis != 1: - raise exception.Exception(_("Unexpected number of VDIs (%(num_vdis)s) found" + raise exception.Exception(_("Unexpected number of VDIs" + "(%(num_vdis)s) found" " for VM %(vm_ref)s") % locals()) vdi_ref = vdi_refs[0] -- cgit