127 lines
9.6 KiB
HTML
127 lines
9.6 KiB
HTML
---
|
|
title: "Enroll"
|
|
html_title: "Enroll - Turn existing Linux hosts into Ansible"
|
|
description: "Enroll harvests real Linux host state and renders Ansible configuration-management output. Documentation for current 0.7 beta behavior."
|
|
og_title: "Enroll - Turn existing Linux hosts into Ansible"
|
|
og_description: "Harvest real Linux host state and render reviewable Ansible roles/playbooks."
|
|
og_type: "website"
|
|
---
|
|
<header class="hero py-5">
|
|
<div class="container py-4">
|
|
<div class="row align-items-center g-4">
|
|
<div class="col-lg-6">
|
|
<div class="kicker mb-3"><i class="bi bi-compass"></i> Current 0.7 beta documentation</div>
|
|
<h1 class="display-5 fw-800 lh-1 mb-3" style="letter-spacing:-0.03em;">Turn a real Linux host into reviewable Ansible.</h1>
|
|
<p class="lead mb-4">Enroll inspects Debian-like and RedHat-like machines, writes a harvest bundle (<code>state.json</code> plus artifacts), then renders Ansible roles and playbooks from that snapshot.</p>
|
|
<div class="d-flex flex-wrap gap-2 mb-4">
|
|
<a class="btn btn-dark btn-lg" href="#quickstart"><i class="bi bi-rocket-takeoff"></i> Quickstart</a>
|
|
<a class="btn btn-outline-dark btn-lg" href="docs.html"><i class="bi bi-journal-text"></i> Read docs</a>
|
|
<a class="btn btn-outline-secondary btn-lg" href="security.html"><i class="bi bi-shield-lock"></i> Security model</a>
|
|
</div>
|
|
<div class="d-flex flex-wrap gap-2">
|
|
<span class="badge badge-soft rounded-pill px-3 py-2">Harvest → Manifest</span>
|
|
<span class="badge badge-soft rounded-pill px-3 py-2">Local or remote over SSH</span>
|
|
<span class="badge badge-soft rounded-pill px-3 py-2">Optional SOPS bundles</span>
|
|
<span class="badge badge-soft rounded-pill px-3 py-2">Ansible output</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
<div class="hero-card p-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<div class="fw-semibold"><i class="bi bi-terminal"></i> The core workflow</div>
|
|
<div class="small text-muted">dry-run before applying</div>
|
|
</div>
|
|
<div class="terminal">
|
|
<pre class="mb-0"><code><span class="prompt">$</span> enroll harvest --out ./harvest
|
|
<span class="prompt">$</span> enroll validate ./harvest
|
|
<span class="prompt">$</span> enroll manifest --harvest ./harvest --out ./ansible
|
|
<span class="prompt">$</span> cd ./ansible
|
|
<span class="prompt">$</span> ansible-galaxy collection install -r requirements.yml
|
|
<span class="prompt">$</span> ansible-playbook -i localhost, -c local playbook.yml --check --diff</code></pre>
|
|
</div>
|
|
<div class="alert alert-warning mt-3 mb-0 small">
|
|
<strong>Trust boundary:</strong> validation proves structure and artifact consistency, not semantic safety. Only apply manifests generated from harvests whose provenance you trust.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<section class="py-5" id="how">
|
|
<div class="container">
|
|
<div class="row g-4 align-items-start">
|
|
<div class="col-lg-5">
|
|
<h2 class="display-6 fw-bold section-title mb-3">What Enroll does today</h2>
|
|
<p class="text-secondary">Enroll is a migration and recovery helper. It gives you a generated Ansible starting point from a machine that already exists; it does not prove that the machine is well designed, compliant, or safe to replicate.</p>
|
|
<div class="callout p-4 mt-4">
|
|
<div class="fw-semibold mb-2">Current output target</div>
|
|
<p class="small text-secondary mb-0">The public CLI renders Ansible. The codebase has an internal renderer-neutral model, but the documented user-facing manifest output is Ansible roles, playbooks, inventory, variables, files, templates, handlers, and a generated <code>README.md</code>.</p>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-7">
|
|
<div class="row g-3">
|
|
<div class="col-md-6"><div class="feature-card p-4 h-100"><div class="fw-semibold mb-1">Harvest</div><div class="text-muted">Collect package, service, user, file, runtime, Flatpak/Snap, and container-image evidence into a private bundle.</div></div></div>
|
|
<div class="col-md-6"><div class="feature-card p-4 h-100"><div class="fw-semibold mb-1">Validate</div><div class="text-muted">Check <code>state.json</code>, the vendored JSON schema, referenced artifacts, and orphaned files before rendering or CI use.</div></div></div>
|
|
<div class="col-md-6"><div class="feature-card p-4 h-100"><div class="fw-semibold mb-1">Manifest</div><div class="text-muted">Freeze the harvest, warn about semantic trust, then render Ansible. Use <code>--fqdn</code> for inventory-driven multi-host output.</div></div></div>
|
|
<div class="col-md-6"><div class="feature-card p-4 h-100"><div class="fw-semibold mb-1">Diff, explain, notify</div><div class="text-muted">Compare harvests, suppress noisy package-version or path drift, produce text/Markdown/JSON, and optionally send webhooks or email.</div></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="py-5 bg-light" id="quickstart">
|
|
<div class="container">
|
|
<div class="row align-items-end g-3 mb-3">
|
|
<div class="col-lg-8">
|
|
<h2 class="display-6 fw-bold section-title mb-2">Quickstart paths</h2>
|
|
<p class="text-secondary mb-0">Choose the shape that matches the job: one host, remote harvest, or a shared multi-host Ansible tree.</p>
|
|
</div>
|
|
<div class="col-lg-4 text-lg-end"><a class="btn btn-outline-dark" href="examples.html">More examples</a></div>
|
|
</div>
|
|
|
|
<ul class="nav nav-pills gap-2" id="qsTabs" role="tablist">
|
|
<li class="nav-item" role="presentation"><button class="nav-link active" id="qs-local-tab" data-bs-toggle="tab" data-bs-target="#qs-local" type="button" role="tab">Local</button></li>
|
|
<li class="nav-item" role="presentation"><button class="nav-link" id="qs-remote-tab" data-bs-toggle="tab" data-bs-target="#qs-remote" type="button" role="tab">Remote</button></li>
|
|
<li class="nav-item" role="presentation"><button class="nav-link" id="qs-fqdn-tab" data-bs-toggle="tab" data-bs-target="#qs-fqdn" type="button" role="tab">Multi-site</button></li>
|
|
<li class="nav-item" role="presentation"><button class="nav-link" id="qs-drift-tab" data-bs-toggle="tab" data-bs-target="#qs-drift" type="button" role="tab">Drift</button></li>
|
|
</ul>
|
|
|
|
<div class="tab-content mt-3">
|
|
<div class="tab-pane fade show active" id="qs-local" role="tabpanel">
|
|
<div class="codeblock"><button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs-local-code"><i class="bi bi-clipboard"></i> Copy</button><pre class="terminal mb-0"><code id="qs-local-code">enroll harvest --out ./harvest
|
|
enroll manifest --harvest ./harvest --out ./ansible
|
|
cd ./ansible
|
|
ansible-playbook -i localhost, -c local playbook.yml --check --diff</code></pre></div>
|
|
</div>
|
|
<div class="tab-pane fade" id="qs-remote" role="tabpanel">
|
|
<div class="codeblock"><button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs-remote-code"><i class="bi bi-clipboard"></i> Copy</button><pre class="terminal mb-0"><code id="qs-remote-code">enroll harvest --remote-host app01.example.net --remote-user mig --out ./harvest
|
|
# Use -K / --ask-become-pass when remote sudo needs a password.
|
|
enroll manifest --harvest ./harvest --out ./ansible</code></pre></div>
|
|
</div>
|
|
<div class="tab-pane fade" id="qs-fqdn" role="tabpanel">
|
|
<div class="codeblock"><button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs-fqdn-code"><i class="bi bi-clipboard"></i> Copy</button><pre class="terminal mb-0"><code id="qs-fqdn-code">host=app01.example.net
|
|
enroll single-shot --remote-host "$host" --remote-user mig \
|
|
--harvest "./harvest-$host" --out ./ansible-site --fqdn "$host"
|
|
cd ./ansible-site
|
|
ansible-playbook -i inventory/hosts.ini "playbooks/${host}.yml" --check --diff</code></pre></div>
|
|
</div>
|
|
<div class="tab-pane fade" id="qs-drift" role="tabpanel">
|
|
<div class="codeblock"><button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs-drift-code"><i class="bi bi-clipboard"></i> Copy</button><pre class="terminal mb-0"><code id="qs-drift-code">enroll diff --old ./harvest-golden --new ./harvest-current \
|
|
--format markdown --ignore-package-versions --exclude-path /var/anacron</code></pre></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="py-5">
|
|
<div class="container">
|
|
<div class="row g-4">
|
|
<div class="col-lg-4"><div class="feature-card p-4 h-100"><h3 class="h5 fw-bold">Single-site by default</h3><p class="text-secondary mb-0">Without <code>--fqdn</code>, Enroll renders self-contained roles where role files live under <code>roles/<role>/files</code> and variables live in <code>defaults/main.yml</code>.</p></div></div>
|
|
<div class="col-lg-4"><div class="feature-card p-4 h-100"><h3 class="h5 fw-bold">Multi-site with <code>--fqdn</code></h3><p class="text-secondary mb-0">With <code>--fqdn</code>, shared role tasks stay reusable while host-specific files and variables live under <code>inventory/host_vars/<fqdn></code>. <code>--fqdn</code> implies one-role-per-package/unit behavior.</p></div></div>
|
|
<div class="col-lg-4"><div class="feature-card p-4 h-100"><h3 class="h5 fw-bold">Security-first rendering</h3><p class="text-secondary mb-0">Directory harvests are frozen into private temp copies before use, artifact paths are no-follow validated, and harvested Jinja-looking values are emitted as Ansible <code>!unsafe</code> data.</p></div></div>
|
|
</div>
|
|
</div>
|
|
</section>
|