Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ make molecule # containerised converge/verify of the decdn_node role (ne
cd ansible
make deps # vendor pinned Galaxy collections into ./collections
make check / deploy # deCDN node (site.yml): dry-run / provision
# fleet-wide by default; LIMIT=<host> scopes, ANSIBLE_ARGS='…' passes through
make build / galaxy-check # stage + build the decdn.node collection, then validate it
```

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ make security # KICS IaC scan of ansible/ (pinned engine image)
cd ansible
make deps # vendor pinned Galaxy collections into ./collections
make check / deploy # deCDN node (site.yml): dry-run / provision
# fleet-wide by default; LIMIT=<host> scopes, ANSIBLE_ARGS='…' passes through
```

**Gotcha — pre-commit is local-only.** Hygiene/shellcheck/yamllint/markdown run via
Expand Down
44 changes: 42 additions & 2 deletions ansible/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,53 @@ lint:
ansible-lint

# --- Primary: the public deCDN node ------------------------------------------
# Optional scoping for the deploy targets. Both are empty by default, so check/deploy
# stay fleet-wide (every host in decdn_nodes) unless you say otherwise.
# make deploy LIMIT=decdn-node-1 # one host
# make deploy LIMIT='decdn-node-1,decdn-node-2' # a list
# make deploy ANSIBLE_ARGS='--tags decdn_node -vv'
#
# Quote both values at YOUR prompt, not just in the examples:
# - make expands the --limit value single-quoted, so ansible host patterns reach
# ansible intact — but your own shell runs first, and eats an unquoted '!node'
# (history expansion) or 'decdn-node-*' (globbing) before make ever starts.
# - ANSIBLE_ARGS is substituted unquoted on purpose: the recipe's shell splits it
# back into separate flags (so inner quoting works —
# ANSIBLE_ARGS='--start-at-task="Install the decdn binaries"' survives). Unquoted
# at your prompt, make takes the extra words as goals and flags of its own — a
# bare -vv is make's own -v. A literal $ must be written $$.
LIMIT ?=
ANSIBLE_ARGS ?=
limit_arg = $(if $(LIMIT),--limit '$(LIMIT)')

# Fail loud on the two ways a run can look scoped but silently be fleet-wide. Scoped to
# check/deploy via MAKECMDGOALS so an unrelated `make lint` is never blocked. NOTE: this
# does not catch an argument that is well-formed but selects nothing — `--tags` with a
# typo (decdn-node vs decdn_node) runs zero tasks and still exits 0. See ansible/README.md.
ifneq ($(filter check deploy,$(MAKECMDGOALS)),)
# Echo back the goal the operator actually typed, so the hint never nudges a
# `make check` dry-run toward the mutating `make deploy`.
scoped_goal := $(firstword $(filter check deploy,$(MAKECMDGOALS)))
ifeq ($(origin LIMIT),environment)
$(error LIMIT is set in your environment ($(LIMIT)) and would silently scope this run. Unset it or pass it on the command line: make $(scoped_goal) LIMIT=<host>)
endif
ifeq ($(origin ANSIBLE_ARGS),environment)
$(error ANSIBLE_ARGS is set in your environment and would silently alter this run. Unset it or pass it on the command line)
endif
ifeq ($(origin LIMIT),command line)
ifeq ($(strip $(LIMIT)),)
$(error LIMIT was supplied but expanded empty (unset shell variable?) - refusing to run fleet-wide by accident. Omit LIMIT entirely to mean "all hosts")
endif
endif
endif

# Dry run against the real inventory — shows diffs, mutates nothing.
check:
ansible-playbook playbooks/site.yml --check --diff
ansible-playbook playbooks/site.yml --check --diff $(limit_arg) $(ANSIBLE_ARGS)

# Provision the deCDN node host(s) in inventory/hosts.yml.
deploy:
ansible-playbook playbooks/site.yml
ansible-playbook playbooks/site.yml $(limit_arg) $(ANSIBLE_ARGS)

# --- Tests -------------------------------------------------------------------
# Containerised converge + idempotence + verify of the decdn_node role against a
Expand Down
39 changes: 39 additions & 0 deletions ansible/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,45 @@ make check # dry run (--check --diff); asserts fire if required knobs a
make deploy # provision + start the node
```

Both targets are **fleet-wide by default** — every host in `decdn_nodes`. Scope a run with
`LIMIT`:

```bash
make check LIMIT=decdn-node-1 # dry-run one host
make deploy LIMIT=decdn-node-1 # converge one host
make deploy LIMIT='decdn-node-1,decdn-node-2' # a list
make deploy LIMIT='!decdn-node-2' # any ansible host pattern
```

Quote the pattern at your own prompt — your shell runs before make does, and eats a bare
`!decdn-node-2` (history expansion) or `decdn-node-*` (globbing).

Use `LIMIT` when **bringing up a new node**: that host's first converge creates the
operator account and then lets `ssh_hardening` disable root + password login — after which
you switch its `ansible_user` by hand (see [Setup](#setup) above; the converge does not
edit your inventory). You do not want that play re-converging nodes already serving
paid traffic. Same when re-running a single node after a config change, a failed play, or a
binary bump.

`make check`/`make deploy` refuse to run if `LIMIT` or `ANSIBLE_ARGS` reaches them from an
exported shell variable, or if `LIMIT` expands empty — both are ways a run looks scoped but
is silently fleet-wide.

`ANSIBLE_ARGS` passes anything else straight through. Quote the whole value at your prompt,
or make will read the extra words as its own goals and flags (a bare `-vv` is make's `-v`);
the recipe's shell then splits it back into separate flags, so inner quoting works. Write a
literal `$` as `$$`:

```bash
make deploy LIMIT=decdn-node-1 ANSIBLE_ARGS='--tags decdn_node -vv'
make deploy LIMIT=decdn-node-1 ANSIBLE_ARGS='--start-at-task="Install the decdn binaries"'
```

> **Watch the PLAY RECAP.** A *well-formed* argument that selects nothing is not an error:
> `--tags decdn-node` (hyphen, vs the real `decdn_node`) runs zero tasks and still exits 0,
> as does a `--limit` matching a host outside `decdn_nodes`. A malformed flag fails loudly;
> these do not. Confirm the recap lists the hosts you expected.

Then confirm:

```bash
Expand Down
Loading