Skip to content

Commit

Permalink
Rebuild layer if a change in ARG is detected
Browse files Browse the repository at this point in the history
Check whether the ARG in the containerfile is changed by
either the --build-arg flag or local environment and use
the cached layer or rebuild the layer accordingly.
Add tests for this use case as well.

Signed-off-by: Urvashi Mohnani <[email protected]>
  • Loading branch information
umohnani8 committed Jan 27, 2021
1 parent 0c5bfcd commit 4a07a77
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 6 deletions.
9 changes: 8 additions & 1 deletion imagebuildah/stage_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,11 @@ func (s *StageExecutor) Execute(ctx context.Context, base string) (imgID string,
// Check if there's already an image based on our parent that
// has the same change that we're about to make, so far as we
// can tell.
if checkForLayers {
// Only do this if there were no build args given by the user,
// we need to call ib.Run() to correctly put the args together before
// determining if a cached layer with the same build args already exists
// and that is done in the if block below.
if checkForLayers && s.builder.Args == nil {
cacheID, err = s.intermediateImageExists(ctx, node, addedContentSummary, s.stepRequiresLayer(step))
if err != nil {
return "", nil, errors.Wrap(err, "error checking if cached image exists from a previous build")
Expand Down Expand Up @@ -1022,6 +1026,9 @@ func (s *StageExecutor) getCreatedBy(node *parser.Node, addedContentSummary stri
return "/bin/sh"
}
switch strings.ToUpper(node.Value) {
case "ARG":
buildArgs := s.getBuildArgs()
return "/bin/sh -c #(nop) ARG " + buildArgs
case "RUN":
buildArgs := s.getBuildArgs()
if buildArgs != "" {
Expand Down
35 changes: 30 additions & 5 deletions tests/bud.bats
Original file line number Diff line number Diff line change
Expand Up @@ -303,17 +303,17 @@ symlink(subdir)"
# two more, starting at the "echo $user" instruction
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --build-arg=user=1 --layers -t test1 -f Dockerfile.build-args ${TESTSDIR}/bud/use-layers
run_buildah images -a
expect_line_count 7
expect_line_count 8

# one more, because we added a new name to the same image
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --build-arg=user=1 --layers -t test2 -f Dockerfile.build-args ${TESTSDIR}/bud/use-layers
run_buildah images -a
expect_line_count 8
expect_line_count 9

# two more, starting at the "echo $user" instruction
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test3 -f Dockerfile.build-args ${TESTSDIR}/bud/use-layers
run_buildah images -a
expect_line_count 10
expect_line_count 12
}

@test "bud with --rm flag" {
Expand Down Expand Up @@ -1688,13 +1688,14 @@ _EOF
}

@test "bud-build-arg-cache" {
_prefetch busybox
_prefetch busybox alpine
target=derived-image
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t ${target} -f Dockerfile3 ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' ${target}
targetid="$output"

# With build args, we should not find the previous build as a cached result.
# With build args, we should not find the previous build as a cached result. This will be true because there is a RUN command after all the ARG
# commands in the containerfile, so this does not truly test if the ARG commands were using cache or not. There is a test for that case below.
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t ${target} -f Dockerfile3 --build-arg=UID=17122 --build-arg=CODE=/copr/coprs_frontend --build-arg=USERNAME=praiskup --build-arg=PGDATA=/pgdata ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' ${target}
argsid="$output"
Expand All @@ -1716,6 +1717,30 @@ _EOF
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t ${target} -f Dockerfile3 --build-arg=PGDATA=/pgdata --build-arg=UID=17122 --build-arg=CODE=/copr/coprs_frontend --build-arg=USERNAME=praiskup ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' ${target}
expect_output "$argsid"

# If build-arg is specifified via the command line and is different form the previous cached build, it should not use the cached layers.
# Note, this containerfile does not have any RUN commands and we verify that the ARG steps are being rebuilt when a change is detected.
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test-img -f Dockerfile4 ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' test-img
initialid="$output"

# Build the same containerfile again and verify that the cached layers were used
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test-img-1 -f Dockerfile4 ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' test-img-1
expect_output "$initialid"

# Set the build-arg flag and verify that the cached layers are not used
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test-img-2 --build-arg TEST=foo -f Dockerfile4 ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' test-img-2
argsid="$output"
[[ "$argsid" != "$initialid" ]]

# Set the build-arg via an ENV in the local environment and verify that the cached layers are not used
export TEST=bar
run_buildah bud --signature-policy ${TESTSDIR}/policy.json --layers -t test-img-3 --build-arg TEST -f Dockerfile4 ${TESTSDIR}/bud/build-arg
run_buildah inspect -f '{{.FromImageID}}' test-img-3
argsid="$output"
[[ "$argsid" != "$initialid" ]]
}

@test "bud test RUN with a priv'd command" {
Expand Down
3 changes: 3 additions & 0 deletions tests/bud/build-arg/Dockerfile4
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
FROM alpine
ARG TEST
ENV NAME=$TEST

0 comments on commit 4a07a77

Please sign in to comment.