vars: make upload actually upload

This commit is contained in:
lassulus
2024-11-28 21:00:12 +01:00
parent d4fb4efd1f
commit 513431148e
5 changed files with 30 additions and 29 deletions

View File

@@ -13,9 +13,6 @@ class SecretStoreBase(StoreBase):
def is_secret_store(self) -> bool: def is_secret_store(self) -> bool:
return True return True
def needs_upload(self) -> bool:
return True
def ensure_machine_has_access(self, generator: "Generator", name: str) -> None: def ensure_machine_has_access(self, generator: "Generator", name: str) -> None:
pass pass
@@ -39,5 +36,9 @@ class SecretStoreBase(StoreBase):
""" """
@abstractmethod @abstractmethod
def upload(self, output_dir: Path) -> None: def populate_dir(self, output_dir: Path) -> None:
pass
@abstractmethod
def upload(self) -> None:
pass pass

View File

@@ -4,11 +4,12 @@ import os
import tarfile import tarfile
from itertools import chain from itertools import chain
from pathlib import Path from pathlib import Path
from typing import override from tempfile import TemporaryDirectory
from clan_cli.cmd import Log, RunOpts, run from clan_cli.cmd import Log, RunOpts, run
from clan_cli.machines.machines import Machine from clan_cli.machines.machines import Machine
from clan_cli.nix import nix_shell from clan_cli.nix import nix_shell
from clan_cli.ssh.upload import upload
from clan_cli.vars.generate import Generator, Var from clan_cli.vars.generate import Generator, Var
from . import SecretStoreBase from . import SecretStoreBase
@@ -131,7 +132,6 @@ class SecretStore(SecretStoreBase):
manifest += hashes manifest += hashes
return b"\n".join(manifest) return b"\n".join(manifest)
@override
def needs_upload(self) -> bool: def needs_upload(self) -> bool:
local_hash = self.generate_hash() local_hash = self.generate_hash()
remote_hash = self.machine.target_host.run( remote_hash = self.machine.target_host.run(
@@ -150,7 +150,7 @@ class SecretStore(SecretStoreBase):
return local_hash.decode() != remote_hash return local_hash.decode() != remote_hash
def upload(self, output_dir: Path) -> None: def populate_dir(self, output_dir: Path) -> None:
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 self.machine.vars_generators:
dir_exists = False dir_exists = False
@@ -173,3 +173,14 @@ class SecretStore(SecretStoreBase):
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))
(output_dir / ".pass_info").write_bytes(self.generate_hash()) (output_dir / ".pass_info").write_bytes(self.generate_hash())
def upload(self) -> None:
if not self.needs_upload():
log.info("Secrets already uploaded")
return
with TemporaryDirectory(prefix="vars-upload-") as tempdir:
pass_dir = Path(tempdir)
upload_dir = Path(
self.machine.deployment["password-store"]["secretLocation"]
)
upload(self.machine.target_host, pass_dir, upload_dir)

View File

@@ -1,5 +1,6 @@
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from tempfile import TemporaryDirectory
from typing import override from typing import override
from clan_cli.errors import ClanError from clan_cli.errors import ClanError
@@ -17,6 +18,7 @@ from clan_cli.secrets.secrets import (
encrypt_secret, encrypt_secret,
has_secret, has_secret,
) )
from clan_cli.ssh.upload import upload
from clan_cli.vars.generate import Generator from clan_cli.vars.generate import Generator
from clan_cli.vars.var import Var from clan_cli.vars.var import Var
@@ -114,7 +116,7 @@ class SecretStore(SecretStoreBase):
self.machine.flake_dir, self.secret_path(generator, name) self.machine.flake_dir, self.secret_path(generator, name)
).encode("utf-8") ).encode("utf-8")
def upload(self, output_dir: Path) -> None: def populate_dir(self, output_dir: Path) -> None:
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):
# skip uploading the secret, not managed by us # skip uploading the secret, not managed by us
@@ -125,6 +127,12 @@ class SecretStore(SecretStoreBase):
) )
(output_dir / "key.txt").write_text(key) (output_dir / "key.txt").write_text(key)
def upload(self) -> None:
with TemporaryDirectory(prefix="sops-upload-") as tempdir:
sops_upload_dir = Path(tempdir)
self.populate_dir(sops_upload_dir)
upload(self.machine.target_host, sops_upload_dir, Path("/var/lib/sops-nix"))
def exists(self, generator: Generator, name: str) -> bool: def exists(self, generator: Generator, name: str) -> bool:
secret_folder = self.secret_path(generator, name) secret_folder = self.secret_path(generator, name)
return (secret_folder / "secret").exists() return (secret_folder / "secret").exists()

View File

@@ -33,7 +33,7 @@ class SecretStore(SecretStoreBase):
secret_file = self.dir / generator.name / name secret_file = self.dir / generator.name / name
return secret_file.read_bytes() return secret_file.read_bytes()
def upload(self, output_dir: Path) -> None: def populate_dir(self, output_dir: Path) -> None:
if output_dir.exists(): if output_dir.exists():
shutil.rmtree(output_dir) shutil.rmtree(output_dir)
shutil.copytree(self.dir, output_dir) shutil.copytree(self.dir, output_dir)

View File

@@ -1,13 +1,9 @@
import argparse import argparse
import importlib import importlib
import logging import logging
from pathlib import Path
from tempfile import TemporaryDirectory
from clan_cli.completions import add_dynamic_completer, complete_machines from clan_cli.completions import add_dynamic_completer, complete_machines
from clan_cli.errors import ClanError
from clan_cli.machines.machines import Machine from clan_cli.machines.machines import Machine
from clan_cli.ssh.upload import upload
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@@ -15,22 +11,7 @@ log = logging.getLogger(__name__)
def upload_secret_vars(machine: Machine) -> None: def upload_secret_vars(machine: Machine) -> None:
secret_store_module = importlib.import_module(machine.secret_vars_module) secret_store_module = importlib.import_module(machine.secret_vars_module)
secret_store = secret_store_module.SecretStore(machine=machine) secret_store = secret_store_module.SecretStore(machine=machine)
secret_store.upload()
if not secret_store.needs_upload():
log.info("Secrets already uploaded")
return
with TemporaryDirectory(prefix="vars-upload-") as tempdir:
secret_dir = Path(tempdir)
secret_store.upload(secret_dir)
if secret_store.store_name == "password-store":
upload_dir = Path(machine.deployment["password-store"]["secretLocation"])
upload(machine.target_host, secret_dir, upload_dir)
elif secret_store.store_name == "sops":
upload_dir = Path("/var/lib/sops-nix")
upload(machine.target_host, secret_dir, upload_dir)
else:
msg = "upload function used on unsuitable secret_store"
raise ClanError(msg)
def upload_command(args: argparse.Namespace) -> None: def upload_command(args: argparse.Namespace) -> None: