From df5681dcd4066d082fa22c4935a353a8f095679b Mon Sep 17 00:00:00 2001 From: Felix Stupp Date: Fri, 5 Aug 2022 16:16:21 +0000 Subject: [PATCH] Add support resolving mounted volumes --- podman-compose-backup.py | 64 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/podman-compose-backup.py b/podman-compose-backup.py index 032689e..9c61f7b 100644 --- a/podman-compose-backup.py +++ b/podman-compose-backup.py @@ -54,6 +54,7 @@ from podman_compose_tools.defs.compose import ( ServiceName, ContainerName, ComposeServiceDef, + ComposeServiceVolumeDef, VolumeName, PublicVolumeName, ComposeVolumeDef, @@ -293,6 +294,13 @@ class ComposeService(ExecutorTarget): def depends_on(self) -> Sequence[ComposeService]: return [self.compose.services[name] for name in self.base.get("depends_on", [])] + @cached_property + def volume_mounts(self) -> Sequence[ComposeServiceVolume]: + return [ + ComposeServiceVolume(service=self, volume_def=volume_def) + for volume_def in self.base.get("volumes", []) + ] + def exec_cmd( self, command: CommandArgs, @@ -329,6 +337,14 @@ class ComposeVolume: "name", PublicVolumeName(f"{self.compose.project_name}_{self.name}") ) + @cached_property + def used_by(self) -> Sequence[ComposeServiceVolume]: + return [ + service_vol + for service in self.compose.services.values() + for service_vol in service.volume_mounts + ] + @cached_property def backup_config(self) -> VolumeBackupConfig: return VolumeBackupConfig.from_labels(self.inspect()["Labels"]) @@ -349,6 +365,54 @@ class ComposeVolume: ) +class ComposeServiceVolume: + + service: ComposeService + volume: ComposeVolume + read_only: bool + + def __init__( + self, + *, + service: ComposeService, + volume_def: ComposeServiceVolumeDef, + ) -> None: + self.service = service + vol_name: VolumeName + if isinstance(volume_def, str): + values = volume_def.split(sep=":", maxsplit=2) + if len(values) == 1: + # implicit volume + # TODO specialize + raise Exception(f"Do not support implicit volumes: {volume_def!r}") + if len(values) == 2: + src, _ = values + mode = "rw" # default + else: + src, _, mode = values + if mode not in {"ro", "rw"}: + # TODO specialize + raise Exception(f"Unsupported mode {mode!r} for volume {volume_def!r}") + if "/" in src: + # volume type: bind + # TODO specialize + raise Exception( + f"Unsupported volume type 'bind' for volume {volume_def!r}" + ) + # volume type: volume + vol_name = VolumeName(src) + self.read_only = mode == "ro" + else: + if volume_def["type"] != "volume": + # TODO specialize + raise Exception( + f"Unsupported volume type {volume_def['type']!r} for volume" + ) + vol_name = volume_def["source"] + self.read_only = volume_def.get("read_only", False) + self.volume = service.compose.volumes[vol_name] + + def parse_labels(labels: LabelDict) -> LabelDict: ret = dict[str, str]() for key, val in labels.items():