Repository: code-ready/crc
Pull request #2156 (2021-03-26 09:08:28)

Prepare the daemon to be started from the tray
If the application is in a bad state, the user will restart it. Having the tray separated of the daemon makes hard to reset the status of the daemon when restarting the tray. 

This PR adds a mechanism to automatically shutdown itself when the parent process dies. 
It also checks no other daemons are running before starting. 

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

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2156#" title="Author self-approved">guillaumerose</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)~~ [guillaumerose]

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":[]} -->
cfergeau: > Having the tray separated of the daemon makes hard to reset the status of the daemon when restarting the tray.

Is it problematic to reconnect to an already running crc daemon instance when the tray restarts? Stopping the daemon is useful when you want to stop the tray for good, but are there also issues you want to solve on restart?
guillaumerose: > Is it problematic to reconnect to an already running crc daemon instance when the tray restarts? 

No but with the tray launching the daemon, there is guarantee that the daemon will be in the correct version. 

> Stopping the daemon is useful when you want to stop the tray for good, but are there also issues you want to solve on restart?

Nothing special. The state is in the daemon (esp. with the new locking system), not in the tray. An angry user might restart the tray and see no change. If the daemon is restarted also, the user has good chance to get something working. 
cfergeau: > > Is it problematic to reconnect to an already running crc daemon instance when the tray restarts?
> 
> No but with the tray launching the daemon, there is guarantee that the daemon will be in the correct version.
> 
> > Stopping the daemon is useful when you want to stop the tray for good, but are there also issues you want to solve on restart?
> 
> Nothing special. The state is in the daemon (esp. with the new locking system), not in the tray. An angry user might restart the tray and see no change. If the daemon is restarted also, the user has good chance to get something working.

Yup, it does not hurt to restart the daemon, I just wanted to make sure I'm not missing something :)
openshift-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2156#pullrequestreview-624485364" title="Approved">cfergeau</a>*, *<a href="https://github.com/code-ready/crc/pull/2156#" title="Author self-approved">guillaumerose</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,guillaumerose]

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-robot: New changes are detected. LGTM label has been removed.
guillaumerose: retest this please

Patch:
diff --git a/cmd/crc/cmd/console.go b/cmd/crc/cmd/console.go
index 717a811f3..83e6f5c31 100644
--- a/cmd/crc/cmd/console.go
+++ b/cmd/crc/cmd/console.go
@@ -8,6 +8,7 @@ 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/types"
 	"github.com/code-ready/machine/libmachine/state"
 	"github.com/pkg/browser"
 	"github.com/spf13/cobra"
@@ -36,7 +37,7 @@ var consoleCmd = &cobra.Command{
 	},
 }
 
-func showConsole(client machine.Client) (*machine.ConsoleResult, error) {
+func showConsole(client machine.Client) (*types.ConsoleResult, error) {
 	if err := checkIfMachineMissing(client); err != nil {
 		// In case of machine doesn't exist then consoleResult error
 		// should be updated so that when rendering the result it have
@@ -105,14 +106,14 @@ func (s *consoleResult) prettyPrintTo(writer io.Writer) error {
 	return nil
 }
 
-func toState(result *machine.ConsoleResult) state.State {
+func toState(result *types.ConsoleResult) state.State {
 	if result == nil {
 		return state.Error
 	}
 	return result.State
 }
 
-func toConsoleClusterConfig(result *machine.ConsoleResult) *clusterConfig {
+func toConsoleClusterConfig(result *types.ConsoleResult) *clusterConfig {
 	if result == nil {
 		return nil
 	}
diff --git a/cmd/crc/cmd/daemon.go b/cmd/crc/cmd/daemon.go
index fec7cd2a3..148fd7f2f 100644
--- a/cmd/crc/cmd/daemon.go
+++ b/cmd/crc/cmd/daemon.go
@@ -1,7 +1,9 @@
 package cmd
 
 import (
+	"errors"
 	"fmt"
+	"io/ioutil"
 	"net"
 	"net/http"
 	"os"
@@ -14,6 +16,7 @@ import (
 	cmdConfig "github.com/code-ready/crc/cmd/crc/cmd/config"
 	"github.com/code-ready/crc/pkg/crc/api"
 	"github.com/code-ready/crc/pkg/crc/constants"
+	"github.com/code-ready/crc/pkg/crc/daemonclient"
 	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/gvisor-tap-vsock/pkg/types"
 	"github.com/code-ready/gvisor-tap-vsock/pkg/virtualnetwork"
@@ -22,7 +25,10 @@ import (
 	"github.com/spf13/cobra"
 )
 
+var watchdog bool
+
 func init() {
+	daemonCmd.Flags().BoolVar(&watchdog, "watchdog", false, "Monitor stdin and shutdown the daemon if stdin is closed")
 	rootCmd.AddCommand(daemonCmd)
 }
 
@@ -34,6 +40,10 @@ var daemonCmd = &cobra.Command{
 	Long:   "Run the crc daemon",
 	Hidden: true,
 	RunE: func(cmd *cobra.Command, args []string) error {
+		if _, err := daemonclient.New().APIClient.Version(); err == nil {
+			return errors.New("daemon is already running")
+		}
+
 		virtualNetworkConfig := types.Configuration{
 			Debug:             false, // never log packets
 			CaptureFile:       captureFile(),
@@ -152,6 +162,17 @@ func run(configuration *types.Configuration) error {
 	}()
 
 	c := make(chan os.Signal, 1)
+
+	if watchdog {
+		go func() {
+			if _, err := ioutil.ReadAll(os.Stdin); err != nil {
+				logging.Errorf("unexpected error while reading stdin: %v", err)
+			}
+			logging.Error("stdin is closed, shutdown...")
+			c <- syscall.SIGTERM
+		}()
+	}
+
 	signal.Notify(c, os.Interrupt, syscall.SIGTERM)
 	select {
 	case <-c:
diff --git a/cmd/crc/cmd/start.go b/cmd/crc/cmd/start.go
index 67dcbadb1..97aadf5ad 100644
--- a/cmd/crc/cmd/start.go
+++ b/cmd/crc/cmd/start.go
@@ -15,7 +15,7 @@ import (
 	"github.com/code-ready/crc/pkg/crc/constants"
 	crcErrors "github.com/code-ready/crc/pkg/crc/errors"
 	"github.com/code-ready/crc/pkg/crc/logging"
-	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/preflight"
 	"github.com/code-ready/crc/pkg/crc/validation"
 	crcversion "github.com/code-ready/crc/pkg/crc/version"
@@ -55,14 +55,14 @@ var startCmd = &cobra.Command{
 	},
 }
 
-func runStart(ctx context.Context) (*machine.StartResult, error) {
+func runStart(ctx context.Context) (*types.StartResult, error) {
 	if err := validateStartFlags(); err != nil {
 		return nil, err
 	}
 
 	checkIfNewVersionAvailable(config.Get(cmdConfig.DisableUpdateCheck).AsBool())
 
-	startConfig := machine.StartConfig{
+	startConfig := types.StartConfig{
 		BundlePath: config.Get(cmdConfig.Bundle).AsString(),
 		Memory:     config.Get(cmdConfig.Memory).AsInt(),
 		DiskSize:   config.Get(cmdConfig.DiskSize).AsInt(),
@@ -83,7 +83,7 @@ func runStart(ctx context.Context) (*machine.StartResult, error) {
 	return client.Start(ctx, startConfig)
 }
 
-func renderStartResult(result *machine.StartResult, err error) error {
+func renderStartResult(result *types.StartResult, err error) error {
 	return render(&startResult{
 		Success:       err == nil,
 		Error:         crcErrors.ToSerializableError(err),
@@ -91,7 +91,7 @@ func renderStartResult(result *machine.StartResult, err error) error {
 	}, os.Stdout, outputFormat)
 }
 
-func toClusterConfig(result *machine.StartResult) *clusterConfig {
+func toClusterConfig(result *types.StartResult) *clusterConfig {
 	if result == nil {
 		return nil
 	}
diff --git a/pkg/crc/api/adapter.go b/pkg/crc/api/adapter.go
index 4abcb41e8..21bb94bb6 100644
--- a/pkg/crc/api/adapter.go
+++ b/pkg/crc/api/adapter.go
@@ -6,6 +6,7 @@ import (
 	"github.com/code-ready/crc/pkg/crc/api/client"
 	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/machine/libmachine/state"
 )
 
@@ -13,7 +14,7 @@ type AdaptedClient interface {
 	GetName() string
 	Delete() client.Result
 	GetConsoleURL() client.ConsoleResult
-	Start(ctx context.Context, startConfig machine.StartConfig) client.StartResult
+	Start(ctx context.Context, startConfig types.StartConfig) client.StartResult
 	Status() client.ClusterStatusResult
 	Stop() client.Result
 }
@@ -57,7 +58,7 @@ func (a *Adapter) GetConsoleURL() client.ConsoleResult {
 	}
 }
 
-func (a *Adapter) Start(ctx context.Context, startConfig machine.StartConfig) client.StartResult {
+func (a *Adapter) Start(ctx context.Context, startConfig types.StartConfig) client.StartResult {
 	res, err := a.Underlying.Start(ctx, startConfig)
 	if err != nil {
 		logging.Error(err)
diff --git a/pkg/crc/api/client/client.go b/pkg/crc/api/client/client.go
index ed34ef7de..a6c22bc42 100644
--- a/pkg/crc/api/client/client.go
+++ b/pkg/crc/api/client/client.go
@@ -7,8 +7,6 @@ import (
 	"io"
 	"io/ioutil"
 	"net/http"
-
-	"github.com/code-ready/crc/pkg/crc/logging"
 )
 
 type Client struct {
@@ -27,12 +25,10 @@ func (c *Client) Version() (VersionResult, error) {
 	var vr = VersionResult{}
 	body, err := c.sendGetRequest("/version")
 	if err != nil {
-		logging.Error(err)
 		return vr, err
 	}
 	err = json.Unmarshal(body, &vr)
 	if err != nil {
-		logging.Error(err)
 		return vr, err
 	}
 	return vr, nil
@@ -42,12 +38,10 @@ func (c *Client) Status() (ClusterStatusResult, error) {
 	var sr = ClusterStatusResult{}
 	body, err := c.sendGetRequest("/status")
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	err = json.Unmarshal(body, &sr)
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	return sr, nil
@@ -64,12 +58,10 @@ func (c *Client) Start(config StartConfig) (StartResult, error) {
 	}
 	body, err := c.sendPostRequest("/start", data)
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	err = json.Unmarshal(body, &sr)
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	return sr, nil
@@ -79,12 +71,10 @@ func (c *Client) Stop() (Result, error) {
 	var sr = Result{}
 	body, err := c.sendGetRequest("/stop")
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	err = json.Unmarshal(body, &sr)
 	if err != nil {
-		logging.Error(err)
 		return sr, err
 	}
 	return sr, nil
@@ -94,12 +84,10 @@ func (c *Client) Delete() (Result, error) {
 	var dr = Result{}
 	body, err := c.sendGetRequest("/delete")
 	if err != nil {
-		logging.Error(err)
 		return dr, err
 	}
 	err = json.Unmarshal(body, &dr)
 	if err != nil {
-		logging.Error(err)
 		return dr, err
 	}
 	return dr, nil
@@ -109,12 +97,10 @@ func (c *Client) WebconsoleURL() (ConsoleResult, error) {
 	var cr = ConsoleResult{}
 	body, err := c.sendGetRequest("/webconsoleurl")
 	if err != nil {
-		logging.Error(err)
 		return cr, err
 	}
 	err = json.Unmarshal(body, &cr)
 	if err != nil {
-		logging.Error(err)
 		return cr, err
 	}
 	return cr, nil
@@ -134,12 +120,10 @@ func (c *Client) GetConfig(configs []string) (GetConfigResult, error) {
 	}
 	body, err := c.sendPostRequest("/config/get", data)
 	if err != nil {
-		logging.Error(err)
 		return gcr, err
 	}
 	err = json.Unmarshal(body, &gcr)
 	if err != nil {
-		logging.Error(err)
 		return gcr, err
 	}
 	return gcr, nil
@@ -159,7 +143,6 @@ func (c *Client) SetConfig(configs SetConfigRequest) (SetOrUnsetConfigResult, er
 
 	body, err := c.sendPostRequest("/config/set", data)
 	if err != nil {
-		logging.Error(err)
 		return scr, err
 	}
 
@@ -182,12 +165,10 @@ func (c *Client) UnsetConfig(configs []string) (SetOrUnsetConfigResult, error) {
 	}
 	body, err := c.sendPostRequest("/config/unset", data)
 	if err != nil {
-		logging.Error(err)
 		return ucr, err
 	}
 	err = json.Unmarshal(body, &ucr)
 	if err != nil {
-		logging.Error(err)
 		return ucr, err
 	}
 	return ucr, nil
@@ -196,7 +177,6 @@ func (c *Client) UnsetConfig(configs []string) (SetOrUnsetConfigResult, error) {
 func (c *Client) sendGetRequest(url string) ([]byte, error) {
 	res, err := c.client.Get(fmt.Sprintf("%s%s", c.base, url))
 	if err != nil {
-		logging.Error(err)
 		return nil, err
 	}
 	if res.StatusCode != http.StatusOK {
@@ -219,7 +199,6 @@ func (c *Client) sendPostRequest(url string, data io.Reader) ([]byte, error) {
 
 	res, err := c.client.Do(req)
 	if err != nil {
-		logging.Error(err)
 		return nil, err
 	}
 	if res.StatusCode != http.StatusOK {
diff --git a/pkg/crc/api/client/types.go b/pkg/crc/api/client/types.go
index 5767ae969..9acd8922b 100644
--- a/pkg/crc/api/client/types.go
+++ b/pkg/crc/api/client/types.go
@@ -1,7 +1,7 @@
 package client
 
 import (
-	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 )
 
 type VersionResult struct {
@@ -21,7 +21,7 @@ type StartResult struct {
 	Name           string
 	Status         string
 	Error          string
-	ClusterConfig  machine.ClusterConfig
+	ClusterConfig  types.ClusterConfig
 	KubeletStarted bool
 }
 
@@ -37,7 +37,7 @@ type ClusterStatusResult struct {
 }
 
 type ConsoleResult struct {
-	ClusterConfig machine.ClusterConfig
+	ClusterConfig types.ClusterConfig
 	Success       bool
 	Error         string
 }
diff --git a/pkg/crc/api/handlers.go b/pkg/crc/api/handlers.go
index d862cb54b..729f08f5e 100644
--- a/pkg/crc/api/handlers.go
+++ b/pkg/crc/api/handlers.go
@@ -13,6 +13,7 @@ import (
 	"github.com/code-ready/crc/pkg/crc/errors"
 	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/preflight"
 	"github.com/code-ready/crc/pkg/crc/version"
 )
@@ -89,8 +90,8 @@ func parseStartArgs(args json.RawMessage) (startArgs, error) {
 	return parsedArgs, nil
 }
 
-func getStartConfig(cfg crcConfig.Storage, args startArgs) machine.StartConfig {
-	return machine.StartConfig{
+func getStartConfig(cfg crcConfig.Storage, args startArgs) types.StartConfig {
+	return types.StartConfig{
 		BundlePath: cfg.Get(config.Bundle).AsString(),
 		Memory:     cfg.Get(config.Memory).AsInt(),
 		CPUs:       cfg.Get(config.CPUs).AsInt(),
diff --git a/pkg/crc/daemonclient/client.go b/pkg/crc/daemonclient/client.go
index aa866634a..7df516385 100644
--- a/pkg/crc/daemonclient/client.go
+++ b/pkg/crc/daemonclient/client.go
@@ -3,17 +3,22 @@ package daemonclient
 import (
 	"net/http"
 
+	"github.com/code-ready/crc/pkg/crc/api/client"
 	networkclient "github.com/code-ready/gvisor-tap-vsock/pkg/client"
 )
 
 type Client struct {
-	*networkclient.Client
+	NetworkClient *networkclient.Client
+	APIClient     *client.Client
 }
 
 func New() *Client {
 	return &Client{
-		Client: networkclient.New(&http.Client{
+		NetworkClient: networkclient.New(&http.Client{
 			Transport: transport(),
 		}, "http://unix/network"),
+		APIClient: client.New(&http.Client{
+			Transport: transport(),
+		}, "http://unix/api"),
 	}
 }
diff --git a/pkg/crc/machine/client.go b/pkg/crc/machine/client.go
index b3770047f..58101cd2e 100644
--- a/pkg/crc/machine/client.go
+++ b/pkg/crc/machine/client.go
@@ -5,6 +5,7 @@ import (
 
 	cmdConfig "github.com/code-ready/crc/cmd/crc/cmd/config"
 	crcConfig "github.com/code-ready/crc/pkg/crc/config"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/machine/libmachine/state"
 )
@@ -14,11 +15,11 @@ type Client interface {
 
 	Delete() error
 	Exists() (bool, error)
-	GetConsoleURL() (*ConsoleResult, error)
+	GetConsoleURL() (*types.ConsoleResult, error)
 	IP() (string, error)
 	PowerOff() error
-	Start(ctx context.Context, startConfig StartConfig) (*StartResult, error)
-	Status() (*ClusterStatusResult, error)
+	Start(ctx context.Context, startConfig types.StartConfig) (*types.StartResult, error)
+	Status() (*types.ClusterStatusResult, error)
 	Stop() (state.State, error)
 	IsRunning() (bool, error)
 }
diff --git a/pkg/crc/machine/console.go b/pkg/crc/machine/console.go
index c5c1a5ff0..54b216938 100644
--- a/pkg/crc/machine/console.go
+++ b/pkg/crc/machine/console.go
@@ -1,9 +1,12 @@
 package machine
 
-import "github.com/pkg/errors"
+import (
+	"github.com/code-ready/crc/pkg/crc/machine/types"
+	"github.com/pkg/errors"
+)
 
 // Return console URL if the VM is present.
-func (client *client) GetConsoleURL() (*ConsoleResult, error) {
+func (client *client) GetConsoleURL() (*types.ConsoleResult, error) {
 	// Here we are only checking if the VM exist and not the status of the VM.
 	// We might need to improve and use crc status logic, only
 	// return if the Openshift is running as part of status.
@@ -29,7 +32,7 @@ func (client *client) GetConsoleURL() (*ConsoleResult, error) {
 		return nil, errors.Wrap(err, "Error loading cluster configuration")
 	}
 
-	return &ConsoleResult{
+	return &types.ConsoleResult{
 		ClusterConfig: *clusterConfig,
 		State:         vmState,
 	}, nil
diff --git a/pkg/crc/machine/fakemachine/client.go b/pkg/crc/machine/fakemachine/client.go
index 64387aece..0e9ecb9ec 100644
--- a/pkg/crc/machine/fakemachine/client.go
+++ b/pkg/crc/machine/fakemachine/client.go
@@ -4,7 +4,7 @@ import (
 	"context"
 	"errors"
 
-	"github.com/code-ready/crc/pkg/crc/machine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/machine/libmachine/state"
 )
@@ -23,7 +23,7 @@ type Client struct {
 	Failing bool
 }
 
-var DummyClusterConfig = machine.ClusterConfig{
+var DummyClusterConfig = types.ClusterConfig{
 	ClusterCACert: "MIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJ",
 	KubeConfig:    "/tmp/kubeconfig",
 	KubeAdminPass: "foobar",
@@ -43,11 +43,11 @@ func (c *Client) Delete() error {
 	return nil
 }
 
-func (c *Client) GetConsoleURL() (*machine.ConsoleResult, error) {
+func (c *Client) GetConsoleURL() (*types.ConsoleResult, error) {
 	if c.Failing {
 		return nil, errors.New("console failed")
 	}
-	return &machine.ConsoleResult{
+	return &types.ConsoleResult{
 		ClusterConfig: DummyClusterConfig,
 		State:         state.Running,
 	}, nil
@@ -68,11 +68,11 @@ func (c *Client) PowerOff() error {
 	return nil
 }
 
-func (c *Client) Start(ctx context.Context, startConfig machine.StartConfig) (*machine.StartResult, error) {
+func (c *Client) Start(ctx context.Context, startConfig types.StartConfig) (*types.StartResult, error) {
 	if c.Failing {
 		return nil, errors.New("Failed to start")
 	}
-	return &machine.StartResult{
+	return &types.StartResult{
 		ClusterConfig:  DummyClusterConfig,
 		KubeletStarted: true,
 	}, nil
@@ -85,11 +85,11 @@ func (c *Client) Stop() (state.State, error) {
 	return state.Stopped, nil
 }
 
-func (c *Client) Status() (*machine.ClusterStatusResult, error) {
+func (c *Client) Status() (*types.ClusterStatusResult, error) {
 	if c.Failing {
 		return nil, errors.New("broken")
 	}
-	return &machine.ClusterStatusResult{
+	return &types.ClusterStatusResult{
 		CrcStatus:        state.Running,
 		OpenshiftStatus:  "Running",
 		OpenshiftVersion: "4.5.1",
diff --git a/pkg/crc/machine/kubeconfig.go b/pkg/crc/machine/kubeconfig.go
index a398f03b6..fd6b950bd 100644
--- a/pkg/crc/machine/kubeconfig.go
+++ b/pkg/crc/machine/kubeconfig.go
@@ -14,6 +14,7 @@ import (
 	"time"
 
 	"github.com/code-ready/crc/pkg/crc/constants"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/openshift/oc/pkg/helpers/tokencmd"
 	restclient "k8s.io/client-go/rest"
 	"k8s.io/client-go/tools/clientcmd"
@@ -25,7 +26,7 @@ const (
 	developerContext = "crc-developer"
 )
 
-func writeKubeconfig(ip string, clusterConfig *ClusterConfig) error {
+func writeKubeconfig(ip string, clusterConfig *types.ClusterConfig) error {
 	kubeconfig := getGlobalKubeConfigPath()
 	dir := filepath.Dir(kubeconfig)
 	if err := os.MkdirAll(dir, 0755); err != nil {
@@ -86,7 +87,7 @@ func hostname(clusterAPI string) (string, error) {
 	return p.Host, nil
 }
 
-func addContext(cfg *api.Config, ip string, clusterConfig *ClusterConfig, ca []byte, context, username, password string) error {
+func addContext(cfg *api.Config, ip string, clusterConfig *types.ClusterConfig, ca []byte, context, username, password string) error {
 	host, err := hostname(clusterConfig.ClusterAPI)
 	if err != nil {
 		return err
diff --git a/pkg/crc/machine/machine.go b/pkg/crc/machine/machine.go
index ae7fdd3df..01dfbd189 100644
--- a/pkg/crc/machine/machine.go
+++ b/pkg/crc/machine/machine.go
@@ -6,13 +6,14 @@ import (
 
 	"github.com/code-ready/crc/pkg/crc/constants"
 	"github.com/code-ready/crc/pkg/crc/machine/bundle"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/crc/pkg/libmachine"
 	"github.com/code-ready/crc/pkg/libmachine/host"
 	"github.com/code-ready/machine/libmachine/drivers"
 )
 
-func getClusterConfig(bundleInfo *bundle.CrcBundleInfo, generatedKubeadminPassword string) (*ClusterConfig, error) {
+func getClusterConfig(bundleInfo *bundle.CrcBundleInfo, generatedKubeadminPassword string) (*types.ClusterConfig, error) {
 	kubeadminPassword, err := bundleInfo.GetKubeadminPassword()
 	if err != nil {
 		return nil, fmt.Errorf("Error reading kubeadmin password from bundle %v", err)
@@ -28,7 +29,7 @@ func getClusterConfig(bundleInfo *bundle.CrcBundleInfo, generatedKubeadminPasswo
 	if err != nil {
 		return nil, err
 	}
-	return &ClusterConfig{
+	return &types.ClusterConfig{
 		ClusterCACert: base64.StdEncoding.EncodeToString(clusterCACert),
 		KubeConfig:    bundleInfo.GetKubeConfigPath(),
 		KubeAdminPass: kubeadminPassword,
diff --git a/pkg/crc/machine/start.go b/pkg/crc/machine/start.go
index 1716f5ea0..0096c1169 100644
--- a/pkg/crc/machine/start.go
+++ b/pkg/crc/machine/start.go
@@ -17,6 +17,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/types"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/crc/pkg/crc/oc"
 	"github.com/code-ready/crc/pkg/crc/services"
@@ -52,7 +53,7 @@ func getCrcBundleInfo(bundlePath string) (*bundle.CrcBundleInfo, error) {
 	return bundle.Use(bundleName)
 }
 
-func (client *client) updateVMConfig(startConfig StartConfig, api libmachine.API, host *host.Host) error {
+func (client *client) updateVMConfig(startConfig types.StartConfig, api libmachine.API, host *host.Host) error {
 	/* Memory */
 	logging.Debugf("Updating CRC VM configuration")
 	if err := setMemory(host, startConfig.Memory); err != nil {
@@ -128,7 +129,7 @@ func growRootFileSystem(sshRunner *crcssh.Runner) error {
 
 	return nil
 }
-func (client *client) Start(ctx context.Context, startConfig StartConfig) (*StartResult, error) {
+func (client *client) Start(ctx context.Context, startConfig types.StartConfig) (*types.StartResult, error) {
 	telemetry.SetCPUs(ctx, startConfig.CPUs)
 	telemetry.SetMemory(ctx, uint64(startConfig.Memory)*1024*1024)
 	telemetry.SetDiskSize(ctx, uint64(startConfig.DiskSize)*1024*1024*1024)
@@ -228,7 +229,7 @@ func (client *client) Start(ctx context.Context, startConfig StartConfig) (*Star
 			}
 
 			telemetry.SetStartType(ctx, telemetry.AlreadyRunningStartType)
-			return &StartResult{
+			return &types.StartResult{
 				Status:         vmState,
 				ClusterConfig:  *clusterConfig,
 				KubeletStarted: true,
@@ -459,7 +460,7 @@ func (client *client) Start(ctx context.Context, startConfig StartConfig) (*Star
 		logging.Errorf("Cannot update kubeconfig: %v", err)
 	}
 
-	return &StartResult{
+	return &types.StartResult{
 		KubeletStarted: true,
 		ClusterConfig:  *clusterConfig,
 		Status:         vmState,
@@ -487,7 +488,7 @@ func (client *client) IsRunning() (bool, error) {
 	return true, nil
 }
 
-func (client *client) validateStartConfig(startConfig StartConfig) error {
+func (client *client) validateStartConfig(startConfig types.StartConfig) error {
 	if client.monitoringEnabled() && startConfig.Memory < minimumMemoryForMonitoring {
 		return fmt.Errorf("Too little memory (%s) allocated to the virtual machine to start the monitoring stack, %s is the minimum",
 			units.BytesSize(float64(startConfig.Memory)*1024*1024),
diff --git a/pkg/crc/machine/status.go b/pkg/crc/machine/status.go
index 43630ae04..d1fae2a77 100644
--- a/pkg/crc/machine/status.go
+++ b/pkg/crc/machine/status.go
@@ -4,13 +4,14 @@ import (
 	"github.com/code-ready/crc/pkg/crc/cluster"
 	"github.com/code-ready/crc/pkg/crc/constants"
 	"github.com/code-ready/crc/pkg/crc/logging"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/oc"
 	crcssh "github.com/code-ready/crc/pkg/crc/ssh"
 	"github.com/code-ready/machine/libmachine/state"
 	"github.com/pkg/errors"
 )
 
-func (client *client) Status() (*ClusterStatusResult, error) {
+func (client *client) Status() (*types.ClusterStatusResult, error) {
 	libMachineAPIClient, cleanup := createLibMachineClient()
 	defer cleanup()
 
@@ -34,7 +35,7 @@ func (client *client) Status() (*ClusterStatusResult, error) {
 	}
 
 	if vmStatus != state.Running {
-		return &ClusterStatusResult{
+		return &types.ClusterStatusResult{
 			CrcStatus:        vmStatus,
 			OpenshiftStatus:  "Stopped",
 			OpenshiftVersion: crcBundleMetadata.GetOpenshiftVersion(),
@@ -55,7 +56,7 @@ func (client *client) Status() (*ClusterStatusResult, error) {
 	if err != nil {
 		logging.Debugf("Cannot get root partition usage: %v", err)
 	}
-	return &ClusterStatusResult{
+	return &types.ClusterStatusResult{
 		CrcStatus:        state.Running,
 		OpenshiftStatus:  getOpenShiftStatus(sshRunner, client.monitoringEnabled()),
 		OpenshiftVersion: crcBundleMetadata.GetOpenshiftVersion(),
diff --git a/pkg/crc/machine/types.go b/pkg/crc/machine/types/types.go
similarity index 98%
rename from pkg/crc/machine/types.go
rename to pkg/crc/machine/types/types.go
index 196bd07fa..6bb212e75 100644
--- a/pkg/crc/machine/types.go
+++ b/pkg/crc/machine/types/types.go
@@ -1,4 +1,4 @@
-package machine
+package types
 
 import (
 	"github.com/code-ready/crc/pkg/crc/cluster"
diff --git a/pkg/crc/machine/vsock.go b/pkg/crc/machine/vsock.go
index b45b030c2..b09601ec5 100644
--- a/pkg/crc/machine/vsock.go
+++ b/pkg/crc/machine/vsock.go
@@ -12,7 +12,7 @@ import (
 func exposePorts() error {
 	daemonClient := daemonclient.New()
 	portsToExpose := vsockPorts()
-	alreadyOpenedPorts, err := daemonClient.List()
+	alreadyOpenedPorts, err := daemonClient.NetworkClient.List()
 	if err != nil {
 		return err
 	}
@@ -24,7 +24,7 @@ func exposePorts() error {
 	}
 	for i := range missingPorts {
 		port := &missingPorts[i]
-		if err := daemonClient.Expose(port); err != nil {
+		if err := daemonClient.NetworkClient.Expose(port); err != nil {
 			return errors.Wrapf(err, "failed to expose port %s -> %s", port.Local, port.Remote)
 		}
 	}


Test patch:
diff --git a/pkg/crc/api/api_http_test.go b/pkg/crc/api/api_http_test.go
index 9be5e88f4..8b1025dec 100644
--- a/pkg/crc/api/api_http_test.go
+++ b/pkg/crc/api/api_http_test.go
@@ -6,8 +6,8 @@ import (
 	"testing"
 
 	apiClient "github.com/code-ready/crc/pkg/crc/api/client"
-	"github.com/code-ready/crc/pkg/crc/machine"
 	"github.com/code-ready/crc/pkg/crc/machine/fakemachine"
+	"github.com/code-ready/crc/pkg/crc/machine/types"
 	"github.com/code-ready/crc/pkg/crc/version"
 	"github.com/stretchr/testify/assert"
 )
@@ -59,7 +59,7 @@ func TestHTTPApi(t *testing.T) {
 			Status:         "",
 			Error:          "",
 			KubeletStarted: true,
-			ClusterConfig: machine.ClusterConfig{
+			ClusterConfig: types.ClusterConfig{
 				ClusterCACert: "MIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJ",
 				KubeConfig:    "/tmp/kubeconfig",
 				KubeAdminPass: "foobar",