-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.go
138 lines (113 loc) · 3.32 KB
/
app.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 (
"fmt"
"net/http"
"os"
"sync"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/slok/kubewebhook/pkg/observability/metrics"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/robfig/cron/v3"
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
)
// Config holds the application configuration
type Config struct {
enableWebhook bool
kubeconfig string
locoAPIKeys map[string]string
schedule string
tlsCertFile string
tlsPrivateKeyFile string
}
// App represents the main application object
type App struct {
config *Config
translations TranslationsProvider
refresher *Refresher
}
func newApp(c *Config) *App {
return &App{config: c}
}
// Init initializes the application
func (app *App) Init() error {
// create the kubernetes client config
config, err := app.configFromKubeConfig()
if err != nil {
return err
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return err
}
// create the Refresher service
app.refresher = NewRefresher(clientset)
// create the Loco clients
locoClients := CreateLocoClients(app.config.locoAPIKeys)
// create the Loco translations provider
app.translations = NewLocoProvider(locoClients)
return nil
}
// Run the application
func (app *App) Run() {
// create Prometheus recorder
recorder := metrics.NewPrometheus(prometheus.DefaultRegisterer)
// compute translation hashes
hashes := app.translations.Fetch()
if app.config.schedule != "" {
cron := cron.New()
_, _ = cron.AddFunc(app.config.schedule, func() {
// make sure we have the latest translations
app.translations.Fetch()
// update kubernetes deployments
app.refresher.Refresh(hashes)
})
go cron.Run()
}
if app.config.enableWebhook {
// We need the handler func with all the translations sync logic
deployHandler := Appsv1ResourceHandler("etsglobal.org", hashes)
// Create the mutating webhook
mw := NewMutatingWebhook(deployHandler, recorder)
// Start the mutating webhook server in a separate goroutine
go func() {
err := mw.ListenAndServeTLS(":8443", app.config.tlsCertFile, app.config.tlsPrivateKeyFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Error serving webhook: %s", err)
os.Exit(1)
}
}()
}
var wg sync.WaitGroup
go func() {
wg.Add(1)
defer wg.Done()
// HTTP server
mux := http.NewServeMux()
mux.Handle("/health", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(200)
}))
mux.Handle("/metrics", http.Handler(promhttp.Handler()))
mux.Handle("/api/v1/refresh", http.HandlerFunc(app.ApiHandler))
fmt.Println("Listening on port 8080")
err := http.ListenAndServe(":8080", mux)
if err != nil {
fmt.Fprintf(os.Stderr, "Error serving HTTP requests: %s", err)
}
}()
// When everythins is up and running, we can finally run the refresh
app.refresher.Refresh(hashes)
wg.Wait()
}
func (app App) configFromKubeConfig() (*rest.Config, error) {
_, err := os.Stat(app.config.kubeconfig)
if os.IsNotExist(err) {
// kubeconfig file doesn't exist, try in-cluster config
return rest.InClusterConfig()
}
// use the current context in kubeconfig
return clientcmd.BuildConfigFromFlags("", app.config.kubeconfig)
}