@@ -52,13 +52,16 @@ func (routeStrategy) NamespaceScoped() bool {
52
52
func (s routeStrategy ) PrepareForCreate (ctx apirequest.Context , obj runtime.Object ) {
53
53
route := obj .(* api.Route )
54
54
route .Status = api.RouteStatus {}
55
+
56
+ stripEmptyDestinationCACertificate (route )
55
57
}
56
58
57
59
func (s routeStrategy ) PrepareForUpdate (ctx apirequest.Context , obj , old runtime.Object ) {
58
60
route := obj .(* api.Route )
59
61
oldRoute := old .(* api.Route )
60
- route .Status = oldRoute .Status
61
62
63
+ route .Status = oldRoute .Status
64
+ stripEmptyDestinationCACertificate (route )
62
65
// Ignore attempts to clear the spec Host
63
66
// Prevents "immutable field" errors when applying the same route definition used to create
64
67
if len (route .Spec .Host ) == 0 {
@@ -218,6 +221,56 @@ func (routeStatusStrategy) ValidateUpdate(ctx apirequest.Context, obj, old runti
218
221
return validation .ValidateRouteStatusUpdate (obj .(* api.Route ), old .(* api.Route ))
219
222
}
220
223
224
+ const emptyDestinationCertificate = `-----BEGIN COMMENT-----
225
+ This is an empty PEM file created to provide backwards compatibility
226
+ for reencrypt routes that have no destinationCACertificate. This
227
+ content will only appear for routes accessed via /oapi/v1/routes.
228
+ -----END COMMENT-----
229
+ `
230
+
231
+ // stripEmptyDestinationCACertificate removes the empty destinationCACertificate if it matches
232
+ // the current route destination CA certificate.
233
+ func stripEmptyDestinationCACertificate (route * api.Route ) {
234
+ tls := route .Spec .TLS
235
+ if tls == nil || tls .Termination != api .TLSTerminationReencrypt {
236
+ return
237
+ }
238
+ if tls .DestinationCACertificate == emptyDestinationCertificate {
239
+ tls .DestinationCACertificate = ""
240
+ }
241
+ }
242
+
243
+ // DecorateLegacyRouteWithEmptyDestinationCACertificates is used for /oapi/v1 route endpoints
244
+ // to prevent legacy clients from seeing an empty destination CA certificate for reencrypt routes,
245
+ // which the 'route.openshift.io/v1' endpoint allows. These values are injected in REST responses
246
+ // and stripped in PrepareForCreate and PrepareForUpdate.
247
+ func DecorateLegacyRouteWithEmptyDestinationCACertificates (obj runtime.Object ) error {
248
+ switch t := obj .(type ) {
249
+ case * api.Route :
250
+ tls := t .Spec .TLS
251
+ if tls == nil || tls .Termination != api .TLSTerminationReencrypt {
252
+ return nil
253
+ }
254
+ if len (tls .DestinationCACertificate ) == 0 {
255
+ tls .DestinationCACertificate = emptyDestinationCertificate
256
+ }
257
+ return nil
258
+ case * api.RouteList :
259
+ for i := range t .Items {
260
+ tls := t .Items [i ].Spec .TLS
261
+ if tls == nil || tls .Termination != api .TLSTerminationReencrypt {
262
+ continue
263
+ }
264
+ if len (tls .DestinationCACertificate ) == 0 {
265
+ tls .DestinationCACertificate = emptyDestinationCertificate
266
+ }
267
+ }
268
+ return nil
269
+ default :
270
+ return fmt .Errorf ("unknown type passed to %T" , obj )
271
+ }
272
+ }
273
+
221
274
// GetAttrs returns labels and fields of a given object for filtering purposes
222
275
func GetAttrs (obj runtime.Object ) (objLabels labels.Set , objFields fields.Set , err error ) {
223
276
route , ok := obj .(* api.Route )
0 commit comments