diff --git a/ansible/roles/devpi/defaults/main.yml b/ansible/roles/devpi/defaults/main.yml deleted file mode 100644 index 0fc0569..0000000 --- a/ansible/roles/devpi/defaults/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -devpi_port: 3141 -devpi_serverdir: /Users/erichblume/devpi -devpi_log_dir: /Users/erichblume/Library/Logs -devpi_host: 0.0.0.0 # Listen on all interfaces for Tailscale -devpi_outside_url: https://pypi.tail8d86e.ts.net # URL for Tailscale proxy -devpi_secretfile: /Users/erichblume/devpi/.secret # Persistent auth secret diff --git a/ansible/roles/devpi/handlers/main.yml b/ansible/roles/devpi/handlers/main.yml deleted file mode 100644 index 7e29c43..0000000 --- a/ansible/roles/devpi/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Reload devpi - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist - changed_when: true diff --git a/ansible/roles/devpi/tasks/main.yml b/ansible/roles/devpi/tasks/main.yml deleted file mode 100644 index 2c6d03e..0000000 --- a/ansible/roles/devpi/tasks/main.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -# Note: devpi is installed via mise (pipx/uvx), not managed here. -# -# ONE-TIME SETUP (before running ansible): -# -# 1. Add to ~/.config/mise/config.toml on indri: -# -# [tools] -# "pipx:devpi-server" = { version = "latest", uvx = "true", uvx_args = "--with devpi-web" } -# "pipx:devpi-client" = { version = "latest", uvx = "true" } -# -# 2. Install: mise install -# -# 3. Initialize with root password (generate password in 1password): -# mise x -- devpi-init --serverdir {{ devpi_serverdir }} --root-passwd YOUR_PASSWORD -# -# 4. Run ansible to deploy LaunchAgent -# -# 5. Set up Tailscale service (see management log) - -- name: Ensure devpi data directory exists - ansible.builtin.file: - path: "{{ devpi_serverdir }}" - state: directory - mode: '0755' - -- name: Generate devpi secret file if not exists - ansible.builtin.shell: | - openssl rand -hex 32 > "{{ devpi_secretfile }}" - args: - creates: "{{ devpi_secretfile }}" - -- name: Ensure devpi secret file has secure permissions - ansible.builtin.file: - path: "{{ devpi_secretfile }}" - mode: '0600' - -- name: Deploy devpi LaunchAgent plist - ansible.builtin.template: - src: devpi.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.eblume.devpi.plist - mode: '0644' - notify: Reload devpi - -- name: Check if devpi LaunchAgent is loaded - ansible.builtin.command: launchctl list mcquack.eblume.devpi - register: devpi_launchctl_check - changed_when: false - failed_when: false - -- name: Load devpi LaunchAgent if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist - when: devpi_launchctl_check.rc != 0 - changed_when: true - failed_when: false diff --git a/ansible/roles/devpi/templates/devpi.plist.j2 b/ansible/roles/devpi/templates/devpi.plist.j2 deleted file mode 100644 index b2ed6aa..0000000 --- a/ansible/roles/devpi/templates/devpi.plist.j2 +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - KeepAlive - - Label - mcquack.eblume.devpi - EnvironmentVariables - - PATH - /opt/homebrew/bin:/usr/bin:/bin - - ProgramArguments - - /opt/homebrew/opt/mise/bin/mise - x - -- - devpi-server - --serverdir - {{ devpi_serverdir }} - --host - {{ devpi_host }} - --port - {{ devpi_port }} - --outside-url - {{ devpi_outside_url }} - --secretfile - {{ devpi_secretfile }} - - RunAtLoad - - StandardErrorPath - {{ devpi_log_dir }}/mcquack.devpi.err.log - StandardOutPath - {{ devpi_log_dir }}/mcquack.devpi.out.log - - diff --git a/ansible/roles/devpi_metrics/defaults/main.yml b/ansible/roles/devpi_metrics/defaults/main.yml deleted file mode 100644 index d1aa18b..0000000 --- a/ansible/roles/devpi_metrics/defaults/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -devpi_metrics_url: http://localhost:3141/+status -devpi_metrics_dir: /opt/homebrew/var/node_exporter/textfile -devpi_metrics_script: /Users/erichblume/bin/devpi-metrics -devpi_metrics_interval: 60 # seconds between metric collection -devpi_metrics_log_dir: /opt/homebrew/var/log diff --git a/ansible/roles/devpi_metrics/handlers/main.yml b/ansible/roles/devpi_metrics/handlers/main.yml deleted file mode 100644 index 81bfd1d..0000000 --- a/ansible/roles/devpi_metrics/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Reload devpi-metrics - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist - changed_when: true diff --git a/ansible/roles/devpi_metrics/meta/main.yml b/ansible/roles/devpi_metrics/meta/main.yml deleted file mode 100644 index b05a43b..0000000 --- a/ansible/roles/devpi_metrics/meta/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -# Role ordering is controlled by indri.yml playbook - do not add dependencies here -# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies) -dependencies: [] diff --git a/ansible/roles/devpi_metrics/tasks/main.yml b/ansible/roles/devpi_metrics/tasks/main.yml deleted file mode 100644 index b267648..0000000 --- a/ansible/roles/devpi_metrics/tasks/main.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- -- name: Ensure metrics directory exists - ansible.builtin.file: - path: "{{ devpi_metrics_dir }}" - state: directory - mode: '0755' - -- name: Ensure log directory exists - ansible.builtin.file: - path: "{{ devpi_metrics_log_dir }}" - state: directory - mode: '0755' - -- name: Deploy devpi-metrics script - ansible.builtin.template: - src: devpi-metrics.sh.j2 - dest: "{{ devpi_metrics_script }}" - mode: '0755' - -- name: Deploy devpi-metrics LaunchAgent plist - ansible.builtin.template: - src: devpi-metrics.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist - mode: '0644' - notify: Reload devpi-metrics - -- name: Check if devpi-metrics LaunchAgent is loaded - ansible.builtin.command: launchctl list mcquack.eblume.devpi-metrics - register: devpi_metrics_launchctl_check - changed_when: false - failed_when: false - -- name: Load devpi-metrics LaunchAgent if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist - when: devpi_metrics_launchctl_check.rc != 0 - changed_when: true - failed_when: false diff --git a/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2 b/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2 deleted file mode 100644 index a8141df..0000000 --- a/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2 +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - Label - mcquack.eblume.devpi-metrics - ProgramArguments - - {{ devpi_metrics_script }} - - StartInterval - {{ devpi_metrics_interval }} - RunAtLoad - - StandardErrorPath - {{ devpi_metrics_log_dir }}/mcquack.devpi-metrics.err.log - StandardOutPath - {{ devpi_metrics_log_dir }}/mcquack.devpi-metrics.out.log - - diff --git a/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2 b/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2 deleted file mode 100644 index 2a1141d..0000000 --- a/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2 +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# {{ ansible_managed }} -# Collects devpi-server metrics for node_exporter textfile collector - -set -euo pipefail - -STATUS_URL="{{ devpi_metrics_url }}" -OUTPUT_FILE="{{ devpi_metrics_dir }}/devpi.prom" -TEMP_FILE="${OUTPUT_FILE}.tmp" - -# Fetch status JSON -status_json=$(curl -s -H "Accept: application/json" "$STATUS_URL" 2>/dev/null) - -if [ -z "$status_json" ] || ! echo "$status_json" | jq -e '.result' >/dev/null 2>&1; then - echo "Failed to fetch devpi status" >&2 - exit 1 -fi - -# Start output file -cat > "$TEMP_FILE" << 'HEADER' -# HELP devpi_up devpi-server is up and responding -# TYPE devpi_up gauge -devpi_up 1 - -HEADER - -# Extract serial number using jq -serial=$(echo "$status_json" | jq -r '.result.serial // empty') -if [ -n "$serial" ]; then - cat >> "$TEMP_FILE" << EOF -# HELP devpi_serial Current changelog serial number -# TYPE devpi_serial gauge -devpi_serial $serial - -EOF -fi - -# Parse metrics array using jq - format is ["name", "type", value] -echo "$status_json" | jq -r '.result.metrics[]? | @json' | while read -r metric_json; do - name=$(echo "$metric_json" | jq -r '.[0]') - type=$(echo "$metric_json" | jq -r '.[1]') - value=$(echo "$metric_json" | jq -r '.[2]') - - # Write metric in Prometheus format - cat >> "$TEMP_FILE" << EOF -# HELP $name devpi metric -# TYPE $name $type -$name $value - -EOF -done - -# Atomic move -mv "$TEMP_FILE" "$OUTPUT_FILE" diff --git a/ansible/roles/kiwix/defaults/main.yml b/ansible/roles/kiwix/defaults/main.yml deleted file mode 100644 index 41f3abb..0000000 --- a/ansible/roles/kiwix/defaults/main.yml +++ /dev/null @@ -1,131 +0,0 @@ ---- -kiwix_serve_bin: /Users/erichblume/code/3rd/kiwix-tools/kiwix-serve -kiwix_zim_dir: /Users/erichblume/code/3rd/kiwix-tools -kiwix_bin_dir: /Users/erichblume/.local/bin -kiwix_port: 5501 -kiwix_log_dir: /Users/erichblume/Library/Logs - -# Transmission integration -# When enabled, ZIM archives are downloaded via BitTorrent instead of direct HTTP -kiwix_use_transmission: true -kiwix_torrent_base_url: "https://download.kiwix.org/zim" - -# ZIM archives to download and serve -# Each item needs: category, filename -# Torrent URL: {{ kiwix_torrent_base_url }}/{{ category }}/{{ filename }}.torrent -kiwix_zim_archives: - # Wikipedia - Top 1M articles with images (43G) - - category: wikipedia - filename: wikipedia_en_top1m_maxi_2025-09.zim - - ## Other Wikipedia options: - # - category: wikipedia - # filename: wikipedia_en_all_maxi_2025-08.zim # 111G - Full English Wikipedia - # - category: wikipedia - # filename: wikipedia_en_top_maxi_2025-12.zim # 7.6G - Top 100K articles - - # Project Gutenberg - Public domain books (72G) - - category: gutenberg - filename: gutenberg_en_all_2023-08.zim - - ## Newer Gutenberg (much larger, unclear why): - # - category: gutenberg - # filename: gutenberg_en_all_2025-11.zim # 206G - Full collection (2025) - - # iFixit - Repair guides (3.3G) - - category: ifixit - filename: ifixit_en_all_2025-12.zim - - # Stack Exchange - - category: stack_exchange - filename: superuser.com_en_all_2025-12.zim # 3.7G - # - category: stack_exchange - # filename: serverfault.com_en_all_2025-12.zim # 1.5G - # - category: stack_exchange - # filename: askubuntu.com_en_all_2025-12.zim # 2.6G - # - category: stack_exchange - # filename: unix.stackexchange.com_en_all_2025-12.zim # 1.2G - - category: stack_exchange - filename: math.stackexchange.com_en_all_2025-12.zim # 6.9G - # - category: stack_exchange - # filename: stackoverflow.com_en_all_2023-11.zim # 75G - Full StackOverflow - - # LibreTexts - Open educational resources - - category: libretexts - filename: libretexts.org_en_bio_2025-01.zim # 2.1G - - category: libretexts - filename: libretexts.org_en_chem_2025-01.zim # 2.0G - - category: libretexts - filename: libretexts.org_en_eng_2025-01.zim # 647M - - category: libretexts - filename: libretexts.org_en_math_2025-01.zim # 744M - - category: libretexts - filename: libretexts.org_en_phys_2025-01.zim # 464M - - category: libretexts - filename: libretexts.org_en_human_2025-01.zim # 3.5G - - # DevDocs - Programming documentation - - category: devdocs - filename: devdocs_en_bash_2026-01.zim - - category: devdocs - filename: devdocs_en_c_2026-01.zim - - category: devdocs - filename: devdocs_en_click_2026-01.zim - - category: devdocs - filename: devdocs_en_cmake_2026-01.zim - - category: devdocs - filename: devdocs_en_cpp_2026-01.zim - - category: devdocs - filename: devdocs_en_css_2026-01.zim - - category: devdocs - filename: devdocs_en_django-rest-framework_2026-01.zim - - category: devdocs - filename: devdocs_en_django_2026-01.zim - - category: devdocs - filename: devdocs_en_docker_2026-01.zim - - category: devdocs - filename: devdocs_en_duckdb_2026-01.zim - - category: devdocs - filename: devdocs_en_fish_2026-01.zim - - category: devdocs - filename: devdocs_en_gcc_2026-01.zim - - category: devdocs - filename: devdocs_en_git_2026-01.zim - - category: devdocs - filename: devdocs_en_go_2026-01.zim - - category: devdocs - filename: devdocs_en_godot_2026-01.zim - - category: devdocs - filename: devdocs_en_hammerspoon_2026-01.zim - - category: devdocs - filename: devdocs_en_homebrew_2026-01.zim - - category: devdocs - filename: devdocs_en_javascript_2026-01.zim - - category: devdocs - filename: devdocs_en_kubectl_2026-01.zim - - category: devdocs - filename: devdocs_en_kubernetes_2026-01.zim - - category: devdocs - filename: devdocs_en_latex_2026-01.zim - - category: devdocs - filename: devdocs_en_lua_2026-01.zim - - category: devdocs - filename: devdocs_en_markdown_2026-01.zim - - category: devdocs - filename: devdocs_en_nginx_2026-01.zim - - category: devdocs - filename: devdocs_en_nix_2026-01.zim - - category: devdocs - filename: devdocs_en_postgresql_2026-01.zim - - category: devdocs - filename: devdocs_en_python_2026-01.zim - - category: devdocs - filename: devdocs_en_redis_2026-01.zim - - category: devdocs - filename: devdocs_en_sqlite_2026-01.zim - - category: devdocs - filename: devdocs_en_typescript_2026-01.zim - - category: devdocs - filename: devdocs_en_werkzeug_2026-01.zim - - category: devdocs - filename: devdocs_en_zig_2026-01.zim diff --git a/ansible/roles/kiwix/handlers/main.yml b/ansible/roles/kiwix/handlers/main.yml deleted file mode 100644 index ef6e408..0000000 --- a/ansible/roles/kiwix/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Restart kiwix-serve - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist - changed_when: true diff --git a/ansible/roles/kiwix/meta/main.yml b/ansible/roles/kiwix/meta/main.yml deleted file mode 100644 index b05a43b..0000000 --- a/ansible/roles/kiwix/meta/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -# Role ordering is controlled by indri.yml playbook - do not add dependencies here -# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies) -dependencies: [] diff --git a/ansible/roles/kiwix/tasks/main.yml b/ansible/roles/kiwix/tasks/main.yml deleted file mode 100644 index 85a09a2..0000000 --- a/ansible/roles/kiwix/tasks/main.yml +++ /dev/null @@ -1,119 +0,0 @@ ---- -- name: Ensure kiwix ZIM directory exists - ansible.builtin.file: - path: "{{ kiwix_zim_dir }}" - state: directory - mode: '0755' - -- name: Ensure kiwix bin directory exists - ansible.builtin.file: - path: "{{ kiwix_bin_dir }}" - state: directory - mode: '0755' - -# --- Deploy management scripts --- -- name: Deploy kiwix torrent sync script - ansible.builtin.template: - src: kiwix-sync-torrents.sh.j2 - dest: "{{ kiwix_bin_dir }}/kiwix-sync-torrents.sh" - mode: '0755' - when: kiwix_use_transmission - -- name: Deploy kiwix symlink script - ansible.builtin.template: - src: kiwix-symlink-zims.sh.j2 - dest: "{{ kiwix_bin_dir }}/kiwix-symlink-zims.sh" - mode: '0755' - when: kiwix_use_transmission - -- name: Deploy kiwix torrent list - ansible.builtin.template: - src: kiwix-torrents.txt.j2 - dest: "{{ kiwix_bin_dir }}/kiwix-torrents.txt" - mode: '0644' - when: kiwix_use_transmission - -# --- Transmission-based torrent management --- -- name: Check transmission daemon is responding - ansible.builtin.command: transmission-remote -l - register: kiwix_transmission_check - changed_when: false - failed_when: false - when: kiwix_use_transmission - -- name: Fail if transmission is not running - ansible.builtin.fail: - msg: "Transmission daemon is not responding. Ensure transmission role ran successfully." - when: kiwix_use_transmission and kiwix_transmission_check.rc != 0 - -- name: Sync ZIM torrents to transmission - ansible.builtin.command: "{{ kiwix_bin_dir }}/kiwix-sync-torrents.sh {{ kiwix_bin_dir }}/kiwix-torrents.txt" - register: kiwix_torrent_sync - changed_when: "'Added:' in kiwix_torrent_sync.stdout" - when: kiwix_use_transmission - -# --- Symlink completed ZIM files --- -- name: Symlink completed ZIM files to kiwix directory - ansible.builtin.command: "{{ kiwix_bin_dir }}/kiwix-symlink-zims.sh {{ transmission_download_dir }} {{ kiwix_zim_dir }}" - register: kiwix_symlink_result - changed_when: "'Linked:' in kiwix_symlink_result.stdout" - when: kiwix_use_transmission - notify: Restart kiwix-serve - -# --- Fallback: Direct HTTP download (original behavior) --- -- name: Check which ZIM archives exist (direct download mode) - ansible.builtin.stat: - path: "{{ kiwix_zim_dir }}/{{ item.filename }}" - get_checksum: false - loop: "{{ kiwix_zim_archives }}" - loop_control: - label: "{{ item.filename }}" - register: kiwix_zim_stat - when: not kiwix_use_transmission - -- name: Download missing ZIM archives (direct download mode) - ansible.builtin.get_url: - url: "https://download.kiwix.org/zim/{{ item.item.category }}/{{ item.item.filename }}" - dest: "{{ kiwix_zim_dir }}/{{ item.item.filename }}" - mode: '0644' - timeout: 3600 - loop: "{{ kiwix_zim_stat.results | default([]) }}" - loop_control: - label: "{{ item.item.filename | default('unknown') }}" - when: - - not kiwix_use_transmission - - item.stat is defined - - not item.stat.exists - notify: Restart kiwix-serve - -# --- Determine which archives are available --- -- name: Find available ZIM archives in kiwix directory - ansible.builtin.find: - paths: "{{ kiwix_zim_dir }}" - patterns: "*.zim" - file_type: any # includes symlinks - register: kiwix_available_zim_files - -- name: Build list of available archive filenames - ansible.builtin.set_fact: - kiwix_available_archives: "{{ kiwix_available_zim_files.files | map(attribute='path') | map('basename') | list }}" - -# --- LaunchAgent deployment --- -- name: Deploy kiwix-serve LaunchAgent plist - ansible.builtin.template: - src: kiwix-serve.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist - mode: '0644' - notify: Restart kiwix-serve - -- name: Check if kiwix-serve LaunchAgent is loaded - ansible.builtin.command: launchctl list mcquack.eblume.kiwix-serve - register: kiwix_launchctl_check - changed_when: false - failed_when: false - -- name: Load kiwix-serve LaunchAgent if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist - when: kiwix_launchctl_check.rc != 0 - changed_when: true - failed_when: false diff --git a/ansible/roles/kiwix/templates/kiwix-serve.plist.j2 b/ansible/roles/kiwix/templates/kiwix-serve.plist.j2 deleted file mode 100644 index 26a61d1..0000000 --- a/ansible/roles/kiwix/templates/kiwix-serve.plist.j2 +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - KeepAlive - - Label - mcquack.eblume.kiwix-serve - ProgramArguments - - {{ kiwix_serve_bin }} - --port={{ kiwix_port }} -{% for filename in kiwix_available_archives %} - {{ kiwix_zim_dir }}/{{ filename }} -{% endfor %} - - RunAtLoad - - StandardErrorPath - {{ kiwix_log_dir }}/mcquack.kiwix-serve.err.log - StandardOutPath - {{ kiwix_log_dir }}/mcquack.kiwix-serve.out.log - - diff --git a/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2 b/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2 deleted file mode 100644 index 29e7630..0000000 --- a/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2 +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# Symlink completed ZIM files from download directory to kiwix directory -set -euo pipefail - -SOURCE_DIR="${1:-}" -TARGET_DIR="${2:-}" - -if [[ -z "$SOURCE_DIR" || -z "$TARGET_DIR" ]]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -if [[ ! -d "$SOURCE_DIR" ]]; then - echo "Error: Source directory not found: $SOURCE_DIR" >&2 - exit 1 -fi - -if [[ ! -d "$TARGET_DIR" ]]; then - echo "Error: Target directory not found: $TARGET_DIR" >&2 - exit 1 -fi - -created=0 -skipped=0 - -# Find all .zim files in source directory -for zim_file in "$SOURCE_DIR"/*.zim; do - # Handle case where no .zim files exist - [[ -e "$zim_file" ]] || continue - - filename=$(basename "$zim_file") - target_path="$TARGET_DIR/$filename" - - if [[ -e "$target_path" || -L "$target_path" ]]; then - ((skipped++)) || true - else - ln -s "$zim_file" "$target_path" - echo "Linked: $filename" - ((created++)) || true - fi -done - -echo "Symlink complete: $created created, $skipped already present" - -# Exit with special code if new symlinks were created (for ansible changed detection) -if [[ $created -gt 0 ]]; then - exit 0 -else - exit 0 -fi diff --git a/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2 b/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2 deleted file mode 100644 index 4a293b3..0000000 --- a/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2 +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# Sync ZIM archive torrents to transmission -# Reads torrent URLs from stdin or file, adds any missing to transmission -set -euo pipefail - -TORRENT_LIST="${1:-}" - -if [[ -z "$TORRENT_LIST" ]]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -if [[ ! -f "$TORRENT_LIST" ]]; then - echo "Error: Torrent list file not found: $TORRENT_LIST" >&2 - exit 1 -fi - -# Get current torrents from transmission (extract names, skip header/footer) -# Note: Use sed '$d' instead of head -n -1 for macOS compatibility -current_torrents=$(transmission-remote -l 2>/dev/null | tail -n +2 | sed '$d' | awk '{print $NF}' || true) - -added=0 -skipped=0 - -while IFS= read -r torrent_url || [[ -n "$torrent_url" ]]; do - # Skip empty lines and comments - [[ -z "$torrent_url" || "$torrent_url" =~ ^# ]] && continue - - # Extract base name from URL (remove .torrent extension and path) - base_name=$(basename "$torrent_url" .torrent) - # Also try without .zim in case transmission reports it differently - base_without_zim="${base_name%.zim}" - - # Check if already in transmission - if echo "$current_torrents" | grep -qF "$base_without_zim"; then - ((skipped++)) || true - else - if transmission-remote -a "$torrent_url" 2>/dev/null; then - echo "Added: $base_name" - ((added++)) || true - else - echo "Warning: Failed to add $torrent_url" >&2 - fi - fi -done < "$TORRENT_LIST" - -echo "Sync complete: $added added, $skipped already present" diff --git a/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2 b/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2 deleted file mode 100644 index fcc4b4e..0000000 --- a/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2 +++ /dev/null @@ -1,5 +0,0 @@ -# ZIM archive torrent URLs for kiwix -# Generated by ansible - do not edit manually -{% for archive in kiwix_zim_archives %} -{{ kiwix_torrent_base_url }}/{{ archive.category }}/{{ archive.filename }}.torrent -{% endfor %} diff --git a/ansible/roles/node_exporter/defaults/main.yml b/ansible/roles/node_exporter/defaults/main.yml deleted file mode 100644 index a8f3e63..0000000 --- a/ansible/roles/node_exporter/defaults/main.yml +++ /dev/null @@ -1,2 +0,0 @@ ---- -node_exporter_textfile_dir: /opt/homebrew/var/node_exporter/textfile diff --git a/ansible/roles/node_exporter/handlers/main.yml b/ansible/roles/node_exporter/handlers/main.yml deleted file mode 100644 index fa0c59b..0000000 --- a/ansible/roles/node_exporter/handlers/main.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -- name: Restart node_exporter - ansible.builtin.command: brew services restart node_exporter - listen: Restart node_exporter - changed_when: true diff --git a/ansible/roles/node_exporter/tasks/main.yml b/ansible/roles/node_exporter/tasks/main.yml deleted file mode 100644 index 55c0398..0000000 --- a/ansible/roles/node_exporter/tasks/main.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -# Note: node_exporter is installed via homebrew manually. -# This role manages the args file to enable textfile collector. - -- name: Create textfile collector directory - ansible.builtin.file: - path: "{{ node_exporter_textfile_dir }}" - state: directory - mode: '0755' - -- name: Configure node_exporter args - ansible.builtin.template: - src: node_exporter.args.j2 - dest: /opt/homebrew/etc/node_exporter.args - mode: '0644' - notify: Restart node_exporter - -- name: Ensure node_exporter service is started - ansible.builtin.command: brew services start node_exporter - register: node_exporter_brew_start - changed_when: "'Successfully started' in node_exporter_brew_start.stdout" - failed_when: false diff --git a/ansible/roles/node_exporter/templates/node_exporter.args.j2 b/ansible/roles/node_exporter/templates/node_exporter.args.j2 deleted file mode 100644 index be763d0..0000000 --- a/ansible/roles/node_exporter/templates/node_exporter.args.j2 +++ /dev/null @@ -1 +0,0 @@ ---collector.textfile.directory={{ node_exporter_textfile_dir }} diff --git a/ansible/roles/podman/handlers/main.yml b/ansible/roles/podman/handlers/main.yml deleted file mode 100644 index 89a6a94..0000000 --- a/ansible/roles/podman/handlers/main.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -# No handlers currently - podman machine start is unreliable via Ansible -# See known issue in tasks/main.yml diff --git a/ansible/roles/podman/tasks/main.yml b/ansible/roles/podman/tasks/main.yml deleted file mode 100644 index e1bb78f..0000000 --- a/ansible/roles/podman/tasks/main.yml +++ /dev/null @@ -1,58 +0,0 @@ ---- -# Podman installation and machine setup for indri -# Used as container runtime for minikube -# -# KNOWN ISSUE: podman machine init/start has reliability issues when run via -# Ansible/SSH. The machine sometimes gets stuck in "Starting" state due to a -# race condition (see https://github.com/containers/podman/issues/16945). -# Additionally, Apple Hypervisor may require GUI session context. -# -# WORKAROUND: If the machine fails to start via Ansible, manually run on indri: -# podman machine rm -f podman-machine-default -# podman machine init --cpus 4 --memory 8192 --disk-size 220 -# podman machine start -# -# TODO: Investigate proper LaunchAgent or other solution for reliable automation. - -- name: Install podman via homebrew - community.general.homebrew: - name: podman - state: present - -- name: Check if podman machine exists - ansible.builtin.command: - cmd: podman machine list --format json - register: podman_machine_list - changed_when: false - check_mode: false # Safe to run in check mode - read-only - -- name: Initialize podman machine (if not exists) - ansible.builtin.command: - cmd: podman machine init --cpus 4 --memory 8192 --disk-size 220 - register: podman_init - changed_when: podman_init.rc == 0 - failed_when: podman_init.rc not in [0, 125] # 125 = already exists - when: podman_machine_list.stdout == '[]' - -- name: Check if podman machine is running - ansible.builtin.command: - cmd: podman machine list --format "{{ '{{' }}.Running{{ '}}' }}" - register: podman_running - changed_when: false - check_mode: false # Safe to run in check mode - read-only - -- name: Start podman machine (if stopped) - ansible.builtin.command: - cmd: podman machine start - register: podman_start - changed_when: "'started successfully' in podman_start.stdout" - failed_when: false # Don't fail - see known issue above - when: "'true' not in podman_running.stdout" - -- name: Warn if podman machine failed to start - ansible.builtin.debug: - msg: "WARNING: podman machine may not have started. Run 'podman machine start' manually on indri if needed." - when: - - "'true' not in podman_running.stdout" - - podman_start is defined - - podman_start.rc != 0 or "'started successfully' not in podman_start.stdout" diff --git a/ansible/roles/transmission/defaults/main.yml b/ansible/roles/transmission/defaults/main.yml deleted file mode 100644 index 6eb9391..0000000 --- a/ansible/roles/transmission/defaults/main.yml +++ /dev/null @@ -1,24 +0,0 @@ ---- -# Homebrew's transmission-cli service uses this config directory -transmission_config_dir: /opt/homebrew/var/transmission - -# Download directories -transmission_download_dir: /Users/erichblume/transmission -transmission_incomplete_dir: /Users/erichblume/transmission/.incomplete - -# RPC settings (local only - no authentication needed) -transmission_rpc_enabled: true -transmission_rpc_port: 9091 -transmission_rpc_bind_address: "127.0.0.1" -transmission_rpc_authentication_required: false -transmission_rpc_whitelist_enabled: true -transmission_rpc_whitelist: "127.0.0.1" - -# Speed limits (KB/s, 0 = unlimited) -transmission_speed_limit_down: 0 -transmission_speed_limit_up: 100 - -# P2P settings -transmission_dht_enabled: true -transmission_pex_enabled: true -transmission_encryption: 1 # 0=prefer unencrypted, 1=prefer encrypted, 2=require encrypted diff --git a/ansible/roles/transmission/handlers/main.yml b/ansible/roles/transmission/handlers/main.yml deleted file mode 100644 index db948a4..0000000 --- a/ansible/roles/transmission/handlers/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -- name: Restart transmission - ansible.builtin.command: brew services restart transmission-cli - changed_when: true diff --git a/ansible/roles/transmission/tasks/main.yml b/ansible/roles/transmission/tasks/main.yml deleted file mode 100644 index f264b0d..0000000 --- a/ansible/roles/transmission/tasks/main.yml +++ /dev/null @@ -1,52 +0,0 @@ ---- -- name: Install transmission-cli via homebrew - community.general.homebrew: - name: transmission-cli - state: present - -- name: Ensure transmission download directory exists - ansible.builtin.file: - path: "{{ transmission_download_dir }}" - state: directory - mode: '0755' - -- name: Ensure transmission incomplete directory exists - ansible.builtin.file: - path: "{{ transmission_incomplete_dir }}" - state: directory - mode: '0755' - -- name: Remove old config directory (was deployed to wrong location) - ansible.builtin.file: - path: ~/.config/transmission-daemon - state: absent - -# Note: transmission must be stopped before modifying settings.json -# otherwise it may overwrite our changes on shutdown -- name: Check if settings.json needs updating - ansible.builtin.template: - src: settings.json.j2 - dest: "{{ transmission_config_dir }}/settings.json" - mode: '0600' - check_mode: true - register: transmission_settings_check - -- name: Stop transmission before config changes - ansible.builtin.command: brew services stop transmission-cli - when: transmission_settings_check.changed - register: transmission_brew_stop - changed_when: false - failed_when: false - -- name: Deploy transmission settings.json - ansible.builtin.template: - src: settings.json.j2 - dest: "{{ transmission_config_dir }}/settings.json" - mode: '0600' - notify: Restart transmission - -- name: Ensure transmission service is started - ansible.builtin.command: brew services start transmission-cli - register: transmission_brew_start - changed_when: "'Successfully started' in transmission_brew_start.stdout" - failed_when: false diff --git a/ansible/roles/transmission/templates/settings.json.j2 b/ansible/roles/transmission/templates/settings.json.j2 deleted file mode 100644 index 36b0513..0000000 --- a/ansible/roles/transmission/templates/settings.json.j2 +++ /dev/null @@ -1,89 +0,0 @@ -{# - RPC is required for transmission-remote CLI to manage torrents. - Config is secure: bound to localhost only, no auth needed. - - rpc-password uses a static hash starting with '{' so transmission - recognizes it as pre-hashed and won't regenerate it on restart. - Without this, transmission writes a new hash each startup causing - perpetual ansible diffs. -#} -{ - "_comment": "{{ ansible_managed }}", - "alt-speed-down": 50, - "alt-speed-enabled": false, - "alt-speed-time-begin": 540, - "alt-speed-time-day": 127, - "alt-speed-time-enabled": false, - "alt-speed-time-end": 1020, - "alt-speed-up": 50, - "announce-ip": "", - "announce-ip-enabled": false, - "anti-brute-force-enabled": false, - "anti-brute-force-threshold": 100, - "bind-address-ipv4": "0.0.0.0", - "bind-address-ipv6": "::", - "blocklist-enabled": false, - "blocklist-url": "http://www.example.com/blocklist", - "cache-size-mb": 4, - "default-trackers": "", - "dht-enabled": {{ transmission_dht_enabled | lower }}, - "download-dir": "{{ transmission_download_dir }}", - "download-queue-enabled": true, - "download-queue-size": 5, - "encryption": {{ transmission_encryption }}, - "idle-seeding-limit": 30, - "idle-seeding-limit-enabled": false, - "incomplete-dir": "{{ transmission_incomplete_dir }}", - "incomplete-dir-enabled": true, - "lpd-enabled": true, - "message-level": 4, - "peer-congestion-algorithm": "", - "peer-limit-global": 200, - "peer-limit-per-torrent": 50, - "peer-port": 51413, - "peer-port-random-high": 65535, - "peer-port-random-low": 49152, - "peer-port-random-on-start": false, - "peer-socket-tos": "le", - "pex-enabled": {{ transmission_pex_enabled | lower }}, - "port-forwarding-enabled": true, - "preallocation": 1, - "prefetch-enabled": true, - "queue-stalled-enabled": true, - "queue-stalled-minutes": 30, - "ratio-limit": 2, - "ratio-limit-enabled": false, - "rename-partial-files": false, - "rpc-authentication-required": {{ transmission_rpc_authentication_required | lower }}, - "rpc-bind-address": "{{ transmission_rpc_bind_address }}", - "rpc-enabled": {{ transmission_rpc_enabled | lower }}, - "rpc-host-whitelist": "", - "rpc-host-whitelist-enabled": true, - "rpc-password": "{00000000000000000000000000000000000000000000000e", - "rpc-port": {{ transmission_rpc_port }}, - "rpc-socket-mode": "0750", - "rpc-url": "/transmission/", - "rpc-username": "", - "rpc-whitelist": "{{ transmission_rpc_whitelist }}", - "rpc-whitelist-enabled": {{ transmission_rpc_whitelist_enabled | lower }}, - "scrape-paused-torrents-enabled": true, - "script-torrent-added-enabled": false, - "script-torrent-added-filename": "", - "script-torrent-done-enabled": false, - "script-torrent-done-filename": "", - "script-torrent-done-seeding-enabled": false, - "script-torrent-done-seeding-filename": "", - "seed-queue-enabled": false, - "seed-queue-size": 10, - "speed-limit-down": {{ transmission_speed_limit_down }}, - "speed-limit-down-enabled": {{ (transmission_speed_limit_down > 0) | lower }}, - "speed-limit-up": {{ transmission_speed_limit_up }}, - "speed-limit-up-enabled": {{ (transmission_speed_limit_up > 0) | lower }}, - "start-added-torrents": true, - "tcp-enabled": true, - "torrent-added-verify-mode": "fast", - "trash-original-torrent-files": false, - "umask": "022", - "upload-slots-per-torrent": 8, - "utp-enabled": true -} diff --git a/ansible/roles/transmission_metrics/defaults/main.yml b/ansible/roles/transmission_metrics/defaults/main.yml deleted file mode 100644 index 9e9e2b0..0000000 --- a/ansible/roles/transmission_metrics/defaults/main.yml +++ /dev/null @@ -1,7 +0,0 @@ ---- -transmission_metrics_rpc_host: 127.0.0.1 -transmission_metrics_rpc_port: 9091 -transmission_metrics_dir: /opt/homebrew/var/node_exporter/textfile -transmission_metrics_script: /Users/erichblume/bin/transmission-metrics -transmission_metrics_interval: 60 # seconds between metric collection -transmission_metrics_log_dir: /opt/homebrew/var/log diff --git a/ansible/roles/transmission_metrics/handlers/main.yml b/ansible/roles/transmission_metrics/handlers/main.yml deleted file mode 100644 index 5e4d922..0000000 --- a/ansible/roles/transmission_metrics/handlers/main.yml +++ /dev/null @@ -1,6 +0,0 @@ ---- -- name: Reload transmission-metrics - ansible.builtin.shell: | - launchctl unload ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist 2>/dev/null || true - launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist - changed_when: true diff --git a/ansible/roles/transmission_metrics/meta/main.yml b/ansible/roles/transmission_metrics/meta/main.yml deleted file mode 100644 index b05a43b..0000000 --- a/ansible/roles/transmission_metrics/meta/main.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -# Role ordering is controlled by indri.yml playbook - do not add dependencies here -# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies) -dependencies: [] diff --git a/ansible/roles/transmission_metrics/tasks/main.yml b/ansible/roles/transmission_metrics/tasks/main.yml deleted file mode 100644 index 31323c9..0000000 --- a/ansible/roles/transmission_metrics/tasks/main.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -- name: Deploy transmission metrics collection script - ansible.builtin.template: - src: transmission-metrics.sh.j2 - dest: "{{ transmission_metrics_script }}" - mode: '0755' - notify: Reload transmission-metrics - -- name: Deploy transmission-metrics LaunchAgent plist - ansible.builtin.template: - src: transmission-metrics.plist.j2 - dest: ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist - mode: '0644' - notify: Reload transmission-metrics - -- name: Check if transmission-metrics LaunchAgent is loaded - ansible.builtin.command: launchctl list mcquack.eblume.transmission-metrics - register: transmission_metrics_launchctl_check - changed_when: false - failed_when: false - -- name: Load transmission-metrics LaunchAgent if not loaded - ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist - when: transmission_metrics_launchctl_check.rc != 0 - changed_when: true - failed_when: false diff --git a/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2 b/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2 deleted file mode 100644 index a68e0c8..0000000 --- a/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2 +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - Label - mcquack.eblume.transmission-metrics - EnvironmentVariables - - PATH - /opt/homebrew/bin:/usr/bin:/bin - - ProgramArguments - - {{ transmission_metrics_script }} - - StartInterval - {{ transmission_metrics_interval }} - RunAtLoad - - StandardErrorPath - {{ transmission_metrics_log_dir }}/transmission-metrics.err.log - StandardOutPath - {{ transmission_metrics_log_dir }}/transmission-metrics.out.log - - diff --git a/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2 b/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2 deleted file mode 100644 index 0e394af..0000000 --- a/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2 +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash -# {{ ansible_managed }} -# Collects transmission-daemon metrics for node_exporter textfile collector - -set -euo pipefail - -RPC_URL="http://{{ transmission_metrics_rpc_host }}:{{ transmission_metrics_rpc_port }}/transmission/rpc" -OUTPUT_FILE="{{ transmission_metrics_dir }}/transmission.prom" -TEMP_FILE="${OUTPUT_FILE}.tmp" - -# Get session ID (required for transmission RPC) -# Note: transmission doesn't support HEAD requests, so we make a request and parse -# the 409 response headers. We use sed to stop at the blank line (which has \r) before body. -get_session_id() { - curl -s -i "$RPC_URL" 2>/dev/null | sed '/^\r$/q' | grep -i '^X-Transmission-Session-Id:' | awk '{print $2}' | tr -d '\r' -} - -# Make RPC request -rpc_request() { - local method="$1" - local args="${2:-}" - local session_id - session_id=$(get_session_id) - - if [ -z "$session_id" ]; then - echo "Failed to get session ID" >&2 - return 1 - fi - - local payload - if [ -n "$args" ]; then - payload="{\"method\": \"$method\", \"arguments\": $args}" - else - payload="{\"method\": \"$method\"}" - fi - - curl -s "$RPC_URL" \ - -H "X-Transmission-Session-Id: $session_id" \ - -H "Content-Type: application/json" \ - -d "$payload" -} - -# Get session stats -session_stats=$(rpc_request "session-stats") - -if [ -z "$session_stats" ] || ! echo "$session_stats" | grep -q '"result":"success"'; then - echo "Failed to get session stats" >&2 - exit 1 -fi - -# Extract values using grep/sed (avoiding jq dependency) -extract_json_int() { - echo "$1" | grep -o "\"$2\":[0-9]*" | head -1 | sed "s/\"$2\"://" -} - -# Session stats -download_speed=$(extract_json_int "$session_stats" "downloadSpeed") -upload_speed=$(extract_json_int "$session_stats" "uploadSpeed") -torrents_active=$(extract_json_int "$session_stats" "activeTorrentCount") -torrents_paused=$(extract_json_int "$session_stats" "pausedTorrentCount") -torrents_total=$(extract_json_int "$session_stats" "torrentCount") - -# Cumulative stats -downloaded_bytes=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"downloadedBytes":[0-9]*' | sed 's/"downloadedBytes"://') -uploaded_bytes=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"uploadedBytes":[0-9]*' | sed 's/"uploadedBytes"://') -seconds_active=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"secondsActive":[0-9]*' | sed 's/"secondsActive"://') - -# Get total size of all torrents -torrent_info=$(rpc_request "torrent-get" '{"fields": ["totalSize"]}') -total_size_bytes=0 -if echo "$torrent_info" | grep -q '"result":"success"'; then - # Sum all totalSize values - total_size_bytes=$(echo "$torrent_info" | grep -o '"totalSize":[0-9]*' | sed 's/"totalSize"://' | awk '{sum += $1} END {print sum}') -fi - -# Write metrics -cat > "$TEMP_FILE" << EOF -# HELP transmission_download_speed_bytes Current download speed in bytes per second -# TYPE transmission_download_speed_bytes gauge -transmission_download_speed_bytes ${download_speed:-0} - -# HELP transmission_upload_speed_bytes Current upload speed in bytes per second -# TYPE transmission_upload_speed_bytes gauge -transmission_upload_speed_bytes ${upload_speed:-0} - -# HELP transmission_torrents_active Number of active torrents -# TYPE transmission_torrents_active gauge -transmission_torrents_active ${torrents_active:-0} - -# HELP transmission_torrents_paused Number of paused torrents -# TYPE transmission_torrents_paused gauge -transmission_torrents_paused ${torrents_paused:-0} - -# HELP transmission_torrents_total Total number of torrents -# TYPE transmission_torrents_total gauge -transmission_torrents_total ${torrents_total:-0} - -# HELP transmission_torrents_size_bytes Total size of all torrents in bytes -# TYPE transmission_torrents_size_bytes gauge -transmission_torrents_size_bytes ${total_size_bytes:-0} - -# HELP transmission_downloaded_bytes_total Total bytes downloaded (cumulative) -# TYPE transmission_downloaded_bytes_total counter -transmission_downloaded_bytes_total ${downloaded_bytes:-0} - -# HELP transmission_uploaded_bytes_total Total bytes uploaded (cumulative) -# TYPE transmission_uploaded_bytes_total counter -transmission_uploaded_bytes_total ${uploaded_bytes:-0} - -# HELP transmission_seconds_active_total Total seconds transmission has been active -# TYPE transmission_seconds_active_total counter -transmission_seconds_active_total ${seconds_active:-0} - -# HELP transmission_up Transmission daemon is up and responding -# TYPE transmission_up gauge -transmission_up 1 -EOF - -# Atomic move -mv "$TEMP_FILE" "$OUTPUT_FILE" diff --git a/argocd/apps/kiwix.yaml b/argocd/apps/kiwix.yaml index d69da7c..70be2c1 100644 --- a/argocd/apps/kiwix.yaml +++ b/argocd/apps/kiwix.yaml @@ -16,3 +16,9 @@ spec: syncPolicy: syncOptions: - CreateNamespace=true + # Ignore zim-hash annotation - updated dynamically by zim-watcher CronJob + ignoreDifferences: + - group: apps + kind: Deployment + jsonPointers: + - /metadata/annotations/kiwix.blumeops~1zim-hash diff --git a/pulumi/__main__.py b/pulumi/__main__.py index 0a08ee8..7c76c26 100644 --- a/pulumi/__main__.py +++ b/pulumi/__main__.py @@ -36,7 +36,8 @@ acl = tailscale.Acl( # Tags control access via the ACL policy in policy.hujson. # indri - Mac Mini M1, primary homelab server -# Hosts all user-facing services (grafana, forge, kiwix, etc.) +# Hosts forge, loki, zot registry, and the k8s control plane. +# Other services (grafana, kiwix, devpi, etc.) run in k8s with their own Tailscale devices. indri = tailscale.get_device(name="indri.tail8d86e.ts.net") indri_tags = tailscale.DeviceTags( "indri-tags", @@ -44,16 +45,11 @@ indri_tags = tailscale.DeviceTags( tags=[ "tag:homelab", # Server role - allows SSH from workstations "tag:blumeops", # Managed by this IaC - # Service tags - enable fine-grained access control per service - "tag:grafana", + # Service tags for services still hosted directly on indri "tag:forge", - "tag:kiwix", - "tag:devpi", "tag:loki", - "tag:pg", - "tag:feed", "tag:registry", # Zot container registry - "tag:k8s-api", # Kubernetes API server + "tag:k8s-api", # Kubernetes API server (minikube) ], )