github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/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 // test lower/ uppercase handling 190 { 191 local: []interface{}{ 192 map[string]interface{}{ 193 "from_port": 80, 194 "to_port": 8000, 195 "protocol": "TCP", 196 }, 197 }, 198 remote: []map[string]interface{}{ 199 map[string]interface{}{ 200 "from_port": int64(80), 201 "to_port": int64(8000), 202 "protocol": "tcp", 203 }, 204 }, 205 saves: []map[string]interface{}{ 206 map[string]interface{}{ 207 "from_port": 80, 208 "to_port": 8000, 209 "protocol": "tcp", 210 }, 211 }, 212 }, 213 // local and remote differ 214 { 215 local: []interface{}{ 216 map[string]interface{}{ 217 "from_port": 80, 218 "to_port": 8000, 219 "protocol": "tcp", 220 "cidr_blocks": []interface{}{"172.8.0.0/16"}, 221 }, 222 }, 223 remote: []map[string]interface{}{ 224 map[string]interface{}{ 225 "from_port": int64(80), 226 "to_port": int64(8000), 227 "protocol": "tcp", 228 "cidr_blocks": []string{"10.0.0.0/16"}, 229 }, 230 }, 231 // Because this is the remote rule being saved, we need to check for int64 232 // encoding. We could convert this code, but ultimately Terraform doesn't 233 // care it's for the reflect.DeepEqual in this test 234 saves: []map[string]interface{}{ 235 map[string]interface{}{ 236 "from_port": int64(80), 237 "to_port": int64(8000), 238 "protocol": "tcp", 239 "cidr_blocks": []string{"10.0.0.0/16"}, 240 }, 241 }, 242 }, 243 // local with more rules and the remote (the remote should then be saved) 244 { 245 local: []interface{}{ 246 map[string]interface{}{ 247 "from_port": 80, 248 "to_port": 8000, 249 "protocol": "tcp", 250 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 251 }, 252 }, 253 remote: []map[string]interface{}{ 254 map[string]interface{}{ 255 "from_port": int64(80), 256 "to_port": int64(8000), 257 "protocol": "tcp", 258 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 259 }, 260 }, 261 saves: []map[string]interface{}{ 262 map[string]interface{}{ 263 "from_port": int64(80), 264 "to_port": int64(8000), 265 "protocol": "tcp", 266 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 267 }, 268 }, 269 }, 270 // 3 local rules 271 // this should trigger a diff (not shown) 272 { 273 local: []interface{}{ 274 map[string]interface{}{ 275 "from_port": 80, 276 "to_port": 8000, 277 "protocol": "tcp", 278 "cidr_blocks": []interface{}{"172.8.0.0/16"}, 279 }, 280 map[string]interface{}{ 281 "from_port": 80, 282 "to_port": 8000, 283 "protocol": "tcp", 284 "cidr_blocks": []interface{}{"10.8.0.0/16"}, 285 }, 286 map[string]interface{}{ 287 "from_port": 80, 288 "to_port": 8000, 289 "protocol": "tcp", 290 "cidr_blocks": []interface{}{"192.168.0.0/16"}, 291 }, 292 }, 293 remote: []map[string]interface{}{ 294 map[string]interface{}{ 295 "from_port": int64(80), 296 "to_port": int64(8000), 297 "protocol": "tcp", 298 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 299 }, 300 }, 301 saves: []map[string]interface{}{ 302 map[string]interface{}{ 303 "from_port": 80, 304 "to_port": 8000, 305 "protocol": "tcp", 306 "cidr_blocks": []string{"172.8.0.0/16"}, 307 }, 308 map[string]interface{}{ 309 "from_port": 80, 310 "to_port": 8000, 311 "protocol": "tcp", 312 "cidr_blocks": []string{"192.168.0.0/16"}, 313 }, 314 }, 315 }, 316 // a local rule with 2 cidrs, remote has 4 cidrs, should be saved to match 317 // the local but also an extra rule found 318 { 319 local: []interface{}{ 320 map[string]interface{}{ 321 "from_port": 80, 322 "to_port": 8000, 323 "protocol": "tcp", 324 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16"}, 325 }, 326 }, 327 remote: []map[string]interface{}{ 328 map[string]interface{}{ 329 "from_port": int64(80), 330 "to_port": int64(8000), 331 "protocol": "tcp", 332 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16", "10.8.0.0/16", "206.8.0.0/16"}, 333 }, 334 }, 335 saves: []map[string]interface{}{ 336 map[string]interface{}{ 337 "from_port": 80, 338 "to_port": 8000, 339 "protocol": "tcp", 340 "cidr_blocks": []string{"172.8.0.0/16", "10.8.0.0/16"}, 341 }, 342 map[string]interface{}{ 343 "from_port": int64(80), 344 "to_port": int64(8000), 345 "protocol": "tcp", 346 "cidr_blocks": []string{"192.168.0.0/16", "206.8.0.0/16"}, 347 }, 348 }, 349 }, 350 // testing some SGS 351 { 352 local: []interface{}{}, 353 remote: []map[string]interface{}{ 354 map[string]interface{}{ 355 "from_port": int64(22), 356 "to_port": int64(22), 357 "protocol": "tcp", 358 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 359 }, 360 }, 361 saves: []map[string]interface{}{ 362 map[string]interface{}{ 363 // we're saving the remote, so it will be int64 encoded 364 "from_port": int64(22), 365 "to_port": int64(22), 366 "protocol": "tcp", 367 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 368 }, 369 }, 370 }, 371 // two local blocks that match a single remote group, but are saved as two 372 { 373 local: []interface{}{ 374 map[string]interface{}{ 375 "from_port": 22, 376 "to_port": 22, 377 "protocol": "tcp", 378 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876"}), 379 }, 380 map[string]interface{}{ 381 "from_port": 22, 382 "to_port": 22, 383 "protocol": "tcp", 384 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-4444"}), 385 }, 386 }, 387 remote: []map[string]interface{}{ 388 map[string]interface{}{ 389 "from_port": int64(22), 390 "to_port": int64(22), 391 "protocol": "tcp", 392 "security_groups": schema.NewSet( 393 schema.HashString, 394 []interface{}{ 395 "sg-9876", 396 "sg-4444", 397 }, 398 ), 399 }, 400 }, 401 saves: []map[string]interface{}{ 402 map[string]interface{}{ 403 "from_port": 22, 404 "to_port": 22, 405 "protocol": "tcp", 406 "security_groups": schema.NewSet( 407 schema.HashString, 408 []interface{}{ 409 "sg-9876", 410 }, 411 ), 412 }, 413 map[string]interface{}{ 414 "from_port": 22, 415 "to_port": 22, 416 "protocol": "tcp", 417 "security_groups": schema.NewSet( 418 schema.HashString, 419 []interface{}{ 420 "sg-4444", 421 }, 422 ), 423 }, 424 }, 425 }, 426 // test self with other rules 427 { 428 local: []interface{}{ 429 map[string]interface{}{ 430 "from_port": 22, 431 "to_port": 22, 432 "protocol": "tcp", 433 "self": true, 434 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 435 }, 436 }, 437 remote: []map[string]interface{}{ 438 map[string]interface{}{ 439 "from_port": int64(22), 440 "to_port": int64(22), 441 "protocol": "tcp", 442 "self": true, 443 }, 444 }, 445 saves: []map[string]interface{}{ 446 map[string]interface{}{ 447 "from_port": int64(22), 448 "to_port": int64(22), 449 "protocol": "tcp", 450 "self": true, 451 }, 452 }, 453 }, 454 // test self 455 { 456 local: []interface{}{ 457 map[string]interface{}{ 458 "from_port": 22, 459 "to_port": 22, 460 "protocol": "tcp", 461 "self": true, 462 }, 463 }, 464 remote: []map[string]interface{}{ 465 map[string]interface{}{ 466 "from_port": int64(22), 467 "to_port": int64(22), 468 "protocol": "tcp", 469 "self": true, 470 }, 471 }, 472 saves: []map[string]interface{}{ 473 map[string]interface{}{ 474 "from_port": int64(22), 475 "to_port": int64(22), 476 "protocol": "tcp", 477 "self": true, 478 }, 479 }, 480 }, 481 { 482 local: []interface{}{ 483 map[string]interface{}{ 484 "from_port": 22, 485 "to_port": 22, 486 "protocol": "tcp", 487 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 488 }, 489 }, 490 remote: []map[string]interface{}{ 491 map[string]interface{}{ 492 "from_port": int64(22), 493 "to_port": int64(22), 494 "protocol": "tcp", 495 "self": true, 496 }, 497 }, 498 saves: []map[string]interface{}{ 499 map[string]interface{}{ 500 "from_port": int64(22), 501 "to_port": int64(22), 502 "protocol": "tcp", 503 "self": true, 504 }, 505 }, 506 }, 507 // mix of sgs and cidrs 508 { 509 local: []interface{}{ 510 map[string]interface{}{ 511 "from_port": 80, 512 "to_port": 8000, 513 "protocol": "tcp", 514 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 515 }, 516 map[string]interface{}{ 517 "from_port": 80, 518 "to_port": 8000, 519 "protocol": "tcp", 520 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 521 }, 522 }, 523 remote: []map[string]interface{}{ 524 map[string]interface{}{ 525 "from_port": int64(80), 526 "to_port": int64(8000), 527 "protocol": "tcp", 528 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 529 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 530 }, 531 }, 532 saves: []map[string]interface{}{ 533 map[string]interface{}{ 534 "from_port": int64(80), 535 "to_port": int64(8000), 536 "protocol": "tcp", 537 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 538 }, 539 map[string]interface{}{ 540 "from_port": int64(80), 541 "to_port": int64(8000), 542 "protocol": "tcp", 543 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 544 }, 545 }, 546 }, 547 { 548 local: []interface{}{ 549 map[string]interface{}{ 550 "from_port": 80, 551 "to_port": 8000, 552 "protocol": "tcp", 553 "cidr_blocks": []interface{}{"172.8.0.0/16", "10.8.0.0/16", "192.168.0.0/16"}, 554 }, 555 map[string]interface{}{ 556 "from_port": 80, 557 "to_port": 8000, 558 "protocol": "tcp", 559 "self": true, 560 }, 561 }, 562 remote: []map[string]interface{}{ 563 map[string]interface{}{ 564 "from_port": int64(80), 565 "to_port": int64(8000), 566 "protocol": "tcp", 567 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 568 "self": true, 569 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 570 }, 571 }, 572 saves: []map[string]interface{}{ 573 map[string]interface{}{ 574 "from_port": 80, 575 "to_port": 8000, 576 "protocol": "tcp", 577 "self": true, 578 }, 579 map[string]interface{}{ 580 "from_port": int64(80), 581 "to_port": int64(8000), 582 "protocol": "tcp", 583 "cidr_blocks": []string{"172.8.0.0/16", "192.168.0.0/16"}, 584 "security_groups": schema.NewSet(schema.HashString, []interface{}{"sg-9876", "sg-4444"}), 585 }, 586 }, 587 }, 588 } 589 for i, c := range cases { 590 saves := matchRules("ingress", c.local, c.remote) 591 log.Printf("\n======\n\nSaves:\n%#v\n\nCS Saves:\n%#v\n\n======\n", saves, c.saves) 592 log.Printf("\n\tTest %d:\n", i) 593 594 if len(saves) != len(c.saves) { 595 t.Fatalf("Expected %d saves, got %d", len(c.saves), len(saves)) 596 } 597 598 shouldFind := len(c.saves) 599 var found int 600 for _, s := range saves { 601 for _, cs := range c.saves { 602 // deep equal cannot compare schema.Set's directly 603 // make sure we're not failing the reflect b/c of ports/type 604 for _, attr := range []string{"to_port", "from_port", "type"} { 605 if s[attr] != cs[attr] { 606 continue 607 } 608 } 609 610 var numExpectedCidrs, numExpectedSGs, numRemoteCidrs, numRemoteSGs int 611 // var matchingCidrs []string 612 // var matchingSGs []string 613 614 var cidrsMatch, sGsMatch bool 615 616 if _, ok := s["cidr_blocks"]; ok { 617 switch s["cidr_blocks"].(type) { 618 case []string: 619 numExpectedCidrs = len(s["cidr_blocks"].([]string)) 620 default: 621 numExpectedCidrs = len(s["cidr_blocks"].([]interface{})) 622 } 623 624 } 625 if _, ok := s["security_groups"]; ok { 626 numExpectedSGs = len(s["security_groups"].(*schema.Set).List()) 627 } 628 629 if _, ok := cs["cidr_blocks"]; ok { 630 numRemoteCidrs = len(cs["cidr_blocks"].([]string)) 631 } 632 633 if _, ok := cs["security_groups"]; ok { 634 numRemoteSGs = len(cs["security_groups"].(*schema.Set).List()) 635 } 636 637 // skip early 638 if numExpectedSGs != numRemoteSGs { 639 log.Printf("\n\ncontinuning on numRemoteSGs \n\n") 640 continue 641 } 642 if numExpectedCidrs != numRemoteCidrs { 643 log.Printf("\n\ncontinuning numRemoteCidrs\n\n") 644 continue 645 } 646 647 if numExpectedCidrs == 0 { 648 cidrsMatch = true 649 } 650 if numExpectedSGs == 0 { 651 sGsMatch = true 652 } 653 654 // convert save cidrs to set 655 var lcs []interface{} 656 if _, ok := s["cidr_blocks"]; ok { 657 switch s["cidr_blocks"].(type) { 658 case []string: 659 for _, c := range s["cidr_blocks"].([]string) { 660 lcs = append(lcs, c) 661 } 662 default: 663 for _, c := range s["cidr_blocks"].([]interface{}) { 664 lcs = append(lcs, c) 665 } 666 } 667 } 668 savesCidrs := schema.NewSet(schema.HashString, lcs) 669 670 // convert cs cidrs to set 671 var cslcs []interface{} 672 if _, ok := cs["cidr_blocks"]; ok { 673 for _, c := range cs["cidr_blocks"].([]string) { 674 cslcs = append(cslcs, c) 675 } 676 } 677 csCidrs := schema.NewSet(schema.HashString, cslcs) 678 679 if csCidrs.Equal(savesCidrs) { 680 log.Printf("\nmatched cidrs") 681 cidrsMatch = true 682 } 683 684 if rawS, ok := s["security_groups"]; ok { 685 outSet := rawS.(*schema.Set) 686 if rawL, ok := cs["security_groups"]; ok { 687 localSet := rawL.(*schema.Set) 688 if outSet.Equal(localSet) { 689 log.Printf("\nmatched sgs") 690 sGsMatch = true 691 } 692 } 693 } 694 695 var lSelf bool 696 var rSelf bool 697 if _, ok := s["self"]; ok { 698 lSelf = s["self"].(bool) 699 } 700 if _, ok := cs["self"]; ok { 701 rSelf = cs["self"].(bool) 702 } 703 704 if (sGsMatch && cidrsMatch) && (lSelf == rSelf) { 705 found++ 706 } 707 } 708 } 709 710 if found != shouldFind { 711 t.Fatalf("Bad sg rule matches (%d / %d)", found, shouldFind) 712 } 713 } 714 }