diff options
Diffstat (limited to 'cmd/podman/shared/create.go')
-rw-r--r-- | cmd/podman/shared/create.go | 109 |
1 files changed, 81 insertions, 28 deletions
diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 7cf230605..9578eb17d 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/containers/libpod/pkg/errorhandling" "io" "os" "path/filepath" @@ -25,7 +26,6 @@ import ( "github.com/docker/docker/pkg/signal" "github.com/docker/go-connections/nat" "github.com/docker/go-units" - "github.com/google/shlex" "github.com/opencontainers/selinux/go-selinux/label" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" @@ -56,15 +56,15 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. } if c.IsSet("cidfile") && os.Geteuid() == 0 { - cidFile, err = libpod.OpenExclusiveFile(c.String("cidfile")) + cidFile, err = util.OpenExclusiveFile(c.String("cidfile")) if err != nil && os.IsExist(err) { return nil, nil, errors.Errorf("container id file exists. Ensure another container is not using it or delete %s", c.String("cidfile")) } if err != nil { return nil, nil, errors.Errorf("error opening cidfile %s", c.String("cidfile")) } - defer cidFile.Close() - defer cidFile.Sync() + defer errorhandling.CloseQuiet(cidFile) + defer errorhandling.SyncQuiet(cidFile) } imageName := "" @@ -77,11 +77,14 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. writer = os.Stderr } - newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, "", writer, nil, image.SigningOptions{}, false, nil) + newImage, err := runtime.ImageRuntime().New(ctx, c.InputArgs[0], rtc.SignaturePolicyPath, GetAuthFile(""), writer, nil, image.SigningOptions{}, false, nil) if err != nil { return nil, nil, err } data, err = newImage.Inspect(ctx) + if err != nil { + return nil, nil, err + } names := newImage.Names() if len(names) > 0 { imageName = names[0] @@ -89,9 +92,8 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. imageName = newImage.ID() } - var healthCheckCommandInput string // if the user disabled the healthcheck with "none", we skip adding it - healthCheckCommandInput = c.String("healthcheck-command") + healthCheckCommandInput := c.String("healthcheck-command") // the user didnt disable the healthcheck but did pass in a healthcheck command // now we need to make a healthcheck from the commandline input @@ -113,6 +115,30 @@ func CreateContainer(ctx context.Context, c *GenericCLIResults, runtime *libpod. if err != nil { return nil, nil, errors.Wrapf(err, "unable to get healthcheck for %s", c.InputArgs[0]) } + + if healthCheck != nil { + hcCommand := healthCheck.Test + if len(hcCommand) < 1 || hcCommand[0] == "" || hcCommand[0] == "NONE" { + // disable health check + healthCheck = nil + } else { + // apply defaults if image doesn't override them + if healthCheck.Interval == 0 { + healthCheck.Interval = 30 * time.Second + } + if healthCheck.Timeout == 0 { + healthCheck.Timeout = 30 * time.Second + } + /* Docker default is 0s, so the following would be a no-op + if healthCheck.StartPeriod == 0 { + healthCheck.StartPeriod = 0 * time.Second + } + */ + if healthCheck.Retries == 0 { + healthCheck.Retries = 3 + } + } + } } } } @@ -191,7 +217,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l } else { con := strings.SplitN(opt, "=", 2) if len(con) != 2 { - return fmt.Errorf("Invalid --security-opt 1: %q", opt) + return fmt.Errorf("invalid --security-opt 1: %q", opt) } switch con[0] { @@ -202,7 +228,7 @@ func parseSecurityOpt(config *cc.CreateConfig, securityOpts []string, runtime *l case "seccomp": config.SeccompProfilePath = con[1] default: - return fmt.Errorf("Invalid --security-opt 2: %q", opt) + return fmt.Errorf("invalid --security-opt 2: %q", opt) } } } @@ -256,13 +282,26 @@ func configurePod(c *GenericCLIResults, runtime *libpod.Runtime, namespaces map[ if err != nil { return namespaces, err } + hasUserns := false + if podInfraID != "" { + podCtr, err := runtime.GetContainer(podInfraID) + if err != nil { + return namespaces, err + } + mappings, err := podCtr.IDMappings() + if err != nil { + return namespaces, err + } + hasUserns = len(mappings.UIDMap) > 0 + } + if (namespaces["pid"] == cc.Pod) || (!c.IsSet("pid") && pod.SharesPID()) { namespaces["pid"] = fmt.Sprintf("container:%s", podInfraID) } if (namespaces["net"] == cc.Pod) || (!c.IsSet("net") && !c.IsSet("network") && pod.SharesNet()) { namespaces["net"] = fmt.Sprintf("container:%s", podInfraID) } - if (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) { + if hasUserns && (namespaces["user"] == cc.Pod) || (!c.IsSet("user") && pod.SharesUser()) { namespaces["user"] = fmt.Sprintf("container:%s", podInfraID) } if (namespaces["ipc"] == cc.Pod) || (!c.IsSet("ipc") && pod.SharesIPC()) { @@ -374,11 +413,12 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. namespaceNet = c.String("net") } namespaces = map[string]string{ - "pid": c.String("pid"), - "net": namespaceNet, - "ipc": c.String("ipc"), - "user": c.String("userns"), - "uts": c.String("uts"), + "cgroup": c.String("cgroupns"), + "pid": c.String("pid"), + "net": namespaceNet, + "ipc": c.String("ipc"), + "user": c.String("userns"), + "uts": c.String("uts"), } originalPodName := c.String("pod") @@ -436,6 +476,11 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. return nil, errors.Errorf("--uts %q is not valid", namespaces["uts"]) } + cgroupMode := ns.CgroupMode(namespaces["cgroup"]) + if !cgroupMode.Valid() { + return nil, errors.Errorf("--cgroup %q is not valid", namespaces["cgroup"]) + } + ipcMode := ns.IpcMode(namespaces["ipc"]) if !cc.Valid(string(ipcMode), ipcMode) { return nil, errors.Errorf("--ipc %q is not valid", ipcMode) @@ -479,6 +524,16 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. // ENVIRONMENT VARIABLES env := EnvVariablesFromData(data) + if c.Bool("env-host") { + for _, e := range os.Environ() { + pair := strings.SplitN(e, "=", 2) + if _, ok := env[pair[0]]; !ok { + if len(pair) > 1 { + env[pair[0]] = pair[1] + } + } + } + } if err := parse.ReadKVStrings(env, c.StringSlice("env-file"), c.StringArray("env")); err != nil { return nil, errors.Wrapf(err, "unable to process environment variables") } @@ -615,6 +670,8 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. ImageVolumeType: c.String("image-volume"), CapAdd: c.StringSlice("cap-add"), CapDrop: c.StringSlice("cap-drop"), + CidFile: c.String("cidfile"), + Cgroupns: c.String("cgroupns"), CgroupParent: c.String("cgroup-parent"), Command: command, Detach: c.Bool("detach"), @@ -650,6 +707,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. NetMode: netMode, UtsMode: utsMode, PidMode: pidMode, + CgroupMode: cgroupMode, Pod: podName, Privileged: c.Bool("privileged"), Publish: c.StringSlice("publish"), @@ -690,7 +748,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. StopTimeout: c.Uint("stop-timeout"), Sysctl: sysctl, Systemd: systemd, - Tmpfs: c.StringSlice("tmpfs"), + Tmpfs: c.StringArray("tmpfs"), Tty: tty, User: user, UsernsMode: usernsMode, @@ -730,14 +788,6 @@ func CreateContainerFromCreateConfig(r *libpod.Runtime, createConfig *cc.CreateC if err != nil { return nil, err } - - createConfigJSON, err := json.Marshal(createConfig) - if err != nil { - return nil, err - } - if err := ctr.AddArtifact("create-config", createConfigJSON); err != nil { - return nil, err - } return ctr, nil } @@ -775,9 +825,12 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig return nil, errors.New("Must define a healthcheck command for all healthchecks") } - cmd, err := shlex.Split(inCommand) + // first try to parse option value as JSON array of strings... + cmd := []string{} + err := json.Unmarshal([]byte(inCommand), &cmd) if err != nil { - return nil, errors.Wrap(err, "failed to parse healthcheck command") + // ...otherwise pass it to "/bin/sh -c" inside the container + cmd = []string{"CMD-SHELL", inCommand} } hc := manifest.Schema2HealthConfig{ Test: cmd, @@ -801,7 +854,7 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig if err != nil { return nil, errors.Wrapf(err, "invalid healthcheck-timeout %s", inTimeout) } - if timeoutDuration < time.Duration(time.Second*1) { + if timeoutDuration < time.Duration(1) { return nil, errors.New("healthcheck-timeout must be at least 1 second") } hc.Timeout = timeoutDuration @@ -811,7 +864,7 @@ func makeHealthCheckFromCli(c *GenericCLIResults) (*manifest.Schema2HealthConfig return nil, errors.Wrapf(err, "invalid healthcheck-start-period %s", inStartPeriod) } if startPeriodDuration < time.Duration(0) { - return nil, errors.New("healthcheck-start-period must be a 0 seconds or greater") + return nil, errors.New("healthcheck-start-period must be 0 seconds or greater") } hc.StartPeriod = startPeriodDuration |