diff options
author | Matthew Sartori <msartori@google.com> | 2015-09-11 18:16:05 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2015-09-14 17:10:20 -0700 |
commit | 00bee1914d326717386842e19b22ea7ba45266d2 (patch) | |
tree | c530b78a77abbf27d8da34d4a9dc3027cbd93677 /mobmonitor | |
parent | 6367f86371a3819ba8312355e7113d0467b85df4 (diff) | |
download | chromite-00bee1914d326717386842e19b22ea7ba45266d2.tar.gz |
mobmonitor: Fixes for the Mob* Monitor.
The Mob* Monitor assumed that repair actions were
unique up to the service that they repaired.
Recent work on the UI and checkfiles have introduced
changes that make actions unique up to a healthcheck
instead of up to a service. This CL updates the ActionInfo
and RepairService RPCs to take a healthcheck name as a
parameter. This does not introduce any useability
changes for users of the web UI.
From the perspective of the monitor, actions now repair
a particular failed healthcheck of a service, rather than a
service that has a failed healthcheck.
BUG=None
TEST=Unittests and tested on moblab.
Change-Id: I47372c3c1b5181bd395402d6501b17bea633ffa1
Reviewed-on: https://chromium-review.googlesource.com/299540
Commit-Ready: Matthew Sartori <msartori@chromium.org>
Tested-by: Matthew Sartori <msartori@chromium.org>
Reviewed-by: Simran Basi <sbasi@chromium.org>
Diffstat (limited to 'mobmonitor')
-rw-r--r-- | mobmonitor/checkfile/manager.py | 48 | ||||
-rw-r--r-- | mobmonitor/checkfile/manager_unittest.py | 40 | ||||
-rw-r--r-- | mobmonitor/rpc/rpc.py | 35 | ||||
-rwxr-xr-x | mobmonitor/scripts/mobmoncli.py | 15 | ||||
-rw-r--r-- | mobmonitor/scripts/mobmoncli_unittest.py | 11 | ||||
-rwxr-xr-x | mobmonitor/scripts/mobmonitor.py | 11 | ||||
-rw-r--r-- | mobmonitor/scripts/mobmonitor_unittest.py | 9 | ||||
-rw-r--r-- | mobmonitor/static/css/style.css | 3 | ||||
-rw-r--r-- | mobmonitor/static/js/main.js | 9 | ||||
-rw-r--r-- | mobmonitor/static/js/rpc.js | 11 | ||||
-rw-r--r-- | mobmonitor/static/templates/healthstatuscontainer.html | 4 |
11 files changed, 122 insertions, 74 deletions
diff --git a/mobmonitor/checkfile/manager.py b/mobmonitor/checkfile/manager.py index c0a305b69..3b09cf846 100644 --- a/mobmonitor/checkfile/manager.py +++ b/mobmonitor/checkfile/manager.py @@ -387,16 +387,19 @@ class CheckFileManager(object): return self.service_states.get(service, SERVICE_STATUS(service, False, [])) - def ActionInfo(self, service, action): + def ActionInfo(self, service, healthcheck, action): """Describes a currently valid action for the given service and healthcheck. An action is valid if the following hold: The |service| is recognized and is in an unhealthy or quasi-healthy state. + The |healthcheck| is recognized and is in an unhealthy or quasi-healthy + state and it belongs to |service|. The |action| is one specified as a suitable repair action by the Diagnose method of some non-healthy healthcheck of |service|. Args: service: A string. The name of a service being monitored. + healthcheck: A string. The name of a healthcheck belonging to |service|. action: A string. The name of an action returned by some healthcheck's Diagnose method. @@ -415,18 +418,20 @@ class CheckFileManager(object): elif isServiceHealthy(status): return ACTION_INFO(action, 'Service is healthy.', [], {}) - def FindAction(): - for hc in status.healthchecks: - if isHealthcheckHealthy(hc): - continue - for a in hc.actions: - if a.__name__ == action: - return a - return None + hc = [x for x in status.healthchecks if x.name == healthcheck] + if not hc: + return ACTION_INFO(action, 'Healthcheck not recognized.', [], {}) + hc = hc[0] + if isHealthcheckHealthy(hc): + return ACTION_INFO(action, 'Healthcheck is healthy.', [], {}) - func = FindAction() + func = None + for a in hc.actions: + if a.__name__ == action: + func = a + break - if not func: + if func is None: return ACTION_INFO(action, 'Action not recognized.', [], {}) # Collect information on the repair action. @@ -445,11 +450,12 @@ class CheckFileManager(object): return ACTION_INFO(action, info, args, kwargs) - def RepairService(self, service, action, args, kwargs): + def RepairService(self, service, healthcheck, action, args, kwargs): """Execute the repair action on the specified service. Args: service: The name of the service to be repaired. + healthcheck: The particular healthcheck we are repairing. action: The name of the action to execute. args: A list of positional arguments for the given repair action. kwargs: A dictionary of keyword arguments for the given repair action. @@ -464,14 +470,18 @@ class CheckFileManager(object): elif isServiceHealthy(status): return self.GetStatus(service) - # Check that at least one unhealthy/quasi-healthy check specifies this - # repair action. Actions are assumed to be service-centric at this point. + # No repair occurs if the healthcheck is not specifed or perfectly healthy. + hc = [x for x in status.healthchecks if x.name == healthcheck] + if not hc or isHealthcheckHealthy(hc[0]): + return SERVICE_STATUS(healthcheck, False, []) + hc = hc[0] + + # Get the repair action from the healthcheck. repair_func = None - for hc in status.healthchecks: - for action_func in hc.actions: - if action == action_func.__name__: - repair_func = action_func - break + for a in hc.actions: + if a.__name__ == action: + repair_func = a + break # TODO (msartori): Implement crbug.com/503373 if repair_func is not None: diff --git a/mobmonitor/checkfile/manager_unittest.py b/mobmonitor/checkfile/manager_unittest.py index aa71bbead..d666bb9d6 100644 --- a/mobmonitor/checkfile/manager_unittest.py +++ b/mobmonitor/checkfile/manager_unittest.py @@ -741,6 +741,7 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): cfm.service_states[TEST_SERVICE_NAME] = healthy_status self.assertEquals(healthy_status, cfm.RepairService(TEST_SERVICE_NAME, + 'HealthcheckName', 'RepairFuncName', [], {})) @@ -751,7 +752,8 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): self.assertFalse(TEST_SERVICE_NAME in cfm.service_states) expected = manager.SERVICE_STATUS(TEST_SERVICE_NAME, False, []) - result = cfm.RepairService(TEST_SERVICE_NAME, 'DummyAction', [], {}) + result = cfm.RepairService(TEST_SERVICE_NAME, 'DummyHealthcheck', + 'DummyAction', [], {}) self.assertEquals(expected, result) def testRepairServiceInvalidAction(self): @@ -772,7 +774,8 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): self.assertFalse(status.health) self.assertEquals(1, len(status.healthchecks)) - status = cfm.RepairService(TEST_SERVICE_NAME, 'Blah', [], {}) + status = cfm.RepairService(TEST_SERVICE_NAME, hcobj.__class__.__name__, + 'Blah', [], {}) self.assertFalse(status.health) self.assertEquals(1, len(status.healthchecks)) @@ -794,7 +797,8 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): self.assertFalse(status.health) self.assertEquals(1, len(status.healthchecks)) - status = cfm.RepairService(TEST_SERVICE_NAME, 'Repair', [1, 2, 3], {}) + status = cfm.RepairService(TEST_SERVICE_NAME, hcobj.__class__.__name__, + 'Repair', [1, 2, 3], {}) self.assertFalse(status.health) self.assertEquals(1, len(status.healthchecks)) @@ -816,7 +820,9 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): self.assertFalse(status.health) self.assertEquals(1, len(status.healthchecks)) - status = cfm.RepairService(TEST_SERVICE_NAME, hcobj.Repair.__name__, + status = cfm.RepairService(TEST_SERVICE_NAME, + hcobj.__class__.__name__, + hcobj.Repair.__name__, [], {}) self.assertTrue(status.health) self.assertEquals(0, len(status.healthchecks)) @@ -829,7 +835,7 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): expect = manager.ACTION_INFO('test', 'Service not recognized.', [], {}) - result = cfm.ActionInfo(TEST_SERVICE_NAME, 'test') + result = cfm.ActionInfo(TEST_SERVICE_NAME, 'test', 'test') self.assertEquals(expect, result) def testActionInfoServiceHealthy(self): @@ -841,7 +847,7 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): expect = manager.ACTION_INFO('test', 'Service is healthy.', [], {}) - result = cfm.ActionInfo(TEST_SERVICE_NAME, 'test') + result = cfm.ActionInfo(TEST_SERVICE_NAME, 'test', 'test') self.assertEquals(expect, result) def testActionInfoActionNonExistent(self): @@ -859,7 +865,8 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): cfm.service_states[TEST_SERVICE_NAME] = unhealthy_status expect = manager.ACTION_INFO('test', 'Action not recognized.', [], {}) - result = cfm.ActionInfo(TEST_SERVICE_NAME, 'test') + result = cfm.ActionInfo(TEST_SERVICE_NAME, hcobj.__class__.__name__, + 'test') self.assertEquals(expect, result) def testActionInfo(self): @@ -867,38 +874,41 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase): cfm = manager.CheckFileManager(checkdir=CHECKDIR) hcobj = TestHealthCheckMultipleActions() + hcname = hcobj.__class__.__name__ actions = [hcobj.NoParams, hcobj.PositionalParams, hcobj.DefaultParams, hcobj.MixedParams] - cfm.service_checks[TEST_SERVICE_NAME] = { - hcobj.__class__.__name__: (TEST_MTIME, hcobj)} + cfm.service_checks[TEST_SERVICE_NAME] = {hcname: (TEST_MTIME, hcobj)} unhealthy_status = manager.SERVICE_STATUS( TEST_SERVICE_NAME, False, - [manager.HEALTHCHECK_STATUS(hcobj.__class__.__name__, - False, 'Always fails', actions)]) + [manager.HEALTHCHECK_STATUS(hcname, False, 'Always fails', actions)]) cfm.service_states[TEST_SERVICE_NAME] = unhealthy_status # Test ActionInfo when the action has no parameters. expect = manager.ACTION_INFO('NoParams', 'NoParams Action.', [], {}) - self.assertEquals(expect, cfm.ActionInfo(TEST_SERVICE_NAME, 'NoParams')) + self.assertEquals(expect, + cfm.ActionInfo(TEST_SERVICE_NAME, hcname, 'NoParams')) # Test ActionInfo when the action has only positional parameters. expect = manager.ACTION_INFO('PositionalParams', 'PositionalParams Action.', ['x', 'y', 'z'], {}) self.assertEquals(expect, - cfm.ActionInfo(TEST_SERVICE_NAME, 'PositionalParams')) + cfm.ActionInfo(TEST_SERVICE_NAME, + hcname, 'PositionalParams')) # Test ActionInfo when the action has only default parameters. expect = manager.ACTION_INFO('DefaultParams', 'DefaultParams Action.', [], {'x': 1, 'y': 2, 'z': 3}) self.assertEquals(expect, - cfm.ActionInfo(TEST_SERVICE_NAME, 'DefaultParams')) + cfm.ActionInfo(TEST_SERVICE_NAME, + hcname, 'DefaultParams')) # Test ActionInfo when the action has positional and default parameters. expect = manager.ACTION_INFO('MixedParams', 'MixedParams Action.', ['x', 'y'], {'z': 1}) - self.assertEquals(expect, cfm.ActionInfo(TEST_SERVICE_NAME, 'MixedParams')) + self.assertEquals(expect, cfm.ActionInfo(TEST_SERVICE_NAME, + hcname, 'MixedParams')) @cros_test_lib.NetworkTest() diff --git a/mobmonitor/rpc/rpc.py b/mobmonitor/rpc/rpc.py index 1b9140fcb..4d1b9d90f 100644 --- a/mobmonitor/rpc/rpc.py +++ b/mobmonitor/rpc/rpc.py @@ -105,7 +105,7 @@ class RpcExecutor(object): return self.Execute('GetStatus', service=service) - def ActionInfo(self, service=None, action=None): + def ActionInfo(self, service=None, healthcheck=None, action=None): """Collect argument and usage information for |action|. See checkfile.manager.ActionInfo for more documentation on the @@ -113,7 +113,8 @@ class RpcExecutor(object): Args: service: A string. The name of a service being monitored. - action: A string. The name of an action returned by some healthcheck's + healthcheck: A string. The name of a healthcheck belonging to |service|. + action: A string. The name of an action returned by |healthcheck|'s Diagnose method. Returns: @@ -123,18 +124,22 @@ class RpcExecutor(object): args: A list of the positional arguments for |action|. kwargs: A dictionary of default arguments for |action|. """ - if service is None or action is None: - raise RpcError('ActionInfo requires both the service' - ' and action to be provided.' - ' Given: service=%s action=%s' % (service, action)) + if any([x is None for x in [service, healthcheck, action]]): + raise RpcError('ActionInfo requires the service, the healthcheck' + ' and the action to be provided.' + ' Given: service=%s healthcheck=%s action=%s' % ( + service, healthcheck, action)) - return self.Execute('ActionInfo', service=service, action=action) + return self.Execute('ActionInfo', service=service, healthcheck=healthcheck, + action=action) - def RepairService(self, service=None, action=None, args=None, kwargs=None): + def RepairService(self, service=None, healthcheck=None, action=None, + args=None, kwargs=None): """Apply the specified action to the specified service. Args: service: A string. The service to repair. + healthcheck: A string. The healthcheck of |service| that we are fixing. action: A string. The action to take. args: The positional argument inputs to the repair action. kwargs: The keyword argument inputs to the repair action. @@ -142,13 +147,15 @@ class RpcExecutor(object): Returns: The same output of running get_status(service=service). """ - if service is None or action is None: - raise RpcError('repair_service requires both the service' - ' and action to be provided.' - ' Given: service="%s" action="%s"' % (service, action)) + if any([x is None for x in [service, healthcheck, action]]): + raise RpcError('RepairService requires the service, the healthcheck' + ' and the action to be provided.' + ' Given: service=%s healthcheck=%s action=%s' % ( + service, healthcheck, action)) args = [] if args is None else args kwargs = {} if kwargs is None else kwargs - return self.Execute('RepairService', service=service, action=action, - args=args, kwargs=kwargs) + return self.Execute('RepairService', service=service, + healthcheck=healthcheck, action=action, args=args, + kwargs=kwargs) diff --git a/mobmonitor/scripts/mobmoncli.py b/mobmonitor/scripts/mobmoncli.py index f69871984..45c42663a 100755 --- a/mobmonitor/scripts/mobmoncli.py +++ b/mobmonitor/scripts/mobmoncli.py @@ -56,12 +56,13 @@ class MobMonCli(object): self.host = host self.port = remote_access.NormalizePort(port) - def ExecuteRequest(self, request, service, action, inputs): + def ExecuteRequest(self, request, service, healthcheck, action, inputs): """Execute the request if an appropriate RPC function is defined. Args: request: The name of the RPC. service: The name of the service involved in the RPC. + healthcheck: The name of the healthcheck involved in the RPC. action: The action to be performed. inputs: A string. The inputs of the specified repair action. """ @@ -79,17 +80,20 @@ class MobMonCli(object): return rpcexec.GetStatus(service=service) if 'ActionInfo' == request: - return rpcexec.ActionInfo(service=service, action=action) + return rpcexec.ActionInfo(service=service, healthcheck=healthcheck, + action=action) if 'RepairService' == request: - return rpcexec.RepairService(service=service, action=action, args=args, - kwargs=kwargs) + return rpcexec.RepairService(service=service, healthcheck=healthcheck, + action=action, args=args, kwargs=kwargs) def ParseArguments(argv): parser = commandline.ArgumentParser() parser.add_argument('request', choices=rpc.RPC_LIST) parser.add_argument('-s', '--service', help='The service to act upon.') + parser.add_argument('-c', '--healthcheck', + help='The healthcheck to act upon.') parser.add_argument('-a', '--action', help='The action to execute.') parser.add_argument('--host', default='localhost', help='The hostname of the Mob* Monitor.') @@ -115,7 +119,8 @@ def main(argv): cli = MobMonCli(options.host, options.port) result = cli.ExecuteRequest(options.request, options.service, - options.action, options.inputs) + options.healthcheck, options.action, + options.inputs) print(result) diff --git a/mobmonitor/scripts/mobmoncli_unittest.py b/mobmonitor/scripts/mobmoncli_unittest.py index cd4ad3699..5e3857790 100644 --- a/mobmonitor/scripts/mobmoncli_unittest.py +++ b/mobmonitor/scripts/mobmoncli_unittest.py @@ -46,14 +46,14 @@ class MobMonCliTest(cros_test_lib.MockTestCase): def testBadRequest(self): """Test that we error when an unrecognized request is passed.""" with self.assertRaises(rpc.RpcError): - self.cli.ExecuteRequest('InvalidRequest', 'TestService', '', '') + self.cli.ExecuteRequest('InvalidRequest', 'TestService', '', '', '') def testGetServiceList(self): """Test that we correctly execute a GetServiceList RPC.""" with mock.patch('chromite.mobmonitor.rpc.rpc.RpcExecutor') as rpc_executor: mock_executor = mock.MagicMock() rpc_executor.return_value = mock_executor - self.cli.ExecuteRequest('GetServiceList', 'TestService', '', '') + self.cli.ExecuteRequest('GetServiceList', 'TestService', '', '', '') self.assertTrue(mock_executor.GetServiceList.called) def testGetStatus(self): @@ -61,7 +61,7 @@ class MobMonCliTest(cros_test_lib.MockTestCase): with mock.patch('chromite.mobmonitor.rpc.rpc.RpcExecutor') as rpc_executor: mock_executor = mock.MagicMock() rpc_executor.return_value = mock_executor - self.cli.ExecuteRequest('GetStatus', 'TestService', '', '') + self.cli.ExecuteRequest('GetStatus', 'TestService', '', '', '') self.assertTrue(mock_executor.GetStatus.called) def testActionInfo(self): @@ -69,7 +69,8 @@ class MobMonCliTest(cros_test_lib.MockTestCase): with mock.patch('chromite.mobmonitor.rpc.rpc.RpcExecutor') as rpc_executor: mock_executor = mock.MagicMock() rpc_executor.return_value = mock_executor - self.cli.ExecuteRequest('ActionInfo', 'TestService', 'action', '') + self.cli.ExecuteRequest('ActionInfo', 'TestService', + 'healthcheck', 'action', '') self.assertTrue(mock_executor.ActionInfo.called) def testRepairService(self): @@ -77,5 +78,5 @@ class MobMonCliTest(cros_test_lib.MockTestCase): with mock.patch('chromite.mobmonitor.rpc.rpc.RpcExecutor') as rpc_executor: mock_executor = mock.MagicMock() rpc_executor.return_value = mock_executor - self.cli.ExecuteRequest('RepairService', 'TestService', '', '') + self.cli.ExecuteRequest('RepairService', 'TestService', '', '', '') self.assertTrue(mock_executor.RepairService.called) diff --git a/mobmonitor/scripts/mobmonitor.py b/mobmonitor/scripts/mobmonitor.py index 64ba0f27f..2bc70b874 100755 --- a/mobmonitor/scripts/mobmonitor.py +++ b/mobmonitor/scripts/mobmonitor.py @@ -75,26 +75,28 @@ class MobMonitorRoot(object): return json.dumps(result) @cherrypy.expose - def ActionInfo(self, service, action): + def ActionInfo(self, service, healthcheck, action): """Return usage and argument information for |action|. Args: service: A string. The name of a service being monitored. + healthcheck: A string. The name of the healthcheck the action belongs to. action: A string. The name of an action specified by some healthcheck's Diagnose method. Returns: TBD """ - result = self.checkfile_manager.ActionInfo(service, action) + result = self.checkfile_manager.ActionInfo(service, healthcheck, action) return json.dumps(manager.MapActionInfoToDict(result)) @cherrypy.expose - def RepairService(self, service, action, args, kwargs): + def RepairService(self, service, healthcheck, action, args, kwargs): """Execute the repair action on the specified service. Args: service: The service that the specified action will be applied to. + healthcheck: The particular healthcheck we are repairing. action: The action to be applied. args: A list of the positional arguments for the given repair action. kwargs: A dictionary of keyword arguments for the given repair action. @@ -105,7 +107,8 @@ class MobMonitorRoot(object): args = json.loads(args.replace('\'', '"')) kwargs = json.loads(kwargs.replace('\'', '"')) - status = self.checkfile_manager.RepairService(service, action, args, kwargs) + status = self.checkfile_manager.RepairService(service, healthcheck, action, + args, kwargs) return json.dumps(manager.MapServiceStatusToDict(status)) diff --git a/mobmonitor/scripts/mobmonitor_unittest.py b/mobmonitor/scripts/mobmonitor_unittest.py index 731f63da7..6fc35b180 100644 --- a/mobmonitor/scripts/mobmonitor_unittest.py +++ b/mobmonitor/scripts/mobmonitor_unittest.py @@ -38,11 +38,11 @@ class MockCheckFileManager(object): return self.service_statuses[0] - def ActionInfo(self, _service, _action): + def ActionInfo(self, _service, _healthcheck, _action): """Mock ActionInfo response.""" return self.action_info - def RepairService(self, _service, _action, _args, _kwargs): + def RepairService(self, _service, _healthcheck, _action, _args, _kwargs): """Mock RepairService response.""" return self.service_statuses[0] @@ -93,7 +93,9 @@ class MobMonitorRootTest(cros_test_lib.MockTempDirTestCase): expect = {'action': 'DummyAction', 'info': '', 'args': ['x'], 'kwargs': {}} self.assertEquals(expect, - json.loads(root.ActionInfo('service2', 'DummyAction'))) + json.loads(root.ActionInfo('service2', + 'dummy_healthcheck', + 'DummyAction'))) def testRepairService(self): """Test the RepairService RPC.""" @@ -107,6 +109,7 @@ class MobMonitorRootTest(cros_test_lib.MockTempDirTestCase): string_kwargs = '{"a": 1}' self.assertEquals(expect, json.loads(root.RepairService('dummy_service', + 'dummy_healthcheck', 'dummy_action', string_args, string_kwargs))) diff --git a/mobmonitor/static/css/style.css b/mobmonitor/static/css/style.css index 18becf5ed..1df111899 100644 --- a/mobmonitor/static/css/style.css +++ b/mobmonitor/static/css/style.css @@ -114,8 +114,7 @@ td { width: 35%; } -.healthcheck { - background-color: grey; +.healthcheck-info { } .run-repair-action { diff --git a/mobmonitor/static/js/main.js b/mobmonitor/static/js/main.js index 40ba4e6aa..ec1fad689 100644 --- a/mobmonitor/static/js/main.js +++ b/mobmonitor/static/js/main.js @@ -26,6 +26,7 @@ $(document).ready(function() { $(document).on('click', '.run-repair-action', function() { // Retrieve the service and action for this repair button. var action = $(this).attr('action'); + var healthcheck = $(this).closest('.healthcheck-info').attr('hcname'); var service = $(this).closest('.health-container').attr('id'); if (service.indexOf(SERVICE_CONTAINER_PREFIX) === 0) { service = service.replace(SERVICE_CONTAINER_PREFIX, ''); @@ -40,15 +41,17 @@ $(document).ready(function() { $('#healthStatusDisplay').healthDisplay('markStale', response.service); } - rpcActionInfo(service, action, function(response) { + rpcActionInfo(service, healthcheck, action, function(response) { if (isEmpty(response.args) && isEmpty(response.kwargs)) { - rpcRepairService(service, action, [], {}, repairServiceCallback); + rpcRepairService(service, healthcheck, action, + [], {}, repairServiceCallback); return; } var dialog = new ActionRepairDialog(service, response); dialog.submitHandler = function(service, action, args, kwargs) { - rpcRepairService(service, action, args, kwargs, repairServiceCallback); + rpcRepairService(service, healthcheck, action, + args, kwargs, repairServiceCallback); }; dialog.open(); }); diff --git a/mobmonitor/static/js/rpc.js b/mobmonitor/static/js/rpc.js index 1556c6e49..7b27e606e 100644 --- a/mobmonitor/static/js/rpc.js +++ b/mobmonitor/static/js/rpc.js @@ -13,27 +13,34 @@ function rpcGetStatus(service, callback) { $.getJSON('/GetStatus', {service: service}, callback); } -function rpcActionInfo(service, action, callback) { +function rpcActionInfo(service, healthcheck, action, callback) { var data = { service: service, + healthcheck: healthcheck, action: action }; $.getJSON('/ActionInfo', data, callback); } -function rpcRepairService(service, action, args, kwargs, callback) { +function rpcRepairService(service, healthcheck, action, + args, kwargs, callback) { if (isEmpty(service)) throw new InvalidRpcArgumentError( 'Must specify service in RepairService RPC'); + if (isEmpty(healthcheck)) + throw new InvalidRpcArgumentError( + 'Must specify healthcheck in RepairService RPC'); + if (isEmpty(action)) throw new InvalidRpcArgumentError( 'Must specify action in RepairService RPC'); var data = { service: service, + healthcheck: healthcheck, action: action, args: JSON.stringify(args), kwargs: JSON.stringify(kwargs) diff --git a/mobmonitor/static/templates/healthstatuscontainer.html b/mobmonitor/static/templates/healthstatuscontainer.html index 607294a17..2840094c4 100644 --- a/mobmonitor/static/templates/healthstatuscontainer.html +++ b/mobmonitor/static/templates/healthstatuscontainer.html @@ -30,7 +30,7 @@ <td class="bold healthcheck-table-column2">Recommended Action(s)</td> </tr> {{#each errors}} - <tr> + <tr class="healthcheck-info" hcname="{{name}}"> <td>{{description}}</td> <td> <ul> @@ -58,7 +58,7 @@ <td class="bold healthcheck-table-column2">Recommended Action(s)</td> </tr> {{#each warnings}} - <tr> + <tr class="healthcheck-info" hcname="{{name}}"> <td>{{description}}</td> <td> <ul> |