From ad48215db10246fa9d210529b107dc5e0f6008ad Mon Sep 17 00:00:00 2001 From: Ahmed Elkhouly Date: Mon, 8 Feb 2016 17:32:19 -0500 Subject: [PATCH] Add heat client support for Resource set health Add a new command to set resource's health. The command takes the following format: heat resource-mark-unhealthy [--reset] reason Change-Id: I4e0a127343e591c176f451172a1c8a59bf36f6eb Partially-implements: blueprint mark-unhealthy Depends-On: Ifa48b179723a2100fff548467db9e162bc669d13 --- heatclient/tests/unit/test_resources.py | 14 +++++ heatclient/tests/unit/test_shell.py | 81 +++++++++++++++++++++++++ heatclient/v1/resources.py | 21 +++++++ heatclient/v1/shell.py | 22 +++++++ 4 files changed, 138 insertions(+) diff --git a/heatclient/tests/unit/test_resources.py b/heatclient/tests/unit/test_resources.py index 120b1c4b..e68bdf2b 100644 --- a/heatclient/tests/unit/test_resources.py +++ b/heatclient/tests/unit/test_resources.py @@ -192,6 +192,20 @@ class ResourceManagerTest(testtools.TestCase): manager.signal(**fields) self.m.VerifyAll() + def test_mark_unhealthy(self): + fields = {'stack_id': 'teststack', + 'resource_name': 'testresource', + 'mark_unhealthy': 'True', + 'resource_status_reason': 'Anything'} + expect = ('PATCH', + '/stacks/teststack%2Fabcd1234/resources' + '/testresource') + key = 'mark_unhealthy' + + manager = self._base_test(expect, key) + manager.mark_unhealthy(**fields) + self.m.VerifyAll() + class ResourceStackNameTest(testtools.TestCase): diff --git a/heatclient/tests/unit/test_shell.py b/heatclient/tests/unit/test_shell.py index a1056867..75572f7c 100644 --- a/heatclient/tests/unit/test_shell.py +++ b/heatclient/tests/unit/test_shell.py @@ -4032,6 +4032,87 @@ class ShellTestResources(ShellBase): stack_id, resource_name, data_file.name)) self.assertEqual("", text) + def test_resource_mark_unhealthy(self): + self.register_keystone_auth_fixture() + resp = fakes.FakeHTTPResponse( + 200, + 'OK', + {}, + '') + stack_id = 'teststack/1' + resource_name = 'aResource' + http.SessionClient.request( + '/stacks/%s/resources/%s' % + ( + parse.quote(stack_id, ''), + parse.quote(encodeutils.safe_encode( + resource_name), '') + ), + 'PATCH', + data={'mark_unhealthy': True, + 'resource_status_reason': 'Any'}).AndReturn(resp) + + self.m.ReplayAll() + + text = self.shell( + 'resource-mark-unhealthy {0} {1} Any'.format( + stack_id, resource_name)) + self.assertEqual("", text) + + def test_resource_mark_unhealthy_reset(self): + self.register_keystone_auth_fixture() + resp = fakes.FakeHTTPResponse( + 200, + 'OK', + {}, + '') + stack_id = 'teststack/1' + resource_name = 'aResource' + http.SessionClient.request( + '/stacks/%s/resources/%s' % + ( + parse.quote(stack_id, ''), + parse.quote(encodeutils.safe_encode( + resource_name), '') + ), + 'PATCH', + data={'mark_unhealthy': False, + 'resource_status_reason': 'Any'}).AndReturn(resp) + + self.m.ReplayAll() + + text = self.shell( + 'resource-mark-unhealthy --reset {0} {1} Any'.format( + stack_id, resource_name)) + self.assertEqual("", text) + + def test_resource_mark_unhealthy_no_reason(self): + self.register_keystone_auth_fixture() + resp = fakes.FakeHTTPResponse( + 200, + 'OK', + {}, + '') + stack_id = 'teststack/1' + resource_name = 'aResource' + http.SessionClient.request( + '/stacks/%s/resources/%s' % + ( + parse.quote(stack_id, ''), + parse.quote(encodeutils.safe_encode( + resource_name), '') + ), + 'PATCH', + data={'mark_unhealthy': True, + 'resource_status_reason': ''}).AndReturn(resp) + + self.m.ReplayAll() + + text = self.shell( + 'resource-mark-unhealthy {0} {1}'.format( + stack_id, resource_name)) + self.assertEqual("", text) + class ShellTestResourceTypes(ShellBase): def setUp(self): diff --git a/heatclient/v1/resources.py b/heatclient/v1/resources.py index f063c841..3ad6fdf0 100644 --- a/heatclient/v1/resources.py +++ b/heatclient/v1/resources.py @@ -112,6 +112,27 @@ class ResourceManager(stacks.StackChildManager): body = utils.get_response_body(resp) return body + def mark_unhealthy(self, stack_id, resource_name, + mark_unhealthy, resource_status_reason): + """Mark a resource as healthy or unhealthy. + + :param stack_id: ID of stack containing the resource + :param resource_name: ID of resource + :param mark_unhealthy: Mark resource unhealthy if set to True + :param resource_status_reason: Reason for resource status change. + """ + stack_id = self._resolve_stack_id(stack_id) + url_str = '/stacks/%s/resources/%s' % ( + parse.quote(stack_id, ''), + parse.quote(encodeutils.safe_encode(resource_name), '')) + resp = self.client.patch( + url_str, + data={"mark_unhealthy": mark_unhealthy, + "resource_status_reason": resource_status_reason}) + + body = utils.get_response_body(resp) + return body + def generate_template(self, resource_name): """Deprecated in favor of generate_template in ResourceTypeManager.""" diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index f0fcd6d8..85b8a3d5 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -962,6 +962,28 @@ def do_resource_signal(hc, args): {'id': args.id, 'resource': args.resource}) +@utils.arg('id', metavar='', + help=_('Name or ID of stack the resource belongs to.')) +@utils.arg('resource', metavar='', + help=_('Name of the resource.')) +@utils.arg('reason', default="", nargs='?', + help=_('Reason for state change.')) +@utils.arg('--reset', default=False, action="store_true", + help=_('Set the resource as healthy.')) +def do_resource_mark_unhealthy(hc, args): + '''Set resource's health.''' + fields = {'stack_id': args.id, + 'resource_name': args.resource, + 'mark_unhealthy': not args.reset, + 'resource_status_reason': args.reason} + try: + hc.resources.mark_unhealthy(**fields) + except exc.HTTPNotFound: + raise exc.CommandError(_('Stack or resource not found: ' + '%(id)s %(resource)s') % + {'id': args.id, 'resource': args.resource}) + + @utils.arg('id', metavar='', help=_('Name or ID of the stack these resources belong to.')) @utils.arg('--pre-create', action='store_true', default=False,