docker-tidy/dockertidy/autostop.py

93 lines
3.1 KiB
Python
Raw Permalink Normal View History

2020-03-05 22:51:21 +00:00
#!/usr/bin/env python3
"""Stop long running docker iamges."""
import dateutil.parser
import docker.errors
import requests.exceptions
2020-11-16 00:02:32 +00:00
import docker
from dockertidy.config import SingleConfig
from dockertidy.logger import SingleLog
from dockertidy.parser import timedelta
2020-03-05 22:51:21 +00:00
class AutoStop:
2020-03-06 21:39:32 +00:00
"""Autostop object to handle long running containers."""
2020-03-05 22:51:21 +00:00
def __init__(self):
self.config = SingleConfig()
self.log = SingleLog()
self.logger = SingleLog().logger
self.docker = self._get_docker_client()
def stop_containers(self):
2020-03-06 21:39:32 +00:00
"""Identify long running containers and terminate them."""
2020-03-05 22:51:21 +00:00
client = self.docker
config = self.config.config
max_run_time = timedelta(config["stop"]["max_run_time"])
prefix = config["stop"]["prefix"]
dry_run = config["dry_run"]
matcher = self._build_container_matcher(prefix)
2020-03-09 09:25:45 +00:00
self.logger.info(
"Stopping containers older than '{}'".format(
timedelta(config["stop"]["max_run_time"], dt_format="%Y-%m-%d, %H:%M:%S")
)
)
2020-03-05 22:51:21 +00:00
for container_summary in client.containers():
container = client.inspect_container(container_summary["Id"])
name = container["Name"].lstrip("/")
2020-03-09 09:25:45 +00:00
if (
prefix and matcher(name) and self._has_been_running_since(container, max_run_time)
) or (not prefix and self._has_been_running_since(container, max_run_time)):
2020-03-05 22:51:21 +00:00
self.logger.info(
2020-04-11 12:50:11 +00:00
"Stopping container {id} {name}: running since {started}".format(
id=container["Id"][:16],
name=name,
started=container["State"]["StartedAt"]
)
2020-03-05 22:51:21 +00:00
)
if not dry_run:
self._stop_container(client, container["Id"])
def _stop_container(self, client, cid):
try:
client.stop(cid)
except requests.exceptions.Timeout as e:
2020-04-11 12:50:11 +00:00
self.logger.warn("Failed to stop container {id}: {msg}".format(id=cid, msg=str(e)))
except docker.errors.APIError as e:
self.logger.warn("Error stopping {id}: {msg}".format(id=cid, msg=str(e)))
2020-03-05 22:51:21 +00:00
def _build_container_matcher(self, prefixes):
def matcher(name):
return any(name.startswith(prefix) for prefix in prefixes)
return matcher
def _has_been_running_since(self, container, min_time):
started_at = container.get("State", {}).get("StartedAt")
if not started_at:
return False
return dateutil.parser.parse(started_at) <= min_time
def _get_docker_client(self):
config = self.config.config
2020-03-09 00:05:17 +00:00
return docker.APIClient(version="auto", timeout=config["http_timeout"])
def run(self):
"""Autostop main method."""
2020-03-09 09:25:45 +00:00
self.logger.info("Start autostop")
config = self.config.config
if config["stop"]["max_run_time"]:
self.stop_containers()
if not config["stop"]["max_run_time"]:
self.logger.warn("Skipped, no arguments given")