@@ -105,28 +105,40 @@ func TestTailscaleEgressServices(t *testing.T) {
105105 condition (tsapi .ProxyGroupReady , metav1 .ConditionTrue , "" , "" , clock ),
106106 }
107107 })
108- // Quirks of the fake client.
109- mustUpdateStatus (t , fc , "default" , "test" , func (svc * corev1.Service ) {
110- svc .Status .Conditions = []metav1.Condition {}
108+ expectReconciled (t , esr , "default" , "test" )
109+ validateReadyService (t , fc , esr , svc , clock , zl , cm )
110+ })
111+ t .Run ("service_retain_one_unnamed_port" , func (t * testing.T ) {
112+ svc .Spec .Ports = []corev1.ServicePort {{Protocol : "TCP" , Port : 80 }}
113+ mustUpdate (t , fc , "default" , "test" , func (s * corev1.Service ) {
114+ s .Spec .Ports = svc .Spec .Ports
111115 })
112116 expectReconciled (t , esr , "default" , "test" )
113- // Verify that a ClusterIP Service has been created.
114- name := findGenNameForEgressSvcResources (t , fc , svc )
115- expectEqual (t , fc , clusterIPSvc (name , svc ), removeTargetPortsFromSvc )
116- clusterSvc := mustGetClusterIPSvc (t , fc , name )
117- // Verify that an EndpointSlice has been created.
118- expectEqual (t , fc , endpointSlice (name , svc , clusterSvc ), nil )
119- // Verify that ConfigMap contains configuration for the new egress service.
120- mustHaveConfigForSvc (t , fc , svc , clusterSvc , cm )
121- r := svcConfiguredReason (svc , true , zl .Sugar ())
122- // Verify that the user-created ExternalName Service has Configured set to true and ExternalName pointing to the
123- // CluterIP Service.
124- svc .Status .Conditions = []metav1.Condition {
125- condition (tsapi .EgressSvcConfigured , metav1 .ConditionTrue , r , r , clock ),
126- }
127- svc .ObjectMeta .Finalizers = []string {"tailscale.com/finalizer" }
128- svc .Spec .ExternalName = fmt .Sprintf ("%s.operator-ns.svc.cluster.local" , name )
129- expectEqual (t , fc , svc , nil )
117+ validateReadyService (t , fc , esr , svc , clock , zl , cm )
118+ })
119+ t .Run ("service_add_two_named_ports" , func (t * testing.T ) {
120+ svc .Spec .Ports = []corev1.ServicePort {{Protocol : "TCP" , Port : 80 , Name : "http" }, {Protocol : "TCP" , Port : 443 , Name : "https" }}
121+ mustUpdate (t , fc , "default" , "test" , func (s * corev1.Service ) {
122+ s .Spec .Ports = svc .Spec .Ports
123+ })
124+ expectReconciled (t , esr , "default" , "test" )
125+ validateReadyService (t , fc , esr , svc , clock , zl , cm )
126+ })
127+ t .Run ("service_add_udp_port" , func (t * testing.T ) {
128+ svc .Spec .Ports = append (svc .Spec .Ports , corev1.ServicePort {Port : 53 , Protocol : "UDP" , Name : "dns" })
129+ mustUpdate (t , fc , "default" , "test" , func (s * corev1.Service ) {
130+ s .Spec .Ports = svc .Spec .Ports
131+ })
132+ expectReconciled (t , esr , "default" , "test" )
133+ validateReadyService (t , fc , esr , svc , clock , zl , cm )
134+ })
135+ t .Run ("service_change_protocol" , func (t * testing.T ) {
136+ svc .Spec .Ports = []corev1.ServicePort {{Protocol : "TCP" , Port : 80 , Name : "http" }, {Protocol : "TCP" , Port : 443 , Name : "https" }, {Port : 53 , Protocol : "TCP" , Name : "tcp_dns" }}
137+ mustUpdate (t , fc , "default" , "test" , func (s * corev1.Service ) {
138+ s .Spec .Ports = svc .Spec .Ports
139+ })
140+ expectReconciled (t , esr , "default" , "test" )
141+ validateReadyService (t , fc , esr , svc , clock , zl , cm )
130142 })
131143
132144 t .Run ("delete_external_name_service" , func (t * testing.T ) {
@@ -143,6 +155,29 @@ func TestTailscaleEgressServices(t *testing.T) {
143155 })
144156}
145157
158+ func validateReadyService (t * testing.T , fc client.WithWatch , esr * egressSvcsReconciler , svc * corev1.Service , clock * tstest.Clock , zl * zap.Logger , cm * corev1.ConfigMap ) {
159+ expectReconciled (t , esr , "default" , "test" )
160+ // Verify that a ClusterIP Service has been created.
161+ name := findGenNameForEgressSvcResources (t , fc , svc )
162+ expectEqual (t , fc , clusterIPSvc (name , svc ), removeTargetPortsFromSvc )
163+ clusterSvc := mustGetClusterIPSvc (t , fc , name )
164+ // Verify that an EndpointSlice has been created.
165+ expectEqual (t , fc , endpointSlice (name , svc , clusterSvc ), nil )
166+ // Verify that ConfigMap contains configuration for the new egress service.
167+ mustHaveConfigForSvc (t , fc , svc , clusterSvc , cm )
168+ r := svcConfiguredReason (svc , true , zl .Sugar ())
169+ // Verify that the user-created ExternalName Service has Configured set to true and ExternalName pointing to the
170+ // CluterIP Service.
171+ svc .Status .Conditions = []metav1.Condition {
172+ condition (tsapi .EgressSvcValid , metav1 .ConditionTrue , "EgressSvcValid" , "EgressSvcValid" , clock ),
173+ condition (tsapi .EgressSvcConfigured , metav1 .ConditionTrue , r , r , clock ),
174+ }
175+ svc .ObjectMeta .Finalizers = []string {"tailscale.com/finalizer" }
176+ svc .Spec .ExternalName = fmt .Sprintf ("%s.operator-ns.svc.cluster.local" , name )
177+ expectEqual (t , fc , svc , nil )
178+
179+ }
180+
146181func condition (typ tsapi.ConditionType , st metav1.ConditionStatus , r , msg string , clock tstime.Clock ) metav1.Condition {
147182 return metav1.Condition {
148183 Type : string (typ ),
0 commit comments