Compare commits

...

1 Commits

Author SHA1 Message Date
IamTheFij 54207b4f51 Initial Python version 2020-12-01 17:04:35 -08:00
6 changed files with 169 additions and 1 deletions

2
.gitignore vendored
View File

@ -15,3 +15,5 @@
# Dependency directories (remove the comment below to include it)
# vendor/
__pycache__/
venv/

10
Dockerfile Normal file
View File

@ -0,0 +1,10 @@
FROM python:3
RUN mkdir -p /app
WORKDIR /app
COPY ./requirements.txt /app/
RUN pip install -r ./requirements.txt
COPY . /app
CMD ["python", "./main.py"]

View File

@ -1,3 +1,8 @@
# docker-check-version-updates
Checks current running containers for newer tags according to semver
Checks current running containers for newer tags according to semver
Usage:
python -m venv venv
./venv/bin/python main.py

144
main.py Normal file
View File

@ -0,0 +1,144 @@
"""
Checks to see if newer tagged versions of running images exist
When a newer tag based on semver is found, the tags will be printed and the script will exit with
a non-zero code.
"""
from dataclasses import dataclass
from typing import Generator
from typing import List
import docker # type: ignore
import requests
class NotComparableException(ValueError):
pass
@dataclass
class ImageTag(object):
image_tag: str
image: str
full_tag: str
version: str
tag_desc: str
version_parts: List[int]
@classmethod
def from_str(cls, image_tag):
image, _, full_tag = image_tag.partition(":")
version, _, tag_desc = full_tag.partition("-")
# Remove leading v
if version[0].lower() == "v":
version = version[1:]
try:
version_parts = [int(p) for p in version.split(".")]
except ValueError:
version_parts = []
return ImageTag(
image_tag=image_tag,
image=image,
full_tag=full_tag,
version=version,
tag_desc=tag_desc,
version_parts=version_parts,
)
def is_same_image(self, other):
return self.image == other.image
def is_same_type(self, other):
return self.tag_desc == other.tag_desc
def is_same_grain(self, other):
return len(self.version_parts) == len(other.version_parts)
def is_comparable(self, other):
return all(
(
self.is_same_image(other),
self.is_same_type(other),
self.is_same_grain(other),
)
)
def __eq__(self, other):
if not self.is_comparable(other):
raise NotComparableException()
return self.version_parts == other.version_parts
def __lt__(self, other):
if not self.is_comparable(other):
raise NotComparableException()
for s, o in zip(self.version_parts, other.version_parts):
if s < o:
return True
elif s > o:
return False
return False
def is_newer_than(self, other):
return self.is_comparable(other) and self > other
def get_all_tags(image_name: str) -> Generator[ImageTag, None, None]:
"""Generates all tags for a given image"""
if "/" not in image_name:
image_name = f"library/{image_name}"
url = "https://registry.hub.docker.com/v2/repositories/{}/tags".format(
image_name,
)
page_count = 0
max_pages = 1000
while url and page_count <= max_pages:
data = requests.get(url).json()
for tag in data["results"]:
try:
yield ImageTag.from_str(f"{image_name}:{tag['name']}")
except ValueError:
pass
url = data["next"]
page_count += 1
def generate_message(current: ImageTag, newer_tags: List[ImageTag]) -> str:
if not current.version_parts:
return f"[{current.image_tag}] No numeric version recognized"
if not newer_tags:
return f"[{current.image_tag}] No newer tags found for image tag"
else:
newer_tags = list(reversed(sorted(newer_tags)))
tags_list = ", ".join(tag.version for tag in newer_tags)
latest_tag = newer_tags[0].image_tag
return f"[{current.image_tag}] New versions found {tags_list}. Recommended update to {latest_tag}"
def run() -> int:
client = docker.from_env()
running_images = {container.image.tags[0]
for container in client.containers.list()}
has_update = False
for image_name in running_images:
current = ImageTag.from_str(image_name)
newer_tags: List[ImageTag] = []
if current.version_parts:
newer_tags = [
tag for tag in get_all_tags(current.image) if tag.is_newer_than(current)
]
has_update |= bool(newer_tags)
print(generate_message(current, newer_tags))
if has_update:
return 1
return 0
if __name__ == "__main__":
exit(run())

5
requirements-dev.txt Normal file
View File

@ -0,0 +1,5 @@
pyls
pyls-black
ipython
ipdb
mypy

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
requests
docker