def verify_base_size(base, size, base_size=0): """Check that the base image is not larger than size. Since images can't be generally shrunk, enforce this constraint taking account of virtual image size. """ # Note(pbrady): The size and min_disk parameters of a glance # image are checked against the instance size before the image # is even downloaded from glance, but currently min_disk is # adjustable and doesn't currently account for virtual disk size, # so we need this extra check here. # 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. if size is None: return if size and not base_size: base_size = disk.get_disk_size(base) if size < base_size: msg = _('%(base)s virtual size %(base_size)s ' 'larger than flavor root disk size %(size)s') LOG.error(msg % { 'base': base, 'base_size': base_size, 'size': size }) raise exception.FlavorDiskTooSmall()
def create_image(self, prepare_template, base, size, *args, **kwargs): if self.rbd is None: raise RuntimeError(_('rbd python libraries not found')) old_format = True features = 0 if self._supports_layering(): old_format = False features = self.rbd.RBD_FEATURE_LAYERING if not os.path.exists(base): prepare_template(target=base, max_size=size, *args, **kwargs) else: self.verify_base_size(base, size) # keep using the command line import instead of librbd since it # detects zeroes to preserve sparseness in the image args = ['--pool', self.pool, base, self.rbd_name] if self._supports_layering(): args += ['--new-format'] args += self._ceph_args() libvirt_utils.import_rbd_image(*args) base_size = disk.get_disk_size(base) if size and size > base_size: self._resize(self.rbd_name, size)
def verify_base_size(base, size, base_size=0): """Check that the base image is not larger than size. Since images can't be generally shrunk, enforce this constraint taking account of virtual image size. """ # Note(pbrady): The size and min_disk parameters of a glance # image are checked against the instance size before the image # is even downloaded from glance, but currently min_disk is # adjustable and doesn't currently account for virtual disk size, # so we need this extra check here. # 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. if size is None: return if size and not base_size: base_size = disk.get_disk_size(base) if size < base_size: msg = _LE('%(base)s virtual size %(base_size)s ' 'larger than flavor root disk size %(size)s') LOG.error(msg % {'base': base, 'base_size': base_size, 'size': size}) raise exception.FlavorDiskTooSmall()
def create_image(self, prepare_template, base, size, *args, **kwargs): if self.exists(): self.connect_disk() return generating = 'image_id' not in kwargs # NOTE(ft): We assume that only root disk is recreated in rescue mode. # With this assumption the code becomes more simple and fast. if generating: sio_utils.verify_volume_size(size) self.sio_id = self.driver.create_volume(self.sio_name, size, self.extra_specs) self.path = self.driver.map_volume(self.sio_id) prepare_template(target=self.path, is_block_dev=True, *args, **kwargs) else: if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) base_size = disk.get_disk_size(base) if (size is None and sio_utils.is_sio_volume_rescuer(self.sio_name)): size = sio_utils.choose_volume_size(base_size) self.extra_specs = dict(self.extra_specs) self.extra_specs[sio_utils.PROVISIONING_TYPE_KEY] = 'thin' else: sio_utils.verify_volume_size(size) self.verify_base_size(base, size, base_size=base_size) self.sio_id = self.driver.create_volume(self.sio_name, size, self.extra_specs) self.path = self.driver.map_volume(self.sio_id) self.driver.import_image(base, self.path)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) resize = size > base_size size = size if resize else base_size libvirt_utils.create_lvm_image(self.vg, self.lv, size, sparse=self.sparse) images.convert_image(base, self.path, "raw", run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) self.verify_base_size(base, size, base_size=base_size) resize = size > base_size size = size if resize else base_size lvm.create_volume(self.vg, self.lv, size, sparse=self.sparse) images.convert_image(base, self.path, 'raw', run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) resize = size > base_size size = size if resize else base_size libvirt_utils.create_lvm_image(self.vg, self.lv, size, sparse=self.sparse) cmd = ('dd', 'if=%s' % base, 'of=%s' % self.path, 'bs=4M') utils.execute(*cmd, run_as_root=True) if resize: disk.resize2fs(self.path)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) resize = size > base_size size = size if resize else base_size libvirt_utils.create_lvm_image(self.vg, self.lv, size, sparse=self.sparse) cmd = ('dd', 'if=%s' % base, 'of=%s' % self.path, 'bs=4M') utils.execute(*cmd, run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
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_lvm_image(base, size): base_size = disk.get_disk_size(base) self.verify_base_size(base, size, base_size=base_size) resize = size > base_size size = size if resize else base_size lvm.create_volume(self.vg, self.lv, size, sparse=self.sparse) if self.ephemeral_key_uuid is not None: encrypt_lvm_image() images.convert_image(base, self.path, "raw", run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
def test_get_disk_size(self, mock_execute, mock_exists): path = "/some/path" example_output = """image: 00000001 file format: raw virtual size: 4.4M (4592640 bytes) disk size: 4.4M """ mock_execute.return_value = (example_output, "") self.assertEqual(4592640, disk.get_disk_size("/some/path")) mock_execute.assert_called_once_with("env", "LC_ALL=C", "LANG=C", "qemu-img", "info", path) mock_exists.assert_called_once_with(path)
def test_get_disk_size(self, mock_execute, mock_exists): path = '/some/path' example_output = """image: 00000001 file format: raw virtual size: 4.4M (4592640 bytes) disk size: 4.4M """ mock_execute.return_value = (example_output, '') self.assertEqual(4592640, disk.get_disk_size('/some/path')) mock_execute.assert_called_once_with('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', path) mock_exists.assert_called_once_with(path)
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 test_get_disk_size(self): self.mox.StubOutWithMock(os.path, 'exists') self.mox.StubOutWithMock(utils, 'execute') os.path.exists('/some/path').AndReturn(True) utils.execute('env', 'LC_ALL=C', 'LANG=C', 'qemu-img', 'info', '/some/path').AndReturn(('''image: 00000001 file format: raw virtual size: 4.4M (4592640 bytes) disk size: 4.4M''', '')) # Start test self.mox.ReplayAll() self.assertEqual(disk.get_disk_size('/some/path'), 4592640)
def test_get_disk_size(self): self.mox.StubOutWithMock(os.path, "exists") self.mox.StubOutWithMock(utils, "execute") os.path.exists("/some/path").AndReturn(True) utils.execute("env", "LC_ALL=C", "LANG=C", "qemu-img", "info", "/some/path").AndReturn( ( """image: 00000001 file format: raw virtual size: 4.4M (4592640 bytes) disk size: 4.4M""", "", ) ) # Start test self.mox.ReplayAll() self.assertEqual(disk.get_disk_size("/some/path"), 4592640)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) self.verify_base_size(base, size, base_size=base_size) resize = size > base_size size = size if resize else base_size lvm.create_volume(self.vg, self.lv, size, sparse=self.sparse) if self.ephemeral_key_uuid is not None: encrypt_lvm_image() # NOTE: by calling convert_image_unsafe here we're # telling qemu-img convert to do format detection on the input, # because we don't know what the format is. For example, # we might have downloaded a qcow2 image, or created an # ephemeral filesystem locally, we just don't know here. Having # audited this, all current sources have been sanity checked, # either because they're locally generated, or because they have # come from images.fetch_to_raw. However, this is major code smell. images.convert_image_unsafe(base, self.path, self.driver_format, run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
def create_lvm_image(base, size): base_size = disk.get_disk_size(base) self.verify_base_size(base, size, base_size=base_size) resize = size > base_size if size else False size = size if resize else base_size lvm.create_volume(self.vg, self.lv, size, sparse=self.sparse) if self.ephemeral_key_uuid is not None: encrypt_lvm_image() # NOTE: by calling convert_image_unsafe here we're # telling qemu-img convert to do format detection on the input, # because we don't know what the format is. For example, # we might have downloaded a qcow2 image, or created an # ephemeral filesystem locally, we just don't know here. Having # audited this, all current sources have been sanity checked, # either because they're locally generated, or because they have # come from images.fetch_to_raw. However, this is major code smell. images.convert_image_unsafe(base, self.path, self.driver_format, run_as_root=True) if resize: disk.resize2fs(self.path, run_as_root=True)
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) if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) # 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. if size and size < disk.get_disk_size(base): LOG.error("%s virtual size larger than flavor root disk size %s" % (base, size)) raise exception.InstanceTypeDiskTooSmall() if not os.path.exists(self.path): with utils.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) if not os.path.exists(base): prepare_template(target=base, *args, **kwargs) # 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. if size and size < disk.get_disk_size(base): LOG.error('%s virtual size larger than flavor root disk size %s' % (base, size)) raise exception.InstanceTypeDiskTooSmall() if not os.path.exists(self.path): with utils.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): qcow2_base = base if size: size_gb = size / (1024 * 1024 * 1024) qcow2_base += '_%d' % size_gb if not os.path.exists(qcow2_base): with utils.remove_path_on_error(qcow2_base): libvirt_utils.copy_image(base, qcow2_base) disk.extend(qcow2_base, size) libvirt_utils.create_cow_image(qcow2_base, target) prepare_template(target=base, *args, **kwargs) # 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. if size and size < disk.get_disk_size(base): LOG.error('%s virtual size larger than flavor root disk size %s' % (base, size)) raise exception.ImageTooLarge() with utils.remove_path_on_error(self.path): copy_qcow2_image(base, self.path, size)
def get_disk_size(self, name): disk.get_disk_size(name)
def get_disk_size(self, name): return disk.get_disk_size(name)