do not instantiate vars_generators several times

We should really not have any property that has side effects i.e.
spawning processes.
This commit is contained in:
Jörg Thalheim
2025-05-14 09:09:40 +02:00
parent 75fa7ac609
commit b5d132b193
9 changed files with 25 additions and 23 deletions

View File

@@ -91,7 +91,7 @@ def flash_machine(
"users": {"root": {"openssh": {"authorizedKeys": {"keys": root_keys}}}} "users": {"root": {"openssh": {"authorizedKeys": {"keys": root_keys}}}}
} }
for generator in machine.vars_generators: for generator in machine.vars_generators():
for file in generator.files: for file in generator.files:
if file.needed_for == "partitioning": if file.needed_for == "partitioning":
msg = f"Partitioning time secrets are not supported with `clan flash write`: clan.core.vars.generators.{generator.name}.files.{file.name}" msg = f"Partitioning time secrets are not supported with `clan flash write`: clan.core.vars.generators.{generator.name}.files.{file.name}"

View File

@@ -123,7 +123,6 @@ class Machine:
return self.deployment["facts"]["services"] return self.deployment["facts"]["services"]
return {} return {}
@property
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

View File

@@ -105,7 +105,7 @@ def test_add_module_to_inventory(
generator = None generator = None
for gen in machine.vars_generators: for gen in machine.vars_generators():
if gen.name == "borgbackup": if gen.name == "borgbackup":
generator = gen generator = gen
break break

View File

@@ -33,7 +33,7 @@ def vars_status(machine: Machine, generator_name: None | str = None) -> VarStatu
# signals if a var needs to be updated (eg. needs re-encryption due to new users added) # signals if a var needs to be updated (eg. needs re-encryption due to new users added)
unfixed_secret_vars = [] unfixed_secret_vars = []
invalid_generators = [] invalid_generators = []
generators = machine.vars_generators generators = machine.vars_generators()
if generator_name: if generator_name:
for generator in generators: for generator in generators:
if generator_name == generator.name: if generator_name == generator.name:

View File

@@ -9,7 +9,7 @@ log = logging.getLogger(__name__)
def fix_vars(machine: Machine, generator_name: None | str = None) -> None: def fix_vars(machine: Machine, generator_name: None | str = None) -> None:
generators = machine.vars_generators generators = machine.vars_generators()
if generator_name: if generator_name:
for generator in generators: for generator in generators:
if generator_name == generator.name: if generator_name == generator.name:

View File

@@ -132,7 +132,7 @@ def decrypt_dependencies(
decrypted_dependencies: dict[str, Any] = {} decrypted_dependencies: dict[str, Any] = {}
for generator_name in set(generator.dependencies): for generator_name in set(generator.dependencies):
decrypted_dependencies[generator_name] = {} decrypted_dependencies[generator_name] = {}
for dep_generator in machine.vars_generators: for dep_generator in machine.vars_generators():
if generator_name == dep_generator.name: if generator_name == dep_generator.name:
break break
else: else:
@@ -320,7 +320,7 @@ def get_closure(
) -> list[Generator]: ) -> list[Generator]:
from .graph import all_missing_closure, full_closure from .graph import all_missing_closure, full_closure
vars_generators = machine.vars_generators vars_generators = machine.vars_generators()
generators: dict[str, Generator] = { generators: dict[str, Generator] = {
generator.name: generator for generator in vars_generators generator.name: generator for generator in vars_generators
} }
@@ -399,7 +399,7 @@ def generate_vars_for_machine(
machine = Machine(name=machine_name, flake=Flake(str(base_dir))) machine = Machine(name=machine_name, flake=Flake(str(base_dir)))
generators_set = set(generators) generators_set = set(generators)
generators_ = [g for g in machine.vars_generators if g.name in generators_set] generators_ = [g for g in machine.vars_generators() if g.name in generators_set]
return _generate_vars_for_machine( return _generate_vars_for_machine(
machine=machine, machine=machine,
@@ -417,7 +417,7 @@ def generate_vars_for_machine_interactive(
) -> bool: ) -> bool:
_generator = None _generator = None
if generator_name: if generator_name:
for generator in machine.vars_generators: for generator in machine.vars_generators():
if generator.name == generator_name: if generator.name == generator_name:
_generator = generator _generator = generator
break break

View File

@@ -19,7 +19,7 @@ def get_vars(base_dir: str, machine_name: str) -> list[Var]:
pub_store = machine.public_vars_store pub_store = machine.public_vars_store
sec_store = machine.secret_vars_store sec_store = machine.secret_vars_store
all_vars = [] all_vars = []
for generator in machine.vars_generators: for generator in machine.vars_generators():
for var in generator.files: for var in generator.files:
if var.secret: if var.secret:
var.store(sec_store) var.store(sec_store)
@@ -50,7 +50,7 @@ def _get_previous_value(
@API.register @API.register
def get_generators(base_dir: str, machine_name: str) -> list[Generator]: def get_generators(base_dir: str, machine_name: str) -> list[Generator]:
machine = Machine(name=machine_name, flake=Flake(base_dir)) machine = Machine(name=machine_name, flake=Flake(base_dir))
generators: list[Generator] = machine.vars_generators generators: list[Generator] = machine.vars_generators()
for generator in generators: for generator in generators:
for prompt in generator.prompts: for prompt in generator.prompts:
prompt.previous_value = _get_previous_value(machine, generator, prompt) prompt.previous_value = _get_previous_value(machine, generator, prompt)
@@ -66,7 +66,7 @@ def set_prompts(
) -> None: ) -> None:
machine = Machine(name=machine_name, flake=Flake(base_dir)) machine = Machine(name=machine_name, flake=Flake(base_dir))
for update in updates: for update in updates:
for generator in machine.vars_generators: for generator in machine.vars_generators():
if generator.name == update.generator: if generator.name == update.generator:
break break
else: else:

View File

@@ -141,7 +141,7 @@ class SecretStore(StoreBase):
hashes.sort() hashes.sort()
manifest = [] manifest = []
for generator in self.machine.vars_generators: for generator in self.machine.vars_generators():
for file in generator.files: for file in generator.files:
manifest.append(f"{generator.name}/{file.name}".encode()) manifest.append(f"{generator.name}/{file.name}".encode())
manifest += hashes manifest += hashes
@@ -165,11 +165,12 @@ class SecretStore(StoreBase):
return local_hash.decode() != remote_hash return local_hash.decode() != remote_hash
def populate_dir(self, output_dir: Path, phases: list[str]) -> None: def populate_dir(self, output_dir: Path, phases: list[str]) -> None:
vars_generators = self.machine.vars_generators()
if "users" in phases: if "users" in phases:
with tarfile.open( with tarfile.open(
output_dir / "secrets_for_users.tar.gz", "w:gz" output_dir / "secrets_for_users.tar.gz", "w:gz"
) as user_tar: ) as user_tar:
for generator in self.machine.vars_generators: for generator in vars_generators:
dir_exists = False dir_exists = False
for file in generator.files: for file in generator.files:
if not file.deploy: if not file.deploy:
@@ -184,7 +185,7 @@ class SecretStore(StoreBase):
if "services" in phases: if "services" in phases:
with tarfile.open(output_dir / "secrets.tar.gz", "w:gz") as tar: with tarfile.open(output_dir / "secrets.tar.gz", "w:gz") as tar:
for generator in self.machine.vars_generators: for generator in vars_generators:
dir_exists = False dir_exists = False
for file in generator.files: for file in generator.files:
if not file.deploy: if not file.deploy:
@@ -205,7 +206,7 @@ class SecretStore(StoreBase):
tar_file.gname = file.group tar_file.gname = file.group
tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content)) tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content))
if "activation" in phases: if "activation" in phases:
for generator in self.machine.vars_generators: for generator in vars_generators:
for file in generator.files: for file in generator.files:
if file.needed_for == "activation": if file.needed_for == "activation":
out_file = ( out_file = (
@@ -214,7 +215,7 @@ class SecretStore(StoreBase):
out_file.parent.mkdir(parents=True, exist_ok=True) out_file.parent.mkdir(parents=True, exist_ok=True)
out_file.write_bytes(self.get(generator, file.name)) out_file.write_bytes(self.get(generator, file.name))
if "partitioning" in phases: if "partitioning" in phases:
for generator in self.machine.vars_generators: for generator in vars_generators:
for file in generator.files: for file in generator.files:
if file.needed_for == "partitioning": if file.needed_for == "partitioning":
out_file = ( out_file = (

View File

@@ -51,10 +51,11 @@ class SecretStore(StoreBase):
self.machine = machine self.machine = machine
# no need to generate keys if we don't manage secrets # no need to generate keys if we don't manage secrets
if not self.machine.vars_generators: vars_generators = self.machine.vars_generators()
if not vars_generators:
return return
has_secrets = False has_secrets = False
for generator in self.machine.vars_generators: for generator in vars_generators:
for file in generator.files: for file in generator.files:
if file.secret: if file.secret:
has_secrets = True has_secrets = True
@@ -108,7 +109,7 @@ class SecretStore(StoreBase):
""" """
if generator is None: if generator is None:
generators = self.machine.vars_generators generators = self.machine.vars_generators()
else: else:
generators = [generator] generators = [generator]
file_found = False file_found = False
@@ -179,6 +180,7 @@ class SecretStore(StoreBase):
return [store_folder] return [store_folder]
def populate_dir(self, output_dir: Path, phases: list[str]) -> None: def populate_dir(self, output_dir: Path, phases: list[str]) -> None:
vars_generators = self.machine.vars_generators()
if "users" in phases or "services" in phases: if "users" in phases or "services" in phases:
key_name = f"{self.machine.name}-age.key" key_name = f"{self.machine.name}-age.key"
if not has_secret(sops_secrets_folder(self.machine.flake_dir) / key_name): if not has_secret(sops_secrets_folder(self.machine.flake_dir) / key_name):
@@ -192,7 +194,7 @@ class SecretStore(StoreBase):
(output_dir / "key.txt").write_text(key) (output_dir / "key.txt").write_text(key)
if "activation" in phases: if "activation" in phases:
for generator in self.machine.vars_generators: for generator in vars_generators:
for file in generator.files: for file in generator.files:
if file.needed_for == "activation": if file.needed_for == "activation":
target_path = ( target_path = (
@@ -208,7 +210,7 @@ class SecretStore(StoreBase):
target_path.chmod(file.mode) target_path.chmod(file.mode)
if "partitioning" in phases: if "partitioning" in phases:
for generator in self.machine.vars_generators: for generator in vars_generators:
for file in generator.files: for file in generator.files:
if file.needed_for == "partitioning": if file.needed_for == "partitioning":
target_path = output_dir / generator.name / file.name target_path = output_dir / generator.name / file.name
@@ -284,7 +286,7 @@ class SecretStore(StoreBase):
from clan_cli.secrets.secrets import update_keys from clan_cli.secrets.secrets import update_keys
if generator is None: if generator is None:
generators = self.machine.vars_generators generators = self.machine.vars_generators()
else: else:
generators = [generator] generators = [generator]
file_found = False file_found = False