Repository: code-ready/crc
Pull request #1978 (2021-02-11 04:39:53)

Use HTTP to serve the daemon api
**Fixes:** #1914 

Needs #1993 

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

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

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: @anjannath: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci[bot]: @anjannath: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | f0f7fa311c348b66b53ca54470072e49da432167 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1359723814073667584) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @anjannath: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | f0f7fa311c348b66b53ca54470072e49da432167 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1359723814073667584) | `/test images`
ci/prow/e2e-crc | f0f7fa311c348b66b53ca54470072e49da432167 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-e2e-crc/1359723814040113152) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @anjannath: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/e2e-crc | 40b707f6f764d81580a237a3063799e91eed2cf3 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-e2e-crc/1359787623127715840) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anjannath: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci-robot: @anjannath: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci[bot]: @anjannath: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 179596e6bb6e4f3a513cceb9eedc616907b1183c | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1371385625537679360) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @anjannath: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | 179596e6bb6e4f3a513cceb9eedc616907b1183c | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1371385625537679360) | `/test images`
ci/prow/e2e-crc | 179596e6bb6e4f3a513cceb9eedc616907b1183c | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-e2e-crc/1371385625508319232) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci-robot: @anjannath: PR needs rebase.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository.
</details>
openshift-ci[bot]: @anjannath: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | a5e3ec328e6017b4fb9bfa397ce33437eb9cb175 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1372073415183175680) | `/test images`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
openshift-ci[bot]: @anjannath: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ci/prow/images | a5e3ec328e6017b4fb9bfa397ce33437eb9cb175 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-images/1372073415183175680) | `/test images`
ci/prow/e2e-crc | a5e3ec328e6017b4fb9bfa397ce33437eb9cb175 | [link](https://prow.ci.openshift.org/view/gs/origin-ci-test/pr-logs/pull/code-ready_crc/1978/pull-ci-code-ready-crc-master-e2e-crc/1372073415141232640) | `/test e2e-crc`

[Full PR test history](https://prow.ci.openshift.org/pr-history?org=code-ready&repo=crc&pr=1978). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:anjannath).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
guillaumerose: Thanks! 

/lgtm

Patch:
diff --git a/cmd/crc/cmd/config/config.go b/cmd/crc/cmd/config/config.go
index b27cc2e5e..317ec9d2f 100644
--- a/cmd/crc/cmd/config/config.go
+++ b/cmd/crc/cmd/config/config.go
@@ -3,6 +3,7 @@ package config
 import (
 	"bytes"
 	"fmt"
+	"runtime"
 	"sort"
 	"strings"
 	"text/tabwriter"
@@ -36,6 +37,16 @@ const (
 )
 
 func RegisterSettings(cfg *config.Config) {
+	validateTrayAutostart := func(value interface{}) (bool, string) {
+		if runtime.GOOS != "darwin" {
+			return false, "Tray autostart is only supported on macOS"
+		}
+		if !cfg.Get(ExperimentalFeatures).AsBool() {
+			return false, fmt.Sprintf("'%s' must be enabled in order to use the tray", ExperimentalFeatures)
+		}
+		return config.ValidateBool(value)
+	}
+
 	validateHostNetworkAccess := func(value interface{}) (bool, string) {
 		mode := network.ParseMode(cfg.Get(NetworkMode).AsString())
 		if mode != network.VSockMode {
@@ -84,7 +95,7 @@ func RegisterSettings(cfg *config.Config) {
 	cfg.AddSetting(HostNetworkAccess, false, validateHostNetworkAccess, config.SuccessfullyApplied,
 		"Allow TCP/IP connections from the CodeReady Containers VM to services running on the host (true/false, default: false)")
 	// System tray auto-start config
-	cfg.AddSetting(AutostartTray, true, tray.ValidateTrayAutostart, disableEnableTrayAutostart,
+	cfg.AddSetting(AutostartTray, true, validateTrayAutostart, disableEnableTrayAutostart,
 		"Automatically start the tray (true/false, default: true)")
 	// Proxy Configuration
 	cfg.AddSetting(HTTPProxy, "", config.ValidateURI, config.SuccessfullyApplied,
diff --git a/cmd/crc/cmd/daemon.go b/cmd/crc/cmd/daemon.go
index a5e7bea32..fec7cd2a3 100644
--- a/cmd/crc/cmd/daemon.go
+++ b/cmd/crc/cmd/daemon.go
@@ -122,6 +122,7 @@ func run(configuration *types.Configuration) error {
 		}
 		mux := http.NewServeMux()
 		mux.Handle("/network/", http.StripPrefix("/network", vn.Mux()))
+		mux.Handle("/api/", http.StripPrefix("/api", api.NewMux(config, newMachine())))
 		if err := http.Serve(listener, mux); err != nil {
 			errCh <- err
 		}
diff --git a/cmd/crc/cmd/delete.go b/cmd/crc/cmd/delete.go
index 01a31ea31..80dba55e7 100644
--- a/cmd/crc/cmd/delete.go
+++ b/cmd/crc/cmd/delete.go
@@ -9,6 +9,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/input"
+	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/code-ready/crc/pkg/crc/machine"
 	"github.com/spf13/cobra"
 )
@@ -53,7 +54,10 @@ func deleteMachine(client machine.Client, clearCache bool, cacheDir string, inte
 
 	yes := input.PromptUserForYesOrNo("Do you want to delete the OpenShift cluster", force)
 	if yes {
-		return true, client.Delete()
+		if err := client.Delete(); err != nil {
+			return true, err
+		}
+		return true, logging.BackupLogFile()
 	}
 	return false, nil
 }
diff --git a/docs/source/meta/product-attributes.adoc b/docs/source/meta/product-attributes.adoc
index 4aa3b7356..77db6ab14 100644
--- a/docs/source/meta/product-attributes.adoc
+++ b/docs/source/meta/product-attributes.adoc
@@ -36,3 +36,5 @@
 :odo-docs-url: https://docs.openshift.com/container-platform/latest/cli_reference/developer_cli_odo/understanding-odo.html
 :odo-docs-url-installing: https://docs.openshift.com/container-platform/latest/cli_reference/developer_cli_odo/installing-odo.html
 :odo-docs-url-single-component: https://docs.openshift.com/container-platform/latest/cli_reference/developer_cli_odo/creating_and_deploying_applications_with_odo/creating-a-single-component-application-with-odo.html
+
+:rhel-resolved-docs: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/using-different-dns-servers-for-different-domains_configuring-and-managing-networking
diff --git a/docs/source/topics/ref_dns-configuration.adoc b/docs/source/topics/ref_dns-configuration.adoc
index b80b654f8..1ff4d1c5e 100644
--- a/docs/source/topics/ref_dns-configuration.adoc
+++ b/docs/source/topics/ref_dns-configuration.adoc
@@ -29,6 +29,7 @@ This configuration is used on Fedora 33 or newer, and on Ubuntu Desktop editions
 * `systemd-resolved` configuration is done through a NetworkManager dispatcher script in `/etc/NetworkManager/dispatcher.d/99-crc.sh`:
 +
 ----
+#!/bin/sh
 resolvectl domain crc ~testing
 resolvectl dns crc 192.168.130.11
 resolvectl default-route crc false
@@ -36,6 +37,19 @@ resolvectl default-route crc false
 exit 0
 ----
 
+[NOTE]
+====
+`systemd-resolved` is also available as an unsupported Technology Preview on {rhel} and {centos} 8.3. After {rhel-resolved-docs}[configuring the host] to use `systemd-resolved`, any {prod} `dnsmasq` configurations need to be removed and the above script needs to be created with executable permissions.
+
+Configure the {prod} binary to skip startup checks for `dnsmasq` and NetworkManager configuration:
+
+[subs="+quotes,attributes"]
+----
+$ {bin} config set skip-check-crc-dnsmasq-file true
+$ {bin} config set skip-check-network-manager-config true
+----
+====
+
 === NetworkManager + dnsmasq
 
 This configuration is used on Fedora 32 or older, on {rhel}, and on {centos}.
diff --git a/go.mod b/go.mod
index 7b12e73c0..c09f66afd 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/cavaliercoder/grab v2.0.0+incompatible
 	github.com/cheggaaa/pb/v3 v3.0.5
 	github.com/code-ready/clicumber v0.0.0-20210201104241-cecb794bdf9a
-	github.com/code-ready/gvisor-tap-vsock v0.0.0-20210216090540-914d522b9c38
+	github.com/code-ready/gvisor-tap-vsock v0.0.0-20210308122700-d61f9aac135c
 	github.com/code-ready/machine v0.0.0-20210122113819-281ccfbb4566
 	github.com/cucumber/godog v0.9.0
 	github.com/cucumber/messages-go/v10 v10.0.3
diff --git a/go.sum b/go.sum
index 534a6fef9..9f3ba956c 100644
--- a/go.sum
+++ b/go.sum
@@ -163,8 +163,8 @@ github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/code-ready/clicumber v0.0.0-20210201104241-cecb794bdf9a h1:VOQmCj9Y8pAPU4C0rIvF2ByUBuuqnaR9JSvb9C8uBQE=
 github.com/code-ready/clicumber v0.0.0-20210201104241-cecb794bdf9a/go.mod h1:ZPZUcYGpv/FQGnwakUuhiHP9x/IIcU2SKbn8xPe4ROc=
-github.com/code-ready/gvisor-tap-vsock v0.0.0-20210216090540-914d522b9c38 h1:vo1A+Tvie+BVZoSyYOzShDH6ieQkD1Q9l4JeeC0jCxA=
-github.com/code-ready/gvisor-tap-vsock v0.0.0-20210216090540-914d522b9c38/go.mod h1:DsNrkk0GUSTqt0E/4/GMvjqsP7ns++O/6YaJn/TDBVM=
+github.com/code-ready/gvisor-tap-vsock v0.0.0-20210308122700-d61f9aac135c h1:UOg6w7Uv5hWvFVABjJpawCEmAK99vG96SozUaulqVCk=
+github.com/code-ready/gvisor-tap-vsock v0.0.0-20210308122700-d61f9aac135c/go.mod h1:DsNrkk0GUSTqt0E/4/GMvjqsP7ns++O/6YaJn/TDBVM=
 github.com/code-ready/machine v0.0.0-20210122113819-281ccfbb4566 h1:zBDinebc2kFq99UNTmLmTRfgxcxC6YieKQuXDRCljzw=
 github.com/code-ready/machine v0.0.0-20210122113819-281ccfbb4566/go.mod h1:4JgMqho7KuxFifYCIi7cKVmh4yA2l0QHOPftv9f5PNc=
 github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
diff --git a/pkg/crc/api/adapter.go b/pkg/crc/api/adapter.go
index 1334d592c..4abcb41e8 100644
--- a/pkg/crc/api/adapter.go
+++ b/pkg/crc/api/adapter.go
@@ -3,6 +3,7 @@ package api
 import (
 	"context"
 
+	"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/machine/libmachine/state"
@@ -10,43 +11,11 @@ import (
 
 type AdaptedClient interface {
 	GetName() string
-
-	Delete() Result
-	GetConsoleURL() ConsoleResult
-	Start(ctx context.Context, startConfig machine.StartConfig) StartResult
-	Status() ClusterStatusResult
-	Stop() Result
-}
-
-type Result struct {
-	Name    string
-	Success bool
-	Error   string
-}
-
-type StartResult struct {
-	Name           string
-	Status         string
-	Error          string
-	ClusterConfig  machine.ClusterConfig
-	KubeletStarted bool
-}
-
-type ClusterStatusResult struct {
-	Name             string
-	CrcStatus        string
-	OpenshiftStatus  string
-	OpenshiftVersion string
-	DiskUse          int64
-	DiskSize         int64
-	Error            string
-	Success          bool
-}
-
-type ConsoleResult struct {
-	ClusterConfig machine.ClusterConfig
-	Success       bool
-	Error         string
+	Delete() client.Result
+	GetConsoleURL() client.ConsoleResult
+	Start(ctx context.Context, startConfig machine.StartConfig) client.StartResult
+	Status() client.ClusterStatusResult
+	Stop() client.Result
 }
 
 type Adapter struct {
@@ -57,47 +26,47 @@ func (a *Adapter) GetName() string {
 	return a.Underlying.GetName()
 }
 
-func (a *Adapter) Delete() Result {
+func (a *Adapter) Delete() client.Result {
 	err := a.Underlying.Delete()
 	if err != nil {
 		logging.Error(err)
-		return Result{
+		return client.Result{
 			Name:    a.Underlying.GetName(),
 			Success: false,
 			Error:   err.Error(),
 		}
 	}
-	return Result{
+	return client.Result{
 		Name:    a.Underlying.GetName(),
 		Success: true,
 	}
 }
 
-func (a *Adapter) GetConsoleURL() ConsoleResult {
+func (a *Adapter) GetConsoleURL() client.ConsoleResult {
 	res, err := a.Underlying.GetConsoleURL()
 	if err != nil {
 		logging.Error(err)
-		return ConsoleResult{
+		return client.ConsoleResult{
 			Success: false,
 			Error:   err.Error(),
 		}
 	}
-	return ConsoleResult{
+	return client.ConsoleResult{
 		ClusterConfig: res.ClusterConfig,
 		Success:       true,
 	}
 }
 
-func (a *Adapter) Start(ctx context.Context, startConfig machine.StartConfig) StartResult {
+func (a *Adapter) Start(ctx context.Context, startConfig machine.StartConfig) client.StartResult {
 	res, err := a.Underlying.Start(ctx, startConfig)
 	if err != nil {
 		logging.Error(err)
-		return StartResult{
+		return client.StartResult{
 			Name:  a.Underlying.GetName(),
 			Error: err.Error(),
 		}
 	}
-	return StartResult{
+	return client.StartResult{
 		Name:           a.Underlying.GetName(),
 		Status:         res.Status.String(),
 		ClusterConfig:  res.ClusterConfig,
@@ -105,17 +74,17 @@ func (a *Adapter) Start(ctx context.Context, startConfig machine.StartConfig) St
 	}
 }
 
-func (a *Adapter) Status() ClusterStatusResult {
+func (a *Adapter) Status() client.ClusterStatusResult {
 	res, err := a.Underlying.Status()
 	if err != nil {
 		logging.Error(err)
-		return ClusterStatusResult{
+		return client.ClusterStatusResult{
 			Name:    a.Underlying.GetName(),
 			Error:   err.Error(),
 			Success: false,
 		}
 	}
-	return ClusterStatusResult{
+	return client.ClusterStatusResult{
 		Name:             a.Underlying.GetName(),
 		CrcStatus:        res.CrcStatus.String(),
 		OpenshiftStatus:  res.OpenshiftStatus,
@@ -126,7 +95,7 @@ func (a *Adapter) Status() ClusterStatusResult {
 	}
 }
 
-func (a *Adapter) Stop() Result {
+func (a *Adapter) Stop() client.Result {
 	vmState, err := a.Underlying.Stop()
 	if err != nil {
 		logging.Error(err)
@@ -134,7 +103,7 @@ func (a *Adapter) Stop() Result {
 			err := a.Underlying.PowerOff()
 			if err != nil {
 				logging.Error(err)
-				return Result{
+				return client.Result{
 					Name:    a.Underlying.GetName(),
 					Success: false,
 					Error:   err.Error(),
@@ -142,7 +111,7 @@ func (a *Adapter) Stop() Result {
 			}
 		}
 	}
-	return Result{
+	return client.Result{
 		Name:    a.Underlying.GetName(),
 		Success: true,
 	}
diff --git a/pkg/crc/api/api_http.go b/pkg/crc/api/api_http.go
new file mode 100644
index 000000000..f0d0eb7e6
--- /dev/null
+++ b/pkg/crc/api/api_http.go
@@ -0,0 +1,150 @@
+package api
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"strings"
+
+	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 NewMux(config crcConfig.Storage, machine machine.Client) http.Handler {
+	handler := NewHandler(config, machine)
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/start", func(w http.ResponseWriter, r *http.Request) {
+		var startResult string
+		data, err := verifyRequestAndReadBody(w, r, http.MethodGet, http.MethodPost)
+		if err != nil {
+			return
+		}
+		if len(data) > 0 {
+			startResult = handler.Start(data)
+		} else {
+			startResult = handler.Start(nil)
+		}
+		sendResponse(w, startResult)
+	})
+
+	mux.HandleFunc("/stop", func(w http.ResponseWriter, r *http.Request) {
+		if wrongHTTPMethodUsed(r, w, http.MethodGet) {
+			return
+		}
+		stopResult := handler.Stop()
+		sendResponse(w, stopResult)
+	})
+
+	mux.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
+		if wrongHTTPMethodUsed(r, w, http.MethodGet) {
+			return
+		}
+		status := handler.Status()
+		sendResponse(w, status)
+	})
+
+	mux.HandleFunc("/delete", func(w http.ResponseWriter, r *http.Request) {
+		if wrongHTTPMethodUsed(r, w, http.MethodGet) {
+			return
+		}
+		deleteResult := handler.Delete()
+		sendResponse(w, deleteResult)
+	})
+
+	mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) {
+		if wrongHTTPMethodUsed(r, w, http.MethodGet) {
+			return
+		}
+		versionResult := handler.GetVersion()
+		sendResponse(w, versionResult)
+	})
+
+	mux.HandleFunc("/webconsoleurl", func(w http.ResponseWriter, r *http.Request) {
+		if wrongHTTPMethodUsed(r, w, http.MethodGet) {
+			return
+		}
+		webconsoleInfo := handler.GetWebconsoleInfo()
+		sendResponse(w, webconsoleInfo)
+	})
+
+	mux.Handle("/config/", http.StripPrefix("/config", newConfigMux(handler)))
+
+	return mux
+}
+
+func newConfigMux(handler *Handler) http.Handler {
+	mux := http.NewServeMux()
+
+	mux.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
+		var configGetResult string
+		data, err := verifyRequestAndReadBody(w, r, http.MethodGet, http.MethodPost)
+		if err != nil {
+			return
+		}
+		if len(data) > 0 {
+			configGetResult = handler.GetConfig(data)
+		} else {
+			configGetResult = handler.GetConfig(nil)
+		}
+		sendResponse(w, configGetResult)
+	})
+
+	mux.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
+		handleConfigSetUnset(w, r, func(data []byte) string { return handler.SetConfig(data) })
+	})
+
+	mux.HandleFunc("/unset", func(w http.ResponseWriter, r *http.Request) {
+		handleConfigSetUnset(w, r, func(data []byte) string { return handler.UnsetConfig(data) })
+	})
+
+	return mux
+}
+
+func wrongHTTPMethodUsed(r *http.Request, w http.ResponseWriter, allowedMethods ...string) bool {
+	for _, method := range allowedMethods {
+		if r.Method == method {
+			return false
+		}
+	}
+	logging.Debugf("Wrong method: %s used for request to: %s", r.Method, r.RequestURI)
+	http.Error(w, fmt.Sprintf("Only %s is allowed.", strings.Join(allowedMethods, ",")), http.StatusMethodNotAllowed)
+	return true
+}
+
+func sendResponse(w http.ResponseWriter, response string) {
+	w.Header().Set("Content-Type", "application/json")
+	if _, err := io.WriteString(w, response); err != nil {
+		logging.Error("Failed to send response: ", err)
+	}
+}
+
+func handleConfigSetUnset(w http.ResponseWriter, r *http.Request, fn func([]byte) string) {
+	data, err := verifyRequestAndReadBody(w, r, http.MethodPost)
+	if err != nil {
+		return
+	}
+	if len(data) < 1 {
+		http.Error(w, "Not enough arguments for /config/(un)set", http.StatusBadRequest)
+		return
+	}
+
+	result := fn(data)
+	sendResponse(w, result)
+}
+
+func verifyRequestAndReadBody(w http.ResponseWriter, r *http.Request, method ...string) ([]byte, error) {
+	if wrongHTTPMethodUsed(r, w, method...) {
+		return nil, fmt.Errorf("Wrong HTTP method used")
+	}
+
+	data, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		logging.Debugf("Unable to read request body for URI: %s", r.RequestURI)
+		http.Error(w, "Unable to read request body", http.StatusInternalServerError)
+		return nil, err
+	}
+	return data, nil
+}
diff --git a/pkg/crc/api/client/client.go b/pkg/crc/api/client/client.go
new file mode 100644
index 000000000..ed34ef7de
--- /dev/null
+++ b/pkg/crc/api/client/client.go
@@ -0,0 +1,236 @@
+package client
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net/http"
+
+	"github.com/code-ready/crc/pkg/crc/logging"
+)
+
+type Client struct {
+	client *http.Client
+	base   string
+}
+
+func New(client *http.Client, baseURL string) *Client {
+	return &Client{
+		client: client,
+		base:   baseURL,
+	}
+}
+
+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
+}
+
+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
+}
+
+func (c *Client) Start(config StartConfig) (StartResult, error) {
+	var sr = StartResult{}
+	var data = new(bytes.Buffer)
+
+	if config != (StartConfig{}) {
+		if err := json.NewEncoder(data).Encode(config); err != nil {
+			return sr, fmt.Errorf("Failed to encode data to JSON: %w", err)
+		}
+	}
+	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
+}
+
+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
+}
+
+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
+}
+
+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
+}
+
+func (c *Client) GetConfig(configs []string) (GetConfigResult, error) {
+	var gcr = GetConfigResult{}
+	var data = new(bytes.Buffer)
+
+	if len(configs) > 0 {
+		cfg := getOrUnsetConfigRequest{
+			Properties: configs,
+		}
+		if err := json.NewEncoder(data).Encode(cfg); err != nil {
+			return gcr, fmt.Errorf("Failed to encode data to JSON: %w", err)
+		}
+	}
+	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
+}
+
+func (c *Client) SetConfig(configs SetConfigRequest) (SetOrUnsetConfigResult, error) {
+	var scr = SetOrUnsetConfigResult{}
+	var data = new(bytes.Buffer)
+
+	if len(configs.Properties) == 0 {
+		return scr, fmt.Errorf("No config key value pair provided to set")
+	}
+
+	if err := json.NewEncoder(data).Encode(configs); err != nil {
+		return scr, fmt.Errorf("Failed to encode data to JSON: %w", err)
+	}
+
+	body, err := c.sendPostRequest("/config/set", data)
+	if err != nil {
+		logging.Error(err)
+		return scr, err
+	}
+
+	err = json.Unmarshal(body, &scr)
+	if err != nil {
+		return scr, err
+	}
+	return scr, nil
+}
+
+func (c *Client) UnsetConfig(configs []string) (SetOrUnsetConfigResult, error) {
+	var ucr = SetOrUnsetConfigResult{}
+	var data = new(bytes.Buffer)
+
+	cfg := getOrUnsetConfigRequest{
+		Properties: configs,
+	}
+	if err := json.NewEncoder(data).Encode(cfg); err != nil {
+		return ucr, fmt.Errorf("Failed to encode data to JSON: %w", err)
+	}
+	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
+}
+
+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 {
+		return nil, fmt.Errorf("Error occurred sending GET request to : %s : %d", url, res.StatusCode)
+	}
+	defer res.Body.Close()
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return nil, fmt.Errorf("Unknown error reading response: %w", err)
+	}
+	return body, nil
+}
+
+func (c *Client) sendPostRequest(url string, data io.Reader) ([]byte, error) {
+	req, err := http.NewRequest("POST", fmt.Sprintf("%s%s", c.base, url), data)
+	if err != nil {
+		return nil, err
+	}
+	req.Header.Set("Content-Type", "application/json")
+
+	res, err := c.client.Do(req)
+	if err != nil {
+		logging.Error(err)
+		return nil, err
+	}
+	if res.StatusCode != http.StatusOK {
+		return nil, fmt.Errorf("Error occurred sending POST request to : %s : %d", url, res.StatusCode)
+	}
+
+	defer res.Body.Close()
+
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return nil, fmt.Errorf("Unknown error reading response: %w", err)
+	}
+	return body, nil
+}
diff --git a/pkg/crc/api/client/types.go b/pkg/crc/api/client/types.go
new file mode 100644
index 000000000..5767ae969
--- /dev/null
+++ b/pkg/crc/api/client/types.go
@@ -0,0 +1,68 @@
+package client
+
+import (
+	"github.com/code-ready/crc/pkg/crc/machine"
+)
+
+type VersionResult struct {
+	CrcVersion       string
+	CommitSha        string
+	OpenshiftVersion string
+	Success          bool
+}
+
+type Result struct {
+	Name    string
+	Success bool
+	Error   string
+}
+
+type StartResult struct {
+	Name           string
+	Status         string
+	Error          string
+	ClusterConfig  machine.ClusterConfig
+	KubeletStarted bool
+}
+
+type ClusterStatusResult struct {
+	Name             string
+	CrcStatus        string
+	OpenshiftStatus  string
+	OpenshiftVersion string
+	DiskUse          int64
+	DiskSize         int64
+	Error            string
+	Success          bool
+}
+
+type ConsoleResult struct {
+	ClusterConfig machine.ClusterConfig
+	Success       bool
+	Error         string
+}
+
+// setOrUnsetConfigResult struct is used to return the result of
+// setconfig/unsetconfig command
+type SetOrUnsetConfigResult struct {
+	Error      string
+	Properties []string
+}
+
+// getConfigResult struct is used to return the result of getconfig command
+type GetConfigResult struct {
+	Error   string
+	Configs map[string]interface{}
+}
+
+type StartConfig struct {
+	PullSecretPath string
+}
+
+type SetConfigRequest struct {
+	Properties map[string]interface{} `json:"properties"`
+}
+
+type getOrUnsetConfigRequest struct {
+	Properties []string `json:"properties"`
+}
diff --git a/pkg/crc/api/handlers.go b/pkg/crc/api/handlers.go
index 5eb57df20..d862cb54b 100644
--- a/pkg/crc/api/handlers.go
+++ b/pkg/crc/api/handlers.go
@@ -7,6 +7,7 @@ import (
 	"fmt"
 
 	"github.com/code-ready/crc/cmd/crc/cmd/config"
+	"github.com/code-ready/crc/pkg/crc/api/client"
 	"github.com/code-ready/crc/pkg/crc/cluster"
 	crcConfig "github.com/code-ready/crc/pkg/crc/config"
 	"github.com/code-ready/crc/pkg/crc/errors"
@@ -33,6 +34,15 @@ func (h *Handler) Logs() string {
 	})
 }
 
+func NewHandler(config crcConfig.Storage, machine machine.Client) *Handler {
+	return &Handler{
+		MachineClient: &Adapter{
+			Underlying: machine,
+		},
+		Config: config,
+	}
+}
+
 func (h *Handler) Status() string {
 	clusterStatus := h.MachineClient.Status()
 	return encodeStructToJSON(clusterStatus)
@@ -49,7 +59,7 @@ func (h *Handler) Start(args json.RawMessage) string {
 	if args != nil {
 		parsedArgs, err = parseStartArgs(args)
 		if err != nil {
-			startErr := &StartResult{
+			startErr := &client.StartResult{
 				Name:  h.MachineClient.GetName(),
 				Error: fmt.Sprintf("Incorrect arguments given: %s", err.Error()),
 			}
@@ -57,7 +67,7 @@ func (h *Handler) Start(args json.RawMessage) string {
 		}
 	}
 	if err := preflight.StartPreflightChecks(h.Config); err != nil {
-		startErr := &StartResult{
+		startErr := &client.StartResult{
 			Name:  h.MachineClient.GetName(),
 			Error: err.Error(),
 		}
@@ -89,15 +99,8 @@ func getStartConfig(cfg crcConfig.Storage, args startArgs) machine.StartConfig {
 	}
 }
 
-type VersionResult struct {
-	CrcVersion       string
-	CommitSha        string
-	OpenshiftVersion string
-	Success          bool
-}
-
 func (h *Handler) GetVersion() string {
-	v := &VersionResult{
+	v := &client.VersionResult{
 		CrcVersion:       version.GetCRCVersion(),
 		CommitSha:        version.GetCommitSha(),
 		OpenshiftVersion: version.GetBundleVersion(),
@@ -117,7 +120,7 @@ func (h *Handler) GetWebconsoleInfo() string {
 }
 
 func (h *Handler) SetConfig(args json.RawMessage) string {
-	setConfigResult := setOrUnsetConfigResult{}
+	setConfigResult := client.SetOrUnsetConfigResult{}
 	if args == nil {
 		setConfigResult.Error = "No config keys provided"
 		return encodeStructToJSON(setConfigResult)
@@ -155,7 +158,7 @@ func (h *Handler) SetConfig(args json.RawMessage) string {
 }
 
 func (h *Handler) UnsetConfig(args json.RawMessage) string {
-	unsetConfigResult := setOrUnsetConfigResult{}
+	unsetConfigResult := client.SetOrUnsetConfigResult{}
 	if args == nil {
 		unsetConfigResult.Error = "No config keys provided"
 		return encodeStructToJSON(unsetConfigResult)
@@ -190,7 +193,7 @@ func (h *Handler) UnsetConfig(args json.RawMessage) string {
 }
 
 func (h *Handler) GetConfig(args json.RawMessage) string {
-	configResult := getConfigResult{}
+	configResult := client.GetConfigResult{}
 	if args == nil {
 		allConfigs := h.Config.AllConfigs()
 		configResult.Error = ""
@@ -234,7 +237,7 @@ func encodeStructToJSON(v interface{}) string {
 	s, err := json.Marshal(v)
 	if err != nil {
 		logging.Error(err.Error())
-		err := Result{
+		err := client.Result{
 			Success: false,
 			Error:   "Failed while encoding JSON to string",
 		}
@@ -245,7 +248,7 @@ func encodeStructToJSON(v interface{}) string {
 }
 
 func encodeErrorToJSON(errMsg string) string {
-	err := Result{
+	err := client.Result{
 		Success: false,
 		Error:   errMsg,
 	}
diff --git a/pkg/crc/api/types.go b/pkg/crc/api/types.go
index 4909dfc29..c4aa6cac2 100644
--- a/pkg/crc/api/types.go
+++ b/pkg/crc/api/types.go
@@ -36,19 +36,6 @@ type commandRequest struct {
 	Args    json.RawMessage `json:"args,omitempty"`
 }
 
-// setOrUnsetConfigResult struct is used to return the result of
-// setconfig/unsetconfig command
-type setOrUnsetConfigResult struct {
-	Error      string
-	Properties []string
-}
-
-// getConfigResult struct is used to return the result of getconfig command
-type getConfigResult struct {
-	Error   string
-	Configs map[string]interface{}
-}
-
 // startArgs is used to get the pull secret file path as argument for start handler
 type startArgs struct {
 	PullSecretFile string `json:"pullSecretFile"`
diff --git a/pkg/crc/constants/constants.go b/pkg/crc/constants/constants.go
index ff968e833..447f77687 100644
--- a/pkg/crc/constants/constants.go
+++ b/pkg/crc/constants/constants.go
@@ -27,10 +27,11 @@ const (
 	DaemonLogFile             = "crcd.log"
 	CrcLandingPageURL         = "https://cloud.redhat.com/openshift/create/local" // #nosec G101
 	DefaultPodmanURLBase      = "https://storage.googleapis.com/libpod-master-releases"
-	DefaultAdminHelperCliBase = "https://github.com/code-ready/admin-helper/releases/download/0.0.2"
+	DefaultAdminHelperCliBase = "https://github.com/code-ready/admin-helper/releases/download/0.0.3"
 	CRCMacTrayDownloadURL     = "https://github.com/code-ready/tray-macos/releases/download/v%s/crc-tray-macos.tar.gz"
 	CRCWindowsTrayDownloadURL = "https://github.com/code-ready/tray-windows/releases/download/v%s/crc-tray-windows.zip"
 	DefaultContext            = "admin"
+	DaemonHTTPEndpoint        = "http://unix/api"
 
 	VSockGateway = "192.168.127.1"
 	VsockSSHPort = 2222
diff --git a/pkg/crc/logging/logging.go b/pkg/crc/logging/logging.go
index 8645dc33d..f5d7bb797 100644
--- a/pkg/crc/logging/logging.go
+++ b/pkg/crc/logging/logging.go
@@ -34,8 +34,11 @@ func CloseLogging() {
 	logrus.StandardLogger().ReplaceHooks(make(logrus.LevelHooks))
 }
 
-func BackupLogFile() {
-	os.Rename(logfile.Name(), fmt.Sprintf("%s_%s", logfile.Name(), time.Now().Format("20060102150405"))) // nolint
+func BackupLogFile() error {
+	if logfile == nil {
+		return nil
+	}
+	return os.Rename(logfile.Name(), fmt.Sprintf("%s_%s", logfile.Name(), time.Now().Format("20060102150405")))
 }
 
 func InitLogrus(logLevel, logFilePath string) {
diff --git a/pkg/crc/machine/delete.go b/pkg/crc/machine/delete.go
index ca24ad5f1..535ea55ec 100644
--- a/pkg/crc/machine/delete.go
+++ b/pkg/crc/machine/delete.go
@@ -1,13 +1,11 @@
 package machine
 
 import (
-	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/pkg/errors"
 )
 
 func (client *client) Delete() error {
 	libMachineAPIClient, cleanup := createLibMachineClient()
-	defer logging.BackupLogFile()
 	defer cleanup()
 	host, err := libMachineAPIClient.Load(client.name)
 
diff --git a/pkg/crc/machine/hyperkit/constants.go b/pkg/crc/machine/hyperkit/constants.go
index a3cfe45f8..c11fcca8a 100644
--- a/pkg/crc/machine/hyperkit/constants.go
+++ b/pkg/crc/machine/hyperkit/constants.go
@@ -6,7 +6,7 @@ import "fmt"
 
 const (
 	MachineDriverCommand = "crc-driver-hyperkit"
-	MachineDriverVersion = "0.12.11"
+	MachineDriverVersion = "0.12.12"
 	HyperKitCommand      = "hyperkit"
 	HyperKitVersion      = "v0.20200224-44-gb54460"
 )
diff --git a/pkg/crc/preflight/preflight_darwin.go b/pkg/crc/preflight/preflight_darwin.go
index a61486ea7..47ab3b07e 100644
--- a/pkg/crc/preflight/preflight_darwin.go
+++ b/pkg/crc/preflight/preflight_darwin.go
@@ -113,7 +113,7 @@ func getAllPreflightChecks() []Check {
 	return getPreflightChecks(true, true, network.DefaultMode)
 }
 
-func getPreflightChecks(_ bool, trayAutostart bool, mode network.Mode) []Check {
+func getPreflightChecks(experimentalFeatures bool, trayAutostart bool, mode network.Mode) []Check {
 	checks := []Check{}
 
 	checks = append(checks, nonWinPreflightChecks[:]...)
@@ -121,18 +121,20 @@ func getPreflightChecks(_ bool, trayAutostart bool, mode network.Mode) []Check {
 	checks = append(checks, hyperkitPreflightChecks(mode)...)
 	checks = append(checks, dnsPreflightChecks[:]...)
 
-	if trayAutostart || mode == network.VSockMode {
+	switch mode {
+	case network.DefaultMode:
+		checks = append(checks, resolverPreflightChecks[:]...)
+	case network.VSockMode:
 		checks = append(checks, daemonSetupChecks[:]...)
 	}
 
-	if trayAutostart {
+	if experimentalFeatures && trayAutostart {
+		if mode != network.VSockMode {
+			checks = append(checks, daemonSetupChecks[:]...)
+		}
 		checks = append(checks, traySetupChecks[:]...)
 	}
 
-	if mode == network.DefaultMode {
-		checks = append(checks, resolverPreflightChecks[:]...)
-	}
-
 	checks = append(checks, bundleCheck)
 	return checks
 }
diff --git a/pkg/crc/version/version.go b/pkg/crc/version/version.go
index 445a9f0ca..f74991867 100644
--- a/pkg/crc/version/version.go
+++ b/pkg/crc/version/version.go
@@ -29,7 +29,7 @@ var (
 const (
 	releaseInfoLink = "https://mirror.openshift.com/pub/openshift-v4/clients/crc/latest/release-info.json"
 	// Tray version to be embedded in executable
-	crcMacTrayVersion = "1.0.3"
+	crcMacTrayVersion = "1.0.4"
 	// Windows forms application version type major.minor.buildnumber.revesion
 	crcWindowsTrayVersion = "0.4.0.0"
 )
diff --git a/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/services/dns/dns.go b/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/services/dns/dns.go
index ed6a40763..1ffd1cacf 100644
--- a/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/services/dns/dns.go
+++ b/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/services/dns/dns.go
@@ -27,8 +27,6 @@ func (h *dnsHandler) handle(w dns.ResponseWriter, r *dns.Msg) {
 
 func (h *dnsHandler) addAnswers(m *dns.Msg) {
 	for _, q := range m.Question {
-		log.Debugf("DNS query for %s", q.String())
-
 		for _, zone := range h.zones {
 			zoneSuffix := fmt.Sprintf(".%s", zone.Name)
 			if strings.HasSuffix(q.Name, zoneSuffix) {
diff --git a/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/tap/ip_pool.go b/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/tap/ip_pool.go
index ce158dbe4..9df2d17c6 100644
--- a/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/tap/ip_pool.go
+++ b/vendor/github.com/code-ready/gvisor-tap-vsock/pkg/tap/ip_pool.go
@@ -24,7 +24,13 @@ func NewIPPool(base *net.IPNet) *IPPool {
 }
 
 func (p *IPPool) Leases() map[string]int {
-	return p.leases
+	p.lock.Lock()
+	defer p.lock.Unlock()
+	leases := map[string]int{}
+	for key, value := range p.leases {
+		leases[key] = value
+	}
+	return leases
 }
 
 func (p *IPPool) Mask() int {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 1bbab9d68..ef8f245b7 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -36,7 +36,7 @@ github.com/cheggaaa/pb/v3/termutil
 ## explicit
 github.com/code-ready/clicumber/testsuite
 github.com/code-ready/clicumber/util
-# github.com/code-ready/gvisor-tap-vsock v0.0.0-20210216090540-914d522b9c38
+# github.com/code-ready/gvisor-tap-vsock v0.0.0-20210308122700-d61f9aac135c
 ## explicit
 github.com/code-ready/gvisor-tap-vsock/pkg/client
 github.com/code-ready/gvisor-tap-vsock/pkg/services/dns


Test patch:
diff --git a/pkg/crc/api/api_http_test.go b/pkg/crc/api/api_http_test.go
new file mode 100644
index 000000000..9be5e88f4
--- /dev/null
+++ b/pkg/crc/api/api_http_test.go
@@ -0,0 +1,125 @@
+package api
+
+import (
+	"net/http"
+	"net/http/httptest"
+	"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/version"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestHTTPApi(t *testing.T) {
+	fakeMachine := fakemachine.NewClient()
+	config := setupNewInMemoryConfig()
+
+	ts := httptest.NewServer(NewMux(config, fakeMachine))
+	defer ts.Close()
+
+	client := apiClient.New(http.DefaultClient, ts.URL)
+	vr, err := client.Version()
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.VersionResult{
+			CrcVersion:       version.GetCRCVersion(),
+			OpenshiftVersion: version.GetBundleVersion(),
+			CommitSha:        version.GetCommitSha(),
+			Success:          true,
+		},
+		vr,
+	)
+
+	statusResult, err := client.Status()
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.ClusterStatusResult{
+			Name:             "crc",
+			CrcStatus:        "Running",
+			OpenshiftStatus:  "Running",
+			OpenshiftVersion: "4.5.1",
+			DiskUse:          int64(10000000000),
+			DiskSize:         int64(20000000000),
+			Success:          true,
+		},
+		statusResult,
+	)
+
+	var startConfig = apiClient.StartConfig{}
+	startResult, err := client.Start(startConfig)
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.StartResult{
+			Name:           "crc",
+			Status:         "",
+			Error:          "",
+			KubeletStarted: true,
+			ClusterConfig: machine.ClusterConfig{
+				ClusterCACert: "MIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJ",
+				KubeConfig:    "/tmp/kubeconfig",
+				KubeAdminPass: "foobar",
+				ClusterAPI:    "https://foo.testing:6443",
+				WebConsoleURL: "https://console.foo.testing:6443",
+				ProxyConfig:   nil,
+			},
+		},
+		startResult,
+	)
+
+	stopResult, err := client.Stop()
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.Result{
+			Name:    "crc",
+			Success: true,
+			Error:   "",
+		},
+		stopResult,
+	)
+
+	deleteResult, err := client.Delete()
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.Result{
+			Name:    "crc",
+			Success: true,
+			Error:   "",
+		},
+		deleteResult,
+	)
+
+	configGetResult, err := client.GetConfig([]string{"cpus"})
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.GetConfigResult{
+			Error: "",
+			Configs: map[string]interface{}{
+				"cpus": float64(4),
+			},
+		},
+		configGetResult,
+	)
+
+	configSetResult, err := client.SetConfig(apiClient.SetConfigRequest{
+		Properties: map[string]interface{}{
+			"cpus": float64(5),
+		},
+	})
+	assert.NoError(t, err)
+	assert.Equal(
+		t,
+		apiClient.SetOrUnsetConfigResult{
+			Error:      "",
+			Properties: []string{"cpus"},
+		},
+		configSetResult,
+	)
+}
diff --git a/pkg/crc/api/api_test.go b/pkg/crc/api/api_test.go
index 76822ad87..67b58de27 100644
--- a/pkg/crc/api/api_test.go
+++ b/pkg/crc/api/api_test.go
@@ -8,13 +8,10 @@ import (
 	"net"
 	"os"
 	"path/filepath"
-	"strings"
 	"testing"
 
-	cmdConfig "github.com/code-ready/crc/cmd/crc/cmd/config"
-	"github.com/code-ready/crc/pkg/crc/config"
+	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/preflight"
 	"github.com/code-ready/crc/pkg/crc/version"
 	log "github.com/sirupsen/logrus"
 	"github.com/stretchr/testify/assert"
@@ -167,9 +164,9 @@ func TestSetconfigApi(t *testing.T) {
 	n, err := client.Read(payload)
 	assert.NoError(t, err)
 
-	var setconfigRes setOrUnsetConfigResult
+	var setconfigRes apiClient.SetOrUnsetConfigResult
 	assert.NoError(t, json.Unmarshal(payload[:n], &setconfigRes))
-	assert.Equal(t, setOrUnsetConfigResult{
+	assert.Equal(t, apiClient.SetOrUnsetConfigResult{
 		Error:      "",
 		Properties: []string{"cpus"},
 	}, setconfigRes)
@@ -193,29 +190,18 @@ func TestGetconfigApi(t *testing.T) {
 	n, err := client.Read(payload)
 	assert.NoError(t, err)
 
-	var getconfigRes getConfigResult
+	var getconfigRes apiClient.GetConfigResult
 	assert.NoError(t, json.Unmarshal(payload[:n], &getconfigRes))
 
 	configs := make(map[string]interface{})
 	configs["cpus"] = 4.0
 
-	assert.Equal(t, getConfigResult{
+	assert.Equal(t, apiClient.GetConfigResult{
 		Error:   "",
 		Configs: configs,
 	}, getconfigRes)
 }
 
-func setupNewInMemoryConfig() config.Storage {
-	storage := config.NewEmptyInMemoryStorage()
-	cfg := config.New(&skipPreflights{
-		storage: storage,
-	})
-	cmdConfig.RegisterSettings(cfg)
-	preflight.RegisterSettings(cfg)
-
-	return cfg
-}
-
 func setupAPIServer(t *testing.T) (string, func()) {
 	dir, err := ioutil.TempDir("", "api")
 	require.NoError(t, err)
@@ -236,25 +222,6 @@ func setupAPIServer(t *testing.T) (string, func()) {
 	return socket, func() { os.RemoveAll(dir) }
 }
 
-type skipPreflights struct {
-	storage config.RawStorage
-}
-
-func (s *skipPreflights) Get(key string) interface{} {
-	if strings.HasPrefix(key, "skip-") {
-		return "true"
-	}
-	return s.storage.Get(key)
-}
-
-func (s *skipPreflights) Set(key string, value interface{}) error {
-	return s.storage.Set(key, value)
-}
-
-func (s *skipPreflights) Unset(key string) error {
-	return s.storage.Unset(key)
-}
-
 type mockLogger struct {
 }
 
diff --git a/pkg/crc/api/apitest.go b/pkg/crc/api/apitest.go
new file mode 100644
index 000000000..f28a6996b
--- /dev/null
+++ b/pkg/crc/api/apitest.go
@@ -0,0 +1,39 @@
+package api
+
+import (
+	"strings"
+
+	cmdConfig "github.com/code-ready/crc/cmd/crc/cmd/config"
+	"github.com/code-ready/crc/pkg/crc/config"
+	"github.com/code-ready/crc/pkg/crc/preflight"
+)
+
+func setupNewInMemoryConfig() config.Storage {
+	storage := config.NewEmptyInMemoryStorage()
+	cfg := config.New(&skipPreflights{
+		storage: storage,
+	})
+	cmdConfig.RegisterSettings(cfg)
+	preflight.RegisterSettings(cfg)
+
+	return cfg
+}
+
+type skipPreflights struct {
+	storage config.RawStorage
+}
+
+func (s *skipPreflights) Get(key string) interface{} {
+	if strings.HasPrefix(key, "skip-") {
+		return "true"
+	}
+	return s.storage.Get(key)
+}
+
+func (s *skipPreflights) Set(key string, value interface{}) error {
+	return s.storage.Set(key, value)
+}
+
+func (s *skipPreflights) Unset(key string) error {
+	return s.storage.Unset(key)
+}
diff --git a/pkg/crc/preflight/preflight_darwin_test.go b/pkg/crc/preflight/preflight_darwin_test.go
index a56f7ac31..214b967ce 100644
--- a/pkg/crc/preflight/preflight_darwin_test.go
+++ b/pkg/crc/preflight/preflight_darwin_test.go
@@ -23,8 +23,8 @@ func TestCountPreflights(t *testing.T) {
 	assert.Len(t, getPreflightChecks(true, true, network.VSockMode), 19)
 
 	assert.Len(t, getPreflightChecks(true, false, network.VSockMode), 15)
-	assert.Len(t, getPreflightChecks(false, true, network.VSockMode), 19)
+	assert.Len(t, getPreflightChecks(false, true, network.VSockMode), 15)
 
-	assert.Len(t, getPreflightChecks(false, true, network.DefaultMode), 20)
+	assert.Len(t, getPreflightChecks(false, true, network.DefaultMode), 14)
 	assert.Len(t, getPreflightChecks(true, false, network.DefaultMode), 14)
 }