@@ -22,6 +22,7 @@ import (
22
22
"context"
23
23
"encoding/json"
24
24
"fmt"
25
+ "sort"
25
26
"strconv"
26
27
"strings"
27
28
@@ -48,7 +49,7 @@ func (g *Cloud) ensureInternalLoadBalancer(clusterName, clusterID string, svc *v
48
49
}
49
50
50
51
nm := types.NamespacedName {Name : svc .Name , Namespace : svc .Namespace }
51
- ports , protocol := getPortsAndProtocol (svc .Spec .Ports )
52
+ ports , _ , protocol := getPortsAndProtocol (svc .Spec .Ports )
52
53
if protocol != v1 .ProtocolTCP && protocol != v1 .ProtocolUDP {
53
54
return nil , fmt .Errorf ("Invalid protocol %s, only TCP and UDP are supported" , string (protocol ))
54
55
}
@@ -231,7 +232,7 @@ func (g *Cloud) updateInternalLoadBalancer(clusterName, clusterID string, svc *v
231
232
}
232
233
233
234
// Generate the backend service name
234
- _ , protocol := getPortsAndProtocol (svc .Spec .Ports )
235
+ _ , _ , protocol := getPortsAndProtocol (svc .Spec .Ports )
235
236
scheme := cloud .SchemeInternal
236
237
loadBalancerName := g .GetLoadBalancerName (context .TODO (), clusterName , svc )
237
238
backendServiceName := makeBackendServiceName (loadBalancerName , clusterID , shareBackendService (svc ), scheme , protocol , svc .Spec .SessionAffinity )
@@ -241,7 +242,7 @@ func (g *Cloud) updateInternalLoadBalancer(clusterName, clusterID string, svc *v
241
242
242
243
func (g * Cloud ) ensureInternalLoadBalancerDeleted (clusterName , clusterID string , svc * v1.Service ) error {
243
244
loadBalancerName := g .GetLoadBalancerName (context .TODO (), clusterName , svc )
244
- _ , protocol := getPortsAndProtocol (svc .Spec .Ports )
245
+ _ , _ , protocol := getPortsAndProtocol (svc .Spec .Ports )
245
246
scheme := cloud .SchemeInternal
246
247
sharedBackend := shareBackendService (svc )
247
248
sharedHealthCheck := ! servicehelpers .RequestsOnlyLocalTraffic (svc )
@@ -344,7 +345,7 @@ func (g *Cloud) teardownInternalHealthCheckAndFirewall(svc *v1.Service, hcName s
344
345
return nil
345
346
}
346
347
347
- func (g * Cloud ) ensureInternalFirewall (svc * v1.Service , fwName , fwDesc string , sourceRanges []string , ports []string , protocol v1.Protocol , nodes []* v1.Node , legacyFwName string ) error {
348
+ func (g * Cloud ) ensureInternalFirewall (svc * v1.Service , fwName , fwDesc string , sourceRanges []string , portRanges []string , protocol v1.Protocol , nodes []* v1.Node , legacyFwName string ) error {
348
349
klog .V (2 ).Infof ("ensureInternalFirewall(%v): checking existing firewall" , fwName )
349
350
targetTags , err := g .GetNodeTags (nodeNames (nodes ))
350
351
if err != nil {
@@ -388,7 +389,7 @@ func (g *Cloud) ensureInternalFirewall(svc *v1.Service, fwName, fwDesc string, s
388
389
Allowed : []* compute.FirewallAllowed {
389
390
{
390
391
IPProtocol : strings .ToLower (string (protocol )),
391
- Ports : ports ,
392
+ Ports : portRanges ,
392
393
},
393
394
},
394
395
}
@@ -421,12 +422,12 @@ func (g *Cloud) ensureInternalFirewall(svc *v1.Service, fwName, fwDesc string, s
421
422
func (g * Cloud ) ensureInternalFirewalls (loadBalancerName , ipAddress , clusterID string , nm types.NamespacedName , svc * v1.Service , healthCheckPort string , sharedHealthCheck bool , nodes []* v1.Node ) error {
422
423
// First firewall is for ingress traffic
423
424
fwDesc := makeFirewallDescription (nm .String (), ipAddress )
424
- ports , protocol := getPortsAndProtocol (svc .Spec .Ports )
425
+ _ , portRanges , protocol := getPortsAndProtocol (svc .Spec .Ports )
425
426
sourceRanges , err := servicehelpers .GetLoadBalancerSourceRanges (svc )
426
427
if err != nil {
427
428
return err
428
429
}
429
- err = g .ensureInternalFirewall (svc , MakeFirewallName (loadBalancerName ), fwDesc , sourceRanges .StringSlice (), ports , protocol , nodes , loadBalancerName )
430
+ err = g .ensureInternalFirewall (svc , MakeFirewallName (loadBalancerName ), fwDesc , sourceRanges .StringSlice (), portRanges , protocol , nodes , loadBalancerName )
430
431
if err != nil {
431
432
return err
432
433
}
@@ -747,17 +748,62 @@ func backendSvcEqual(a, b *compute.BackendService) bool {
747
748
backendsListEqual (a .Backends , b .Backends )
748
749
}
749
750
750
- func getPortsAndProtocol (svcPorts []v1.ServicePort ) (ports []string , protocol v1.Protocol ) {
751
+ func getPortsAndProtocol (svcPorts []v1.ServicePort ) (ports []string , portRanges [] string , protocol v1.Protocol ) {
751
752
if len (svcPorts ) == 0 {
752
- return []string {}, v1 .ProtocolUDP
753
+ return []string {}, [] string {}, v1 .ProtocolUDP
753
754
}
754
755
755
756
// GCP doesn't support multiple protocols for a single load balancer
756
757
protocol = svcPorts [0 ].Protocol
758
+ portInts := []int {}
757
759
for _ , p := range svcPorts {
758
760
ports = append (ports , strconv .Itoa (int (p .Port )))
761
+ portInts = append (portInts , int (p .Port ))
759
762
}
760
- return ports , protocol
763
+
764
+ return ports , getPortRanges (portInts ), protocol
765
+ }
766
+
767
+ func getPortRanges (ports []int ) (ranges []string ) {
768
+ if len (ports ) < 1 {
769
+ return ranges
770
+ }
771
+ sort .Ints (ports )
772
+
773
+ start := ports [0 ]
774
+ prev := ports [0 ]
775
+ for ix , current := range ports {
776
+ switch {
777
+ case current == prev :
778
+ // Loop over duplicates, except if the end of list is reached.
779
+ if ix == len (ports )- 1 {
780
+ if start == current {
781
+ ranges = append (ranges , fmt .Sprintf ("%d" , current ))
782
+ } else {
783
+ ranges = append (ranges , fmt .Sprintf ("%d-%d" , start , current ))
784
+ }
785
+ }
786
+ case current == prev + 1 :
787
+ // continue the streak, create the range if this is the last element in the list.
788
+ if ix == len (ports )- 1 {
789
+ ranges = append (ranges , fmt .Sprintf ("%d-%d" , start , current ))
790
+ }
791
+ default :
792
+ // current is not prev + 1, streak is broken. Construct the range and handle last element case.
793
+ if start == prev {
794
+ ranges = append (ranges , fmt .Sprintf ("%d" , prev ))
795
+ } else {
796
+ ranges = append (ranges , fmt .Sprintf ("%d-%d" , start , prev ))
797
+ }
798
+ if ix == len (ports )- 1 {
799
+ ranges = append (ranges , fmt .Sprintf ("%d" , current ))
800
+ }
801
+ // reset start element
802
+ start = current
803
+ }
804
+ prev = current
805
+ }
806
+ return ranges
761
807
}
762
808
763
809
func (g * Cloud ) getBackendServiceLink (name string ) string {
0 commit comments