Refactor orders cleanup

This patch continues the refactor of cleanup logic.  It adds a
new `cleanup()` method to the order client that attempts to delete
all orders and all screts created by those orders on cleanup.

This patch also adds some scaffolding to the Container client that
will be fleshed out in a follow-up patch.

Change-Id: I78d875980637e82ddc3173aad2fc7ecf4941230c
This commit is contained in:
Douglas Mendizábal 2021-07-30 18:21:11 +00:00
parent 4e5e45748d
commit d47ae4245a
4 changed files with 137 additions and 115 deletions

View File

@ -80,3 +80,6 @@ class ContainerClient(base.BarbicanTempestClient):
)
self.expected_success(204, response.status)
return
def queue_for_cleanup(self, container_id):
raise NotImplementedError

View File

@ -15,6 +15,7 @@ import json
from urllib import parse as urllib
from tempest import config
from tempest.lib import exceptions
from barbican_tempest_plugin.services.key_manager.json import base
@ -24,6 +25,18 @@ CONF = config.CONF
class OrderClient(base.BarbicanTempestClient):
def __init__(self, *args, secret_client=None, container_client=None,
**kwargs):
"""Create a new order client
secret_client and container_client are optional and will be used
to queue the respective objects for cleanup when given.
"""
super().__init__(*args, **kwargs)
self._order_ids = set()
self._secret_client = secret_client
self._container_client = container_client
def list_orders(self, **kwargs):
uri = "/v1/orders"
if kwargs:
@ -38,7 +51,9 @@ class OrderClient(base.BarbicanTempestClient):
response, body = self.post(uri, json.dumps(kwargs))
self.expected_success(202, response.status)
return json.loads(body.decode("utf-8"))
resp = json.loads(body.decode("utf-8"))
self._order_ids.add(self.ref_to_uuid(resp['order_ref']))
return resp
def get_order(self, order_id):
uri = "v1/orders/%s" % order_id
@ -48,8 +63,46 @@ class OrderClient(base.BarbicanTempestClient):
return json.loads(body.decode("utf-8"))
def delete_order(self, order_id):
self._order_ids.discard(order_id)
uri = "/v1/orders/%s" % order_id
self._queue_cleanup(order_id)
response, _ = self.delete(uri)
self.expected_success(204, response.status)
return
def cleanup(self):
"""Attempt to delete all orders created by this client
If this client was instantiated with secret and/or container
clients, then we try to queue for cleanup any objects generated
by the orders.
"""
cleanup_ids = self._order_ids
self._order_ids = set()
for order_id in cleanup_ids:
self._queue_cleanup(order_id)
try:
self.delete_order(order_id)
except exceptions.NotFound:
continue
def _queue_cleanup(self, order_id):
try:
order = self.get_order(order_id)
except exceptions.NotFound:
pass
except exceptions.Forbidden:
pass
else:
if (self._secret_client is not None) and \
(order.get('secret_ref') is not None):
self._secret_client.queue_for_cleanup(
self.ref_to_uuid(order['secret_ref'])
)
if (self._container_client is not None) and \
(order.get('container_ref') is not None):
self._container_client.queue_for_cleanup(
self.ref_to_uuid(order['container_ref'])
)

View File

@ -127,24 +127,7 @@ class BarbicanV1RbacBase(test.BaseTestCase):
def setup_clients(cls):
super().setup_clients()
# set up member clients
os = cls.os_project_member
cls.secret_client = os.secret_v1.SecretClient()
cls.secret_metadata_client = os.secret_v1.SecretMetadataClient(
service='key-manager'
)
cls.consumer_client = os.secret_v1.ConsumerClient(
service='key-manager'
)
cls.container_client = os.secret_v1.ContainerClient()
cls.order_client = os.secret_v1.OrderClient()
cls.quota_client = os.secret_v1.QuotaClient()
cls.secret_metadata_client = os.secret_v1.SecretMetadataClient(
service='key-manager'
)
# setup clients for admin persona
# this client is used for any cleanup/setup etc. as needed
adm = cls.os_project_admin
cls.admin_secret_client = adm.secret_v1.SecretClient()
cls.admin_secret_metadata_client = adm.secret_v1.SecretMetadataClient(
@ -154,11 +137,29 @@ class BarbicanV1RbacBase(test.BaseTestCase):
service='key-manager'
)
cls.admin_container_client = adm.secret_v1.ContainerClient()
cls.admin_order_client = adm.secret_v1.OrderClient()
cls.admin_order_client = adm.secret_v1.OrderClient(
secret_client=cls.admin_secret_client,
container_client=cls.admin_container_client
)
cls.admin_quota_client = adm.secret_v1.QuotaClient()
cls.admin_secret_metadata_client = adm.secret_v1.SecretMetadataClient(
# set clients for member persona
member = cls.os_project_member
cls.secret_client = member.secret_v1.SecretClient()
cls.secret_metadata_client = member.secret_v1.SecretMetadataClient(
service='key-manager'
)
cls.consumer_client = member.secret_v1.ConsumerClient(
service='key-manager'
)
cls.container_client = member.secret_v1.ContainerClient()
cls.order_client = member.secret_v1.OrderClient(
secret_client=cls.secret_client,
container_client=cls.container_client
)
cls.quota_client = member.secret_v1.QuotaClient()
# set up clients for member persona associated with a different
# project
cls.other_client = cls.os_project_alt_member.secret_v1.SecretClient()
@classmethod
@ -173,17 +174,17 @@ class BarbicanV1RbacBase(test.BaseTestCase):
for container_uuid in list(cls.created_objects['container']):
cls.admin_container_client.delete_container(container_uuid)
cls.created_objects['container'].remove(container_uuid)
for order_uuid in list(cls.created_objects['order']):
cls.admin_order_client.delete_order(order_uuid)
cls.created_objects['order'].remove(order_uuid)
for quota_uuid in list(cls.created_objects['quota']):
cls.admin_quota_client.delete_project_quota(quota_uuid)
cls.created_objects['quota'].remove(quota_uuid)
for secret_uuid in list(cls.created_objects['secret']):
cls.admin_secret_client.delete_secret(secret_uuid)
cls.created_objects['secret'].remove(secret_uuid)
for client in [cls.secret_client,
cls.order_client,
cls.admin_secret_client,
cls.admin_order_client,
cls.other_client]:
client.cleanup()
finally:
@ -193,13 +194,6 @@ class BarbicanV1RbacBase(test.BaseTestCase):
def add_cleanup(cls, resource, response):
if resource == 'container':
uuid = cls.ref_to_uuid(response['container_ref'])
if resource == 'order':
uuid = cls.ref_to_uuid(response.get('order_ref'))
order_metadata = cls.admin_order_client.get_order(uuid)
secret_ref = order_metadata.get('secret_ref')
if secret_ref:
cls.created_objects['secret'].add(cls.ref_to_uuid(secret_ref))
uuid = cls.ref_to_uuid(response['order_ref'])
if resource == 'quota':
uuid = cls.ref_to_uuid(response['quota_ref'])
if resource == 'secret':
@ -261,3 +255,25 @@ class BarbicanV1RbacBase(test.BaseTestCase):
kwargs['payload_content_type'] = 'text/plain'
resp = self.other_client.create_secret(**kwargs)
return self.other_client.ref_to_uuid(resp['secret_ref'])
def create_key_order(self, name=None):
"""Create a symmetric key order for testing
The new order is created using the default
member persona.
:returns: the uuid for the new order
"""
meta = {
'algorithm': 'AES',
'bit_length': 256,
'mode': 'CBC'
}
if name is not None:
meta['name'] = name
kwargs = {
'type': 'key',
'meta': meta
}
resp = self.order_client.create_order(**kwargs)
return self.order_client.ref_to_uuid(resp['order_ref'])

View File

@ -10,7 +10,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import abc
import time
from tempest.lib import exceptions
@ -68,58 +67,28 @@ class ProjectMemberTests(base.BarbicanV1RbacBase, BarbicanV1RbacOrders):
cls.client = cls.os_project_member.secret_v1.OrderClient()
def test_list_orders(self):
self.do_request('create_order', cleanup='order',
name='list_orders', type='key',
meta={
'name': 'list_orders_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
resp = self.do_request('list_orders')
_ = self.create_key_order('test_list_orders')
resp = self.client.list_orders()
self.assertGreaterEqual(len(resp['orders']), 1)
def test_create_order(self):
self.do_request('create_order', cleanup='order',
name='create_order', type='key',
meta={
'name': 'create_orders_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
self.client.create_order(
name='create_order', type='key',
meta={
'name': 'create_orders_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
def test_get_order(self):
resp = self.do_request('create_order', cleanup='order',
name='get_order', type='key',
meta={
'name': 'get_order_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
order_id = self.ref_to_uuid(resp['order_ref'])
resp = self.do_request('get_order', order_id=order_id)
self.assertEqual(order_id, self.ref_to_uuid(resp['order_ref']))
order_id = self.create_key_order('test_get_order')
resp = self.client.get_order(order_id)
self.assertEqual(order_id, self.client.ref_to_uuid(resp['order_ref']))
def test_delete_order(self):
resp = self.do_request('create_order',
name='delete_order', type='key',
meta={
'name': 'delete_order_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
order_id = self.ref_to_uuid(resp['order_ref'])
while True:
time.sleep(1)
resp = self.do_request('get_order', order_id=order_id)
if 'ACTIVE' == resp['status']:
self.add_cleanup('secret', resp)
break
self.do_request('delete_order', order_id=order_id)
order_id = self.create_key_order('test_delete_order')
self.client.delete_order(order_id)
class ProjectAdminTests(ProjectMemberTests):
@ -138,49 +107,30 @@ class ProjectReaderTests(base.BarbicanV1RbacBase, BarbicanV1RbacOrders):
cls.client = cls.os_project_reader.secret_v1.OrderClient()
def test_list_orders(self):
self.do_request('list_orders', expected_status=exceptions.Forbidden)
self.assertRaises(exceptions.Forbidden, self.client.list_orders)
def test_create_order(self):
self.do_request('create_order',
expected_status=exceptions.Forbidden,
cleanup='order',
name='create_order', type='key',
meta={
'name': 'create_orders_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
def test_get_order(self):
resp = self.do_request(
'create_order',
client=self.os_project_member.secret_v1.OrderClient(),
cleanup='order',
name='get_order', type='key',
self.assertRaises(
exceptions.Forbidden,
self.client.create_order,
name='test_create_order', type='key',
meta={
'name': 'get_order_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
}
)
order_id = self.ref_to_uuid(resp['order_ref'])
self.do_request('get_order', expected_status=exceptions.Forbidden,
order_id=order_id)
def test_delete_order(self):
resp = self.do_request(
'create_order',
client=self.os_project_member.secret_v1.OrderClient(),
cleanup='order',
name='delete_order', type='key',
meta={
'name': 'delete_order_s',
'name': 'create_orders_s',
'algorithm': 'aes',
'bit_length': 256,
'mode': 'cbc',
})
order_id = self.ref_to_uuid(resp['order_ref'])
self.do_request('delete_order', expected_status=exceptions.Forbidden,
order_id=order_id)
def test_get_order(self):
order_id = self.create_key_order('test_get_order')
self.assertRaises(
exceptions.Forbidden,
self.client.get_order,
order_id=order_id)
def test_delete_order(self):
order_id = self.create_key_order('test_delete_order')
self.assertRaises(
exceptions.Forbidden,
self.client.delete_order,
order_id=order_id)