@@ -18,6 +18,7 @@ package scaleway
1818
1919import (
2020 "encoding/json"
21+ "fmt"
2122 "reflect"
2223 "strings"
2324 "testing"
@@ -1530,6 +1531,181 @@ func TestMakeACLPrefix(t *testing.T) {
15301531 }
15311532}
15321533
1534+ func TestMakeACLSpecs (t * testing.T ) {
1535+ allowACL := & scwlb.ACLAction {Type : scwlb .ACLActionTypeAllow }
1536+ denyACL := & scwlb.ACLAction {Type : scwlb .ACLActionTypeDeny }
1537+ denyAllMatch := & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"0.0.0.0/0" , "::/0" })}
1538+
1539+ t .Run ("no source ranges returns empty acls" , func (t * testing.T ) {
1540+ got := makeACLSpecs (& v1.Service {}, nil , nil )
1541+ want := []* scwlb.ACLSpec {}
1542+ if ! reflect .DeepEqual (got , want ) {
1543+ t .Errorf ("want: %v, got: %v" , want , got )
1544+ }
1545+ })
1546+
1547+ matrix := []struct {
1548+ name string
1549+ sourceRanges []string
1550+ nodes []* v1.Node
1551+ frontend * scwlb.Frontend
1552+ want []* scwlb.ACLSpec
1553+ }{
1554+ {
1555+ name : "ipv4 /32 mask is stripped" ,
1556+ sourceRanges : []string {"1.2.3.4/32" },
1557+ want : []* scwlb.ACLSpec {
1558+ {
1559+ Name : "lb-source-range-0" ,
1560+ Action : allowACL ,
1561+ Index : 0 ,
1562+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"1.2.3.4" })},
1563+ },
1564+ {
1565+ Name : "lb-source-range-end" ,
1566+ Action : denyACL ,
1567+ Index : 1 ,
1568+ Match : denyAllMatch ,
1569+ },
1570+ },
1571+ },
1572+ {
1573+ name : "ipv4 non-/32 mask is kept" ,
1574+ sourceRanges : []string {"10.0.0.0/24" },
1575+ want : []* scwlb.ACLSpec {
1576+ {
1577+ Name : "lb-source-range-0" ,
1578+ Action : allowACL ,
1579+ Index : 0 ,
1580+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"10.0.0.0/24" })},
1581+ },
1582+ {
1583+ Name : "lb-source-range-end" ,
1584+ Action : denyACL ,
1585+ Index : 1 ,
1586+ Match : denyAllMatch ,
1587+ },
1588+ },
1589+ },
1590+ {
1591+ name : "ipv6 /128 mask is stripped" ,
1592+ sourceRanges : []string {"2001:db8::1/128" },
1593+ want : []* scwlb.ACLSpec {
1594+ {
1595+ Name : "lb-source-range-0" ,
1596+ Action : allowACL ,
1597+ Index : 0 ,
1598+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"2001:db8::1" })},
1599+ },
1600+ {
1601+ Name : "lb-source-range-end" ,
1602+ Action : denyACL ,
1603+ Index : 1 ,
1604+ Match : denyAllMatch ,
1605+ },
1606+ },
1607+ },
1608+ {
1609+ name : "ipv6 non-/128 mask is kept" ,
1610+ sourceRanges : []string {"2001:db8::/32" },
1611+ want : []* scwlb.ACLSpec {
1612+ {
1613+ Name : "lb-source-range-0" ,
1614+ Action : allowACL ,
1615+ Index : 0 ,
1616+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"2001:db8::/32" })},
1617+ },
1618+ {
1619+ Name : "lb-source-range-end" ,
1620+ Action : denyACL ,
1621+ Index : 1 ,
1622+ Match : denyAllMatch ,
1623+ },
1624+ },
1625+ },
1626+ {
1627+ name : "invalid CIDR is ignored" ,
1628+ sourceRanges : []string {"not-a-cidr" , "1.2.3.4/32" },
1629+ want : []* scwlb.ACLSpec {
1630+ {
1631+ Name : "lb-source-range-0" ,
1632+ Action : allowACL ,
1633+ Index : 0 ,
1634+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"1.2.3.4" })},
1635+ },
1636+ {
1637+ Name : "lb-source-range-end" ,
1638+ Action : denyACL ,
1639+ Index : 1 ,
1640+ Match : denyAllMatch ,
1641+ },
1642+ },
1643+ },
1644+ {
1645+ name : "source ranges are combined with node ips, sorted, and use the frontend prefix" ,
1646+ sourceRanges : []string {"1.2.3.4/32" },
1647+ nodes : []* v1.Node {
1648+ {Status : v1.NodeStatus {Addresses : []v1.NodeAddress {
1649+ {Type : v1 .NodeInternalIP , Address : "10.0.0.1" },
1650+ {Type : v1 .NodeExternalIP , Address : "51.15.0.1" },
1651+ }}},
1652+ },
1653+ frontend : & scwlb.Frontend {ID : "uid" },
1654+ want : []* scwlb.ACLSpec {
1655+ {
1656+ Name : "uid-lb-source-range-0" ,
1657+ Action : allowACL ,
1658+ Index : 0 ,
1659+ Match : & scwlb.ACLMatch {IPSubnet : scw .StringSlicePtr ([]string {"1.2.3.4" , "10.0.0.1" , "51.15.0.1" })},
1660+ },
1661+ {
1662+ Name : "uid-lb-source-range-end" ,
1663+ Action : denyACL ,
1664+ Index : 1 ,
1665+ Match : denyAllMatch ,
1666+ },
1667+ },
1668+ },
1669+ }
1670+
1671+ for _ , tt := range matrix {
1672+ t .Run (tt .name , func (t * testing.T ) {
1673+ svc := & v1.Service {
1674+ Spec : v1.ServiceSpec {LoadBalancerSourceRanges : tt .sourceRanges },
1675+ }
1676+ got := makeACLSpecs (svc , tt .nodes , tt .frontend )
1677+ if ! reflect .DeepEqual (got , tt .want ) {
1678+ t .Errorf ("want: %v, got: %v" , tt .want , got )
1679+ }
1680+ })
1681+ }
1682+
1683+ t .Run ("whitelist is split into multiple ACL chunks" , func (t * testing.T ) {
1684+ sourceRanges := make ([]string , 0 , MaxEntriesPerACL + 1 )
1685+ for i := 0 ; i <= MaxEntriesPerACL ; i ++ {
1686+ sourceRanges = append (sourceRanges , fmt .Sprintf ("10.0.%d.1/32" , i ))
1687+ }
1688+
1689+ svc := & v1.Service {
1690+ Spec : v1.ServiceSpec {LoadBalancerSourceRanges : sourceRanges },
1691+ }
1692+ got := makeACLSpecs (svc , nil , nil )
1693+
1694+ if len (got ) != 3 {
1695+ t .Fatalf ("expected 3 acls, got %d" , len (got ))
1696+ }
1697+ if got [0 ].Name != "lb-source-range-0" || got [0 ].Index != 0 || len (got [0 ].Match .IPSubnet ) != MaxEntriesPerACL {
1698+ t .Errorf ("unexpected first chunk: %+v" , got [0 ])
1699+ }
1700+ if got [1 ].Name != "lb-source-range-1" || got [1 ].Index != 1 || len (got [1 ].Match .IPSubnet ) != 1 {
1701+ t .Errorf ("unexpected second chunk: %+v" , got [1 ])
1702+ }
1703+ if got [2 ].Name != "lb-source-range-end" || got [2 ].Index != 2 || got [2 ].Action .Type != scwlb .ACLActionTypeDeny {
1704+ t .Errorf ("unexpected last chunk: %+v" , got [2 ])
1705+ }
1706+ })
1707+ }
1708+
15331709func TestGetHTTPHealthCheck (t * testing.T ) {
15341710 matrix := []struct {
15351711 name string
0 commit comments