diff --git a/cmd/minikube/cmd/docker-env.go b/cmd/minikube/cmd/docker-env.go index 5f34398ddd..f27513a471 100644 --- a/cmd/minikube/cmd/docker-env.go +++ b/cmd/minikube/cmd/docker-env.go @@ -30,6 +30,7 @@ import ( "github.com/spf13/cobra" "k8s.io/klog/v2" + "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/command" "k8s.io/minikube/pkg/minikube/constants" @@ -43,7 +44,31 @@ import ( "k8s.io/minikube/pkg/minikube/sysinit" ) -var dockerEnvTmpl = fmt.Sprintf("{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}", constants.DockerTLSVerifyEnv, constants.DockerHostEnv, constants.DockerCertPathEnv, constants.MinikubeActiveDockerdEnv) +var dockerSetEnvTmpl = fmt.Sprintf( + "{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}"+ + "{{ if .ExistingDockerTLSVerify }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .ExistingDockerTLSVerify }}{{ .Suffix }}"+ + "{{ end }}"+ + "{{ if .ExistingDockerHost }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .ExistingDockerHost }}{{ .Suffix }}"+ + "{{ end }}"+ + "{{ if .ExistingDockerCertPath }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .ExistingDockerCertPath }}{{ .Suffix }}"+ + "{{ end }}"+ + "{{ .Prefix }}%s{{ .Delimiter }}{{ .MinikubeDockerdProfile }}{{ .Suffix }}"+ + "{{ if .NoProxyVar }}"+ + "{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}"+ + "{{ end }}"+ + "{{ .UsageHint }}", + constants.DockerTLSVerifyEnv, + constants.DockerHostEnv, + constants.DockerCertPathEnv, + constants.ExistingDockerTLSVerifyEnv, + constants.ExistingDockerHostEnv, + constants.ExistingDockerCertPathEnv, + constants.MinikubeActiveDockerdEnv) // DockerShellConfig represents the shell config for Docker type DockerShellConfig struct { @@ -54,6 +79,10 @@ type DockerShellConfig struct { MinikubeDockerdProfile string NoProxyVar string NoProxyValue string + + ExistingDockerCertPath string + ExistingDockerHost string + ExistingDockerTLSVerify string } var ( @@ -81,6 +110,11 @@ func dockerShellCfgSet(ec DockerEnvConfig, envMap map[string]string) *DockerShel s.DockerCertPath = envMap[constants.DockerCertPathEnv] s.DockerHost = envMap[constants.DockerHostEnv] s.DockerTLSVerify = envMap[constants.DockerTLSVerifyEnv] + + s.ExistingDockerCertPath = envMap[constants.ExistingDockerCertPathEnv] + s.ExistingDockerHost = envMap[constants.ExistingDockerHostEnv] + s.ExistingDockerTLSVerify = envMap[constants.ExistingDockerTLSVerifyEnv] + s.MinikubeDockerdProfile = envMap[constants.MinikubeActiveDockerdEnv] if ec.noProxy { @@ -228,7 +262,7 @@ type DockerEnvConfig struct { // dockerSetScript writes out a shell-compatible 'docker-env' script func dockerSetScript(ec DockerEnvConfig, w io.Writer) error { envVars := dockerEnvVars(ec) - return shell.SetScript(ec.EnvConfig, w, dockerEnvTmpl, dockerShellCfgSet(ec, envVars)) + return shell.SetScript(ec.EnvConfig, w, dockerSetEnvTmpl, dockerShellCfgSet(ec, envVars)) } // dockerSetScript writes out a shell-compatible 'docker-env unset' script @@ -246,7 +280,6 @@ func dockerUnsetScript(ec DockerEnvConfig, w io.Writer) error { vars = append(vars, k) } } - return shell.UnsetScript(ec.EnvConfig, w, vars) } @@ -257,14 +290,21 @@ func dockerURL(ip string, port int) string { // dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon func dockerEnvVars(ec DockerEnvConfig) map[string]string { - env := map[string]string{ + rt := map[string]string{ constants.DockerTLSVerifyEnv: "1", constants.DockerHostEnv: dockerURL(ec.hostIP, ec.port), constants.DockerCertPathEnv: ec.certsDir, constants.MinikubeActiveDockerdEnv: ec.profile, } - - return env + if os.Getenv(constants.MinikubeActiveDockerdEnv) == "" { + for _, env := range constants.DockerDaemonEnvs { + if v := oci.InitialEnv(env); v != "" { + key := constants.MinikubeExistingPrefix + env + rt[key] = v + } + } + } + return rt } // dockerEnvVarsList gets the necessary docker env variables to allow the use of minikube's docker daemon to be used in a exec.Command diff --git a/pkg/drivers/kic/kic.go b/pkg/drivers/kic/kic.go index 10c5aebdcc..0f13b64085 100644 --- a/pkg/drivers/kic/kic.go +++ b/pkg/drivers/kic/kic.go @@ -95,10 +95,11 @@ func (d *Driver) Create() error { } // control plane specific options - params.PortMappings = append(params.PortMappings, oci.PortMapping{ - ListenAddress: oci.DefaultBindIPV4, - ContainerPort: int32(params.APIServerPort), - }, + params.PortMappings = append(params.PortMappings, + oci.PortMapping{ + ListenAddress: oci.DefaultBindIPV4, + ContainerPort: int32(params.APIServerPort), + }, oci.PortMapping{ ListenAddress: oci.DefaultBindIPV4, ContainerPort: constants.SSHPort, diff --git a/pkg/drivers/kic/oci/env.go b/pkg/drivers/kic/oci/env.go new file mode 100644 index 0000000000..6899016f11 --- /dev/null +++ b/pkg/drivers/kic/oci/env.go @@ -0,0 +1,47 @@ +/* +Copyright 2020 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package oci + +import ( + "os" + + "k8s.io/minikube/pkg/minikube/constants" +) + +var initialEnvs = make(map[string]string) + +func init() { + for _, env := range constants.DockerDaemonEnvs { + if v, set := os.LookupEnv(env); set { + initialEnvs[env] = v + } + exEnv := constants.MinikubeExistingPrefix + env + if v, set := os.LookupEnv(exEnv); set { + initialEnvs[exEnv] = v + } + } +} + +// InitialEnv returns the value of the environment variable env before any environment changes made by minikube +func InitialEnv(env string) string { + return initialEnvs[env] +} + +// LookupInitialEnv returns the value of the environment variable env before any environment changes made by minikube +func LookupInitialEnv(env string) (string, bool) { + v, set := initialEnvs[env] + return v, set +} diff --git a/pkg/drivers/kic/oci/oci.go b/pkg/drivers/kic/oci/oci.go index e55cfd147b..ced79caf08 100644 --- a/pkg/drivers/kic/oci/oci.go +++ b/pkg/drivers/kic/oci/oci.go @@ -523,11 +523,10 @@ func PointToHostDockerDaemon() error { if p := os.Getenv(constants.MinikubeActiveDockerdEnv); p != "" { klog.Infof("shell is pointing to dockerd inside minikube. will unset to use host") - } - - for _, e := range constants.DockerDaemonEnvs { - if err := resetEnv(e); err != nil { - return err + for _, e := range constants.DockerDaemonEnvs { + if err := resetEnv(e); err != nil { + return err + } } } @@ -542,7 +541,6 @@ func resetEnv(key string) error { } return nil } - if err := os.Setenv(key, v); err != nil { return errors.Wrapf(err, "resetting %s env", key) } diff --git a/pkg/drivers/kic/oci/oci_test.go b/pkg/drivers/kic/oci/oci_test.go index 897762345d..164793537f 100644 --- a/pkg/drivers/kic/oci/oci_test.go +++ b/pkg/drivers/kic/oci/oci_test.go @@ -25,6 +25,7 @@ func TestPointToHostDockerDaemonEmpty(t *testing.T) { _ = os.Setenv("DOCKER_HOST", "foo_host") _ = os.Setenv("DOCKER_CERT_PATH", "foo_cert_path") _ = os.Setenv("DOCKER_TLS_VERIFY", "foo_tls_verify") + _ = os.Setenv("MINIKUBE_ACTIVE_DOCKERD", "minikube") _ = os.Unsetenv("MINIKUBE_EXISTING_DOCKER_HOST") _ = os.Unsetenv("MINIKUBE_EXISTING_DOCKER_CERT_PATH") diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index 54238fe6bb..00896b69f5 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -75,8 +75,16 @@ const ( MinikubeForceSystemdEnv = "MINIKUBE_FORCE_SYSTEMD" // TestDiskUsedEnv is used in integration tests for insufficient storage with 'minikube status' TestDiskUsedEnv = "MINIKUBE_TEST_STORAGE_CAPACITY" + // MinikubeExistingPrefix is used to save the original environment when executing docker-env MinikubeExistingPrefix = "MINIKUBE_EXISTING_" + + // ExistingDockerHostEnv is used to save original docker environment + ExistingDockerHostEnv = MinikubeExistingPrefix + "DOCKER_HOST" + // ExistingDockerCertPathEnv is used to save original docker environment + ExistingDockerCertPathEnv = MinikubeExistingPrefix + "DOCKER_CERT_PATH" + // ExistingDockerTLSVerifyEnv is used to save original docker environment + ExistingDockerTLSVerifyEnv = MinikubeExistingPrefix + "DOCKER_TLS_VERIFY" ) var ( @@ -92,6 +100,9 @@ var ( // DockerDaemonEnvs is list of docker-daemon related environment variables. DockerDaemonEnvs = [3]string{DockerHostEnv, DockerTLSVerifyEnv, DockerCertPathEnv} + // ExistingDockerDaemonEnvs is list of docker-daemon related environment variables. + ExistingDockerDaemonEnvs = [3]string{ExistingDockerHostEnv, ExistingDockerTLSVerifyEnv, ExistingDockerCertPathEnv} + // PodmanRemoteEnvs is list of podman-remote related environment variables. PodmanRemoteEnvs = [1]string{PodmanVarlinkBridgeEnv} diff --git a/pkg/minikube/shell/shell.go b/pkg/minikube/shell/shell.go index 5d562ba653..f224c41c9c 100644 --- a/pkg/minikube/shell/shell.go +++ b/pkg/minikube/shell/shell.go @@ -24,12 +24,21 @@ import ( "io" "os" "runtime" - "strings" "text/template" "github.com/docker/machine/libmachine/shell" + + "k8s.io/minikube/pkg/minikube/constants" ) +var unsetEnvTmpl = "{{ $root := .}}" + + "{{ range .Unset }}" + + "{{ $root.UnsetPrefix }}{{ . }}{{ $root.UnsetDelimiter }}{{ $root.UnsetSuffix }}" + + "{{ end }}" + + "{{ range .Set }}" + + "{{ $root.SetPrefix }}{{ .Env }}{{ $root.SetDelimiter }}{{ .Value }}{{ $root.SetSuffix }}" + + "{{ end }}" + // Config represents the shell config type Config struct { Prefix string @@ -107,7 +116,7 @@ REM @FOR /f "tokens=*" %%i IN ('%s') DO @%%i suffix: "\"\n", delimiter: "=\"", unsetPrefix: "unset ", - unsetSuffix: "\n", + unsetSuffix: ";\n", unsetDelimiter: "", usageHint: func(s ...interface{}) string { return fmt.Sprintf(` @@ -181,24 +190,46 @@ func SetScript(ec EnvConfig, w io.Writer, envTmpl string, data interface{}) erro return tmpl.Execute(w, data) } +type unsetConfigItem struct { + Env, Value string +} +type unsetConfig struct { + Set []unsetConfigItem + Unset []string + SetPrefix string + SetDelimiter string + SetSuffix string + UnsetPrefix string + UnsetDelimiter string + UnsetSuffix string +} + // UnsetScript writes out a shell-compatible unset script func UnsetScript(ec EnvConfig, w io.Writer, vars []string) error { - var sb strings.Builder shellCfg := ec.getShell() - pfx, sfx, delim := shellCfg.unsetPrefix, shellCfg.unsetSuffix, shellCfg.unsetDelimiter - switch ec.Shell { - case "cmd", "emacs", "fish": - break - case "powershell": - vars = []string{strings.Join(vars, " Env:\\\\")} - default: - vars = []string{strings.Join(vars, " ")} + cfg := unsetConfig{ + SetPrefix: shellCfg.prefix, + SetDelimiter: shellCfg.delimiter, + SetSuffix: shellCfg.suffix, + UnsetPrefix: shellCfg.unsetPrefix, + UnsetDelimiter: shellCfg.unsetDelimiter, + UnsetSuffix: shellCfg.unsetSuffix, } - for _, v := range vars { - if _, err := sb.WriteString(fmt.Sprintf("%s%s%s%s", pfx, v, delim, sfx)); err != nil { - return err + var tempUnset []string + for _, env := range vars { + exEnv := constants.MinikubeExistingPrefix + env + if v := os.Getenv(exEnv); v == "" { + cfg.Unset = append(cfg.Unset, env) + } else { + cfg.Set = append(cfg.Set, unsetConfigItem{ + Env: env, + Value: v, + }) + tempUnset = append(tempUnset, exEnv) } } - _, err := w.Write([]byte(sb.String())) - return err + cfg.Unset = append(cfg.Unset, tempUnset...) + + tmpl := template.Must(template.New("unsetEnv").Parse(unsetEnvTmpl)) + return tmpl.Execute(w, &cfg) } diff --git a/pkg/minikube/shell/shell_test.go b/pkg/minikube/shell/shell_test.go index 43dcdcaa71..cf8de26c26 100644 --- a/pkg/minikube/shell/shell_test.go +++ b/pkg/minikube/shell/shell_test.go @@ -87,16 +87,19 @@ func TestUnsetScript(t *testing.T) { ec EnvConfig expected string }{ - {[]string{"baz", "bar"}, EnvConfig{""}, `unset baz bar`}, - {[]string{"baz", "bar"}, EnvConfig{"bash"}, `unset baz bar`}, - {[]string{"baz", "bar"}, EnvConfig{"powershell"}, `Remove-Item Env:\\baz Env:\\bar`}, + {[]string{"baz", "bar"}, EnvConfig{""}, `unset baz; +unset bar;`}, + {[]string{"baz", "bar"}, EnvConfig{"bash"}, `unset baz; +unset bar;`}, + {[]string{"baz", "bar"}, EnvConfig{"powershell"}, `Remove-Item Env:\\baz +Remove-Item Env:\\bar`}, {[]string{"baz", "bar"}, EnvConfig{"cmd"}, `SET baz= SET bar=`}, {[]string{"baz", "bar"}, EnvConfig{"fish"}, `set -e baz; set -e bar;`}, {[]string{"baz", "bar"}, EnvConfig{"emacs"}, `(setenv "baz" nil) (setenv "bar" nil)`}, - {[]string{"baz", "bar"}, EnvConfig{"none"}, `baz bar`}, + {[]string{"baz", "bar"}, EnvConfig{"none"}, "baz\nbar"}, } for _, tc := range testCases { tc := tc