-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
137 lines (124 loc) · 3.7 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 (
"context"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
"sync"
"syscall"
"gopkg.in/yaml.v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
)
type Service struct {
Name string `yaml:"name"`
RemotePort int `yaml:"remotePort"`
LocalPort int `yaml:"localPort"`
}
type ServiceList struct {
Services []Service `yaml:"services"`
}
func main() {
stopChs := []chan struct{}{}
readyChs := []chan struct{}{}
//defer close(stopCh)
var wg sync.WaitGroup
wg.Add(1)
// 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...")
for _, ch := range stopChs {
close(ch)
}
wg.Done()
}()
// Get the path to the kubeconfig file
homeDir, err := os.UserHomeDir()
if err != nil {
log.Fatal(err)
}
kubeconfigPath := filepath.Join(homeDir, ".kube", "config")
// Build the clientset from the kubeconfig file
config, err := clientcmd.BuildConfigFromFlags("", kubeconfigPath)
if err != nil {
log.Fatal(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
log.Fatal(err)
}
// read service.yaml
var serviceList ServiceList
yamlFile, err := ioutil.ReadFile(".portpilot.yaml")
if err != nil {
log.Fatal(err)
}
err = yaml.Unmarshal(yamlFile, &serviceList)
if err != nil {
log.Fatal(err)
}
for _, serviceName := range serviceList.Services {
// Start the port forwarding
go func(serviceName Service) {
podName := findPod(clientset, serviceName.Name)
port := fmt.Sprintf("%d", serviceName.RemotePort)
path := fmt.Sprintf("api/v1/namespaces/%s/pods/%s/portforward", "default", podName)
svcURL, err := url.Parse(fmt.Sprintf("%s/%v", config.Host, path))
if err != nil {
log.Fatal("url parse", err)
}
fmt.Println(svcURL)
transport, upgrader, err := spdy.RoundTripperFor(config)
if err != nil {
log.Fatal("spdy roundtripper", err)
}
stopCh := make(chan struct{}, 1)
readyCh := make(chan struct{})
readyChs = append(readyChs, readyCh)
stopChs = append(stopChs, stopCh)
dialer := spdy.NewDialer(upgrader, &http.Client{Transport: transport}, http.MethodPost, svcURL)
portForwarder, err := portforward.New(dialer, []string{fmt.Sprintf("%d:%v", serviceName.LocalPort, port)}, stopCh, readyCh, os.Stdout, os.Stderr)
if err != nil {
log.Fatal("error forwarding", err)
}
if err := portForwarder.ForwardPorts(); err != nil {
log.Fatal("port-forwarder", err)
}
}(serviceName)
fmt.Printf("Port forwarding to service '%s' started.\n", serviceName.Name)
fmt.Println("You can now access the service on http://localhost:" + fmt.Sprintf("%d", serviceName.LocalPort))
}
fmt.Println("Press Ctrl+C to stop forwarding.")
wg.Wait()
fmt.Println("Bye...")
}
// findPod finds a pod from a service name
func findPod(clientset *kubernetes.Clientset, serviceName string) string {
// Retrieve the service object
service, err := clientset.CoreV1().Services("default").Get(context.Background(), serviceName, metav1.GetOptions{})
if err != nil {
log.Fatal(err)
}
// Get the labels associated with the service
serviceLabels := service.Spec.Selector
// Retrieve the pods with matching labels
pods, err := clientset.CoreV1().Pods(service.Namespace).List(context.Background(), metav1.ListOptions{
LabelSelector: metav1.FormatLabelSelector(&metav1.LabelSelector{MatchLabels: serviceLabels}),
})
if err != nil {
log.Fatal(err)
}
return pods.Items[0].Name
}