diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/adapter/containers.go | 37 | ||||
-rw-r--r-- | pkg/adapter/containers_remote.go | 2 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 9 | ||||
-rw-r--r-- | pkg/adapter/shortcuts/shortcuts.go | 7 | ||||
-rw-r--r-- | pkg/api/handlers/utils/handler.go | 6 | ||||
-rw-r--r-- | pkg/cgroups/cgroups.go | 6 | ||||
-rw-r--r-- | pkg/hooks/docs/oci-hooks.5.md | 2 | ||||
-rw-r--r-- | pkg/inspect/inspect.go | 1 | ||||
-rw-r--r-- | pkg/spec/createconfig.go | 5 | ||||
-rw-r--r-- | pkg/spec/namespaces.go | 42 | ||||
-rw-r--r-- | pkg/spec/parse.go | 13 | ||||
-rw-r--r-- | pkg/spec/storage.go | 7 | ||||
-rw-r--r-- | pkg/systemdgen/systemdgen.go | 63 | ||||
-rw-r--r-- | pkg/systemdgen/systemdgen_test.go | 51 | ||||
-rw-r--r-- | pkg/timetype/timestamp.go | 2 | ||||
-rw-r--r-- | pkg/util/utils.go | 43 |
16 files changed, 218 insertions, 78 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index 3334e9fa1..8b21d6b94 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -375,7 +375,7 @@ func (r *LocalRuntime) selectDetachKeys(flagValue string) (string, error) { config, err := r.GetConfig() if err != nil { - return "", errors.Wrapf(err, "unable to retrive runtime config") + return "", errors.Wrapf(err, "unable to retrieve runtime config") } if config.DetachKeys != "" { return config.DetachKeys, nil @@ -609,11 +609,12 @@ func (r *LocalRuntime) Restore(ctx context.Context, c *cliconfig.RestoreValues) return state == define.ContainerStateExited }) - if c.Import != "" { + switch { + case c.Import != "": containers, err = crImportCheckpoint(ctx, r.Runtime, c.Import, c.Name) - } else if c.All { + case c.All: containers, err = r.GetContainers(filterFuncs...) - } else { + default: containers, err = shortcuts.GetContainersByContext(false, c.Latest, c.InputArgs, r.Runtime) } if err != nil { @@ -835,25 +836,26 @@ func (r *LocalRuntime) Restart(ctx context.Context, c *cliconfig.RestartValues) inputTimeout := c.Timeout // Handle --latest - if c.Latest { + switch { + case c.Latest: lastCtr, err := r.Runtime.GetLatestContainer() if err != nil { return nil, nil, errors.Wrapf(err, "unable to get latest container") } restartContainers = append(restartContainers, lastCtr) - } else if c.Running { + case c.Running: containers, err = r.GetRunningContainers() if err != nil { return nil, nil, err } restartContainers = append(restartContainers, containers...) - } else if c.All { + case c.All: containers, err = r.Runtime.GetAllContainers() if err != nil { return nil, nil, err } restartContainers = append(restartContainers, containers...) - } else { + default: for _, id := range c.InputArgs { ctr, err := r.Runtime.LookupContainer(id) if err != nil { @@ -1048,7 +1050,7 @@ func (r *LocalRuntime) ExecContainer(ctx context.Context, cli *cliconfig.ExecVal } // Prune removes stopped containers -func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filters []string) ([]string, map[string]error, error) { +func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filters []string) ([]string, map[string]error, error) { var ( ok = []string{} failures = map[string]error{} @@ -1100,7 +1102,7 @@ func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, fi pool.Add(shared.Job{ ID: ctr.ID(), Fn: func() error { - err := r.Runtime.RemoveContainer(ctx, ctr, force, false) + err := r.Runtime.RemoveContainer(ctx, ctr, false, false) if err != nil { logrus.Debugf("Failed to prune container %s: %s", ctr.ID(), err.Error()) } @@ -1230,6 +1232,7 @@ func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSyst PIDFile: conmonPidFile, StopTimeout: timeout, GenerateTimestamp: true, + CreateCommand: config.CreateCommand, } return info, true, nil @@ -1237,11 +1240,21 @@ func (r *LocalRuntime) generateSystemdgenContainerInfo(c *cliconfig.GenerateSyst // GenerateSystemd creates a unit file for a container or pod. func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) { + opts := systemdgen.Options{ + Files: c.Files, + New: c.New, + } + // First assume it's a container. if info, found, err := r.generateSystemdgenContainerInfo(c, c.InputArgs[0], nil); found && err != nil { return "", err } else if found && err == nil { - return systemdgen.CreateContainerSystemdUnit(info, c.Files) + return systemdgen.CreateContainerSystemdUnit(info, opts) + } + + // --new does not support pods. + if c.New { + return "", errors.Errorf("error generating systemd unit files: cannot generate generic files for a pod") } // We're either having a pod or garbage. @@ -1312,7 +1325,7 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri if i > 0 { builder.WriteByte('\n') } - out, err := systemdgen.CreateContainerSystemdUnit(info, c.Files) + out, err := systemdgen.CreateContainerSystemdUnit(info, opts) if err != nil { return "", err } diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 36db4af68..60ee3cb2d 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -922,7 +922,7 @@ func (r *LocalRuntime) Top(cli *cliconfig.TopValues) ([]string, error) { } // Prune removes stopped containers -func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, force bool, filter []string) ([]string, map[string]error, error) { +func (r *LocalRuntime) Prune(ctx context.Context, maxWorkers int, filter []string) ([]string, map[string]error, error) { var ( ok = []string{} diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 5f880e807..40089797d 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -59,7 +59,7 @@ type Volume struct { // VolumeFilter is for filtering volumes on the client type VolumeFilter func(*Volume) bool -// GetRuntimeNoStore returns a localruntime struct wit an embedded runtime but +// GetRuntimeNoStore returns a localruntime struct with an embedded runtime but // without a configured storage. func GetRuntimeNoStore(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { runtime, err := libpodruntime.GetRuntimeNoStore(ctx, c) @@ -407,7 +407,8 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error { } w := bufio.NewWriter(os.Stdout) for event := range eventChannel { - if c.Format == formats.JSONString { + switch { + case c.Format == formats.JSONString: jsonStr, err := event.ToJSONString() if err != nil { return errors.Wrapf(err, "unable to format json") @@ -415,11 +416,11 @@ func (r *LocalRuntime) Events(c *cliconfig.EventValues) error { if _, err := w.Write([]byte(jsonStr)); err != nil { return err } - } else if len(c.Format) > 0 { + case len(c.Format) > 0: if err := tmpl.Execute(w, event); err != nil { return err } - } else { + default: if _, err := w.Write([]byte(event.ToHumanReadable())); err != nil { return err } diff --git a/pkg/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go index 4f6cfd6a3..8a8459c6c 100644 --- a/pkg/adapter/shortcuts/shortcuts.go +++ b/pkg/adapter/shortcuts/shortcuts.go @@ -42,12 +42,13 @@ func GetContainersByContext(all, latest bool, names []string, runtime *libpod.Ru var ctr *libpod.Container ctrs = []*libpod.Container{} - if all { + switch { + case all: ctrs, err = runtime.GetAllContainers() - } else if latest { + case latest: ctr, err = runtime.GetLatestContainer() ctrs = append(ctrs, ctr) - } else { + default: for _, n := range names { ctr, e := runtime.LookupContainer(n) if e != nil { diff --git a/pkg/api/handlers/utils/handler.go b/pkg/api/handlers/utils/handler.go index 0815e6eca..8c2110f97 100644 --- a/pkg/api/handlers/utils/handler.go +++ b/pkg/api/handlers/utils/handler.go @@ -12,19 +12,19 @@ import ( // WriteResponse encodes the given value as JSON or string and renders it for http client func WriteResponse(w http.ResponseWriter, code int, value interface{}) { - switch value.(type) { + switch v := value.(type) { case string: w.Header().Set("Content-Type", "text/plain; charset=us-ascii") w.WriteHeader(code) - if _, err := fmt.Fprintln(w, value); err != nil { + if _, err := fmt.Fprintln(w, v); err != nil { log.Errorf("unable to send string response: %q", err) } case *os.File: w.Header().Set("Content-Type", "application/octet; charset=us-ascii") w.WriteHeader(code) - if _, err := io.Copy(w, value.(*os.File)); err != nil { + if _, err := io.Copy(w, v); err != nil { log.Errorf("unable to copy to response: %q", err) } default: diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index 9711e8120..6b28b2759 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -155,7 +155,7 @@ func (c *CgroupControl) getCgroupv1Path(name string) string { } // createCgroupv2Path creates the cgroupv2 path and enables all the available controllers -func createCgroupv2Path(path string) (Err error) { +func createCgroupv2Path(path string) (deferredError error) { content, err := ioutil.ReadFile("/sys/fs/cgroup/cgroup.controllers") if err != nil { return errors.Wrapf(err, "read /sys/fs/cgroup/cgroup.controllers") @@ -169,7 +169,7 @@ func createCgroupv2Path(path string) (Err error) { if i == 0 { res = fmt.Sprintf("+%s", c) } else { - res = res + fmt.Sprintf(" +%s", c) + res += fmt.Sprintf(" +%s", c) } } resByte := []byte(res) @@ -186,7 +186,7 @@ func createCgroupv2Path(path string) (Err error) { } else { // If the directory was created, be sure it is not left around on errors. defer func() { - if Err != nil { + if deferredError != nil { os.Remove(current) } }() diff --git a/pkg/hooks/docs/oci-hooks.5.md b/pkg/hooks/docs/oci-hooks.5.md index b50a6bddc..7d13ffa82 100644 --- a/pkg/hooks/docs/oci-hooks.5.md +++ b/pkg/hooks/docs/oci-hooks.5.md @@ -25,7 +25,7 @@ Tools consuming this format may also opt to monitor the hook directories for cha Hooks are injected in the order obtained by sorting the JSON file names, after converting them to lower case, based on their Unicode code points. For example, a matching hook defined in `01-my-hook.json` would be injected before matching hooks defined in `02-another-hook.json` and `01-UPPERCASE.json`. -It is strongly recommended to make the sort oder unambiguous depending on an ASCII-only prefix (like the `01`/`02` above). +It is strongly recommended to make the sort order unambiguous depending on an ASCII-only prefix (like the `01`/`02` above). Each JSON file should contain an object with one of the following schemas. diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go index ec3d98613..8249dc4aa 100644 --- a/pkg/inspect/inspect.go +++ b/pkg/inspect/inspect.go @@ -31,6 +31,7 @@ type ImageData struct { ManifestType string `json:"ManifestType"` User string `json:"User"` History []v1.History `json:"History"` + NamesHistory []string `json:"NamesHistory"` } // RootFS holds the root fs information of an image diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index 244a8d1cd..6d058229b 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -282,10 +282,13 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l options = append(options, libpod.WithStopSignal(c.StopSignal)) options = append(options, libpod.WithStopTimeout(c.StopTimeout)) - logPath := getLoggingPath(c.LogDriverOpt) + logPath, logTag := getLoggingOpts(c.LogDriverOpt) if logPath != "" { options = append(options, libpod.WithLogPath(logPath)) } + if logTag != "" { + options = append(options, libpod.WithLogTag(logTag)) + } if c.LogDriver != "" { options = append(options, libpod.WithLogDriver(c.LogDriver)) diff --git a/pkg/spec/namespaces.go b/pkg/spec/namespaces.go index 8e95a3ca0..e62d4ed0a 100644 --- a/pkg/spec/namespaces.go +++ b/pkg/spec/namespaces.go @@ -44,7 +44,8 @@ func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserCon } } - if c.NetMode.IsNS() { + switch { + case c.NetMode.IsNS(): ns := c.NetMode.NS() if ns == "" { return nil, errors.Errorf("invalid empty user-defined network namespace") @@ -53,13 +54,13 @@ func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserCon if err != nil { return nil, err } - } else if c.NetMode.IsContainer() { + case c.NetMode.IsContainer(): connectedCtr, err := runtime.LookupContainer(c.NetMode.Container()) if err != nil { return nil, errors.Wrapf(err, "container %q not found", c.NetMode.Container()) } options = append(options, libpod.WithNetNSFrom(connectedCtr)) - } else if !c.NetMode.IsHost() && !c.NetMode.IsNone() { + case !c.NetMode.IsHost() && !c.NetMode.IsNone(): postConfigureNetNS := userns.getPostConfigureNetNS() options = append(options, libpod.WithNetNS(portBindings, postConfigureNetNS, string(c.NetMode), networks)) } @@ -102,29 +103,31 @@ func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserCon // state of the NetworkConfig. func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error { netMode := c.NetMode - if netMode.IsHost() { + netCtr := netMode.Container() + switch { + case netMode.IsHost(): logrus.Debug("Using host netmode") if err := g.RemoveLinuxNamespace(string(spec.NetworkNamespace)); err != nil { return err } - } else if netMode.IsNone() { + case netMode.IsNone(): logrus.Debug("Using none netmode") - } else if netMode.IsBridge() { + case netMode.IsBridge(): logrus.Debug("Using bridge netmode") - } else if netCtr := netMode.Container(); netCtr != "" { + case netCtr != "": logrus.Debugf("using container %s netmode", netCtr) - } else if IsNS(string(netMode)) { + case IsNS(string(netMode)): logrus.Debug("Using ns netmode") if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), NS(string(netMode))); err != nil { return err } - } else if IsPod(string(netMode)) { + case IsPod(string(netMode)): logrus.Debug("Using pod netmode, unless pod is not sharing") - } else if netMode.IsSlirp4netns() { + case netMode.IsSlirp4netns(): logrus.Debug("Using slirp4netns netmode") - } else if netMode.IsUserDefined() { + case netMode.IsUserDefined(): logrus.Debug("Using user defined netmode") - } else { + default: return errors.Errorf("unknown network mode") } @@ -220,7 +223,8 @@ func (c *CgroupConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCre // ToCreateOptions converts the input to container create options. func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreateOption, error) { options := make([]libpod.CtrCreateOption, 0) - if c.UsernsMode.IsNS() { + switch { + case c.UsernsMode.IsNS(): ns := c.UsernsMode.NS() if ns == "" { return nil, errors.Errorf("invalid empty user-defined user namespace") @@ -230,13 +234,13 @@ func (c *UserConfig) ToCreateOptions(runtime *libpod.Runtime) ([]libpod.CtrCreat return nil, err } options = append(options, libpod.WithIDMappings(*c.IDMappings)) - } else if c.UsernsMode.IsContainer() { + case c.UsernsMode.IsContainer(): connectedCtr, err := runtime.LookupContainer(c.UsernsMode.Container()) if err != nil { return nil, errors.Wrapf(err, "container %q not found", c.UsernsMode.Container()) } options = append(options, libpod.WithUserNSFrom(connectedCtr)) - } else { + default: options = append(options, libpod.WithIDMappings(*c.IDMappings)) } @@ -413,20 +417,22 @@ func (c *UtsConfig) ToCreateOptions(runtime *libpod.Runtime, pod *libpod.Pod) ([ // of the UtsConfig. func (c *UtsConfig) ConfigureGenerator(g *generate.Generator, net *NetworkConfig, runtime *libpod.Runtime) error { hostname := c.Hostname + utsCtrID := c.UtsMode.Container() var err error if hostname == "" { - if utsCtrID := c.UtsMode.Container(); utsCtrID != "" { + switch { + case utsCtrID != "": utsCtr, err := runtime.GetContainer(utsCtrID) if err != nil { return errors.Wrapf(err, "unable to retrieve hostname from dependency container %s", utsCtrID) } hostname = utsCtr.Hostname() - } else if net.NetMode.IsHost() || c.UtsMode.IsHost() { + case net.NetMode.IsHost() || c.UtsMode.IsHost(): hostname, err = os.Hostname() if err != nil { return errors.Wrap(err, "unable to retrieve hostname of the host") } - } else { + default: logrus.Debug("No hostname set; container's hostname will default to runtime default") } } diff --git a/pkg/spec/parse.go b/pkg/spec/parse.go index c2572a033..6fa0b0636 100644 --- a/pkg/spec/parse.go +++ b/pkg/spec/parse.go @@ -132,16 +132,23 @@ func validateIOpsDevice(val string) (*throttleDevice, error) { //nolint }, nil } -func getLoggingPath(opts []string) string { +// getLoggingOpts splits the path= and tag= options provided to --log-opt. +func getLoggingOpts(opts []string) (string, string) { + var path, tag string for _, opt := range opts { arr := strings.SplitN(opt, "=", 2) if len(arr) == 2 { if strings.TrimSpace(arr[0]) == "path" { - return strings.TrimSpace(arr[1]) + path = strings.TrimSpace(arr[1]) + } else if strings.TrimSpace(arr[0]) == "tag" { + tag = strings.TrimSpace(arr[1]) } } + if path != "" && tag != "" { + break + } } - return "" + return path, tag } // ParseDevice parses device mapping string to a src, dest & permissions string diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index dbdab0030..0e2098c1d 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -409,9 +409,10 @@ func getBindMount(args []string) (spec.Mount, error) { // ro=[true|false] // rw // rw=[true|false] - if len(kv) == 1 { + switch len(kv) { + case 1: newMount.Options = append(newMount.Options, kv[0]) - } else if len(kv) == 2 { + case 2: switch strings.ToLower(kv[1]) { case "true": newMount.Options = append(newMount.Options, kv[0]) @@ -424,7 +425,7 @@ func getBindMount(args []string) (spec.Mount, error) { default: return newMount, errors.Wrapf(optionArgError, "%s must be set to true or false, instead received %q", kv[0], kv[1]) } - } else { + default: return newMount, errors.Wrapf(optionArgError, "badly formatted option %q", val) } case "nosuid", "suid": diff --git a/pkg/systemdgen/systemdgen.go b/pkg/systemdgen/systemdgen.go index 09d3c6fd5..b6167a23e 100644 --- a/pkg/systemdgen/systemdgen.go +++ b/pkg/systemdgen/systemdgen.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "sort" + "strings" "text/template" "time" @@ -48,6 +49,14 @@ type ContainerInfo struct { Executable string // TimeStamp at the time of creating the unit file. Will be set internally. TimeStamp string + // New controls if a new container is created or if an existing one is started. + New bool + // CreateCommand is the full command plus arguments of the process the + // container has been created with. + CreateCommand []string + // RunCommand is a post-processed variant of CreateCommand and used for + // the ExecStart field in generic unit files. + RunCommand string } var restartPolicies = []string{"no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always"} @@ -84,17 +93,35 @@ Before={{- range $index, $value := .RequiredServices -}}{{if $index}} {{end}}{{ [Service] Restart={{.RestartPolicy}} +{{- if .New}} +ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid +ExecStart={{.RunCommand}} +ExecStop={{.Executable}} stop --cidfile /%t/%n-cid {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} +ExecStopPost={{.Executable}} rm -f --cidfile /%t/%n-cid +PIDFile=/%t/%n-pid +{{- else}} ExecStart={{.Executable}} start {{.ContainerName}} ExecStop={{.Executable}} stop {{if (ge .StopTimeout 0)}}-t {{.StopTimeout}}{{end}} {{.ContainerName}} +PIDFile={{.PIDFile}} +{{- end}} KillMode=none Type=forking -PIDFile={{.PIDFile}} [Install] WantedBy=multi-user.target` +// Options include different options to control the unit file generation. +type Options struct { + // When set, generate service files in the current working directory and + // return the paths to these files instead of returning all contents in one + // big string. + Files bool + // New controls if a new container is created or if an existing one is started. + New bool +} + // CreateContainerSystemdUnit creates a systemd unit file for a container. -func CreateContainerSystemdUnit(info *ContainerInfo, generateFiles bool) (string, error) { +func CreateContainerSystemdUnit(info *ContainerInfo, opts Options) (string, error) { if err := validateRestartPolicy(info.RestartPolicy); err != nil { return "", err } @@ -109,6 +136,36 @@ func CreateContainerSystemdUnit(info *ContainerInfo, generateFiles bool) (string info.Executable = executable } + // Assemble the ExecStart command when creating a new container. + // + // Note that we cannot catch all corner cases here such that users + // *must* manually check the generated files. A container might have + // been created via a Python script, which would certainly yield an + // invalid `info.CreateCommand`. Hence, we're doing a best effort unit + // generation and don't try aiming at completeness. + if opts.New { + // The create command must at least have three arguments: + // /usr/bin/podman run $IMAGE + index := 2 + if info.CreateCommand[1] == "container" { + index = 3 + } + if len(info.CreateCommand) < index+1 { + return "", errors.Errorf("container's create command is too short or invalid: %v", info.CreateCommand) + } + // We're hard-coding the first four arguments and append the + // CreatCommand with a stripped command and subcomand. + command := []string{ + info.Executable, + "run", + "--conmon-pidfile", "/%t/%n-pid", + "--cidfile", "/%t/%n-cid", + } + command = append(command, info.CreateCommand[index:]...) + info.RunCommand = strings.Join(command, " ") + info.New = true + } + if info.PodmanVersion == "" { info.PodmanVersion = version.Version } @@ -131,7 +188,7 @@ func CreateContainerSystemdUnit(info *ContainerInfo, generateFiles bool) (string return "", err } - if !generateFiles { + if !opts.Files { return buf.String(), nil } diff --git a/pkg/systemdgen/systemdgen_test.go b/pkg/systemdgen/systemdgen_test.go index 1ddb0c514..e1da7e8e0 100644 --- a/pkg/systemdgen/systemdgen_test.go +++ b/pkg/systemdgen/systemdgen_test.go @@ -44,9 +44,9 @@ Documentation=man:podman-generate-systemd(1) Restart=always ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 +PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid KillMode=none Type=forking -PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid [Install] WantedBy=multi-user.target` @@ -62,9 +62,9 @@ Documentation=man:podman-generate-systemd(1) Restart=always ExecStart=/usr/bin/podman start foobar ExecStop=/usr/bin/podman stop -t 10 foobar +PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid KillMode=none Type=forking -PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid [Install] WantedBy=multi-user.target` @@ -84,9 +84,9 @@ After=a.service b.service c.service pod.service Restart=always ExecStart=/usr/bin/podman start foobar ExecStop=/usr/bin/podman stop -t 10 foobar +PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid KillMode=none Type=forking -PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid [Install] WantedBy=multi-user.target` @@ -104,9 +104,29 @@ Before=container-1.service container-2.service Restart=always ExecStart=/usr/bin/podman start jadda-jadda-infra ExecStop=/usr/bin/podman stop -t 10 jadda-jadda-infra +PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid +KillMode=none +Type=forking + +[Install] +WantedBy=multi-user.target` + + goodNameNew := `# jadda-jadda.service +# autogenerated by Podman CI + +[Unit] +Description=Podman jadda-jadda.service +Documentation=man:podman-generate-systemd(1) + +[Service] +Restart=always +ExecStartPre=/usr/bin/rm -f /%t/%n-pid /%t/%n-cid +ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /%t/%n-cid --name jadda-jadda --hostname hello-world awesome-image:latest command arg1 ... argN +ExecStop=/usr/bin/podman stop --cidfile /%t/%n-cid -t 42 +ExecStopPost=/usr/bin/podman rm -f --cidfile /%t/%n-cid +PIDFile=/%t/%n-pid KillMode=none Type=forking -PIDFile=/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid [Install] WantedBy=multi-user.target` @@ -184,16 +204,35 @@ WantedBy=multi-user.target` "", true, }, + {"good with name and generic", + ContainerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "jadda-jadda", + ContainerName: "jadda-jadda", + RestartPolicy: "always", + PIDFile: "/var/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 42, + PodmanVersion: "CI", + New: true, + CreateCommand: []string{"I'll get stripped", "container", "run", "--name", "jadda-jadda", "--hostname", "hello-world", "awesome-image:latest", "command", "arg1", "...", "argN"}, + }, + goodNameNew, + false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := CreateContainerSystemdUnit(&tt.info, false) + opts := Options{ + Files: false, + New: tt.info.New, + } + got, err := CreateContainerSystemdUnit(&tt.info, opts) if (err != nil) != tt.wantErr { t.Errorf("CreateContainerSystemdUnit() error = \n%v, wantErr \n%v", err, tt.wantErr) return } if got != tt.want { - t.Errorf("CreateContainerSystemdUnit() = \n%v, want \n%v", got, tt.want) + t.Errorf("CreateContainerSystemdUnit() = \n%v\n---------> want\n%v", got, tt.want) } }) } diff --git a/pkg/timetype/timestamp.go b/pkg/timetype/timestamp.go index eb904a574..2de1a005f 100644 --- a/pkg/timetype/timestamp.go +++ b/pkg/timetype/timestamp.go @@ -34,7 +34,7 @@ func GetTimestamp(value string, reference time.Time) (string, error) { // if the string has a Z or a + or three dashes use parse otherwise use parseinlocation parseInLocation := !(strings.ContainsAny(value, "zZ+") || strings.Count(value, "-") == 3) - if strings.Contains(value, ".") { + if strings.Contains(value, ".") { // nolint(gocritic) if parseInLocation { format = rFC3339NanoLocal } else { diff --git a/pkg/util/utils.go b/pkg/util/utils.go index c9d09b8b5..6aa3c221e 100644 --- a/pkg/util/utils.go +++ b/pkg/util/utils.go @@ -321,20 +321,27 @@ func ParseSignal(rawSignal string) (syscall.Signal, error) { } // ParseIDMapping takes idmappings and subuid and subgid maps and returns a storage mapping -func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) { +func ParseIDMapping(mode namespaces.UsernsMode, uidMapSlice, gidMapSlice []string, subUIDMap, subGIDMap string) (*storage.IDMappingOptions, error) { options := storage.IDMappingOptions{ HostUIDMapping: true, HostGIDMapping: true, } if mode.IsKeepID() { - if len(UIDMapSlice) > 0 || len(GIDMapSlice) > 0 { + if len(uidMapSlice) > 0 || len(gidMapSlice) > 0 { return nil, errors.New("cannot specify custom mappings with --userns=keep-id") } if len(subUIDMap) > 0 || len(subGIDMap) > 0 { return nil, errors.New("cannot specify subuidmap or subgidmap with --userns=keep-id") } if rootless.IsRootless() { + min := func(a, b int) int { + if a < b { + return a + } + return b + } + uid := rootless.GetRootlessUID() gid := rootless.GetRootlessGID() @@ -352,13 +359,17 @@ func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []strin options.UIDMap, options.GIDMap = nil, nil - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: uid}) + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(uid, maxUID)}) options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid, HostID: 0, Size: 1}) - options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) + if maxUID > uid { + options.UIDMap = append(options.UIDMap, idtools.IDMap{ContainerID: uid + 1, HostID: uid + 1, Size: maxUID - uid}) + } - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: gid}) + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: 0, HostID: 1, Size: min(gid, maxGID)}) options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid, HostID: 0, Size: 1}) - options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) + if maxGID > gid { + options.GIDMap = append(options.GIDMap, idtools.IDMap{ContainerID: gid + 1, HostID: gid + 1, Size: maxGID - gid}) + } options.HostUIDMapping = false options.HostGIDMapping = false @@ -373,17 +384,17 @@ func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []strin if subUIDMap == "" && subGIDMap != "" { subUIDMap = subGIDMap } - if len(GIDMapSlice) == 0 && len(UIDMapSlice) != 0 { - GIDMapSlice = UIDMapSlice + if len(gidMapSlice) == 0 && len(uidMapSlice) != 0 { + gidMapSlice = uidMapSlice } - if len(UIDMapSlice) == 0 && len(GIDMapSlice) != 0 { - UIDMapSlice = GIDMapSlice + if len(uidMapSlice) == 0 && len(gidMapSlice) != 0 { + uidMapSlice = gidMapSlice } - if len(UIDMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 { - UIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())} + if len(uidMapSlice) == 0 && subUIDMap == "" && os.Getuid() != 0 { + uidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getuid())} } - if len(GIDMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 { - GIDMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())} + if len(gidMapSlice) == 0 && subGIDMap == "" && os.Getuid() != 0 { + gidMapSlice = []string{fmt.Sprintf("0:%d:1", os.Getgid())} } if subUIDMap != "" && subGIDMap != "" { @@ -394,11 +405,11 @@ func ParseIDMapping(mode namespaces.UsernsMode, UIDMapSlice, GIDMapSlice []strin options.UIDMap = mappings.UIDs() options.GIDMap = mappings.GIDs() } - parsedUIDMap, err := idtools.ParseIDMap(UIDMapSlice, "UID") + parsedUIDMap, err := idtools.ParseIDMap(uidMapSlice, "UID") if err != nil { return nil, err } - parsedGIDMap, err := idtools.ParseIDMap(GIDMapSlice, "GID") + parsedGIDMap, err := idtools.ParseIDMap(gidMapSlice, "GID") if err != nil { return nil, err } |