istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/pkg/compare/compare_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package compare 16 17 import ( 18 "strings" 19 "testing" 20 21 "istio.io/istio/operator/pkg/object" 22 ) 23 24 func TestYAMLCmp(t *testing.T) { 25 tests := []struct { 26 desc string 27 a string 28 b string 29 want any 30 }{ 31 { 32 desc: "empty string into nil", 33 a: `metadata: ""`, 34 b: `metadata: `, 35 want: ``, 36 }, 37 { 38 desc: "empty array into nil", 39 a: `metadata: []`, 40 b: `metadata: `, 41 want: ``, 42 }, 43 { 44 desc: "empty map into nil", 45 a: `metadata: {}`, 46 b: `metadata: `, 47 want: ``, 48 }, 49 { 50 desc: "two additional", 51 a: `apiVersion: autoscaling/v2 52 kind: HorizontalPodAutoscaler 53 metadata: 54 namespace: istio-system 55 labels: 56 release: istio`, 57 b: `apiVersion: autoscaling/v2 58 kind: HorizontalPodAutoscaler 59 metadata: 60 name: istio-ingressgateway 61 namespace: istio-system 62 labels: 63 app: istio-ingressgateway 64 release: istio`, 65 want: `metadata: 66 labels: 67 app: <empty> -> istio-ingressgateway (ADDED) 68 name: <empty> -> istio-ingressgateway (ADDED) 69 `, 70 }, 71 { 72 desc: "two missing", 73 a: `apiVersion: autoscaling/v2 74 kind: HorizontalPodAutoscaler 75 metadata: 76 name: istio-ingressgateway 77 namespace: istio-system 78 labels: 79 app: istio-ingressgateway 80 release: istio`, 81 b: `apiVersion: autoscaling/v2 82 kind: HorizontalPodAutoscaler 83 metadata: 84 namespace: istio-system 85 labels: 86 release: istio`, 87 want: `metadata: 88 labels: 89 app: istio-ingressgateway -> <empty> (REMOVED) 90 name: istio-ingressgateway -> <empty> (REMOVED) 91 `, 92 }, 93 { 94 desc: "one missing", 95 a: `apiVersion: autoscaling/v2 96 kind: HorizontalPodAutoscaler 97 metadata: 98 name: istio-ingressgateway 99 namespace: istio-system 100 labels: 101 app: istio-ingressgateway 102 release: istio`, 103 b: `apiVersion: autoscaling/v2 104 kind: HorizontalPodAutoscaler 105 metadata: 106 name: istio-ingressgateway 107 namespace: istio-system 108 labels: 109 release: istio`, 110 want: `metadata: 111 labels: 112 app: istio-ingressgateway -> <empty> (REMOVED) 113 `, 114 }, 115 { 116 desc: "one additional", 117 a: `apiVersion: autoscaling/v2 118 kind: HorizontalPodAutoscaler 119 metadata: 120 name: istio-ingressgateway 121 namespace: istio-system 122 labels: 123 release: istio`, 124 b: `apiVersion: autoscaling/v2 125 kind: HorizontalPodAutoscaler 126 metadata: 127 name: istio-ingressgateway 128 namespace: istio-system 129 labels: 130 app: istio-ingressgateway 131 release: istio`, 132 want: `metadata: 133 labels: 134 app: <empty> -> istio-ingressgateway (ADDED) 135 `, 136 }, 137 { 138 desc: "identical", 139 a: `apiVersion: autoscaling/v2 140 kind: HorizontalPodAutoscaler 141 metadata: 142 name: istio-ingressgateway 143 namespace: istio-system 144 labels: 145 app: istio-ingressgateway 146 release: istio`, 147 b: `apiVersion: autoscaling/v2 148 kind: HorizontalPodAutoscaler 149 metadata: 150 name: istio-ingressgateway 151 namespace: istio-system 152 labels: 153 app: istio-ingressgateway 154 release: istio`, 155 want: ``, 156 }, 157 { 158 desc: "first item changed", 159 a: `apiVersion: autoscaling/v2beta1 160 kind: HorizontalPodAutoscaler 161 metadata: 162 name: istio-ingressgateway 163 namespace: istio-system 164 labels: 165 app: istio-ingressgateway 166 release: istio`, 167 b: `apiVersion: autoscaling/v2 168 kind: HorizontalPodAutoscaler 169 metadata: 170 name: istio-ingressgateway 171 namespace: istio-system 172 labels: 173 app: istio-ingressgateway 174 release: istio`, 175 want: `apiVersion: autoscaling/v2beta1 -> autoscaling/v2 176 `, 177 }, 178 { 179 desc: "nested item changed", 180 a: `apiVersion: autoscaling/v2 181 kind: HorizontalPodAutoscaler 182 metadata: 183 name: istio-ingressgateway 184 namespace: istio-system 185 labels: 186 app: istio-ingressgateway 187 release: istio`, 188 b: `apiVersion: autoscaling/v2 189 kind: HorizontalPodAutoscaler 190 metadata: 191 name: istio-ingressgateway 192 namespace: istio-system 193 labels: 194 app: istio-egressgateway 195 release: istio`, 196 want: `metadata: 197 labels: 198 app: istio-ingressgateway -> istio-egressgateway 199 `, 200 }, 201 { 202 desc: "one map value changed, order changed", 203 a: `apiVersion: autoscaling/v2 204 kind: HorizontalPodAutoscaler 205 metadata: 206 name: istio-ingressgateway 207 namespace: istio-system 208 labels: 209 app: istio-ingressgateway 210 release: istio 211 spec: 212 maxReplicas: 5 213 minReplicas: 1 214 scaleTargetRef: 215 apiVersion: apps/v1 216 kind: Deployment 217 name: ingressgateway 218 metrics: 219 - type: Resource 220 resource: 221 name: cpu 222 target: 223 type: Utilization 224 averageUtilization: 80`, 225 b: `apiVersion: autoscaling/v2 226 kind: HorizontalPodAutoscaler 227 metadata: 228 labels: 229 app: istio-ingressgateway 230 release: istio 231 name: istio-ingressgateway 232 namespace: istio-system 233 spec: 234 maxReplicas: 5 235 metrics: 236 - resource: 237 name: cpu 238 target: 239 type: Utilization 240 averageUtilization: 80 241 type: Resource 242 minReplicas: 1 243 scaleTargetRef: 244 apiVersion: apps/v1 245 kind: Deployment 246 name: istio-ingressgateway`, 247 want: `spec: 248 scaleTargetRef: 249 name: ingressgateway -> istio-ingressgateway 250 `, 251 }, 252 { 253 desc: "arrays with same items", 254 a: `apiVersion: autoscaling/v2 255 kind: HorizontalPodAutoscaler 256 metadata: 257 name: istio-ingressgateway 258 namespace: istio-system 259 labels: 260 - label1 261 - label2 262 - label3 263 `, 264 b: `apiVersion: autoscaling/v2 265 kind: HorizontalPodAutoscaler 266 metadata: 267 name: istio-ingressgateway 268 namespace: istio-system 269 labels: 270 - label1 271 - label2 272 - label3 273 `, 274 want: ``, 275 }, 276 { 277 desc: "arrays with different items", 278 a: `apiVersion: autoscaling/v2 279 kind: HorizontalPodAutoscaler 280 metadata: 281 name: istio-ingressgateway 282 namespace: istio-system 283 labels: 284 - label1 285 - label2 286 - label3 287 `, 288 b: `apiVersion: autoscaling/v2 289 kind: HorizontalPodAutoscaler 290 metadata: 291 name: istio-ingressgateway 292 namespace: istio-system 293 labels: 294 - label1 295 - label5 296 - label6 297 `, 298 want: `metadata: 299 labels: 300 '[#1]': label2 -> label5 301 '[#2]': label3 -> label6 302 `, 303 }, 304 { 305 desc: "arrays with same items, order changed", 306 a: `apiVersion: autoscaling/v2 307 kind: HorizontalPodAutoscaler 308 metadata: 309 name: istio-ingressgateway 310 namespace: istio-system 311 labels: 312 - label1 313 - label2 314 - label3 315 `, 316 b: `apiVersion: autoscaling/v2 317 kind: HorizontalPodAutoscaler 318 metadata: 319 name: istio-ingressgateway 320 namespace: istio-system 321 labels: 322 - label2 323 - label3 324 - label1 325 `, 326 want: `metadata: 327 labels: 328 '[?->2]': <empty> -> label1 (ADDED) 329 '[0->?]': label1 -> <empty> (REMOVED) 330 `, 331 }, 332 { 333 desc: "arrays with items", 334 a: `apiVersion: autoscaling/v2 335 kind: HorizontalPodAutoscaler 336 metadata: 337 name: istio-ingressgateway 338 namespace: istio-system 339 labels: 340 - label0 341 - label1 342 - label2 343 `, 344 b: `apiVersion: autoscaling/v2 345 kind: HorizontalPodAutoscaler 346 metadata: 347 name: istio-ingressgateway 348 namespace: istio-system 349 labels: 350 - label4 351 - label5 352 - label2 353 - label3 354 - label1 355 - label0 356 `, 357 want: `metadata: 358 labels: 359 '[#0]': label0 -> label4 360 '[?->1]': <empty> -> label5 (ADDED) 361 '[?->2]': <empty> -> label2 (ADDED) 362 '[?->3]': <empty> -> label3 (ADDED) 363 '[2->5]': label2 -> label0 364 `, 365 }, 366 { 367 desc: "arrays with additional items", 368 a: `apiVersion: autoscaling/v2 369 kind: HorizontalPodAutoscaler 370 metadata: 371 name: istio-ingressgateway 372 namespace: istio-system 373 labels: 374 - label1 375 - label2 376 - label3 377 `, 378 b: `apiVersion: autoscaling/v2 379 kind: HorizontalPodAutoscaler 380 metadata: 381 name: istio-ingressgateway 382 namespace: istio-system 383 labels: 384 - label1 385 - label2 386 - label3 387 - label4 388 - label5 389 `, 390 want: `metadata: 391 labels: 392 '[?->3]': <empty> -> label4 (ADDED) 393 '[?->4]': <empty> -> label5 (ADDED) 394 `, 395 }, 396 { 397 desc: "arrays with missing items", 398 a: `apiVersion: autoscaling/v2 399 kind: HorizontalPodAutoscaler 400 metadata: 401 name: istio-ingressgateway 402 namespace: istio-system 403 labels: 404 - label1 405 - label2 406 - label3 407 - label4 408 - label5 409 `, 410 b: `apiVersion: autoscaling/v2 411 kind: HorizontalPodAutoscaler 412 metadata: 413 name: istio-ingressgateway 414 namespace: istio-system 415 labels: 416 - label1 417 - label2 418 - label3 419 `, 420 want: `metadata: 421 labels: 422 '[3->?]': label4 -> <empty> (REMOVED) 423 '[4->?]': label5 -> <empty> (REMOVED) 424 `, 425 }, 426 } 427 for _, tt := range tests { 428 t.Run(tt.desc, func(t *testing.T) { 429 if got, want := YAMLCmp(tt.a, tt.b), tt.want; !(got == want) { 430 t.Errorf("%s: got:%v, want:%v", tt.desc, got, want) 431 } 432 }) 433 } 434 } 435 436 func TestYAMLCmpWithIgnore(t *testing.T) { 437 tests := []struct { 438 desc string 439 a string 440 b string 441 i []string 442 want any 443 }{ 444 { 445 desc: "identical", 446 a: `apiVersion: autoscaling/v2 447 kind: HorizontalPodAutoscaler 448 metadata: 449 name: istio-ingressgateway 450 namespace: istio-system 451 labels: 452 app: istio-ingressgateway 453 release: istio`, 454 b: `apiVersion: autoscaling/v2 455 kind: HorizontalPodAutoscaler 456 metadata: 457 name: istio-ingressgateway 458 namespace: istio-system 459 labels: 460 app: istio-ingressgateway 461 release: istio`, 462 i: []string{"metadata.annotations.checksum/config-volume"}, 463 want: ``, 464 }, 465 { 466 desc: "ignore checksum", 467 a: `apiVersion: autoscaling/v2 468 kind: Deployment 469 metadata: 470 annotations: 471 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 472 name: istio-ingressgateway 473 namespace: istio-system 474 labels: 475 app: istio-ingressgateway 476 release: istio`, 477 b: `apiVersion: autoscaling/v2 478 kind: Deployment 479 metadata: 480 annotations: 481 checksum/config-volume: 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 482 name: istio-ingressgateway 483 namespace: istio-system 484 labels: 485 app: istio-ingressgateway 486 release: istio`, 487 i: []string{"metadata.annotations.checksum/config-volume"}, 488 want: ``, 489 }, 490 { 491 desc: "ignore missing checksum value", 492 a: `apiVersion: autoscaling/v2 493 kind: Deployment 494 metadata: 495 annotations: 496 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 497 name: istio-ingressgateway 498 namespace: istio-system 499 labels: 500 app: istio-ingressgateway 501 release: istio`, 502 b: `apiVersion: autoscaling/v2 503 kind: Deployment 504 metadata: 505 annotations: 506 checksum/config-volume: 507 name: istio-ingressgateway 508 namespace: istio-system 509 labels: 510 app: istio-ingressgateway 511 release: istio`, 512 i: []string{"metadata.annotations.checksum/config-volume"}, 513 want: ``, 514 }, 515 { 516 desc: "ignore additional checksum value", 517 a: `apiVersion: autoscaling/v2 518 kind: Deployment 519 metadata: 520 annotations: 521 checksum/config-volume: 522 name: istio-ingressgateway 523 namespace: istio-system 524 labels: 525 app: istio-ingressgateway 526 release: istio`, 527 b: `apiVersion: autoscaling/v2 528 kind: Deployment 529 metadata: 530 annotations: 531 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 532 name: istio-ingressgateway 533 namespace: istio-system 534 labels: 535 app: istio-ingressgateway 536 release: istio`, 537 i: []string{"metadata.annotations.checksum/config-volume"}, 538 want: ``, 539 }, 540 { 541 desc: "show checksum not exist", 542 a: `apiVersion: autoscaling/v2 543 kind: Deployment 544 metadata: 545 annotations: 546 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 547 name: istio-ingressgateway 548 namespace: istio-system 549 labels: 550 app: istio-ingressgateway 551 release: istio`, 552 b: `apiVersion: autoscaling/v2 553 kind: Deployment 554 metadata: 555 annotations: 556 name: istio-ingressgateway 557 namespace: istio-system 558 labels: 559 app: istio-ingressgateway 560 release: istio`, 561 i: []string{"metadata.annotations.checksum/config-volume"}, 562 want: `metadata: 563 annotations: map[checksum/config-volume:43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60] 564 -> <empty> (REMOVED) 565 `, 566 }, 567 { 568 desc: "ignore by wildcard", 569 a: `apiVersion: autoscaling/v2 570 kind: Deployment 571 metadata: 572 annotations: 573 checksum/config-volume: 01d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 574 name: istio-ingressgateway 575 namespace: istio-system 576 labels: 577 checksum/config-volume: 02ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 578 app: istio-ingressgateway 579 release: istio`, 580 b: `apiVersion: autoscaling/v2 581 kind: Deployment 582 metadata: 583 annotations: 584 checksum/config-volume: 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 585 name: istio-ingressgateway 586 namespace: istio-system 587 labels: 588 checksum/config-volume: 04ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 589 app: istio-ingressgateway 590 release: istio`, 591 i: []string{"*.checksum/config-volume"}, 592 want: ``, 593 }, 594 { 595 desc: "ignore by wildcard negative", 596 a: `apiVersion: autoscaling/v2 597 kind: Deployment 598 metadata: 599 annotations: 600 checksum/config-volume: 01d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 601 name: istio-ingressgateway 602 namespace: istio-system 603 labels: 604 checksum/config-volume: 02ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 605 app: istio-ingressgateway 606 release: istio`, 607 b: `apiVersion: autoscaling/v2 608 kind: Deployment 609 metadata: 610 annotations: 611 checksum/config-volume: 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 612 name: istio-ingressgateway 613 namespace: istio-system 614 labels: 615 checksum/config-volume: 04ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 616 app: istio-ingressgateway 617 release: istio`, 618 i: []string{"*labels.checksum/config-volume"}, 619 want: `metadata: 620 annotations: 621 checksum/config-volume: 01d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 622 -> 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 623 `, 624 }, 625 { 626 desc: "ignore multiple paths", 627 a: `apiVersion: autoscaling/v2 628 kind: Deployment 629 metadata: 630 annotations: 631 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 632 name: istio-ingressgateway 633 namespace: istio-system 634 labels: 635 app: ingressgateway 636 release: istio`, 637 b: `apiVersion: autoscaling/v2 638 kind: Deployment 639 metadata: 640 annotations: 641 checksum/config-volume: 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 642 name: istio-ingressgateway 643 namespace: istio-system 644 labels: 645 app: istio-ingressgateway 646 release: istio`, 647 i: []string{ 648 "metadata.annotations.checksum/config-volume", 649 "metadata.labels.app", 650 }, 651 want: ``, 652 }, 653 { 654 desc: "ignore multiple paths negative", 655 a: `apiVersion: autoscaling/v2 656 kind: Deployment 657 metadata: 658 annotations: 659 checksum/config-volume: 43d72e930ed33e3e01731f8bcbf31dbf02cb1c1fc53bcc09199ab45c0d031b60 660 name: istio-ingressgateway 661 namespace: istio-system 662 labels: 663 app: ingressgateway 664 release: istio`, 665 b: `apiVersion: autoscaling/v2 666 kind: Deployment 667 metadata: 668 annotations: 669 checksum/config-volume: 03ba6246b2c39b48a4f8c3a92c3420a0416804d38ebe292e65cf674fb0875192 670 name: istio-ingressgateway 671 namespace: istio-system 672 labels: 673 app: istio-ingressgateway 674 release: istio`, 675 i: []string{ 676 "metadata.annotations.checksum/config-volume", 677 }, 678 want: `metadata: 679 labels: 680 app: ingressgateway -> istio-ingressgateway 681 `, 682 }, 683 } 684 for _, tt := range tests { 685 t.Run(tt.desc, func(t *testing.T) { 686 if got, want := YAMLCmpWithIgnore(tt.a, tt.b, tt.i, ""), tt.want; !(got == want) { 687 t.Errorf("%s: got:%v, want:%v", tt.desc, got, want) 688 } 689 }) 690 } 691 } 692 693 func TestYAMLCmpWithIgnoreTree(t *testing.T) { 694 tests := []struct { 695 desc string 696 a string 697 b string 698 mask string 699 want any 700 }{ 701 { 702 desc: "ignore masked", 703 a: ` 704 ak: av 705 bk: 706 b1k: b1v 707 b2k: b2v 708 `, 709 b: ` 710 ak: av 711 bk: 712 b1k: b1v-changed 713 b2k: b2v-changed 714 `, 715 mask: ` 716 bk: 717 b1k: ignored 718 b2k: ignored 719 `, 720 want: ``, 721 }, 722 { 723 desc: "ignore nested masked", 724 a: ` 725 ak: av 726 bk: 727 bbk: 728 b1k: b1v 729 b2k: b2v 730 `, 731 b: ` 732 ak: av 733 bk: 734 bbk: 735 b1k: b1v-changed 736 b2k: b2v-changed 737 `, 738 mask: ` 739 bk: 740 bbk: 741 b1k: ignored 742 `, 743 want: `bk: 744 bbk: 745 b2k: b2v -> b2v-changed 746 `, 747 }, 748 { 749 desc: "not ignore non-masked", 750 a: ` 751 ak: av 752 bk: 753 bbk: 754 b1k: b1v 755 b2k: b2v 756 `, 757 b: ` 758 ak: av 759 bk: 760 bbk: 761 b1k: b1v-changed 762 b2k: b2v 763 `, 764 mask: ` 765 bk: 766 bbk: 767 b1k: 768 bbb1k: ignored 769 `, 770 want: `bk: 771 bbk: 772 b1k: b1v -> b1v-changed 773 `, 774 }, 775 } 776 for _, tt := range tests { 777 t.Run(tt.desc, func(t *testing.T) { 778 if got, want := YAMLCmpWithIgnore(tt.a, tt.b, nil, tt.mask), tt.want; !(got == want) { 779 t.Errorf("%s: got:%v, want:%v", tt.desc, got, want) 780 } 781 }) 782 } 783 } 784 785 func TestYAMLCmpWithYamlInline(t *testing.T) { 786 tests := []struct { 787 desc string 788 a string 789 b string 790 want any 791 }{ 792 { 793 desc: "ConfigMap data order changed", 794 a: `kind: ConfigMap 795 data: 796 validatingwebhookconfiguration.yaml: |- 797 kind: ValidatingWebhookConfiguration 798 apiVersion: admissionregistration.k8s.io/v1beta1 799 metadata: 800 name: istio-galley 801 value: foo`, 802 b: `kind: ConfigMap 803 data: 804 validatingwebhookconfiguration.yaml: |- 805 apiVersion: admissionregistration.k8s.io/v1beta1 806 kind: ValidatingWebhookConfiguration 807 metadata: 808 value: foo 809 name: istio-galley`, 810 want: ``, 811 }, 812 { 813 desc: "ConfigMap data value change", 814 a: `kind: ConfigMap 815 data: 816 validatingwebhookconfiguration.yaml: |- 817 apiVersion: admissionregistration.k8s.io/v1beta1 818 kind: ValidatingWebhookConfiguration 819 metadata: 820 name: istio-galley`, 821 b: `kind: ConfigMap 822 data: 823 validatingwebhookconfiguration.yaml: |- 824 kind: ValidatingWebhookConfiguration 825 apiVersion: admissionregistration.k8s.io/v1beta2 826 metadata: 827 name: istio-galley`, 828 want: `data: 829 validatingwebhookconfiguration.yaml: 830 apiVersion: admissionregistration.k8s.io/v1beta1 -> admissionregistration.k8s.io/v1beta2 831 `, 832 }, 833 { 834 desc: "ConfigMap data deep nested value change", 835 a: `apiVersion: v1 836 kind: ConfigMap 837 metadata: 838 name: injector-mesh 839 data: 840 mesh: |- 841 defaultConfig: 842 tracing: 843 zipkin: 844 address: zipkin.istio-system:9411 845 controlPlaneAuthPolicy: NONE 846 connectTimeout: 10s`, 847 b: `apiVersion: v1 848 kind: ConfigMap 849 metadata: 850 name: injector-mesh 851 data: 852 mesh: |- 853 defaultConfig: 854 connectTimeout: 10s 855 tracing: 856 zipkin: 857 address: zipkin.istio-system:9412 858 controlPlaneAuthPolicy: NONE`, 859 want: `data: 860 mesh: 861 defaultConfig: 862 tracing: 863 zipkin: 864 address: zipkin.istio-system:9411 -> zipkin.istio-system:9412 865 `, 866 }, 867 { 868 desc: "ConfigMap data multiple changes", 869 a: `apiVersion: v1 870 kind: ConfigMap 871 metadata: 872 name: injector-mesh 873 namespace: istio-system 874 labels: 875 release: istio 876 data: 877 mesh: |- 878 defaultConfig: 879 connectTimeout: 10s 880 configPath: "/etc/istio/proxyv1" 881 serviceCluster: istio-proxy 882 drainDuration: 45s 883 proxyAdminPortA: 15000 884 concurrency: 2 885 tracing: 886 zipkin: 887 address: zipkin.istio-system:9411 888 controlPlaneAuthPolicy: NONE 889 discoveryAddress: istio-pilot.istio-system:15010`, 890 b: `apiVersion: v1 891 kind: ConfigMap 892 metadata: 893 name: injector-mesh 894 namespace: istio-system 895 labels: 896 release: istio 897 data: 898 mesh: |- 899 defaultConfig: 900 connectTimeout: 10s 901 configPath: "/etc/istio/proxyv2" 902 serviceCluster: istio-proxy 903 drainDuration: 45s 904 proxyAdminPortB: 15000 905 concurrency: 2 906 tracing: 907 zipkin: 908 address: zipkin.istio-system:9411 909 controlPlaneAuthPolicy: NONE 910 discoveryAddress: istio-pilot.istio-system:15010`, 911 want: `data: 912 mesh: 913 defaultConfig: 914 configPath: /etc/istio/proxyv1 -> /etc/istio/proxyv2 915 proxyAdminPortA: 15000 -> <empty> (REMOVED) 916 proxyAdminPortB: <empty> -> 15000 (ADDED) 917 `, 918 }, 919 { 920 desc: "Not ConfigMap, identical", 921 a: `kind: Config 922 data: 923 validatingwebhookconfiguration.yaml: |- 924 apiVersion: admissionregistration.k8s.io/v1beta1 925 kind: ValidatingWebhookConfiguration 926 metadata: 927 name: istio-galley`, 928 b: `kind: Config 929 data: 930 validatingwebhookconfiguration.yaml: |- 931 apiVersion: admissionregistration.k8s.io/v1beta1 932 kind: ValidatingWebhookConfiguration 933 metadata: 934 name: istio-galley`, 935 want: ``, 936 }, 937 { 938 desc: "Not ConfigMap, Order changed", 939 a: `kind: Config 940 data: 941 validatingwebhookconfiguration.yaml: |- 942 apiVersion: admissionregistration.k8s.io/v1beta1 943 kind: ValidatingWebhookConfiguration 944 metadata: 945 name: istio-galley`, 946 b: `kind: Config 947 data: 948 validatingwebhookconfiguration.yaml: |- 949 kind: ValidatingWebhookConfiguration 950 apiVersion: admissionregistration.k8s.io/v1beta1 951 metadata: 952 name: istio-galley`, 953 want: `data: 954 validatingwebhookconfiguration.yaml: |- 955 apiVersion: admissionregistration.k8s.io/v1beta1 956 kind: ValidatingWebhookConfiguration 957 metadata: 958 name: istio-galley -> kind: ValidatingWebhookConfiguration 959 apiVersion: admissionregistration.k8s.io/v1beta1 960 metadata: 961 name: istio-galley 962 `, 963 }, 964 } 965 for _, tt := range tests { 966 t.Run(tt.desc, func(t *testing.T) { 967 if got, want := YAMLCmp(tt.a, tt.b), tt.want; !(got == want) { 968 t.Errorf("%s: got:%v, want:%v", tt.desc, got, want) 969 } 970 }) 971 } 972 } 973 974 func TestManifestDiff(t *testing.T) { 975 testDeploymentYaml1 := `apiVersion: apps/v1 976 kind: Deployment 977 metadata: 978 name: istio-citadel 979 namespace: istio-system 980 labels: 981 istio: citadel 982 spec: 983 replicas: 1 984 template: 985 metadata: 986 labels: 987 istio: citadel 988 spec: 989 containers: 990 - name: citadel 991 image: docker.io/istio/citadel:1.1.8 992 ` 993 994 testDeploymentYaml2 := `apiVersion: apps/v1 995 kind: Deployment 996 metadata: 997 name: istio-citadel 998 namespace: istio-system 999 labels: 1000 istio: citadel 1001 spec: 1002 replicas: 1 1003 template: 1004 metadata: 1005 labels: 1006 istio: citadel 1007 spec: 1008 containers: 1009 - name: citadel 1010 image: docker.io/istio/citadel:1.2.2 1011 ` 1012 1013 testPodYaml1 := `apiVersion: v1 1014 kind: Pod 1015 metadata: 1016 name: istio-galley-75bcd59768-hpt5t 1017 namespace: istio-system 1018 labels: 1019 istio: galley 1020 spec: 1021 containers: 1022 - name: galley 1023 image: docker.io/istio/galley:1.1.8 1024 ports: 1025 - containerPort: 443 1026 protocol: TCP 1027 - containerPort: 15014 1028 protocol: TCP 1029 - containerPort: 9901 1030 protocol: TCP 1031 ` 1032 1033 testServiceYaml1 := `apiVersion: v1 1034 kind: Service 1035 metadata: 1036 labels: 1037 app: pilot 1038 name: istio-pilot 1039 namespace: istio-system 1040 spec: 1041 type: ClusterIP 1042 ports: 1043 - name: grpc-xds 1044 port: 15010 1045 protocol: TCP 1046 targetPort: 15010 1047 - name: http-monitoring 1048 port: 15014 1049 protocol: TCP 1050 targetPort: 15014 1051 selector: 1052 istio: pilot 1053 ` 1054 1055 manifestDiffTests := []struct { 1056 desc string 1057 yamlStringA string 1058 yamlStringB string 1059 want string 1060 }{ 1061 { 1062 "ManifestDiffWithIdenticalResource", 1063 testDeploymentYaml1 + object.YAMLSeparator, 1064 testDeploymentYaml1, 1065 "", 1066 }, 1067 { 1068 "ManifestDiffWithIdenticalMultipleResources", 1069 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1070 testPodYaml1 + object.YAMLSeparator + testServiceYaml1 + object.YAMLSeparator + testDeploymentYaml1, 1071 "", 1072 }, 1073 { 1074 "ManifestDiffWithDifferentResource", 1075 testDeploymentYaml1, 1076 testDeploymentYaml2, 1077 "Object Deployment:istio-system:istio-citadel has diffs", 1078 }, 1079 { 1080 "ManifestDiffWithDifferentMultipleResources", 1081 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1082 testDeploymentYaml2 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1083 "Object Deployment:istio-system:istio-citadel has diffs", 1084 }, 1085 { 1086 "ManifestDiffMissingResourcesInA", 1087 testPodYaml1 + object.YAMLSeparator + testDeploymentYaml1 + object.YAMLSeparator, 1088 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1089 "Object Service:istio-system:istio-pilot is missing in A", 1090 }, 1091 { 1092 "ManifestDiffMissingResourcesInB", 1093 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1094 testServiceYaml1 + object.YAMLSeparator + testPodYaml1, 1095 "Object Deployment:istio-system:istio-citadel is missing in B", 1096 }, 1097 } 1098 1099 for _, tt := range manifestDiffTests { 1100 for _, v := range []bool{true, false} { 1101 t.Run(tt.desc, func(t *testing.T) { 1102 got, err := ManifestDiff(tt.yamlStringA, tt.yamlStringB, v) 1103 if err != nil { 1104 t.Fatalf("unexpected error: %v", err) 1105 } 1106 if !strings.Contains(got, tt.want) { 1107 t.Errorf("%s:\ngot:\n%v\ndoes't contains\nwant:\n%v", tt.desc, got, tt.want) 1108 } 1109 }) 1110 } 1111 } 1112 } 1113 1114 func TestManifestDiffWithSelectAndIgnore(t *testing.T) { 1115 testDeploymentYaml1 := `apiVersion: apps/v1 1116 kind: Deployment 1117 metadata: 1118 name: istio-citadel 1119 namespace: istio-system 1120 labels: 1121 istio: citadel 1122 spec: 1123 replicas: 1 1124 selector: 1125 matchLabels: 1126 istio: citadel 1127 template: 1128 metadata: 1129 labels: 1130 istio: citadel 1131 spec: 1132 containers: 1133 - name: citadel 1134 image: docker.io/istio/citadel:1.1.8 1135 --- 1136 ` 1137 1138 testDeploymentYaml2 := `apiVersion: apps/v1 1139 kind: Deployment 1140 metadata: 1141 name: istio-citadel 1142 namespace: istio-system 1143 labels: 1144 istio: citadel 1145 spec: 1146 replicas: 1 1147 selector: 1148 matchLabels: 1149 istio: citadel 1150 template: 1151 metadata: 1152 labels: 1153 istio: citadel 1154 spec: 1155 containers: 1156 - name: citadel 1157 image: docker.io/istio/citadel:1.2.2 1158 --- 1159 ` 1160 1161 testPodYaml1 := `apiVersion: v1 1162 kind: Pod 1163 metadata: 1164 name: istio-galley-75bcd59768-hpt5t 1165 namespace: istio-system 1166 labels: 1167 istio: galley 1168 spec: 1169 containers: 1170 - name: galley 1171 image: docker.io/istio/galley:1.1.8 1172 ports: 1173 - containerPort: 443 1174 protocol: TCP 1175 - containerPort: 15014 1176 protocol: TCP 1177 - containerPort: 9901 1178 protocol: TCP 1179 --- 1180 ` 1181 1182 testServiceYaml1 := `apiVersion: v1 1183 kind: Service 1184 metadata: 1185 labels: 1186 app: pilot 1187 name: istio-pilot 1188 namespace: istio-system 1189 spec: 1190 type: ClusterIP 1191 ports: 1192 - name: grpc-xds 1193 port: 15010 1194 protocol: TCP 1195 targetPort: 15010 1196 - name: http-monitoring 1197 port: 15014 1198 protocol: TCP 1199 targetPort: 15014 1200 selector: 1201 istio: pilot 1202 --- 1203 ` 1204 1205 manifestDiffWithSelectAndIgnoreTests := []struct { 1206 desc string 1207 yamlStringA string 1208 yamlStringB string 1209 selectResources string 1210 ignoreResources string 1211 want string 1212 }{ 1213 { 1214 "ManifestDiffWithSelectAndIgnoreForIdenticalResource", 1215 testDeploymentYaml1 + object.YAMLSeparator, 1216 testDeploymentYaml1, 1217 "::", 1218 "", 1219 "", 1220 }, 1221 { 1222 "ManifestDiffWithSelectAndIgnoreForDifferentResourcesIgnoreSingle", 1223 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1224 testDeploymentYaml1 + object.YAMLSeparator, 1225 "Deployment:*:istio-citadel", 1226 "Service:*:", 1227 "", 1228 }, 1229 { 1230 "ManifestDiffWithSelectAndIgnoreForDifferentResourcesIgnoreMultiple", 1231 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1232 testDeploymentYaml1, 1233 "Deployment:*:istio-citadel", 1234 "Pod::*,Service:istio-system:*", 1235 "", 1236 }, 1237 { 1238 "ManifestDiffWithSelectAndIgnoreForDifferentResourcesSelectSingle", 1239 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1240 testServiceYaml1 + object.YAMLSeparator + testDeploymentYaml1, 1241 "Deployment::istio-citadel", 1242 "Pod:*:*", 1243 "", 1244 }, 1245 { 1246 "ManifestDiffWithSelectAndIgnoreForDifferentResourcesSelectSingle", 1247 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1248 testServiceYaml1 + object.YAMLSeparator + testDeploymentYaml1, 1249 "Deployment::istio-citadel,Service:istio-system:istio-pilot,Pod:*:*", 1250 "Pod:*:*", 1251 "", 1252 }, 1253 { 1254 "ManifestDiffWithSelectAndIgnoreForDifferentResourceForDefault", 1255 testDeploymentYaml1, 1256 testDeploymentYaml2 + object.YAMLSeparator, 1257 "::", 1258 "", 1259 "Object Deployment:istio-system:istio-citadel has diffs", 1260 }, 1261 { 1262 "ManifestDiffWithSelectAndIgnoreForDifferentResourceForSingleSelectAndIgnore", 1263 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1264 testDeploymentYaml2 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1265 "Deployment:*:*", 1266 "Pod:*:*", 1267 "Object Deployment:istio-system:istio-citadel has diffs", 1268 }, 1269 { 1270 "ManifestDiffWithSelectAndIgnoreForMissingResourcesInA", 1271 testPodYaml1 + object.YAMLSeparator + testDeploymentYaml1, 1272 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1273 "Pod:istio-system:Citadel,Service:istio-system:", 1274 "Pod:*:*", 1275 "Object Service:istio-system:istio-pilot is missing in A", 1276 }, 1277 { 1278 "ManifestDiffWithSelectAndIgnoreForMissingResourcesInB", 1279 testDeploymentYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator + testServiceYaml1, 1280 testServiceYaml1 + object.YAMLSeparator + testPodYaml1 + object.YAMLSeparator, 1281 "*:istio-system:*", 1282 "Pod::", 1283 "Object Deployment:istio-system:istio-citadel is missing in B", 1284 }, 1285 } 1286 1287 for _, tt := range manifestDiffWithSelectAndIgnoreTests { 1288 for _, v := range []bool{true, false} { 1289 t.Run(tt.desc, func(t *testing.T) { 1290 got, err := ManifestDiffWithRenameSelectIgnore(tt.yamlStringA, tt.yamlStringB, 1291 "", tt.selectResources, tt.ignoreResources, v) 1292 if err != nil { 1293 t.Fatalf("unexpected error: %v", err) 1294 } 1295 if !strings.Contains(got, tt.want) { 1296 t.Errorf("%s:\ngot:\n%v\ndoes't contains\nwant:\n%v", tt.desc, got, tt.want) 1297 } 1298 }) 1299 } 1300 } 1301 } 1302 1303 func TestManifestDiffWithRenameSelectIgnore(t *testing.T) { 1304 testDeploymentYaml := `apiVersion: apps/v1 1305 kind: Deployment 1306 metadata: 1307 name: istio-citadel 1308 namespace: istio-system 1309 labels: 1310 istio: citadel 1311 spec: 1312 replicas: 1 1313 selector: 1314 matchLabels: 1315 istio: citadel 1316 template: 1317 metadata: 1318 labels: 1319 istio: citadel 1320 spec: 1321 containers: 1322 - name: citadel 1323 image: docker.io/istio/citadel:1.1.8 1324 --- 1325 ` 1326 1327 testDeploymentYamlRenamed := `apiVersion: apps/v1 1328 kind: Deployment 1329 metadata: 1330 name: istio-ca 1331 namespace: istio-system 1332 labels: 1333 istio: citadel 1334 spec: 1335 replicas: 1 1336 selector: 1337 matchLabels: 1338 istio: citadel 1339 template: 1340 metadata: 1341 labels: 1342 istio: citadel 1343 spec: 1344 containers: 1345 - name: citadel 1346 image: docker.io/istio/citadel:1.1.8 1347 --- 1348 ` 1349 1350 testServiceYaml := `apiVersion: v1 1351 kind: Service 1352 metadata: 1353 labels: 1354 app: pilot 1355 name: istio-pilot 1356 namespace: istio-system 1357 spec: 1358 type: ClusterIP 1359 ports: 1360 - name: grpc-xds 1361 port: 15010 1362 protocol: TCP 1363 targetPort: 15010 1364 - name: http-monitoring 1365 port: 15014 1366 protocol: TCP 1367 targetPort: 15014 1368 selector: 1369 istio: pilot 1370 --- 1371 ` 1372 1373 testServiceYamlRenamed := `apiVersion: v1 1374 kind: Service 1375 metadata: 1376 labels: 1377 app: pilot 1378 name: istio-control 1379 namespace: istio-system 1380 spec: 1381 type: ClusterIP 1382 ports: 1383 - name: grpc-xds 1384 port: 15010 1385 protocol: TCP 1386 targetPort: 15010 1387 - name: http-monitoring 1388 port: 15014 1389 protocol: TCP 1390 targetPort: 15014 1391 selector: 1392 istio: pilot 1393 --- 1394 ` 1395 1396 manifestDiffWithRenameSelectIgnoreTests := []struct { 1397 desc string 1398 yamlStringA string 1399 yamlStringB string 1400 renameResources string 1401 selectResources string 1402 ignoreResources string 1403 want string 1404 }{ 1405 { 1406 "ManifestDiffDeployWithRenamedFlagMultiResourceWildcard", 1407 testDeploymentYaml + object.YAMLSeparator + testServiceYaml, 1408 testDeploymentYamlRenamed + object.YAMLSeparator + testServiceYamlRenamed, 1409 "Service:*:istio-pilot->::istio-control,Deployment::istio-citadel->::istio-ca", 1410 "::", 1411 "", 1412 ` 1413 1414 Object Deployment:istio-system:istio-ca has diffs: 1415 1416 metadata: 1417 name: istio-citadel -> istio-ca 1418 1419 1420 Object Service:istio-system:istio-control has diffs: 1421 1422 metadata: 1423 name: istio-pilot -> istio-control 1424 `, 1425 }, 1426 { 1427 "ManifestDiffDeployWithRenamedFlagMultiResource", 1428 testDeploymentYaml + object.YAMLSeparator + testServiceYaml, 1429 testDeploymentYamlRenamed + object.YAMLSeparator + testServiceYamlRenamed, 1430 "Service:istio-system:istio-pilot->Service:istio-system:istio-control,Deployment:istio-system:istio-citadel->Deployment:istio-system:istio-ca", 1431 "::", 1432 "", 1433 ` 1434 1435 Object Deployment:istio-system:istio-ca has diffs: 1436 1437 metadata: 1438 name: istio-citadel -> istio-ca 1439 1440 1441 Object Service:istio-system:istio-control has diffs: 1442 1443 metadata: 1444 name: istio-pilot -> istio-control 1445 `, 1446 }, 1447 { 1448 "ManifestDiffDeployWithRenamedFlag", 1449 testDeploymentYaml, 1450 testDeploymentYamlRenamed, 1451 "Deployment:istio-system:istio-citadel->Deployment:istio-system:istio-ca", 1452 "::", 1453 "", 1454 ` 1455 1456 Object Deployment:istio-system:istio-ca has diffs: 1457 1458 metadata: 1459 name: istio-citadel -> istio-ca 1460 `, 1461 }, 1462 { 1463 "ManifestDiffRenamedDeploy", 1464 testDeploymentYaml, 1465 testDeploymentYamlRenamed, 1466 "", 1467 "::", 1468 "", 1469 ` 1470 1471 Object Deployment:istio-system:istio-ca is missing in A: 1472 1473 1474 1475 Object Deployment:istio-system:istio-citadel is missing in B: 1476 1477 `, 1478 }, 1479 } 1480 1481 for _, tt := range manifestDiffWithRenameSelectIgnoreTests { 1482 t.Run(tt.desc, func(t *testing.T) { 1483 got, err := ManifestDiffWithRenameSelectIgnore(tt.yamlStringA, tt.yamlStringB, 1484 tt.renameResources, tt.selectResources, tt.ignoreResources, false) 1485 if err != nil { 1486 t.Fatalf("unexpected error: %v", err) 1487 } 1488 if got != tt.want { 1489 t.Errorf("%s:\ngot:\n%v\ndoes't equals to\nwant:\n%v", tt.desc, got, tt.want) 1490 } 1491 }) 1492 } 1493 }