blob: f1e11d7d545590bac7433dba80815461e6366cf5 [file] [log] [blame]
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# 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 os
import sys
import logging
import logging.handlers
import argparse
from cherrypy.lib.static import serve_file
from checkfile import manager
from util import collect_logs
STATICDIR = '/usr/local/moblab/mobmonitor/static/'
LOGDIR = '/var/log/mobmonitor/'
LOGFILE = 'mobmonitor.log'
LOGFILE_SIZE_BYTES = 1024 * 1024
class MobMonitorRoot(object):
"""The central object supporting the Mob* Monitor web interface."""
def __init__(self, checkfile_manager, staticdir=STATICDIR):
if not os.path.exists(staticdir):
raise IOError('Static directory does not exist: %s' % staticdir)
self.staticdir = staticdir
self.checkfile_manager = checkfile_manager
def index(self):
"""Presents a welcome message."""
raise cherrypy.HTTPRedirect('/static/index.html')
def GetServiceList(self):
"""Return a list of the monitored services.
A list of the monitored services.
return json.dumps(self.checkfile_manager.GetServiceList())
def GetStatus(self, service=None):
"""Return the health status of the specified service.
service: The service whose health status is being queried. If service
is None, return the health status of all monitored services.
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)
def ActionInfo(self, service, healthcheck, action):
"""Return usage and argument information for |action|.
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.
result = self.checkfile_manager.ActionInfo(service, healthcheck, action)
return json.dumps(manager.MapActionInfoToDict(result))
def RepairService(self, service, healthcheck, action, params):
"""Execute the repair action on the specified service.
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.
# The mobmonitor's RPC library encodes arguments as strings when
# making a remote call to the monitor. The checkfile manager expects
# lists and dicts for the arugments, so we convert them here.
params = json.loads(params.replace('\'', '"'))
status = self.checkfile_manager.RepairService(service, healthcheck, action,
return json.dumps(manager.MapServiceStatusToDict(status))
def CollectLogs(self):
tarfile = collect_logs.collect_logs()
return serve_file(tarfile, 'application/x-download',
'attachment', os.path.basename(tarfile))
def SetupLogging(logdir):
format='%(asctime)s:%(name)s:%(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M',
filename=os.path.join(logdir, LOGFILE),
rotate = logging.handlers.RotatingFileHandler(
os.path.join(logdir, LOGFILE), maxBytes=LOGFILE_SIZE_BYTES,
def ParseArguments(argv):
"""Creates the argument parser."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-d', '--checkdir',
help='The Mob* Monitor checkfile directory.')
parser.add_argument('-p', '--port', type=int, default=9991,
help='The Mob* Monitor port.')
parser.add_argument('-s', '--staticdir', default=STATICDIR,
help='Mob* Monitor web ui static content directory')
parser.add_argument('--logdir', dest='logdir', default=LOGDIR,
help='Mob* Monitor log file directory.')
return parser.parse_args(argv)
def _validate_port(check_port):
port = int(check_port)
if port <= 0 or port >= 65536:
raise ValueError('%d is not a valid port' % port)
return port
def main(argv):
options = ParseArguments(argv)
# Configure logger.
# Configure global cherrypy parameters.
{'server.socket_host': '',
'server.socket_port': _validate_port(options.port)
mobmon_appconfig = {
{'tools.staticdir.root': options.staticdir
{'tools.staticdir.on': True,
'tools.staticdir.dir': ''
{'tools.staticdir.dir': 'css'
{'tools.staticdir.dir': 'js'
# Setup the mobmonitor
checkfile_manager = manager.CheckFileManager(checkdir=options.checkdir)
mobmonitor = MobMonitorRoot(checkfile_manager, staticdir=options.staticdir)
# Start the checkfile collection and execution background task.
# Start the Mob* Monitor.
cherrypy.quickstart(mobmonitor, config=mobmon_appconfig)
if __name__ == '__main__':