generated from vshn/go-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.go
138 lines (117 loc) · 3.59 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
138
package main
import (
"flag"
"net/netip"
"os"
"strings"
"time"
"github.com/appuio/tailscale-service-observer/tailscaleupdater"
"github.com/go-logr/logr"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
var (
// these variables are populated by Goreleaser when releasing
version = "unknown"
commit = "-dirty-"
date = time.Now().Format("2006-01-02")
appName = "tailscale-service-observer"
defaultTailscaleAPIURL = "http://localhost:8088"
)
// createClient creates a new Kubernetes client either from the current
// kubeconfig context, or from the in-cluster config if the program is running
// in a pod.
func createClient() (*kubernetes.Clientset, error) {
// if you want to change the loading rules (which files in which order), you can do so here
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
// if you want to change override values or bind them to flags, there are methods to help you
configOverrides := &clientcmd.ConfigOverrides{}
kubeConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, configOverrides)
config, err := kubeConfig.ClientConfig()
if err != nil {
return nil, err
}
return kubernetes.NewForConfig(config)
}
// parseEnv parses comma-separated values from an env variable
func parseEnv(raw string) []string {
parts := strings.Split(raw, ",")
parsed := []string{}
for _, ns := range parts {
trimmed := strings.Trim(ns, " ")
if trimmed != "" {
parsed = append(parsed, trimmed)
}
}
return parsed
}
func advertiseAdditionalRoutes(l logr.Logger, t *tailscaleupdater.TailscaleAdvertisementUpdater, rawRoutes string) {
for _, rspec := range parseEnv(rawRoutes) {
r, err := netip.ParsePrefix(rspec)
if err != nil {
a, err2 := netip.ParseAddr(rspec)
if err2 == nil {
r2, err2 := a.Prefix(a.BitLen())
if err2 != nil {
l.Error(err, "converting bare IP to prefix")
}
r = r2
err = err2
}
}
if err != nil {
l.Info("Failed to parse additional route, ignoring", "value", rspec)
continue
}
if err := t.AddRoute(r.String()); err != nil {
l.Error(err, "adding additional route", "route", r.String())
}
}
}
func main() {
// use controller-runtime to setup logging and context
opts := zap.Options{
Development: false,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
ctx := ctrl.SetupSignalHandler()
setupLog := ctrl.Log.WithName("setup")
rawTargetNamespace, ok := os.LookupEnv("TARGET_NAMESPACE")
if !ok {
setupLog.Info("Unable to read target namespace from environment ($TARGET_NAMESPACE)")
os.Exit(1)
}
targetNamespaces := parseEnv(rawTargetNamespace)
var apiURL string
apiURL, ok = os.LookupEnv("TAILSCALE_API_URL")
if !ok {
apiURL = defaultTailscaleAPIURL
}
tsUpdater, err := tailscaleupdater.New(targetNamespaces, apiURL)
additionalRoutes, ok := os.LookupEnv("OBSERVER_ADDITIONAL_ROUTES")
if ok {
advertiseAdditionalRoutes(setupLog, tsUpdater, additionalRoutes)
}
client, err := createClient()
if err != nil {
setupLog.Error(err, "setting up Kubernetes client")
os.Exit(1)
}
if err != nil {
setupLog.Error(err, "while creating Tailscale updater")
os.Exit(1)
}
for _, ns := range targetNamespaces {
factory := informers.NewSharedInformerFactoryWithOptions(client, 10*time.Minute, informers.WithNamespace(ns))
_ = tsUpdater.SetupInformer(factory)
// start informers
factory.Start(ctx.Done()) // runs in background
factory.WaitForCacheSync(ctx.Done())
}
<-ctx.Done()
}