sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/loadbalancers/spec_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package loadbalancers 18 19 import ( 20 "context" 21 "testing" 22 23 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" 24 . "github.com/onsi/gomega" 25 "k8s.io/utils/ptr" 26 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 27 ) 28 29 func getExistingLBWithMissingFrontendIPConfigs() armnetwork.LoadBalancer { 30 existingLB := newSamplePublicAPIServerLB(false, true, true, true, true) 31 existingLB.Properties.FrontendIPConfigurations = []*armnetwork.FrontendIPConfiguration{} 32 33 return existingLB 34 } 35 36 func getExistingLBWithMissingBackendPool() armnetwork.LoadBalancer { 37 existingLB := newSamplePublicAPIServerLB(true, false, true, true, true) 38 existingLB.Properties.BackendAddressPools = []*armnetwork.BackendAddressPool{} 39 40 return existingLB 41 } 42 43 func getExistingLBWithMissingLBRules() armnetwork.LoadBalancer { 44 existingLB := newSamplePublicAPIServerLB(true, true, false, true, true) 45 existingLB.Properties.LoadBalancingRules = []*armnetwork.LoadBalancingRule{} 46 47 return existingLB 48 } 49 50 func getExistingLBWithMissingProbes() armnetwork.LoadBalancer { 51 existingLB := newSamplePublicAPIServerLB(true, true, true, false, true) 52 existingLB.Properties.Probes = []*armnetwork.Probe{} 53 54 return existingLB 55 } 56 57 func getExistingLBWithMissingOutboundRules() armnetwork.LoadBalancer { 58 existingLB := newSamplePublicAPIServerLB(true, true, true, true, false) 59 existingLB.Properties.OutboundRules = []*armnetwork.OutboundRule{} 60 61 return existingLB 62 } 63 64 func TestParameters(t *testing.T) { 65 testcases := []struct { 66 name string 67 spec *LBSpec 68 existing interface{} 69 expect func(g *WithT, result interface{}) 70 expectedError string 71 }{ 72 { 73 name: "public API load balancer exists with all expected values", 74 spec: &fakePublicAPILBSpec, 75 existing: newSamplePublicAPIServerLB(false, false, false, false, false), 76 expect: func(g *WithT, result interface{}) { 77 g.Expect(result).To(BeNil()) 78 }, 79 expectedError: "", 80 }, 81 { 82 name: "internal API load balancer with all expected values", 83 spec: &fakeInternalAPILBSpec, 84 existing: newDefaultInternalAPIServerLB(), 85 expect: func(g *WithT, result interface{}) { 86 g.Expect(result).To(BeNil()) 87 }, 88 expectedError: "", 89 }, 90 { 91 name: "node outbound load balancer exists with all expected values", 92 spec: &fakeNodeOutboundLBSpec, 93 existing: newDefaultNodeOutboundLB(), 94 expect: func(g *WithT, result interface{}) { 95 g.Expect(result).To(BeNil()) 96 }, 97 expectedError: "", 98 }, 99 { 100 name: "load balancer exists with missing frontend IP configs", 101 spec: &fakePublicAPILBSpec, 102 existing: getExistingLBWithMissingFrontendIPConfigs(), 103 expect: func(g *WithT, result interface{}) { 104 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.LoadBalancer{})) 105 g.Expect(result.(armnetwork.LoadBalancer)).To(Equal(newSamplePublicAPIServerLB(false, true, true, true, true))) 106 }, 107 expectedError: "", 108 }, 109 { 110 name: "load balancer exists with missing backend pool", 111 spec: &fakePublicAPILBSpec, 112 existing: getExistingLBWithMissingBackendPool(), 113 expect: func(g *WithT, result interface{}) { 114 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.LoadBalancer{})) 115 g.Expect(result.(armnetwork.LoadBalancer)).To(Equal(newSamplePublicAPIServerLB(true, false, true, true, true))) 116 }, 117 expectedError: "", 118 }, 119 { 120 name: "load balancer exists with missing load balancing rules", 121 spec: &fakePublicAPILBSpec, 122 existing: getExistingLBWithMissingLBRules(), 123 expect: func(g *WithT, result interface{}) { 124 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.LoadBalancer{})) 125 g.Expect(result.(armnetwork.LoadBalancer)).To(Equal(newSamplePublicAPIServerLB(true, true, false, true, true))) 126 }, 127 expectedError: "", 128 }, 129 { 130 name: "load balancer exists with missing probes", 131 spec: &fakePublicAPILBSpec, 132 existing: getExistingLBWithMissingProbes(), 133 expect: func(g *WithT, result interface{}) { 134 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.LoadBalancer{})) 135 g.Expect(result.(armnetwork.LoadBalancer)).To(Equal(newSamplePublicAPIServerLB(true, true, true, false, true))) 136 }, 137 expectedError: "", 138 }, 139 { 140 name: "load balancer exists with missing outbound rules", 141 spec: &fakePublicAPILBSpec, 142 existing: getExistingLBWithMissingOutboundRules(), 143 expect: func(g *WithT, result interface{}) { 144 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.LoadBalancer{})) 145 g.Expect(result.(armnetwork.LoadBalancer)).To(Equal(newSamplePublicAPIServerLB(true, true, true, true, false))) 146 }, 147 expectedError: "", 148 }, 149 } 150 for _, tc := range testcases { 151 tc := tc 152 t.Run(tc.name, func(t *testing.T) { 153 g := NewWithT(t) 154 t.Parallel() 155 156 result, err := tc.spec.Parameters(context.TODO(), tc.existing) 157 if tc.expectedError != "" { 158 g.Expect(err).To(HaveOccurred()) 159 g.Expect(err).To(MatchError(tc.expectedError)) 160 } else { 161 g.Expect(err).NotTo(HaveOccurred()) 162 } 163 tc.expect(g, result) 164 }) 165 } 166 } 167 168 func newDefaultNodeOutboundLB() armnetwork.LoadBalancer { 169 return armnetwork.LoadBalancer{ 170 Tags: map[string]*string{ 171 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 172 "sigs.k8s.io_cluster-api-provider-azure_role": ptr.To(infrav1.NodeOutboundRole), 173 }, 174 SKU: &armnetwork.LoadBalancerSKU{Name: ptr.To(armnetwork.LoadBalancerSKUNameStandard)}, 175 Location: ptr.To("my-location"), 176 Properties: &armnetwork.LoadBalancerPropertiesFormat{ 177 FrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{ 178 { 179 Name: ptr.To("my-cluster-frontEnd"), 180 Properties: &armnetwork.FrontendIPConfigurationPropertiesFormat{ 181 PublicIPAddress: &armnetwork.PublicIPAddress{ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/publicIPAddresses/outbound-publicip")}, 182 }, 183 }, 184 }, 185 BackendAddressPools: []*armnetwork.BackendAddressPool{ 186 { 187 Name: ptr.To("my-cluster-outboundBackendPool"), 188 }, 189 }, 190 LoadBalancingRules: []*armnetwork.LoadBalancingRule{}, 191 Probes: []*armnetwork.Probe{}, 192 OutboundRules: []*armnetwork.OutboundRule{ 193 { 194 Name: ptr.To("OutboundNATAllProtocols"), 195 Properties: &armnetwork.OutboundRulePropertiesFormat{ 196 FrontendIPConfigurations: []*armnetwork.SubResource{ 197 {ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-cluster/frontendIPConfigurations/my-cluster-frontEnd")}, 198 }, 199 BackendAddressPool: &armnetwork.SubResource{ 200 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-cluster/backendAddressPools/my-cluster-outboundBackendPool"), 201 }, 202 Protocol: ptr.To(armnetwork.LoadBalancerOutboundRuleProtocolAll), 203 IdleTimeoutInMinutes: ptr.To[int32](30), 204 }, 205 }, 206 }, 207 }, 208 } 209 } 210 211 func newSamplePublicAPIServerLB(verifyFrontendIP bool, verifyBackendAddressPools bool, verifyLBRules bool, verifyProbes bool, verifyOutboundRules bool) armnetwork.LoadBalancer { 212 var subnet *armnetwork.Subnet 213 var backendAddressPoolProps *armnetwork.BackendAddressPoolPropertiesFormat 214 enableFloatingIP := ptr.To(false) 215 numProbes := ptr.To[int32](4) 216 idleTimeout := ptr.To[int32](4) 217 218 if verifyFrontendIP { 219 subnet = &armnetwork.Subnet{ 220 Name: ptr.To("fake-test-subnet"), 221 } 222 } 223 if verifyBackendAddressPools { 224 backendAddressPoolProps = &armnetwork.BackendAddressPoolPropertiesFormat{ 225 Location: ptr.To("fake-test-location"), 226 } 227 } 228 if verifyLBRules { 229 enableFloatingIP = ptr.To(true) 230 } 231 if verifyProbes { 232 numProbes = ptr.To[int32](999) 233 } 234 if verifyOutboundRules { 235 idleTimeout = ptr.To[int32](1000) 236 } 237 238 return armnetwork.LoadBalancer{ 239 Tags: map[string]*string{ 240 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 241 "sigs.k8s.io_cluster-api-provider-azure_role": ptr.To(infrav1.APIServerRole), 242 }, 243 SKU: &armnetwork.LoadBalancerSKU{Name: ptr.To(armnetwork.LoadBalancerSKUNameStandard)}, 244 Location: ptr.To("my-location"), 245 Properties: &armnetwork.LoadBalancerPropertiesFormat{ 246 FrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{ 247 { 248 Name: ptr.To("my-publiclb-frontEnd"), 249 Properties: &armnetwork.FrontendIPConfigurationPropertiesFormat{ 250 PublicIPAddress: &armnetwork.PublicIPAddress{ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/publicIPAddresses/my-publicip")}, 251 Subnet: subnet, // Add to verify that FrontendIPConfigurations aren't overwritten on update 252 }, 253 }, 254 }, 255 BackendAddressPools: []*armnetwork.BackendAddressPool{ 256 { 257 Name: ptr.To("my-publiclb-backendPool"), 258 Properties: backendAddressPoolProps, // Add to verify that BackendAddressPools aren't overwritten on update 259 }, 260 }, 261 LoadBalancingRules: []*armnetwork.LoadBalancingRule{ 262 { 263 Name: ptr.To(lbRuleHTTPS), 264 Properties: &armnetwork.LoadBalancingRulePropertiesFormat{ 265 DisableOutboundSnat: ptr.To(true), 266 Protocol: ptr.To(armnetwork.TransportProtocolTCP), 267 FrontendPort: ptr.To[int32](6443), 268 BackendPort: ptr.To[int32](6443), 269 IdleTimeoutInMinutes: ptr.To[int32](4), 270 EnableFloatingIP: enableFloatingIP, // Add to verify that LoadBalancingRules aren't overwritten on update 271 LoadDistribution: ptr.To(armnetwork.LoadDistributionDefault), 272 FrontendIPConfiguration: &armnetwork.SubResource{ 273 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-publiclb/frontendIPConfigurations/my-publiclb-frontEnd"), 274 }, 275 BackendAddressPool: &armnetwork.SubResource{ 276 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-publiclb/backendAddressPools/my-publiclb-backendPool"), 277 }, 278 Probe: &armnetwork.SubResource{ 279 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-publiclb/probes/HTTPSProbe"), 280 }, 281 }, 282 }, 283 }, 284 Probes: []*armnetwork.Probe{ 285 { 286 Name: ptr.To(httpsProbe), 287 Properties: &armnetwork.ProbePropertiesFormat{ 288 Protocol: ptr.To(armnetwork.ProbeProtocolHTTPS), 289 Port: ptr.To[int32](6443), 290 RequestPath: ptr.To(httpsProbeRequestPath), 291 IntervalInSeconds: ptr.To[int32](15), 292 NumberOfProbes: numProbes, // Add to verify that Probes aren't overwritten on update 293 }, 294 }, 295 }, 296 OutboundRules: []*armnetwork.OutboundRule{ 297 { 298 Name: ptr.To("OutboundNATAllProtocols"), 299 Properties: &armnetwork.OutboundRulePropertiesFormat{ 300 FrontendIPConfigurations: []*armnetwork.SubResource{ 301 {ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-publiclb/frontendIPConfigurations/my-publiclb-frontEnd")}, 302 }, 303 BackendAddressPool: &armnetwork.SubResource{ 304 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-publiclb/backendAddressPools/my-publiclb-backendPool"), 305 }, 306 Protocol: ptr.To(armnetwork.LoadBalancerOutboundRuleProtocolAll), 307 IdleTimeoutInMinutes: idleTimeout, // Add to verify that OutboundRules aren't overwritten on update 308 }, 309 }, 310 }, 311 }, 312 } 313 } 314 315 func newDefaultInternalAPIServerLB() armnetwork.LoadBalancer { 316 return armnetwork.LoadBalancer{ 317 Tags: map[string]*string{ 318 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 319 "sigs.k8s.io_cluster-api-provider-azure_role": ptr.To(infrav1.APIServerRole), 320 }, 321 SKU: &armnetwork.LoadBalancerSKU{Name: ptr.To(armnetwork.LoadBalancerSKUNameStandard)}, 322 Location: ptr.To("my-location"), 323 Properties: &armnetwork.LoadBalancerPropertiesFormat{ 324 FrontendIPConfigurations: []*armnetwork.FrontendIPConfiguration{ 325 { 326 Name: ptr.To("my-private-lb-frontEnd"), 327 Properties: &armnetwork.FrontendIPConfigurationPropertiesFormat{ 328 PrivateIPAllocationMethod: ptr.To(armnetwork.IPAllocationMethodStatic), 329 Subnet: &armnetwork.Subnet{ 330 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/virtualNetworks/my-vnet/subnets/my-cp-subnet"), 331 }, 332 PrivateIPAddress: ptr.To("10.0.0.10"), 333 }, 334 }, 335 }, 336 BackendAddressPools: []*armnetwork.BackendAddressPool{ 337 { 338 Name: ptr.To("my-private-lb-backendPool"), 339 }, 340 }, 341 LoadBalancingRules: []*armnetwork.LoadBalancingRule{ 342 { 343 Name: ptr.To(lbRuleHTTPS), 344 Properties: &armnetwork.LoadBalancingRulePropertiesFormat{ 345 DisableOutboundSnat: ptr.To(true), 346 Protocol: ptr.To(armnetwork.TransportProtocolTCP), 347 FrontendPort: ptr.To[int32](6443), 348 BackendPort: ptr.To[int32](6443), 349 IdleTimeoutInMinutes: ptr.To[int32](4), 350 EnableFloatingIP: ptr.To(false), 351 LoadDistribution: ptr.To(armnetwork.LoadDistributionDefault), 352 FrontendIPConfiguration: &armnetwork.SubResource{ 353 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-private-lb/frontendIPConfigurations/my-private-lb-frontEnd"), 354 }, 355 BackendAddressPool: &armnetwork.SubResource{ 356 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-private-lb/backendAddressPools/my-private-lb-backendPool"), 357 }, 358 Probe: &armnetwork.SubResource{ 359 ID: ptr.To("/subscriptions/123/resourceGroups/my-rg/providers/Microsoft.Network/loadBalancers/my-private-lb/probes/HTTPSProbe"), 360 }, 361 }, 362 }, 363 }, 364 OutboundRules: []*armnetwork.OutboundRule{}, 365 Probes: []*armnetwork.Probe{ 366 { 367 Name: ptr.To(httpsProbe), 368 Properties: &armnetwork.ProbePropertiesFormat{ 369 Protocol: ptr.To(armnetwork.ProbeProtocolHTTPS), 370 Port: ptr.To[int32](6443), 371 RequestPath: ptr.To(httpsProbeRequestPath), 372 IntervalInSeconds: ptr.To[int32](15), 373 NumberOfProbes: ptr.To[int32](4), 374 }, 375 }, 376 }, 377 }, 378 } 379 }