diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/common/create.go | 12 | ||||
-rw-r--r-- | cmd/podman/completion/completion.go | 8 | ||||
-rw-r--r-- | cmd/podman/containers/create.go | 5 | ||||
-rw-r--r-- | cmd/podman/containers/run.go | 10 | ||||
-rw-r--r-- | cmd/podman/images/build.go | 50 | ||||
-rw-r--r-- | cmd/podman/machine/init.go | 96 | ||||
-rw-r--r-- | cmd/podman/machine/list.go | 143 | ||||
-rw-r--r-- | cmd/podman/machine/machine.go | 67 | ||||
-rw-r--r-- | cmd/podman/machine/machine_unsupported.go | 5 | ||||
-rw-r--r-- | cmd/podman/machine/rm.go | 91 | ||||
-rw-r--r-- | cmd/podman/machine/ssh.go | 84 | ||||
-rw-r--r-- | cmd/podman/machine/start.go | 51 | ||||
-rw-r--r-- | cmd/podman/machine/stop.go | 52 | ||||
-rw-r--r-- | cmd/podman/main.go | 1 | ||||
-rw-r--r-- | cmd/podman/root.go | 4 | ||||
-rw-r--r-- | cmd/podman/system/service_abi.go | 30 |
16 files changed, 670 insertions, 39 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index d1170710b..dda709ecd 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -765,11 +765,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) @@ -804,4 +808,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/completion/completion.go b/cmd/podman/completion/completion.go index a4ceab4b0..472068130 100644 --- a/cmd/podman/completion/completion.go +++ b/cmd/podman/completion/completion.go @@ -21,7 +21,7 @@ const ( var ( file string noDesc bool - shells = []string{"bash", "zsh", "fish"} + shells = []string{"bash", "zsh", "fish", "powershell"} completionCmd = &cobra.Command{ Use: fmt.Sprintf("completion [options] {%s}", strings.Join(shells, "|")), Short: "Generate shell autocompletions", @@ -76,6 +76,12 @@ func completion(cmd *cobra.Command, args []string) error { } case "fish": err = cmd.Root().GenFishCompletion(w, !noDesc) + case "powershell": + if noDesc { + err = cmd.Root().GenPowerShellCompletion(w) + } else { + err = cmd.Root().GenPowerShellCompletionWithDesc(w) + } } if err != nil { 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/run.go b/cmd/podman/containers/run.go index 83a5d7b8a..1a9fa2f0f 100644 --- a/cmd/podman/containers/run.go +++ b/cmd/podman/containers/run.go @@ -17,6 +17,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "golang.org/x/crypto/ssh/terminal" ) var ( @@ -75,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}, @@ -106,6 +105,11 @@ func run(cmd *cobra.Command, args []string) error { return err } + // TODO: Breaking change should be made fatal in next major Release + if cliVals.TTY && cliVals.Interactive && !terminal.IsTerminal(int(os.Stdin.Fd())) { + logrus.Warnf("The input device is not a TTY. The --tty and --interactive flags might not work properly") + } + if af := cliVals.Authfile; len(af) > 0 { if _, err := os.Stat(af); err != nil { return err diff --git a/cmd/podman/images/build.go b/cmd/podman/images/build.go index 3b34a6bf6..da7f5d862 100644 --- a/cmd/podman/images/build.go +++ b/cmd/podman/images/build.go @@ -8,8 +8,7 @@ import ( "strings" "time" - "github.com/containers/buildah" - "github.com/containers/buildah/imagebuildah" + buildahDefine "github.com/containers/buildah/define" buildahCLI "github.com/containers/buildah/pkg/cli" "github.com/containers/buildah/pkg/parse" "github.com/containers/common/pkg/completion" @@ -159,11 +158,11 @@ func buildFlags(cmd *cobra.Command) { flags.SetNormalizeFunc(buildahCLI.AliasFlags) if registry.IsRemote() { flag = flags.Lookup("isolation") - buildOpts.Isolation = buildah.OCI - if err := flag.Value.Set(buildah.OCI); err != nil { - logrus.Errorf("unable to set --isolation to %v: %v", buildah.OCI, err) + buildOpts.Isolation = buildahDefine.OCI + if err := flag.Value.Set(buildahDefine.OCI); err != nil { + logrus.Errorf("unable to set --isolation to %v: %v", buildahDefine.OCI, err) } - flag.DefValue = buildah.OCI + flag.DefValue = buildahDefine.OCI _ = flags.MarkHidden("disable-content-trust") _ = flags.MarkHidden("cache-from") _ = flags.MarkHidden("sign-by") @@ -196,7 +195,7 @@ func build(cmd *cobra.Command, args []string) error { var contextDir string if len(args) > 0 { // The context directory could be a URL. Try to handle that. - tempDir, subDir, err := imagebuildah.TempDirForURL("", "buildah", args[0]) + tempDir, subDir, err := buildahDefine.TempDirForURL("", "buildah", args[0]) if err != nil { return errors.Wrapf(err, "error prepping temporary context directory") } @@ -304,16 +303,31 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil return nil, err } - pullPolicy := imagebuildah.PullIfMissing + pullFlagsCount := 0 + if c.Flag("pull").Changed { + pullFlagsCount++ + } + if c.Flag("pull-always").Changed { + pullFlagsCount++ + } + if c.Flag("pull-never").Changed { + pullFlagsCount++ + } + + if pullFlagsCount > 1 { + return nil, errors.Errorf("can only set one of 'pull' or 'pull-always' or 'pull-never'") + } + + pullPolicy := buildahDefine.PullIfMissing if c.Flags().Changed("pull") && flags.Pull { - pullPolicy = imagebuildah.PullAlways + pullPolicy = buildahDefine.PullAlways } if flags.PullAlways { - pullPolicy = imagebuildah.PullAlways + pullPolicy = buildahDefine.PullAlways } if flags.PullNever { - pullPolicy = imagebuildah.PullIfMissing + pullPolicy = buildahDefine.PullNever } args := make(map[string]string) @@ -388,9 +402,9 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil flags.Layers = false } - compression := imagebuildah.Gzip + compression := buildahDefine.Gzip if flags.DisableCompression { - compression = imagebuildah.Uncompressed + compression = buildahDefine.Uncompressed } isolation, err := parse.IsolationOption(flags.Isolation) @@ -412,10 +426,10 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil format := "" flags.Format = strings.ToLower(flags.Format) switch { - case strings.HasPrefix(flags.Format, buildah.OCI): - format = buildah.OCIv1ImageManifest - case strings.HasPrefix(flags.Format, buildah.DOCKER): - format = buildah.Dockerv2ImageManifest + case strings.HasPrefix(flags.Format, buildahDefine.OCI): + format = buildahDefine.OCIv1ImageManifest + case strings.HasPrefix(flags.Format, buildahDefine.DOCKER): + format = buildahDefine.Dockerv2ImageManifest default: return nil, errors.Errorf("unrecognized image type %q", flags.Format) } @@ -443,7 +457,7 @@ func buildFlagsWrapperToOptions(c *cobra.Command, contextDir string, flags *buil return nil, errors.Wrapf(err, "unable to obtain decrypt config") } - opts := imagebuildah.BuildOptions{ + opts := buildahDefine.BuildOptions{ AddCapabilities: flags.CapAdd, AdditionalTags: tags, Annotations: flags.Annotation, diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go new file mode 100644 index 000000000..61261e008 --- /dev/null +++ b/cmd/podman/machine/init.go @@ -0,0 +1,96 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +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" + "github.com/containers/podman/v3/pkg/machine/qemu" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +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.", + RunE: initMachine, + Args: cobra.MaximumNArgs(1), + Example: `podman machine init myvm`, + ValidArgsFunction: completion.AutocompleteNone, + } +) + +var ( + initOpts = machine.InitOptions{} + defaultMachineName string = "podman-machine-default" +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: initCmd, + Parent: machineCmd, + }) + flags := initCmd.Flags() + + cpusFlagName := "cpus" + flags.Uint64Var( + &initOpts.CPUS, + cpusFlagName, 1, + "Number of CPUs. The default is 1.", + ) + _ = initCmd.RegisterFlagCompletionFunc(cpusFlagName, completion.AutocompleteNone) + + diskSizeFlagName := "disk-size" + flags.Uint64Var( + &initOpts.DiskSize, + diskSizeFlagName, 10, + "Disk size in GB", + ) + + _ = initCmd.RegisterFlagCompletionFunc(diskSizeFlagName, completion.AutocompleteNone) + + memoryFlagName := "memory" + flags.Uint64VarP( + &initOpts.Memory, + memoryFlagName, "m", 2048, + "Memory (in MB)", + ) + _ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) + + ImagePathFlagName := "image-path" + flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, "", "Path to qcow image") + _ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault) + + IgnitionPathFlagName := "ignition-path" + flags.StringVar(&initOpts.IgnitionPath, IgnitionPathFlagName, "", "Path to ignition file") + _ = initCmd.RegisterFlagCompletionFunc(IgnitionPathFlagName, completion.AutocompleteDefault) +} + +// TODO should we allow for a users to append to the qemu cmdline? +func initMachine(cmd *cobra.Command, args []string) error { + var ( + vm machine.VM + vmType string + err error + ) + initOpts.Name = defaultMachineName + if len(args) > 0 { + initOpts.Name = args[0] + } + switch vmType { + default: // qemu is the default + if _, err := qemu.LoadVMByName(initOpts.Name); err == nil { + return errors.Wrap(machine.ErrVMAlreadyExists, initOpts.Name) + } + vm, err = qemu.NewMachine(initOpts) + } + if err != nil { + return err + } + return vm.Init(initOpts) +} diff --git a/cmd/podman/machine/list.go b/cmd/podman/machine/list.go new file mode 100644 index 000000000..3c8368c6b --- /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 Podman 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 new file mode 100644 index 000000000..d8cdf5568 --- /dev/null +++ b/cmd/podman/machine/machine.go @@ -0,0 +1,67 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +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" +) + +var ( + noOp = func(cmd *cobra.Command, args []string) error { + return nil + } + // Command: podman _machine_ + machineCmd = &cobra.Command{ + Use: "machine", + Short: "Manage a virtual machine", + Long: "Manage a virtual machine. Virtual machines are used to run Podman.", + PersistentPreRunE: noOp, + PersistentPostRunE: noOp, + RunE: validate.SubCommandExists, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + 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/machine_unsupported.go b/cmd/podman/machine/machine_unsupported.go new file mode 100644 index 000000000..3bb44b51f --- /dev/null +++ b/cmd/podman/machine/machine_unsupported.go @@ -0,0 +1,5 @@ +// +build !amd64 amd64,windows + +package machine + +func init() {} diff --git a/cmd/podman/machine/rm.go b/cmd/podman/machine/rm.go new file mode 100644 index 000000000..e05b5f7a8 --- /dev/null +++ b/cmd/podman/machine/rm.go @@ -0,0 +1,91 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +package machine + +import ( + "bufio" + "fmt" + "os" + "strings" + + "github.com/containers/podman/v3/cmd/podman/registry" + "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" +) + +var ( + rmCmd = &cobra.Command{ + Use: "rm [options] [MACHINE]", + Short: "Remove an existing machine", + Long: "Remove an existing machine ", + RunE: rm, + Args: cobra.MaximumNArgs(1), + Example: `podman machine rm myvm`, + ValidArgsFunction: autocompleteMachine, + } +) + +var ( + destoryOptions machine.RemoveOptions +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: rmCmd, + Parent: machineCmd, + }) + + flags := rmCmd.Flags() + formatFlagName := "force" + flags.BoolVar(&destoryOptions.Force, formatFlagName, false, "Do not prompt before rming") + + keysFlagName := "save-keys" + flags.BoolVar(&destoryOptions.SaveKeys, keysFlagName, false, "Do not delete SSH keys") + + ignitionFlagName := "save-ignition" + flags.BoolVar(&destoryOptions.SaveIgnition, ignitionFlagName, false, "Do not delete ignition file") + + imageFlagName := "save-image" + flags.BoolVar(&destoryOptions.SaveImage, imageFlagName, false, "Do not delete the image file") +} + +func rm(cmd *cobra.Command, args []string) error { + var ( + err error + vm machine.VM + vmType string + ) + vmName := defaultMachineName + if len(args) > 0 && len(args[0]) > 0 { + vmName = args[0] + } + switch vmType { + default: + vm, err = qemu.LoadVMByName(vmName) + } + if err != nil { + return err + } + confirmationMessage, remove, err := vm.Remove(vmName, machine.RemoveOptions{}) + if err != nil { + return err + } + + if !destoryOptions.Force { + // Warn user + fmt.Println(confirmationMessage) + reader := bufio.NewReader(os.Stdin) + fmt.Print("Are you sure you want to continue? [y/N] ") + answer, err := reader.ReadString('\n') + if err != nil { + return err + } + if strings.ToLower(answer)[0] != 'y' { + return nil + } + } + return remove() +} diff --git a/cmd/podman/machine/ssh.go b/cmd/podman/machine/ssh.go new file mode 100644 index 000000000..fc7c71992 --- /dev/null +++ b/cmd/podman/machine/ssh.go @@ -0,0 +1,84 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +package machine + +import ( + "github.com/containers/podman/v3/cmd/podman/registry" + "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/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + sshCmd = &cobra.Command{ + Use: "ssh [NAME] [COMMAND [ARG ...]]", + Short: "SSH into a virtual machine", + Long: "SSH into a virtual machine ", + RunE: ssh, + Example: `podman machine ssh myvm + podman machine ssh -e myvm echo hello`, + ValidArgsFunction: autocompleteMachineSSH, + } +) + +var ( + sshOpts machine.SSHOptions +) + +func init() { + sshCmd.Flags().SetInterspersed(false) + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: sshCmd, + Parent: machineCmd, + }) +} + +func ssh(cmd *cobra.Command, args []string) error { + var ( + err error + validVM bool + vm machine.VM + vmType string + ) + + // 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]) + } + } + } + // 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 { + default: + vm, err = qemu.LoadVMByName(vmName) + } + if err != nil { + return errors.Wrapf(err, "vm %s not found", args[0]) + } + return vm.SSH(vmName, sshOpts) +} diff --git a/cmd/podman/machine/start.go b/cmd/podman/machine/start.go new file mode 100644 index 000000000..959fa21d2 --- /dev/null +++ b/cmd/podman/machine/start.go @@ -0,0 +1,51 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +package machine + +import ( + "github.com/containers/podman/v3/cmd/podman/registry" + "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" +) + +var ( + startCmd = &cobra.Command{ + Use: "start [MACHINE]", + Short: "Start an existing machine", + Long: "Start an existing machine ", + RunE: start, + Args: cobra.MaximumNArgs(1), + Example: `podman machine start myvm`, + ValidArgsFunction: autocompleteMachine, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: startCmd, + Parent: machineCmd, + }) +} + +func start(cmd *cobra.Command, args []string) error { + var ( + err error + vm machine.VM + vmType string + ) + vmName := defaultMachineName + if len(args) > 0 && len(args[0]) > 0 { + vmName = args[0] + } + switch vmType { + default: + vm, err = qemu.LoadVMByName(vmName) + } + if err != nil { + return err + } + return vm.Start(vmName, machine.StartOptions{}) +} diff --git a/cmd/podman/machine/stop.go b/cmd/podman/machine/stop.go new file mode 100644 index 000000000..36b434d8e --- /dev/null +++ b/cmd/podman/machine/stop.go @@ -0,0 +1,52 @@ +// +build amd64,linux arm64,linux amd64,darwin arm64,darwin + +package machine + +import ( + "github.com/containers/podman/v3/cmd/podman/registry" + "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" +) + +var ( + stopCmd = &cobra.Command{ + Use: "stop [MACHINE]", + Short: "Stop an existing machine", + Long: "Stop an existing machine ", + RunE: stop, + Args: cobra.MaximumNArgs(1), + Example: `podman machine stop myvm`, + ValidArgsFunction: autocompleteMachine, + } +) + +func init() { + registry.Commands = append(registry.Commands, registry.CliCommand{ + Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, + Command: stopCmd, + Parent: machineCmd, + }) +} + +// TODO Name shouldnt be required, need to create a default vm +func stop(cmd *cobra.Command, args []string) error { + var ( + err error + vm machine.VM + vmType string + ) + vmName := defaultMachineName + if len(args) > 0 && len(args[0]) > 0 { + vmName = args[0] + } + switch vmType { + default: + vm, err = qemu.LoadVMByName(vmName) + } + if err != nil { + return err + } + return vm.Stop(vmName, machine.StopOptions{}) +} diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 561459c31..5219da26d 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -9,6 +9,7 @@ import ( _ "github.com/containers/podman/v3/cmd/podman/generate" _ "github.com/containers/podman/v3/cmd/podman/healthcheck" _ "github.com/containers/podman/v3/cmd/podman/images" + _ "github.com/containers/podman/v3/cmd/podman/machine" _ "github.com/containers/podman/v3/cmd/podman/manifest" _ "github.com/containers/podman/v3/cmd/podman/networks" _ "github.com/containers/podman/v3/cmd/podman/play" diff --git a/cmd/podman/root.go b/cmd/podman/root.go index 7722e35dd..2b77afbeb 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -3,7 +3,7 @@ package main import ( "fmt" "os" - "path" + "path/filepath" "runtime" "runtime/pprof" "strings" @@ -57,7 +57,7 @@ Options: var ( rootCmd = &cobra.Command{ - Use: path.Base(os.Args[0]) + " [options]", + Use: filepath.Base(os.Args[0]) + " [options]", Long: "Manage pods, containers and images", SilenceUsage: true, SilenceErrors: true, diff --git a/cmd/podman/system/service_abi.go b/cmd/podman/system/service_abi.go index 0e96e1fbb..9e8a9f9b4 100644 --- a/cmd/podman/system/service_abi.go +++ b/cmd/podman/system/service_abi.go @@ -24,16 +24,28 @@ func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entiti ) if opts.URI != "" { - fields := strings.Split(opts.URI, ":") - if len(fields) == 1 { - return errors.Errorf("%s is an invalid socket destination", opts.URI) + if os.Getenv("LISTEN_FDS") != "" { + // If it is activated by systemd, use the first LISTEN_FD (3) + // instead of opening the socket file. + f := os.NewFile(uintptr(3), "podman.sock") + l, err := net.FileListener(f) + if err != nil { + return err + } + listener = &l + } else { + fields := strings.Split(opts.URI, ":") + if len(fields) == 1 { + return errors.Errorf("%s is an invalid socket destination", opts.URI) + } + network := fields[0] + address := strings.Join(fields[1:], ":") + l, err := net.Listen(network, address) + if err != nil { + return errors.Wrapf(err, "unable to create socket") + } + listener = &l } - address := strings.Join(fields[1:], ":") - l, err := net.Listen(fields[0], address) - if err != nil { - return errors.Wrapf(err, "unable to create socket") - } - listener = &l } // Close stdin, so shortnames will not prompt |