Skip to content

Source: examples/skeleton/Makefile#

# makefile
ROOTDIR := $(patsubst %/,%,$(dir $(realpath $(firstword $(MAKEFILE_LIST)))))
.DEFAULT_GOAL := help
_CONTAINER_CMD := $(shell test -z "$$CONTAINER_CMD" && echo "podman" || echo "$$CONTAINER_CMD")
PULUMI := pulumi --logtostderr --logflow --non-interactive
PULUMI_INTERACTIVE := pulumi --logtostderr --logflow
define BROWSER_PYSCRIPT
import os, webbrowser, sys, urllib.request
webbrowser.open("file://" + urllib.request.pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT
BROWSER := python -c "$$BROWSER_PYSCRIPT"

# skip annoying version information
PULUMI_SKIP_UPDATE_CHECK=true
PULUMI_DIY_BACKEND_GZIP=true

.PHONY: help
help:
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \
        awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' | sort

# translate json to list of json keys in yaml
define json2keylist_python
import json
import sys
def itd(d,lvl=0,max_lvl=0):
  for k,v in d.items():
    if(isinstance(v,dict)):
      if max_lvl == 0 or lvl < max_lvl:
        print(" "*lvl*2, "-", k)
      itd(v,lvl+1)
      continue
    if max_lvl == 0 or lvl < max_lvl:
      print(" "*lvl*2, "-", k)
itd(json.loads(sys.stdin.read()))
endef
export json2keylist_python
json2keylist := python -c "$$json2keylist_python"


.PHONY: submodules
submodules: ## Pull and update git submodules recursively
    @echo "+ $@"
    git pull --recurse-submodules
    git submodule update --init --recursive

.PHONY: provision-client
provision-client: ## Build dependencies for provisioning using a container
    @echo "+ $@"
    $(_CONTAINER_CMD) build -t provision-client:latest -f infra/Containerfile/provision-client/Containerfile infra/Containerfile/provision-client

.PHONY: install-requirements
install-requirements: ## Build dependencies for provisioning using system apps
    @echo "+ $@"
    ./infra/scripts/requirements.sh --install
    ./infra/scripts/requirements.sh --install-extra

uv.lock: pyproject.toml
    @echo "+ $@"
    ./infra/scripts/requirements.sh --check
    uv lock

.venv/bin/activate: uv.lock
    @echo "+ $@"
    @./infra/scripts/requirements.sh --check
    # create venv
    if test -d .venv; then rm -rf .venv; fi
    uv venv

.venv/installed: .venv/bin/activate
    @echo "+++ $@"
    . .venv/bin/activate && uv sync --all-extras
    # register environment with local ipykernel environment
    . .venv/bin/activate && python -m ipykernel install --user --name=$$(basename $(ROOTDIR)/)
    touch $@

.PHONY: buildenv
buildenv: .venv/installed ## Build python environment

.PHONY: py-clean
py-clean: ## Remove python related artifacts
    @echo "+ $@"
    find . -type d -name '__pycache__' -exec rm -rf {} +
    find . -type d -name '.ipynb_checkpoints' -exec rm -rf {} +
    find . -type f -name '*.py[co]' -exec rm -f {} +

.PHONY: buildenv-clean
buildenv-clean: py-clean ## Remove build environment artifacts
    @echo "+ $@"
    rm -rf .venv


Pulumi.sim.yaml: buildenv
ifeq ($(shell test -f Pulumi.sim.yaml && echo "ok"), ok)
    @touch -c Pulumi.sim.yaml
else
    @echo "+ $@"
    mkdir -p $(ROOTDIR)/state/pulumi
    $(PULUMI) login file://$(ROOTDIR)/state/pulumi
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) stack init sim --secrets-provider passphrase
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) stack "select" "sim"
    cat config-template.yaml >> Pulumi.sim.yaml
endif

.PHONY: sim-create
sim-create: Pulumi.sim.yaml ## Create pulumi "sim" stack

.PHONY: sim-up
sim-up: sim-create ## Run "pulumi up --stack=sim $(args)
    @echo "+ $@"
    $(PULUMI) login file://$(ROOTDIR)/state/pulumi
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) up --stack "sim" --suppress-outputs --yes $(args)

.PHONY: sim-preview
sim-preview: sim-create ## Run "pulumi preview --stack=sim --suppress-outputs $(args)
    @echo "+ $@"
    $(PULUMI) login file://$(ROOTDIR)/state/pulumi
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) preview --stack "sim" --suppress-outputs $(args)

.PHONY: sim-show
sim-show: ## Run "pulumi stack output --stack=sim --json $(args)"
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) stack output --json --stack "sim" $(args)

.PHONY: sim-list
sim-list: ## Run "pulumi stack output --stack=sim --json | json2keylist"
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) stack output --json --stack "sim" | $(json2keylist)

.PHONY: sim__
sim__: ## Run "pulumi $(args)" on sim stack
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @$(PULUMI) stack select sim &> /dev/null
    @if test "$(args)" = "" -o "$(args)" = "help"; then PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI_INTERACTIVE) help; else PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI_INTERACTIVE) $(args); fi

.PHONY: sim-clean
sim-clean: ## Remove/Destroy "sim" stack
ifeq ($(shell test -f Pulumi.sim.yaml && echo "ok"), ok)
    @echo "+ $@"
    $(PULUMI) login file://$(ROOTDIR)/state/pulumi
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) --stack "sim" state unprotect --yes 'urn:pulumi:sim::athome::pkg:authority:CACertFactory$$command:local:Command::ca_factory_vault_ca' || true
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) --stack "sim" state unprotect --yes 'urn:pulumi:sim::athome::pkg:authority:CACertFactory$$tls:index/selfSignedCert:SelfSignedCert::ca_factory_root_cert' || true
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) --stack "sim" state unprotect --yes 'urn:pulumi:sim::athome::pkg:authority:CACertFactory$$tls:index/privateKey:PrivateKey::ca_factory_root_key' || true    PULUMI_CONFIG_PASSPHRASE="sim" PULUMI_CONTINUE_ON_ERROR=true $(PULUMI) destroy --stack "sim" --yes || true
    PULUMI_CONFIG_PASSPHRASE="sim" $(PULUMI) stack rm "sim" --force --yes  || true
    rm -rf state/pulumi/.pulumi/backups/sim state/pulumi/.pulumi/history/sim
    rm Pulumi.sim.yaml
endif


.PHONY: docs
docs: buildenv ## Build docs for local usage
    @echo "+ $@"
    mkdir -p build/docs
    . .venv/bin/activate && mkdocs build --no-directory-urls -d build/docs -f mkdocs.yml
    @echo "Finished. Browse at file:///$(ROOTDIR)/build/docs/index.html"

.PHONY: docs-online-build
docs-online-build: buildenv ## Build docs for http serve
    @echo "+ $@"
    mkdir -p build/docs-online
    . .venv/bin/activate && mkdocs build -d build/docs-online -f mkdocs.yml
    @echo "Finished. serve with"
    @echo ". .venv/bin/activate && python -m http.server --directory build/docs-online"

.PHONY: docs-serve
docs-serve: buildenv ## Rebuild and serve docs with autoreload
    @echo "+ $@"
    . .venv/bin/activate && mkdocs serve -f mkdocs.yml

.PHONY: docs-clean
docs-clean: ## Remove all generated docs
    @echo "+ $@"
    rm -rf build/docs build/docs-online
    mkdir -p build/docs build/docs-online


.PHONY: clean-all
clean-all: sim-clean buildenv-clean py-clean docs-clean ## Remove build, docs, tmp, salt & sim stack artifacts
    @echo "+ $@"
    rm -rf build/tmp
    rm -rf build/salt
    mkdir build/tmp build/salt


.PHONY: check_authorized_keys
check_authorized_keys:
    @if test ! -s $(ROOTDIR)/authorized_keys; then echo "ERROR: 'authorized_keys' is empty."; exit 1; fi

prod_passphrase.age: buildenv check_authorized_keys
ifeq ($(shell test -f prod_passphrase.age && echo "ok"), ok)
    @touch -c prod_passphrase.age
else
    @echo "+ $@"
    @openssl rand --base64 24 | age --encrypt -R $(ROOTDIR)/authorized_keys -a > prod_passphrase.age
endif

Pulumi.prod.yaml: buildenv check_authorized_keys
ifeq ($(shell test -f Pulumi.prod.yaml && echo "ok"), ok)
    @touch -c Pulumi.prod.yaml
else
    @echo "+ $@"
    @mkdir -p $(ROOTDIR)/state/pulumi
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi
    @PULUMI_CONFIG_PASSPHRASE="$$(age --decrypt -i ~/.ssh/id_rsa prod_passphrase.age)" $(PULUMI) stack init prod --secrets-provider passphrase
endif

.PHONY: prod-create
prod-create: prod_passphrase.age Pulumi.prod.yaml ## Create pulumi "prod" stack

.PHONY: prod-show
prod-show: ## Run "pulumi stack output --stack "prod" --json $(args)"
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @PULUMI_CONFIG_PASSPHRASE="$$(age --decrypt -i ~/.ssh/id_rsa prod_passphrase.age)" $(PULUMI) stack output --json --stack "prod" $(args)

.PHONY: prod-up
prod-up: prod-create ## Run "pulumi up --stack=prod $(args)
    @echo "+ $@"
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @PULUMI_CONFIG_PASSPHRASE="$$(age --decrypt -i ~/.ssh/id_rsa prod_passphrase.age)" $(PULUMI) up --stack "prod" --suppress-outputs $(args)

.PHONY: prod-preview
prod-preview: prod-create ## Run "pulumi preview --stack=prod --suppress-outputs $(args)
    @echo "+ $@"
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @PULUMI_CONFIG_PASSPHRASE="$$(age --decrypt -i ~/.ssh/id_rsa prod_passphrase.age)" $(PULUMI) preview --stack "prod" --suppress-outputs $(args)

.PHONY: prod__
prod__: prod-create ## Run pulumi "$(args)" on prod stack
    @$(PULUMI) login file://$(ROOTDIR)/state/pulumi &> /dev/null
    @$(PULUMI) stack select prod
    @if test "$(args)" = "" -o "$(args)" = "help"; then $(PULUMI_INTERACTIVE) help; else PULUMI_CONFIG_PASSPHRASE="$$(age --decrypt -i ~/.ssh/id_rsa prod_passphrase.age)" $(PULUMI_INTERACTIVE) $(args); fi