chore: pin openstack deps (#391)
* chore: pin openstack deps
This commit adds infrastructure to pin OpenStack images which are
tagged by release in order to ensure the exact image is used in
a specific Atmosphere release.
It also adds an Earthfile which can automatically execute the
pinning.
* fix: allow for missing groups
diff --git a/build/pin-images.py b/build/pin-images.py
new file mode 100755
index 0000000..fd9b385
--- /dev/null
+++ b/build/pin-images.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python3
+
+import argparse
+import functools
+
+from docker_image import reference
+from oslo_config import cfg
+from oslo_log import log as logging
+from ruyaml import YAML
+import requests
+
+LOG = logging.getLogger(__name__)
+CONF = cfg.CONF
+
+
+@functools.cache
+def get_pinned_image(image_src):
+ image_ref = reference.Reference.parse(image_src)
+
+ if image_ref.domain() == "quay.io":
+ r = requests.get(
+ f"https://quay.io/api/v1/repository/{image_ref.path()}/tag/",
+ params={"specificTag": image_ref["tag"]},
+ )
+ r.raise_for_status()
+ digest = r.json()["tags"][0]["manifest_digest"]
+
+ return f"{image_ref.domain()}/{image_ref.path()}@{digest}"
+
+
+def main():
+ logging.register_options(CONF)
+ logging.setup(CONF, "atmosphere-bump-images")
+
+ parser = argparse.ArgumentParser("bump-images")
+ parser.add_argument(
+ "src", help="Path for default values file", type=argparse.FileType("r")
+ )
+ parser.add_argument("dst", help="Path for output file", type=argparse.FileType("w"))
+
+ args = parser.parse_args()
+
+ yaml = YAML(typ="rt")
+ data = yaml.load(args.src)
+
+ for image in data["atmosphere_images"].ca.items:
+ token = data["atmosphere_images"].ca.get(image, 2).value
+ if not token.startswith("# image-source: "):
+ LOG.info("Skipping image %s", image)
+ continue
+
+ image_src = token.replace("# image-source: ", "").strip()
+ pinned_image = get_pinned_image(image_src)
+
+ LOG.info("Pinning image %s from %s to %s", image, image_src, pinned_image)
+ data["atmosphere_images"][image] = pinned_image
+
+ yaml.dump(data, args.dst)
+
+
+if __name__ == "__main__":
+ main()