diff --git a/cmd/minikube/cmd/env.go b/cmd/minikube/cmd/env.go index 546a6a5cc5..290c6041d3 100644 --- a/cmd/minikube/cmd/env.go +++ b/cmd/minikube/cmd/env.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -21,25 +21,29 @@ package cmd import ( "fmt" + "io" + "net" "os" + "strconv" "strings" "text/template" - "github.com/docker/machine/libmachine" "github.com/docker/machine/libmachine/drivers" - "github.com/docker/machine/libmachine/host" - "github.com/docker/machine/libmachine/log" "github.com/docker/machine/libmachine/shell" "github.com/docker/machine/libmachine/state" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" + "k8s.io/minikube/pkg/drivers/kic" + "k8s.io/minikube/pkg/drivers/kic/oci" "k8s.io/minikube/pkg/minikube/cluster" "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/constants" "k8s.io/minikube/pkg/minikube/driver" "k8s.io/minikube/pkg/minikube/exit" + "k8s.io/minikube/pkg/minikube/localpath" "k8s.io/minikube/pkg/minikube/machine" + "k8s.io/minikube/pkg/minikube/out" ) var envTmpl = 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) @@ -108,18 +112,9 @@ var ( noProxy bool forceShell string unset bool - defaultShellDetector ShellDetector defaultNoProxyGetter NoProxyGetter ) -// ShellDetector detects shell -type ShellDetector interface { - GetShell(string) (string, error) -} - -// LibmachineShellDetector detects shell, using libmachine -type LibmachineShellDetector struct{} - // NoProxyGetter gets the no_proxy variable type NoProxyGetter interface { GetNoProxyVar() (string, string) @@ -128,7 +123,7 @@ type NoProxyGetter interface { // EnvNoProxyGetter gets the no_proxy variable, using environment type EnvNoProxyGetter struct{} -func generateUsageHint(profile string, userShell string) string { +func generateUsageHint(profile, sh string) string { const usgPlz = "Please run command bellow to point your shell to minikube's docker-daemon :" var usgCmd = fmt.Sprintf("minikube -p %s docker-env", profile) var usageHintMap = map[string]string{ @@ -154,148 +149,108 @@ REM @FOR /f "tokens=*" %%i IN ('%s') DO @%%i `, usgPlz, usgCmd), } - hint, ok := usageHintMap[userShell] + hint, ok := usageHintMap[sh] if !ok { return usageHintMap["bash"] } return hint } -func shellCfgSet(api libmachine.API) (*ShellConfig, error) { - - envMap, err := cluster.GetNodeDockerEnv(api) - if err != nil { - return nil, err - } - - userShell, err := defaultShellDetector.GetShell(forceShell) - if err != nil { - return nil, err - } - - shellCfg := &ShellConfig{ +// shellCfgSet generates context variables for "docker-env" +func shellCfgSet(ec EnvConfig, envMap map[string]string) *ShellConfig { + s := &ShellConfig{ DockerCertPath: envMap[constants.DockerCertPathEnv], DockerHost: envMap[constants.DockerHostEnv], DockerTLSVerify: envMap[constants.DockerTLSVerifyEnv], MinikubeDockerdProfile: envMap[constants.MinikubeActiveDockerdEnv], - UsageHint: generateUsageHint(viper.GetString(config.MachineProfile), userShell), + UsageHint: generateUsageHint(ec.profile, ec.shell), } - if noProxy { - host, err := api.Load(viper.GetString(config.MachineProfile)) - if err != nil { - return nil, errors.Wrap(err, "Error getting IP") - } - - ip, err := host.Driver.GetIP() - if err != nil { - return nil, errors.Wrap(err, "Error getting host IP") - } - + if ec.noProxy { noProxyVar, noProxyValue := defaultNoProxyGetter.GetNoProxyVar() // add the docker host to the no_proxy list idempotently switch { case noProxyValue == "": - noProxyValue = ip - case strings.Contains(noProxyValue, ip): + noProxyValue = ec.hostIP + case strings.Contains(noProxyValue, ec.hostIP): // ip already in no_proxy list, nothing to do default: - noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ip) + noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ec.hostIP) } - shellCfg.NoProxyVar = noProxyVar - shellCfg.NoProxyValue = noProxyValue + s.NoProxyVar = noProxyVar + s.NoProxyValue = noProxyValue } - switch userShell { + switch ec.shell { case "fish": - shellCfg.Prefix = fishSetPfx - shellCfg.Suffix = fishSetSfx - shellCfg.Delimiter = fishSetDelim + s.Prefix = fishSetPfx + s.Suffix = fishSetSfx + s.Delimiter = fishSetDelim case "powershell": - shellCfg.Prefix = psSetPfx - shellCfg.Suffix = psSetSfx - shellCfg.Delimiter = psSetDelim + s.Prefix = psSetPfx + s.Suffix = psSetSfx + s.Delimiter = psSetDelim case "cmd": - shellCfg.Prefix = cmdSetPfx - shellCfg.Suffix = cmdSetSfx - shellCfg.Delimiter = cmdSetDelim + s.Prefix = cmdSetPfx + s.Suffix = cmdSetSfx + s.Delimiter = cmdSetDelim case "emacs": - shellCfg.Prefix = emacsSetPfx - shellCfg.Suffix = emacsSetSfx - shellCfg.Delimiter = emacsSetDelim + s.Prefix = emacsSetPfx + s.Suffix = emacsSetSfx + s.Delimiter = emacsSetDelim case "none": - shellCfg.Prefix = nonePfx - shellCfg.Suffix = noneSfx - shellCfg.Delimiter = noneDelim - shellCfg.UsageHint = "" + s.Prefix = nonePfx + s.Suffix = noneSfx + s.Delimiter = noneDelim + s.UsageHint = "" default: - shellCfg.Prefix = bashSetPfx - shellCfg.Suffix = bashSetSfx - shellCfg.Delimiter = bashSetDelim + s.Prefix = bashSetPfx + s.Suffix = bashSetSfx + s.Delimiter = bashSetDelim } - - return shellCfg, nil + return s } -func shellCfgUnset() (*ShellConfig, error) { - - userShell, err := defaultShellDetector.GetShell(forceShell) - if err != nil { - return nil, err +// shellCfgUnset generates context variables for "docker-env -u" +func shellCfgUnset(ec EnvConfig) *ShellConfig { + s := &ShellConfig{ + UsageHint: generateUsageHint(ec.profile, ec.shell), } - shellCfg := &ShellConfig{ - UsageHint: generateUsageHint(viper.GetString(config.MachineProfile), userShell), + if ec.noProxy { + s.NoProxyVar, s.NoProxyValue = defaultNoProxyGetter.GetNoProxyVar() } - if noProxy { - shellCfg.NoProxyVar, shellCfg.NoProxyValue = defaultNoProxyGetter.GetNoProxyVar() - } - - switch userShell { + switch ec.shell { case "fish": - shellCfg.Prefix = fishUnsetPfx - shellCfg.Suffix = fishUnsetSfx - shellCfg.Delimiter = fishUnsetDelim + s.Prefix = fishUnsetPfx + s.Suffix = fishUnsetSfx + s.Delimiter = fishUnsetDelim case "powershell": - shellCfg.Prefix = psUnsetPfx - shellCfg.Suffix = psUnsetSfx - shellCfg.Delimiter = psUnsetDelim + s.Prefix = psUnsetPfx + s.Suffix = psUnsetSfx + s.Delimiter = psUnsetDelim case "cmd": - shellCfg.Prefix = cmdUnsetPfx - shellCfg.Suffix = cmdUnsetSfx - shellCfg.Delimiter = cmdUnsetDelim + s.Prefix = cmdUnsetPfx + s.Suffix = cmdUnsetSfx + s.Delimiter = cmdUnsetDelim case "emacs": - shellCfg.Prefix = emacsUnsetPfx - shellCfg.Suffix = emacsUnsetSfx - shellCfg.Delimiter = emacsUnsetDelim + s.Prefix = emacsUnsetPfx + s.Suffix = emacsUnsetSfx + s.Delimiter = emacsUnsetDelim case "none": - shellCfg.Prefix = nonePfx - shellCfg.Suffix = noneSfx - shellCfg.Delimiter = noneDelim - shellCfg.UsageHint = "" + s.Prefix = nonePfx + s.Suffix = noneSfx + s.Delimiter = noneDelim + s.UsageHint = "" default: - shellCfg.Prefix = bashUnsetPfx - shellCfg.Suffix = bashUnsetSfx - shellCfg.Delimiter = bashUnsetDelim + s.Prefix = bashUnsetPfx + s.Suffix = bashUnsetSfx + s.Delimiter = bashUnsetDelim } - - return shellCfg, nil -} - -func executeTemplateStdout(shellCfg *ShellConfig) error { - tmpl := template.Must(template.New("envConfig").Parse(envTmpl)) - return tmpl.Execute(os.Stdout, shellCfg) -} - -// GetShell detects the shell -func (LibmachineShellDetector) GetShell(userShell string) (string, error) { - if userShell != "" { - return userShell, nil - } - return shell.Detect() + return s } // GetNoProxyVar gets the no_proxy var @@ -312,30 +267,18 @@ func (EnvNoProxyGetter) GetNoProxyVar() (string, string) { return noProxyVar, noProxyValue } -// same as drivers.RunSSHCommandFromDriver, but allows errors -func runSSHCommandFromDriver(d drivers.Driver, command string) (string, error) { +// isDockerActive checks if Docker is active +func isDockerActive(d drivers.Driver) (bool, error) { client, err := drivers.GetSSHClientFromDriver(d) if err != nil { - return "", err + return false, err + } + output, err := client.Output("sudo systemctl is-active docker") + if err != nil { + return false, err } - - log.Debugf("About to run SSH command:\n%s", command) - output, err := client.Output(command) - log.Debugf("SSH cmd err, output: %v: %s", err, output) - return output, err -} - -// same as host.RunSSHCommand, but allows errors -func runSSHCommand(h *host.Host, command string) (string, error) { - return runSSHCommandFromDriver(h.Driver, command) -} - -// GetDockerActive checks if Docker is active -func GetDockerActive(host *host.Host) (bool, error) { - statusCmd := `sudo systemctl is-active docker` - status, err := runSSHCommand(host, statusCmd) // systemd returns error code on inactive - s := strings.TrimSpace(status) + s := strings.TrimSpace(output) return err == nil && s == "active", nil } @@ -350,7 +293,9 @@ var dockerEnvCmd = &cobra.Command{ exit.WithError("Error getting client", err) } defer api.Close() - cc, err := config.Load(viper.GetString(config.MachineProfile)) + + profile := viper.GetString(config.MachineProfile) + cc, err := config.Load(profile) if err != nil { exit.WithError("Error getting config", err) } @@ -361,43 +306,108 @@ var dockerEnvCmd = &cobra.Command{ if host.Driver.DriverName() == driver.None { exit.UsageT(`'none' driver does not support 'minikube docker-env' command`) } + hostSt, err := cluster.GetHostStatus(api, cc.Name) if err != nil { exit.WithError("Error getting host status", err) } if hostSt != state.Running.String() { - exit.WithCodeT(exit.Unavailable, `The docker host is currently not running`) + exit.WithCodeT(exit.Unavailable, `'{{.profile}}' is not running`, out.V{"profile": profile}) } - docker, err := GetDockerActive(host) + ok, err := isDockerActive(host.Driver) if err != nil { exit.WithError("Error getting service status", err) } - if !docker { - exit.WithCodeT(exit.Unavailable, `The docker service is currently not active`) + + if !ok { + exit.WithCodeT(exit.Unavailable, `The docker service within '{{.profile}}' is not active`, out.V{"profile": profile}) } - var shellCfg *ShellConfig + hostIP, err := host.Driver.GetIP() + if err != nil { + exit.WithError("Error getting host IP", err) + } + + ec := EnvConfig{ + profile: profile, + driver: host.DriverName, + shell: forceShell, + hostIP: hostIP, + certsDir: localpath.MakeMiniPath("certs"), + noProxy: noProxy, + } + + if ec.shell == "" { + ec.shell, err = shell.Detect() + if err != nil { + exit.WithError("Error detecting shell", err) + } + } if unset { - shellCfg, err = shellCfgUnset() - if err != nil { - exit.WithError("Error unsetting shell variables", err) - } - } else { - shellCfg, err = shellCfgSet(api) - if err != nil { - exit.WithError("Error setting shell variables", err) + if err := unsetScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating unset output", err) } + return } - if err := executeTemplateStdout(shellCfg); err != nil { - exit.WithError("Error executing template", err) + if err := setScript(ec, os.Stdout); err != nil { + exit.WithError("Error generating set output", err) } }, } +// EnvConfig encapsulates all external inputs into shell generation +type EnvConfig struct { + profile string + shell string + driver string + hostIP string + certsDir string + noProxy bool +} + +// setScript writes out a shell-compatible 'docker-env' script +func setScript(ec EnvConfig, w io.Writer) error { + tmpl := template.Must(template.New("envConfig").Parse(envTmpl)) + envVars, err := dockerEnvVars(ec) + if err != nil { + return err + } + return tmpl.Execute(w, shellCfgSet(ec, envVars)) +} + +// setScript writes out a shell-compatible 'docker-env unset' script +func unsetScript(ec EnvConfig, w io.Writer) error { + tmpl := template.Must(template.New("envConfig").Parse(envTmpl)) + return tmpl.Execute(w, shellCfgUnset(ec)) +} + +// dockerURL returns a the docker endpoint URL for an ip/port pair. +func dockerURL(ip string, port int) string { + return fmt.Sprintf("tcp://%s", net.JoinHostPort(ip, strconv.Itoa(port))) +} + +// dockerEnvVars gets the necessary docker env variables to allow the use of minikube's docker daemon +func dockerEnvVars(ec EnvConfig) (map[string]string, error) { + env := map[string]string{ + constants.DockerTLSVerifyEnv: "1", + constants.DockerHostEnv: dockerURL(ec.hostIP, constants.DockerDaemonPort), + constants.DockerCertPathEnv: ec.certsDir, + constants.MinikubeActiveDockerdEnv: ec.profile, + } + + if driver.IsKIC(ec.driver) { // for kic we need to find out what port docker allocated during creation + port, err := oci.HostPortBinding(ec.driver, ec.profile, constants.DockerDaemonPort) + if err != nil { + return nil, errors.Wrapf(err, "get hostbind port for %d", constants.DockerDaemonPort) + } + env[constants.DockerCertPathEnv] = dockerURL(kic.DefaultBindIPV4, port) + } + return env, nil +} + func init() { - defaultShellDetector = &LibmachineShellDetector{} defaultNoProxyGetter = &EnvNoProxyGetter{} dockerEnvCmd.Flags().BoolVar(&noProxy, "no-proxy", false, "Add machine IP to NO_PROXY environment variable") dockerEnvCmd.Flags().StringVar(&forceShell, "shell", "", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect") diff --git a/cmd/minikube/cmd/env_test.go b/cmd/minikube/cmd/env_test.go index f304471e6f..f287b4bdc0 100644 --- a/cmd/minikube/cmd/env_test.go +++ b/cmd/minikube/cmd/env_test.go @@ -1,5 +1,5 @@ /* -Copyright 2016 The Kubernetes Authors All rights reserved. +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. @@ -17,25 +17,12 @@ limitations under the License. package cmd import ( - "reflect" + "bytes" "testing" - "github.com/docker/machine/libmachine/host" - "github.com/spf13/viper" - "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/localpath" - "k8s.io/minikube/pkg/minikube/tests" + "github.com/google/go-cmp/cmp" ) -type FakeShellDetector struct { - Shell string -} - -func (f FakeShellDetector) GetShell(_ string) (string, error) { - return f.Shell, nil -} - type FakeNoProxyGetter struct { NoProxyVar string NoProxyValue string @@ -45,297 +32,250 @@ func (f FakeNoProxyGetter) GetNoProxyVar() (string, string) { return f.NoProxyVar, f.NoProxyValue } -var defaultAPI = &tests.MockAPI{ - FakeStore: tests.FakeStore{ - Hosts: map[string]*host.Host{ - constants.DefaultMachineName: { - Name: constants.DefaultMachineName, - Driver: &tests.MockDriver{}, - }, - }, - }, -} - -// Most of the shell cfg isn't configurable -func newShellCfg(shell, prefix, suffix, delim string) *ShellConfig { - return &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", shell), - Prefix: prefix, - Suffix: suffix, - Delimiter: delim, - MinikubeDockerdProfile: "minikube", - } -} - -func TestShellCfgSet(t *testing.T) { +func TestGenerateScripts(t *testing.T) { var tests = []struct { - description string - api *tests.MockAPI - shell string - noProxyVar string - noProxyValue string - expectedShellCfg *ShellConfig - shouldErr bool - noProxyFlag bool + config EnvConfig + noProxyGetter *FakeNoProxyGetter + wantSet string + wantUnset string }{ { - description: "no host specified", - api: &tests.MockAPI{ - FakeStore: tests.FakeStore{ - Hosts: make(map[string]*host.Host), - }, - }, - shell: "bash", - expectedShellCfg: nil, - shouldErr: true, + EnvConfig{profile: "bash", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"}, + nil, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://127.0.0.1:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="bash" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash docker-env) +`, + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash docker-env) +`, }, { - description: "default", - api: defaultAPI, - shell: "bash", - expectedShellCfg: newShellCfg("", bashSetPfx, bashSetSfx, bashSetDelim), - shouldErr: false, + EnvConfig{profile: "ipv6", shell: "bash", driver: "kvm2", hostIP: "fe80::215:5dff:fe00:a903", certsDir: "/certs"}, + nil, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://[fe80::215:5dff:fe00:a903]:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="ipv6" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p ipv6 docker-env) +`, + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p ipv6 docker-env) +`, }, { - description: "bash", - api: defaultAPI, - shell: "bash", - expectedShellCfg: newShellCfg("bash", bashSetPfx, bashSetSfx, bashSetDelim), - shouldErr: false, + EnvConfig{profile: "fish", shell: "fish", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs"}, + nil, + `set -gx DOCKER_TLS_VERIFY "1"; +set -gx DOCKER_HOST "tcp://127.0.0.1:2376"; +set -gx DOCKER_CERT_PATH "/certs"; +set -gx MINIKUBE_ACTIVE_DOCKERD "fish"; + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval (minikube -p fish docker-env) +`, + `set -e DOCKER_TLS_VERIFY; +set -e DOCKER_HOST; +set -e DOCKER_CERT_PATH; +set -e MINIKUBE_ACTIVE_DOCKERD; + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval (minikube -p fish docker-env) +`, }, { - description: "fish", - api: defaultAPI, - shell: "fish", - expectedShellCfg: newShellCfg("fish", fishSetPfx, fishSetSfx, fishSetDelim), - shouldErr: false, + EnvConfig{profile: "powershell", shell: "powershell", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"}, + nil, + `$Env:DOCKER_TLS_VERIFY = "1" +$Env:DOCKER_HOST = "tcp://192.168.0.1:2376" +$Env:DOCKER_CERT_PATH = "/certs" +$Env:MINIKUBE_ACTIVE_DOCKERD = "powershell" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# & minikube -p powershell docker-env | Invoke-Expression + `, + + `Remove-Item Env:\\DOCKER_TLS_VERIFY +Remove-Item Env:\\DOCKER_HOST +Remove-Item Env:\\DOCKER_CERT_PATH +Remove-Item Env:\\MINIKUBE_ACTIVE_DOCKERD + +# Please run command bellow to point your shell to minikube's docker-daemon : +# & minikube -p powershell docker-env | Invoke-Expression + `, }, { - description: "powershell", - api: defaultAPI, - shell: "powershell", - expectedShellCfg: newShellCfg("powershell", psSetPfx, psSetSfx, psSetDelim), - shouldErr: false, + EnvConfig{profile: "cmd", shell: "cmd", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"}, + nil, + `SET DOCKER_TLS_VERIFY=1 +SET DOCKER_HOST=tcp://192.168.0.1:2376 +SET DOCKER_CERT_PATH=/certs +SET MINIKUBE_ACTIVE_DOCKERD=cmd + +REM Please run command bellow to point your shell to minikube's docker-daemon : +REM @FOR /f "tokens=*" %i IN ('minikube -p cmd docker-env') DO @%i + `, + + `SET DOCKER_TLS_VERIFY= +SET DOCKER_HOST= +SET DOCKER_CERT_PATH= +SET MINIKUBE_ACTIVE_DOCKERD= + +REM Please run command bellow to point your shell to minikube's docker-daemon : +REM @FOR /f "tokens=*" %i IN ('minikube -p cmd docker-env') DO @%i + `, }, { - description: "cmd", - api: defaultAPI, - shell: "cmd", - expectedShellCfg: newShellCfg("cmd", cmdSetPfx, cmdSetSfx, cmdSetDelim), - shouldErr: false, + EnvConfig{profile: "emacs", shell: "emacs", driver: "hyperv", hostIP: "192.168.0.1", certsDir: "/certs"}, + nil, + `(setenv "DOCKER_TLS_VERIFY" "1") +(setenv "DOCKER_HOST" "tcp://192.168.0.1:2376") +(setenv "DOCKER_CERT_PATH" "/certs") +(setenv "MINIKUBE_ACTIVE_DOCKERD" "emacs") + +;; Please run command bellow to point your shell to minikube's docker-daemon : +;; (with-temp-buffer (shell-command "minikube -p emacs docker-env" (current-buffer)) (eval-buffer)) + `, + `(setenv "DOCKER_TLS_VERIFY" nil) +(setenv "DOCKER_HOST" nil) +(setenv "DOCKER_CERT_PATH" nil) +(setenv "MINIKUBE_ACTIVE_DOCKERD" nil) + +;; Please run command bellow to point your shell to minikube's docker-daemon : +;; (with-temp-buffer (shell-command "minikube -p emacs docker-env" (current-buffer)) (eval-buffer)) + `, }, { - description: "emacs", - api: defaultAPI, - shell: "emacs", - expectedShellCfg: newShellCfg("emacs", emacsSetPfx, emacsSetSfx, emacsSetDelim), - shouldErr: false, + EnvConfig{profile: "bash-no-proxy", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true}, + &FakeNoProxyGetter{"NO_PROXY", "127.0.0.1"}, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://127.0.0.1:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="bash-no-proxy" +export NO_PROXY="127.0.0.1" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy docker-env) +`, + + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD +unset NO_PROXY127.0.0.1 + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy docker-env) +`, }, { - description: "no proxy add uppercase", - api: defaultAPI, - shell: "bash", - noProxyVar: "NO_PROXY", - noProxyValue: "", - noProxyFlag: true, - expectedShellCfg: &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", "bash"), - Prefix: bashSetPfx, - Suffix: bashSetSfx, - Delimiter: bashSetDelim, - NoProxyVar: "NO_PROXY", - NoProxyValue: "127.0.0.1", - MinikubeDockerdProfile: "minikube", - }, + EnvConfig{profile: "bash-no-proxy-lower", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true}, + &FakeNoProxyGetter{"no_proxy", "127.0.0.1"}, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://127.0.0.1:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="bash-no-proxy-lower" +export no_proxy="127.0.0.1" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy-lower docker-env) +`, + + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD +unset no_proxy127.0.0.1 + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy-lower docker-env) +`, }, { - description: "no proxy add lowercase", - api: defaultAPI, - shell: "bash", - noProxyVar: "no_proxy", - noProxyValue: "", - noProxyFlag: true, - expectedShellCfg: &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", "bash"), - Prefix: bashSetPfx, - Suffix: bashSetSfx, - Delimiter: bashSetDelim, - NoProxyVar: "no_proxy", - NoProxyValue: "127.0.0.1", - MinikubeDockerdProfile: "minikube", - }, + EnvConfig{profile: "bash-no-proxy-idempotent", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true}, + &FakeNoProxyGetter{"no_proxy", "127.0.0.1"}, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://127.0.0.1:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="bash-no-proxy-idempotent" +export no_proxy="127.0.0.1" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy-idempotent docker-env) +`, + + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD +unset no_proxy127.0.0.1 + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p bash-no-proxy-idempotent docker-env) +`, }, { - description: "no proxy idempotent", - api: defaultAPI, - shell: "bash", - noProxyVar: "no_proxy", - noProxyValue: "127.0.0.1", - noProxyFlag: true, - expectedShellCfg: &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", "bash"), - Prefix: bashSetPfx, - Suffix: bashSetSfx, - Delimiter: bashSetDelim, - NoProxyVar: "no_proxy", - NoProxyValue: "127.0.0.1", - MinikubeDockerdProfile: "minikube", - }, - }, - { - description: "no proxy list add", - api: defaultAPI, - shell: "bash", - noProxyVar: "no_proxy", - noProxyValue: "0.0.0.0", - noProxyFlag: true, - expectedShellCfg: &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", "bash"), - Prefix: bashSetPfx, - Suffix: bashSetSfx, - Delimiter: bashSetDelim, - NoProxyVar: "no_proxy", - NoProxyValue: "0.0.0.0,127.0.0.1", - MinikubeDockerdProfile: "minikube", - }, - }, - { - description: "no proxy list already present", - api: defaultAPI, - shell: "bash", - noProxyVar: "no_proxy", - noProxyValue: "0.0.0.0,127.0.0.1", - noProxyFlag: true, - expectedShellCfg: &ShellConfig{ - DockerCertPath: localpath.MakeMiniPath("certs"), - DockerTLSVerify: "1", - DockerHost: "tcp://127.0.0.1:2376", - UsageHint: generateUsageHint("minikube", "bash"), - Prefix: bashSetPfx, - Suffix: bashSetSfx, - Delimiter: bashSetDelim, - NoProxyVar: "no_proxy", - NoProxyValue: "0.0.0.0,127.0.0.1", - MinikubeDockerdProfile: "minikube", - }, + EnvConfig{profile: "sh-no-proxy-add", shell: "bash", driver: "kvm2", hostIP: "127.0.0.1", certsDir: "/certs", noProxy: true}, + &FakeNoProxyGetter{"NO_PROXY", "192.168.0.1,10.0.0.4"}, + `export DOCKER_TLS_VERIFY="1" +export DOCKER_HOST="tcp://127.0.0.1:2376" +export DOCKER_CERT_PATH="/certs" +export MINIKUBE_ACTIVE_DOCKERD="sh-no-proxy-add" +export NO_PROXY="192.168.0.1,10.0.0.4,127.0.0.1" + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p sh-no-proxy-add docker-env) +`, + + `unset DOCKER_TLS_VERIFY +unset DOCKER_HOST +unset DOCKER_CERT_PATH +unset MINIKUBE_ACTIVE_DOCKERD +unset NO_PROXY192.168.0.1,10.0.0.4 + +# Please run command bellow to point your shell to minikube's docker-daemon : +# eval $(minikube -p sh-no-proxy-add docker-env) +`, }, } + for _, tc := range tests { + t.Run(tc.config.profile, func(t *testing.T) { + defaultNoProxyGetter = tc.noProxyGetter + var b []byte + buf := bytes.NewBuffer(b) + if err := setScript(tc.config, buf); err != nil { + t.Errorf("setScript(%+v) error: %v", tc.config, err) + } + got := buf.String() + if diff := cmp.Diff(tc.wantSet, got); diff != "" { + t.Errorf("setScript(%+v) mismatch (-want +got):\n%s\n\nraw output:\n%s\nquoted: %q", tc.config, diff, got, got) + } - for _, test := range tests { - test := test - t.Run(test.description, func(t *testing.T) { + buf = bytes.NewBuffer(b) + if err := unsetScript(tc.config, buf); err != nil { + t.Errorf("unsetScript(%+v) error: %v", tc.config, err) + } + got = buf.String() + if diff := cmp.Diff(tc.wantUnset, got); diff != "" { + t.Errorf("unsetScript(%+v) mismatch (-want +got):\n%s\n\nraw output:\n%s\nquoted: %q", tc.config, diff, got, got) + } - viper.Set(config.MachineProfile, constants.DefaultMachineName) - defaultShellDetector = &FakeShellDetector{test.shell} - defaultNoProxyGetter = &FakeNoProxyGetter{test.noProxyVar, test.noProxyValue} - noProxy = test.noProxyFlag - test.api.T = t - shellCfg, err := shellCfgSet(test.api) - if !reflect.DeepEqual(shellCfg, test.expectedShellCfg) { - t.Errorf("Shell cfgs differ: expected %+v, \n\n got %+v", test.expectedShellCfg, shellCfg) - } - if err != nil && !test.shouldErr { - t.Errorf("Unexpected error occurred: %s, error: %v", test.description, err) - } - if err == nil && test.shouldErr { - t.Errorf("Test didn't return error but should have: %s", test.description) - } - }) - } -} - -func TestShellCfgUnset(t *testing.T) { - - var tests = []struct { - description string - shell string - expectedShellCfg *ShellConfig - }{ - { - description: "unset default", - shell: "bash", - expectedShellCfg: &ShellConfig{ - Prefix: bashUnsetPfx, - Suffix: bashUnsetSfx, - Delimiter: bashUnsetDelim, - UsageHint: generateUsageHint("minikube", "bash"), - }, - }, - { - description: "unset bash", - shell: "bash", - expectedShellCfg: &ShellConfig{ - Prefix: bashUnsetPfx, - Suffix: bashUnsetSfx, - Delimiter: bashUnsetDelim, - UsageHint: generateUsageHint("minikube", "bash"), - }, - }, - { - description: "unset fish", - shell: "fish", - expectedShellCfg: &ShellConfig{ - Prefix: fishUnsetPfx, - Suffix: fishUnsetSfx, - Delimiter: fishUnsetDelim, - UsageHint: generateUsageHint("minikube", "fish"), - }, - }, - { - description: "unset powershell", - shell: "powershell", - expectedShellCfg: &ShellConfig{ - Prefix: psUnsetPfx, - Suffix: psUnsetSfx, - Delimiter: psUnsetDelim, - UsageHint: generateUsageHint("minikube", "powershell"), - }, - }, - { - description: "unset cmd", - shell: "cmd", - expectedShellCfg: &ShellConfig{ - Prefix: cmdUnsetPfx, - Suffix: cmdUnsetSfx, - Delimiter: cmdUnsetDelim, - UsageHint: generateUsageHint("minikube", "cmd"), - }, - }, - { - description: "unset emacs", - shell: "emacs", - expectedShellCfg: &ShellConfig{ - Prefix: emacsUnsetPfx, - Suffix: emacsUnsetSfx, - Delimiter: emacsUnsetDelim, - UsageHint: generateUsageHint("minikube", "emacs"), - }, - }, - } - - for _, test := range tests { - t.Run(test.description, func(t *testing.T) { - defaultShellDetector = &FakeShellDetector{test.shell} - defaultNoProxyGetter = &FakeNoProxyGetter{} - actual, _ := shellCfgUnset() - if !reflect.DeepEqual(actual, test.expectedShellCfg) { - t.Errorf("Actual shell config did not match expected: \n\n actual: \n%+v \n\n expected: \n%+v \n\n", actual, test.expectedShellCfg) - } }) } } diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index 4c9490ecb8..14c809360c 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -18,7 +18,6 @@ package cluster import ( "fmt" - "os" "testing" "time" @@ -338,73 +337,6 @@ func TestGetHostStatus(t *testing.T) { checkState(state.Stopped.String()) } -func TestGetNodeDockerEnv(t *testing.T) { - RegisterMockDriver(t) - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - - api := tests.NewMockAPI(t) - h, err := createHost(api, defaultMachineConfig) - if err != nil { - t.Fatalf("Error creating host: %v", err) - } - d := &tests.MockDriver{ - BaseDriver: drivers.BaseDriver{ - IPAddress: "127.0.0.1", - }, - T: t, - } - h.Driver = d - - envMap, err := GetNodeDockerEnv(api) - if err != nil { - t.Fatalf("Unexpected error getting env: %v", err) - } - - dockerEnvKeys := [...]string{ - constants.DockerTLSVerifyEnv, - constants.DockerHostEnv, - constants.DockerCertPathEnv, - constants.MinikubeActiveDockerdEnv, - } - for _, dockerEnvKey := range dockerEnvKeys { - if _, hasKey := envMap[dockerEnvKey]; !hasKey { - t.Fatalf("Expected envMap[\"%s\"] key to be defined", dockerEnvKey) - } - } -} - -func TestGetNodeDockerEnvIPv6(t *testing.T) { - RegisterMockDriver(t) - - tempDir := tests.MakeTempDir() - defer os.RemoveAll(tempDir) - - api := tests.NewMockAPI(t) - h, err := createHost(api, defaultMachineConfig) - if err != nil { - t.Fatalf("Error creating host: %v", err) - } - d := &tests.MockDriver{ - BaseDriver: drivers.BaseDriver{ - IPAddress: "fe80::215:5dff:fe00:a903", - }, - T: t, - } - h.Driver = d - - envMap, err := GetNodeDockerEnv(api) - if err != nil { - t.Fatalf("Unexpected error getting env: %v", err) - } - - expected := "tcp://[fe80::215:5dff:fe00:a903]:2376" - v := envMap["DOCKER_HOST"] - if v != expected { - t.Fatalf("Expected DOCKER_HOST to be defined as %s but was %s", expected, v) - } -} - func TestCreateSSHShell(t *testing.T) { api := tests.NewMockAPI(t) diff --git a/pkg/minikube/cluster/docker_env.go b/pkg/minikube/cluster/docker_env.go deleted file mode 100644 index d3feac7fca..0000000000 --- a/pkg/minikube/cluster/docker_env.go +++ /dev/null @@ -1,67 +0,0 @@ -/* -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 cluster - -import ( - "fmt" - "net" - - "github.com/docker/machine/libmachine" - "github.com/pkg/errors" - "github.com/spf13/viper" - "k8s.io/minikube/pkg/drivers/kic" - "k8s.io/minikube/pkg/drivers/kic/oci" - "k8s.io/minikube/pkg/minikube/config" - "k8s.io/minikube/pkg/minikube/constants" - "k8s.io/minikube/pkg/minikube/driver" - "k8s.io/minikube/pkg/minikube/localpath" -) - -// GetNodeDockerEnv gets the necessary docker env variables to allow the use of docker through minikube's vm -func GetNodeDockerEnv(api libmachine.API) (map[string]string, error) { - pName := viper.GetString(config.MachineProfile) - host, err := CheckIfHostExistsAndLoad(api, pName) - if err != nil { - return nil, errors.Wrap(err, "Error checking that api exists and loading it") - } - - ip := kic.DefaultBindIPV4 - if !driver.IsKIC(host.Driver.DriverName()) { // kic externally accessible ip is different that node ip - ip, err = host.Driver.GetIP() - if err != nil { - return nil, errors.Wrap(err, "Error getting ip from host") - } - - } - - tcpPrefix := "tcp://" - port := constants.DockerDaemonPort - if driver.IsKIC(host.Driver.DriverName()) { // for kic we need to find out what port docker allocated during creation - port, err = oci.HostPortBinding(host.Driver.DriverName(), pName, constants.DockerDaemonPort) - if err != nil { - return nil, errors.Wrapf(err, "get hostbind port for %d", constants.DockerDaemonPort) - } - } - - envMap := map[string]string{ - constants.DockerTLSVerifyEnv: "1", - constants.DockerHostEnv: tcpPrefix + net.JoinHostPort(ip, fmt.Sprint(port)), - constants.DockerCertPathEnv: localpath.MakeMiniPath("certs"), - constants.MinikubeActiveDockerdEnv: pName, - } - return envMap, nil -}