provisioning/scripts/nixos/generate-hetzner-nixos-flake.nu

203 lines
5.8 KiB
Text
Raw Normal View History

#!/usr/bin/env nu
# Generate NixOS flake for Hetzner server from provisioning config
# Combines workspace Nickel config + os-nixos taskserv to generate target flake
use std
# Validate input files
def validate-inputs [servers_ncl: string, output_dir: string] {
if not ($servers_ncl | path exists) {
error make {msg: $"servers.ncl not found: ($servers_ncl)"}
}
if not ($output_dir | path exists) {
mkdir $output_dir
}
}
# Export Nickel servers config to JSON
def export-servers-config [servers_ncl: string] {
let export_result = (nickel export $servers_ncl 2>&1 | complete)
if $export_result.exit_code != 0 {
error make {msg: $"nickel export failed: ($export_result.stderr)"}
}
$export_result.stdout | from json
}
# Generate flake.nix from server config
def generate-flake-nix [server: record, taskservs_dir: string, output_path: string] {
let hostname = $server.hostname
let server_type = $server.server_type
let os_type = ($server.os_type? // "debian")
let flake_content = $"
{
description = \"NixOS configuration for Hetzner server ($hostname)\";
inputs = {
nixpkgs.url = \"github:NixOS/nixpkgs/nixos-24.11\";
nixos-anywhere = {
url = \"github:nix-community/nixos-anywhere\";
inputs.nixpkgs.follows = \"nixpkgs\";
};
provisioning-os-nixos = {
url = \"path:($taskservs_dir)/infrastructure/os-nixos\";
};
};
outputs = { self, nixpkgs, nixos-anywhere, provisioning-os-nixos }: {
nixosConfigurations.default = nixpkgs.lib.nixosSystem {
system = if (builtins.elem \"cax\" [\"$server_type\"]) then \"aarch64-linux\" else \"x86_64-linux\";
modules = [
provisioning-os-nixos.nixosModules.default
provisioning-os-nixos.nixosModules.hetzner-$server_type
./hardware-configuration.nix
./configuration.nix
];
};
};
}
"
$flake_content | save --force $output_path
print $"Generated flake.nix at ($output_path)"
}
# Generate hardware-configuration.nix based on server type
def generate-hardware-config [server: record, output_path: string] {
let server_type = $server.server_type
let arch = if ($server_type | str contains "cax") { "aarch64" } else { "x86_64" }
let hardware_config = $"
# Auto-generated hardware configuration for Hetzner ($server_type)
{ config, lib, pkgs, ... }: {
imports = [
<nixpkgs/nixos/modules/profiles/qemu-guest.nix>
<nixpkgs/nixos/modules/profiles/headless.nix>
];
boot.initrd.availableKernelModules = [ \"ata_piix\" \"uhci_hcd\" \"ahci\" \"virtio_pci\" \"virtio_blk\" ];
boot.kernelModules = [ ];
boot.extraModulePackages = [ ];
fileSystems.\"/\" = {
device = \"/dev/sda1\";
fsType = \"ext4\";
};
swapDevices = [ ];
hardware.cpu.intel.updateMicrocode = lib.mkDefault (pkgs.stdenv.hostPlatform.isx86_64);
system.stateVersion = \"24.11\";
}
"
$hardware_config | save --force $output_path
print $"Generated hardware-configuration.nix at ($output_path)"
}
# Generate base configuration.nix
def generate-configuration [server: record, output_path: string] {
let hostname = $server.hostname
let domain = "librecloud.online"
let config = $"
# NixOS configuration for ($hostname)
{ config, lib, pkgs, ... }: {
networking.hostName = \"$hostname\";
networking.domain = \"$domain\";
networking.fqdn = \"$hostname.$domain\";
time.timeZone = \"UTC\";
i18n.defaultLocale = \"en_US.UTF-8\";
services.openssh = {
enable = true;
settings = {
PasswordAuthentication = false;
PubkeyAuthentication = true;
};
};
users.users.devadm = {
isNormalUser = true;
home = \"/home/devadm\";
group = \"devadm\";
groups = [ \"wheel\" ];
shell = pkgs.bash;
openssh.authorizedKeys.keys = [ ];
};
users.groups.devadm = { };
security.sudo.wheelNeedsPassword = false;
system.activationScripts.mkdir-provisioning = ''
mkdir -p /nix/provisioning
chown devadm:devadm /nix/provisioning
'';
nix.settings.experimental-features = [ \"nix-command\" \"flakes\" ];
system.stateVersion = \"24.11\";
}
"
$config | save --force $output_path
print $"Generated configuration.nix at ($output_path)"
}
# Main function
export def main [
servers_ncl: string # Path to servers.ncl
--output-dir: string # Output directory for flakes
--taskservs-dir: string # Path to provisioning/extensions/taskservs (for imports)
--filter: string # Filter servers by hostname pattern
] {
let output_base = ($output_dir? // "./nixos")
let taskservs_base = ($taskservs_dir? // "./provisioning/extensions/taskservs")
validate-inputs $servers_ncl $output_base
let servers_config = (export-servers-config $servers_ncl)
let servers_list = if ($servers_config | has "servers") {
$servers_config.servers
} else {
[$servers_config]
}
print $"Generating flakes for ($servers_list | length) server(s)..."
for server in $servers_list {
let hostname = $server.hostname
let os_type = ($server.os_type? // "debian")
# Skip Debian servers
if $os_type != "nixos" {
print $"⊘ ($hostname): os_type is ($os_type), skipping (not NixOS)"
continue
}
# Apply filter if specified
if ($filter != null) and not ($hostname | str contains $filter) {
print $"⊘ ($hostname): filtered out"
continue
}
let server_dir = $"($output_base)/($hostname)"
mkdir $server_dir
generate-flake-nix $server $taskservs_base $"($server_dir)/flake.nix"
generate-hardware-config $server $"($server_dir)/hardware-configuration.nix"
generate-configuration $server $"($server_dir)/configuration.nix"
print $"✓ ($hostname): flake generated at ($server_dir)"
}
print "All flakes generated successfully"
}