diff --git a/cmd/argo/commands/client/conn.go b/cmd/argo/commands/client/conn.go index 8d92587bbcab..c0d1a47299a7 100644 --- a/cmd/argo/commands/client/conn.go +++ b/cmd/argo/commands/client/conn.go @@ -3,6 +3,8 @@ package client import ( "context" "fmt" + "net/http" + "net/url" "os" log "github.com/sirupsen/logrus" @@ -55,6 +57,15 @@ func AddAPIClientFlagsToCmd(cmd *cobra.Command) { } func NewAPIClient(ctx context.Context) (context.Context, apiclient.Client) { + var proxy func(*http.Request) (*url.URL, error) + if overrides.ClusterInfo.ProxyURL != "" { + proxyURL, err := url.Parse(overrides.ClusterInfo.ProxyURL) + if err != nil { + log.Fatal(err) + } + proxy = http.ProxyURL(proxyURL) + } + ctx, client, err := apiclient.NewClientFromOpts( apiclient.Opts{ ArgoServerOpts: ArgoServerOpts, @@ -66,6 +77,7 @@ func NewAPIClient(ctx context.Context) (context.Context, apiclient.Client) { Offline: Offline, OfflineFiles: OfflineFiles, Context: ctx, + Proxy: proxy, }) if err != nil { log.Fatal(err) @@ -88,6 +100,7 @@ func Namespace() string { if err != nil { log.Fatal(err) } + return namespace } diff --git a/pkg/apiclient/apiclient.go b/pkg/apiclient/apiclient.go index e1a90e9f2efe..4b1e84bc5c16 100644 --- a/pkg/apiclient/apiclient.go +++ b/pkg/apiclient/apiclient.go @@ -3,6 +3,8 @@ package apiclient import ( "context" "fmt" + "net/http" + "net/url" log "github.com/sirupsen/logrus" "k8s.io/client-go/tools/clientcmd" @@ -35,6 +37,7 @@ type Opts struct { Offline bool OfflineFiles []string Context context.Context + Proxy func(*http.Request) (*url.URL, error) } func (o Opts) String() string { @@ -73,7 +76,8 @@ func NewClientFromOpts(opts Opts) (context.Context, Client, error) { if opts.AuthSupplier == nil { return nil, nil, fmt.Errorf("AuthSupplier cannot be empty when connecting to Argo Server") } - return newHTTP1Client(opts.ArgoServerOpts.GetURL(), opts.AuthSupplier(), opts.ArgoServerOpts.InsecureSkipVerify, opts.ArgoServerOpts.Headers) + + return newHTTP1Client(opts.ArgoServerOpts.GetURL(), opts.AuthSupplier(), opts.ArgoServerOpts.InsecureSkipVerify, opts.ArgoServerOpts.Headers, opts.Proxy) } else if opts.ArgoServerOpts.URL != "" { if opts.AuthSupplier == nil { return nil, nil, fmt.Errorf("AuthSupplier cannot be empty when connecting to Argo Server") diff --git a/pkg/apiclient/http1-client.go b/pkg/apiclient/http1-client.go index f200e19dcda8..7596dbbd68ae 100644 --- a/pkg/apiclient/http1-client.go +++ b/pkg/apiclient/http1-client.go @@ -2,6 +2,8 @@ package apiclient import ( "context" + "net/http" + "net/url" "github.com/argoproj/argo-workflows/v3/pkg/apiclient/clusterworkflowtemplate" cronworkflowpkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/cronworkflow" @@ -40,6 +42,6 @@ func (h httpClient) NewInfoServiceClient() (infopkg.InfoServiceClient, error) { return http1.InfoServiceClient(h), nil } -func newHTTP1Client(baseUrl string, auth string, insecureSkipVerify bool, headers []string) (context.Context, Client, error) { - return context.Background(), httpClient(http1.NewFacade(baseUrl, auth, insecureSkipVerify, headers)), nil +func newHTTP1Client(baseUrl string, auth string, insecureSkipVerify bool, headers []string, proxy func(*http.Request) (*url.URL, error)) (context.Context, Client, error) { + return context.Background(), httpClient(http1.NewFacade(baseUrl, auth, insecureSkipVerify, headers, proxy)), nil } diff --git a/pkg/apiclient/http1/facade.go b/pkg/apiclient/http1/facade.go index 5329f72219bb..1a245459839c 100644 --- a/pkg/apiclient/http1/facade.go +++ b/pkg/apiclient/http1/facade.go @@ -25,10 +25,11 @@ type Facade struct { authorization string insecureSkipVerify bool headers []string + proxy func(*http.Request) (*url.URL, error) } -func NewFacade(baseUrl, authorization string, insecureSkipVerify bool, headers []string) Facade { - return Facade{baseUrl, authorization, insecureSkipVerify, headers} +func NewFacade(baseUrl, authorization string, insecureSkipVerify bool, headers []string, proxy func(*http.Request) (*url.URL, error)) Facade { + return Facade{baseUrl, authorization, insecureSkipVerify, headers, proxy} } func (h Facade) Get(in, out interface{}, path string) error { @@ -65,6 +66,7 @@ func (h Facade) EventStreamReader(in interface{}, path string) (*bufio.Reader, e req.Header.Set("Accept", "text/event-stream") req.Header.Set("Authorization", h.authorization) log.Debugf("curl -H 'Accept: text/event-stream' -H 'Authorization: ******' '%v'", u) + client := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ @@ -108,8 +110,21 @@ func (h Facade) do(in interface{}, out interface{}, method string, path string) req.Header = headers req.Header.Set("Authorization", h.authorization) log.Debugf("curl -X %s -H 'Authorization: ******' -d '%s' '%v'", method, string(data), u) + + proxy := http.ProxyFromEnvironment + + if h.proxy != nil { + proxy = h.proxy + } + + proxyURL, err := proxy(req) + if err != nil { + return err + } + client := &http.Client{ Transport: &http.Transport{ + Proxy: http.ProxyURL(proxyURL), TLSClientConfig: &tls.Config{ InsecureSkipVerify: h.insecureSkipVerify, },