mirror of
https://github.com/thegeeklab/docker-tidy.git
synced 2024-11-28 07:00:36 +00:00
replace pytimeparse with dateparser
This commit is contained in:
parent
178137d0f4
commit
cc23232f32
2
Pipfile
2
Pipfile
@ -34,7 +34,6 @@ docker-pycreds = "*"
|
||||
idna = "*"
|
||||
ipaddress = "*"
|
||||
python-dateutil = "*"
|
||||
pytimeparse = "*"
|
||||
requests = "*"
|
||||
appdirs = "*"
|
||||
colorama = "*"
|
||||
@ -46,3 +45,4 @@ environs = "*"
|
||||
nested-lookup = "*"
|
||||
"ruamel.yaml" = "*"
|
||||
websocket-client = "*"
|
||||
dateparser = "*"
|
||||
|
84
Pipfile.lock
generated
84
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "bf5cf1a93672e4870e15ed4800cde2558d3915c10d294353e6e4c28c4e14524e"
|
||||
"sha256": "2655d80711d8731029d69fc90a9adf0fcad44197d18758eaffceb9a93ac38091"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@ -60,6 +60,14 @@
|
||||
"index": "pypi",
|
||||
"version": "==0.4.3"
|
||||
},
|
||||
"dateparser": {
|
||||
"hashes": [
|
||||
"sha256:1b1f0e3034f82d1f92b45fa445826da6a36d67af8a1169e04869685594276011",
|
||||
"sha256:fb5bfde4795fa4b179fe05c2c25b3981f785de26bec37e247dee1079c63d5689"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.4"
|
||||
},
|
||||
"docker": {
|
||||
"hashes": [
|
||||
"sha256:1c2ddb7a047b2599d1faec00889561316c674f7099427b9c51e8cb804114b553",
|
||||
@ -167,13 +175,38 @@
|
||||
"index": "pypi",
|
||||
"version": "==0.1.11"
|
||||
},
|
||||
"pytimeparse": {
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:04b7be6cc8bd9f5647a6325444926c3ac34ee6bc7e69da4367ba282f076036bd",
|
||||
"sha256:e86136477be924d7e670646a98561957e8ca7308d44841e21f5ddea757556a0a"
|
||||
"sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d",
|
||||
"sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.8"
|
||||
"version": "==2019.3"
|
||||
},
|
||||
"regex": {
|
||||
"hashes": [
|
||||
"sha256:01b2d70cbaed11f72e57c1cfbaca71b02e3b98f739ce33f5f26f71859ad90431",
|
||||
"sha256:046e83a8b160aff37e7034139a336b660b01dbfe58706f9d73f5cdc6b3460242",
|
||||
"sha256:113309e819634f499d0006f6200700c8209a2a8bf6bd1bdc863a4d9d6776a5d1",
|
||||
"sha256:200539b5124bc4721247a823a47d116a7a23e62cc6695744e3eb5454a8888e6d",
|
||||
"sha256:25f4ce26b68425b80a233ce7b6218743c71cf7297dbe02feab1d711a2bf90045",
|
||||
"sha256:269f0c5ff23639316b29f31df199f401e4cb87529eafff0c76828071635d417b",
|
||||
"sha256:5de40649d4f88a15c9489ed37f88f053c15400257eeb18425ac7ed0a4e119400",
|
||||
"sha256:7f78f963e62a61e294adb6ff5db901b629ef78cb2a1cfce3cf4eeba80c1c67aa",
|
||||
"sha256:82469a0c1330a4beb3d42568f82dffa32226ced006e0b063719468dcd40ffdf0",
|
||||
"sha256:8c2b7fa4d72781577ac45ab658da44c7518e6d96e2a50d04ecb0fd8f28b21d69",
|
||||
"sha256:974535648f31c2b712a6b2595969f8ab370834080e00ab24e5dbb9d19b8bfb74",
|
||||
"sha256:99272d6b6a68c7ae4391908fc15f6b8c9a6c345a46b632d7fdb7ef6c883a2bbb",
|
||||
"sha256:9b64a4cc825ec4df262050c17e18f60252cdd94742b4ba1286bcfe481f1c0f26",
|
||||
"sha256:9e9624440d754733eddbcd4614378c18713d2d9d0dc647cf9c72f64e39671be5",
|
||||
"sha256:9ff16d994309b26a1cdf666a6309c1ef51ad4f72f99d3392bcd7b7139577a1f2",
|
||||
"sha256:b33ebcd0222c1d77e61dbcd04a9fd139359bded86803063d3d2d197b796c63ce",
|
||||
"sha256:bba52d72e16a554d1894a0cc74041da50eea99a8483e591a9edf1025a66843ab",
|
||||
"sha256:bed7986547ce54d230fd8721aba6fd19459cdc6d315497b98686d0416efaff4e",
|
||||
"sha256:c7f58a0e0e13fb44623b65b01052dae8e820ed9b8b654bb6296bc9c41f571b70",
|
||||
"sha256:d58a4fa7910102500722defbde6e2816b0372a4fcc85c7e239323767c74f5cbc",
|
||||
"sha256:f1ac2dc65105a53c1c2d72b1d3e98c2464a133b4067a51a3d2477b28449709a0"
|
||||
],
|
||||
"version": "==2020.2.20"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
@ -223,6 +256,13 @@
|
||||
],
|
||||
"version": "==1.14.0"
|
||||
},
|
||||
"tzlocal": {
|
||||
"hashes": [
|
||||
"sha256:11c9f16e0a633b4b60e1eede97d8a46340d042e67b670b290ca526576e039048",
|
||||
"sha256:949b9dd5ba4be17190a80c0268167d7e6c92c62b30026cf9764caf3e308e5590"
|
||||
],
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:2f3db8b19923a873b3e5256dc9c2dedfa883e33d87c690d9c7913e1f40673cdc",
|
||||
@ -324,10 +364,10 @@
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
"sha256:8a18b4ea89d8820c5d0c7da8a64b2c324b4dabb695804dbfea19b9be9d88c0cc",
|
||||
"sha256:e345d143d80bf5ee7534056164e5e112ea5e22716bbb1ce727941f4c8b471b9a"
|
||||
],
|
||||
"version": "==7.0"
|
||||
"version": "==7.1.1"
|
||||
},
|
||||
"colorama": {
|
||||
"hashes": [
|
||||
@ -438,11 +478,11 @@
|
||||
},
|
||||
"flake8-builtins": {
|
||||
"hashes": [
|
||||
"sha256:29bc0f7e68af481d088f5c96f8aeb02520abdfc900500484e3af969f42a38a5f",
|
||||
"sha256:c44415fb19162ef3737056e700d5b99d48c3612a533943b4e16419a5d3de3a64"
|
||||
"sha256:5de3917b9b6d81e8b92d56ebc2873cc178978658848a7a16a638a6ea5842f70c",
|
||||
"sha256:b4aaa42bf503ae287c436a822374996542003ddfd73a971988b4c383652c9c58"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.2"
|
||||
"version": "==1.5.0"
|
||||
},
|
||||
"flake8-colors": {
|
||||
"hashes": [
|
||||
@ -620,10 +660,10 @@
|
||||
},
|
||||
"pip-shims": {
|
||||
"hashes": [
|
||||
"sha256:1cc3e2e4e5d5863edd4760d2032b180a6ef81719277fe95404df1bb0e58b7261",
|
||||
"sha256:b5bb01c4394a2e0260bddb4cfdc7e6fdd9d6e61c8febd18c3594e2ea2596c190"
|
||||
"sha256:2b9a88ff0fd31e7d27a362d3e36e6e75d8fbc339c9c4367f4a97b72b22e6f4f4",
|
||||
"sha256:5861da6f48e60b55d40b984795c63681e4db7ac576c1c3b05f4b54a9d508e3da"
|
||||
],
|
||||
"version": "==0.5.0"
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"pipenv-setup": {
|
||||
"hashes": [
|
||||
@ -701,11 +741,11 @@
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:0d5fe9189a148acc3c3eb2ac8e1ac0742cb7618c084f3d228baaec0c254b318d",
|
||||
"sha256:ff615c761e25eb25df19edddc0b970302d2a9091fbce0e7213298d85fb61fef6"
|
||||
"sha256:0e5b30f5cb04e887b91b1ee519fa3d89049595f428c1db76e73bd7f17b09b172",
|
||||
"sha256:84dde37075b8805f3d1f392cc47e38a0e59518fb46a431cfdaf7cf1ce805f970"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.3.5"
|
||||
"version": "==5.4.1"
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
@ -745,14 +785,6 @@
|
||||
"index": "pypi",
|
||||
"version": "==0.1.11"
|
||||
},
|
||||
"pytimeparse": {
|
||||
"hashes": [
|
||||
"sha256:04b7be6cc8bd9f5647a6325444926c3ac34ee6bc7e69da4367ba282f076036bd",
|
||||
"sha256:e86136477be924d7e670646a98561957e8ca7308d44841e21f5ddea757556a0a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.1.8"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6",
|
||||
|
@ -30,15 +30,13 @@ class DockerTidy:
|
||||
|
||||
:return: args objec
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Generate documentation from annotated Ansible roles using templates"
|
||||
)
|
||||
parser = argparse.ArgumentParser(description="keep docker hosts tidy")
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
default=None,
|
||||
dest="dry_run",
|
||||
help="Only log actions, don't stop anything."
|
||||
help="only log actions, don't stop anything"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
@ -46,7 +44,7 @@ class DockerTidy:
|
||||
type=int,
|
||||
dest="http_timeout",
|
||||
metavar="HTTP_TIMEOUT",
|
||||
help="HTTP timeout in seconds for making docker API calls."
|
||||
help="HTTP timeout in seconds for making docker API calls"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-v", dest="logging.level", action="append_const", const=-1, help="increase log level"
|
||||
@ -61,30 +59,28 @@ class DockerTidy:
|
||||
subparsers = parser.add_subparsers(dest="command", help="sub-command help")
|
||||
subparsers.required = True
|
||||
|
||||
parser_gc = subparsers.add_parser("gc", help="Run docker garbage collector.")
|
||||
parser_gc = subparsers.add_parser("gc", help="run docker garbage collector")
|
||||
parser_gc.add_argument(
|
||||
"--max-container-age",
|
||||
type=timedelta_validator,
|
||||
dest="gc.max_container_age",
|
||||
metavar="MAX_CONTAINER_AGE",
|
||||
help="Maximum age for a container. Containers older than this age "
|
||||
"will be removed. Age can be specified in any pytimeparse "
|
||||
"supported format."
|
||||
help="maximum age for a container, containers older than this age "
|
||||
"will be removed (dateparser value)"
|
||||
)
|
||||
parser_gc.add_argument(
|
||||
"--max-image-age",
|
||||
type=timedelta_validator,
|
||||
dest="gc.max_image_age",
|
||||
metavar="MAX_IMAGE_AGE",
|
||||
help="Maxium age for an image. Images older than this age will be "
|
||||
"removed. Age can be specified in any pytimeparse supported "
|
||||
"format."
|
||||
help="maxium age for an image, images older than this age will be "
|
||||
"removed (dateparser value)"
|
||||
)
|
||||
parser_gc.add_argument(
|
||||
"--dangling-volumes",
|
||||
action="store_true",
|
||||
dest="gc.dangling_volumes",
|
||||
help="Dangling volumes will be removed."
|
||||
help="dangling volumes will be removed"
|
||||
)
|
||||
parser_gc.add_argument(
|
||||
"--exclude-image",
|
||||
@ -92,7 +88,7 @@ class DockerTidy:
|
||||
type=str,
|
||||
dest="gc.exclude_images",
|
||||
metavar="EXCLUDE_IMAGE",
|
||||
help="Never remove images with this tag."
|
||||
help="never remove images with this tag"
|
||||
)
|
||||
parser_gc.add_argument(
|
||||
"--exclude-container-label",
|
||||
@ -100,20 +96,19 @@ class DockerTidy:
|
||||
type=str,
|
||||
dest="gc.exclude_container_labels",
|
||||
metavar="EXCLUDE_CONTAINER_LABEL",
|
||||
help="Never remove containers with this label key "
|
||||
help="never remove containers with this label key "
|
||||
"or label key=value"
|
||||
)
|
||||
|
||||
parser_stop = subparsers.add_parser(
|
||||
"stop", help="Stop containers that have been running for too long."
|
||||
"stop", help="stop containers that have been running for too long"
|
||||
)
|
||||
parser_stop.add_argument(
|
||||
"--max-run-time",
|
||||
type=timedelta_validator,
|
||||
dest="stop.max_run_time",
|
||||
metavar="MAX_RUN_TIME",
|
||||
help="Maximum time a container is allows to run. Time may "
|
||||
"be specified in any pytimeparse supported format."
|
||||
help="maximum time a container is allows to run (dateparser value)"
|
||||
)
|
||||
parser_stop.add_argument(
|
||||
"--prefix",
|
||||
@ -121,8 +116,7 @@ class DockerTidy:
|
||||
type=str,
|
||||
dest="stop.prefix",
|
||||
metavar="PREFIX",
|
||||
help="Only stop containers which match one of the "
|
||||
"prefix."
|
||||
help="only stop containers which match one of the prefix"
|
||||
)
|
||||
|
||||
return parser.parse_args().__dict__
|
||||
|
@ -313,7 +313,7 @@ class GarbageCollector:
|
||||
self.cleanup_volumes()
|
||||
|
||||
if (
|
||||
not config["gc"]["max_container_age"] or not config["gc"]["max_image_age"]
|
||||
or not config["gc"]["dangling_volumes"]
|
||||
not config["gc"]["max_container_age"] and not config["gc"]["max_image_age"]
|
||||
and not config["gc"]["dangling_volumes"]
|
||||
):
|
||||
self.logger.warn("Skipped, no arguments given")
|
||||
|
@ -1,52 +1,51 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Custom input type parser."""
|
||||
|
||||
import datetime
|
||||
from argparse import ArgumentTypeError
|
||||
|
||||
import dateparser
|
||||
import environs
|
||||
from dateutil import tz
|
||||
from pytimeparse import timeparse
|
||||
|
||||
env = environs.Env()
|
||||
|
||||
|
||||
def timedelta_validator(value):
|
||||
"""Return the :class:`datetime.datetime.DateTime` for a time in the past.
|
||||
"""Return the dateparser string for a time in the past.
|
||||
|
||||
:param value: a string containing a time format supported by
|
||||
mod:`pytimeparse`
|
||||
mod:`dateparser`
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
_datetime_seconds_ago(timeparse.timeparse(value))
|
||||
return value
|
||||
except TypeError:
|
||||
raise
|
||||
if not dateparser.parse(value):
|
||||
raise ArgumentTypeError("'{}' is not a valid timedelta string".format(value))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def timedelta(value, dt_format=None):
|
||||
"""Return the :class:`datetime.datetime.DateTime` for a time in the past.
|
||||
|
||||
:param value: a string containing a time format supported by
|
||||
mod:`pytimeparse`
|
||||
mod:`dateparser`
|
||||
"""
|
||||
if value is None:
|
||||
return None
|
||||
|
||||
timedelta = _datetime_seconds_ago(timeparse.timeparse(value))
|
||||
timedelta = dateparser.parse(
|
||||
value, settings={
|
||||
"TO_TIMEZONE": "UTC",
|
||||
"RETURN_AS_TIMEZONE_AWARE": True
|
||||
}
|
||||
)
|
||||
|
||||
if dt_format:
|
||||
timedelta = timedelta.strftime(dt_format)
|
||||
|
||||
return timedelta
|
||||
|
||||
|
||||
def _datetime_seconds_ago(seconds):
|
||||
now = datetime.datetime.now(tz.tzutc())
|
||||
return now - datetime.timedelta(seconds=seconds)
|
||||
|
||||
|
||||
@env.parser_for("timedelta_validator")
|
||||
def timedelta_parser(value):
|
||||
try:
|
||||
|
@ -74,18 +74,18 @@ $ docker-tidy --help
|
||||
usage: docker-tidy [-h] [--dry-run] [-t HTTP_TIMEOUT] [-v] [-q] [--version]
|
||||
{gc,stop} ...
|
||||
|
||||
Generate documentation from annotated Ansible roles using templates
|
||||
keep docker hosts tidy
|
||||
|
||||
positional arguments:
|
||||
{gc,stop} sub-command help
|
||||
gc Run docker garbage collector.
|
||||
stop Stop containers that have been running for too long.
|
||||
gc run docker garbage collector
|
||||
stop stop containers that have been running for too long
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--dry-run Only log actions, don't stop anything.
|
||||
--dry-run only log actions, don't stop anything
|
||||
-t HTTP_TIMEOUT, --timeout HTTP_TIMEOUT
|
||||
HTTP timeout in seconds for making docker API calls.
|
||||
HTTP timeout in seconds for making docker API calls
|
||||
-v increase log level
|
||||
-q decrease log level
|
||||
--version show program's version number and exit
|
||||
|
@ -13,12 +13,12 @@ than \"max age\". Running containers, and images which are used by a
|
||||
container are never removed.
|
||||
|
||||
Maximum age can be specificied with any format supported by
|
||||
[pytimeparse](https://github.com/wroberts/pytimeparse).
|
||||
[dateparser](https://dateparser.readthedocs.io/en/latest/index.html#features).
|
||||
|
||||
__Example:__
|
||||
|
||||
```Shell
|
||||
docker-tidy gc --max-container-age 3days --max-image-age 30days
|
||||
docker-tidy gc --max-container-age "3 days ago" --max-image-age "30 days ago"
|
||||
```
|
||||
|
||||
### Prevent images from being removed
|
||||
@ -58,5 +58,5 @@ If no prefix is set, __all__ containers matching the `max-run-time` will be stop
|
||||
__Example:__
|
||||
|
||||
```Shell
|
||||
docker-tidy stop --max-run-time 2days --prefix "projectprefix_"
|
||||
docker-tidy stop --max-run-time "2 days ago" --prefix "projectprefix_"
|
||||
```
|
||||
|
5
setup.py
5
setup.py
@ -69,6 +69,7 @@ setup(
|
||||
"certifi==2019.11.28",
|
||||
"chardet==3.0.4",
|
||||
"colorama==0.4.3",
|
||||
"dateparser==0.7.4",
|
||||
"docker==4.2.0",
|
||||
"docker-pycreds==0.4.0",
|
||||
"environs==7.3.0",
|
||||
@ -83,11 +84,13 @@ setup(
|
||||
"python-dateutil==2.8.1",
|
||||
"python-dotenv==0.12.0",
|
||||
"python-json-logger==0.1.11",
|
||||
"pytimeparse==1.1.8",
|
||||
"pytz==2019.3",
|
||||
"regex==2020.2.20",
|
||||
"requests==2.23.0",
|
||||
"ruamel.yaml==0.16.10",
|
||||
"ruamel.yaml.clib==0.2.0; platform_python_implementation == 'CPython' and python_version < '3.9'",
|
||||
"six==1.14.0",
|
||||
"tzlocal==2.0.0",
|
||||
"urllib3==1.25.8",
|
||||
"websocket-client==0.57.0",
|
||||
"zipp==1.2.0",
|
||||
|
Loading…
Reference in New Issue
Block a user