data model: add TF test #4

Closed
kiara wants to merge 76 commits from data-model-tf-test into main
8 changed files with 210 additions and 114 deletions
Showing only changes of commit b5a96a70b8 - Show all commits

View file

@ -163,7 +163,7 @@ in
'')} '')}
${ ${
if config.useFlake then if true then
'' ''
## NOTE: This is super slow. It could probably be optimised in Nix, for ## NOTE: This is super slow. It could probably be optimised in Nix, for
## instance by allowing to grab things directly from the host's store. ## instance by allowing to grab things directly from the host's store.

View file

@ -1,7 +1,9 @@
{ {
targetMachines = [ targetMachines = [
"hello" "ssh"
"nixops4"
]; ];
pathToRoot = ../../..; pathToRoot = ../../..;
pathFromRoot = ./.; pathFromRoot = ./.;
enableAcme = true;
} }

View file

@ -12,5 +12,10 @@ runNixOSTest {
./nixosTest.nix ./nixosTest.nix
]; ];
_module.args = { inherit inputs sources; }; _module.args = { inherit inputs sources; };
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; inherit (import ./constants.nix)
targetMachines
pathToRoot
pathFromRoot
enableAcme
;
} }

View file

@ -12,11 +12,12 @@ let
inherit (pkgs) lib; inherit (pkgs) lib;
deployment-config = config; deployment-config = config;
inherit (lib) mkOption types; inherit (lib) mkOption types;
inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot;
eval = eval =
module: module:
(lib.evalModules { (lib.evalModules {
specialArgs = { specialArgs = {
inherit inputs; inherit pkgs inputs;
}; };
modules = [ modules = [
module module
@ -98,44 +99,67 @@ let
}; };
}; };
}; };
environments.single-nixos-vm = environment: { environments =
resources."operator-environment".login-shell.username = "operator"; let
implementation = requests: { mkNixosConfiguration =
input = requests; environment: requests:
output.ssh-host = { { ... }:
ssh = { {
username = "root"; imports = [
inherit (deployment-config) host; ./options.nix
key-file = null; ../common/sharedOptions.nix
../common/targetNode.nix
"${nixpkgs}/nixos/modules/profiles/qemu-guest.nix"
];
users.users = environment.config.resources."operator-environment".login-shell.apply {
resources = lib.filterAttrs (_name: value: value ? login-shell) (
lib.concatMapAttrs (
k': req: lib.mapAttrs' (k: lib.nameValuePair "${k'}.${k}") req.resources
) requests
);
};
}; };
nixos-configuration = in
{ ... }: {
{ single-nixos-vm-ssh = environment: {
imports = [ resources."operator-environment".login-shell.username = "operator";
./options.nix implementation = requests: {
../common/sharedOptions.nix input = requests;
../common/targetNode.nix output.ssh-host = {
"${nixpkgs}/nixos/modules/profiles/qemu-guest.nix" nixos-configuration = mkNixosConfiguration environment requests;
]; ssh = {
username = "root";
inherit (deployment-config) enableAcme; inherit (deployment-config) host;
acmeNodeIP = key-file = null;
if deployment-config.enableAcme then
deployment-config.nodes.acme.networking.primaryIPAddress
else
null;
users.users = environment.config.resources."operator-environment".login-shell.apply {
resources = lib.filterAttrs (_name: value: value ? login-shell) (
lib.concatMapAttrs (
k': req: lib.mapAttrs' (k: lib.nameValuePair "${k'}.${k}") req.resources
) requests
);
}; };
}; };
};
};
single-nixos-vm-nixops4 = environment: {
resources."operator-environment".login-shell.username = "operator";
implementation = requests: {
input = requests;
output.nixops4 =
{ providers, ... }:
{
providers = {
inherit (inputs.nixops4.modules.nixops4Provider) local;
};
resources = lib.genAttrs targetMachines (nodeName: {
type = providers.local.exec;
imports = [
inputs.nixops4-nixos.modules.nixops4Resource.nixos
../common/targetResource.nix
];
nixos.module = mkNixosConfiguration environment requests;
_module.args = { inherit inputs sources; };
inherit nodeName pathToRoot pathFromRoot;
});
};
};
}; };
}; };
};
}; };
options = { options = {
"example-configuration" = mkOption { "example-configuration" = mkOption {
@ -145,12 +169,24 @@ let
applications.hello.enable = true; applications.hello.enable = true;
}; };
}; };
"example-deployment" = mkOption { "ssh-deployment" =
type = config.environments.single-nixos-vm.resource-mapping.output-type; let
default = config.environments.single-nixos-vm.deployment config."example-configuration"; env = config.environments."single-nixos-vm-ssh";
}; in
mkOption {
type = env.resource-mapping.output-type;
default = env.deployment config."example-configuration";
};
"nixops4-deployment" =
let
env = config.environments."single-nixos-vm-nixops4";
in
mkOption {
type = env.resource-mapping.output-type;
default = env.deployment config."example-configuration";
};
}; };
} }
); );
in in
fediversity."example-deployment" fediversity

View file

@ -0,0 +1,26 @@
{
inputs = {
nixops4.follows = "nixops4-nixos/nixops4";
nixops4-nixos.url = "github:nixops4/nixops4-nixos";
};
outputs =
inputs:
import ./mkFlake.nix inputs (
{ inputs, ... }:
let
system = "x86_64-linux";
in
{
imports = [
inputs.nixops4.modules.flake.default
];
nixops4Deployments.check-deployment-model =
(import ./deployment/check/data-model/deployment.nix {
inherit system inputs;
config.host = "nixops4";
})."nixops4-deployment".nixops4;
}
);
}

View file

@ -2,11 +2,28 @@
lib, lib,
config, config,
pkgs, pkgs,
inputs,
... ...
}: }:
let let
inherit (import ./constants.nix) targetMachines pathToRoot; inherit (import ./constants.nix) pathToRoot;
escapedJson = v: lib.replaceStrings [ "\"" ] [ "\\\\\"" ] (lib.strings.toJSON v); escapedJson = v: lib.replaceStrings [ "\"" ] [ "\\\\\"" ] (lib.strings.toJSON v);
deployment-config = {
inherit (config) enableAcme;
acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null;
host = "ssh";
};
inherit
((import ./deployment.nix {
inherit (pkgs) system;
inherit inputs;
config = deployment-config;
})."ssh-deployment".ssh-host.ssh
)
host
username
key-file
;
in in
{ {
_class = "nixosTest"; _class = "nixosTest";
@ -20,14 +37,24 @@ in
../../function.nix ../../function.nix
./constants.nix ./constants.nix
./deployment.nix ./deployment.nix
./options.nix
(config.pathToCwd + "/flake-under-test.nix")
]; ];
nodes.deployer = nodes.deployer =
{ pkgs, ... }: { pkgs, ... }:
{ {
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
inputs.nixops4.packages.${system}.default
jq jq
]; ];
# FIXME: sad times
system.extraDependencies = with pkgs; [
jq
jq.inputDerivation
];
system.extraDependenciesFromModule = system.extraDependenciesFromModule =
{ pkgs, ... }: { pkgs, ... }:
{ {
@ -38,77 +65,58 @@ in
}; };
extraTestScript = '' extraTestScript = ''
${lib.concatStringsSep "\n" ( with subtest("nixops4"):
lib.lists.map ( nixops4.fail("hello 1>&2")
nodeName: deployer.succeed("nixops4 apply check-deployment-model --show-trace --verbose --no-interactive 1>&2")
let nixops4.succeed("su - operator -c hello 1>&2")
deployment-config = {
inherit (config) enableAcme;
acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null;
host = nodeName;
};
inherit
((import ./deployment.nix {
inherit (pkgs) system;
config = deployment-config;
}).ssh-host.ssh
)
host
username
key-file
;
in
''
with subtest("Check the status before deployment"):
${nodeName}.fail("${nodeName} 1>&2")
with subtest("Run the deployment for ${nodeName}"): with subtest("ssh: Check the status before deployment"):
deployer.succeed(""" ssh.fail("hello 1>&2")
set -euo pipefail
# INSTANTIATE with subtest("ssh: Run the deployment"):
command=(nix-instantiate --show-trace --expr ' deployer.succeed("""
let set -euo pipefail
system = "${pkgs.system}"; # FIXME: what system are we deploying to?
in # INSTANTIATE
import ${pathToRoot}/deployment/nixos.nix { command=(nix-instantiate --show-trace --expr '
inherit system; let
configuration = ( system = "${pkgs.system}"; # FIXME: what system are we deploying to?
import ${pathToRoot}/deployment/check/data-model/deployment.nix { in
inherit system; import ${pathToRoot}/deployment/nixos.nix {
config = builtins.fromJSON "${escapedJson deployment-config}"; inherit system;
} configuration = (
).ssh-host.nixos-configuration; import ${pathToRoot}/deployment/check/data-model/deployment.nix {
} inherit system;
') config = builtins.fromJSON "${escapedJson deployment-config}";
# DEPLOY }
host="${lib.defaultTo "root" username}@${host}" )."ssh-deployment".ssh-host.nixos-configuration;
sshOpts=( }
${if key-file == null then "" else "-i ${key-file}"} ')
-o StrictHostKeyChecking=no # DEPLOY
-o "ConnectTimeout=1" host="${lib.defaultTo "root" username}@${host}"
-o "ServerAliveInterval=1" sshOpts=(
) ${if key-file == null then "" else "-i ${key-file}"}
# instantiate the config in /nix/store -o StrictHostKeyChecking=no
"''${command[@]}" --show-trace -A out_path -o "ConnectTimeout=1"
# get the realized derivation to deploy -o "ServerAliveInterval=1"
outPath=$(nix-store --realize "$("''${command[@]}" --show-trace --eval --strict --json | jq -r '.drv_path')") )
# deploy the config by nix-copy-closure # instantiate the config in /nix/store
NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes "''${command[@]}" --show-trace -A out_path
# switch the remote host to the config # get the realized derivation to deploy
output=$(ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; nohup $outPath/bin/switch-to-configuration switch &" 2>&1) || echo "status code: $?" outPath=$(nix-store --realize "$("''${command[@]}" --show-trace --eval --strict --json | jq -r '.drv_path')")
echo "output: $output" # deploy the config by nix-copy-closure
if [[ $output != *"Timeout, server ${nodeName} not responding"* ]]; then NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes
echo "non-timeout error: $output" # switch the remote host to the config
exit 1 output=$(ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; nohup $outPath/bin/switch-to-configuration switch &" 2>&1) || echo "status code: $?"
else echo "output: $output"
exit 0 if [[ $output != *"Timeout, server ssh not responding"* ]]; then
fi echo "non-timeout error: $output"
""") exit 1
${nodeName}.wait_for_unit("multi-user.target") else
${nodeName}.succeed("su - operator -c ${nodeName} 1>&2") exit 0
'' fi
) targetMachines """)
)} ssh.wait_for_unit("multi-user.target")
ssh.succeed("su - operator -c hello 1>&2")
''; '';
} }

View file

@ -6,7 +6,7 @@ let
module: module:
(lib.evalModules { (lib.evalModules {
specialArgs = { specialArgs = {
inherit inputs; inherit pkgs inputs;
}; };
modules = [ modules = [
module module

View file

@ -1,6 +1,8 @@
{ {
lib, lib,
config, config,
inputs,
pkgs,
... ...
}: }:
let let
@ -28,6 +30,19 @@ let
); );
}; };
}; };
nixops4Deployment = types.deferredModuleWith {
staticModules = [
inputs.nixops4.modules.nixops4Deployment.default
{
_class = "nixops4Deployment";
_module.args = {
resourceProviderSystem = pkgs.system;
resources = { };
};
}
];
};
nixos-configuration = mkOption { nixos-configuration = mkOption {
description = "A NixOS configuration."; description = "A NixOS configuration.";
type = raw; type = raw;
@ -63,6 +78,10 @@ let
}; };
}; };
}; };
nixops4 = mkOption {
description = "A NixOps4 NixOS deployment. For an example, see https://github.com/nixops4/nixops4-nixos/blob/main/example/deployment.nix.";
type = nixops4Deployment;
};
}; };
in in
{ {