Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dashboard can be served on a non-root path #79

Merged
merged 13 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 33 additions & 28 deletions karton/dashboard/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@
from typing import Any, Dict, List, Optional, Tuple

import mistune # type: ignore
from flask import ( # type: ignore
Flask,
jsonify,
redirect,
render_template,
request,
send_from_directory,
)
from flask import Flask, jsonify, redirect
from flask import render_template as flask_render_template # type: ignore
from flask import request, send_from_directory
from karton.core.backend import KartonMetrics
from karton.core.base import KartonBase
from karton.core.inspect import KartonAnalysis, KartonQueue, KartonState
Expand All @@ -43,13 +38,23 @@ class KartonDashboard(KartonBase):

karton = KartonDashboard()

base_path = (
karton.config.get("dashboard", "base_path")
if karton.config.has_option("dashboard", "base_path")
else ""
)
psrok1 marked this conversation as resolved.
Show resolved Hide resolved

markdown = mistune.create_markdown(
escape=True,
renderer="html",
plugins=["url", "strikethrough", "footnotes", "table"],
)


def render_template(template_name: str, **kwargs: Dict[str, Any]) -> str:
return flask_render_template(template_name, base_path=base_path, **kwargs)


def cancel_tasks(tasks: List[Task]) -> None:
for task in tasks:
karton.backend.set_task_status(task=task, status=TaskState.FINISHED)
Expand Down Expand Up @@ -191,7 +196,7 @@ def add_metrics(state: KartonState, metric: KartonMetrics, key: str) -> None:
karton_metrics.labels(key, name).set(value)


@app.route("/varz", methods=["GET"])
@app.route(base_path + "/varz", methods=["GET"])
def varz():
"""Update and get prometheus metrics"""

Expand All @@ -208,7 +213,7 @@ def varz():
task_infos[(safe_name, task.priority, task.status)] += 1

# set the default of active queues to 0 to avoid gaps in graphs
for (priority, status) in product(TaskPriority, TaskState):
for priority, status in product(TaskPriority, TaskState):
karton_tasks.labels(safe_name, priority.value, status.value).set(0)

for (name, priority, status), count in task_infos.items():
Expand All @@ -226,18 +231,18 @@ def varz():
return generate_latest()


@app.route("/static/<path:path>", methods=["GET"])
@app.route(base_path + "/static/<path:path>", methods=["GET"])
def static(path: str):
return send_from_directory(static_folder, path)


@app.route("/", methods=["GET"])
@app.route(base_path + "/", methods=["GET"])
def get_queues():
state = KartonState(karton.backend)
return render_template("index.html", queues=state.queues)


@app.route("/services", methods=["GET"])
@app.route(base_path + "/services", methods=["GET"])
def get_services():
aggregated_services = defaultdict(list)
online_services = karton.backend.get_online_services()
Expand All @@ -246,7 +251,7 @@ def get_services():
return render_template("services.html", services=aggregated_services)


@app.route("/api/queues", methods=["GET"])
@app.route(base_path + "/api/queues", methods=["GET"])
def get_queues_api():
state = KartonState(karton.backend)
return jsonify(
Expand All @@ -257,7 +262,7 @@ def get_queues_api():
)


@app.route("/<queue_name>/restart_crashed", methods=["POST"])
@app.route(base_path + "/<queue_name>/restart_crashed", methods=["POST"])
def restart_crashed_queue_tasks(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -269,7 +274,7 @@ def restart_crashed_queue_tasks(queue_name):
return redirect(request.referrer)


@app.route("/<queue_name>/cancel_crashed", methods=["POST"])
@app.route(base_path + "/<queue_name>/cancel_crashed", methods=["POST"])
def cancel_crashed_queue_tasks(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -280,7 +285,7 @@ def cancel_crashed_queue_tasks(queue_name):
return redirect(request.referrer)


@app.route("/<queue_name>/cancel_pending", methods=["POST"])
@app.route(base_path + "/<queue_name>/cancel_pending", methods=["POST"])
def cancel_pending_queue_tasks(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -291,7 +296,7 @@ def cancel_pending_queue_tasks(queue_name):
return redirect(request.referrer)


@app.route("/restart_task/<task_id>/restart", methods=["POST"])
@app.route(base_path + "/restart_task/<task_id>/restart", methods=["POST"])
def restart_task(task_id):
task = karton.backend.get_task(task_id)
if not task:
Expand All @@ -301,7 +306,7 @@ def restart_task(task_id):
return redirect(request.referrer)


@app.route("/cancel_task/<task_id>/cancel", methods=["POST"])
@app.route(base_path + "/cancel_task/<task_id>/cancel", methods=["POST"])
def cancel_task(task_id):
task = karton.backend.get_task(task_id)
if not task:
Expand All @@ -311,7 +316,7 @@ def cancel_task(task_id):
return redirect(request.referrer)


@app.route("/queue/<queue_name>", methods=["GET"])
@app.route(base_path + "/queue/<queue_name>", methods=["GET"])
def get_queue(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -321,7 +326,7 @@ def get_queue(queue_name):
return render_template("queue.html", name=queue_name, queue=queue)


@app.route("/queue/<queue_name>/crashed", methods=["GET"])
@app.route(base_path + "/queue/<queue_name>/crashed", methods=["GET"])
def get_crashed_queue(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -331,7 +336,7 @@ def get_crashed_queue(queue_name):
return render_template("crashed.html", name=queue_name, queue=queue)


@app.route("/api/queue/<queue_name>", methods=["GET"])
@app.route(base_path + "/api/queue/<queue_name>", methods=["GET"])
def get_queue_api(queue_name):
state = KartonState(karton.backend)
queue = state.queues.get(queue_name)
Expand All @@ -340,7 +345,7 @@ def get_queue_api(queue_name):
return jsonify(QueueView(queue).to_dict())


@app.route("/task/<task_id>", methods=["GET"])
@app.route(base_path + "/task/<task_id>", methods=["GET"])
def get_task(task_id):
task = karton.backend.get_task(task_id)
if not task:
Expand All @@ -351,15 +356,15 @@ def get_task(task_id):
)


@app.route("/api/task/<task_id>", methods=["GET"])
@app.route(base_path + "/api/task/<task_id>", methods=["GET"])
def get_task_api(task_id):
task = karton.backend.get_task(task_id)
if not task:
return jsonify({"error": "Task doesn't exist"}), 404
return jsonify(TaskView(task).to_dict())


@app.route("/analysis/<root_id>", methods=["GET"])
@app.route(base_path + "/analysis/<root_id>", methods=["GET"])
def get_analysis(root_id):
state = KartonState(karton.backend)
analysis = state.analyses.get(root_id)
Expand All @@ -371,7 +376,7 @@ def get_analysis(root_id):
)


@app.route("/api/analysis/<root_id>", methods=["GET"])
@app.route(base_path + "/api/analysis/<root_id>", methods=["GET"])
def get_analysis_api(root_id):
state = KartonState(karton.backend)
analysis = state.analyses.get(root_id)
Expand All @@ -381,12 +386,12 @@ def get_analysis_api(root_id):
return jsonify(AnalysisView(analysis).to_dict())


@app.route("/graph", methods=["GET"])
@app.route(base_path + "/graph", methods=["GET"])
def get_graph():
return render_template("graph.html")


@app.route("/graph/generate", methods=["GET"])
@app.route(base_path + "/graph/generate", methods=["GET"])
def generate_graph():
state = KartonState(karton.backend)
graph = KartonGraph(state)
Expand Down
4 changes: 2 additions & 2 deletions karton/dashboard/templates/analysis.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ <h4>Tasks</h4>
{% for task in queue.pending_tasks %}
<tr>
<td>
<a href="/queue/{{identity}}">{{identity}}</a>
<a href="{{ base_path }}/queue/{{identity}}">{{identity}}</a>
</td>
<td>
<a href="/task/{{task.uid}}">{{ task.uid }}</a>
<a href="{{ base_path }}/task/{{task.uid}}">{{ task.uid }}</a>
</td>
<td>
{% if task.priority.value != 'normal' %}
Expand Down
2 changes: 1 addition & 1 deletion karton/dashboard/templates/crashed.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ <h4>
{% for task in queue.crashed_tasks|sort(attribute='last_update', reverse=True) %}
<tr>
<td>
<a href="/task/{{ task.uid }}">{{ task.uid }}</a>
<a href="{{ base_path }}/task/{{ task.uid }}">{{ task.uid }}</a>
</td>
<td><pre>{{ task.last_update|render_timestamp }}</pre></td>
<td>
Expand Down
2 changes: 1 addition & 1 deletion karton/dashboard/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h3 class="text-center">binds</h3>
{% for (queue_name, queue) in queues|dictsort %}
<tr>
<td>
<a href="queue/{{ queue_name }}">{{ queue_name }}</a>
<a href="{{ base_path }}/queue/{{ queue_name }}">{{ queue_name }}</a>
<div>
<span class="badge bg-info" title="karton-core library version">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-box-seam" viewBox="0 0 16 16">
Expand Down
10 changes: 5 additions & 5 deletions karton/dashboard/templates/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>{% block title %}karton-dashboard{% endblock %}</title>
<link rel="stylesheet" href="/static/bootstrap.css">
<link rel="stylesheet" href="{{ base_path }}/static/bootstrap.css">
<link rel="shortcut icon" href="{{ url_for('static', path='favicon.ico') }}">
</head>

<body>
<div class="navbar navbar-expand-lg navbar-dark bg-primary">
<div class="container">
<a href="/" class="navbar-brand">karton</a>
<a href="{{ base_path }}/" class="navbar-brand">karton</a>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/">home</a>
<a class="nav-link" href="{{ base_path }}/">home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/services">services</a>
<a class="nav-link" href="{{ base_path }}/services">services</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/graph">graph</a>
<a class="nav-link" href="{{ base_path }}/graph">graph</a>
</li>
</ul>
</div>
Expand Down
2 changes: 1 addition & 1 deletion karton/dashboard/templates/queue.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h4>
{% for task in queue.pending_tasks|sort(attribute='last_update', reverse=True) %}
<tr>
<td>
<a href="/task/{{task.uid}}">{{ task.uid }}</a>
<a href="{{ base_path }}/task/{{task.uid}}">{{ task.uid }}</a>
</td>
<td><pre>{{ task.last_update|render_timestamp }}</pre></td>
<td>
Expand Down
4 changes: 2 additions & 2 deletions karton/dashboard/templates/task.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ <h3 class="text-center">task <code>{{ task.uid }}</code></h3>
</dd>
<dt class="col-3">Origin</dt>
<dd class="col-9">
<a href="/queue/{{task.headers['origin']}}">{{task.headers['origin']}}</a>
<a href="{{ base_path }}/queue/{{task.headers['origin']}}">{{task.headers['origin']}}</a>
</dd>
<dt class="col-3">Receiver</dt>
<dd class="col-9">
<a href="/queue/{{task.headers['receiver']}}">{{task.headers['receiver']}}</a>
<a href="{{ base_path }}/queue/{{task.headers['receiver']}}">{{task.headers['receiver']}}</a>
</dd>
<dt class="col-3">Xrefs</dt>
<dd class="col-9">
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Flask==2.0.3
Flask==3.0.0
karton-core>=5.1.0,<6.0.0
mistune<3.0.0
prometheus_client==0.11.0
Expand Down
Loading