{ lib, pkgs, modulesPath, sources, config, ... }: let inherit (pkgs) system; netboxUser = "netbox"; netboxPassword = "netbox"; backendPort = builtins.toString 8080; tfBackend = fragment: { address = "http://localhost:${backendPort}/state/${fragment}"; }; template-deployment = (import ./setups/template.nix { inherit sources system modulesPath; config = { httpBackend = tfBackend "proxmox-test/upload"; nodeName = "pve"; targetSystem = system; node-name = "pve"; imageDatastoreId = "local"; }; }).default.tf-proxmox-template; vm-deployment = (import ./setups/vm.nix { inherit sources system modulesPath; config = { httpBackend = tfBackend "proxmox-test/nixos"; inherit (import ./constants.nix) pathToRoot; nodeName = "pve"; targetSystem = system; # for the test use the proxmox host as jump host, # as we have no static IPs the deployer can reach the deployed VM on sshOpts = [ "ProxyCommand=ssh -W %h:%p pve" ]; key-file = "/root/.ssh/id_ed25519"; node-name = "pve"; bridge = "br0"; vlanId = 0; imageDatastoreId = "local"; vmDatastoreId = "local"; cdDatastoreId = "local"; ipv4Gateway = "192.168.10.1"; # ipv4Address = "192.168.10.236/24"; ipv4Address = null; ipv6Gateway = ""; ipv6Address = ""; # dynamically get the id from the template upload step templateId = null; }; }).default.tf-proxmox-vm; inherit (pkgs.callPackage ../../run { inherit sources system; }) tf-netbox-store-ips tf-netbox-get-ip ; netbox-store-ips = (lib.evalModules { modules = [ { options = { inherit tf-netbox-store-ips; }; config.tf-netbox-store-ips = { httpBackend = tfBackend "proxmox-test/store-ips"; startAddress = "192.168.10.236/24"; endAddress = "192.168.10.240/24"; }; } ]; }).config.tf-netbox-store-ips; netbox-get-ip = (lib.evalModules { modules = [ { options = { inherit tf-netbox-get-ip; }; config.tf-netbox-get-ip = { httpBackend = tfBackend "proxmox-test/get-ip"; }; } ]; }).config.tf-netbox-get-ip; in { _class = "nixosTest"; name = "deployment-model"; sourceFileset = lib.fileset.unions [ ../../run/tf-proxmox-vm/await-ssh.sh ]; nodes.pve = { sources, ... }: { imports = [ "${sources.proxmox-nixos}/modules/proxmox-ve" ]; environment.systemPackages = [ pkgs.jq pkgs.qemu ]; networking.firewall.enable = false; networking.vlans = { vlan0 = { id = 0; interface = "eth0"; }; }; networking.useDHCP = false; networking = { bridges.br0.interfaces = [ ]; interfaces.br0.ipv4.addresses = [ { address = "192.168.10.1"; prefixLength = 24; } ]; nat = { enable = true; internalInterfaces = [ "br0" ]; }; }; boot.kernel.sysctl."net.ipv4.ip_forward" = "1"; users.users.root = { password = "mytestpw"; hashedPasswordFile = lib.mkForce null; }; # https://github.com/SaumonNet/proxmox-nixos/blob/main/modules/proxmox-ve/default.nix services.proxmox-ve = { enable = true; ipAddress = "192.168.1.1"; }; virtualisation = { diskSize = 5 * 1024; memorySize = 3 * 1024; }; }; nodes.deployer = { ... }: { imports = [ ../../modules/terraform-backend ]; networking.firewall.enable = false; nix.nixPath = [ (lib.concatStringsSep ":" (lib.mapAttrsToList (k: v: k + "=" + v) sources)) ]; environment.systemPackages = [ vm-deployment.run template-deployment.run pkgs.pve-manager pkgs.openssl pkgs.jq pkgs.netbox (pkgs.callPackage ../../run/tf-proxmox-template/tf.nix { }) (pkgs.callPackage ../../run/tf-proxmox-vm/tf.nix { }) (pkgs.callPackage ../../run/tf-netbox-store-ips/tf.nix { }) (pkgs.callPackage ../../run/tf-netbox-get-ip/tf.nix { }) ]; # needed only when building from deployer system.extraDependenciesFromModule = { pkgs, ... }: { environment.systemPackages = with pkgs; [ hello ]; }; system.extraDependencies = [ sources.disko pkgs.ubootQemuX86 pkgs.ubootQemuX86.inputDerivation pkgs.pve-qemu pkgs.pve-qemu.inputDerivation pkgs.gnu-config pkgs.byacc pkgs.stdenv pkgs.stdenvNoCC sources.nixpkgs pkgs.vte ]; services.terraform-backend = { enable = true; settings = { LISTEN_ADDR = ":${backendPort}"; # FIXME randomly generate this KMS_KEY = "tsjxw9NjKUBUlzbTnD7orqIAdEmpGYRARvxD51jtY+o="; }; }; services.netbox = { enable = true; # FIXME randomly generate this secretKeyFile = pkgs.writeText "netbox-secret" "634da8232803a8155a58584d3186127000207e079d600fc10a890e5cd59c2f4b8f0e0654005944d2ce87f5be9c22ceebec66"; # listenAddress = "[::1]"; port = 8001; }; }; extraTestScript = '' deployer.succeed(""" DJANGO_SUPERUSER_PASSWORD='${netboxPassword}' netbox-manage createsuperuser --noinput --user '${netboxUser}' --email 'test@domain.tld' >&2 """) # FIXME use https netbox_token = deployer.succeed(""" resp=$(curl -X POST -H "Content-Type: application/json" -H "Accept: application/json" http://localhost:8001/api/users/tokens/provision/ --data '{"username": "${netboxUser}", "password": "${netboxPassword}" }') echo "resp: $resp" >&2 echo $resp | jq .key """).strip() deployer.succeed(f""" export NETBOX_SERVER_URL="localhost:8001" export NETBOX_API_TOKEN="{netbox_token}" export NETBOX_ALLOW_INSECURE_HTTPS="true" # export NETBOX_CA_CERT_FILE="" ${lib.getExe netbox-store-ips.run} """) ipv4 = deployer.succeed(f""" export NETBOX_SERVER_URL="localhost:8001" export NETBOX_API_TOKEN="{netbox_token}" export NETBOX_ALLOW_INSECURE_HTTPS="true" # export NETBOX_CA_CERT_FILE="" ${lib.getExe netbox-get-ip.run} | jq -r '.ipv4.value' """).strip() pve.wait_for_unit("pveproxy.service") assert "running" in pve.succeed("pveproxy status") pve.succeed("mkdir -p /run/pve") assert "Proxmox" in pve.succeed("curl -s -i -k https://localhost:8006") cert = pve.succeed("cat /etc/pve/pve-root-ca.pem").strip() pve.succeed("pvesh create /pools --poolid Fediversity") # allow upload of `import` (template) files pve.succeed(""" pvesh set /storage/local --content "vztmpl,rootdir,backup,snippets,import,iso,images" 1>/dev/null """) template_token = pve.succeed(""" pvesh create /access/users/root@pam/token/template --output-format json | jq -r .value pvesh set /access/acl --path "/" --token "root@pam!template" --roles "PVEDatastoreAdmin" """).strip() vm_token = pve.succeed(""" pvesh create /access/users/root@pam/token/vm --output-format json | jq -r .value pvesh set /access/acl --path "/" --token "root@pam!vm" --roles "PVEVMAdmin PVEDatastoreAdmin PVESDNUser" """).strip() # skip indent for EOF deployer.succeed(f""" cat > /etc/ssl/certs/pve-root-ca.pem < /root/.ssh/id_ed25519 < new-ca-bundle.crt rm ca-bundle.crt ca-certificates.crt mv new-ca-bundle.crt ca-bundle.crt ln -s ca-bundle.crt ca-certificates.crt openssl verify -CApath /etc/ssl/certs ./pve-root-ca.pem """) with subtest("Deploy the template"): template_id = deployer.succeed(f""" ssh -o BatchMode=yes -o StrictHostKeyChecking=no pve "true" export PROXMOX_VE_INSECURE="true" export SSL_CERT_FILE=/tmp/pve-ca-bundle.crt export PROXMOX_VE_API_TOKEN="root@pam!template={template_token}" export TF_VAR_ipv4_address="{ipv4}" ${lib.getExe template-deployment.run} | jq -r '.id.value' """).strip() deploy = f""" set -e ssh -o BatchMode=yes -o StrictHostKeyChecking=no pve "true" export PROXMOX_VE_INSECURE="true" export SSL_CERT_FILE=/tmp/pve-ca-bundle.crt export PROXMOX_VE_API_TOKEN="root@pam!vm={vm_token}" export TF_VAR_template_id="{template_id}" export TF_VAR_ipv4_address="{ipv4}" ${lib.getExe vm-deployment.run} | jq -r '.ipv4.value[0]' """ with subtest("Run the deployment"): ip = deployer.succeed(deploy).strip() with subtest("Verify package"): deployer.succeed(f""" ssh -i "/root/.ssh/id_ed25519" -o StrictHostKeyChecking=no -o BatchMode=yes -J pve root@{ip} su - operator -c hello >&2 """) with subtest("No-op update"): deployer.succeed(deploy, timeout=120) ''; }