Repository: code-ready/crc
Pull request #2415 (2021-06-09 12:25:08)

docs: Expand installation procedure, cover binary and installer
## Solution/Idea

Describe the installation procedure in more detail, particularly for installing the portable binary on RHEL. This PR also briefly documents that CRC is available on macOS using a guided installer. In the future, we will likely replace the Windows instructions in this PR once the installer for Windows is the default installation method for that platform (but will retain the notice regarding installing to the `C:\` drive).

**Note:** Regarding the wording of the installation procedure, I wasn't sure if we should advocate for _copying_ the executable or _moving_ it from the extracted location. I opted for copying due to that action being non-destructive.

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

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2415#" title="Author self-approved">robin-owen</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:

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

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]: @jc-berger: changing LGTM is restricted to collaborators

<details>

In response to [this](https://github.com/code-ready/crc/pull/2415#pullrequestreview-679794831):

>LGTM from doc's point of view. Great job! 


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]: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/code-ready/crc/pull/2415#pullrequestreview-679794831" title="Approved">jc-berger</a>*, *<a href="https://github.com/code-ready/crc/pull/2415#" title="Author self-approved">robin-owen</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:

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

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 3b773568f..6d262be5c 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ SHELL := /bin/bash
 
 BUNDLE_VERSION ?= 4.7.13
 BUNDLE_EXTENSION = crcbundle
-CRC_VERSION = 1.27.0
+CRC_VERSION = 1.28.0
 COMMIT_SHA=$(shell git rev-parse --short HEAD)
 MACOS_INSTALL_PATH = /Applications/CodeReady Containers.app/Contents/Resources/
 CONTAINER_RUNTIME ?= podman
@@ -319,7 +319,7 @@ endif
 
 $(BUILD_DIR)/windows-amd64/crc-windows-amd64.msi: msidir
 	candle.exe -arch x64 -ext WixUtilExtension -o $(PACKAGE_DIR)/msi/ $(PACKAGE_DIR)/msi/*.wxs
-	cd $(PACKAGE_DIR)/msi && light.exe -ext WixUIExtension -ext WixUtilExtension -sacl -spdb -sice:ICE61 -out ../../../$@ *.wixobj
+	cd $(PACKAGE_DIR)/msi && light.exe -ext WixUIExtension -ext WixUtilExtension -sacl -spdb -sice:ICE61 -sice:ICE69 -out ../../../$@ *.wixobj
 
 CABS_MSI = "cab1.cab,cab2.cab,cab3.cab,crc-windows-amd64.msi"
 $(BUILD_DIR)/windows-amd64/crc-windows-installer.zip: $(BUILD_DIR)/windows-amd64/crc-windows-amd64.msi
diff --git a/cmd/crc/cmd/podman_env.go b/cmd/crc/cmd/podman_env.go
index dbda33da8..d4ab4681e 100644
--- a/cmd/crc/cmd/podman_env.go
+++ b/cmd/crc/cmd/podman_env.go
@@ -9,7 +9,7 @@ import (
 )
 
 var (
-	rootless bool
+	root bool
 )
 
 var podmanEnvCmd = &cobra.Command{
@@ -37,9 +37,9 @@ func runPodmanEnv() error {
 		return err
 	}
 
-	socket := "/run/podman/podman.sock"
-	if rootless {
-		socket = "/run/user/1000/podman/podman.sock"
+	socket := "/run/user/1000/podman/podman.sock"
+	if root {
+		socket = "/run/podman/podman.sock"
 	}
 	fmt.Println(shell.GetPathEnvString(userShell, constants.CrcOcBinDir))
 	fmt.Println(shell.GetEnvString(userShell, "CONTAINER_SSHKEY", connectionDetails.SSHKeys[0]))
@@ -54,7 +54,7 @@ func runPodmanEnv() error {
 }
 
 func init() {
-	podmanEnvCmd.Flags().BoolVar(&rootless, "rootless", false, "Use rootless podman in the virtual machine")
+	podmanEnvCmd.Flags().BoolVar(&root, "root", false, "Use root podman in the virtual machine")
 	podmanEnvCmd.Flags().StringVar(&forceShell, "shell", "", "Set the environment for the specified shell: [fish, cmd, powershell, tcsh, bash, zsh]. Default is auto-detect.")
 	rootCmd.AddCommand(podmanEnvCmd)
 }
diff --git a/docs/source/topics/proc_installing-codeready-containers.adoc b/docs/source/topics/proc_installing-codeready-containers.adoc
index 707a9ec4a..6c3acb4cc 100644
--- a/docs/source/topics/proc_installing-codeready-containers.adoc
+++ b/docs/source/topics/proc_installing-codeready-containers.adoc
@@ -1,6 +1,9 @@
 [id="installing-codeready-containers_{context}"]
 = Installing {prod}
 
+{prod} is available as a portable executable for {rhel} and {msw}.
+On {mac}, {prod} is available using a guided installer.
+
 .Prerequisites
 
 * Your host machine must meet the minimum system requirements.
@@ -8,4 +11,47 @@ For more information, see link:{crc-gsg-url}#minimum-system-requirements_gsg[Min
 
 .Procedure
 
-. Download the link:{crc-download-url}[latest release of {prod}] for your platform and extract the contents of the archive to a location in your `_PATH_`.
+. Download the link:{crc-download-url}[latest release of {prod}] for your platform.
+
+. On {mac}, run the guided installer and follow the instructions.
+On {rhel} or {msw}, assuming the archive is in the [filename]*_~/Downloads_* directory, follow the procedure for your platform.
++
+** For {rhel}:
++
+... Extract the contents of the archive:
++
+[subs="attributes"]
+----
+$ cd ~/Downloads
+$ tar xvf crc-linux-amd64.tar.xz
+----
++
+... Create the [filename]*_~/bin_* directory if it does not exist and copy the [command]`{bin}` executable to it:
++
+[subs="attributes"]
+----
+$ mkdir -p ~/bin
+$ cp ~/Downloads/crc-linux-*-amd64/{bin} ~/bin
+----
++
+... Add the [filename]*_~/bin_* directory to your `_PATH_`:
++
+[subs="attributes"]
+----
+$ export PATH=$PATH:$HOME/bin
+$ echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc
+----
++
+** For {msw}:
++
+... Extract the contents of the archive.
+... Create the desired directory path for {prod} and copy the extracted [command]`{bin}.exe` executable to it.
+... Add the directory path to your `_PATH_` environment variable.
++
+[NOTE]
+====
+On {msw}, you must execute the {prod} executable from your local [filename]*_C:\_* drive.
+You cannot run {prod} from a network drive.
+
+If you cannot install the executable in your `_PATH_`, run {prod} from the current directory as `./{bin}.exe`.
+====
diff --git a/go.mod b/go.mod
index ca15049bc..070580662 100644
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
 	github.com/cavaliercoder/grab v2.0.0+incompatible
 	github.com/cheggaaa/pb/v3 v3.0.8
-	github.com/code-ready/admin-helper v0.0.0-20210518083720-ee7100e9f7ae
+	github.com/code-ready/admin-helper v0.0.0-20210602075518-d22477037442
 	github.com/code-ready/clicumber v0.0.0-20210201104241-cecb794bdf9a
 	github.com/code-ready/gvisor-tap-vsock v0.0.0-20210308122700-d61f9aac135c
 	github.com/code-ready/machine v0.0.0-20210122113819-281ccfbb4566
diff --git a/go.sum b/go.sum
index ffdb0aa39..5fdbd7321 100644
--- a/go.sum
+++ b/go.sum
@@ -143,8 +143,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
-github.com/code-ready/admin-helper v0.0.0-20210518083720-ee7100e9f7ae h1:2oPNH50PMnFXA+bfa7bHcg8XtVOt/maFb0A7V8qkKbc=
-github.com/code-ready/admin-helper v0.0.0-20210518083720-ee7100e9f7ae/go.mod h1:4HSCLxIh62FmyT+XNNdPT7svzEcdcFvrlyzeUa1sqHY=
+github.com/code-ready/admin-helper v0.0.0-20210602075518-d22477037442 h1:uuCCqdNeZs2nETXs7qQ2i8wxthI8WgTZylQdyvTXcIA=
+github.com/code-ready/admin-helper v0.0.0-20210602075518-d22477037442/go.mod h1:JIRSIX+K3gN+A4DGJIcnG/opLnj5zOVG+H2h2eA9Wgo=
 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-20210308122700-d61f9aac135c h1:UOg6w7Uv5hWvFVABjJpawCEmAK99vG96SozUaulqVCk=
@@ -548,6 +548,7 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
 github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
+github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -1142,6 +1143,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201026133411-418715ba6fdd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/packaging/windows/product.wxs.in b/packaging/windows/product.wxs.in
index 8044028c0..5d89c508b 100755
--- a/packaging/windows/product.wxs.in
+++ b/packaging/windows/product.wxs.in
@@ -59,6 +59,28 @@
                     </Component>
                 </Directory>
             </Directory>
+            <Directory Id="StartupFolder">
+                <Component Id="TrayStartup" Guid="*">
+                    <Shortcut Id="TrayStartupShortcut" 
+                     Name="CodeReady Containers"
+                     Target="[#CrcTray]"
+                     Icon="crcicon.ico"
+                     WorkingDirectory="AppDataFolder"/>
+                    <RemoveFile Id="RemoveTrayShortCut" Name="CodeReady Containers" On="uninstall"/>
+                    <RegistryValue Root="HKCU" Key="Software\Red Hat\CodeReady Containers" Name="installed" Type="integer" Value="1" KeyPath="yes"/>
+                </Component>
+            </Directory>
+            <Directory Id="ProgramMenuFolder">
+                <Component Id="StartMenuEntry" Guid="*">
+                    <Shortcut Id="TrayStartMenuEntry" 
+                        Name="CodeReady Containers"
+                        Target="[#CrcTray]"
+                        Icon="crcicon.ico"
+                        WorkingDirectory="AppDataFolder"/>
+                    <RemoveFile Id="RemoveStartMenuEntry" Name="CodeReady Containers" On="uninstall"/>
+                    <RegistryValue Root="HKCU" Key="Software\Red Hat\CodeReady Containers" Name="startmenu" Type="integer" Value="1" KeyPath="yes"/>
+                </Component>
+            </Directory>
         </Directory>
         <SetProperty Action="CAJoinBundle"  Id="JoinBundle"  Value='"[WindowsFolder]\System32\cmd.exe" /c cd "[INSTALLDIR]" &amp;&amp; copy /b $(var.crcBundlePart0)+$(var.crcBundlePart1)+$(var.crcBundlePart2) $(var.crcBundleName)' Before="JoinBundle" Sequence="execute"/>
         <CustomAction Id="JoinBundle" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Impersonate="no" />
@@ -81,6 +103,8 @@
             <ComponentRef Id="CrcTray" />
             <ComponentRef Id="AdminHelper" />
             <ComponentRef Id="AddToPath"/>
+            <ComponentRef Id="TrayStartup"/>
+            <ComponentRef Id="StartMenuEntry" />
         </Feature>
         <UI>
             <UIRef Id="WixUI_ErrorProgressText"/>
diff --git a/pkg/crc/adminhelper/hosts.go b/pkg/crc/adminhelper/hosts.go
index 1e901341a..2f6f7379b 100644
--- a/pkg/crc/adminhelper/hosts.go
+++ b/pkg/crc/adminhelper/hosts.go
@@ -4,11 +4,12 @@ import (
 	"path/filepath"
 
 	"github.com/code-ready/admin-helper/pkg/hosts"
+	"github.com/code-ready/admin-helper/pkg/types"
 	"github.com/code-ready/crc/pkg/crc/constants"
 )
 
 var (
-	adminHelperPath = filepath.Join(constants.BinDir(), constants.GetAdminHelperExecutable())
+	BinPath = filepath.Join(constants.BinDir(), constants.GetAdminHelperExecutable())
 )
 
 // UpdateHostsFile updates the host's /etc/hosts file with Instance IP.
@@ -36,13 +37,27 @@ func AddToHostsFile(instanceIP string, hostnames ...string) error {
 	if len(filtered) == 0 {
 		return nil
 	}
-	return execute(append([]string{"add", instanceIP}, hostnames...)...)
+
+	return instance().Add(&types.AddRequest{
+		IP:    instanceIP,
+		Hosts: filtered,
+	})
 }
 
 func RemoveFromHostsFile(hostnames ...string) error {
-	return execute(append([]string{"rm"}, hostnames...)...)
+	return instance().Remove(&types.RemoveRequest{
+		Hosts: hostnames,
+	})
 }
 
 func CleanHostsFile() error {
-	return execute("clean", constants.ClusterDomain, constants.AppsDomain)
+	return instance().Clean(&types.CleanRequest{
+		Domains: []string{constants.ClusterDomain, constants.AppsDomain},
+	})
+}
+
+type helper interface {
+	Add(req *types.AddRequest) error
+	Remove(req *types.RemoveRequest) error
+	Clean(req *types.CleanRequest) error
 }
diff --git a/pkg/crc/adminhelper/hosts_nowin.go b/pkg/crc/adminhelper/hosts_nowin.go
index feb2a2e2a..74a6878b4 100644
--- a/pkg/crc/adminhelper/hosts_nowin.go
+++ b/pkg/crc/adminhelper/hosts_nowin.go
@@ -3,10 +3,30 @@
 package adminhelper
 
 import (
+	"github.com/code-ready/admin-helper/pkg/types"
 	crcos "github.com/code-ready/crc/pkg/os"
 )
 
 func execute(args ...string) error {
-	_, _, err := crcos.RunWithDefaultLocale(adminHelperPath, args...)
+	_, _, err := crcos.RunWithDefaultLocale(BinPath, args...)
 	return err
 }
+
+func instance() helper {
+	return &cliHelper{}
+}
+
+type cliHelper struct {
+}
+
+func (c *cliHelper) Add(req *types.AddRequest) error {
+	return execute(append([]string{"add", req.IP}, req.Hosts...)...)
+}
+
+func (c *cliHelper) Remove(req *types.RemoveRequest) error {
+	return execute(append([]string{"rm"}, req.Hosts...)...)
+}
+
+func (c *cliHelper) Clean(req *types.CleanRequest) error {
+	return execute(append([]string{"clean"}, req.Domains...)...)
+}
diff --git a/pkg/crc/adminhelper/hosts_windows.go b/pkg/crc/adminhelper/hosts_windows.go
index 54fac5255..9c09d2741 100644
--- a/pkg/crc/adminhelper/hosts_windows.go
+++ b/pkg/crc/adminhelper/hosts_windows.go
@@ -1,12 +1,26 @@
 package adminhelper
 
 import (
-	"strings"
+	"context"
+	"net"
+	"net/http"
+	"time"
 
-	"github.com/code-ready/crc/pkg/os/windows/powershell"
+	"github.com/Microsoft/go-winio"
+	"github.com/code-ready/admin-helper/pkg/client"
 )
 
-func execute(args ...string) error {
-	_, _, err := powershell.ExecuteAsAdmin("modifying hosts file", strings.Join(append([]string{adminHelperPath}, args...), " "))
-	return err
+func instance() helper {
+	return Client()
+}
+
+func Client() *client.Client {
+	return client.New(&http.Client{
+		Transport: &http.Transport{
+			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+				return winio.DialPipeContext(ctx, `\\.\pipe\crc-admin-helper`)
+			},
+		},
+		Timeout: 3 * time.Second,
+	}, "http://unix")
 }
diff --git a/pkg/crc/constants/constants.go b/pkg/crc/constants/constants.go
index 98a9d62b7..32f5c7053 100644
--- a/pkg/crc/constants/constants.go
+++ b/pkg/crc/constants/constants.go
@@ -27,7 +27,7 @@ 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.4"
+	DefaultAdminHelperCliBase = "https://github.com/code-ready/admin-helper/releases/download/0.0.6"
 	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"
diff --git a/pkg/crc/machine/delete.go b/pkg/crc/machine/delete.go
index 535ea55ec..a0a73d1a6 100644
--- a/pkg/crc/machine/delete.go
+++ b/pkg/crc/machine/delete.go
@@ -1,6 +1,7 @@
 package machine
 
 import (
+	"github.com/code-ready/crc/pkg/crc/logging"
 	"github.com/pkg/errors"
 )
 
@@ -20,5 +21,9 @@ func (client *client) Delete() error {
 	if err := libMachineAPIClient.Remove(client.name); err != nil {
 		return errors.Wrap(err, "Cannot remove machine")
 	}
+
+	if err := cleanKubeconfig(getGlobalKubeConfigPath(), getGlobalKubeConfigPath()); err != nil {
+		logging.Warn(err)
+	}
 	return nil
 }
diff --git a/pkg/crc/machine/kubeconfig.go b/pkg/crc/machine/kubeconfig.go
index 20371c213..880e9442d 100644
--- a/pkg/crc/machine/kubeconfig.go
+++ b/pkg/crc/machine/kubeconfig.go
@@ -142,3 +142,55 @@ func getGlobalKubeConfigPath() string {
 	}
 	return filepath.Join(constants.GetHomeDir(), ".kube", "config")
 }
+
+func cleanKubeconfig(input, output string) error {
+	cfg, err := clientcmd.LoadFromFile(input)
+	if err != nil {
+		return err
+	}
+
+	var clusterNames []string
+	for name, cluster := range cfg.Clusters {
+		if cluster.Server == fmt.Sprintf("https://api%s:6443", constants.ClusterDomain) {
+			clusterNames = append(clusterNames, name)
+		}
+	}
+	var contextNames []string
+	authNames := make(map[string]struct{})
+	for name, context := range cfg.Contexts {
+		if contains(clusterNames, context.Cluster) {
+			contextNames = append(contextNames, name)
+			authNames[context.AuthInfo] = struct{}{}
+		}
+	}
+	// keep auth if it is shared with other contexts
+	for _, context := range cfg.Contexts {
+		if !contains(clusterNames, context.Cluster) {
+			delete(authNames, context.AuthInfo)
+		}
+	}
+
+	for _, name := range clusterNames {
+		delete(cfg.Clusters, name)
+	}
+	for _, name := range contextNames {
+		delete(cfg.Contexts, name)
+		if cfg.CurrentContext == name {
+			cfg.CurrentContext = ""
+		}
+	}
+	for name := range authNames {
+		delete(cfg.AuthInfos, name)
+	}
+
+	return clientcmd.WriteToFile(*cfg, output)
+}
+
+func contains(arr []string, str string) bool {
+	for _, a := range arr {
+		if a == str {
+			return true
+		}
+	}
+	return false
+}
diff --git a/pkg/crc/preflight/preflight_checks_common.go b/pkg/crc/preflight/preflight_checks_common.go
index b1724980e..548560392 100644
--- a/pkg/crc/preflight/preflight_checks_common.go
+++ b/pkg/crc/preflight/preflight_checks_common.go
@@ -76,13 +76,6 @@ var genericPreflightChecks = []Check{
 
 		labels: None,
 	},
-	{
-		cleanupDescription: "Removing hosts file records added by CRC",
-		cleanup:            removeHostsFileEntry,
-		flags:              CleanUpOnly,
-
-		labels: None,
-	},
 	{
 		cleanupDescription: "Removing older logs",
 		cleanup:            removeOldLogs,
@@ -99,6 +92,14 @@ var genericPreflightChecks = []Check{
 	},
 }
 
+var cleanUpHostsFile = Check{
+	cleanupDescription: "Removing hosts file records added by CRC",
+	cleanup:            removeHostsFileEntry,
+	flags:              CleanUpOnly,
+
+	labels: None,
+}
+
 func checkSupportedCPUArch() error {
 	if runtime.GOARCH != "amd64" {
 		logging.Debugf("GOARCH is %s", runtime.GOARCH)
diff --git a/pkg/crc/preflight/preflight_checks_tray_windows.go b/pkg/crc/preflight/preflight_checks_tray_windows.go
index 71af9b14a..98f0a2b18 100644
--- a/pkg/crc/preflight/preflight_checks_tray_windows.go
+++ b/pkg/crc/preflight/preflight_checks_tray_windows.go
@@ -16,13 +16,6 @@ import (
 
 var daemonBatchFileShortcutPath = filepath.Join(constants.StartupFolder, constants.DaemonBatchFileShortcutName)
 
-func checkIfTrayInstalled() error {
-	if os.FileExists(filepath.Join(constants.StartupFolder, constants.TrayShortcutName)) && checkTrayVersion() {
-		return nil
-	}
-	return fmt.Errorf("CodeReady Containers tray is not Installed")
-}
-
 func checkIfDaemonInstalled() error {
 	if os.FileExists(constants.DaemonBatchFilePath) || os.FileExists(constants.DaemonPSScriptPath) {
 		return fmt.Errorf("Daemon should not be installed")
@@ -33,38 +26,6 @@ func checkIfDaemonInstalled() error {
 	return nil
 }
 
-func fixTrayInstalled() error {
-	/* Start the tray process and copy the executable to start-up folder
-	 * "$USERPROFILE\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"
-	 */
-	_ = stopTray()
-
-	cmd := fmt.Sprintf(`New-Item -ItemType SymbolicLink -Path "%s" -Name "%s" -Value "%s"`,
-		constants.StartupFolder,
-		constants.TrayShortcutName,
-		constants.TrayExecutablePath,
-	)
-	if _, _, err := powershell.ExecuteAsAdmin("Create symlink to tray in start-up folder", cmd); err != nil {
-		return fmt.Errorf("Error trying to create symlink to tray in start-up folder: %w", err)
-	}
-	cmd = fmt.Sprintf(`Start-Process -FilePath "%s"`, constants.TrayExecutablePath)
-	if _, _, err := powershell.Execute(cmd); err != nil {
-		return fmt.Errorf("Failed to start tray process: %w", err)
-	}
-	return nil
-}
-
-func removeTray() error {
-	trayShortcutPath := filepath.Join(constants.StartupFolder, constants.TrayShortcutName)
-	_ = stopTray()
-	/* we changed the name of the tray executable to crc-tray.exe from tray-windows.exe
-	 * this tries to remove the old tray shortcut, can be removed after a  few releases
-	 */
-	_ = os.RemoveFileIfExists(filepath.Join(constants.StartupFolder, "tray-windows.lnk"))
-
-	return os.RemoveFileIfExists(trayShortcutPath)
-}
-
 func stopTray() error {
 	/* we changed the name of the tray executable to crc-tray from tray-windows
 	 * this tries to stop the old tray process, can be removed after a  few releases
@@ -141,3 +102,25 @@ func checkTrayVersion() bool {
 	logging.Debugf("Got tray version: %s", strings.TrimSpace(stdOut))
 	return strings.TrimSpace(stdOut) == version.GetCRCWindowsTrayVersion()
 }
+
+func checkIfTrayRunning() error {
+	cmd := fmt.Sprintf("Get-Process -Name %s",
+		strings.TrimSuffix(constants.TrayExecutableName, filepath.Ext(constants.TrayExecutableName)))
+
+	_, stdErr, err := powershell.Execute(cmd)
+	if err != nil {
+		return err
+	}
+	if strings.TrimSpace(stdErr) != "" {
+		return fmt.Errorf("Tray not running: %s", stdErr)
+	}
+	return nil
+}
+
+func startTray() error {
+	cmd := fmt.Sprintf(`Start-Process -FilePath "%s"`, constants.TrayExecutablePath)
+	if _, _, err := powershell.Execute(cmd); err != nil {
+		return fmt.Errorf("Failed to start tray process: %w", err)
+	}
+	return nil
+}
diff --git a/pkg/crc/preflight/preflight_darwin.go b/pkg/crc/preflight/preflight_darwin.go
index a88e20cd5..11b041c24 100644
--- a/pkg/crc/preflight/preflight_darwin.go
+++ b/pkg/crc/preflight/preflight_darwin.go
@@ -134,6 +134,7 @@ func getChecks(mode network.Mode) []Check {
 
 	checks = append(checks, nonWinPreflightChecks...)
 	checks = append(checks, genericPreflightChecks...)
+	checks = append(checks, cleanUpHostsFile)
 	checks = append(checks, hyperkitPreflightChecks(mode)...)
 	checks = append(checks, daemonSetupChecks...)
 	checks = append(checks, resolverPreflightChecks...)
diff --git a/pkg/crc/preflight/preflight_linux.go b/pkg/crc/preflight/preflight_linux.go
index fe7ade6df..4f92a7be2 100644
--- a/pkg/crc/preflight/preflight_linux.go
+++ b/pkg/crc/preflight/preflight_linux.go
@@ -312,6 +312,7 @@ func getChecks(distro *linux.OsRelease) []Check {
 	checks = append(checks, nonWinPreflightChecks...)
 	checks = append(checks, wsl2PreflightCheck)
 	checks = append(checks, genericPreflightChecks...)
+	checks = append(checks, cleanUpHostsFile)
 	checks = append(checks, libvirtPreflightChecks(distro)...)
 	checks = append(checks, ubuntuPreflightChecks...)
 	checks = append(checks, nmPreflightChecks...)
diff --git a/pkg/crc/preflight/preflight_windows.go b/pkg/crc/preflight/preflight_windows.go
index 5c4c91f70..d8779baf9 100644
--- a/pkg/crc/preflight/preflight_windows.go
+++ b/pkg/crc/preflight/preflight_windows.go
@@ -3,8 +3,13 @@ package preflight
 import (
 	"errors"
 	"fmt"
+	"os"
+	"path/filepath"
 	"strings"
 
+	"github.com/code-ready/crc/pkg/crc/adminhelper"
+	"github.com/code-ready/crc/pkg/crc/constants"
+	crcerrors "github.com/code-ready/crc/pkg/crc/errors"
 	"github.com/code-ready/crc/pkg/crc/network"
 	"github.com/code-ready/crc/pkg/crc/version"
 	"github.com/code-ready/crc/pkg/os/windows/powershell"
@@ -47,13 +52,46 @@ var hypervPreflightChecks = []Check{
 
 		labels: labels{Os: Windows},
 	},
+	{
+		configKeySuffix:  "check-crc-users-group-exists",
+		checkDescription: "Checking if crc-users group exists",
+		check: func() error {
+			_, _, err := powershell.Execute("Get-LocalGroup -Name crc-users")
+			return err
+		},
+		fixDescription: "Creating crc-users group",
+		fix: func() error {
+			_, _, err := powershell.ExecuteAsAdmin("create crc-users group", "New-LocalGroup -Name crc-users")
+			return err
+		},
+		labels: labels{Os: Windows},
+	},
 	{
 		configKeySuffix:  "check-user-in-hyperv-group",
-		checkDescription: "Checking if user is a member of the Hyper-V Administrators group",
-		check:            checkIfUserPartOfHyperVAdmins,
-		fixDescription:   "Adding user to the Hyper-V Administrators group",
-		fix:              fixUserPartOfHyperVAdmins,
-
+		checkDescription: "Checking if current user is in Hyper-V group and crc-users group",
+		check: func() error {
+			if err := adminHelperGroup.check(); err != nil {
+				return err
+			}
+			return hypervGroup.check()
+		},
+		fixDescription: "Adding current user to group",
+		fix: func() error {
+			m := crcerrors.MultiError{}
+			if err := adminHelperGroup.check(); err != nil {
+				m.Collect(adminHelperGroup.fix())
+			}
+			if err := hypervGroup.check(); err != nil {
+				m.Collect(hypervGroup.fix())
+			}
+			if len(m.Errors) == 0 {
+				return nil
+			}
+			if m.Errors[0] == errReboot {
+				return errReboot
+			}
+			return m
+		},
 		labels: labels{Os: Windows},
 	},
 	{
@@ -112,13 +150,18 @@ var traySetupChecks = []Check{
 		labels: labels{Os: Windows, Tray: Enabled},
 	},
 	{
-		checkDescription:   "Checking if tray is installed",
-		check:              checkIfTrayInstalled,
-		fixDescription:     "Installing CodeReady Containers tray",
-		fix:                fixTrayInstalled,
-		cleanupDescription: "Uninstalling tray if installed",
-		cleanup:            removeTray,
-		flags:              SetupOnly,
+		checkDescription: "Checking if tray is running",
+		check:            checkIfTrayRunning,
+		fixDescription:   "Starting CodeReady Containers tray",
+		fix:              startTray,
+		flags:            SetupOnly,
+
+		labels: labels{Os: Windows, Tray: Enabled},
+	},
+	{
+		cleanupDescription: "Stopping tray if running",
+		cleanup:            stopTray,
+		flags:              CleanUpOnly,
 
 		labels: labels{Os: Windows, Tray: Enabled},
 	},
@@ -136,6 +179,57 @@ var vsockChecks = []Check{
 	},
 }
 
+var errReboot = errors.New("Please reboot your system and run 'crc setup' to complete the setup process")
+
+var adminHelperGroup = Check{
+	check: func() error {
+		_, _, err := powershell.Execute(fmt.Sprintf("Get-LocalGroupMember -Name crc-users -Member '%s'", os.Getenv("USERNAME")))
+		return err
+	},
+	fix: func() error {
+		_, _, err := powershell.ExecuteAsAdmin("adding current user to crc-users group", fmt.Sprintf("Add-LocalGroupMember -Group crc-users -Member '%s'", os.Getenv("USERNAME")))
+		if err != nil {
+			return err
+		}
+		return errReboot
+	},
+}
+
+var hypervGroup = Check{
+	check: checkIfUserPartOfHyperVAdmins,
+	fix:   fixUserPartOfHyperVAdmins,
+}
+
+var adminHelperChecks = []Check{
+	{
+		configKeySuffix:  "check-admin-helper-daemon-installed",
+		checkDescription: "Checking if admin-helper daemon is installed",
+		check: func() error {
+			version, err := adminhelper.Client().Version()
+			if err != nil {
+				return err
+			}
+			expected := filepath.Base(constants.DefaultAdminHelperCliBase)
+			if version != expected {
+				return fmt.Errorf("unexpected admin-helper daemon version (expected: %s, got: %s)", expected, version)
+			}
+			return nil
+		},
+		fixDescription: "Installing admin-helper daemon",
+		fix: func() error {
+			_, _, err := powershell.ExecuteAsAdmin("install admin-helper daemon", fmt.Sprintf("& '%s' uninstall-daemon; & '%s' install-daemon", adminhelper.BinPath, adminhelper.BinPath))
+			return err
+		},
+		cleanupDescription: "Uninstalling admin-helper daemon",
+		cleanup: func() error {
+			_, _, err := powershell.ExecuteAsAdmin("uninstall admin-helper daemon", fmt.Sprintf("& '%s' uninstall-daemon", adminhelper.BinPath))
+			return err
+		},
+		labels: labels{Os: Windows},
+	},
+	cleanUpHostsFile,
+}
+
 const (
 	// This key is required to activate the vsock communication
 	registryDirectory = `HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices`
@@ -197,10 +291,10 @@ func getChecks() []Check {
 	checks := []Check{}
 	checks = append(checks, genericPreflightChecks...)
 	checks = append(checks, hypervPreflightChecks...)
+	checks = append(checks, adminHelperChecks...)
 	checks = append(checks, vsockChecks...)
 	checks = append(checks, traySetupChecks...)
 	checks = append(checks, bundleCheck)
-
 	return checks
 }
 
diff --git a/pkg/crc/version/version.go b/pkg/crc/version/version.go
index d73b49915..9fd1894fe 100644
--- a/pkg/crc/version/version.go
+++ b/pkg/crc/version/version.go
@@ -33,7 +33,7 @@ const (
 	// Tray version to be embedded in executable
 	crcMacTrayVersion = "1.0.9"
 	// Windows forms application version type major.minor.buildnumber.revesion
-	crcWindowsTrayVersion = "0.6.0.0"
+	crcWindowsTrayVersion = "0.7.0.0"
 )
 
 type CrcReleaseInfo struct {
diff --git a/pkg/os/windows/powershell/powershell_windows.go b/pkg/os/windows/powershell/powershell_windows.go
index 1499dc310..0a1d4c272 100644
--- a/pkg/os/windows/powershell/powershell_windows.go
+++ b/pkg/os/windows/powershell/powershell_windows.go
@@ -95,7 +95,13 @@ func runAsCmds(powershell string) []string {
 		`  $procInfo.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden`,
 		`  $procInfo.Arguments = "-ExecutionPolicy RemoteSigned & '" + $script:MyInvocation.MyCommand.Path + "'"`,
 		`  $procInfo.Verb = "runas";`,
-		`  [System.Diagnostics.Process]::Start($procInfo);`,
+		`  $p = New-Object System.Diagnostics.Process`,
+		`  $p.StartInfo = $procInfo`,
+		`  $p.Start() | Out-Null`,
+		`  $p.WaitForExit()`,
+		`  if ($p.ExitCode -ne 0) {`,
+		`    throw "Unexpected failure";`,
+		`  }`,
 		`  Exit;`,
 		`}`,
 	}
diff --git a/vendor/github.com/code-ready/admin-helper/pkg/client/client.go b/vendor/github.com/code-ready/admin-helper/pkg/client/client.go
new file mode 100644
index 000000000..1cdf57ce4
--- /dev/null
+++ b/vendor/github.com/code-ready/admin-helper/pkg/client/client.go
@@ -0,0 +1,101 @@
+package client
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+
+	"github.com/code-ready/admin-helper/pkg/types"
+)
+
+type Client struct {
+	client *http.Client
+	base   string
+}
+
+func New(client *http.Client, base string) *Client {
+	return &Client{
+		client: client,
+		base:   base,
+	}
+}
+
+func (c *Client) Version() (string, error) {
+	res, err := c.client.Get(fmt.Sprintf("%s%s", c.base, "/version"))
+	if err != nil {
+		return "", err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		return "", fmt.Errorf("unexpected status: %d", res.StatusCode)
+	}
+	body, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(string(body)), nil
+}
+
+func (c *Client) Add(req *types.AddRequest) error {
+	bin, err := json.Marshal(req)
+	if err != nil {
+		return err
+	}
+	res, err := c.client.Post(fmt.Sprintf("%s%s", c.base, "/add"), "application/json", bytes.NewReader(bin))
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		err, readErr := ioutil.ReadAll(res.Body)
+		if readErr != nil {
+			return fmt.Errorf("error while reading error message: %v", readErr)
+		}
+		return errors.New(strings.TrimSpace(string(err)))
+	}
+	return nil
+}
+
+func (c *Client) Remove(req *types.RemoveRequest) error {
+	bin, err := json.Marshal(req)
+	if err != nil {
+		return err
+	}
+	res, err := c.client.Post(fmt.Sprintf("%s%s", c.base, "/remove"), "application/json", bytes.NewReader(bin))
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		err, readErr := ioutil.ReadAll(res.Body)
+		if readErr != nil {
+			return fmt.Errorf("error while reading error message: %v", readErr)
+		}
+		return errors.New(strings.TrimSpace(string(err)))
+	}
+	return nil
+}
+
+func (c *Client) Clean(req *types.CleanRequest) error {
+	bin, err := json.Marshal(req)
+	if err != nil {
+		return err
+	}
+	res, err := c.client.Post(fmt.Sprintf("%s%s", c.base, "/clean"), "application/json", bytes.NewReader(bin))
+	if err != nil {
+		return err
+	}
+	defer res.Body.Close()
+	if res.StatusCode != http.StatusOK {
+		err, readErr := ioutil.ReadAll(res.Body)
+		if readErr != nil {
+			return fmt.Errorf("error while reading error message: %v", readErr)
+		}
+		return errors.New(strings.TrimSpace(string(err)))
+	}
+	return nil
+}
diff --git a/vendor/github.com/code-ready/admin-helper/pkg/types/requests.go b/vendor/github.com/code-ready/admin-helper/pkg/types/requests.go
new file mode 100644
index 000000000..7b9ef40ec
--- /dev/null
+++ b/vendor/github.com/code-ready/admin-helper/pkg/types/requests.go
@@ -0,0 +1,14 @@
+package types
+
+type AddRequest struct {
+	IP    string   `json:"ip"`
+	Hosts []string `json:"hosts"`
+}
+
+type RemoveRequest struct {
+	Hosts []string `json:"hosts"`
+}
+
+type CleanRequest struct {
+	Domains []string `json:"domains"`
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3259cc3bb..8114a70db 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -33,9 +33,11 @@ github.com/cavaliercoder/grab
 ## explicit
 github.com/cheggaaa/pb/v3
 github.com/cheggaaa/pb/v3/termutil
-# github.com/code-ready/admin-helper v0.0.0-20210518083720-ee7100e9f7ae
+# github.com/code-ready/admin-helper v0.0.0-20210602075518-d22477037442
 ## explicit
+github.com/code-ready/admin-helper/pkg/client
 github.com/code-ready/admin-helper/pkg/hosts
+github.com/code-ready/admin-helper/pkg/types
 # github.com/code-ready/clicumber v0.0.0-20210201104241-cecb794bdf9a
 ## explicit
 github.com/code-ready/clicumber/testsuite


Test patch:
diff --git a/pkg/crc/machine/kubeconfig_test.go b/pkg/crc/machine/kubeconfig_test.go
index 475259d60..0bbbeb555 100644
--- a/pkg/crc/machine/kubeconfig_test.go
+++ b/pkg/crc/machine/kubeconfig_test.go
@@ -2,6 +2,8 @@ package machine
 
 import (
 	"io/ioutil"
+	"os"
+	"path/filepath"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -37,3 +39,16 @@ func TestCertificateAuthority(t *testing.T) {
 	expectedString := "-----BEGIN CERTIFICATE-----\nMIIDODCCAiCgAwIBAgIIRVfCKNUa1wIwDQYJKoZIhvcNAQELBQAwJjEkMCIGA1UE\nAwwbaW5ncmVzcy1vcGVyYXRvckAxNTk5OTkxMDc4MB4XDTIwMDkxMzA5NTgwOFoX\nDTIyMDkxMzA5NTgwOVowHTEbMBkGA1UEAwwSKi5hcHBzLWNyYy50ZXN0aW5nMIIB\nIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtClYnM1FYiH+wcYiGIUnLvNi\nzLWWjsqJrQ/4Snnu61HDaU5w3An9yDZojyaJdCmWUg6CKXDiCoJB+lxMFdyaolXU\ndohJ9vr2wt6iuNfshmtxUwiBhI9ZBsVhztWdu3cgnUcYW8KMyUmajiEyXD8Npvba\nZ4ifUsjAYE1LByZzPIkmBmKPnv0fFZu1ejgg7HuQlYmfN/pJHudWMvwZJ8b3Zhqn\nsA0cDsaCDU1SJk6cQvNJFgF38+IWNhJpiQlGfFwKkal64/RYcR9yv8/pMV+7jj1z\nBPI9yxbFgLuxLxlyS8Kxnz9ln/4V0ZB12qU3c6aM4Ew3uhYv8ZDSOnpTUSjrRwID\nAQABo3MwcTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYD\nVR0TAQH/BAIwADAdBgNVHQ4EFgQUTtNCBUyuPpf4M4YhlYBqJhZGQYYwHQYDVR0R\nBBYwFIISKi5hcHBzLWNyYy50ZXN0aW5nMA0GCSqGSIb3DQEBCwUAA4IBAQBkGZiv\nBqqEDKUTiifFfTxQXJzO5OBBTUDqSntrknAw0sidPgn9A8a2gGdCr7mKEH16FQ7N\n1SpkjXWZghE/1pZTaS7JVcT6+Yuplfy5Reoim/Nlu8ulDDfBSSp9S9BO+Q/lFJdM\nomwyIu0sSXI79ColhLirDinEmyQMDHdmTJ+kJfctpSH27L4j5osJxtNSAEABmUgX\n1HQ7FYzrNmys5OcK9SlDn0vCyOTHyqBbxRnF6L9Ec2bU6KD0DvEBurBpAYGMc9ss\nBD0FXdHEPg7HP0Nep79jhe10IXGrghtep3D5jUjbj1I4DGSsQ8y4df2vo6IFd96A\nf0uUS/73sncN64gl\n-----END CERTIFICATE-----\n"
 	assert.Equal(t, expectedString, string(st), "")
 }
+
+func TestCleanKubeconfig(t *testing.T) {
+	dir, err := ioutil.TempDir("", "clean")
+	assert.NoError(t, err)
+	defer os.RemoveAll(dir)
+
+	assert.NoError(t, cleanKubeconfig(filepath.Join("testdata", "kubeconfig.in"), filepath.Join(dir, "kubeconfig")))
+	actual, err := ioutil.ReadFile(filepath.Join(dir, "kubeconfig"))
+	assert.NoError(t, err)
+	expected, err := ioutil.ReadFile(filepath.Join("testdata", "kubeconfig.out"))
+	assert.NoError(t, err)
+	assert.YAMLEq(t, string(expected), string(actual))
+}
diff --git a/pkg/crc/machine/testdata/kubeconfig.in b/pkg/crc/machine/testdata/kubeconfig.in
new file mode 100644
index 000000000..bfdbc3819
--- /dev/null
+++ b/pkg/crc/machine/testdata/kubeconfig.in
@@ -0,0 +1,63 @@
+apiVersion: v1
+clusters:
+- cluster:
+    certificate-authority-data: ZW1wdHkK
+    server: https://192.168.42.71:8443
+  name: 192-168-42-71:8443
+- cluster:
+    certificate-authority-data: ZW1wdHkK
+    server: https://api.crc.testing:6443
+  name: api-crc-testing:6443
+- cluster:
+    certificate-authority-data: ZW1wdHkK
+    server: https://127.0.0.1:33407
+  name: kind-reference
+contexts:
+- context:
+    cluster: api-crc-testing:6443
+    user: developer
+  name: /api-crc-testing:6443/developer
+- context:
+    cluster: api-crc-testing:6443
+    namespace: default
+    user: kubeadmin
+  name: crc-admin
+- context:
+    cluster: api-crc-testing:6443
+    namespace: default
+    user: developer
+  name: crc-developer
+- context:
+    cluster: kind-reference
+    user: kind-reference
+  name: kind-reference
+- context:
+    cluster: 192-168-42-71:8443
+    namespace: myproject
+    user: developer/192-168-42-71:8443
+  name: minishift
+- context:
+    cluster: api-crc-testing:6443
+    namespace: project1
+    user: developer
+  name: project1/api-crc-testing:6443/developer
+current-context: project1/api-crc-testing:6443/developer
+kind: Config
+preferences: {}
+users:
+- name: developer
+  user:
+    token: token1
+- name: developer/192-168-42-71:8443
+  user:
+    token: token2
+- name: developer/api-crc-testing:6443
+  user:
+    token: token3
+- name: kind-reference
+  user:
+    client-certificate-data: ZW1wdHkK
+    client-key-data: ZW1wdHkK
+- name: kubeadmin
+  user:
+    token: token4
diff --git a/pkg/crc/machine/testdata/kubeconfig.out b/pkg/crc/machine/testdata/kubeconfig.out
new file mode 100644
index 000000000..62d93a5d9
--- /dev/null
+++ b/pkg/crc/machine/testdata/kubeconfig.out
@@ -0,0 +1,34 @@
+apiVersion: v1
+clusters:
+- cluster:
+    certificate-authority-data: ZW1wdHkK
+    server: https://192.168.42.71:8443
+  name: 192-168-42-71:8443
+- cluster:
+    certificate-authority-data: ZW1wdHkK
+    server: https://127.0.0.1:33407
+  name: kind-reference
+contexts:
+- context:
+    cluster: kind-reference
+    user: kind-reference
+  name: kind-reference
+- context:
+    cluster: 192-168-42-71:8443
+    namespace: myproject
+    user: developer/192-168-42-71:8443
+  name: minishift
+current-context: ""
+kind: Config
+preferences: {}
+users:
+- name: developer/192-168-42-71:8443
+  user:
+    token: token2
+- name: developer/api-crc-testing:6443
+  user:
+    token: token3
+- name: kind-reference
+  user:
+    client-certificate-data: ZW1wdHkK
+    client-key-data: ZW1wdHkK
diff --git a/pkg/crc/preflight/preflight_linux_test.go b/pkg/crc/preflight/preflight_linux_test.go
index 7cc456890..31952142f 100644
--- a/pkg/crc/preflight/preflight_linux_test.go
+++ b/pkg/crc/preflight/preflight_linux_test.go
@@ -69,9 +69,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -104,9 +104,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -138,9 +138,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -166,9 +166,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -201,9 +201,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -235,9 +235,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -263,9 +263,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -298,9 +298,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -332,9 +332,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -360,9 +360,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -396,9 +396,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
@@ -431,9 +431,9 @@ var checkListForDistros = []checkListForDistro{
 			{check: checkSupportedCPUArch},
 			{configKeySuffix: "check-ram"},
 			{cleanup: removeCRCMachinesDir},
-			{cleanup: removeHostsFileEntry},
 			{cleanup: removeOldLogs},
 			{cleanup: cluster.ForgetPullSecret},
+			{cleanup: removeHostsFileEntry},
 			{check: checkVirtualizationEnabled},
 			{check: checkKvmEnabled},
 			{check: checkLibvirtInstalled},
diff --git a/pkg/crc/preflight/preflight_windows_test.go b/pkg/crc/preflight/preflight_windows_test.go
index 3feeb5cb8..0362822d3 100644
--- a/pkg/crc/preflight/preflight_windows_test.go
+++ b/pkg/crc/preflight/preflight_windows_test.go
@@ -11,13 +11,13 @@ import (
 func TestCountConfigurationOptions(t *testing.T) {
 	cfg := config.New(config.NewEmptyInMemoryStorage())
 	RegisterSettings(cfg)
-	assert.Len(t, cfg.AllConfigs(), 13)
+	assert.Len(t, cfg.AllConfigs(), 15)
 }
 
 func TestCountPreflights(t *testing.T) {
-	assert.Len(t, getPreflightChecks(false, false, network.SystemNetworkingMode), 18)
-	assert.Len(t, getPreflightChecks(true, true, network.SystemNetworkingMode), 18)
+	assert.Len(t, getPreflightChecks(false, false, network.SystemNetworkingMode), 20)
+	assert.Len(t, getPreflightChecks(true, true, network.SystemNetworkingMode), 20)
 
-	assert.Len(t, getPreflightChecks(false, false, network.UserNetworkingMode), 19)
-	assert.Len(t, getPreflightChecks(true, true, network.UserNetworkingMode), 19)
+	assert.Len(t, getPreflightChecks(false, false, network.UserNetworkingMode), 21)
+	assert.Len(t, getPreflightChecks(true, true, network.UserNetworkingMode), 21)
 }