Change:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . --Is this a BUG REPORT or FEATURE REQUEST?: /kind bug What happened: In , which is used by many clients, homedir favors a concatenation of %HOMEDRIVE% and %HOMEPATH% over %USERPROFILE% What you expected to happen: HOME should be favored if it is set, then fallback to USERPROFILE, then maybe HOMEDRIVE and HOMEPATH combination. Anything else we need to know?: The current implementation of resolves a homedir in this order: concatenation of HOMEDRIVE and HOMEPATH I believe that this is wrong, notably the HOMEDRIVE and HOMEPATH construct. In the corporate environment where I work, these variables are hard set to network drives which are not writable. This results in many problems for dependant projects like minikube, kubectl kubernetes/kubectl (which would benefit from using client-go code). There are almost no mention of using HOMEDRIVE and HOMEPATH, but authoritative information on the subject is hard to find. Relevant documentation: Environment: Windows
cc
sounds reasonable. but I'd like to have sig/windows folks to chime in.
Additional profiles directory information: (v=vs.85).aspx Microsoft makes it difficult to reason about these environment variables as they are not readily mentioned/searchable in the online documentation. Even in the previously mentioned doc on profiles, no mention of the %USERPROFILE% environment variable is made. Python already does this resolution in the order suggested: HOME, USERPROFILE, and HOMEDRIVE/ HOMEPATH: There could be another way to implement this: If it is possible, call the Windows API .aspx) to know the path, regardless of env variables.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale still relevant
This continues to be an issue in 1.11.0. Basically, the HOMEDRIVE/HOMEPATH is a holdover from NT4 days with roaming profiles. This is not a standard env variable anymore. The existence of HOMEDRIVE / HOMEPATH should be ignored if USERPROFILE is set. Neither HOMEDRIVE nor HOMEPATH are standard environment variables: They are not use in any known folder locations: (v=vs.85).aspx The existence of a HOMEDRIVE / HOMEPATH will cause to look in the wrong home folder for the . A use-case here is with AKS - the Azure CLI (written by Microsoft) will correctly place credentials into , however will look in . Because of this, will think it should connect to localhost until the HOMEDRIVE and HOMEPATH variables are unset or removed in the session.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale
Since has proposed a different approach, I wanted to discuss it in the original issue for clarity. I do not believe we should not favor the use of at all as is proposed with here: Based on the use-case raised by and experienced by myself as well, this will cause more problems if we continue to prefer . I understand moving existing configs from a prior path to be more aligned valid environment variables (which is not) will cause some breakage without migrating old configs. To illustrate the issue, some tools on Windows like the Azure CLI do not honor and thus, when authenticating users to Microsoft's own managed Kubernetes offerings, it writes the configuration to . When the config is written to , but is looking in , the client does not get the correct configuration. With the PR proposed, I'm afraid we may further fracture things with clients writing to non-standard environment variables and where some outlier cases would end up with a folder in both and . The , then , then would follow what I think most tools and languages use. I believe this is in wide adoption and the evaluation of environment variables should be in that order. For example, python's ordering:
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale

Discussion:
import ( "os" <ins> "path/filepath" </ins> "runtime" ) <del> // HomeDir returns the home directory for the current user </del> <ins> // HomeDir returns the home directory for the current user. // On Windows: // 1. the first of %HOME%, %HOMEDRIVE%%HOMEPATH%, %USERPROFILE% containing a `.kubeconfig` file is returned. // 2. if none of those locations contain a `.kubeconfig` file, the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists and is writeable is returned. // 3. if none of those locations are writeable, the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that exists is returned. // 4. if none of those locations exists, the first of %HOME%, %USERPROFILE%, %HOMEDRIVE%%HOMEPATH% that is set is returned. </ins> func HomeDir() string { if runtime.GOOS == "windows" { <ins> home := os.Getenv("HOME") homeDriveHomePath := "" if homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"); len(homeDrive) > 0 && len(homePath) > 0 { homeDriveHomePath = homeDrive + homePath } userProfile := os.Getenv("USERPROFILE") </ins> <del> // First prefer the HOME environmental variable if home := os.Getenv("HOME"); len(home) > 0 { if _, err := os.Stat(home); err == nil { return home </del> <ins> // Return first of %HOME%, %HOMEDRIVE%/%HOMEPATH%, %USERPROFILE% that contains a `.kubeconfig` file. // %HOMEDRIVE%/%HOMEPATH% is preferred over %USERPROFILE% for backwards-compatibility. for _, p := range []string{home, homeDriveHomePath, userProfile} { if len(p) == 0 { continue </ins> } <del> } if homeDrive, homePath := os.Getenv("HOMEDRIVE"), os.Getenv("HOMEPATH"); len(homeDrive) > 0 && len(homePath) > 0 { homeDir := homeDrive + homePath if _, err := os.Stat(homeDir); err == nil { return homeDir </del> <ins> if _, err := os.Stat(filepath.Join(p, ".kube", "config")); err != nil { continue </ins> } <ins> return p </ins> } <del> if userProfile := os.Getenv("USERPROFILE"); len(userProfile) > 0 { if _, err := os.Stat(userProfile); err == nil { return userProfile </del> <ins> firstSetPath := "" firstExistingPath := "" // Prefer %USERPROFILE% over %HOMEDRIVE%/%HOMEPATH% for compatibility with other auth-writing tools for _, p := range []string{home, userProfile, homeDriveHomePath} { if len(p) == 0 { continue } if len(firstSetPath) == 0 { // remember the first path that is set firstSetPath = p } info, err := os.Stat(p) if err != nil { continue </ins> } <ins> if len(firstExistingPath) == 0 { // remember the first path that exists firstExistingPath = p } if info.IsDir() && info.Mode().Perm()&(1<<(uint(7))) != 0 { // return first path that is writeable return p } } // If none are writeable, return first location that exists if len(firstExistingPath) > 0 { return firstExistingPath </ins> } <ins> // If none exist, return first location that is set if len(firstSetPath) > 0 { return firstSetPath } // We've got nothing return "" </ins> } return os.Getenv("HOME") }