Add --quiet and --no-info flags to podman machine start

Add quiet and no-info flags to podman machine start.
No-info suppresses helpful informational tips
Quiet suppresses machine start progress output, as well as informational
tips.

Signed-off-by: Ashley Cui <acui@redhat.com>
This commit is contained in:
Ashley Cui
2022-10-13 19:36:18 -04:00
parent c75b05996d
commit dd98e3cc64
8 changed files with 134 additions and 60 deletions

View File

@ -14,7 +14,7 @@ import (
var ( var (
startCmd = &cobra.Command{ startCmd = &cobra.Command{
Use: "start [MACHINE]", Use: "start [options] [MACHINE]",
Short: "Start an existing machine", Short: "Start an existing machine",
Long: "Start a managed virtual machine ", Long: "Start a managed virtual machine ",
PersistentPreRunE: rootlessOnly, PersistentPreRunE: rootlessOnly,
@ -23,6 +23,7 @@ var (
Example: `podman machine start myvm`, Example: `podman machine start myvm`,
ValidArgsFunction: autocompleteMachine, ValidArgsFunction: autocompleteMachine,
} }
startOpts = machine.StartOptions{}
) )
func init() { func init() {
@ -30,6 +31,13 @@ func init() {
Command: startCmd, Command: startCmd,
Parent: machineCmd, Parent: machineCmd,
}) })
flags := startCmd.Flags()
noInfoFlagName := "no-info"
flags.BoolVar(&startOpts.NoInfo, noInfoFlagName, false, "Suppress informational tips")
quietFlagName := "quiet"
flags.BoolVarP(&startOpts.Quiet, quietFlagName, "q", false, "Suppress machine starting status output")
} }
func start(_ *cobra.Command, args []string) error { func start(_ *cobra.Command, args []string) error {
@ -37,6 +45,9 @@ func start(_ *cobra.Command, args []string) error {
err error err error
vm machine.VM vm machine.VM
) )
startOpts.NoInfo = startOpts.Quiet || startOpts.NoInfo
vmName := defaultMachineName vmName := defaultMachineName
if len(args) > 0 && len(args[0]) > 0 { if len(args) > 0 && len(args[0]) > 0 {
vmName = args[0] vmName = args[0]
@ -58,8 +69,10 @@ func start(_ *cobra.Command, args []string) error {
} }
return fmt.Errorf("cannot start VM %s. VM %s is currently running or starting: %w", vmName, activeName, machine.ErrMultipleActiveVM) return fmt.Errorf("cannot start VM %s. VM %s is currently running or starting: %w", vmName, activeName, machine.ErrMultipleActiveVM)
} }
fmt.Printf("Starting machine %q\n", vmName) if !startOpts.Quiet {
if err := vm.Start(vmName, machine.StartOptions{}); err != nil { fmt.Printf("Starting machine %q\n", vmName)
}
if err := vm.Start(vmName, startOpts); err != nil {
return err return err
} }
fmt.Printf("Machine %q started successfully\n", vmName) fmt.Printf("Machine %q started successfully\n", vmName)

View File

@ -28,6 +28,14 @@ Only one Podman managed VM can be active at a time. If a VM is already running,
Print usage statement. Print usage statement.
#### **--no-info**
Suppress informational tips.
#### **--quiet**, **-q**
Suppress machine starting status output.
## EXAMPLES ## EXAMPLES
``` ```

View File

@ -114,7 +114,11 @@ type SSHOptions struct {
Username string Username string
Args []string Args []string
} }
type StartOptions struct{}
type StartOptions struct {
NoInfo bool
Quiet bool
}
type StopOptions struct{} type StopOptions struct{}

View File

@ -4,6 +4,8 @@ type startMachine struct {
/* /*
No command line args other than a machine vm name (also not required) No command line args other than a machine vm name (also not required)
*/ */
quiet bool
noInfo bool
} }
func (s startMachine) buildCmd(m *machineTestBuilder) []string { func (s startMachine) buildCmd(m *machineTestBuilder) []string {
@ -11,5 +13,21 @@ func (s startMachine) buildCmd(m *machineTestBuilder) []string {
if len(m.name) > 0 { if len(m.name) > 0 {
cmd = append(cmd, m.name) cmd = append(cmd, m.name)
} }
if s.quiet {
cmd = append(cmd, "--quiet")
}
if s.noInfo {
cmd = append(cmd, "--no-info")
}
return cmd return cmd
} }
func (s startMachine) withQuiet() startMachine {
s.quiet = true
return s
}
func (s startMachine) withNoInfo() startMachine {
s.noInfo = true
return s
}

View File

@ -33,5 +33,25 @@ var _ = Describe("podman machine start", func() {
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(ec).To(BeZero()) Expect(ec).To(BeZero())
Expect(info[0].State).To(Equal(machine.Running)) Expect(info[0].State).To(Equal(machine.Running))
stop := new(stopMachine)
stopSession, err := mb.setCmd(stop).run()
Expect(err).To(BeNil())
Expect(stopSession).To(Exit(0))
// suppress output
startSession, err = mb.setCmd(s.withNoInfo()).run()
Expect(err).To(BeNil())
Expect(startSession).To(Exit(0))
Expect(startSession.outputToString()).ToNot(ContainSubstring("API forwarding"))
stopSession, err = mb.setCmd(stop).run()
Expect(err).To(BeNil())
Expect(stopSession).To(Exit(0))
startSession, err = mb.setCmd(s.withQuiet()).run()
Expect(err).To(BeNil())
Expect(startSession).To(Exit(0))
Expect(len(startSession.outputToStringSlice())).To(Equal(1))
}) })
}) })

View File

@ -34,7 +34,6 @@ var _ = Describe("podman machine stop", func() {
Expect(session).To(Exit(0)) Expect(session).To(Exit(0))
stop := new(stopMachine) stop := new(stopMachine)
// Removing a running machine should fail
stopSession, err := mb.setCmd(stop).run() stopSession, err := mb.setCmd(stop).run()
Expect(err).To(BeNil()) Expect(err).To(BeNil())
Expect(stopSession).To(Exit(0)) Expect(stopSession).To(Exit(0))

View File

@ -467,7 +467,7 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) {
} }
// Start executes the qemu command line and forks it // Start executes the qemu command line and forks it
func (v *MachineVM) Start(name string, _ machine.StartOptions) error { func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
var ( var (
conn net.Conn conn net.Conn
err error err error
@ -613,7 +613,11 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
} }
} }
defer cmd.Process.Release() //nolint:errcheck defer cmd.Process.Release() //nolint:errcheck
fmt.Println("Waiting for VM ...")
if !opts.Quiet {
fmt.Println("Waiting for VM ...")
}
socketPath, err := getRuntimeDir() socketPath, err := getRuntimeDir()
if err != nil { if err != nil {
return err return err
@ -659,7 +663,9 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
} }
} }
for _, mount := range v.Mounts { for _, mount := range v.Mounts {
fmt.Printf("Mounting volume... %s:%s\n", mount.Source, mount.Target) if !opts.Quiet {
fmt.Printf("Mounting volume... %s:%s\n", mount.Source, mount.Target)
}
// create mountpoint directory if it doesn't exist // create mountpoint directory if it doesn't exist
// because / is immutable, we have to monkey around with permissions // because / is immutable, we have to monkey around with permissions
// if we dont mount in /home or /mnt // if we dont mount in /home or /mnt
@ -692,7 +698,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
} }
} }
v.waitAPIAndPrintInfo(forwardState, forwardSock) v.waitAPIAndPrintInfo(forwardState, forwardSock, opts.NoInfo)
return nil return nil
} }
@ -1439,7 +1445,7 @@ func waitAndPingAPI(sock string) {
} }
} }
func (v *MachineVM) waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string) { func (v *MachineVM) waitAPIAndPrintInfo(forwardState apiForwardingState, forwardSock string, noInfo bool) {
suffix := "" suffix := ""
if v.Name != machine.DefaultMachineName { if v.Name != machine.DefaultMachineName {
suffix = " " + v.Name suffix = " " + v.Name
@ -1467,38 +1473,41 @@ func (v *MachineVM) waitAPIAndPrintInfo(forwardState apiForwardingState, forward
} }
waitAndPingAPI(forwardSock) waitAndPingAPI(forwardSock)
if !v.Rootful {
fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
}
fmt.Printf("API forwarding listening on: %s\n", forwardSock) if !noInfo {
if forwardState == dockerGlobal { if !v.Rootful {
fmt.Printf("Docker API clients default to this address. You do not need to set DOCKER_HOST.\n\n") fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
} else { fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
stillString := "still " fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
switch forwardState { fmt.Printf("\n\tpodman machine set --rootful%s\n\n", suffix)
case notInstalled:
fmt.Printf("\nThe system helper service is not installed; the default Docker API socket\n")
fmt.Printf("address can't be used by podman. ")
if helper := findClaimHelper(); len(helper) > 0 {
fmt.Printf("If you would like to install it run the\nfollowing commands:\n")
fmt.Printf("\n\tsudo %s install\n", helper)
fmt.Printf("\tpodman machine stop%s; podman machine start%s\n\n", suffix, suffix)
}
case machineLocal:
fmt.Printf("\nAnother process was listening on the default Docker API socket address.\n")
case claimUnsupported:
fallthrough
default:
stillString = ""
} }
fmt.Printf("You can %sconnect Docker API clients by setting DOCKER_HOST using the\n", stillString) fmt.Printf("API forwarding listening on: %s\n", forwardSock)
fmt.Printf("following command in your terminal session:\n") if forwardState == dockerGlobal {
fmt.Printf("\n\texport DOCKER_HOST='unix://%s'\n\n", forwardSock) fmt.Printf("Docker API clients default to this address. You do not need to set DOCKER_HOST.\n\n")
} else {
stillString := "still "
switch forwardState {
case notInstalled:
fmt.Printf("\nThe system helper service is not installed; the default Docker API socket\n")
fmt.Printf("address can't be used by podman. ")
if helper := findClaimHelper(); len(helper) > 0 {
fmt.Printf("If you would like to install it run the\nfollowing commands:\n")
fmt.Printf("\n\tsudo %s install\n", helper)
fmt.Printf("\tpodman machine stop%s; podman machine start%s\n\n", suffix, suffix)
}
case machineLocal:
fmt.Printf("\nAnother process was listening on the default Docker API socket address.\n")
case claimUnsupported:
fallthrough
default:
stillString = ""
}
fmt.Printf("You can %sconnect Docker API clients by setting DOCKER_HOST using the\n", stillString)
fmt.Printf("following command in your terminal session:\n")
fmt.Printf("\n\texport DOCKER_HOST='unix://%s'\n\n", forwardSock)
}
} }
} }

View File

@ -577,7 +577,7 @@ func configureSystem(v *MachineVM, dist string) error {
return nil return nil
} }
func configureProxy(dist string, useProxy bool) error { func configureProxy(dist string, useProxy bool, quiet bool) error {
if !useProxy { if !useProxy {
_ = wslInvoke(dist, "sh", "-c", clearProxySettings) _ = wslInvoke(dist, "sh", "-c", clearProxySettings)
return nil return nil
@ -598,8 +598,9 @@ func configureProxy(dist string, useProxy bool) error {
if exitErr, isExit := err.(*exec.ExitError); isExit && exitErr.ExitCode() != 42 { if exitErr, isExit := err.(*exec.ExitError); isExit && exitErr.ExitCode() != 42 {
return fmt.Errorf("%v: %w", failMessage, err) return fmt.Errorf("%v: %w", failMessage, err)
} }
if !quiet {
fmt.Println("Installing proxy support") fmt.Println("Installing proxy support")
}
_ = wslPipe(proxyConfigSetup, dist, "sh", "-c", _ = wslPipe(proxyConfigSetup, dist, "sh", "-c",
"cat > /usr/local/bin/proxyinit; chmod 755 /usr/local/bin/proxyinit") "cat > /usr/local/bin/proxyinit; chmod 755 /usr/local/bin/proxyinit")
@ -981,14 +982,14 @@ func (v *MachineVM) Set(_ string, opts machine.SetOptions) ([]error, error) {
return setErrors, v.writeConfig() return setErrors, v.writeConfig()
} }
func (v *MachineVM) Start(name string, _ machine.StartOptions) error { func (v *MachineVM) Start(name string, opts machine.StartOptions) error {
if v.isRunning() { if v.isRunning() {
return fmt.Errorf("%q is already running", name) return fmt.Errorf("%q is already running", name)
} }
dist := toDist(name) dist := toDist(name)
useProxy := setupWslProxyEnv() useProxy := setupWslProxyEnv()
if err := configureProxy(dist, useProxy); err != nil { if err := configureProxy(dist, useProxy, opts.Quiet); err != nil {
return err return err
} }
@ -997,7 +998,7 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
return fmt.Errorf("the WSL bootstrap script failed: %w", err) return fmt.Errorf("the WSL bootstrap script failed: %w", err)
} }
if !v.Rootful { if !v.Rootful && !opts.NoInfo {
fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n") fmt.Printf("\nThis machine is currently configured in rootless mode. If your containers\n")
fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n") fmt.Printf("require root permissions (e.g. ports < 1024), or if you run into compatibility\n")
fmt.Printf("issues with non-podman clients, you can switch using the following command: \n") fmt.Printf("issues with non-podman clients, you can switch using the following command: \n")
@ -1010,22 +1011,24 @@ func (v *MachineVM) Start(name string, _ machine.StartOptions) error {
} }
globalName, pipeName, err := launchWinProxy(v) globalName, pipeName, err := launchWinProxy(v)
if err != nil { if !opts.NoInfo {
fmt.Fprintln(os.Stderr, "API forwarding for Docker API clients is not available due to the following startup failures.") if err != nil {
fmt.Fprintf(os.Stderr, "\t%s\n", err.Error()) fmt.Fprintln(os.Stderr, "API forwarding for Docker API clients is not available due to the following startup failures.")
fmt.Fprintln(os.Stderr, "\nPodman clients are still able to connect.") fmt.Fprintf(os.Stderr, "\t%s\n", err.Error())
} else { fmt.Fprintln(os.Stderr, "\nPodman clients are still able to connect.")
fmt.Printf("API forwarding listening on: %s\n", pipeName)
if globalName {
fmt.Printf("\nDocker API clients default to this address. You do not need to set DOCKER_HOST.\n")
} else { } else {
fmt.Printf("\nAnother process was listening on the default Docker API pipe address.\n") fmt.Printf("API forwarding listening on: %s\n", pipeName)
fmt.Printf("You can still connect Docker API clients by setting DOCKER HOST using the\n") if globalName {
fmt.Printf("following powershell command in your terminal session:\n") fmt.Printf("\nDocker API clients default to this address. You do not need to set DOCKER_HOST.\n")
fmt.Printf("\n\t$Env:DOCKER_HOST = '%s'\n", pipeName) } else {
fmt.Printf("\nOr in a classic CMD prompt:\n") fmt.Printf("\nAnother process was listening on the default Docker API pipe address.\n")
fmt.Printf("\n\tset DOCKER_HOST = '%s'\n", pipeName) fmt.Printf("You can still connect Docker API clients by setting DOCKER HOST using the\n")
fmt.Printf("\nAlternatively terminate the other process and restart podman machine.\n") fmt.Printf("following powershell command in your terminal session:\n")
fmt.Printf("\n\t$Env:DOCKER_HOST = '%s'\n", pipeName)
fmt.Printf("\nOr in a classic CMD prompt:\n")
fmt.Printf("\n\tset DOCKER_HOST = '%s'\n", pipeName)
fmt.Printf("\nAlternatively terminate the other process and restart podman machine.\n")
}
} }
} }