summaryrefslogtreecommitdiff
path: root/mobmonitor
diff options
context:
space:
mode:
authorMatthew Sartori <msartori@chromium.org>2015-07-09 17:18:30 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-15 23:15:37 +0000
commitaf96c840889ef457c3f897e3f94e2ad9912ed833 (patch)
tree4912a4b711c137179536dad357d800c6153abcf6 /mobmonitor
parent355c6cee60e0a1abe8d7907ad4c186c6024a2e83 (diff)
downloadchromite-af96c840889ef457c3f897e3f94e2ad9912ed833.tar.gz
mobmonitor: Changes for deploying Mob* Monitor to moblab
This CL re-organizes the mobmonitor project so that all scripts are located under the mobmonitor directory, rather than under chromite/scripts. Mob* Monitor related executables have been removed from chromite/bin. Some changes were made to account for import path changes. BUG=chromium:507898 TEST=Unittests. Change-Id: Ieee4da6fcef59a18c63d612eb9efbea6f01734be Reviewed-on: https://chromium-review.googlesource.com/284675 Reviewed-by: Matthew Sartori <msartori@chromium.org> Tested-by: Matthew Sartori <msartori@chromium.org> Commit-Queue: Matthew Sartori <msartori@chromium.org>
Diffstat (limited to 'mobmonitor')
-rw-r--r--mobmonitor/checkfile/manager_unittest.py6
-rw-r--r--mobmonitor/scripts/__init__.py0
-rwxr-xr-xmobmonitor/scripts/mobmoncli.py77
-rwxr-xr-xmobmonitor/scripts/mobmonitor.py106
l---------mobmonitor/scripts/mobmonitor_unittest1
-rw-r--r--mobmonitor/scripts/mobmonitor_unittest.py83
6 files changed, 270 insertions, 3 deletions
diff --git a/mobmonitor/checkfile/manager_unittest.py b/mobmonitor/checkfile/manager_unittest.py
index 66dea410d..be149f0d6 100644
--- a/mobmonitor/checkfile/manager_unittest.py
+++ b/mobmonitor/checkfile/manager_unittest.py
@@ -758,8 +758,8 @@ class CheckFileManagerTest(cros_test_lib.MockTestCase):
class CheckFileModificationTest(cros_test_lib.MockTempDirTestCase):
"""Unittests for checking when live changes are made to a checkfile."""
- MOBMONITOR_BASENAME = 'chromite'
- MOBMONITOR_REL_CMD = 'bin/mobmonitor'
+ MOBMONITOR_BASENAME = 'mobmonitor'
+ MOBMONITOR_REL_CMD = 'scripts/mobmonitor.py'
SERVICE_DIR = 'test_service'
CHECKFILE_REL_PATH = 'test_check.py'
NOTACHECK_REL_PATH = 'notacheck.py'
@@ -835,7 +835,7 @@ class CheckFileModificationTest(cros_test_lib.MockTempDirTestCase):
while os.path.basename(path) != self.MOBMONITOR_BASENAME:
path = os.path.dirname(path)
path = os.path.join(path, self.MOBMONITOR_REL_CMD)
- self.cmd = [path, '-d', self.checkdir]
+ self.cmd = ['python', path, '-d', self.checkdir]
# Setup an rpc client for communicating with the Mob* Monitor.
self.rpc = rpc.RpcExecutor()
diff --git a/mobmonitor/scripts/__init__.py b/mobmonitor/scripts/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/mobmonitor/scripts/__init__.py
diff --git a/mobmonitor/scripts/mobmoncli.py b/mobmonitor/scripts/mobmoncli.py
new file mode 100755
index 000000000..909c014c2
--- /dev/null
+++ b/mobmonitor/scripts/mobmoncli.py
@@ -0,0 +1,77 @@
+#!/usr/bin/python2
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Command-line interface for the Mob* Monitor."""
+
+from __future__ import print_function
+
+import sys
+
+from chromite.lib import commandline
+from chromite.lib import remote_access
+from chromite.mobmonitor.rpc import rpc
+
+
+class MobMonCli(object):
+ """Provides command-line functionality for using the Mob* Monitor."""
+
+ def __init__(self, host='localhost', port=9999):
+ self.host = host
+ self.port = remote_access.NormalizePort(port)
+
+ def ExecuteRequest(self, request, service, action):
+ """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.
+ action: The action to be performed.
+ """
+ rpcexec = rpc.RpcExecutor(self.host, self.port)
+
+ if not hasattr(rpcexec, request):
+ raise rpc.RpcError('The request "%s" is not recognized.' % request)
+
+ if 'GetServiceList' == request:
+ return rpcexec.GetServiceList()
+
+ if 'GetStatus' == request:
+ return rpcexec.GetStatus(service=service)
+
+ if 'RepairService' == request:
+ return rpcexec.RepairService(service=service, action=action)
+
+
+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('-a', '--action', help='The action to execute')
+ parser.add_argument('--host', default='localhost',
+ help='The hostname of the Mob* Monitor.')
+ parser.add_argument('-p', '--port', type=int, default=9999,
+ help='The Mob* Monitor port.')
+
+ return parser.parse_args(argv)
+
+
+def main(argv):
+ """Command line interface for the Mob* Monitor.
+
+ The basic syntax is:
+ mobmon <request> [args]
+ mobmon --help
+ """
+ options = ParseArguments(argv)
+
+ cli = MobMonCli(options.host, options.port)
+ result = cli.ExecuteRequest(options.request, options.service,
+ options.action)
+
+ print(result)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/mobmonitor/scripts/mobmonitor.py b/mobmonitor/scripts/mobmonitor.py
new file mode 100755
index 000000000..329fac18f
--- /dev/null
+++ b/mobmonitor/scripts/mobmonitor.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python2
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The Mob* Monitor web interface."""
+
+from __future__ import print_function
+
+import cherrypy
+import json
+import sys
+
+from chromite.lib import remote_access
+from chromite.lib import commandline
+from chromite.mobmonitor.checkfile import manager
+
+
+class MobMonitorRoot(object):
+ """The central object supporting the Mob* Monitor web interface."""
+
+ def __init__(self, checkfile_manager):
+ self.checkfile_manager = checkfile_manager
+
+ @cherrypy.expose
+ def index(self):
+ """Presents a welcome message."""
+ return 'Welcome to the Mob* Monitor!'
+
+ @cherrypy.expose
+ def GetServiceList(self):
+ """Return a list of the monitored services.
+
+ Returns:
+ A list of the monitored services.
+ """
+ return json.dumps(self.checkfile_manager.GetServiceList())
+
+ @cherrypy.expose
+ def GetStatus(self, service=None):
+ """Return the health status of the specified service.
+
+ Args:
+ service: The service whose health status is being queried. If service
+ is None, return the health status of all monitored services.
+
+ Returns:
+ A list of dictionaries. Each dictionary contains the keys:
+ service: The name of the service.
+ health: A boolean describing the overall service health.
+ healthchecks: A list of unhealthy or quasi-healthy health checks.
+ """
+ service_statuses = self.checkfile_manager.GetStatus(service)
+ if not isinstance(service_statuses, list):
+ service_statuses = [service_statuses]
+
+ result = [
+ manager.MapServiceStatusToDict(status) for status in service_statuses]
+ return json.dumps(result)
+
+ # TODO (msartori): Implement crbug.com/505066.
+ @cherrypy.expose
+ def RepairService(self, service, action):
+ """Execute the repair action on the specified service.
+
+ Args:
+ service: The service that the specified action will be applied to.
+ action: The action to be applied.
+ """
+ status = self.checkfile_manager.RepairService(service, action)
+ return json.dumps(manager.MapServiceStatusToDict(status))
+
+
+def ParseArguments(argv):
+ """Creates the argument parser."""
+ parser = commandline.ArgumentParser(description=__doc__)
+
+ parser.add_argument('-d', '--checkdir',
+ default='/etc/mobmonitor/checkfiles/',
+ help='The Mob* Monitor checkfile directory.')
+ parser.add_argument('-p', '--port', type=int, default=9999,
+ help='The Mob* Monitor port.')
+
+ return parser.parse_args(argv)
+
+
+def main(argv):
+ options = ParseArguments(argv)
+ options.Freeze()
+
+ # Start the Mob* Monitor web interface.
+ cherrypy.config.update({'server.socket_port':
+ remote_access.NormalizePort(options.port)})
+
+ # Setup the mobmonitor
+ checkfile_manager = manager.CheckFileManager(checkdir=options.checkdir)
+ mobmonitor = MobMonitorRoot(checkfile_manager)
+
+ # Start the checkfile collection and execution background task.
+ checkfile_manager.StartCollectionExecution()
+
+ cherrypy.quickstart(mobmonitor)
+
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/mobmonitor/scripts/mobmonitor_unittest b/mobmonitor/scripts/mobmonitor_unittest
new file mode 120000
index 000000000..ef3e37b67
--- /dev/null
+++ b/mobmonitor/scripts/mobmonitor_unittest
@@ -0,0 +1 @@
+../../scripts/wrapper.py \ No newline at end of file
diff --git a/mobmonitor/scripts/mobmonitor_unittest.py b/mobmonitor/scripts/mobmonitor_unittest.py
new file mode 100644
index 000000000..e2aa263b1
--- /dev/null
+++ b/mobmonitor/scripts/mobmonitor_unittest.py
@@ -0,0 +1,83 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Unittests for the main Mob* Monitor script."""
+
+from __future__ import print_function
+
+import json
+
+from chromite.lib import cros_test_lib
+from chromite.mobmonitor.checkfile import manager
+from chromite.mobmonitor.scripts import mobmonitor
+
+
+class MockCheckFileManager(object):
+ """Mock CheckFileManager object that returns 'real' responses for testing."""
+
+ def __init__(self):
+ failed_check = manager.HEALTHCHECK_STATUS('hc1', False, 'Failed', [])
+
+ self.service_statuses = [
+ manager.SERVICE_STATUS('service1', True, []),
+ manager.SERVICE_STATUS('service2', False, [failed_check])]
+
+ def GetServiceList(self):
+ """Mock GetServiceList response."""
+ return ['test_service_1', 'test_service_2']
+
+ def GetStatus(self, service=None):
+ """Mock GetStatus response."""
+ if service is None:
+ return self.service_statuses
+
+ return self.service_statuses[0]
+
+ def RepairService(self, _service, _action):
+ """Mock RepairService response."""
+ return self.service_statuses[0]
+
+
+class MobMonitorRootTest(cros_test_lib.MockTestCase):
+ """Unittests for the MobMonitorRoot."""
+
+ def testGetServiceList(self):
+ """Test the GetServiceList RPC."""
+ cfm = MockCheckFileManager()
+ root = mobmonitor.MobMonitorRoot(cfm)
+ self.assertEqual(cfm.GetServiceList(), json.loads(root.GetServiceList()))
+
+ def testGetStatus(self):
+ """Test the GetStatus RPC."""
+ cfm = MockCheckFileManager()
+ root = mobmonitor.MobMonitorRoot(cfm)
+
+ # Test the result for a single service.
+ status = cfm.service_statuses[0]
+ expect = {'service': status.service, 'health': status.health,
+ 'healthchecks': []}
+ self.assertEquals([expect], json.loads(root.GetStatus(status.service)))
+
+ # Test the result for multiple services.
+ status1, status2 = cfm.service_statuses
+ check = status2.healthchecks[0]
+ expect = [{'service': status1.service, 'health': status1.health,
+ 'healthchecks': []},
+ {'service': status2.service, 'health': status2.health,
+ 'healthchecks': [{'name': check.name, 'health': check.health,
+ 'description': check.description,
+ 'actions': []}]}]
+ self.assertEquals(expect, json.loads(root.GetStatus()))
+
+ def testRepairService(self):
+ """Test the RepairService RPC."""
+ cfm = MockCheckFileManager()
+ root = mobmonitor.MobMonitorRoot(cfm)
+
+ status = cfm.service_statuses[0]
+ expect = {'service': status.service, 'health': status.health,
+ 'healthchecks': []}
+ self.assertEquals(expect,
+ json.loads(root.RepairService('dummy_service',
+ 'dummy_action')))