From 517080aeabffdb708b268df75979c899ede8a288 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Thu, 12 Feb 2026 19:18:46 -0800 Subject: [PATCH] Add reference/tools/ category with Dagger, ArgoCD CLI, Ansible, and Pulumi cards (#178) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Create `docs/reference/tools/` with four reference cards: Dagger (build engine), ArgoCD CLI (deployment workflows), Ansible (config management), and Pulumi (DNS/Tailscale IaC) - Move `ansible/roles.md` → `tools/ansible.md`, broadened with CLI patterns and dry-run usage - Update `reference.md` index: add "Tools" section, remove old "Ansible" section - Update `update-documentation.md` to reflect Dagger build process (workflow steps, manual build recipe, runner environment) - Update `adopt-dagger-ci.md` plan to note how-to articles were handled via reference card + existing how-to updates - Fix all broken `[[roles]]` wiki-links across 5 files → `[[ansible]]` ## Verification - `docs-check-links` ✓ — no broken wiki-links - `docs-check-index` ✓ — all docs referenced in category index - `docs-check-filenames` ✓ — no duplicate filenames - All pre-commit hooks pass Reviewed-on: https://forge.ops.eblu.me/eblume/blumeops/pulls/178 --- .../feature-reference-tools-category.doc.md | 1 + docs/explanation/why-gitops.md | 4 +- docs/how-to/add-ansible-role.md | 2 +- .../how-to/plans/completed/adopt-dagger-ci.md | 9 +-- docs/how-to/update-documentation.md | 39 ++++------ docs/reference/reference.md | 15 ++-- docs/reference/services/argocd.md | 1 + .../{ansible/roles.md => tools/ansible.md} | 25 ++++-- docs/reference/tools/argocd-cli.md | 54 +++++++++++++ docs/reference/tools/dagger.md | 78 +++++++++++++++++++ docs/reference/tools/pulumi.md | 53 +++++++++++++ docs/tutorials/replication/core-services.md | 2 +- .../replication/observability-stack.md | 2 +- 13 files changed, 237 insertions(+), 48 deletions(-) create mode 100644 docs/changelog.d/feature-reference-tools-category.doc.md rename docs/reference/{ansible/roles.md => tools/ansible.md} (73%) create mode 100644 docs/reference/tools/argocd-cli.md create mode 100644 docs/reference/tools/dagger.md create mode 100644 docs/reference/tools/pulumi.md diff --git a/docs/changelog.d/feature-reference-tools-category.doc.md b/docs/changelog.d/feature-reference-tools-category.doc.md new file mode 100644 index 0000000..e5a87ca --- /dev/null +++ b/docs/changelog.d/feature-reference-tools-category.doc.md @@ -0,0 +1 @@ +Add reference/tools/ category with Dagger, ArgoCD CLI, Ansible, and Pulumi reference cards diff --git a/docs/explanation/why-gitops.md b/docs/explanation/why-gitops.md index fbc02af..e03978b 100644 --- a/docs/explanation/why-gitops.md +++ b/docs/explanation/why-gitops.md @@ -46,7 +46,7 @@ BlumeOps uses layered GitOps: | Layer | Tool | What it manages | |-------|------|-----------------| | **Tailnet** | [[tailscale|Pulumi]] | ACLs, tags, DNS | -| **Host config** | [[roles|Ansible]] | Services on [[indri]] | +| **Host config** | [[ansible|Ansible]] | Services on [[indri]] | | **Kubernetes** | [[argocd|ArgoCD]] | Containerized workloads | Each layer has its own reconciliation loop: @@ -68,4 +68,4 @@ But for BlumeOps, the trade-off is worth it. The infrastructure is complex enoug - [[architecture]] - How the pieces fit together - [[argocd]] - Kubernetes GitOps -- [[roles|Ansible roles]] - Host configuration +- [[ansible]] - Host configuration diff --git a/docs/how-to/add-ansible-role.md b/docs/how-to/add-ansible-role.md index 4d78e47..cad4095 100644 --- a/docs/how-to/add-ansible-role.md +++ b/docs/how-to/add-ansible-role.md @@ -137,6 +137,6 @@ See [[alloy]] for how metrics are collected from textfiles. ## Related -- [[roles|Roles]] - Available roles reference +- [[ansible]] - Available roles reference - [[indri]] - Target host - [[observability]] - Metrics collection diff --git a/docs/how-to/plans/completed/adopt-dagger-ci.md b/docs/how-to/plans/completed/adopt-dagger-ci.md index ae4f5f6..a3ec8ce 100644 --- a/docs/how-to/plans/completed/adopt-dagger-ci.md +++ b/docs/how-to/plans/completed/adopt-dagger-ci.md @@ -517,14 +517,9 @@ BuildKit caches aggressively, making repeated builds fast. Since the Forgejo run - **Changelog dates show UTC date:** Towncrier uses `datetime.date.today()` which respects `TZ`, and `tzdata` is installed in the runner image, but the changelog still renders tomorrow's date (UTC). The runner pod and job containers both have `TZ=America/Los_Angeles` set. Root cause is unresolved — may require passing an explicit `--date` flag to towncrier or patching the Dagger `build_changelog` container. -## How-To Articles to Write +## How-To Articles -The following how-to guides should be created alongside implementation: - -| Article | Description | -|---------|-------------| -| `docs/how-to/use-dagger-containers.md` | Creating and iterating on containers with Dagger (build, terminal, publish workflow) | -| `docs/how-to/release-docs.md` | Updated docs release process using Dagger + Forgejo packages (replaces current [[update-documentation]]) | +Standalone how-to articles for Dagger were deemed unnecessary — the existing [[update-documentation]] how-to was updated to reflect the Dagger build process, and a [[dagger]] reference card covers CLI usage and function signatures. ## Reference diff --git a/docs/how-to/update-documentation.md b/docs/how-to/update-documentation.md index 4786939..e9991e6 100644 --- a/docs/how-to/update-documentation.md +++ b/docs/how-to/update-documentation.md @@ -25,13 +25,13 @@ Direct link: https://forge.ops.eblu.me/eblume/blumeops/actions?workflow=build-bl The `build-blumeops` workflow (`.forgejo/workflows/build-blumeops.yaml`): -1. **Resolves version** - Uses input or auto-increments from latest release -2. **Builds changelog** - Runs towncrier to collect changelog fragments -3. **Builds docs** - Clones Quartz, builds static site from `docs/` -4. **Creates release** - Uploads `docs-.tar.gz` to Forgejo releases -5. **Updates deployment** - Edits `argocd/manifests/docs/deployment.yaml` with new URL -6. **Commits changes** - Pushes changelog and deployment updates to main -7. **Deploys** - Syncs the `docs` ArgoCD app +1. **Resolves version** — Uses input or auto-increments from latest release +2. **Builds changelog** — Calls `dagger call build-changelog` (towncrier in a container) +3. **Builds docs** — Calls `dagger call build-docs` (Quartz build in a container) +4. **Creates release** — Uploads `docs-.tar.gz` to Forgejo releases +5. **Updates deployment** — Edits `argocd/manifests/docs/deployment.yaml` with new URL +6. **Commits changes** — Pushes changelog and deployment updates to main +7. **Deploys** — Syncs the `docs` ArgoCD app ## Changelog Fragments (Towncrier) @@ -66,7 +66,7 @@ The workflow runs on the `k8s` label, which uses the [[forgejo]]-runner in Kuber - **Runner deployment**: `argocd/manifests/forgejo-runner/` - **Job image**: `registry.ops.eblu.me/blumeops/forgejo-runner:latest` -- **Includes**: Node.js 24, npm, git, jq, Docker CLI, uv/uvx, argocd CLI +- **Build engine**: [[dagger]] CLI installed at runtime; Node.js and Python run inside Dagger containers The job image is built from `containers/forgejo-runner/Dockerfile`. @@ -89,24 +89,14 @@ Quartz is cloned fresh during each build (not vendored) to use the latest versio To test docs locally without triggering a release: ```bash -# Clone Quartz -git clone --depth 1 https://github.com/jackyzha0/quartz.git /tmp/quartz -cd /tmp/quartz +# Build docs tarball (identical to CI) +dagger call build-docs --src=. --version=dev export --path=./docs-dev.tar.gz -# Install dependencies -npm ci +# Inspect the output +tar tf docs-dev.tar.gz | head -20 -# Copy config and content -cp /path/to/blumeops/docs/quartz.config.ts . -cp /path/to/blumeops/docs/quartz.layout.ts . -rm -rf content -cp -r /path/to/blumeops/docs content - -# Build -npx quartz build - -# Serve locally -npx quartz build --serve +# Debug a Quartz build failure interactively +dagger call --interactive build-docs --src=. --version=dev ``` ## Troubleshooting @@ -128,5 +118,6 @@ npx quartz build --serve ## Related - [[docs]] - Documentation service reference +- [[dagger]] - Build engine reference - [[forgejo]] - Git forge and CI/CD - [[argocd]] - GitOps deployment diff --git a/docs/reference/reference.md b/docs/reference/reference.md index cbbbc0d..9576089 100644 --- a/docs/reference/reference.md +++ b/docs/reference/reference.md @@ -52,6 +52,15 @@ Host inventory and network configuration. - [[routing|Routing]] - DNS domains, port mappings - [[power]] - Battery-backed power chain +## Tools + +Build, deployment, and IaC tool reference. + +- [[dagger]] - CI/CD build engine (Python SDK) +- [[argocd-cli]] - ArgoCD CLI workflows +- [[ansible]] - Configuration management for indri +- [[pulumi]] - Infrastructure-as-Code (DNS, Tailscale ACLs) + ## Kubernetes Cluster configuration and application registry. @@ -61,12 +70,6 @@ Cluster configuration and application registry. - [[tailscale-operator]] - Tailscale ingress for k8s services - [[external-secrets]] - Secrets management -## Ansible - -Configuration management for [[indri]]-hosted services. - -- [[roles]] - Available ansible roles - ## Storage Network storage and backup configuration. diff --git a/docs/reference/services/argocd.md b/docs/reference/services/argocd.md index f33cf35..8972714 100644 --- a/docs/reference/services/argocd.md +++ b/docs/reference/services/argocd.md @@ -34,5 +34,6 @@ GitOps continuous delivery platform for the [[cluster|Kubernetes cluster]]. ## Related +- [[argocd-cli]] - CLI usage and deployment workflows - [[apps|Apps]] - Full application registry - [[forgejo]] - Git source diff --git a/docs/reference/ansible/roles.md b/docs/reference/tools/ansible.md similarity index 73% rename from docs/reference/ansible/roles.md rename to docs/reference/tools/ansible.md index db5a175..2f21eb2 100644 --- a/docs/reference/ansible/roles.md +++ b/docs/reference/tools/ansible.md @@ -1,14 +1,27 @@ --- -title: Roles -modified: 2026-02-07 +title: Ansible +modified: 2026-02-12 tags: - ansible - reference --- -# Ansible Roles +# Ansible -Roles for provisioning services on [[indri]]. Run via `mise run provision-indri`. +Configuration management for native services on [[indri]]. The primary playbook is `ansible/playbooks/indri.yml`. + +## CLI Patterns + +```bash +# Full provisioning +mise run provision-indri + +# Specific role only +mise run provision-indri -- --tags caddy + +# Dry run (preview changes) +mise run provision-indri -- --check --diff +``` ## Available Roles @@ -44,5 +57,5 @@ Roles that need secrets use 1Password via the playbook's `pre_tasks`. Secrets ar ## Related -- [[indri]] - Target host -- [[observability]] - Metrics collection +- [[indri]] — Target host +- [[observability]] — Metrics collection diff --git a/docs/reference/tools/argocd-cli.md b/docs/reference/tools/argocd-cli.md new file mode 100644 index 0000000..67fb281 --- /dev/null +++ b/docs/reference/tools/argocd-cli.md @@ -0,0 +1,54 @@ +--- +title: ArgoCD CLI +modified: 2026-02-12 +tags: + - reference + - gitops + - argocd +--- + +# ArgoCD CLI + +Command-line workflows for deploying and managing applications via [[argocd]]. + +## CLI Commands + +```bash +argocd app list # List all applications and sync status +argocd app get # Show app details, health, and resources +argocd app diff # Preview what would change on sync +argocd app sync # Apply pending changes +argocd app sync apps # Sync the app-of-apps (picks up new Application manifests) +``` + +## Login + +```bash +argocd login argocd.ops.eblu.me \ + --username admin \ + --password "$(op read 'op://vg6xf6vvfmoh5hqjjhlhbeoaie/srogeebssulhtb6tnqd7ls6qey/password')" +``` + +## Branch-Testing Workflow + +Test changes from a feature branch before merging: + +```bash +# 1. Point the app at your branch +argocd app set --revision + +# 2. Sync to deploy the branch version +argocd app sync + +# 3. Test the changes... + +# 4. After merge, reset to main and sync +argocd app set --revision main +argocd app sync +``` + +## Related + +- [[argocd]] — Service reference (URLs, credentials, sync policy) +- [[apps]] — Full application registry +- [[forgejo]] — Git source diff --git a/docs/reference/tools/dagger.md b/docs/reference/tools/dagger.md new file mode 100644 index 0000000..c78a706 --- /dev/null +++ b/docs/reference/tools/dagger.md @@ -0,0 +1,78 @@ +--- +title: Dagger +modified: 2026-02-12 +tags: + - reference + - ci-cd + - dagger +--- + +# Dagger + +Build engine for BlumeOps CI/CD pipelines. Replaces shell-based build scripts with Python functions that run identically locally and in CI. + +## Quick Reference + +| Property | Value | +|----------|-------| +| **Module** | `blumeops-ci` | +| **Engine Version** | v0.19.11 | +| **SDK** | Python | +| **Source** | `.dagger/src/blumeops_ci/main.py` | +| **Config** | `dagger.json` | + +## Functions + +| Function | Signature | Description | +|----------|-----------|-------------| +| `build` | `(src, container_name) → Container` | Build a container from `containers//Dockerfile` | +| `publish` | `(src, container_name, version, registry?) → str` | Build and push to registry (default: `registry.ops.eblu.me`) | +| `build_changelog` | `(src, version) → Directory` | Run towncrier to collect changelog fragments | +| `build_docs` | `(src, version) → File` | Build changelog then Quartz site, return docs tarball | + +## CLI Examples + +```bash +# Build a container +dagger call build --src=. --container-name=devpi + +# Drop into container shell for inspection +dagger call build --src=. --container-name=devpi terminal + +# Debug a failure interactively +dagger call --interactive build --src=. --container-name=devpi + +# Publish a container to zot +dagger call publish --src=. --container-name=devpi --version=v1.1.0 + +# Build docs tarball locally +dagger call build-docs --src=. --version=dev export --path=./docs-dev.tar.gz + +# Debug a docs build failure +dagger call --interactive build-docs --src=. --version=dev +``` + +## Secrets + +Dagger has a first-class `Secret` type — values are never logged or cached. Pass secrets from environment variables using the `env:VAR` syntax: + +```bash +dagger call release-docs \ + --src=. --version=v1.6.0 \ + --forgejo-token=env:FORGEJO_TOKEN \ + --argocd-token=env:ARGOCD_TOKEN +``` + +In [[forgejo]] Actions, secrets are injected as env vars. Locally, mise tasks call `op read` to populate them. + +## Caveats + +- **Pre-1.0 API** — Current version is v0.19.x. Pin the CLI version and test upgrades on a branch before adopting. +- **Privileged container** — The Dagger engine requires privileged container access. The Forgejo runner's DinD sidecar provides this. + +## Related + +- [[forgejo]] — CI/CD trigger layer +- [[zot]] — Container registry (publish target) +- [[docs]] — Documentation site (build target) +- [[adopt-dagger-ci]] — Adoption plan (phases 1–3 complete) diff --git a/docs/reference/tools/pulumi.md b/docs/reference/tools/pulumi.md new file mode 100644 index 0000000..3af94cd --- /dev/null +++ b/docs/reference/tools/pulumi.md @@ -0,0 +1,53 @@ +--- +title: Pulumi +modified: 2026-02-12 +tags: + - reference + - iac + - pulumi +--- + +# Pulumi + +Infrastructure-as-Code for DNS and Tailscale ACL management. Two independent projects, both using the Python SDK with uv toolchain. + +## Projects + +| Project | Stack | Source | Manages | +|---------|-------|--------|---------| +| `blumeops-dns` | `eblu-me` | `pulumi/gandi/` | DNS records for `eblu.me` via Gandi LiveDNS | +| `blumeops-tailnet` | `tail8d86e` | `pulumi/tailscale/` | ACL policy, device tags, auth keys | + +### DNS (`blumeops-dns`) + +Manages `*.ops.eblu.me` wildcard and base records pointing to [[indri]]'s Tailscale IP, plus public CNAME records for services routed via [[flyio-proxy]]. + +### Tailnet (`blumeops-tailnet`) + +Manages the ACL policy (`policy.hujson`), device tags for [[indri]] and [[sifaka]], and auth keys for the Fly.io proxy. + +## CLI Patterns + +All operations use mise tasks that wrap `pulumi` with the correct stack and working directory: + +```bash +# DNS +mise run dns-preview # Preview DNS changes +mise run dns-up # Apply DNS changes + +# Tailscale +mise run tailnet-preview # Preview ACL/tag changes +mise run tailnet-up # Apply ACL/tag changes +``` + +## Authentication + +- **Gandi**: `GANDI_PERSONAL_ACCESS_TOKEN` environment variable +- **Tailscale**: `TAILSCALE_API_KEY` environment variable +- **Pulumi state**: Local backend (no Pulumi Cloud) + +## Related + +- [[gandi]] — DNS hosting +- [[tailscale]] — Tailnet configuration +- [[routing]] — How DNS records map to services diff --git a/docs/tutorials/replication/core-services.md b/docs/tutorials/replication/core-services.md index d655201..6657eab 100644 --- a/docs/tutorials/replication/core-services.md +++ b/docs/tutorials/replication/core-services.md @@ -30,7 +30,7 @@ Forgejo runs directly on your server (not in Kubernetes) because Kubernetes depe ### Using Ansible (BlumeOps Approach) -BlumeOps manages Forgejo via an Ansible role. See [[roles|Ansible Roles]]. +BlumeOps manages Forgejo via an Ansible role. See [[ansible]]. ### Manual Installation diff --git a/docs/tutorials/replication/observability-stack.md b/docs/tutorials/replication/observability-stack.md index 316c125..db98683 100644 --- a/docs/tutorials/replication/observability-stack.md +++ b/docs/tutorials/replication/observability-stack.md @@ -178,7 +178,7 @@ spec: namespace: monitoring ``` -BluemeOps uses Alloy on both [[indri]] (for host metrics, via [[roles|Ansible role]]) and in the [[cluster]] (for pod logs and service probes). +BluemeOps uses Alloy on both [[indri]] (for host metrics, via [[ansible|Ansible role]]) and in the [[cluster]] (for pod logs and service probes). ## What You Now Have