-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
154 lines (132 loc) · 5.34 KB
/
main.go
File metadata and controls
154 lines (132 loc) · 5.34 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2026 BWI GmbH and Dependency Controller contributors
// SPDX-License-Identifier: Apache-2.0
package main
import (
"context"
"flag"
"os"
"github.com/kcp-dev/multicluster-provider/apiexport"
apisv1alpha1 "github.com/kcp-dev/sdk/apis/apis/v1alpha1"
corev1alpha1 "github.com/kcp-dev/sdk/apis/core/v1alpha1"
tenancyv1alpha1 "github.com/kcp-dev/sdk/apis/tenancy/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
mcbuilder "sigs.k8s.io/multicluster-runtime/pkg/builder"
mcmanager "sigs.k8s.io/multicluster-runtime/pkg/manager"
mcreconcile "sigs.k8s.io/multicluster-runtime/pkg/reconcile"
v1alpha1 "go.opendefense.cloud/dependency-controller/api/v1alpha1"
"go.opendefense.cloud/dependency-controller/internal/controller"
"go.opendefense.cloud/dependency-controller/internal/kcp"
)
var scheme = runtime.NewScheme()
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(v1alpha1.AddToScheme(scheme))
utilruntime.Must(apisv1alpha1.AddToScheme(scheme))
utilruntime.Must(corev1alpha1.AddToScheme(scheme))
utilruntime.Must(tenancyv1alpha1.AddToScheme(scheme))
}
func main() {
var apiExportName string
var kcpBaseHost string
var webhookURL string
var webhookCABundlePath string
var healthProbeBindAddress string
flag.StringVar(&apiExportName, "api-export-name", "dependencies.opendefense.cloud", "Name of the dependency-controller's APIExport")
flag.StringVar(&kcpBaseHost, "kcp-base-host", "", "Base kcp host URL (without workspace path). If empty, derived from kubeconfig.")
flag.StringVar(&webhookURL, "webhook-url", "", "URL of the dependency-webhook server (e.g. https://dependency-webhook.ns.svc:443/validate)")
flag.StringVar(&webhookCABundlePath, "webhook-ca-bundle-path", "", "Path to CA bundle PEM file for the webhook server's TLS certificate")
flag.StringVar(&healthProbeBindAddress, "health-probe-bind-address", ":8081", "Address to bind the health probe endpoint")
opts := zap.Options{Development: true}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
setupLog := ctrl.Log.WithName("setup")
cfg := ctrl.GetConfigOrDie()
if err := kcp.ValidateKubeconfig(cfg); err != nil {
setupLog.Error(err, "invalid kubeconfig")
os.Exit(1)
}
// Derive base config (root kcp URL without workspace path).
baseCfg, err := kcp.BaseConfig(cfg)
if err != nil {
setupLog.Error(err, "unable to derive front-proxy base URL from kubeconfig")
os.Exit(1)
}
if kcpBaseHost != "" {
baseCfg.Host = kcpBaseHost
}
// Resolve the APIExportEndpointSlice name for the dep-ctrl's APIExport.
// The slice name is not necessarily the same as the APIExport name.
directClient, err := client.New(cfg, client.Options{Scheme: scheme})
if err != nil {
setupLog.Error(err, "unable to create client for endpoint slice discovery")
os.Exit(1)
}
ess, err := kcp.FindEndpointSlice(context.Background(), directClient, apiExportName)
if err != nil {
setupLog.Error(err, "unable to find APIExportEndpointSlice", "apiExport", apiExportName)
os.Exit(1)
}
// Create apiexport provider for the dependency-controller's own APIExport.
depCtrlProvider, err := apiexport.New(cfg, ess.Name, apiexport.Options{
Scheme: scheme,
})
if err != nil {
setupLog.Error(err, "unable to create apiexport provider")
os.Exit(1)
}
mgr, err := mcmanager.New(cfg, depCtrlProvider, manager.Options{
Scheme: scheme,
HealthProbeBindAddress: healthProbeBindAddress,
})
if err != nil {
setupLog.Error(err, "unable to create manager")
os.Exit(1)
}
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to add healthz check")
os.Exit(1)
}
// Readyz uses Ping because the controller has no safety-critical readiness
// gate. Unlike the webhook (which must block admission until its rule registry
// is populated), the controller only installs ValidatingWebhookConfigurations —
// if it reconciles before initialization completes, it retries on the next event.
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to add readyz check")
os.Exit(1)
}
// Register the multicluster DependencyRule reconciler.
reconciler := controller.NewDependencyRuleReconciler(mgr)
reconciler.BaseConfig = baseCfg
// Wire up webhook installer if configured.
if webhookURL != "" {
var caBundle []byte
if webhookCABundlePath != "" {
caBundle, err = os.ReadFile(webhookCABundlePath)
if err != nil {
setupLog.Error(err, "unable to read webhook CA bundle", "path", webhookCABundlePath)
os.Exit(1)
}
}
reconciler.WebhookInstaller = controller.NewWebhookInstaller(mgr, webhookURL, caBundle)
}
if err := mcbuilder.ControllerManagedBy(mgr).
Named("dependencyrule").
For(&v1alpha1.DependencyRule{}).
Complete(mcreconcile.Func(reconciler.Reconcile)); err != nil {
setupLog.Error(err, "unable to create DependencyRule controller")
os.Exit(1)
}
setupLog.Info("starting manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "manager failed")
os.Exit(1)
}
}