Repository: kubernetes/minikube (go)

Issue:
Current MINIKUBE_HOME environment variable setting logic is confusing
### What Happened?

We set `export MINIKUBE_HOME=~/somewhere_else/minikube`,

But after setting it, the real minikube home lies in `~/somewhere_else/minikube/.minikube`.

This is inconsistent with the usual XXX_HOME setting logic and is very confusing.

---

By looking at the code, we found the following logic and know why this happened: https://github.com/kubernetes/minikube/blob/5c0c9e8e7c20b603665204d065e418027e3a930a/pkg/minikube/localpath/localpath.go#L42-L51

Can anyone give more context why it is set up this way?

If no special reason, we should respect the `MINIKUBE_HOME` env var. i.e., the real minikube home should lies in `~/somewhere_else/minikube` rather than `~/somewhere_else/minikube/.minikube`.

### Attach the log file

N/A

### Operating System

None

### Driver

None
```[tasklist]
### Tasks
```


Pull request description:
Update MINIKUBE_HOME usage
Resolves #15835

Make `MINIKUBE_HOME` env variable usage more convenient with backward compatibility.

Current logic of `MINIKUBE_HOME` env usage isn't really obvious:
- If env var is not set, it uses `${HOME}/.minikube` as default.
- If env var is set, it **checks its basename** (for some reason??):
  - If basename equals `.minikube` - use env var
  - Else it **appends** `.minikube` to env var value (for some reason??)

It's very implicit logic and goes against the conventional use of `*_HOME` env vars.

With this changes, the logic changes a bit:
- If env var is not set, it uses `${HOME}/.minikube` as default (***as it's now***)
- If env var is set, it **checks its basename** (***as it's now***)
  - If basename equals `.minikube` - use env var (***as it's now***)
  - Else it **checks existence** of `.minikube` inside path, provided via env var (***for backward compatibility***)
    - If `${MINIKUBE_HOME}/.minikube` exists - use this **legacy** path (***for backward compatibility***)
    - Else - use `MINIKUBE_HOME` as is (***new***)

So, here is example cases:
1) Env is unset:
   ```
   $ export MINIKUBE_HOME=""
   $ # run minikube
   $ ls -hAF ~ | grep minikube
   .minikube/
   $ ls -hAF ~/.minikube
   addons/   cache/    certs/    config/   files/    logs/     machines/
   ```
2) Env is set AND its basename is `.minikube`:
   ```
   $ export MINIKUBE_HOME="${XDG_DATA_HOME}/.minikube"
   $ # run minikube
   $ ls -hAF $XDG_DATA_HOME | grep minikube
   .minikube/
   $ ls -hAF $XDG_DATA_HOME/.minikube
   addons/   cache/    certs/    config/   files/    logs/     machines/
   ```
3) Env is set AND its basename is **not** `.minikube` AND there is NO `.minikube` inside:
   ```
   $ export MINIKUBE_HOME="${XDG_DATA_HOME}/minikube"
   $ ls -hAF $MINIKUBE_HOME
   $ # MINIKUBE_HOME is empty
   $ # run minikube
   $ ls -hAF $MINIKUBE_HOME
   addons/   cache/    certs/    config/   files/    logs/     machines/
   ```
4) Env is set AND its basename is **not** `.minikube` AND there is `.minikube` inside provided path:
   ```
   $ export MINIKUBE_HOME="${XDG_DATA_HOME}/minikube"
   $ ls -hAF $MINIKUBE_HOME
   .minikube/
   $ # MINIKUBE_HOME has state from previous version
   $ # run minikube
   $ ls -hAF $MINIKUBE_HOME
   .minikube/
   $ ls -hAF $MINIKUBE_HOME/.minikube
   addons/   cache/    certs/    config/   files/    logs/     machines/
   ```

<!-- 🎉 Thank you for contributing to minikube! 🎉 Here are some hints to get your PR merged faster:

1. Your PR title will be included in the release notes, choose it carefully
2. If the PR fixes an issue, add "fixes #<issue number>" to the description.
3. If the PR is a user interface change, please include a "before" and "after" example.
4. If the PR is a large design change, please include an enhancement proposal:
https://github.com/kubernetes/minikube/tree/master/enhancements
-->


Patch:
diff --git a/pkg/minikube/localpath/localpath.go b/pkg/minikube/localpath/localpath.go
index ef77e07dc..08609c0f5 100644
--- a/pkg/minikube/localpath/localpath.go
+++ b/pkg/minikube/localpath/localpath.go
@@ -47,7 +47,12 @@ func MiniPath() string {
 	if filepath.Base(minikubeHomeEnv) == ".minikube" {
 		return minikubeHomeEnv
 	}
-	return filepath.Join(minikubeHomeEnv, ".minikube")
+
+	legacyMinikubeHome := filepath.Join(minikubeHomeEnv, ".minikube")
+	if _, err := os.Stat(legacyMinikubeHome); !os.IsNotExist(err) {
+		return legacyMinikubeHome
+	}
+	return filepath.Clean(minikubeHomeEnv)
 }
 
 // MakeMiniPath is a utility to calculate a relative path to our directory.


Test patch:
diff --git a/pkg/minikube/kubeconfig/kubeconfig_test.go b/pkg/minikube/kubeconfig/kubeconfig_test.go
index eedc08239..b1a22f5e0 100644
--- a/pkg/minikube/kubeconfig/kubeconfig_test.go
+++ b/pkg/minikube/kubeconfig/kubeconfig_test.go
@@ -456,7 +456,7 @@ func TestUpdateIP(t *testing.T) {
 		},
 	}
 
-	t.Setenv(localpath.MinikubeHome, "/home/la-croix")
+	t.Setenv(localpath.MinikubeHome, "/home/la-croix/.minikube")
 
 	for _, test := range tests {
 		test := test
@@ -492,7 +492,7 @@ func TestUpdateIP(t *testing.T) {
 }
 
 func TestMissingContext(t *testing.T) {
-	t.Setenv(localpath.MinikubeHome, "/home/la-croix")
+	t.Setenv(localpath.MinikubeHome, "/home/la-croix/.minikube")
 	configFilename := tempFile(t, kubeConfigMissingContext)
 	defer os.Remove(configFilename)
 	if _, err := UpdateEndpoint("minikube", "192.168.10.100", 8080, configFilename, nil); err != nil {
diff --git a/pkg/minikube/localpath/localpath_test.go b/pkg/minikube/localpath/localpath_test.go
index ad62cc361..705d81634 100644
--- a/pkg/minikube/localpath/localpath_test.go
+++ b/pkg/minikube/localpath/localpath_test.go
@@ -63,19 +63,18 @@ func TestHasWindowsDriveLetter(t *testing.T) {
 
 func TestMiniPath(t *testing.T) {
 	var testCases = []struct {
-		env, basePath string
+		env, expectedPath string
 	}{
-		{"/tmp/.minikube", "/tmp/"},
-		{"/tmp/", "/tmp"},
-		{"", homedir.HomeDir()},
+		{"/tmp/.minikube", "/tmp/.minikube"},
+		{"/tmp", "/tmp"},
+		{"", filepath.Join(homedir.HomeDir(), ".minikube")},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.env, func(t *testing.T) {
-			expectedPath := filepath.Join(tc.basePath, ".minikube")
 			t.Setenv(MinikubeHome, tc.env)
 			path := MiniPath()
-			if path != expectedPath {
-				t.Errorf("MiniPath expected to return '%s', but got '%s'", expectedPath, path)
+			if path != tc.expectedPath {
+				t.Errorf("MiniPath expected to return '%s', but got '%s'", tc.expectedPath, path)
 			}
 		})
 	}