def list_npm_modules(collector, no_print=False): """List the npm modules that get installed in a docker image for the react server""" default = ReactServer().default_npm_deps() for _, module in sorted(collector.configuration["__active_modules__"].items()): default.update(module.npm_deps()) if not no_print: print(json.dumps(default, indent=4, sort_keys=True)) return default
def __init__( self, host, port, debug, dashboards, modules, module_options, datastore, dynamic_dashboard_js, compiled_static_prep, compiled_static_folder, without_checks, ): self.thread_stopper = {"finished": False} self.host = host self.port = port self.modules = modules self.datastore = datastore self.dashboards = dashboards self.module_options = module_options self.without_checks = without_checks self.dynamic_dashboard_js = dynamic_dashboard_js self.compiled_static_prep = compiled_static_prep self.compiled_static_folder = compiled_static_folder self.react_server = ReactServer()
def collect_dashboard_js(collector): """Generate dashboard javascript for each dashboard""" dashmat = collector.configuration["dashmat"] modules = collector.configuration["__active_modules__"] compiled_static_prep = dashmat.compiled_static_prep compiled_static_folder = dashmat.compiled_static_folder npm_deps = list_npm_modules(collector, no_print=True) react_server = ReactServer() react_server.prepare(npm_deps, compiled_static_folder) for dashboard in collector.configuration["dashboards"].values(): log.info("Generating compiled javascript for dashboard:{0}".format(dashboard.path)) filename = dashboard.path.replace("_", "__").replace("/", "_") location = os.path.join(compiled_static_folder, "dashboards", "{0}.js".format(filename)) if os.path.exists(location): os.remove(location) generate_dashboard_js(dashboard, react_server, compiled_static_folder, compiled_static_prep, modules)
class Server(object): def __init__( self, host, port, debug, dashboards, modules, module_options, datastore, dynamic_dashboard_js, compiled_static_prep, compiled_static_folder, without_checks, ): self.thread_stopper = {"finished": False} self.host = host self.port = port self.modules = modules self.datastore = datastore self.dashboards = dashboards self.module_options = module_options self.without_checks = without_checks self.dynamic_dashboard_js = dynamic_dashboard_js self.compiled_static_prep = compiled_static_prep self.compiled_static_folder = compiled_static_folder self.react_server = ReactServer() def serve(self): http_server = HTTPServer(WSGIContainer(self.app)) scheduler = Scheduler(self.datastore) if not self.without_checks: for name, (module, server) in self.servers.items(): scheduler.register(module, server, name) try: if not self.without_checks: scheduler.start() http_server.listen(self.port, self.host) log.info("Starting server on http://%s:%s", self.host, self.port) try: IOLoop.instance().start() finally: self.thread_stopper["finished"] = True finally: scheduler.finish() @property def app(self): if getattr(self, "_app", None) is None: self._app = Flask("dashmat.server") # Remove auto generated static route while self._app.url_map._rules: self._app.url_map._rules.pop() for key in list(self._app.url_map._rules_by_endpoint): self._app.url_map._rules_by_endpoint.pop(key) self._app.url_map.update() self._app.view_functions.clear() self.servers = {} for name, module in self.modules.items(): self.servers[name] = (module, module.make_server(self.module_options[name].server_options)) # Register our own routes self.register_routes(self._app) if self.dynamic_dashboard_js: # Prepare the docker image for translating jsx into javascript deps = {} for _, module in sorted(self.modules.items()): deps.update(module.npm_deps()) self.react_server.prepare(deps, self.compiled_static_folder) return self._app def register_routes(self, app): class EverythingConverter(PathConverter): regex = ".*?" app.url_map.converters["everything"] = EverythingConverter def make_view(func, module, module_name): @wraps(func) def wrapper(*args, **kwargs): ds = self.datastore.prefixed("{0}-{1}".format(module.relative_to, module_name)) res = func(ds, *args, **kwargs) return flask.jsonify({"value": res}) return wrapper for name, (module, server) in self.servers.items(): try: for route_name, func in server.routes: view = make_view(func, module, name) view.__name__ = "server_route_{0}_{1}".format(name, route_name) route = "/data/{0}/{1}".format(name, route_name) log.info("Adding route %s", route) app.route(route)(view) except Exception as error: raise DashMatError("Failed to setup routes for a server", server=server, error=error) @app.route("/diagnostic/status/heartbeat", methods=["GET"]) def heartbeat(): return "" @app.route("/diagnostic/status/nagios", methods=["GET"]) def nagios(): return "OK" @app.route("/diagnostic/version", methods=["Get"]) def version(): static_dir = os.path.join(here, "static") return send_from_directory(static_dir, "version") @app.route("/static/dashboards/<everything:path>", methods=["GET"]) def static_dashboards(path): if path not in self.dashboards: raise abort(404) location = generate_dashboard_js( self.dashboards[path], self.react_server, self.compiled_static_folder, self.compiled_static_prep, self.modules, dynamic_dashboard_js=self.dynamic_dashboard_js, ) return send_from_directory(os.path.dirname(location), os.path.basename(location)) @app.route("/static/css/<import_path>/<path:name>", methods=["GET"]) def static_css(import_path, name): static_folder = pkg_resources.resource_filename(import_path, "static") static_file = os.path.join(static_folder, name) if os.path.exists(static_file): return send_from_directory(static_folder, name) else: raise abort(404) def make_dashboard(path, dashboard): def dashboard_view(): title = path.replace("/", " ").replace("_", " ").title() css = [] enabled_modules = list(dashboard.enabled_modules) for imprt in dashboard.imports: if hasattr(imprt, "module_name"): if isinstance(imprt.module_name, six.string_types): module = self.modules[imprt.module_name] elif isinstance(imprt.module_name, dict): module = imprt.module_name["import_path"] else: module = imprt.module_name enabled_modules.append(module) def add_dependencies(): added = False for module in enabled_modules: for dependency in module.dependencies(): if self.modules[dependency] not in enabled_modules: enabled_modules.append(self.modules[dependency]) added = True if added: add_dependencies() add_dependencies() first_state = {} for module in enabled_modules: css.extend(["/static/css/{0}/{1}".format(module.relative_to, c) for c in module.css()]) for name, (module, server) in self.servers.items(): for route_name, func in server.routes: route = "/data/{0}/{1}".format(name, route_name) ds = self.datastore.prefixed("{0}-{1}".format(module.relative_to, name)) first_state[route] = func(ds) return render_template( "index.html", dashboardjs="/static/dashboards/{0}".format(path), title=title, css=css, first_state=json.dumps(first_state), ) dashboard_view.__name__ = "dashboard_{0}".format(path.replace("_", "__").replace("/", "_")) return dashboard_view for path, dashboard in self.dashboards.items(): app.route(path, methods=["GET"])(make_dashboard(path, dashboard))