Ansible schedule form: structured playbook-variable fields + first-item dropdown defaults #2
@@ -372,14 +372,6 @@ async def _fleet_rows(session) -> list[dict]:
|
||||
return rows
|
||||
|
||||
|
||||
@host_agent_bp.get("/")
|
||||
@require_role(UserRole.viewer)
|
||||
async def index():
|
||||
"""The fleet view folded into the Hosts hub — kept as a redirect so old
|
||||
links/widgets don't 404."""
|
||||
return redirect("/hosts/")
|
||||
|
||||
|
||||
@host_agent_bp.get("/widget")
|
||||
async def widget_table():
|
||||
"""Fleet-glance dashboard widget: one row per monitored host, latest metrics."""
|
||||
@@ -568,13 +560,6 @@ async def host_panel(host_id: str):
|
||||
)
|
||||
|
||||
|
||||
@host_agent_bp.get("/settings/")
|
||||
@require_role(UserRole.admin)
|
||||
async def settings_redirect():
|
||||
"""Old management URL — agent management moved into the Hosts section."""
|
||||
return redirect(url_for("host_agent.fleet"))
|
||||
|
||||
|
||||
@host_agent_bp.get("/fleet/")
|
||||
@require_role(UserRole.admin)
|
||||
async def fleet():
|
||||
@@ -618,7 +603,7 @@ async def fleet():
|
||||
)
|
||||
|
||||
|
||||
@host_agent_bp.post("/settings/add-host")
|
||||
@host_agent_bp.post("/fleet/add-host")
|
||||
@require_role(UserRole.admin)
|
||||
async def add_host():
|
||||
form = await request.form
|
||||
@@ -650,7 +635,7 @@ async def add_host():
|
||||
return redirect(url_for("host_agent.fleet") + f"?new_token={raw}&host_id={host_id}")
|
||||
|
||||
|
||||
@host_agent_bp.post("/settings/<host_id>/rotate-token")
|
||||
@host_agent_bp.post("/fleet/<host_id>/rotate-token")
|
||||
@require_role(UserRole.admin)
|
||||
async def rotate_token(host_id: str):
|
||||
async with current_app.db_sessionmaker() as session:
|
||||
@@ -666,7 +651,7 @@ async def rotate_token(host_id: str):
|
||||
return redirect(url_for("host_agent.fleet") + f"?new_token={raw}&host_id={host_id}")
|
||||
|
||||
|
||||
@host_agent_bp.post("/settings/<host_id>/delete")
|
||||
@host_agent_bp.post("/fleet/<host_id>/delete")
|
||||
@require_role(UserRole.admin)
|
||||
async def delete_registration(host_id: str):
|
||||
async with current_app.db_sessionmaker() as session:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "_macros.html" import crumbs %}
|
||||
{% block title %}{{ host.name }} — Host Agent — Steward{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Host Agents", "/plugins/host_agent/"), (host.name, "")]) }}{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Hosts", "/hosts/"), (host.name, "/hosts/" ~ host.id), ("Metrics", "")]) }}{% endblock %}
|
||||
|
||||
{% macro fmt_bps(v) %}
|
||||
{%- if v is none -%}—
|
||||
@@ -27,7 +27,7 @@
|
||||
{% block content %}
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin-bottom:0.75rem;">
|
||||
<div style="display:flex;align-items:center;gap:0.6rem;">
|
||||
<a href="/plugins/host_agent/" class="btn btn-ghost btn-sm">← Fleet</a>
|
||||
<a href="/hosts/{{ host.id }}" class="btn btn-ghost btn-sm">← Host</a>
|
||||
<h1 class="page-title" style="margin-bottom:0;">{{ host.name }}</h1>
|
||||
{% if stale %}<span class="badge badge-red">stale</span>{% else %}<span class="badge badge-green">live</span>{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "_macros.html" import crumbs %}
|
||||
{% block title %}Host Agents — Steward{% endblock %}
|
||||
{% block breadcrumb %}{{ crumbs([("Dashboard", "/"), ("Host Agents", "")]) }}{% endblock %}
|
||||
{% block content %}
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.25rem;gap:1rem;flex-wrap:wrap;">
|
||||
<h1 class="page-title" style="margin-bottom:0;">Host Agents</h1>
|
||||
{% if session.user_role == 'admin' %}
|
||||
<a class="btn btn-ghost" href="/plugins/host_agent/settings/">Manage agents →</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not rows %}
|
||||
<div class="card empty">
|
||||
No hosts are reporting agent metrics yet.
|
||||
{% if session.user_role == 'admin' %}
|
||||
Add one from <a href="/plugins/host_agent/settings/">Host Agent settings</a> and run the install command on the target.
|
||||
{% else %}
|
||||
Ask an admin to install the agent on a host.
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:1rem;">
|
||||
{% for r in rows %}
|
||||
<a href="/plugins/host_agent/{{ r.host.id }}/" class="card" style="display:block;margin-bottom:0;color:inherit;">
|
||||
<div style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.7rem;">
|
||||
<span class="dot {% if r.stale %}dot-dim{% elif (r.cpu_pct or 0) >= 90 or (r.mem_used_pct or 0) >= 90 or (r.disk_worst or 0) >= 90 %}dot-warn{% else %}dot-up{% endif %}"></span>
|
||||
<span style="font-weight:600;flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ r.host.name }}</span>
|
||||
{% if r.stale %}<span class="badge badge-dim">stale</span>{% endif %}
|
||||
</div>
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.45rem 0.9rem;font-size:0.84rem;font-variant-numeric:tabular-nums;">
|
||||
<span><span style="color:var(--text-dim);">CPU</span> {% if r.cpu_pct is not none %}{{ "%.0f"|format(r.cpu_pct) }}%{% else %}—{% endif %}</span>
|
||||
<span><span style="color:var(--text-dim);">Mem</span> {% if r.mem_used_pct is not none %}{{ "%.0f"|format(r.mem_used_pct) }}%{% else %}—{% endif %}</span>
|
||||
<span><span style="color:var(--text-dim);">Disk</span> {% if r.disk_worst is not none %}{{ "%.0f"|format(r.disk_worst) }}%{% else %}—{% endif %}</span>
|
||||
<span><span style="color:var(--text-dim);">Load</span> {% if r.load_1m is not none %}{{ "%.2f"|format(r.load_1m) }}{% else %}—{% endif %}</span>
|
||||
{% if r.temp_max is not none %}<span><span style="color:var(--text-dim);">Temp</span> {{ "%.0f"|format(r.temp_max) }}°C</span>{% endif %}
|
||||
</div>
|
||||
<div style="margin-top:0.6rem;font-size:0.72rem;color:var(--text-dim);">
|
||||
last seen {{ r.reg.last_seen_at.strftime("%Y-%m-%d %H:%M:%S") ~ " UTC" if r.reg.last_seen_at else "never" }}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
@@ -37,11 +37,11 @@
|
||||
<button type="submit" class="btn btn-sm" title="Refresh agent.py + restart (token preserved)">Update agent</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
<form method="post" action="/plugins/host_agent/settings/{{ host.id }}/rotate-token" style="margin:0;"
|
||||
<form method="post" action="/plugins/host_agent/fleet/{{ host.id }}/rotate-token" style="margin:0;"
|
||||
onsubmit="return confirm('Rotate token? The agent stops reporting until reinstalled/updated with the new token.');">
|
||||
<button type="submit" class="btn btn-sm btn-ghost">Rotate token</button>
|
||||
</form>
|
||||
<form method="post" action="/plugins/host_agent/settings/{{ host.id }}/delete" style="margin:0;"
|
||||
<form method="post" action="/plugins/host_agent/fleet/{{ host.id }}/delete" style="margin:0;"
|
||||
onsubmit="return confirm('Remove this agent registration? Metrics stop until re-registered.');">
|
||||
<button type="submit" class="btn btn-sm btn-danger">Remove</button>
|
||||
</form>
|
||||
@@ -65,7 +65,7 @@
|
||||
{% elif not ansible_available %}
|
||||
<p style="color:var(--text-dim);font-size:0.85rem;">
|
||||
Ansible isn't available, so the agent can't be deployed from here. Install it manually with the
|
||||
<a href="/plugins/host_agent/settings/">curl install command</a>.
|
||||
<a href="/plugins/host_agent/fleet/">curl install command</a>.
|
||||
</p>
|
||||
|
||||
{% elif not managed_key_set %}
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="card">
|
||||
<form method="post" action="/plugins/host_agent/settings/add-host"
|
||||
<form method="post" action="/plugins/host_agent/fleet/add-host"
|
||||
style="display:flex;gap:0.75rem;align-items:flex-end;flex-wrap:wrap;">
|
||||
<div class="form-group" style="margin-bottom:0;">
|
||||
<label>Host name</label>
|
||||
@@ -155,12 +155,12 @@
|
||||
<td>{{ item.reg.distro or "—" }}</td>
|
||||
<td>{{ item.reg.last_seen_at.strftime("%Y-%m-%d %H:%M:%S") if item.reg.last_seen_at else "never" }}</td>
|
||||
<td class="td-actions">
|
||||
<form method="post" action="/plugins/host_agent/settings/{{ item.reg.host_id }}/rotate-token"
|
||||
<form method="post" action="/plugins/host_agent/fleet/{{ item.reg.host_id }}/rotate-token"
|
||||
style="display:inline;"
|
||||
onsubmit="return confirm('Rotate the token for this host? The existing agent will stop working until reinstalled with the new token.');">
|
||||
<button type="submit" class="btn btn-ghost btn-sm">Rotate token</button>
|
||||
</form>
|
||||
<form method="post" action="/plugins/host_agent/settings/{{ item.reg.host_id }}/delete"
|
||||
<form method="post" action="/plugins/host_agent/fleet/{{ item.reg.host_id }}/delete"
|
||||
style="display:inline;"
|
||||
onsubmit="return confirm('Delete this host registration? The agent will be unable to report metrics until re-registered.');">
|
||||
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
|
||||
|
||||
@@ -262,7 +262,7 @@ WIDGET_REGISTRY: dict[str, dict] = {
|
||||
"label": "Host Agent — Resources",
|
||||
"description": "Fleet view: CPU, memory, disk, and load per monitored host",
|
||||
"hx_url": "/plugins/host_agent/widget",
|
||||
"detail_url": "/plugins/host_agent/",
|
||||
"detail_url": "/hosts/",
|
||||
"plugin": "host_agent",
|
||||
"poll": True,
|
||||
"params": [],
|
||||
@@ -272,7 +272,7 @@ WIDGET_REGISTRY: dict[str, dict] = {
|
||||
"label": "Host Agent — History",
|
||||
"description": "CPU/memory/disk history for one host",
|
||||
"hx_url": "/plugins/host_agent/widget/history",
|
||||
"detail_url": "/plugins/host_agent/settings/",
|
||||
"detail_url": "/plugins/host_agent/fleet/",
|
||||
"plugin": "host_agent",
|
||||
"poll": True,
|
||||
"params": [
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
Steward's reusable Ansible identity. Provisioning installs the <strong>public</strong>
|
||||
key into each host's <code>{{ ssh_user }}</code> account; steady-state runs authenticate
|
||||
with the private half (stored encrypted). Generate it once, then provision hosts from
|
||||
<a href="/plugins/host_agent/settings/">Host Agents</a>.
|
||||
<a href="/plugins/host_agent/fleet/">Host Agents</a>.
|
||||
</p>
|
||||
{% if ssh_public_key %}
|
||||
<div class="form-group">
|
||||
|
||||
Reference in New Issue
Block a user