allow passing of extra_config into machines
checks-impure / test (pull_request) Successful in 1m40s Details
checks / test (pull_request) Successful in 2m41s Details

This commit is contained in:
lassulus 2024-02-10 11:47:09 +01:00
parent 10cbe11e53
commit eebd9d0b4a
6 changed files with 123 additions and 68 deletions

View File

@ -15,7 +15,7 @@ let
in
{
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_backup_client; };
flake.clanInternals.machines = clan.clanInternals.machines;
flake.clanInternals = clan.clanInternals;
flake.nixosModules = {
test_backup_server = { ... }: {
imports = [

View File

@ -13,7 +13,7 @@ let
in
{
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_install_machine; };
flake.clanInternals.machines = clan.clanInternals.machines;
flake.clanInternals = clan.clanInternals;
flake.nixosModules = {
test_install_machine = { lib, modulesPath, ... }: {
imports = [

View File

@ -49,6 +49,9 @@
machines = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
};
machinesFunc = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified);
};
};
};
};

View File

@ -30,13 +30,14 @@ let
(machineSettings.clanImports or [ ]);
# TODO: remove default system once we have a hardware-config mechanism
nixosConfiguration = { system ? "x86_64-linux", name, pkgs ? null }: nixpkgs.lib.nixosSystem {
nixosConfiguration = { system ? "x86_64-linux", name, pkgs ? null, extraConfig ? { } }: nixpkgs.lib.nixosSystem {
modules =
let
settings = machineSettings name;
in
(machineImports settings)
++ [
(nixpkgs.lib.mkOverride 51 extraConfig)
settings
clan-core.nixosModules.clanCore
(machines.${name} or { })
@ -77,7 +78,13 @@ let
configsPerSystem = builtins.listToAttrs
(builtins.map
(system: lib.nameValuePair system
(lib.mapAttrs (name: _: nixosConfiguration { inherit name system; pkgs = nixpkgs.legacyPackages.${system}; }) allMachines))
(lib.mapAttrs (name: _: nixosConfiguration { inherit name system; }) allMachines))
supportedSystems);
configsFuncPerSystem = builtins.listToAttrs
(builtins.map
(system: lib.nameValuePair system
(lib.mapAttrs (name: _: args: nixosConfiguration (args // { inherit name system; })) allMachines))
supportedSystems);
in
{
@ -85,6 +92,7 @@ in
clanInternals = {
machines = configsPerSystem;
machinesFunc = configsFuncPerSystem;
all-machines-json = lib.mapAttrs
(system: configs: nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs))
configsPerSystem;

View File

@ -1,33 +0,0 @@
import json
from pathlib import Path
from clan_cli.nix import nix_eval
from .cmd import run
def get_clan_module_names(
flake_dir: Path,
) -> list[str]:
"""
Get the list of clan modules from the clan-core flake input
"""
proc = run(
nix_eval(
[
"--impure",
"--show-trace",
"--expr",
f"""
let
flake = builtins.getFlake (toString {flake_dir});
in
builtins.attrNames flake.inputs.clan-core.clanModules
""",
],
),
cwd=flake_dir,
)
module_names = json.loads(proc.stdout)
return module_names

View File

@ -2,6 +2,7 @@ import json
import logging
from os import path
from pathlib import Path
from tempfile import NamedTemporaryFile
from time import sleep
from clan_cli.dirs import vm_state_dir
@ -149,52 +150,128 @@ class Machine:
meta={"machine": self, "target_host": self.target_host},
)
def eval_nix(self, attr: str, refresh: bool = False) -> str:
def nix(
self,
method: str,
attr: str,
extra_config: None | dict = None,
impure: bool = False,
) -> str | Path:
"""
eval a nix attribute of the machine
@attr: the attribute to get
Build the machine and return the path to the result
accepts a secret store and a facts store # TODO
"""
config = nix_config()
system = config["system"]
attr = f'clanInternals.machines."{system}".{self.name}.{attr}'
with NamedTemporaryFile(mode="w") as config_json:
if extra_config is not None:
json.dump(extra_config, config_json, indent=2)
else:
json.dump({}, config_json)
config_json.flush()
if attr in self.eval_cache and not refresh:
nar_hash = json.loads(
run(
nix_eval(
[
"--impure",
"--expr",
f'(builtins.fetchTree {{ type = "file"; url = "{config_json.name}"; }}).narHash',
]
)
).stdout.strip()
)
args = []
# get git commit from flake
if extra_config is not None:
metadata = nix_metadata(self.flake_dir)
url = metadata["url"]
if "dirtyRev" in metadata:
if not impure:
raise ClanError(
"The machine has a dirty revision, and impure mode is not allowed"
)
else:
args += ["--impure"]
if "dirtyRev" in nix_metadata(self.flake_dir):
dirty_rev = nix_metadata(self.flake_dir)["dirtyRevision"]
url = f"{url}?rev={dirty_rev}"
args += [
"--expr",
f"""
((builtins.getFlake "{url}").clanInternals.machinesFunc."{system}"."{self.name}" {{
extraConfig = builtins.fromJSON (builtins.readFile (builtins.fetchTree {{
type = "file";
url = "{config_json.name}";
narHash = "{nar_hash}";
}}));
}}).{attr}
""",
]
else:
if isinstance(self.flake, Path):
if (self.flake / ".git").exists():
flake = f"git+file://{self.flake}"
else:
flake = f"path:{self.flake}"
else:
flake = self.flake
args += [
f'{flake}#clanInternals.machines."{system}".{self.name}.{attr}'
]
if method == "eval":
output = run(nix_eval(args)).stdout.strip()
return output
elif method == "build":
outpath = run(nix_build(args)).stdout.strip()
return Path(outpath)
else:
raise ValueError(f"Unknown method {method}")
def eval_nix(
self,
attr: str,
refresh: bool = False,
extra_config: None | dict = None,
impure: bool = False,
) -> str:
"""
eval a nix attribute of the machine
@attr: the attribute to get
"""
if attr in self.eval_cache and not refresh and extra_config is None:
return self.eval_cache[attr]
if isinstance(self.flake, Path):
if (self.flake / ".git").exists():
flake = f"git+file://{self.flake}"
else:
flake = f"path:{self.flake}"
output = self.nix("eval", attr, extra_config, impure)
if isinstance(output, str):
self.eval_cache[attr] = output
return output
else:
flake = self.flake
raise ClanError("eval_nix returned not a string")
cmd = nix_eval([f"{flake}#{attr}"])
output = run(cmd).stdout.strip()
self.eval_cache[attr] = output
return output
def build_nix(self, attr: str, refresh: bool = False) -> Path:
def build_nix(
self,
attr: str,
refresh: bool = False,
extra_config: None | dict = None,
impure: bool = False,
) -> Path:
"""
build a nix attribute of the machine
@attr: the attribute to get
"""
config = nix_config()
system = config["system"]
attr = f'clanInternals.machines."{system}".{self.name}.{attr}'
if attr in self.build_cache and not refresh:
if attr in self.build_cache and not refresh and extra_config is None:
return self.build_cache[attr]
if isinstance(self.flake, Path):
flake = f"path:{self.flake}"
output = self.nix("build", attr, extra_config, impure)
if isinstance(output, Path):
self.build_cache[attr] = output
return output
else:
flake = self.flake
outpath = run(nix_build([f"{flake}#{attr}"])).stdout.strip()
self.build_cache[attr] = Path(outpath)
return Path(outpath)
raise ClanError("build_nix returned not a Path")