blob: d72b06c8340d780597217a2ada99605207522dd9 [file] [log] [blame]
#!/usr/bin/env python2.7
# -*- encoding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
''' main.py '''
from __future__ import print_function
import logging
import os
import signal
import sys
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.log
import tornado.template
from tornado.httpclient import AsyncHTTPClient
from tornado.options import define
from tornado.web import url
import heron.common.src.python.utils.log as log
import heron.tools.common.src.python.utils.config as common_config
from heron.tools.ui.src.python import handlers
from heron.tools.ui.src.python import args
Log = log.Log
class Application(tornado.web.Application):
''' Application '''
def __init__(self, base_url):
# pylint: disable=fixme
# TODO: hacky solution
# sys.path[0] should be the path to the extracted files for heron-ui, as it is added
# when bootstrapping the pex file
static_prefix = '/static/'
if base_url != "":
static_prefix = os.path.join(base_url, 'static/')
AsyncHTTPClient.configure(None, defaults=dict(request_timeout=120.0))
Log.info("Using base url: %s", base_url)
settings = dict(
template_path=os.path.join(sys.path[0], "heron/tools/ui/resources/templates"),
static_path=os.path.join(sys.path[0], "heron/tools/ui/resources/static"),
static_url_prefix=static_prefix,
gzip=True,
debug=True,
default_handler_class=handlers.NotFoundHandler,
)
Log.info(os.path.join(base_url, 'static/'))
# Change these to query string parameters, since
# current format can lead to pattern matching issues.
callbacks = [
(r"/", handlers.MainHandler),
url(r"/topologies", handlers.ListTopologiesHandler, dict(baseUrl=base_url),
name='topologies'),
url(r"/topologies/filestats/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)",
handlers.ContainerFileStatsHandler, dict(baseUrl=base_url)),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/config",
handlers.TopologyConfigHandler, dict(baseUrl=base_url)),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/exceptions",
handlers.TopologyExceptionsPageHandler, dict(baseUrl=base_url)),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)",
handlers.TopologyPlanHandler, dict(baseUrl=base_url)),
# topology metric apis
(r"/topologies/metrics",
handlers.api.MetricsHandler),
(r"/topologies/metrics/timeline",
handlers.api.MetricsTimelineHandler),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/file",
handlers.ContainerFileHandler, dict(baseUrl=base_url)),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/filedata",
handlers.ContainerFileDataHandler, dict(baseUrl=base_url)),
url(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/filedownload",
handlers.ContainerFileDownloadHandler, dict(baseUrl=base_url)),
# Topology list and plan handlers
(r"/topologies/list.json",
handlers.api.ListTopologiesJsonHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/logicalplan.json",
handlers.api.TopologyLogicalPlanJsonHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/physicalplan.json",
handlers.api.TopologyPhysicalPlanJsonHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/executionstate.json",
handlers.api.TopologyExecutionStateJsonHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/schedulerlocation.json",
handlers.api.TopologySchedulerLocationJsonHandler),
# Counter Handlers
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/exceptions.json",
handlers.api.TopologyExceptionsJsonHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/exceptionsummary.json",
handlers.api.TopologyExceptionSummaryHandler),
# Heron shell Handlers
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/pid",
handlers.api.PidHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/jstack",
handlers.api.JstackHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/jmap",
handlers.api.JmapHandler),
(r"/topologies/([^\/]+)/([^\/]+)/([^\/]+)/([^\/]+)/histo",
handlers.api.MemoryHistogramHandler),
## Static files
(r"/static/(.*)", tornado.web.StaticFileHandler,
dict(path=settings['static_path']))
]
tornado.web.Application.__init__(self, callbacks, **settings)
def define_options(address, port, tracker_url, base_url):
'''
:param address:
:param port:
:param tracker_url:
:return:
'''
define("address", default=address)
define("port", default=port)
define("tracker_url", default=tracker_url)
define("base_url", default=base_url)
def main():
'''
:param argv:
:return:
'''
log.configure(logging.DEBUG)
tornado.log.enable_pretty_logging()
# create the parser and parse the arguments
(parser, child_parser) = args.create_parsers()
(parsed_args, remaining) = parser.parse_known_args()
if remaining:
r = child_parser.parse_args(args=remaining, namespace=parsed_args)
namespace = vars(r)
if 'version' in namespace:
common_config.print_build_info(zipped_pex=True)
else:
parser.print_help()
parser.exit()
# log additional information
command_line_args = vars(parsed_args)
Log.info("Listening at http://%s:%d%s", command_line_args['address'],
command_line_args['port'], command_line_args['base_url'])
Log.info("Using tracker url: %s", command_line_args['tracker_url'])
# pass the options to tornado and start the ui server
define_options(command_line_args['address'],
command_line_args['port'],
command_line_args['tracker_url'],
command_line_args['base_url'])
http_server = tornado.httpserver.HTTPServer(Application(command_line_args['base_url']))
http_server.listen(command_line_args['port'], address=command_line_args['address'])
# pylint: disable=unused-argument
# stop Tornado IO loop
def signal_handler(signum, frame):
# start a new line after ^C character because this looks nice
print('\n', end='')
Log.debug('SIGINT received. Stopping UI')
tornado.ioloop.IOLoop.instance().stop()
# associate SIGINT and SIGTERM with a handler
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# start Tornado IO loop
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()