提交 32bc0ff7 编写于 作者: T Thomas Stromberg

Refactor docker-env for testability

上级 9c70693e
/*
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,28 +21,35 @@ 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)
var (
forceShell string
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)
)
const (
fishSetPfx = "set -gx "
......@@ -105,21 +112,9 @@ type ShellConfig struct {
}
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,169 +123,134 @@ type NoProxyGetter interface {
// EnvNoProxyGetter gets the no_proxy variable, using environment
type EnvNoProxyGetter struct{}
func generateUsageHint(profile string, userShell string) string {
const usgPlz = "To point your shell to minikube's docker-daemon:"
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{
"bash": fmt.Sprintf(`# %s
"bash": fmt.Sprintf(`
# %s
# eval $(%s)
`, usgPlz, usgCmd),
"fish": fmt.Sprintf(`# %s
"fish": fmt.Sprintf(`
# %s
# eval (%s)
`, usgPlz, usgCmd),
"powershell": fmt.Sprintf(`# %s
"powershell": fmt.Sprintf(`
# %s
# & %s | Invoke-Expression
`, usgPlz, usgCmd),
"cmd": fmt.Sprintf(`REM %s
"cmd": fmt.Sprintf(`
REM %s
REM @FOR /f "tokens=*" %%i IN ('%s') DO @%%i
`, usgPlz, usgCmd),
"emacs": fmt.Sprintf(`;; %s
"emacs": fmt.Sprintf(`
;; %s
;; (with-temp-buffer (shell-command "%s" (current-buffer)) (eval-buffer))
`, 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
}
shellCfg := &ShellConfig{
UsageHint: generateUsageHint(viper.GetString(config.MachineProfile), userShell),
// shellCfgUnset generates context variables for "docker-env -u"
func shellCfgUnset(ec EnvConfig) *ShellConfig {
s := &ShellConfig{
UsageHint: generateUsageHint(ec.profile, ec.shell),
}
if noProxy {
shellCfg.NoProxyVar, shellCfg.NoProxyValue = defaultNoProxyGetter.GetNoProxyVar()
if ec.noProxy {
s.NoProxyVar, s.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
}
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
s.Prefix = bashUnsetPfx
s.Suffix = bashUnsetSfx
s.Delimiter = bashUnsetDelim
}
return shell.Detect()
return s
}
// GetNoProxyVar gets the no_proxy var
......@@ -307,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
}
......@@ -345,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)
}
......@@ -356,45 +306,113 @@ 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)
}
if unset {
shellCfg, err = shellCfgUnset()
ec := EnvConfig{
profile: profile,
driver: host.DriverName,
hostIP: hostIP,
certsDir: localpath.MakeMiniPath("certs"),
noProxy: viper.GetBool("no-proxy"),
}
sh := viper.GetString("shell")
fmt.Printf("user shell=%s\n", sh)
if sh == "" {
sh, err = shell.Detect()
if err != nil {
exit.WithError("Error unsetting shell variables", err)
exit.WithError("Error detecting shell", err)
}
} else {
shellCfg, err = shellCfgSet(api)
if err != nil {
exit.WithError("Error setting shell variables", err)
}
ec.shell = sh
fmt.Printf("shell=%s, ec: %+v\n", viper.GetString("shell"), ec)
if viper.GetBool("unset") {
if err := generateUnsetScript(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 := generateSetScript(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
}
// generateSetScript writes out a shell-compatible 'docker-env' script
func generateSetScript(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))
}
// generateSetScript writes out a shell-compatible 'docker-env unset' script
func generateUnsetScript(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 docker through minikube's vm
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")
dockerEnvCmd.Flags().BoolVarP(&unset, "unset", "u", false, "Unset variables instead of setting them")
dockerEnvCmd.Flags().Bool("no-proxy", false, "Add machine IP to NO_PROXY environment variable")
dockerEnvCmd.Flags().StringVar(&forceShell, "shell", "auto", "Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect")
dockerEnvCmd.Flags().BoolP("unset", "u", false, "Unset variables instead of setting them")
}
/*
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,212 @@ 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,
},
{
description: "default",
api: defaultAPI,
shell: "bash",
expectedShellCfg: newShellCfg("", bashSetPfx, bashSetSfx, bashSetDelim),
shouldErr: false,
},
{
description: "bash",
api: defaultAPI,
shell: "bash",
expectedShellCfg: newShellCfg("bash", bashSetPfx, bashSetSfx, bashSetDelim),
shouldErr: false,
},
{
description: "fish",
api: defaultAPI,
shell: "fish",
expectedShellCfg: newShellCfg("fish", fishSetPfx, fishSetSfx, fishSetDelim),
shouldErr: false,
},
{
description: "powershell",
api: defaultAPI,
shell: "powershell",
expectedShellCfg: newShellCfg("powershell", psSetPfx, psSetSfx, psSetDelim),
shouldErr: false,
},
{
description: "cmd",
api: defaultAPI,
shell: "cmd",
expectedShellCfg: newShellCfg("cmd", cmdSetPfx, cmdSetSfx, cmdSetDelim),
shouldErr: false,
},
{
description: "emacs",
api: defaultAPI,
shell: "emacs",
expectedShellCfg: newShellCfg("emacs", emacsSetPfx, emacsSetSfx, emacsSetDelim),
shouldErr: false,
},
{
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",
},
},
{
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",
},
},
{
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: "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"
# 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
# To point your shell to minikube's docker-daemon,
# eval $(minikube -p bash docker-env)`,
},
{
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";
# 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;
# To point your shell to minikube's docker-daemon,
# eval (minikube -p fish docker-env)`,
},
{
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"
# 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
# To point your shell to minikube's docker-daemon,
# & minikube -p powershell docker-env | Invoke-Expression`,
},
{
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 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 To point your shell to minikube's docker-daemon,
REM @FOR /f "tokens=*" %i IN ('minikube -p cmd docker-env') DO @%i`,
},
{
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")
;; 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)
;; To point your shell to minikube's docker-daemon,
;; (with-temp-buffer (shell-command "minikube -p emacs docker-env" (current-buffer)) (eval-buffer))`,
},
{
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"
# 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`,
},
{
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"
# 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`,
},
{
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"
# 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
# To point your shell to minikube's docker-daemon,
# eval $(minikube -p bash-no-proxy-idempotent docker-env)`,
},
{
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"
# 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
# To point your shell to minikube's docker-daemon,
# eval $(minikube -p sh-no-proxy-add docker-env)`,
},
}
for _, test := range tests {
test := test
t.Run(test.description, func(t *testing.T) {
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)
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 := generateSetScript(tc.config, buf); err != nil {
t.Errorf("generateSetScript(%+v) error: %v", tc.config, err)
}
if err == nil && test.shouldErr {
t.Errorf("Test didn't return error but should have: %s", test.description)
got := buf.String()
if diff := cmp.Diff(tc.wantSet, got); diff != "" {
t.Errorf("generateSetScript(%+v) content mismatch (-want +got):\n%s\n\nraw output:\n%s", tc.config, diff, got)
}
})
}
}
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)
buf = bytes.NewBuffer(b)
if err := generateUnsetScript(tc.config, buf); err != nil {
t.Errorf("generateUnsetScript(%+v) error: %v", tc.config, err)
}
got = buf.String()
if diff := cmp.Diff(tc.wantUnset, got); diff != "" {
t.Errorf("generateUnsetScript(%+v) content mismatch (-want +got):\n%s\n\nraw output:\n%s", tc.config, diff, got)
}
})
}
}
......@@ -45,6 +45,7 @@ require (
github.com/juju/version v0.0.0-20180108022336-b64dbd566305 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/libvirt/libvirt-go v3.4.0+incompatible
github.com/lithammer/dedent v1.1.0
github.com/machine-drivers/docker-machine-driver-vmware v0.1.1
github.com/mattn/go-isatty v0.0.9
github.com/mitchellh/go-ps v0.0.0-20170309133038-4fdf99ab2936
......
......@@ -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)
......
/*
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
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册