def _list_backing_images(self): """List the backing images currently in use.""" inuse_images = [] for ent in os.listdir(FLAGS.instances_path): if ent.startswith('instance-'): disk_path = os.path.join(FLAGS.instances_path, ent, 'disk') if os.path.exists(disk_path): backing_file = virtutils.get_disk_backing_file(disk_path) LOG.debug(_('Instance %(instance)s is backed by ' '%(backing)s'), {'instance': ent, 'backing': backing_file}) backing_path = os.path.join(FLAGS.instances_path, '_base', backing_file) if not backing_path in inuse_images: inuse_images.append(backing_path) if backing_path in self.unexplained_images: LOG.warning(_('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 _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) backing_file = virtutils.get_disk_backing_file(disk_path) 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.base_dir_name, backing_file) if backing_path not in inuse_images: inuse_images.append(backing_path) if backing_path in self.unexplained_images: LOG.warning(_('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 _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) backing_file = virtutils.get_disk_backing_file(disk_path) 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.warning( _( "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 _handle_disk_files(self, disk_path, ent, inuse_images): 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) return 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.warning( '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)
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) disk_format = kwargs.get('disk_format', '') if disk_format == 'iso': libvirt_utils.create_image('qcow2', target, size) else: libvirt_utils.create_cow_image(base, target) if size: image = imgmodel.LocalFileImage(target, imgmodel.FORMAT_QCOW2) disk.extend(image, size) # Download the unmodified base image unless we already have a copy. if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) # NOTE(ankit): Update the mtime of the base file so the image # cache manager knows it is in use. libvirt_utils.update_mtime(base) 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) image = imgmodel.LocalFileImage(legacy_base, imgmodel.FORMAT_QCOW2) disk.extend(image, legacy_backing_size) if not os.path.exists(self.path): with fileutils.remove_path_on_error(self.path): copy_qcow2_image(base, self.path, size)
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 create_image(self, prepare_template, base, size, *args, **kwargs): @utils.synchronized(base, 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) # Download the unmodified base image unless we already have a copy. if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) 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 *= 1024 * 1024 * 1024 # 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) # NOTE(cfb): Having a flavor that sets the root size to 0 and having # nova effectively ignore that size and use the size of the # image is considered a feature at this time, not a bug. disk_size = disk.get_disk_size(base) if size and size < disk_size: msg = _('%(base)s virtual size %(disk_size)s' 'larger than flavor root disk size %(size)s') LOG.error(msg % { 'base': base, 'disk_size': disk_size, 'size': size }) raise exception.InstanceTypeDiskTooSmall() if not os.path.exists(self.path): with fileutils.remove_path_on_error(self.path): copy_qcow2_image(base, self.path, size)
def create_image(self, prepare_template, base, size, *args, **kwargs): @utils.synchronized(base, 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, *args, **kwargs) 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 *= 1024 * 1024 * 1024 # 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) # NOTE(cfb): Having a flavor that sets the root size to 0 and having # nova effectively ignore that size and use the size of the # image is considered a feature at this time, not a bug. disk_size = disk.get_disk_size(base) if size and size < disk_size: msg = _('%(base)s virtual size %(disk_size)s' 'larger than flavor root disk size %(size)s') LOG.error(msg % {'base': base, 'disk_size': disk_size, 'size': size}) raise exception.InstanceTypeDiskTooSmall() 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, context): """List the backing images currently in use.""" #TODO:now we just implement it temporarily all_instances=objects.InstanceList.get_by_host(context, self.host) running = self._list_running_instances(context, all_instances) self.instance_names = running['instance_names'] inuse_images = [] for ent in os.listdir(CONF.instances_path): if ent in self.instance_names: disk_path = os.path.join(CONF.instances_path, ent, 'disk') if os.path.exists(disk_path): try: backing_file = libvirt_utils.get_disk_backing_file( disk_path) except processutils.ProcessExecutionError: if not os.path.exists(disk_path): continue else: raise if backing_file: if backing_file not in inuse_images: inuse_images.append(backing_file) backing_path = os.path.join( CONF.instances_path, CONF.image_cache_subdirectory_name, backing_file) try: base_file = libvirt_utils.get_disk_backing_file( backing_path) except processutils.ProcessExecutionError: if not os.path.exists(backing_path): continue else: raise if base_file and base_file not in inuse_images: inuse_images.append(base_file) 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: image = imgmodel.LocalFileImage(target, imgmodel.FORMAT_QCOW2) disk.extend(image, size) # 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) # NOTE(ankit): Update the mtime of the base file so the image # cache manager knows it is in use. libvirt_utils.update_mtime(base) 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) image = imgmodel.LocalFileImage(legacy_base, imgmodel.FORMAT_QCOW2) disk.extend(image, legacy_backing_size) if not os.path.exists(self.path): with fileutils.remove_path_on_error(self.path): copy_qcow2_image(base, self.path, size)
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 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_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.stub_out('nova.utils.execute', fake_execute) self.stub_out('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): 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}) self.mox.StubOutWithMock(os.path, "exists") self.mox.StubOutWithMock(utils, "execute") os.path.exists(path).AndReturn(True) utils.execute("env", "LC_ALL=C", "LANG=C", "qemu-img", "info", path).AndReturn((output, "")) self.mox.ReplayAll() d_backing = libvirt_utils.get_disk_backing_file(path) self.assertIsNone(d_backing)
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 test_disk_backing(self): 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, }) self.mox.StubOutWithMock(utils, 'execute') utils.execute('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path).AndReturn((output, '')) self.mox.ReplayAll() d_backing = libvirt_utils.get_disk_backing_file(path) self.assertEquals(None, d_backing)
def create_image(self, prepare_template, base, size, *args, **kwargs): filename = os.path.split(base)[-1] @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) else: 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.warning( _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 = os.path.split(base)[-1] @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) else: 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 test_disk_backing(self): 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, }) self.mox.StubOutWithMock(os.path, 'exists') self.mox.StubOutWithMock(utils, 'execute') os.path.exists(path).AndReturn(True) utils.execute('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path).AndReturn((output, '')) self.mox.ReplayAll() d_backing = libvirt_utils.get_disk_backing_file(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 _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 = virtutils.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.warning( _( "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