github.com/argoproj/argo-cd/v2@v2.10.5/util/kube/portforwarder.go (about) 1 package kube 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "net" 8 "net/http" 9 "os" 10 11 corev1 "k8s.io/api/core/v1" 12 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 13 "k8s.io/client-go/kubernetes" 14 "k8s.io/client-go/tools/clientcmd" 15 "k8s.io/client-go/tools/portforward" 16 "k8s.io/client-go/transport/spdy" 17 18 "github.com/argoproj/argo-cd/v2/util/io" 19 ) 20 21 func PortForward(targetPort int, namespace string, overrides *clientcmd.ConfigOverrides, podSelectors ...string) (int, error) { 22 loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() 23 loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig 24 clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin) 25 config, err := clientConfig.ClientConfig() 26 if err != nil { 27 return -1, err 28 } 29 30 if namespace == "" { 31 namespace, _, err = clientConfig.Namespace() 32 if err != nil { 33 return -1, err 34 } 35 } 36 37 clientSet, err := kubernetes.NewForConfig(config) 38 if err != nil { 39 return -1, err 40 } 41 42 var pod *corev1.Pod 43 44 for _, podSelector := range podSelectors { 45 pods, err := clientSet.CoreV1().Pods(namespace).List(context.Background(), v1.ListOptions{ 46 LabelSelector: podSelector, 47 }) 48 if err != nil { 49 return -1, err 50 } 51 52 if len(pods.Items) > 0 { 53 pod = &pods.Items[0] 54 break 55 } 56 } 57 58 if pod == nil { 59 return -1, fmt.Errorf("cannot find pod with selector: %v - use the --{component}-name flag in this command or set the environmental variable (Refer to https://argo-cd.readthedocs.io/en/stable/user-guide/environment-variables), to change the Argo CD component name in the CLI", podSelectors) 60 } 61 62 url := clientSet.CoreV1().RESTClient().Post(). 63 Resource("pods"). 64 Namespace(pod.Namespace). 65 Name(pod.Name). 66 SubResource("portforward").URL() 67 68 transport, upgrader, err := spdy.RoundTripperFor(config) 69 if err != nil { 70 return -1, fmt.Errorf("could not create round tripper: %w", err) 71 } 72 dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url) 73 74 readyChan := make(chan struct{}, 1) 75 failedChan := make(chan error, 1) 76 out := new(bytes.Buffer) 77 errOut := new(bytes.Buffer) 78 79 ln, err := net.Listen("tcp", "localhost:0") 80 if err != nil { 81 return -1, err 82 } 83 port := ln.Addr().(*net.TCPAddr).Port 84 io.Close(ln) 85 86 forwarder, err := portforward.New(dialer, []string{fmt.Sprintf("%d:%d", port, targetPort)}, context.Background().Done(), readyChan, out, errOut) 87 if err != nil { 88 return -1, err 89 } 90 91 go func() { 92 err = forwarder.ForwardPorts() 93 if err != nil { 94 failedChan <- err 95 } 96 }() 97 select { 98 case err = <-failedChan: 99 return -1, err 100 case <-readyChan: 101 } 102 if len(errOut.String()) != 0 { 103 return -1, fmt.Errorf(errOut.String()) 104 } 105 return port, nil 106 }