This commit is contained in:
parent
7e4f85b0fd
commit
42683598fa
12 changed files with 967 additions and 1125 deletions
|
|
@ -1,385 +1,127 @@
|
|||
---
|
||||
title: "Enroll"
|
||||
html_title: "Enroll - Reverse-engineering servers into Ansible"
|
||||
description: "Enroll inspects Debian-like and RedHat-like Linux hosts and generates Ansible roles/playbooks from what it finds. Harvest → Manifest → Manage."
|
||||
og_title: "Enroll - Reverse-engineering servers into Ansible"
|
||||
og_description: "Harvest a host's real configuration and turn it into Ansible roles/playbooks. Safe-by-default, with optional SOPS encryption."
|
||||
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-magic"></i> Reverse-engineering servers into Ansible</div>
|
||||
<h1 class="display-5 fw-800 lh-1 mb-3" style="letter-spacing:-0.03em;">Get an existing Linux host into Ansible in seconds.</h1>
|
||||
<p class="lead mb-4">Enroll inspects a Debian-like or RedHat-like system, harvests the state that matters, and generates Ansible roles/playbooks so you can bring snowflakes under management fast.</p>
|
||||
<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="#demos"><i class="bi bi-play-circle"></i> Watch demos</a>
|
||||
<a class="btn btn-outline-secondary btn-lg" href="https://pypi.org/project/enroll/" target="_blank" rel="noreferrer"><i class="bi bi-box-seam"></i> PyPI</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"><i class="bi bi-speedometer"></i> Super fast</span>
|
||||
<span class="badge badge-soft rounded-pill px-3 py-2"><i class="bi bi-lock"></i> Optional SOPS encryption</span>
|
||||
<span class="badge badge-soft rounded-pill px-3 py-2"><i class="bi bi-hdd-network"></i> Remote over SSH</span>
|
||||
<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 p-lg-4">
|
||||
<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> Config in the blink of an eye</div>
|
||||
<div class="small text-muted">single-shot → ansible-playbook</div>
|
||||
<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">
|
||||
<div class="mb-2"><span class="prompt">$</span> <code style="font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;">enroll single-shot --harvest ./harvest --out ./ansible</code></div>
|
||||
<div class="mb-2"><span class="prompt">$</span> <code style="font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;">cd ./ansible && tree -L 2</code></div>
|
||||
<pre class="mb-0" style="white-space:pre-wrap; font-family:'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace; font-size:.9rem;">.
|
||||
├── ansible.cfg
|
||||
├── playbook.yml
|
||||
├── roles/
|
||||
│ ├── cron/
|
||||
│ ├── etc_custom/
|
||||
│ ├── firewall/
|
||||
│ ├── nginx/
|
||||
│ ├── openssh-server/
|
||||
│ ├── users/
|
||||
└── README.md</pre>
|
||||
<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 class="smallprint mt-3">Tip: for multiple hosts, use <code>--fqdn</code> to generate inventory-driven, data-driven roles.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section class="py-5" id="how" aria-label="How it works">
|
||||
<section class="py-5" id="how">
|
||||
<div class="container">
|
||||
<div class="row g-4 align-items-start">
|
||||
<div class="col-lg-5">
|
||||
<h2 class="section-title display-6 fw-bold mb-3">A simple mental model</h2>
|
||||
<p class="mb-4">Enroll is built around two phases, plus optional drift and reporting tools:</p>
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div class="d-flex gap-3">
|
||||
<div class="icon-pill"><i class="bi bi-bucket"></i></div>
|
||||
<div>
|
||||
<div class="fw-semibold">Harvest</div>
|
||||
<div class="text-muted">Collect host facts + relevant files into a bundle.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="icon-pill"><i class="bi bi-diagram-3"></i></div>
|
||||
<div>
|
||||
<div class="fw-semibold">Manifest</div>
|
||||
<div class="text-muted">Render Ansible roles & playbooks from the harvest.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="icon-pill"><i class="bi bi-plus-slash-minus"></i></div>
|
||||
<div>
|
||||
<div class="fw-semibold">Diff</div>
|
||||
<div class="text-muted">Compare two harvests and notify via webhook/email.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="icon-pill"><i class="bi bi-patch-question"></i></div>
|
||||
<div>
|
||||
<div class="fw-semibold">Explain</div>
|
||||
<div class="text-muted">Analyze what's included/excluded in the harvest and why.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-3">
|
||||
<div class="icon-pill"><i class="bi bi-check-square"></i></div>
|
||||
<div>
|
||||
<div class="fw-semibold">Validate</div>
|
||||
<div class="text-muted">Confirm that a harvest isn't corrupt or lacking artifacts.</div>
|
||||
</div>
|
||||
</div>
|
||||
<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="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Safe-by-default harvesting</div>
|
||||
<div class="text-muted">Enroll avoids likely secrets with a path denylist, content sniffing, and size caps - then lets you opt in to more aggressive collection when you're ready.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Multi-site without "shared role broke host2"</div>
|
||||
<div class="text-muted">In <code>--fqdn</code> mode, roles are data-driven and host inventory decides what gets managed per host.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Remote over SSH</div>
|
||||
<div class="text-muted">Harvest a remote host from your workstation, then manifest Ansible output locally.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Encrypt bundles at rest</div>
|
||||
<div class="text-muted">Use <code>--sops</code> to store harvests/manifests as a single encrypted <code>.tar.gz.sops</code> file (GPG) for safer long-term storage as a DR strategy.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="callout p-4 mt-3">
|
||||
<div class="fw-semibold mb-2"><i class="bi bi-lightning-charge"></i> Why sysadmins like it</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6 text-muted">• Rapid enrolling of existing infra into config management<br>• Tweak include/exclude paths as needed</div>
|
||||
<div class="col-md-6 text-muted">• Capture what changed from package defaults<br>• <code>diff</code> mode detects and alerts about drift</div>
|
||||
</div>
|
||||
<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" aria-label="Quickstart">
|
||||
<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-7">
|
||||
<h2 class="section-title display-6 fw-bold mb-2">Quickstart</h2>
|
||||
</div>
|
||||
<div class="col-lg-5 text-lg-end">
|
||||
<a class="btn btn-outline-dark" href="https://git.mig5.net/mig5/enroll#readme" target="_blank" rel="noreferrer"><i class="bi bi-journal-text"></i> Full README</a>
|
||||
<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="qs1-tab" data-bs-toggle="tab" data-bs-target="#qs1" type="button" role="tab">Local</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" id="qs2-tab" data-bs-toggle="tab" data-bs-target="#qs2" type="button" role="tab">Remote</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" id="qs3-tab" data-bs-toggle="tab" data-bs-target="#qs3" type="button" role="tab">Multi-site</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" id="qs4-tab" data-bs-toggle="tab" data-bs-target="#qs4" type="button" role="tab">Diff</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" id="qs5-tab" data-bs-toggle="tab" data-bs-target="#qs5" type="button" role="tab">Explain</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" id="qs6-tab" data-bs-toggle="tab" data-bs-target="#qs6" type="button" role="tab">Validate</button></li>
|
||||
<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="qs1" role="tabpanel" aria-labelledby="qs1-tab">
|
||||
<div class="row g-3">
|
||||
<div class="col-lg-6">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs1code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs1code"># Harvest → Manifest in one go
|
||||
enroll single-shot --harvest ./harvest --out ./ansible
|
||||
|
||||
# Then run Ansible locally
|
||||
ansible-playbook -i "localhost," -c local ./ansible/playbook.yml</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<div class="callout p-4 h-100">
|
||||
<div class="fw-semibold mb-2">Good for</div>
|
||||
<div class="text-muted">Disaster recovery snapshots, "make this one host reproducible", and carving a golden role set you'll refine over time.</div>
|
||||
<hr>
|
||||
<div class="smallprint">Want templates for structured configs? Install <a href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">JinjaTurtle</a> and use <code>--jinjaturtle</code> (or let it auto-detect).</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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="qs2" role="tabpanel" aria-labelledby="qs2-tab">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs2code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs2code"># Remote harvest over SSH, then manifest locally
|
||||
enroll single-shot \
|
||||
--remote-host myhost.example.com \
|
||||
--remote-user myuser \
|
||||
--harvest /tmp/enroll-harvest \
|
||||
--out ./ansible \
|
||||
--fqdn myhost.example.com</code></pre>
|
||||
</div>
|
||||
<div class="smallprint mt-3">If you don't want/need sudo on the remote host, add <code>--no-sudo</code> (expect a less complete harvest). For remote sudo prompts use <code>--ask-become-pass</code>/<code>-K</code>. If your SSH private key is encrypted, use <code>--ask-key-passphrase</code> (interactive) or <code>--ssh-key-passphrase-env ENV_VAR</code> (non-interactive/CI).</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="qs3" role="tabpanel" aria-labelledby="qs3-tab">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs3code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs3code"># Multi-site mode: shared roles, host-specific state in inventory
|
||||
enroll harvest --out /tmp/enroll-harvest
|
||||
enroll manifest --harvest /tmp/enroll-harvest --out ./ansible --fqdn "$(hostname -f)"
|
||||
|
||||
# Run the per-host playbook
|
||||
ansible-playbook ./ansible/playbooks/"$(hostname -f)".yml</code></pre>
|
||||
</div>
|
||||
<div class="smallprint mt-3">Rule of thumb: single-site for "one server, easy-to-read roles"; <code>--fqdn</code> for "many servers, high abstraction, fast adoption".</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="qs4" role="tabpanel" aria-labelledby="qs4-tab">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs4code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs4code"># Compare two harvests and get a human-friendly report (ignoring noise)
|
||||
enroll diff --old /path/to/harvestA --new /path/to/harvestB --format markdown \
|
||||
--exclude-path /var/anacron \
|
||||
--ignore-package-versions
|
||||
|
||||
# Send a webhook when differences are detected
|
||||
enroll diff \
|
||||
--old /path/to/harvestA \
|
||||
--new /path/to/harvestB \
|
||||
--webhook https://example.net/webhook \
|
||||
--webhook-format json \
|
||||
--webhook-header 'X-Enroll-Secret: ...' \
|
||||
--ignore-package-versions \
|
||||
--exit-code
|
||||
|
||||
# Ignore a path and changes to package versions, and optionally
|
||||
# enforce the old state locally (requires ansible-playbook)
|
||||
enroll diff --old /path/to/harvestA --new /path/to/harvestB \
|
||||
--exclude-path /var/anacron \
|
||||
--ignore-package-versions \
|
||||
--enforce</code></pre>
|
||||
</div>
|
||||
<div class="smallprint mt-3">E-mail notifications are also supported. Run it on a systemd timer to alert to drift!</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 class="tab-pane fade" id="qs5" role="tabpanel" aria-labelledby="qs5-tab">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs5code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs5code"># Explain what's in a harvest
|
||||
enroll explain /path/to/harvest
|
||||
|
||||
# JSON format, and using a SOPS-encrypted harvest
|
||||
enroll explain /path/to/harvest.sops \
|
||||
--sops \
|
||||
--format json
|
||||
</code></pre>
|
||||
</div>
|
||||
<div class="smallprint mt-3">'explain' tells you why something was included, but also why something was <em>excluded</em>.</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="qs6" role="tabpanel" aria-labelledby="qs6-tab">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#qs6code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="qs5code"># Validate a harvest is correct.
|
||||
enroll validate /path/to/harvest
|
||||
|
||||
# Check against the latest published version of the state schema specification
|
||||
enroll validate /path/to/harvest --schema https://enroll.sh/schema/state.schema.json
|
||||
</code></pre>
|
||||
</div>
|
||||
<div class="smallprint mt-3">'validate' makes sure the harvest's state confirms to Enroll's <a href="/schema.html">state schema</a>, doesn't contain orphaned artifacts and isn't missing any artifacts needed by the state. By default, it checks against the schema packaged with Enroll, but you can also check against the latest version on this site.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="py-5" id="demos" aria-label="Demos">
|
||||
<section class="py-5">
|
||||
<div class="container">
|
||||
<div class="row g-3 align-items-end mb-3">
|
||||
<div class="col-lg-8">
|
||||
<h2 class="section-title display-6 fw-bold mb-2">Demonstrations</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Harvest</div>
|
||||
<div class="text-muted mb-3">Collect state into a bundle.</div>
|
||||
<div class="asciicast" data-asciinema-id="765203"><script src="https://asciinema.org/a/765203.js" id="asciicast-765203" async="true"></script></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Manifest</div>
|
||||
<div class="text-muted mb-3">Render Ansible roles/playbooks.</div>
|
||||
<div class="asciicast" data-asciinema-id="765204"><script src="https://asciinema.org/a/765204.js" id="asciicast-765204" async="true"></script></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Single-shot</div>
|
||||
<div class="text-muted mb-3">Harvest → Manifest in one command.</div>
|
||||
<div class="asciicast" data-asciinema-id="765127"><script src="https://asciinema.org/a/765127.js" id="asciicast-765127" async="true"></script></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-lg-6">
|
||||
<div class="card feature-card h-100">
|
||||
<div class="card-body p-4">
|
||||
<div class="fw-semibold mb-1">Diff</div>
|
||||
<div class="text-muted mb-3">Drift report + webhook/email notifications, or optionally <em>enforce</em> the previous state!</div>
|
||||
<div class="asciicast" data-asciinema-id="767081"><script src="https://asciinema.org/a/767081.js" id="asciicast-767081" async="true"></script></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="py-5 bg-light" id="install" aria-label="Install">
|
||||
<div class="container">
|
||||
<div class="row g-3 align-items-end mb-3">
|
||||
<div class="col-lg-8">
|
||||
<h2 class="section-title display-6 fw-bold mb-2">Install</h2>
|
||||
<p class="text-muted mb-0">Use your preferred packaging. An AppImage is also available.</p>
|
||||
</div>
|
||||
<div class="col-lg-4 text-lg-end">
|
||||
<a class="btn btn-outline-dark" href="https://git.mig5.net/mig5/enroll#install" target="_blank" rel="noreferrer"><i class="bi bi-link-45deg"></i>Other install steps</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-pills gap-2" id="installTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#inst1" type="button" role="tab">Debian/Ubuntu</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#inst2" type="button" role="tab">Fedora</button></li>
|
||||
<li class="nav-item" role="presentation"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#inst3" type="button" role="tab">Pip</button></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content mt-3">
|
||||
<div class="tab-pane fade show active" id="inst1" role="tabpanel">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst1code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="inst1code">sudo mkdir -p /usr/share/keyrings
|
||||
curl -fsSL https://mig5.net/static/mig5.asc | sudo gpg --dearmor -o /usr/share/keyrings/mig5.gpg
|
||||
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/mig5.gpg] https://apt.mig5.net $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/mig5.list
|
||||
sudo apt update
|
||||
sudo apt install enroll</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="inst2" role="tabpanel">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst2code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="inst2code">sudo rpm --import https://mig5.net/static/mig5.asc
|
||||
|
||||
sudo tee /etc/yum.repos.d/mig5.repo > /dev/null << 'EOF'
|
||||
[mig5]
|
||||
name=mig5 Repository
|
||||
baseurl=https://rpm.mig5.net/$releasever/rpm/$basearch
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
repo_gpgcheck=1
|
||||
gpgkey=https://mig5.net/static/mig5.asc
|
||||
EOF
|
||||
|
||||
sudo dnf upgrade --refresh
|
||||
sudo dnf install enroll</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="inst3" role="tabpanel">
|
||||
<div class="codeblock">
|
||||
<button class="btn btn-sm btn-outline-secondary copy-btn" data-copy-target="#inst3code"><i class="bi bi-clipboard"></i> Copy</button>
|
||||
<pre class="terminal mb-0"><code id="inst3code">pip install enroll
|
||||
# or: pipx install enroll</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue