From b6ba3acbaf6206deeadb935cd97d8047a5415187 Mon Sep 17 00:00:00 2001 From: Sora Date: Sat, 11 Nov 2023 22:05:25 +0100 Subject: [PATCH] still testing --- configuration.ini.example | 1 + main.py | 105 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 103 insertions(+), 3 deletions(-) diff --git a/configuration.ini.example b/configuration.ini.example index abfd934..7199d4c 100644 --- a/configuration.ini.example +++ b/configuration.ini.example @@ -1,6 +1,7 @@ [backandup] bindcludepattern=list of fixed strings bindexcludepattern=list of fixed strings +composefile=path to the docker-compose file to parse [restic] remotehost= diff --git a/main.py b/main.py index cb88cc0..35c346d 100644 --- a/main.py +++ b/main.py @@ -1,3 +1,5 @@ +import os.path + import docker import restic import yaml @@ -75,9 +77,106 @@ def stop_backup_restart_container(ct: docker.models.containers.Container): ct.start() return 0 + +def yaml_to_services_list(filepath: str) -> dict|None: + ''' + Retourne la liste des services définis dans un fichier docker-compose.yaml sous forme de liste + :param filepath: str + :return: list|None + ''' + + serviceslist = dict() + + if not os.path.isfile(filepath): + raise OSError(2, "No such file", filepath) + + ycontent = None + with open(filepath, 'r') as yfile: + try: + ycontent = yaml.load(yfile.readlines()) + except yaml.YAMLError as yerror: + print(f"{filepath} doesn't seems to be a yaml file.") + raise yerror + + if ycontent is None: + return None + + if "services" not in ycontent: + raise Exception("The file doesn't seems to be a correct docker-compose yaml") + + # on liste les services et ceux dont ils dépendent + for servicename in ycontent["services"]: + mustbefore = [] + if "depends_on" in ycontent["services"]: + for dependance in ycontent["services"]["depends_on"]: + mustbefore.append(dependance) + + serviceslist[servicename] = {"must_before": mustbefore, "must_after": None, "backupdone": False} + + # on reparcourt une seconde fois pour définir de quels services ilssont les dépendances + for service in serviceslist: + if len(serviceslist[service]["must_before"]): + for dependance in serviceslist[service]["must_before"]: + if service not in serviceslist[dependance]["must_after"]: + serviceslist[dependance]["must_after"].append(service) + + return serviceslist + + +def yaml_file_to_container_list(filepath: str) -> list|None: + ''' + Retourne le contenu d'un fichier yaml sous forme de dictionnaire + :param filepath: str + :return: dict|None + ''' + + + dependances = [] + if "depends_on" in ycontent["services"][servicename]: + dependances = ycontent["services"][servicename]["depends_on"] + + bindslist = [] + volumeslist = [] + for mount in ycontent["services"][servicename]["volumes"]: + localpart = mount.split(":") + # TODO: adapter avec pathlib pour gérer Windows + # si un /, signifie qu'il s'agit d'un chemin et donc d'un bind mount, pas volume. + if localpart.find("/") != -1: + bindslist.append(localpart) + else: + volumeslist.append(localpart) + + containersid = os.popen(f"docker-compose --file {filepath} ps --quiet {servicename}").readlines() + containersnames = os.popen(f"docker-compose --file {filepath} ps {servicename} | tail -n +3").readlines() + + containerslist = [] + for i in range(0, len(containersid)): + containerslist.append((containersnames[i], containersid[i])) + + for containerfound in containerslist: + container = {"service": servicename, + "name": containerfound[0], + "id": containerfound[1], + "binds": bindslist, + "depends_on": dependances} + + + + + + # Press the green button in the gutter to run the script. if __name__ == '__main__': - dockerhost = docker.from_env() + dockerhost = docker.from_env() + + bindcludepattern = None + bindexcludepattern = None + composefile = "/root/compose/core/docker-compose.yml" + remotehost = None + remoteuser = None + repository = None + passwordfile = None + read_config_file() - for container in dockerhost.containers.list(all=True): - stop_backup_restart_container(container) + + print(yaml_file_to_container_list(composefile))