diff --git a/doc/source/user/proxies/orchestration.rst b/doc/source/user/proxies/orchestration.rst index 2e8721b31..c9f3fa41f 100644 --- a/doc/source/user/proxies/orchestration.rst +++ b/doc/source/user/proxies/orchestration.rst @@ -23,6 +23,13 @@ Stack Operations get_stack_template, stacks, validate_template, resources, export_stack +Stack Event Operations +^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: openstack.orchestration.v1._proxy.Proxy + :noindex: + :members: stack_events + Software Configuration Operations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/user/resources/orchestration/index.rst b/doc/source/user/resources/orchestration/index.rst index 0af426b4a..d0c53f6b8 100644 --- a/doc/source/user/resources/orchestration/index.rst +++ b/doc/source/user/resources/orchestration/index.rst @@ -6,3 +6,4 @@ Orchestration Resources v1/stack v1/resource + v1/stack_event diff --git a/doc/source/user/resources/orchestration/v1/stack_event.rst b/doc/source/user/resources/orchestration/v1/stack_event.rst new file mode 100644 index 000000000..8838f44f4 --- /dev/null +++ b/doc/source/user/resources/orchestration/v1/stack_event.rst @@ -0,0 +1,12 @@ +openstack.orchestration.v1.stack_event +====================================== + +.. automodule:: openstack.orchestration.v1.stack_event + +The StackEvent Class +-------------------- + +The ``StackEvent`` class inherits from :class:`~openstack.resource.Resource`. + +.. autoclass:: openstack.orchestration.v1.stack_event.StackEvent + :members: diff --git a/openstack/orchestration/v1/_proxy.py b/openstack/orchestration/v1/_proxy.py index 908c73fa6..d68cee8e1 100644 --- a/openstack/orchestration/v1/_proxy.py +++ b/openstack/orchestration/v1/_proxy.py @@ -17,6 +17,7 @@ from openstack.orchestration.v1 import software_config as _sc from openstack.orchestration.v1 import software_deployment as _sd from openstack.orchestration.v1 import stack as _stack from openstack.orchestration.v1 import stack_environment as _stack_environment +from openstack.orchestration.v1 import stack_event as _stack_event from openstack.orchestration.v1 import stack_files as _stack_files from openstack.orchestration.v1 import stack_template as _stack_template from openstack.orchestration.v1 import template as _template @@ -608,3 +609,38 @@ class Proxy(proxy.Proxy): for stack in stacks: self.wait_for_delete(stack) + + def stack_events(self, stack, resource_name=None, **attr): + """Get a stack events + + :param stack: The value can be the ID of a stack or an instance of + :class:`~openstack.orchestration.v1.stack.Stack` + :param resource_name: The name of resource. If the resource_name is not None, + the base_path changes. + + :returns: A generator of stack_events objects + :rtype: :class:`~openstack.orchestration.v1.stack_event.StackEvent` + """ + + if isinstance(stack, _stack.Stack): + obj = stack + else: + obj = self._get(_stack.Stack, stack) + + if resource_name: + base_path = '/stacks/%(stack_name)s/%(stack_id)s/resources/%(resource_name)s/events' + return self._list( + _stack_event.StackEvent, + stack_name=obj.name, + stack_id=obj.id, + resource_name=resource_name, + base_path=base_path, + **attr + ) + + return self._list( + _stack_event.StackEvent, + stack_name=obj.name, + stack_id=obj.id, + **attr + ) diff --git a/openstack/orchestration/v1/stack_event.py b/openstack/orchestration/v1/stack_event.py new file mode 100644 index 000000000..640659e6a --- /dev/null +++ b/openstack/orchestration/v1/stack_event.py @@ -0,0 +1,53 @@ +# 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 openstack import resource + + +class StackEvent(resource.Resource): + base_path = '/stacks/%(stack_name)s/%(stack_id)s/events' + resources_key = 'events' + + # capabilities + allow_create = False + allow_list = True + allow_fetch = True + allow_delete = False + allow_commit = False + + _query_mapping = resource.QueryParameters( + "resource_action", + "resource_status", + "resource_name", + "resource_type", + "nested_depth", + "sort_key", + "sort_dir", + ) + + # Properties + #: The date and time when the event was created + event_time = resource.Body('event_time') + #: The ID of the event object + id = resource.Body('id') + #: A list of dictionaries containing links relevant to the stack. + links = resource.Body('links') + #: The ID of the logical stack resource. + logical_resource_id = resource.Body('logical_resource_id') + #: The ID of the stack physical resource. + physical_resource_id = resource.Body('physical_resource_id') + #: The name of the resource. + resource_name = resource.Body('resource_name') + #: The status of the resource. + resource_status = resource.Body('resource_status') + #: The reason for the current stack resource state. + resource_status_reason = resource.Body('resource_status_reason') diff --git a/openstack/tests/unit/orchestration/v1/test_proxy.py b/openstack/tests/unit/orchestration/v1/test_proxy.py index 583d64b65..0e8206085 100644 --- a/openstack/tests/unit/orchestration/v1/test_proxy.py +++ b/openstack/tests/unit/orchestration/v1/test_proxy.py @@ -21,9 +21,11 @@ from openstack.orchestration.v1 import software_config as sc from openstack.orchestration.v1 import software_deployment as sd from openstack.orchestration.v1 import stack from openstack.orchestration.v1 import stack_environment +from openstack.orchestration.v1 import stack_event from openstack.orchestration.v1 import stack_files from openstack.orchestration.v1 import stack_template from openstack.orchestration.v1 import template +from openstack import proxy from openstack.tests.unit import test_proxy_base @@ -498,3 +500,59 @@ class TestExtractName(TestOrchestrationProxy): def test_extract_name(self): results = self.proxy._extract_name(self.url) self.assertEqual(self.parts, results) + + +class TestOrchestrationStackEvents(TestOrchestrationProxy): + def test_stack_events_with_stack_object(self): + stack_id = '1234' + stack_name = 'test_stack' + stk = stack.Stack(id=stack_id, name=stack_name) + + self._verify( + 'openstack.proxy.Proxy._list', + self.proxy.stack_events, + method_args=[stk], + expected_args=[stack_event.StackEvent], + expected_kwargs={ + 'stack_name': stack_name, + 'stack_id': stack_id, + }, + ) + + @mock.patch.object(proxy.Proxy, '_get') + def test_stack_events_with_stack_id(self, mock_get): + stack_id = '1234' + stack_name = 'test_stack' + stk = stack.Stack(id=stack_id, name=stack_name) + mock_get.return_value = stk + + self._verify( + 'openstack.proxy.Proxy._list', + self.proxy.stack_events, + method_args=[stk], + expected_args=[stack_event.StackEvent], + expected_kwargs={ + 'stack_name': stack_name, + 'stack_id': stack_id, + }, + ) + + def test_stack_events_with_resource_name(self): + stack_id = '1234' + stack_name = 'test_stack' + resource_name = 'id' + base_path = '/stacks/%(stack_name)s/%(stack_id)s/resources/%(resource_name)s/events' + stk = stack.Stack(id=stack_id, name=stack_name) + + self._verify( + 'openstack.proxy.Proxy._list', + self.proxy.stack_events, + method_args=[stk, resource_name], + expected_args=[stack_event.StackEvent], + expected_kwargs={ + 'stack_name': stack_name, + 'stack_id': stack_id, + 'resource_name': resource_name, + 'base_path': base_path, + }, + ) diff --git a/openstack/tests/unit/orchestration/v1/test_stack_event.py b/openstack/tests/unit/orchestration/v1/test_stack_event.py new file mode 100644 index 000000000..5c5057287 --- /dev/null +++ b/openstack/tests/unit/orchestration/v1/test_stack_event.py @@ -0,0 +1,53 @@ +# 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 openstack.orchestration.v1 import stack_event +from openstack.tests.unit import base + + +FAKE_ID = 'ce8ae86c-9810-4cb1-8888-7fb53bc523bf' +FAKE_NAME = 'test_stack' +FAKE = { + 'event_time': '2015-03-09T12:15:57.233772', + 'id': FAKE_ID, + 'links': [{'href': 'stacks/%s/%s' % (FAKE_NAME, FAKE_ID), 'rel': 'self'}], + 'logical_resource_id': 'my_test_group', + 'physical_resource_id': 'my_test_group', + 'resource_name': 'my_test_resource', + 'resource_status': 'CREATE_IN_PROGRESS', + 'resource_status_reason': 'state changed', +} + + +class TestStackEvent(base.TestCase): + def test_basic(self): + sot = stack_event.StackEvent() + self.assertFalse(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertFalse(sot.allow_commit) + self.assertFalse(sot.allow_delete) + self.assertTrue(sot.allow_list) + + def test_make_it(self): + sot = stack_event.StackEvent(**FAKE) + self.assertEqual(FAKE['event_time'], sot.event_time) + self.assertEqual(FAKE['id'], sot.id) + self.assertEqual(FAKE['links'], sot.links) + self.assertEqual(FAKE['logical_resource_id'], sot.logical_resource_id) + self.assertEqual( + FAKE['physical_resource_id'], sot.physical_resource_id + ) + self.assertEqual(FAKE['resource_name'], sot.resource_name) + self.assertEqual(FAKE['resource_status'], sot.resource_status) + self.assertEqual( + FAKE['resource_status_reason'], sot.resource_status_reason + ) diff --git a/releasenotes/notes/add-stack-events-b8674d7bb657e789.yaml b/releasenotes/notes/add-stack-events-b8674d7bb657e789.yaml new file mode 100644 index 000000000..cdc9367f0 --- /dev/null +++ b/releasenotes/notes/add-stack-events-b8674d7bb657e789.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + The ``stack_events`` method and ``StackEvent`` Class have been + added to retrieve stack events \ No newline at end of file