diff options
Diffstat (limited to 'cmd/podman/build.go')
-rw-r--r-- | cmd/podman/build.go | 410 |
1 files changed, 158 insertions, 252 deletions
diff --git a/cmd/podman/build.go b/cmd/podman/build.go index 92823f72b..180b43cbc 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -1,270 +1,176 @@ package main import ( - "fmt" "os" - "os/exec" - "strconv" + "path/filepath" + "strings" "github.com/pkg/errors" + "github.com/projectatomic/buildah/imagebuildah" + buildahcli "github.com/projectatomic/buildah/pkg/cli" + "github.com/projectatomic/buildah/pkg/parse" + "github.com/projectatomic/libpod/cmd/podman/libpodruntime" + "github.com/sirupsen/logrus" "github.com/urfave/cli" ) var ( - buildFlags = []cli.Flag{ - // The following flags are emulated from: - // src/github.com/projectatomic/buildah/cmd/bud.go - cli.StringFlag{ - Name: "authfile", - Usage: "path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json", - }, - cli.StringSliceFlag{ - Name: "build-arg", - Usage: "`argument=value` to supply to the builder", - }, - cli.StringFlag{ - Name: "cert-dir", - Value: "", - Usage: "use certificates at the specified path to access the registry", - }, - cli.StringFlag{ - Name: "creds", - Value: "", - Usage: "use `[username[:password]]` for accessing the registry", - }, - cli.StringSliceFlag{ - Name: "file, f", - Usage: "`pathname or URL` of a Dockerfile", - }, - cli.StringFlag{ - Name: "format", - Usage: "`format` of the built image's manifest and metadata", - }, - cli.BoolFlag{ - Name: "pull-always", - Usage: "pull the image, even if a version is present", - }, - cli.BoolFlag{ - Name: "quiet, q", - Usage: "refrain from announcing build instructions and image read/write progress", - }, - cli.StringFlag{ - Name: "runtime", - Usage: "`path` to an alternate runtime", - }, - cli.StringSliceFlag{ - Name: "runtime-flag", - Usage: "add global flags for the container runtime", - }, - cli.StringFlag{ - Name: "signature-policy", - Usage: "`pathname` of signature policy file (not usually used)", - }, - cli.StringSliceFlag{ - Name: "tag, t", - Usage: "`tag` to apply to the built image", - }, - cli.BoolFlag{ - Name: "tls-verify", - Usage: "require HTTPS and verify certificates when accessing the registry", - }, - // The following flags are emulated from: - // src/github.com/projectatomic/buildah/cmd/common.go fromAndBudFlags - cli.StringSliceFlag{ - Name: "add-host", - Usage: "add a custom host-to-IP mapping (host:ip) (default [])", - }, - cli.StringFlag{ - Name: "cgroup-parent", - Usage: "optional parent cgroup for the container", - }, - cli.Uint64Flag{ - Name: "cpu-period", - Usage: "limit the CPU CFS (Completely Fair Scheduler) period", - }, - cli.Int64Flag{ - Name: "cpu-quota", - Usage: "limit the CPU CFS (Completely Fair Scheduler) quota", - }, - cli.Uint64Flag{ - Name: "cpu-shares", - Usage: "CPU shares (relative weight)", - }, - cli.StringFlag{ - Name: "cpuset-cpus", - Usage: "CPUs in which to allow execution (0-3, 0,1)", - }, - cli.StringFlag{ - Name: "cpuset-mems", - Usage: "memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.", - }, - cli.StringFlag{ - Name: "memory, m", - Usage: "memory limit (format: <number>[<unit>], where unit = b, k, m or g)", - }, - cli.StringFlag{ - Name: "memory-swap", - Usage: "swap limit equal to memory plus swap: '-1' to enable unlimited swap", - }, - cli.StringSliceFlag{ - Name: "security-opt", - Usage: "security Options (default [])", - }, - cli.StringFlag{ - Name: "shm-size", - Usage: "size of `/dev/shm`. The format is `<number><unit>`.", - Value: "65536k", - }, - cli.StringSliceFlag{ - Name: "ulimit", - Usage: "ulimit options (default [])", - }, - cli.StringSliceFlag{ - Name: "volume, v", - Usage: "bind mount a volume into the container (default [])", - }, - } buildDescription = "podman build launches the Buildah command to build an OCI Image. Buildah must be installed for this command to work." buildCommand = cli.Command{ - Name: "build", - Usage: "Build an image using instructions in a Dockerfile", - Description: buildDescription, - Flags: buildFlags, - Action: buildCmd, - ArgsUsage: "CONTEXT-DIRECTORY | URL", + Name: "build", + Usage: "Build an image using instructions in a Dockerfile", + Description: buildDescription, + Flags: append(buildahcli.BudFlags, buildahcli.FromAndBudFlags...), + Action: buildCmd, + ArgsUsage: "CONTEXT-DIRECTORY | URL", + SkipArgReorder: true, } ) func buildCmd(c *cli.Context) error { - - budCmdArgs := []string{} - - // Handle Global Options - logLevel := c.GlobalString("log-level") - if logLevel == "debug" { - budCmdArgs = append(budCmdArgs, "--debug") - } - if c.GlobalIsSet("root") { - budCmdArgs = append(budCmdArgs, "--root", c.GlobalString("root")) - } - if c.GlobalIsSet("runroot") { - budCmdArgs = append(budCmdArgs, "--runroot", c.GlobalString("runroot")) - } - if c.GlobalIsSet("storage-driver") { - budCmdArgs = append(budCmdArgs, "--storage-driver", c.GlobalString("storage-driver")) - } - for _, storageOpt := range c.GlobalStringSlice("storage-opt") { - budCmdArgs = append(budCmdArgs, "--storage-opt", storageOpt) - } - - budCmdArgs = append(budCmdArgs, "bud") - - // Buildah bud specific options - if c.IsSet("authfile") { - budCmdArgs = append(budCmdArgs, "--authfile", c.String("authfile")) - } - for _, buildArg := range c.StringSlice("build-arg") { - budCmdArgs = append(budCmdArgs, "--build-arg", buildArg) - } - if c.IsSet("cert-dir") { - budCmdArgs = append(budCmdArgs, "--cert-dir", c.String("cert-dir")) - } - if c.IsSet("creds") { - budCmdArgs = append(budCmdArgs, "--creds", c.String("creds")) - } - for _, fileName := range c.StringSlice("file") { - budCmdArgs = append(budCmdArgs, "--file", fileName) - } + // The following was taken directly from projectatomic/buildah/cmd/bud.go + // TODO Find a away to vendor more of this in rather than copy from bud + output := "" + tags := []string{} + if c.IsSet("tag") || c.IsSet("t") { + tags = c.StringSlice("tag") + if len(tags) > 0 { + output = tags[0] + tags = tags[1:] + } + } + pullPolicy := imagebuildah.PullNever + if c.BoolT("pull") { + pullPolicy = imagebuildah.PullIfMissing + } + if c.Bool("pull-always") { + pullPolicy = imagebuildah.PullAlways + } + + args := make(map[string]string) + if c.IsSet("build-arg") { + for _, arg := range c.StringSlice("build-arg") { + av := strings.SplitN(arg, "=", 2) + if len(av) > 1 { + args[av[0]] = av[1] + } else { + delete(args, av[0]) + } + } + } + + dockerfiles := c.StringSlice("file") + format := "oci" if c.IsSet("format") { - budCmdArgs = append(budCmdArgs, "--format", c.String("format")) - } - if c.IsSet("pull-always") { - budCmdArgs = append(budCmdArgs, "--pull-always") - } - if c.IsSet("quiet") { - quietParam := "--quiet=" + strconv.FormatBool(c.Bool("quiet")) - budCmdArgs = append(budCmdArgs, quietParam) - } - if c.IsSet("runtime") { - budCmdArgs = append(budCmdArgs, "--runtime", c.String("runtime")) - } - for _, runtimeArg := range c.StringSlice("runtime-flag") { - budCmdArgs = append(budCmdArgs, "--runtime-flag", runtimeArg) - } - if c.IsSet("signature-policy") { - budCmdArgs = append(budCmdArgs, "--signature-policy", c.String("signature-policy")) - } - for _, tagArg := range c.StringSlice("tag") { - budCmdArgs = append(budCmdArgs, "--tag", tagArg) - } - if c.IsSet("tls-verify") { - tlsParam := "--tls-verify=" + strconv.FormatBool(c.Bool("tls-verify")) - budCmdArgs = append(budCmdArgs, tlsParam) - } - - // Buildah bud and from options from cmd/buildah/common.go - for _, addHostArg := range c.StringSlice("add-host") { - budCmdArgs = append(budCmdArgs, "--add-host", addHostArg) - } - if c.IsSet("cgroup-parent") { - budCmdArgs = append(budCmdArgs, "--cgroup-parent", c.String("cgroup-parent")) - } - if c.IsSet("cpu-period") { - budCmdArgs = append(budCmdArgs, "--cpu-period", fmt.Sprintf("%v", c.Int64("cpu-period"))) - } - if c.IsSet("cpu-quota") { - budCmdArgs = append(budCmdArgs, "--cpu-quota", fmt.Sprintf("%v", c.Uint64("cpu-quota"))) - } - if c.IsSet("cpu-shares") { - budCmdArgs = append(budCmdArgs, "--cpu-shares", fmt.Sprintf("%v", c.Uint64("cpu-shares"))) - } - if c.IsSet("cpuset-cpus") { - budCmdArgs = append(budCmdArgs, "--cpuset-cpus", c.String("cpuset-cpus")) - } - if c.IsSet("cpuset-mems") { - budCmdArgs = append(budCmdArgs, "--cpuset-mems", c.String("cpuset-mems")) - } - if c.IsSet("memory") { - budCmdArgs = append(budCmdArgs, "--memory", c.String("memory")) - } - if c.IsSet("memory-swap") { - budCmdArgs = append(budCmdArgs, "--memory-swap", c.String("memory-swap")) - } - for _, securityOptArg := range c.StringSlice("security-opt") { - budCmdArgs = append(budCmdArgs, "--security-opt", securityOptArg) - } - if c.IsSet("shm-size") { - budCmdArgs = append(budCmdArgs, "--shm-size", c.String("shm-size")) - } - for _, ulimitArg := range c.StringSlice("ulimit") { - budCmdArgs = append(budCmdArgs, "--ulimit", ulimitArg) - } - for _, volumeArg := range c.StringSlice("volume") { - budCmdArgs = append(budCmdArgs, "--volume", volumeArg) - } - - if len(c.Args()) > 0 { - budCmdArgs = append(budCmdArgs, c.Args()...) - } - - buildah := "buildah" - - if _, err := exec.LookPath(buildah); err != nil { - return errors.Wrapf(err, "buildah not found in PATH") - } - if _, err := exec.Command(buildah).Output(); err != nil { - return errors.Wrapf(err, "buildah is not operational on this server") - } - - cmd := exec.Command(buildah, budCmdArgs...) - - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - - if err := cmd.Run(); err != nil { - return errors.Wrapf(err, "error running the buildah build-using-dockerfile (bud) command") - } - - return nil + format = strings.ToLower(c.String("format")) + } + if strings.HasPrefix(format, "oci") { + format = imagebuildah.OCIv1ImageFormat + } else if strings.HasPrefix(format, "docker") { + format = imagebuildah.Dockerv2ImageFormat + } else { + return errors.Errorf("unrecognized image type %q", format) + } + contextDir := "" + cliArgs := c.Args() + if len(cliArgs) > 0 { + // The context directory could be a URL. Try to handle that. + tempDir, subDir, err := imagebuildah.TempDirForURL("", "buildah", cliArgs[0]) + if err != nil { + return errors.Wrapf(err, "error prepping temporary context directory") + } + if tempDir != "" { + // We had to download it to a temporary directory. + // Delete it later. + defer func() { + if err = os.RemoveAll(tempDir); err != nil { + logrus.Errorf("error removing temporary directory %q: %v", contextDir, err) + } + }() + contextDir = filepath.Join(tempDir, subDir) + } else { + // Nope, it was local. Use it as is. + absDir, err := filepath.Abs(cliArgs[0]) + if err != nil { + return errors.Wrapf(err, "error determining path to directory %q", cliArgs[0]) + } + contextDir = absDir + } + cliArgs = cliArgs.Tail() + } else { + // No context directory or URL was specified. Try to use the + // home of the first locally-available Dockerfile. + for i := range dockerfiles { + if strings.HasPrefix(dockerfiles[i], "http://") || + strings.HasPrefix(dockerfiles[i], "https://") || + strings.HasPrefix(dockerfiles[i], "git://") || + strings.HasPrefix(dockerfiles[i], "github.com/") { + continue + } + absFile, err := filepath.Abs(dockerfiles[i]) + if err != nil { + return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i]) + } + contextDir = filepath.Dir(absFile) + dockerfiles[i], err = filepath.Rel(contextDir, absFile) + if err != nil { + return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i]) + } + break + } + } + if contextDir == "" { + return errors.Errorf("no context directory specified, and no dockerfile specified") + } + if len(dockerfiles) == 0 { + dockerfiles = append(dockerfiles, filepath.Join(contextDir, "Dockerfile")) + } + if err := parse.ValidateFlags(c, buildahcli.BudFlags); err != nil { + return err + } + + runtimeFlags := []string{} + for _, arg := range c.StringSlice("runtime-flag") { + runtimeFlags = append(runtimeFlags, "--"+arg) + } + // end from buildah + + runtime, err := libpodruntime.GetRuntime(c) + if err != nil { + return errors.Wrapf(err, "could not get runtime") + } + defer runtime.Shutdown(false) + + systemContext, err := parse.SystemContextFromOptions(c) + if err != nil { + return errors.Wrapf(err, "error building system context") + } + + commonOpts, err := parse.ParseCommonBuildOptions(c) + if err != nil { + return err + } + + options := imagebuildah.BuildOptions{ + ContextDirectory: contextDir, + PullPolicy: pullPolicy, + Compression: imagebuildah.Gzip, + Quiet: c.Bool("quiet"), + SignaturePolicyPath: c.String("signature-policy"), + Args: args, + Output: output, + AdditionalTags: tags, + Runtime: c.String("runtime"), + RuntimeArgs: runtimeFlags, + OutputFormat: format, + SystemContext: systemContext, + CommonBuildOpts: commonOpts, + DefaultMountsFilePath: c.GlobalString("default-mounts-file"), + } + + if !c.Bool("quiet") { + options.ReportWriter = os.Stderr + } + + return runtime.Build(getContext(), options, dockerfiles...) } |