Loading images/docker/compose-health-check +43 −34 Original line number Diff line number Diff line Loading @@ -26,15 +26,22 @@ def get_project_containers_health(client, project): } def check_project_health(project, timeout): """Checks if a Docker Compose project is healthy. def get_unhealthy_project_containers(client, project): """Returns a list (could be empty) of containers that are not healthy or not running (in case a health check is not set).""" healths = get_project_containers_health(client, project) return [x for x in healths if healths[x] not in ["healthy", "running"]] def wait_for_project_health(project, timeout): """Wait for a Docker Compose project to be healthy. If all of the containers are healthy or running (because there's no healthcheck set), return True. If any of the containers is starting (health check hasn't run yet or in the grace period), sleep 10 and try again (ignoring the timeout). Otherwise, if haven't passed the timeout, sleep 10 and try again, if over the timeout, return if all the containers are healthy or running. healthcheck set), return an empty list. If any of the containers are starting (health check hasn't run yet or in the grace period), sleep 10 and try again (ignoring the timeout). Otherwise, if the timeout hasn't passed, sleep 10 and try again, if over the timeout, return a list of the containers that aren't healthy or aren't running. """ starttime = datetime.datetime.now() deadline = starttime + datetime.timedelta(seconds=timeout) Loading @@ -43,8 +50,8 @@ def check_project_health(project, timeout): while True: healths = get_project_containers_health(docker_client, project) # pylint: disable=no-else-return if all(map(lambda x: x in ["healthy", "running"], healths.values())): return True if not get_unhealthy_project_containers(docker_client, project): return [] elif any(map(lambda x: x == "starting", healths.values())): time.sleep(10) continue Loading @@ -53,24 +60,26 @@ def check_project_health(project, timeout): else: time.sleep(10) if all(map(lambda x: x in ["healthy", "running"], healths.values())): return True unhealthy = ", ".join( [ f"{x.id}({x.name})" for x in healths if healths[x] not in ["healthy", "running"] ] ) print(f"""Containers {unhealthy} are not healthy.""") return False return get_project_containers_health(docker_client, project) def get_project_name(args): """Returns the name of the Docker Compose project, or None if unable to.""" if args.project: return args.project env = dotenv.dotenv_values(dotenv_path=".env") if "COMPOSE_PROJECT_NAME" in env: return env["COMPOSE_PROJECT_NAME"] if "COMPOSE_PROJECT_NAME" in os.environ: return os.environ["COMPOSE_PROJECT_NAME"] return None def main(): """Main entrypoint.""" epilog = ( "The Docker Compose project name is resolved in the following order:" # noqa: E501 "The Docker Compose project name is resolved in the following order:" "\n1. From the command line parameter." "\n2. From the COMPOSE_PROJECT_NAME variable in the .env file." "\n3. From the COMPOSE_PROJECT_NAME environment variable." Loading @@ -91,21 +100,21 @@ def main(): default=300, ) args = arg_parser.parse_args() if args.project: project = args.project else: env = dotenv.dotenv_values(dotenv_path=".env") if "COMPOSE_PROJECT_NAME" in env: project = env["COMPOSE_PROJECT_NAME"] elif "COMPOSE_PROJECT_NAME" in os.environ: project = os.environ["COMPOSE_PROJECT_NAME"] else: project = get_project_name(args) if project is None: arg_parser.error( "Compose project wasn't specified, the COMPOSE_PROJECT_NAME variable is missing from the environment and from the .env file." # noqa: E501 ) if check_project_health(project, args.timeout): unhealthy = wait_for_project_health(project, args.timeout) if not unhealthy: print(f"Project {project} is healthy.") return 0 print( f"""The {", ".join(map(lambda x: x.name, unhealthy))} container for project {project} are not healthy.""" # noqa: E501 ) return 1 Loading Loading
images/docker/compose-health-check +43 −34 Original line number Diff line number Diff line Loading @@ -26,15 +26,22 @@ def get_project_containers_health(client, project): } def check_project_health(project, timeout): """Checks if a Docker Compose project is healthy. def get_unhealthy_project_containers(client, project): """Returns a list (could be empty) of containers that are not healthy or not running (in case a health check is not set).""" healths = get_project_containers_health(client, project) return [x for x in healths if healths[x] not in ["healthy", "running"]] def wait_for_project_health(project, timeout): """Wait for a Docker Compose project to be healthy. If all of the containers are healthy or running (because there's no healthcheck set), return True. If any of the containers is starting (health check hasn't run yet or in the grace period), sleep 10 and try again (ignoring the timeout). Otherwise, if haven't passed the timeout, sleep 10 and try again, if over the timeout, return if all the containers are healthy or running. healthcheck set), return an empty list. If any of the containers are starting (health check hasn't run yet or in the grace period), sleep 10 and try again (ignoring the timeout). Otherwise, if the timeout hasn't passed, sleep 10 and try again, if over the timeout, return a list of the containers that aren't healthy or aren't running. """ starttime = datetime.datetime.now() deadline = starttime + datetime.timedelta(seconds=timeout) Loading @@ -43,8 +50,8 @@ def check_project_health(project, timeout): while True: healths = get_project_containers_health(docker_client, project) # pylint: disable=no-else-return if all(map(lambda x: x in ["healthy", "running"], healths.values())): return True if not get_unhealthy_project_containers(docker_client, project): return [] elif any(map(lambda x: x == "starting", healths.values())): time.sleep(10) continue Loading @@ -53,24 +60,26 @@ def check_project_health(project, timeout): else: time.sleep(10) if all(map(lambda x: x in ["healthy", "running"], healths.values())): return True unhealthy = ", ".join( [ f"{x.id}({x.name})" for x in healths if healths[x] not in ["healthy", "running"] ] ) print(f"""Containers {unhealthy} are not healthy.""") return False return get_project_containers_health(docker_client, project) def get_project_name(args): """Returns the name of the Docker Compose project, or None if unable to.""" if args.project: return args.project env = dotenv.dotenv_values(dotenv_path=".env") if "COMPOSE_PROJECT_NAME" in env: return env["COMPOSE_PROJECT_NAME"] if "COMPOSE_PROJECT_NAME" in os.environ: return os.environ["COMPOSE_PROJECT_NAME"] return None def main(): """Main entrypoint.""" epilog = ( "The Docker Compose project name is resolved in the following order:" # noqa: E501 "The Docker Compose project name is resolved in the following order:" "\n1. From the command line parameter." "\n2. From the COMPOSE_PROJECT_NAME variable in the .env file." "\n3. From the COMPOSE_PROJECT_NAME environment variable." Loading @@ -91,21 +100,21 @@ def main(): default=300, ) args = arg_parser.parse_args() if args.project: project = args.project else: env = dotenv.dotenv_values(dotenv_path=".env") if "COMPOSE_PROJECT_NAME" in env: project = env["COMPOSE_PROJECT_NAME"] elif "COMPOSE_PROJECT_NAME" in os.environ: project = os.environ["COMPOSE_PROJECT_NAME"] else: project = get_project_name(args) if project is None: arg_parser.error( "Compose project wasn't specified, the COMPOSE_PROJECT_NAME variable is missing from the environment and from the .env file." # noqa: E501 ) if check_project_health(project, args.timeout): unhealthy = wait_for_project_health(project, args.timeout) if not unhealthy: print(f"Project {project} is healthy.") return 0 print( f"""The {", ".join(map(lambda x: x.name, unhealthy))} container for project {project} are not healthy.""" # noqa: E501 ) return 1 Loading