diff --git a/rally-jobs/barbican.yaml b/rally-jobs/barbican.yaml index 6d3da0a7..3a41d1f1 100644 --- a/rally-jobs/barbican.yaml +++ b/rally-jobs/barbican.yaml @@ -147,3 +147,43 @@ users: tenants: 1 users_per_tenant: 1 + - + title: BarbicanOrders.create_asymmetric_and_delete + workloads: + - + scenario: + BarbicanOrders.create_asymmetric_and_delete: {} + runner: + constant: + times: 4 + concurrency: 2 + - + title: BarbicanOrders.create_key_and_delete + workloads: + - + scenario: + BarbicanOrders.create_key_and_delete: {} + runner: + constant: + times: 4 + concurrency: 2 + - + title: BarbicanOrders.create_certificate_and_delete + workloads: + - + scenario: + BarbicanOrders.create_certificate_and_delete: {} + runner: + constant: + times: 4 + concurrency: 2 + - + title: BarbicanOrders.list + workloads: + - + scenario: + BarbicanOrders.list: {} + runner: + constant: + times: 4 + concurrency: 2 diff --git a/rally_openstack/cleanup/resources.py b/rally_openstack/cleanup/resources.py index 085f3bb8..f4668177 100644 --- a/rally_openstack/cleanup/resources.py +++ b/rally_openstack/cleanup/resources.py @@ -1171,3 +1171,9 @@ class BarbicanSecrets(base.ResourceManager): perform_for_admin_only=True) class BarbicanContainers(base.ResourceManager): pass + + +@base.resource("barbican", "orders", order=1500, admin_required=True, + perform_for_admin_only=True) +class BarbicanOrders(base.ResourceManager): + pass diff --git a/rally_openstack/scenarios/barbican/orders.py b/rally_openstack/scenarios/barbican/orders.py new file mode 100644 index 00000000..13186c70 --- /dev/null +++ b/rally_openstack/scenarios/barbican/orders.py @@ -0,0 +1,60 @@ +# Copyright 2018 Red Hat, Inc. +# +# 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 rally.task import validation + +from rally_openstack import consts +from rally_openstack import scenario +from rally_openstack.scenarios.barbican import utils + +"""Scenarios for Barbican orders.""" + + +@validation.add("required_services", services=[consts.Service.BARBICAN]) +@validation.add("required_platform", platform="openstack", admin=True) +@scenario.configure(name="BarbicanOrders.list") +class BarbicanOrdersList(utils.BarbicanBase): + def run(self): + """List secrets.""" + self.admin_barbican.orders_list() + + +@validation.add("required_services", services=[consts.Service.BARBICAN]) +@validation.add("required_platform", platform="openstack", admin=True) +@scenario.configure(name="BarbicanOrders.create_key_and_delete") +class BarbicanOrdersCreateKeyAndDelete(utils.BarbicanBase): + def run(self): + """Create and delete key orders""" + keys = self.admin_barbican.create_key() + self.admin_barbican.orders_delete(keys.order_ref) + + +@validation.add("required_services", services=[consts.Service.BARBICAN]) +@validation.add("required_platform", platform="openstack", admin=True) +@scenario.configure(name="BarbicanOrders.create_certificate_and_delete") +class BarbicanOrdersCreateCertificateAndDelete(utils.BarbicanBase): + def run(self): + """Create and delete certificate orders""" + certificate = self.admin_barbican.create_certificate() + self.admin_barbican.orders_delete(certificate.order_ref) + + +@validation.add("required_services", services=[consts.Service.BARBICAN]) +@validation.add("required_platform", platform="openstack", admin=True) +@scenario.configure(name="BarbicanOrders.create_asymmetric_and_delete") +class BarbicanOrdersCreateAsymmetricAndDelete(utils.BarbicanBase): + def run(self): + """Create and delete asymmetric order.""" + certificate = self.admin_barbican.create_asymmetric() + self.admin_barbican.orders_delete(certificate.order_ref) diff --git a/rally_openstack/services/key_manager/barbican.py b/rally_openstack/services/key_manager/barbican.py index b976c8be..5235bf3f 100644 --- a/rally_openstack/services/key_manager/barbican.py +++ b/rally_openstack/services/key_manager/barbican.py @@ -141,3 +141,94 @@ class BarbicanService(service.Service): private_key=private_key, private_key_passphrase=None) val.store() return val + + @atomic.action_timer("barbican.orders_list") + def orders_list(self): + """list orders""" + return self._clients.barbican().orders.list() + + @atomic.action_timer("barbican.orders_delete") + def orders_delete(self, order_ref): + """Delete the order + + :param order_ref: The order reference + """ + return self._clients.barbican().orders.delete(order_ref) + + @atomic.action_timer("barbican.orders_get") + def orders_get(self, order_ref): + """Get the order + + :param order_ref: The order reference + """ + return self._clients.barbican().orders.get(order_ref) + + @atomic.action_timer("barbican.create_key") + def create_key(self, name=None, algorithm="aes", bit_length=256, mode=None, + payload_content_type=None, expiration=None): + """Create a key order object + + :param name: A friendly name for the secret to be created + :param algorithm: The algorithm associated with this secret key + :param bit_length: The bit length of this secret key + :param mode: The algorithm mode used with this secret key + :param payload_content_type: The format/type of the secret data + :param expiration: The expiration time of the secret + in ISO 8601 format + :returns: KeyOrder + """ + name = name or self.generate_random_name() + order = self._clients.barbican().orders.create_key( + name=name, algorithm=algorithm, bit_length=bit_length, + mode=mode, payload_content_type=payload_content_type, + expiration=expiration) + order.submit() + return order + + @atomic.action_timer("barbican.create_asymmetric") + def create_asymmetric(self, name=None, algorithm="aes", bit_length=256, + pass_phrase=None, payload_content_type=None, + expiration=None): + """Create an asymmetric order object + + :param name: A friendly name for the container to be created + :param algorithm: The algorithm associated with this secret key + :param bit_length: The bit length of this secret key + :param pass_phrase: Optional passphrase + :param payload_content_type: The format/type of the secret data + :param expiration: The expiration time of the secret + in ISO 8601 format + :returns: AsymmetricOrder + """ + name = name or self.generate_random_name() + order = self._clients.barbican().orders.create_asymmetric( + name=name, algorithm=algorithm, bit_length=bit_length, + pass_phrase=pass_phrase, payload_content_type=payload_content_type, + expiration=expiration) + order.submit() + return order + + @atomic.action_timer("barbican.create_certificate") + def create_certificate(self, name=None, request_type=None, subject_dn=None, + source_container_ref=None, ca_id=None, profile=None, + request_data=None): + """Create a certificate order object + + :param name: A friendly name for the container to be created + :param request_type: The type of the certificate request + :param subject_dn: A subject for the certificate + :param source_container_ref: A container with a + public/private key pair to use as source for stored-key + requests + :param ca_id: The identifier of the CA to use + :param profile: The profile of certificate to use + :param request_data: The CSR content + :returns: CertificateOrder + """ + name = name or self.generate_random_name() + order = self._clients.barbican().orders.create_certificate( + name=name, request_type=request_type, subject_dn=subject_dn, + source_container_ref=source_container_ref, ca_id=ca_id, + profile=profile, request_data=request_data) + order.submit() + return order diff --git a/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.json b/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.json new file mode 100644 index 00000000..892dd3c6 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.json @@ -0,0 +1,22 @@ +{ + "BarbicanOrders.create_asymmetric_and_delete": [ + { + "runner": { + "type": "constant", + "times": 2, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.yaml b/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.yaml new file mode 100644 index 00000000..691522c4 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-asymmetric.yaml @@ -0,0 +1,15 @@ +--- + BarbicanOrders.create_asymmetric_and_delete: + - + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + diff --git a/samples/tasks/scenarios/barbican/create-and-delete-keys.json b/samples/tasks/scenarios/barbican/create-and-delete-keys.json new file mode 100644 index 00000000..d09b35b4 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-keys.json @@ -0,0 +1,22 @@ +{ + "BarbicanOrders.create_key_and_delete": [ + { + "runner": { + "type": "constant", + "times": 2, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/barbican/create-and-delete-keys.yaml b/samples/tasks/scenarios/barbican/create-and-delete-keys.yaml new file mode 100644 index 00000000..25c5fa84 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-keys.yaml @@ -0,0 +1,15 @@ +--- + BarbicanOrders.create_key_and_delete: + - + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + diff --git a/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.json b/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.json new file mode 100644 index 00000000..1d0d8c36 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.json @@ -0,0 +1,22 @@ +{ + "BarbicanOrders.create_certificate_and_delete": [ + { + "runner": { + "type": "constant", + "times": 2, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.yaml b/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.yaml new file mode 100644 index 00000000..47ce2708 --- /dev/null +++ b/samples/tasks/scenarios/barbican/create-and-delete-order-certificate.yaml @@ -0,0 +1,15 @@ +--- + BarbicanOrders.create_certificate_and_delete: + - + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + diff --git a/samples/tasks/scenarios/barbican/list-orders.json b/samples/tasks/scenarios/barbican/list-orders.json new file mode 100644 index 00000000..0f07db7c --- /dev/null +++ b/samples/tasks/scenarios/barbican/list-orders.json @@ -0,0 +1,22 @@ +{ + "BarbicanOrders.list": [ + { + "runner": { + "type": "constant", + "times": 2, + "concurrency": 1 + }, + "context": { + "users": { + "tenants": 1, + "users_per_tenant": 1 + } + }, + "sla": { + "failure_rate": { + "max": 0 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/barbican/list-orders.yaml b/samples/tasks/scenarios/barbican/list-orders.yaml new file mode 100644 index 00000000..856a2e26 --- /dev/null +++ b/samples/tasks/scenarios/barbican/list-orders.yaml @@ -0,0 +1,15 @@ +--- + BarbicanOrders.list: + - + runner: + type: "constant" + times: 2 + concurrency: 1 + context: + users: + tenants: 1 + users_per_tenant: 1 + sla: + failure_rate: + max: 0 + diff --git a/tests/unit/scenarios/barbican/test_orders.py b/tests/unit/scenarios/barbican/test_orders.py new file mode 100644 index 00000000..cabe52fb --- /dev/null +++ b/tests/unit/scenarios/barbican/test_orders.py @@ -0,0 +1,82 @@ +# Copyright 2018 Red Hat Inc +# 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 rally_openstack.scenarios.barbican import orders +from tests.unit import test + + +class BarbicanOrdersTestCase(test.ScenarioTestCase): + + def get_test_context(self): + context = super(BarbicanOrdersTestCase, self).get_test_context() + context.update({ + "admin": { + "user_id": "fake", + "credential": mock.MagicMock() + }, + "user": { + "user_id": "fake", + "credential": mock.MagicMock() + }, + "tenant": {"id": "fake"} + }) + return context + + def setUp(self): + super(BarbicanOrdersTestCase, self).setUp() + patch = mock.patch( + "rally_openstack.services.key_manager.barbican.BarbicanService") + self.addCleanup(patch.stop) + self.mock_secrets = patch.start() + + def test_list_orders(self): + barbican_service = self.mock_secrets.return_value + scenario = orders.BarbicanOrdersList(self.context) + scenario.run() + barbican_service.orders_list.assert_called_once_with() + + def test_key_create_and_delete(self): + keys = {"order_ref": "fake-key"} + barbican_service = self.mock_secrets.return_value + scenario = orders.BarbicanOrdersCreateKeyAndDelete(self.context) + scenario.run() + keys = barbican_service.create_key.return_value + barbican_service.create_key.assert_called_once_with() + barbican_service.orders_delete.assert_called_once_with( + keys.order_ref) + + def test_certificate_create_and_delete(self): + certificate = {"order_ref": "fake-certificate"} + barbican_service = self.mock_secrets.return_value + scenario = orders.BarbicanOrdersCreateCertificateAndDelete( + self.context) + scenario.run() + certificate = barbican_service.create_certificate.return_value + barbican_service.create_certificate.assert_called_once_with() + barbican_service.orders_delete.assert_called_once_with( + certificate.order_ref) + + def test_asymmetric_create_and_delete(self): + certificate = {"order_ref": "fake-certificate"} + barbican_service = self.mock_secrets.return_value + scenario = orders.BarbicanOrdersCreateAsymmetricAndDelete( + self.context) + scenario.run() + certificate = barbican_service.create_asymmetric.return_value + barbican_service.create_asymmetric.assert_called_once_with() + barbican_service.orders_delete.assert_called_once_with( + certificate.order_ref) diff --git a/tests/unit/services/barbican/test_secrets.py b/tests/unit/services/barbican/test_secrets.py index 33debcf9..19e602e3 100644 --- a/tests/unit/services/barbican/test_secrets.py +++ b/tests/unit/services/barbican/test_secrets.py @@ -100,3 +100,56 @@ class BarbicanServiceTestCase(test.TestCase): certificate=None, intermediates=None, name="container", private_key=None, private_key_passphrase=None) + + def test__list_orders(self): + self.assertEqual( + self.service.orders_list(), + self.service._clients.barbican().orders.list.return_value) + self._test_atomic_action_timer( + self.atomic_actions(), "barbican.orders_list") + + def test__orders_get(self): + self.service.orders_get("fake_order") + self.service._clients.barbican().orders.get \ + .assert_called_once_with("fake_order") + + def test__orders_delete(self): + self.service.orders_delete("fake_order") + self.service._clients.barbican().orders.delete \ + .assert_called_once_with("fake_order") + self._test_atomic_action_timer( + self.atomic_actions(), "barbican.orders_delete") + + def test__create_key(self): + self.service.generate_random_name = mock.MagicMock( + return_value="key") + self.service.create_key() + self.service._clients.barbican().orders.create_key \ + .assert_called_once_with( + name="key", algorithm="aes", bit_length=256, mode=None, + payload_content_type=None, expiration=None) + self._test_atomic_action_timer( + self.atomic_actions(), "barbican.create_key") + + def test__create_asymmetric(self): + self.service.generate_random_name = mock.MagicMock( + return_value="key") + self.service.create_asymmetric() + self.service._clients.barbican().orders.create_asymmetric \ + .assert_called_once_with( + algorithm="aes", bit_length=256, expiration=None, name="key", + pass_phrase=None, payload_content_type=None) + self._test_atomic_action_timer( + self.atomic_actions(), "barbican.create_asymmetric") + + def test_create_certificate(self): + self.service.generate_random_name = mock.MagicMock( + return_value="key") + self.service.create_certificate() + self.service._clients.barbican().orders.create_certificate \ + .assert_called_once_with( + name="key", request_type=None, subject_dn=None, + source_container_ref=None, ca_id=None, profile=None, + request_data=None) + self._test_atomic_action_timer( + self.atomic_actions(), "barbican.create_certificate")