@@ -807,6 +807,215 @@ func newGateway(
807807 return gw
808808}
809809
810+ func TestGetDesiredDownstreamGateway_UnclaimedHostnameNoAnnotations (t * testing.T ) {
811+ logger := zap .New (zap .UseFlagOptions (& zap.Options {Development : true }))
812+ ctx := log .IntoContext (context .Background (), logger )
813+
814+ tests := []struct {
815+ name string
816+ perGatewayCertIssuer bool
817+ listeners []gatewayv1.Listener
818+ claimedHostnames []string
819+ expectIssuerAnnotation bool
820+ expectClusterAnnotation bool
821+ expectListeners int
822+ }{
823+ {
824+ name : "unclaimed hostname with TLS option does not produce annotations" ,
825+ perGatewayCertIssuer : true ,
826+ listeners : []gatewayv1.Listener {
827+ {
828+ Name : "custom-https" ,
829+ Port : 443 ,
830+ Protocol : gatewayv1 .HTTPSProtocolType ,
831+ Hostname : ptr .To (gatewayv1 .Hostname ("unclaimed.example.com" )),
832+ TLS : & gatewayv1.GatewayTLSConfig {
833+ Options : map [gatewayv1.AnnotationKey ]gatewayv1.AnnotationValue {
834+ certificateIssuerTLSOption : "letsencrypt" ,
835+ },
836+ },
837+ },
838+ },
839+ claimedHostnames : nil ,
840+ expectIssuerAnnotation : false ,
841+ expectClusterAnnotation : false ,
842+ expectListeners : 0 ,
843+ },
844+ {
845+ name : "claimed hostname with TLS option produces issuer annotation (per-gateway mode)" ,
846+ perGatewayCertIssuer : true ,
847+ listeners : []gatewayv1.Listener {
848+ {
849+ Name : "custom-https" ,
850+ Port : 443 ,
851+ Protocol : gatewayv1 .HTTPSProtocolType ,
852+ Hostname : ptr .To (gatewayv1 .Hostname ("claimed.example.com" )),
853+ TLS : & gatewayv1.GatewayTLSConfig {
854+ Options : map [gatewayv1.AnnotationKey ]gatewayv1.AnnotationValue {
855+ certificateIssuerTLSOption : "letsencrypt" ,
856+ },
857+ },
858+ },
859+ },
860+ claimedHostnames : []string {"claimed.example.com" },
861+ expectIssuerAnnotation : true ,
862+ expectClusterAnnotation : false ,
863+ expectListeners : 1 ,
864+ },
865+ {
866+ name : "claimed hostname with TLS option produces cluster-issuer annotation (cluster mode)" ,
867+ perGatewayCertIssuer : false ,
868+ listeners : []gatewayv1.Listener {
869+ {
870+ Name : "custom-https" ,
871+ Port : 443 ,
872+ Protocol : gatewayv1 .HTTPSProtocolType ,
873+ Hostname : ptr .To (gatewayv1 .Hostname ("claimed.example.com" )),
874+ TLS : & gatewayv1.GatewayTLSConfig {
875+ Options : map [gatewayv1.AnnotationKey ]gatewayv1.AnnotationValue {
876+ certificateIssuerTLSOption : "letsencrypt" ,
877+ },
878+ },
879+ },
880+ },
881+ claimedHostnames : []string {"claimed.example.com" },
882+ expectIssuerAnnotation : false ,
883+ expectClusterAnnotation : true ,
884+ expectListeners : 1 ,
885+ },
886+ {
887+ name : "mix: only claimed hostname contributes annotations" ,
888+ perGatewayCertIssuer : true ,
889+ listeners : []gatewayv1.Listener {
890+ {
891+ Name : "unclaimed-https" ,
892+ Port : 443 ,
893+ Protocol : gatewayv1 .HTTPSProtocolType ,
894+ Hostname : ptr .To (gatewayv1 .Hostname ("unclaimed.example.com" )),
895+ TLS : & gatewayv1.GatewayTLSConfig {
896+ Options : map [gatewayv1.AnnotationKey ]gatewayv1.AnnotationValue {
897+ certificateIssuerTLSOption : "letsencrypt" ,
898+ },
899+ },
900+ },
901+ {
902+ Name : "claimed-https" ,
903+ Port : 443 ,
904+ Protocol : gatewayv1 .HTTPSProtocolType ,
905+ Hostname : ptr .To (gatewayv1 .Hostname ("claimed.example.com" )),
906+ TLS : & gatewayv1.GatewayTLSConfig {
907+ Options : map [gatewayv1.AnnotationKey ]gatewayv1.AnnotationValue {
908+ certificateIssuerTLSOption : "letsencrypt" ,
909+ },
910+ },
911+ },
912+ },
913+ claimedHostnames : []string {"claimed.example.com" },
914+ expectIssuerAnnotation : true ,
915+ expectClusterAnnotation : false ,
916+ expectListeners : 1 ,
917+ },
918+ }
919+
920+ for _ , tt := range tests {
921+ t .Run (tt .name , func (t * testing.T ) {
922+ reconciler := & GatewayReconciler {
923+ Config : config.NetworkServicesOperator {
924+ Gateway : config.GatewayConfig {
925+ DownstreamGatewayClassName : "envoy" ,
926+ PerGatewayCertificateIssuer : tt .perGatewayCertIssuer ,
927+ },
928+ },
929+ }
930+
931+ upstream := & gatewayv1.Gateway {
932+ ObjectMeta : metav1.ObjectMeta {Name : "test-gw" , Namespace : "default" },
933+ Spec : gatewayv1.GatewaySpec {Listeners : tt .listeners },
934+ }
935+
936+ desired := reconciler .getDesiredDownstreamGateway (ctx , "test-cluster" , upstream , tt .claimedHostnames )
937+
938+ _ , hasIssuer := desired .Annotations ["cert-manager.io/issuer" ]
939+ _ , hasClusterIssuer := desired .Annotations ["cert-manager.io/cluster-issuer" ]
940+
941+ assert .Equal (t , tt .expectIssuerAnnotation , hasIssuer , "cert-manager.io/issuer annotation presence" )
942+ assert .Equal (t , tt .expectClusterAnnotation , hasClusterIssuer , "cert-manager.io/cluster-issuer annotation presence" )
943+ assert .Len (t , desired .Spec .Listeners , tt .expectListeners , "downstream listener count" )
944+ })
945+ }
946+ }
947+
948+ func TestSyncCertManagerAnnotations (t * testing.T ) {
949+ t .Parallel ()
950+
951+ tests := []struct {
952+ name string
953+ existingAnnotations map [string ]string
954+ desiredAnnotations map [string ]string
955+ wantAnnotations map [string ]string
956+ }{
957+ {
958+ name : "stale issuer annotation removed" ,
959+ existingAnnotations : map [string ]string {
960+ "cert-manager.io/issuer" : "old-issuer" ,
961+ "other-annotation" : "keep-me" ,
962+ },
963+ desiredAnnotations : map [string ]string {},
964+ wantAnnotations : map [string ]string {
965+ "other-annotation" : "keep-me" ,
966+ },
967+ },
968+ {
969+ name : "issuer annotation updated to cluster-issuer" ,
970+ existingAnnotations : map [string ]string {
971+ "cert-manager.io/issuer" : "old-issuer" ,
972+ },
973+ desiredAnnotations : map [string ]string {
974+ "cert-manager.io/cluster-issuer" : "new-cluster-issuer" ,
975+ },
976+ wantAnnotations : map [string ]string {
977+ "cert-manager.io/cluster-issuer" : "new-cluster-issuer" ,
978+ },
979+ },
980+ {
981+ name : "no-op when annotations match" ,
982+ existingAnnotations : map [string ]string {"cert-manager.io/issuer" : "my-issuer" },
983+ desiredAnnotations : map [string ]string {"cert-manager.io/issuer" : "my-issuer" },
984+ wantAnnotations : map [string ]string {"cert-manager.io/issuer" : "my-issuer" },
985+ },
986+ {
987+ name : "all three cert-manager annotations cleaned up" ,
988+ existingAnnotations : map [string ]string {
989+ "cert-manager.io/issuer" : "old" ,
990+ "cert-manager.io/cluster-issuer" : "old" ,
991+ "cert-manager.io/secret-template" : "old" ,
992+ "unrelated" : "preserved" ,
993+ },
994+ desiredAnnotations : map [string ]string {},
995+ wantAnnotations : map [string ]string {
996+ "unrelated" : "preserved" ,
997+ },
998+ },
999+ }
1000+
1001+ for _ , tt := range tests {
1002+ t .Run (tt .name , func (t * testing.T ) {
1003+ t .Parallel ()
1004+
1005+ existing := & gatewayv1.Gateway {
1006+ ObjectMeta : metav1.ObjectMeta {Annotations : tt .existingAnnotations },
1007+ }
1008+ desired := & gatewayv1.Gateway {
1009+ ObjectMeta : metav1.ObjectMeta {Annotations : tt .desiredAnnotations },
1010+ }
1011+
1012+ syncCertManagerAnnotations (existing , desired )
1013+
1014+ assert .Equal (t , tt .wantAnnotations , existing .Annotations )
1015+ })
1016+ }
1017+ }
1018+
8101019func newHTTPRoute (namespace , name string , opts ... func (* gatewayv1.HTTPRoute )) * gatewayv1.HTTPRoute {
8111020 route := & gatewayv1.HTTPRoute {
8121021 ObjectMeta : metav1.ObjectMeta {
0 commit comments