From becd57467ad54d7887ed5713e814c5b4327dc54b Mon Sep 17 00:00:00 2001 From: Rajat Dhasmana Date: Tue, 2 Jun 2020 09:15:50 +0000 Subject: [PATCH] Don't allow image creation with encrypted nfs volumes With change[1], we will enabled encrypted volume support for cinder nfs driver. Before enabling that, we require handling in cinder consuming projects (like glance_store) to not have unexpected behavior. This patch blocks image creation if the destination volume (in which the image will be written) is an encrypted nfs volume. [1] https://review.opendev.org/#/c/597148/ Closes-Bug: #1884482 Change-Id: I3b4c6782e561f22a7118624e26bf056cd6405a30 --- glance_store/_drivers/cinder.py | 15 +++++++ glance_store/tests/unit/test_cinder_store.py | 42 ++++++++++++++----- ...ncrypted-nfs-volumes-d0ff370ab762042e.yaml | 6 +++ 3 files changed, 52 insertions(+), 11 deletions(-) create mode 100644 releasenotes/notes/block-creating-encrypted-nfs-volumes-d0ff370ab762042e.yaml diff --git a/glance_store/_drivers/cinder.py b/glance_store/_drivers/cinder.py index 7ccb4fc8..33894204 100644 --- a/glance_store/_drivers/cinder.py +++ b/glance_store/_drivers/cinder.py @@ -305,6 +305,11 @@ Possible values: Related options: * None +NOTE: You cannot use an encrypted volume_type associated with an NFS backend. +An encrypted volume stored on an NFS backend will raise an exception whenever +glance_store tries to write or access image data stored in that volume. +Consult your Cinder administrator to determine an appropriate volume_type. + """), cfg.BoolOpt('cinder_enforce_multipath', default=False, @@ -581,6 +586,16 @@ class Store(glance_store.driver.Store): connection_info['driver_volume_type'], root_helper, conn=connection_info) if connection_info['driver_volume_type'] == 'nfs': + if volume.encrypted: + volume.unreserve(volume) + volume.delete() + msg = (_('Encrypted volume creation for cinder nfs is not ' + 'supported from glance_store. Failed to create ' + 'volume %(volume_id)s') + % {'volume_id': volume.id}) + LOG.error(msg) + raise exceptions.BackendException(msg) + @utils.synchronized(connection_info['data']['export']) def connect_volume_nfs(): data = connection_info['data'] diff --git a/glance_store/tests/unit/test_cinder_store.py b/glance_store/tests/unit/test_cinder_store.py index fc699b7c..f90e03ac 100644 --- a/glance_store/tests/unit/test_cinder_store.py +++ b/glance_store/tests/unit/test_cinder_store.py @@ -151,7 +151,8 @@ class TestCinderStore(base.StoreBaseTest, def _test_open_cinder_volume(self, open_mode, attach_mode, error, multipath_supported=False, - enforce_multipath=False): + enforce_multipath=False, + encrypted_nfs=False): self.config(cinder_mount_point_base=None) fake_volume = mock.MagicMock(id=str(uuid.uuid4()), status='available') fake_volumes = FakeObject(get=lambda id: fake_volume, @@ -193,19 +194,35 @@ class TestCinderStore(base.StoreBaseTest, 'get_connector_properties') as mock_conn: if error: self.assertRaises(error, do_open) + elif encrypted_nfs: + fake_volume.initialize_connection.return_value = { + 'driver_volume_type': 'nfs' + } + fake_volume.encrypted = True + try: + with self.store._open_cinder_volume( + fake_client, fake_volume, open_mode): + pass + except exceptions.BackendException: + self.assertEqual(1, + fake_volume.unreserve.call_count) + self.assertEqual(1, + fake_volume.delete.call_count) else: do_open() - mock_conn.assert_called_once_with( - root_helper, socket.gethostname(), multipath_supported, - enforce_multipath) - fake_connector.connect_volume.assert_called_once_with(mock.ANY) - fake_connector.disconnect_volume.assert_called_once_with( - mock.ANY, fake_devinfo) - fake_volume.attach.assert_called_once_with( - None, 'glance_store', attach_mode, - host_name=socket.gethostname()) - fake_volumes.detach.assert_called_once_with(fake_volume) + if not encrypted_nfs: + mock_conn.assert_called_once_with( + root_helper, socket.gethostname(), + multipath_supported, enforce_multipath) + fake_connector.connect_volume.assert_called_once_with( + mock.ANY) + fake_connector.disconnect_volume.assert_called_once_with( + mock.ANY, fake_devinfo) + fake_volume.attach.assert_called_once_with( + None, 'glance_store', attach_mode, + host_name=socket.gethostname()) + fake_volumes.detach.assert_called_once_with(fake_volume) def test_open_cinder_volume_rw(self): self._test_open_cinder_volume('wb', 'rw', None) @@ -228,6 +245,9 @@ class TestCinderStore(base.StoreBaseTest, multipath_supported=True, enforce_multipath=True) + def test_open_cinder_volume_nfs_encrypted(self): + self._test_open_cinder_volume('rb', 'ro', None, encrypted_nfs=True) + def test_cinder_configure_add(self): self.assertRaises(exceptions.BadStoreConfiguration, self.store._check_context, None) diff --git a/releasenotes/notes/block-creating-encrypted-nfs-volumes-d0ff370ab762042e.yaml b/releasenotes/notes/block-creating-encrypted-nfs-volumes-d0ff370ab762042e.yaml new file mode 100644 index 00000000..8459d9b1 --- /dev/null +++ b/releasenotes/notes/block-creating-encrypted-nfs-volumes-d0ff370ab762042e.yaml @@ -0,0 +1,6 @@ +--- +fixes: + - | + `Bug #1884482 `_: + Blocked creation of images on encrypted nfs volumes when glance store + is cinder.