github.com/articulate/terraform@v0.6.13-0.20160303003731-8d31c93862de/builtin/providers/aws/resource_aws_security_group_rules_matching_test.go (about) 1 package aws 2 3 import ( 4 "log" 5 "testing" 6 7 "github.com/hashicorp/terraform/helper/schema" 8 ) 9 10 // testing rulesForGroupPermissions 11 func TestRulesMixedMatching(t *testing.T) { 12 cases := []struct { 13 groupId string 14 local []interface{} 15 remote []map[string]interface{} 16 saves []map[string]interface{} 17 }{ 18 { 19 local: []interface{}{ 20 map[string]interface{}{ 21 "from_port": 80, 22 "to_port": 8000, 23 "protocol": "tcp", 24 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.0.0.0/16"}, 25 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 26 }, 27 }, 28 remote: []map[string]interface{}{ 29 map[string]interface{}{ 30 "from_port": int64(80), 31 "to_port": int64(8000), 32 "protocol": "tcp", 33 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 34 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 35 }, 36 }, 37 saves: []map[string]interface{}{ 38 map[string]interface{}{ 39 "from_port": 80, 40 "to_port": 8000, 41 "protocol": "tcp", 42 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 43 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 44 }, 45 }, 46 }, 47 { 48 local: []interface{}{ 49 map[string]interface{}{ 50 "from_port": 80, 51 "to_port": 8000, 52 "protocol": "tcp", 53 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 54 }, 55 }, 56 remote: []map[string]interface{}{ 57 map[string]interface{}{ 58 "from_port": int64(80), 59 "to_port": int64(8000), 60 "protocol": "tcp", 61 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 62 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 63 }, 64 }, 65 saves: []map[string]interface{}{ 66 map[string]interface{}{ 67 "from_port": 80, 68 "to_port": 8000, 69 "protocol": "tcp", 70 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 71 }, 72 map[string]interface{}{ 73 "from_port": int64(80), 74 "to_port": int64(8000), 75 "protocol": "tcp", 76 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 77 }, 78 }, 79 }, 80 { 81 local: []interface{}{ 82 map[string]interface{}{ 83 "from_port": 80, 84 "to_port": 8000, 85 "protocol": "tcp", 86 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.0.0.0/16"}, 87 }, 88 }, 89 remote: []map[string]interface{}{ 90 map[string]interface{}{ 91 "from_port": int64(80), 92 "to_port": int64(8000), 93 "protocol": "tcp", 94 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 95 }, 96 }, 97 saves: []map[string]interface{}{ 98 map[string]interface{}{ 99 "from_port": 80, 100 "to_port": 8000, 101 "protocol": "tcp", 102 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 103 }, 104 }, 105 }, 106 { 107 local: []interface{}{ 108 map[string]interface{}{ 109 "from_port": 80, 110 "to_port": 8000, 111 "protocol": "tcp", 112 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 113 }, 114 }, 115 remote: []map[string]interface{}{ 116 map[string]interface{}{ 117 "from_port": int64(80), 118 "to_port": int64(8000), 119 "protocol": "tcp", 120 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 121 }, 122 }, 123 saves: []map[string]interface{}{ 124 map[string]interface{}{ 125 "from_port": 80, 126 "to_port": 8000, 127 "protocol": "tcp", 128 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 129 }, 130 }, 131 }, 132 { 133 local: []interface{}{ 134 map[string]interface{}{ 135 "from_port": 80, 136 "to_port": 8000, 137 "protocol": "tcp", 138 "cidr_blocks": []interface{}{"172.8.0.0/16"}, 139 }, 140 map[string]interface{}{ 141 "from_port": 80, 142 "to_port": 8000, 143 "protocol": "tcp", 144 "cidr_blocks": []interface{}{"192.168.0.0/16"}, 145 }, 146 }, 147 remote: []map[string]interface{}{ 148 map[string]interface{}{ 149 "from_port": int64(80), 150 "to_port": int64(8000), 151 "protocol": "tcp", 152 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 153 }, 154 }, 155 saves: []map[string]interface{}{ 156 map[string]interface{}{ 157 "from_port": 80, 158 "to_port": 8000, 159 "protocol": "tcp", 160 "cidr_blocks": []string{"172.8.0.0/16"}, 161 }, 162 map[string]interface{}{ 163 "from_port": 80, 164 "to_port": 8000, 165 "protocol": "tcp", 166 "cidr_blocks": []string{"192.168.0.0/16"}, 167 }, 168 }, 169 }, 170 { 171 local: []interface{}{}, 172 remote: []map[string]interface{}{ 173 map[string]interface{}{ 174 "from_port": int64(80), 175 "to_port": int64(8000), 176 "protocol": "tcp", 177 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 178 }, 179 }, 180 saves: []map[string]interface{}{ 181 map[string]interface{}{ 182 "from_port": int64(80), 183 "to_port": int64(8000), 184 "protocol": "tcp", 185 "cidr_blocks": []string{"172.8.0.0/16", "10.0.0.0/16"}, 186 }, 187 }, 188 }, 189 // local and remote differ 190 { 191 local: []interface{}{ 192 map[string]interface{}{ 193 "from_port": 80, 194 "to_port": 8000, 195 "protocol": "tcp", 196 "cidr_blocks": []interface{}{"172.8.0.0/16"}, 197 }, 198 }, 199 remote: []map[string]interface{}{ 200 map[string]interface{}{ 201 "from_port": int64(80), 202 "to_port": int64(8000), 203 "protocol": "tcp", 204 "cidr_blocks": []string{"10.0.0.0/16"}, 205 }, 206 }, 207 // Because this is the remote rule being saved, we need to check for int64 208 // encoding. We could convert this code, but ultimately Terraform doesn't 209 // care it's for the reflect.DeepEqual in this test 210 saves: []map[string]interface{}{ 211 map[string]interface{}{ 212 "from_port": int64(80), 213 "to_port": int64(8000), 214 "protocol": "tcp", 215 "cidr_blocks": []string{"10.0.0.0/16"}, 216 }, 217 }, 218 }, 219 // local with more rules and the remote (the remote should then be saved) 220 { 221 local: []interface{}{ 222 map[string]interface{}{ 223 "from_port": 80, 224 "to_port": 8000, 225 "protocol": "tcp", 226 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 227 }, 228 }, 229 remote: []map[string]interface{}{ 230 map[string]interface{}{ 231 "from_port": int64(80), 232 "to_port": int64(8000), 233 "protocol": "tcp", 234 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 235 }, 236 }, 237 saves: []map[string]interface{}{ 238 map[string]interface{}{ 239 "from_port": int64(80), 240 "to_port": int64(8000), 241 "protocol": "tcp", 242 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 243 }, 244 }, 245 }, 246 // 3 local rules 247 // this should trigger a diff (not shown) 248 { 249 local: []interface{}{ 250 map[string]interface{}{ 251 "from_port": 80, 252 "to_port": 8000, 253 "protocol": "tcp", 254 "cidr_blocks": []interface{}{"172.8.0.0/16"}, 255 }, 256 map[string]interface{}{ 257 "from_port": 80, 258 "to_port": 8000, 259 "protocol": "tcp", 260 "cidr_blocks": []interface{}{"10.8.0.0/16"}, 261 }, 262 map[string]interface{}{ 263 "from_port": 80, 264 "to_port": 8000, 265 "protocol": "tcp", 266 "cidr_blocks": []interface{}{"192.168.0.0/16"}, 267 }, 268 }, 269 remote: []map[string]interface{}{ 270 map[string]interface{}{ 271 "from_port": int64(80), 272 "to_port": int64(8000), 273 "protocol": "tcp", 274 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 275 }, 276 }, 277 saves: []map[string]interface{}{ 278 map[string]interface{}{ 279 "from_port": 80, 280 "to_port": 8000, 281 "protocol": "tcp", 282 "cidr_blocks": []string{"172.8.0.0/16"}, 283 }, 284 map[string]interface{}{ 285 "from_port": 80, 286 "to_port": 8000, 287 "protocol": "tcp", 288 "cidr_blocks": []string{"192.168.0.0/16"}, 289 }, 290 }, 291 }, 292 // a local rule with 2 cidrs, remote has 4 cidrs, shoudl be saved to match 293 // the local but also an extra rule found 294 { 295 local: []interface{}{ 296 map[string]interface{}{ 297 "from_port": 80, 298 "to_port": 8000, 299 "protocol": "tcp", 300 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16"}, 301 }, 302 }, 303 remote: []map[string]interface{}{ 304 map[string]interface{}{ 305 "from_port": int64(80), 306 "to_port": int64(8000), 307 "protocol": "tcp", 308 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16", "10.8.0.0/16", "206.8.0.0/16"}, 309 }, 310 }, 311 saves: []map[string]interface{}{ 312 map[string]interface{}{ 313 "from_port": 80, 314 "to_port": 8000, 315 "protocol": "tcp", 316 "cidr_blocks": []string{"172.8.0.0/16", "10.8.0.0/16"}, 317 }, 318 map[string]interface{}{ 319 "from_port": int64(80), 320 "to_port": int64(8000), 321 "protocol": "tcp", 322 "cidr_blocks": []string{"192.168.0.0/16", "206.8.0.0/16"}, 323 }, 324 }, 325 }, 326 // testing some SGS 327 { 328 local: []interface{}{}, 329 remote: []map[string]interface{}{ 330 map[string]interface{}{ 331 "from_port": int64(22), 332 "to_port": int64(22), 333 "protocol": "tcp", 334 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 335 }, 336 }, 337 saves: []map[string]interface{}{ 338 map[string]interface{}{ 339 // we're saving the remote, so it will be int64 encoded 340 "from_port": int64(22), 341 "to_port": int64(22), 342 "protocol": "tcp", 343 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 344 }, 345 }, 346 }, 347 // two local blocks that match a single remote group, but are saved as two 348 { 349 local: []interface{}{ 350 map[string]interface{}{ 351 "from_port": 22, 352 "to_port": 22, 353 "protocol": "tcp", 354 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 355 }, 356 map[string]interface{}{ 357 "from_port": 22, 358 "to_port": 22, 359 "protocol": "tcp", 360 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-4444"}), 361 }, 362 }, 363 remote: []map[string]interface{}{ 364 map[string]interface{}{ 365 "from_port": int64(22), 366 "to_port": int64(22), 367 "protocol": "tcp", 368 "security_groups": schema.NewSet( 369 schema.HashString, 370 []interface{}{ 371 "sg-9876", 372 "sg-4444", 373 }, 374 ), 375 }, 376 }, 377 saves: []map[string]interface{}{ 378 map[string]interface{}{ 379 "from_port": 22, 380 "to_port": 22, 381 "protocol": "tcp", 382 "security_groups": schema.NewSet( 383 schema.HashString, 384 []interface{}{ 385 "sg-9876", 386 }, 387 ), 388 }, 389 map[string]interface{}{ 390 "from_port": 22, 391 "to_port": 22, 392 "protocol": "tcp", 393 "security_groups": schema.NewSet( 394 schema.HashString, 395 []interface{}{ 396 "sg-4444", 397 }, 398 ), 399 }, 400 }, 401 }, 402 // test self with other rules 403 { 404 local: []interface{}{ 405 map[string]interface{}{ 406 "from_port": 22, 407 "to_port": 22, 408 "protocol": "tcp", 409 "self": true, 410 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 411 }, 412 }, 413 remote: []map[string]interface{}{ 414 map[string]interface{}{ 415 "from_port": int64(22), 416 "to_port": int64(22), 417 "protocol": "tcp", 418 "self": true, 419 }, 420 }, 421 saves: []map[string]interface{}{ 422 map[string]interface{}{ 423 "from_port": int64(22), 424 "to_port": int64(22), 425 "protocol": "tcp", 426 "self": true, 427 }, 428 }, 429 }, 430 // test self 431 { 432 local: []interface{}{ 433 map[string]interface{}{ 434 "from_port": 22, 435 "to_port": 22, 436 "protocol": "tcp", 437 "self": true, 438 }, 439 }, 440 remote: []map[string]interface{}{ 441 map[string]interface{}{ 442 "from_port": int64(22), 443 "to_port": int64(22), 444 "protocol": "tcp", 445 "self": true, 446 }, 447 }, 448 saves: []map[string]interface{}{ 449 map[string]interface{}{ 450 "from_port": int64(22), 451 "to_port": int64(22), 452 "protocol": "tcp", 453 "self": true, 454 }, 455 }, 456 }, 457 { 458 local: []interface{}{ 459 map[string]interface{}{ 460 "from_port": 22, 461 "to_port": 22, 462 "protocol": "tcp", 463 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 464 }, 465 }, 466 remote: []map[string]interface{}{ 467 map[string]interface{}{ 468 "from_port": int64(22), 469 "to_port": int64(22), 470 "protocol": "tcp", 471 "self": true, 472 }, 473 }, 474 saves: []map[string]interface{}{ 475 map[string]interface{}{ 476 "from_port": int64(22), 477 "to_port": int64(22), 478 "protocol": "tcp", 479 "self": true, 480 }, 481 }, 482 }, 483 // mix of sgs and cidrs 484 { 485 local: []interface{}{ 486 map[string]interface{}{ 487 "from_port": 80, 488 "to_port": 8000, 489 "protocol": "tcp", 490 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 491 }, 492 map[string]interface{}{ 493 "from_port": 80, 494 "to_port": 8000, 495 "protocol": "tcp", 496 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 497 }, 498 }, 499 remote: []map[string]interface{}{ 500 map[string]interface{}{ 501 "from_port": int64(80), 502 "to_port": int64(8000), 503 "protocol": "tcp", 504 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 505 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 506 }, 507 }, 508 saves: []map[string]interface{}{ 509 map[string]interface{}{ 510 "from_port": int64(80), 511 "to_port": int64(8000), 512 "protocol": "tcp", 513 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 514 }, 515 map[string]interface{}{ 516 "from_port": int64(80), 517 "to_port": int64(8000), 518 "protocol": "tcp", 519 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 520 }, 521 }, 522 }, 523 { 524 local: []interface{}{ 525 map[string]interface{}{ 526 "from_port": 80, 527 "to_port": 8000, 528 "protocol": "tcp", 529 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 530 }, 531 map[string]interface{}{ 532 "from_port": 80, 533 "to_port": 8000, 534 "protocol": "tcp", 535 "self": true, 536 }, 537 }, 538 remote: []map[string]interface{}{ 539 map[string]interface{}{ 540 "from_port": int64(80), 541 "to_port": int64(8000), 542 "protocol": "tcp", 543 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 544 "self": true, 545 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 546 }, 547 }, 548 saves: []map[string]interface{}{ 549 map[string]interface{}{ 550 "from_port": 80, 551 "to_port": 8000, 552 "protocol": "tcp", 553 "self": true, 554 }, 555 map[string]interface{}{ 556 "from_port": int64(80), 557 "to_port": int64(8000), 558 "protocol": "tcp", 559 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 560 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 561 }, 562 }, 563 }, 564 } 565 for i, c := range cases { 566 saves := matchRules("ingress", c.local, c.remote) 567 log.Printf("\n======\n\nSaves:\n%#v\n\nCS Saves:\n%#v\n\n======\n", saves, c.saves) 568 log.Printf("\n\tTest %d:\n", i) 569 570 if len(saves) != len(c.saves) { 571 t.Fatalf("Expected %d saves, got %d", len(c.saves), len(saves)) 572 } 573 574 shouldFind := len(c.saves) 575 var found int 576 for _, s := range saves { 577 for _, cs := range c.saves { 578 // deep equal cannot compare schema.Set's directly 579 // make sure we're not failing the reflect b/c of ports/type 580 for _, attr := range []string{"to_port", "from_port", "type"} { 581 if s[attr] != cs[attr] { 582 continue 583 } 584 } 585 586 var numExpectedCidrs, numExpectedSGs, numRemoteCidrs, numRemoteSGs int 587 // var matchingCidrs []string 588 // var matchingSGs []string 589 590 var cidrsMatch, sGsMatch bool 591 592 if _, ok := s["cidr_blocks"]; ok { 593 switch s["cidr_blocks"].(type) { 594 case []string: 595 numExpectedCidrs = len(s["cidr_blocks"].([]string)) 596 default: 597 numExpectedCidrs = len(s["cidr_blocks"].([]interface{})) 598 } 599 600 } 601 if _, ok := s["security_groups"]; ok { 602 numExpectedSGs = len(s["security_groups"].(*schema.Set).List()) 603 } 604 605 if _, ok := cs["cidr_blocks"]; ok { 606 numRemoteCidrs = len(cs["cidr_blocks"].([]string)) 607 } 608 609 if _, ok := cs["security_groups"]; ok { 610 numRemoteSGs = len(cs["security_groups"].(*schema.Set).List()) 611 } 612 613 // skip early 614 if numExpectedSGs != numRemoteSGs { 615 log.Printf("\n\ncontinuning on numRemoteSGs \n\n") 616 continue 617 } 618 if numExpectedCidrs != numRemoteCidrs { 619 log.Printf("\n\ncontinuning numRemoteCidrs\n\n") 620 continue 621 } 622 623 if numExpectedCidrs == 0 { 624 cidrsMatch = true 625 } 626 if numExpectedSGs == 0 { 627 sGsMatch = true 628 } 629 630 // convert save cidrs to set 631 var lcs []interface{} 632 if _, ok := s["cidr_blocks"]; ok { 633 switch s["cidr_blocks"].(type) { 634 case []string: 635 for _, c := range s["cidr_blocks"].([]string) { 636 lcs = append(lcs, c) 637 } 638 default: 639 for _, c := range s["cidr_blocks"].([]interface{}) { 640 lcs = append(lcs, c) 641 } 642 } 643 } 644 savesCidrs := schema.NewSet(schema.HashString, lcs) 645 646 // convert cs cidrs to set 647 var cslcs []interface{} 648 if _, ok := cs["cidr_blocks"]; ok { 649 for _, c := range cs["cidr_blocks"].([]string) { 650 cslcs = append(cslcs, c) 651 } 652 } 653 csCidrs := schema.NewSet(schema.HashString, cslcs) 654 655 if csCidrs.Equal(savesCidrs) { 656 log.Printf("\nmatched cidrs") 657 cidrsMatch = true 658 } 659 660 if rawS, ok := s["security_groups"]; ok { 661 outSet := rawS.(*schema.Set) 662 if rawL, ok := cs["security_groups"]; ok { 663 localSet := rawL.(*schema.Set) 664 if outSet.Equal(localSet) { 665 log.Printf("\nmatched sgs") 666 sGsMatch = true 667 } 668 } 669 } 670 671 var lSelf bool 672 var rSelf bool 673 if _, ok := s["self"]; ok { 674 lSelf = s["self"].(bool) 675 } 676 if _, ok := cs["self"]; ok { 677 rSelf = cs["self"].(bool) 678 } 679 680 if (sGsMatch && cidrsMatch) && (lSelf == rSelf) { 681 found++ 682 } 683 } 684 } 685 686 if found != shouldFind { 687 t.Fatalf("Bad sg rule matches (%d / %d)", found, shouldFind) 688 } 689 } 690 }