pkg/machine/wsl: wrap command errors

First of some commands ignored cmd.Wait() error which means it was
impossible to notice any command errors. And others only returned
the wait error as it which when a command fails is just
`exit status <code>` which is not helpful at all.

This commit should add proper error wrapping with stderr to get useful
strings back hopefully.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2024-06-17 14:58:52 +02:00
parent f269485295
commit bd906cb314
3 changed files with 61 additions and 14 deletions

View File

@ -4,6 +4,7 @@ package wsl
import ( import (
"bufio" "bufio"
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -550,7 +551,10 @@ func runCmdPassThrough(name string, arg ...string) error {
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() if err := cmd.Run(); err != nil {
return fmt.Errorf("command %s %v failed: %w", name, arg, err)
}
return nil
} }
func runCmdPassThroughTee(out io.Writer, name string, arg ...string) error { func runCmdPassThroughTee(out io.Writer, name string, arg ...string) error {
@ -562,7 +566,10 @@ func runCmdPassThroughTee(out io.Writer, name string, arg ...string) error {
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = io.MultiWriter(os.Stdout, out) cmd.Stdout = io.MultiWriter(os.Stdout, out)
cmd.Stderr = io.MultiWriter(os.Stderr, out) cmd.Stderr = io.MultiWriter(os.Stderr, out)
return cmd.Run() if err := cmd.Run(); err != nil {
return fmt.Errorf("command %s %v failed: %w", name, arg, err)
}
return nil
} }
func pipeCmdPassThrough(name string, input string, arg ...string) error { func pipeCmdPassThrough(name string, input string, arg ...string) error {
@ -571,7 +578,10 @@ func pipeCmdPassThrough(name string, input string, arg ...string) error {
cmd.Stdin = strings.NewReader(input) cmd.Stdin = strings.NewReader(input)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() if err := cmd.Run(); err != nil {
return fmt.Errorf("command %s %v failed: %w", name, arg, err)
}
return nil
} }
func setupWslProxyEnv() (hasProxy bool) { func setupWslProxyEnv() (hasProxy bool) {
@ -638,8 +648,10 @@ func getAllWSLDistros(running bool) (map[string]struct{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
if err = cmd.Start(); err != nil { if err = cmd.Start(); err != nil {
return nil, err return nil, fmt.Errorf("failed to start command %s %v: %w", cmd.Path, args, err)
} }
all := make(map[string]struct{}) all := make(map[string]struct{})
@ -651,7 +663,10 @@ func getAllWSLDistros(running bool) (map[string]struct{}, error) {
} }
} }
_ = cmd.Wait() err = cmd.Wait()
if err != nil {
return nil, fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, args, err, strings.TrimSpace(stderr.String()))
}
return all, nil return all, nil
} }
@ -663,6 +678,8 @@ func isSystemdRunning(dist string) (bool, error) {
if err != nil { if err != nil {
return false, err return false, err
} }
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
if err = cmd.Start(); err != nil { if err = cmd.Start(); err != nil {
return false, err return false, err
} }
@ -676,19 +693,30 @@ func isSystemdRunning(dist string) (bool, error) {
} }
} }
_ = cmd.Wait() err = cmd.Wait()
if err != nil {
return false, fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, cmd.Args, err, strings.TrimSpace(stderr.String()))
}
return result, nil return result, nil
} }
func terminateDist(dist string) error { func terminateDist(dist string) error {
cmd := exec.Command(wutil.FindWSL(), "--terminate", dist) cmd := exec.Command(wutil.FindWSL(), "--terminate", dist)
return cmd.Run() out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, cmd.Args, err, strings.TrimSpace(string(out)))
}
return nil
} }
func unregisterDist(dist string) error { func unregisterDist(dist string) error {
cmd := exec.Command(wutil.FindWSL(), "--unregister", dist) cmd := exec.Command(wutil.FindWSL(), "--unregister", dist)
return cmd.Run() out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, cmd.Args, err, strings.TrimSpace(string(out)))
}
return nil
} }
func isRunning(name string) (bool, error) { func isRunning(name string) (bool, error) {
@ -736,6 +764,8 @@ func getCPUs(name string) (uint64, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
if err = cmd.Start(); err != nil { if err = cmd.Start(); err != nil {
return 0, err return 0, err
} }
@ -744,7 +774,10 @@ func getCPUs(name string) (uint64, error) {
for scanner.Scan() { for scanner.Scan() {
result = scanner.Text() result = scanner.Text()
} }
_ = cmd.Wait() err = cmd.Wait()
if err != nil {
return 0, fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, cmd.Args, err, strings.TrimSpace(strings.TrimSpace(stderr.String())))
}
ret, err := strconv.Atoi(result) ret, err := strconv.Atoi(result)
return uint64(ret), err return uint64(ret), err
@ -761,6 +794,8 @@ func getMem(name string) (strongunits.MiB, error) {
if err != nil { if err != nil {
return 0, err return 0, err
} }
stderr := &bytes.Buffer{}
cmd.Stderr = stderr
if err = cmd.Start(); err != nil { if err = cmd.Start(); err != nil {
return 0, err return 0, err
} }
@ -783,7 +818,10 @@ func getMem(name string) (strongunits.MiB, error) {
break break
} }
} }
_ = cmd.Wait() err = cmd.Wait()
if err != nil {
return 0, fmt.Errorf("command %s %v failed: %w (%s)", cmd.Path, cmd.Args, err, strings.TrimSpace(stderr.String()))
}
return strongunits.MiB(total - available), err return strongunits.MiB(total - available), err
} }

View File

@ -3,6 +3,7 @@
package wsl package wsl
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@ -110,7 +111,7 @@ func (w WSLStubber) Remove(mc *vmconfigs.MachineConfig) ([]string, func() error,
// of the vm // of the vm
wslRemoveFunc := func() error { wslRemoveFunc := func() error {
if err := runCmdPassThrough(wutil.FindWSL(), "--unregister", env.WithPodmanPrefix(mc.Name)); err != nil { if err := runCmdPassThrough(wutil.FindWSL(), "--unregister", env.WithPodmanPrefix(mc.Name)); err != nil {
logrus.Error(err) return err
} }
return nil return nil
} }
@ -251,17 +252,21 @@ func (w WSLStubber) StopVM(mc *vmconfigs.MachineConfig, hardStop bool) error {
cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "sh") cmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "sh")
cmd.Stdin = strings.NewReader(waitTerm) cmd.Stdin = strings.NewReader(waitTerm)
out := &bytes.Buffer{}
cmd.Stderr = out
cmd.Stdout = out
if err = cmd.Start(); err != nil { if err = cmd.Start(); err != nil {
return fmt.Errorf("executing wait command: %w", err) return fmt.Errorf("executing wait command: %w", err)
} }
exitCmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "/usr/local/bin/enterns", "systemctl", "exit", "0") exitCmd := exec.Command(wutil.FindWSL(), "-u", "root", "-d", dist, "/usr/local/bin/enterns", "systemctl", "exit", "0")
if err = exitCmd.Run(); err != nil { if err = exitCmd.Run(); err != nil {
return fmt.Errorf("stopping sysd: %w", err) return fmt.Errorf("stopping systemd: %w", err)
} }
if err = cmd.Wait(); err != nil { if err = cmd.Wait(); err != nil {
return err return fmt.Errorf("wait for systemd to exit: %w (%s)", err, strings.TrimSpace(out.String()))
} }
return terminateDist(dist) return terminateDist(dist)

View File

@ -4,6 +4,7 @@ package wutil
import ( import (
"bufio" "bufio"
"fmt"
"io" "io"
"os" "os"
"os/exec" "os/exec"
@ -74,7 +75,10 @@ func SilentExec(command string, args ...string) error {
cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000} cmd.SysProcAttr = &syscall.SysProcAttr{CreationFlags: 0x08000000}
cmd.Stdout = nil cmd.Stdout = nil
cmd.Stderr = nil cmd.Stderr = nil
return cmd.Run() if err := cmd.Run(); err != nil {
return fmt.Errorf("command %s %v failed: %w", command, args, err)
}
return nil
} }
func SilentExecCmd(command string, args ...string) *exec.Cmd { func SilentExecCmd(command string, args ...string) *exec.Cmd {