github.com/argoproj/argo-cd@v1.8.7/util/kube/portforwarder.go (about) 1 package kube 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "log" 8 "net" 9 "net/http" 10 "os" 11 12 "github.com/pkg/errors" 13 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 14 "k8s.io/client-go/kubernetes" 15 "k8s.io/client-go/tools/clientcmd" 16 "k8s.io/client-go/tools/portforward" 17 "k8s.io/client-go/transport/spdy" 18 19 "github.com/argoproj/argo-cd/util/io" 20 ) 21 22 func PortForward(podSelector string, targetPort int, namespace string) (int, error) { 23 loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() 24 loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig 25 overrides := clientcmd.ConfigOverrides{} 26 clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin) 27 config, err := clientConfig.ClientConfig() 28 if err != nil { 29 return -1, err 30 } 31 32 if namespace == "" { 33 namespace, _, err = clientConfig.Namespace() 34 if err != nil { 35 return -1, err 36 } 37 } 38 39 clientSet, err := kubernetes.NewForConfig(config) 40 if err != nil { 41 return -1, err 42 } 43 44 pods, err := clientSet.CoreV1().Pods(namespace).List(context.Background(), v1.ListOptions{ 45 LabelSelector: podSelector, 46 }) 47 if err != nil { 48 return -1, err 49 } 50 51 if len(pods.Items) == 0 { 52 return -1, fmt.Errorf("cannot find %s pod", podSelector) 53 } 54 55 url := clientSet.CoreV1().RESTClient().Post(). 56 Resource("pods"). 57 Namespace(pods.Items[0].Namespace). 58 Name(pods.Items[0].Name). 59 SubResource("portforward").URL() 60 61 transport, upgrader, err := spdy.RoundTripperFor(config) 62 if err != nil { 63 return -1, errors.Wrap(err, "Could not create round tripper") 64 } 65 dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, "POST", url) 66 67 readyChan := make(chan struct{}, 1) 68 out := new(bytes.Buffer) 69 errOut := new(bytes.Buffer) 70 71 ln, err := net.Listen("tcp", "[::]:0") 72 if err != nil { 73 return -1, err 74 } 75 port := ln.Addr().(*net.TCPAddr).Port 76 io.Close(ln) 77 78 forwarder, err := portforward.New(dialer, []string{fmt.Sprintf("%d:%d", port, targetPort)}, context.Background().Done(), readyChan, out, errOut) 79 if err != nil { 80 return -1, err 81 } 82 83 go func() { 84 err = forwarder.ForwardPorts() 85 if err != nil { 86 log.Fatal(err) 87 } 88 }() 89 for range readyChan { 90 } 91 if len(errOut.String()) != 0 { 92 return -1, fmt.Errorf(errOut.String()) 93 } 94 return port, nil 95 }