blob: e3fff64315e9ccef52b275603bac8b845342684c [file] [log] [blame]
#!/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 os
import sys
from cherrypy.lib.static import serve_file
from logging import handlers as logging_handlers
from chromite.lib import remote_access
from chromite.lib import commandline
from chromite.lib import cros_logging as logging
from chromite.mobmonitor.checkfile import manager
from chromite.mobmonitor.util import collect_logs
STATICDIR = '/etc/mobmonitor/static'
LOGDIR = '/var/log/mobmonitor/'
LOGFILE = 'mobmonitor.log'
LOGFILE_SIZE_BYTES = 1024 * 1024
LOGFILE_COUNT = 10
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
@cherrypy.expose
def index(self):
"""Presents a welcome message."""
return open(os.path.join(self.staticdir, 'templates', 'index.html'))
@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)
@cherrypy.expose
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, healthcheck, action)
return json.dumps(manager.MapActionInfoToDict(result))
@cherrypy.expose
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.
"""
# 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.
args = json.loads(args.replace('\'', '"'))
kwargs = json.loads(kwargs.replace('\'', '"'))
status = self.checkfile_manager.RepairService(service, healthcheck, action,
args, kwargs)
return json.dumps(manager.MapServiceStatusToDict(status))
@cherrypy.expose
def CollectLogs(self):
tarfile = collect_logs.collect_logs()
return serve_file(tarfile, 'application/x-download',
'attachment', os.path.basename(tarfile))
def SetupLogging(logdir):
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s:%(name)s:%(levelname)-8s %(message)s',
datefmt='%Y-%m-%d %H:%M',
filename=os.path.join(logdir, LOGFILE),
filemode='w'
)
rotate = logging_handlers.RotatingFileHandler(
os.path.join(logdir, LOGFILE), maxBytes=LOGFILE_SIZE_BYTES,
backupCount=LOGFILE_COUNT)
logging.getLogger().addHandler(rotate)
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=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', type='path', default=LOGDIR,
help='Mob* Monitor log file directory.')
return parser.parse_args(argv)
def main(argv):
options = ParseArguments(argv)
options.Freeze()
# Configure logger.
SetupLogging(options.logdir)
# Configure global cherrypy parameters.
cherrypy.config.update(
{'server.socket_host': '0.0.0.0',
'server.socket_port': remote_access.NormalizePort(options.port)
})
mobmon_appconfig = {
'/':
{'tools.staticdir.root': options.staticdir
},
'/static':
{'tools.staticdir.on': True,
'tools.staticdir.dir': ''
},
'/static/css':
{'tools.staticdir.dir': 'css'
},
'/static/js':
{'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.
checkfile_manager.StartCollectionExecution()
# Start the Mob* Monitor.
cherrypy.quickstart(mobmonitor, config=mobmon_appconfig)
if __name__ == '__main__':
main(sys.argv[1:])