diff --git a/compute_hyperv/nova/pdk.py b/compute_hyperv/nova/pdk.py index 40a3ac39..eb3bf908 100644 --- a/compute_hyperv/nova/pdk.py +++ b/compute_hyperv/nova/pdk.py @@ -1,79 +1,79 @@ -# Copyright 2016 Cloudbase Solutions Srl -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from barbicanclient import client as barbican_client -from keystoneauth1 import session -from nova import exception -from os_win._i18n import _ - - -class PDK(object): - - def create_pdk(self, context, instance, image_meta, pdk_filepath): - """Generates a pdk file using the barbican container referenced by - the image metadata or instance metadata. A pdk file is a shielding - data file which contains a RDP certificate, unattended file, - volume signature catalogs and guardian metadata. - """ - - with open(pdk_filepath, 'wb') as pdk_file_handle: - pdk_reference = self._get_pdk_reference(instance, image_meta) - pdk_container = self._get_pdk_container(context, instance, - pdk_reference) - pdk_data = self._get_pdk_data(pdk_container) - pdk_file_handle.write(pdk_data) - - def _get_pdk_reference(self, instance, image_meta): - image_pdk_ref = image_meta['properties'].get('img_pdk_reference') - boot_metadata_pdk_ref = instance.metadata.get('img_pdk_reference') - - if not (image_pdk_ref or boot_metadata_pdk_ref): - reason = _('A reference to a barbican container containing the ' - 'pdk file must be passed as an image property. This ' - 'is required in order to enable VTPM') - raise exception.InstanceUnacceptable(instance_id=instance.uuid, - reason=reason) - return boot_metadata_pdk_ref or image_pdk_ref - - def _get_pdk_container(self, context, instance, pdk_reference): - """Retrieves the barbican container containing the pdk file. - """ - - auth = context.get_auth_plugin() - sess = session.Session(auth=auth) - brb_client = barbican_client.Client(session=sess) - - try: - pdk_container = brb_client.containers.get(pdk_reference) - except Exception as e: - err_msg = _("Retrieving barbican container with reference " - "%(pdk_reference)s failed with error: %(error)s") % { - 'pdk_reference': pdk_reference, - 'error': e} - raise exception.InvalidMetadata(instance_id=instance.uuid, - reason=err_msg) - return pdk_container - - def _get_pdk_data(self, pdk_container): - """Return the data from all barbican container's secrets. - """ - - no_of_secrets = len(pdk_container.secrets) - data = bytes() - for index in range(no_of_secrets): - current_secret = pdk_container.secrets[str(index + 1)] - retrived_secret_data = current_secret.payload - data += retrived_secret_data - return data +# Copyright 2016 Cloudbase Solutions Srl +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from barbicanclient import client as barbican_client +from keystoneauth1 import session +from nova import exception +from os_win._i18n import _ + + +class PDK(object): + + def create_pdk(self, context, instance, image_meta, pdk_filepath): + """Generates a pdk file using the barbican container referenced by + the image metadata or instance metadata. A pdk file is a shielding + data file which contains a RDP certificate, unattended file, + volume signature catalogs and guardian metadata. + """ + + with open(pdk_filepath, 'wb') as pdk_file_handle: + pdk_reference = self._get_pdk_reference(instance, image_meta) + pdk_container = self._get_pdk_container(context, instance, + pdk_reference) + pdk_data = self._get_pdk_data(pdk_container) + pdk_file_handle.write(pdk_data) + + def _get_pdk_reference(self, instance, image_meta): + image_pdk_ref = image_meta['properties'].get('img_pdk_reference') + boot_metadata_pdk_ref = instance.metadata.get('img_pdk_reference') + + if not (image_pdk_ref or boot_metadata_pdk_ref): + reason = _('A reference to a barbican container containing the ' + 'pdk file must be passed as an image property. This ' + 'is required in order to enable VTPM') + raise exception.InstanceUnacceptable(instance_id=instance.uuid, + reason=reason) + return boot_metadata_pdk_ref or image_pdk_ref + + def _get_pdk_container(self, context, instance, pdk_reference): + """Retrieves the barbican container containing the pdk file. + """ + + auth = context.get_auth_plugin() + sess = session.Session(auth=auth) + brb_client = barbican_client.Client(session=sess) + + try: + pdk_container = brb_client.containers.get(pdk_reference) + except Exception as e: + err_msg = _("Retrieving barbican container with reference " + "%(pdk_reference)s failed with error: %(error)s") % { + 'pdk_reference': pdk_reference, + 'error': e} + raise exception.InvalidMetadata(instance_id=instance.uuid, + reason=err_msg) + return pdk_container + + def _get_pdk_data(self, pdk_container): + """Return the data from all barbican container's secrets. + """ + + no_of_secrets = len(pdk_container.secrets) + data = bytes() + for index in range(no_of_secrets): + current_secret = pdk_container.secrets[str(index + 1)] + retrived_secret_data = current_secret.payload + data += retrived_secret_data + return data diff --git a/compute_hyperv/tests/unit/test_pdk.py b/compute_hyperv/tests/unit/test_pdk.py index bff6857a..0c0b20d4 100644 --- a/compute_hyperv/tests/unit/test_pdk.py +++ b/compute_hyperv/tests/unit/test_pdk.py @@ -1,130 +1,130 @@ -# Copyright 2016 Cloudbase Solutions Srl -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from nova import exception - -from compute_hyperv.nova import pdk -from compute_hyperv.tests.unit import test_base -from six.moves import builtins - - -class PDKTestCase(test_base.HyperVBaseTestCase): - - _FAKE_PDK_FILE_PATH = 'C:\\path\\to\\fakepdk.pdk' - - def setUp(self): - super(PDKTestCase, self).setUp() - self._pdk = pdk.PDK() - - @mock.patch.object(builtins, 'open') - @mock.patch.object(pdk.PDK, '_get_pdk_data') - @mock.patch.object(pdk.PDK, '_get_pdk_container') - @mock.patch.object(pdk.PDK, '_get_pdk_reference') - def test_create_pdk(self, mock_get_pdk_reference, mock_get_pdk_container, - mock_get_pdk_data, mock_open): - mock_instance = mock.MagicMock() - pdk_file_handle = mock_open.return_value.__enter__.return_value - - pdk_reference = mock_get_pdk_reference.return_value - pdk_container = mock_get_pdk_container.return_value - - self._pdk.create_pdk(mock.sentinel.context, - mock_instance, - mock.sentinel.image_meta, - self._FAKE_PDK_FILE_PATH) - mock_get_pdk_reference.assert_called_once_with( - mock_instance, mock.sentinel.image_meta) - mock_get_pdk_container.assert_called_once_with(mock.sentinel.context, - mock_instance, - pdk_reference) - mock_get_pdk_data.assert_called_once_with(pdk_container) - pdk_file_handle.write.assert_called_once_with( - mock_get_pdk_data.return_value) - - def _test_get_pdk_reference(self, pdk_reference=None, - image_meta_pdk_ref=None): - mock_instance = mock.MagicMock( - metadata={'img_pdk_reference': image_meta_pdk_ref}) - image_meta = { - 'properties': {'img_pdk_reference': pdk_reference}} - - expected_result = image_meta_pdk_ref or pdk_reference - result = self._pdk._get_pdk_reference(mock_instance, - image_meta) - self.assertEqual(expected_result, result) - - def test_get_pdk_boot_reference(self): - self._test_get_pdk_reference( - image_meta_pdk_ref=mock.sentinel.image_meta_pdk_ref) - - def test_get_pdk_image_reference(self): - self._test_get_pdk_reference(pdk_reference=mock.sentinel.pdk_reference) - - def test_get_pdk_no_reference(self): - image_meta = {'properties': {}} - mock_instance = mock.MagicMock(metadata={}) - - self.assertRaises(exception.InstanceUnacceptable, - self._pdk._get_pdk_reference, - mock_instance, image_meta) - - @mock.patch('barbicanclient.client.Client') - @mock.patch('keystoneauth1.session.Session') - def test_get_pdk_container(self, mock_session, mock_barbican_client): - instance = mock.MagicMock() - context = mock.MagicMock() - auth = context.get_auth_plugin.return_value - sess = mock_session.return_value - barbican_client = mock_barbican_client.return_value - barbican_client.containers.get.return_value = ( - mock.sentinel.pdk_container) - - result = self._pdk._get_pdk_container(context, instance, - mock.sentinel.pdk_reference) - - self.assertEqual(mock.sentinel.pdk_container, result) - mock_session.assert_called_once_with(auth=auth) - mock_barbican_client.assert_called_once_with(session=sess) - - @mock.patch('barbicanclient.client.Client') - @mock.patch('keystoneauth1.session.Session') - def test_get_pdk_container_exception(self, mock_session, - mock_barbican_client): - instance = mock.MagicMock() - context = mock.MagicMock() - auth = context.get_auth_plugin.return_value - sess = mock_session.return_value - - barbican_client = mock_barbican_client.return_value - barbican_client.containers.get.side_effect = [ - exception.InvalidMetadata] - - self.assertRaises(exception.InvalidMetadata, - self._pdk._get_pdk_container, - context, - instance, - mock.sentinel.pdk_reference) - mock_session.assert_called_once_with(auth=auth) - mock_barbican_client.assert_called_once_with(session=sess) - - def test_get_pdk_data(self): - pdk_container = mock.MagicMock() - pdk_container.secrets = {'1': mock.MagicMock(payload=b'fake_secret1'), - '2': mock.MagicMock(payload=b'fake_secret2')} - - response = self._pdk._get_pdk_data(pdk_container) - expected_result = b'fake_secret1fake_secret2' - self.assertEqual(expected_result, response) +# Copyright 2016 Cloudbase Solutions Srl +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import mock +from nova import exception + +from compute_hyperv.nova import pdk +from compute_hyperv.tests.unit import test_base +from six.moves import builtins + + +class PDKTestCase(test_base.HyperVBaseTestCase): + + _FAKE_PDK_FILE_PATH = 'C:\\path\\to\\fakepdk.pdk' + + def setUp(self): + super(PDKTestCase, self).setUp() + self._pdk = pdk.PDK() + + @mock.patch.object(builtins, 'open') + @mock.patch.object(pdk.PDK, '_get_pdk_data') + @mock.patch.object(pdk.PDK, '_get_pdk_container') + @mock.patch.object(pdk.PDK, '_get_pdk_reference') + def test_create_pdk(self, mock_get_pdk_reference, mock_get_pdk_container, + mock_get_pdk_data, mock_open): + mock_instance = mock.MagicMock() + pdk_file_handle = mock_open.return_value.__enter__.return_value + + pdk_reference = mock_get_pdk_reference.return_value + pdk_container = mock_get_pdk_container.return_value + + self._pdk.create_pdk(mock.sentinel.context, + mock_instance, + mock.sentinel.image_meta, + self._FAKE_PDK_FILE_PATH) + mock_get_pdk_reference.assert_called_once_with( + mock_instance, mock.sentinel.image_meta) + mock_get_pdk_container.assert_called_once_with(mock.sentinel.context, + mock_instance, + pdk_reference) + mock_get_pdk_data.assert_called_once_with(pdk_container) + pdk_file_handle.write.assert_called_once_with( + mock_get_pdk_data.return_value) + + def _test_get_pdk_reference(self, pdk_reference=None, + image_meta_pdk_ref=None): + mock_instance = mock.MagicMock( + metadata={'img_pdk_reference': image_meta_pdk_ref}) + image_meta = { + 'properties': {'img_pdk_reference': pdk_reference}} + + expected_result = image_meta_pdk_ref or pdk_reference + result = self._pdk._get_pdk_reference(mock_instance, + image_meta) + self.assertEqual(expected_result, result) + + def test_get_pdk_boot_reference(self): + self._test_get_pdk_reference( + image_meta_pdk_ref=mock.sentinel.image_meta_pdk_ref) + + def test_get_pdk_image_reference(self): + self._test_get_pdk_reference(pdk_reference=mock.sentinel.pdk_reference) + + def test_get_pdk_no_reference(self): + image_meta = {'properties': {}} + mock_instance = mock.MagicMock(metadata={}) + + self.assertRaises(exception.InstanceUnacceptable, + self._pdk._get_pdk_reference, + mock_instance, image_meta) + + @mock.patch('barbicanclient.client.Client') + @mock.patch('keystoneauth1.session.Session') + def test_get_pdk_container(self, mock_session, mock_barbican_client): + instance = mock.MagicMock() + context = mock.MagicMock() + auth = context.get_auth_plugin.return_value + sess = mock_session.return_value + barbican_client = mock_barbican_client.return_value + barbican_client.containers.get.return_value = ( + mock.sentinel.pdk_container) + + result = self._pdk._get_pdk_container(context, instance, + mock.sentinel.pdk_reference) + + self.assertEqual(mock.sentinel.pdk_container, result) + mock_session.assert_called_once_with(auth=auth) + mock_barbican_client.assert_called_once_with(session=sess) + + @mock.patch('barbicanclient.client.Client') + @mock.patch('keystoneauth1.session.Session') + def test_get_pdk_container_exception(self, mock_session, + mock_barbican_client): + instance = mock.MagicMock() + context = mock.MagicMock() + auth = context.get_auth_plugin.return_value + sess = mock_session.return_value + + barbican_client = mock_barbican_client.return_value + barbican_client.containers.get.side_effect = [ + exception.InvalidMetadata] + + self.assertRaises(exception.InvalidMetadata, + self._pdk._get_pdk_container, + context, + instance, + mock.sentinel.pdk_reference) + mock_session.assert_called_once_with(auth=auth) + mock_barbican_client.assert_called_once_with(session=sess) + + def test_get_pdk_data(self): + pdk_container = mock.MagicMock() + pdk_container.secrets = {'1': mock.MagicMock(payload=b'fake_secret1'), + '2': mock.MagicMock(payload=b'fake_secret2')} + + response = self._pdk._get_pdk_data(pdk_container) + expected_result = b'fake_secret1fake_secret2' + self.assertEqual(expected_result, response)