Files
puppet-prod/site/profiles/manifests/base.pp
T
unkinben aebe80e73f Add profiles::puppet::migrate: repoint VM agents onto puppet-on-k8s (#493)
## Why

Migrate the VM puppet agents off the legacy VM puppetmasters onto the new puppet-on-kubernetes servers, one wave at a time and reversible without re-enrolment.

Changing `server`/`ca_server` alone is insufficient: each agent's ssldir holds a client certificate signed by the **old** CA, which the new k8s CA neither trusts nor recognises. Migrated nodes switch to a **fresh ssldir**, so the agent generates a new key + CSR on its next run (autosigned immediately by the k8s CA, which runs `autosign = true`), pulls its catalog from the new compilers, and leaves the old CA-signed creds intact on disk for rollback.

The reconfiguration catalog is compiled by the **old** server (the node still points there when it applies the change). `profiles::puppet::client` rewrites `puppet.conf` with the new endpoints + ssldir and notifies `Service['puppet']`, so the very next agent run lands on k8s.

**Single-boolean design (reworked):** cutover is now driven by one hiera key. `profiles::puppet::migrate` ships wired into `profiles::base` with `enabled => false`, so every node evaluates it but nothing changes until the boolean is flipped. `profiles::puppet::client` includes migrate and folds the migrate endpoints into the effective values it renders. Flip `profiles::puppet::migrate::enabled: true` at any hiera layer (node/role/common) to migrate a target -- no other keys required.

## Changes

- `profiles::base` (`site/profiles/manifests/base.pp`): `include profiles::puppet::migrate` alongside the other puppet profiles (ships disabled).
- `profiles::puppet::migrate` (`site/profiles/manifests/puppet/migrate.pp`): unchanged params (`enabled=false`, `new_server`, `new_ca_server`, `new_ssldir`); when enabled and the node is not a puppetmaster it owns the fresh ssldir directory. Class-header runbook rewritten for the single-boolean flow. No longer opt-in via `hiera_include`.
- `profiles::puppet::client` (`site/profiles/manifests/puppet/client.pp`): `include profiles::puppet::migrate` and compute `$effective_server` / `$effective_ca_server` / `$effective_report_server` / `$effective_ssldir`, feeding those to the template. Keeps the existing optional `$ssldir` / `$report_server` params as manual overrides.
- `puppet.conf.erb`: render from the `@effective_*` vars.

## Precedence

- **ssldir / report_server** (`Optional`, default `undef`): explicit `profiles::puppet::client::ssldir` / `::report_server` in hiera wins; else the migrate-derived value when `enabled`; else the legacy default (ssldir omitted -> puppet default; report_server -> effective server).
- **server / ca_server** (`String`, no undef sentinel): the migrate endpoint wins while `enabled => true`; otherwise the client param (legacy default unless set explicitly). To pin a bespoke server, leave `enabled => false` for that target and set `profiles::puppet::client::server` directly.
- No include cycle: migrate.pp never references client.pp; its guard uses `$facts['enc_role']`.

## Runbook

- **Canary (one node)** -> `hieradata/nodes/<certname>.yaml`: `profiles::puppet::migrate::enabled: true`
- **Wave (a role)** -> `hieradata/roles/<t1>/<t2>[/<t3>].yaml`: `profiles::puppet::migrate::enabled: true`
- **Estate flip** -> `hieradata/common.yaml`: `profiles::puppet::migrate::enabled: true`
- **Rollback** -> remove the key (or set `false`) at that layer; next run rewrites puppet.conf back to the legacy server + legacy ssldir (original CA-signed cert intact).
- The k8s endpoints (`new_server` / `new_ca_server` / `new_ssldir`) are `profiles::puppet::migrate` param defaults; override them in hiera if the k8s names change.

## Verification

- Render comparison: unmigrated node renders a **byte-identical** `puppet.conf` to `develop` (diff empty). Migrated render (only `enabled: true`) emits `server`/`ca_server`/`report_server` = k8s endpoints and `ssldir = /etc/puppetlabs/puppet/ssl-k8s`.
- `puppet-lint` (repo args `--no-80chars-check --no-documentation-check --no-puppet_url_without_modules-check --fail-on-warnings`): clean on all 3 manifests.
- `puppet parser validate`: OK. ERB syntax: OK. Repo pre-commit hooks (erb-validate, puppet-lint, puppet-validate): all Passed.

Reviewed-on: #493
Co-authored-by: Ben Vincent <ben@unkin.net>
Co-committed-by: Ben Vincent <ben@unkin.net>
2026-07-25 00:04:11 +10:00

75 lines
2.3 KiB
Puppet

# this is the base class, which will be used by all servers
class profiles::base () {
# run a limited set of classes on the first run aimed at bootstrapping the new node
if $facts['firstrun'] {
include profiles::firstrun::init
}else{
# install the vault ca first
include profiles::pki::vaultca
# manage the puppet agent
include profiles::puppet::agent
include profiles::puppet::client
# k8s migration switch; ships disabled, flip its ::enabled boolean in
# hiera (node/role/common) to repoint a target onto puppet-on-k8s.
include profiles::puppet::migrate
# include the base profiles
include profiles::base::repos
include profiles::packages
include profiles::base::motd
include profiles::base::scripts
include profiles::base::hosts
include profiles::base::groups
include profiles::accounts::root
include profiles::accounts::sysadmin
if $facts['virtual'] != 'lxc' {
include profiles::ntp::client
}
include profiles::dns::base
include profiles::pki::vault
include profiles::ssh::sign
include profiles::ssh::knownhosts
include profiles::ssh::service
include profiles::cloudinit::init
include profiles::helpers::node_lookup
include profiles::consul::client
include victorialogs::client::journald
# include the python class
class { 'python':
manage_python_package => true,
manage_venv_package => true,
manage_pip_package => true,
use_epel => false,
}
# all hosts will have sudo applied
class { 'sudo':
secure_path => '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/puppetlabs/bin'
}
# manage virtualised guest agents
if $::facts['is_virtual'] and $::facts['dmi']['manufacturer'] == 'QEMU' {
include profiles::qemu::agent
}
class { 'limits':
purge_limits_d_dir => false,
}
# include classes from hiera
$hiera_include = lookup('hiera_include', Array[String], 'unique', [])
$hiera_exclude = lookup('hiera_exclude', Array[String], 'unique', [])
($hiera_include - $hiera_exclude).include
# specifc ordering constraints
Class['profiles::defaults']
-> Class['profiles::pki::vaultca']
-> Class['profiles::base::repos']
-> Class['profiles::packages']
}
}