docker-env command: Added support for multiple shells with no-proxy and unset flags
parent
e88306d1ed
commit
c847979cab
|
@ -815,6 +815,11 @@
|
|||
"Comment": "v0.7.0-62-g6002b41",
|
||||
"Rev": "6002b411ce820eaf03ac972a7fb354bb56f7aa95"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/machine/libmachine/shell",
|
||||
"Comment": "v0.7.0-62-g6002b41",
|
||||
"Rev": "6002b411ce820eaf03ac972a7fb354bb56f7aa95"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/machine/libmachine/ssh",
|
||||
"Comment": "v0.7.0-62-g6002b41",
|
||||
|
|
|
@ -14,47 +14,251 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Part of this code is heavily inspired/copied by the following file:
|
||||
// github.com/docker/machine/commands/env.go
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/docker/machine/libmachine"
|
||||
"github.com/docker/machine/libmachine/shell"
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
"k8s.io/minikube/pkg/minikube/cluster"
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
)
|
||||
|
||||
const (
|
||||
envTmpl = `{{ .Prefix }}DOCKER_TLS_VERIFY{{ .Delimiter }}{{ .DockerTLSVerify }}{{ .Suffix }}{{ .Prefix }}DOCKER_HOST{{ .Delimiter }}{{ .DockerHost }}{{ .Suffix }}{{ .Prefix }}DOCKER_CERT_PATH{{ .Delimiter }}{{ .DockerCertPath }}{{ .Suffix }}{{ if .NoProxyVar }}{{ .Prefix }}{{ .NoProxyVar }}{{ .Delimiter }}{{ .NoProxyValue }}{{ .Suffix }}{{end}}{{ .UsageHint }}`
|
||||
)
|
||||
|
||||
type ShellConfig struct {
|
||||
Prefix string
|
||||
Delimiter string
|
||||
Suffix string
|
||||
DockerCertPath string
|
||||
DockerHost string
|
||||
DockerTLSVerify string
|
||||
UsageHint string
|
||||
NoProxyVar string
|
||||
NoProxyValue string
|
||||
}
|
||||
|
||||
var (
|
||||
noProxy bool
|
||||
forceShell string
|
||||
unset bool
|
||||
)
|
||||
|
||||
func generateUsageHint(userShell string) string {
|
||||
|
||||
cmd := ""
|
||||
comment := "#"
|
||||
commandLine := "minikube docker-env"
|
||||
|
||||
switch userShell {
|
||||
case "fish":
|
||||
cmd = fmt.Sprintf("eval (%s)", commandLine)
|
||||
case "powershell":
|
||||
cmd = fmt.Sprintf("& %s | Invoke-Expression", commandLine)
|
||||
case "cmd":
|
||||
cmd = fmt.Sprintf("\t@FOR /f \"tokens=*\" %%i IN ('%s') DO @%%i", commandLine)
|
||||
comment = "REM"
|
||||
case "emacs":
|
||||
cmd = fmt.Sprintf("(with-temp-buffer (shell-command \"%s\" (current-buffer)) (eval-buffer))", commandLine)
|
||||
comment = ";;"
|
||||
default:
|
||||
cmd = fmt.Sprintf("eval $(%s)", commandLine)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s Run this command to configure your shell: \n%s %s\n", comment, comment, cmd)
|
||||
}
|
||||
|
||||
func shellCfgSet(api libmachine.API) (*ShellConfig, error) {
|
||||
|
||||
envMap, err := cluster.GetHostDockerEnv(api)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
userShell, err := getShell(forceShell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shellCfg := &ShellConfig{
|
||||
DockerCertPath: envMap["DOCKER_CERT_PATH"],
|
||||
DockerHost: envMap["DOCKER_HOST"],
|
||||
DockerTLSVerify: envMap["DOCKER_TLS_VERIFY"],
|
||||
UsageHint: generateUsageHint(userShell),
|
||||
}
|
||||
|
||||
if noProxy {
|
||||
|
||||
host, err := api.Load(constants.MachineName)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error getting IP: ", err)
|
||||
}
|
||||
|
||||
ip, err := host.Driver.GetIP()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Error getting host IP: %s", err)
|
||||
}
|
||||
|
||||
noProxyVar, noProxyValue := findNoProxyFromEnv()
|
||||
|
||||
// add the docker host to the no_proxy list idempotently
|
||||
switch {
|
||||
case noProxyValue == "":
|
||||
noProxyValue = ip
|
||||
case strings.Contains(noProxyValue, ip):
|
||||
//ip already in no_proxy list, nothing to do
|
||||
default:
|
||||
noProxyValue = fmt.Sprintf("%s,%s", noProxyValue, ip)
|
||||
}
|
||||
|
||||
shellCfg.NoProxyVar = noProxyVar
|
||||
shellCfg.NoProxyValue = noProxyValue
|
||||
}
|
||||
|
||||
switch userShell {
|
||||
case "fish":
|
||||
shellCfg.Prefix = "set -gx "
|
||||
shellCfg.Suffix = "\";\n"
|
||||
shellCfg.Delimiter = " \""
|
||||
case "powershell":
|
||||
shellCfg.Prefix = "$Env:"
|
||||
shellCfg.Suffix = "\"\n"
|
||||
shellCfg.Delimiter = " = \""
|
||||
case "cmd":
|
||||
shellCfg.Prefix = "SET "
|
||||
shellCfg.Suffix = "\n"
|
||||
shellCfg.Delimiter = "="
|
||||
case "emacs":
|
||||
shellCfg.Prefix = "(setenv \""
|
||||
shellCfg.Suffix = "\")\n"
|
||||
shellCfg.Delimiter = "\" \""
|
||||
default:
|
||||
shellCfg.Prefix = "export "
|
||||
shellCfg.Suffix = "\"\n"
|
||||
shellCfg.Delimiter = "=\""
|
||||
}
|
||||
|
||||
return shellCfg, nil
|
||||
}
|
||||
|
||||
func shellCfgUnset(api libmachine.API) (*ShellConfig, error) {
|
||||
|
||||
userShell, err := getShell(forceShell)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shellCfg := &ShellConfig{
|
||||
UsageHint: generateUsageHint(userShell),
|
||||
}
|
||||
|
||||
if noProxy {
|
||||
shellCfg.NoProxyVar, shellCfg.NoProxyValue = findNoProxyFromEnv()
|
||||
}
|
||||
|
||||
switch userShell {
|
||||
case "fish":
|
||||
shellCfg.Prefix = "set -e "
|
||||
shellCfg.Suffix = ";\n"
|
||||
shellCfg.Delimiter = ""
|
||||
case "powershell":
|
||||
shellCfg.Prefix = `Remove-Item Env:\\`
|
||||
shellCfg.Suffix = "\n"
|
||||
shellCfg.Delimiter = ""
|
||||
case "cmd":
|
||||
shellCfg.Prefix = "SET "
|
||||
shellCfg.Suffix = "\n"
|
||||
shellCfg.Delimiter = "="
|
||||
case "emacs":
|
||||
shellCfg.Prefix = "(setenv \""
|
||||
shellCfg.Suffix = ")\n"
|
||||
shellCfg.Delimiter = "\" nil"
|
||||
default:
|
||||
shellCfg.Prefix = "unset "
|
||||
shellCfg.Suffix = "\n"
|
||||
shellCfg.Delimiter = ""
|
||||
}
|
||||
|
||||
return shellCfg, nil
|
||||
}
|
||||
|
||||
func executeTemplateStdout(shellCfg *ShellConfig) error {
|
||||
t := template.New("envConfig")
|
||||
tmpl, err := t.Parse(envTmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tmpl.Execute(os.Stdout, shellCfg)
|
||||
}
|
||||
|
||||
func getShell(userShell string) (string, error) {
|
||||
if userShell != "" {
|
||||
return userShell, nil
|
||||
}
|
||||
return shell.Detect()
|
||||
}
|
||||
|
||||
func findNoProxyFromEnv() (string, string) {
|
||||
// first check for an existing lower case no_proxy var
|
||||
noProxyVar := "no_proxy"
|
||||
noProxyValue := os.Getenv("no_proxy")
|
||||
|
||||
// otherwise default to allcaps HTTP_PROXY
|
||||
if noProxyValue == "" {
|
||||
noProxyVar = "NO_PROXY"
|
||||
noProxyValue = os.Getenv("NO_PROXY")
|
||||
}
|
||||
return noProxyVar, noProxyValue
|
||||
}
|
||||
|
||||
// envCmd represents the docker-env command
|
||||
var dockerEnvCmd = &cobra.Command{
|
||||
Use: "docker-env",
|
||||
Short: "sets up docker env variables; similar to '$(docker-machine env)'",
|
||||
Long: `sets up docker env variables; similar to '$(docker-machine env)'`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
|
||||
api := libmachine.NewClient(constants.Minipath, constants.MakeMiniPath("certs"))
|
||||
defer api.Close()
|
||||
|
||||
envMap, err := cluster.GetHostDockerEnv(api)
|
||||
if err != nil {
|
||||
glog.Errorln("Error setting machine env variable(s):", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Fprintln(os.Stdout, buildDockerEnvShellOutput(envMap))
|
||||
},
|
||||
}
|
||||
var (
|
||||
err error
|
||||
shellCfg *ShellConfig
|
||||
)
|
||||
|
||||
func buildDockerEnvShellOutput(envMap map[string]string) string {
|
||||
output := ""
|
||||
for env_name, env_val := range envMap {
|
||||
output += fmt.Sprintf("export %s=%s\n", env_name, env_val)
|
||||
}
|
||||
howToRun := "# Run this command to configure your shell: \n# eval $(minikube docker-env)"
|
||||
output += howToRun
|
||||
return output
|
||||
if unset {
|
||||
shellCfg, err = shellCfgUnset(api)
|
||||
if err != nil {
|
||||
glog.Errorln("Error setting machine env variable(s):", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
shellCfg, err = shellCfgSet(api)
|
||||
if err != nil {
|
||||
glog.Errorln("Error setting machine env variable(s):", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
executeTemplateStdout(shellCfg)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
RootCmd.AddCommand(dockerEnvCmd)
|
||||
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")
|
||||
}
|
||||
|
|
|
@ -11,6 +11,14 @@ sets up docker env variables; similar to '$(docker-machine env)'
|
|||
minikube docker-env
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
--no-proxy[=false]: Add machine IP to NO_PROXY environment variable
|
||||
--shell="": Force environment to be configured for a specified shell: [fish, cmd, powershell, tcsh, bash, zsh], default is auto-detect
|
||||
-u, --unset[=false]: Unset variables instead of setting them
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
||||
```
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
// +build !windows
|
||||
|
||||
package shell
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnknownShell = errors.New("Error: Unknown shell")
|
||||
)
|
||||
|
||||
// Detect detects user's current shell.
|
||||
func Detect() (string, error) {
|
||||
shell := os.Getenv("SHELL")
|
||||
|
||||
if shell == "" {
|
||||
fmt.Printf("The default lines below are for a sh/bash shell, you can specify the shell you're using, with the --shell flag.\n\n")
|
||||
return "", ErrUnknownShell
|
||||
}
|
||||
|
||||
if os.Getenv("__fish_bin_dir") != "" {
|
||||
return "fish", nil
|
||||
}
|
||||
|
||||
return filepath.Base(shell), nil
|
||||
}
|
84
vendor/github.com/docker/machine/libmachine/shell/shell_windows.go
generated
vendored
Normal file
84
vendor/github.com/docker/machine/libmachine/shell/shell_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
package shell
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// re-implementation of private function in https://github.com/golang/go/blob/master/src/syscall/syscall_windows.go#L945
|
||||
func getProcessEntry(pid int) (pe *syscall.ProcessEntry32, err error) {
|
||||
snapshot, err := syscall.CreateToolhelp32Snapshot(syscall.TH32CS_SNAPPROCESS, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer syscall.CloseHandle(syscall.Handle(snapshot))
|
||||
|
||||
var processEntry syscall.ProcessEntry32
|
||||
processEntry.Size = uint32(unsafe.Sizeof(processEntry))
|
||||
err = syscall.Process32First(snapshot, &processEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
if processEntry.ProcessID == uint32(pid) {
|
||||
pe = &processEntry
|
||||
return
|
||||
}
|
||||
|
||||
err = syscall.Process32Next(snapshot, &processEntry)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getNameAndItsPpid returns the exe file name its parent process id.
|
||||
func getNameAndItsPpid(pid int) (exefile string, parentid int, err error) {
|
||||
pe, err := getProcessEntry(pid)
|
||||
if err != nil {
|
||||
return "", 0, err
|
||||
}
|
||||
|
||||
name := syscall.UTF16ToString(pe.ExeFile[:])
|
||||
return name, int(pe.ParentProcessID), nil
|
||||
}
|
||||
|
||||
func Detect() (string, error) {
|
||||
shell := os.Getenv("SHELL")
|
||||
|
||||
if shell == "" {
|
||||
shell, shellppid, err := getNameAndItsPpid(os.Getppid())
|
||||
if err != nil {
|
||||
return "cmd", err // defaulting to cmd
|
||||
}
|
||||
if strings.Contains(strings.ToLower(shell), "powershell") {
|
||||
return "powershell", nil
|
||||
} else if strings.Contains(strings.ToLower(shell), "cmd") {
|
||||
return "cmd", nil
|
||||
} else {
|
||||
shell, _, err := getNameAndItsPpid(shellppid)
|
||||
if err != nil {
|
||||
return "cmd", err // defaulting to cmd
|
||||
}
|
||||
if strings.Contains(strings.ToLower(shell), "powershell") {
|
||||
return "powershell", nil
|
||||
} else if strings.Contains(strings.ToLower(shell), "cmd") {
|
||||
return "cmd", nil
|
||||
} else {
|
||||
fmt.Printf("You can further specify your shell with either 'cmd' or 'powershell' with the --shell flag.\n\n")
|
||||
return "cmd", nil // this could be either powershell or cmd, defaulting to cmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if os.Getenv("__fish_bin_dir") != "" {
|
||||
return "fish", nil
|
||||
}
|
||||
|
||||
return filepath.Base(shell), nil
|
||||
}
|
Loading…
Reference in New Issue