@@ -216,4 +216,289 @@ var _ = Describe("KeystoneAPI Webhook", func() {
216216 "spec.topologyRef.namespace: Invalid value: \" namespace\" : Customizing namespace field is not supported" ),
217217 )
218218 })
219+
220+ When ("ExternalKeystoneAPI validation" , func () {
221+ It ("rejects ExternalKeystoneAPI=true with nil service override" , func () {
222+ spec := GetDefaultKeystoneAPISpec ()
223+ spec ["externalKeystoneAPI" ] = true
224+ // Don't set any override
225+
226+ raw := map [string ]any {
227+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
228+ "kind" : "KeystoneAPI" ,
229+ "metadata" : map [string ]any {
230+ "name" : keystoneAPIName .Name ,
231+ "namespace" : keystoneAPIName .Namespace ,
232+ },
233+ "spec" : spec ,
234+ }
235+
236+ unstructuredObj := & unstructured.Unstructured {Object : raw }
237+ _ , err := controllerutil .CreateOrPatch (
238+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
239+ Expect (err ).To (HaveOccurred ())
240+ Expect (err .Error ()).To (
241+ ContainSubstring (
242+ "external Keystone API requires service override configuration" ),
243+ )
244+ })
245+
246+ It ("rejects ExternalKeystoneAPI=true with empty service override" , func () {
247+ spec := GetDefaultKeystoneAPISpec ()
248+ spec ["externalKeystoneAPI" ] = true
249+ spec ["override" ] = map [string ]any {
250+ "service" : map [string ]any {},
251+ }
252+
253+ raw := map [string ]any {
254+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
255+ "kind" : "KeystoneAPI" ,
256+ "metadata" : map [string ]any {
257+ "name" : keystoneAPIName .Name ,
258+ "namespace" : keystoneAPIName .Namespace ,
259+ },
260+ "spec" : spec ,
261+ }
262+
263+ unstructuredObj := & unstructured.Unstructured {Object : raw }
264+ _ , err := controllerutil .CreateOrPatch (
265+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
266+ Expect (err ).To (HaveOccurred ())
267+ Expect (err .Error ()).To (
268+ ContainSubstring (
269+ "external Keystone API requires service override configuration" ),
270+ )
271+ })
272+
273+ It ("rejects ExternalKeystoneAPI=true with service override but no endpoints" , func () {
274+ spec := GetDefaultKeystoneAPISpec ()
275+ spec ["externalKeystoneAPI" ] = true
276+ spec ["override" ] = map [string ]any {
277+ "service" : map [string ]any {
278+ "admin" : map [string ]any {
279+ "metadata" : map [string ]any {
280+ "labels" : map [string ]any {
281+ "custom" : "label" ,
282+ },
283+ },
284+ },
285+ },
286+ }
287+
288+ raw := map [string ]any {
289+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
290+ "kind" : "KeystoneAPI" ,
291+ "metadata" : map [string ]any {
292+ "name" : keystoneAPIName .Name ,
293+ "namespace" : keystoneAPIName .Namespace ,
294+ },
295+ "spec" : spec ,
296+ }
297+
298+ unstructuredObj := & unstructured.Unstructured {Object : raw }
299+ _ , err := controllerutil .CreateOrPatch (
300+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
301+ Expect (err ).To (HaveOccurred ())
302+ Expect (err .Error ()).To (
303+ ContainSubstring (
304+ "external Keystone API requires public endpoint to be defined" ),
305+ )
306+ })
307+
308+ It ("rejects ExternalKeystoneAPI=true with missing public endpoint" , func () {
309+ spec := GetDefaultKeystoneAPISpec ()
310+ spec ["externalKeystoneAPI" ] = true
311+ spec ["override" ] = map [string ]any {
312+ "service" : map [string ]any {
313+ "internal" : map [string ]any {
314+ "endpointURL" : "http://internal.keystone.example.com:5000" ,
315+ },
316+ },
317+ }
318+
319+ raw := map [string ]any {
320+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
321+ "kind" : "KeystoneAPI" ,
322+ "metadata" : map [string ]any {
323+ "name" : keystoneAPIName .Name ,
324+ "namespace" : keystoneAPIName .Namespace ,
325+ },
326+ "spec" : spec ,
327+ }
328+
329+ unstructuredObj := & unstructured.Unstructured {Object : raw }
330+ _ , err := controllerutil .CreateOrPatch (
331+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
332+ Expect (err ).To (HaveOccurred ())
333+ Expect (err .Error ()).To (
334+ ContainSubstring (
335+ "external Keystone API requires public endpoint to be defined" ),
336+ )
337+ })
338+
339+ It ("rejects ExternalKeystoneAPI=true with missing internal endpoint" , func () {
340+ spec := GetDefaultKeystoneAPISpec ()
341+ spec ["externalKeystoneAPI" ] = true
342+ spec ["override" ] = map [string ]any {
343+ "service" : map [string ]any {
344+ "public" : map [string ]any {
345+ "endpointURL" : "http://public.keystone.example.com:5000" ,
346+ },
347+ },
348+ }
349+
350+ raw := map [string ]any {
351+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
352+ "kind" : "KeystoneAPI" ,
353+ "metadata" : map [string ]any {
354+ "name" : keystoneAPIName .Name ,
355+ "namespace" : keystoneAPIName .Namespace ,
356+ },
357+ "spec" : spec ,
358+ }
359+
360+ unstructuredObj := & unstructured.Unstructured {Object : raw }
361+ _ , err := controllerutil .CreateOrPatch (
362+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
363+ Expect (err ).To (HaveOccurred ())
364+ Expect (err .Error ()).To (
365+ ContainSubstring (
366+ "external Keystone API requires internal endpoint to be defined" ),
367+ )
368+ })
369+
370+ It ("rejects ExternalKeystoneAPI=true with empty endpointURL" , func () {
371+ spec := GetDefaultKeystoneAPISpec ()
372+ spec ["externalKeystoneAPI" ] = true
373+ spec ["override" ] = map [string ]any {
374+ "service" : map [string ]any {
375+ "public" : map [string ]any {
376+ "endpointURL" : "" ,
377+ },
378+ "internal" : map [string ]any {
379+ "endpointURL" : "http://internal.keystone.example.com:5000" ,
380+ },
381+ },
382+ }
383+
384+ raw := map [string ]any {
385+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
386+ "kind" : "KeystoneAPI" ,
387+ "metadata" : map [string ]any {
388+ "name" : keystoneAPIName .Name ,
389+ "namespace" : keystoneAPIName .Namespace ,
390+ },
391+ "spec" : spec ,
392+ }
393+
394+ unstructuredObj := & unstructured.Unstructured {Object : raw }
395+ _ , err := controllerutil .CreateOrPatch (
396+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
397+ Expect (err ).To (HaveOccurred ())
398+ Expect (err .Error ()).To (
399+ ContainSubstring (
400+ "external Keystone API requires endpointURL to be set for public endpoint" ),
401+ )
402+ })
403+
404+ It ("rejects ExternalKeystoneAPI=true with invalid URL format for public endpoint" , func () {
405+ spec := GetDefaultKeystoneAPISpec ()
406+ spec ["externalKeystoneAPI" ] = true
407+ spec ["override" ] = map [string ]any {
408+ "service" : map [string ]any {
409+ "public" : map [string ]any {
410+ "endpointURL" : "not-a-valid-url" ,
411+ },
412+ "internal" : map [string ]any {
413+ "endpointURL" : "http://internal.keystone.example.com:5000" ,
414+ },
415+ },
416+ }
417+
418+ raw := map [string ]any {
419+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
420+ "kind" : "KeystoneAPI" ,
421+ "metadata" : map [string ]any {
422+ "name" : keystoneAPIName .Name ,
423+ "namespace" : keystoneAPIName .Namespace ,
424+ },
425+ "spec" : spec ,
426+ }
427+
428+ unstructuredObj := & unstructured.Unstructured {Object : raw }
429+ _ , err := controllerutil .CreateOrPatch (
430+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
431+ Expect (err ).To (HaveOccurred ())
432+ Expect (err .Error ()).To (
433+ ContainSubstring (
434+ "URL must include a scheme" ),
435+ )
436+ })
437+
438+ It ("rejects ExternalKeystoneAPI=true with invalid URL format for internal endpoint" , func () {
439+ spec := GetDefaultKeystoneAPISpec ()
440+ spec ["externalKeystoneAPI" ] = true
441+ spec ["override" ] = map [string ]any {
442+ "service" : map [string ]any {
443+ "public" : map [string ]any {
444+ "endpointURL" : "http://public.keystone.example.com:5000" ,
445+ },
446+ "internal" : map [string ]any {
447+ "endpointURL" : "://invalid-url" ,
448+ },
449+ },
450+ }
451+
452+ raw := map [string ]any {
453+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
454+ "kind" : "KeystoneAPI" ,
455+ "metadata" : map [string ]any {
456+ "name" : keystoneAPIName .Name ,
457+ "namespace" : keystoneAPIName .Namespace ,
458+ },
459+ "spec" : spec ,
460+ }
461+
462+ unstructuredObj := & unstructured.Unstructured {Object : raw }
463+ _ , err := controllerutil .CreateOrPatch (
464+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
465+ Expect (err ).To (HaveOccurred ())
466+ Expect (err .Error ()).To (
467+ Or (
468+ ContainSubstring ("invalid URL format" ),
469+ ContainSubstring ("URL must include a scheme" ),
470+ ),
471+ )
472+ })
473+
474+ It ("accepts ExternalKeystoneAPI=true with valid endpoints" , func () {
475+ spec := GetDefaultKeystoneAPISpec ()
476+ spec ["externalKeystoneAPI" ] = true
477+ spec ["override" ] = map [string ]any {
478+ "service" : map [string ]any {
479+ "public" : map [string ]any {
480+ "endpointURL" : "http://public.keystone.example.com:5000" ,
481+ },
482+ "internal" : map [string ]any {
483+ "endpointURL" : "http://internal.keystone.example.com:5000" ,
484+ },
485+ },
486+ }
487+
488+ raw := map [string ]any {
489+ "apiVersion" : "keystone.openstack.org/v1beta1" ,
490+ "kind" : "KeystoneAPI" ,
491+ "metadata" : map [string ]any {
492+ "name" : keystoneAPIName .Name ,
493+ "namespace" : keystoneAPIName .Namespace ,
494+ },
495+ "spec" : spec ,
496+ }
497+
498+ unstructuredObj := & unstructured.Unstructured {Object : raw }
499+ _ , err := controllerutil .CreateOrPatch (
500+ th .Ctx , th .K8sClient , unstructuredObj , func () error { return nil })
501+ Expect (err ).NotTo (HaveOccurred ())
502+ })
503+ })
219504})
0 commit comments