# homelab-docs-services.nix - Service documentation generator CLI { writeShellScriptBin, jq, }: writeShellScriptBin "homelab-docs-services" '' #!/usr/bin/env bash set -euo pipefail cat << 'EOF' # Service Catalog > Available services and their configuration options > > Generated on: $(date) This document catalogs all available homelab services, their configuration options, and integration capabilities. EOF # Get all services and their configurations services_catalog=$(colmena eval -E '{ nodes, pkgs, lib, ... }: let # Collect all services from all nodes to build a complete catalog allServiceConfigs = lib.flatten (lib.mapAttrsToList (nodeName: node: if (node.config.homelab.enable or false) then lib.mapAttrsToList (serviceName: service: { inherit serviceName; config = { # Core service options enable = service.enable or false; port = service.port or null; description = service.description or serviceName; tags = service.tags or []; # Integration options monitoring = { enabled = service.monitoring.enable or false; metricsPath = service.monitoring.metrics.path or "/metrics"; healthPath = service.monitoring.healthCheck.path or "/health"; extraLabels = service.monitoring.extraLabels or {}; }; logging = { enabled = service.logging.enable or false; files = service.logging.files or []; extraLabels = service.logging.extraLabels or {}; }; proxy = { enabled = service.proxy.enable or false; subdomain = service.proxy.subdomain or serviceName; enableAuth = service.proxy.enableAuth or false; }; # Service-specific options (everything else) serviceSpecific = removeAttrs service [ "enable" "port" "description" "tags" "monitoring" "logging" "proxy" ]; }; deployedOn = nodeName; }) (node.config.homelab.services or {}) else [] ) nodes); # Group by service name and merge configurations serviceGroups = lib.groupBy (svc: svc.serviceName) allServiceConfigs; # Get unique services with merged configuration examples uniqueServices = lib.mapAttrs (serviceName: instances: let # Take the first enabled instance as the canonical example enabledInstances = lib.filter (inst: inst.config.enable) instances; canonicalConfig = if enabledInstances != [] then (lib.head enabledInstances).config else (lib.head instances).config; in { inherit serviceName; config = canonicalConfig; deploymentCount = lib.length (lib.filter (inst: inst.config.enable) instances); deployedOn = lib.unique (map (inst: inst.deployedOn or "unknown") enabledInstances); } ) serviceGroups; in { services = uniqueServices; totalUniqueServices = lib.length (lib.attrNames uniqueServices); }') total_services=$(echo "$services_catalog" | ${jq}/bin/jq -r '.totalUniqueServices') echo "## Overview" echo echo "**Total Available Services:** $total_services" echo # Create a summary table of services and their default integrations echo "## Service Integration Matrix" echo echo "| Service | Monitoring | Logging | Proxy | Auth Default |" echo "|---------|------------|---------|-------|--------------|" echo "$services_catalog" | ${jq}/bin/jq -r '.services | to_entries[] | .key' | sort | while read -r service; do service_data=$(echo "$services_catalog" | ${jq}/bin/jq -r ".services[\"$service\"]") monitoring_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.monitoring.enabled') logging_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.logging.enabled') proxy_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.enabled') auth_default=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.enableAuth') monitoring_icon=$(if [[ "$monitoring_enabled" == "true" ]]; then echo "✅"; else echo "❌"; fi) logging_icon=$(if [[ "$logging_enabled" == "true" ]]; then echo "✅"; else echo "❌"; fi) proxy_icon=$(if [[ "$proxy_enabled" == "true" ]]; then echo "✅"; else echo "❌"; fi) auth_icon=$(if [[ "$auth_default" == "true" ]]; then echo "🔒"; else echo "🌐"; fi) echo "| \`$service\` | $monitoring_icon | $logging_icon | $proxy_icon | $auth_icon |" done echo echo "**Legend:** ✅ = Enabled by default, ❌ = Available but disabled, 🔒 = Auth required, 🌐 = Public access" echo echo "## Service Reference" echo # Process each service echo "$services_catalog" | ${jq}/bin/jq -r '.services | to_entries[] | .key' | sort | while read -r service; do echo "### $service" echo # Get service details service_data=$(echo "$services_catalog" | ${jq}/bin/jq -r ".services[\"$service\"]") description=$(echo "$service_data" | ${jq}/bin/jq -r '.config.description // "No description available"') port=$(echo "$service_data" | ${jq}/bin/jq -r '.config.port // "N/A"') tags=$(echo "$service_data" | ${jq}/bin/jq -r '.config.tags | join(", ")') deployment_count=$(echo "$service_data" | ${jq}/bin/jq -r '.deploymentCount') deployed_on=$(echo "$service_data" | ${jq}/bin/jq -r '.deployedOn | join(", ")') echo "**Description:** $description" echo echo "**Default Port:** \`$port\`" echo if [[ -n "$tags" && "$tags" != "" ]]; then echo "**Tags:** $tags" echo fi echo "**Current Deployments:** $deployment_count instance(s) on: $deployed_on" echo # Integration Status Overview monitoring_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.monitoring.enabled') logging_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.logging.enabled') proxy_enabled=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.enabled') echo "#### Default Integration Status" echo echo "| Integration | Status | Default Configuration |" echo "|-------------|--------|----------------------|" # Monitoring status if [[ "$monitoring_enabled" == "true" ]]; then metrics_path=$(echo "$service_data" | ${jq}/bin/jq -r '.config.monitoring.metricsPath') health_path=$(echo "$service_data" | ${jq}/bin/jq -r '.config.monitoring.healthPath') echo "| 📊 Monitoring | ✅ **Enabled** | Metrics: \`$metrics_path\`, Health: \`$health_path\` |" else echo "| 📊 Monitoring | ❌ Disabled | Available but requires \`monitoring.enable = true\` |" fi # Logging status if [[ "$logging_enabled" == "true" ]]; then log_files=$(echo "$service_data" | ${jq}/bin/jq -r '.config.logging.files | length') if [[ "$log_files" -gt 0 ]]; then echo "| 📝 Logging | ✅ **Enabled** | Collecting $log_files log file(s) |" else echo "| 📝 Logging | ✅ **Enabled** | Auto-configured log collection |" fi else echo "| 📝 Logging | ❌ Disabled | Available but requires \`logging.enable = true\` |" fi # Proxy status if [[ "$proxy_enabled" == "true" ]]; then subdomain=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.subdomain') enable_auth=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.enableAuth') auth_status=$(if [[ "$enable_auth" == "true" ]]; then echo "🔒 Auth required"; else echo "🌐 Public access"; fi) echo "| 🔀 Proxy | ✅ **Enabled** | Subdomain: \`$subdomain\`, $auth_status |" else echo "| 🔀 Proxy | ❌ Disabled | Available but requires \`proxy.enable = true\` |" fi echo # Core Configuration echo "#### Core Configuration" echo echo "\`\`\`nix" echo "homelab.services.$service = {" echo " enable = true;" if [[ "$port" != "N/A" ]]; then echo " port = $port;" fi echo " description = \"$description\";" if [[ -n "$tags" && "$tags" != "" ]]; then echo " tags = [ $(echo "$tags" | sed 's/, /" "/g' | sed 's/^/"/; s/$/"/') ];" fi echo echo " # Default integrations (adjust as needed)" if [[ "$monitoring_enabled" == "true" ]]; then echo " monitoring.enable = true; # ✅ Enabled by default" else echo " # monitoring.enable = true; # ❌ Disabled by default" fi if [[ "$logging_enabled" == "true" ]]; then echo " logging.enable = true; # ✅ Enabled by default" else echo " # logging.enable = true; # ❌ Disabled by default" fi if [[ "$proxy_enabled" == "true" ]]; then echo " proxy.enable = true; # ✅ Enabled by default" else echo " # proxy.enable = true; # ❌ Disabled by default" fi echo "};" echo "\`\`\`" echo # Service-specific options service_specific=$(echo "$service_data" | ${jq}/bin/jq -r '.config.serviceSpecific') if [[ "$service_specific" != "{}" && "$service_specific" != "null" ]]; then echo "#### Service-Specific Options" echo echo "Available configuration options for $service:" echo echo "\`\`\`nix" echo "homelab.services.$service = {" echo " # ... core options above ..." echo echo " # Service-specific configuration" echo "$service_specific" | ${jq}/bin/jq -r 'to_entries[] | " \(.key) = \(.value | tostring);"' echo "};" echo "\`\`\`" echo fi echo "---" echo done echo "## Integration Summary" echo echo "### Available Integration Types" echo echo "| Integration | Purpose | Default Behavior | Configuration |" echo "|-------------|---------|------------------|---------------|" echo "| **📊 Monitoring** | Prometheus metrics + health checks | Service-dependent | \`monitoring.enable = true\` |" echo "| **📝 Logging** | Centralized log collection | Service-dependent | \`logging.enable = true\` |" echo "| **🔀 Proxy** | Reverse proxy with SSL + auth | Service-dependent | \`proxy.enable = true\` |" echo echo "### Integration Benefits" echo echo "- **🔄 Automatic Discovery:** Enabled integrations are automatically discovered by fleet-wide services" echo "- **📊 Unified Monitoring:** All metrics and health checks appear in Prometheus/Grafana" echo "- **📝 Centralized Logging:** All logs are collected and indexed in Loki" echo "- **🌐 Consistent Access:** All services get consistent subdomain access with SSL" echo "- **🎯 Smart Defaults:** Each service comes with sensible default configurations" echo echo "---" echo echo "*This service catalog is generated from actual service configurations across your homelab fleet.*" ''