diff --git a/os_brick/encryptors/__init__.py b/os_brick/encryptors/__init__.py index 92aca1b03..064fbd50f 100644 --- a/os_brick/encryptors/__init__.py +++ b/os_brick/encryptors/__init__.py @@ -22,6 +22,23 @@ from oslo_utils import strutils LOG = logging.getLogger(__name__) +LUKS = "luks" +PLAIN = "plain" + +FORMAT_TO_FRONTEND_ENCRYPTOR_MAP = { + LUKS: 'os_brick.encryptors.luks.LuksEncryptor', + PLAIN: 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor' +} + +LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP = { + "os_brick.encryptors.luks.LuksEncryptor": LUKS, + "os_brick.encryptors.cryptsetup.CryptsetupEncryptor": PLAIN, + "os_brick.encryptors.nop.NoopEncryptor": None, + "LuksEncryptor": LUKS, + "CryptsetupEncryptor": PLAIN, + "NoOpEncryptor": None, +} + def get_volume_encryptor(root_helper, connection_info, @@ -43,14 +60,24 @@ def get_volume_encryptor(root_helper, if location and location.lower() == 'front-end': # case insensitive provider = kwargs.get('provider') - if provider == 'LuksEncryptor' or 'LuksEncryptor' in provider: - provider = 'os_brick.encryptors.luks.LuksEncryptor' - elif (provider == 'CryptsetupEncryptor' or - 'CryptsetupEncryptor' in provider): - provider = \ - 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor' - elif (provider == 'NoOpEncryptor' or 'NoOpEncryptor' in provider): - provider = 'os_brick.encryptors.nop.NoOpEncryptor' + # TODO(lyarwood): Remove the following in Pike and raise an + # ERROR if provider is not a key in SUPPORTED_ENCRYPTION_PROVIDERS. + # Until then continue to allow both the class name and path to be used. + if provider in LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP: + LOG.warning(_LW("Use of the in tree encryptor class %(provider)s" + " by directly referencing the implementation class" + " will be blocked in the Pike release of" + " os-brick."), {'provider': provider}) + provider = LEGACY_PROVIDER_CLASS_TO_FORMAT_MAP[provider] + + if provider in FORMAT_TO_FRONTEND_ENCRYPTOR_MAP: + provider = FORMAT_TO_FRONTEND_ENCRYPTOR_MAP[provider] + elif provider is None: + provider = "os_brick.encryptors.nop.NoOpEncryptor" + else: + LOG.warning(_LW("Use of the out of tree encryptor class " + "%(provider)s will be blocked with the Pike " + "release of os-brick."), {'provider': provider}) try: encryptor = importutils.import_object( diff --git a/os_brick/tests/encryptors/test_base.py b/os_brick/tests/encryptors/test_base.py index b9d8d19ed..8609cb9f7 100644 --- a/os_brick/tests/encryptors/test_base.py +++ b/os_brick/tests/encryptors/test_base.py @@ -40,44 +40,42 @@ class VolumeEncryptorTestCase(base.TestCase): class BaseEncryptorTestCase(VolumeEncryptorTestCase): + def _test_get_encryptor(self, provider, expected_provider_class): + encryption = {'control_location': 'front-end', + 'provider': provider} + encryptor = encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + self.assertIsInstance(encryptor, expected_provider_class) + def test_get_encryptors(self): - encryption = {'control_location': 'front-end', - 'provider': 'LuksEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) + self._test_get_encryptor('luks', + encryptors.luks.LuksEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('LuksEncryptor', + encryptors.luks.LuksEncryptor) + self._test_get_encryptor('os_brick.encryptors.luks.LuksEncryptor', + encryptors.luks.LuksEncryptor) - self.assertIsInstance(encryptor, - encryptors.luks.LuksEncryptor, - "encryptor is not an instance of LuksEncryptor") + self._test_get_encryptor('plain', + encryptors.cryptsetup.CryptsetupEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('CryptsetupEncryptor', + encryptors.cryptsetup.CryptsetupEncryptor) + self._test_get_encryptor( + 'os_brick.encryptors.cryptsetup.CryptsetupEncryptor', + encryptors.cryptsetup.CryptsetupEncryptor) - encryption = {'control_location': 'front-end', - 'provider': 'CryptsetupEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) - - self.assertIsInstance(encryptor, - encryptors.cryptsetup.CryptsetupEncryptor, - "encryptor is not an instance of" - "CryptsetupEncryptor") - - encryption = {'control_location': 'front-end', - 'provider': 'NoOpEncryptor'} - encryptor = encryptors.get_volume_encryptor( - root_helper=self.root_helper, - connection_info=self.connection_info, - keymgr=self.keymgr, - **encryption) - - self.assertIsInstance(encryptor, - encryptors.nop.NoOpEncryptor, - "encryptor is not an instance of NoOpEncryptor") + self._test_get_encryptor(None, + encryptors.nop.NoOpEncryptor) + # TODO(lyarwood): Remove the following in Pike + self._test_get_encryptor('NoOpEncryptor', + encryptors.nop.NoOpEncryptor) + self._test_get_encryptor('os_brick.encryptors.nop.NoOpEncryptor', + encryptors.nop.NoOpEncryptor) def test_get_error_encryptors(self): encryption = {'control_location': 'front-end', @@ -106,3 +104,55 @@ class BaseEncryptorTestCase(VolumeEncryptorTestCase): "%(exception)s", {'provider': provider, 'exception': e}) + + @mock.patch('os_brick.encryptors.LOG') + def test_get_missing_out_of_tree_encryptor_log(self, log): + provider = 'TestEncryptor' + encryption = {'control_location': 'front-end', + 'provider': provider} + try: + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + except Exception as e: + log.error.assert_called_once_with("Error instantiating " + "%(provider)s: " + "%(exception)s", + {'provider': provider, + 'exception': e}) + log.warning.assert_called_once_with("Use of the out of tree " + "encryptor class %(provider)s " + "will be blocked with the " + "Pike release of os-brick.", + {'provider': provider}) + + @mock.patch('os_brick.encryptors.LOG') + def test_get_direct_encryptor_log(self, log): + encryption = {'control_location': 'front-end', + 'provider': 'LuksEncryptor'} + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + + encryption = {'control_location': 'front-end', + 'provider': 'os_brick.encryptors.luks.LuksEncryptor'} + encryptors.get_volume_encryptor( + root_helper=self.root_helper, + connection_info=self.connection_info, + keymgr=self.keymgr, + **encryption) + + log.warning.assert_has_calls([ + mock.call("Use of the in tree encryptor class %(provider)s by " + "directly referencing the implementation class will be " + "blocked in the Pike release of os-brick.", + {'provider': 'LuksEncryptor'}), + mock.call("Use of the in tree encryptor class %(provider)s by " + "directly referencing the implementation class will be " + "blocked in the Pike release of os-brick.", + {'provider': + 'os_brick.encryptors.luks.LuksEncryptor'})]) diff --git a/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml b/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml new file mode 100644 index 000000000..ec9fe21d1 --- /dev/null +++ b/releasenotes/notes/introduce-encryption-provider-constants-a7cd0ce58da2bae8.yaml @@ -0,0 +1,14 @@ +--- +features: + - | + Encryption provider constants have been introduced detailing the supported + encryption formats such as LUKs along with their associated in-tree + provider implementations. These constants should now be used to identify an + encryption provider implementation for a given encryption format. +deprecations: + - | + The direct use of the encryption provider classes such as + os_brick.encryptors.luks.LuksEncryptor is now deprecated and will be + blocked in the Pike release of os-brick. The use of out of tree encryption + provider classes is also deprecated and will be blocked in the Pike release + of os-brick.