[cleanup] Fix identifiers for Mistral resources

Rally cleanup supports 3 Mistral resources: workbooks, workflows and
executions.

The min version of supported python-mistralclient (3.1.0 from our
requirements.txt) represents all these resources via special classes
[1][2][3] which have one parent class [4].

Issues with current rally cleanup code:

- Despite the fact that raw mistral objects do not support __getitem__
  method, `id` and `name` fields are tried to be accessed in such way,
  which made cleanup those resources broken for a long time (from the
  beggining?!)
- Mistral executions do not have own name, which we can use for
  filtering, but it stores workflow name, even if it was removed.
  Workflow name can be and should be used as an identifier.

Why these issues were not detected before:

- The Rally task which we used in CI has `do_delete=true` option for all
  workloads which makes workload to delete resources by itself without
  waiting for global cleanup.

  The fix is provided in this patch

- Despite the fact that osresources includes mistral resources to check
  that nothing is left after task execution, it doesn't help since there
  is no `all-tenants` option which turns listing resources from admin
  tenant to listing all existing resources.

  Cannot be fixed via our code.

[1] https://github.com/openstack/python-mistralclient/blob/3.1.0/mistralclient/api/v2/workbooks.py#L20
[2] https://github.com/openstack/python-mistralclient/blob/3.1.0/mistralclient/api/v2/workflows.py#L25
[3] https://github.com/openstack/python-mistralclient/blob/3.1.0/mistralclient/api/v2/executions.py#L27
[4] https://github.com/openstack/python-mistralclient/blob/3.1.0/mistralclient/api/base.py#L19

Change-Id: I57fa05ff26aa0836224ba7a3393833ba31fe58dd
This commit is contained in:
Andrey Kurilin 2018-01-23 13:40:45 +02:00
parent 548d2f5b37
commit dbdb175270
3 changed files with 63 additions and 48 deletions

View File

@ -58,18 +58,40 @@
users_per_tenant: 2
-
title: MistralExecutions.create_execution_from_workbook tests
scenario:
MistralExecutions.create_execution_from_workbook:
definition: "~/.rally/extra/mistral_wb.yaml"
workflow_name: "wf1"
params: "~/.rally/extra/mistral_params.json"
wf_input: "~/.rally/extra/mistral_input.json"
do_delete: true
runner:
constant:
times: 50
concurrency: 10
contexts:
users:
tenants: 2
users_per_tenant: 2
workloads:
-
description: MistralExecutions.create_execution_from_workbook scenario\
with delete option
scenario:
MistralExecutions.create_execution_from_workbook:
definition: "~/.rally/extra/mistral_wb.yaml"
workflow_name: "wf1"
params: "~/.rally/extra/mistral_params.json"
wf_input: "~/.rally/extra/mistral_input.json"
do_delete: true
runner:
constant:
times: 50
concurrency: 10
contexts:
users:
tenants: 2
users_per_tenant: 2
-
description: MistralExecutions.create_execution_from_workbook scenario\
without delete option
scenario:
MistralExecutions.create_execution_from_workbook:
definition: "~/.rally/extra/mistral_wb.yaml"
workflow_name: "wf1"
params: "~/.rally/extra/mistral_params.json"
wf_input: "~/.rally/extra/mistral_input.json"
do_delete: false
runner:
constant:
times: 50
concurrency: 10
contexts:
users:
tenants: 2
users_per_tenant: 2

View File

@ -814,30 +814,28 @@ class SwiftContainer(SwiftMixin):
_mistral_order = get_order(1100)
class MistralMixin(SynchronizedDeletion, base.ResourceManager):
def delete(self):
self._manager().delete(self.raw_resource["id"])
@base.resource("mistral", "workbooks", order=next(_mistral_order),
tenant_resource=True)
class MistralWorkbooks(MistralMixin):
class MistralWorkbooks(SynchronizedDeletion, base.ResourceManager):
def delete(self):
self._manager().delete(self.raw_resource["name"])
self._manager().delete(self.raw_resource.name)
@base.resource("mistral", "workflows", order=next(_mistral_order),
tenant_resource=True)
class MistralWorkflows(MistralMixin):
class MistralWorkflows(SynchronizedDeletion, base.ResourceManager):
pass
@base.resource("mistral", "executions", order=next(_mistral_order),
tenant_resource=True)
class MistralExecutions(MistralMixin):
pass
class MistralExecutions(SynchronizedDeletion, base.ResourceManager):
def name(self):
# NOTE(andreykurilin): Mistral Execution doesn't have own name which
# we can use for filtering, but it stores workflow id and name, even
# after workflow deletion.
return self.raw_resource.workflow_name
# MURANO

View File

@ -915,36 +915,31 @@ class ManilaSecurityServiceTestCase(test.TestCase):
"fake_id")
class MistralMixinTestCase(test.TestCase):
def test_delete(self):
mistral = resources.MistralMixin()
mistral._service = "mistral"
mistral.user = mock.MagicMock()
mistral._resource = "some_resources"
mistral.raw_resource = {"id": "TEST_ID"}
mistral.user.mistral().some_resources.delete.return_value = None
mistral.delete()
mistral.user.mistral().some_resources.delete.assert_called_once_with(
"TEST_ID")
class MistralWorkbookTestCase(test.TestCase):
def test_delete(self):
mistral = resources.MistralWorkbooks()
mistral._service = "mistral"
mistral.user = mock.MagicMock()
mistral._resource = "some_resources"
mistral.raw_resource = {"name": "TEST_NAME"}
mistral.user.mistral().some_resources.delete.return_value = None
clients = mock.MagicMock()
resource = mock.Mock()
resource.name = "TEST_NAME"
mistral = resources.MistralWorkbooks(
user=clients,
resource=resource)
mistral.delete()
mistral.user.mistral().some_resources.delete.assert_called_once_with(
clients.mistral().workbooks.delete.assert_called_once_with(
"TEST_NAME")
class MistralExecutionsTestCase(test.TestCase):
def test_name(self):
execution = mock.MagicMock(workflow_name="bar")
execution.name = "foo"
self.assertEqual("bar", resources.MistralExecutions(execution).name())
class SenlinMixinTestCase(test.TestCase):
def test_id(self):