def test_get_disk_backing_file(self): with_actual_path = False def fake_execute(*args, **kwargs): if with_actual_path: return ("some: output\n" "backing file: /foo/bar/baz (actual path: /a/b/c)\n" "...: ...\n"), '' else: return ("some: output\n" "backing file: /foo/bar/baz\n" "...: ...\n"), '' def return_true(*args, **kwargs): return True self.stubs.Set(utils, 'execute', fake_execute) self.stubs.Set(os.path, 'exists', return_true) out = libvirt_utils.get_disk_backing_file('') self.assertEqual(out, 'baz') with_actual_path = True out = libvirt_utils.get_disk_backing_file('') self.assertEqual(out, 'c')
def test_disk_backing(self, mock_execute, mock_exists): path = '/myhome/disk.config' template_output = """image: %(path)s file format: raw virtual size: 2K (2048 bytes) cluster_size: 65536 disk size: 96K """ output = template_output % ({ 'path': path, }) mock_execute.return_value = (output, '') d_backing = libvirt_utils.get_disk_backing_file(path) mock_execute.assert_called_once_with('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) mock_exists.assert_called_once_with(path) self.assertIsNone(d_backing)
def _list_backing_images(self): """List the backing images currently in use.""" inuse_images = [] for ent in os.listdir(CONF.instances_path): if ent in self.instance_names: LOG.debug('%s is a valid instance name', ent) disk_path = os.path.join(CONF.instances_path, ent, 'disk') if os.path.exists(disk_path): LOG.debug('%s has a disk file', ent) try: backing_file = libvirt_utils.get_disk_backing_file( disk_path) except processutils.ProcessExecutionError: # (for bug 1261442) if not os.path.exists(disk_path): LOG.debug('Failed to get disk backing file: %s', disk_path) continue else: raise LOG.debug( 'Instance %(instance)s is backed by ' '%(backing)s', { 'instance': ent, 'backing': backing_file }) if backing_file: backing_path = os.path.join( CONF.instances_path, CONF.image_cache_subdirectory_name, backing_file) if backing_path not in inuse_images: inuse_images.append(backing_path) if backing_path in self.unexplained_images: LOG.warn( _LW('Instance %(instance)s is using a ' 'backing file %(backing)s which ' 'does not appear in the image ' 'service'), { 'instance': ent, 'backing': backing_file }) self.unexplained_images.remove(backing_path) return inuse_images
def create_image(self, prepare_template, base, size, *args, **kwargs): filename = self._get_lock_name(base) @utils.synchronized(filename, external=True, lock_path=self.lock_path) def copy_qcow2_image(base, target, size): # TODO(pbrady): Consider copying the cow image here # with preallocation=metadata set for performance reasons. # This would be keyed on a 'preallocate_images' setting. libvirt_utils.create_cow_image(base, target) if size: disk.extend(target, size, use_cow=True) # Download the unmodified base image unless we already have a copy. if not os.path.exists(base): prepare_template(target=base, max_size=size, *args, **kwargs) self.verify_base_size(base, size) legacy_backing_size = None legacy_base = base # Determine whether an existing qcow2 disk uses a legacy backing by # actually looking at the image itself and parsing the output of the # backing file it expects to be using. if os.path.exists(self.path): backing_path = libvirt_utils.get_disk_backing_file(self.path) if backing_path is not None: backing_file = os.path.basename(backing_path) backing_parts = backing_file.rpartition('_') if backing_file != backing_parts[-1] and \ backing_parts[-1].isdigit(): legacy_backing_size = int(backing_parts[-1]) legacy_base += '_%d' % legacy_backing_size legacy_backing_size *= units.Gi # Create the legacy backing file if necessary. if legacy_backing_size: if not os.path.exists(legacy_base): with fileutils.remove_path_on_error(legacy_base): libvirt_utils.copy_image(base, legacy_base) disk.extend(legacy_base, legacy_backing_size, use_cow=True) if not os.path.exists(self.path): with fileutils.remove_path_on_error(self.path): copy_qcow2_image(base, self.path, size)
def _list_backing_images(self): """List the backing images currently in use.""" inuse_images = [] for ent in os.listdir(CONF.instances_path): if ent in self.instance_names: LOG.debug('%s is a valid instance name', ent) disk_path = os.path.join(CONF.instances_path, ent, 'disk') if os.path.exists(disk_path): LOG.debug('%s has a disk file', ent) try: backing_file = libvirt_utils.get_disk_backing_file( disk_path) except processutils.ProcessExecutionError: # (for bug 1261442) if not os.path.exists(disk_path): LOG.debug('Failed to get disk backing file: %s', disk_path) continue else: raise LOG.debug('Instance %(instance)s is backed by ' '%(backing)s', {'instance': ent, 'backing': backing_file}) if backing_file: backing_path = os.path.join( CONF.instances_path, CONF.image_cache_subdirectory_name, backing_file) if backing_path not in inuse_images: inuse_images.append(backing_path) if backing_path in self.unexplained_images: LOG.warn(_LW('Instance %(instance)s is using a ' 'backing file %(backing)s which ' 'does not appear in the image ' 'service'), {'instance': ent, 'backing': backing_file}) self.unexplained_images.remove(backing_path) return inuse_images