boma/Makefile

163 lines
6.8 KiB
Makefile
Raw Normal View History

# Ansible + Terraform homelab monorepo — Makefile
# All operations go through these targets. Never run ansible-playbook or terraform directly.
VENV := .venv
PYTHON := $(VENV)/bin/python
PIP := $(VENV)/bin/pip
ANSIBLE := $(VENV)/bin/ansible
PLAYBOOK_BIN := $(VENV)/bin/ansible-playbook
GALAXY := $(VENV)/bin/ansible-galaxy
LINT := $(VENV)/bin/ansible-lint
MOLECULE := $(VENV)/bin/molecule
# Vault password is resolved via ansible.cfg (vault_password_file); no flag needed.
VAULT_ARGS :=
INVENTORY := -i inventories/production/hosts.yml
TF := terraform
TF_ENV ?= staging
MOLECULE_IMAGE := forgejo.nyumbani.baobab.band/sjat/molecule-debian13:latest
MOLECULE_DOCKERFILE := .docker/molecule-debian13/Dockerfile
.DEFAULT_GOAL := help
.PHONY: help setup collections lint test test-all check deploy encrypt decrypt new-role \
tf-init tf-plan tf-apply tf-output tf-inventory \
molecule-image molecule-image-push
help:
@echo ""
@echo "Ansible homelab — available targets:"
@echo ""
@echo " make setup Create venv and install Python deps"
@echo " make collections Install Ansible collections"
@echo " make lint Run yamllint + ansible-lint"
@echo " make test ROLE=<name> Run Molecule tests for a role"
@echo " make test-all Run Molecule tests for all roles"
@echo " make check PLAYBOOK=<name> Dry-run a playbook (check mode)"
@echo " make deploy PLAYBOOK=<name> Run a playbook against production"
@echo " make encrypt FILE=<path> Encrypt a vault file"
@echo " make decrypt FILE=<path> Decrypt a vault file"
@echo " make new-role NAME=<name> Scaffold a new role"
@echo ""
@echo " make tf-init [TF_ENV=staging] Initialise Terraform providers"
@echo " make tf-plan [TF_ENV=staging] Show Terraform plan"
@echo " make tf-apply [TF_ENV=staging] Apply Terraform changes"
@echo " make tf-output [TF_ENV=staging] Print Terraform outputs as JSON"
@echo " make tf-inventory [TF_ENV=staging] Regenerate Ansible inventory from Terraform outputs"
@echo ""
@echo " TF_ENV defaults to 'staging'. Use TF_ENV=production for production."
@echo ""
@echo " make molecule-image Build the Molecule test image locally"
@echo " make molecule-image-push Push the test image to the Forgejo registry"
@echo ""
# ── Environment setup ─────────────────────────────────────────────────────────
setup:
python3 -m venv $(VENV)
$(PIP) install --upgrade pip
$(PIP) install -r requirements.txt
@echo "Venv ready. Activate with: source $(VENV)/bin/activate"
collections:
$(GALAXY) collection install -r requirements.yml --upgrade
# ── Linting ───────────────────────────────────────────────────────────────────
lint:
$(VENV)/bin/yamllint .
$(LINT)
$(PYTHON) scripts/check-tags.py
# ── Testing ───────────────────────────────────────────────────────────────────
test:
ifndef ROLE
$(error ROLE is required: make test ROLE=<rolename>)
endif
cd roles/$(ROLE) && PATH="$(CURDIR)/$(VENV)/bin:$$PATH" molecule test
test-all:
@for role in roles/*/; do \
echo "── Testing $$role ──"; \
cd $$role && PATH="$(CURDIR)/$(VENV)/bin:$$PATH" molecule test; cd ../..; \
done
# ── Playbook execution ────────────────────────────────────────────────────────
check:
ifndef PLAYBOOK
$(error PLAYBOOK is required: make check PLAYBOOK=<name>)
endif
$(PLAYBOOK_BIN) $(INVENTORY) $(VAULT_ARGS) --check --diff playbooks/$(PLAYBOOK).yml
deploy:
ifndef PLAYBOOK
$(error PLAYBOOK is required: make deploy PLAYBOOK=<name>)
endif
$(PLAYBOOK_BIN) $(INVENTORY) $(VAULT_ARGS) playbooks/$(PLAYBOOK).yml
# ── Vault ─────────────────────────────────────────────────────────────────────
encrypt:
ifndef FILE
$(error FILE is required: make encrypt FILE=<path>)
endif
$(ANSIBLE)-vault encrypt $(FILE)
decrypt:
ifndef FILE
$(error FILE is required: make decrypt FILE=<path>)
endif
$(ANSIBLE)-vault decrypt $(FILE)
# ── Molecule test image ───────────────────────────────────────────────────────
molecule-image:
docker build -t $(MOLECULE_IMAGE) -f $(MOLECULE_DOCKERFILE) .
molecule-image-push: molecule-image
docker push $(MOLECULE_IMAGE)
# ── Terraform ─────────────────────────────────────────────────────────────────
tf-init:
$(TF) -chdir=terraform/environments/$(TF_ENV) init
tf-plan:
$(TF) -chdir=terraform/environments/$(TF_ENV) plan
tf-apply:
$(TF) -chdir=terraform/environments/$(TF_ENV) apply
tf-output:
$(TF) -chdir=terraform/environments/$(TF_ENV) output -json
tf-inventory:
ifndef TF_ENV
$(error TF_ENV is required: make tf-inventory TF_ENV=<staging|production>)
endif
$(TF) -chdir=terraform/environments/$(TF_ENV) output -json \
| $(PYTHON) scripts/tf_to_inventory.py > inventories/$(TF_ENV)/hosts.yml
@echo "Inventory written to inventories/$(TF_ENV)/hosts.yml"
# ── Role scaffolding ──────────────────────────────────────────────────────────
new-role:
ifndef NAME
$(error NAME is required: make new-role NAME=<rolename>)
endif
mkdir -p roles/$(NAME)/tasks roles/$(NAME)/handlers roles/$(NAME)/defaults \
roles/$(NAME)/templates roles/$(NAME)/files roles/$(NAME)/meta \
roles/$(NAME)/molecule/default
echo "---" > roles/$(NAME)/tasks/main.yml
echo "---" > roles/$(NAME)/handlers/main.yml
echo "---" > roles/$(NAME)/defaults/main.yml
echo "---" > roles/$(NAME)/meta/main.yml
printf '# %s\n\nRole description here.\n' "$(NAME)" > roles/$(NAME)/README.md
cp .scaffold/molecule.yml roles/$(NAME)/molecule/default/molecule.yml
sed 's/ROLE_NAME_PLACEHOLDER/$(NAME)/g' .scaffold/converge.yml > roles/$(NAME)/molecule/default/converge.yml
cp .scaffold/verify.yml roles/$(NAME)/molecule/default/verify.yml
@echo "Role $(NAME) scaffolded at roles/$(NAME)/"
@echo "Next: fill in meta/main.yml, defaults/main.yml, tasks/main.yml, README.md"