homelab/pkgs/homelab-docs.nix
plasmagoat ce8c543e84
Some checks failed
Test / tests (push) Has been cancelled
/ OpenTofu (push) Has been cancelled
auto docs
2025-07-29 16:28:17 +02:00

841 lines
30 KiB
Nix
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# homelab-docs.nix - Standalone documentation generator package
{
lib,
stdenv,
writeShellScriptBin,
jq,
nixfmt,
}: let
# Main documentation generator script
docsGenerator = writeShellScriptBin "homelab-generate-docs" ''
#!/usr/bin/env bash
set -euo pipefail
# Colors
BLUE='\033[0;34m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m'
info() { echo -e "''${BLUE}$1''${NC}"; }
success() { echo -e "''${GREEN}$1''${NC}"; }
warn() { echo -e "''${YELLOW}$1''${NC}"; }
error() { echo -e "''${RED}$1''${NC}"; }
# Configuration
DOCS_DIR="''${1:-./docs}"
info "📚 Generating homelab documentation..."
echo " Output directory: $DOCS_DIR"
echo
# Check if we're in a directory with a flake
if [[ ! -f flake.nix ]]; then
error "No flake.nix found in current directory"
echo "Please run this command from your homelab flake directory"
exit 1
fi
# Check if colmena is available
if ! command -v colmena >/dev/null 2>&1; then
error "colmena command not found."
echo "Please ensure colmena is available in your environment"
echo "Add it to your devShell or install it globally"
exit 1
fi
# Create docs directory
mkdir -p "$DOCS_DIR"
# Generate fleet overview
info " 🌐 Generating fleet overview..."
homelab-docs-fleet > "$DOCS_DIR/fleet-overview.md"
# Generate node documentation
info " 🖥 Generating node configurations..."
homelab-docs-nodes > "$DOCS_DIR/nodes.md"
# Generate service documentation
info " Generating service configurations..."
homelab-docs-services > "$DOCS_DIR/services.md"
# Generate current deployment
info " 🏠 Generating current deployment..."
homelab-docs-deployment > "$DOCS_DIR/current-deployment.md"
# Generate README
info " 📋 Generating README..."
homelab-docs-readme > "$DOCS_DIR/README.md"
success " Documentation generated successfully!"
echo
echo "Generated files:"
echo " 🌐 fleet-overview.md - Fleet statistics and overview"
echo " 🖥 nodes.md - Per-node configurations"
echo " services.md - Service configurations"
echo " 🏠 current-deployment.md - Current deployment state"
echo " 📋 README.md - Documentation index"
echo
echo "💡 Tip: Add these files to your repository and set up GitHub Actions"
echo " to automatically regenerate documentation on changes!"
'';
# Fleet overview generator
fleetDocsGenerator = writeShellScriptBin "homelab-docs-fleet" ''
#!/usr/bin/env bash
set -euo pipefail
cat << EOF
# Homelab Fleet Overview
> Auto-generated fleet overview
>
> Generated on: $(date)
> Source: $(pwd)
## Fleet Statistics
EOF
# Get basic fleet stats
echo "### Basic Information"
echo
fleet_stats=$(colmena eval -E '{ nodes, pkgs, lib, ... }: {
totalNodes = lib.length (lib.attrNames nodes);
nodeNames = lib.attrNames nodes;
}')
total_nodes=$(echo "$fleet_stats" | ${jq}/bin/jq -r '.totalNodes')
node_names=$(echo "$fleet_stats" | ${jq}/bin/jq -r '.nodeNames[]' | tr '\n' ' ')
echo "| Metric | Value |"
echo "|--------|-------|"
echo "| Total Nodes | $total_nodes |"
echo "| Node Names | $node_names |"
echo
# Get homelab-enabled nodes
echo "### Homelab Configuration"
echo
homelab_info=$(colmena eval -E '{ nodes, pkgs, lib, ... }: {
homelabNodes = lib.mapAttrs (name: node: {
enabled = node.config.homelab.enable or false;
hostname = node.config.homelab.hostname or null;
environment = node.config.homelab.environment or null;
}) nodes;
}')
echo "| Node | Homelab Enabled | Hostname | Environment |"
echo "|------|----------------|----------|-------------|"
echo "$homelab_info" | ${jq}/bin/jq -r '.homelabNodes | to_entries[] |
[.key, (.value.enabled | tostring), (.value.hostname // "N/A"), (.value.environment // "N/A")] |
@tsv' | while IFS=$'\t' read -r node enabled hostname environment; do
enabled_icon=$(if [[ "$enabled" == "true" ]]; then echo ""; else echo ""; fi)
echo "| \`$node\` | $enabled_icon | $hostname | $environment |"
done
echo
# Get service distribution
echo "### Service Distribution"
echo
service_info=$(colmena eval -E '{ nodes, pkgs, lib, ... }:
lib.mapAttrs (name: node:
if (node.config.homelab.enable or false) then {
serviceCount = lib.length (lib.attrNames (lib.filterAttrs (n: v: v.enable or false) (node.config.homelab.services or {})));
serviceNames = lib.attrNames (lib.filterAttrs (n: v: v.enable or false) (node.config.homelab.services or {}));
} else {
serviceCount = 0;
serviceNames = [];
}
) nodes')
echo "| Node | Service Count | Services |"
echo "|------|---------------|----------|"
echo "$service_info" | ${jq}/bin/jq -r 'to_entries[] |
[.key, (.value.serviceCount | tostring), (.value.serviceNames | join(", "))] |
@tsv' | while IFS=$'\t' read -r node count services; do
echo "| \`$node\` | $count | $services |"
done
echo
# Environment distribution
echo "### Environment Distribution"
echo
env_distribution=$(echo "$homelab_info" | ${jq}/bin/jq -r '
[.homelabNodes | to_entries[] | select(.value.enabled == true) | .value.environment // "unknown"] |
group_by(.) |
map({environment: .[0], count: length}) |
.[]')
if [[ -n "$env_distribution" ]]; then
echo "| Environment | Node Count |"
echo "|-------------|------------|"
echo "$env_distribution" | ${jq}/bin/jq -r '[.environment, (.count | tostring)] | @tsv' | \
while IFS=$'\t' read -r env count; do
echo "| $env | $count |"
done
else
echo "No homelab-enabled nodes found."
fi
echo
echo "---"
echo
echo "*Fleet overview generated from colmena evaluation*"
'';
# Node documentation generator
nodeDocsGenerator = writeShellScriptBin "homelab-docs-nodes" ''
#!/usr/bin/env bash
set -euo pipefail
cat << EOF
# Node Configurations
> Detailed per-node configuration
>
> Generated on: $(date)
EOF
# Get all node information
node_info=$(colmena eval -E '{ nodes, pkgs, lib, ... }:
lib.mapAttrs (name: node: {
# Basic system info
nixosVersion = node.config.system.nixos.version;
hostName = node.config.networking.hostName;
system = node.config.nixpkgs.system;
# Homelab config (safe extraction)
homelab = if (node.config.homelab.enable or false) then {
enabled = true;
hostname = node.config.homelab.hostname or null;
domain = node.config.homelab.domain or null;
externalDomain = node.config.homelab.externalDomain or null;
environment = node.config.homelab.environment or null;
location = node.config.homelab.location or null;
tags = node.config.homelab.tags or [];
} else {
enabled = false;
};
# Services (safe extraction)
services = if (node.config.homelab.enable or false) then
lib.mapAttrs (svcName: svc: {
enabled = svc.enable or false;
port = svc.port or null;
description = svc.description or svcName;
tags = svc.tags or [];
}) (node.config.homelab.services or {})
else {};
}) nodes')
echo "$node_info" | ${jq}/bin/jq -r 'to_entries[] | .key' | while read -r node; do
echo "## Node: $node"
echo
# Basic system information
echo "### System Information"
echo
nixos_version=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].nixosVersion")
hostname=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].hostName")
system=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].system")
echo "| Property | Value |"
echo "|----------|-------|"
echo "| NixOS Version | \`$nixos_version\` |"
echo "| Hostname | \`$hostname\` |"
echo "| System | \`$system\` |"
echo
# Homelab configuration
homelab_enabled=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.enabled")
if [[ "$homelab_enabled" == "true" ]]; then
echo "### Homelab Configuration"
echo
hl_hostname=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.hostname // \"N/A\"")
hl_domain=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.domain // \"N/A\"")
hl_external=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.externalDomain // \"N/A\"")
hl_env=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.environment // \"N/A\"")
hl_location=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.location // \"N/A\"")
hl_tags=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].homelab.tags | join(\", \")")
echo "| Property | Value |"
echo "|----------|-------|"
echo "| Homelab Hostname | \`$hl_hostname\` |"
echo "| Domain | \`$hl_domain\` |"
echo "| External Domain | \`$hl_external\` |"
echo "| Environment | \`$hl_env\` |"
echo "| Location | \`$hl_location\` |"
echo "| Tags | $hl_tags |"
echo
# Services
echo "### Services"
echo
services_data=$(echo "$node_info" | ${jq}/bin/jq -r ".[\"$node\"].services")
service_count=$(echo "$services_data" | ${jq}/bin/jq 'length')
if [[ "$service_count" -gt 0 ]]; then
echo "| Service | Enabled | Port | Description | Tags |"
echo "|---------|---------|------|-------------|------|"
echo "$services_data" | ${jq}/bin/jq -r 'to_entries[] |
[.key, (.value.enabled | tostring), (.value.port // "N/A" | tostring), (.value.description // "N/A"), (.value.tags | join(", "))] |
@tsv' | while IFS=$'\t' read -r service enabled port description tags; do
enabled_icon=$(if [[ "$enabled" == "true" ]]; then echo ""; else echo ""; fi)
echo "| \`$service\` | $enabled_icon | $port | $description | $tags |"
done
else
echo "No services configured."
fi
else
echo "### Homelab Configuration"
echo
echo " Homelab is not enabled on this node."
fi
echo
echo "---"
echo
done
'';
# Service documentation generator - refocused on service capabilities
serviceDocsGenerator = 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;
additionalSubdomains = service.proxy.additionalSubdomains or [];
};
# Service-specific options (everything else)
serviceSpecific = removeAttrs service [
"enable" "port" "description" "tags"
"monitoring" "logging" "proxy"
];
};
}) (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);
availableOn = lib.unique (map (inst: inst.nodeName 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
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')
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)"
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 "\`\`\`"
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
# Integration Options
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')
if [[ "$monitoring_enabled" == "true" || "$logging_enabled" == "true" || "$proxy_enabled" == "true" ]]; then
echo "#### Available Integrations"
echo
fi
# Monitoring Integration
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')
extra_labels=$(echo "$service_data" | ${jq}/bin/jq -r '.config.monitoring.extraLabels')
echo "##### 📊 Monitoring"
echo
echo "- **Metrics Endpoint:** \`$metrics_path\`"
echo "- **Health Check:** \`$health_path\`"
if [[ "$extra_labels" != "{}" ]]; then
echo "- **Default Labels:** $(echo "$extra_labels" | ${jq}/bin/jq -r 'to_entries[] | "\(.key)=\(.value)"' | paste -sd, -)"
fi
echo
echo "\`\`\`nix"
echo "homelab.services.$service.monitoring = {"
echo " enable = true;"
echo " metrics.path = \"$metrics_path\";"
echo " healthCheck.path = \"$health_path\";"
if [[ "$extra_labels" != "{}" ]]; then
echo " extraLabels = $extra_labels;"
fi
echo "};"
echo "\`\`\`"
echo
fi
# Logging Integration
if [[ "$logging_enabled" == "true" ]]; then
log_files=$(echo "$service_data" | ${jq}/bin/jq -r '.config.logging.files[]?')
log_labels=$(echo "$service_data" | ${jq}/bin/jq -r '.config.logging.extraLabels')
echo "##### 📝 Logging"
echo
if [[ -n "$log_files" ]]; then
echo "- **Log Files:**"
echo "$log_files" | while read -r file; do
echo " - \`$file\`"
done
fi
if [[ "$log_labels" != "{}" ]]; then
echo "- **Default Labels:** $(echo "$log_labels" | ${jq}/bin/jq -r 'to_entries[] | "\(.key)=\(.value)"' | paste -sd, -)"
fi
echo
echo "\`\`\`nix"
echo "homelab.services.$service.logging = {"
echo " enable = true;"
if [[ -n "$log_files" ]]; then
echo " files = ["
echo "$log_files" | while read -r file; do
echo " \"$file\""
done
echo " ];"
fi
if [[ "$log_labels" != "{}" ]]; then
echo " extraLabels = $log_labels;"
fi
echo "};"
echo "\`\`\`"
echo
fi
# Proxy Integration
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')
additional_subdomains=$(echo "$service_data" | ${jq}/bin/jq -r '.config.proxy.additionalSubdomains')
echo "##### 🔀 Reverse Proxy"
echo
echo "- **Primary Subdomain:** \`$subdomain\`"
echo "- **Authentication Required:** $(if [[ "$enable_auth" == "true" ]]; then echo " Yes"; else echo " No"; fi)"
if [[ "$additional_subdomains" != "[]" && "$additional_subdomains" != "null" ]]; then
echo "- **Additional Subdomains:** Available"
fi
echo
echo "\`\`\`nix"
echo "homelab.services.$service.proxy = {"
echo " enable = true;"
echo " subdomain = \"$subdomain\";"
echo " enableAuth = $enable_auth;"
if [[ "$additional_subdomains" != "[]" && "$additional_subdomains" != "null" ]]; then
echo " additionalSubdomains = ["
echo " # Configure additional proxy entries as needed"
echo " ];"
fi
echo "};"
echo "\`\`\`"
echo
fi
# Usage Examples
echo "#### Complete Example"
echo
echo "\`\`\`nix"
echo "# Full configuration example for $service"
echo "homelab.services.$service = {"
echo " enable = true;"
if [[ "$port" != "N/A" ]]; then
echo " port = $port;"
fi
echo " description = \"$description\";"
# Add integration examples
if [[ "$monitoring_enabled" == "true" ]]; then
echo " "
echo " # Monitoring integration"
echo " monitoring.enable = true;"
fi
if [[ "$logging_enabled" == "true" ]]; then
echo " "
echo " # Logging integration"
echo " logging.enable = true;"
fi
if [[ "$proxy_enabled" == "true" ]]; then
echo " "
echo " # Reverse proxy integration"
echo " proxy = {"
echo " enable = true;"
echo " subdomain = \"$subdomain\";"
echo " enableAuth = $enable_auth;"
echo " };"
fi
echo "};"
echo "\`\`\`"
echo
echo "---"
echo
done
echo "## Integration Summary"
echo
echo "### Available Integration Types"
echo
echo "| Integration | Purpose | Configuration |"
echo "|-------------|---------|---------------|"
echo "| **Monitoring** | Prometheus metrics + health checks | \`monitoring.enable = true\` |"
echo "| **Logging** | Centralized log collection | \`logging.enable = true\` |"
echo "| **Proxy** | Reverse proxy with SSL + auth | \`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
echo "---"
echo
echo "*This service catalog is generated from actual service configurations across your homelab fleet.*"
'';
# Current deployment generator
deploymentDocsGenerator = writeShellScriptBin "homelab-docs-deployment" ''
#!/usr/bin/env bash
set -euo pipefail
cat << EOF
# Current Deployment State
> Current homelab deployment configuration
>
> Generated on: $(date)
> Working directory: $(pwd)
## Deployment Summary
EOF
# Get deployment summary
deployment_summary=$(colmena eval -E '{ nodes, pkgs, lib, ... }:
let
homelabNodes = lib.filterAttrs (name: node: node.config.homelab.enable or false) nodes;
allServices = lib.flatten (lib.mapAttrsToList (nodeName: node:
lib.attrNames (lib.filterAttrs (n: v: v.enable or false) (node.config.homelab.services or {}))
) homelabNodes);
in {
totalNodes = lib.length (lib.attrNames nodes);
homelabEnabledNodes = lib.length (lib.attrNames homelabNodes);
uniqueServices = lib.length (lib.unique allServices);
totalServiceInstances = lib.length allServices;
nodeNames = lib.attrNames nodes;
homelabNodeNames = lib.attrNames homelabNodes;
}')
total_nodes=$(echo "$deployment_summary" | ${jq}/bin/jq -r '.totalNodes')
homelab_nodes=$(echo "$deployment_summary" | ${jq}/bin/jq -r '.homelabEnabledNodes')
unique_services=$(echo "$deployment_summary" | ${jq}/bin/jq -r '.uniqueServices')
service_instances=$(echo "$deployment_summary" | ${jq}/bin/jq -r '.totalServiceInstances')
echo "| Metric | Count |"
echo "|--------|-------|"
echo "| Total Nodes | $total_nodes |"
echo "| Homelab-Enabled Nodes | $homelab_nodes |"
echo "| Unique Services | $unique_services |"
echo "| Service Instances | $service_instances |"
echo
echo "## Node Status"
echo
# Get detailed node status
node_status=$(colmena eval -E '{ nodes, pkgs, lib, ... }:
lib.mapAttrs (name: node: {
homelabEnabled = node.config.homelab.enable or false;
environment = node.config.homelab.environment or "unknown";
serviceCount = if (node.config.homelab.enable or false) then
lib.length (lib.attrNames (lib.filterAttrs (n: v: v.enable or false) (node.config.homelab.services or {})))
else 0;
monitoringEnabled = if (node.config.homelab.enable or false) then
node.config.homelab.monitoring.enable or false
else false;
backupsEnabled = if (node.config.homelab.enable or false) then
node.config.homelab.backups.enable or false
else false;
proxyEnabled = if (node.config.homelab.enable or false) then
node.config.homelab.reverseProxy.enable or false
else false;
}) nodes')
echo "| Node | Homelab | Environment | Services | Monitoring | Backups | Proxy |"
echo "|------|---------|-------------|----------|------------|---------|-------|"
echo "$node_status" | ${jq}/bin/jq -r 'to_entries[] |
[.key, (.value.homelabEnabled | if . then "" else "" end), .value.environment, (.value.serviceCount | tostring),
(.value.monitoringEnabled | if . then "" else "" end),
(.value.backupsEnabled | if . then "" else "" end),
(.value.proxyEnabled | if . then "" else "" end)] |
@tsv' | while IFS=$'\t' read -r node homelab env services monitoring backups proxy; do
echo "| \`$node\` | $homelab | $env | $services | $monitoring | $backups | $proxy |"
done
echo
echo "---"
echo
echo "*Deployment state extracted from live colmena configuration*"
'';
# README generator
readmeGenerator = writeShellScriptBin "homelab-docs-readme" ''
#!/usr/bin/env bash
set -euo pipefail
cat << EOF
# Homelab Documentation
> Auto-generated documentation for the homelab deployment
>
> Generated on: $(date)
> Source: $(pwd)
## 📚 Documentation Files
This documentation is automatically generated from your colmena flake configuration.
### 📊 Overview Documents
- **[Fleet Overview](fleet-overview.md)** - High-level fleet statistics and service distribution
- **[Current Deployment](current-deployment.md)** - Current deployment state and node status
### 📖 Detailed Configuration
- **[Node Configurations](nodes.md)** - Per-node detailed configuration and services
- **[Service Configurations](services.md)** - Service configurations across the fleet
## 🚀 Quick Actions
### View Current Status
\`\`\`bash
# Service status across fleet (if homelab CLI is available)
homelab services --global
# Backup status
homelab backups --global
# Overall status
homelab status
\`\`\`
### Update Documentation
\`\`\`bash
# Regenerate all documentation
homelab-generate-docs ./docs
# Generate in different directory
homelab-generate-docs /path/to/output
\`\`\`
## 📋 Quick Stats
EOF
# Add live stats
quick_stats=$(colmena eval -E '{ nodes, pkgs, lib, ... }:
let
homelabNodes = lib.filterAttrs (name: node: node.config.homelab.enable or false) nodes;
in {
totalNodes = lib.length (lib.attrNames nodes);
homelabNodes = lib.length (lib.attrNames homelabNodes);
}')
total_nodes=$(echo "$quick_stats" | ${jq}/bin/jq -r '.totalNodes')
homelab_nodes=$(echo "$quick_stats" | ${jq}/bin/jq -r '.homelabNodes')
echo "- **Total Nodes**: $total_nodes"
echo "- **Homelab-Enabled Nodes**: $homelab_nodes"
echo "- **Generated**: $(date)"
echo
echo "## 🛠 Management Tools"
echo
echo "### Documentation Commands"
echo "- \`homelab-generate-docs\` - Regenerate this documentation"
echo "- \`homelab-docs-fleet\` - Generate fleet overview only"
echo "- \`homelab-docs-nodes\` - Generate node configurations only"
echo "- \`homelab-docs-services\` - Generate service configurations only"
echo "- \`homelab-docs-deployment\` - Generate deployment state only"
echo
echo "### Colmena Commands"
echo "- \`colmena eval\` - Evaluate flake expressions"
echo "- \`colmena apply\` - Deploy configuration changes"
echo "- \`colmena build\` - Build configurations without deploying"
echo
echo "---"
echo
echo "*This documentation reflects the live state of your homelab deployment as evaluated by colmena.*"
'';
in
stdenv.mkDerivation {
pname = "homelab-docs";
version = "1.0.0";
dontUnpack = true;
dontBuild = true;
installPhase = ''
mkdir -p $out/bin
# Install all the generators
cp ${docsGenerator}/bin/homelab-generate-docs $out/bin/
cp ${fleetDocsGenerator}/bin/homelab-docs-fleet $out/bin/
cp ${nodeDocsGenerator}/bin/homelab-docs-nodes $out/bin/
cp ${serviceDocsGenerator}/bin/homelab-docs-services $out/bin/
cp ${deploymentDocsGenerator}/bin/homelab-docs-deployment $out/bin/
cp ${readmeGenerator}/bin/homelab-docs-readme $out/bin/
# Make sure they're executable
chmod +x $out/bin/*
'';
meta = with lib; {
description = "Documentation generator for homelab colmena deployments";
longDescription = ''
A collection of tools to generate comprehensive documentation
for homelab deployments managed with colmena. Extracts configuration
from flakes and generates markdown documentation.
'';
license = licenses.mit;
maintainers = [];
platforms = platforms.all;
};
}