Doc updates

This commit is contained in:
Miguel Jacq 2026-01-03 15:16:51 +11:00
parent d884676612
commit 418fc7e4ef
Signed by: mig5
GPG key ID: 59B3F0C24135C6A9
2 changed files with 46 additions and 6 deletions

View file

@ -60,6 +60,7 @@
<div class="position-sticky" style="top: 96px;"> <div class="position-sticky" style="top: 96px;">
<div class="list-group"> <div class="list-group">
<a class="list-group-item list-group-item-action" href="#model">Mental model</a> <a class="list-group-item list-group-item-action" href="#model">Mental model</a>
<a class="list-group-item list-group-item-action" href="#harvest">How harvesting works</a>
<a class="list-group-item list-group-item-action" href="#modes">Single-site vs multi-site</a> <a class="list-group-item list-group-item-action" href="#modes">Single-site vs multi-site</a>
<a class="list-group-item list-group-item-action" href="#remote">Remote harvesting</a> <a class="list-group-item list-group-item-action" href="#remote">Remote harvesting</a>
<a class="list-group-item list-group-item-action" href="#templates">JinjaTurtle templates</a> <a class="list-group-item list-group-item-action" href="#templates">JinjaTurtle templates</a>
@ -123,6 +124,40 @@
</div> </div>
</section> </section>
<section id="harvest" class="scroll-mt-nav mb-5">
<h2 class="section-title fw-bold">How harvesting works</h2>
<p class="text-secondary">At a high level, this is what happens when <code>enroll harvest</code> runs on a host:</p>
<ul class="mb-0 small">
<li>Detects the OS and its package backend (e.g dpkg vs rpm)</li>
<li>Detects what packages are installed</li>
<li>For each package, it tries to detect files in <code>/etc</code> that have been modified from the default that get shipped with the package.</li>
<li>It detects running/enabled services and timers via systemd. For each of these, it looks for the unit files, any 'drop-in' files, environment variable files, etc, as well as what executable it executes, and tries to map those systemd services to the packages it's already learned about earlier (that way, those 'packages' or future Ansible roles, can also be associated with 'handlers' in Ansible, to handle restart of the services if/when the configs change)</li>
<li>Aside from known packages already learned, it optimistically tries to capture extra system configuration in <code>/etc</code> that is common for config management. This is stuff like the apt or dnf configuration, crons, logrotate configs, networking settings, hosts files, etc.</li>
<li>It also looks for other snowflake stuff in <code>/etc</code> not associated with packages/services or other typical system config, and will put these into an <code>etc_custom</code> role.</li>
<li>Likewise, it looks in <code>/usr/local</code> for stuff, on the assumption that this is an area that custom apps/configs might've been placed in. These go into a <code>usr_local_custom</code> role.</li>
<li>It captures non-system user accounts, their group memberships and their <code>.ssh/authorized_keys</code></li>
<li>It takes into account anything the user set with <code>--exclude-path</code> or <code>--include-path</code>. For anything extra that is included, it will put these into an '<code>extra_paths</code>' role. The location could be anywhere e.g something in <code>/opt</code>, <code>/srv</code>, whatever you want.</li>
<li>It writes the state.json and captures the artifacts.</li>
</ul>
<br />
<p class="text-secondary">Other things to be aware of:</p>
<ul class="mb-0 small">
<li>You can use multiple invocations of <code>--exclude-path</code> to skip the bits you don't want. You also can always comment out from the playbook.yml or delete certain roles it generates once you've run the <code>enroll manifest</code>.</li>
<li>In terms of safety measures: it doesn't traverse symlinks, and it has an 'IgnorePolicy' that makes it ignore most binary files (except GPG binary keys used with apt) - though if you specify certain paths with <code>--include-path</code> and use <code>--dangerous</code>, it will skip some policy statements such as what types of content to ignore.</li>
<li>It will skip files that are too large, and it also currently has a hardcoded cap of the number of files that it will harvest (4000 for <code>/etc</code>, <code>/usr/local/etc</code> and <code>/usr/local/bin</code>, and 500 files per 'role'), to avoid unintentional 'runaway' situations.</li>
</ul>
<div class="alert alert-secondary mt-3 mb-0">
<div class="fw-semibold">Does Enroll use Ansible community/galaxy roles?</div>
<div class="small mb-0">No, Enroll doesn't have any knowledge of Ansible Galaxy roles or community plugins. It generates all the roles itself. If you really want to use roles from the community, Enroll may not be the tool for you, other than perhaps to help get you started.</div>
<br />
<div class="small mb-0">Keep in mind that a lot of software config files are also good candidates for being Jinja templates with abstracted vars for separate hosts.</div>
<br />
<div class="small mb-0">Enroll does use my companion tool <a href="https://git.mig5.net/mig5/jinjaturtle" target="_blank" rel="noopener noreferrer">JinjaTurtle</a> if it's installed, but JinjaTurtle only recognises certain types of files (.ini style, .json, .xml, .yaml, .toml, but not special ones like Nginx or Apache conf files which have their own special syntax). When Enroll can't turn a config file into a template, it copies the raw file instead and uses it with <code>ansible.builtin.copy</code> in role tasks.</div>
</div>
</section>
<section id="modes" class="scroll-mt-nav mb-5"> <section id="modes" class="scroll-mt-nav mb-5">
<h2 class="section-title fw-bold">Single-site vs multi-site</h2> <h2 class="section-title fw-bold">Single-site vs multi-site</h2>
<p class="text-secondary">Manifest output has two styles. Choose based on how you'll use the result.</p> <p class="text-secondary">Manifest output has two styles. Choose based on how you'll use the result.</p>
@ -164,7 +199,13 @@
<p class="text-secondary">Run Enroll on your workstation, harvest a remote host over SSH. The harvest is pulled locally.</p> <p class="text-secondary">Run Enroll on your workstation, harvest a remote host over SSH. The harvest is pulled locally.</p>
<div class="terminal"> <div class="terminal">
<pre class="mb-0"><code><span class="prompt">$</span> enroll harvest --remote-host myhost.example.com --remote-user myuser --out /tmp/enroll-harvest <pre class="mb-0"><code><span class="prompt">$</span> enroll harvest --remote-host myhost.example.com --remote-user myuser --out /tmp/enroll-harvest
<span class="prompt">$</span> enroll single-shot --remote-host myhost.example.com --remote-user myuser --out /tmp/enroll-ansible --fqdn myhost.example.com</code></pre> <span class="prompt">$</span> enroll manifest --harvest /tmp/enroll-harvest --out /tmp/enroll-manifest
# Alternatively, run both commands combined together with the 'single-shot' mode:
<span class="prompt">$</span> enroll single-shot --remote-host myhost.example.com --remote-user myuser \
--harvest /tmp/enroll-harvest --out /tmp/enroll-ansible \
--fqdn myhost.example.com</code></pre>
</div> </div>
<div class="alert alert-secondary mt-3"> <div class="alert alert-secondary mt-3">
<div class="fw-semibold">Tip</div> <div class="fw-semibold">Tip</div>

View file

@ -276,8 +276,7 @@ enroll diff \
<div class="card-body p-4"> <div class="card-body p-4">
<div class="fw-semibold mb-1">Harvest</div> <div class="fw-semibold mb-1">Harvest</div>
<div class="text-muted mb-3">Collect state into a bundle.</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 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> </div>
</div> </div>
@ -296,7 +295,7 @@ enroll diff \
<div class="card feature-card h-100"> <div class="card feature-card h-100">
<div class="card-body p-4"> <div class="card-body p-4">
<div class="fw-semibold mb-1">Single-shot</div> <div class="fw-semibold mb-1">Single-shot</div>
<div class="text-muted mb-3">One command → workable output.</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 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>
@ -305,7 +304,7 @@ enroll diff \
<div class="card feature-card h-100"> <div class="card feature-card h-100">
<div class="card-body p-4"> <div class="card-body p-4">
<div class="fw-semibold mb-1">Diff</div> <div class="fw-semibold mb-1">Diff</div>
<div class="text-muted mb-3">Drift report + notifications.</div> <div class="text-muted mb-3">Drift report + webhook/email notifications.</div>
<div class="asciicast" data-asciinema-id="765128"><script src="https://asciinema.org/a/765128.js" id="asciicast-765128" async="true"></script></div> <div class="asciicast" data-asciinema-id="765128"><script src="https://asciinema.org/a/765128.js" id="asciicast-765128" async="true"></script></div>
</div> </div>
</div> </div>
@ -352,7 +351,7 @@ sudo apt install enroll</code></pre>
sudo tee /etc/yum.repos.d/mig5.repo > /dev/null << 'EOF' sudo tee /etc/yum.repos.d/mig5.repo > /dev/null << 'EOF'
[mig5] [mig5]
name=mig5 Repository name=mig5 Repository
baseurl=https://rpm.mig5.net/rpm/$basearch baseurl=https://rpm.mig5.net/$releasever/rpm/$basearch
enabled=1 enabled=1
gpgcheck=1 gpgcheck=1
repo_gpgcheck=1 repo_gpgcheck=1