@@ -8,35 +8,37 @@ import (
8
8
"encoding/json"
9
9
"flag"
10
10
"fmt"
11
+ "net/http"
11
12
"os"
13
+ "path/filepath"
14
+ "strconv"
12
15
13
16
"github.com/pkg/errors"
14
17
"github.com/spf13/pflag"
15
18
admissionv1 "k8s.io/api/admissionregistration/v1"
16
19
corev1 "k8s.io/api/core/v1"
20
+ apiv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
17
21
clientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
18
22
apiclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
19
23
apierrors "k8s.io/apimachinery/pkg/api/errors"
20
24
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21
25
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
22
26
"k8s.io/apimachinery/pkg/runtime"
27
+ "k8s.io/apimachinery/pkg/runtime/serializer"
23
28
"k8s.io/client-go/kubernetes"
24
29
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
25
30
"k8s.io/client-go/tools/clientcmd"
26
31
"k8s.io/kubectl/pkg/util"
27
32
28
33
configv1alpha2 "github.com/openservicemesh/osm/pkg/apis/config/v1alpha2"
34
+ configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
29
35
30
36
"github.com/openservicemesh/osm/pkg/certificate/providers"
31
- "github.com/openservicemesh/osm/pkg/configurator"
32
37
"github.com/openservicemesh/osm/pkg/constants"
33
- "github.com/openservicemesh/osm/pkg/crdconversion"
34
- configClientset "github.com/openservicemesh/osm/pkg/gen/client/config/clientset/versioned"
35
38
"github.com/openservicemesh/osm/pkg/httpserver"
36
39
httpserverconstants "github.com/openservicemesh/osm/pkg/httpserver/constants"
37
40
"github.com/openservicemesh/osm/pkg/k8s/events"
38
41
"github.com/openservicemesh/osm/pkg/logger"
39
- "github.com/openservicemesh/osm/pkg/messaging"
40
42
"github.com/openservicemesh/osm/pkg/metricsstore"
41
43
"github.com/openservicemesh/osm/pkg/reconciler"
42
44
"github.com/openservicemesh/osm/pkg/signals"
@@ -47,6 +49,8 @@ const (
47
49
meshConfigName = "osm-mesh-config"
48
50
presetMeshConfigName = "preset-mesh-config"
49
51
presetMeshConfigJSONKey = "preset-mesh-config.json"
52
+ webhookHealthPath = "/healthz"
53
+ healthPort = 9095
50
54
)
51
55
52
56
var (
57
61
meshName string
58
62
osmVersion string
59
63
60
- crdConverterConfig crdconversion.Config
61
-
62
64
certProviderKind string
63
65
64
- tresorOptions providers.TresorOptions
65
66
vaultOptions providers.VaultOptions
66
67
certManagerOptions providers.CertManagerOptions
67
68
@@ -147,6 +148,8 @@ func main() {
147
148
namespace : osmNamespace ,
148
149
}
149
150
151
+ applyOrUpdateCRDs (crdClient )
152
+
150
153
err = bootstrap .ensureMeshConfig ()
151
154
if err != nil {
152
155
log .Fatal ().Err (err ).Msgf ("Error setting up default MeshConfig %s from ConfigMap %s" , meshConfigName , presetMeshConfigName )
@@ -158,37 +161,27 @@ func main() {
158
161
log .Fatal ().Err (err ).Msg ("Error initializing Kubernetes events recorder" )
159
162
}
160
163
161
- stop := signals .RegisterExitHandlers ()
162
164
_ , cancel := context .WithCancel (context .Background ())
163
165
defer cancel ()
166
+ stop := signals .RegisterExitHandlers ()
164
167
165
168
// Start the default metrics store
166
169
metricsstore .DefaultMetricsStore .Start (
167
170
metricsstore .DefaultMetricsStore .ErrCodeCounter ,
168
171
metricsstore .DefaultMetricsStore .HTTPResponseTotal ,
169
172
metricsstore .DefaultMetricsStore .HTTPResponseDuration ,
170
- metricsstore .DefaultMetricsStore .ConversionWebhookResourceTotal ,
171
173
)
172
174
173
- msgBroker := messaging .NewBroker (stop )
174
-
175
- // Initialize Configurator to retrieve mesh specific config
176
- cfg := configurator .NewConfigurator (configClient , stop , osmNamespace , osmMeshConfigName , msgBroker )
177
-
178
- // Intitialize certificate manager/provider
179
- certProviderConfig := providers .NewCertificateProviderConfig (kubeClient , kubeConfig , cfg , providers .Kind (certProviderKind ), osmNamespace ,
180
- caBundleSecretName , tresorOptions , vaultOptions , certManagerOptions , msgBroker )
181
-
182
- certManager , _ , err := certProviderConfig .GetCertificateManager ()
183
- if err != nil {
184
- events .GenericEventRecorder ().FatalEvent (err , events .InvalidCertificateManager ,
185
- "Error initializing certificate manager of kind %s" , certProviderKind )
186
- }
187
-
188
- // Initialize the crd conversion webhook server to support the conversion of OSM's CRDs
189
- crdConverterConfig .ListenPort = constants .CRDConversionWebhookPort
190
- if err := crdconversion .NewConversionWebhook (crdConverterConfig , kubeClient , crdClient , certManager , osmNamespace , enableReconciler , stop ); err != nil {
191
- events .GenericEventRecorder ().FatalEvent (err , events .InitializationError , "Error creating crd conversion webhook" )
175
+ /*
176
+ * Initialize osm-bootstrap's HTTP server
177
+ */
178
+ if enableReconciler {
179
+ log .Info ().Msgf ("OSM reconciler enabled for custom resource definitions" )
180
+ err = reconciler .NewReconcilerClient (kubeClient , apiServerClient , meshName , osmVersion , stop , reconciler .CrdInformerKey )
181
+ if err != nil {
182
+ events .GenericEventRecorder ().FatalEvent (err , events .InitializationError , "Error creating reconciler client for custom resource definitions" )
183
+ log .Fatal ().Err (err ).Msgf ("Failed to create reconcile client for custom resource definitions" )
184
+ }
192
185
}
193
186
194
187
/*
@@ -199,22 +192,92 @@ func main() {
199
192
httpServer .AddHandler (httpserverconstants .MetricsPath , metricsstore .DefaultMetricsStore .Handler ())
200
193
// Version
201
194
httpServer .AddHandler (httpserverconstants .VersionPath , version .GetVersionHandler ())
202
- // Start HTTP server
195
+ // Health
196
+ healthMux := http .NewServeMux ()
197
+ healthMux .Handle (webhookHealthPath , metricsstore .AddHTTPMetrics (http .HandlerFunc (healthHandler )))
198
+
199
+ healthServer := & http.Server {
200
+ Addr : fmt .Sprintf (":%d" , healthPort ),
201
+ Handler : healthMux ,
202
+ }
203
+
204
+ go func () {
205
+ if err := healthServer .ListenAndServe (); err != nil {
206
+ log .Error ().Err (err ).Msg ("crd-converter health server failed to start" )
207
+ return
208
+ }
209
+ }()
210
+
203
211
err = httpServer .Start ()
204
212
if err != nil {
205
213
log .Fatal ().Err (err ).Msgf ("Failed to start OSM metrics/probes HTTP server" )
206
214
}
207
215
208
- if enableReconciler {
209
- log .Info ().Msgf ("OSM reconciler enabled for custom resource definitions" )
210
- err = reconciler .NewReconcilerClient (kubeClient , apiServerClient , meshName , osmVersion , stop , reconciler .CrdInformerKey )
216
+ <- stop
217
+ cancel ()
218
+ log .Info ().Msgf ("Stopping osm-bootstrap %s; %s; %s" , version .Version , version .GitCommit , version .BuildDate )
219
+ }
220
+
221
+ func healthHandler (w http.ResponseWriter , _ * http.Request ) {
222
+ w .WriteHeader (http .StatusOK )
223
+ if _ , err := w .Write ([]byte ("Health OK" )); err != nil {
224
+ log .Error ().Err (err ).Msg ("Error writing bytes for webhook health check handler" )
225
+ }
226
+ }
227
+
228
+ func applyOrUpdateCRDs (crdClient * apiclient.ApiextensionsV1Client ) {
229
+ crdFiles , err := filepath .Glob ("/osm-crds/*.yaml" )
230
+
231
+ if err != nil {
232
+ log .Fatal ().Err (err ).Msgf ("error reading files from /osm-crds" )
233
+ }
234
+
235
+ scheme = runtime .NewScheme ()
236
+ codecs := serializer .NewCodecFactory (scheme )
237
+ decode := codecs .UniversalDeserializer ().Decode
238
+
239
+ for _ , file := range crdFiles {
240
+ yaml , err := os .ReadFile (filepath .Clean (file ))
211
241
if err != nil {
212
- events . GenericEventRecorder ().FatalEvent (err , events . InitializationError , "Error creating reconciler client for custom resource definitions" )
242
+ log . Fatal ().Err (err ). Msgf ( "Error reading CRD file %s" , file )
213
243
}
214
- }
215
244
216
- <- stop
217
- log .Info ().Msgf ("Stopping osm-bootstrap %s; %s; %s" , version .Version , version .GitCommit , version .BuildDate )
245
+ crd := & apiv1.CustomResourceDefinition {}
246
+ _ , _ , err = decode (yaml , nil , crd )
247
+ if err != nil {
248
+ log .Fatal ().Err (err ).Msgf ("Error decoding CRD file %s" , file )
249
+ }
250
+
251
+ crd .Labels [constants .ReconcileLabel ] = strconv .FormatBool (enableReconciler )
252
+
253
+ crdExisting , err := crdClient .CustomResourceDefinitions ().Get (context .Background (), crd .Name , metav1.GetOptions {})
254
+ if err != nil && ! apierrors .IsNotFound (err ) {
255
+ log .Fatal ().Err (err ).Msgf ("error getting CRD %s" , crd .Name )
256
+ }
257
+
258
+ if apierrors .IsNotFound (err ) {
259
+ log .Info ().Msgf ("crds %s not found, creating CRD" , crd .Name )
260
+ if err := util .CreateApplyAnnotation (crd , unstructured .UnstructuredJSONScheme ); err != nil {
261
+ log .Fatal ().Err (err ).Msgf ("Error applying annotation to CRD %s" , crd .Name )
262
+ }
263
+ if _ , err = crdClient .CustomResourceDefinitions ().Create (context .Background (), crd , metav1.CreateOptions {}); err != nil {
264
+ log .Fatal ().Err (err ).Msgf ("Error creating crd : %s" , crd .Name )
265
+ }
266
+ log .Info ().Msgf ("Successfully created crd: %s" , crd .Name )
267
+ } else {
268
+ log .Info ().Msgf ("Patching conversion webhook configuration for crd: %s, setting to \" None\" " , crd .Name )
269
+
270
+ crdExisting .Labels [constants .ReconcileLabel ] = strconv .FormatBool (enableReconciler )
271
+ crdExisting .Spec = crd .Spec
272
+ crdExisting .Spec .Conversion = & apiv1.CustomResourceConversion {
273
+ Strategy : apiv1 .NoneConverter ,
274
+ }
275
+ if _ , err = crdClient .CustomResourceDefinitions ().Update (context .Background (), crdExisting , metav1.UpdateOptions {}); err != nil {
276
+ log .Fatal ().Err (err ).Msgf ("Error updating conversion webhook configuration for crd : %s" , crd .Name )
277
+ }
278
+ log .Info ().Msgf ("successfully set conversion webhook configuration for crd : %s to \" None\" " , crd .Name )
279
+ }
280
+ }
218
281
}
219
282
220
283
func (b * bootstrap ) createDefaultMeshConfig () error {
@@ -267,8 +330,9 @@ func (b *bootstrap) ensureMeshConfig() error {
267
330
}
268
331
269
332
// initiatilizeKubernetesEventsRecorder initializes the generic Kubernetes event recorder and associates it with
333
+ //
270
334
// the osm-bootstrap pod resource. The events recorder allows the osm-bootstap to publish Kubernets events to
271
- // report fatal errors with initializing this application. These events will show up in the output of `kubectl get events`
335
+ // report fatal errors with initializing this application. These events will show up in the output of `kubectl get events`
272
336
func (b * bootstrap ) initiatilizeKubernetesEventsRecorder () error {
273
337
bootstrapPod , err := b .getBootstrapPod ()
274
338
if err != nil {
0 commit comments