From b5d1d89a377e38762a75c2042dcc50a370ba6707 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Sun, 31 May 2020 17:35:59 +0200 Subject: Add shell completion with cobra Allow automatic generation for shell completion scripts with the internal cobra functions (requires v1.0.0+). This should replace the handwritten completion scripts and even adds support for fish. With this approach it is less likley that completions and code are out of sync. We can now create the scripts with - podman completion bash - podman completion zsh - podman completion fish To test the completion run: source <(podman completion bash) The same works for podman-remote and podman --remote and it will complete your remote containers/images with the correct endpoints values from --url/--connection. The completion logic is written in go and provided by the cobra library. The completion functions lives in `cmd/podman/completion/completion.go`. The unit test at cmd/podman/shell_completion_test.go checks if each command and flag has an autocompletion function set. This prevents that commands and flags have no shell completion set. This commit does not replace the current autocompletion scripts. Closes #6440 Signed-off-by: Paul Holzinger --- cmd/podman/common/completion.go | 638 ++++++++++++++++++++++++++++++++++++++++ cmd/podman/common/create.go | 446 ++++++++++++++++++++++------ cmd/podman/common/netflags.go | 53 +++- 3 files changed, 1035 insertions(+), 102 deletions(-) create mode 100644 cmd/podman/common/completion.go (limited to 'cmd/podman/common') diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go new file mode 100644 index 000000000..4d66b4e2b --- /dev/null +++ b/cmd/podman/common/completion.go @@ -0,0 +1,638 @@ +package common + +import ( + "bufio" + "os" + "strings" + + "github.com/containers/common/pkg/config" + "github.com/containers/podman/v2/cmd/podman/registry" + "github.com/containers/podman/v2/libpod" + "github.com/containers/podman/v2/libpod/define" + "github.com/containers/podman/v2/pkg/domain/entities" + "github.com/containers/podman/v2/pkg/registries" + systemdGen "github.com/containers/podman/v2/pkg/systemd/generate" + "github.com/spf13/cobra" +) + +var ( + // ChangeCmds is the list of valid Change commands to passed to the Commit call + ChangeCmds = []string{"CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR"} + // LogLevels supported by podman + LogLevels = []string{"debug", "info", "warn", "error", "fatal", "panic"} +) + +func getContainers(status string, toComplete string) ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + listOpts := entities.ContainerListOptions{ + Filters: make(map[string][]string), + } + listOpts.All = true + + if status != "all" { + listOpts.Filters = map[string][]string{"status": {status}} + } + + containers, err := registry.ContainerEngine().ContainerList(registry.GetContext(), listOpts) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for _, container := range containers { + // include ids in suggestions if more then 2 chars are typed + if len(toComplete) > 1 { + suggestions = append(suggestions, container.ID[0:12]) + } + // include name in suggestions + suggestions = append(suggestions, container.Names...) + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +func getPods(status string, toComplete string) ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + listOpts := entities.PodPSOptions{ + Filters: make(map[string][]string), + } + + if status != "all" { + listOpts.Filters = map[string][]string{"status": {status}} + } + + pods, err := registry.ContainerEngine().PodPs(registry.GetContext(), listOpts) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for _, pod := range pods { + // include ids in suggestions if more then 2 chars are typed + if len(toComplete) > 1 { + suggestions = append(suggestions, pod.Id[0:12]) + } + // include name in suggestions + suggestions = append(suggestions, pod.Name) + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +func getVolumes() ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + lsOpts := entities.VolumeListOptions{} + + volumes, err := registry.ContainerEngine().VolumeList(registry.GetContext(), lsOpts) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for _, volume := range volumes { + suggestions = append(suggestions, volume.Name) + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +func getImages(toComplete string) ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + listOptions := entities.ImageListOptions{} + + images, err := registry.ImageEngine().List(registry.GetContext(), listOptions) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for _, image := range images { + // FIXME: need ux testing + // discuss when image ids should be completed + // include ids in suggestions if more then 2 chars are typed + if len(toComplete) > 1 { + suggestions = append(suggestions, image.ID[0:12]) + } + for _, repo := range image.RepoTags { + if toComplete == "" { + // suggest only full repo path if no input is given + suggestions = append(suggestions, repo) + } else { + // suggested "registry.fedoraproject.org/f29/httpd:latest" as + // - "registry.fedoraproject.org/f29/httpd:latest" + // - "registry.fedoraproject.org/f29/httpd" + // - "f29/httpd:latest" + // - "f29/httpd" + // - "httpd:latest" + // - "httpd" + paths := strings.Split(repo, "/") + for i := range paths { + suggestionWithTag := strings.Join(paths[i:], "/") + suggestionWithoutTag := strings.SplitN(strings.SplitN(suggestionWithTag, ":", 2)[0], "@", 2)[0] + suggestions = append(suggestions, suggestionWithTag, suggestionWithoutTag) + } + } + } + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +func getRegistries() ([]string, cobra.ShellCompDirective) { + regs, err := registries.GetRegistries() + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + return regs, cobra.ShellCompDirectiveNoFileComp +} + +func getNetworks() ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + networkListOptions := entities.NetworkListOptions{} + + networks, err := registry.ContainerEngine().NetworkList(registry.Context(), networkListOptions) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for _, network := range networks { + suggestions = append(suggestions, network.Name) + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +/* Autocomplete Functions for cobra ValidArgsFunction */ + +// AutocompleteContainers - Autocomplete all container names. +func AutocompleteContainers(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getContainers("all", toComplete) +} + +// AutocompleteContainersCreated - Autocomplete only created container names. +func AutocompleteContainersCreated(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getContainers("created", toComplete) +} + +// AutocompleteContainersExited - Autocomplete only exited container names. +func AutocompleteContainersExited(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getContainers("exited", toComplete) +} + +// AutocompleteContainersPaused - Autocomplete only paused container names. +func AutocompleteContainersPaused(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getContainers("paused", toComplete) +} + +// AutocompleteContainersRunning - Autocomplete only running container names. +func AutocompleteContainersRunning(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getContainers("running", toComplete) +} + +// AutocompleteContainersStartable - Autocomplete only created and exited container names. +func AutocompleteContainersStartable(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + containersCreated, _ := getContainers("created", toComplete) + containersExited, _ := getContainers("exited", toComplete) + return append(containersCreated, containersExited...), cobra.ShellCompDirectiveNoFileComp +} + +// AutocompletePods - Autocomplete all pod names. +func AutocompletePods(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getPods("all", toComplete) +} + +// AutocompletePodsRunning - Autocomplete only running pod names. +func AutocompletePodsRunning(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getPods("running", toComplete) +} + +// AutocompleteContainersAndPods - Autocomplete container names and pod names. +func AutocompleteContainersAndPods(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + containers, _ := getContainers("all", toComplete) + pods, _ := getPods("all", toComplete) + return append(containers, pods...), cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteContainersAndImages - Autocomplete container names and pod names. +func AutocompleteContainersAndImages(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + containers, _ := getContainers("all", toComplete) + images, _ := getImages(toComplete) + return append(containers, images...), cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteVolumes - Autocomplete volumes. +func AutocompleteVolumes(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getVolumes() +} + +// AutocompleteImages - Autocomplete images. +func AutocompleteImages(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getImages(toComplete) +} + +// AutocompleteCreateRun - Autocomplete only the fist argument as image and then do file completion. +func AutocompleteCreateRun(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) < 1 { + return getImages(toComplete) + } + // TODO: add path completion for files in the image + return nil, cobra.ShellCompDirectiveDefault +} + +// AutocompleteRegistries - Autocomplete registries. +func AutocompleteRegistries(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getRegistries() +} + +// AutocompleteNetworks - Autocomplete networks. +func AutocompleteNetworks(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return getNetworks() +} + +// AutocompleteCpCommand - Autocomplete podman cp command args. +func AutocompleteCpCommand(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) < 2 { + containers, _ := getContainers("all", toComplete) + for _, container := range containers { + // TODO: Add path completion for inside the container if possible + if strings.HasPrefix(container, toComplete) { + return containers, cobra.ShellCompDirectiveNoSpace + } + } + // else complete paths + return nil, cobra.ShellCompDirectiveDefault + } + // don't complete more than 2 args + return nil, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteSystemConnections - Autocomplete system connections. +func AutocompleteSystemConnections(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + cfg, err := config.ReadCustomConfig() + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveError + } + + for k, v := range cfg.Engine.ServiceDestinations { + // the URI will be show as description in shells like zsh + suggestions = append(suggestions, k+"\t"+v.URI) + } + + return suggestions, cobra.ShellCompDirectiveNoFileComp +} + +/* -------------- Flags ----------------- */ + +// AutocompleteDetachKeys - Autocomplete detach-keys options. +// -> "ctrl-" +func AutocompleteDetachKeys(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if strings.HasSuffix(toComplete, ",") { + return []string{toComplete + "ctrl-"}, cobra.ShellCompDirectiveNoSpace + } + return []string{"ctrl-"}, cobra.ShellCompDirectiveNoSpace +} + +// AutocompleteChangeInstructions - Autocomplete change instructions options for commit and import. +// -> "CMD", "ENTRYPOINT", "ENV", "EXPOSE", "LABEL", "ONBUILD", "STOPSIGNAL", "USER", "VOLUME", "WORKDIR" +func AutocompleteChangeInstructions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return ChangeCmds, cobra.ShellCompDirectiveNoSpace +} + +// AutocompleteImageFormat - Autocomplete image format options. +// -> "oci", "docker" +func AutocompleteImageFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + ImageFormat := []string{"oci", "docker"} + return ImageFormat, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteCreateAttach - Autocomplete create --attach options. +// -> "stdin", "stdout", "stderr" +func AutocompleteCreateAttach(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"stdin", "stdout", "stderr"}, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteNamespace - Autocomplete namespace options. +// -> host,container:[name],ns:[path],private +func AutocompleteNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + namespacesOptions := []string{"host", "container:", "ns:", "private"} + + switch { + case strings.HasPrefix(toComplete, "container:"): + // Complete containers after colon + containers, _ := getContainers("all", toComplete[10:]) //trim "container:" + + // add "container:" in front of the suggestions + var suggestions []string + for _, container := range containers { + suggestions = append(suggestions, "container:"+container) + } + + return suggestions, cobra.ShellCompDirectiveNoFileComp + + case strings.HasPrefix(toComplete, "ns:"): + // Complete path after colon + return nil, cobra.ShellCompDirectiveDefault + + case strings.HasPrefix(toComplete, "c") || strings.HasPrefix(toComplete, "n"): + // don't insert space for container: and ns: + return []string{"container:", "ns:"}, cobra.ShellCompDirectiveNoSpace + } + return namespacesOptions, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteUserNamespace - Autocomplete namespace options. +// -> same as AutocompleteNamespace with "auto", "keep-id" added +func AutocompleteUserNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + results, directive := AutocompleteNamespace(cmd, args, toComplete) + if directive == cobra.ShellCompDirectiveNoFileComp { + // add the auto and keep-id options + results = append(results, "auto", "keep-id") + } + return results, directive +} + +// AutocompleteCgroupMode - Autocomplete cgroup mode options. +// -> "enabled", "disabled", "no-conmon", "split" +func AutocompleteCgroupMode(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + cgroupModes := []string{"enabled", "disabled", "no-conmon", "split"} + return cgroupModes, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteImageVolume - Autocomplete image volume options. +// -> "bind", "tmpfs", "ignore" +func AutocompleteImageVolume(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + imageVolumes := []string{"bind", "tmpfs", "ignore"} + return imageVolumes, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteLogDriver - Autocomplete log-driver options. +// -> "journald", "none", "k8s-file" +func AutocompleteLogDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // don't show json-file + logDrivers := []string{define.JournaldLogging, define.NoLogging, define.KubernetesLogging} + return logDrivers, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteLogOpt - Autocomplete log-opt options. +// -> "path=", "tag=" +func AutocompleteLogOpt(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // FIXME: are these the only one? the man page states these but in the current shell completion they are more options + logOptions := []string{"path=", "tag="} + if strings.HasPrefix(toComplete, "path=") { + return nil, cobra.ShellCompDirectiveDefault + } + return logOptions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace +} + +// AutocompletePullOption - Autocomplete pull options for create and run command. +// -> "always", "missing", "never" +func AutocompletePullOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + pullOptions := []string{"always", "missing", "never"} + return pullOptions, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteRestartOption - Autocomplete restart options for create and run command. +// -> "always", "no", "on-failure", "unless-stopped" +func AutocompleteRestartOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + restartOptions := []string{libpod.RestartPolicyAlways, libpod.RestartPolicyNo, + libpod.RestartPolicyOnFailure, libpod.RestartPolicyUnlessStopped} + return restartOptions, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteSecurityOption - Autocomplete security options options. +func AutocompleteSecurityOption(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + SecurityOptions := []string{"apparmor=", "no-new-privileges", "seccomp=", "label="} + switch { + case strings.HasPrefix(toComplete, "apparmor=u"): + // add space after unconfined + return []string{"apparmor=unconfined"}, cobra.ShellCompDirectiveNoFileComp + + case strings.HasPrefix(toComplete, "label=d"): + // add space after disable + return []string{"label=disable"}, cobra.ShellCompDirectiveNoFileComp + + case strings.HasPrefix(toComplete, "label="): + return []string{"label=user:", "label=role:", "label=type:", "label=level:", "label=filetype:", "label=disable"}, + cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace + + case strings.HasPrefix(toComplete, "seccomp="): + // complete files + return nil, cobra.ShellCompDirectiveDefault + + case strings.HasPrefix(toComplete, "n"): + // add space if no-new-privileges + return []string{"no-new-privileges"}, cobra.ShellCompDirectiveNoFileComp + } + return SecurityOptions, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace +} + +// AutocompleteStopSignal - Autocomplete stop signal options. +// -> "SIGHUP", "SIGINT", "SIGKILL", "SIGTERM" +func AutocompleteStopSignal(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + // FIXME: add more/different signals? + stopSignals := []string{"SIGHUP", "SIGINT", "SIGKILL", "SIGTERM"} + return stopSignals, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteSystemdFlag - Autocomplete systemd flag options. +// -> "true", "false", "always" +func AutocompleteSystemdFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + systemd := []string{"true", "false", "always"} + return systemd, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteUserFlag - Autocomplete user flag based on the names and groups (includes ids after first char) in /etc/passwd and /etc/group files. +// -> user:group +func AutocompleteUserFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if strings.Contains(toComplete, ":") { + // It would be nice to read the file in the image + // but at this point we don't know the image. + file, err := os.Open("/etc/group") + if err != nil { + return nil, cobra.ShellCompDirectiveError + } + defer file.Close() + + var groups []string + scanner := bufio.NewScanner(file) + user := strings.SplitN(toComplete, ":", 2)[0] + for scanner.Scan() { + entries := strings.SplitN(scanner.Text(), ":", 4) + groups = append(groups, user+":"+entries[0]) + // complete ids after at least one char is given + if len(user)+1 < len(toComplete) { + groups = append(groups, user+":"+entries[2]) + } + } + if err = scanner.Err(); err != nil { + return nil, cobra.ShellCompDirectiveError + } + return groups, cobra.ShellCompDirectiveNoFileComp + } + + // It would be nice to read the file in the image + // but at this point we don't know the image. + file, err := os.Open("/etc/passwd") + if err != nil { + return nil, cobra.ShellCompDirectiveError + } + defer file.Close() + + var users []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + entries := strings.SplitN(scanner.Text(), ":", 7) + users = append(users, entries[0]+":") + // complete ids after at least one char is given + if len(toComplete) > 0 { + users = append(users, entries[2]+":") + } + } + if err = scanner.Err(); err != nil { + return nil, cobra.ShellCompDirectiveError + } + return users, cobra.ShellCompDirectiveNoSpace +} + +// AutocompleteMountFlag - Autocomplete mount flag options. +// -> "type=bind,", "type=volume,", "type=tmpfs," +func AutocompleteMountFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"type=bind,", "type=volume,", "type=tmpfs,"} + // TODO: Add support for all different options + return types, cobra.ShellCompDirectiveNoSpace +} + +// AutocompleteVolumeFlag - Autocomplete volume flag options. +// -> volumes and paths +func AutocompleteVolumeFlag(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + result := []string{} + volumes, _ := getVolumes() + for _, volume := range volumes { + // If we don't filter on "toComplete", zsh and fish will not do file completion + // even if the prefix typed by the user does not match the returned completions + if strings.HasPrefix(volume, toComplete) { + result = append(result, volume) + } + } + directive := cobra.ShellCompDirectiveNoSpace | cobra.ShellCompDirectiveDefault + if strings.Contains(toComplete, ":") { + // add space after second path + directive = cobra.ShellCompDirectiveDefault + } + return result, directive +} + +// AutocompleteJSONFormat - Autocomplete format flag option. +// -> "json" +func AutocompleteJSONFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return []string{"json"}, cobra.ShellCompDirectiveNoFileComp +} + +// 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 +} + +// AutocompleteSystemdRestartOptions - Autocomplete systemd restart options. +// -> "no", "on-success", "on-failure", "on-abnormal", "on-watchdog", "on-abort", "always" +func AutocompleteSystemdRestartOptions(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return systemdGen.RestartPolicies, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteTrustType - Autocomplete trust type options. +// -> "signedBy", "accept", "reject" +func AutocompleteTrustType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"signedBy", "accept", "reject"} + return types, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteImageSort - Autocomplete images sort options. +// -> "created", "id", "repository", "size", "tag" +func AutocompleteImageSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + sortBy := []string{"created", "id", "repository", "size", "tag"} + return sortBy, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteInspectType - Autocomplete inspect type options. +// -> "container", "image", "all" +func AutocompleteInspectType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"container", "image", "all"} + return types, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteManifestFormat - Autocomplete manifest format options. +// -> "oci", "v2s2" +func AutocompleteManifestFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"oci", "v2s2"} + return types, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteNetworkDriver - Autocomplete network driver option. +// -> "bridge" +func AutocompleteNetworkDriver(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + drivers := []string{"bridge"} + return drivers, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompletePodShareNamespace - Autocomplete pod create --share flag option. +// -> "ipc", "net", "pid", "user", "uts", "cgroup", "none" +func AutocompletePodShareNamespace(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + namespaces := []string{"ipc", "net", "pid", "user", "uts", "cgroup", "none"} + return namespaces, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompletePodPsSort - Autocomplete images sort options. +// -> "created", "id", "name", "status", "number" +func AutocompletePodPsSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + sortBy := []string{"created", "id", "name", "status", "number"} + return sortBy, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompletePsSort - Autocomplete images sort options. +// -> "command", "created", "id", "image", "names", "runningfor", "size", "status" +func AutocompletePsSort(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + sortBy := []string{"command", "created", "id", "image", "names", "runningfor", "size", "status"} + return sortBy, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteImageSaveFormat - Autocomplete image save format options. +// -> "oci-archive", "oci-dir", "docker-dir" +func AutocompleteImageSaveFormat(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + formats := []string{"oci-archive", "oci-dir", "docker-dir"} + return formats, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteWaitCondition - Autocomplete wait condition options. +// -> "unknown", "configured", "created", "running", "stopped", "paused", "exited", "removing" +func AutocompleteWaitCondition(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + states := []string{"unknown", "configured", "created", "running", "stopped", "paused", "exited", "removing"} + return states, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteCgroupManager - Autocomplete cgroup manager options. +// -> "cgroupfs", "systemd" +func AutocompleteCgroupManager(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"cgroupfs", "systemd"} + return types, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteEventBackend - Autocomplete event backend options. +// -> "file", "journald", "none" +func AutocompleteEventBackend(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"file", "journald", "none"} + return types, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteLogLevel - Autocomplete log level options. +// -> "debug", "info", "warn", "error", "fatal", "panic" +func AutocompleteLogLevel(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + return LogLevels, cobra.ShellCompDirectiveNoFileComp +} + +// AutocompleteSDNotify - Autocomplete sdnotify options. +// -> "container", "conmon", "ignore" +func AutocompleteSDNotify(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + types := []string{"container", "conmon", "ignore"} + return types, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 60f4e526c..ab3a984f0 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -5,296 +5,457 @@ import ( "os" "github.com/containers/common/pkg/auth" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/registry" "github.com/containers/podman/v2/libpod/define" - "github.com/spf13/pflag" + "github.com/spf13/cobra" ) const sizeWithUnitFormat = "(format: `[]`, where unit = b (bytes), k (kilobytes), m (megabytes), or g (gigabytes))" var containerConfig = registry.PodmanConfig() -func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { - createFlags := pflag.FlagSet{} +func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { + createFlags := cmd.Flags() + + annotationFlagName := "annotation" createFlags.StringSliceVar( &cf.Annotation, - "annotation", []string{}, + annotationFlagName, []string{}, "Add annotations to container (key:value)", ) + _ = cmd.RegisterFlagCompletionFunc(annotationFlagName, completion.AutocompleteNone) + + attachFlagName := "attach" createFlags.StringSliceVarP( &cf.Attach, - "attach", "a", []string{}, + attachFlagName, "a", []string{}, "Attach to STDIN, STDOUT or STDERR", ) + _ = cmd.RegisterFlagCompletionFunc(attachFlagName, AutocompleteCreateAttach) + + authfileFlagName := "authfile" createFlags.StringVar( &cf.Authfile, - "authfile", auth.GetDefaultAuthFile(), + authfileFlagName, auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override", ) + _ = cmd.RegisterFlagCompletionFunc(authfileFlagName, completion.AutocompleteDefault) + + blkioWeightFlagName := "blkio-weight" createFlags.StringVar( &cf.BlkIOWeight, - "blkio-weight", "", + blkioWeightFlagName, "", "Block IO weight (relative weight) accepts a weight value between 10 and 1000.", ) + _ = cmd.RegisterFlagCompletionFunc(blkioWeightFlagName, completion.AutocompleteNone) + + blkioWeightDeviceFlagName := "blkio-weight-device" createFlags.StringSliceVar( &cf.BlkIOWeightDevice, - "blkio-weight-device", []string{}, + blkioWeightDeviceFlagName, []string{}, "Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)", ) + _ = cmd.RegisterFlagCompletionFunc(blkioWeightDeviceFlagName, completion.AutocompleteDefault) + + capAddFlagName := "cap-add" createFlags.StringSliceVar( &cf.CapAdd, - "cap-add", []string{}, + capAddFlagName, []string{}, "Add capabilities to the container", ) + _ = cmd.RegisterFlagCompletionFunc(capAddFlagName, completion.AutocompleteCapabilities) + + capDropFlagName := "cap-drop" createFlags.StringSliceVar( &cf.CapDrop, - "cap-drop", []string{}, + capDropFlagName, []string{}, "Drop capabilities from the container", ) + _ = cmd.RegisterFlagCompletionFunc(capDropFlagName, completion.AutocompleteCapabilities) + + cgroupnsFlagName := "cgroupns" createFlags.String( - "cgroupns", "", + cgroupnsFlagName, "", "cgroup namespace to use", ) + _ = cmd.RegisterFlagCompletionFunc(cgroupnsFlagName, AutocompleteNamespace) + + cgroupsFlagName := "cgroups" createFlags.StringVar( &cf.CGroupsMode, - "cgroups", containerConfig.Cgroups(), + cgroupsFlagName, containerConfig.Cgroups(), `control container cgroup configuration ("enabled"|"disabled"|"no-conmon"|"split")`, ) + _ = cmd.RegisterFlagCompletionFunc(cgroupsFlagName, AutocompleteCgroupMode) + + cgroupParentFlagName := "cgroup-parent" createFlags.StringVar( &cf.CGroupParent, - "cgroup-parent", "", + cgroupParentFlagName, "", "Optional parent cgroup for the container", ) + _ = cmd.RegisterFlagCompletionFunc(cgroupParentFlagName, completion.AutocompleteDefault) + + cidfileFlagName := "cidfile" createFlags.StringVar( &cf.CIDFile, - "cidfile", "", + cidfileFlagName, "", "Write the container ID to the file", ) + _ = cmd.RegisterFlagCompletionFunc(cidfileFlagName, completion.AutocompleteDefault) + + conmonPidfileFlagName := "conmon-pidfile" createFlags.StringVar( &cf.ConmonPIDFile, - "conmon-pidfile", "", + conmonPidfileFlagName, "", "Path to the file that will receive the PID of conmon", ) + _ = cmd.RegisterFlagCompletionFunc(conmonPidfileFlagName, completion.AutocompleteDefault) + + cpuPeriodFlagName := "cpu-period" createFlags.Uint64Var( &cf.CPUPeriod, - "cpu-period", 0, + cpuPeriodFlagName, 0, "Limit the CPU CFS (Completely Fair Scheduler) period", ) + _ = cmd.RegisterFlagCompletionFunc(cpuPeriodFlagName, completion.AutocompleteNone) + + cpuQuotaFlagName := "cpu-quota" createFlags.Int64Var( &cf.CPUQuota, - "cpu-quota", 0, + cpuQuotaFlagName, 0, "Limit the CPU CFS (Completely Fair Scheduler) quota", ) + _ = cmd.RegisterFlagCompletionFunc(cpuQuotaFlagName, completion.AutocompleteNone) + + cpuRtPeriodFlagName := "cpu-rt-period" createFlags.Uint64Var( &cf.CPURTPeriod, - "cpu-rt-period", 0, + cpuRtPeriodFlagName, 0, "Limit the CPU real-time period in microseconds", ) + _ = cmd.RegisterFlagCompletionFunc(cpuRtPeriodFlagName, completion.AutocompleteNone) + + cpuRtRuntimeFlagName := "cpu-rt-runtime" createFlags.Int64Var( &cf.CPURTRuntime, - "cpu-rt-runtime", 0, + cpuRtRuntimeFlagName, 0, "Limit the CPU real-time runtime in microseconds", ) + _ = cmd.RegisterFlagCompletionFunc(cpuRtRuntimeFlagName, completion.AutocompleteNone) + + cpuSharesFlagName := "cpu-shares" createFlags.Uint64Var( &cf.CPUShares, - "cpu-shares", 0, + cpuSharesFlagName, 0, "CPU shares (relative weight)", ) + _ = cmd.RegisterFlagCompletionFunc(cpuSharesFlagName, completion.AutocompleteNone) + + cpusFlagName := "cpus" createFlags.Float64Var( &cf.CPUS, - "cpus", 0, + cpusFlagName, 0, "Number of CPUs. The default is 0.000 which means no limit", ) + _ = cmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone) + + cpusetCpusFlagName := "cpuset-cpus" createFlags.StringVar( &cf.CPUSetCPUs, - "cpuset-cpus", "", + cpusetCpusFlagName, "", "CPUs in which to allow execution (0-3, 0,1)", ) + _ = cmd.RegisterFlagCompletionFunc(cpusetCpusFlagName, completion.AutocompleteNone) + + cpusetMemsFlagName := "cpuset-mems" createFlags.StringVar( &cf.CPUSetMems, - "cpuset-mems", "", + cpusetMemsFlagName, "", "Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.", ) + _ = cmd.RegisterFlagCompletionFunc(cpusetMemsFlagName, completion.AutocompleteNone) + + deviceFlagName := "device" createFlags.StringSliceVar( &cf.Devices, - "device", containerConfig.Devices(), + deviceFlagName, containerConfig.Devices(), fmt.Sprintf("Add a host device to the container"), ) + _ = cmd.RegisterFlagCompletionFunc(deviceFlagName, completion.AutocompleteDefault) + + deviceCgroupRuleFlagName := "device-cgroup-rule" createFlags.StringSliceVar( &cf.DeviceCGroupRule, - "device-cgroup-rule", []string{}, + deviceCgroupRuleFlagName, []string{}, "Add a rule to the cgroup allowed devices list", ) + _ = cmd.RegisterFlagCompletionFunc(deviceCgroupRuleFlagName, completion.AutocompleteNone) + + deviceReadBpsFlagName := "device-read-bps" createFlags.StringSliceVar( &cf.DeviceReadBPs, - "device-read-bps", []string{}, + deviceReadBpsFlagName, []string{}, "Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)", ) + _ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault) + + deviceReadIopsFlagName := "device-read-iops" createFlags.StringSliceVar( &cf.DeviceReadIOPs, - "device-read-iops", []string{}, + deviceReadIopsFlagName, []string{}, "Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)", ) + _ = cmd.RegisterFlagCompletionFunc(deviceReadIopsFlagName, completion.AutocompleteDefault) + + deviceWriteBpsFlagName := "device-write-bps" createFlags.StringSliceVar( &cf.DeviceWriteBPs, - "device-write-bps", []string{}, + deviceWriteBpsFlagName, []string{}, "Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)", ) + _ = cmd.RegisterFlagCompletionFunc(deviceWriteBpsFlagName, completion.AutocompleteDefault) + + deviceWriteIopsFlagName := "device-write-iops" createFlags.StringSliceVar( &cf.DeviceWriteIOPs, - "device-write-iops", []string{}, + deviceWriteIopsFlagName, []string{}, "Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)", ) + _ = cmd.RegisterFlagCompletionFunc(deviceWriteIopsFlagName, completion.AutocompleteDefault) + createFlags.Bool( "disable-content-trust", false, "This is a Docker specific option and is a NOOP", ) - createFlags.String("entrypoint", "", + + entrypointFlagName := "entrypoint" + createFlags.String(entrypointFlagName, "", "Overwrite the default ENTRYPOINT of the image", ) + _ = cmd.RegisterFlagCompletionFunc(entrypointFlagName, completion.AutocompleteNone) + + envFlagName := "env" createFlags.StringArrayP( - "env", "e", containerConfig.Env(), + envFlagName, "e", containerConfig.Env(), "Set environment variables in container", ) + _ = cmd.RegisterFlagCompletionFunc(envFlagName, completion.AutocompleteNone) + if !registry.IsRemote() { createFlags.BoolVar( &cf.EnvHost, "env-host", false, "Use all current host environment variables in container", ) } + + envFileFlagName := "env-file" createFlags.StringSliceVar( &cf.EnvFile, - "env-file", []string{}, + envFileFlagName, []string{}, "Read in a file of environment variables", ) + _ = cmd.RegisterFlagCompletionFunc(envFileFlagName, completion.AutocompleteDefault) + + exposeFlagName := "expose" createFlags.StringSliceVar( &cf.Expose, - "expose", []string{}, + exposeFlagName, []string{}, "Expose a port or a range of ports", ) + _ = cmd.RegisterFlagCompletionFunc(exposeFlagName, completion.AutocompleteNone) + + gidmapFlagName := "gidmap" createFlags.StringSliceVar( &cf.GIDMap, - "gidmap", []string{}, + gidmapFlagName, []string{}, "GID map to use for the user namespace", ) + _ = cmd.RegisterFlagCompletionFunc(gidmapFlagName, completion.AutocompleteNone) + + groupAddFlagName := "group-add" createFlags.StringSliceVar( &cf.GroupAdd, - "group-add", []string{}, + groupAddFlagName, []string{}, "Add additional groups to join", ) + _ = cmd.RegisterFlagCompletionFunc(groupAddFlagName, completion.AutocompleteNone) + createFlags.Bool( "help", false, "", ) + + healthCmdFlagName := "health-cmd" createFlags.StringVar( &cf.HealthCmd, - "health-cmd", "", + healthCmdFlagName, "", "set a healthcheck command for the container ('none' disables the existing healthcheck)", ) + _ = cmd.RegisterFlagCompletionFunc(healthCmdFlagName, completion.AutocompleteNone) + + healthIntervalFlagName := "health-interval" createFlags.StringVar( &cf.HealthInterval, - "health-interval", DefaultHealthCheckInterval, + healthIntervalFlagName, DefaultHealthCheckInterval, "set an interval for the healthchecks (a value of disable results in no automatic timer setup)", ) + _ = cmd.RegisterFlagCompletionFunc(healthIntervalFlagName, completion.AutocompleteNone) + + healthRetriesFlagName := "health-retries" createFlags.UintVar( &cf.HealthRetries, - "health-retries", DefaultHealthCheckRetries, + healthRetriesFlagName, DefaultHealthCheckRetries, "the number of retries allowed before a healthcheck is considered to be unhealthy", ) + _ = cmd.RegisterFlagCompletionFunc(healthRetriesFlagName, completion.AutocompleteNone) + + healthStartPeriodFlagName := "health-start-period" createFlags.StringVar( &cf.HealthStartPeriod, - "health-start-period", DefaultHealthCheckStartPeriod, + healthStartPeriodFlagName, DefaultHealthCheckStartPeriod, "the initialization time needed for a container to bootstrap", ) + _ = cmd.RegisterFlagCompletionFunc(healthStartPeriodFlagName, completion.AutocompleteNone) + + healthTimeoutFlagName := "health-timeout" createFlags.StringVar( &cf.HealthTimeout, - "health-timeout", DefaultHealthCheckTimeout, + healthTimeoutFlagName, DefaultHealthCheckTimeout, "the maximum time allowed to complete the healthcheck before an interval is considered failed", ) + _ = cmd.RegisterFlagCompletionFunc(healthTimeoutFlagName, completion.AutocompleteNone) + + hostnameFlagName := "hostname" createFlags.StringVarP( &cf.Hostname, - "hostname", "h", "", + hostnameFlagName, "h", "", "Set container hostname", ) + _ = cmd.RegisterFlagCompletionFunc(hostnameFlagName, completion.AutocompleteNone) + createFlags.BoolVar( &cf.HTTPProxy, "http-proxy", true, "Set proxy environment variables in the container based on the host proxy vars", ) + + imageVolumeFlagName := "image-volume" createFlags.StringVar( &cf.ImageVolume, - "image-volume", DefaultImageVolume, + imageVolumeFlagName, DefaultImageVolume, `Tells podman how to handle the builtin image volumes ("bind"|"tmpfs"|"ignore")`, ) + _ = cmd.RegisterFlagCompletionFunc(imageVolumeFlagName, AutocompleteImageVolume) + createFlags.BoolVar( &cf.Init, "init", false, "Run an init binary inside the container that forwards signals and reaps processes", ) + + initPathFlagName := "init-path" createFlags.StringVar( &cf.InitPath, - "init-path", containerConfig.InitPath(), + initPathFlagName, containerConfig.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"), ) + _ = cmd.RegisterFlagCompletionFunc(initPathFlagName, completion.AutocompleteDefault) + createFlags.BoolVarP( &cf.Interactive, "interactive", "i", false, "Keep STDIN open even if not attached", ) + + ipcFlagName := "ipc" createFlags.String( - "ipc", "", + ipcFlagName, "", "IPC namespace to use", ) + _ = cmd.RegisterFlagCompletionFunc(ipcFlagName, AutocompleteNamespace) + + kernelMemoryFlagName := "kernel-memory" createFlags.StringVar( &cf.KernelMemory, - "kernel-memory", "", + kernelMemoryFlagName, "", "Kernel memory limit "+sizeWithUnitFormat, ) + _ = cmd.RegisterFlagCompletionFunc(kernelMemoryFlagName, completion.AutocompleteNone) + + labelFlagName := "label" createFlags.StringArrayVarP( &cf.Label, - "label", "l", []string{}, + labelFlagName, "l", []string{}, "Set metadata on container", ) + _ = cmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone) + + labelFileFlagName := "label-file" createFlags.StringSliceVar( &cf.LabelFile, - "label-file", []string{}, + labelFileFlagName, []string{}, "Read in a line delimited file of labels", ) + _ = cmd.RegisterFlagCompletionFunc(labelFileFlagName, completion.AutocompleteDefault) + + logDriverFlagName := "log-driver" createFlags.StringVar( &cf.LogDriver, - "log-driver", "", + logDriverFlagName, "", "Logging driver for the container", ) + _ = cmd.RegisterFlagCompletionFunc(logDriverFlagName, AutocompleteLogDriver) + + logOptFlagName := "log-opt" createFlags.StringSliceVar( &cf.LogOptions, - "log-opt", []string{}, + logOptFlagName, []string{}, "Logging driver options", ) + _ = cmd.RegisterFlagCompletionFunc(logOptFlagName, AutocompleteLogOpt) + + memoryFlagName := "memory" createFlags.StringVarP( &cf.Memory, - "memory", "m", "", + memoryFlagName, "m", "", "Memory limit "+sizeWithUnitFormat, ) + _ = cmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) + + memoryReservationFlagName := "memory-reservation" createFlags.StringVar( &cf.MemoryReservation, - "memory-reservation", "", + memoryReservationFlagName, "", "Memory soft limit "+sizeWithUnitFormat, ) + _ = cmd.RegisterFlagCompletionFunc(memoryReservationFlagName, completion.AutocompleteNone) + + memorySwapFlagName := "memory-swap" createFlags.StringVar( &cf.MemorySwap, - "memory-swap", "", + memorySwapFlagName, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap", ) + _ = cmd.RegisterFlagCompletionFunc(memorySwapFlagName, completion.AutocompleteNone) + + memorySwappinessFlagName := "memory-swappiness" createFlags.Int64Var( &cf.MemorySwappiness, - "memory-swappiness", -1, + memorySwappinessFlagName, -1, "Tune container memory swappiness (0 to 100, or -1 for system default)", ) + _ = cmd.RegisterFlagCompletionFunc(memorySwappinessFlagName, completion.AutocompleteNone) + + nameFlagName := "name" createFlags.StringVar( &cf.Name, - "name", "", + nameFlagName, "", "Assign a name to the container", ) + _ = cmd.RegisterFlagCompletionFunc(nameFlagName, completion.AutocompleteNone) + createFlags.BoolVar( &cf.NoHealthCheck, "no-healthcheck", false, @@ -305,44 +466,69 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "oom-kill-disable", false, "Disable OOM Killer", ) + + oomScoreAdjFlagName := "oom-score-adj" createFlags.IntVar( &cf.OOMScoreAdj, - "oom-score-adj", 0, + oomScoreAdjFlagName, 0, "Tune the host's OOM preferences (-1000 to 1000)", ) + _ = cmd.RegisterFlagCompletionFunc(oomScoreAdjFlagName, completion.AutocompleteNone) + + overrideArchFlagName := "override-arch" createFlags.StringVar( &cf.OverrideArch, - "override-arch", "", + overrideArchFlagName, "", "use `ARCH` instead of the architecture of the machine for choosing images", ) + _ = cmd.RegisterFlagCompletionFunc(overrideArchFlagName, completion.AutocompleteNone) + + overrideOSFlagName := "override-os" createFlags.StringVar( &cf.OverrideOS, - "override-os", "", + overrideOSFlagName, "", "use `OS` instead of the running OS for choosing images", ) + _ = cmd.RegisterFlagCompletionFunc(overrideOSFlagName, completion.AutocompleteNone) + + overrideVariantFlagName := "override-variant" createFlags.StringVar( &cf.OverrideVariant, - "override-variant", "", + overrideVariantFlagName, "", "Use _VARIANT_ instead of the running architecture variant for choosing images", ) + _ = cmd.RegisterFlagCompletionFunc(overrideVariantFlagName, completion.AutocompleteNone) + + pidFlagName := "pid" createFlags.String( - "pid", "", + pidFlagName, "", "PID namespace to use", ) + _ = cmd.RegisterFlagCompletionFunc(pidFlagName, AutocompleteNamespace) + + pidsLimitFlagName := "pids-limit" createFlags.Int64( - "pids-limit", containerConfig.PidsLimit(), + pidsLimitFlagName, containerConfig.PidsLimit(), "Tune container pids limit (set 0 for unlimited, -1 for server defaults)", ) + _ = cmd.RegisterFlagCompletionFunc(pidsLimitFlagName, completion.AutocompleteNone) + + podFlagName := "pod" createFlags.StringVar( &cf.Pod, - "pod", "", + podFlagName, "", "Run container in an existing pod", ) + _ = cmd.RegisterFlagCompletionFunc(podFlagName, AutocompletePods) + + podIDFileFlagName := "pod-id-file" createFlags.StringVar( &cf.PodIDFile, - "pod-id-file", "", + podIDFileFlagName, "", "Read the pod ID from the file", ) + _ = cmd.RegisterFlagCompletionFunc(podIDFileFlagName, completion.AutocompleteDefault) + createFlags.BoolVar( &cf.Privileged, "privileged", false, @@ -353,11 +539,15 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "publish-all", "P", false, "Publish all exposed ports to random ports on the host interface", ) + + pullFlagName := "pull" createFlags.StringVar( &cf.Pull, - "pull", containerConfig.Engine.PullPolicy, + pullFlagName, containerConfig.Engine.PullPolicy, `Pull image before creating ("always"|"missing"|"never")`, ) + _ = cmd.RegisterFlagCompletionFunc(pullFlagName, AutocompletePullOption) + createFlags.BoolVarP( &cf.Quiet, "quiet", "q", false, @@ -378,11 +568,15 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "replace", false, `If a container with the same name exists, replace it`, ) + + restartFlagName := "restart" createFlags.StringVar( &cf.Restart, - "restart", "", + restartFlagName, "", `Restart policy to apply when a container exits ("always"|"no"|"on-failure"|"unless-stopped")`, ) + _ = cmd.RegisterFlagCompletionFunc(restartFlagName, AutocompleteRestartOption) + createFlags.BoolVar( &cf.Rm, "rm", false, @@ -393,20 +587,31 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { "rootfs", false, "The first argument is not an image but the rootfs to the exploded container", ) + + sdnotifyFlagName := "sdnotify" createFlags.StringVar( &cf.SdNotifyMode, - "sdnotify", define.SdNotifyModeContainer, + sdnotifyFlagName, define.SdNotifyModeContainer, `control sd-notify behavior ("container"|"conmon"|"ignore")`, ) + _ = cmd.RegisterFlagCompletionFunc(sdnotifyFlagName, AutocompleteSDNotify) + + securityOptFlagName := "security-opt" createFlags.StringArrayVar( &cf.SecurityOpt, - "security-opt", []string{}, + securityOptFlagName, []string{}, "Security Options", ) + _ = cmd.RegisterFlagCompletionFunc(securityOptFlagName, AutocompleteSecurityOption) + + shmSizeFlagName := "shm-size" createFlags.String( - "shm-size", containerConfig.ShmSize(), + shmSizeFlagName, containerConfig.ShmSize(), "Size of /dev/shm "+sizeWithUnitFormat, ) + _ = cmd.RegisterFlagCompletionFunc(shmSizeFlagName, completion.AutocompleteNone) + + stopSignalFlagName := "stop-signal" createFlags.StringVar( &cf.SignaturePolicy, "signature-policy", "", @@ -414,112 +619,175 @@ func GetCreateFlags(cf *ContainerCLIOpts) *pflag.FlagSet { ) createFlags.StringVar( &cf.StopSignal, - "stop-signal", "", + stopSignalFlagName, "", "Signal to stop a container. Default is SIGTERM", ) + _ = cmd.RegisterFlagCompletionFunc(stopSignalFlagName, AutocompleteStopSignal) + + stopTimeoutFlagName := "stop-timeout" createFlags.UintVar( &cf.StopTimeout, - "stop-timeout", containerConfig.Engine.StopTimeout, + stopTimeoutFlagName, containerConfig.Engine.StopTimeout, "Timeout (in seconds) to stop a container. Default is 10", ) + _ = cmd.RegisterFlagCompletionFunc(stopTimeoutFlagName, completion.AutocompleteNone) + + storageOptFlagName := "storage-opt" createFlags.StringSliceVar( &cf.StoreageOpt, - "storage-opt", []string{}, + storageOptFlagName, []string{}, "Storage driver options per container", ) + //FIXME: What should we suggest here? The flag is not in the man page. + _ = cmd.RegisterFlagCompletionFunc(storageOptFlagName, completion.AutocompleteNone) + + subgidnameFlagName := "subgidname" createFlags.StringVar( &cf.SubUIDName, - "subgidname", "", + subgidnameFlagName, "", "Name of range listed in /etc/subgid for use in user namespace", ) + _ = cmd.RegisterFlagCompletionFunc(subgidnameFlagName, completion.AutocompleteSubgidName) + + subuidnameFlagName := "subuidname" createFlags.StringVar( &cf.SubGIDName, - "subuidname", "", + subuidnameFlagName, "", "Name of range listed in /etc/subuid for use in user namespace", ) + _ = cmd.RegisterFlagCompletionFunc(subuidnameFlagName, completion.AutocompleteSubuidName) + sysctlFlagName := "sysctl" createFlags.StringSliceVar( &cf.Sysctl, - "sysctl", []string{}, + sysctlFlagName, []string{}, "Sysctl options", ) + //TODO: Add function for systctl completion. + _ = cmd.RegisterFlagCompletionFunc(sysctlFlagName, completion.AutocompleteNone) + + systemdFlagName := "systemd" createFlags.StringVar( &cf.Systemd, - "systemd", "true", + systemdFlagName, "true", `Run container in systemd mode ("true"|"false"|"always")`, ) + _ = cmd.RegisterFlagCompletionFunc(systemdFlagName, AutocompleteSystemdFlag) + + tmpfsFlagName := "tmpfs" createFlags.StringArrayVar( &cf.TmpFS, - "tmpfs", []string{}, + tmpfsFlagName, []string{}, "Mount a temporary filesystem (`tmpfs`) into a container", ) + _ = cmd.RegisterFlagCompletionFunc(tmpfsFlagName, completion.AutocompleteDefault) + createFlags.BoolVarP( &cf.TTY, "tty", "t", false, "Allocate a pseudo-TTY for container", ) + + timezonezFlagName := "tz" createFlags.StringVar( &cf.Timezone, - "tz", containerConfig.TZ(), + timezonezFlagName, containerConfig.TZ(), "Set timezone in container", ) + _ = cmd.RegisterFlagCompletionFunc(timezonezFlagName, completion.AutocompleteNone) //TODO: add timezone completion + + umaskFlagName := "umask" createFlags.StringVar( &cf.Umask, - "umask", containerConfig.Umask(), + umaskFlagName, containerConfig.Umask(), "Set umask in container", ) + _ = cmd.RegisterFlagCompletionFunc(umaskFlagName, completion.AutocompleteNone) + + uidmapFlagName := "uidmap" createFlags.StringSliceVar( &cf.UIDMap, - "uidmap", []string{}, + uidmapFlagName, []string{}, "UID map to use for the user namespace", ) + _ = cmd.RegisterFlagCompletionFunc(uidmapFlagName, completion.AutocompleteNone) + + ulimitFlagName := "ulimit" createFlags.StringSliceVar( &cf.Ulimit, - "ulimit", containerConfig.Ulimits(), + ulimitFlagName, containerConfig.Ulimits(), "Ulimit options", ) + _ = cmd.RegisterFlagCompletionFunc(ulimitFlagName, completion.AutocompleteNone) + + userFlagName := "user" createFlags.StringVarP( &cf.User, - "user", "u", "", + userFlagName, "u", "", "Username or UID (format: [:])", ) + _ = cmd.RegisterFlagCompletionFunc(userFlagName, AutocompleteUserFlag) + + usernsFlagName := "userns" createFlags.String( - "userns", os.Getenv("PODMAN_USERNS"), + usernsFlagName, os.Getenv("PODMAN_USERNS"), "User namespace to use", ) + _ = cmd.RegisterFlagCompletionFunc(usernsFlagName, AutocompleteUserNamespace) + + utsFlagName := "uts" createFlags.String( - "uts", "", + utsFlagName, "", "UTS namespace to use", ) + _ = cmd.RegisterFlagCompletionFunc(utsFlagName, AutocompleteNamespace) + + mountFlagName := "mount" createFlags.StringArrayVar( &cf.Mount, - "mount", []string{}, + mountFlagName, []string{}, "Attach a filesystem mount to the container", ) + _ = cmd.RegisterFlagCompletionFunc(mountFlagName, AutocompleteMountFlag) + + volumeFlagName := "volume" createFlags.StringArrayVarP( &cf.Volume, - "volume", "v", containerConfig.Volumes(), + volumeFlagName, "v", containerConfig.Volumes(), "Bind mount a volume into the container", ) + _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) + + volumesFromFlagName := "volumes-from" createFlags.StringArrayVar( &cf.VolumesFrom, - "volumes-from", []string{}, + volumesFromFlagName, []string{}, "Mount volumes from the specified container(s)", ) + _ = cmd.RegisterFlagCompletionFunc(volumesFromFlagName, AutocompleteContainers) + + workdirFlagName := "workdir" createFlags.StringVarP( &cf.Workdir, - "workdir", "w", "", + workdirFlagName, "w", "", "Working directory inside the container", ) + _ = cmd.RegisterFlagCompletionFunc(workdirFlagName, completion.AutocompleteDefault) + + seccompPolicyFlagName := "seccomp-policy" createFlags.StringVar( &cf.SeccompPolicy, - "seccomp-policy", "default", + seccompPolicyFlagName, "default", "Policy for selecting a seccomp profile (experimental)", ) + _ = cmd.RegisterFlagCompletionFunc(seccompPolicyFlagName, completion.AutocompleteDefault) + + cgroupConfFlagName := "cgroup-conf" createFlags.StringSliceVar( &cf.CgroupConf, - "cgroup-conf", []string{}, + cgroupConfFlagName, []string{}, "Configure cgroup v2 (key=value)", ) - return &createFlags + _ = cmd.RegisterFlagCompletionFunc(cgroupConfFlagName, completion.AutocompleteNone) + } diff --git a/cmd/podman/common/netflags.go b/cmd/podman/common/netflags.go index 935a5f7b9..cae52ccaa 100644 --- a/cmd/podman/common/netflags.go +++ b/cmd/podman/common/netflags.go @@ -4,58 +4,85 @@ import ( "net" "strings" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v2/cmd/podman/parse" "github.com/containers/podman/v2/libpod/define" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/specgen" "github.com/pkg/errors" "github.com/spf13/cobra" - "github.com/spf13/pflag" ) -func GetNetFlags() *pflag.FlagSet { - netFlags := pflag.FlagSet{} +func DefineNetFlags(cmd *cobra.Command) { + netFlags := cmd.Flags() + + addHostFlagName := "add-host" netFlags.StringSlice( - "add-host", []string{}, + addHostFlagName, []string{}, "Add a custom host-to-IP mapping (host:ip) (default [])", ) + _ = cmd.RegisterFlagCompletionFunc(addHostFlagName, completion.AutocompleteNone) + + dnsFlagName := "dns" netFlags.StringSlice( - "dns", containerConfig.DNSServers(), + dnsFlagName, containerConfig.DNSServers(), "Set custom DNS servers", ) + _ = cmd.RegisterFlagCompletionFunc(dnsFlagName, completion.AutocompleteNone) + + dnsOptFlagName := "dns-opt" netFlags.StringSlice( - "dns-opt", containerConfig.DNSOptions(), + dnsOptFlagName, containerConfig.DNSOptions(), "Set custom DNS options", ) + _ = cmd.RegisterFlagCompletionFunc(dnsOptFlagName, completion.AutocompleteNone) + + dnsSearchFlagName := "dns-search" netFlags.StringSlice( - "dns-search", containerConfig.DNSSearches(), + dnsSearchFlagName, containerConfig.DNSSearches(), "Set custom DNS search domains", ) + _ = cmd.RegisterFlagCompletionFunc(dnsSearchFlagName, completion.AutocompleteNone) + + ipFlagName := "ip" netFlags.String( - "ip", "", + ipFlagName, "", "Specify a static IPv4 address for the container", ) + _ = cmd.RegisterFlagCompletionFunc(ipFlagName, completion.AutocompleteNone) + + macAddressFlagName := "mac-address" netFlags.String( - "mac-address", "", + macAddressFlagName, "", "Container MAC address (e.g. 92:d0:c6:0a:29:33)", ) + _ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone) + + networkFlagName := "network" netFlags.String( - "network", containerConfig.NetNS(), + networkFlagName, containerConfig.NetNS(), "Connect a container to a network", ) + _ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks) + + networkAliasFlagName := "network-alias" netFlags.StringSlice( - "network-alias", []string{}, + networkAliasFlagName, []string{}, "Add network-scoped alias for the container", ) + _ = cmd.RegisterFlagCompletionFunc(networkAliasFlagName, completion.AutocompleteNone) + + publishFlagName := "publish" netFlags.StringSliceP( - "publish", "p", []string{}, + publishFlagName, "p", []string{}, "Publish a container's port, or a range of ports, to the host (default [])", ) + _ = cmd.RegisterFlagCompletionFunc(publishFlagName, completion.AutocompleteNone) + netFlags.Bool( "no-hosts", false, "Do not create /etc/hosts within the container, instead use the version from the image", ) - return &netFlags } func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) { -- cgit v1.2.3-54-g00ecf