Merge pull request 'vars: raise error when shared generators differ between machines' (#5425) from dave into main
Reviewed-on: https://git.clan.lol/clan/clan-core/pulls/5425
This commit is contained in:
@@ -1335,6 +1335,46 @@ def test_cache_misses_for_vars_operations(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.with_core
|
||||||
|
def test_shared_generator_conflicting_definition_raises_error(
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
flake_with_sops: ClanFlake,
|
||||||
|
) -> None:
|
||||||
|
"""Test that vars generation raises an error when two machines have different
|
||||||
|
definitions for the same shared generator.
|
||||||
|
"""
|
||||||
|
flake = flake_with_sops
|
||||||
|
|
||||||
|
# Create machine1 with a shared generator
|
||||||
|
machine1_config = flake.machines["machine1"] = create_test_machine_config()
|
||||||
|
shared_gen1 = machine1_config["clan"]["core"]["vars"]["generators"][
|
||||||
|
"shared_generator"
|
||||||
|
]
|
||||||
|
shared_gen1["share"] = True
|
||||||
|
shared_gen1["files"]["file1"]["secret"] = False
|
||||||
|
shared_gen1["script"] = 'echo "test" > "$out"/file1'
|
||||||
|
|
||||||
|
# Create machine2 with the same shared generator but different files
|
||||||
|
machine2_config = flake.machines["machine2"] = create_test_machine_config()
|
||||||
|
shared_gen2 = machine2_config["clan"]["core"]["vars"]["generators"][
|
||||||
|
"shared_generator"
|
||||||
|
]
|
||||||
|
shared_gen2["share"] = True
|
||||||
|
shared_gen2["files"]["file2"]["secret"] = False # Different file name
|
||||||
|
shared_gen2["script"] = 'echo "test" > "$out"/file2'
|
||||||
|
|
||||||
|
flake.refresh()
|
||||||
|
monkeypatch.chdir(flake.path)
|
||||||
|
|
||||||
|
# Attempting to generate vars for both machines should raise an error
|
||||||
|
# because they have conflicting definitions for the same shared generator
|
||||||
|
with pytest.raises(
|
||||||
|
ClanError,
|
||||||
|
match=".*differ.*",
|
||||||
|
):
|
||||||
|
cli.run(["vars", "generate", "--flake", str(flake.path)])
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.with_core
|
@pytest.mark.with_core
|
||||||
def test_dynamic_invalidation(
|
def test_dynamic_invalidation(
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
|||||||
@@ -144,6 +144,9 @@ class Generator:
|
|||||||
flake.precache(cls.get_machine_selectors(machine_names))
|
flake.precache(cls.get_machine_selectors(machine_names))
|
||||||
|
|
||||||
generators = []
|
generators = []
|
||||||
|
shared_generators_raw: dict[
|
||||||
|
str, tuple[str, dict, dict]
|
||||||
|
] = {} # name -> (machine_name, gen_data, files_data)
|
||||||
|
|
||||||
for machine_name in machine_names:
|
for machine_name in machine_names:
|
||||||
# Get all generator metadata in one select (safe fields only)
|
# Get all generator metadata in one select (safe fields only)
|
||||||
@@ -165,6 +168,38 @@ class Generator:
|
|||||||
sec_store = machine.secret_vars_store
|
sec_store = machine.secret_vars_store
|
||||||
|
|
||||||
for gen_name, gen_data in generators_data.items():
|
for gen_name, gen_data in generators_data.items():
|
||||||
|
# Check for conflicts in shared generator definitions using raw data
|
||||||
|
if gen_data["share"]:
|
||||||
|
if gen_name in shared_generators_raw:
|
||||||
|
prev_machine, prev_gen_data, prev_files_data = (
|
||||||
|
shared_generators_raw[gen_name]
|
||||||
|
)
|
||||||
|
# Compare raw data
|
||||||
|
prev_gen_files = prev_files_data.get(gen_name, {})
|
||||||
|
curr_gen_files = files_data.get(gen_name, {})
|
||||||
|
# Build list of differences with details
|
||||||
|
differences = []
|
||||||
|
if prev_gen_files != curr_gen_files:
|
||||||
|
differences.append("files")
|
||||||
|
if prev_gen_data.get("prompts") != gen_data.get("prompts"):
|
||||||
|
differences.append("prompts")
|
||||||
|
if prev_gen_data.get("dependencies") != gen_data.get(
|
||||||
|
"dependencies"
|
||||||
|
):
|
||||||
|
differences.append("dependencies")
|
||||||
|
if prev_gen_data.get("validationHash") != gen_data.get(
|
||||||
|
"validationHash"
|
||||||
|
):
|
||||||
|
differences.append("validation_hash")
|
||||||
|
if differences:
|
||||||
|
msg = f"Machines {prev_machine} and {machine_name} have different definitions for shared generator '{gen_name}' (differ in: {', '.join(differences)})"
|
||||||
|
raise ClanError(msg)
|
||||||
|
else:
|
||||||
|
shared_generators_raw[gen_name] = (
|
||||||
|
machine_name,
|
||||||
|
gen_data,
|
||||||
|
files_data,
|
||||||
|
)
|
||||||
# Build files from the files_data
|
# Build files from the files_data
|
||||||
files = []
|
files = []
|
||||||
gen_files = files_data.get(gen_name, {})
|
gen_files = files_data.get(gen_name, {})
|
||||||
@@ -216,6 +251,7 @@ class Generator:
|
|||||||
_public_store=pub_store,
|
_public_store=pub_store,
|
||||||
_secret_store=sec_store,
|
_secret_store=sec_store,
|
||||||
)
|
)
|
||||||
|
|
||||||
generators.append(generator)
|
generators.append(generator)
|
||||||
|
|
||||||
# TODO: This should be done in a non-mutable way.
|
# TODO: This should be done in a non-mutable way.
|
||||||
|
|||||||
Reference in New Issue
Block a user