homelab framework module init (everything is a mess)
This commit is contained in:
parent
0347f4d325
commit
bcbcc8b17b
94 changed files with 7289 additions and 436 deletions
18
scripts/config.nix
Normal file
18
scripts/config.nix
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
nodes,
|
||||
lib,
|
||||
...
|
||||
}: let
|
||||
extractGlobal = name: node:
|
||||
if node ? config.homelab.global
|
||||
then {
|
||||
${name} = {
|
||||
hostname = node.config.homelab.global.hostname;
|
||||
monitoring = map (e: "${e.name}:${toString e.port}") node.config.homelab.global.monitoring.endpoints;
|
||||
backups = map (b: "${b.name}(${b.backend})") node.config.homelab.global.backups.jobs;
|
||||
proxy = map (p: "${p.subdomain}.${node.config.homelab.global.domain}") node.config.homelab.global.reverseProxy.entries;
|
||||
};
|
||||
}
|
||||
else {};
|
||||
in
|
||||
lib.foldl (acc: name: acc // (extractGlobal name nodes.${name})) {} (builtins.attrNames nodes)
|
||||
115
scripts/deploy-homelab.sh
Executable file
115
scripts/deploy-homelab.sh
Executable file
|
|
@ -0,0 +1,115 @@
|
|||
# Helper script: scripts/deploy-homelab.sh
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}=== Homelab Deployment Script ===${NC}"
|
||||
|
||||
# Function to print colored output
|
||||
log() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if colmena is available
|
||||
if ! command -v colmena &> /dev/null; then
|
||||
error "colmena is not installed. Please install it first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
COMMAND=${1:-"deploy"}
|
||||
TARGET=${2:-""}
|
||||
|
||||
case $COMMAND in
|
||||
"deploy")
|
||||
if [ -n "$TARGET" ]; then
|
||||
log "Deploying to specific target: $TARGET"
|
||||
colmena apply --on "$TARGET"
|
||||
else
|
||||
log "Deploying to all targets"
|
||||
colmena apply
|
||||
fi
|
||||
;;
|
||||
"build")
|
||||
if [ -n "$TARGET" ]; then
|
||||
log "Building specific target: $TARGET"
|
||||
colmena build --on "$TARGET"
|
||||
else
|
||||
log "Building all targets"
|
||||
colmena build
|
||||
fi
|
||||
;;
|
||||
"status")
|
||||
log "Checking deployment status"
|
||||
colmena apply --dry-run
|
||||
;;
|
||||
"config")
|
||||
log "Showing global configuration summary"
|
||||
# Extract global configs from all nodes
|
||||
colmena eval ./scripts/config.nix | jq .
|
||||
;;
|
||||
"backup-status")
|
||||
log "Checking backup status across all nodes"
|
||||
if [ -n "$TARGET" ]; then
|
||||
colmena exec --on "$TARGET" -- backup-status
|
||||
else
|
||||
colmena exec -- backup-status
|
||||
fi
|
||||
;;
|
||||
"monitoring")
|
||||
log "Collecting monitoring endpoints"
|
||||
nix eval --json .#colmena --apply 'colmena:
|
||||
let
|
||||
lib = (import <nixpkgs> {}).lib;
|
||||
nodes = removeAttrs colmena ["meta"];
|
||||
collectEndpoints = lib.flatten (
|
||||
lib.mapAttrsToList (name: node:
|
||||
if node ? config.homelab.global.monitoring.endpoints then
|
||||
map (e: {
|
||||
node = name;
|
||||
hostname = node.config.homelab.global.hostname;
|
||||
endpoint = "${e.name}:${toString e.port}${e.path}";
|
||||
job = e.jobName;
|
||||
}) node.config.homelab.global.monitoring.endpoints
|
||||
else []
|
||||
) nodes
|
||||
);
|
||||
in collectEndpoints
|
||||
' | jq .
|
||||
;;
|
||||
"help")
|
||||
echo "Usage: $0 [COMMAND] [TARGET]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " deploy [TARGET] Deploy to all nodes or specific target"
|
||||
echo " build [TARGET] Build configuration for all nodes or specific target"
|
||||
echo " status Show deployment status (dry-run)"
|
||||
echo " config Show global configuration summary"
|
||||
echo " backup-status Check backup status on all nodes"
|
||||
echo " monitoring List all monitoring endpoints"
|
||||
echo " help Show this help message"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 deploy media-server # Deploy only to media-server"
|
||||
echo " $0 build # Build all configurations"
|
||||
echo " $0 config # Show global config summary"
|
||||
;;
|
||||
*)
|
||||
error "Unknown command: $COMMAND"
|
||||
echo "Run '$0 help' for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
41
scripts/generate-docs.sh
Executable file
41
scripts/generate-docs.sh
Executable file
|
|
@ -0,0 +1,41 @@
|
|||
# scripts/generate-docs.sh
|
||||
#!/bin/bash
|
||||
|
||||
echo "# Homelab Global Configuration Documentation"
|
||||
echo
|
||||
echo "This document describes the global configuration system for the NixOS homelab."
|
||||
echo
|
||||
echo "## Available Services"
|
||||
echo
|
||||
|
||||
# List all service modules
|
||||
find modules/nixos/services -name "*.nix" | while read -r file; do
|
||||
service=$(basename "$file" .nix)
|
||||
echo "### $service"
|
||||
echo
|
||||
# Extract description from the module
|
||||
grep -m1 "mkEnableOption" "$file" | sed 's/.*mkEnableOption "\([^"]*\)".*/\1/' || echo "Service module for $service"
|
||||
echo
|
||||
done
|
||||
|
||||
echo "## Configuration Examples"
|
||||
echo
|
||||
echo "### Basic Media Server Setup"
|
||||
echo '```nix'
|
||||
echo 'media-server = { ... }: {'
|
||||
echo ' homelab.global = {'
|
||||
echo ' enable = true;'
|
||||
echo ' hostname = "media-server";'
|
||||
echo ' domain = "homelab.local";'
|
||||
echo ' };'
|
||||
echo ' services.jellyfin.enable = true;'
|
||||
echo '};'
|
||||
echo '```'
|
||||
echo
|
||||
|
||||
echo "### Monitoring Configuration"
|
||||
echo '```nix'
|
||||
echo 'monitoring = { nodes, ... }: {'
|
||||
echo ' services.prometheus.scrapeConfigs = collectMonitoringEndpoints nodes;'
|
||||
echo '};'
|
||||
echo '```'# modules/global-config.nix
|
||||
79
scripts/validate-config.nix
Normal file
79
scripts/validate-config.nix
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# scripts/validate-config.nix
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
}: let
|
||||
inherit (lib) types mkOption;
|
||||
|
||||
# Validation functions
|
||||
validateBackupJob = job: let
|
||||
errors =
|
||||
[]
|
||||
++ (
|
||||
if job.paths == []
|
||||
then ["Backup job '${job.name}' has no paths defined"]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if !(builtins.elem job.backend ["restic" "borg" "rclone"])
|
||||
then ["Invalid backup backend: ${job.backend}"]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if job.schedule == ""
|
||||
then ["Backup job '${job.name}' has no schedule defined"]
|
||||
else []
|
||||
);
|
||||
in
|
||||
errors;
|
||||
|
||||
validateMonitoringEndpoint = endpoint: let
|
||||
errors =
|
||||
[]
|
||||
++ (
|
||||
if endpoint.port < 1 || endpoint.port > 65535
|
||||
then ["Invalid port ${toString endpoint.port} for endpoint '${endpoint.name}'"]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if endpoint.jobName == ""
|
||||
then ["Monitoring endpoint '${endpoint.name}' has no job name"]
|
||||
else []
|
||||
);
|
||||
in
|
||||
errors;
|
||||
|
||||
validateReverseProxyEntry = entry: let
|
||||
errors =
|
||||
[]
|
||||
++ (
|
||||
if entry.subdomain == ""
|
||||
then ["Reverse proxy entry has no subdomain defined"]
|
||||
else []
|
||||
)
|
||||
++ (
|
||||
if entry.port < 1 || entry.port > 65535
|
||||
then ["Invalid port ${toString entry.port} for subdomain '${entry.subdomain}'"]
|
||||
else []
|
||||
);
|
||||
in
|
||||
errors;
|
||||
|
||||
validateGlobalConfig = config: let
|
||||
backupErrors = lib.flatten (map validateBackupJob config.backups.jobs);
|
||||
monitoringErrors = lib.flatten (map validateMonitoringEndpoint config.monitoring.endpoints);
|
||||
proxyErrors = lib.flatten (map validateReverseProxyEntry config.reverseProxy.entries);
|
||||
allErrors = backupErrors ++ monitoringErrors ++ proxyErrors;
|
||||
in
|
||||
if allErrors == []
|
||||
then {
|
||||
valid = true;
|
||||
errors = [];
|
||||
}
|
||||
else {
|
||||
valid = false;
|
||||
errors = allErrors;
|
||||
};
|
||||
in {
|
||||
inherit validateGlobalConfig validateBackupJob validateMonitoringEndpoint validateReverseProxyEntry;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue