From 8e5ba6ba93d9b39e1a8b8e7fc666fa42fc2cec92 Mon Sep 17 00:00:00 2001 From: fabiorafaelcoutada Date: Sun, 12 Jul 2026 20:51:27 +0100 Subject: [PATCH] =?UTF-8?q?docs(guides):=20CLI=20install=20guides=20?= =?UTF-8?q?=E2=80=94=20forge/cloud/devops/edge/iot/embedded-linux=20(24=20?= =?UTF-8?q?guides=20+=20index,=20self-hosted-first=20policy)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/guides/README.md | 96 ++++++++++++++++ docs/guides/cli/acli.md | 82 +++++++++++++ docs/guides/cli/ansible.md | 89 ++++++++++++++ docs/guides/cli/arduino-cli.md | 83 ++++++++++++++ docs/guides/cli/aws.md | 106 +++++++++++++++++ docs/guides/cli/az.md | 90 +++++++++++++++ docs/guides/cli/buildroot.md | 79 +++++++++++++ docs/guides/cli/cloudflared-wrangler.md | 97 ++++++++++++++++ docs/guides/cli/cross-toolchains.md | 95 +++++++++++++++ docs/guides/cli/docker-compose.md | 95 +++++++++++++++ docs/guides/cli/doctl.md | 80 +++++++++++++ docs/guides/cli/esptool.md | 75 ++++++++++++ docs/guides/cli/flyctl.md | 76 ++++++++++++ docs/guides/cli/gcloud.md | 91 +++++++++++++++ docs/guides/cli/gh.md | 96 ++++++++++++++++ docs/guides/cli/helm.md | 77 +++++++++++++ docs/guides/cli/kubectl.md | 86 ++++++++++++++ docs/guides/cli/mosquitto-clients.md | 94 +++++++++++++++ docs/guides/cli/netlify.md | 75 ++++++++++++ docs/guides/cli/platformio.md | 89 ++++++++++++++ docs/guides/cli/tea.md | 93 +++++++++++++++ docs/guides/cli/terraform-opentofu.md | 118 +++++++++++++++++++ docs/guides/cli/uboot-tools.md | 83 ++++++++++++++ docs/guides/cli/vercel.md | 77 +++++++++++++ docs/guides/cli/yocto.md | 101 ++++++++++++++++ docs/guides/selfhosted/cloud-emulators.md | 134 ++++++++++++++++++++++ 26 files changed, 2357 insertions(+) create mode 100644 docs/guides/README.md create mode 100644 docs/guides/cli/acli.md create mode 100644 docs/guides/cli/ansible.md create mode 100644 docs/guides/cli/arduino-cli.md create mode 100644 docs/guides/cli/aws.md create mode 100644 docs/guides/cli/az.md create mode 100644 docs/guides/cli/buildroot.md create mode 100644 docs/guides/cli/cloudflared-wrangler.md create mode 100644 docs/guides/cli/cross-toolchains.md create mode 100644 docs/guides/cli/docker-compose.md create mode 100644 docs/guides/cli/doctl.md create mode 100644 docs/guides/cli/esptool.md create mode 100644 docs/guides/cli/flyctl.md create mode 100644 docs/guides/cli/gcloud.md create mode 100644 docs/guides/cli/gh.md create mode 100644 docs/guides/cli/helm.md create mode 100644 docs/guides/cli/kubectl.md create mode 100644 docs/guides/cli/mosquitto-clients.md create mode 100644 docs/guides/cli/netlify.md create mode 100644 docs/guides/cli/platformio.md create mode 100644 docs/guides/cli/tea.md create mode 100644 docs/guides/cli/terraform-opentofu.md create mode 100644 docs/guides/cli/uboot-tools.md create mode 100644 docs/guides/cli/vercel.md create mode 100644 docs/guides/cli/yocto.md create mode 100644 docs/guides/selfhosted/cloud-emulators.md diff --git a/docs/guides/README.md b/docs/guides/README.md new file mode 100644 index 00000000..e8ab60e5 --- /dev/null +++ b/docs/guides/README.md @@ -0,0 +1,96 @@ +# CLI Guides + +Install, authenticate, and configure the command-line tools used across the +Portugal Futurista fleet. Every guide follows the same shape: +**What it is → Install → Authenticate → Configure for this environment → +Self-hosted equivalent → Aurélio integration → Verify → Troubleshooting**. + +## Self-hosted first policy + +Default to self-hosted endpoints in dev. Public clouds only when required. + +Concretely: + +- **Forge** — [Forgejo](https://code.portugalfuturista.org) (LAN `192.168.0.9:3001`) + is the default. `github.com` is for public mirrors only; use `tea`, not `gh`. +- **Object storage** — MinIO on `http://192.168.0.40:9000` (console `:9001`), + S3-compatible. Point `aws s3`, Terraform/OpenTofu state, and backup jobs here first. +- **AWS APIs** — LocalStack on `http://192.168.0.40:4566` emulates the common + AWS services. Develop against it; switch profiles to real AWS only for + cloud-specific behaviour. +- **Azure Storage** — Azurite on `192.168.0.40` (blob `:10000`, queue `:10001`, + table `:10002`) via connection strings. +- **Secrets** — never in shell history or dotfiles. Store API tokens in + Vaultwarden (https://vault.portugalfuturista.org, see + [docs/vaultwarden-setup.md](../vaultwarden-setup.md)) and reference them from + `~/.config` files with `chmod 600`. + +## Self-hosted services + +| Guide | What it covers | +|-------|----------------| +| [cloud-emulators](selfhosted/cloud-emulators.md) | MinIO + LocalStack v3 + Azurite on lattepanda (`192.168.0.40`) — deploy/manage, credentials, CLI wiring, Terraform state backend | + +All guides target the laptop: **Linux x86_64, Debian/Ubuntu-based, bash** +(arm64 variants noted where relevant). + +## Guides + +### Core (forge & collaboration) + +| Guide | Tool | One-liner | Self-hosted equivalent | +|-------|------|-----------|------------------------| +| [gh](cli/gh.md) | GitHub CLI | PRs/issues/releases on github.com (public mirrors only) | Forgejo → use `tea` instead | +| [tea](cli/tea.md) | Gitea/Forgejo CLI | **Primary forge tool** for code.portugalfuturista.org | It *is* the self-hosted tool | +| [acli](cli/acli.md) | Atlassian CLI | Jira + Confluence from the terminal | None deployed (Plane/OpenProject deferred) | + +### DevOps + +| Guide | Tool | One-liner | Self-hosted equivalent | +|-------|------|-----------|------------------------| +| [aws](cli/aws.md) | AWS CLI v2 | AWS API access, profiles | LocalStack `:4566` + MinIO `:9000` | +| [gcloud](cli/gcloud.md) | Google Cloud CLI | GCP projects, GKE, GCS | None real; Firebase emulators / fake-gcs-server | +| [az](cli/az.md) | Azure CLI | Azure resources + storage | Azurite `:10000-10002` via connection strings | +| [kubectl](cli/kubectl.md) | Kubernetes CLI | Cluster ops | k3s on Proxmox | +| [helm](cli/helm.md) | Helm | Kubernetes package manager | Same — points at the k3s cluster | +| [terraform-opentofu](cli/terraform-opentofu.md) | Terraform / OpenTofu | IaC; prefer OpenTofu (MPL-2.0) | State on MinIO via S3 backend | +| [docker-compose](cli/docker-compose.md) | Docker Engine + Compose | Containers on the laptop | Docker itself is the self-hosted runtime | +| [ansible](cli/ansible.md) | Ansible | Agentless config of Proxmox nodes | It *is* self-hosted (inventory = LAN nodes) | + +### Edge / serverless + +| Guide | Tool | One-liner | Self-hosted equivalent | +|-------|------|-----------|------------------------| +| [cloudflared-wrangler](cli/cloudflared-wrangler.md) | cloudflared + wrangler | Cloudflare tunnel `pf-tunnel-v2` + Workers | Tunnel already self-hosted on asus | +| [vercel](cli/vercel.md) | Vercel CLI | Deploy previews / serverless frontends | None deployed (Coolify on Proxmox = future) | +| [netlify](cli/netlify.md) | Netlify CLI | Static + functions deploys | None deployed; Caddy behind pf-tunnel-v2 | +| [flyctl](cli/flyctl.md) | Fly.io CLI | Global container deploys | None; k3s/Kamal on Proxmox | +| [doctl](cli/doctl.md) | DigitalOcean CLI | DO droplets/spaces | Proxmox cluster (`pct`/`qm`) is the self-hosted equivalent | + +### IoT + +| Guide | Tool | One-liner | Self-hosted equivalent | +|-------|------|-----------|------------------------| +| [mosquitto-clients](cli/mosquitto-clients.md) | mosquitto-clients | MQTT pub/sub from the shell | mosquitto broker LXC on Proxmox | + +### Embedded Linux + +| Guide | Tool | One-liner | Self-hosted equivalent | +|-------|------|-----------|------------------------| +| [esptool](cli/esptool.md) | esptool.py | ESP32 flash/serial | Local tool — no cloud dependency | +| [arduino-cli](cli/arduino-cli.md) | Arduino CLI | Compile/upload Arduino sketches | Local tool — no cloud dependency | +| [platformio](cli/platformio.md) | PlatformIO Core | Multi-platform embedded builds | Local tool; registry mirrorable | +| [yocto](cli/yocto.md) | Yocto / poky + kas | Custom Linux images | Build in crops/poky container; Proxmox CT later | +| [buildroot](cli/buildroot.md) | Buildroot | Minimal embedded Linux images | Fully local by design | +| [uboot-tools](cli/uboot-tools.md) | u-boot-tools | `mkimage` for U-Boot images | Fully local by design | +| [cross-toolchains](cli/cross-toolchains.md) | gcc-arm-none-eabi, aarch64-linux-gnu, west | Cross-compile for ARM targets | Fully local by design | + +## Infra reference + +| Host | IP | Role | +|------|-----|------| +| asus | 192.168.0.38 | Proxmox (CTs 202–220), cloudflared `pf-tunnel-v2` | +| gigabyte | 192.168.0.104 | Proxmox (CTs 200–211), media stack, signal-cli | +| lattepanda | 192.168.0.40 | Proxmox node; cloud emulators (MinIO, LocalStack, Azurite) | +| Forgejo | 192.168.0.9:3001 / code.portugalfuturista.org | Default git forge | +| Vaultwarden | vault.portugalfuturista.org | Secrets (see [setup](../vaultwarden-setup.md)) | diff --git a/docs/guides/cli/acli.md b/docs/guides/cli/acli.md new file mode 100644 index 00000000..ae0cfd83 --- /dev/null +++ b/docs/guides/cli/acli.md @@ -0,0 +1,82 @@ +# acli (Atlassian CLI) + +## What it is + +Atlassian's official CLI (`acli`) for Jira and Confluence from the terminal: +search issues, create/transition tickets, read and edit Confluence pages. + +## Install + +Linux x86_64 — official binary (always the latest stable; see the +[Atlassian CLI docs](https://developer.atlassian.com/cloud/acli/guides/introduction/) +for the canonical link): + +```bash +curl -LO "https://acli.atlassian.com/linux/latest/acli_linux_amd64/acli" +chmod +x acli +sudo mv acli /usr/local/bin/acli +``` + +On arm64 use the `acli_linux_arm64` variant of the same URL. The CLI +self-updates via `acli update` unless you disable it. + +## Authenticate + +```bash +acli jira auth login +``` + +Browser-based OAuth 2.0 (3LO) against your Atlassian cloud site; the token is +cached under `~/.config/atlassian-cli/`. Keep a note of which Atlassian +account/org you authorized in Vaultwarden so onboarding a second laptop is a +one-minute job. + +## Configure for this environment + +```bash +acli jira workitem search --jql "project = PF AND status != Done" --limit 10 +acli confluence page view --id +``` + +Set a default site once so commands don't prompt: + +```bash +acli jira site list # pick your site +``` + +## Self-hosted equivalent + +None deployed yet. Self-hosted Jira/Confluence replacements +(**Plane**, **OpenProject**) were evaluated and deferred — when one lands on +the Proxmox cluster it will be announced, and it won't be `acli`-compatible +(Plane and OpenProject have their own REST APIs; closest dev stand-in today is +the Plane community Docker compose stack). + +## Aurélio integration + +The **cli-atlassian** skill drives `acli` for Jira/Confluence queries and +ticket updates. Connector registry id: `atlassian` +(OAuth 2.0 3LO, `api.atlassian.com`). + +## Verify + +```bash +acli --version +# acli version x.y.z +acli jira auth status +# ✓ Authenticated as (.atlassian.net) +acli jira workitem search --jql "assignee = currentUser()" --limit 3 +# KEY SUMMARY STATUS ... +``` + +## Troubleshooting + +- **Browser flow fails on a headless shell** — run `acli jira auth login` from + a desktop session, or copy the printed URL to a browser and paste the + callback back. +- **Wrong site** — you authorized multiple Atlassian sites; pass `--site` or + re-login with the right tenant. +- **403 on Jira API** — missing OAuth scope; re-run `auth login` and accept the + full scope list. +- **Corporate proxy breaking OAuth callback** — set `HTTPS_PROXY` before + running `acli`, or use the API-token auth fallback for Jira REST scripts. diff --git a/docs/guides/cli/ansible.md b/docs/guides/cli/ansible.md new file mode 100644 index 00000000..8c30d4c7 --- /dev/null +++ b/docs/guides/cli/ansible.md @@ -0,0 +1,89 @@ +# ansible (Ansible CLI) + +## What it is + +Agentless configuration management over SSH: `ansible` for ad-hoc commands, +`ansible-playbook` for playbooks. Ideal for keeping the Proxmox nodes and CTs +consistent. + +## Install + +Via pipx (current stable, isolated env — preferred over the lagging distro +package): + +```bash +sudo apt install pipx +pipx install --include-deps ansible-core +pipx ensurepath # re-login so ~/.local/bin is on PATH +``` + +Or the distro package if you don't need recent versions: `sudo apt install +ansible`. Extra collections (e.g. `community.general`) via +`ansible-galaxy collection install `. + +## Authenticate + +Auth = SSH. Use your existing key: + +```bash +ssh-copy-id root@192.168.0.38 # asus +ssh-copy-id root@192.168.0.104 # gigabyte +ssh-copy-id root@192.168.0.40 # lattepanda +``` + +Vault-stored secrets (sudo passwords, API tokens) go in Vaultwarden +(https://vault.portugalfuturista.org); for playbook-level secrets use +`ansible-vault encrypt_string`. + +## Configure for this environment + +Inventory `~/.ansible/inventory/proxmox.ini`: + +```ini +[proxmox] +asus ansible_host=192.168.0.38 +gigabyte ansible_host=192.168.0.104 +lattepanda ansible_host=192.168.0.40 + +[proxmox:vars] +ansible_user=root +ansible_python_interpreter=/usr/bin/python3 +``` + +Ad-hoc check: + +```bash +ansible -i ~/.ansible/inventory/proxmox.ini proxmox -m ping +ansible -i ~/.ansible/inventory/proxmox.ini proxmox -a "pveversion" +``` + +## Self-hosted equivalent + +Ansible is inherently self-hosted — controller on the laptop, targets on the +LAN. No cloud service involved; the closest "managed" analogue (AWX/Tower) is +overkill for three nodes. + +## Aurélio integration + +The **cli-devops** skill uses `ansible` for fleet maintenance tasks against +the Proxmox nodes. Connector registry id: `ansible`. + +## Verify + +```bash +ansible --version +# ansible [core 2.x.y] ... +ansible -i ~/.ansible/inventory/proxmox.ini asus -m ping +# asus | SUCCESS => { "ping": "pong" } +``` + +## Troubleshooting + +- **`UNREACHABLE`** — SSH key not installed on the node, or you're not on the + LAN/VPN; test with plain `ssh root@`. +- **`/usr/bin/python: not found`** — minimal Debian CTs ship only `python3`; + set `ansible_python_interpreter=/usr/bin/python3` (as above). +- **Privilege escalation prompts** — add `-b --ask-become-pass` or configure + passwordless sudo on managed CTs. +- **Slow runs** — enable SSH pipelining and `forks = 20` in + `~/.ansible.cfg`. diff --git a/docs/guides/cli/arduino-cli.md b/docs/guides/cli/arduino-cli.md new file mode 100644 index 00000000..bfa9f406 --- /dev/null +++ b/docs/guides/cli/arduino-cli.md @@ -0,0 +1,83 @@ +# arduino-cli (Arduino CLI) + +## What it is + +Arduino's headless build tool: manage cores (board support packages) and +libraries, compile sketches, and upload over serial — no IDE required. Good +fit for CI builds of Arduino-based firmware. + +## Install + +Official script (latest stable into `~/.local/bin`): + +```bash +curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \ + | BINDIR=~/.local/bin sh +``` + +Static binaries (x86_64/arm64) also on the releases page if you want to pin a +version. Add `~/.local/bin` to PATH if it isn't already. + +## Authenticate + +None for core functionality. Only the (optional) Arduino Cloud integration +uses credentials — we don't use it; keep any such tokens in Vaultwarden if you +ever enable it. + +## Configure for this environment + +First-run setup for AVR + ESP32: + +```bash +arduino-cli config init +arduino-cli config add board_manager.additional_urls \ + https://espressif.github.io/arduino-esp32/package_esp32_index.json +arduino-cli core update-index +arduino-cli core install arduino:avr +arduino-cli core install esp32:esp32 +arduino-cli lib install "PubSubClient" +``` + +Serial access: `sudo usermod -aG dialout $USER` (re-login). + +Typical cycle: + +```bash +arduino-cli board list # find the port + FQBN +arduino-cli compile --fqbn esp32:esp32:esp32 sketch/ +arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 sketch/ +arduino-cli monitor -p /dev/ttyUSB0 -c baudrate=115200 +``` + +## Self-hosted equivalent + +Fully local — cores/libraries download from public indexes, but builds and +uploads happen on the laptop. No cloud dependency. (Build artifacts can be +mirrored to MinIO `http://192.168.0.40:9000` with the rest of the firmware.) + +## Aurélio integration + +The **embedded-linux** skill uses `arduino-cli` for Arduino-core firmware +builds and uploads (ESP32/AVR). Flashed devices usually talk to the +`mqtt-local` broker connector. + +## Verify + +```bash +arduino-cli version +# arduino-cli Version: 1.x.y ... +arduino-cli board list +# Port Protocol Type Board Name FQBN Core +# /dev/ttyUSB0 serial Serial Port (USB) Unknown esp32:esp32:... esp32:esp32 +``` + +## Troubleshooting + +- **`Board not found` on compile** — the core isn't installed; + `arduino-cli core search ` then `core install`. +- **ESP32 package index ignored** — the `additional_urls` must be added via + `config add` (as above), then `core update-index` again. +- **Upload permission denied** — `dialout` group missing, or `arduino-cli + monitor`/minicom still holding the port. +- **Compile cache confusion after core upgrade** — `arduino-cli cache clean` + then rebuild. diff --git a/docs/guides/cli/aws.md b/docs/guides/cli/aws.md new file mode 100644 index 00000000..e08dd99a --- /dev/null +++ b/docs/guides/cli/aws.md @@ -0,0 +1,106 @@ +# aws (AWS CLI v2) + +## What it is + +The official AWS command line (v2): S3, IAM, Lambda, IoT Core, CloudFormation — +every AWS API from the shell, with named profiles for multi-account work. + +## Install + +Official Linux x86_64 installer (always current stable; use the `-aarch64` URL +on arm64): + +```bash +curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip +unzip -q /tmp/awscliv2.zip -d /tmp +sudo /tmp/aws/install # add --update to upgrade in place +``` + +Do **not** use the distro `awscli` package — it is usually the legacy v1. + +## Authenticate + +```bash +aws configure --profile prod +# AWS Access Key ID: +# AWS Secret Access Key: +# Default region name: eu-west-1 +# Default output format: json +``` + +Credentials live in `~/.aws/credentials` (chmod 600). Keep the root copies of +all access keys in Vaultwarden (https://vault.portugalfuturista.org); rotate +rather than leak. + +## Configure for this environment + +`~/.aws/config` — real AWS plus the local emulators: + +```ini +[default] +region = eu-west-1 +output = json + +[profile prod] +region = eu-west-1 + +[profile localstack] +region = us-east-1 +output = json +``` + +`~/.aws/credentials`: + +```ini +[localstack] +aws_access_key_id = test +aws_secret_access_key = test +``` + +## Self-hosted equivalent + +**LocalStack** (AWS emulator, lattepanda `http://192.168.0.40:4566`) and +**MinIO** (S3-compatible, `http://192.168.0.40:9000`, console `:9001`). + +```bash +# LocalStack: everything behind one endpoint +aws --profile localstack --endpoint-url http://192.168.0.40:4566 s3 ls +aws --profile localstack --endpoint-url http://192.168.0.40:4566 lambda list-functions + +# MinIO: S3 only +aws --profile localstack --endpoint-url http://192.168.0.40:9000 s3 mb s3://firmware +aws --profile localstack --endpoint-url http://192.168.0.40:9000 s3 cp build.bin s3://firmware/ +``` + +For MinIO use its own access/secret keys (console at `:9001`), stored in +Vaultwarden — not `test/test`. + +Alternative: `pipx install awscli-local` gives `awslocal`, which wraps `aws` +with the LocalStack endpoint pre-set (`awslocal s3 ls`). + +## Aurélio integration + +The **cli-aws** skill wraps `aws` (and `awslocal`) for infra and IoT Core +tasks. Connector registry ids: `aws` (real), `aws-localstack` (emulator), +`minio` (S3 storage). + +## Verify + +```bash +aws --version +# aws-cli/2.x.y Python/3.x Linux/x86_64 ... +aws --profile localstack --endpoint-url http://192.168.0.40:4566 sts get-caller-identity +# { "Account": "000000000000", "Arn": "arn:aws:iam::000000000000:root", ... } +``` + +## Troubleshooting + +- **`aws: command not found` after install** — installer puts it in + `/usr/local/bin`; check your `PATH`. +- **Signature errors against MinIO** — wrong keys or clock skew; verify keys in + the MinIO console and that the laptop clock is NTP-synced. +- **`Connection refused` to LocalStack** — the emulator stack on lattepanda + (192.168.0.40) isn't up; check its Docker stack before debugging `aws`. +- **Real AWS used by accident** — always pass `--profile localstack + --endpoint-url ...` in dev scripts; export `AWS_PROFILE=localstack` in your + dev shell as a seatbelt. diff --git a/docs/guides/cli/az.md b/docs/guides/cli/az.md new file mode 100644 index 00000000..486fbd66 --- /dev/null +++ b/docs/guides/cli/az.md @@ -0,0 +1,90 @@ +# az (Azure CLI) + +## What it is + +Microsoft's CLI for Azure resources (`az group`, `az vm`, `az storage`, +`az iot`, ...). One login covers all Azure services. + +## Install + +Official Microsoft apt repo: + +```bash +curl -sLS https://packages.microsoft.com/keys/microsoft.asc \ + | sudo gpg --dearmor -o /etc/apt/keyrings/microsoft.gpg +echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/microsoft.gpg] \ + https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" \ + | sudo tee /etc/apt/sources.list.d/azure-cli.list +sudo apt update && sudo apt install azure-cli +``` + +(On arm64 use `arch=arm64`.) The one-liner `curl -sL +https://aka.ms/InstallAzureCLIDeb | sudo bash` does the same but pins less — +the explicit repo above is preferred. + +## Authenticate + +```bash +az login # browser flow +az account set --subscription +``` + +Token cache: `~/.azure/`. For automation, create a service principal and keep +the client secret in Vaultwarden (https://vault.portugalfuturista.org): + +```bash +az login --service-principal -u -p --tenant +``` + +## Configure for this environment + +```bash +az config set defaults.group= defaults.location=westeurope +az account list --output table +``` + +## Self-hosted equivalent + +**Azurite** — the Azure Storage emulator on lattepanda +(`192.168.0.40`: blob `:10000`, queue `:10001`, table `:10002`). Point `az +storage` at it with a connection string: + +```bash +export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;\ +AccountName=devstoreaccount1;\ +AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;\ +BlobEndpoint=http://192.168.0.40:10000/devstoreaccount1;\ +QueueEndpoint=http://192.168.0.40:10001/devstoreaccount1;\ +TableEndpoint=http://192.168.0.40:10002/devstoreaccount1;" + +az storage container create --name firmware +az storage blob upload --container-name firmware --file build.bin --name build.bin +``` + +(The account key above is Azurite's well-known dev key, not a secret.) +There is no emulator for non-storage Azure services — use real Azure for those. + +## Aurélio integration + +The **cli-azure** skill wraps `az` for resource and storage ops. Connector +registry ids: `azure` (real), `azure-azurite` (storage emulator). + +## Verify + +```bash +az version +# "azure-cli": "2.x.y", ... +az account show --output table +# Name CloudName SubscriptionId State IsDefault +``` + +## Troubleshooting + +- **`az login` opens no browser** — use `az login --use-device-code` and + complete the flow at microsoft.com/devicelogin. +- **Connection string ignored** — `az storage` flags (`--account-name`) win + over the env var; unset conflicting flags or export + `AZURE_STORAGE_ACCOUNT`/`AZURE_STORAGE_KEY` instead. +- **Azurite SSL errors** — Azurite here is plain HTTP; make sure the + connection string uses `DefaultEndpointsProtocol=http`. +- **Wrong tenant** — `az account clear` then `az login --tenant `. diff --git a/docs/guides/cli/buildroot.md b/docs/guides/cli/buildroot.md new file mode 100644 index 00000000..94188165 --- /dev/null +++ b/docs/guides/cli/buildroot.md @@ -0,0 +1,79 @@ +# buildroot (Buildroot) + +## What it is + +Buildroot builds minimal embedded Linux systems (cross toolchain, rootfs, +kernel, bootloader) with a Kconfig interface — much lighter than Yocto for +simple appliances. One `make` produces a flashable image. + +## Install + +Host dependencies (Debian/Ubuntu): + +```bash +sudo apt install build-essential git libncurses-dev bison flex \ + libssl-dev bc rsync unzip wget cpio file python3 +``` + +Buildroot itself is just a git clone (pin a release branch or tag, e.g. +`2024.02.x` LTS or newer — check buildroot.org for the current LTS): + +```bash +git clone -b 2024.02.x https://github.com/buildroot/buildroot.git ~/buildroot +# or shallow: git clone --depth 1 -b ... +``` + +## Authenticate + +None. Everything is local; packages download from upstream mirrors over HTTPS. + +## Configure for this environment + +```bash +cd ~/buildroot +make list-defconfigs | grep -i # e.g. raspberrypi, beaglebone +make _defconfig +make menuconfig # adjust packages/kernel/rootfs +make -j"$(nproc)" # ~30-60 min first build +ls output/images/ # sdcard.img, zImage, rootfs.tar... +``` + +Keep project-specific configs as **external trees** (BR2_EXTERNAL) in the +firmware repo on Forgejo — never fork Buildroot itself: + +``` +BR2_EXTERNAL=../my-overlay make myboard_defconfig +``` + +Archive release images to MinIO (`http://192.168.0.40:9000`) with the defconfig +that produced them. + +## Self-hosted equivalent + +Fully self-hosted by design — no cloud services anywhere in the loop. For +reproducible offline builds, set `BR2_PRIMARY_SITE` to an internal mirror and +commit the downloaded `dl/` cache to MinIO. + +## Aurélio integration + +The **embedded-linux** skill uses Buildroot for minimal appliance images. +Resulting images are deployed with the [uboot-tools](uboot-tools.md) / +`swupdate` flow and talk to the `mqtt-local` connector at runtime. + +## Verify + +```bash +cd ~/buildroot && make show-info | head -5 # prints configured packages as JSON +make _defconfig && make -j"$(nproc)" linux +# ... after a full build: output/images/ contains the artifacts +``` + +## Troubleshooting + +- **Missing host tool error at `make`** — install the package named in the + error; `make` checks the host first (see deps above). +- **Defconfig for your board missing** — look in `configs/` upstream or the + board vendor's BR2_EXTERNAL layer; don't hand-write one from scratch. +- **`make menuconfig` can't find ncurses** — `sudo apt install libncurses-dev`. +- **Build breaks after `git pull`** — rebuild from clean: `make clean && make + _defconfig && make`; Buildroot doesn't support in-tree upgrades. diff --git a/docs/guides/cli/cloudflared-wrangler.md b/docs/guides/cli/cloudflared-wrangler.md new file mode 100644 index 00000000..7ef5801c --- /dev/null +++ b/docs/guides/cli/cloudflared-wrangler.md @@ -0,0 +1,97 @@ +# cloudflared & wrangler (Cloudflare tunnel + Workers CLIs) + +## What it is + +Two Cloudflare CLIs: **cloudflared** runs/manages tunnels (our +`pf-tunnel-v2` exposes the `*.portugalfuturista.org` services), and +**wrangler** builds and deploys Cloudflare Workers/Pages. + +## Install + +cloudflared (official apt repo): + +```bash +curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \ + | sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null +echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] \ + https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \ + | sudo tee /etc/apt/sources.list.d/cloudflared.list +sudo apt update && sudo apt install cloudflared +``` + +wrangler (via npm, current stable): + +```bash +npm install -g wrangler +``` + +## Authenticate + +```bash +cloudflared tunnel login # browser → authorizes the zone, writes ~/.cloudflared/cert.pem +wrangler login # browser OAuth for your Cloudflare account +``` + +API tokens (for CI) go in Vaultwarden (https://vault.portugalfuturista.org) +and are exported as `CLOUDFLARE_API_TOKEN`. + +## Configure for this environment + +`pf-tunnel-v2` **runs on asus** (192.168.0.38), config at +`/etc/cloudflared/config-v2.yml` — tunnel administration happens there, not +on the laptop. From the laptop you typically only: + +```bash +cloudflared tunnel list # see pf-tunnel-v2 and its connectors +cloudflared tunnel info pf-tunnel-v2 +cloudflared tunnel route dns pf-tunnel-v2 new-service.portugalfuturista.org +``` + +Adding a service = edit `config-v2.yml` on asus (ingress rule) + DNS route, +then restart the cloudflared service on asus. + +wrangler for Workers: + +```bash +wrangler init my-worker +cd my-worker && wrangler dev # local dev server +wrangler deploy +``` + +## Self-hosted equivalent + +The tunnel **is** our self-hosted edge: `pf-tunnel-v2` on asus fronts all +`*.portugalfuturista.org` services — no third-party ingress needed. Workers +have no self-hosted runtime in production; for local dev `wrangler dev` (and +Miniflare under the hood) emulates the Workers runtime on the laptop. + +## Aurélio integration + +The **cli-edge** skill uses `cloudflared` for tunnel/DNS routes and `wrangler` +for Workers deploys. Connector registry id: `cloudflare`. + +## Verify + +```bash +cloudflared --version +# cloudflared version 20xx.y.z ... +wrangler --version +# ⛅️ wrangler x.y.z +cloudflared tunnel list +# ID NAME CREATED CONNECTIONS +# ... pf-tunnel-v2 ... 2xLISB +``` + +## Troubleshooting + +- **`tunnel login` cert lands on the wrong machine** — the cert is per-user, + per-machine; run `cloudflared tunnel login` on asus if you're managing the + tunnel there, then copy `~/.cloudflared/.json` credentials carefully. +- **DNS route already exists** — `cloudflared tunnel route dns` refuses to + overwrite; delete the CNAME in the dashboard or with `cloudflared tunnel + route dns --overwrite-dns`. +- **wrangler `Unauthorized`** — token scope too narrow; create a token with + "Workers Scripts:Edit" and re-export `CLOUDFLARE_API_TOKEN`. +- **Service 502 behind the tunnel** — check the ingress rule in + `config-v2.yml` on asus points at a reachable LAN address, then + `journalctl -u cloudflared` on asus. diff --git a/docs/guides/cli/cross-toolchains.md b/docs/guides/cli/cross-toolchains.md new file mode 100644 index 00000000..55c439a9 --- /dev/null +++ b/docs/guides/cli/cross-toolchains.md @@ -0,0 +1,95 @@ +# cross-toolchains (ARM GCC + Zephyr west) + +## What it is + +Cross-compilers that run on the laptop (x86_64) and target embedded ARM: +`gcc-arm-none-eabi` (bare-metal Cortex-M), `aarch64-linux-gnu` (64-bit ARM +Linux userland/kernel), and Zephyr's `west` (meta-tool for Zephyr RTOS +builds). + +## Install + +Debian/Ubuntu: + +```bash +# Bare-metal ARM (Cortex-M): distro package is fine for most work +sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi + +# aarch64 Linux cross toolchain +sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + +# Zephyr west + build deps +sudo apt install pipx python3-venv cmake ninja-build gperf ccache dfu-util \ + device-tree-compiler xz-utils file make gcc g++ multilib gcc-multilib +pipx install west +pipx ensurepath # re-login +``` + +Note: distro `gcc-arm-none-eabi` can lag or be huge (newlib variants). The +Arm GNU Toolchain tarball from developer.arm.com is the pin-able alternative — +extract to `/opt` and add its `bin/` to PATH when a project requires a +specific version. + +## Authenticate + +None. Zephyr modules fetch from public git (Forgejo mirrors where available: +`code.portugalfuturista.org`). + +## Configure for this environment + +Zephyr workspace: + +```bash +west init -m https://github.com/zephyrproject-rtos/zephyr --mr main ~/zephyrproject +cd ~/zephyrproject && west update +west zephyr-export +pipx runpip west install -r zephyr/scripts/requirements.txt # python deps +``` + +(Alternatively install the Zephyr SDK tarball for its bundled toolchains, or +set `ZEPHYR_TOOLCHAIN_VARIANT=cross-compile` + +`CROSS_COMPILE=/usr/bin/arm-none-eabi-` to reuse the distro GCC.) + +Kernel cross-compile example: + +```bash +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig +make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j"$(nproc)" +``` + +## Self-hosted equivalent + +Fully local — no cloud involved. Zephyr module fetches and toolchain tarballs +can be mirrored to MinIO (`http://192.168.0.40:9000`) for CI reproducibility. + +## Aurélio integration + +The **embedded-linux** skill uses these toolchains for bare-metal and RTOS +firmware (`west build`, kernel cross-compiles). Firmware targets the +`mqtt-local` broker at runtime. + +## Verify + +```bash +arm-none-eabi-gcc --version | head -1 +# arm-none-eabi-gcc (...) x.y.z ... +aarch64-linux-gnu-gcc --version | head -1 +# aarch64-linux-gnu-gcc (Debian ...) x.y.z ... +west --version +# West version: v1.x.y +west boards | grep -i nrf52840 | head -3 # in a zephyr workspace +# nrf52840dk/nrf52840 ... +``` + +## Troubleshooting + +- **`arm-none-eabi-gcc: command not found` in make** — toolchain bin dir not + on PATH in that shell (common when mixing tarball + distro installs). +- **Newlib missing (`nano.specs` errors)** — install + `libnewlib-arm-none-eabi` (and `libstdc++-arm-none-eabi-newlib` for C++). +- **`west build` can't find the Zephyr SDK** — either install the SDK or + point `ZEPHYR_TOOLCHAIN_VARIANT`/`CROSS_COMPILE` at the distro toolchain as + above. +- **Wrong architecture triplet** — `aarch64-linux-gnu-` for 64-bit ARM Linux, + `arm-linux-gnueabihf-` for 32-bit hard-float, `arm-none-eabi-` for + bare-metal; mixing them produces very confusing linker errors. diff --git a/docs/guides/cli/docker-compose.md b/docs/guides/cli/docker-compose.md new file mode 100644 index 00000000..9af481a2 --- /dev/null +++ b/docs/guides/cli/docker-compose.md @@ -0,0 +1,95 @@ +# docker compose (Docker Engine + Compose plugin) + +## What it is + +Docker Engine runs containers on the laptop; the Compose plugin (`docker +compose`, v2) brings up multi-container stacks from a `compose.yaml`. This is +the local dev runtime for everything — including the MinIO/LocalStack/Azurite +emulators. + +## Install + +Official Docker apt repo (Debian/Ubuntu; the `docker.io` distro package lags): + +```bash +sudo apt install ca-certificates curl +sudo install -m 0755 -d /etc/apt/keyrings +curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ + | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \ + https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \ + | sudo tee /etc/apt/sources.list.d/docker.list +sudo apt update +sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin +sudo usermod -aG docker $USER # re-login to pick up the group +``` + +(On Debian use `download.docker.com/linux/debian`.) The repo always serves the +current stable channel; pin with `apt install docker-ce=5:` if needed. + +## Authenticate + +Only for registries: + +```bash +docker login # Docker Hub (PAT, not password) +docker login code.portugalfuturista.org # if a Forgejo package registry is used +``` + +Tokens are in `~/.docker/config.json` (base64 — treat it as secret; keep the +PATs themselves in Vaultwarden, https://vault.portugalfuturista.org). + +## Configure for this environment + +Compose overrides for LAN services live in `compose.override.yaml` (gitignored). +Typical dev stack pointing at the emulators on lattepanda: + +```yaml +services: + app: + build: . + environment: + AWS_ENDPOINT_URL: http://192.168.0.40:4566 + S3_ENDPOINT: http://192.168.0.40:9000 + ports: ["8080:8080"] +``` + +```bash +docker compose up -d +docker compose ps +docker compose logs -f app +``` + +## Self-hosted equivalent + +Docker **is** the self-hosted runtime — no cloud dependency. The cloud +counterpart would be managed container services (ECS/Cloud Run/ACI), which we +only touch when a deployment target requires it. + +## Aurélio integration + +The **cli-devops** skill shells out to `docker compose` for local stack +management. No dedicated connector-registry entry — Docker is the local +runtime the other connectors (minio, aws-localstack, azure-azurite) run on. + +## Verify + +```bash +docker --version +# Docker version 2x.y.z, build ... +docker compose version +# Docker Compose version v2.x.y +docker run --rm hello-world +# Hello from Docker! ... +``` + +## Troubleshooting + +- **Permission denied on `/var/run/docker.sock`** — you're not in the `docker` + group (or haven't re-logged in since `usermod`). +- **`docker-compose: command not found`** — that's v1 syntax; use the plugin: + `docker compose ...`. +- **Disk full** — `docker system df`, then `docker system prune -a` (drops + unused images; emulator volumes survive unless you add `--volumes`). +- **CT/VM can't reach images** — Docker Hub rate limits: `docker login` with a + Hub account, or pull through a mirror. diff --git a/docs/guides/cli/doctl.md b/docs/guides/cli/doctl.md new file mode 100644 index 00000000..d4b475b4 --- /dev/null +++ b/docs/guides/cli/doctl.md @@ -0,0 +1,80 @@ +# doctl (DigitalOcean CLI) + +## What it is + +DigitalOcean's CLI: droplets, Kubernetes (DOKS), Spaces (S3-compatible), App +Platform, container registry — everything in the DO API from the shell. + +## Install + +GitHub release binary (x86_64; use the `arm64` archive on ARM): + +```bash +VERSION=$(curl -fsSL https://api.github.com/repos/digitalocean/doctl/releases/latest \ + | grep -oP '"tag_name":\s*"v\K[^"]+') +curl -fsSL -o /tmp/doctl.tar.gz \ + "https://github.com/digitalocean/doctl/releases/download/v${VERSION}/doctl-${VERSION}-linux-amd64.tar.gz" +tar -xzf /tmp/doctl.tar.gz -C /tmp +sudo install /tmp/doctl /usr/local/bin/doctl +``` + +(Also available as a snap, but the static binary pins cleanly and has no snap +confinement surprises.) + +## Authenticate + +Create a personal access token in the DO dashboard (read+write), store it in +Vaultwarden (https://vault.portugalfuturista.org), then: + +```bash +doctl auth init # paste the token +doctl auth list +``` + +Config: `~/.config/doctl/config.yaml`. Multiple tokens → +`doctl auth init --context ` and `doctl auth switch`. + +## Configure for this environment + +```bash +doctl account get +doctl compute droplet list +doctl kubernetes cluster list +doctl registry login # docker creds for registry.digitalocean.com +``` + +## Self-hosted equivalent + +Our **Proxmox cluster is the self-hosted DigitalOcean**: droplets → VMs/CTs +managed with `qm`/`pct` (via SSH on asus/gigabyte/lattepanda), Spaces → +**MinIO** at `http://192.168.0.40:9000` (S3-compatible, works with `aws s3 +--endpoint-url`), DOKS → planned **k3s** (see [kubectl.md](kubectl.md)). +`doctl` is used only for resources that must live outside the lab. + +## Aurélio integration + +The **cli-devops** skill can drive `doctl` for external VPS/registry ops. No +dedicated connector-registry entry — external SaaS; the self-hosted +counterparts are covered by `minio` and `kubernetes`. + +## Verify + +```bash +doctl version +# doctl version 1.x.y-release ... +doctl account get +# Email Droplet Limit Email Verified UUID Status +# you@... 25 true ... active +``` + +## Troubleshooting + +- **`401 Unable to authenticate you`** — token expired/revoked; regenerate in + the dashboard, update Vaultwarden, `doctl auth init` again. +- **Wrong context active** — `doctl auth list` then `doctl auth switch + --context `. +- **Registry push denied** — run `doctl registry login` so Docker gets the + short-lived registry credentials. +- **Spaces endpoint confusion** — Spaces is S3-compatible; use `aws s3 + --endpoint-url https://.digitaloceanspaces.com` rather than looking + for a `doctl spaces` subcommand. diff --git a/docs/guides/cli/esptool.md b/docs/guides/cli/esptool.md new file mode 100644 index 00000000..f839c7be --- /dev/null +++ b/docs/guides/cli/esptool.md @@ -0,0 +1,75 @@ +# esptool (Espressif flashing tool) + +## What it is + +`esptool.py` — Espressif's official tool for ESP32/ESP8266: flash firmware, +read flash, chip info, baud-tuned serial boot control. The standard last-mile +tool for ESP32 firmware. + +## Install + +Via pipx (isolated, current stable): + +```bash +sudo apt install pipx python3-venv +pipx install esptool +pipx ensurepath # re-login so ~/.local/bin is on PATH +``` + +(`pip install esptool` in a venv works too. Needs Python 3.8+.) + +USB serial access: + +```bash +sudo usermod -aG dialout $USER # re-login to apply +``` + +## Authenticate + +None — talks to the chip over USB/UART. No tokens involved. + +## Configure for this environment + +Devices appear as `/dev/ttyUSB0` (or `/dev/ttyACM0` for native-USB chips like +ESP32-S3). Convenience alias for the common fast-flash settings: + +```bash +alias espflash='esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800' +``` + +For firmware destined at AWS IoT Core, keep device certificates in Vaultwarden +(https://vault.portugalfuturista.org) — never bake shared certs into images. + +## Self-hosted equivalent + +Fully local by design — flashing happens over USB on the laptop. Firmware +artifacts can be archived to MinIO (`http://192.168.0.40:9000`) for +reproducibility. For OTA at scale the self-hosted route is an update server +behind the LAN; cloud OTA (AWS IoT Jobs) only when devices are off-LAN. + +## Aurélio integration + +The **embedded-linux** skill uses `esptool` for ESP32 flash/verify cycles. +Flashed firmware typically targets the `mqtt-local` broker or `aws-iot` +connector endpoints. + +## Verify + +```bash +esptool.py version +# esptool.py v4.x / v5.x ... +esptool.py --port /dev/ttyUSB0 chip_id +# Chip is ESP32-D0WDQ6 (revision ...) +# MAC: xx:xx:xx:xx:xx:xx +``` + +## Troubleshooting + +- **`Permission denied: /dev/ttyUSB0`** — not in `dialout` group, or a + lingering serial monitor (minicom/IDE) holds the port. +- **`Failed to connect`** — hold BOOT while plugging in (or press BOOT during + connect) to force download mode; also try a lower `--baud`. +- **Device not enumerated** — bad USB cable (charge-only) or missing driver + for the CP210x/CH340 bridge; check `dmesg | tail`. +- **Flash write errors at high baud** — drop to `--baud 115200`; some bridges + and cables can't sustain 460800+. diff --git a/docs/guides/cli/flyctl.md b/docs/guides/cli/flyctl.md new file mode 100644 index 00000000..26b5bfcd --- /dev/null +++ b/docs/guides/cli/flyctl.md @@ -0,0 +1,76 @@ +# flyctl (Fly.io CLI) + +## What it is + +Fly.io's CLI (`fly`/`flyctl`): deploy containers globally as "Machines", +manage volumes, WireGuard into your private Fly network, stream logs. + +## Install + +Official install script (current stable; also has arm64 builds): + +```bash +curl -fsSL https://fly.io/install.sh | sh +``` + +It installs to `~/.fly/bin` and prints the PATH snippet to add to `~/.bashrc` +(`export FLYCTL_INSTALL="$HOME/.fly"; export PATH="$FLYCTL_INSTALL/bin:$PATH"`). +Upgrade later with `fly version upgrade`. + +## Authenticate + +```bash +fly auth login # browser OAuth +``` + +Token cached in `~/.fly/config.yml`. For CI, `fly auth token` prints a +deploy token — keep it in Vaultwarden (https://vault.portugalfuturista.org) +and export as `FLY_API_TOKEN`. + +## Configure for this environment + +```bash +cd +fly launch # detects Dockerfile, creates fly.toml + app +fly deploy +fly logs +fly ssh console # shell into the machine +fly status # machines + regions +``` + +## Self-hosted equivalent + +None deployed. The self-hosted counterpart for "run this container somewhere +reachable" is: Docker on a Proxmox CT exposed via the `pf-tunnel-v2` tunnel +(see [docker-compose.md](docker-compose.md) and +[cloudflared-wrangler.md](cloudflared-wrangler.md)), or **k3s** once the +cluster lands (see [kubectl.md](kubectl.md)). Fly stays in the toolbox for +genuinely global/multi-region workloads only. + +## Aurélio integration + +The **cli-edge** skill can use `flyctl` for global container deploys. No +dedicated connector-registry entry (external SaaS; nearest listed edge +connectors are `cloudflare` / `vercel`). + +## Verify + +```bash +fly version +# flyctl v0.x.y linux/amd64 ... +fly auth whoami +# Email: you@example.com +fly apps list +# NAME OWNER STATUS LATEST DEPLOY +``` + +## Troubleshooting + +- **`fly` not found after install** — the PATH snippet wasn't added to + `~/.bashrc`; open a new shell or export it manually. +- **`Error: could not find app`** — run commands from the directory with + `fly.toml`, or pass `-a `. +- **Deploy hangs on wireguard** — `fly wireguard reset` or toggle the agent + with `fly agent restart`. +- **Health checks failing** — the app must bind `0.0.0.0` and the port in + `fly.toml` `internal_port`; check `fly logs` for the bind address. diff --git a/docs/guides/cli/gcloud.md b/docs/guides/cli/gcloud.md new file mode 100644 index 00000000..23ecfb30 --- /dev/null +++ b/docs/guides/cli/gcloud.md @@ -0,0 +1,91 @@ +# gcloud (Google Cloud CLI) + +## What it is + +Google Cloud's CLI: `gcloud` (projects, compute, IAM, GKE), bundled with +`gsutil` (Cloud Storage) and `bq` (BigQuery). + +## Install + +Official apt repo (Debian/Ubuntu): + +```bash +sudo apt install apt-transport-https ca-certificates gnupg curl +curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg \ + | sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg +echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \ + | sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list +sudo apt update && sudo apt install google-cloud-cli +``` + +Alternative: the versioned tarballs from the +[install docs](https://cloud.google.com/sdk/docs/install) (`linux-x86_64` or +`linux-arm`); extract and run `./google-cloud-sdk/install.sh`. + +## Authenticate + +```bash +gcloud auth login # browser OAuth, user account +gcloud config set project +gcloud auth application-default login # for SDKs/tools using ADC +``` + +Credentials land in `~/.config/gcloud/`. For service accounts, store the JSON +key in Vaultwarden (https://vault.portugalfuturista.org) and activate with: + +```bash +gcloud auth activate-service-account --key-file= --project= +``` + +## Configure for this environment + +Named configurations keep personal/lab projects apart: + +```bash +gcloud config configurations create lab +gcloud config set project +gcloud config configurations list +gcloud config configurations activate lab +``` + +## Self-hosted equivalent + +There is no real self-hosted GCP. Dev stand-ins we use instead: + +- **Firebase Emulator Suite** (`firebase emulators:start`, via + `npm i -g firebase-tools`) for Firestore/Auth/Functions. +- **fake-gcs-server** for Cloud Storage: + `docker run -p 4443:4443 fsouza/fake-gcs-server -scheme http`, then + `STORAGE_EMULATOR_HOST=http://localhost:4443` for client libraries. +- For plain object storage, prefer **MinIO** (`http://192.168.0.40:9000`) — + S3-compatible and already on the LAN. + +## Aurélio integration + +The **cli-gcloud** skill wraps `gcloud`/`gsutil` for project and storage ops. +Connector registry id: `google-cloud`. + +## Verify + +```bash +gcloud --version +# Google Cloud SDK x.y.z +gcloud auth list +# Credentialed Accounts +# ACTIVE ACCOUNT +# * you@example.com +gcloud config list project +# [core] +# project = +``` + +## Troubleshooting + +- **Old SDK from distro packages** — only use the Google apt repo above; + distro `google-cloud-sdk` packages are frequently broken/stale. +- **`gcloud auth login` opens no browser** — run `gcloud auth login + --no-browser` and paste the code back. +- **ADC errors in scripts** — you authenticated `gcloud` but not + application-default credentials; run `gcloud auth application-default login`. +- **Wrong project billed** — check `gcloud config get-value project` before + provisioning; use named configurations. diff --git a/docs/guides/cli/gh.md b/docs/guides/cli/gh.md new file mode 100644 index 00000000..a9ea2f0f --- /dev/null +++ b/docs/guides/cli/gh.md @@ -0,0 +1,96 @@ +# gh (GitHub CLI) + +## What it is + +GitHub's official CLI for pull requests, issues, releases, Actions runs, and +repo management against github.com and GitHub Enterprise hosts. + +## Install + +Debian/Ubuntu, official apt repo (recommended — tracks the stable channel): + +```bash +sudo mkdir -p -m 755 /etc/apt/keyrings +curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null +echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \ + https://cli.github.com/packages stable main" \ + | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null +sudo apt update && sudo apt install gh +``` + +Alternative: download the `linux_amd64` tarball from the +[releases page](https://github.com/cli/cli/releases) and drop `bin/gh` into +`~/.local/bin`. Pin a version there if you need reproducibility across machines. + +## Authenticate + +```bash +gh auth login +``` + +Choose `GitHub.com` → `HTTPS` → browser flow. The token is stored in +`~/.config/gh/hosts.yml` (mode 600). Keep a copy of a fine-grained PAT in +Vaultwarden (https://vault.portugalfuturista.org) as the recovery secret; +prefer `GH_TOKEN` env var in CI instead of the interactive login. + +## Configure for this environment + +github.com is **not** the default forge here — Forgejo is (see +[tea.md](tea.md)). Use `gh` only for the public GitHub mirrors. + +If you ever point `gh` at a GHE-style host: + +```bash +export GH_HOST=git.example.com # per-shell default host +gh auth login --hostname git.example.com +``` + +Note: `GH_HOST` assumes a GitHub Enterprise API layout. Forgejo speaks the +Gitea API, so `gh` will not work against it — use `tea` instead. + +```bash +gh config set git_protocol https +gh config set editor nvim +``` + +## Self-hosted equivalent + +**Forgejo** at https://code.portugalfuturista.org (LAN `192.168.0.9:3001`) is +our default forge. The equivalent CLI is [`tea`](tea.md): + +```bash +tea login add --url https://code.portugalfuturista.org +``` + +Everything you'd do with `gh pr create` maps to `tea pr create` against the +Forgejo remote. + +## Aurélio integration + +The **cli-forge** skill drives `gh`/`tea` for PR and issue workflows. The +connector registry (`.aurelio/connectors/registry.yaml`) covers github.com +under id `github`; the Forgejo instance is id `forgejo`. + +## Verify + +```bash +gh --version +# gh version 2.x.x (YYYY-MM-DD) +gh auth status +# github.com +# ✓ Logged in to github.com account (...) +gh repo list --limit 3 +# / ... +``` + +## Troubleshooting + +- **`gh` talks to the wrong host** — check `echo $GH_HOST`; unset it or pass + `--hostname github.com` explicitly. +- **Auth prompts in headless shells** — use `GH_TOKEN= gh ...` (token from + Vaultwarden) instead of the browser flow. +- **`error connecting to code.portugalfuturista.org`** — you used `gh` against + Forgejo; switch to `tea`. +- **Old version from distro repo** — Debian's `gh` package lags; use the + official apt repo above. diff --git a/docs/guides/cli/helm.md b/docs/guides/cli/helm.md new file mode 100644 index 00000000..cb4117f0 --- /dev/null +++ b/docs/guides/cli/helm.md @@ -0,0 +1,77 @@ +# helm (Helm CLI) + +## What it is + +Helm is the package manager for Kubernetes: charts bundle manifests, and +`helm install/upgrade/rollback` manages releases against the cluster your +kubeconfig points at. + +## Install + +Official install script (latest stable, detects arch): + +```bash +curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash +``` + +Or the static binary: download `helm--linux-amd64.tar.gz` (or +`-linux-arm64`) from the [releases page](https://github.com/helm/helm/releases) +and move `linux-amd64/helm` to `/usr/local/bin`. Pin a version from the +releases page when you need identical clients across machines. + +## Authenticate + +No separate auth — Helm reuses your kubeconfig (`~/.kube/config`, see +[kubectl.md](kubectl.md)). Chart repos with private registries authenticate +via: + +```bash +helm repo add https://charts.example.com --username --password

+``` + +Store repo credentials in Vaultwarden (https://vault.portugalfuturista.org). + +## Configure for this environment + +```bash +helm repo add bitnami https://charts.bitnami.com/bitnami +helm repo update +helm search repo bitnami | head +``` + +Point it at the self-hosted k3s cluster by setting `KUBECONFIG` (see +kubectl.md). Values overrides for LAN endpoints (MinIO etc.) go in a local +`values-lab.yaml` kept out of git. + +## Self-hosted equivalent + +Helm itself is infrastructure-neutral — the self-hosted part is the cluster it +targets (**k3s** on Proxmox, see kubectl.md) and, if you outgrow public chart +repos, a self-hosted **ChartMuseum** (which can store charts on MinIO at +`http://192.168.0.40:9000`). OCI registries (e.g. `helm push ... oci://...`) +are another option once a registry is deployed. + +## Aurélio integration + +The **cli-devops** skill drives `helm` for release management alongside +`kubectl`. Connector registry id: `kubernetes` (same cluster connector). + +## Verify + +```bash +helm version +# version.BuildInfo{Version:"v3.x.y", ...} +helm list --all-namespaces # against a configured cluster +# NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +``` + +## Troubleshooting + +- **`Error: Kubernetes cluster unreachable`** — kubeconfig/context problem; + fix with `kubectl` first, Helm inherits it. +- **Chart not found after `helm repo add`** — run `helm repo update`. +- **Upgrade fails with "another operation in progress"** — a release is stuck + `pending-*`; `helm history ` then `helm rollback `. +- **CRDs missing** — some charts (e.g. cert-manager) need CRDs installed first + (`helm install --set crds.enabled=true` or a separate CRD step); read the + chart's README. diff --git a/docs/guides/cli/kubectl.md b/docs/guides/cli/kubectl.md new file mode 100644 index 00000000..198d9955 --- /dev/null +++ b/docs/guides/cli/kubectl.md @@ -0,0 +1,86 @@ +# kubectl (Kubernetes CLI) + +## What it is + +`kubectl` is the Kubernetes control client: apply manifests, inspect workloads, +stream logs, exec into pods. It talks to any cluster via a kubeconfig. + +## Install + +Static binary, current stable (x86_64; swap `amd64`→`arm64` for ARM): + +```bash +curl -fsSLO "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" +sudo install -m 0755 kubectl /usr/local/bin/kubectl && rm kubectl +``` + +Or the Google apt repo (`sudo apt install kubectl` after adding +`pkgs.k8s.io`). Keep the client within one minor version of the server. + +## Authenticate + +Auth is the kubeconfig, not a login command: + +```bash +export KUBECONFIG=~/.kube/config # default +kubectl config get-contexts +kubectl config use-context +``` + +Kubeconfigs are bearer secrets — keep them mode 600, and archive copies in +Vaultwarden (https://vault.portugalfuturista.org). + +## Configure for this environment + +No production cluster yet on the Proxmox fleet; the plan is k3s (below). For +cloud clusters, fetch credentials with the vendor CLI: + +```bash +gcloud container clusters get-credentials --zone +aws eks update-kubeconfig --name +``` + +## Self-hosted equivalent + +**k3s** — lightweight Kubernetes, ideal on a Proxmox CT/VM (asus or gigabyte): + +```bash +# on the node (Debian/Ubuntu CT, privileged or with nesting enabled) +curl -sfL https://get.k3s.io | sh - +sudo cat /etc/rancher/k3s/k3s.yaml # copy to laptop ~/.kube/config +``` + +On the laptop, edit the `server:` line to `https://:6443` and: + +```bash +kubectl get nodes +# NAME STATUS ROLES AGE VERSION +# k3s1 Ready control-plane,master 1m v1.x.y+k3s1 +``` + +For a pure-laptop dev cluster, `k3d` (k3s in Docker) is the fastest option. + +## Aurélio integration + +The **cli-devops** skill uses `kubectl`/`helm` for cluster operations. +Connector registry id: `kubernetes`. + +## Verify + +```bash +kubectl version --client +# Client Version: v1.x.y ... +kubectl get --raw /readyz # against a configured cluster +# ok +``` + +## Troubleshooting + +- **`connection refused` to 127.0.0.1:8080** — no context set; run + `kubectl config get-contexts` and `use-context`. +- **k3s kubeconfig 403 on the laptop** — you copied `k3s.yaml` but left + `server: https://127.0.0.1:6443`; point it at the node IP. +- **Version skew warnings** — keep kubectl within ±1 minor of the server; + reinstall from `dl.k8s.io/release/stable.txt`. +- **Proxmox CT can't run k3s** — enable nesting/keyctl or use an + unprivileged-with-features CT; plain VMs are the least-friction path. diff --git a/docs/guides/cli/mosquitto-clients.md b/docs/guides/cli/mosquitto-clients.md new file mode 100644 index 00000000..f499be99 --- /dev/null +++ b/docs/guides/cli/mosquitto-clients.md @@ -0,0 +1,94 @@ +# mosquitto-clients (MQTT pub/sub CLI) + +## What it is + +`mosquitto_pub` / `mosquitto_sub` — the reference MQTT command-line clients +from the Eclipse Mosquitto project. The quickest way to poke a broker from a +shell or script. + +## Install + +Debian/Ubuntu: + +```bash +sudo apt install mosquitto-clients +``` + +(The `mosquitto` package is the broker — only install that on a broker host.) + +## Authenticate + +Broker-dependent. Typical username/password: + +```bash +mosquitto_sub -h -t 'lab/#' -u -P +``` + +Keep broker credentials in Vaultwarden (https://vault.portugalfuturista.org). +For TLS brokers: `-p 8883 --cafile ` (+ `--cert/--key` for mutual TLS). + +## Configure for this environment + +Convenience env for the lab broker: + +```bash +export MQTT_HOST=192.168.0.40 # or wherever the broker CT lands +export MQTT_PORT=1883 + +mosquitto_sub -h $MQTT_HOST -t 'lab/#' -v & # watch everything +mosquitto_pub -h $MQTT_HOST -t lab/test -m "hello" +``` + +## Self-hosted equivalent + +The broker itself: **mosquitto in a Proxmox LXC** (Debian template): + +```bash +# on the Proxmox host, in the CT console: +apt update && apt install mosquitto mosquitto-clients +systemctl enable --now mosquitto +``` + +Minimal hardening (`/etc/mosquitto/conf.d/lab.conf`): + +```conf +listener 1883 0.0.0.0 +allow_anonymous false +password_file /etc/mosquitto/passwd +``` + +```bash +mosquitto_passwd -c /etc/mosquitto/passwd labuser +systemctl restart mosquitto +``` + +(LAN-only, so no TLS required; add it if the broker ever leaves the LAN.) +Cloud MQTT (AWS IoT Core etc.) is only for production device fleets. + +## Aurélio integration + +The **cli-iot** skill uses `mosquitto_pub/sub` to probe device topics during +IoT bring-up. Connector registry ids: `mqtt-local` (LAN broker), `aws-iot` +(cloud counterpart). + +## Verify + +```bash +mosquitto_sub --help | head -3 +# mosquitto_sub is a simple mqtt client ... +mosquitto_pub -h $MQTT_HOST -t lab/test -m ping +mosquitto_sub -h $MQTT_HOST -t lab/test -C 1 -W 5 +# ping +``` + +## Troubleshooting + +- **`Connection refused`** — broker not running, or listening on + `127.0.0.1` only (default on many distros); add `listener 1883 0.0.0.0`. +- **`Not authorized`** — anonymous access disabled; pass `-u/-P`, and check + the password file matches the config path. +- **Nothing received but publish succeeds** — topic mismatch; remember MQTT + wildcards: `+` single level, `#` multi-level (and `#` must be quoted in + bash). +- **TLS handshake failure** — wrong CA file or hostname mismatch; use + `--insecure` only as a temporary diagnostic, never in scripts. diff --git a/docs/guides/cli/netlify.md b/docs/guides/cli/netlify.md new file mode 100644 index 00000000..82f2cd74 --- /dev/null +++ b/docs/guides/cli/netlify.md @@ -0,0 +1,75 @@ +# netlify (Netlify CLI) + +## What it is + +Netlify's CLI: deploy static sites and serverless functions, run the local dev +server (`netlify dev`) that emulates Netlify's edge/functions environment, and +manage sites/env from the terminal. + +## Install + +Via npm (current stable; Node LTS required): + +```bash +npm install -g netlify-cli +``` + +## Authenticate + +```bash +netlify login # browser OAuth +netlify status # shows account + site link +``` + +Token stored under `~/.config/netlify/`. For CI use a personal access token +from the dashboard, kept in Vaultwarden (https://vault.portugalfuturista.org), +exported as `NETLIFY_AUTH_TOKEN` (plus `NETLIFY_SITE_ID`). + +## Configure for this environment + +```bash +cd +netlify init # or: netlify link +netlify dev # local server w/ functions emulation +netlify deploy # draft deploy, prints a preview URL +netlify deploy --prod # production +netlify env:list +``` + +## Self-hosted equivalent + +None deployed. Closest self-hosted path for static + functions today: +**Caddy** serving a build output directory on a Proxmox CT, exposed through +the `pf-tunnel-v2` Cloudflare tunnel (route added via cloudflared — see +[cloudflared-wrangler.md](cloudflared-wrangler.md)). Netlify-style edge +functions have no drop-in self-hosted runtime; Cloudflare Workers + `wrangler +dev` is the nearest alternative. + +## Aurélio integration + +The **cli-edge** skill can drive `netlify` for legacy site deploys. No +dedicated connector-registry entry — treated as an external SaaS; closest +listed edge connector is `vercel`. + +## Verify + +```bash +netlify --version +# netlify-cli/1x.y.z linux-x64 node-v2x.y.z +netlify status +# ──────────────────────┐ +# Current Netlify User │ +# ... │ +netlify sites:list | head +``` + +## Troubleshooting + +- **`netlify login` hangs** — no browser on a headless shell; use + `NETLIFY_AUTH_TOKEN` from Vaultwarden instead. +- **Functions work locally, 404 in prod** — check `netlify.toml` + `[functions] directory` and that the deploy actually bundled them + (`netlify deploy --prod --build` logs show "Functions bundling"). +- **Redirects not applied** — `_redirects` must end up in the publish dir; + verify with `netlify deploy --prod` output listing published files. +- **Wrong site linked** — `netlify unlink` then `netlify link` again. diff --git a/docs/guides/cli/platformio.md b/docs/guides/cli/platformio.md new file mode 100644 index 00000000..555280f4 --- /dev/null +++ b/docs/guides/cli/platformio.md @@ -0,0 +1,89 @@ +# platformio (PlatformIO Core) + +## What it is + +PlatformIO Core (`pio`) — cross-platform embedded build system: one +`platformio.ini` pins the platform, board, framework (Arduino/ESP-IDF/Zephyr), +and library deps. The default for multi-board firmware projects. + +## Install + +Via pipx (isolated, current stable): + +```bash +sudo apt install pipx python3-venv +pipx install platformio +pipx ensurepath # re-login so ~/.local/bin is on PATH +``` + +Serial access + udev rules for common boards: + +```bash +sudo usermod -aG dialout $USER +curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/system/99-platformio-udev.rules \ + | sudo tee /etc/udev/rules.d/99-platformio-udev.rules +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +## Authenticate + +Core features need no login. `pio account` (registry publishing, remote +builds) is optional — skip it; if ever used, token goes in Vaultwarden. + +## Configure for this environment + +Example `platformio.ini` for an ESP32 lab node: + +```ini +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +monitor_speed = 115200 +upload_port = /dev/ttyUSB0 +lib_deps = + knolleary/PubSubClient @ ^2.8 +``` + +```bash +pio run # build all envs +pio run -t upload # flash +pio device monitor # serial +pio run -t clean +``` + +## Self-hosted equivalent + +Builds are fully local. The PlatformIO Registry is a cloud service, but deps +are cached in `~/.platformio/` and can be vendored into the repo +(`lib_deps = symlink://lib/...` or committed libraries) for offline +reproducibility; firmware artifacts archive to MinIO +(`http://192.168.0.40:9000`). + +## Aurélio integration + +The **embedded-linux** skill drives `pio` for firmware build/upload/monitor +cycles. Devices built here typically target the `mqtt-local` broker or +`aws-iot` connectors. + +## Verify + +```bash +pio --version +# PlatformIO Core, version 6.x.y +pio device list +# /dev/ttyUSB0 ... USB Serial +pio run +# ... SUCCESS ... RAM: [...] Flash: [...] +``` + +## Troubleshooting + +- **First build downloads a lot** — platforms/toolchains install into + `~/.platformio/` on demand; keep that dir cached between CI runs. +- **Upload fails, port busy** — close `pio device monitor` (or the IDE + serial monitor) before flashing. +- **Board not auto-detected** — set `upload_port` explicitly in + `platformio.ini` (as above) after checking `pio device list`. +- **`dialout` permission errors** — group membership needs a re-login; udev + rules above fix most FTDI/CP210x/CH340 cases. diff --git a/docs/guides/cli/tea.md b/docs/guides/cli/tea.md new file mode 100644 index 00000000..a802b21b --- /dev/null +++ b/docs/guides/cli/tea.md @@ -0,0 +1,93 @@ +# tea (Gitea/Forgejo CLI) + +## What it is + +`tea` is the official CLI for Gitea and Forgejo instances — repos, pull +requests, issues, releases, notifications. Since Forgejo is our default forge, +`tea` is the **primary forge CLI** on this fleet. + +## Install + +Debian/Ubuntu: + +```bash +sudo apt install tea # may lag upstream; fine for basics +``` + +Latest stable binary (x86_64; use `linux-arm64` on arm64): + +```bash +curl -fsSL -o ~/.local/bin/tea \ + https://dl.gitea.com/tea/$(curl -fsSL https://dl.gitea.com/tea/version.json | grep -oP '"Version":\s*"\K[^"]+')/tea-linux-amd64 +chmod +x ~/.local/bin/tea +``` + +Or build/pin via the Gitea releases page if you need a specific version. + +## Authenticate + +Create an access token first: in Forgejo → *Settings → Applications → Generate +New Token* (scopes: `repo`, `issue`, `read:org`). Store it in Vaultwarden +(https://vault.portugalfuturista.org). + +```bash +tea login add \ + --name portugalfuturista \ + --url https://code.portugalfuturista.org \ + --token +tea login default portugalfuturista +``` + +Logins live in `~/.config/tea/config.yml` (keep it mode 600 — it holds tokens). + +## Configure for this environment + +```bash +# inside a clone +git remote -v +# origin https://code.portugalfuturista.org/portugalfuturista/.git +``` + +`tea` auto-detects the login from the git remote. On the LAN the same instance +is reachable at `http://192.168.0.9:3001` — prefer the TLS name so certs and +tokens stay consistent. + +```bash +tea repos ls --limit 5 +tea issues ls +tea pr create --title "..." --description "..." +``` + +## Self-hosted equivalent + +`tea` *is* the self-hosted equivalent — Forgejo at +https://code.portugalfuturista.org is the self-hosted GitHub. For public +github.com mirrors only, see [gh.md](gh.md). + +## Aurélio integration + +The **cli-forge** skill uses `tea` for PR/issue automation against Forgejo. +Connector registry id: `forgejo` (github.com mirrors: `github`). + +## Verify + +```bash +tea --version +# Version: 0.x.x ... +tea logins ls +# NAME URL DEFAULT +# portugalfuturista https://code.portugalfuturista.org true +tea whoami +# +``` + +## Troubleshooting + +- **`401 Unauthorized`** — token missing the needed scope; regenerate in + Forgejo with `repo`/`issue` and re-run `tea login add` (or edit + `~/.config/tea/config.yml`). +- **Wrong login picked up** — `tea` matches by remote URL; set the default + with `tea login default ` or pass `--login`. +- **TLS error on the LAN IP** — the cert is for `code.portugalfuturista.org`; + use the name, not `192.168.0.9:3001`, with HTTPS. +- **`unknown command`** — distro package is old; install the latest binary. diff --git a/docs/guides/cli/terraform-opentofu.md b/docs/guides/cli/terraform-opentofu.md new file mode 100644 index 00000000..102e7a5c --- /dev/null +++ b/docs/guides/cli/terraform-opentofu.md @@ -0,0 +1,118 @@ +# terraform / tofu (Terraform + OpenTofu) + +## What it is + +Infrastructure-as-code CLIs. **OpenTofu** (`tofu`) is the open-source +(MPL-2.0) fork of Terraform and is our default; `terraform` is kept for modules +or providers that lag Tofu compatibility. CLIs are drop-in compatible for +current Terraform 1.5-era workflows. + +## Install + +OpenTofu (preferred — official apt repo): + +```bash +curl -fsSL https://get.opentofu.org/install-opentofu.sh -o /tmp/install-opentofu.sh +chmod +x /tmp/install-opentofu.sh +sudo /tmp/install-opentofu.sh --install-method deb +``` + +Terraform (HashiCorp apt repo): + +```bash +curl -fsSL https://apt.releases.hashicorp.com/gpg \ + | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg +echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \ + https://apt.releases.hashicorp.com $(lsb_release -cs) main" \ + | sudo tee /etc/apt/sources.list.d/hashicorp.list +sudo apt update && sudo apt install terraform +``` + +Both publish static binaries too — pin versions via `required_version` in your +root module rather than relying on whatever is installed. + +## Authenticate + +Per provider, via environment variables — keep the real secrets in Vaultwarden +(https://vault.portugalfuturista.org) and load them into the shell: + +```bash +export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... # aws provider +export ARM_CLIENT_ID=... ARM_CLIENT_SECRET=... # azurerm +``` + +## Configure for this environment + +Dev targets are the self-hosted emulators on lattepanda (`192.168.0.40`), so +provider blocks point at them: + +```hcl +provider "aws" { + region = "us-east-1" + access_key = "test" + secret_key = "test" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_requesting_account_id = true + endpoints { + s3 = "http://192.168.0.40:4566" # LocalStack + lambda = "http://192.168.0.40:4566" + } +} +``` + +## Self-hosted equivalent + +**State on MinIO** via the S3 backend (`backend.tf`): + +```hcl +terraform { + backend "s3" { + bucket = "tf-state" + key = "lab/terraform.tfstate" + region = "us-east-1" + endpoint = "http://192.168.0.40:9000" + access_key = "" + secret_key = "" + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + force_path_style = true + } +} +``` + +Create the bucket first (`aws --endpoint-url http://192.168.0.40:9000 s3 mb +s3://tf-state`), then `tofu init`. Better still, pass the MinIO keys via +`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` at init time so secrets never sit +in `.tf` files. + +## Aurélio integration + +The **cli-devops** skill runs `tofu plan/apply` against lab stacks. Connector +registry ids: `terraform` (tool), `minio` (state backend), `aws-localstack` +(provider target). + +## Verify + +```bash +tofu version +# OpenTofu v1.x.y +terraform version +# Terraform v1.x.y +tofu init && tofu validate +# Success! The configuration is valid. +``` + +## Troubleshooting + +- **`Error acquiring the state lock`** — with the MinIO backend there's no + DynamoDB lock table; don't run two applies concurrently (MinIO conditional + writes give basic protection only). +- **Provider downloads blocked offline** — `tofu init` needs registry access + once; use a filesystem mirror or vendor providers into + `~/.terraform.d/plugins`. +- **LocalStack endpoint ignored** — every `endpoints {}` service you use must + be listed; unknown services fall through to real AWS. +- **`InvalidSignatureException` on MinIO state** — clock skew or wrong keys; + sync NTP and re-check Vaultwarden entry. diff --git a/docs/guides/cli/uboot-tools.md b/docs/guides/cli/uboot-tools.md new file mode 100644 index 00000000..2ee83abf --- /dev/null +++ b/docs/guides/cli/uboot-tools.md @@ -0,0 +1,83 @@ +# u-boot-tools (mkimage & friends) + +## What it is + +The `u-boot-tools` package provides host-side utilities for U-Boot images: +`mkimage` (wrap kernels/ramdisks/scripts into U-Boot's legacy/FIT formats), +`mkenvimage` (binary environment images), `dumpimage`, and `fw_printenv` / +`fw_setenv` (read/write the U-Boot environment from Linux). + +## Install + +Debian/Ubuntu: + +```bash +sudo apt install u-boot-tools +``` + +(For device-tree work also grab `device-tree-compiler`.) + +## Authenticate + +None — local file manipulation tools. + +## Configure for this environment + +Common lab uses: + +```bash +# legacy uImage for a kernel +mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 \ + -n "lab-kernel" -d zImage uImage + +# FIT image (kernel + dtb + ramdisk) — preferred on modern boards +mkimage -f image.its fitImage.itb + +# boot script +mkimage -A arm -T script -C none -n "boot script" -d boot.cmd boot.scr + +# environment image +mkenvimage -s 0x20000 -o uboot.env env.txt +``` + +FIT source files (`.its`) and board-specific addresses live with the board +bring-up docs in the firmware repo on Forgejo — don't guess addresses, copy +them from the vendor BSP. + +## Self-hosted equivalent + +Fully local tooling; no cloud equivalent exists or is needed. For **OTA / +A-B updates** on deployed boards, the self-hosted stack is **SWUpdate** +(`swupdate` on the target, update artifacts served from any LAN HTTP server or +MinIO at `http://192.168.0.40:9000`) — that is our cloud-free alternative to +managed update services like Mender cloud. + +## Aurélio integration + +The **embedded-linux** skill uses `mkimage` when packaging kernels/ramdisks +for U-Boot boards, and mentions `swupdate` for field update flows. No +connector-registry entry — local build tooling. + +## Verify + +```bash +mkimage -V +# mkimage version 20xx.xx ... +mkimage -l uImage # on a real image +# Image Name: lab-kernel +# Image Type: ARM Linux Kernel Image (uncompressed) +# ... +``` + +## Troubleshooting + +- **`mkimage: Can't open ...`** — input path wrong; remember `-d ` + is the payload, output is the last positional argument. +- **Board rejects the image (`Bad Magic Number`)** — wrong architecture `-A` + or load/entry addresses; take them from the vendor BSP, not another board. +- **FIT fails to boot with "hash mismatch"** — the `.its` referenced files + changed after `mkimage` ran, or signing keys differ; rebuild the FIT and + check `sign-images` config in U-Boot. +- **`fw_printenv` CRC error** — environment not yet saved on the board + (`saveenv` once from U-Boot), or `/etc/fw_env.config` offsets don't match + the partition layout. diff --git a/docs/guides/cli/vercel.md b/docs/guides/cli/vercel.md new file mode 100644 index 00000000..e8b76070 --- /dev/null +++ b/docs/guides/cli/vercel.md @@ -0,0 +1,77 @@ +# vercel (Vercel CLI) + +## What it is + +Vercel's CLI: link a project, get instant preview deploys from a branch, +promote to production, manage env vars and domains. + +## Install + +Via npm (current stable; requires Node LTS): + +```bash +npm install -g vercel +``` + +Standalone binaries also exist on the releases page if you don't want a global +npm package. + +## Authenticate + +```bash +vercel login # email link confirmation +``` + +Token cached in `~/.vercel/` (actually platform config dir). For CI, create a +token in the dashboard, store it in Vaultwarden +(https://vault.portugalfuturista.org), and use: + +```bash +vercel --token "$VERCEL_TOKEN" deploy --prod +``` + +## Configure for this environment + +```bash +cd +vercel link # pick scope + project +vercel env pull .env.local # fetch env vars for local dev +vercel dev # local dev server with Vercel routing +vercel # preview deploy +vercel --prod # production +``` + +## Self-hosted equivalent + +None deployed. The planned self-hosted alternative is **Coolify** (or Dokku) +on a Proxmox CT — git-push deploys with preview-like behaviour. Until then, +static frontends are served via Caddy on the LAN behind the `pf-tunnel-v2` +Cloudflare tunnel; Vercel is used only when its edge network or Next.js +integration is genuinely required. + +## Aurélio integration + +The **cli-edge** skill wraps `vercel` for preview/prod deploys of edge +frontends. Connector registry id: `vercel`. + +## Verify + +```bash +vercel --version +# 3x.y.z +vercel whoami +# > Success! ... +vercel ls +# ... project deployments table ... +``` + +## Troubleshooting + +- **`vercel login` email never arrives** — check spam; or use + `vercel login ` and the token flow from the dashboard instead. +- **Wrong scope/team** — `vercel switch` to change the active team, or + re-run `vercel link`. +- **Build works locally, fails on Vercel** — Node version mismatch; pin + `"engines"` in `package.json` or the project settings. +- **Env var missing in preview** — Vercel envs are per-environment + (Production/Preview/Development); set the var for the right target. diff --git a/docs/guides/cli/yocto.md b/docs/guides/cli/yocto.md new file mode 100644 index 00000000..991b5c7b --- /dev/null +++ b/docs/guides/cli/yocto.md @@ -0,0 +1,101 @@ +# yocto (Yocto Project / poky + kas) + +## What it is + +The Yocto Project builds custom Linux distributions from recipes. `poky` is +the reference distribution; `kas` is the config-driven wrapper that pins +layers/revisions in one YAML file. This is how we build appliance images for +embedded targets. + +## Requirements (read before building) + +- **Disk: ~100 GB+ free** (sstate cache + downloads grow fast; 200 GB is + comfortable). +- **RAM: 16 GB** (8 GB works with a big swapfile and patience). +- Long builds: first `core-image-minimal` can take hours on a laptop. + +## Install (host tools) + +```bash +sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential \ + chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \ + iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \ + pylint xterm python3-subunit mesa-common-dev zstd liblz4-tool file locales +pipx install kas +``` + +## Recommended: build inside the crops/poky container + +The laptop should not be a Yocto host. Use the official container (Ubuntu +base, all deps preinstalled): + +```bash +docker run --rm -it \ + -v ~/yocto:/work -w /work \ + crops/poky:ubuntu-22.04 +# inside the container: +git clone -b scarthgap https://git.yoctoproject.org/poky +source poky/oe-init-build-env build +bitbake core-image-minimal +``` + +With kas instead of manual sourcing: + +```bash +kas build project.yml # runs bitbake per the pinned layer config +kas shell project.yml # interactive shell inside the build env +``` + +A dedicated **Proxmox CT/VM for Yocto builds** (100+ GB disk, 16 GB RAM, +Docker or bare Debian) may come later — designs should already assume builds +run there, not on the laptop. + +## Authenticate + +None. Layer repos clone over HTTPS/SSH (use Forgejo mirrors where they exist: +`code.portugalfuturista.org`). Private-layer SSH keys stay in `~/.ssh`; never +in recipes. + +## Configure for this environment + +- Set `DL_DIR` and `SSTATE_DIR` outside the build tree so multiple builds + share downloads/cache (`local.conf`): + ``` + DL_DIR ?= "/work/downloads" + SSTATE_DIR ?= "/work/sstate-cache" + ``` +- Pin every layer branch in the kas YAML — reproducibility over freshness. +- Archive release images to MinIO (`http://192.168.0.40:9000`). + +## Self-hosted equivalent + +Yocto is inherently self-hosted — the entire toolchain and mirrorable source +cache live on your infrastructure. For air-gapped reproducibility run an +`sstate` mirror on MinIO (`SSTATE_MIRRORS` in `local.conf`). + +## Aurélio integration + +The **embedded-linux** skill drives `kas`/`bitbake` for image builds. Images +produced are flashed with tools from [esptool.md](esptool.md) / +[uboot-tools.md](uboot-tools.md) and target the `mqtt-local` connector at +runtime. + +## Verify + +```bash +kas --version +# kas 4.x +docker run --rm crops/poky:ubuntu-22.04 bitbake --version +# BitBake Build Tool Core version 2.x ... +``` + +## Troubleshooting + +- **`do_fetch` stalls** — upstream git flaky; set a premirror or retry; check + you cloned the matching release branch (e.g. `scarthgap`) for all layers. +- **Disk full mid-build** — Yocto needs ~100 GB; clean with + `bitbake -c cleanall ` or prune `tmp/` (keep `DL_DIR`/`SSTATE_DIR`). +- **Host distro too new/old for a release** — that's exactly why we build in + `crops/poky`; pick the container Ubuntu version matching the Yocto release. +- **`kas` can't find layers** — paths in the kas YAML are relative to the + repo root; run `kas build` from there or pass absolute `--target` paths. diff --git a/docs/guides/selfhosted/cloud-emulators.md b/docs/guides/selfhosted/cloud-emulators.md new file mode 100644 index 00000000..2b94f30e --- /dev/null +++ b/docs/guides/selfhosted/cloud-emulators.md @@ -0,0 +1,134 @@ +# Cloud emulators (self-hosted dev cloud) — MinIO + LocalStack + Azurite + +Self-hosted cloud services for development, running on **lattepanda** +(192.168.0.40) as Docker containers. Part of the "self-hosted first" policy: +dev work targets these endpoints; public clouds only when explicitly required. + +## What's deployed + +| Service | Emulates | Endpoint (LAN) | Console | +|---|---|---|---| +| MinIO | AWS S3 | `http://192.168.0.40:9000` | `http://192.168.0.40:9001` | +| LocalStack v3 | AWS (S3, SQS, SNS, IAM, Lambda, DynamoDB, IoT, …) | `http://192.168.0.40:4566` | — | +| Azurite | Azure Storage | blob `:10000` · queue `:10001` · table `:10002` | — | + +Pre-created MinIO buckets: `terraform-state`, `firmware-artifacts`, `backups`. + +> **Why LocalStack v3?** `localstack/localstack:latest` (2026+) requires a +> `LOCALSTACK_AUTH_TOKEN` (Pro license). The v3 tag is the last community +> line that runs token-free. + +## Deploy / manage + +The stack lives at `/opt/cloud-emulators/` on lattepanda: + +``` +/opt/cloud-emulators/ +├── cloud-emulators.yml # compose file (source of truth: repo docs/compose/cloud-emulators.yml) +└── .env # MINIO_ROOT_USER / MINIO_ROOT_PASSWORD (chmod 600) +``` + +```bash +ssh root@192.168.0.40 +cd /opt/cloud-emulators +docker compose -f cloud-emulators.yml up -d # start/update +docker compose -f cloud-emulators.yml ps # status +docker compose -f cloud-emulators.yml logs -f # logs +``` + +After editing `docs/compose/cloud-emulators.yml` in the repo, sync it: + +```bash +scp docs/compose/cloud-emulators.yml root@192.168.0.40:/opt/cloud-emulators/ +ssh root@192.168.0.40 'cd /opt/cloud-emulators && docker compose -f cloud-emulators.yml up -d' +``` + +## Credentials + +MinIO root credentials are in `/opt/cloud-emulators/.env` on lattepanda +(chmod 600). Store a copy in **Vaultwarden** (entry: "MinIO lattepanda"). +LocalStack and Azurite accept any credentials in dev — use `test`/`test`. + +## CLI wiring + +### aws CLI → MinIO / LocalStack + +Add to `~/.aws/config`: + +```ini +[profile localstack] +region = eu-west-1 +output = json + +[profile minio] +region = eu-west-1 +output = json +``` + +`~/.aws/credentials`: + +```ini +[localstack] +aws_access_key_id = test +aws_secret_access_key = test + +[minio] +aws_access_key_id = minioadmin +aws_secret_access_key = +``` + +Usage: + +```bash +aws --profile localstack --endpoint-url http://192.168.0.40:4566 sqs list-queues +aws --profile minio --endpoint-url http://192.168.0.40:9000 s3 ls +``` + +(See `docs/guides/cli/aws.md` for full setup.) + +### az CLI → Azurite + +```bash +export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://192.168.0.40:10000/devstoreaccount1;QueueEndpoint=http://192.168.0.40:10001/devstoreaccount1;TableEndpoint=http://192.168.0.40:10002/devstoreaccount1;" +az storage container list --connection-string "$AZURE_STORAGE_CONNECTION_STRING" +``` + +(The Azurite account key above is the well-known public dev key — fine for LAN dev.) + +### OpenTofu/Terraform state on MinIO + +```hcl +terraform { + backend "s3" { + bucket = "terraform-state" + key = "lab/terraform.tfstate" + region = "eu-west-1" + endpoint = "http://192.168.0.40:9000" + access_key = "minioadmin" # or env AWS_ACCESS_KEY_ID + secret_key = "…" # or env AWS_SECRET_ACCESS_KEY + skip_credentials_validation = true + skip_metadata_api_check = true + skip_region_validation = true + force_path_style = true + } +} +``` + +## Verify + +```bash +curl -sf http://192.168.0.40:9000/minio/health/live # MinIO → 200 +curl -sf http://192.168.0.40:4566/_localstack/health | jq # LocalStack → services available +curl -s -o /dev/null -w '%{http_code}\n' http://192.168.0.40:10000/ # Azurite → 400 (up, auth required) +``` + +## Troubleshooting + +- **LocalStack restart loop, exit 55** — you're on `latest` (Pro-only). The + compose file pins `localstack/localstack:3`; don't bump without a license. +- **MinIO `mc` commands** — exec inside the container: + `docker exec minio mc ls local` (alias `local` preconfigured at bootstrap). +- **Azurite 400 on root URL** — expected; the service requires an account path. + Use the connection string above. +- **Disk pressure** — all three volumes live on lattepanda's root disk (85G + free at deploy time). `docker system df` to audit.