373d21a744
Postgres-backed External Node Classifier for Puppet, replacing Cobbler. - encapi HTTP server (chi + pgx): read/write API + two ENC document shapes (reshaped for the exec terminus; cobbler-wire for enc_direct_facts.rb) - encapi-cli: classify/node/role/status CRUD + import-cobbler seeder - pkg/client Go SDK; unit tests across all packages (DB via testcontainers) - Dockerfile (distroless), Makefile, nfpm RPM (encapi-cli + encapi-enc wrapper), Woodpecker CI, docs/cutover.md
87 lines
3.2 KiB
Markdown
87 lines
3.2 KiB
Markdown
# Cutover: Cobbler ENC → encapi
|
|
|
|
Today Cobbler is Puppet's ENC. **Two** consumers hit
|
|
`http://cobbler.main.unkin.net/cblr/svc/op/puppet/hostname/<host>`:
|
|
|
|
1. **The exec ENC** — `puppet-prod` sets, in
|
|
`site/profiles/manifests/puppet/server.pp`:
|
|
```
|
|
node_terminus = exec
|
|
external_nodes = /opt/cobbler-enc/cobbler-enc
|
|
```
|
|
`/opt/cobbler-enc/cobbler-enc` (templated from
|
|
`site/profiles/templates/puppet/server/cobbler-enc.erb`) fetches Cobbler and
|
|
reshapes it (list-form classes, drops `environment` when `testing`, adds
|
|
`enc_role`/`enc_env`).
|
|
|
|
2. **The `enc_role`/`enc_env` facts** — `modules/libs/lib/facter/enc_direct_facts.rb`,
|
|
a fact on *every* node, fetches the same Cobbler endpoint (cached 7d at
|
|
`/var/cache/puppet_enc.yaml`) and derives `enc_role = classes.keys.first`,
|
|
`enc_env = environment`. Those facts drive `enc_role_tier1/2/3` +
|
|
`enc_role_path`, i.e. the whole Hiera hierarchy.
|
|
|
|
encapi serves drop-in replacements for **both**.
|
|
|
|
## 1. Seed encapi from the current estate
|
|
|
|
```bash
|
|
export ENCAPI_URL=https://encapi.k8s.syd1.au.unkin.net
|
|
export ENCAPI_WRITE_TOKEN=…
|
|
encapi-cli import-cobbler --dry-run # review
|
|
encapi-cli import-cobbler # writes statuses, roles, nodes
|
|
```
|
|
|
|
`import-cobbler` lists hosts from PuppetDB
|
|
(`http://puppetdbapi.service.consul:8080`), reads each host's Cobbler ENC, and
|
|
creates the derived status, role, and node.
|
|
|
|
## 2. Repoint the exec ENC (`profiles::puppet::cobbler_enc`)
|
|
|
|
Install the CLI RPM on the puppet masters (it ships `encapi-cli`,
|
|
`/usr/local/bin/encapi-enc`, and `/etc/encapi/enc.conf`), set
|
|
`ENCAPI_URL` in `/etc/encapi/enc.conf`, and point Puppet at the wrapper:
|
|
|
|
```
|
|
node_terminus = exec
|
|
external_nodes = /usr/local/bin/encapi-enc
|
|
```
|
|
|
|
`encapi-enc <certname>` runs `encapi-cli classify <certname>`, which returns the
|
|
identical reshaped document (`GET /api/v1/nodes/<certname>/enc`).
|
|
|
|
## 3. Repoint the `enc_direct_facts.rb` fact
|
|
|
|
Change only the base URL in `enc_direct_facts.rb`:
|
|
|
|
```ruby
|
|
uri = URI("https://encapi.k8s.syd1.au.unkin.net/cblr/svc/op/puppet/hostname/#{...}")
|
|
```
|
|
|
|
encapi's `/cblr/svc/op/puppet/hostname/<host>` returns the cobbler-wire shape
|
|
(`classes` as a map, `environment` always present), so `classes.keys.first` and
|
|
`environment` still resolve. No other fact logic changes.
|
|
|
|
## 4. Verify before flipping
|
|
|
|
For a sample of hosts, diff the old and new output:
|
|
|
|
```bash
|
|
diff <(curl -s "http://cobbler.main.unkin.net/cblr/svc/op/puppet/hostname/$H") \
|
|
<(curl -s "https://encapi.k8s.syd1.au.unkin.net/cblr/svc/op/puppet/hostname/$H")
|
|
|
|
diff <(/opt/cobbler-enc/cobbler-enc "$H") \
|
|
<(encapi-cli classify "$H")
|
|
```
|
|
|
|
The `classes`/`environment`/`enc_role`/`enc_env` fields must match. (Cobbler's
|
|
provisioning params — `epel`, `tree`, `from_cobbler`, `operatingsystemrelease` —
|
|
are intentionally dropped: they are unused by the Puppet manifests. If a future
|
|
need arises, wire `ENCAPI_DISTRO_API_URL` to the kickstart-replacement API and
|
|
they reappear under `parameters`.)
|
|
|
|
## 5. Decommission
|
|
|
|
Once masters and agents are repointed and a Puppet run is clean, retire
|
|
`profiles::puppet::cobbler_enc` and Cobbler's ENC role. Cobbler can keep doing
|
|
provisioning/kickstart; only its ENC duty moves to encapi.
|