|
@@ -10,8 +10,7 @@ from typing import Any
|
|
|
is_windows = os.name == "nt"
|
|
is_windows = os.name == "nt"
|
|
|
|
|
|
|
|
|
|
|
|
|
-def read_data_sources(hostname: str, login: str) -> list[Path]:
|
|
|
|
|
- file = Path(f"./data_sources_{hostname}_{login}")
|
|
|
|
|
|
|
+def read_data_sources(file: Path) -> list[Path]:
|
|
|
with open(file) as f:
|
|
with open(file) as f:
|
|
|
paths = f.readlines()
|
|
paths = f.readlines()
|
|
|
return [Path(p_str.strip()).expanduser() for p_str in paths]
|
|
return [Path(p_str.strip()).expanduser() for p_str in paths]
|
|
@@ -68,8 +67,7 @@ class Secret:
|
|
|
return sub_class.from_line(name, *args)
|
|
return sub_class.from_line(name, *args)
|
|
|
|
|
|
|
|
@classmethod
|
|
@classmethod
|
|
|
- def read_sources(cls, hostname: str, login: str) -> list["Secret"]:
|
|
|
|
|
- file = Path(f"./secret_sources_{hostname}_{login}")
|
|
|
|
|
|
|
+ def read_sources(cls, file: Path) -> list["Secret"]:
|
|
|
with open(file) as f:
|
|
with open(file) as f:
|
|
|
lines = f.readlines()
|
|
lines = f.readlines()
|
|
|
return [cls.from_line(l.strip()) for l in lines]
|
|
return [cls.from_line(l.strip()) for l in lines]
|
|
@@ -122,6 +120,31 @@ class SecretFile(Secret):
|
|
|
return cls(host_path=path, name=name, mode=0o0400)
|
|
return cls(host_path=path, name=name, mode=0o0400)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+@dataclass
|
|
|
|
|
+class Configuration:
|
|
|
|
|
+ secret_sources: list[Secret]
|
|
|
|
|
+ data_sources: list[Path]
|
|
|
|
|
+ borgmatic_d_path: Path
|
|
|
|
|
+ borgmatic_path: Path
|
|
|
|
|
+ history_file: Path
|
|
|
|
|
+ ssh_auth_sock: Path | None
|
|
|
|
|
+
|
|
|
|
|
+ @classmethod
|
|
|
|
|
+ def read(cls, hostname: str, login: str, config_dir: Path):
|
|
|
|
|
+ secret_sources_file = config_dir / f"secret_sources_{hostname}_{login}"
|
|
|
|
|
+ data_sources_file = config_dir / f"data_sources_{hostname}_{login}"
|
|
|
|
|
+ ssh_auth_sock = os.getenv("SSH_AUTH_SOCK")
|
|
|
|
|
+
|
|
|
|
|
+ return cls(
|
|
|
|
|
+ secret_sources=Secret.read_sources(secret_sources_file),
|
|
|
|
|
+ data_sources=read_data_sources(data_sources_file),
|
|
|
|
|
+ borgmatic_d_path=config_dir / "borgmatic.d",
|
|
|
|
|
+ borgmatic_path=config_dir / "borgmatic",
|
|
|
|
|
+ history_file=config_dir / ".bash_history",
|
|
|
|
|
+ ssh_auth_sock=Path(ssh_auth_sock) if ssh_auth_sock else None
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
@dataclass
|
|
@dataclass
|
|
|
class BorgmaticContainer:
|
|
class BorgmaticContainer:
|
|
|
hostname: str
|
|
hostname: str
|
|
@@ -129,34 +152,31 @@ class BorgmaticContainer:
|
|
|
name: str
|
|
name: str
|
|
|
image: str = "ghcr.io/borgmatic-collective/borgmatic"
|
|
image: str = "ghcr.io/borgmatic-collective/borgmatic"
|
|
|
|
|
|
|
|
- def run(self, data_sources: list[Path], secret_sources: list[Secret]):
|
|
|
|
|
|
|
+ def run(self, config: Configuration):
|
|
|
container_name = f"borgmatic_{self.login}"
|
|
container_name = f"borgmatic_{self.login}"
|
|
|
- ssh_auth_sock = os.getenv("SSH_AUTH_SOCK")
|
|
|
|
|
|
|
|
|
|
- data_path = Path.cwd() / "pc_backup" / "data"
|
|
|
|
|
- config_d_path = data_path / "borgmatic.d"
|
|
|
|
|
- config_path = data_path / "borgmatic"
|
|
|
|
|
- history_file = data_path / ".bash_history"
|
|
|
|
|
- history_file.touch()
|
|
|
|
|
|
|
+ config.history_file.touch()
|
|
|
volumes = [
|
|
volumes = [
|
|
|
- f"{config_d_path}:/etc/borgmatic.d/",
|
|
|
|
|
- f"{config_path}:/etc/borgmatic/",
|
|
|
|
|
- f"{history_file}:/root/.bash_history",
|
|
|
|
|
|
|
+ f"{config.borgmatic_d_path}:/etc/borgmatic.d/",
|
|
|
|
|
+ f"{config.borgmatic_path}:/etc/borgmatic/",
|
|
|
|
|
+ f"{config.history_file}:/root/.bash_history",
|
|
|
"borg_ssh_dir:/root/.ssh",
|
|
"borg_ssh_dir:/root/.ssh",
|
|
|
"borg_config:/root/.config/borg",
|
|
"borg_config:/root/.config/borg",
|
|
|
"borg_cache:/root/.cache/borg",
|
|
"borg_cache:/root/.cache/borg",
|
|
|
"borgmatic_state:/root/.local/state/borgmatic",
|
|
"borgmatic_state:/root/.local/state/borgmatic",
|
|
|
]
|
|
]
|
|
|
- if ssh_auth_sock:
|
|
|
|
|
- volumes += [f"{ssh_auth_sock}:{ssh_auth_sock}:Z"]
|
|
|
|
|
|
|
+ if config.ssh_auth_sock:
|
|
|
|
|
+ volumes += [f"{config.ssh_auth_sock}:{config.ssh_auth_sock}:Z"]
|
|
|
|
|
|
|
|
- volumes += [f"{vol}:{self.to_source_path(vol)}:ro" for vol in data_sources]
|
|
|
|
|
|
|
+ volumes += [
|
|
|
|
|
+ f"{vol}:{self.to_source_path(vol)}:ro" for vol in config.data_sources
|
|
|
|
|
+ ]
|
|
|
|
|
|
|
|
volume_args = [a for vol in volumes for a in ["-v", vol]]
|
|
volume_args = [a for vol in volumes for a in ["-v", vol]]
|
|
|
|
|
|
|
|
secrets_args = [
|
|
secrets_args = [
|
|
|
a
|
|
a
|
|
|
- for s in secret_sources
|
|
|
|
|
|
|
+ for s in config.secret_sources
|
|
|
for a in ["--secret", f"{s.name},mode=0{s.mode:o}"]
|
|
for a in ["--secret", f"{s.name},mode=0{s.mode:o}"]
|
|
|
]
|
|
]
|
|
|
|
|
|
|
@@ -252,11 +272,10 @@ class CommandStart(Command):
|
|
|
self,
|
|
self,
|
|
|
*,
|
|
*,
|
|
|
container: BorgmaticContainer,
|
|
container: BorgmaticContainer,
|
|
|
- data_sources: list[Path],
|
|
|
|
|
- secret_sources: list[Secret],
|
|
|
|
|
|
|
+ config: Configuration,
|
|
|
**kwargs,
|
|
**kwargs,
|
|
|
):
|
|
):
|
|
|
- container.run(data_sources, secret_sources)
|
|
|
|
|
|
|
+ container.run(config)
|
|
|
|
|
|
|
|
|
|
|
|
|
class CommandRm(Command):
|
|
class CommandRm(Command):
|
|
@@ -313,10 +332,9 @@ def main():
|
|
|
login = os.getlogin()
|
|
login = os.getlogin()
|
|
|
hostname = socket.gethostname()
|
|
hostname = socket.gethostname()
|
|
|
|
|
|
|
|
- secret_sources = Secret.read_sources(hostname, login)
|
|
|
|
|
- data_sources = read_data_sources(hostname, login)
|
|
|
|
|
|
|
+ config = Configuration.read(hostname, login, Path.cwd() / "pc_backup" / "config")
|
|
|
|
|
|
|
|
- if not secret_sources:
|
|
|
|
|
|
|
+ if not config.secret_sources:
|
|
|
print("no secret required ?")
|
|
print("no secret required ?")
|
|
|
|
|
|
|
|
container = BorgmaticContainer.new(hostname, login)
|
|
container = BorgmaticContainer.new(hostname, login)
|
|
@@ -324,8 +342,9 @@ def main():
|
|
|
parser = CliArguments.new()
|
|
parser = CliArguments.new()
|
|
|
command = CliArguments.read_command(parser)
|
|
command = CliArguments.read_command(parser)
|
|
|
command.run(
|
|
command.run(
|
|
|
- secret_sources=secret_sources,
|
|
|
|
|
- data_sources=data_sources,
|
|
|
|
|
|
|
+ config=config,
|
|
|
|
|
+ secret_sources=config.secret_sources,
|
|
|
|
|
+ data_sources=config.data_sources,
|
|
|
container=container,
|
|
container=container,
|
|
|
)
|
|
)
|
|
|
|
|
|