Initial commit
This commit is contained in:
244
Taskfile.yml
Normal file
244
Taskfile.yml
Normal file
@@ -0,0 +1,244 @@
|
||||
# ------------------------------------------------------------
|
||||
# Taskfile – Docker‑based Nix development & Colmena deployment
|
||||
# ------------------------------------------------------------
|
||||
version: "3"
|
||||
|
||||
vars:
|
||||
# Base directory of the repository – pass it when you invoke `task`,
|
||||
# e.g. `task -v ROOT_DIR=$(pwd) …`. You can also export it in your shell.
|
||||
ROOT_DIR: "{{ .ROOT_DIR }}"
|
||||
|
||||
# Convenience paths (expanded by `task` before being passed to Docker)
|
||||
FLAKE_DIR: "{{ .ROOT_DIR }}"
|
||||
AGE_KEY_PATH: "{{ .ROOT_DIR }}/age.key"
|
||||
SECRETS_YAML_PATH: "{{ .ROOT_DIR }}/hosts/blade/secrets.yaml"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Docker helpers (the Nix container always gets the repo mounted at
|
||||
# /workspace). `DOCKER_NIX_CMD` is used for *any* command that runs
|
||||
# inside the container.
|
||||
# -----------------------------------------------------------------
|
||||
DOCKER_COMPOSE_CMD: "docker compose -f {{ .ROOT_DIR }}/docker-compose.yml"
|
||||
DOCKER_NIX_CMD: >-
|
||||
{{ .DOCKER_COMPOSE_CMD }} run --rm
|
||||
-v "{{ .ROOT_DIR }}:/workspace"
|
||||
nixos
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Docker management
|
||||
# -----------------------------------------------------------------
|
||||
tasks:
|
||||
docker-build:
|
||||
desc: Build the Docker container for Nix
|
||||
cmds:
|
||||
- "{{ .DOCKER_COMPOSE_CMD }} build"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# NOTE: we now use DOCKER_NIX_CMD (which already has the bind‑mount)
|
||||
# ---------------------------------------------------------------
|
||||
docker-shell:
|
||||
desc: Enter a shell in the Docker container (repo is mounted)
|
||||
cmds:
|
||||
- "{{ .DOCKER_NIX_CMD }} bash"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
docker-up:
|
||||
desc: Start the Docker container (detached)
|
||||
cmds:
|
||||
- "{{ .DOCKER_COMPOSE_CMD }} up -d"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
docker-down:
|
||||
desc: Stop the Docker container
|
||||
cmds:
|
||||
- "{{ .DOCKER_COMPOSE_CMD }} down"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Age‑key handling (SOPS)
|
||||
# -----------------------------------------------------------------
|
||||
generate-age-key:
|
||||
desc: Generate a new age key for a host (default - all hosts without a key)
|
||||
vars:
|
||||
# If HOST is supplied we generate only for that host; otherwise we
|
||||
# iterate over every directory under `hosts/` that lacks an age.key.
|
||||
TARGET_HOSTS: |
|
||||
{{- if .HOST -}}
|
||||
{{ .HOST }}
|
||||
{{- else -}}
|
||||
{{- range $dir := (files (printf "%s/hosts/*" .ROOT_DIR)) -}}
|
||||
{{- $name := base $dir -}}
|
||||
{{- if not (fileExists (printf "%s/age.key" $dir)) -}}
|
||||
{{ $name }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
cmds:
|
||||
- |
|
||||
{{- $list := splitList "\n" .TARGET_HOSTS -}}
|
||||
{{- range $h := $list }}
|
||||
echo "🔑 Generating age.key for host '{{ $h }}' ..."
|
||||
{{ .DOCKER_NIX_CMD }} -v "{{ .ROOT_DIR }}/hosts/{{ $h }}:/workspace/hosts/{{ $h }}" \
|
||||
nixos age-keygen -o /workspace/hosts/{{ $h }}/age.key
|
||||
{{- end }}
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Encrypt / Decrypt (loop over hosts)
|
||||
# -----------------------------------------------------------------
|
||||
encrypt-secrets:
|
||||
desc: |
|
||||
Encrypt `secrets.yaml` for every host that has an age.key.
|
||||
Pass HOST=<name> to limit to a single host.
|
||||
vars:
|
||||
# Space‑separated list of hosts that have both age.key & secrets.yaml
|
||||
TARGET_HOSTS: |
|
||||
{{- if .HOST -}}
|
||||
{{ .HOST }}
|
||||
{{- else -}}
|
||||
{{- $list := slice -}}
|
||||
{{- range $dir := (files (printf "%s/hosts/*" .ROOT_DIR)) -}}
|
||||
{{- $name := base $dir -}}
|
||||
{{- $age := printf "%s/age.key" $dir -}}
|
||||
{{- $sec := printf "%s/secrets.yaml" $dir -}}
|
||||
{{- if (and (fileExists $age) (fileExists $sec)) -}}
|
||||
{{- $list = append $list $name -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- join " " $list -}}
|
||||
{{- end }}
|
||||
preconditions:
|
||||
- sh: test -n "{{ .TARGET_HOSTS }}"
|
||||
msg: "No hosts with both age.key and secrets.yaml were found."
|
||||
cmds:
|
||||
- |
|
||||
for host in {{ .TARGET_HOSTS }}; do
|
||||
echo "🔐 Encrypting secrets for host '$host' ..."
|
||||
{{ .DOCKER_NIX_CMD }} -v "{{ .ROOT_DIR }}/hosts/$host:/workspace/hosts/$host" \
|
||||
nixos sh -c "\
|
||||
pub=\$(grep 'public key' /workspace/hosts/$host/age.key | awk '{print \$NF}') && \
|
||||
sops --encrypt --age=\$pub --in-place /workspace/hosts/$host/secrets.yaml"
|
||||
done
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
decrypt-secrets:
|
||||
desc: |
|
||||
Decrypt `secrets.yaml` for every host that has an age.key.
|
||||
Decrypted output is written to `secrets.yaml.decrypted`.
|
||||
Pass HOST=<name> to limit to a single host.
|
||||
vars:
|
||||
TARGET_HOSTS: |
|
||||
{{- if .HOST -}}
|
||||
{{ .HOST }}
|
||||
{{- else -}}
|
||||
{{- $list := slice -}}
|
||||
{{- range $dir := (files (printf "%s/hosts/*" .ROOT_DIR)) -}}
|
||||
{{- $name := base $dir -}}
|
||||
{{- $age := printf "%s/age.key" $dir -}}
|
||||
{{- $sec := printf "%s/secrets.yaml" $dir -}}
|
||||
{{- if (and (fileExists $age) (fileExists $sec)) -}}
|
||||
{{- $list = append $list $name -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- join " " $list -}}
|
||||
{{- end }}
|
||||
preconditions:
|
||||
- sh: test -n "{{ .TARGET_HOSTS }}"
|
||||
msg: "No hosts with both age.key and secrets.yaml were found."
|
||||
cmds:
|
||||
- |
|
||||
for host in {{ .TARGET_HOSTS }}; do
|
||||
echo "🔓 Decrypting secrets for host '$host' ..."
|
||||
{{ .DOCKER_NIX_CMD }} -v "{{ .ROOT_DIR }}/hosts/$host:/workspace/hosts/$host" \
|
||||
nixos sh -c "\
|
||||
pub=\$(grep '# public key' /workspace/hosts/$host/age.key | awk '{print \$NF}') && \
|
||||
sops --decrypt --age=\$pub /workspace/hosts/$host/secrets.yaml \
|
||||
> /workspace/hosts/$host/secrets.yaml.decrypted"
|
||||
done
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Nix flake & build
|
||||
# -----------------------------------------------------------------
|
||||
flake-check:
|
||||
desc: Run `nix flake check` on the repository
|
||||
cmds:
|
||||
- "{{ .DOCKER_NIX_CMD }} nix flake check --flake /workspace"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
build-blade:
|
||||
desc: Build the NixOS configuration for the *blade* host
|
||||
cmds:
|
||||
- "{{ .DOCKER_NIX_CMD }} nix build /workspace#nixosConfigurations.blade"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Colmena deployment
|
||||
# -----------------------------------------------------------------
|
||||
deploy:
|
||||
desc: Deploy to an arbitrary node (usage - task deploy NODE=blade)
|
||||
cmds:
|
||||
- "{{ .DOCKER_NIX_CMD }} colmena apply --on {{ .NODE }}"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
preconditions:
|
||||
- sh: test -n "{{ .NODE }}"
|
||||
msg: "NODE variable is required. Example: task deploy NODE=blade"
|
||||
- sh: test -f "{{ .ROOT_DIR }}/age.key"
|
||||
- sh: test -f "{{ .ROOT_DIR }}/hosts/{{ .NODE }}/secrets.yaml"
|
||||
|
||||
deploy-blade:
|
||||
desc: Deploy the configuration to the *blade* host
|
||||
cmds:
|
||||
- "{{ .DOCKER_NIX_CMD }} colmena apply --on blade"
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
preconditions:
|
||||
- sh: test -f "{{ .ROOT_DIR }}/age.key"
|
||||
- sh: test -f "{{ .ROOT_DIR }}/hosts/blade/secrets.yaml"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# Helper: add a new node
|
||||
# -----------------------------------------------------------------
|
||||
add-node:
|
||||
desc: Create a new host directory with skeleton Nix files
|
||||
prompt: "Enter the name of the new node (e.g., node2):"
|
||||
cmds:
|
||||
- mkdir -p "{{ .FLAKE_DIR }}/hosts/{{ .CLI_ARGS }}"
|
||||
- |
|
||||
cat > "{{ .FLAKE_DIR }}/hosts/{{ .CLI_ARGS }}/configuration.nix" <<'EOF'
|
||||
{ config, lib, pkgs, ... }:
|
||||
{
|
||||
imports = [
|
||||
./hardware-configuration.nix
|
||||
../../common.nix
|
||||
];
|
||||
networking.hostName = "{{ .CLI_ARGS }}";
|
||||
}
|
||||
EOF
|
||||
- |
|
||||
cat > "{{ .FLAKE_DIR }}/hosts/{{ .CLI_ARGS }}/hardware-configuration.nix" <<'EOF'
|
||||
# Add hardware‑specific configurations here
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
{
|
||||
imports = [ (modulesPath + "/installer/scan/not-detected.nix") ];
|
||||
}
|
||||
EOF
|
||||
- |
|
||||
cat > "{{ .FLAKE_DIR }}/hosts/{{ .CLI_ARGS }}/secrets.yaml" <<'EOF'
|
||||
# Add node‑specific secrets here
|
||||
EOF
|
||||
- |
|
||||
cat > "{{ .FLAKE_DIR }}/hosts/{{ .CLI_ARGS }}/default.nix" <<'EOF'
|
||||
{ ... }: { imports = [ ./configuration.nix ./hardware-configuration.nix ../../common.nix ]; }
|
||||
EOF
|
||||
dir: "{{ .ROOT_DIR }}"
|
||||
|
||||
# -----------------------------------------------------------------
|
||||
# House‑keeping
|
||||
# -----------------------------------------------------------------
|
||||
clean:
|
||||
desc: Remove temporary/decrypted secret files for all hosts
|
||||
cmds:
|
||||
- |
|
||||
find "{{ .ROOT_DIR }}/hosts" -name 'secrets.yaml.decrypted' -delete
|
||||
silent: true
|
||||
Reference in New Issue
Block a user