sigs.k8s.io/cluster-api-provider-azure@v1.14.3/azure/services/securitygroups/spec_test.go (about) 1 /* 2 Copyright 2022 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 securitygroups 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 "sigs.k8s.io/cluster-api-provider-azure/azure/converters" 28 ) 29 30 var ( 31 sshRule = infrav1.SecurityRule{ 32 Name: "allow_ssh", 33 Description: "Allow SSH", 34 Priority: 2200, 35 Protocol: infrav1.SecurityGroupProtocolTCP, 36 Direction: infrav1.SecurityRuleDirectionInbound, 37 Source: ptr.To("*"), 38 SourcePorts: ptr.To("*"), 39 Destination: ptr.To("*"), 40 DestinationPorts: ptr.To("22"), 41 Action: infrav1.SecurityRuleActionAllow, 42 } 43 otherRule = infrav1.SecurityRule{ 44 Name: "other_rule", 45 Description: "Test Rule", 46 Priority: 500, 47 Protocol: infrav1.SecurityGroupProtocolTCP, 48 Direction: infrav1.SecurityRuleDirectionInbound, 49 Source: ptr.To("*"), 50 SourcePorts: ptr.To("*"), 51 Destination: ptr.To("*"), 52 DestinationPorts: ptr.To("80"), 53 Action: infrav1.SecurityRuleActionAllow, 54 } 55 customRule = infrav1.SecurityRule{ 56 Name: "custom_rule", 57 Description: "Test Rule", 58 Priority: 501, 59 Protocol: infrav1.SecurityGroupProtocolTCP, 60 Direction: infrav1.SecurityRuleDirectionOutbound, 61 Source: ptr.To("*"), 62 SourcePorts: ptr.To("*"), 63 Destination: ptr.To("*"), 64 DestinationPorts: ptr.To("80"), 65 Action: infrav1.SecurityRuleActionAllow, 66 } 67 denyRule = infrav1.SecurityRule{ 68 Name: "deny_rule", 69 Description: "Deny Rule", 70 Priority: 510, 71 Protocol: infrav1.SecurityGroupProtocolTCP, 72 Direction: infrav1.SecurityRuleDirectionOutbound, 73 Source: ptr.To("*"), 74 SourcePorts: ptr.To("*"), 75 Destination: ptr.To("*"), 76 DestinationPorts: ptr.To("80"), 77 Action: infrav1.SecurityRuleActionDeny, 78 } 79 ) 80 81 func TestParameters(t *testing.T) { 82 testcases := []struct { 83 name string 84 spec *NSGSpec 85 existing interface{} 86 expect func(g *WithT, result interface{}) 87 expectedError string 88 }{ 89 { 90 name: "NSG already exists with all rules present", 91 spec: &NSGSpec{ 92 Name: "test-nsg", 93 Location: "test-location", 94 SecurityRules: infrav1.SecurityRules{ 95 sshRule, 96 otherRule, 97 }, 98 ResourceGroup: "test-group", 99 ClusterName: "my-cluster", 100 }, 101 existing: armnetwork.SecurityGroup{ 102 Name: ptr.To("test-nsg"), 103 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 104 SecurityRules: []*armnetwork.SecurityRule{ 105 converters.SecurityRuleToSDK(sshRule), 106 converters.SecurityRuleToSDK(otherRule), 107 }, 108 }, 109 }, 110 expect: func(g *WithT, result interface{}) { 111 g.Expect(result).To(BeNil()) 112 }, 113 }, 114 { 115 name: "NSG already exists but missing a rule", 116 spec: &NSGSpec{ 117 Name: "test-nsg", 118 Location: "test-location", 119 SecurityRules: infrav1.SecurityRules{ 120 sshRule, 121 otherRule, 122 }, 123 ResourceGroup: "test-group", 124 ClusterName: "my-cluster", 125 }, 126 existing: armnetwork.SecurityGroup{ 127 Name: ptr.To("test-nsg"), 128 Location: ptr.To("test-location"), 129 Etag: ptr.To("fake-etag"), 130 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 131 SecurityRules: []*armnetwork.SecurityRule{ 132 converters.SecurityRuleToSDK(sshRule), 133 converters.SecurityRuleToSDK(customRule), 134 }, 135 }, 136 }, 137 expect: func(g *WithT, result interface{}) { 138 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.SecurityGroup{})) 139 g.Expect(result).To(Equal(armnetwork.SecurityGroup{ 140 Location: ptr.To("test-location"), 141 Etag: ptr.To("fake-etag"), 142 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 143 SecurityRules: []*armnetwork.SecurityRule{ 144 converters.SecurityRuleToSDK(otherRule), 145 converters.SecurityRuleToSDK(sshRule), 146 converters.SecurityRuleToSDK(customRule), 147 }, 148 }, 149 Tags: map[string]*string{ 150 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 151 "Name": ptr.To("test-nsg"), 152 }, 153 })) 154 }, 155 }, 156 { 157 name: "NSG already exists but missing a rule", 158 spec: &NSGSpec{ 159 Name: "test-nsg", 160 Location: "test-location", 161 SecurityRules: infrav1.SecurityRules{ 162 sshRule, 163 otherRule, 164 }, 165 ResourceGroup: "test-group", 166 ClusterName: "my-cluster", 167 }, 168 existing: armnetwork.SecurityGroup{ 169 Name: ptr.To("test-nsg"), 170 Location: ptr.To("test-location"), 171 Etag: ptr.To("fake-etag"), 172 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 173 SecurityRules: []*armnetwork.SecurityRule{ 174 converters.SecurityRuleToSDK(sshRule), 175 converters.SecurityRuleToSDK(denyRule), 176 }, 177 }, 178 }, 179 expect: func(g *WithT, result interface{}) { 180 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.SecurityGroup{})) 181 g.Expect(result).To(Equal(armnetwork.SecurityGroup{ 182 Location: ptr.To("test-location"), 183 Etag: ptr.To("fake-etag"), 184 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 185 SecurityRules: []*armnetwork.SecurityRule{ 186 converters.SecurityRuleToSDK(otherRule), 187 converters.SecurityRuleToSDK(sshRule), 188 converters.SecurityRuleToSDK(denyRule), 189 }, 190 }, 191 Tags: map[string]*string{ 192 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 193 "Name": ptr.To("test-nsg"), 194 }, 195 })) 196 }, 197 }, 198 { 199 name: "NSG already exists and a rule is deleted", 200 spec: &NSGSpec{ 201 Name: "test-nsg", 202 Location: "test-location", 203 SecurityRules: infrav1.SecurityRules{ 204 sshRule, 205 customRule, 206 }, 207 ResourceGroup: "test-group", 208 ClusterName: "my-cluster", 209 LastAppliedSecurityRules: map[string]interface{}{ 210 "allow_ssh": sshRule, 211 "custom_rule": customRule, 212 "other_rule": otherRule, 213 }, 214 }, 215 existing: armnetwork.SecurityGroup{ 216 Name: ptr.To("test-nsg"), 217 Location: ptr.To("test-location"), 218 Etag: ptr.To("fake-etag"), 219 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 220 SecurityRules: []*armnetwork.SecurityRule{ 221 converters.SecurityRuleToSDK(sshRule), 222 converters.SecurityRuleToSDK(customRule), 223 converters.SecurityRuleToSDK(otherRule), 224 }, 225 }, 226 }, 227 expect: func(g *WithT, result interface{}) { 228 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.SecurityGroup{})) 229 g.Expect(result).To(Equal(armnetwork.SecurityGroup{ 230 Location: ptr.To("test-location"), 231 Etag: ptr.To("fake-etag"), 232 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 233 SecurityRules: []*armnetwork.SecurityRule{ 234 converters.SecurityRuleToSDK(sshRule), 235 converters.SecurityRuleToSDK(customRule), 236 }, 237 }, 238 Tags: map[string]*string{ 239 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 240 "Name": ptr.To("test-nsg"), 241 }, 242 })) 243 }, 244 }, 245 { 246 name: "NSG already exists and a deny rule is deleted", 247 spec: &NSGSpec{ 248 Name: "test-nsg", 249 Location: "test-location", 250 SecurityRules: infrav1.SecurityRules{ 251 sshRule, 252 customRule, 253 }, 254 ResourceGroup: "test-group", 255 ClusterName: "my-cluster", 256 LastAppliedSecurityRules: map[string]interface{}{ 257 "allow_ssh": sshRule, 258 "custom_rule": customRule, 259 "deny_rule": denyRule, 260 }, 261 }, 262 existing: armnetwork.SecurityGroup{ 263 Name: ptr.To("test-nsg"), 264 Location: ptr.To("test-location"), 265 Etag: ptr.To("fake-etag"), 266 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 267 SecurityRules: []*armnetwork.SecurityRule{ 268 converters.SecurityRuleToSDK(sshRule), 269 converters.SecurityRuleToSDK(customRule), 270 converters.SecurityRuleToSDK(denyRule), 271 }, 272 }, 273 }, 274 expect: func(g *WithT, result interface{}) { 275 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.SecurityGroup{})) 276 g.Expect(result).To(Equal(armnetwork.SecurityGroup{ 277 Location: ptr.To("test-location"), 278 Etag: ptr.To("fake-etag"), 279 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 280 SecurityRules: []*armnetwork.SecurityRule{ 281 converters.SecurityRuleToSDK(sshRule), 282 converters.SecurityRuleToSDK(customRule), 283 }, 284 }, 285 Tags: map[string]*string{ 286 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 287 "Name": ptr.To("test-nsg"), 288 }, 289 })) 290 }, 291 }, 292 { 293 name: "NSG already exists and a rule not owned by CAPZ is present", 294 spec: &NSGSpec{ 295 Name: "test-nsg", 296 Location: "test-location", 297 SecurityRules: infrav1.SecurityRules{ 298 sshRule, 299 customRule, 300 }, 301 ResourceGroup: "test-group", 302 ClusterName: "my-cluster", 303 LastAppliedSecurityRules: map[string]interface{}{ 304 "allow_ssh": sshRule, 305 "custom_rule": customRule, 306 }, 307 }, 308 existing: armnetwork.SecurityGroup{ 309 Name: ptr.To("test-nsg"), 310 Location: ptr.To("test-location"), 311 Etag: ptr.To("fake-etag"), 312 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 313 SecurityRules: []*armnetwork.SecurityRule{ 314 converters.SecurityRuleToSDK(sshRule), 315 converters.SecurityRuleToSDK(customRule), 316 converters.SecurityRuleToSDK(otherRule), 317 }, 318 }, 319 }, 320 expect: func(g *WithT, result interface{}) { 321 g.Expect(result).To(BeNil()) 322 }, 323 }, 324 { 325 name: "NSG does not exist", 326 spec: &NSGSpec{ 327 Name: "test-nsg", 328 Location: "test-location", 329 SecurityRules: infrav1.SecurityRules{ 330 sshRule, 331 otherRule, 332 }, 333 ResourceGroup: "test-group", 334 ClusterName: "my-cluster", 335 }, 336 existing: nil, 337 expect: func(g *WithT, result interface{}) { 338 g.Expect(result).To(BeAssignableToTypeOf(armnetwork.SecurityGroup{})) 339 g.Expect(result).To(Equal(armnetwork.SecurityGroup{ 340 Properties: &armnetwork.SecurityGroupPropertiesFormat{ 341 SecurityRules: []*armnetwork.SecurityRule{ 342 converters.SecurityRuleToSDK(sshRule), 343 converters.SecurityRuleToSDK(otherRule), 344 }, 345 }, 346 Location: ptr.To("test-location"), 347 Tags: map[string]*string{ 348 "sigs.k8s.io_cluster-api-provider-azure_cluster_my-cluster": ptr.To("owned"), 349 "Name": ptr.To("test-nsg"), 350 }, 351 })) 352 }, 353 }, 354 } 355 356 for _, tc := range testcases { 357 tc := tc 358 t.Run(tc.name, func(t *testing.T) { 359 g := NewWithT(t) 360 t.Parallel() 361 362 result, err := tc.spec.Parameters(context.TODO(), tc.existing) 363 if tc.expectedError != "" { 364 g.Expect(err).To(HaveOccurred()) 365 g.Expect(err).To(MatchError(tc.expectedError)) 366 } else { 367 g.Expect(err).NotTo(HaveOccurred()) 368 } 369 tc.expect(g, result) 370 }) 371 } 372 } 373 374 func TestRuleExists(t *testing.T) { 375 testcases := []struct { 376 name string 377 rules []*armnetwork.SecurityRule 378 rule *armnetwork.SecurityRule 379 expected bool 380 }{ 381 { 382 name: "rule doesn't exitst", 383 rules: []*armnetwork.SecurityRule{ruleA}, 384 rule: ruleB, 385 expected: false, 386 }, 387 { 388 name: "rule exists", 389 rules: []*armnetwork.SecurityRule{ruleA, ruleB}, 390 rule: ruleB, 391 expected: true, 392 }, 393 { 394 name: "rule exists but has been modified", 395 rules: []*armnetwork.SecurityRule{ruleA, ruleB}, 396 rule: ruleBModified, 397 expected: false, 398 }, 399 } 400 for _, tc := range testcases { 401 tc := tc 402 t.Run(tc.name, func(t *testing.T) { 403 g := NewWithT(t) 404 t.Parallel() 405 result := ruleExists(tc.rules, tc.rule) 406 g.Expect(result).To(Equal(tc.expected)) 407 }) 408 } 409 }