Skip to content

Commit 52f2a02

Browse files
committed
build-rootfs: add com.coreos.inputhash label
Right now, there is no change detection in our builds. We just always do a new build, which is wasteful. Let's re-implement a concept similar to rpm-ostree's inputhash, which just hashes all the relevant inputs. We then add a label to the final image with that input. On the cosa side, we can compare the hash to the previous build to know if to no-op. One major difference from rpm-ostree's inputhash is that it could know the hash right after doing the depsolve (to have the final list of RPMs) and thus avoid a full build. It's possible to do this here too though it'd require bootc-base-imagectl and rpm-ostree changes. We'd need to also define an API for having a `podman build` actually signal "no-op"; e.g. writing a file in the build context and erroring the build... awkward. Much more interesting and related to this is reproducible builds; if our builds were reproducible, we wouldn't have to worry about this because we'd just build the exact same artifact everytime. There's some work required to get there though, and likely we'd have to rework how we calculate our versions, since that's a dynamic value which affects the rootfs and OCI labels (e.g. always have the same version for the set of inputs; see also discussions in coreos/fedora-coreos-tracker#2015).
1 parent ac76680 commit 52f2a02

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

Containerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ RUN --mount=type=cache,rw,id=coreos-build-cache,target=/cache \
4545
RUN --mount=type=bind,target=/run/src,rw \
4646
rpm-ostree experimental compose build-chunked-oci \
4747
--bootc --format-version=1 --rootfs /target-rootfs \
48-
--output oci-archive:/run/src/out.ociarchive
48+
--output oci-archive:/run/src/out.ociarchive \
49+
--label com.coreos.inputhash=$(cat /run/inputhash)
4950

5051
FROM oci-archive:./out.ociarchive
5152
ARG VERSION

build-rootfs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
# 5. It runs the postprocess scripts defined in the manifest.
99

1010
import glob
11+
import hashlib
1112
import json
1213
import os
1314
import shutil
@@ -19,6 +20,7 @@ import yaml
1920

2021
ARCH = os.uname().machine
2122
SRCDIR = '/src'
23+
INPUTHASH = '/run/inputhash'
2224

2325

2426
def main():
@@ -66,6 +68,7 @@ def main():
6668
inject_content_manifest(target_rootfs, manifest)
6769

6870
if version != "":
71+
overlays.remove(dracut_tmpd.name)
6972
cleanup_dracut_version(target_rootfs, dracut_tmpd)
7073
inject_version_info(target_rootfs, manifest['mutate-os-release'], version)
7174

@@ -75,6 +78,8 @@ def main():
7578
run_postprocess_scripts(target_rootfs, manifest)
7679
cleanup_extraneous_files(target_rootfs)
7780

81+
calculate_inputhash(target_rootfs, overlays, manifest)
82+
7883

7984
def get_treefile(manifest_path):
8085
with tempfile.NamedTemporaryFile(suffix='.json', mode='w') as tmp_manifest:
@@ -434,6 +439,35 @@ def cleanup_extraneous_files(rootfs):
434439
unlink_optional('usr/share/rpm/.rpm.lock')
435440

436441

442+
def calculate_inputhash(rootfs, overlays, manifest):
443+
h = hashlib.sha256()
444+
445+
# rpms
446+
rpms = bwrap(rootfs, ['rpm', '-qa', '--qf', '%{NEVRA}\n'], capture=True)
447+
rpms = sorted(rpms.splitlines())
448+
h.update(''.join(rpms).encode('utf-8'))
449+
450+
# overlays
451+
for overlay in overlays:
452+
all_files = []
453+
for root, _, files in os.walk(overlay):
454+
for file in files:
455+
all_files.append(os.path.join(root, file))
456+
all_files = sorted(all_files)
457+
for file in all_files:
458+
with open(file, 'rb') as f:
459+
h.update(hashlib.file_digest(f, 'sha256').digest())
460+
has_x_bit = os.stat(f.fileno()).st_mode & 0o111 != 0
461+
h.update(bytes([has_x_bit]))
462+
463+
# postprocess
464+
for script in manifest.get('postprocess', []):
465+
h.update(script.encode('utf-8'))
466+
467+
with open(INPUTHASH, 'w', encoding='utf-8') as f:
468+
f.write(h.hexdigest())
469+
470+
437471
# Imported from cosa
438472
# Merge two lists, avoiding duplicates. Exact duplicate kargs could be valid
439473
# but we have no use case for them right now in our official images.

0 commit comments

Comments
 (0)