diff --git a/openstack/cloud/_orchestration.py b/openstack/cloud/_orchestration.py index bab1ed0ce..5bcc5ae11 100644 --- a/openstack/cloud/_orchestration.py +++ b/openstack/cloud/_orchestration.py @@ -209,15 +209,16 @@ class OrchestrationCloudMixin(_normalize.Normalizer): return _utils._filter_list(stacks, name_or_id, filters) @_utils.cache_on_arguments(should_cache_fn=_no_pending_stacks) - def list_stacks(self): + def list_stacks(self, **query): """List all stacks. + :param dict query: Query parameters to limit stacks. :returns: a list of ``munch.Munch`` containing the stack description. :raises: ``OpenStackCloudException`` if something goes wrong during the OpenStack API call. """ - data = self.orchestration.stacks() + data = self.orchestration.stacks(**query) return self._normalize_stacks(data) def get_stack(self, name_or_id, filters=None, resolve_outputs=True): diff --git a/openstack/orchestration/v1/stack.py b/openstack/orchestration/v1/stack.py index adb577b01..1bfc1a7dd 100644 --- a/openstack/orchestration/v1/stack.py +++ b/openstack/orchestration/v1/stack.py @@ -29,7 +29,10 @@ class Stack(resource.Resource): allow_delete = True _query_mapping = resource.QueryParameters( - 'resolve_outputs' + 'action', 'name', 'status', + 'project_id', 'owner_id', 'username', + project_id='tenant_id', + **resource.TagMixin._tag_query_parameters ) # Properties @@ -84,7 +87,7 @@ class Stack(resource.Resource): #: A text explaining how the stack transits to its current status. status_reason = resource.Body('stack_status_reason') #: A list of strings used as tags on the stack - tags = resource.Body('tags') + tags = resource.Body('tags', type=list, default=[]) #: A dict containing the template use for stack creation. template = resource.Body('template', type=dict) #: Stack template description text. Currently contains the same text diff --git a/openstack/tests/unit/cloud/test_stack.py b/openstack/tests/unit/cloud/test_stack.py index 72335f740..1da6381d2 100644 --- a/openstack/tests/unit/cloud/test_stack.py +++ b/openstack/tests/unit/cloud/test_stack.py @@ -51,6 +51,30 @@ class TestStack(base.TestCase): self.assert_calls() + def test_list_stacks_filters(self): + fake_stacks = [ + self.stack, + fakes.make_fake_stack( + self.getUniqueString('id'), + self.getUniqueString('name')) + ] + self.register_uris([ + dict(method='GET', + uri=self.get_mock_url( + 'orchestration', 'public', + append=['stacks'], + qs_elements=['name=a', 'status=b'], + ), + json={"stacks": fake_stacks}), + ]) + stacks = self.cloud.list_stacks(name='a', status='b') + self.assertEqual( + [f.toDict() for f in self.cloud._normalize_stacks( + stack.Stack(**st) for st in fake_stacks)], + [f.toDict() for f in stacks]) + + self.assert_calls() + def test_list_stacks_exception(self): self.register_uris([ dict(method='GET', diff --git a/openstack/tests/unit/orchestration/v1/test_stack.py b/openstack/tests/unit/orchestration/v1/test_stack.py index 080ede820..f3aad5d5f 100644 --- a/openstack/tests/unit/orchestration/v1/test_stack.py +++ b/openstack/tests/unit/orchestration/v1/test_stack.py @@ -135,6 +135,23 @@ class TestStack(base.TestCase): self.assertTrue(sot.allow_delete) self.assertTrue(sot.allow_list) + self.assertDictEqual( + { + 'action': 'action', + 'any_tags': 'tags-any', + 'limit': 'limit', + 'marker': 'marker', + 'name': 'name', + 'not_any_tags': 'not-tags-any', + 'not_tags': 'not-tags', + 'owner_id': 'owner_id', + 'project_id': 'tenant_id', + 'status': 'status', + 'tags': 'tags', + 'username': 'username', + }, + sot._query_mapping._mapping) + def test_make_it(self): sot = stack.Stack(**FAKE) self.assertEqual(FAKE['capabilities'], sot.capabilities)