refactor: remove deployment.json and use direct selectors
- Remove deployment.json file generation from outputs.nix - Add throw for deprecated deployment.file usage with upgrade instructions - Remove vars data from deployment.data - Update Machine class to use direct select() calls instead of deployment property - Update all deployment property accesses to use direct selectors - Add precaching for frequently accessed values in update.py: - Module paths for facts and vars - Deployment settings (requireExplicitUpdate, nixosMobileWorkaround) - Services and generators data - Secret upload locations - This removes unnecessary JSON serialization and makes the code more composable
This commit is contained in:
@@ -22,7 +22,6 @@
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
self
|
self
|
||||||
pkgs.stdenv.drvPath
|
pkgs.stdenv.drvPath
|
||||||
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-backup.config.system.clan.deployment.file
|
|
||||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.toplevel
|
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.toplevel
|
||||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript
|
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript
|
||||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript.drvPath
|
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.build.diskoScript.drvPath
|
||||||
self.nixosConfigurations."test-flash-machine-${pkgs.hostPlatform.system}".config.system.clan.deployment.file
|
|
||||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ let
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
|
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.toplevel
|
||||||
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
|
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.build.diskoScript
|
||||||
self.clan.clanInternals.machines.${pkgs.hostPlatform.system}.test-install-machine-with-system.config.system.clan.deployment.file
|
|
||||||
pkgs.stdenv.drvPath
|
pkgs.stdenv.drvPath
|
||||||
pkgs.bash.drvPath
|
pkgs.bash.drvPath
|
||||||
pkgs.nixos-anywhere
|
pkgs.nixos-anywhere
|
||||||
|
|||||||
@@ -35,7 +35,6 @@
|
|||||||
pkgs.stdenv.drvPath
|
pkgs.stdenv.drvPath
|
||||||
pkgs.stdenvNoCC
|
pkgs.stdenvNoCC
|
||||||
self.nixosConfigurations.test-morph-machine.config.system.build.toplevel
|
self.nixosConfigurations.test-morph-machine.config.system.build.toplevel
|
||||||
self.nixosConfigurations.test-morph-machine.config.system.clan.deployment.file
|
|
||||||
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
] ++ builtins.map (i: i.outPath) (builtins.attrValues self.inputs);
|
||||||
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
closureInfo = pkgs.closureInfo { rootPaths = dependencies; };
|
||||||
in
|
in
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
lib,
|
lib,
|
||||||
pkgs,
|
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
@@ -24,6 +23,14 @@
|
|||||||
description = ''
|
description = ''
|
||||||
the location of the deployment.json file
|
the location of the deployment.json file
|
||||||
'';
|
'';
|
||||||
|
default = throw ''
|
||||||
|
deployment.json file generation has been removed in favor of direct selectors.
|
||||||
|
|
||||||
|
Please upgrade your clan-cli to the latest version.
|
||||||
|
|
||||||
|
The deployment data is now accessed directly from the configuration
|
||||||
|
instead of being written to a separate JSON file.
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
deployment.buildHost = lib.mkOption {
|
deployment.buildHost = lib.mkOption {
|
||||||
type = lib.types.nullOr lib.types.str;
|
type = lib.types.nullOr lib.types.str;
|
||||||
@@ -83,8 +90,5 @@
|
|||||||
inherit (config.clan.core.deployment) requireExplicitUpdate;
|
inherit (config.clan.core.deployment) requireExplicitUpdate;
|
||||||
inherit (config.system.clan.deployment) nixosMobileWorkaround;
|
inherit (config.system.clan.deployment) nixosMobileWorkaround;
|
||||||
};
|
};
|
||||||
system.clan.deployment.file = pkgs.writeText "deployment.json" (
|
|
||||||
builtins.toJSON config.system.clan.deployment.data
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,10 +73,5 @@ in
|
|||||||
) [ ] (lib.attrValues generator.files)
|
) [ ] (lib.attrValues generator.files)
|
||||||
) [ ] (lib.attrValues config.clan.core.vars.generators);
|
) [ ] (lib.attrValues config.clan.core.vars.generators);
|
||||||
|
|
||||||
system.clan.deployment.data = {
|
|
||||||
vars = config.clan.core.vars._serialized;
|
|
||||||
inherit (config.clan.core.networking) targetHost buildHost;
|
|
||||||
inherit (config.clan.core.deployment) requireExplicitUpdate;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,8 +64,6 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
config = {
|
config = {
|
||||||
system.clan.deployment.data.password-store.secretLocation =
|
|
||||||
config.clan.vars.password-store.secretLocation;
|
|
||||||
clan.core.vars.settings =
|
clan.core.vars.settings =
|
||||||
lib.mkIf (config.clan.core.vars.settings.secretStore == "password-store")
|
lib.mkIf (config.clan.core.vars.settings.secretStore == "password-store")
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class SecretStore(SecretStoreBase):
|
|||||||
sops_secrets_folder(self.machine.flake_dir)
|
sops_secrets_folder(self.machine.flake_dir)
|
||||||
/ f"{self.machine.name}-age.key",
|
/ f"{self.machine.name}-age.key",
|
||||||
priv_key,
|
priv_key,
|
||||||
add_groups=self.machine.deployment["sops"]["defaultGroups"],
|
add_groups=self.machine.select("config.clan.core.sops.defaultGroups"),
|
||||||
age_plugins=load_age_plugins(self.machine.flake),
|
age_plugins=load_age_plugins(self.machine.flake),
|
||||||
)
|
)
|
||||||
add_machine(self.machine.flake_dir, self.machine.name, pub_key, False)
|
add_machine(self.machine.flake_dir, self.machine.name, pub_key, False)
|
||||||
|
|||||||
@@ -58,8 +58,11 @@ def update_command(args: argparse.Namespace) -> None:
|
|||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
|
|
||||||
def filter_machine(m: Machine) -> bool:
|
def filter_machine(m: Machine) -> bool:
|
||||||
if m.deployment.get("requireExplicitUpdate", False):
|
try:
|
||||||
return False
|
if m.select("config.clan.deployment.requireExplicitUpdate"):
|
||||||
|
return False
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# check if the machine has a target host set
|
# check if the machine has a target host set
|
||||||
@@ -96,7 +99,17 @@ def update_command(args: argparse.Namespace) -> None:
|
|||||||
args.flake.precache(
|
args.flake.precache(
|
||||||
[
|
[
|
||||||
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
||||||
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.system.clan.deployment.file",
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.deployment.requireExplicitUpdate",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.system.clan.deployment.nixosMobileWorkaround",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.facts.secretModule",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.facts.publicModule",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.settings.secretModule",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.settings.publicModule",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.facts.services",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars._serialized.generators",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.facts.secretUploadDirectory",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.vars.password-store.secretLocation",
|
||||||
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.settings.passBackend",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -535,7 +535,6 @@ def generate_command(args: argparse.Namespace) -> None:
|
|||||||
args.flake.precache(
|
args.flake.precache(
|
||||||
[
|
[
|
||||||
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
||||||
f"clanInternals.machines.{system}.{{{','.join(machine_names)}}}.config.system.clan.deployment.file",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
has_changed = generate_vars(
|
has_changed = generate_vars(
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ class SecretStore(StoreBase):
|
|||||||
# TODO get the path to the secrets from the machine
|
# TODO get the path to the secrets from the machine
|
||||||
[
|
[
|
||||||
"cat",
|
"cat",
|
||||||
f"{self.machine.deployment['password-store']['secretLocation']}/.{self._store_backend}_info",
|
f"{self.machine.select('config.clan.vars.password-store.secretLocation')}/.{self._store_backend}_info",
|
||||||
],
|
],
|
||||||
RunOpts(log=Log.STDERR, check=False),
|
RunOpts(log=Log.STDERR, check=False),
|
||||||
).stdout.strip()
|
).stdout.strip()
|
||||||
@@ -237,6 +237,6 @@ class SecretStore(StoreBase):
|
|||||||
pass_dir = Path(_tempdir).resolve()
|
pass_dir = Path(_tempdir).resolve()
|
||||||
self.populate_dir(pass_dir, phases)
|
self.populate_dir(pass_dir, phases)
|
||||||
upload_dir = Path(
|
upload_dir = Path(
|
||||||
self.machine.deployment["password-store"]["secretLocation"]
|
self.machine.select("config.clan.vars.password-store.secretLocation")
|
||||||
)
|
)
|
||||||
upload(host, pass_dir, upload_dir)
|
upload(host, pass_dir, upload_dir)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ class SecretStore(StoreBase):
|
|||||||
sops_secrets_folder(self.machine.flake_dir)
|
sops_secrets_folder(self.machine.flake_dir)
|
||||||
/ f"{self.machine.name}-age.key",
|
/ f"{self.machine.name}-age.key",
|
||||||
priv_key,
|
priv_key,
|
||||||
add_groups=self.machine.deployment["sops"]["defaultGroups"],
|
add_groups=self.machine.select("config.clan.core.sops.defaultGroups"),
|
||||||
age_plugins=load_age_plugins(self.machine.flake),
|
age_plugins=load_age_plugins(self.machine.flake),
|
||||||
)
|
)
|
||||||
add_machine(self.machine.flake_dir, self.machine.name, pub_key, False)
|
add_machine(self.machine.flake_dir, self.machine.name, pub_key, False)
|
||||||
@@ -158,7 +158,7 @@ class SecretStore(StoreBase):
|
|||||||
secret_folder,
|
secret_folder,
|
||||||
value,
|
value,
|
||||||
add_machines=[self.machine.name] if var.deploy else [],
|
add_machines=[self.machine.name] if var.deploy else [],
|
||||||
add_groups=self.machine.deployment["sops"]["defaultGroups"],
|
add_groups=self.machine.select("config.clan.core.sops.defaultGroups"),
|
||||||
git_commit=False,
|
git_commit=False,
|
||||||
age_plugins=load_age_plugins(self.machine.flake),
|
age_plugins=load_age_plugins(self.machine.flake),
|
||||||
)
|
)
|
||||||
@@ -259,7 +259,7 @@ class SecretStore(StoreBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
keys = collect_keys_for_path(path)
|
keys = collect_keys_for_path(path)
|
||||||
for group in self.machine.deployment["sops"]["defaultGroups"]:
|
for group in self.machine.select("config.clan.core.sops.defaultGroups"):
|
||||||
keys.update(
|
keys.update(
|
||||||
collect_keys_for_type(
|
collect_keys_for_type(
|
||||||
self.machine.flake_dir / "sops" / "groups" / group / "machines"
|
self.machine.flake_dir / "sops" / "groups" / group / "machines"
|
||||||
@@ -314,7 +314,7 @@ class SecretStore(StoreBase):
|
|||||||
|
|
||||||
age_plugins = load_age_plugins(self.machine.flake)
|
age_plugins = load_age_plugins(self.machine.flake)
|
||||||
|
|
||||||
for group in self.machine.deployment["sops"]["defaultGroups"]:
|
for group in self.machine.select("config.clan.core.sops.defaultGroups"):
|
||||||
allow_member(
|
allow_member(
|
||||||
groups_folder(secret_path),
|
groups_folder(secret_path),
|
||||||
sops_groups_folder(self.machine.flake_dir),
|
sops_groups_folder(self.machine.flake_dir),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import importlib
|
import importlib
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
@@ -15,7 +14,7 @@ from clan_lib.api import API
|
|||||||
from clan_lib.errors import ClanCmdError, ClanError
|
from clan_lib.errors import ClanCmdError, ClanError
|
||||||
from clan_lib.flake import Flake
|
from clan_lib.flake import Flake
|
||||||
from clan_lib.machines.actions import get_machine
|
from clan_lib.machines.actions import get_machine
|
||||||
from clan_lib.nix import nix_config, nix_test_store
|
from clan_lib.nix import nix_config
|
||||||
from clan_lib.nix_models.clan import InventoryMachine
|
from clan_lib.nix_models.clan import InventoryMachine
|
||||||
from clan_lib.ssh.remote import Remote
|
from clan_lib.ssh.remote import Remote
|
||||||
|
|
||||||
@@ -79,58 +78,57 @@ class Machine:
|
|||||||
f'{self._class_}Configurations."{self.name}".pkgs.hostPlatform.system'
|
f'{self._class_}Configurations."{self.name}".pkgs.hostPlatform.system'
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def deployment(self) -> dict:
|
|
||||||
output = Path(self.select("config.system.clan.deployment.file"))
|
|
||||||
if tmp_store := nix_test_store():
|
|
||||||
output = tmp_store.joinpath(*output.parts[1:])
|
|
||||||
deployment = json.loads(output.read_text())
|
|
||||||
return deployment
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def secret_facts_store(self) -> facts_secret_modules.SecretStoreBase:
|
def secret_facts_store(self) -> facts_secret_modules.SecretStoreBase:
|
||||||
module = importlib.import_module(self.deployment["facts"]["secretModule"])
|
secret_module = self.select("config.clan.core.facts.secretModule")
|
||||||
|
module = importlib.import_module(secret_module)
|
||||||
return module.SecretStore(machine=self)
|
return module.SecretStore(machine=self)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def public_facts_store(self) -> facts_public_modules.FactStoreBase:
|
def public_facts_store(self) -> facts_public_modules.FactStoreBase:
|
||||||
module = importlib.import_module(self.deployment["facts"]["publicModule"])
|
public_module = self.select("config.clan.core.facts.publicModule")
|
||||||
|
module = importlib.import_module(public_module)
|
||||||
return module.FactStore(machine=self)
|
return module.FactStore(machine=self)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def secret_vars_store(self) -> StoreBase:
|
def secret_vars_store(self) -> StoreBase:
|
||||||
module = importlib.import_module(self.deployment["vars"]["secretModule"])
|
secret_module = self.select("config.clan.core.vars.settings.secretModule")
|
||||||
|
module = importlib.import_module(secret_module)
|
||||||
return module.SecretStore(machine=self)
|
return module.SecretStore(machine=self)
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def public_vars_store(self) -> StoreBase:
|
def public_vars_store(self) -> StoreBase:
|
||||||
module = importlib.import_module(self.deployment["vars"]["publicModule"])
|
public_module = self.select("config.clan.core.vars.settings.publicModule")
|
||||||
|
module = importlib.import_module(public_module)
|
||||||
return module.FactStore(machine=self)
|
return module.FactStore(machine=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def facts_data(self) -> dict[str, dict[str, Any]]:
|
def facts_data(self) -> dict[str, dict[str, Any]]:
|
||||||
if self.deployment["facts"]["services"]:
|
services = self.select("config.clan.core.facts.services")
|
||||||
return self.deployment["facts"]["services"]
|
if services:
|
||||||
|
return services
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
def vars_generators(self) -> list["Generator"]:
|
def vars_generators(self) -> list["Generator"]:
|
||||||
from clan_cli.vars.generate import Generator
|
from clan_cli.vars.generate import Generator
|
||||||
|
|
||||||
clan_vars = self.deployment.get("vars")
|
try:
|
||||||
if clan_vars is None:
|
generators_data = self.select(
|
||||||
|
"config.clan.core.vars._serialized.generators"
|
||||||
|
)
|
||||||
|
if generators_data is None:
|
||||||
|
return []
|
||||||
|
_generators = [Generator.from_json(gen) for gen in generators_data.values()]
|
||||||
|
for gen in _generators:
|
||||||
|
gen.machine(self)
|
||||||
|
except Exception:
|
||||||
return []
|
return []
|
||||||
generators: dict[str, Any] = clan_vars.get("generators")
|
else:
|
||||||
if generators is None:
|
return _generators
|
||||||
return []
|
|
||||||
_generators = [Generator.from_json(gen) for gen in generators.values()]
|
|
||||||
for gen in _generators:
|
|
||||||
gen.machine(self)
|
|
||||||
|
|
||||||
return _generators
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def secrets_upload_directory(self) -> str:
|
def secrets_upload_directory(self) -> str:
|
||||||
return self.deployment["facts"]["secretUploadDirectory"]
|
return self.select("config.clan.core.facts.secretUploadDirectory")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def flake_dir(self) -> Path:
|
def flake_dir(self) -> Path:
|
||||||
|
|||||||
@@ -184,7 +184,12 @@ def deploy_machine(
|
|||||||
|
|
||||||
# retry nixos-rebuild switch if the first attempt failed
|
# retry nixos-rebuild switch if the first attempt failed
|
||||||
if ret.returncode != 0:
|
if ret.returncode != 0:
|
||||||
is_mobile = machine.deployment.get("nixosMobileWorkaround", False)
|
try:
|
||||||
|
is_mobile = machine.select(
|
||||||
|
"config.system.clan.deployment.nixosMobileWorkaround"
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
is_mobile = False
|
||||||
# if the machine is mobile, we retry to deploy with the mobile workaround method
|
# if the machine is mobile, we retry to deploy with the mobile workaround method
|
||||||
if is_mobile:
|
if is_mobile:
|
||||||
machine.info(
|
machine.info(
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ def main() -> None:
|
|||||||
flake.precache(
|
flake.precache(
|
||||||
[
|
[
|
||||||
f"checks.{test_system}.{opts.check_attr}.machinesCross.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
f"checks.{test_system}.{opts.check_attr}.machinesCross.{system}.{{{','.join(machine_names)}}}.config.clan.core.vars.generators.*.validationHash",
|
||||||
f"checks.{test_system}.{opts.check_attr}.machinesCross.{system}.{{{','.join(machine_names)}}}.config.system.clan.deployment.file",
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user