[stable/2023.2] [ATMOSPHERE-483] fix: Directly import converted image to RBD (#2071)
This is an automated cherry-pick of #2000
/assign ricolin
diff --git a/images/cinder/patches/cinder/0002-Directly-import-converted-image-to-RBD.patch b/images/cinder/patches/cinder/0002-Directly-import-converted-image-to-RBD.patch
new file mode 100644
index 0000000..f63c4e9
--- /dev/null
+++ b/images/cinder/patches/cinder/0002-Directly-import-converted-image-to-RBD.patch
@@ -0,0 +1,152 @@
+From ddb4c87da6d20cc2cf37db70498f6890db1b2498 Mon Sep 17 00:00:00 2001
+From: ricolin <rlin@vexxhost.com>
+Date: Tue, 22 Oct 2024 18:31:52 +0800
+Subject: [PATCH] Directly import converted image to RBD
+
+For volume encryption from Glance image case,
+once we cloned the image down, we do convert and import back to RBD.
+
+This patch allows us to avoid another tempfile write and directly
+upload image to RBD.
+
+Related-Bug: #2055517
+Change-Id: Ib5e15eeee6a02e2833d14ac34f6fdeb4a6548a67
+---
+ cinder/tests/unit/volume/drivers/test_rbd.py | 2 -
+ cinder/volume/drivers/rbd.py | 57 ++++++++-----------
+ ...verted-encrypt-image-005986a59d1027e1.yaml | 9 +++
+ 3 files changed, 34 insertions(+), 34 deletions(-)
+ create mode 100644 releasenotes/notes/allow-direct-import-converted-encrypt-image-005986a59d1027e1.yaml
+
+diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py
+index 13f67b3d4..291db326d 100644
+--- a/cinder/volume/drivers/rbd.py
++++ b/cinder/volume/drivers/rbd.py
+@@ -32,7 +32,6 @@ from oslo_log import log as logging
+ from oslo_service import loopingcall
+ from oslo_utils import encodeutils
+ from oslo_utils import excutils
+-from oslo_utils import fileutils
+ from oslo_utils import units
+ try:
+ import rados
+@@ -1992,11 +1991,10 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
+ self._copy_image_to_volume(context, volume, image_service, image_id,
+ disable_sparse=disable_sparse)
+
+- def _encrypt_image(self,
+- context: context.RequestContext,
+- volume: Volume,
+- tmp_dir: str,
+- src_image_path: Any) -> None:
++ def _encrypt_image_and_upload(
++ self, context: context.RequestContext,
++ volume: Volume, tmp_dir: str, src_image_path: Any
++ ) -> None:
+ encryption = volume_utils.check_encryption_provider(
+ volume,
+ context)
+@@ -2010,6 +2008,19 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
+ cipher_spec = image_utils.decode_cipher(encryption['cipher'],
+ encryption['key_size'])
+
++ _, conf, user_id, _ = self._get_config_tuple()
++ rbd_options = ''
++ if user_id:
++ rbd_options += f':id={user_id}'
++ if conf:
++ rbd_options += f':conf={conf}'
++
++ rbd_dest = 'rbd:%(pool_name)s/%(image_name)s%(rbd_options)s' % {
++ 'pool_name': self.configuration.rbd_pool,
++ 'image_name': volume.name,
++ 'rbd_options': rbd_options
++ }
++
+ tmp_dir = volume_utils.image_conversion_dir()
+
+ with tempfile.NamedTemporaryFile(prefix='luks_',
+@@ -2017,18 +2028,10 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
+ with open(pass_file.name, 'w') as f:
+ f.write(passphrase)
+
+- # Convert the raw image to luks
+- dest_image_path = src_image_path + '.luks'
+- try:
+- image_utils.convert_image(src_image_path, dest_image_path,
+- 'luks', src_format='raw',
+- cipher_spec=cipher_spec,
+- passphrase_file=pass_file.name)
+-
+- # Replace the original image with the now encrypted image
+- os.rename(dest_image_path, src_image_path)
+- finally:
+- fileutils.delete_if_exists(dest_image_path)
++ image_utils.convert_image(src_image_path, rbd_dest,
++ 'luks', src_format='raw',
++ cipher_spec=cipher_spec,
++ passphrase_file=pass_file.name)
+
+ def _copy_image_to_volume(self,
+ context: context.RequestContext,
+@@ -2047,9 +2050,6 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
+ size=volume.size,
+ disable_sparse=disable_sparse)
+
+- if encrypted:
+- self._encrypt_image(context, volume, tmp_dir, tmp.name)
+-
+ @utils.retry(exception.VolumeIsBusy,
+ self.configuration.rados_connection_interval,
+ self.configuration.rados_connection_retries)
+@@ -2058,17 +2058,21 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
+
+ _delete_volume(volume)
+
+- chunk_size = self.configuration.rbd_store_chunk_size * units.Mi
+- order = int(math.log(chunk_size, 2))
+- # keep using the command line import instead of librbd since it
+- # detects zeroes to preserve sparseness in the image
+- args = ['rbd', 'import',
+- '--pool', self.configuration.rbd_pool,
+- '--order', order,
+- tmp.name, volume.name,
+- '--new-format']
+- args.extend(self._ceph_args())
+- self._try_execute(*args)
++ if encrypted:
++ self._encrypt_image_and_upload(
++ context, volume, tmp_dir, tmp.name)
++ else:
++ chunk_size = self.configuration.rbd_store_chunk_size * units.Mi
++ order = int(math.log(chunk_size, 2))
++ # keep using the command line import instead of librbd since it
++ # detects zeroes to preserve sparseness in the image
++ args = ['rbd', 'import',
++ '--pool', self.configuration.rbd_pool,
++ '--order', order,
++ tmp.name, volume.name,
++ '--new-format']
++ args.extend(self._ceph_args())
++ self._try_execute(*args)
+ self._resize(volume)
+ # We may need to re-enable replication because we have deleted the
+ # original image and created a new one using the command line import.
+diff --git a/releasenotes/notes/allow-direct-import-converted-encrypt-image-005986a59d1027e1.yaml b/releasenotes/notes/allow-direct-import-converted-encrypt-image-005986a59d1027e1.yaml
+new file mode 100644
+index 000000000..b1544214d
+--- /dev/null
++++ b/releasenotes/notes/allow-direct-import-converted-encrypt-image-005986a59d1027e1.yaml
+@@ -0,0 +1,9 @@
++---
++fixes:
++ - |
++ [Bug 255517](https://bugs.launchpad.net/cinder/+bug/2055517): Improve slow
++ on create encrypted volumes with temp file import.
++ For volume encryption from Glance image case, once we cloned the image
++ down, we do convert and import back to RBD. We now avoid another tempfile
++ write and directly upload image to RBD. And it is now directly upload to
++ RBD with qemu-img command without temprory converted image file generated.
+--
+2.25.1
+