This repository has been archived by the owner on Sep 8, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
/
main.go
137 lines (123 loc) · 3.57 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package main
import (
"flag"
"fmt"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"strings"
"sync"
"syscall"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
)
type PortForwardAPodRequest struct {
// RestConfig is the kubernetes config
RestConfig *rest.Config
// Pod is the selected pod for this port forwarding
Pod v1.Pod
// LocalPort is the local port that will be selected to expose the PodPort
LocalPort int
// PodPort is the target port for the pod
PodPort int
// Steams configures where to write or read input from
Streams genericclioptions.IOStreams
// StopCh is the channel used to manage the port forward lifecycle
StopCh <-chan struct{}
// ReadyCh communicates when the tunnel is ready to receive traffic
ReadyCh chan struct{}
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
var kubeconfig *string
if home := homeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// stopCh control the port forwarding lifecycle. When it gets closed the
// port forward will terminate
stopCh := make(chan struct{}, 1)
// readyCh communicate when the port forward is ready to get traffic
readyCh := make(chan struct{})
// stream is used to tell the port forwarder where to place its output or
// where to expect input if needed. For the port forwarding we just need
// the output eventually
stream := genericclioptions.IOStreams{
In: os.Stdin,
Out: os.Stdout,
ErrOut: os.Stderr,
}
// managing termination signal from the terminal. As you can see the stopCh
// gets closed to gracefully handle its termination.
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
fmt.Println("Bye...")
close(stopCh)
wg.Done()
}()
go func() {
// PortForward the pod specified from its port 9090 to the local port
// 8080
err := PortForwardAPod(PortForwardAPodRequest{
RestConfig: config,
Pod: v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "influxdb-v2",
Namespace: "default",
},
},
LocalPort: 8080,
PodPort: 9999,
Streams: stream,
StopCh: stopCh,
ReadyCh: readyCh,
})
if err != nil {
panic(err)
}
}()
select {
case <-readyCh:
break
}
println("Port forwarding is ready to get traffic. have fun!")
wg.Wait()
}
func PortForwardAPod(req PortForwardAPodRequest) error {
path := fmt.Sprintf("/api/v1/namespaces/%s/pods/%s/portforward",
req.Pod.Namespace, req.Pod.Name)
hostIP := strings.TrimLeft(req.RestConfig.Host, "htps:/")
transport, upgrader, err := spdy.RoundTripperFor(req.RestConfig)
if err != nil {
return err
}
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, http.MethodPost, &url.URL{Scheme: "https", Path: path, Host: hostIP})
fw, err := portforward.New(dialer, []string{fmt.Sprintf("%d:%d", req.LocalPort, req.PodPort)}, req.StopCh, req.ReadyCh, req.Streams.Out, req.Streams.ErrOut)
if err != nil {
return err
}
return fw.ForwardPorts()
}
func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // windows
}