From 10dfd8d92abaaecd04721be7167f57aa1669e446 Mon Sep 17 00:00:00 2001 From: umohnani8 Date: Thu, 28 Jun 2018 16:41:59 -0400 Subject: Vendor latest projectatomic/buildah Fixes issue with build for last step of docker file when building with --layers. Signed-off-by: umohnani8 Closes: #1023 Approved by: mheon --- .../projectatomic/buildah/imagebuildah/build.go | 118 +++++++++++----- vendor/github.com/projectatomic/buildah/run.go | 154 ++++++++++++--------- .../github.com/projectatomic/buildah/util/util.go | 53 ++++++- 3 files changed, 220 insertions(+), 105 deletions(-) (limited to 'vendor/github.com') diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go index 2c75fcfe1..e7fad7f67 100644 --- a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go +++ b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go @@ -11,6 +11,7 @@ import ( "strings" "time" + cp "github.com/containers/image/copy" is "github.com/containers/image/storage" "github.com/containers/image/transports" "github.com/containers/image/transports/alltransports" @@ -697,6 +698,33 @@ func (b *Executor) Delete() (err error) { return err } +// resolveNameToImageRef creates a types.ImageReference from b.output +func (b *Executor) resolveNameToImageRef() (types.ImageReference, error) { + var ( + imageRef types.ImageReference + err error + ) + if b.output != "" { + imageRef, err = alltransports.ParseImageName(b.output) + if err != nil { + candidates := util.ResolveName(b.output, "", b.systemContext, b.store) + if len(candidates) == 0 { + return imageRef, errors.Errorf("error parsing target image name %q", b.output) + } + imageRef2, err2 := is.Transport.ParseStoreReference(b.store, candidates[0]) + if err2 != nil { + return imageRef, errors.Wrapf(err, "error parsing target image name %q", b.output) + } + return imageRef2, nil + } + } + imageRef, err = is.Transport.ParseStoreReference(b.store, "@"+stringid.GenerateRandomID()) + if err != nil { + return imageRef, errors.Wrapf(err, "error parsing reference for image to be written") + } + return imageRef, nil +} + // Execute runs each of the steps in the parsed tree, in turn. func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node *parser.Node) error { checkForLayers := true @@ -745,18 +773,31 @@ func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node * return errors.Wrap(err, "error checking if cached image exists from a previous build") } } + + if cacheID != "" { + fmt.Fprintf(b.out, "--> Using cache %s\n", cacheID) + } + + // If a cache is found for the last step, that means nothing in the + // Dockerfile changed. Just create a copy of the existing image and + // save it with the new name passed in by the user. + if cacheID != "" && i == len(children)-1 { + if err := b.copyExistingImage(ctx, cacheID); err != nil { + return err + } + break + } + if cacheID == "" || !checkForLayers { checkForLayers = false err := ib.Run(step, b, requiresStart) if err != nil { return errors.Wrapf(err, "error building at step %+v", *step) } - } else { - b.log("Using cache %s", cacheID) } - // Commit if at the last step of the Dockerfile and a cached image is found. - // Also commit steps if no cache is found. - if (cacheID != "" && i == len(children)-1) || cacheID == "" { + + // Commit if no cache is found + if cacheID == "" { imgID, err = b.Commit(ctx, ib, getCreatedBy(node)) if err != nil { return errors.Wrapf(err, "error committing container for step %+v", *step) @@ -785,6 +826,32 @@ func (b *Executor) Execute(ctx context.Context, ib *imagebuilder.Builder, node * return nil } +// copyExistingImage creates a copy of an image already in store +func (b *Executor) copyExistingImage(ctx context.Context, cacheID string) error { + // Get the destination Image Reference + dest, err := b.resolveNameToImageRef() + if err != nil { + return err + } + + policyContext, err := util.GetPolicyContext(b.systemContext) + if err != nil { + return err + } + defer policyContext.Destroy() + + // Look up the source image, expecting it to be in local storage + src, err := is.Transport.ParseStoreReference(b.store, cacheID) + if err != nil { + return errors.Wrapf(err, "error getting source imageReference for %q", cacheID) + } + if err := cp.Image(ctx, policyContext, dest, src, nil); err != nil { + return errors.Wrapf(err, "error copying image %q", cacheID) + } + b.log("COMMIT %s", b.output) + return nil +} + // layerExists returns true if an intermediate image of currNode exists in the image store from a previous build. // It verifies tihis by checking the parent of the top layer of the image and the history. func (b *Executor) layerExists(ctx context.Context, currNode *parser.Node, children []*parser.Node) (string, error) { @@ -958,30 +1025,11 @@ func urlContentModified(url string, historyTime *time.Time) (bool, error) { // Commit writes the container's contents to an image, using a passed-in tag as // the name if there is one, generating a unique ID-based one otherwise. func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder, createdBy string) (string, error) { - var ( - imageRef types.ImageReference - err error - ) - - if b.output != "" { - imageRef, err = alltransports.ParseImageName(b.output) - if err != nil { - candidates := util.ResolveName(b.output, "", b.systemContext, b.store) - if len(candidates) == 0 { - return "", errors.Errorf("error parsing target image name %q", b.output) - } - imageRef2, err2 := is.Transport.ParseStoreReference(b.store, candidates[0]) - if err2 != nil { - return "", errors.Wrapf(err, "error parsing target image name %q", b.output) - } - imageRef = imageRef2 - } - } else { - imageRef, err = is.Transport.ParseStoreReference(b.store, "@"+stringid.GenerateRandomID()) - if err != nil { - return "", errors.Wrapf(err, "error parsing reference for image to be written") - } + imageRef, err := b.resolveNameToImageRef() + if err != nil { + return "", err } + if ib.Author != "" { b.builder.SetMaintainer(ib.Author) } @@ -1062,7 +1110,7 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder, created return "", err } if options.IIDFile == "" && imgID != "" { - fmt.Fprintf(b.out, "%s\n", imgID) + fmt.Fprintf(b.out, "--> %s\n", imgID) } return imgID, nil } @@ -1089,12 +1137,12 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) error return err } } - if b.layers || b.noCache { - return nil - } - _, err := stageExecutor.Commit(ctx, stages[len(stages)-1].Builder, "") - if err != nil { - return err + + if !b.layers && !b.noCache { + _, err := stageExecutor.Commit(ctx, stages[len(stages)-1].Builder, "") + if err != nil { + return err + } } // If building with layers and b.removeIntermediateCtrs is true // only remove intermediate container for each step if an error diff --git a/vendor/github.com/projectatomic/buildah/run.go b/vendor/github.com/projectatomic/buildah/run.go index e111c5207..0efb79922 100644 --- a/vendor/github.com/projectatomic/buildah/run.go +++ b/vendor/github.com/projectatomic/buildah/run.go @@ -19,6 +19,7 @@ import ( "time" "github.com/containernetworking/cni/libcni" + "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/reexec" units "github.com/docker/go-units" @@ -579,8 +580,8 @@ func runSetupVolumeMounts(mountLabel string, volumeMounts []string, optionMounts } // addNetworkConfig copies files from host and sets them up to bind mount into container -func (b *Builder) addNetworkConfig(rdir, hostPath string) (string, error) { - copyFileWithTar := b.copyFileWithTar(nil, nil) +func (b *Builder) addNetworkConfig(rdir, hostPath string, chownOpts *idtools.IDPair) (string, error) { + copyFileWithTar := b.copyFileWithTar(chownOpts, nil) cfile := filepath.Join(rdir, filepath.Base(hostPath)) @@ -684,11 +685,6 @@ func setupCapabilities(g *generate.Generator, firstAdds, firstDrops, secondAdds, return nil } -func setupApparmor(spec *specs.Spec, apparmorProfile string) error { - spec.Process.ApparmorProfile = apparmorProfile - return nil -} - func setupTerminal(g *generate.Generator, terminalPolicy TerminalPolicy, terminalSize *specs.Box) { switch terminalPolicy { case DefaultTerminal: @@ -844,9 +840,77 @@ func runLookupPath(g *generate.Generator, command []string) []string { return command } +func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, options RunOptions) error { + // Set the user UID/GID/supplemental group list/capabilities lists. + user, err := b.user(mountPoint, options.User) + if err != nil { + return err + } + if err := setupCapabilities(g, b.AddCapabilities, b.DropCapabilities, options.AddCapabilities, options.DropCapabilities); err != nil { + return err + } + g.SetProcessUID(user.UID) + g.SetProcessGID(user.GID) + for _, gid := range user.AdditionalGids { + g.AddProcessAdditionalGid(gid) + } + + // Remove capabilities if not running as root + if user.UID != 0 { + g.ClearProcessCapabilities() + } + + return nil +} + +func (b *Builder) configureEnvironment(g *generate.Generator, options RunOptions) { + g.ClearProcessEnv() + for _, envSpec := range append(b.Env(), options.Env...) { + env := strings.SplitN(envSpec, "=", 2) + if len(env) > 1 { + g.AddProcessEnv(env[0], env[1]) + } + } + + for src, dest := range b.Args { + g.AddProcessEnv(src, dest) + } +} + +func (b *Builder) configureNamespaces(g *generate.Generator, options RunOptions) (bool, []string, error) { + defaultNamespaceOptions, err := DefaultNamespaceOptions() + if err != nil { + return false, nil, err + } + + namespaceOptions := defaultNamespaceOptions + namespaceOptions.AddOrReplace(b.NamespaceOptions...) + namespaceOptions.AddOrReplace(options.NamespaceOptions...) + + networkPolicy := options.ConfigureNetwork + if networkPolicy == NetworkDefault { + networkPolicy = b.ConfigureNetwork + } + + configureNetwork, configureNetworks, configureUTS, err := setupNamespaces(g, namespaceOptions, b.IDMappingOptions, networkPolicy) + if err != nil { + return false, nil, err + } + + if configureUTS { + if options.Hostname != "" { + g.SetHostname(options.Hostname) + } else if b.Hostname() != "" { + g.SetHostname(b.Hostname()) + } + } else { + g.SetHostname("") + } + return configureNetwork, configureNetworks, nil +} + // Run runs the specified command in the container's root filesystem. func (b *Builder) Run(command []string, options RunOptions) error { - var user specs.User p, err := ioutil.TempDir("", Package) if err != nil { return err @@ -870,17 +934,7 @@ func (b *Builder) Run(command []string, options RunOptions) error { g := &gp - g.ClearProcessEnv() - for _, envSpec := range append(b.Env(), options.Env...) { - env := strings.SplitN(envSpec, "=", 2) - if len(env) > 1 { - g.AddProcessEnv(env[0], env[1]) - } - } - - for src, dest := range b.Args { - g.AddProcessEnv(src, dest) - } + b.configureEnvironment(g, options) if b.CommonBuildOpts == nil { return errors.Errorf("Invalid format on container you must recreate the container") @@ -919,62 +973,22 @@ func (b *Builder) Run(command []string, options RunOptions) error { setupTerminal(g, options.Terminal, options.TerminalSize) - defaultNamespaceOptions, err := DefaultNamespaceOptions() + configureNetwork, configureNetworks, err := b.configureNamespaces(g, options) if err != nil { return err } - namespaceOptions := defaultNamespaceOptions - namespaceOptions.AddOrReplace(b.NamespaceOptions...) - namespaceOptions.AddOrReplace(options.NamespaceOptions...) - - networkPolicy := options.ConfigureNetwork - if networkPolicy == NetworkDefault { - networkPolicy = b.ConfigureNetwork - } - - configureNetwork, configureNetworks, configureUTS, err := setupNamespaces(g, namespaceOptions, b.IDMappingOptions, networkPolicy) - if err != nil { + if err := b.configureUIDGID(g, mountPoint, options); err != nil { return err } - if configureUTS { - if options.Hostname != "" { - g.SetHostname(options.Hostname) - } else if b.Hostname() != "" { - g.SetHostname(b.Hostname()) - } - } else { - g.SetHostname("") - } - - // Set the user UID/GID/supplemental group list/capabilities lists. - if user, err = b.user(mountPoint, options.User); err != nil { - return err - } - if err = setupCapabilities(g, b.AddCapabilities, b.DropCapabilities, options.AddCapabilities, options.DropCapabilities); err != nil { - return err - } - g.SetProcessUID(user.UID) - g.SetProcessGID(user.GID) - for _, gid := range user.AdditionalGids { - g.AddProcessAdditionalGid(gid) - } + g.SetProcessApparmorProfile(b.CommonBuildOpts.ApparmorProfile) // Now grab the spec from the generator. Set the generator to nil so that future contributors // will quickly be able to tell that they're supposed to be modifying the spec directly from here. spec := g.Spec() g = nil - // Remove capabilities if not running as root - if user.UID != 0 { - var caplist []string - spec.Process.Capabilities.Permitted = caplist - spec.Process.Capabilities.Inheritable = caplist - spec.Process.Capabilities.Effective = caplist - spec.Process.Capabilities.Ambient = caplist - } - // Set the working directory, creating it if we must. if spec.Process.Cwd == "" { spec.Process.Cwd = DefaultWorkingDir @@ -983,11 +997,6 @@ func (b *Builder) Run(command []string, options RunOptions) error { return errors.Wrapf(err, "error ensuring working directory %q exists", spec.Process.Cwd) } - // Set the apparmor profile name. - if err = setupApparmor(spec, b.CommonBuildOpts.ApparmorProfile); err != nil { - return err - } - // Set the seccomp configuration using the specified profile name. Some syscalls are // allowed if certain capabilities are to be granted (example: CAP_SYS_CHROOT and chroot), // so we sorted out the capabilities lists first. @@ -995,11 +1004,18 @@ func (b *Builder) Run(command []string, options RunOptions) error { return err } - hostFile, err := b.addNetworkConfig(path, "/etc/hosts") + // Figure out who owns files that will appear to be owned by UID/GID 0 in the container. + rootUID, rootGID, err := util.GetHostRootIDs(spec) + if err != nil { + return err + } + rootIDPair := &idtools.IDPair{UID: int(rootUID), GID: int(rootGID)} + + hostFile, err := b.addNetworkConfig(path, "/etc/hosts", rootIDPair) if err != nil { return err } - resolvFile, err := b.addNetworkConfig(path, "/etc/resolv.conf") + resolvFile, err := b.addNetworkConfig(path, "/etc/resolv.conf", rootIDPair) if err != nil { return err } diff --git a/vendor/github.com/projectatomic/buildah/util/util.go b/vendor/github.com/projectatomic/buildah/util/util.go index 61705867d..2617a27b7 100644 --- a/vendor/github.com/projectatomic/buildah/util/util.go +++ b/vendor/github.com/projectatomic/buildah/util/util.go @@ -7,6 +7,7 @@ import ( "net/url" "os" "path" + "path/filepath" "strconv" "strings" @@ -15,6 +16,7 @@ import ( "github.com/containers/image/docker/reference" ociarchive "github.com/containers/image/oci/archive" "github.com/containers/image/pkg/sysregistries" + "github.com/containers/image/signature" is "github.com/containers/image/storage" "github.com/containers/image/tarball" "github.com/containers/image/types" @@ -330,7 +332,8 @@ func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) { return mappings, nil } -// GetHostIDMappings reads mappings for the current process from the kernel. +// GetHostIDMappings reads mappings for the specified process (or the current +// process if pid is "self" or an empty string) from the kernel. func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { if pid == "" { pid = "self" @@ -428,3 +431,51 @@ func ParseIDMappings(uidmap, gidmap []string) ([]idtools.IDMap, []idtools.IDMap, } return uid, gid, nil } + +// UnsharedRootPath returns a location under ($XDG_DATA_HOME/containers/storage, +// or $HOME/.local/share/containers/storage, or +// (the user's home directory)/.local/share/containers/storage, or an error. +func UnsharedRootPath(homedir string) (string, error) { + // If $XDG_DATA_HOME is defined... + if envDataHome, haveDataHome := os.LookupEnv("XDG_DATA_HOME"); haveDataHome { + return filepath.Join(envDataHome, "containers", "storage"), nil + } + // If $XDG_DATA_HOME is not defined, but $HOME is defined... + if envHomedir, haveHomedir := os.LookupEnv("HOME"); haveHomedir { + // Default to the user's $HOME/.local/share/containers/storage subdirectory. + return filepath.Join(envHomedir, ".local", "share", "containers", "storage"), nil + } + // If we know where our home directory is... + if homedir != "" { + // Default to the user's homedir/.local/share/containers/storage subdirectory. + return filepath.Join(homedir, ".local", "share", "containers", "storage"), nil + } + return "", errors.New("unable to determine a --root location: neither $XDG_DATA_HOME nor $HOME is set") +} + +// UnsharedRunrootPath returns $XDG_RUNTIME_DIR/run, /var/run/user/(the user's UID)/run, or an error. +func UnsharedRunrootPath(uid string) (string, error) { + // If $XDG_RUNTIME_DIR is defined... + if envRuntimeDir, haveRuntimeDir := os.LookupEnv("XDG_RUNTIME_DIR"); haveRuntimeDir { + return filepath.Join(envRuntimeDir, "run"), nil + } + // If $XDG_RUNTIME_DIR is not defined, but we know our UID... + if uid != "" { + return filepath.Join("/var/run/user", uid, "run"), nil + } + return "", errors.New("unable to determine a --runroot location: $XDG_RUNTIME_DIR is not set, and we don't know our UID") +} + +// GetPolicyContext sets up, initializes and returns a new context for the specified policy +func GetPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error) { + policy, err := signature.DefaultPolicy(ctx) + if err != nil { + return nil, err + } + + policyContext, err := signature.NewPolicyContext(policy) + if err != nil { + return nil, err + } + return policyContext, nil +} -- cgit v1.2.3-54-g00ecf