docker-tidy/dockertidy/docker_autostop.py

104 lines
2.8 KiB
Python
Raw Normal View History

2020-03-01 17:42:29 +00:00
#!/usr/bin/env python3
"""Stop long running docker iamges."""
2015-06-30 22:33:43 +00:00
import argparse
import logging
import sys
import dateutil.parser
import docker
import docker.errors
import requests.exceptions
from docker.utils import kwargs_from_env
2020-03-01 17:42:29 +00:00
from docker_custodian.args import timedelta_type
2015-06-30 22:33:43 +00:00
log = logging.getLogger(__name__)
def stop_containers(client, max_run_time, matcher, dry_run):
for container_summary in client.containers():
2020-03-01 17:42:29 +00:00
container = client.inspect_container(container_summary["Id"])
name = container["Name"].lstrip("/")
2015-06-30 22:33:43 +00:00
if (
2020-03-01 17:42:29 +00:00
matcher(name) and has_been_running_since(container, max_run_time)
2015-06-30 22:33:43 +00:00
):
log.info("Stopping container %s %s: running since %s" % (
2020-03-01 17:42:29 +00:00
container["Id"][:16],
2015-06-30 22:33:43 +00:00
name,
2020-03-01 17:42:29 +00:00
container["State"]["StartedAt"]))
2015-06-30 22:33:43 +00:00
if not dry_run:
2020-03-01 17:42:29 +00:00
stop_container(client, container["Id"])
2015-06-30 22:33:43 +00:00
2020-03-01 17:42:29 +00:00
def stop_container(client, cid):
2015-06-30 22:33:43 +00:00
try:
2020-03-01 17:42:29 +00:00
client.stop(cid)
2015-06-30 22:33:43 +00:00
except requests.exceptions.Timeout as e:
2020-03-01 17:42:29 +00:00
log.warn("Failed to stop container %s: %s" % (cid, e))
2015-06-30 22:33:43 +00:00
except docker.errors.APIError as ae:
2020-03-01 17:42:29 +00:00
log.warn("Error stopping %s: %s" % (cid, ae))
2015-06-30 22:33:43 +00:00
def build_container_matcher(prefixes):
def matcher(name):
return any(name.startswith(prefix) for prefix in prefixes)
return matcher
def has_been_running_since(container, min_time):
2020-03-01 17:42:29 +00:00
started_at = container.get("State", {}).get("StartedAt")
2015-06-30 22:33:43 +00:00
if not started_at:
return False
return dateutil.parser.parse(started_at) <= min_time
def main():
logging.basicConfig(
level=logging.INFO,
format="%(message)s",
stream=sys.stdout)
opts = get_opts()
2020-03-01 17:42:29 +00:00
client = docker.APIClient(version="auto",
timeout=opts.timeout,
**kwargs_from_env())
2015-06-30 22:33:43 +00:00
matcher = build_container_matcher(opts.prefix)
stop_containers(client, opts.max_run_time, matcher, opts.dry_run)
def get_opts(args=None):
parser = argparse.ArgumentParser()
parser.add_argument(
2020-03-01 17:42:29 +00:00
"--max-run-time",
2015-06-30 22:33:43 +00:00
type=timedelta_type,
help="Maximum time a container is allows to run. Time may "
"be specified in any pytimeparse supported format."
)
2015-06-30 22:33:43 +00:00
parser.add_argument(
2020-03-01 17:42:29 +00:00
"--prefix", action="append", default=[],
2015-06-30 22:33:43 +00:00
help="Only stop containers which match one of the "
"prefix."
)
2015-06-30 22:33:43 +00:00
parser.add_argument(
2020-03-01 17:42:29 +00:00
"--dry-run", action="store_true",
help="Only log actions, don't stop anything."
)
2015-06-30 22:33:43 +00:00
parser.add_argument(
2020-03-01 17:42:29 +00:00
"-t", "--timeout", type=int, default=60,
help="HTTP timeout in seconds for making docker API calls."
)
2015-06-30 22:33:43 +00:00
opts = parser.parse_args(args=args)
if not opts.prefix:
parser.error("Running with no --prefix will match nothing.")
return opts
if __name__ == "__main__":
main()