Compare commits

..

2 Commits

View File

@ -1,130 +1,333 @@
{% extends 'remotectl/base.html' %}
{% block title %}Manual | Remote Admin{% endblock %}
{% block content %}
<h1 class="text-3xl font-semibold mb-6">Application Manual</h1>
<p class="mb-6 text-sm text-gray-600 dark:text-gray-400">Detailed reference for using the Remote Admin console. Use your
browser search (Ctrl+F) to find topics quickly.</p>
<div class="prose dark:prose-invert max-w-none text-sm">
<h2 id="overview">1. Overview</h2>
<p>This application lets you manage remote Linux hosts over SSH, execute ad-hoc commands, run saved tasks, and
process multi-step batch scripts with real-time streaming output via WebSockets.</p>
<div class="space-y-12 text-sm">
<section class="bg-gradient-to-br from-slate-900 via-slate-800 to-slate-700 text-white rounded-3xl shadow-2xl">
<div class="grid md:grid-cols-2 gap-8 p-10">
<div>
<p class="uppercase tracking-widest text-slate-300 text-xs mb-3">Remote Admin Manual</p>
<h1 class="text-4xl font-semibold leading-tight mb-4">Operate Linux fleets with clarity and control.</h1>
<p class="text-slate-300 mb-6">This guide highlights the essential flows for onboarding hosts, running
commands, orchestrating batches, and understanding every status signal the console emits.</p>
<div class="flex flex-wrap gap-3">
<a href="#workflow"
class="px-4 py-2 rounded-full bg-white/10 backdrop-blur text-white border border-white/30 hover:bg-white/20 transition">
View workflow</a>
<a href="#troubleshooting"
class="px-4 py-2 rounded-full bg-slate-700 border border-slate-500 hover:bg-slate-600 transition">Troubleshoot</a>
</div>
</div>
<div class="bg-white/5 rounded-2xl border border-white/10 p-6">
<p class="text-xs uppercase tracking-[0.2em] text-slate-400 mb-4">Snapshot</p>
<dl class="grid grid-cols-2 gap-4 text-sm">
<div>
<dt class="text-slate-400">Channels</dt>
<dd class="text-2xl font-semibold text-white">SSH + WebSockets</dd>
</div>
<div>
<dt class="text-slate-400">Run Modes</dt>
<dd class="text-2xl font-semibold text-white">Single / Batch</dd>
</div>
<div>
<dt class="text-slate-400">Cancel Safety</dt>
<dd class="text-xl font-semibold text-white">Graceful SIGTERM</dd>
</div>
<div>
<dt class="text-slate-400">Auth</dt>
<dd class="text-xl font-semibold text-white">Key or Agent</dd>
</div>
</dl>
</div>
</div>
</section>
<h2 id="hosts">2. Hosts</h2>
<p>Create remote hosts under <strong>Hosts</strong>. Each host stores:</p>
<ul>
<li><code>name</code>: Friendly display name</li>
<li><code>hostname</code>: DNS name or IP</li>
<li><code>port</code>: SSH port (default 22)</li>
<li><code>username</code>: SSH login user</li>
<li><code>auth_method</code>: <code>ssh_key</code> or <code>agent</code> (password not yet implemented)</li>
<li><code>key_path</code>: Optional explicit private key path (not uploaded)</li>
<li><code>strict_host_key_checking</code>: Enforce known_hosts validation</li>
</ul>
<p><strong>Example:</strong></p>
<pre>Host: prod-app-1
<section class="bg-white rounded-2xl shadow-lg border border-slate-100 p-6">
<div class="flex flex-wrap gap-3">
<a href="#overview" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Overview</a>
<a href="#hosts" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Hosts</a>
<a href="#console" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Console</a>
<a href="#tasks" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Tasks</a>
<a href="#batches" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Batch scripts</a>
<a href="#status" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Status</a>
<a href="#logs" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Logs</a>
<a href="#workflow" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Workflow</a>
<a href="#security" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Security</a>
<a href="#troubleshooting"
class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Troubleshooting</a>
<a href="#future" class="px-3 py-2 rounded-full bg-slate-100 text-slate-600 hover:bg-slate-200">Future</a>
</div>
</section>
<section id="overview" class="bg-white rounded-3xl border border-slate-100 shadow-lg p-8 space-y-4">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400">01</p>
<h2 class="text-2xl font-semibold text-slate-800">Overview</h2>
<p class="text-slate-600">Remote Admin lets you register hosts, dispatch commands through SSH, and observe output
in real time over WebSockets. Use it as a single pane of glass for routine ops, emergency fixes, and
long-running batch jobs.</p>
<div class="grid md:grid-cols-3 gap-4">
<article class="p-4 rounded-2xl border border-slate-200 bg-slate-50">
<p class="text-xs uppercase text-slate-500 mb-2">Visibility</p>
<p class="text-slate-700">Live logs, exit codes, and batch step markers surface progress at a glance.</p>
</article>
<article class="p-4 rounded-2xl border border-slate-200 bg-slate-50">
<p class="text-xs uppercase text-slate-500 mb-2">Repeatability</p>
<p class="text-slate-700">Save complex commands as tasks or batches for consistent, auditable actions.</p>
</article>
<article class="p-4 rounded-2xl border border-slate-200 bg-slate-50">
<p class="text-xs uppercase text-slate-500 mb-2">Control</p>
<p class="text-slate-700">Cancel runs safely, and rely on strict host key checks for production-grade SSH.</p>
</article>
</div>
</section>
<section id="hosts" class="grid lg:grid-cols-2 gap-6">
<article class="bg-white rounded-3xl border border-slate-100 p-8 shadow-lg">
<div class="flex items-center justify-between mb-4">
<h2 class="text-2xl font-semibold text-slate-800">Hosts</h2>
<span class="text-xs px-3 py-1 rounded-full bg-slate-900 text-white uppercase tracking-widest">Inventory</span>
</div>
<p class="text-slate-600 mb-4">Create remote endpoints under <span class="font-semibold">Hosts</span>. Each entry
stores credentials without uploading your private key.</p>
<dl class="grid grid-cols-2 gap-4 text-sm text-slate-600">
<div>
<dt class="font-semibold text-slate-900">name</dt>
<dd>Friendly display label.</dd>
</div>
<div>
<dt class="font-semibold text-slate-900">hostname</dt>
<dd>DNS or IP.</dd>
</div>
<div>
<dt class="font-semibold text-slate-900">port</dt>
<dd>Default 22 unless overridden.</dd>
</div>
<div>
<dt class="font-semibold text-slate-900">username</dt>
<dd>SSH login user.</dd>
</div>
<div>
<dt class="font-semibold text-slate-900">auth_method</dt>
<dd><code class="bg-slate-100 px-2 py-0.5 rounded">ssh_key</code> or <code
class="bg-slate-100 px-2 py-0.5 rounded">agent</code>.</dd>
</div>
<div>
<dt class="font-semibold text-slate-900">key_path</dt>
<dd>Optional explicit key location.</dd>
</div>
</dl>
<div class="mt-6 bg-slate-50 rounded-2xl p-4 border border-dashed border-slate-200 text-xs">
<p class="uppercase tracking-[0.3em] text-slate-500 mb-2">Example</p>
<pre
class="text-slate-800 overflow-x-auto"><code>Host: prod-app-1
Hostname: 10.10.10.15
User: deploy
Auth: ssh_key
Key Path: /home/deploy/.ssh/id_ed25519</pre>
Key Path: /home/deploy/.ssh/id_ed25519</code></pre>
</div>
</article>
<article id="console" class="bg-slate-900 text-white rounded-3xl border border-slate-800 p-8 shadow-lg">
<div class="flex items-center justify-between mb-4">
<h2 class="text-2xl font-semibold">Console Modes</h2>
<span class="text-xs px-3 py-1 rounded-full bg-white/10 border border-white/20 uppercase tracking-widest">Run
Center</span>
</div>
<p class="text-slate-300 mb-6">Connect to a host then choose how to execute.</p>
<ul class="space-y-4">
<li class="bg-white/5 rounded-2xl p-4 border border-white/10">
<p class="text-sm uppercase tracking-[0.3em] text-slate-400">Saved Task</p>
<p class="text-lg font-semibold">Pick a curated command and optionally edit before launch.</p>
</li>
<li class="bg-white/5 rounded-2xl p-4 border border-white/10">
<p class="text-sm uppercase tracking-[0.3em] text-slate-400">Ad-hoc</p>
<p class="text-lg font-semibold">Type anything (e.g. <code>uname -a</code>) for fast diagnostics.</p>
</li>
<li class="bg-white/5 rounded-2xl p-4 border border-white/10">
<p class="text-sm uppercase tracking-[0.3em] text-slate-400">Batch</p>
<p class="text-lg font-semibold">Execute multi-step scripts with streamed STDOUT/STDERR markers.</p>
</li>
</ul>
<p class="text-slate-300 mt-6">Cancel anytime; the UI highlights stderr lines so failures stand out instantly.</p>
</article>
</section>
<h2 id="console">3. Console</h2>
<p>Connect to a host then choose one of:</p>
<ul>
<li><strong>Saved Task</strong>: Select a predefined, editable command.</li>
<li><strong>Ad-hoc Command</strong>: Type any shell command (e.g. <code>uname -a</code>).</li>
<li><strong>Batch Script</strong>: Multi-step script defined under Batches.</li>
</ul>
<p>While running you can cancel. Output streams in real-time; stderr lines are highlighted.</p>
<h2 id="tasks">4. Tasks</h2>
<p>Tasks are named reusable commands. Fields:</p>
<ul>
<li><code>name</code>: Unique internal key (no spaces recommended)</li>
<li><code>label</code>: Display label</li>
<li><code>command</code>: Shell snippet executed exactly on remote host</li>
</ul>
<p><strong>Example task:</strong></p>
<pre>Name: restart_app
<section id="tasks" class="grid lg:grid-cols-2 gap-6">
<article class="bg-white rounded-3xl border border-slate-100 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Reusable Commands</p>
<h2 class="text-2xl font-semibold text-slate-800 mb-4">Tasks</h2>
<p class="text-slate-600 mb-4">Tasks encapsulate commands with friendly labels so teams can run critical actions
without remembering exact syntax.</p>
<ul class="space-y-3 text-slate-700">
<li><span class="font-semibold text-slate-900">name</span>: Unique key (use dashes/underscores).</li>
<li><span class="font-semibold text-slate-900">label</span>: Human friendly description.</li>
<li><span class="font-semibold text-slate-900">command</span>: Executed verbatim on the remote host.</li>
</ul>
<div class="mt-6 bg-slate-50 rounded-2xl p-4 border border-slate-200">
<pre
class="text-xs text-slate-900 overflow-x-auto"><code>Name: restart_app
Label: Restart App Service
Command: sudo systemctl restart app.service</pre>
<h2 id="batches">5. Batch Scripts</h2>
<p>A batch script is a list of steps (one per line). Blank lines and lines starting with <code>#</code> are ignored.
A line starting with <code>cd &lt;dir&gt;</code> sets the working directory for subsequent commands.</p>
<p><strong>Example batch:</strong></p>
<pre># Deploy sequence
Command: sudo systemctl restart app.service</code></pre>
</div>
</article>
<article id="batches" class="bg-slate-900 text-white rounded-3xl border border-slate-900 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Multi-step orchestration</p>
<h2 class="text-2xl font-semibold mb-4">Batch Scripts</h2>
<p class="text-slate-300 mb-4">Define a sequence of commands, one per line. Blank lines or lines starting with
<code>#</code> are ignored. Use <code>cd path</code> to change context for subsequent steps.</p>
<div class="bg-black/40 rounded-2xl border border-white/10 p-4 text-xs">
<pre class="overflow-x-auto text-slate-100"><code># Deploy sequence
cd /srv/app
./stop.sh
./build.sh
./start.sh</pre>
<p>During execution you will see markers like:</p>
<pre>&gt;&gt;&gt; [2/4] ./build.sh</pre>
./start.sh</code></pre>
</div>
<p class="text-slate-300 mt-4">During execution you will see markers like <code>&gt;&gt;&gt; [2/4] ./build.sh</code>
to track progress.</p>
</article>
</section>
<h2 id="status">6. Status & Progress</h2>
<p>Status badge meanings:</p>
<ul>
<li><strong>CONNECTED</strong>: WebSocket open, no command running</li>
<li><strong>RUNNING</strong>: Command or batch executing</li>
<li><strong>STEP X/Y</strong>: Current batch step progress</li>
<li><strong>CANCELING</strong>: Cancel requested; waiting for termination</li>
<li><strong>COMPLETED (exit n)</strong>: Finished with exit code</li>
<li><strong>FAILED / ERROR</strong>: Non-zero exit or SSH/runtime issue</li>
</ul>
<section id="status" class="bg-white rounded-3xl border border-slate-100 shadow-lg p-8 space-y-6">
<div class="flex items-center justify-between">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-slate-400">Signals</p>
<h2 class="text-2xl font-semibold text-slate-800">Status & Progress</h2>
</div>
<span class="text-xs px-3 py-1 rounded-full bg-slate-900 text-white uppercase tracking-widest">Live badges</span>
</div>
<div class="grid md:grid-cols-3 gap-4">
<article class="p-4 rounded-2xl border border-green-100 bg-green-50">
<h3 class="font-semibold text-green-900">CONNECTED</h3>
<p class="text-green-800 text-sm">WebSocket open; idle until you run a task.</p>
</article>
<article class="p-4 rounded-2xl border border-blue-100 bg-blue-50">
<h3 class="font-semibold text-blue-900">RUNNING / STEP X/Y</h3>
<p class="text-blue-800 text-sm">Command or batch in-flight; watch the live stream.</p>
</article>
<article class="p-4 rounded-2xl border border-amber-100 bg-amber-50">
<h3 class="font-semibold text-amber-900">CANCELING</h3>
<p class="text-amber-800 text-sm">Terminate signal sent; waiting for graceful stop.</p>
</article>
<article class="p-4 rounded-2xl border border-slate-200 bg-slate-50">
<h3 class="font-semibold text-slate-900">COMPLETED (exit n)</h3>
<p class="text-slate-700 text-sm">Finished with exit code context.</p>
</article>
<article class="p-4 rounded-2xl border border-rose-200 bg-rose-50">
<h3 class="font-semibold text-rose-900">FAILED / ERROR</h3>
<p class="text-rose-800 text-sm">Non-zero exit or SSH/runtime problem.</p>
</article>
</div>
</section>
<h2 id="logs">7. Logs</h2>
<p>Each execution creates a log entry with:</p>
<ul>
<li><code>run_type</code>: <code>single</code> or <code>batch</code></li>
<li><code>status</code>, <code>exit_code</code></li>
<li><code>failed_step</code> (batch only on failure)</li>
<li>Tail output (last 32K captured)</li>
<li>Timestamps and duration</li>
</ul>
<section id="logs" class="grid lg:grid-cols-2 gap-6">
<article class="bg-white rounded-3xl border border-slate-100 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Run evidence</p>
<h2 class="text-2xl font-semibold text-slate-800">Logs</h2>
<p class="text-slate-600 mb-4">Every execution produces a structured record:</p>
<ul class="space-y-2 text-slate-700">
<li><code class="bg-slate-100 px-2 py-0.5 rounded">run_type</code>: <code
class="bg-slate-50 px-2 py-0.5 rounded">single</code> or <code
class="bg-slate-50 px-2 py-0.5 rounded">batch</code></li>
<li><code class="bg-slate-100 px-2 py-0.5 rounded">status</code> and <code
class="bg-slate-100 px-2 py-0.5 rounded">exit_code</code></li>
<li><code class="bg-slate-100 px-2 py-0.5 rounded">failed_step</code> for batch failures</li>
<li>Tail output (last 32K), timestamps, and duration</li>
</ul>
</article>
<article id="errors" class="bg-slate-900 text-white rounded-3xl border border-slate-900 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Structured errors</p>
<h2 class="text-2xl font-semibold mb-4">Error shape</h2>
<div class="bg-black/40 rounded-2xl border border-white/10 p-4 text-xs">
<pre class="overflow-x-auto text-slate-100"><code>{"event":"error","type":"ssh|runtime","message":"..."}</code></pre>
</div>
<p class="text-slate-300 mt-4">SSH errors reflect connection/auth issues. Runtime errors signal validation or
conflicting state (for example, duplicate run requests).</p>
</article>
</section>
<h2 id="errors">8. Errors</h2>
<p>Error events are structured as:</p>
<pre>{"event":"error","type":"ssh|runtime","message":"..."}</pre>
<p>SSH errors come from connection/auth issues; runtime errors are validation or state (e.g. duplicate run).</p>
<h2 id="cancellation">9. Cancellation</h2>
<p>When you press Cancel the server sends a terminate signal; some commands may take time to exit gracefully. Batch
processing stops at the current step.</p>
<h2 id="security">10. Security Notes</h2>
<ul>
<li>Private keys are referenced by filesystem path only (never stored in DB).</li>
<li>Strict host key checking recommended for production.</li>
<li>All operations require authentication (Django login).</li>
</ul>
<h2 id="examples">11. Example Use Cases</h2>
<h3>Deploy Application</h3>
<pre>Task: build_assets
Command: npm run build
Batch:
cd /srv/app
<section id="workflow" class="bg-white rounded-3xl border border-slate-100 shadow-lg p-8 space-y-6">
<div class="flex items-center justify-between">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-slate-400">Flow</p>
<h2 class="text-2xl font-semibold text-slate-800">Deployment Workflow</h2>
</div>
<span class="text-xs px-3 py-1 rounded-full bg-slate-900 text-white uppercase tracking-widest">Best practice</span>
</div>
<div class="grid md:grid-cols-2 gap-6">
<article class="bg-slate-50 rounded-2xl border border-slate-200 p-4">
<p class="text-xs uppercase tracking-[0.3em] text-slate-500 mb-2">Task example</p>
<pre
class="text-xs text-slate-800 overflow-x-auto"><code>Task: build_assets
Command: npm run build</code></pre>
</article>
<article class="bg-slate-900 text-white rounded-2xl border border-slate-900 p-4">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Batch companion</p>
<pre class="text-xs text-slate-100 overflow-x-auto"><code>cd /srv/app
./stop.sh
./deploy.sh
./start.sh</pre>
./start.sh</code></pre>
</article>
</div>
<div class="grid md:grid-cols-4 gap-4 text-sm text-slate-600">
<div class="p-4 rounded-2xl border border-slate-200 bg-slate-50">1. Connect to host with validated keys.</div>
<div class="p-4 rounded-2xl border border-slate-200 bg-slate-50">2. Choose saved task or attach ad-hoc pre-flight checks.</div>
<div class="p-4 rounded-2xl border border-slate-200 bg-slate-50">3. Launch batch for deterministic rollout, watching live markers.</div>
<div class="p-4 rounded-2xl border border-slate-200 bg-slate-50">4. Inspect logs, confirm exit codes, archive evidence.</div>
</div>
</section>
<h3>Quick Diagnostics</h3>
<pre>Ad-hoc: df -h | grep /data
Ad-hoc: sudo journalctl -u app.service -n 50</pre>
<section id="cancellation" class="bg-slate-900 text-white rounded-3xl border border-slate-900 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Control</p>
<h2 class="text-2xl font-semibold mb-4">Cancellation</h2>
<p class="text-slate-300">Cancel sends a terminate signal to the remote process. Some commands need additional time
to unwind; batch processing stops immediately after the active step finishes.</p>
</section>
<h2 id="troubleshooting">12. Troubleshooting</h2>
<ul>
<li><strong>Permission denied</strong>: Check user, key, and file permissions.</li>
<li><strong>Host key not trusted</strong>: Add host to known_hosts or disable strict checking (dev only).</li>
<li><strong>No output</strong>: Some scripts buffer output; use unbuffered modes (e.g. <code>python -u</code>).
</li>
</ul>
<section id="security" class="grid lg:grid-cols-2 gap-6">
<article class="bg-white rounded-3xl border border-slate-100 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Security Notes</p>
<h2 class="text-2xl font-semibold text-slate-800">Hardening checklist</h2>
<ul class="space-y-2 text-slate-700">
<li>Private keys stay on disk; only file paths are stored.</li>
<li>Enable strict host key checking in production.</li>
<li>Django authentication gates every operation.</li>
</ul>
</article>
<article class="bg-slate-50 rounded-3xl border border-slate-200 p-8 shadow-lg">
<p class="text-xs uppercase tracking-[0.3em] text-slate-500 mb-2">Pro tips</p>
<ul class="space-y-2 text-slate-700">
<li>Segment hosts with naming conventions (prod-, staging-, etc.).</li>
<li>Store frequently used directories in batches via <code>cd</code> steps.</li>
<li>Use <code>python -u</code> or <code>stdbuf -o0</code> to force unbuffered output.</li>
</ul>
</article>
</section>
<h2 id="future">13. Future Extensions</h2>
<ul>
<li>Parameterized tasks</li>
<li>Role-based permissions</li>
<li>Streaming partial log persistence</li>
</ul>
<section id="troubleshooting" class="bg-white rounded-3xl border border-rose-100 shadow-lg p-8">
<p class="text-xs uppercase tracking-[0.3em] text-rose-400 mb-2">Troubleshooting</p>
<h2 class="text-2xl font-semibold text-slate-800 mb-4">Fix common blockers</h2>
<div class="space-y-4 text-slate-700">
<article class="border border-rose-200 rounded-2xl p-4">
<h3 class="font-semibold text-rose-900">Permission denied</h3>
<p>Verify SSH user, key permissions (<code>chmod 600</code>), and host-based ACLs.</p>
</article>
<article class="border border-amber-200 rounded-2xl p-4">
<h3 class="font-semibold text-amber-900">Host key not trusted</h3>
<p>Add the host to <code>known_hosts</code> or temporarily disable strict checks only for development.</p>
</article>
<article class="border border-blue-200 rounded-2xl p-4">
<h3 class="font-semibold text-blue-900">No output</h3>
<p>Some binaries buffer stdout; prefer unbuffered flags such as <code>python -u</code>.</p>
</article>
</div>
</section>
<section id="future" class="bg-white rounded-3xl border border-slate-100 shadow-lg p-8">
<p class="text-xs uppercase tracking-[0.3em] text-slate-400 mb-2">Roadmap hints</p>
<h2 class="text-2xl font-semibold text-slate-800 mb-4">Future extensions</h2>
<ul class="space-y-2 text-slate-700">
<li>Parameterized tasks for templatized commands.</li>
<li>Role-based permissions and scoped execution.</li>
<li>Streaming partial log persistence for long sessions.</li>
</ul>
</section>
</div>
{% endblock %}
{% endblock %}