fix case when secrets are regenerated during update/install
This commit is contained in:
@@ -36,101 +36,101 @@ def generate_service_facts(
|
|||||||
public_facts_store: FactStoreBase,
|
public_facts_store: FactStoreBase,
|
||||||
tmpdir: Path,
|
tmpdir: Path,
|
||||||
prompt: Callable[[str], str],
|
prompt: Callable[[str], str],
|
||||||
) -> None:
|
) -> bool:
|
||||||
service_dir = tmpdir / service
|
service_dir = tmpdir / service
|
||||||
# check if all secrets exist and generate them if at least one is missing
|
# check if all secrets exist and generate them if at least one is missing
|
||||||
needs_regeneration = not check_secrets(machine, service=service)
|
needs_regeneration = not check_secrets(machine, service=service)
|
||||||
log.debug(f"{service} needs_regeneration: {needs_regeneration}")
|
log.debug(f"{service} needs_regeneration: {needs_regeneration}")
|
||||||
if needs_regeneration:
|
if not needs_regeneration:
|
||||||
if not isinstance(machine.flake, Path):
|
return False
|
||||||
msg = f"flake is not a Path: {machine.flake}"
|
if not isinstance(machine.flake, Path):
|
||||||
msg += "fact/secret generation is only supported for local flakes"
|
msg = f"flake is not a Path: {machine.flake}"
|
||||||
|
msg += "fact/secret generation is only supported for local flakes"
|
||||||
|
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
facts_dir = service_dir / "facts"
|
facts_dir = service_dir / "facts"
|
||||||
facts_dir.mkdir(parents=True)
|
facts_dir.mkdir(parents=True)
|
||||||
env["facts"] = str(facts_dir)
|
env["facts"] = str(facts_dir)
|
||||||
secrets_dir = service_dir / "secrets"
|
secrets_dir = service_dir / "secrets"
|
||||||
secrets_dir.mkdir(parents=True)
|
secrets_dir.mkdir(parents=True)
|
||||||
env["secrets"] = str(secrets_dir)
|
env["secrets"] = str(secrets_dir)
|
||||||
# compatibility for old outputs.nix users
|
# compatibility for old outputs.nix users
|
||||||
if isinstance(machine.facts_data[service]["generator"], str):
|
if isinstance(machine.facts_data[service]["generator"], str):
|
||||||
generator = machine.facts_data[service]["generator"]
|
generator = machine.facts_data[service]["generator"]
|
||||||
|
else:
|
||||||
|
generator = machine.facts_data[service]["generator"]["finalScript"]
|
||||||
|
if machine.facts_data[service]["generator"]["prompt"]:
|
||||||
|
prompt_value = prompt(machine.facts_data[service]["generator"]["prompt"])
|
||||||
|
env["prompt_value"] = prompt_value
|
||||||
|
# fmt: off
|
||||||
|
cmd = nix_shell(
|
||||||
|
[
|
||||||
|
"nixpkgs#bash",
|
||||||
|
"nixpkgs#bubblewrap",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"bwrap",
|
||||||
|
"--ro-bind", "/nix/store", "/nix/store",
|
||||||
|
"--tmpfs", "/usr/lib/systemd",
|
||||||
|
"--dev", "/dev",
|
||||||
|
"--bind", str(facts_dir), str(facts_dir),
|
||||||
|
"--bind", str(secrets_dir), str(secrets_dir),
|
||||||
|
"--unshare-all",
|
||||||
|
"--unshare-user",
|
||||||
|
"--uid", "1000",
|
||||||
|
"--",
|
||||||
|
"bash", "-c", generator
|
||||||
|
],
|
||||||
|
)
|
||||||
|
# fmt: on
|
||||||
|
run(
|
||||||
|
cmd,
|
||||||
|
env=env,
|
||||||
|
)
|
||||||
|
files_to_commit = []
|
||||||
|
# store secrets
|
||||||
|
for secret in machine.facts_data[service]["secret"]:
|
||||||
|
if isinstance(secret, str):
|
||||||
|
# TODO: This is the old NixOS module, can be dropped everyone has updated.
|
||||||
|
secret_name = secret
|
||||||
|
groups = []
|
||||||
else:
|
else:
|
||||||
generator = machine.facts_data[service]["generator"]["finalScript"]
|
secret_name = secret["name"]
|
||||||
if machine.facts_data[service]["generator"]["prompt"]:
|
groups = secret.get("groups", [])
|
||||||
prompt_value = prompt(
|
|
||||||
machine.facts_data[service]["generator"]["prompt"]
|
|
||||||
)
|
|
||||||
env["prompt_value"] = prompt_value
|
|
||||||
# fmt: off
|
|
||||||
cmd = nix_shell(
|
|
||||||
[
|
|
||||||
"nixpkgs#bash",
|
|
||||||
"nixpkgs#bubblewrap",
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"bwrap",
|
|
||||||
"--ro-bind", "/nix/store", "/nix/store",
|
|
||||||
"--tmpfs", "/usr/lib/systemd",
|
|
||||||
"--dev", "/dev",
|
|
||||||
"--bind", str(facts_dir), str(facts_dir),
|
|
||||||
"--bind", str(secrets_dir), str(secrets_dir),
|
|
||||||
"--unshare-all",
|
|
||||||
"--unshare-user",
|
|
||||||
"--uid", "1000",
|
|
||||||
"--",
|
|
||||||
"bash", "-c", generator
|
|
||||||
],
|
|
||||||
)
|
|
||||||
# fmt: on
|
|
||||||
run(
|
|
||||||
cmd,
|
|
||||||
env=env,
|
|
||||||
)
|
|
||||||
files_to_commit = []
|
|
||||||
# store secrets
|
|
||||||
for secret in machine.facts_data[service]["secret"]:
|
|
||||||
if isinstance(secret, str):
|
|
||||||
# TODO: This is the old NixOS module, can be dropped everyone has updated.
|
|
||||||
secret_name = secret
|
|
||||||
groups = []
|
|
||||||
else:
|
|
||||||
secret_name = secret["name"]
|
|
||||||
groups = secret.get("groups", [])
|
|
||||||
|
|
||||||
secret_file = secrets_dir / secret_name
|
secret_file = secrets_dir / secret_name
|
||||||
if not secret_file.is_file():
|
if not secret_file.is_file():
|
||||||
msg = f"did not generate a file for '{secret_name}' when running the following command:\n"
|
msg = f"did not generate a file for '{secret_name}' when running the following command:\n"
|
||||||
msg += generator
|
msg += generator
|
||||||
raise ClanError(msg)
|
raise ClanError(msg)
|
||||||
secret_path = secret_facts_store.set(
|
secret_path = secret_facts_store.set(
|
||||||
service, secret_name, secret_file.read_bytes(), groups
|
service, secret_name, secret_file.read_bytes(), groups
|
||||||
)
|
|
||||||
if secret_path:
|
|
||||||
files_to_commit.append(secret_path)
|
|
||||||
|
|
||||||
# store facts
|
|
||||||
for name in machine.facts_data[service]["public"]:
|
|
||||||
fact_file = facts_dir / name
|
|
||||||
if not fact_file.is_file():
|
|
||||||
msg = f"did not generate a file for '{name}' when running the following command:\n"
|
|
||||||
msg += machine.facts_data[service]["generator"]
|
|
||||||
raise ClanError(msg)
|
|
||||||
fact_file = public_facts_store.set(service, name, fact_file.read_bytes())
|
|
||||||
if fact_file:
|
|
||||||
files_to_commit.append(fact_file)
|
|
||||||
commit_files(
|
|
||||||
files_to_commit,
|
|
||||||
machine.flake_dir,
|
|
||||||
f"Update facts/secrets for service {service} in machine {machine.name}",
|
|
||||||
)
|
)
|
||||||
|
if secret_path:
|
||||||
|
files_to_commit.append(secret_path)
|
||||||
|
|
||||||
|
# store facts
|
||||||
|
for name in machine.facts_data[service]["public"]:
|
||||||
|
fact_file = facts_dir / name
|
||||||
|
if not fact_file.is_file():
|
||||||
|
msg = f"did not generate a file for '{name}' when running the following command:\n"
|
||||||
|
msg += machine.facts_data[service]["generator"]
|
||||||
|
raise ClanError(msg)
|
||||||
|
fact_file = public_facts_store.set(service, name, fact_file.read_bytes())
|
||||||
|
if fact_file:
|
||||||
|
files_to_commit.append(fact_file)
|
||||||
|
commit_files(
|
||||||
|
files_to_commit,
|
||||||
|
machine.flake_dir,
|
||||||
|
f"Update facts/secrets for service {service} in machine {machine.name}",
|
||||||
|
)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def generate_facts(
|
def generate_facts(
|
||||||
machine: Machine,
|
machine: Machine,
|
||||||
prompt: None | Callable[[str], str] = None,
|
prompt: None | Callable[[str], str] = None,
|
||||||
) -> None:
|
) -> bool:
|
||||||
secret_facts_module = importlib.import_module(machine.secret_facts_module)
|
secret_facts_module = importlib.import_module(machine.secret_facts_module)
|
||||||
secret_facts_store = secret_facts_module.SecretStore(machine=machine)
|
secret_facts_store = secret_facts_module.SecretStore(machine=machine)
|
||||||
|
|
||||||
@@ -145,10 +145,11 @@ def generate_facts(
|
|||||||
|
|
||||||
prompt = prompt_func
|
prompt = prompt_func
|
||||||
|
|
||||||
|
was_regenerated = False
|
||||||
with TemporaryDirectory() as tmp:
|
with TemporaryDirectory() as tmp:
|
||||||
tmpdir = Path(tmp)
|
tmpdir = Path(tmp)
|
||||||
for service in machine.facts_data:
|
for service in machine.facts_data:
|
||||||
generate_service_facts(
|
was_regenerated |= generate_service_facts(
|
||||||
machine=machine,
|
machine=machine,
|
||||||
service=service,
|
service=service,
|
||||||
secret_facts_store=secret_facts_store,
|
secret_facts_store=secret_facts_store,
|
||||||
@@ -157,7 +158,12 @@ def generate_facts(
|
|||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
)
|
)
|
||||||
|
|
||||||
print("successfully generated secrets")
|
if was_regenerated:
|
||||||
|
# flush caches to make sure the new secrets are available in evaluation
|
||||||
|
machine.flush_caches()
|
||||||
|
else:
|
||||||
|
print("All secrets and facts are already up to date")
|
||||||
|
return was_regenerated
|
||||||
|
|
||||||
|
|
||||||
def generate_command(args: argparse.Namespace) -> None:
|
def generate_command(args: argparse.Namespace) -> None:
|
||||||
|
|||||||
@@ -81,6 +81,12 @@ class Machine:
|
|||||||
|
|
||||||
self.vm: QMPWrapper = QMPWrapper(state_dir)
|
self.vm: QMPWrapper = QMPWrapper(state_dir)
|
||||||
|
|
||||||
|
def flush_caches(self) -> None:
|
||||||
|
self._deployment_info = None
|
||||||
|
self._flake_path = None
|
||||||
|
self.build_cache.clear()
|
||||||
|
self.eval_cache.clear()
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return f"Machine(name={self.data.name}, flake={self.data.flake_id})"
|
return f"Machine(name={self.data.name}, flake={self.data.flake_id})"
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,11 @@ def deploy_nixos(hosts: HostGroup) -> None:
|
|||||||
ssh_arg = f"-p {h.port}" if h.port else ""
|
ssh_arg = f"-p {h.port}" if h.port else ""
|
||||||
env = os.environ.copy()
|
env = os.environ.copy()
|
||||||
env["NIX_SSHOPTS"] = ssh_arg
|
env["NIX_SSHOPTS"] = ssh_arg
|
||||||
|
machine: Machine = h.meta["machine"]
|
||||||
|
|
||||||
|
generate_facts(machine)
|
||||||
|
upload_secrets(machine)
|
||||||
|
|
||||||
path = upload_sources(".", target)
|
path = upload_sources(".", target)
|
||||||
|
|
||||||
if h.host_key_check != HostKeyCheck.STRICT:
|
if h.host_key_check != HostKeyCheck.STRICT:
|
||||||
@@ -105,11 +110,6 @@ def deploy_nixos(hosts: HostGroup) -> None:
|
|||||||
|
|
||||||
ssh_arg += " -i " + h.key if h.key else ""
|
ssh_arg += " -i " + h.key if h.key else ""
|
||||||
|
|
||||||
machine: Machine = h.meta["machine"]
|
|
||||||
|
|
||||||
generate_facts(machine)
|
|
||||||
upload_secrets(machine)
|
|
||||||
|
|
||||||
extra_args = h.meta.get("extra_args", [])
|
extra_args = h.meta.get("extra_args", [])
|
||||||
cmd = [
|
cmd = [
|
||||||
"nixos-rebuild",
|
"nixos-rebuild",
|
||||||
|
|||||||
Reference in New Issue
Block a user