def extend_volume(self, volume, new_size): """Extend an existing volume. :param volume: dictionary volume reference :param new_size: int size in GB to extend :raises InvalidResults: """ nfs_mount = volume.provider_location path = self._get_file_path(nfs_mount, volume.name) # Resize the image file on share to new size. LOG.info("Checking file for resize.") if not self._is_file_size_equal(path, new_size): LOG.info("Resizing file to %(sz)sG", {'sz': new_size}) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): LOG.info("LUN %(id)s extended to %(size)s GB.", { 'id': volume.id, 'size': new_size }) else: msg = _("Resizing image file failed.") LOG.error(msg) raise exception.InvalidResults(msg)
def copy_image_to_volume(self, context, volume, image_service, image_id): """Fetch the image from image_service and write it to the volume.""" image_utils.fetch_to_raw(context, image_service, image_id, self.local_path(volume), self.configuration.volume_dd_blocksize, size=volume['size']) # NOTE (leseb): Set the virtual size of the image # the raw conversion overwrote the destination file # (which had the correct size) # with the fetched glance image size, # thus the initial 'size' parameter is not honored # this sets the size to the one asked in the first place by the user # and then verify the final virtual size image_utils.resize_image(self.local_path(volume), volume['size']) data = image_utils.qemu_img_info(self.local_path(volume)) virt_size = data.virtual_size / units.GiB if virt_size != volume['size']: raise exception.ImageUnacceptable( image_id=image_id, reason=(_("Expected volume size was %d") % volume['size']) + (_(" but size is now %d") % virt_size))
def extend_volume(self, volume, new_size): """Extend an existing volume. :param volume: dictionary volume reference :param new_size: int size in GB to extend """ nfs_mount = self._get_provider_location(volume['id']) path = self._get_volume_path(nfs_mount, volume['name']) # Resize the image file on share to new size. LOG.debug('Checking file for resize') if self._is_file_size_equal(path, new_size): return else: LOG.info(_LI('Resizing file to %sG'), new_size) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): LOG.info( _LI("LUN %(id)s extended to %(size)s GB.") % { 'id': volume['id'], 'size': new_size }) return else: raise exception.InvalidResults( _('Resizing image file failed.'))
def test_extend_volume(self): (mox, drv) = self._mox, self._driver volume = self._simple_volume() volume_path = '%s/%s/volume-%s' % ( self.TEST_MNT_POINT_BASE, drv._get_hash_str(self.TEST_QUOBYTE_VOLUME), self.VOLUME_UUID) qemu_img_info_output = """image: volume-%s file format: qcow2 virtual size: 1.0G (1073741824 bytes) disk size: 473K """ % self.VOLUME_UUID img_info = imageutils.QemuImgInfo(qemu_img_info_output) mox.StubOutWithMock(drv, '_execute') mox.StubOutWithMock(drv, 'get_active_image_from_info') mox.StubOutWithMock(image_utils, 'qemu_img_info') mox.StubOutWithMock(image_utils, 'resize_image') drv.get_active_image_from_info(volume).AndReturn(volume['name']) image_utils.qemu_img_info(volume_path).AndReturn(img_info) image_utils.resize_image(volume_path, 3) mox.ReplayAll() drv.extend_volume(volume, 3) mox.VerifyAll()
def copy_image_to_volume(self, context, volume, image_service, image_id): """Fetch the image from image_service and write it to the volume.""" image_utils.fetch_to_raw(context, image_service, image_id, self.local_path(volume), self.configuration.volume_dd_blocksize, size=volume['size']) # NOTE (leseb): Set the virtual size of the image # the raw conversion overwrote the destination file # (which had the correct size) # with the fetched glance image size, # thus the initial 'size' parameter is not honored # this sets the size to the one asked in the first place by the user # and then verify the final virtual size image_utils.resize_image(self.local_path(volume), volume['size']) data = image_utils.qemu_img_info(self.local_path(volume)) virt_size = data.virtual_size / units.Gi if virt_size != volume['size']: raise exception.ImageUnacceptable( image_id=image_id, reason=(_("Expected volume size was %d") % volume['size']) + (_(" but size is now %d") % virt_size))
def test_extend_volume(self): (mox, drv) = self._mox, self._driver volume = self._simple_volume() volume_path = '%s/%s/volume-%s' % (self.TEST_MNT_POINT_BASE, drv._get_hash_str( self.TEST_QUOBYTE_VOLUME), self.VOLUME_UUID) qemu_img_info_output = """image: volume-%s file format: qcow2 virtual size: 1.0G (1073741824 bytes) disk size: 473K """ % self.VOLUME_UUID img_info = imageutils.QemuImgInfo(qemu_img_info_output) mox.StubOutWithMock(drv, '_execute') mox.StubOutWithMock(drv, 'get_active_image_from_info') mox.StubOutWithMock(image_utils, 'qemu_img_info') mox.StubOutWithMock(image_utils, 'resize_image') drv.get_active_image_from_info(volume).AndReturn(volume['name']) image_utils.qemu_img_info(volume_path).AndReturn(img_info) image_utils.resize_image(volume_path, 3) mox.ReplayAll() drv.extend_volume(volume, 3) mox.VerifyAll()
def test_copy_image_to_volume(self): """resize_image common case usage.""" mox = self._mox drv = self._driver TEST_IMG_SOURCE = 'foo.img' volume = {'size': self.TEST_SIZE_IN_GB, 'name': TEST_IMG_SOURCE} def fake_local_path(volume): return volume['name'] self.stubs.Set(drv, 'local_path', fake_local_path) mox.StubOutWithMock(image_utils, 'fetch_to_raw') image_utils.fetch_to_raw(None, None, None, TEST_IMG_SOURCE) mox.StubOutWithMock(image_utils, 'resize_image') image_utils.resize_image(TEST_IMG_SOURCE, self.TEST_SIZE_IN_GB) mox.StubOutWithMock(image_utils, 'qemu_img_info') data = mox_lib.MockAnything() data.virtual_size = 1024**3 image_utils.qemu_img_info(TEST_IMG_SOURCE).AndReturn(data) mox.ReplayAll() drv.copy_image_to_volume(None, volume, None, None) mox.VerifyAll()
def extend_volume(self, volume, new_size): """Extend an existing volume. :param volume: dictionary volume reference :param new_size: int size in GB to extend """ nfs_mount = self._get_provider_location(volume['id']) path = self._get_volume_path(nfs_mount, volume['name']) # Resize the image file on share to new size. LOG.debug(_('Checking file for resize')) if self._is_file_size_equal(path, new_size): return else: LOG.info(_('Resizing file to %sG'), new_size) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): LOG.info(_("LUN %(id)s extended to %(size)s GB.") % {'id': volume['id'], 'size': new_size}) return else: raise exception.InvalidResults( _('Resizing image file failed.'))
def test_copy_image_to_volume(self): """resize_image common case usage.""" mox = self._mox drv = self._driver TEST_IMG_SOURCE = 'foo.img' volume = {'size': self.TEST_SIZE_IN_GB, 'name': TEST_IMG_SOURCE} def fake_local_path(volume): return volume['name'] self.stubs.Set(drv, 'local_path', fake_local_path) mox.StubOutWithMock(image_utils, 'fetch_to_raw') image_utils.fetch_to_raw(None, None, None, TEST_IMG_SOURCE) mox.StubOutWithMock(image_utils, 'resize_image') image_utils.resize_image(TEST_IMG_SOURCE, self.TEST_SIZE_IN_GB) mox.StubOutWithMock(image_utils, 'qemu_img_info') data = mox_lib.MockAnything() data.virtual_size = 1024 ** 3 image_utils.qemu_img_info(TEST_IMG_SOURCE).AndReturn(data) mox.ReplayAll() drv.copy_image_to_volume(None, volume, None, None) mox.VerifyAll()
def extend_volume(self, volume, new_size): """Extend an existing volume to the new size.""" if self._is_volume_attached(volume): # NOTE(kaisers): no attached extensions until #1870367 is fixed msg = (_("Cannot extend volume %s while it is attached.") % volume['id']) raise exception.ExtendVolumeError(msg) LOG.info('Extending volume %s.', volume.id) extend_by = int(new_size) - volume.size if not self._is_share_eligible(volume.provider_location, extend_by): raise exception.ExtendVolumeError(reason='Insufficient space to' ' extend volume %s to %sG' % (volume.id, new_size)) path = self.local_path(volume) LOG.info('Resizing file to %sG...', new_size) file_format = None admin_metadata = objects.Volume.get_by_id( context.get_admin_context(), volume.id).admin_metadata if admin_metadata and 'format' in admin_metadata: file_format = admin_metadata['format'] image_utils.resize_image(path, new_size, run_as_root=self._execute_as_root, file_format=file_format) if file_format == 'qcow2' and not self._is_file_size_equal( path, new_size): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def test_copy_image_to_volume(self): """resize_image common case usage.""" mox = self._mox drv = self._driver TEST_IMG_SOURCE = "foo.img" volume = {"size": self.TEST_SIZE_IN_GB, "name": TEST_IMG_SOURCE} def fake_local_path(volume): return volume["name"] self.stubs.Set(drv, "local_path", fake_local_path) mox.StubOutWithMock(image_utils, "fetch_to_raw") image_utils.fetch_to_raw(None, None, None, TEST_IMG_SOURCE, mox_lib.IgnoreArg(), size=self.TEST_SIZE_IN_GB) mox.StubOutWithMock(image_utils, "resize_image") image_utils.resize_image(TEST_IMG_SOURCE, self.TEST_SIZE_IN_GB) mox.StubOutWithMock(image_utils, "qemu_img_info") data = mox_lib.MockAnything() data.virtual_size = 1 * units.GiB image_utils.qemu_img_info(TEST_IMG_SOURCE).AndReturn(data) mox.ReplayAll() drv.copy_image_to_volume(None, volume, None, None) mox.VerifyAll()
def _do_extend_volume(self, volume_path, size_gb, volume_format): if volume_format == DISK_FORMAT_PLOOP: self._execute('ploop', 'resize', '-s', '%dG' % size_gb, os.path.join(volume_path, 'DiskDescriptor.xml'), run_as_root=True) else: image_utils.resize_image(volume_path, size_gb) if not self._is_file_size_equal(volume_path, size_gb): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def _do_extend_volume(self, volume_path, size_gb, volume_format): if volume_format == "parallels": self._execute('ploop', 'grow', '-s', '%dG' % size_gb, os.path.join(volume_path, 'DiskDescriptor.xml'), run_as_root=True) volume_path = os.path.join(volume_path, PLOOP_BASE_DELTA_NAME) else: image_utils.resize_image(volume_path, size_gb) if not self._is_file_size_equal(volume_path, size_gb): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def extend_volume(self, volume, size_gb): volume_path = self.local_path(volume) info = self._qemu_img_info(volume_path, volume['name']) backing_fmt = info.file_format if backing_fmt not in ['raw', 'qcow2']: msg = _('Unrecognized backing format: %s') raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files image_utils.resize_image(volume_path, size_gb)
def extend_volume(self, volume, size_gb): volume_path = self._active_volume_path(volume) info = self._qemu_img_info(volume_path, volume.name) backing_fmt = info.file_format if backing_fmt not in ['raw', 'qcow2']: msg = _('Unrecognized backing format: %s') raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files image_utils.resize_image(volume_path, size_gb)
def _resize_image_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.debug(_("Checking file for resize")) if self._is_file_size_equal(path, new_size): return else: LOG.info(_("Resizing file to %sG"), new_size) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): return else: raise exception.InvalidResults(_("Resizing image file failed."))
def _resize_volume_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.info(_('Resizing file to %sG'), new_size) try: image_utils.resize_image(path, new_size) except processutils.ProcessExecutionError as e: msg = (_("Failed to resize volume " "%(volume_id)s, error: %(error)s") % {'volume_id': os.path.basename(path).split('-')[1], 'error': e.stderr}) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) return True
def _resize_volume_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.debug("Resizing file to %sG.", new_size) try: image_utils.resize_image(path, new_size, run_as_root=True) except processutils.ProcessExecutionError as e: msg = (_("Failed to resize volume " "%(volume_id)s, error: %(error)s") % {'volume_id': os.path.basename(path).split('-')[1], 'error': e.stderr}) LOG.error(msg) raise exception.VolumeBackendAPIException(data=msg) return True
def _resize_image_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.debug(_('Checking file for resize')) if self._is_file_size_equal(path, new_size): return else: LOG.info(_('Resizing file to %sG'), new_size) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): return else: raise exception.InvalidResults( _('Resizing image file failed.'))
def extend_volume(self, volume, new_size): """Extend an existing volume to the new size.""" LOG.info(_LI("Extending volume %s."), volume["id"]) extend_by = int(new_size) - volume["size"] if not self._is_share_eligible(volume["provider_location"], extend_by): raise exception.ExtendVolumeError( reason="Insufficient space to" " extend volume %s to %sG" % (volume["id"], new_size) ) path = self.local_path(volume) LOG.info(_LI("Resizing file to %sG..."), new_size) image_utils.resize_image(path, new_size, run_as_root=self._execute_as_root) if not self._is_file_size_equal(path, new_size): raise exception.ExtendVolumeError(reason="Resizing image file failed.")
def test_resize_image(self): mox = self._mox mox.StubOutWithMock(utils, "execute") TEST_IMG_SOURCE = "boobar.img" TEST_IMG_SIZE_IN_GB = 1 utils.execute("qemu-img", "resize", TEST_IMG_SOURCE, "%sG" % TEST_IMG_SIZE_IN_GB, run_as_root=False) mox.ReplayAll() image_utils.resize_image(TEST_IMG_SOURCE, TEST_IMG_SIZE_IN_GB) mox.VerifyAll()
def _resize_image_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.debug('Checking file for resize') if self._is_file_size_equal(path, new_size): return else: LOG.info(_LI('Resizing file to %sG'), new_size) image_utils.resize_image(path, new_size, run_as_root=self._execute_as_root) if self._is_file_size_equal(path, new_size): return else: raise exception.InvalidResults( _('Resizing image file failed.'))
def _resize_volume_file(self, volume, new_size): """Resize volume file to new size.""" vol_path = self.local_path(volume) try: image_utils.resize_image(vol_path, new_size) except processutils.ProcessExecutionError as exc: LOG.error(_("Failed to resize volume " "%(volume_id)s, error: %(error)s") % {'volume_id': volume['id'], 'error': exc.stderr}) raise exception.VolumeBackendAPIException(data=exc.stderr) data = image_utils.qemu_img_info(vol_path) return data.virtual_size
def copy_image_to_volume(self, context, volume, image_service, image_id): """Fetch the image from image_service and write it to the volume. Note that cinder.volume.flows.create_volume will attempt to use clone_image to efficiently create volume from image when both source and target are backed by gpfs storage. If that is not the case, this function is invoked and uses fetch_to_raw to create the volume. """ LOG.debug('Copy image to vol %s using image_utils fetch_to_raw' % volume['id']) image_utils.fetch_to_raw(context, image_service, image_id, self.local_path(volume)) image_utils.resize_image(self.local_path(volume), volume['size'])
def test_extend_volume_with_failure(self): new_vol_size = 15 mox = mox_lib.Mox() volume = test_utils.create_volume(self.context, host=CONF.host) volpath = os.path.join(self.volumes_path, volume['name']) mox.StubOutWithMock(image_utils, 'resize_image') image_utils.resize_image(volpath, new_vol_size).AndRaise( processutils.ProcessExecutionError('error')) mox.ReplayAll() self.assertRaises(exception.VolumeBackendAPIException, self.driver.extend_volume, volume, new_vol_size) mox.VerifyAll()
def extend_volume(self, volume, new_size): """Extend an existing volume to the new size.""" LOG.info(_('Extending volume %s.'), volume['id']) extend_by = int(new_size) - volume['size'] if not self._is_share_eligible(volume['provider_location'], extend_by): raise exception.ExtendVolumeError(reason='Insufficient space to' ' extend volume %s to %sG' % (volume['id'], new_size)) path = self.local_path(volume) LOG.info(_('Resizing file to %sG...'), new_size) image_utils.resize_image(path, new_size) if not self._is_file_size_equal(path, new_size): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def copy_image_to_volume(self, context, volume, image_service, image_id): """Fetch the image from image_service and write it to the volume. Note that cinder.volume.flows.create_volume will attempt to use clone_image to efficiently create volume from image when both source and target are backed by gpfs storage. If that is not the case, this function is invoked and uses fetch_to_raw to create the volume. """ # Check if GPFS is mounted self._verify_gpfs_path_state(self.configuration.gpfs_mount_point_base) LOG.debug("Copy image to vol %s using image_utils fetch_to_raw" % volume["id"]) image_utils.fetch_to_raw(context, image_service, image_id, self.local_path(volume), size=volume["size"]) image_utils.resize_image(self.local_path(volume), volume["size"])
def extend_volume(self, volume, size_gb): volume_path = self.local_path(volume) info = self._qemu_img_info(volume_path, volume.name) backing_fmt = info.file_format if backing_fmt not in ['raw', 'qcow2']: msg = _('Unrecognized backing format: %s') raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files active_path = os.path.join( self._get_mount_point_for_share(volume.provider_location), self.get_active_image_from_info(volume)) image_utils.resize_image(active_path, size_gb)
def test_resize_image(self): mox = self._mox mox.StubOutWithMock(utils, 'execute') TEST_IMG_SOURCE = 'boobar.img' TEST_IMG_SIZE_IN_GB = 1 utils.execute('qemu-img', 'resize', TEST_IMG_SOURCE, '%sG' % TEST_IMG_SIZE_IN_GB, run_as_root=False) mox.ReplayAll() image_utils.resize_image(TEST_IMG_SOURCE, TEST_IMG_SIZE_IN_GB) mox.VerifyAll()
def _clone_image(self, volume, image_location, image_id): """Attempt to create a volume by efficiently copying image to volume. If both source and target are backed by gpfs storage and the source image is in raw format move the image to create a volume using either gpfs clone operation or with a file copy. If the image format is not raw, convert it to raw at the volume path. """ # Check if GPFS is mounted self._verify_gpfs_path_state(self.configuration.gpfs_mount_point_base) cloneable_image, reason, image_path = self._is_cloneable(image_id) if not cloneable_image: LOG.debug('Image %(img)s not cloneable: %(reas)s' % {'img': image_id, 'reas': reason}) return (None, False) vol_path = self.local_path(volume) # if the image is not already a GPFS snap file make it so if not self._is_gpfs_parent_file(image_path): self._create_gpfs_snap(image_path, modebits='666') data = image_utils.qemu_img_info(image_path) # if image format is already raw either clone it or # copy it depending on config file settings if data.file_format == 'raw': if (self.configuration.gpfs_images_share_mode == 'copy_on_write'): LOG.debug('Clone image to vol %s using mmclone' % volume['id']) self._create_gpfs_copy(image_path, vol_path) elif self.configuration.gpfs_images_share_mode == 'copy': LOG.debug('Clone image to vol %s using copyfile' % volume['id']) shutil.copyfile(image_path, vol_path) self._execute('chmod', '666', vol_path, run_as_root=True) # if image is not raw convert it to raw into vol_path destination else: LOG.debug('Clone image to vol %s using qemu convert' % volume['id']) image_utils.convert_image(image_path, vol_path, 'raw') self._execute('chmod', '666', vol_path, run_as_root=True) image_utils.resize_image(vol_path, volume['size']) return {'provider_location': None}, True
def _clone_image(self, volume, image_location, image_id): """Attempt to create a volume by efficiently copying image to volume. If both source and target are backed by gpfs storage and the source image is in raw format move the image to create a volume using either gpfs clone operation or with a file copy. If the image format is not raw, convert it to raw at the volume path. """ # Check if GPFS is mounted self._verify_gpfs_path_state(self.configuration.gpfs_mount_point_base) cloneable_image, reason, image_path = self._is_cloneable(image_id) if not cloneable_image: LOG.debug('Image %(img)s not cloneable: %(reas)s' % { 'img': image_id, 'reas': reason }) return (None, False) vol_path = self.local_path(volume) # if the image is not already a GPFS snap file make it so if not self._is_gpfs_parent_file(image_path): self._create_gpfs_snap(image_path, modebits='666') data = image_utils.qemu_img_info(image_path) # if image format is already raw either clone it or # copy it depending on config file settings if data.file_format == 'raw': if (self.configuration.gpfs_images_share_mode == 'copy_on_write'): LOG.debug('Clone image to vol %s using mmclone' % volume['id']) self._create_gpfs_copy(image_path, vol_path) elif self.configuration.gpfs_images_share_mode == 'copy': LOG.debug('Clone image to vol %s using copyfile' % volume['id']) shutil.copyfile(image_path, vol_path) self._execute('chmod', '666', vol_path, run_as_root=True) # if image is not raw convert it to raw into vol_path destination else: LOG.debug('Clone image to vol %s using qemu convert' % volume['id']) image_utils.convert_image(image_path, vol_path, 'raw') self._execute('chmod', '666', vol_path, run_as_root=True) image_utils.resize_image(vol_path, volume['size']) return {'provider_location': None}, True
def _do_extend_volume(self, volume_path, size_gb, volume_name): info = self._qemu_img_info(volume_path, volume_name) fmt = info.file_format # Note(lpetrut): as for version 2.0, qemu-img cannot resize # vhd/x images. For the moment, we'll just use an intermediary # conversion in order to be able to do the resize. if fmt in (self._DISK_FORMAT_VHDX, self._DISK_FORMAT_VHD_LEGACY): temp_image = volume_path + ".tmp" image_utils.convert_image(volume_path, temp_image, self._DISK_FORMAT_RAW) image_utils.resize_image(temp_image, size_gb) image_utils.convert_image(temp_image, volume_path, fmt) self._delete(temp_image) else: image_utils.resize_image(volume_path, size_gb) if not self._is_file_size_equal(volume_path, size_gb): raise exception.ExtendVolumeError(reason="Resizing image file failed.")
def extend_volume(self, volume, size_gb): volume_path = self.local_path(volume) volume_filename = os.path.basename(volume_path) # Ensure no snapshots exist for the volume active_image = self.get_active_image_from_info(volume) if volume_filename != active_image: msg = _("Extend volume is only supported for this" " driver when no snapshots exist.") raise exception.InvalidVolume(msg) info = self._qemu_img_info(volume_path, volume["name"]) backing_fmt = info.file_format if backing_fmt not in ["raw", "qcow2"]: msg = _("Unrecognized backing format: %s") raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files image_utils.resize_image(volume_path, size_gb)
def _copy_volume_from_snapshot(self, snapshot, volume, volume_size): """Copy data from snapshot to destination volume. This is done with a qemu-img convert to raw/qcow2 from the snapshot qcow2. """ info_path = self._local_path_volume_info(snapshot['volume']) # For BC compat' with version < 2 of this driver try: snap_info = self._read_info_file(info_path) except IOError as exc: if exc.errno != errno.ENOENT: raise else: path_to_snap_img = self.local_path(snapshot) else: vol_path = self._local_volume_dir(snapshot['volume']) forward_file = snap_info[snapshot['id']] forward_path = os.path.join(vol_path, forward_file) # Find the file which backs this file, which represents the point # when this snapshot was created. img_info = self._qemu_img_info(forward_path, snapshot['volume']['name']) path_to_snap_img = os.path.join(vol_path, img_info.backing_file) LOG.debug("will copy from snapshot at %s", path_to_snap_img) path_to_new_vol = self.local_path(volume) out_format = 'raw' image_utils.convert_image(path_to_snap_img, path_to_new_vol, out_format, run_as_root=self._execute_as_root) self._set_rw_permissions_for_all(path_to_new_vol) image_utils.resize_image(path_to_new_vol, volume_size)
def extend_volume(self, volume, size_gb): volume_path = self.local_path(volume) volume_filename = os.path.basename(volume_path) # Ensure no snapshots exist for the volume active_image = self.get_active_image_from_info(volume) if volume_filename != active_image: msg = _('Extend volume is only supported for this' ' driver when no snapshots exist.') raise exception.InvalidVolume(msg) info = self._qemu_img_info(volume_path, volume['name']) backing_fmt = info.file_format if backing_fmt not in ['raw', 'qcow2']: msg = _('Unrecognized backing format: %s') raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files image_utils.resize_image(volume_path, size_gb)
def _do_extend_volume(self, volume_path, size_gb, volume_name): info = self._qemu_img_info(volume_path, volume_name) fmt = info.file_format # Note(lpetrut): as for version 2.0, qemu-img cannot resize # vhd/x images. For the moment, we'll just use an intermediary # conversion in order to be able to do the resize. if fmt in (self._DISK_FORMAT_VHDX, self._DISK_FORMAT_VHD_LEGACY): temp_image = volume_path + '.tmp' image_utils.convert_image(volume_path, temp_image, self._DISK_FORMAT_RAW) image_utils.resize_image(temp_image, size_gb) image_utils.convert_image(temp_image, volume_path, fmt) self._delete(temp_image) else: image_utils.resize_image(volume_path, size_gb) if not self._is_file_size_equal(volume_path, size_gb): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def test_extend_volume(self): new_vol_size = 15 mox = mox_lib.Mox() volume = test_utils.create_volume(self.context, host=CONF.host) volpath = os.path.join(self.volumes_path, volume['name']) qemu_img_info_output = """image: %s file format: raw virtual size: %sG (%s bytes) backing file: %s """ % (volume['name'], new_vol_size, new_vol_size * units.GiB, volpath) mox.StubOutWithMock(image_utils, 'resize_image') image_utils.resize_image(volpath, new_vol_size) mox.StubOutWithMock(image_utils, 'qemu_img_info') img_info = imageutils.QemuImgInfo(qemu_img_info_output) image_utils.qemu_img_info(volpath).AndReturn(img_info) mox.ReplayAll() self.driver.extend_volume(volume, new_vol_size) mox.VerifyAll()
def extend_volume(self, volume, size_gb): if self._is_volume_attached(volume): # NOTE(kaisers): no attached extensions until #1870367 is fixed msg = (_("Cannot extend volume %s while it is attached.") % volume['id']) raise exception.ExtendVolumeError(msg) volume_path = self.local_path(volume) info = self._qemu_img_info(volume_path, volume.name) backing_fmt = info.file_format if backing_fmt not in ['raw', 'qcow2']: msg = _('Unrecognized backing format: %s') raise exception.InvalidVolume(msg % backing_fmt) # qemu-img can resize both raw and qcow2 files active_path = os.path.join( self._get_mount_point_for_share(volume.provider_location), self.get_active_image_from_info(volume)) image_utils.resize_image(active_path, size_gb)
def extend_volume(self, volume, new_size): """Extend an existing volume to the new size.""" if self._is_volume_attached(volume): # NOTE(kaisers): no attached extensions until #1870367 is fixed msg = (_("Cannot extend volume %s while it is attached.") % volume['id']) raise exception.ExtendVolumeError(msg) LOG.info('Extending volume %s.', volume.id) extend_by = int(new_size) - volume.size if not self._is_share_eligible(volume.provider_location, extend_by): raise exception.ExtendVolumeError(reason='Insufficient space to' ' extend volume %s to %sG' % (volume.id, new_size)) path = self.local_path(volume) LOG.info('Resizing file to %sG...', new_size) image_utils.resize_image(path, new_size, run_as_root=self._execute_as_root) if not self._is_file_size_equal(path, new_size): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
def extend_volume(self, volume, new_size): """Extend an existing volume. :param volume: dictionary volume reference :param new_size: int size in GB to extend :raises: InvalidResults """ nfs_mount = volume.provider_location path = self._get_volume_path(nfs_mount, volume.name) # Resize the image file on share to new size. LOG.debug("Checking file for resize") if not self._is_file_size_equal(path, new_size): LOG.info(_LI("Resizing file to %(sz)sG"), {'sz': new_size}) image_utils.resize_image(path, new_size) if self._is_file_size_equal(path, new_size): LOG.info(_LI("LUN %(id)s extended to %(size)s GB."), {'id': volume.id, 'size': new_size}) else: raise exception.InvalidResults(_("Resizing image file failed."))
def _do_extend_volume(self, volume_path, size_gb): image_utils.resize_image(volume_path, size_gb) if not self._is_file_size_equal(volume_path, size_gb): raise exception.ExtendVolumeError( reason='Resizing image file failed.')
if self._discover_file_till_timeout(vol_path): self._set_rw_permissions(vol_path) self._resize_image_file(vol_path, volume['size']) return True raise exception.InvalidResults( _("NFS file could not be discovered.")) def _resize_image_file(self, path, new_size): """Resize the image file on share to new size.""" LOG.debug('Checking file for resize') if self._is_file_size_equal(path, new_size): return else: LOG.info(_LI('Resizing file to %sG'), new_size) image_utils.resize_image(path, new_size, run_as_root=self._execute_as_root) if self._is_file_size_equal(path, new_size): return else: raise exception.InvalidResults( _('Resizing image file failed.')) def _is_file_size_equal(self, path, size): """Checks if file size at path is equal to size.""" data = image_utils.qemu_img_info(path, run_as_root=self._execute_as_root) virt_size = data.virtual_size / units.Gi if virt_size == size: return True else: return False