From a8b15f8d451190b67c55305eadab0818d6fee606 Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 7 Oct 2021 09:10:22 -0400 Subject: [PATCH] Report ignorefile location when no content added Users have accidently had a .containerignore or .dockerignore file in their context directly which blocked all content. Currently we report that no globs matched, but do not identify where the globs came from. This change is an attempt to add this data to the error. Example: https://github.com/containers/buildah/issues/3318 Signed-off-by: Daniel J Walsh --- add.go | 10 ++++++++-- cmd/buildah/addcopy.go | 24 ++---------------------- cmd/buildah/build.go | 3 ++- define/build.go | 2 ++ imagebuildah/executor.go | 4 +++- imagebuildah/stage_executor.go | 1 + pkg/parse/parse.go | 18 ++++++++++++++++++ tests/bud.bats | 1 + 8 files changed, 37 insertions(+), 26 deletions(-) diff --git a/add.go b/add.go index f17e3a9c943..f4e2943f057 100644 --- a/add.go +++ b/add.go @@ -47,8 +47,10 @@ type AddAndCopyOptions struct { // If the sources include directory trees, Hasher will be passed // tar-format archives of the directory trees. Hasher io.Writer - // Excludes is the contents of the .dockerignore file. + // Excludes is the contents of the .containerignore file. Excludes []string + // IgnoreFile is the path to the .containerignore file. + IgnoreFile string // ContextDir is the base directory for content being copied and // Excludes patterns. ContextDir string @@ -564,7 +566,11 @@ func (b *Builder) Add(destination string, extract bool, options AddAndCopyOption } } if itemsCopied == 0 { - return errors.Wrapf(syscall.ENOENT, "no items matching glob %q copied (%d filtered out)", localSourceStat.Glob, len(localSourceStat.Globbed)) + excludesFile := "" + if options.IgnoreFile != "" { + excludesFile = " using " + options.IgnoreFile + } + return errors.Wrapf(syscall.ENOENT, "no items matching glob %q copied (%d filtered out%s)", localSourceStat.Glob, len(localSourceStat.Globbed), excludesFile) } } return nil diff --git a/cmd/buildah/addcopy.go b/cmd/buildah/addcopy.go index 48c14b4934b..a77adb5ad41 100644 --- a/cmd/buildah/addcopy.go +++ b/cmd/buildah/addcopy.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -12,7 +11,6 @@ import ( "github.com/containers/buildah/pkg/parse" "github.com/containers/common/pkg/auth" "github.com/containers/storage" - "github.com/openshift/imagebuilder" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -231,11 +229,8 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, iopts addCopyRe } if iopts.contextdir != "" { var excludes []string - if iopts.ignoreFile != "" { - excludes, err = parseIgnore(iopts.ignoreFile) - } else { - excludes, err = imagebuilder.ParseDockerignore(contextdir) - } + + excludes, options.IgnoreFile, err = parse.ContainerIgnoreFile(options.ContextDir, iopts.ignoreFile) if err != nil { return err } @@ -273,18 +268,3 @@ func addAndCopyCmd(c *cobra.Command, args []string, verb string, iopts addCopyRe conditionallyAddHistory(builder, c, "/bin/sh -c #(nop) %s %s%s", verb, contentType, digest.Hex()) return builder.Save() } - -func parseIgnore(ignoreFile string) ([]string, error) { - var excludes []string - ignore, err := ioutil.ReadFile(ignoreFile) - if err != nil { - return excludes, err - } - for _, e := range strings.Split(string(ignore), "\n") { - if len(e) == 0 || e[0] == '#' { - continue - } - excludes = append(excludes, e) - } - return excludes, nil -} diff --git a/cmd/buildah/build.go b/cmd/buildah/build.go index 3bab1637510..bc5898d541d 100644 --- a/cmd/buildah/build.go +++ b/cmd/buildah/build.go @@ -317,7 +317,7 @@ func buildCmd(c *cobra.Command, inputArgs []string, iopts buildOptions) error { var excludes []string if iopts.IgnoreFile != "" { - if excludes, err = parseIgnore(iopts.IgnoreFile); err != nil { + if excludes, _, err = parse.ContainerIgnoreFile(contextDir, iopts.IgnoreFile); err != nil { return err } } @@ -350,6 +350,7 @@ func buildCmd(c *cobra.Command, inputArgs []string, iopts buildOptions) error { IIDFile: iopts.Iidfile, In: stdin, Isolation: isolation, + IgnoreFile: iopts.IgnoreFile, Labels: iopts.Label, Layers: layers, LogRusage: iopts.LogRusage, diff --git a/define/build.go b/define/build.go index c9e3f4a7d73..f5db8a9aaa6 100644 --- a/define/build.go +++ b/define/build.go @@ -227,6 +227,8 @@ type BuildOptions struct { RusageLogFile string // Excludes is a list of excludes to be used instead of the .dockerignore file. Excludes []string + // IgnoreFile is a name of the .containerignore file + IgnoreFile string // From is the image name to use to replace the value specified in the first // FROM instruction in the Containerfile From string diff --git a/imagebuildah/executor.go b/imagebuildah/executor.go index 0afe0a8f72d..ea81cab15a3 100644 --- a/imagebuildah/executor.go +++ b/imagebuildah/executor.go @@ -101,6 +101,7 @@ type Executor struct { rootfsMap map[string]bool // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. blobDirectory string excludes []string + ignoreFile string unusedArgs map[string]struct{} capabilities []string devices define.ContainerDevices @@ -143,7 +144,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o excludes := options.Excludes if len(excludes) == 0 { - excludes, err = imagebuilder.ParseDockerignore(options.ContextDirectory) + excludes, options.IgnoreFile, err = parse.ContainerIgnoreFile(options.ContextDirectory, options.IgnoreFile) if err != nil { return nil, err } @@ -208,6 +209,7 @@ func newExecutor(logger *logrus.Logger, logPrefix string, store storage.Store, o store: store, contextDir: options.ContextDirectory, excludes: excludes, + ignoreFile: options.IgnoreFile, pullPolicy: options.PullPolicy, registry: options.Registry, ignoreUnrecognizedInstructions: options.IgnoreUnrecognizedInstructions, diff --git a/imagebuildah/stage_executor.go b/imagebuildah/stage_executor.go index 059dbada337..1d1f174bed6 100644 --- a/imagebuildah/stage_executor.go +++ b/imagebuildah/stage_executor.go @@ -401,6 +401,7 @@ func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) err PreserveOwnership: preserveOwnership, ContextDir: contextDir, Excludes: copyExcludes, + IgnoreFile: s.executor.ignoreFile, IDMappingOptions: idMappingOptions, StripSetuidBit: stripSetuid, StripSetgidBit: stripSetgid, diff --git a/pkg/parse/parse.go b/pkg/parse/parse.go index 99aa62b28d4..bde6cf71374 100644 --- a/pkg/parse/parse.go +++ b/pkg/parse/parse.go @@ -22,6 +22,7 @@ import ( "github.com/containers/storage/pkg/unshare" units "github.com/docker/go-units" specs "github.com/opencontainers/runtime-spec/specs-go" + "github.com/openshift/imagebuilder" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -1231,3 +1232,20 @@ func SSH(sshSources []string) (map[string]*sshagent.Source, error) { } return parsed, nil } + +func ContainerIgnoreFile(contextDir, path string) ([]string, string, error) { + if path != "" { + excludes, err := imagebuilder.ParseIgnore(path) + return excludes, path, err + } + path = filepath.Join(contextDir, ".containerignore") + excludes, err := imagebuilder.ParseIgnore(path) + if os.IsNotExist(err) { + path = filepath.Join(contextDir, ".dockerignore") + excludes, err = imagebuilder.ParseIgnore(path) + } + if os.IsNotExist(err) { + return excludes, "", nil + } + return excludes, path, err +} diff --git a/tests/bud.bats b/tests/bud.bats index eeb4a338611..3eadf1d2814 100644 --- a/tests/bud.bats +++ b/tests/bud.bats @@ -110,6 +110,7 @@ symlink(subdir)" @test "bud with .dockerignore #2" { run_buildah 125 build -t testbud3 --signature-policy ${TESTSDIR}/policy.json ${TESTSDIR}/bud/dockerignore3 expect_output --substring 'error building.*"COPY test1.txt /upload/test1.txt".*no such file or directory' + expect_output --substring $(realpath "${TESTSDIR}/bud/dockerignore3/.dockerignore") } @test "bud-flags-order-verification" {