Fix docker image hash update script (#2922)
Simplifies and improves the automated hash update process. Move away
from distro + architecture-aware update to more generic token-based
find-and-replace. This fixes a bug where arm64 image digests were not
properly updated in TF files
This generates
https://github.com/bazelbuild/continuous-integration/pull/2923.
diff --git a/buildkite/bazelci.py b/buildkite/bazelci.py
index 37f70ff..72a4b5a 100755
--- a/buildkite/bazelci.py
+++ b/buildkite/bazelci.py
@@ -343,7 +343,6 @@
]
)
-# DO_NOT_MODIFY_IMAGE_HASHES_SENTINEL_START
IMAGE_HASHES = {
"rockylinux8": {
"amd64": "sha256:bf148717fe5349e498345dbf3efc1f7690b89e310a2ae970c3bec1ab4e9cd61e",
@@ -429,7 +428,6 @@
"amd64": "sha256:e6ac038ad949be3e18573735e8a46f5ac74f2e59af2196ed50da0187ea87c259",
},
}
-# DO_NOT_MODIFY_IMAGE_HASHES_SENTINEL_END
def get_docker_image(image_name, is_arm64=False):
diff --git a/buildkite/digests.json b/buildkite/digests.json
new file mode 100644
index 0000000..3f5e34f
--- /dev/null
+++ b/buildkite/digests.json
@@ -0,0 +1,85 @@
+{
+ "rockylinux8": {
+ "amd64": "sha256:bf148717fe5349e498345dbf3efc1f7690b89e310a2ae970c3bec1ab4e9cd61e",
+ "arm64": "sha256:1b7ac73ca16e71e148bc4bb68858d0a0e44129e7f4949b8aa90be2d169ef01b9"
+ },
+ "rockylinux8-releaser": {
+ "amd64": "sha256:164d20f7df3c44789799a6cd956c535adf4a3f15b8b5a0348fd781578b4808e3",
+ "arm64": "sha256:4635e2b5f0a265c45b462c318e81928f3c2b5e02c580eddd8f5ae0dc44254005"
+ },
+ "rockylinux8-java8": {
+ "amd64": "sha256:79b0528e2ce5d3212dbd4f6b8bc6e331038e92288d379043fd941c45dab5be44",
+ "arm64": "sha256:75d11e32035ba1b4a9709431bcb5140d14de4ff455f2d2aec9d659d075d7e75c"
+ },
+ "rockylinux8-java11": {
+ "amd64": "sha256:042605c8ea1ce7bc243cb5b363d3581876c849cc8d99104e3c20ab0b80d6dd87",
+ "arm64": "sha256:ba8450e5285baf2a148b6f5647b02d0781484aa44665b68ce18c3f39dca2830e"
+ },
+ "rockylinux8-java11-devtoolset10": {
+ "amd64": "sha256:9d271aed202917c7769844eb2e2737b109541457fe387ceffc72035483f1ba44",
+ "arm64": "sha256:52002e0cc6a66c96131b10898cd67d85bab3e320261d6e73637830bab0f51fdf"
+ },
+ "debian10-java11": {
+ "amd64": "sha256:4c54ce7c02f61b8cb24a7447eb14b00e4a62f34c8afd3bd27d0c1a760bdf2a10"
+ },
+ "debian11-java17": {
+ "amd64": "sha256:42da27bb2aa6101b3e03728c0f18e20772e70f708e84d708e4f3a28ea40560d8"
+ },
+ "debian12": {
+ "amd64": "sha256:22d6fb6518a579f2fd32f07c7641df663e3d9306d68417c6623aafd9f7813963",
+ "arm64": "sha256:46b1909a9e51f6784d07df101f182b62cb9281b1009ba67276307ab15be69bd7"
+ },
+ "debian13": {
+ "amd64": "sha256:23ea24eb7c394883a7e069918896d36e9090373f27634d9cfdd30b0c6f58796d",
+ "arm64": "sha256:8143489bf8a6f7c890838ce209c0ec940f5b69cbf78aa9158d5a45ce3cf16f4c"
+ },
+ "ubuntu1604-java8": {
+ "amd64": "sha256:9e5e7c5383c4a8e919d02fd81d7197bd76e912b465511dab7b45336ca3b193d0"
+ },
+ "ubuntu1804-java11": {
+ "amd64": "sha256:25cbb00de12a00485b215440d4ef58469ba305afa54283e40f5b7a8b8ca13c0f"
+ },
+ "ubuntu2004-java11": {
+ "amd64": "sha256:da0038022a8173e05549fcd003d0af97f7e89a1ee29c6f2e19db10ae7d8dc328",
+ "arm64": "sha256:51962774622467357982690143105843a387e6c99d465778c212eecdd047f039"
+ },
+ "ubuntu2004": {
+ "amd64": "sha256:ffa90e8bad9b3952a40a0f0a9a42e3438faf0002aaa3f20cba6dd2a258ec1a56",
+ "arm64": "sha256:91b7cac1ac7ccc22a7c814a37bb7e6c4c1cb8ccf6080d6a9136afd19f31d9a85"
+ },
+ "ubuntu2204": {
+ "amd64": "sha256:2a482c928ff7527594f2e528ac3724486f9cf0fd682394b8aa2f5fed4eb9676f",
+ "arm64": "sha256:5ca61bdbd4b0f3aea8947ed9816f29b9da41a8cef9b1b2217f63724edb8a256a"
+ },
+ "ubuntu2404": {
+ "amd64": "sha256:53dd4ae8e1a2b4c070bc15fb3b60e0d30b81ccc85c6c44e18b20de992be8e9a3",
+ "arm64": "sha256:9d4c2fb2962bd49cccb2929e9bd84a9104952caadedbe80e1a7717fb139f9970"
+ },
+ "ubuntu2004-kythe": {
+ "amd64": "sha256:3862183a7674064e7e36ab851166e5a20eaccb47c8dd7205354fc8de6a6be0e9"
+ },
+ "ubuntu2204-kythe": {
+ "amd64": "sha256:3b0fe8e438faacec522eb3cfbfce116fbcddf1c4cd9a32f847217cac154e5782",
+ "arm64": "sha256:bbbf6342d9eaf7846ccf4ea9557c94dcb1c6428eafa46526370d476d907801ef"
+ },
+ "ubuntu2404-kythe": {
+ "amd64": "sha256:e64cd16e729a251538c0776ef68cf2f88eb590a05b88ff4e66fe35e8495babdf",
+ "arm64": "sha256:a3b0bc5627c3480f2529fce16403c74a245a4e5ea60986317cf31abcc1a6b98d"
+ },
+ "ubuntu2204-java17": {
+ "amd64": "sha256:793035b3e53a0fcf341c5ca541886178b04838008b8ed2e67a4c6aa17325fd8c",
+ "arm64": "sha256:ed4059cb3493cbae25cf4c82d50e0f96486e267a0b960a9c1a168e741e5c21ae"
+ },
+ "fedora39-java17": {
+ "amd64": "sha256:ea39c59f30fe9892c58f12664aa12c6d67be7b01268416cb9e7a47167ab8631d"
+ },
+ "fedora40-java21": {
+ "amd64": "sha256:0ab39f88defa6427cbfc033a3480854fcb6ac3e9de78dc1dc6918b4547d46bd0"
+ },
+ "fedora43-java25": {
+ "amd64": "sha256:04ed68b97d884184fbcc89d09e48b5acc09d18b1e10c15021e0210223d1305ae"
+ },
+ "docgen": {
+ "amd64": "sha256:e6ac038ad949be3e18573735e8a46f5ac74f2e59af2196ed50da0187ea87c259"
+ }
+}
diff --git a/buildkite/update_docker_image_hashes.py b/buildkite/update_docker_image_hashes.py
index bfa8e4b..4c31e4a 100755
--- a/buildkite/update_docker_image_hashes.py
+++ b/buildkite/update_docker_image_hashes.py
@@ -133,83 +133,28 @@
return "\n".join(lines)
-SENTINEL_START = "# DO_NOT_MODIFY_IMAGE_HASHES_SENTINEL_START"
-SENTINEL_END = "# DO_NOT_MODIFY_IMAGE_HASHES_SENTINEL_END"
+def find_replace_hashes(curr_hashes, next_hashes, files):
+ for ff in files:
+ for k in IMAGE_KEYS:
+ for arch in ["amd64", "arm64"]:
+ if arch not in curr_hashes[k] or arch not in next_hashes[k]:
+ continue
+ with open(ff, "r") as f:
+ content = f.read()
+ with open(ff, "w") as f:
+ f.write(content.replace(curr_hashes[k][arch], next_hashes[k][arch]))
-def update_bazelci_file(bazelci_path, new_image_hashes_str):
- output_lines = []
- in_sentinel_block = False
- found_start = False
- found_end = False
-
- with open(bazelci_path, "r", encoding="utf-8") as f:
- for line in f:
- if line.startswith(SENTINEL_START):
- output_lines.append(line)
- output_lines.append(f"{new_image_hashes_str}\n")
- in_sentinel_block = True
- found_start = True
- elif line.startswith(SENTINEL_END):
- in_sentinel_block = False
- output_lines.append(line)
- found_end = True
- elif not in_sentinel_block:
- output_lines.append(line)
-
- if not found_start:
- raise ValueError(f"Could not find start sentinel '{SENTINEL_START}' in {bazelci_path}")
- if not found_end:
- raise ValueError(f"Could not find end sentinel '{SENTINEL_END}' in {bazelci_path}")
-
- with open(bazelci_path, "w", encoding="utf-8") as f:
- f.writelines(output_lines)
-
-
-def update_pinned_hashes(files, image_hashes):
- pattern = re.compile(r"gcr\.io/bazel-public/([a-zA-Z0-9_\-]+)(?:@sha256:[a-f0-9]+)?")
-
- updated_files = []
- for fpath in sorted(files):
- with open(fpath, "r", encoding="utf-8") as f:
- content = f.read()
-
- def replacer(match):
- img_name = match.group(1)
- if img_name in image_hashes and "amd64" in image_hashes[img_name]:
- digest = image_hashes[img_name]["amd64"]
- return f"gcr.io/bazel-public/{img_name}@{digest}"
- return match.group(0)
-
- updated_content = pattern.sub(replacer, content)
- if updated_content != content:
- with open(fpath, "w", encoding="utf-8") as f:
- f.write(updated_content)
- updated_files.append(fpath)
-
- return updated_files
-
-
-def update_terraform_configs(terraform_dir, image_hashes):
- tf_files = list(terraform_dir.glob("**/*.tf")) + list(terraform_dir.glob("**/*.tpl"))
- return update_pinned_hashes(tf_files, image_hashes)
-
-
-def update_pipeline_ymls(pipelines_dir, image_hashes):
- pipeline_yml_files = list(pipelines_dir.glob("**/*.yml"))
- return update_pinned_hashes(pipeline_yml_files, image_hashes)
-
-
-def update_rbe_presets(rbe_file, image_hashes):
- return update_pinned_hashes([rbe_file], image_hashes)
-
-
-def update_setup_docker(setup_docker_file, image_hashes):
- return update_pinned_hashes([setup_docker_file], image_hashes)
+def get_git_root() -> str:
+ p = subprocess.run(["git", "rev-parse", "--show-toplevel"],
+ capture_output=True, text=True)
+ if p.returncode != 0:
+ raise RuntimeError("Could not determine the git root: " + p.stderr)
+ return p.stdout.strip()
def main():
- repo_root = Path(__file__).resolve().parent.parent
+ repo_root = Path(get_git_root())
bazelci_path = repo_root / "buildkite" / "bazelci.py"
terraform_dir = repo_root / "buildkite" / "terraform"
pipelines_dir = repo_root / "pipelines"
@@ -240,27 +185,21 @@
digests = fetch_all_image_digests(IMAGE_KEYS)
- new_dict_str = format_image_hashes_dict(digests)
- update_bazelci_file(bazelci_path, new_dict_str)
- print(f"Successfully updated IMAGE_HASHES in {bazelci_path}!")
+ # Load the current digests
+ digests_json_file = repo_root / "buildkite" / "digests.json"
+ with open(digests_json_file, "r") as f:
+ curr_digests = json.loads(f.read())
- updated_tf = update_terraform_configs(terraform_dir, digests)
- print(f"Successfully updated {len(updated_tf)} terraform configuration files:")
- for tf_path in updated_tf:
- print(f" - {tf_path}")
+ files_to_update = [
+ Path(repo_root / "buildkite" / "bazelci.py"),
+ rbe_presets_file,
+ setup_docker_file,
+ ] + list(terraform_dir.glob("**/*.tf")) + \
+ list(pipelines_dir.glob("**/*.yml")) + \
+ list(pipelines_dir.glob("**/*.yml.tpl"))
- updated_rbe = update_rbe_presets(rbe_presets_file, digests)
- if updated_rbe:
- print(f"Successfully updated RBE presets in {rbe_presets_file}!")
-
- updated_pipelines = update_pipeline_ymls(pipelines_dir, digests)
- print(f"Successfully updated {len(updated_pipelines)} pipeline ymls:")
- for p in updated_pipelines:
- print(f" - {p}")
-
- updated_setup_docker = update_setup_docker(setup_docker_file, digests)
- if updated_setup_docker:
- print(f"Successfully updated setup-docker.sh in {setup_docker_file}!")
+ print("Updating image digests...")
+ find_replace_hashes(curr_digests, digests, files_to_update)
if __name__ == "__main__":