diff --git a/cmd/attachNode.go b/cmd/attachNode.go index c556a7ba..c8a5eafb 100644 --- a/cmd/attachNode.go +++ b/cmd/attachNode.go @@ -74,7 +74,7 @@ func attachNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/authoriseNode.go b/cmd/authoriseNode.go index 4742c5e3..36a37dd2 100644 --- a/cmd/authoriseNode.go +++ b/cmd/authoriseNode.go @@ -56,7 +56,7 @@ func authNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index 185c1adb..7e6e45b6 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -99,7 +99,7 @@ func bootstrapCmdRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, bootConfig); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, bootConfig); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/checkNode.go b/cmd/checkNode.go index c85e30ce..8b678b56 100644 --- a/cmd/checkNode.go +++ b/cmd/checkNode.go @@ -72,7 +72,7 @@ func checkNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/config.go b/cmd/config.go index 6f78012c..28319899 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -76,6 +76,7 @@ func init() { configCmdSet.Flags().StringVarP(&cfg.Region, "region", "r", "", "sets region") configCmdSet.Flags().StringVarP(&cfg.Tenant, "tenant", "t", "", "sets tenant") configCmdSet.Flags().StringVar(&cfg.MfaToken, "mfa", "", "set MFA token") + configCmdSet.Flags().StringVarP(&cfg.NoProxy, "noproxy", "", "", "exclude proxy for specified urls. this should be comma-separated list of hostnames or domain names") } func configCmdCreateRun(cmd *cobra.Command, args []string) { @@ -86,6 +87,10 @@ func configCmdCreateRun(cmd *cobra.Command, args []string) { zap.S().Fatal(color.Red("x "), err) } + if err = config.SetNoProxy(cfg.NoProxy); err != nil { + zap.S().Fatal(color.Red("x "), err) + } + if cmd.Flags().Changed("no-prompt") { if err = config.ValidateUserCredentials(&cfg, objects.NodeConfig{}); err != nil { zap.S().Fatal(color.Red("x "), err) diff --git a/cmd/deauthoriseNode.go b/cmd/deauthoriseNode.go index 7055c7bd..4cd90222 100644 --- a/cmd/deauthoriseNode.go +++ b/cmd/deauthoriseNode.go @@ -57,7 +57,7 @@ func deauthNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/decomissionNode.go b/cmd/decomissionNode.go index 073c6ba1..c7b439bc 100644 --- a/cmd/decomissionNode.go +++ b/cmd/decomissionNode.go @@ -71,7 +71,7 @@ func decommissionNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/deleteCluster.go b/cmd/deleteCluster.go index 1ffefeac..a6aff2e6 100644 --- a/cmd/deleteCluster.go +++ b/cmd/deleteCluster.go @@ -66,7 +66,7 @@ func deleteClusterRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/detachNode.go b/cmd/detachNode.go index 86627ae5..4a44cd46 100644 --- a/cmd/detachNode.go +++ b/cmd/detachNode.go @@ -82,7 +82,7 @@ func detachNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nc); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/prepNode.go b/cmd/prepNode.go index 69d984e7..af487303 100644 --- a/cmd/prepNode.go +++ b/cmd/prepNode.go @@ -96,7 +96,7 @@ func prepNodeRun(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, nodeConfig); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nodeConfig); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/cmd/supportBundle.go b/cmd/supportBundle.go index 918097c8..13823acc 100644 --- a/cmd/supportBundle.go +++ b/cmd/supportBundle.go @@ -66,7 +66,7 @@ func supportBundleUpload(cmd *cobra.Command, args []string) { fmt.Println(color.Green("✓ ") + "Loaded Config Successfully") var executor cmdexec.Executor - if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, bundleConfig); err != nil { + if executor, err = cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, bundleConfig); err != nil { zap.S().Fatalf("Unable to create executor: %s\n", err.Error()) } diff --git a/pkg/cmdexec/executor.go b/pkg/cmdexec/executor.go index a80bd14d..f465eb76 100644 --- a/pkg/cmdexec/executor.go +++ b/pkg/cmdexec/executor.go @@ -19,6 +19,7 @@ var StdErrSudoPassword string const ( httpsProxy = "https_proxy" + noProxy = "no_proxy" env_path = "PATH" ) @@ -31,17 +32,22 @@ type Executor interface { // LocalExecutor as the name implies executes commands locally type LocalExecutor struct { ProxyUrl string + NoProxy string } // Run runs a command locally returning just success or failure func (c LocalExecutor) Run(name string, args ...string) error { if c.ProxyUrl != "" { - args = append([]string{httpsProxy + "=" + c.ProxyUrl, name}, args...) + if c.NoProxy != "" { + args = append([]string{httpsProxy + "=" + c.ProxyUrl, noProxy + "=" + c.NoProxy, name}, args...) + } else { + args = append([]string{httpsProxy + "=" + c.ProxyUrl, name}, args...) + } } else { args = append([]string{name}, args...) } cmd := exec.Command("sudo", args...) - cmd.Env = append(cmd.Env, httpsProxy+"="+c.ProxyUrl) + cmd.Env = append(cmd.Env, httpsProxy+"="+c.ProxyUrl, noProxy+"="+c.NoProxy) cmd.Env = append(cmd.Env, env_path+"="+os.Getenv("PATH")) return cmd.Run() } @@ -49,13 +55,19 @@ func (c LocalExecutor) Run(name string, args ...string) error { // RunWithStdout runs a command locally returning stdout and err func (c LocalExecutor) RunWithStdout(name string, args ...string) (string, error) { if c.ProxyUrl != "" { - args = append([]string{httpsProxy + "=" + c.ProxyUrl, name}, args...) + if c.NoProxy != "" { + args = append([]string{httpsProxy + "=" + c.ProxyUrl, noProxy + "=" + c.NoProxy, name}, args...) + } else { + args = append([]string{httpsProxy + "=" + c.ProxyUrl, name}, args...) + } } else { args = append([]string{name}, args...) } cmd := exec.Command("sudo", args...) - cmd.Env = append(cmd.Env, httpsProxy+"="+c.ProxyUrl) + + cmd.Env = append(cmd.Env, httpsProxy+"="+c.ProxyUrl, noProxy+"="+c.NoProxy) cmd.Env = append(cmd.Env, env_path+"="+os.Getenv("PATH")) + byt, err := cmd.Output() stderr := "" if exitError, ok := err.(*exec.ExitError); ok { @@ -80,6 +92,7 @@ func (c LocalExecutor) RunWithStdout(name string, args ...string) (string, error type RemoteExecutor struct { Client ssh.Client proxyURL string + NoProxy string } // Run runs a command locally returning just success or failure @@ -95,7 +108,11 @@ func (r *RemoteExecutor) RunWithStdout(name string, args ...string) (string, err cmd = fmt.Sprintf("%s \"%s\"", cmd, arg) } if r.proxyURL != "" { - cmd = fmt.Sprintf("%s=%s %s", httpsProxy, r.proxyURL, cmd) + if r.NoProxy != "" { + cmd = fmt.Sprintf("%s=%s %s=%s %s", httpsProxy, r.proxyURL, noProxy, r.NoProxy, cmd) + } else { + cmd = fmt.Sprintf("%s=%s %s", httpsProxy, r.proxyURL, cmd) + } } stdout, stderr, err := r.Client.RunCommand(cmd) // To fetch the stderr after executing command. @@ -109,12 +126,12 @@ func (r *RemoteExecutor) RunWithStdout(name string, args ...string) (string, err } // NewRemoteExecutor create an Executor interface to execute commands remotely -func NewRemoteExecutor(host string, port int, username string, privateKey []byte, password, proxyURL string) (Executor, error) { +func NewRemoteExecutor(host string, port int, username string, privateKey []byte, password, proxyURL string, noProxy string) (Executor, error) { client, err := ssh.NewClient(host, port, username, privateKey, password, proxyURL) if err != nil { return nil, err } - re := &RemoteExecutor{Client: client, proxyURL: proxyURL} + re := &RemoteExecutor{Client: client, proxyURL: proxyURL, NoProxy: noProxy} return re, nil } @@ -141,7 +158,7 @@ func ConfidentialInfoRemover(cmd string) string { return cmd } -func GetExecutor(proxyURL string, nc objects.NodeConfig) (Executor, error) { +func GetExecutor(proxyURL string, noProxy string, nc objects.NodeConfig) (Executor, error) { if CheckRemote(nc) { var pKey []byte var err error @@ -151,10 +168,10 @@ func GetExecutor(proxyURL string, nc objects.NodeConfig) (Executor, error) { zap.S().Fatalf("Unable to read the sshKey %s, %s", nc.SshKey, err.Error()) } } - return NewRemoteExecutor(nc.IPs[0], 22, nc.User, pKey, nc.Password, proxyURL) + return NewRemoteExecutor(nc.IPs[0], 22, nc.User, pKey, nc.Password, proxyURL, noProxy) } zap.S().Debug("Using local executor") - return LocalExecutor{ProxyUrl: proxyURL}, nil + return LocalExecutor{ProxyUrl: proxyURL, NoProxy: noProxy}, nil } func CheckRemote(nc objects.NodeConfig) bool { diff --git a/pkg/cmdexec/executor_test.go b/pkg/cmdexec/executor_test.go index ce72bd7c..931eacec 100644 --- a/pkg/cmdexec/executor_test.go +++ b/pkg/cmdexec/executor_test.go @@ -9,11 +9,11 @@ import ( func TestGetExecutor(t *testing.T) { proxyURL := "127.0.0.1" - + noProxy := "" localExecutor := LocalExecutor{ProxyUrl: proxyURL} // Test local executor - executor, err := GetExecutor(proxyURL, objects.NodeConfig{}) + executor, err := GetExecutor(proxyURL, noProxy, objects.NodeConfig{}) assert.Equal(t, nil, err) assert.Equal(t, localExecutor, executor) } diff --git a/pkg/config/config.go b/pkg/config/config.go index b182dd58..97fe6bf1 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -340,6 +340,12 @@ func ConfigCmdCreateRun(cfg *objects.Config) error { cfg.ProxyURL = strings.TrimSuffix(proxyURL, "\n") } + if cfg.NoProxy == "" { + fmt.Print("Noproxy [None]: ") + URL, _ := reader.ReadString('\n') + cfg.NoProxy = strings.TrimSuffix(URL, "\n") + } + if cfg.Region == "" { cfg.Region = "RegionOne" } @@ -359,7 +365,7 @@ func ConfigCmdCreateRun(cfg *objects.Config) error { } func createClient(cfg *objects.Config, nc objects.NodeConfig) (client.Client, error) { - executor, err := cmdexec.GetExecutor(cfg.ProxyURL, nc) + executor, err := cmdexec.GetExecutor(cfg.ProxyURL, cfg.NoProxy, nc) if err != nil { //debug first since Fatalf calls os.Exit zap.S().Debug("Error connecting to host %s", err.Error()) @@ -422,6 +428,15 @@ func SetProxy(proxyURL string) error { return nil } +func SetNoProxy(NoProxy string) error { + if NoProxy != "" { + if err := os.Setenv("no_proxy", NoProxy); err != nil { + return errors.New("Error setting no_proxy as environment variable") + } + } + return nil +} + func validateConfigFields(cfg *objects.Config) error { if cfg.Fqdn == "" || cfg.Username == "" || cfg.Password == "" || cfg.Region == "" || cfg.Tenant == "" { return MISSSING_FIELDS diff --git a/pkg/objects/objects.go b/pkg/objects/objects.go index 2c72bb4e..a6f98ee2 100644 --- a/pkg/objects/objects.go +++ b/pkg/objects/objects.go @@ -12,6 +12,7 @@ type Config struct { WaitPeriod time.Duration `json:"wait_period"` AllowInsecure bool `json:"allow_insecure"` ProxyURL string `json:"proxy_url"` + NoProxy string `json:"no_proxy"` MfaToken string `json:"mfa_token"` AwsIamUsername string `json:"aws_iam_username"` AwsAccessKey string `json:"aws_access_key"`