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

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 in
{ {
flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_backup_client; }; flake.nixosConfigurations = { inherit (clan.nixosConfigurations) test_backup_client; };
flake.clanInternals.machines = clan.clanInternals.machines; flake.clanInternals = clan.clanInternals;
flake.nixosModules = { flake.nixosModules = {
test_backup_server = { ... }: { test_backup_server = { ... }: {
imports = [ imports = [

View File

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

View File

@ -49,6 +49,9 @@
machines = lib.mkOption { machines = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf lib.types.unspecified); 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 [ ]); (machineSettings.clanImports or [ ]);
# TODO: remove default system once we have a hardware-config mechanism # 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 = modules =
let let
settings = machineSettings name; settings = machineSettings name;
in in
(machineImports settings) (machineImports settings)
++ [ ++ [
(nixpkgs.lib.mkOverride 51 extraConfig)
settings settings
clan-core.nixosModules.clanCore clan-core.nixosModules.clanCore
(machines.${name} or { }) (machines.${name} or { })
@ -77,7 +78,13 @@ let
configsPerSystem = builtins.listToAttrs configsPerSystem = builtins.listToAttrs
(builtins.map (builtins.map
(system: lib.nameValuePair system (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); supportedSystems);
in in
{ {
@ -85,6 +92,7 @@ in
clanInternals = { clanInternals = {
machines = configsPerSystem; machines = configsPerSystem;
machinesFunc = configsFuncPerSystem;
all-machines-json = lib.mapAttrs all-machines-json = lib.mapAttrs
(system: configs: nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs)) (system: configs: nixpkgs.legacyPackages.${system}.writers.writeJSON "machines.json" (lib.mapAttrs (_: m: m.config.system.clan.deployment.data) configs))
configsPerSystem; 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 import logging
from os import path from os import path
from pathlib import Path from pathlib import Path
from tempfile import NamedTemporaryFile
from time import sleep from time import sleep
from clan_cli.dirs import vm_state_dir from clan_cli.dirs import vm_state_dir
@ -149,52 +150,128 @@ class Machine:
meta={"machine": self, "target_host": self.target_host}, 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 Build the machine and return the path to the result
@attr: the attribute to get accepts a secret store and a facts store # TODO
""" """
config = nix_config() config = nix_config()
system = config["system"] 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] return self.eval_cache[attr]
if isinstance(self.flake, Path): output = self.nix("eval", attr, extra_config, impure)
if (self.flake / ".git").exists(): if isinstance(output, str):
flake = f"git+file://{self.flake}" self.eval_cache[attr] = output
else: return output
flake = f"path:{self.flake}"
else: else:
flake = self.flake raise ClanError("eval_nix returned not a string")
cmd = nix_eval([f"{flake}#{attr}"]) def build_nix(
self,
output = run(cmd).stdout.strip() attr: str,
self.eval_cache[attr] = output refresh: bool = False,
return output extra_config: None | dict = None,
impure: bool = False,
def build_nix(self, attr: str, refresh: bool = False) -> Path: ) -> Path:
""" """
build a nix attribute of the machine build a nix attribute of the machine
@attr: the attribute to get @attr: the attribute to get
""" """
config = nix_config() if attr in self.build_cache and not refresh and extra_config is None:
system = config["system"]
attr = f'clanInternals.machines."{system}".{self.name}.{attr}'
if attr in self.build_cache and not refresh:
return self.build_cache[attr] return self.build_cache[attr]
if isinstance(self.flake, Path): output = self.nix("build", attr, extra_config, impure)
flake = f"path:{self.flake}" if isinstance(output, Path):
self.build_cache[attr] = output
return output
else: else:
flake = self.flake raise ClanError("build_nix returned not a Path")
outpath = run(nix_build([f"{flake}#{attr}"])).stdout.strip()
self.build_cache[attr] = Path(outpath)
return Path(outpath)