From 99f68898c0f1c4564cebd6a3ee18418c74684403 Mon Sep 17 00:00:00 2001
From: Brent Baude <bbaude@redhat.com>
Date: Wed, 22 Jun 2022 14:17:30 -0500
Subject: [PATCH] reveal machine error, ignore false state

This PR covers two edge cases discovered by fiddling with machine
manually.  It is possible (like after a manual cleanup of a machine)
that a leftover qemu socket file can indicate the prescense of a machine
running.

Also, reveal the error of a Exec.Command by wrapping the generic error
around what was in stderr.

[NO NEW TESTS NEEDED]

Signed-off-by: Brent Baude <bbaude@redhat.com>
---
 pkg/machine/keys.go         | 21 +++++++++++++++++++--
 pkg/machine/qemu/machine.go |  7 ++++++-
 2 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/pkg/machine/keys.go b/pkg/machine/keys.go
index 45d9801cc4..463271427a 100644
--- a/pkg/machine/keys.go
+++ b/pkg/machine/keys.go
@@ -4,14 +4,15 @@
 package machine
 
 import (
-	"errors"
 	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"strings"
 
+	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
@@ -51,7 +52,23 @@ func CreateSSHKeysPrefix(dir string, file string, passThru bool, skipExisting bo
 // generatekeys creates an ed25519 set of keys
 func generatekeys(writeLocation string) error {
 	args := append(append([]string{}, sshCommand[1:]...), writeLocation)
-	return exec.Command(sshCommand[0], args...).Run()
+	cmd := exec.Command(sshCommand[0], args...)
+	stdErr, err := cmd.StderrPipe()
+	if err != nil {
+		return err
+	}
+	if err := cmd.Start(); err != nil {
+		return err
+	}
+	waitErr := cmd.Wait()
+	if waitErr == nil {
+		return nil
+	}
+	errMsg, err := io.ReadAll(stdErr)
+	if err != nil {
+		return fmt.Errorf("key generation failed, unable to read from stderr: %w", waitErr)
+	}
+	return fmt.Errorf("failed to generate keys: %s: %w", string(errMsg), waitErr)
 }
 
 // generatekeys creates an ed25519 set of keys
diff --git a/pkg/machine/qemu/machine.go b/pkg/machine/qemu/machine.go
index 5094345eac..f7ef52573b 100644
--- a/pkg/machine/qemu/machine.go
+++ b/pkg/machine/qemu/machine.go
@@ -930,7 +930,12 @@ func (v *MachineVM) State(bypass bool) (machine.Status, error) {
 	}
 	monitor, err := qmp.NewSocketMonitor(v.QMPMonitor.Network, v.QMPMonitor.Address.GetPath(), v.QMPMonitor.Timeout)
 	if err != nil {
-		// FIXME: this error should probably be returned
+		// If an improper cleanup was done and the socketmonitor was not deleted,
+		// it can appear as though the machine state is not stopped.  Check for ECONNREFUSED
+		// almost assures us that the vm is stopped.
+		if errors.Is(err, syscall.ECONNREFUSED) {
+			return machine.Stopped, nil
+		}
 		return "", err
 	}
 	if err := monitor.Connect(); err != nil {