blob: 7650d68792636bd8e0d62cb910e336569f384dea [file] [log] [blame]
Mohammed Naser8613c862023-04-24 17:26:51 -04001#!/usr/bin/env python3
2
3import argparse
4import functools
5
6from docker_image import reference
7from oslo_config import cfg
8from oslo_log import log as logging
9from ruyaml import YAML
10import requests
11
12LOG = logging.getLogger(__name__)
13CONF = cfg.CONF
14
Oleksandr Kd4e5b232024-01-18 17:20:16 +010015SKIP_IMAGE_LIST = ["secretgen_controller"]
Mohammed Naser8613c862023-04-24 17:26:51 -040016
Mohammed Naser21066a12024-01-02 11:14:53 -050017def get_digest(image_ref, token=None):
18 headers = {}
19 if token:
20 headers["Authorization"] = f"Bearer {token}"
21
22 try:
23 headers["Accept"] = "application/vnd.docker.distribution.manifest.v2+json"
24
25 r = requests.get(
26 f"https://{image_ref.domain()}/v2/{image_ref.path()}/manifests/{image_ref['tag']}",
27 timeout=5,
28 headers=headers,
29 )
30 r.raise_for_status()
31 return r.headers["Docker-Content-Digest"]
32 except requests.exceptions.HTTPError:
33 headers["Accept"] = "application/vnd.oci.image.index.v1+json"
34
35 r = requests.get(
36 f"https://{image_ref.domain()}/v2/{image_ref.path()}/manifests/{image_ref['tag']}",
37 timeout=5,
38 headers=headers,
39 )
40 r.raise_for_status()
41 return r.headers["Docker-Content-Digest"]
42
43
Mohammed Naser8613c862023-04-24 17:26:51 -040044@functools.cache
45def get_pinned_image(image_src):
46 image_ref = reference.Reference.parse(image_src)
47
Mohammed Naser21066a12024-01-02 11:14:53 -050048 if image_ref.domain() in ("registry.k8s.io", "us-docker.pkg.dev"):
49 digest = get_digest(image_ref)
50
Mohammed Naser8613c862023-04-24 17:26:51 -040051 if image_ref.domain() == "quay.io":
52 r = requests.get(
53 f"https://quay.io/api/v1/repository/{image_ref.path()}/tag/",
Mohammed Naser21066a12024-01-02 11:14:53 -050054 timeout=5,
Mohammed Naser8613c862023-04-24 17:26:51 -040055 params={"specificTag": image_ref["tag"]},
56 )
57 r.raise_for_status()
58 digest = r.json()["tags"][0]["manifest_digest"]
59
Mohammed Naser49e66372023-07-10 14:57:00 -040060 if image_ref.domain() == "docker.io":
61 # Get token for docker.io
62 r = requests.get(
63 "https://auth.docker.io/token",
Mohammed Naser21066a12024-01-02 11:14:53 -050064 timeout=5,
Mohammed Naser16baaab2023-07-10 15:07:11 -040065 params={
66 "service": "registry.docker.io",
67 "scope": f"repository:{image_ref.path()}:pull",
68 },
Mohammed Naser49e66372023-07-10 14:57:00 -040069 )
70 r.raise_for_status()
71 token = r.json()["token"]
72
73 r = requests.get(
74 f"https://registry-1.docker.io/v2/{image_ref.path()}/manifests/{image_ref['tag']}",
Mohammed Naser21066a12024-01-02 11:14:53 -050075 timeout=5,
Mohammed Naser16baaab2023-07-10 15:07:11 -040076 headers={
77 "Accept": "application/vnd.docker.distribution.manifest.v2+json",
78 "Authorization": f"Bearer {token}",
79 },
Mohammed Naser49e66372023-07-10 14:57:00 -040080 )
81 r.raise_for_status()
82 digest = r.headers["Docker-Content-Digest"]
83
Mohammed Naser21066a12024-01-02 11:14:53 -050084 if image_ref.domain() == "ghcr.io":
85 # Get token for docker.io
86 r = requests.get(
87 "https://ghcr.io/token",
88 timeout=5,
89 params={
90 "service": "ghcr.io",
91 "scope": f"repository:{image_ref.path()}:pull",
92 },
93 )
94 r.raise_for_status()
95 token = r.json()["token"]
96
97 digest = get_digest(image_ref, token=token)
98
99 return f"{image_ref.domain()}/{image_ref.path()}:{image_ref['tag']}@{digest}"
Mohammed Naser8613c862023-04-24 17:26:51 -0400100
101
102def main():
103 logging.register_options(CONF)
104 logging.setup(CONF, "atmosphere-bump-images")
105
106 parser = argparse.ArgumentParser("bump-images")
107 parser.add_argument(
108 "src", help="Path for default values file", type=argparse.FileType("r")
109 )
110 parser.add_argument("dst", help="Path for output file", type=argparse.FileType("w"))
111
112 args = parser.parse_args()
113
114 yaml = YAML(typ="rt")
115 data = yaml.load(args.src)
116
Mohammed Naser21066a12024-01-02 11:14:53 -0500117 for image in data["_atmosphere_images"]:
Oleksandr Kd4e5b232024-01-18 17:20:16 +0100118 if image in SKIP_IMAGE_LIST:
119 continue
Mohammed Naser21066a12024-01-02 11:14:53 -0500120 image_src = data["_atmosphere_images"][image]
Mohammed Naser8613c862023-04-24 17:26:51 -0400121 pinned_image = get_pinned_image(image_src)
122
123 LOG.info("Pinning image %s from %s to %s", image, image_src, pinned_image)
ricolinb8ab0172023-06-01 15:41:02 +0800124 data["_atmosphere_images"][image] = pinned_image
Mohammed Naser8613c862023-04-24 17:26:51 -0400125
126 yaml.dump(data, args.dst)
127
128
129if __name__ == "__main__":
130 main()