202 lines
5.8 KiB
Text
202 lines
5.8 KiB
Text
#!/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"
|
|
}
|