Reputation: 13684
I have a Yocto build based on Poky that inherits reproducible_build
. This essentially sets BUILD_REPRODUCIBLE_BINARIES
to "1"
, and REPRODUCIBLE_TIMESTAMP_ROOTFS
to "1520598896"
, which is 12:34:56 on 9th March 2018 UTC.
In this build, I have a /www/index.html
file, that is created in the final image with an "mtime" automatically set to this same date. I'm using a third-party web-server that uses the file's mtime to set the E-Tag for caching purposes. Unfortunately, because every build has the same timestamp, the server responds to the web client's If-None-Match
HTTP request header with a 304 response - Not Modified. This causes the client to show the index.html
from the previous build, unless the user does a force-refresh (ctrl+F5). What I'd like to see is the true file being downloaded and displayed to the user.
I would prefer not to disable reproducible builds for the entire image just because of one file, so I'm looking for alternatives.
Is it possible to direct bitbake to skip the effect of BUILD_REPRODUCIBLE_BINARIES
for a single file when creating the final image? Ideally I'd like this file to have an mtime equal to the time at which is was actually built, or perhaps even specify it programmatically (e.g. to the time my pipeline was created).
Upvotes: 0
Views: 1329
Reputation: 13684
As suggested by Richard Purdie, one workaround is to set REPRODUCIBLE_TIMESTAMP_ROOTFS
to the value that uniquely represents the origination time of the build, such as the CI pipeline creation time. This would solve my immediate problem, but it does seem to invalidate the whole point of BUILD_REPRODUCIBLE_BINARIES
and I'm not sure yet what the side-effects of this may be.
An alternative I tried was to create a core-image-minimal.bbappend
for my image recipe that creates a new task that sets the file's mtime appropriately. It is important that this runs after the function reproducible_final_image_task()
, which sets the mtime for all rootfs files, otherwise the effect will be overwritten.
This recipe is tailored for both local and GitLab-CI builds:
# Due to BUILD_REPRODUCIBLE_BINARIES (from 'inherit reproducible_build'), all files in the rootfs have the same
# mtime (REPRODUCIBLE_TIMESTAMP_ROOTFS). This causes a caching problem for web-served files like /www/index.html that change between builds.
# Local builds get the current time (UTC), pipeline builds get the value of CI_PIPELINE_CREATED_AT:
DEFAULT_BUILD_DATE ??= "${@time.strftime('%Y-%m-%dT%H:%M:%S', time.gmtime())}"
BUILD_DATE := "${@d.getVar('BB_ORIGENV').getVar('CI_PIPELINE_CREATED_AT') or '${DEFAULT_BUILD_DATE}'}"
do_fix_www_index_html_mtime() {
touch --time=mtime --date "${BUILD_DATE}" ${IMAGE_ROOTFS}/www/index.html
}
# If CI_PIPELINE_CREATED_AT is not set in the environment, these variables will differ in value
# each time this recipe is parsed. This will result in the error:
# "The metadata is not deterministic and this needs to be fixed."
# Therefore, exclude them from the task's hash:
do_fix_www_index_html_mtime[vardepsexclude] = "DEFAULT_BUILD_DATE BUILD_DATE"
# Ensure that this task runs after the function 'reproducible_final_image_task', as this
# sets all files' mtimes in the rootfs to the value of REPRODUCIBLE_TIMESTAMP_ROOTFS.
addtask fix_www_index_html_mtime after do_image before do_image_complete
Note that using the ROOTFS_POSTPROCESS_COMMAND
mechanism to invoke such a function is insufficient, as it seems to run each function before reproducible_final_image_task()
, which is run by the do_image_complete
task.
Upvotes: 0
Reputation: 2358
Could you set REPRODUCIBLE_TIMESTAMP_ROOTFS to match your index file or otherwise set it to a time which works for your application?
Upvotes: 1