diff options
Diffstat (limited to 'cmd/podman')
-rw-r--r-- | cmd/podman/common/completion.go | 8 | ||||
-rw-r--r-- | cmd/podman/common/create.go | 12 | ||||
-rw-r--r-- | cmd/podman/containers/create.go | 5 | ||||
-rw-r--r-- | cmd/podman/containers/ps.go | 4 | ||||
-rw-r--r-- | cmd/podman/containers/run.go | 4 | ||||
-rw-r--r-- | cmd/podman/images/build.go | 7 | ||||
-rw-r--r-- | cmd/podman/inspect/inspect.go | 12 | ||||
-rw-r--r-- | cmd/podman/machine/init.go | 4 | ||||
-rw-r--r-- | cmd/podman/machine/list.go | 143 | ||||
-rw-r--r-- | cmd/podman/machine/machine.go | 35 | ||||
-rw-r--r-- | cmd/podman/machine/rm.go | 7 | ||||
-rw-r--r-- | cmd/podman/machine/ssh.go | 62 | ||||
-rw-r--r-- | cmd/podman/machine/start.go | 7 | ||||
-rw-r--r-- | cmd/podman/machine/stop.go | 7 | ||||
-rw-r--r-- | cmd/podman/root.go | 8 |
15 files changed, 257 insertions, 68 deletions
diff --git a/cmd/podman/common/completion.go b/cmd/podman/common/completion.go index 6bed5e0c6..bc106263c 100644 --- a/cmd/podman/common/completion.go +++ b/cmd/podman/common/completion.go @@ -1092,11 +1092,3 @@ func AutocompleteVolumeFilters(cmd *cobra.Command, args []string, toComplete str } return completeKeyValues(toComplete, kv) } - -// AutocompleteMachineSSH - Autocomplete machine ssh command. -func AutocompleteMachineSSH(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { - if len(args) == 0 { - return nil, cobra.ShellCompDirectiveNoFileComp - } - return nil, cobra.ShellCompDirectiveDefault -} diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 2169cdc9f..220a30a10 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -773,11 +773,15 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { ) _ = cmd.RegisterFlagCompletionFunc(mountFlagName, AutocompleteMountFlag) + volumeDesciption := "Bind mount a volume into the container" + if registry.IsRemote() { + volumeDesciption = "Bind mount a volume into the container. Volume src will be on the server machine, not the client" + } volumeFlagName := "volume" createFlags.StringArrayVarP( &cf.Volume, volumeFlagName, "v", volumes(), - "Bind mount a volume into the container", + volumeDesciption, ) _ = cmd.RegisterFlagCompletionFunc(volumeFlagName, AutocompleteVolumeFlag) @@ -812,4 +816,10 @@ func DefineCreateFlags(cmd *cobra.Command, cf *ContainerCLIOpts) { "Configure cgroup v2 (key=value)", ) _ = cmd.RegisterFlagCompletionFunc(cgroupConfFlagName, completion.AutocompleteNone) + + _ = createFlags.MarkHidden("signature-policy") + if registry.IsRemote() { + _ = createFlags.MarkHidden("env-host") + _ = createFlags.MarkHidden("http-proxy") + } } diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index af9278ce1..2da9aaf5e 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -63,11 +63,6 @@ func createFlags(cmd *cobra.Command) { common.DefineNetFlags(cmd) flags.SetNormalizeFunc(utils.AliasFlags) - - _ = flags.MarkHidden("signature-policy") - if registry.IsRemote() { - _ = flags.MarkHidden("http-proxy") - } } func init() { diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go index 6b125fede..70bfd3574 100644 --- a/cmd/podman/containers/ps.go +++ b/cmd/podman/containers/ps.go @@ -232,7 +232,9 @@ func ps(cmd *cobra.Command, _ []string) error { ns := strings.NewReplacer(".Namespaces.", ".") format = ns.Replace(format) - tmpl, err := template.New("listContainers").Parse(format) + tmpl, err := template.New("listContainers"). + Funcs(template.FuncMap(report.DefaultFuncs)). + Parse(format) if err != nil { return err } diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go index db7180ca9..1a9fa2f0f 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -76,13 +76,11 @@ func runFlags(cmd *cobra.Command) { detachKeysFlagName := "detach-keys" flags.StringVar(&runOpts.DetachKeys, detachKeysFlagName, containerConfig.DetachKeys(), "Override the key sequence for detaching a container. Format is a single character `[a-Z]` or a comma separated sequence of `ctrl-<value>`, where `<value>` is one of: `a-cf`, `@`, `^`, `[`, `\\`, `]`, `^` or `_`") _ = cmd.RegisterFlagCompletionFunc(detachKeysFlagName, common.AutocompleteDetachKeys) - - _ = flags.MarkHidden("signature-policy") if registry.IsRemote() { - _ = flags.MarkHidden("http-proxy") _ = flags.MarkHidden("preserve-fds") } } + func init() { registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index da7f5d862..04fdeab0a 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -11,6 +11,7 @@ import ( buildahDefine "github.com/containers/buildah/define" buildahCLI "github.com/containers/buildah/pkg/cli" "github.com/containers/buildah/pkg/parse" + "github.com/containers/common/pkg/auth" "github.com/containers/common/pkg/completion" "github.com/containers/common/pkg/config" encconfig "github.com/containers/ocicrypt/config" @@ -330,6 +331,12 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil pullPolicy = buildahDefine.PullNever } + if c.Flag("authfile").Changed { + if err := auth.CheckAuthFile(flags.Authfile); err != nil { + return nil, err + } + } + args := make(map[string]string) if c.Flag("build-arg").Changed { for _, arg := range flags.BuildArg { diff --git a/cmd/podman/inspect/inspect.go b/cmd/podman/inspect/inspect.go index 09721a2a8..351684af1 100644 --- a/cmd/podman/inspect/inspect.go +++ b/cmd/podman/inspect/inspect.go @@ -1,7 +1,6 @@ package inspect import ( - "bytes" "context" "encoding/json" // due to a bug in json-iterator it cannot be used here "fmt" @@ -246,15 +245,8 @@ func printJSON(data []interface{}) error { } func printTmpl(typ, row string, data []interface{}) error { - t, err := template.New(typ + " inspect").Funcs(map[string]interface{}{ - "json": func(v interface{}) string { - b := &bytes.Buffer{} - e := registry.JSONLibrary().NewEncoder(b) - e.SetEscapeHTML(false) - _ = e.Encode(v) - return strings.TrimSpace(b.String()) - }, - }).Parse(row) + // We cannot use c/common/reports here, too many levels of interface{} + t, err := template.New(typ + " inspect").Funcs(template.FuncMap(report.DefaultFuncs)).Parse(row) if err != nil { return err } diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index 61261e008..02dfc80aa 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -15,8 +15,8 @@ import ( var ( initCmd = &cobra.Command{ Use: "init [options] [NAME]", - Short: "initialize a vm", - Long: "initialize a virtual machine for Podman to run on. Virtual machines are used to run Podman.", + Short: "Initialize a virtual machine", + Long: "initialize a virtual machine ", RunE: initMachine, Args: cobra.MaximumNArgs(1), Example: `podman machine init myvm`, diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go new file mode 100644 index 000000000..ce4129e87 --- /dev/null +++ b/cmd/podman/machine/list.go @@ -0,0 +1,143 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +package machine + +import ( + "os" + "sort" + "text/tabwriter" + "text/template" + "time" + + "github.com/containers/common/pkg/completion" + "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/report" + "github.com/containers/podman/v3/cmd/podman/parse" + "github.com/containers/podman/v3/cmd/podman/registry" + "github.com/containers/podman/v3/cmd/podman/validate" + "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/machine" + "github.com/containers/podman/v3/pkg/machine/qemu" + "github.com/docker/go-units" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + lsCmd = &cobra.Command{ + Use: "list [options]", + Aliases: []string{"ls"}, + Short: "List machines", + Long: "List managed virtual machines.", + RunE: list, + Args: validate.NoArgs, + Example: `podman machine list, + podman machine ls`, + ValidArgsFunction: completion.AutocompleteNone, + } + listFlag = listFlagType{} +) + +type listFlagType struct { + format string + noHeading bool +} + +type machineReporter struct { + Name string + Created string + LastUp string + VMType string +} + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: lsCmd, + Parent: machineCmd, + }) + + flags := lsCmd.Flags() + formatFlagName := "format" + flags.StringVar(&listFlag.format, formatFlagName, "{{.Name}}\t{{.VMType}}\t{{.Created}}\t{{.LastUp}}\n", "Format volume output using Go template") + _ = lsCmd.RegisterFlagCompletionFunc(formatFlagName, completion.AutocompleteNone) +} + +func list(cmd *cobra.Command, args []string) error { + var opts machine.ListOptions + // We only have qemu VM's for now + listResponse, err := qemu.List(opts) + if err != nil { + return errors.Wrap(err, "error listing vms") + } + + // Sort by last run + sort.Slice(listResponse, func(i, j int) bool { + return listResponse[i].LastUp.After(listResponse[j].LastUp) + }) + // Bring currently running machines to top + sort.Slice(listResponse, func(i, j int) bool { + return listResponse[i].Running + }) + machineReporter, err := toHumanFormat(listResponse) + if err != nil { + return err + } + + return outputTemplate(cmd, machineReporter) +} + +func outputTemplate(cmd *cobra.Command, responses []*machineReporter) error { + headers := report.Headers(machineReporter{}, map[string]string{ + "LastUp": "LAST UP", + "VmType": "VM TYPE", + }) + + row := report.NormalizeFormat(listFlag.format) + format := parse.EnforceRange(row) + + tmpl, err := template.New("list machines").Parse(format) + if err != nil { + return err + } + w := tabwriter.NewWriter(os.Stdout, 12, 2, 2, ' ', 0) + defer w.Flush() + + if cmd.Flags().Changed("format") && !parse.HasTable(listFlag.format) { + listFlag.noHeading = true + } + + if !listFlag.noHeading { + if err := tmpl.Execute(w, headers); err != nil { + return errors.Wrapf(err, "failed to write report column headers") + } + } + return tmpl.Execute(w, responses) +} + +func toHumanFormat(vms []*machine.ListResponse) ([]*machineReporter, error) { + cfg, err := config.ReadCustomConfig() + if err != nil { + return nil, err + } + + humanResponses := make([]*machineReporter, 0, len(vms)) + for _, vm := range vms { + response := new(machineReporter) + if vm.Name == cfg.Engine.ActiveService { + response.Name = vm.Name + "*" + } else { + response.Name = vm.Name + } + if vm.Running { + response.LastUp = "Currently running" + } else { + response.LastUp = units.HumanDuration(time.Since(vm.LastUp)) + " ago" + } + response.Created = units.HumanDuration(time.Since(vm.CreatedAt)) + " ago" + response.VMType = vm.VMType + + humanResponses = append(humanResponses, response) + } + return humanResponses, nil +} diff --git a/cmd/podman/machine/machine.go b/cmd/podman/machine/machine.go index 9a2377d12..d8cdf5568 100644 --- a/cmd/podman/machine/machine.go +++ b/cmd/podman/machine/machine.go @@ -3,9 +3,13 @@ package machine import ( + "strings" + "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/cmd/podman/validate" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/machine" + "github.com/containers/podman/v3/pkg/machine/qemu" "github.com/spf13/cobra" ) @@ -30,3 +34,34 @@ func init() { Command: machineCmd, }) } + +// autocompleteMachineSSH - Autocomplete machine ssh command. +func autocompleteMachineSSH(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return getMachines(toComplete) + } + return nil, cobra.ShellCompDirectiveDefault +} + +// autocompleteMachine - Autocomplete machines. +func autocompleteMachine(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { + if len(args) == 0 { + return getMachines(toComplete) + } + return nil, cobra.ShellCompDirectiveNoFileComp +} + +func getMachines(toComplete string) ([]string, cobra.ShellCompDirective) { + suggestions := []string{} + machines, err := qemu.List(machine.ListOptions{}) + if err != nil { + cobra.CompErrorln(err.Error()) + return nil, cobra.ShellCompDirectiveNoFileComp + } + for _, m := range machines { + if strings.HasPrefix(m.Name, toComplete) { + suggestions = append(suggestions, m.Name) + } + } + return suggestions, cobra.ShellCompDirectiveNoFileComp +} diff --git a/cmd/podman/machine/rm.go b/cmd/podman/machine/rm.go index 002a793a3..0be2ba40c 100644 --- a/cmd/podman/machine/rm.go +++ b/cmd/podman/machine/rm.go @@ -8,7 +8,6 @@ import ( "os" "strings" - "github.com/containers/common/pkg/completion" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/machine" @@ -18,13 +17,13 @@ import ( var ( rmCmd = &cobra.Command{ - Use: "rm [options] [NAME]", + Use: "rm [options] [MACHINE]", Short: "Remove an existing machine", - Long: "Remove an existing machine ", + Long: "Remove a managed virtual machine ", RunE: rm, Args: cobra.MaximumNArgs(1), Example: `podman machine rm myvm`, - ValidArgsFunction: completion.AutocompleteNone, + ValidArgsFunction: autocompleteMachine, } ) diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go index 586c4267d..504fcbe46 100644 --- a/cmd/podman/machine/ssh.go +++ b/cmd/podman/machine/ssh.go @@ -3,7 +3,6 @@ package machine import ( - "github.com/containers/podman/v3/cmd/podman/common" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/machine" @@ -14,15 +13,13 @@ import ( var ( sshCmd = &cobra.Command{ - Use: "ssh [options] [NAME] [COMMAND [ARG ...]]", - Short: "SSH into a virtual machine", - Long: "SSH into a virtual machine ", + Use: "ssh [NAME] [COMMAND [ARG ...]]", + Short: "SSH into an existing machine", + Long: "SSH into a managed virtual machine ", RunE: ssh, - Args: cobra.MaximumNArgs(1), Example: `podman machine ssh myvm - podman machine ssh -e myvm echo hello`, - - ValidArgsFunction: common.AutocompleteMachineSSH, + podman machine ssh myvm echo hello`, + ValidArgsFunction: autocompleteMachineSSH, } ) @@ -31,36 +28,49 @@ var ( ) func init() { + sshCmd.Flags().SetInterspersed(false) registry.Commands = append(registry.Commands, registry.CliCommand{ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, Command: sshCmd, Parent: machineCmd, }) - - flags := sshCmd.Flags() - executeFlagName := "execute" - flags.BoolVarP(&sshOpts.Execute, executeFlagName, "e", false, "Execute command from args") } func ssh(cmd *cobra.Command, args []string) error { var ( - err error - vm machine.VM - vmType string + err error + validVM bool + vm machine.VM + vmType string ) - vmName := defaultMachineName - if len(args) > 0 && len(args[0]) > 1 { - vmName = args[0] - } - sshOpts.Args = args[1:] - // Error if no execute but args given - if !sshOpts.Execute && len(sshOpts.Args) > 0 { - return errors.New("too many args: to execute commands via ssh, use -e flag") + // Set the VM to default + vmName := defaultMachineName + // If len is greater than 0, it means we may have been + // provided the VM name. If so, we check. The VM name, + // if provided, must be in args[0]. + if len(args) > 0 { + switch vmType { + default: + validVM, err = qemu.IsValidVMName(args[0]) + if err != nil { + return err + } + if validVM { + vmName = args[0] + } else { + sshOpts.Args = append(sshOpts.Args, args[0]) + } + } } - // Error if execute but no args given - if sshOpts.Execute && len(sshOpts.Args) < 1 { - return errors.New("must proivde at least one command to execute") + // If len is greater than 1, it means we might have been + // given a vmname and args or just args + if len(args) > 1 { + if validVM { + sshOpts.Args = args[1:] + } else { + sshOpts.Args = args + } } switch vmType { diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go index 40800160e..d06e04f41 100644 --- a/cmd/podman/machine/start.go +++ b/cmd/podman/machine/start.go @@ -3,7 +3,6 @@ package machine import ( - "github.com/containers/common/pkg/completion" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/machine" @@ -13,13 +12,13 @@ import ( var ( startCmd = &cobra.Command{ - Use: "start [NAME]", + Use: "start [MACHINE]", Short: "Start an existing machine", - Long: "Start an existing machine ", + Long: "Start a managed virtual machine ", RunE: start, Args: cobra.MaximumNArgs(1), Example: `podman machine start myvm`, - ValidArgsFunction: completion.AutocompleteNone, + ValidArgsFunction: autocompleteMachine, } ) diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go index 7d655f0ba..4235b64f1 100644 --- a/cmd/podman/machine/stop.go +++ b/cmd/podman/machine/stop.go @@ -3,7 +3,6 @@ package machine import ( - "github.com/containers/common/pkg/completion" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/domain/entities" "github.com/containers/podman/v3/pkg/machine" @@ -13,13 +12,13 @@ import ( var ( stopCmd = &cobra.Command{ - Use: "stop [NAME]", + Use: "stop [MACHINE]", Short: "Stop an existing machine", - Long: "Stop an existing machine ", + Long: "Stop a managed virtual machine ", RunE: stop, Args: cobra.MaximumNArgs(1), Example: `podman machine stop myvm`, - ValidArgsFunction: completion.AutocompleteNone, + ValidArgsFunction: autocompleteMachine, } ) diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 2b77afbeb..4527c2646 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -180,6 +180,10 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { os.Setenv("TMPDIR", "/var/tmp") } + context := cmd.Root().LocalFlags().Lookup("context") + if context.Value.String() != "default" { + return errors.New("Podman does not support swarm, the only --context value allowed is \"default\"") + } if !registry.IsRemote() { if cmd.Flag("cpu-profile").Changed { f, err := os.Create(cfg.CPUProfile) @@ -269,6 +273,10 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { lFlags.StringVar(&opts.URI, urlFlagName, uri, "URL to access Podman service (CONTAINER_HOST)") _ = cmd.RegisterFlagCompletionFunc(urlFlagName, completion.AutocompleteDefault) + // Context option added just for compatibility with DockerCLI. + lFlags.String("context", "default", "Name of the context to use to connect to the daemon (This flag is a NOOP and provided solely for scripting compatibility.)") + _ = lFlags.MarkHidden("context") + identityFlagName := "identity" lFlags.StringVar(&opts.Identity, identityFlagName, ident, "path to SSH identity file, (CONTAINER_SSHKEY)") _ = cmd.RegisterFlagCompletionFunc(identityFlagName, completion.AutocompleteDefault) |