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