diff options
author | jortkoopmans <jort@jabo-solutions.eu> | 2020-11-25 18:26:22 +0100 |
---|---|---|
committer | jortkoopmans <jort@jabo-solutions.eu> | 2020-11-25 18:27:31 +0100 |
commit | 5cfbe0b78e3672dd67cd028b85d816fc19d6a614 (patch) | |
tree | 375fe5a96bca7d04154daf63ac9b644ebb1adc34 /cmd/podman/common | |
parent | a18365c908d45a8ee9348c5e32a240a7b9a4091b (diff) | |
download | podman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.tar.gz podman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.tar.bz2 podman-5cfbe0b78e3672dd67cd028b85d816fc19d6a614.zip |
squash
Signed-off-by: jortkoopmans <jort@jabo-solutions.eu>
Diffstat (limited to 'cmd/podman/common')
-rw-r--r-- | cmd/podman/common/completion.go | 251 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 18 | ||||
-rw-r--r-- | cmd/podman/common/create_opts.go | 153 | ||||
-rw-r--r-- | cmd/podman/common/createparse.go | 2 | ||||
-rw-r--r-- | cmd/podman/common/netflags.go | 34 | ||||
-rw-r--r-- | cmd/podman/common/volumes.go | 102 |
6 files changed, 345 insertions, 215 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index db4d3d0d3..9856e46ef 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -12,7 +12,9 @@ import ( "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/registries" + "github.com/containers/podman/v2/pkg/rootless" systemdGen "github.com/containers/podman/v2/pkg/systemd/generate" + "github.com/containers/podman/v2/pkg/util" "github.com/spf13/cobra" ) @@ -36,7 +38,35 @@ const ( type keyValueCompletion map[string]func(s string) ([]string, cobra.ShellCompDirective) -func getContainers(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) { +func setupContainerEngine(cmd *cobra.Command) (entities.ContainerEngine, error) { + containerEngine, err := registry.NewContainerEngine(cmd, []string{}) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, err + } + if !registry.IsRemote() && rootless.IsRootless() { + err := containerEngine.SetupRootless(registry.Context(), cmd) + if err != nil { + return nil, err + } + } + return containerEngine, nil +} + +func setupImageEngine(cmd *cobra.Command) (entities.ImageEngine, error) { + imageEngine, err := registry.NewImageEngine(cmd, []string{}) + if err != nil { + return nil, err + } + // we also need to set up the container engine since this + // is required to setup the rootless namespace + if _, err = setupContainerEngine(cmd); err != nil { + return nil, err + } + return imageEngine, nil +} + +func getContainers(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) { suggestions := []string{} listOpts := entities.ContainerListOptions{ Filters: make(map[string][]string), @@ -47,10 +77,15 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([ listOpts.Filters["status"] = statuses } - containers, err := registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts) + engine, err := setupContainerEngine(cmd) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + containers, err := engine.ContainerList(registry.GetContext(), listOpts) if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } for _, c := range containers { @@ -68,7 +103,7 @@ func getContainers(toComplete string, cType completeType, statuses ...string) ([ return suggestions, cobra.ShellCompDirectiveNoFileComp } -func getPods(toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) { +func getPods(cmd *cobra.Command, toComplete string, cType completeType, statuses ...string) ([]string, cobra.ShellCompDirective) { suggestions := []string{} listOpts := entities.PodPSOptions{ Filters: make(map[string][]string), @@ -77,10 +112,15 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin listOpts.Filters["status"] = statuses } - pods, err := registry.ContainerEngine().PodPs(registry.GetContext(), listOpts) + engine, err := setupContainerEngine(cmd) if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp + } + pods, err := engine.PodPs(registry.GetContext(), listOpts) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp } for _, pod := range pods { @@ -98,14 +138,19 @@ func getPods(toComplete string, cType completeType, statuses ...string) ([]strin return suggestions, cobra.ShellCompDirectiveNoFileComp } -func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) { +func getVolumes(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) { suggestions := []string{} lsOpts := entities.VolumeListOptions{} - volumes, err := registry.ContainerEngine().VolumeList(registry.GetContext(), lsOpts) + engine, err := setupContainerEngine(cmd) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + volumes, err := engine.VolumeList(registry.GetContext(), lsOpts) if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } for _, v := range volumes { @@ -116,14 +161,19 @@ func getVolumes(toComplete string) ([]string, cobra.ShellCompDirective) { return suggestions, cobra.ShellCompDirectiveNoFileComp } -func getImages(toComplete string) ([]string, cobra.ShellCompDirective) { +func getImages(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) { suggestions := []string{} listOptions := entities.ImageListOptions{} - images, err := registry.ImageEngine().List(registry.GetContext(), listOptions) + engine, err := setupImageEngine(cmd) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + images, err := engine.List(registry.GetContext(), listOptions) if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } for _, image := range images { @@ -166,19 +216,24 @@ func getRegistries() ([]string, cobra.ShellCompDirective) { regs, err := registries.GetRegistries() if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } return regs, cobra.ShellCompDirectiveNoFileComp } -func getNetworks(toComplete string) ([]string, cobra.ShellCompDirective) { +func getNetworks(cmd *cobra.Command, toComplete string) ([]string, cobra.ShellCompDirective) { suggestions := []string{} networkListOptions := entities.NetworkListOptions{} - networks, err := registry.ContainerEngine().NetworkList(registry.Context(), networkListOptions) + engine, err := setupContainerEngine(cmd) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + networks, err := engine.NetworkList(registry.Context(), networkListOptions) if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } for _, n := range networks { @@ -266,7 +321,7 @@ func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault) + return getContainers(cmd, toComplete, completeDefault) } // AutocompleteContainersCreated - Autocomplete only created container names. @@ -274,7 +329,7 @@ func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault, "created") + return getContainers(cmd, toComplete, completeDefault, "created") } // AutocompleteContainersExited - Autocomplete only exited container names. @@ -282,7 +337,7 @@ func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault, "exited") + return getContainers(cmd, toComplete, completeDefault, "exited") } // AutocompleteContainersPaused - Autocomplete only paused container names. @@ -290,7 +345,7 @@ func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault, "paused") + return getContainers(cmd, toComplete, completeDefault, "paused") } // AutocompleteContainersRunning - Autocomplete only running container names. @@ -298,7 +353,7 @@ func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault, "running") + return getContainers(cmd, toComplete, completeDefault, "running") } // AutocompleteContainersStartable - Autocomplete only created and exited container names. @@ -306,7 +361,7 @@ func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComple if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getContainers(toComplete, completeDefault, "created", "exited") + return getContainers(cmd, toComplete, completeDefault, "created", "exited") } // AutocompletePods - Autocomplete all pod names. @@ -314,7 +369,7 @@ func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]s if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getPods(toComplete, completeDefault) + return getPods(cmd, toComplete, completeDefault) } // AutocompletePodsRunning - Autocomplete only running pod names. @@ -323,7 +378,7 @@ func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete strin if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getPods(toComplete, completeDefault, "running", "degraded") + return getPods(cmd, toComplete, completeDefault, "running", "degraded") } // AutocompleteContainersAndPods - Autocomplete container names and pod names. @@ -331,8 +386,8 @@ func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - containers, _ := getContainers(toComplete, completeDefault) - pods, _ := getPods(toComplete, completeDefault) + containers, _ := getContainers(cmd, toComplete, completeDefault) + pods, _ := getPods(cmd, toComplete, completeDefault) return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp } @@ -341,8 +396,8 @@ func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComple if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - containers, _ := getContainers(toComplete, completeDefault) - images, _ := getImages(toComplete) + containers, _ := getContainers(cmd, toComplete, completeDefault) + images, _ := getImages(cmd, toComplete) return append(containers, images...), cobra.ShellCompDirectiveNoFileComp } @@ -351,7 +406,7 @@ func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) ( if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getVolumes(toComplete) + return getVolumes(cmd, toComplete) } // AutocompleteImages - Autocomplete images. @@ -359,7 +414,7 @@ func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([ if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getImages(toComplete) + return getImages(cmd, toComplete) } // AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion. @@ -368,7 +423,7 @@ func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string) return nil, cobra.ShellCompDirectiveNoFileComp } if len(args) < 1 { - return getImages(toComplete) + return getImages(cmd, toComplete) } // TODO: add path completion for files in the image return nil, cobra.ShellCompDirectiveDefault @@ -387,7 +442,7 @@ func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string) if !validCurrentCmdLine(cmd, args, toComplete) { return nil, cobra.ShellCompDirectiveNoFileComp } - return getNetworks(toComplete) + return getNetworks(cmd, toComplete) } // AutocompleteCpCommand - Autocomplete podman cp command args. @@ -396,7 +451,7 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) return nil, cobra.ShellCompDirectiveNoFileComp } if len(args) < 2 { - containers, _ := getContainers(toComplete, completeDefault) + containers, _ := getContainers(cmd, toComplete, completeDefault) for _, container := range containers { // TODO: Add path completion for inside the container if possible if strings.HasPrefix(container, toComplete) { @@ -410,6 +465,37 @@ func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) return nil, cobra.ShellCompDirectiveNoFileComp } +// AutocompleteNetworkConnectCmd - Autocomplete podman network connect/disconnect command args. +func AutocompleteNetworkConnectCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return getNetworks(cmd, toComplete) + } + if len(args) == 1 { + return getContainers(cmd, toComplete, completeDefault) + } + // don't complete more than 2 args + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteTopCmd - Autocomplete podman top/pod top command args. +func AutocompleteTopCmd(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + latest := cmd.Flags().Lookup("latest") + // only complete containers/pods as first arg if latest is not set + if len(args) == 0 && (latest == nil || !latest.Changed) { + if cmd.Parent().Name() == "pod" { + // need to complete pods since we are using pod top + return getPods(cmd, toComplete, completeDefault) + } + return getContainers(cmd, toComplete, completeDefault) + } + descriptors, err := util.GetContainerPidInformationDescriptors() + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + return descriptors, cobra.ShellCompDirectiveNoFileComp +} + // AutocompleteSystemConnections - Autocomplete system connections. func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if !validCurrentCmdLine(cmd, args, toComplete) { @@ -419,7 +505,7 @@ func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete cfg, err := config.ReadCustomConfig() if err != nil { cobra.CompErrorln(err.Error()) - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } for k, v := range cfg.Engine.ServiceDestinations { @@ -464,7 +550,7 @@ func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete stri // -> host,container:[name],ns:[path],private func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { kv := keyValueCompletion{ - "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) }, + "container:": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) }, "ns:": func(s string) ([]string, cobra.ShellCompDirective) { return nil, cobra.ShellCompDirectiveDefault }, "host": nil, "private": nil, @@ -567,7 +653,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) // but at this point we don't know the image. file, err := os.Open("/etc/group") if err != nil { - return nil, cobra.ShellCompDirectiveError + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp } defer file.Close() @@ -583,7 +670,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) } } if err = scanner.Err(); err != nil { - return nil, cobra.ShellCompDirectiveError + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp } return groups, cobra.ShellCompDirectiveNoFileComp } @@ -592,7 +680,8 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) // but at this point we don't know the image. file, err := os.Open("/etc/passwd") if err != nil { - return nil, cobra.ShellCompDirectiveError + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp } defer file.Close() @@ -607,7 +696,7 @@ func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) } } if err = scanner.Err(); err != nil { - return nil, cobra.ShellCompDirectiveError + return nil, cobra.ShellCompDirectiveNoFileComp } return users, cobra.ShellCompDirectiveNoSpace } @@ -623,7 +712,7 @@ func AutocompleteMountFlag(cmd *cobra.Command, args []string, toComplete string) // AutocompleteVolumeFlag - Autocomplete volume flag options. // -> volumes and paths func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - volumes, _ := getVolumes(toComplete) + volumes, _ := getVolumes(cmd, toComplete) directive := cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveDefault if strings.Contains(toComplete, ":") { // add space after second path @@ -641,8 +730,22 @@ func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string // AutocompleteEventFilter - Autocomplete event filter flag options. // -> "container=", "event=", "image=", "pod=", "volume=", "type=" func AutocompleteEventFilter(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - filters := []string{"container=", "event=", "image=", "pod=", "volume=", "type="} - return filters, cobra.ShellCompDirectiveNoSpace + eventTypes := func(_ string) ([]string, cobra.ShellCompDirective) { + return []string{"attach", "checkpoint", "cleanup", "commit", "create", "exec", + "export", "import", "init", "kill", "mount", "pause", "prune", "remove", + "restart", "restore", "start", "stop", "sync", "unmount", "unpause", + "pull", "push", "save", "tag", "untag", "refresh", "renumber", + }, cobra.ShellCompDirectiveNoFileComp + } + kv := keyValueCompletion{ + "container=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) }, + "image=": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }, + "pod=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeDefault) }, + "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) }, + "event=": eventTypes, + "type=": eventTypes, + } + return completeKeyValues(toComplete, kv) } // AutocompleteSystemdRestartOptions - Autocomplete systemd restart options. @@ -753,15 +856,15 @@ var containerStatuses = []string{"created", "running", "paused", "stopped", "exi // AutocompletePsFilters - Autocomplete ps filter options. func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { kv := keyValueCompletion{ - "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) }, - "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) }, + "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) }, + "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) }, "status=": func(_ string) ([]string, cobra.ShellCompDirective) { return containerStatuses, cobra.ShellCompDirectiveNoFileComp }, - "ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(s) }, - "before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) }, - "since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeDefault) }, - "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(s) }, + "ancestor": func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) }, + "before=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) }, + "since=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeDefault) }, + "volume=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) }, "health=": func(_ string) ([]string, cobra.ShellCompDirective) { return []string{define.HealthCheckHealthy, define.HealthCheckUnhealthy}, cobra.ShellCompDirectiveNoFileComp @@ -776,14 +879,14 @@ func AutocompletePsFilters(cmd *cobra.Command, args []string, toComplete string) // AutocompletePodPsFilters - Autocomplete pod ps filter options. func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { kv := keyValueCompletion{ - "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeIDs) }, - "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(s, completeNames) }, + "id=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeIDs) }, + "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getPods(cmd, s, completeNames) }, "status=": func(_ string) ([]string, cobra.ShellCompDirective) { return []string{"stopped", "running", "paused", "exited", "dead", "created", "degraded"}, cobra.ShellCompDirectiveNoFileComp }, - "ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeIDs) }, - "ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(s, completeNames) }, + "ctr-ids=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeIDs) }, + "ctr-names=": func(s string) ([]string, cobra.ShellCompDirective) { return getContainers(cmd, s, completeNames) }, "ctr-number=": nil, "ctr-status=": func(_ string) ([]string, cobra.ShellCompDirective) { return containerStatuses, cobra.ShellCompDirectiveNoFileComp @@ -792,3 +895,47 @@ func AutocompletePodPsFilters(cmd *cobra.Command, args []string, toComplete stri } return completeKeyValues(toComplete, kv) } + +// AutocompleteImageFilters - Autocomplete image ls --filter options. +func AutocompleteImageFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + getBool := func(_ string) ([]string, cobra.ShellCompDirective) { + return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp + } + getImg := func(s string) ([]string, cobra.ShellCompDirective) { return getImages(cmd, s) } + kv := keyValueCompletion{ + "before=": getImg, + "since=": getImg, + "label=": nil, + "reference=": nil, + "dangling=": getBool, + "readonly=": getBool, + } + return completeKeyValues(toComplete, kv) +} + +// AutocompleteNetworkFilters - Autocomplete network ls --filter options. +func AutocompleteNetworkFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + kv := keyValueCompletion{ + "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getNetworks(cmd, s) }, + "plugin=": nil, + } + return completeKeyValues(toComplete, kv) +} + +// AutocompleteVolumeFilters - Autocomplete volume ls --filter options. +func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + local := func(_ string) ([]string, cobra.ShellCompDirective) { + return []string{"local"}, cobra.ShellCompDirectiveNoFileComp + } + kv := keyValueCompletion{ + "name=": func(s string) ([]string, cobra.ShellCompDirective) { return getVolumes(cmd, s) }, + "driver=": local, + "scope=": local, + "label=": nil, + "opt=": nil, + "dangling=": func(_ string) ([]string, cobra.ShellCompDirective) { + return []string{"true", "false"}, cobra.ShellCompDirectiveNoFileComp + }, + } + return completeKeyValues(toComplete, kv) +} diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index ab3a984f0..599b430ea 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -84,7 +84,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { cgroupsFlagName := "cgroups" createFlags.StringVar( &cf.CGroupsMode, - cgroupsFlagName, containerConfig.Cgroups(), + cgroupsFlagName, cgroupConfig(), `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`, ) _ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode) @@ -180,7 +180,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { deviceFlagName := "device" createFlags.StringSliceVar( &cf.Devices, - deviceFlagName, containerConfig.Devices(), + deviceFlagName, devices(), fmt.Sprintf("Add a host device to the container"), ) _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) @@ -238,7 +238,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { envFlagName := "env" createFlags.StringArrayP( - envFlagName, "e", containerConfig.Env(), + envFlagName, "e", env(), "Set environment variables in container", ) _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone) @@ -357,7 +357,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { initPathFlagName := "init-path" createFlags.StringVar( &cf.InitPath, - initPathFlagName, containerConfig.InitPath(), + initPathFlagName, initPath(), // Do not use the Value field for setting the default value to determine user input (i.e., non-empty string) fmt.Sprintf("Path to the container-init binary"), ) @@ -508,7 +508,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { pidsLimitFlagName := "pids-limit" createFlags.Int64( - pidsLimitFlagName, containerConfig.PidsLimit(), + pidsLimitFlagName, pidsLimit(), "Tune container pids limit (set 0 for unlimited, -1 for server defaults)", ) _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone) @@ -543,7 +543,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { pullFlagName := "pull" createFlags.StringVar( &cf.Pull, - pullFlagName, containerConfig.Engine.PullPolicy, + pullFlagName, policy(), `Pull image before creating ("always"|"missing"|"never")`, ) _ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption) @@ -606,7 +606,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { shmSizeFlagName := "shm-size" createFlags.String( - shmSizeFlagName, containerConfig.ShmSize(), + shmSizeFlagName, shmSize(), "Size of /dev/shm "+sizeWithUnitFormat, ) _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone) @@ -715,7 +715,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ulimitFlagName := "ulimit" createFlags.StringSliceVar( &cf.Ulimit, - ulimitFlagName, containerConfig.Ulimits(), + ulimitFlagName, ulimits(), "Ulimit options", ) _ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone) @@ -753,7 +753,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { volumeFlagName := "volume" createFlags.StringArrayVarP( &cf.Volume, - volumeFlagName, "v", containerConfig.Volumes(), + volumeFlagName, "v", volumes(), "Bind mount a volume into the container", ) _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go index 4b52663c3..6dc43dbc6 100644 --- a/cmd/podman/common/create_opts.go +++ b/cmd/podman/common/create_opts.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/pkg/api/handlers" "github.com/containers/podman/v2/pkg/cgroups" "github.com/containers/podman/v2/pkg/domain/entities" @@ -133,10 +134,9 @@ func stringMaptoArray(m map[string]string) []string { // a specgen spec. func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroupsManager string) (*ContainerCLIOpts, []string, error) { var ( - aliases []string capAdd []string cappDrop []string - entrypoint string + entrypoint *string init bool specPorts []specgen.PortMapping ) @@ -180,13 +180,14 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup // marshall it to json; otherwise it should just be the string // value if len(cc.Config.Entrypoint) > 0 { - entrypoint = cc.Config.Entrypoint[0] + entrypoint = &cc.Config.Entrypoint[0] if len(cc.Config.Entrypoint) > 1 { b, err := json.Marshal(cc.Config.Entrypoint) if err != nil { return nil, nil, err } - entrypoint = string(b) + var jsonString = string(b) + entrypoint = &jsonString } } @@ -210,7 +211,7 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup mounts = append(mounts, mount) } - //volumes + // volumes volumes := make([]string, 0, len(cc.Config.Volumes)) for v := range cc.Config.Volumes { volumes = append(volumes, v) @@ -240,16 +241,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup } } - // network names - endpointsConfig := cc.NetworkingConfig.EndpointsConfig - cniNetworks := make([]string, 0, len(endpointsConfig)) - for netName, endpoint := range endpointsConfig { - cniNetworks = append(cniNetworks, netName) - if len(endpoint.Aliases) > 0 { - aliases = append(aliases, endpoint.Aliases...) - } - } - // netMode nsmode, _, err := specgen.ParseNetworkNamespace(cc.HostConfig.NetworkMode.NetworkName()) if err != nil { @@ -266,8 +257,6 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup // defined when there is only one network. netInfo := entities.NetOptions{ AddHosts: cc.HostConfig.ExtraHosts, - Aliases: aliases, - CNINetworks: cniNetworks, DNSOptions: cc.HostConfig.DNSOptions, DNSSearch: cc.HostConfig.DNSSearch, DNSServers: dns, @@ -275,31 +264,58 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup PublishPorts: specPorts, } - // static IP and MAC - if len(endpointsConfig) == 1 { - for _, ep := range endpointsConfig { - // if IP address is provided - if len(ep.IPAddress) > 0 { - staticIP := net.ParseIP(ep.IPAddress) - netInfo.StaticIP = &staticIP + // network names + switch { + case len(cc.NetworkingConfig.EndpointsConfig) > 0: + var aliases []string + + endpointsConfig := cc.NetworkingConfig.EndpointsConfig + cniNetworks := make([]string, 0, len(endpointsConfig)) + for netName, endpoint := range endpointsConfig { + + cniNetworks = append(cniNetworks, netName) + + if endpoint == nil { + continue } - // If MAC address is provided - if len(ep.MacAddress) > 0 { - staticMac, err := net.ParseMAC(ep.MacAddress) - if err != nil { - return nil, nil, err + if len(endpoint.Aliases) > 0 { + aliases = append(aliases, endpoint.Aliases...) + } + } + + // static IP and MAC + if len(endpointsConfig) == 1 { + for _, ep := range endpointsConfig { + if ep == nil { + continue + } + // if IP address is provided + if len(ep.IPAddress) > 0 { + staticIP := net.ParseIP(ep.IPAddress) + netInfo.StaticIP = &staticIP + } + // If MAC address is provided + if len(ep.MacAddress) > 0 { + staticMac, err := net.ParseMAC(ep.MacAddress) + if err != nil { + return nil, nil, err + } + netInfo.StaticMAC = &staticMac } - netInfo.StaticMAC = &staticMac + break } - break } + netInfo.Aliases = aliases + netInfo.CNINetworks = cniNetworks + case len(cc.HostConfig.NetworkMode) > 0: + netInfo.CNINetworks = []string{string(cc.HostConfig.NetworkMode)} } // Note: several options here are marked as "don't need". this is based // on speculation by Matt and I. We think that these come into play later // like with start. We believe this is just a difference in podman/compat cliOpts := ContainerCLIOpts{ - //Attach: nil, // dont need? + // Attach: nil, // dont need? Authfile: "", CapAdd: append(capAdd, cc.HostConfig.CapAdd...), CapDrop: append(cappDrop, cc.HostConfig.CapDrop...), @@ -310,18 +326,18 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup CPURTPeriod: uint64(cc.HostConfig.CPURealtimePeriod), CPURTRuntime: cc.HostConfig.CPURealtimeRuntime, CPUShares: uint64(cc.HostConfig.CPUShares), - //CPUS: 0, // dont need? + // CPUS: 0, // dont need? CPUSetCPUs: cc.HostConfig.CpusetCpus, CPUSetMems: cc.HostConfig.CpusetMems, - //Detach: false, // dont need - //DetachKeys: "", // dont need + // Detach: false, // dont need + // DetachKeys: "", // dont need Devices: devices, DeviceCGroupRule: nil, DeviceReadBPs: readBps, DeviceReadIOPs: readIops, DeviceWriteBPs: writeBps, DeviceWriteIOPs: writeIops, - Entrypoint: &entrypoint, + Entrypoint: entrypoint, Env: cc.Config.Env, Expose: expose, GroupAdd: cc.HostConfig.GroupAdd, @@ -436,7 +452,70 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, cgroup } // specgen assumes the image name is arg[0] - cmd := []string{cc.Image} + cmd := []string{cc.Config.Image} cmd = append(cmd, cc.Config.Cmd...) return &cliOpts, cmd, nil } + +func ulimits() []string { + if !registry.IsRemote() { + return containerConfig.Ulimits() + } + return nil +} + +func cgroupConfig() string { + if !registry.IsRemote() { + return containerConfig.Cgroups() + } + return "" +} + +func devices() []string { + if !registry.IsRemote() { + return containerConfig.Devices() + } + return nil +} + +func env() []string { + if !registry.IsRemote() { + return containerConfig.Env() + } + return nil +} + +func initPath() string { + if !registry.IsRemote() { + return containerConfig.InitPath() + } + return "" +} + +func pidsLimit() int64 { + if !registry.IsRemote() { + return containerConfig.PidsLimit() + } + return -1 +} + +func policy() string { + if !registry.IsRemote() { + return containerConfig.Engine.PullPolicy + } + return "" +} + +func shmSize() string { + if !registry.IsRemote() { + return containerConfig.ShmSize() + } + return "" +} + +func volumes() []string { + if !registry.IsRemote() { + return containerConfig.Volumes() + } + return nil +} diff --git a/cmd/podman/common/createparse.go b/cmd/podman/common/createparse.go index 09ee5aa0c..3a69f11b6 100644 --- a/cmd/podman/common/createparse.go +++ b/cmd/podman/common/createparse.go @@ -9,7 +9,7 @@ import ( // by validate must not need any state information on the flag (i.e. changed) func (c *ContainerCLIOpts) validate() error { var () - if c.Rm && c.Restart != "" && c.Restart != "no" { + if c.Rm && (c.Restart != "" && c.Restart != "no" && c.Restart != "on-failure") { return errors.Errorf(`the --rm option conflicts with --restart, when the restartPolicy is not "" and "no"`) } diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go index cae52ccaa..898d65bd0 100644 --- a/cmd/podman/common/netflags.go +++ b/cmd/podman/common/netflags.go @@ -59,8 +59,8 @@ func DefineNetFlags(cmd *cobra.Command) { _ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone) networkFlagName := "network" - netFlags.String( - networkFlagName, containerConfig.NetNS(), + netFlags.StringArray( + networkFlagName, []string{containerConfig.NetNS()}, "Connect a container to a network", ) _ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks) @@ -194,25 +194,29 @@ func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) { } if cmd.Flags().Changed("network") { - network, err := cmd.Flags().GetString("network") + networks, err := cmd.Flags().GetStringArray("network") if err != nil { return nil, err } + for i, network := range networks { + parts := strings.SplitN(network, ":", 2) - parts := strings.SplitN(network, ":", 2) - - ns, cniNets, err := specgen.ParseNetworkNamespace(network) - if err != nil { - return nil, err - } + ns, cniNets, err := specgen.ParseNetworkNamespace(network) + if err != nil { + return nil, err + } + if i > 0 && (len(cniNets) == 0 || len(opts.CNINetworks) == 0) { + return nil, errors.Errorf("network conflict between type %s and %s", opts.Network.NSMode, ns.NSMode) + } - if len(parts) > 1 { - opts.NetworkOptions = make(map[string][]string) - opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",") - cniNets = nil + if len(parts) > 1 { + opts.NetworkOptions = make(map[string][]string) + opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",") + cniNets = nil + } + opts.Network = ns + opts.CNINetworks = append(opts.CNINetworks, cniNets...) } - opts.Network = ns - opts.CNINetworks = cniNets } aliases, err := cmd.Flags().GetStringSlice("network-alias") diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go index b3c160ddf..0468f15e0 100644 --- a/cmd/podman/common/volumes.go +++ b/cmd/podman/common/volumes.go @@ -10,7 +10,6 @@ import ( "github.com/containers/podman/v2/pkg/util" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" - "github.com/sirupsen/logrus" ) const ( @@ -45,7 +44,7 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo } // Next --volumes flag. - volumeMounts, volumeVolumes, overlayVolumes, err := getVolumeMounts(volumeFlag) + volumeMounts, volumeVolumes, overlayVolumes, err := specgen.GenVolumeMounts(volumeFlag) if err != nil { return nil, nil, nil, nil, err } @@ -594,105 +593,6 @@ func getImageVolume(args []string) (*specgen.ImageVolume, error) { return newVolume, nil } -func getVolumeMounts(volumeFlag []string) (map[string]spec.Mount, map[string]*specgen.NamedVolume, map[string]*specgen.OverlayVolume, error) { - mounts := make(map[string]spec.Mount) - volumes := make(map[string]*specgen.NamedVolume) - overlayVolumes := make(map[string]*specgen.OverlayVolume) - - volumeFormatErr := errors.Errorf("incorrect volume format, should be [host-dir:]ctr-dir[:option]") - - for _, vol := range volumeFlag { - var ( - options []string - src string - dest string - err error - ) - - splitVol := strings.Split(vol, ":") - if len(splitVol) > 3 { - return nil, nil, nil, errors.Wrapf(volumeFormatErr, vol) - } - - src = splitVol[0] - if len(splitVol) == 1 { - // This is an anonymous named volume. Only thing given - // is destination. - // Name/source will be blank, and populated by libpod. - src = "" - dest = splitVol[0] - } else if len(splitVol) > 1 { - dest = splitVol[1] - } - if len(splitVol) > 2 { - if options, err = parse.ValidateVolumeOpts(strings.Split(splitVol[2], ",")); err != nil { - return nil, nil, nil, err - } - } - - // Do not check source dir for anonymous volumes - if len(splitVol) > 1 { - if err := parse.ValidateVolumeHostDir(src); err != nil { - return nil, nil, nil, err - } - } - if err := parse.ValidateVolumeCtrDir(dest); err != nil { - return nil, nil, nil, err - } - - cleanDest := filepath.Clean(dest) - - if strings.HasPrefix(src, "/") || strings.HasPrefix(src, ".") { - // This is not a named volume - overlayFlag := false - for _, o := range options { - if o == "O" { - overlayFlag = true - if len(options) > 1 { - return nil, nil, nil, errors.New("can't use 'O' with other options") - } - } - } - if overlayFlag { - // This is a overlay volume - newOverlayVol := new(specgen.OverlayVolume) - newOverlayVol.Destination = cleanDest - newOverlayVol.Source = src - if _, ok := overlayVolumes[newOverlayVol.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newOverlayVol.Destination) - } - overlayVolumes[newOverlayVol.Destination] = newOverlayVol - } else { - newMount := spec.Mount{ - Destination: cleanDest, - Type: string(TypeBind), - Source: src, - Options: options, - } - if _, ok := mounts[newMount.Destination]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newMount.Destination) - } - mounts[newMount.Destination] = newMount - } - } else { - // This is a named volume - newNamedVol := new(specgen.NamedVolume) - newNamedVol.Name = src - newNamedVol.Dest = cleanDest - newNamedVol.Options = options - - if _, ok := volumes[newNamedVol.Dest]; ok { - return nil, nil, nil, errors.Wrapf(errDuplicateDest, newNamedVol.Dest) - } - volumes[newNamedVol.Dest] = newNamedVol - } - - logrus.Debugf("User mount %s:%s options %v", src, dest, options) - } - - return mounts, volumes, overlayVolumes, nil -} - // GetTmpfsMounts creates spec.Mount structs for user-requested tmpfs mounts func getTmpfsMounts(tmpfsFlag []string) (map[string]spec.Mount, error) { m := make(map[string]spec.Mount) |