Last active
March 25, 2024 10:34
-
-
Save Tobiaqs/5f378ba12bbd946045c18c671ba95dbb to your computer and use it in GitHub Desktop.
Version pinning for docker-compose
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import json | |
import os | |
import subprocess | |
import sys | |
import yaml | |
if len(sys.argv) <= 1: | |
print( | |
""" | |
Run this script in your docker project folder (where | |
docker-compose.yml resides) | |
Possible flags: | |
Update hashes based on local Docker inventory. docker-compose.yml | |
and related Dockerfiles will be written to. | |
-u, --update | |
Strip (get rid of any hashes in docker-compose.yml and Dockerfiles) | |
-s, --strip | |
Update local Docker image inventory (similar to pull, but also pulls | |
images referenced in context Dockerfiles) | |
-p, --pull | |
To update all image hashes, run dhashes -p && dhashes -u | |
""" | |
) | |
exit() | |
pull = False | |
strip = False | |
if len(sys.argv) > 1 and (sys.argv[1] == "--pull" or sys.argv[1] == "-p"): | |
pull = True | |
if len(sys.argv) > 1 and (sys.argv[1] == "--strip" or sys.argv[1] == "-s"): | |
strip = True | |
def get_new_image(image): | |
image = image.split("@")[0] | |
if strip or pull: | |
return image | |
else: | |
inspection = json.loads( | |
subprocess.run( | |
["docker", "inspect", image], | |
stdout=subprocess.PIPE, | |
stderr=subprocess.DEVNULL, | |
).stdout | |
) | |
if not inspection: | |
raise RuntimeError("Run pull first, not all images are present locally") | |
return image + "@" + inspection[0]["RepoDigests"][0].split("@")[1] | |
encountered_stripped_images = [] | |
for dc_file in filter(lambda p: p.startswith("docker-compose"), os.listdir()): | |
with open(dc_file, "r") as f: | |
yaml_str = f.read() | |
doc = yaml.safe_load(yaml_str) | |
yaml_replacements = [] | |
for obj in doc["services"].values(): | |
if "build" in obj: | |
with open(obj["build"]["context"] + "/Dockerfile", "r") as df: | |
targets = [] | |
new_lines = [] | |
for line in df.read().split("\n"): | |
new_lines.append(line) | |
if line.startswith("FROM"): | |
split = line.split(" ") | |
if len(split) == 4: | |
targets.append(split[3].strip()) | |
if split[1] not in targets: | |
encountered_stripped_images.append( | |
split[1].split("@")[0].strip() | |
) | |
split[1] = get_new_image(split[1]) | |
new_lines[-1] = " ".join(split) | |
if not pull: | |
with open(obj["build"]["context"] + "/Dockerfile", "w") as df: | |
df.write("\n".join(new_lines)) | |
elif "image" in obj: | |
encountered_stripped_images.append(obj["image"].split("@")[0]) | |
yaml_str = yaml_str.replace( | |
"image: " + obj["image"] + "\n", | |
"image: " + get_new_image(obj["image"]) + "\n", | |
) | |
if not pull: | |
with open(dc_file, "w") as f: | |
f.write(yaml_str) | |
else: | |
for stripped_image in set(encountered_stripped_images): | |
print("Pulling ", stripped_image) | |
subprocess.run(["docker", "pull", stripped_image]) | |
break | |
else: | |
print("No docker-compose file found") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment