diff options
author | Daniel J Walsh <dwalsh@redhat.com> | 2018-06-07 01:00:07 -0400 |
---|---|---|
committer | Atomic Bot <atomic-devel@projectatomic.io> | 2018-06-07 17:14:02 +0000 |
commit | cf7c8295b8875ddd4fe87a4207aa302efbd90b18 (patch) | |
tree | f9358349d4574e469b72db2208a57c0f5160da91 /vendor/github.com/projectatomic/buildah | |
parent | 7d6e717dd9f8fe367b64839089db859ca6bd8a83 (diff) | |
download | podman-cf7c8295b8875ddd4fe87a4207aa302efbd90b18.tar.gz podman-cf7c8295b8875ddd4fe87a4207aa302efbd90b18.tar.bz2 podman-cf7c8295b8875ddd4fe87a4207aa302efbd90b18.zip |
Vendor in latest buildah code
Use the parsing code to properly setup podman build namespaces
Fixes support for network namespace and user namespace
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
Closes: #917
Approved by: rhatdan
Diffstat (limited to 'vendor/github.com/projectatomic/buildah')
7 files changed, 316 insertions, 30 deletions
diff --git a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go index f3d28510a..ce0734a2b 100644 --- a/vendor/github.com/projectatomic/buildah/imagebuildah/build.go +++ b/vendor/github.com/projectatomic/buildah/imagebuildah/build.go @@ -16,6 +16,7 @@ import ( "github.com/containers/image/types" "github.com/containers/storage" "github.com/containers/storage/pkg/archive" + "github.com/containers/storage/pkg/ioutils" "github.com/containers/storage/pkg/stringid" "github.com/docker/docker/builder/dockerfile/parser" docker "github.com/fsouza/go-dockerclient" @@ -438,6 +439,11 @@ func (b *Executor) Run(run imagebuilder.Run, config docker.Config) error { if b.builder == nil { return errors.Errorf("no build container available") } + devNull, err := os.Open(os.DevNull) + if err != nil { + return errors.Errorf("error opening %q for reading: %v", os.DevNull, err) + } + defer devNull.Close() options := buildah.RunOptions{ Hostname: config.Hostname, Runtime: b.runtime, @@ -448,6 +454,9 @@ func (b *Executor) Run(run imagebuilder.Run, config docker.Config) error { WorkingDir: config.WorkingDir, Entrypoint: config.Entrypoint, Cmd: config.Cmd, + Stdin: devNull, + Stdout: ioutils.NopWriteCloser(b.out), + Stderr: ioutils.NopWriteCloser(b.err), Quiet: b.quiet, } if config.NetworkDisabled { @@ -463,7 +472,7 @@ func (b *Executor) Run(run imagebuilder.Run, config docker.Config) error { if err := b.volumeCacheSave(); err != nil { return err } - err := b.builder.Run(args, options) + err = b.builder.Run(args, options) if err2 := b.volumeCacheRestore(); err2 != nil { if err == nil { return err2 @@ -772,7 +781,7 @@ func (b *Executor) Commit(ctx context.Context, ib *imagebuilder.Builder) (err er return err } if options.IIDFile == "" && imgID != "" { - fmt.Printf("%s\n", imgID) + fmt.Fprintf(b.out, "%s\n", imgID) } return nil } diff --git a/vendor/github.com/projectatomic/buildah/new.go b/vendor/github.com/projectatomic/buildah/new.go index d6aa21f8e..da170d591 100644 --- a/vendor/github.com/projectatomic/buildah/new.go +++ b/vendor/github.com/projectatomic/buildah/new.go @@ -168,7 +168,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store if options.PullPolicy == PullAlways { pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) if err != nil { - logrus.Debugf("error pulling and reading image %q: %v", image, err) + logrus.Debugf("unable to pull and read image %q: %v", image, err) continue } ref = pulledReference @@ -214,7 +214,7 @@ func resolveImage(ctx context.Context, systemContext *types.SystemContext, store } pulledImg, pulledReference, err := pullAndFindImage(ctx, store, image, options, systemContext) if err != nil { - logrus.Debugf("error pulling and reading image %q: %v", image, err) + logrus.Debugf("unable to pull and read image %q: %v", image, err) continue } ref = pulledReference diff --git a/vendor/github.com/projectatomic/buildah/pkg/cli/common.go b/vendor/github.com/projectatomic/buildah/pkg/cli/common.go index a7b61d561..e545e97d3 100644 --- a/vendor/github.com/projectatomic/buildah/pkg/cli/common.go +++ b/vendor/github.com/projectatomic/buildah/pkg/cli/common.go @@ -79,7 +79,7 @@ var ( }, cli.StringFlag{ Name: "cache-from", - Usage: "Images to utilise as potential cache sources. Buildah does not currently support caching so this is a NOOP.", + Usage: "Images to utilise as potential cache sources. The build process does not currently support caching so this is a NOOP.", }, cli.StringFlag{ Name: "cert-dir", @@ -95,13 +95,17 @@ var ( Value: "", Usage: "use `[username[:password]]` for accessing the registry", }, + cli.BoolFlag{ + Name: "disable-content-trust", + Usage: "This is a Docker specific option and is a NOOP", + }, cli.StringSliceFlag{ Name: "file, f", Usage: "`pathname or URL` of a Dockerfile", }, cli.BoolFlag{ Name: "force-rm", - Usage: "Always remove intermediate containers after a build. Buildah does not currently support caching so this is a NOOP.", + Usage: "Always remove intermediate containers after a build. The build process does not currently support caching so this is a NOOP.", }, cli.StringFlag{ Name: "format", @@ -117,7 +121,11 @@ var ( }, cli.BoolFlag{ Name: "no-cache", - Usage: "Do not use caching for the container build. Buildah does not currently support caching so this is a NOOP.", + Usage: "Do not use caching for the container build. The build process does not currently support caching so this is a NOOP.", + }, + cli.StringFlag{ + Name: "logfile", + Usage: "log to `file` instead of stdout/stderr", }, cli.BoolTFlag{ Name: "pull", @@ -133,7 +141,7 @@ var ( }, cli.BoolFlag{ Name: "rm", - Usage: "Remove intermediate containers after a successful build. Buildah does not currently support caching so this is a NOOP.", + Usage: "Remove intermediate containers after a successful build. The build process does not currently support caching so this is a NOOP.", }, cli.StringFlag{ Name: "runtime", @@ -150,7 +158,7 @@ var ( }, cli.BoolFlag{ Name: "squash", - Usage: "Squash newly built layers into a single new layer. Buildah does not currently support caching so this is a NOOP.", + Usage: "Squash newly built layers into a single new layer. The build process does not currently support caching so this is a NOOP.", }, cli.BoolTFlag{ Name: "stream", diff --git a/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go b/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go index eb7be9c1e..1a4a1e423 100644 --- a/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go +++ b/vendor/github.com/projectatomic/buildah/pkg/parse/parse.go @@ -11,12 +11,17 @@ import ( "path/filepath" "reflect" "regexp" + "strconv" "strings" + "unicode" "github.com/containers/image/types" + "github.com/containers/storage/pkg/idtools" "github.com/docker/go-units" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/projectatomic/buildah" + "github.com/sirupsen/logrus" "github.com/urfave/cli" "golang.org/x/crypto/ssh/terminal" ) @@ -28,8 +33,8 @@ const ( SeccompOverridePath = "/etc/crio/seccomp.json" ) -// ParseCommonBuildOptions parses the build options from the bud cli -func ParseCommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error) { +// CommonBuildOptions parses the build options from the bud cli +func CommonBuildOptions(c *cli.Context) (*buildah.CommonBuildOptions, error) { var ( memoryLimit int64 memorySwap int64 @@ -326,3 +331,194 @@ func getDockerAuth(creds string) (*types.DockerAuthConfig, error) { Password: password, }, nil } + +// IDMappingOptions parses the build options from user namespace +func IDMappingOptions(c *cli.Context) (usernsOptions buildah.NamespaceOptions, idmapOptions *buildah.IDMappingOptions, err error) { + user := c.String("userns-uid-map-user") + group := c.String("userns-gid-map-group") + // If only the user or group was specified, use the same value for the + // other, since we need both in order to initialize the maps using the + // names. + if user == "" && group != "" { + user = group + } + if group == "" && user != "" { + group = user + } + // Either start with empty maps or the name-based maps. + mappings := idtools.NewIDMappingsFromMaps(nil, nil) + if user != "" && group != "" { + submappings, err := idtools.NewIDMappings(user, group) + if err != nil { + return nil, nil, err + } + mappings = submappings + } + // We'll parse the UID and GID mapping options the same way. + buildIDMap := func(basemap []idtools.IDMap, option string) ([]specs.LinuxIDMapping, error) { + outmap := make([]specs.LinuxIDMapping, 0, len(basemap)) + // Start with the name-based map entries. + for _, m := range basemap { + outmap = append(outmap, specs.LinuxIDMapping{ + ContainerID: uint32(m.ContainerID), + HostID: uint32(m.HostID), + Size: uint32(m.Size), + }) + } + // Parse the flag's value as one or more triples (if it's even + // been set), and append them. + idmap, err := parseIDMap(c.StringSlice(option)) + if err != nil { + return nil, err + } + for _, m := range idmap { + outmap = append(outmap, specs.LinuxIDMapping{ + ContainerID: m[0], + HostID: m[1], + Size: m[2], + }) + } + return outmap, nil + } + uidmap, err := buildIDMap(mappings.UIDs(), "userns-uid-map") + if err != nil { + return nil, nil, err + } + gidmap, err := buildIDMap(mappings.GIDs(), "userns-gid-map") + if err != nil { + return nil, nil, err + } + // If we only have one map or the other populated at this point, then + // use the same mapping for both, since we know that no user or group + // name was specified, but a specific mapping was for one or the other. + if len(uidmap) == 0 && len(gidmap) != 0 { + uidmap = gidmap + } + if len(gidmap) == 0 && len(uidmap) != 0 { + gidmap = uidmap + } + // By default, having mappings configured means we use a user + // namespace. Otherwise, we don't. + usernsOption := buildah.NamespaceOption{ + Name: string(specs.UserNamespace), + Host: len(uidmap) == 0 && len(gidmap) == 0, + } + // If the user specifically requested that we either use or don't use + // user namespaces, override that default. + if c.IsSet("userns") { + how := c.String("userns") + switch how { + case "", "container": + usernsOption.Host = false + case "host": + usernsOption.Host = true + default: + if _, err := os.Stat(how); err != nil { + return nil, nil, errors.Wrapf(err, "error checking for %s namespace at %q", string(specs.UserNamespace), how) + } + logrus.Debugf("setting %q namespace to %q", string(specs.UserNamespace), how) + usernsOption.Path = how + } + } + usernsOptions = buildah.NamespaceOptions{usernsOption} + if !c.IsSet("net") { + usernsOptions = append(usernsOptions, buildah.NamespaceOption{ + Name: string(specs.NetworkNamespace), + Host: usernsOption.Host, + }) + } + // If the user requested that we use the host namespace, but also that + // we use mappings, that's not going to work. + if (len(uidmap) != 0 || len(gidmap) != 0) && usernsOption.Host { + return nil, nil, errors.Errorf("can not specify ID mappings while using host's user namespace") + } + return usernsOptions, &buildah.IDMappingOptions{ + HostUIDMapping: usernsOption.Host, + HostGIDMapping: usernsOption.Host, + UIDMap: uidmap, + GIDMap: gidmap, + }, nil +} + +func parseIDMap(spec []string) (m [][3]uint32, err error) { + for _, s := range spec { + args := strings.FieldsFunc(s, func(r rune) bool { return !unicode.IsDigit(r) }) + if len(args)%3 != 0 { + return nil, fmt.Errorf("mapping %q is not in the form containerid:hostid:size[,...]", s) + } + for len(args) >= 3 { + cid, err := strconv.ParseUint(args[0], 10, 32) + if err != nil { + return nil, fmt.Errorf("error parsing container ID %q from mapping %q as a number: %v", args[0], s, err) + } + hostid, err := strconv.ParseUint(args[1], 10, 32) + if err != nil { + return nil, fmt.Errorf("error parsing host ID %q from mapping %q as a number: %v", args[1], s, err) + } + size, err := strconv.ParseUint(args[2], 10, 32) + if err != nil { + return nil, fmt.Errorf("error parsing %q from mapping %q as a number: %v", args[2], s, err) + } + m = append(m, [3]uint32{uint32(cid), uint32(hostid), uint32(size)}) + args = args[3:] + } + } + return m, nil +} + +// NamesapceOptions parses the build options from all namespaces except user namespace +func NamespaceOptions(c *cli.Context) (namespaceOptions buildah.NamespaceOptions, networkPolicy buildah.NetworkConfigurationPolicy, err error) { + options := make(buildah.NamespaceOptions, 0, 7) + policy := buildah.NetworkDefault + for _, what := range []string{string(specs.IPCNamespace), "net", string(specs.PIDNamespace), string(specs.UTSNamespace)} { + if c.IsSet(what) { + how := c.String(what) + switch what { + case "net", "network": + what = string(specs.NetworkNamespace) + } + switch how { + case "", "container": + logrus.Debugf("setting %q namespace to %q", what, "") + options.AddOrReplace(buildah.NamespaceOption{ + Name: what, + }) + case "host": + logrus.Debugf("setting %q namespace to host", what) + options.AddOrReplace(buildah.NamespaceOption{ + Name: what, + Host: true, + }) + default: + if what == specs.NetworkNamespace { + if how == "none" { + options.AddOrReplace(buildah.NamespaceOption{ + Name: what, + }) + policy = buildah.NetworkDisabled + logrus.Debugf("setting network to disabled") + break + } + if !filepath.IsAbs(how) { + options.AddOrReplace(buildah.NamespaceOption{ + Name: what, + Path: how, + }) + policy = buildah.NetworkEnabled + logrus.Debugf("setting network configuration to %q", how) + break + } + } + if _, err := os.Stat(how); err != nil { + return nil, buildah.NetworkDefault, errors.Wrapf(err, "error checking for %s namespace at %q", what, how) + } + logrus.Debugf("setting %q namespace to %q", what, how) + options.AddOrReplace(buildah.NamespaceOption{ + Name: what, + Path: how, + }) + } + } + } + return options, policy, nil +} diff --git a/vendor/github.com/projectatomic/buildah/pull.go b/vendor/github.com/projectatomic/buildah/pull.go index edfaa6216..e1310f7ce 100644 --- a/vendor/github.com/projectatomic/buildah/pull.go +++ b/vendor/github.com/projectatomic/buildah/pull.go @@ -8,6 +8,7 @@ import ( "github.com/containers/image/docker/reference" tarfile "github.com/containers/image/docker/tarfile" 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/transports" @@ -166,12 +167,25 @@ func pullImage(ctx context.Context, store storage.Store, imageName string, optio }() logrus.Debugf("copying %q to %q", spec, destName) - err = cp.Image(ctx, policyContext, destRef, srcRef, getCopyOptions(options.ReportWriter, options.SystemContext, nil, "")) if err == nil { return destRef, nil } - return nil, err + + // If no image was found, we should handle. Lets be nicer to the user and see if we can figure out why. + registryPath := sysregistries.RegistriesConfPath(&types.SystemContext{}) + searchRegistries, err := getRegistries() + if err != nil { + return nil, err + } + hasRegistryInName, err := hasRegistry(imageName) + if err != nil { + return nil, err + } + if !hasRegistryInName && len(searchRegistries) == 0 { + return nil, errors.Errorf("image name provided is a short name and no search registries are defined in %s.", registryPath) + } + return nil, errors.Errorf("unable to find image in the registries defined in %q", registryPath) } // getImageDigest creates an image object and uses the hex value of the digest as the image ID diff --git a/vendor/github.com/projectatomic/buildah/run.go b/vendor/github.com/projectatomic/buildah/run.go index 51dd5107c..436c2ea2e 100644 --- a/vendor/github.com/projectatomic/buildah/run.go +++ b/vendor/github.com/projectatomic/buildah/run.go @@ -150,6 +150,11 @@ type RunOptions struct { // decision can be overridden by specifying either WithTerminal or // WithoutTerminal. Terminal TerminalPolicy + // The stdin/stdout/stderr descriptors to use. If set to nil, the + // corresponding files in the "os" package are used as defaults. + Stdin io.ReadCloser `json:"-"` + Stdout io.WriteCloser `json:"-"` + Stderr io.WriteCloser `json:"-"` // Quiet tells the run to turn off output to stdout. Quiet bool } @@ -886,9 +891,18 @@ func (b *Builder) runUsingRuntimeSubproc(options RunOptions, configureNetwork bo } cmd := reexec.Command(runUsingRuntimeCommand) cmd.Dir = bundlePath - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr + cmd.Stdin = options.Stdin + if cmd.Stdin == nil { + cmd.Stdin = os.Stdin + } + cmd.Stdout = options.Stdout + if cmd.Stdout == nil { + cmd.Stdout = os.Stdout + } + cmd.Stderr = options.Stderr + if cmd.Stderr == nil { + cmd.Stderr = os.Stderr + } cmd.Env = append(os.Environ(), fmt.Sprintf("LOGLEVEL=%d", logrus.GetLevel())) preader, pwriter, err := os.Pipe() if err != nil { @@ -990,7 +1004,9 @@ func runUsingRuntime(options RunOptions, configureNetwork bool, configureNetwork // Default to not specifying a console socket location. moreCreateArgs := func() []string { return nil } // Default to just passing down our stdio. - getCreateStdio := func() (*os.File, *os.File, *os.File) { return os.Stdin, os.Stdout, os.Stderr } + getCreateStdio := func() (io.ReadCloser, io.WriteCloser, io.WriteCloser) { + return os.Stdin, os.Stdout, os.Stderr + } // Figure out how we're doing stdio handling, and create pipes and sockets. var stdio sync.WaitGroup @@ -1028,7 +1044,7 @@ func runUsingRuntime(options RunOptions, configureNetwork bool, configureNetwork } errorFds = []int{stdioPipe[unix.Stdout][0], stdioPipe[unix.Stderr][0]} // Set stdio to our pipes. - getCreateStdio = func() (*os.File, *os.File, *os.File) { + getCreateStdio = func() (io.ReadCloser, io.WriteCloser, io.WriteCloser) { stdin := os.NewFile(uintptr(stdioPipe[unix.Stdin][0]), "/dev/stdin") stdout := os.NewFile(uintptr(stdioPipe[unix.Stdout][1]), "/dev/stdout") stderr := os.NewFile(uintptr(stdioPipe[unix.Stderr][1]), "/dev/stderr") @@ -1038,7 +1054,7 @@ func runUsingRuntime(options RunOptions, configureNetwork bool, configureNetwork } else { if options.Quiet { // Discard stdout. - getCreateStdio = func() (*os.File, *os.File, *os.File) { + getCreateStdio = func() (io.ReadCloser, io.WriteCloser, io.WriteCloser) { return os.Stdin, nil, os.Stderr } } @@ -1203,14 +1219,18 @@ func runCollectOutput(fds ...int) string { var b bytes.Buffer buf := make([]byte, 8192) for _, fd := range fds { - if err := unix.SetNonblock(fd, true); err != nil { - logrus.Errorf("error setting pipe descriptor %d nonblocking: %v", fd, err) - continue - } nread, err := unix.Read(fd, buf) if err != nil { - logrus.Errorf("error reading from pipe %d: %v", fd, err) - break + if errno, isErrno := err.(syscall.Errno); isErrno { + switch errno { + default: + logrus.Errorf("error reading from pipe %d: %v", fd, err) + case syscall.EINTR, syscall.EAGAIN: + } + } else { + logrus.Errorf("unable to wait for data from pipe %d: %v", fd, err) + } + continue } for nread > 0 { r := buf[:nread] @@ -1222,7 +1242,15 @@ func runCollectOutput(fds ...int) string { } nread, err = unix.Read(fd, buf) if err != nil { - logrus.Errorf("error reading from pipe %d: %v", fd, err) + if errno, isErrno := err.(syscall.Errno); isErrno { + switch errno { + default: + logrus.Errorf("error reading from pipe %d: %v", fd, err) + case syscall.EINTR, syscall.EAGAIN: + } + } else { + logrus.Errorf("unable to wait for data from pipe %d: %v", fd, err) + } break } } @@ -1440,11 +1468,11 @@ func runCopyStdio(stdio *sync.WaitGroup, copyStdio bool, stdioPipe [][]int, copy if pollFd.Revents&unix.POLLHUP == unix.POLLHUP { removes = append(removes, int(pollFd.Fd)) } - // If the EPOLLIN flag isn't set, then there's no data to be read from this descriptor. + // If the POLLIN flag isn't set, then there's no data to be read from this descriptor. if pollFd.Revents&unix.POLLIN == 0 { - // If we're using pipes and it's our stdin, close the writing end - // of the corresponding pipe. - if copyStdio && int(pollFd.Fd) == unix.Stdin { + // If we're using pipes and it's our stdin and it's closed, close the writing + // end of the corresponding pipe. + if copyStdio && int(pollFd.Fd) == unix.Stdin && pollFd.Revents&unix.POLLHUP != 0 { unix.Close(stdioPipe[unix.Stdin][1]) stdioPipe[unix.Stdin][1] = -1 } diff --git a/vendor/github.com/projectatomic/buildah/util.go b/vendor/github.com/projectatomic/buildah/util.go index 0d05aa8a2..1b8667b79 100644 --- a/vendor/github.com/projectatomic/buildah/util.go +++ b/vendor/github.com/projectatomic/buildah/util.go @@ -7,6 +7,9 @@ import ( "strconv" "strings" + "github.com/containers/image/docker/reference" + "github.com/containers/image/pkg/sysregistries" + "github.com/containers/image/types" "github.com/containers/storage/pkg/archive" "github.com/containers/storage/pkg/chrootarchive" "github.com/containers/storage/pkg/idtools" @@ -200,3 +203,31 @@ func getHostRootIDs(spec *rspec.Spec) (uint32, uint32, error) { } return getHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, 0, 0) } + +// getRegistries obtains the list of registries defined in the global registries file. +func getRegistries() ([]string, error) { + registryConfigPath := "" + envOverride := os.Getenv("REGISTRIES_CONFIG_PATH") + if len(envOverride) > 0 { + registryConfigPath = envOverride + } + searchRegistries, err := sysregistries.GetRegistries(&types.SystemContext{SystemRegistriesConfPath: registryConfigPath}) + if err != nil { + return nil, errors.Wrapf(err, "unable to parse the registries.conf file") + } + return searchRegistries, nil +} + +// hasRegistry returns a bool/err response if the image has a registry in its +// name +func hasRegistry(imageName string) (bool, error) { + imgRef, err := reference.Parse(imageName) + if err != nil { + return false, err + } + registry := reference.Domain(imgRef.(reference.Named)) + if registry != "" { + return true, nil + } + return false, nil +} |