Add barbican scenarios for orders
Added the following scenarios: - BarbicanOrders.list - BarbicanOrders.create_key_and_delete - BarbicanOrders.create_certificate_and_delete - BarbicanOrders.create_asymmetric_and_delete Change-Id: I6a12bdce95aef34a85cfae306c475905c6b19e7c Signed-off-by: Charles Short <chucks@redhat.com>
This commit is contained in:
parent
d91fda2ce6
commit
ae2e04d82d
@ -147,3 +147,43 @@
|
|||||||
users:
|
users:
|
||||||
tenants: 1
|
tenants: 1
|
||||||
users_per_tenant: 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
|
||||||
|
@ -1123,3 +1123,9 @@ class BarbicanSecrets(base.ResourceManager):
|
|||||||
perform_for_admin_only=True)
|
perform_for_admin_only=True)
|
||||||
class BarbicanContainers(base.ResourceManager):
|
class BarbicanContainers(base.ResourceManager):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@base.resource("barbican", "orders", order=1500, admin_required=True,
|
||||||
|
perform_for_admin_only=True)
|
||||||
|
class BarbicanOrders(base.ResourceManager):
|
||||||
|
pass
|
||||||
|
60
rally_openstack/scenarios/barbican/orders.py
Normal file
60
rally_openstack/scenarios/barbican/orders.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# Copyright 2018 Red Hat, Inc. <http://www.redhat.com>
|
||||||
|
#
|
||||||
|
# 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)
|
@ -141,3 +141,94 @@ class BarbicanService(service.Service):
|
|||||||
private_key=private_key, private_key_passphrase=None)
|
private_key=private_key, private_key_passphrase=None)
|
||||||
val.store()
|
val.store()
|
||||||
return val
|
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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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
|
||||||
|
|
22
samples/tasks/scenarios/barbican/create-and-delete-keys.json
Normal file
22
samples/tasks/scenarios/barbican/create-and-delete-keys.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
15
samples/tasks/scenarios/barbican/create-and-delete-keys.yaml
Normal file
15
samples/tasks/scenarios/barbican/create-and-delete-keys.yaml
Normal file
@ -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
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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
|
||||||
|
|
22
samples/tasks/scenarios/barbican/list-orders.json
Normal file
22
samples/tasks/scenarios/barbican/list-orders.json
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
15
samples/tasks/scenarios/barbican/list-orders.yaml
Normal file
15
samples/tasks/scenarios/barbican/list-orders.yaml
Normal file
@ -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
|
||||||
|
|
82
tests/unit/scenarios/barbican/test_orders.py
Normal file
82
tests/unit/scenarios/barbican/test_orders.py
Normal file
@ -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)
|
@ -100,3 +100,56 @@ class BarbicanServiceTestCase(test.TestCase):
|
|||||||
certificate=None, intermediates=None,
|
certificate=None, intermediates=None,
|
||||||
name="container", private_key=None,
|
name="container", private_key=None,
|
||||||
private_key_passphrase=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")
|
||||||
|
Loading…
Reference in New Issue
Block a user