Coverage for src/rsnapshot_docker_compose_backup/docker.py: 74%
92 statements
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-07 01:03 +0200
« prev ^ index » next coverage.py v7.5.4, created at 2024-07-07 01:03 +0200
1from dataclasses import dataclass
2from enum import Enum, auto
3from pathlib import Path
4from typing import Any, Dict, List, Optional
6from rsnapshot_docker_compose_backup.structure.container import Container
7from rsnapshot_docker_compose_backup.structure.volume import Volume
8from rsnapshot_docker_compose_backup.utils.docker_api_client import Api
11class ContainerState(Enum):
12 CREATED = auto()
13 RESTARTING = auto()
14 RUNNING = auto()
15 REMOVING = auto()
16 PAUSED = auto()
17 EXITED = auto()
18 DEAD = auto()
20 @staticmethod
21 def from_str(value: str) -> "ContainerState":
22 for member in ContainerState:
23 if member.name.lower() == value.lower():
24 return member
25 raise ValueError("Unknown State: " + value)
28class DockerMountType(Enum):
29 VOLUME = auto()
30 BIND = auto()
31 NOT_SET = auto()
33 @staticmethod
34 def from_str(value: str) -> "DockerMountType":
35 for member in DockerMountType:
36 if member.name.lower() == value.lower():
37 return member
38 raise ValueError("Unknown Type: " + value)
41@dataclass
42class DockerMount:
43 name: Optional[str]
44 type: DockerMountType
45 source: str
46 destination: str
47 driver: Optional[str]
48 mode: str
49 rw: bool
50 propagation: str
52 @staticmethod
53 def from_json(json_data: Any) -> "DockerMount":
54 if "Name" in json_data:
55 name = json_data["Name"]
56 else:
57 name = None
58 if "Driver" in json_data:
59 driver = json_data["Driver"]
60 else:
61 driver = None
62 if "Type" in json_data:
63 mount_type = DockerMountType.from_str(json_data["Type"])
64 else:
65 mount_type = DockerMountType.NOT_SET
66 return DockerMount(
67 name=name,
68 type=mount_type,
69 source=json_data["Source"],
70 destination=json_data["Destination"],
71 driver=driver,
72 mode=json_data["Mode"],
73 rw=json_data["RW"],
74 propagation=json_data["Propagation"],
75 )
78@dataclass
79class DockerInspect:
80 id: str
81 names: List[str]
82 image: str
83 image_id: str
84 state: ContainerState
85 mounts: List[DockerMount]
86 labels: Dict[str, str]
88 @staticmethod
89 def from_json(json_data: Any) -> "DockerInspect":
90 print(json_data["Names"])
91 print(json_data["State"])
92 return DockerInspect(
93 id=json_data["Id"],
94 names=[x.lstrip("/") for x in json_data["Names"]],
95 image=json_data["Image"],
96 image_id=json_data["ImageID"],
97 state=ContainerState.from_str(json_data["State"]),
98 mounts=[DockerMount.from_json(x) for x in json_data["Mounts"]],
99 labels=json_data["Labels"],
100 )
103def inspect_container(container_id: str) -> DockerInspect:
104 # converts docker inspect to json and return only first container,
105 # because this works only with one container
106 response = Api().get(f"/containers/{container_id}/json")
107 return DockerInspect.from_json(response.json_body)
110def get_container(socket_connection: Optional[str] = None) -> List[DockerInspect]:
111 parameter = {"all": "true"}
112 if socket_connection is None:
113 api = Api()
114 else:
115 api = Api(socket_connection=socket_connection)
116 response = api.get("/containers/json", query_parameter=parameter)
117 return [DockerInspect.from_json(x) for x in response.json_body]
120def _volumes(mounts: List[DockerMount]) -> List[Volume]:
121 result: List[Volume] = []
122 for mount in mounts:
123 if mount.type == DockerMountType.VOLUME:
124 assert mount.name is not None
125 result.append(Volume(mount.name, mount.source))
126 return sorted(result)
129def get_compose_container() -> List[Container]:
130 container_list: List[Container] = []
131 for container in get_container():
132 if "com.docker.compose.project" in container.labels:
133 print(container.names[0])
134 print(container.state)
135 container_list.append(
136 Container(
137 folder=Path(
138 container.labels["com.docker.compose.project.working_dir"]
139 ),
140 container_id=container.id,
141 container_name=container.names[0], # TODO convert to list
142 running=container.state != ContainerState.EXITED,
143 service_name=container.labels["com.docker.compose.service"],
144 volumes=_volumes(container.mounts),
145 image=container.image,
146 docker_compose_file=Path(
147 container.labels["com.docker.compose.project.config_files"]
148 ), # TODO check if this can be multiple files
149 )
150 )
151 return sorted(container_list)