Repository: code-ready/crc
Pull request #2554 (2021-07-09 09:15:18)

3 small changes
3 commits I don't want to keep locally for too long.

The only user-visible changes are:
- slightly different error message for some daemon startup failures
- `capture.pcap` is no longer always created when the daemon is started with `--log-level debug`, but only when `CRC_DAEMON_PCAP_FILE` is set in the environment

openshift-ci[bot]: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2554#" title="Author self-approved">cfergeau</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=code-ready%2Fcrc).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/code-ready/crc/blob/master/OWNERS)~~ [cfergeau]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
openshift-ci[bot]: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2554#" title="Author self-approved">cfergeau</a>*, *<a href="https://github.com/code-ready/crc/pull/2554#pullrequestreview-703725331" title="Approved">praveenkumar</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=code-ready%2Fcrc).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/code-ready/crc/blob/master/OWNERS)~~ [cfergeau,praveenkumar]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/Makefile b/Makefile
index 5b13a99da..10fa44926 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 SHELL := /bin/bash
 
-BUNDLE_VERSION ?= 4.7.18
+BUNDLE_VERSION ?= 4.8.0
 BUNDLE_EXTENSION = crcbundle
 CRC_VERSION = 1.29.1
 COMMIT_SHA=$(shell git rev-parse --short HEAD)
diff --git a/centos_ci.sh b/centos_ci.sh
index 5104941ca..21d29dd92 100644
--- a/centos_ci.sh
+++ b/centos_ci.sh
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # bundle location
-BUNDLE_VERSION=4.7.18
+BUNDLE_VERSION=4.8.0
 BUNDLE=crc_libvirt_$BUNDLE_VERSION.crcbundle
 GO_VERSION=1.15.13
 
diff --git a/cmd/crc/cmd/console.go b/cmd/crc/cmd/console.go
index 83e6f5c31..961a8251b 100644
--- a/cmd/crc/cmd/console.go
+++ b/cmd/crc/cmd/console.go
@@ -8,8 +8,8 @@ import (
 
 	crcErrors "github.com/code-ready/crc/pkg/crc/errors"
 	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
-	"github.com/code-ready/machine/libmachine/state"
 	"github.com/pkg/browser"
 	"github.com/spf13/cobra"
 )
diff --git a/cmd/crc/cmd/daemon.go b/cmd/crc/cmd/daemon.go
index f30de4d7b..49be1c41c 100644
--- a/cmd/crc/cmd/daemon.go
+++ b/cmd/crc/cmd/daemon.go
@@ -2,16 +2,13 @@ package cmd
 
 import (
 	"encoding/json"
-	"errors"
 	"fmt"
 	"io/ioutil"
 	"net"
 	"net/http"
 	"os"
 	"os/signal"
-	"path/filepath"
 	"regexp"
-	"runtime"
 	"syscall"
 	"time"
 
@@ -26,6 +23,7 @@ import (
 	"github.com/code-ready/gvisor-tap-vsock/pkg/virtualnetwork"
 	"github.com/docker/go-units"
 	"github.com/gorilla/handlers"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"k8s.io/client-go/util/exec"
@@ -59,7 +57,7 @@ var daemonCmd = &cobra.Command{
 
 		virtualNetworkConfig := types.Configuration{
 			Debug:             false, // never log packets
-			CaptureFile:       captureFile(),
+			CaptureFile:       os.Getenv("CRC_DAEMON_PCAP_FILE"),
 			MTU:               4000, // Large packets slightly improve the performance. Less small packets.
 			Subnet:            "192.168.127.0/24",
 			GatewayIP:         constants.VSockGateway,
@@ -114,13 +112,6 @@ var daemonCmd = &cobra.Command{
 	},
 }
 
-func captureFile() string {
-	if !isDebugLog() {
-		return ""
-	}
-	return filepath.Join(constants.CrcBaseDir, "capture.pcap")
-}
-
 func run(configuration *types.Configuration) error {
 	vsockListener, err := vsockListener()
 	if err != nil {
@@ -147,7 +138,7 @@ func run(configuration *types.Configuration) error {
 		mux.Handle("/network/", http.StripPrefix("/network", vn.Mux()))
 		mux.Handle("/api/", http.StripPrefix("/api", api.NewMux(config, newMachine(), logging.Memory, segmentClient)))
 		if err := http.Serve(listener, handlers.LoggingHandler(os.Stderr, mux)); err != nil {
-			errCh <- err
+			errCh <- errors.Wrap(err, "api http.Serve failed")
 		}
 	}()
 
@@ -158,7 +149,7 @@ func run(configuration *types.Configuration) error {
 	go func() {
 		mux := gatewayAPIMux()
 		if err := http.Serve(ln, handlers.LoggingHandler(os.Stderr, mux)); err != nil {
-			errCh <- err
+			errCh <- errors.Wrap(err, "gateway http.Serve failed")
 		}
 	}()
 
@@ -166,7 +157,7 @@ func run(configuration *types.Configuration) error {
 		mux := http.NewServeMux()
 		mux.Handle(types.ConnectPath, vn.Mux())
 		if err := http.Serve(vsockListener, mux); err != nil {
-			errCh <- err
+			errCh <- errors.Wrap(err, "virtualnetwork http.Serve failed")
 		}
 	}()
 
@@ -179,12 +170,6 @@ func run(configuration *types.Configuration) error {
 		}()
 	}
 
-	go func() {
-		if err := runBinaryAPI(); err != nil {
-			errCh <- err
-		}
-	}()
-
 	c := make(chan os.Signal, 1)
 
 	if watchdog {
@@ -239,16 +224,3 @@ func acceptJSONStringArray(w http.ResponseWriter, r *http.Request, fun func(host
 	}
 	w.WriteHeader(http.StatusOK)
 }
-
-func runBinaryAPI() error {
-	if runtime.GOOS != "windows" { // only Windows tray requires the binary protocol
-		return nil
-	}
-	// Remove if an old socket is present
-	os.Remove(constants.DaemonSocketPath)
-	apiServer, err := api.CreateServer(constants.DaemonSocketPath, config, newMachine(), logging.Memory, segmentClient)
-	if err != nil {
-		return err
-	}
-	return apiServer.Serve()
-}
diff --git a/cmd/crc/cmd/status.go b/cmd/crc/cmd/status.go
index a87c362c7..ab4678da3 100644
--- a/cmd/crc/cmd/status.go
+++ b/cmd/crc/cmd/status.go
@@ -68,7 +68,7 @@ func getStatus(client machine.Client, cacheDir string) *status {
 
 	return &status{
 		Success:          true,
-		CrcStatus:        clusterStatus.CrcStatus.String(),
+		CrcStatus:        string(clusterStatus.CrcStatus),
 		OpenShiftStatus:  clusterStatus.OpenshiftStatus,
 		OpenShiftVersion: clusterStatus.OpenshiftVersion,
 		DiskUsage:        clusterStatus.DiskUse,
diff --git a/cmd/crc/cmd/stop.go b/cmd/crc/cmd/stop.go
index e853ffd68..38786936c 100644
--- a/cmd/crc/cmd/stop.go
+++ b/cmd/crc/cmd/stop.go
@@ -8,7 +8,7 @@ import (
 	crcErrors "github.com/code-ready/crc/pkg/crc/errors"
 	"github.com/code-ready/crc/pkg/crc/input"
 	"github.com/code-ready/crc/pkg/crc/machine"
-	"github.com/code-ready/machine/libmachine/state"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/spf13/cobra"
 )
 
diff --git a/pkg/crc/api/adapter.go b/pkg/crc/api/adapter.go
index 5d3ed231f..75584fd57 100644
--- a/pkg/crc/api/adapter.go
+++ b/pkg/crc/api/adapter.go
@@ -62,7 +62,7 @@ func (a *Adapter) Start(ctx context.Context, startConfig types.StartConfig) clie
 	}
 	return client.StartResult{
 		Success:        true,
-		Status:         res.Status.String(),
+		Status:         string(res.Status),
 		ClusterConfig:  res.ClusterConfig,
 		KubeletStarted: res.KubeletStarted,
 	}
@@ -78,7 +78,7 @@ func (a *Adapter) Status() client.ClusterStatusResult {
 		}
 	}
 	return client.ClusterStatusResult{
-		CrcStatus:        res.CrcStatus.String(),
+		CrcStatus:        string(res.CrcStatus),
 		OpenshiftStatus:  string(res.OpenshiftStatus),
 		OpenshiftVersion: res.OpenshiftVersion,
 		DiskUse:          res.DiskUse,
diff --git a/pkg/crc/api/api.go b/pkg/crc/api/api.go
deleted file mode 100644
index 575f0104d..000000000
--- a/pkg/crc/api/api.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package api
-
-import (
-	"bytes"
-	"encoding/json"
-	"fmt"
-	"net"
-
-	crcConfig "github.com/code-ready/crc/pkg/crc/config"
-	"github.com/code-ready/crc/pkg/crc/logging"
-	"github.com/code-ready/crc/pkg/crc/machine"
-)
-
-func CreateServer(socketPath string, config crcConfig.Storage, machine machine.Client, logger Logger, telemetry Telemetry) (Server, error) {
-	listener, err := net.Listen("unix", socketPath)
-	if err != nil {
-		logging.Error("Failed to create socket: ", err.Error())
-		return Server{}, err
-	}
-	return createServerWithListener(listener, config, machine, logger, telemetry)
-}
-
-func createServerWithListener(listener net.Listener, config crcConfig.Storage, machine machine.Client, logger Logger, telemetry Telemetry) (Server, error) {
-	apiServer := Server{
-		listener: listener,
-		handler:  NewHandler(config, machine, logger, telemetry),
-	}
-	return apiServer, nil
-}
-
-func (api Server) Serve() error {
-	for {
-		conn, err := api.listener.Accept()
-		if err != nil {
-			if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
-				logging.Errorf("accept temporary error: %v", err)
-				continue
-			}
-			return err
-		}
-		api.handleConnections(conn) // handle version, status, webconsole, etc. requests
-	}
-}
-
-func (api Server) handleRequest(req commandRequest, conn net.Conn) {
-	defer conn.Close()
-	var result string
-
-	switch req.Command {
-	case "start":
-		result = api.handler.Start(req.Args)
-	case "stop":
-		result = api.handler.Stop()
-	case "poweroff":
-		result = api.handler.PowerOff()
-	case "status":
-		result = api.handler.Status()
-	case "delete":
-		result = api.handler.Delete()
-	case "version":
-		result = api.handler.GetVersion()
-	case "setconfig":
-		result = api.handler.SetConfig(req.Args)
-	case "unsetconfig":
-		result = api.handler.UnsetConfig(req.Args)
-	case "getconfig":
-		result = api.handler.GetConfig(req.Args)
-	case "webconsoleurl":
-		result = api.handler.GetWebconsoleInfo()
-	case "logs":
-		result = api.handler.Logs()
-	case "telemetry":
-		result = api.handler.UploadTelemetry(req.Args)
-	default:
-		result = encodeErrorToJSON(fmt.Sprintf("Unknown command supplied: %s", req.Command))
-	}
-	writeStringToSocket(conn, result)
-}
-
-func (api Server) handleConnections(conn net.Conn) {
-	inBuffer := make([]byte, 1024)
-	var req commandRequest
-	numBytes, err := conn.Read(inBuffer)
-	if err != nil || numBytes == 0 || numBytes == cap(inBuffer) {
-		logging.Error("Error reading from socket")
-		return
-	}
-	logging.Debugf("rpc:%p: Received request: %s", conn, string(inBuffer[0:numBytes]))
-	err = json.Unmarshal(inBuffer[0:numBytes], &req)
-	if err != nil {
-		logging.Error("Error decoding request: ", err.Error())
-		return
-	}
-	go api.handleRequest(req, conn)
-}
-
-func writeStringToSocket(socket net.Conn, msg string) {
-	logging.Debugf("rpc:%p: Sending answer: %s", socket, msg)
-
-	var outBuffer bytes.Buffer
-	_, err := outBuffer.WriteString(msg)
-	if err != nil {
-		logging.Error("Failed writing string to buffer", err.Error())
-		return
-	}
-	_, err = socket.Write(outBuffer.Bytes())
-	if err != nil {
-		logging.Error("Failed writing string to socket", err.Error())
-		return
-	}
-}
diff --git a/pkg/crc/api/types.go b/pkg/crc/api/types.go
index c5b446966..501a96d34 100644
--- a/pkg/crc/api/types.go
+++ b/pkg/crc/api/types.go
@@ -1,21 +1,5 @@
 package api
 
-import (
-	"encoding/json"
-	"net"
-)
-
-type Server struct {
-	handler  *Handler
-	listener net.Listener
-}
-
-// commandRequest struct is used to decode the json request from tray
-type commandRequest struct {
-	Command string          `json:"command"`
-	Args    json.RawMessage `json:"args,omitempty"`
-}
-
 type loggerResult struct {
 	Success  bool
 	Messages []string
diff --git a/pkg/crc/cluster/cluster.go b/pkg/crc/cluster/cluster.go
index f7483cd59..8614515a2 100644
--- a/pkg/crc/cluster/cluster.go
+++ b/pkg/crc/cluster/cluster.go
@@ -192,18 +192,51 @@ func RemovePullSecretFromCluster(ocConfig oc.Config, sshRunner *ssh.Runner) erro
 		return fmt.Errorf("Failed to remove Pull secret %w: %s", err, stderr)
 	}
 
-	cmdArgs = []string{"delete", "machineconfigs", "--all"}
-	_, stderr, err = ocConfig.RunOcCommand(cmdArgs...)
+	return nil
+}
+
+func RemoveOldRenderedMachineConfig(ocConfig oc.Config) error {
+	// This block (#L179-183) should be removed as soon as we start shipping with 4.8 bundle.
+	// This check is only make sure if there is any machineconfig resource or not because
+	// in 4.7 we disabled mco and also deleted all the machineconfig/machineconfig-pools.
+	// For 4.8 we don't disable mco and it does contain the machineconfigs.
+	stdout, stderr, err := ocConfig.RunOcCommand("get mc --sort-by=.metadata.creationTimestamp --no-headers -oname")
 	if err != nil {
-		return fmt.Errorf("Failed to remove machineconfigs %w: %s", err, stderr)
+		return fmt.Errorf("failed to get machineconfig resource %w: %s", err, stderr)
+	}
+	sortedMachineConfigsWithTime := strings.Split(stdout, "\n")
+	if len(sortedMachineConfigsWithTime) == 0 {
+		return nil
 	}
 
-	cmdArgs = []string{"delete", "machineconfigpools", "--all"}
-	_, stderr, err = ocConfig.RunOcCommand(cmdArgs...)
-	if err != nil {
-		return fmt.Errorf("Failed to remove machineconfigpools %w: %s", err, stderr)
+	// We need to make sure only old machine configs are deleted not the new one.
+	var (
+		renderedMaster []string
+		renderedWorker []string
+	)
+	for _, mc := range sortedMachineConfigsWithTime {
+		if strings.HasPrefix(mc, "rendered-master") {
+			renderedMaster = append(renderedMaster, mc)
+		}
+		if strings.HasPrefix(mc, "rendered-worker") {
+			renderedWorker = append(renderedWorker, mc)
+		}
+	}
+
+	var deleteRenderedMachineConfig string
+	if len(renderedMaster) > 0 {
+		deleteRenderedMachineConfig = strings.Join(renderedMaster[:len(renderedMaster)-1], " ")
+	}
+	if len(renderedWorker) > 0 {
+		deleteRenderedMachineConfig = fmt.Sprintf("%s %s", deleteRenderedMachineConfig, strings.Join(renderedWorker[:len(renderedWorker)-1], " "))
 	}
 
+	if deleteRenderedMachineConfig != "" {
+		_, stderr, err = ocConfig.RunOcCommand(fmt.Sprintf("delete %s", deleteRenderedMachineConfig))
+		if err != nil {
+			return fmt.Errorf("Failed to remove machineconfigpools %w: %s", err, stderr)
+		}
+	}
 	return nil
 }
 
diff --git a/pkg/crc/constants/constants.go b/pkg/crc/constants/constants.go
index 4cd5e3483..7ede5ebd3 100644
--- a/pkg/crc/constants/constants.go
+++ b/pkg/crc/constants/constants.go
@@ -128,20 +128,9 @@ func BinDir() string {
 
 // GetHomeDir returns the home directory for the current user
 func GetHomeDir() string {
-	if runtime.GOOS == "windows" {
-		if homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"); len(homeDrive) > 0 && len(homePath) > 0 {
-			homeDir := filepath.Join(homeDrive, homePath)
-			if _, err := os.Stat(homeDir); err == nil {
-				return homeDir
-			}
-		}
-		if userProfile := os.Getenv("USERPROFILE"); len(userProfile) > 0 {
-			if _, err := os.Stat(userProfile); err == nil {
-				return userProfile
-			}
-		}
-	}
-	return os.Getenv("HOME")
+	homeDir, _ := os.UserHomeDir()
+
+	return homeDir
 }
 
 // EnsureBaseDirectoryExists create the ~/.crc directory if it is not present
diff --git a/pkg/crc/machine/client.go b/pkg/crc/machine/client.go
index 8a3b2fdc5..77231a52a 100644
--- a/pkg/crc/machine/client.go
+++ b/pkg/crc/machine/client.go
@@ -5,9 +5,9 @@ import (
 	"time"
 
 	crcConfig "github.com/code-ready/crc/pkg/crc/config"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
-	"github.com/code-ready/machine/libmachine/state"
 	"github.com/kofalt/go-memoize"
 )
 
diff --git a/pkg/crc/machine/console.go b/pkg/crc/machine/console.go
index 1de905335..84ff3ed86 100644
--- a/pkg/crc/machine/console.go
+++ b/pkg/crc/machine/console.go
@@ -1,6 +1,7 @@
 package machine
 
 import (
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/pkg/errors"
 )
@@ -34,6 +35,6 @@ func (client *client) GetConsoleURL() (*types.ConsoleResult, error) {
 
 	return &types.ConsoleResult{
 		ClusterConfig: *clusterConfig,
-		State:         vmState,
+		State:         state.FromMachine(vmState),
 	}, nil
 }
diff --git a/pkg/crc/machine/fakemachine/client.go b/pkg/crc/machine/fakemachine/client.go
index ac0fc2a67..f75bc24fb 100644
--- a/pkg/crc/machine/fakemachine/client.go
+++ b/pkg/crc/machine/fakemachine/client.go
@@ -4,9 +4,9 @@ import (
 	"context"
 	"errors"
 
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
-	"github.com/code-ready/machine/libmachine/state"
 )
 
 func NewClient() *Client {
diff --git a/pkg/crc/machine/generate_bundle.go b/pkg/crc/machine/generate_bundle.go
index 2c17946fe..7347b2f1b 100644
--- a/pkg/crc/machine/generate_bundle.go
+++ b/pkg/crc/machine/generate_bundle.go
@@ -1,7 +1,6 @@
 package machine
 
 import (
-	"fmt"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -25,21 +24,29 @@ func (client *client) GenerateBundle(forceStop bool) error {
 
 	ocConfig := oc.UseOCWithSSH(sshRunner)
 	if err := cluster.RemovePullSecretFromCluster(ocConfig, sshRunner); err != nil {
-		return errors.Wrap(err, "Error loading bundle metadata")
+		return errors.Wrap(err, "Error removing pull secret from cluster")
+	}
+
+	if err := cluster.RemoveOldRenderedMachineConfig(ocConfig); err != nil {
+		return errors.Wrap(err, "Error removing old rendered machine configs")
 	}
 
 	// Stop the cluster
-	currentState, err := client.Stop()
-	if err != nil {
+	if _, err := client.Stop(); err != nil {
 		if forceStop {
 			if err := client.PowerOff(); err != nil {
 				return err
 			}
+		} else {
+			return err
 		}
+	}
+	running, err := client.IsRunning()
+	if err != nil {
 		return err
 	}
-	if currentState != state.Stopped {
-		return fmt.Errorf("VM is not stopped, current state is %s", currentState.String())
+	if running {
+		return errors.New("VM is still running")
 	}
 
 	tmpBaseDir, err := ioutil.TempDir(constants.MachineCacheDir, "crc_custom_bundle")
diff --git a/pkg/crc/machine/start.go b/pkg/crc/machine/start.go
index 7b453453b..aba0a3a82 100644
--- a/pkg/crc/machine/start.go
+++ b/pkg/crc/machine/start.go
@@ -20,6 +20,7 @@ import (
 	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/crc/pkg/crc/machine/bundle"
 	"github.com/code-ready/crc/pkg/crc/machine/config"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/crc/pkg/crc/oc"
@@ -32,10 +33,9 @@ import (
 	"github.com/code-ready/crc/pkg/libmachine"
 	"github.com/code-ready/crc/pkg/libmachine/host"
 	"github.com/code-ready/machine/libmachine/drivers"
-	"github.com/code-ready/machine/libmachine/state"
+	libmachinestate "github.com/code-ready/machine/libmachine/state"
 	"github.com/docker/go-units"
 	"github.com/pkg/errors"
-
 	"golang.org/x/crypto/ssh"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -212,7 +212,7 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
 	if err != nil {
 		return nil, errors.Wrap(err, "Error getting the machine state")
 	}
-	if vmState == state.Running {
+	if vmState == libmachinestate.Running {
 		logging.Infof("A CodeReady Containers VM for OpenShift %s is already running", crcBundleMetadata.GetOpenshiftVersion())
 		clusterConfig, err := getClusterConfig(crcBundleMetadata)
 		if err != nil {
@@ -221,7 +221,7 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
 
 		telemetry.SetStartType(ctx, telemetry.AlreadyRunningStartType)
 		return &types.StartResult{
-			Status:         vmState,
+			Status:         state.FromMachine(vmState),
 			ClusterConfig:  *clusterConfig,
 			KubeletStarted: true,
 		}, nil
@@ -258,7 +258,7 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
 	if err != nil {
 		return nil, errors.Wrap(err, "Error getting the state")
 	}
-	if vmState != state.Running {
+	if vmState != libmachinestate.Running {
 		return nil, errors.Wrap(err, "CodeReady Containers VM is not running")
 	}
 
@@ -473,7 +473,7 @@ func (client *client) Start(ctx context.Context, startConfig types.StartConfig)
 	return &types.StartResult{
 		KubeletStarted: true,
 		ClusterConfig:  *clusterConfig,
-		Status:         vmState,
+		Status:         state.FromMachine(vmState),
 	}, nil
 }
 
@@ -492,7 +492,7 @@ func (client *client) IsRunning() (bool, error) {
 		// but reports not started on error
 		return false, errors.Wrap(err, "Error getting the state")
 	}
-	if vmState != state.Running {
+	if vmState != libmachinestate.Running {
 		return false, nil
 	}
 	return true, nil
@@ -571,7 +571,7 @@ func startHost(ctx context.Context, api libmachine.API, vm *host.Host) error {
 	}
 
 	logging.Debug("Waiting for machine to be running, this may take a few minutes...")
-	if err := crcerrors.RetryAfterWithContext(ctx, 3*time.Minute, host.MachineInState(vm.Driver, state.Running), 3*time.Second); err != nil {
+	if err := crcerrors.RetryAfterWithContext(ctx, 3*time.Minute, host.MachineInState(vm.Driver, libmachinestate.Running), 3*time.Second); err != nil {
 		return fmt.Errorf("Error waiting for machine to be running: %s", err)
 	}
 
diff --git a/pkg/crc/machine/state/state.go b/pkg/crc/machine/state/state.go
new file mode 100644
index 000000000..b5cbc4b31
--- /dev/null
+++ b/pkg/crc/machine/state/state.go
@@ -0,0 +1,24 @@
+package state
+
+import libmachinestate "github.com/code-ready/machine/libmachine/state"
+
+// State represents the state of crc (both VM and components)
+type State string
+
+const (
+	Running  State = "Running"
+	Stopped  State = "Stopped"
+	Stopping State = "Stopping"
+	Starting State = "Starting"
+	Error    State = "Error"
+)
+
+func FromMachine(input libmachinestate.State) State {
+	switch input {
+	case libmachinestate.Running:
+		return Running
+	case libmachinestate.Stopped:
+		return Stopped
+	}
+	return Error
+}
diff --git a/pkg/crc/machine/status.go b/pkg/crc/machine/status.go
index 3600810a4..903059392 100644
--- a/pkg/crc/machine/status.go
+++ b/pkg/crc/machine/status.go
@@ -7,9 +7,10 @@ import (
 	"github.com/code-ready/crc/pkg/crc/constants"
 	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/crc/pkg/crc/machine/bundle"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
 	crcssh "github.com/code-ready/crc/pkg/crc/ssh"
-	"github.com/code-ready/machine/libmachine/state"
+	libmachinestate "github.com/code-ready/machine/libmachine/state"
 	"github.com/pkg/errors"
 )
 
@@ -39,9 +40,9 @@ func (client *client) Status() (*types.ClusterStatusResult, error) {
 		return nil, errors.Wrap(err, "Error loading bundle metadata")
 	}
 
-	if vmStatus != state.Running {
+	if vmStatus != libmachinestate.Running {
 		return &types.ClusterStatusResult{
-			CrcStatus:        vmStatus,
+			CrcStatus:        state.FromMachine(vmStatus),
 			OpenshiftStatus:  types.OpenshiftStopped,
 			OpenshiftVersion: crcBundleMetadata.GetOpenshiftVersion(),
 		}, nil
diff --git a/pkg/crc/machine/stop.go b/pkg/crc/machine/stop.go
index d00e424e8..268198137 100644
--- a/pkg/crc/machine/stop.go
+++ b/pkg/crc/machine/stop.go
@@ -3,10 +3,10 @@ package machine
 import (
 	"github.com/code-ready/crc/pkg/crc/constants"
 	"github.com/code-ready/crc/pkg/crc/logging"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/oc"
 	crcssh "github.com/code-ready/crc/pkg/crc/ssh"
 	"github.com/code-ready/crc/pkg/libmachine/host"
-	"github.com/code-ready/machine/libmachine/state"
 	"github.com/pkg/errors"
 )
 
@@ -27,9 +27,13 @@ func (client *client) Stop() (state.State, error) {
 		if stateErr != nil {
 			logging.Debugf("Cannot get VM status after stopping it: %v", stateErr)
 		}
-		return status, errors.Wrap(err, "Cannot stop machine")
+		return state.FromMachine(status), errors.Wrap(err, "Cannot stop machine")
 	}
-	return host.Driver.GetState()
+	status, err := host.Driver.GetState()
+	if err != nil {
+		return state.Error, errors.Wrap(err, "Cannot get VM status")
+	}
+	return state.FromMachine(status), nil
 }
 
 // This should be removed after https://bugzilla.redhat.com/show_bug.cgi?id=1965992
diff --git a/pkg/crc/machine/sync.go b/pkg/crc/machine/sync.go
index ddbf15994..e053f6034 100644
--- a/pkg/crc/machine/sync.go
+++ b/pkg/crc/machine/sync.go
@@ -7,8 +7,8 @@ import (
 	"time"
 
 	"github.com/code-ready/crc/pkg/crc/logging"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
-	"github.com/code-ready/machine/libmachine/state"
 )
 
 const startCancelTimeout = 15 * time.Second
diff --git a/pkg/crc/machine/types/types.go b/pkg/crc/machine/types/types.go
index bb9cd8bc1..9b3cf9e38 100644
--- a/pkg/crc/machine/types/types.go
+++ b/pkg/crc/machine/types/types.go
@@ -2,8 +2,8 @@ package types
 
 import (
 	"github.com/code-ready/crc/pkg/crc/cluster"
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/network"
-	"github.com/code-ready/machine/libmachine/state"
 )
 
 type StartConfig struct {


Test patch:
diff --git a/pkg/crc/api/api_test.go b/pkg/crc/api/api_test.go
deleted file mode 100644
index ad7a53eb0..000000000
--- a/pkg/crc/api/api_test.go
+++ /dev/null
@@ -1,267 +0,0 @@
-// +build !windows
-
-package api
-
-import (
-	"encoding/json"
-	"io/ioutil"
-	"net"
-	"os"
-	"path/filepath"
-	"testing"
-
-	apiClient "github.com/code-ready/crc/pkg/crc/api/client"
-	"github.com/code-ready/crc/pkg/crc/machine/fakemachine"
-	"github.com/code-ready/crc/pkg/crc/version"
-	log "github.com/sirupsen/logrus"
-	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
-)
-
-func TestApi(t *testing.T) {
-	dir, err := ioutil.TempDir("", "api")
-	require.NoError(t, err)
-	defer os.RemoveAll(dir)
-
-	socket := filepath.Join(dir, "api.sock")
-	listener, err := net.Listen("unix", socket)
-	require.NoError(t, err)
-
-	client := fakemachine.NewClient()
-	api, err := createServerWithListener(listener, setupNewInMemoryConfig(), client, &mockLogger{}, &mockTelemetry{})
-	require.NoError(t, err)
-	go func() {
-		if err := api.Serve(); err != nil {
-			log.Error(err)
-		}
-	}()
-
-	tt := []struct {
-		command       string
-		clientFailing bool
-		args          json.RawMessage
-		expected      map[string]interface{}
-	}{
-		{
-			command: "version",
-			expected: map[string]interface{}{
-				"CrcVersion":       version.GetCRCVersion(),
-				"CommitSha":        version.GetCommitSha(),
-				"OpenshiftVersion": version.GetBundleVersion(),
-				"Success":          true,
-			},
-		},
-		{
-			command: "status",
-			expected: map[string]interface{}{
-				"CrcStatus":        "Running",
-				"OpenshiftStatus":  "Running",
-				"OpenshiftVersion": "4.5.1",
-				"DiskUse":          float64(10000000000),
-				"DiskSize":         float64(20000000000),
-				"Error":            "",
-				"Success":          true,
-			},
-		},
-		{
-			command:       "status",
-			clientFailing: true,
-			expected: map[string]interface{}{
-				"CrcStatus":        "",
-				"OpenshiftStatus":  "",
-				"OpenshiftVersion": "",
-				"DiskUse":          float64(0),
-				"DiskSize":         float64(0),
-				"Error":            "broken",
-				"Success":          false,
-			},
-		},
-		{
-			command:       "start",
-			clientFailing: true,
-			args:          json.RawMessage(`{"pullSecretFile":"/Users/fake/pull-secret"}`),
-			expected: map[string]interface{}{
-				"Status":         "",
-				"Error":          "Failed to start",
-				"KubeletStarted": false,
-				"Success":        false,
-				"ClusterConfig": map[string]interface{}{
-					"KubeConfig":    "",
-					"KubeAdminPass": "",
-					"ClusterAPI":    "",
-					"WebConsoleURL": "",
-					"ProxyConfig":   nil,
-					"ClusterCACert": "",
-				},
-			},
-		},
-		{
-			command:       "start",
-			clientFailing: true,
-			args:          json.RawMessage(`[]`),
-			expected: map[string]interface{}{
-				"Status":         "",
-				"Error":          "Incorrect arguments given: json: cannot unmarshal array into Go value of type client.StartConfig",
-				"KubeletStarted": false,
-				"Success":        false,
-				"ClusterConfig": map[string]interface{}{
-					"KubeConfig":    "",
-					"KubeAdminPass": "",
-					"ClusterAPI":    "",
-					"WebConsoleURL": "",
-					"ProxyConfig":   nil,
-					"ClusterCACert": "",
-				},
-			},
-		},
-		{
-			command: "start",
-			args:    json.RawMessage(`{"pullSecretFile":"/Users/fake/pull-secret"}`),
-			expected: map[string]interface{}{
-				"Status":         "",
-				"Error":          "",
-				"KubeletStarted": true,
-				"Success":        true,
-				"ClusterConfig": map[string]interface{}{
-					"ClusterCACert": "MIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJ",
-					"KubeConfig":    "/tmp/kubeconfig",
-					"KubeAdminPass": "foobar",
-					"ClusterAPI":    "https://foo.testing:6443",
-					"WebConsoleURL": "https://console.foo.testing:6443",
-					"ProxyConfig":   nil,
-				},
-			},
-		},
-		{
-			command: "start",
-			expected: map[string]interface{}{
-				"Status":         "",
-				"Error":          "",
-				"KubeletStarted": true,
-				"Success":        true,
-				"ClusterConfig": map[string]interface{}{
-					"ClusterCACert": "MIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJ",
-					"KubeConfig":    "/tmp/kubeconfig",
-					"KubeAdminPass": "foobar",
-					"ClusterAPI":    "https://foo.testing:6443",
-					"WebConsoleURL": "https://console.foo.testing:6443",
-					"ProxyConfig":   nil,
-				},
-			},
-		},
-		{
-			command: "logs",
-			expected: map[string]interface{}{
-				"Messages": []interface{}{"message 1", "message 2", "message 3"},
-				"Success":  true,
-			},
-		},
-		{
-			command: "telemetry",
-			args:    json.RawMessage(`{"action":"click start"}`),
-			expected: map[string]interface{}{
-				"Success": true,
-				"Error":   "",
-			},
-		},
-	}
-	for _, test := range tt {
-		client.Failing = test.clientFailing
-		client, err := net.Dial("unix", socket)
-		require.NoError(t, err)
-
-		jsonReq, err := json.Marshal(commandRequest{
-			Command: test.command,
-			Args:    test.args,
-		})
-		assert.NoError(t, err)
-		_, err = client.Write(jsonReq)
-		assert.NoError(t, err)
-
-		payload := make([]byte, 1024)
-		n, err := client.Read(payload)
-		assert.NoError(t, err)
-
-		var res map[string]interface{}
-		assert.NoError(t, json.Unmarshal(payload[0:n], &res))
-		assert.Equal(t, test.expected, res)
-	}
-}
-
-func TestSetconfigApi(t *testing.T) {
-	socket, cleanup := setupAPIServer(t)
-	client, err := net.Dial("unix", socket)
-	require.NoError(t, err)
-	defer cleanup()
-
-	jsonReq, err := json.Marshal(commandRequest{
-		Command: "setconfig",
-		Args:    json.RawMessage(`{"properties":{"cpus":"5"}}`),
-	})
-	assert.NoError(t, err)
-	_, err = client.Write(jsonReq)
-	assert.NoError(t, err)
-
-	payload := make([]byte, 1024)
-	n, err := client.Read(payload)
-	assert.NoError(t, err)
-
-	var setconfigRes apiClient.SetOrUnsetConfigResult
-	assert.NoError(t, json.Unmarshal(payload[:n], &setconfigRes))
-	assert.Equal(t, apiClient.SetOrUnsetConfigResult{
-		Success:    true,
-		Error:      "",
-		Properties: []string{"cpus"},
-	}, setconfigRes)
-}
-
-func TestGetconfigApi(t *testing.T) {
-	socket, cleanup := setupAPIServer(t)
-	client, err := net.Dial("unix", socket)
-	require.NoError(t, err)
-	defer cleanup()
-
-	jsonReq, err := json.Marshal(commandRequest{
-		Command: "getconfig",
-		Args:    json.RawMessage(`{"properties":["cpus"]}`),
-	})
-	assert.NoError(t, err)
-	_, err = client.Write(jsonReq)
-	assert.NoError(t, err)
-
-	payload := make([]byte, 1024)
-	n, err := client.Read(payload)
-	assert.NoError(t, err)
-
-	var getconfigRes apiClient.GetConfigResult
-	assert.NoError(t, json.Unmarshal(payload[:n], &getconfigRes))
-
-	configs := make(map[string]interface{})
-	configs["cpus"] = 4.0
-
-	assert.Equal(t, apiClient.GetConfigResult{
-		Success: true,
-		Error:   "",
-		Configs: configs,
-	}, getconfigRes)
-}
-
-func setupAPIServer(t *testing.T) (string, func()) {
-	dir, err := ioutil.TempDir("", "api")
-	require.NoError(t, err)
-
-	socket := filepath.Join(dir, "api.sock")
-	listener, err := net.Listen("unix", socket)
-	require.NoError(t, err)
-
-	client := fakemachine.NewClient()
-	api, err := createServerWithListener(listener, setupNewInMemoryConfig(), client, &mockLogger{}, &mockTelemetry{})
-	require.NoError(t, err)
-	go func() {
-		if err := api.Serve(); err != nil {
-			log.Error(err)
-		}
-	}()
-
-	return socket, func() { os.RemoveAll(dir) }
-}
diff --git a/pkg/crc/machine/sync_test.go b/pkg/crc/machine/sync_test.go
index b973f50bd..7a05d16f3 100644
--- a/pkg/crc/machine/sync_test.go
+++ b/pkg/crc/machine/sync_test.go
@@ -6,8 +6,8 @@ import (
 	"sync"
 	"testing"
 
+	"github.com/code-ready/crc/pkg/crc/machine/state"
 	"github.com/code-ready/crc/pkg/crc/machine/types"
-	"github.com/code-ready/machine/libmachine/state"
 	"github.com/stretchr/testify/assert"
 )
 
diff --git a/test/e2e/features/basic.feature b/test/e2e/features/basic.feature
index 20e8f6272..e822cf65b 100644
--- a/test/e2e/features/basic.feature
+++ b/test/e2e/features/basic.feature
@@ -148,7 +148,7 @@ Feature: Basic test
         # This will remove the pull secret from the instance and from the cluster
         # You need to provide pull secret file again if you want to start this cluster
         # from a stopped state.
-        Given executing "crc bundle generate" succeeds
+        Given executing "crc bundle generate -f" succeeds
 
     @darwin @windows
     Scenario: CRC forcible stop
diff --git a/test/integration/resize_test.go b/test/integration/resize_test.go
index b89c61bc1..1e0c80052 100644
--- a/test/integration/resize_test.go
+++ b/test/integration/resize_test.go
@@ -52,12 +52,7 @@ var _ = Describe("vary VM parameters: memory cpus, disk", func() {
 	Describe("use custom values", func() {
 
 		It("start CRC", func() {
-			if runtime.GOOS == "darwin" {
-				Expect(RunCRCExpectFail("start", "--memory", "12000", "--cpus", "6", "--disk-size", "40")).To(ContainSubstring("Disk resizing is not supported on macOS"))
-				Expect(RunCRCExpectSuccess("start", "--memory", "12000", "--cpus", "6")).To(ContainSubstring("Started the OpenShift cluster"))
-			} else {
-				Expect(RunCRCExpectSuccess("start", "--memory", "12000", "--cpus", "6", "--disk-size", "40")).To(ContainSubstring("Started the OpenShift cluster"))
-			}
+			Expect(RunCRCExpectSuccess("start", "--memory", "12000", "--cpus", "6", "--disk-size", "40")).To(ContainSubstring("Started the OpenShift cluster"))
 		})
 
 		It("check VM's memory size", func() {
@@ -76,11 +71,7 @@ var _ = Describe("vary VM parameters: memory cpus, disk", func() {
 		It("check VM's disk size", func() {
 			out, err := SendCommandToVM("df -h | grep sysroot")
 			Expect(err).NotTo(HaveOccurred())
-			if runtime.GOOS == "darwin" { // darwin does not support resize
-				Expect(out).Should(MatchRegexp(`.*31G[\s].*[\s]/sysroot`))
-			} else {
-				Expect(out).Should(MatchRegexp(`.*40G[\s].*[\s]/sysroot`))
-			}
+			Expect(out).Should(MatchRegexp(`.*40G[\s].*[\s]/sysroot`))
 		})
 
 		It("stop CRC", func() {
@@ -97,13 +88,10 @@ var _ = Describe("vary VM parameters: memory cpus, disk", func() {
 			Expect(RunCRCExpectFail("start", "--cpus", "3")).To(ContainSubstring("requires CPUs >= 4"))
 		})
 		It("start CRC with smaller disk", func() { // bigger than default && smaller than current
-			switch runtime.GOOS {
-			case "darwin":
-				Expect(RunCRCExpectFail("start", "--disk-size", "35")).To(ContainSubstring("Disk resizing is not supported on macOS"))
-			case "linux":
-				Expect(RunCRCExpectFail("start", "--disk-size", "35")).To(ContainSubstring("current disk image capacity is bigger than the requested size"))
-			case "windows":
+			if runtime.GOOS == "windows" {
 				Expect(RunCRCExpectFail("start", "--disk-size", "35")).To(ContainSubstring("Failed to set disk size to"))
+			} else {
+				Expect(RunCRCExpectFail("start", "--disk-size", "35")).To(ContainSubstring("current disk image capacity is bigger than the requested size"))
 			}
 		})
 		It("start CRC with sub-minimum disk", func() { // smaller than min = default = 31GiB