def test_get_cache_fname(self): # Ensure a known input to this function produces a known output. # This test assures us that, used in the expected manner, the function # doesn't raise an exception in either python2 or python3. It also # serves as a canary to warn if any change in underlying libraries # would produce output incompatible with current usage. # Take a known image_id and the pre-calculated hexdigest of its sha1 image_id = 'fd0cb2f1-8375-44c9-b1f4-3e1f4c4a8ef0' expected_cache_name = '0d5e6b61602d758984b3bf038267614d6016eb2a' cache_name = imagecache.get_cache_fname(image_id) self.assertEqual(expected_cache_name, cache_name)
def pre_launch(self, context, new_instance_ref, network_info=None, block_device_info=None, migration=False, skip_image_service=False, image_refs=[], lvm_info={}): image_base_path = os.path.join(CONF.instances_path, CONF.base_dir_name) if not os.path.exists(image_base_path): LOG.debug('Base path %s does not exist. It will be created now.', image_base_path) mkdir_as(image_base_path, self.openstack_uid) artifact_path = None if not(skip_image_service) and CONF.cobalt_use_image_service: artifact_path = image_base_path # We need to first download the descriptor and the disk files # from the image service. LOG.debug("Downloading images %s from the image service." % (image_refs)) for image_ref in image_refs: image = self.image_service.show(context, image_ref) # In previous versions name was the filename (*.gc, *.disk) so # there was no file_name property. Now that name is more descriptive # when uploaded to glance, file_name property is set; use if possible target = os.path.join(image_base_path, image['properties'].get('file_name',image['name'])) if migration or not os.path.exists(target): # If the path does not exist fetch the data from the image # service. NOTE: We always fetch in the case of a # migration, as the descriptor may have changed from its # previous state. Migrating VMs are the only case where a # descriptor for an instance will not be a fixed constant. # We download to a temporary location so we can make the # file appear atomically from the right user. fd, temp_target = tempfile.mkstemp(dir=image_base_path) try: os.close(fd) self.image_service.download(context, image_ref, temp_target) os.chown(temp_target, self.openstack_uid, self.openstack_gid) os.chmod(temp_target, 0644) os.rename(temp_target, target) except: os.unlink(temp_target) raise libvirt_conn_type = 'migration' if migration else 'launch' libvirt_conn = self.libvirt_connections[libvirt_conn_type] # (dscannell) Check to see if we need to convert the network_info # object into the legacy format. if hasattr(network_info, 'legacy') and libvirt_conn.legacy_nwinfo(): network_info = network_info.legacy() # TODO(dscannell): This method can take an optional image_meta that # appears to be the root disk's image metadata. it checks the metadata # for the image format (e.g. iso, disk, etc). Right now we are passing # in None (default) but we need to double check this. disk_info = blockinfo.get_disk_info(CONF.libvirt_type, new_instance_ref, block_device_info) # We need to create the libvirt xml, and associated files. Pass back # the path to the libvirt.xml file. working_dir = os.path.join(CONF.instances_path, new_instance_ref['uuid']) stubbed_disks = self._stub_disks(libvirt_conn, new_instance_ref, disk_info['mapping'], block_device_info, lvm_info) libvirt_file = os.path.join(working_dir, "libvirt.xml") # Make sure that our working directory exists. mkdir_as(working_dir, self.openstack_uid) # (dscannell) We want to disable any injection. We do this by making a # copy of the instance and clearing out some entries. Since OpenStack # uses dictionary-list accessors, we can pass this dictionary through # that code. instance_dict = dict(new_instance_ref) # The name attribute is special and does not carry over like the rest # of the attributes. instance_dict['key_data'] = None instance_dict['metadata'] = [] for network_ref, mapping in network_info: network_ref['injected'] = False # Stub out an image in the _base directory so libvirt_conn._create_image # doesn't try to download the base image that the master was booted # from, which isn't necessary because a clone's thin-provisioned disk is # overlaid on a disk image accessible via VMS_DISK_URL. Note that we # can't just touch the image's file in _base because master instances # will need the real _base data. So we trick _create_image into using # some bogus id for the image id that'll never be the id of a real # image; the new instance's uuid suffices. disk_images = {'image_id': new_instance_ref['uuid'], 'kernel_id': new_instance_ref['kernel_id'], 'ramdisk_id': new_instance_ref['ramdisk_id']} touch_as(os.path.join(image_base_path, get_cache_fname(disk_images, 'image_id')), self.openstack_uid) # (dscannell) This was taken from the core nova project as part of the # boot path for normal instances. We basically want to mimic this # functionality. # (rui-lin) libvirt_xml parameter was removed from 2013.1 to 2013.1.1 # Check if the parameter is in argument list of _create_image to # decide which method signature to use, and whether to write the xml # file to disk afterwards. if 'libvirt_xml' in inspect.getargspec(libvirt_conn._create_image).args: xml = libvirt_conn.to_xml(instance_dict, network_info, disk_info, block_device_info=block_device_info) libvirt_conn._create_image(context, instance_dict, xml, disk_info['mapping'], network_info=network_info, block_device_info=block_device_info, disk_images=disk_images) else: libvirt_conn._create_image(context, instance_dict, disk_info['mapping'], network_info=network_info, block_device_info=block_device_info, disk_images=disk_images) xml = libvirt_conn.to_xml(instance_dict, network_info, disk_info, block_device_info=block_device_info, write_to_disk=True) if not(migration): for disk_name, disk_file in stubbed_disks.iteritems(): disk_path = disk_file.path if os.path.exists(disk_path) and disk_file.source_type == 'file': # (dscannell) Remove the fake disk file (if created). os.remove(disk_path) # Fix up the permissions on the files that we created so that they are owned by the # openstack user. for root, dirs, files in os.walk(working_dir, followlinks=True): for path in dirs + files: LOG.debug("chowning path=%s to openstack user %s" % \ (os.path.join(root, path), self.openstack_uid)) os.chown(os.path.join(root, path), self.openstack_uid, self.openstack_gid) # Return the libvirt file, this will be passed in as the name. This # parameter is overloaded in the management interface as a libvirt # special case. return (libvirt_file, artifact_path)
def pre_launch(self, context, new_instance_ref, network_info=None, block_device_info=None, migration=False, skip_image_service=False, image_refs=[], lvm_info={}): image_base_path = os.path.join(CONF.instances_path, CONF.base_dir_name) if not os.path.exists(image_base_path): LOG.debug('Base path %s does not exist. It will be created now.', image_base_path) mkdir_as(image_base_path, self.openstack_uid) artifact_path = None if not (skip_image_service) and CONF.cobalt_use_image_service: artifact_path = image_base_path # We need to first download the descriptor and the disk files # from the image service. LOG.debug("Downloading images %s from the image service." % (image_refs)) for image_ref in image_refs: image = self.image_service.show(context, image_ref) # In previous versions name was the filename (*.gc, *.disk) so # there was no file_name property. Now that name is more descriptive # when uploaded to glance, file_name property is set; use if possible target = os.path.join( image_base_path, image['properties'].get('file_name', image['name'])) if migration or not os.path.exists(target): # If the path does not exist fetch the data from the image # service. NOTE: We always fetch in the case of a # migration, as the descriptor may have changed from its # previous state. Migrating VMs are the only case where a # descriptor for an instance will not be a fixed constant. # We download to a temporary location so we can make the # file appear atomically from the right user. fd, temp_target = tempfile.mkstemp(dir=image_base_path) try: os.close(fd) self.image_service.download(context, image_ref, temp_target) os.chown(temp_target, self.openstack_uid, self.openstack_gid) os.chmod(temp_target, 0644) os.rename(temp_target, target) except: os.unlink(temp_target) raise # (dscannell): Determine which libvirt_conn to use. If this is for # migration, and there exists some lvm information, then # use the migration libvirt_conn (that will use the # configured image backend). Otherwise, default to launch # libvirt_conn that will always use a qcow2 backend. It is # safer to use the launch libvirt_conn for a migration if # no lvm_info is given. if migration and len(lvm_info) > 0: libvirt_conn_type = 'migration' else: libvirt_conn_type = 'launch' libvirt_conn = self.libvirt_connections[libvirt_conn_type] # (dscannell) Check to see if we need to convert the network_info # object into the legacy format. if hasattr(network_info, 'legacy') and libvirt_conn.legacy_nwinfo(): network_info = network_info.legacy() # TODO(dscannell): This method can take an optional image_meta that # appears to be the root disk's image metadata. it checks the metadata # for the image format (e.g. iso, disk, etc). Right now we are passing # in None (default) but we need to double check this. disk_info = blockinfo.get_disk_info(CONF.libvirt_type, new_instance_ref, block_device_info) # We need to create the libvirt xml, and associated files. Pass back # the path to the libvirt.xml file. working_dir = os.path.join(CONF.instances_path, new_instance_ref['uuid']) stubbed_disks = self._stub_disks(libvirt_conn, new_instance_ref, disk_info['mapping'], block_device_info, lvm_info) libvirt_file = os.path.join(working_dir, "libvirt.xml") # Make sure that our working directory exists. mkdir_as(working_dir, self.openstack_uid) # (dscannell) We want to disable any injection. We do this by making a # copy of the instance and clearing out some entries. Since OpenStack # uses dictionary-list accessors, we can pass this dictionary through # that code. instance_dict = dict(new_instance_ref) # The name attribute is special and does not carry over like the rest # of the attributes. instance_dict['key_data'] = None instance_dict['metadata'] = [] for network_ref, mapping in network_info: network_ref['injected'] = False # Stub out an image in the _base directory so libvirt_conn._create_image # doesn't try to download the base image that the master was booted # from, which isn't necessary because a clone's thin-provisioned disk is # overlaid on a disk image accessible via VMS_DISK_URL. Note that we # can't just touch the image's file in _base because master instances # will need the real _base data. So we trick _create_image into using # some bogus id for the image id that'll never be the id of a real # image; the new instance's uuid suffices. disk_images = { 'image_id': new_instance_ref['uuid'], 'kernel_id': new_instance_ref['kernel_id'], 'ramdisk_id': new_instance_ref['ramdisk_id'] } touch_as( os.path.join(image_base_path, get_cache_fname(disk_images, 'image_id')), self.openstack_uid) # (dscannell) This was taken from the core nova project as part of the # boot path for normal instances. We basically want to mimic this # functionality. # (rui-lin) libvirt_xml parameter was removed from 2013.1 to 2013.1.1 # Check if the parameter is in argument list of _create_image to # decide which method signature to use, and whether to write the xml # file to disk afterwards. if 'libvirt_xml' in inspect.getargspec( libvirt_conn._create_image).args: xml = libvirt_conn.to_xml(instance_dict, network_info, disk_info, block_device_info=block_device_info) libvirt_conn._create_image(context, instance_dict, xml, disk_info['mapping'], network_info=network_info, block_device_info=block_device_info, disk_images=disk_images) else: libvirt_conn._create_image(context, instance_dict, disk_info['mapping'], network_info=network_info, block_device_info=block_device_info, disk_images=disk_images) xml = libvirt_conn.to_xml(instance_dict, network_info, disk_info, block_device_info=block_device_info, write_to_disk=True) if not (migration): for disk_name, disk_file in stubbed_disks.iteritems(): disk_path = disk_file.path if os.path.exists( disk_path) and disk_file.source_type == 'file': # (dscannell) Remove the fake disk file (if created). os.remove(disk_path) # Fix up the permissions on the files that we created so that they are owned by the # openstack user. for root, dirs, files in os.walk(working_dir, followlinks=True): for path in dirs + files: LOG.debug("chowning path=%s to openstack user %s" % \ (os.path.join(root, path), self.openstack_uid)) os.chown(os.path.join(root, path), self.openstack_uid, self.openstack_gid) # Return the libvirt file, this will be passed in as the name. This # parameter is overloaded in the management interface as a libvirt # special case. return (libvirt_file, artifact_path)