github.com/containers/podman/v4@v4.9.4/pkg/specgen/generate/kube/play_test.go (about) 1 //go:build linux && !remote 2 // +build linux,!remote 3 4 package kube 5 6 import ( 7 "math" 8 "runtime" 9 "strconv" 10 "testing" 11 12 "github.com/containers/common/pkg/secrets" 13 v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" 14 "github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/api/resource" 15 v12 "github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/apis/meta/v1" 16 "github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/util/intstr" 17 "github.com/containers/podman/v4/pkg/specgen" 18 "github.com/docker/docker/pkg/meminfo" 19 "github.com/stretchr/testify/assert" 20 "sigs.k8s.io/yaml" 21 ) 22 23 func createSecrets(t *testing.T, d string) *secrets.SecretsManager { 24 secretsManager, err := secrets.NewManager(d) 25 assert.NoError(t, err) 26 27 driver := "file" 28 driverOpts := map[string]string{ 29 "path": d, 30 } 31 32 storeOpts := secrets.StoreOptions{ 33 DriverOpts: driverOpts, 34 } 35 36 for _, s := range k8sSecrets { 37 data, err := yaml.Marshal(s) 38 assert.NoError(t, err) 39 40 _, err = secretsManager.Store(s.ObjectMeta.Name, data, driver, storeOpts) 41 assert.NoError(t, err) 42 } 43 44 return secretsManager 45 } 46 47 func TestConfigMapVolumes(t *testing.T) { 48 yes := true 49 tests := []struct { 50 name string 51 volume v1.Volume 52 configmaps []v1.ConfigMap 53 errorMessage string 54 expectedItems map[string][]byte 55 }{ 56 { 57 "VolumeFromConfigmap", 58 v1.Volume{ 59 Name: "test-volume", 60 VolumeSource: v1.VolumeSource{ 61 ConfigMap: &v1.ConfigMapVolumeSource{ 62 LocalObjectReference: v1.LocalObjectReference{ 63 Name: "bar", 64 }, 65 }, 66 }, 67 }, 68 configMapList, 69 "", 70 map[string][]byte{"myvar": []byte("bar")}, 71 }, 72 { 73 "VolumeFromBinaryConfigmap", 74 v1.Volume{ 75 Name: "test-volume", 76 VolumeSource: v1.VolumeSource{ 77 ConfigMap: &v1.ConfigMapVolumeSource{ 78 LocalObjectReference: v1.LocalObjectReference{ 79 Name: "binary-bar", 80 }, 81 }, 82 }, 83 }, 84 configMapList, 85 "", 86 map[string][]byte{"myvar": []byte("bin-bar")}, 87 }, 88 { 89 "ConfigmapMissing", 90 v1.Volume{ 91 Name: "test-volume", 92 VolumeSource: v1.VolumeSource{ 93 ConfigMap: &v1.ConfigMapVolumeSource{ 94 LocalObjectReference: v1.LocalObjectReference{ 95 Name: "fizz", 96 }, 97 }, 98 }, 99 }, 100 configMapList, 101 `no such ConfigMap "fizz"`, 102 map[string][]byte{}, 103 }, 104 { 105 "ConfigmapMissingOptional", 106 v1.Volume{ 107 Name: "test-volume", 108 VolumeSource: v1.VolumeSource{ 109 ConfigMap: &v1.ConfigMapVolumeSource{ 110 LocalObjectReference: v1.LocalObjectReference{ 111 Name: "fizz", 112 }, 113 Optional: &yes, 114 }, 115 }, 116 }, 117 configMapList, 118 "", 119 map[string][]byte{}, 120 }, 121 { 122 "MultiValue", 123 v1.Volume{ 124 Name: "test-volume", 125 VolumeSource: v1.VolumeSource{ 126 ConfigMap: &v1.ConfigMapVolumeSource{ 127 LocalObjectReference: v1.LocalObjectReference{ 128 Name: "multi-item", 129 }, 130 Optional: &yes, 131 }, 132 }, 133 }, 134 configMapList, 135 "", 136 map[string][]byte{"foo": []byte("bar"), "fizz": []byte("buzz")}, 137 }, 138 { 139 "SpecificValue", 140 v1.Volume{ 141 Name: "test-volume", 142 VolumeSource: v1.VolumeSource{ 143 ConfigMap: &v1.ConfigMapVolumeSource{ 144 LocalObjectReference: v1.LocalObjectReference{ 145 Name: "multi-item", 146 }, 147 Optional: &yes, 148 Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}}, 149 }, 150 }, 151 }, 152 configMapList, 153 "", 154 map[string][]byte{"/custom/path": []byte("buzz")}, 155 }, 156 { 157 "MultiValueBinary", 158 v1.Volume{ 159 Name: "test-volume", 160 VolumeSource: v1.VolumeSource{ 161 ConfigMap: &v1.ConfigMapVolumeSource{ 162 LocalObjectReference: v1.LocalObjectReference{ 163 Name: "multi-binary-item", 164 }, 165 Optional: &yes, 166 }, 167 }, 168 }, 169 configMapList, 170 "", 171 map[string][]byte{"foo": []byte("bin-bar"), "fizz": []byte("bin-buzz")}, 172 }, 173 { 174 "SpecificValueBinary", 175 v1.Volume{ 176 Name: "test-volume", 177 VolumeSource: v1.VolumeSource{ 178 ConfigMap: &v1.ConfigMapVolumeSource{ 179 LocalObjectReference: v1.LocalObjectReference{ 180 Name: "multi-binary-item", 181 }, 182 Optional: &yes, 183 Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}}, 184 }, 185 }, 186 }, 187 configMapList, 188 "", 189 map[string][]byte{"/custom/path": []byte("bin-buzz")}, 190 }, 191 { 192 "DuplicateValues", 193 v1.Volume{ 194 Name: "test-volume", 195 VolumeSource: v1.VolumeSource{ 196 ConfigMap: &v1.ConfigMapVolumeSource{ 197 LocalObjectReference: v1.LocalObjectReference{ 198 Name: "dupe", 199 }, 200 }, 201 }, 202 }, 203 configMapList, 204 `the ConfigMap "dupe" is invalid: duplicate key "foo" present in data and binaryData`, 205 map[string][]byte{}, 206 }, 207 { 208 "DuplicateValuesSpecific", 209 v1.Volume{ 210 Name: "test-volume", 211 VolumeSource: v1.VolumeSource{ 212 ConfigMap: &v1.ConfigMapVolumeSource{ 213 LocalObjectReference: v1.LocalObjectReference{ 214 Name: "dupe", 215 }, 216 Items: []v1.KeyToPath{{Key: "fizz", Path: "/custom/path"}}, 217 }, 218 }, 219 }, 220 configMapList, 221 `the ConfigMap "dupe" is invalid: duplicate key "foo" present in data and binaryData`, 222 map[string][]byte{}, 223 }, 224 } 225 226 for _, test := range tests { 227 test := test 228 t.Run(test.name, func(t *testing.T) { 229 result, err := VolumeFromConfigMap(test.volume.ConfigMap, test.configmaps) 230 if test.errorMessage == "" { 231 assert.NoError(t, err) 232 assert.Equal(t, test.expectedItems, result.Items) 233 } else { 234 assert.Error(t, err) 235 assert.Equal(t, test.errorMessage, err.Error()) 236 } 237 }) 238 } 239 } 240 241 func TestEnvVarsFrom(t *testing.T) { 242 d := t.TempDir() 243 secretsManager := createSecrets(t, d) 244 245 tests := []struct { 246 name string 247 envFrom v1.EnvFromSource 248 options CtrSpecGenOptions 249 succeed bool 250 expected map[string]string 251 }{ 252 { 253 "ConfigMapExists", 254 v1.EnvFromSource{ 255 ConfigMapRef: &v1.ConfigMapEnvSource{ 256 LocalObjectReference: v1.LocalObjectReference{ 257 Name: "foo", 258 }, 259 }, 260 }, 261 CtrSpecGenOptions{ 262 ConfigMaps: configMapList, 263 }, 264 true, 265 map[string]string{ 266 "myvar": "foo", 267 }, 268 }, 269 { 270 "ConfigMapDoesNotExist", 271 v1.EnvFromSource{ 272 ConfigMapRef: &v1.ConfigMapEnvSource{ 273 LocalObjectReference: v1.LocalObjectReference{ 274 Name: "doesnotexist", 275 }, 276 }, 277 }, 278 CtrSpecGenOptions{ 279 ConfigMaps: configMapList, 280 }, 281 false, 282 nil, 283 }, 284 { 285 "OptionalConfigMapDoesNotExist", 286 v1.EnvFromSource{ 287 ConfigMapRef: &v1.ConfigMapEnvSource{ 288 LocalObjectReference: v1.LocalObjectReference{ 289 Name: "doesnotexist", 290 }, 291 Optional: &optional, 292 }, 293 }, 294 CtrSpecGenOptions{ 295 ConfigMaps: configMapList, 296 }, 297 true, 298 map[string]string{}, 299 }, 300 { 301 "EmptyConfigMapList", 302 v1.EnvFromSource{ 303 ConfigMapRef: &v1.ConfigMapEnvSource{ 304 LocalObjectReference: v1.LocalObjectReference{ 305 Name: "foo", 306 }, 307 }, 308 }, 309 CtrSpecGenOptions{ 310 ConfigMaps: []v1.ConfigMap{}, 311 }, 312 false, 313 nil, 314 }, 315 { 316 "OptionalEmptyConfigMapList", 317 v1.EnvFromSource{ 318 ConfigMapRef: &v1.ConfigMapEnvSource{ 319 LocalObjectReference: v1.LocalObjectReference{ 320 Name: "foo", 321 }, 322 Optional: &optional, 323 }, 324 }, 325 CtrSpecGenOptions{ 326 ConfigMaps: []v1.ConfigMap{}, 327 }, 328 true, 329 map[string]string{}, 330 }, 331 { 332 "SecretExists", 333 v1.EnvFromSource{ 334 SecretRef: &v1.SecretEnvSource{ 335 LocalObjectReference: v1.LocalObjectReference{ 336 Name: "foo", 337 }, 338 }, 339 }, 340 CtrSpecGenOptions{ 341 SecretsManager: secretsManager, 342 }, 343 true, 344 map[string]string{ 345 "myvar": "foo", 346 }, 347 }, 348 { 349 "SecretDoesNotExist", 350 v1.EnvFromSource{ 351 SecretRef: &v1.SecretEnvSource{ 352 LocalObjectReference: v1.LocalObjectReference{ 353 Name: "doesnotexist", 354 }, 355 }, 356 }, 357 CtrSpecGenOptions{ 358 SecretsManager: secretsManager, 359 }, 360 false, 361 nil, 362 }, 363 { 364 "SecretExistsMultipleDataEntries", 365 v1.EnvFromSource{ 366 SecretRef: &v1.SecretEnvSource{ 367 LocalObjectReference: v1.LocalObjectReference{ 368 Name: "multi-data", 369 }, 370 }, 371 }, 372 CtrSpecGenOptions{ 373 SecretsManager: secretsManager, 374 }, 375 true, 376 map[string]string{ 377 "myvar": "foo", 378 "myvar1": "foo1", 379 }, 380 }, 381 { 382 "SecretExistsMultipleStringDataEntries", 383 v1.EnvFromSource{ 384 SecretRef: &v1.SecretEnvSource{ 385 LocalObjectReference: v1.LocalObjectReference{ 386 Name: "multi-stringdata", 387 }, 388 }, 389 }, 390 CtrSpecGenOptions{ 391 SecretsManager: secretsManager, 392 }, 393 true, 394 map[string]string{ 395 "myvar": "foo", 396 "myvar1": "foo1", 397 }, 398 }, 399 { 400 "SecretExistsMultipleDataStringDataEntries", 401 v1.EnvFromSource{ 402 SecretRef: &v1.SecretEnvSource{ 403 LocalObjectReference: v1.LocalObjectReference{ 404 Name: "multi-data-stringdata", 405 }, 406 }, 407 }, 408 CtrSpecGenOptions{ 409 SecretsManager: secretsManager, 410 }, 411 true, 412 map[string]string{ 413 "myvardata": "foodata", 414 "myvar1": "foo1string", // stringData overwrites data 415 "myvarstring": "foostring", 416 }, 417 }, 418 { 419 "OptionalSecretDoesNotExist", 420 v1.EnvFromSource{ 421 SecretRef: &v1.SecretEnvSource{ 422 LocalObjectReference: v1.LocalObjectReference{ 423 Name: "doesnotexist", 424 }, 425 Optional: &optional, 426 }, 427 }, 428 CtrSpecGenOptions{ 429 SecretsManager: secretsManager, 430 }, 431 true, 432 map[string]string{}, 433 }, 434 } 435 436 for _, test := range tests { 437 test := test 438 t.Run(test.name, func(t *testing.T) { 439 result, err := envVarsFrom(test.envFrom, &test.options) 440 assert.Equal(t, err == nil, test.succeed) 441 assert.Equal(t, test.expected, result) 442 }) 443 } 444 } 445 446 func TestEnvVarValue(t *testing.T) { 447 d := t.TempDir() 448 secretsManager := createSecrets(t, d) 449 stringNumCPUs := strconv.Itoa(runtime.NumCPU()) 450 451 mi, err := meminfo.Read() 452 assert.Nil(t, err) 453 stringMemTotal := strconv.FormatInt(mi.MemTotal, 10) 454 455 tests := []struct { 456 name string 457 envVar v1.EnvVar 458 options CtrSpecGenOptions 459 succeed bool 460 expected string 461 }{ 462 { 463 "ConfigMapExists", 464 v1.EnvVar{ 465 Name: "FOO", 466 ValueFrom: &v1.EnvVarSource{ 467 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 468 LocalObjectReference: v1.LocalObjectReference{ 469 Name: "foo", 470 }, 471 Key: "myvar", 472 }, 473 }, 474 }, 475 CtrSpecGenOptions{ 476 ConfigMaps: configMapList, 477 }, 478 true, 479 "foo", 480 }, 481 { 482 "ContainerKeyDoesNotExistInConfigMap", 483 v1.EnvVar{ 484 Name: "FOO", 485 ValueFrom: &v1.EnvVarSource{ 486 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 487 LocalObjectReference: v1.LocalObjectReference{ 488 Name: "foo", 489 }, 490 Key: "doesnotexist", 491 }, 492 }, 493 }, 494 CtrSpecGenOptions{ 495 ConfigMaps: configMapList, 496 }, 497 false, 498 nilString, 499 }, 500 { 501 "OptionalContainerKeyDoesNotExistInConfigMap", 502 v1.EnvVar{ 503 Name: "FOO", 504 ValueFrom: &v1.EnvVarSource{ 505 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 506 LocalObjectReference: v1.LocalObjectReference{ 507 Name: "foo", 508 }, 509 Key: "doesnotexist", 510 Optional: &optional, 511 }, 512 }, 513 }, 514 CtrSpecGenOptions{ 515 ConfigMaps: configMapList, 516 }, 517 true, 518 nilString, 519 }, 520 { 521 "ConfigMapDoesNotExist", 522 v1.EnvVar{ 523 Name: "FOO", 524 ValueFrom: &v1.EnvVarSource{ 525 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 526 LocalObjectReference: v1.LocalObjectReference{ 527 Name: "doesnotexist", 528 }, 529 Key: "myvar", 530 }, 531 }, 532 }, 533 CtrSpecGenOptions{ 534 ConfigMaps: configMapList, 535 }, 536 false, 537 nilString, 538 }, 539 { 540 "OptionalConfigMapDoesNotExist", 541 v1.EnvVar{ 542 Name: "FOO", 543 ValueFrom: &v1.EnvVarSource{ 544 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 545 LocalObjectReference: v1.LocalObjectReference{ 546 Name: "doesnotexist", 547 }, 548 Key: "myvar", 549 Optional: &optional, 550 }, 551 }, 552 }, 553 CtrSpecGenOptions{ 554 ConfigMaps: configMapList, 555 }, 556 true, 557 nilString, 558 }, 559 { 560 "EmptyConfigMapList", 561 v1.EnvVar{ 562 Name: "FOO", 563 ValueFrom: &v1.EnvVarSource{ 564 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 565 LocalObjectReference: v1.LocalObjectReference{ 566 Name: "foo", 567 }, 568 Key: "myvar", 569 }, 570 }, 571 }, 572 CtrSpecGenOptions{ 573 ConfigMaps: []v1.ConfigMap{}, 574 }, 575 false, 576 nilString, 577 }, 578 { 579 "OptionalEmptyConfigMapList", 580 v1.EnvVar{ 581 Name: "FOO", 582 ValueFrom: &v1.EnvVarSource{ 583 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 584 LocalObjectReference: v1.LocalObjectReference{ 585 Name: "foo", 586 }, 587 Key: "myvar", 588 Optional: &optional, 589 }, 590 }, 591 }, 592 CtrSpecGenOptions{ 593 ConfigMaps: []v1.ConfigMap{}, 594 }, 595 true, 596 nilString, 597 }, 598 { 599 "SecretExists", 600 v1.EnvVar{ 601 Name: "FOO", 602 ValueFrom: &v1.EnvVarSource{ 603 SecretKeyRef: &v1.SecretKeySelector{ 604 LocalObjectReference: v1.LocalObjectReference{ 605 Name: "foo", 606 }, 607 Key: "myvar", 608 }, 609 }, 610 }, 611 CtrSpecGenOptions{ 612 SecretsManager: secretsManager, 613 }, 614 true, 615 "foo", 616 }, 617 { 618 "ContainerKeyDoesNotExistInSecret", 619 v1.EnvVar{ 620 Name: "FOO", 621 ValueFrom: &v1.EnvVarSource{ 622 SecretKeyRef: &v1.SecretKeySelector{ 623 LocalObjectReference: v1.LocalObjectReference{ 624 Name: "foo", 625 }, 626 Key: "doesnotexist", 627 }, 628 }, 629 }, 630 CtrSpecGenOptions{ 631 SecretsManager: secretsManager, 632 }, 633 false, 634 nilString, 635 }, 636 { 637 "OptionalContainerKeyDoesNotExistInSecret", 638 v1.EnvVar{ 639 Name: "FOO", 640 ValueFrom: &v1.EnvVarSource{ 641 SecretKeyRef: &v1.SecretKeySelector{ 642 LocalObjectReference: v1.LocalObjectReference{ 643 Name: "foo", 644 }, 645 Key: "doesnotexist", 646 Optional: &optional, 647 }, 648 }, 649 }, 650 CtrSpecGenOptions{ 651 SecretsManager: secretsManager, 652 }, 653 true, 654 nilString, 655 }, 656 { 657 "SecretDoesNotExist", 658 v1.EnvVar{ 659 Name: "FOO", 660 ValueFrom: &v1.EnvVarSource{ 661 SecretKeyRef: &v1.SecretKeySelector{ 662 LocalObjectReference: v1.LocalObjectReference{ 663 Name: "doesnotexist", 664 }, 665 Key: "myvar", 666 }, 667 }, 668 }, 669 CtrSpecGenOptions{ 670 SecretsManager: secretsManager, 671 }, 672 false, 673 nilString, 674 }, 675 { 676 "OptionalSecretDoesNotExist", 677 v1.EnvVar{ 678 Name: "FOO", 679 ValueFrom: &v1.EnvVarSource{ 680 SecretKeyRef: &v1.SecretKeySelector{ 681 LocalObjectReference: v1.LocalObjectReference{ 682 Name: "doesnotexist", 683 }, 684 Key: "myvar", 685 Optional: &optional, 686 }, 687 }, 688 }, 689 CtrSpecGenOptions{ 690 SecretsManager: secretsManager, 691 }, 692 true, 693 nilString, 694 }, 695 { 696 "FieldRefMetadataName", 697 v1.EnvVar{ 698 Name: "FOO", 699 ValueFrom: &v1.EnvVarSource{ 700 FieldRef: &v1.ObjectFieldSelector{ 701 FieldPath: "metadata.name", 702 }, 703 }, 704 }, 705 CtrSpecGenOptions{ 706 PodName: "test", 707 }, 708 true, 709 "test", 710 }, 711 { 712 "FieldRefMetadataUID", 713 v1.EnvVar{ 714 Name: "FOO", 715 ValueFrom: &v1.EnvVarSource{ 716 FieldRef: &v1.ObjectFieldSelector{ 717 FieldPath: "metadata.uid", 718 }, 719 }, 720 }, 721 CtrSpecGenOptions{ 722 PodID: "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977", 723 }, 724 true, 725 "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977", 726 }, 727 { 728 "FieldRefMetadataLabelsExist", 729 v1.EnvVar{ 730 Name: "FOO", 731 ValueFrom: &v1.EnvVarSource{ 732 FieldRef: &v1.ObjectFieldSelector{ 733 FieldPath: "metadata.labels['label']", 734 }, 735 }, 736 }, 737 CtrSpecGenOptions{ 738 Labels: map[string]string{"label": "label"}, 739 }, 740 true, 741 "label", 742 }, 743 { 744 "FieldRefMetadataLabelsEmpty", 745 v1.EnvVar{ 746 Name: "FOO", 747 ValueFrom: &v1.EnvVarSource{ 748 FieldRef: &v1.ObjectFieldSelector{ 749 FieldPath: "metadata.labels['label']", 750 }, 751 }, 752 }, 753 CtrSpecGenOptions{ 754 Labels: map[string]string{"label": ""}, 755 }, 756 true, 757 "", 758 }, 759 { 760 "FieldRefMetadataLabelsNotExist", 761 v1.EnvVar{ 762 Name: "FOO", 763 ValueFrom: &v1.EnvVarSource{ 764 FieldRef: &v1.ObjectFieldSelector{ 765 FieldPath: "metadata.labels['label']", 766 }, 767 }, 768 }, 769 CtrSpecGenOptions{}, 770 true, 771 "", 772 }, 773 { 774 "FieldRefMetadataAnnotationsExist", 775 v1.EnvVar{ 776 Name: "FOO", 777 ValueFrom: &v1.EnvVarSource{ 778 FieldRef: &v1.ObjectFieldSelector{ 779 FieldPath: "metadata.annotations['annotation']", 780 }, 781 }, 782 }, 783 CtrSpecGenOptions{ 784 Annotations: map[string]string{"annotation": "annotation"}, 785 }, 786 true, 787 "annotation", 788 }, 789 { 790 "FieldRefMetadataAnnotationsEmpty", 791 v1.EnvVar{ 792 Name: "FOO", 793 ValueFrom: &v1.EnvVarSource{ 794 FieldRef: &v1.ObjectFieldSelector{ 795 FieldPath: "metadata.annotations['annotation']", 796 }, 797 }, 798 }, 799 CtrSpecGenOptions{ 800 Annotations: map[string]string{"annotation": ""}, 801 }, 802 true, 803 "", 804 }, 805 { 806 "FieldRefMetadataAnnotationsNotExist", 807 v1.EnvVar{ 808 Name: "FOO", 809 ValueFrom: &v1.EnvVarSource{ 810 FieldRef: &v1.ObjectFieldSelector{ 811 FieldPath: "metadata.annotations['annotation']", 812 }, 813 }, 814 }, 815 CtrSpecGenOptions{}, 816 true, 817 "", 818 }, 819 { 820 "FieldRefInvalid1", 821 v1.EnvVar{ 822 Name: "FOO", 823 ValueFrom: &v1.EnvVarSource{ 824 FieldRef: &v1.ObjectFieldSelector{ 825 FieldPath: "metadata.annotations['annotation]", 826 }, 827 }, 828 }, 829 CtrSpecGenOptions{}, 830 false, 831 nilString, 832 }, 833 { 834 "FieldRefInvalid2", 835 v1.EnvVar{ 836 Name: "FOO", 837 ValueFrom: &v1.EnvVarSource{ 838 FieldRef: &v1.ObjectFieldSelector{ 839 FieldPath: "metadata.dummy['annotation']", 840 }, 841 }, 842 }, 843 CtrSpecGenOptions{}, 844 false, 845 nilString, 846 }, 847 { 848 "FieldRefNotSupported", 849 v1.EnvVar{ 850 Name: "FOO", 851 ValueFrom: &v1.EnvVarSource{ 852 FieldRef: &v1.ObjectFieldSelector{ 853 FieldPath: "metadata.namespace", 854 }, 855 }, 856 }, 857 CtrSpecGenOptions{}, 858 false, 859 nilString, 860 }, 861 { 862 "ResourceFieldRefNotSupported", 863 v1.EnvVar{ 864 Name: "FOO", 865 ValueFrom: &v1.EnvVarSource{ 866 ResourceFieldRef: &v1.ResourceFieldSelector{ 867 Resource: "limits.dummy", 868 }, 869 }, 870 }, 871 CtrSpecGenOptions{}, 872 false, 873 nilString, 874 }, 875 { 876 "ResourceFieldRefMemoryDivisorNotValid", 877 v1.EnvVar{ 878 Name: "FOO", 879 ValueFrom: &v1.EnvVarSource{ 880 ResourceFieldRef: &v1.ResourceFieldSelector{ 881 Resource: "limits.memory", 882 Divisor: resource.MustParse("2M"), 883 }, 884 }, 885 }, 886 CtrSpecGenOptions{}, 887 false, 888 nilString, 889 }, 890 { 891 "ResourceFieldRefCpuDivisorNotValid", 892 v1.EnvVar{ 893 Name: "FOO", 894 ValueFrom: &v1.EnvVarSource{ 895 ResourceFieldRef: &v1.ResourceFieldSelector{ 896 Resource: "limits.cpu", 897 Divisor: resource.MustParse("2m"), 898 }, 899 }, 900 }, 901 CtrSpecGenOptions{}, 902 false, 903 nilString, 904 }, 905 { 906 "ResourceFieldRefNoDivisor", 907 v1.EnvVar{ 908 Name: "FOO", 909 ValueFrom: &v1.EnvVarSource{ 910 ResourceFieldRef: &v1.ResourceFieldSelector{ 911 Resource: "limits.memory", 912 }, 913 }, 914 }, 915 CtrSpecGenOptions{ 916 Container: container, 917 }, 918 true, 919 memoryString, 920 }, 921 { 922 "ResourceFieldRefMemoryDivisor", 923 v1.EnvVar{ 924 Name: "FOO", 925 ValueFrom: &v1.EnvVarSource{ 926 ResourceFieldRef: &v1.ResourceFieldSelector{ 927 Resource: "limits.memory", 928 Divisor: resource.MustParse("1Mi"), 929 }, 930 }, 931 }, 932 CtrSpecGenOptions{ 933 Container: container, 934 }, 935 true, 936 strconv.Itoa(int(math.Ceil(float64(memoryInt) / 1024 / 1024))), 937 }, 938 { 939 "ResourceFieldRefCpuDivisor", 940 v1.EnvVar{ 941 Name: "FOO", 942 ValueFrom: &v1.EnvVarSource{ 943 ResourceFieldRef: &v1.ResourceFieldSelector{ 944 Resource: "requests.cpu", 945 Divisor: resource.MustParse("1m"), 946 }, 947 }, 948 }, 949 CtrSpecGenOptions{ 950 Container: container, 951 }, 952 true, 953 strconv.Itoa(int(float64(cpuInt) / 0.001)), 954 }, 955 { 956 "ResourceFieldRefNoLimitMemory", 957 v1.EnvVar{ 958 Name: "FOO", 959 ValueFrom: &v1.EnvVarSource{ 960 ResourceFieldRef: &v1.ResourceFieldSelector{ 961 Resource: "limits.memory", 962 }, 963 }, 964 }, 965 CtrSpecGenOptions{ 966 Container: v1.Container{ 967 Name: "test", 968 }, 969 }, 970 true, 971 stringMemTotal, 972 }, 973 { 974 "ResourceFieldRefNoRequestMemory", 975 v1.EnvVar{ 976 Name: "FOO", 977 ValueFrom: &v1.EnvVarSource{ 978 ResourceFieldRef: &v1.ResourceFieldSelector{ 979 Resource: "requests.memory", 980 }, 981 }, 982 }, 983 CtrSpecGenOptions{ 984 Container: v1.Container{ 985 Name: "test", 986 }, 987 }, 988 true, 989 stringMemTotal, 990 }, 991 { 992 "ResourceFieldRefNoLimitCPU", 993 v1.EnvVar{ 994 Name: "FOO", 995 ValueFrom: &v1.EnvVarSource{ 996 ResourceFieldRef: &v1.ResourceFieldSelector{ 997 Resource: "limits.cpu", 998 }, 999 }, 1000 }, 1001 CtrSpecGenOptions{ 1002 Container: v1.Container{ 1003 Name: "test", 1004 }, 1005 }, 1006 true, 1007 stringNumCPUs, 1008 }, 1009 { 1010 "ResourceFieldRefNoRequestCPU", 1011 v1.EnvVar{ 1012 Name: "FOO", 1013 ValueFrom: &v1.EnvVarSource{ 1014 ResourceFieldRef: &v1.ResourceFieldSelector{ 1015 Resource: "requests.cpu", 1016 }, 1017 }, 1018 }, 1019 CtrSpecGenOptions{ 1020 Container: v1.Container{ 1021 Name: "test", 1022 }, 1023 }, 1024 true, 1025 stringNumCPUs, 1026 }, 1027 } 1028 1029 for _, test := range tests { 1030 test := test 1031 t.Run(test.name, func(t *testing.T) { 1032 result, err := envVarValue(test.envVar, &test.options) 1033 assert.Equal(t, err == nil, test.succeed) 1034 if test.expected == nilString { 1035 assert.Nil(t, result) 1036 } else { 1037 assert.Equal(t, test.expected, *result) 1038 } 1039 }) 1040 } 1041 } 1042 1043 var ( 1044 nilString = "<nil>" 1045 configMapList = []v1.ConfigMap{ 1046 { 1047 TypeMeta: v12.TypeMeta{ 1048 Kind: "ConfigMap", 1049 }, 1050 ObjectMeta: v12.ObjectMeta{ 1051 Name: "bar", 1052 }, 1053 Data: map[string]string{ 1054 "myvar": "bar", 1055 }, 1056 }, 1057 { 1058 TypeMeta: v12.TypeMeta{ 1059 Kind: "ConfigMap", 1060 }, 1061 ObjectMeta: v12.ObjectMeta{ 1062 Name: "foo", 1063 }, 1064 Data: map[string]string{ 1065 "myvar": "foo", 1066 }, 1067 }, 1068 { 1069 TypeMeta: v12.TypeMeta{ 1070 Kind: "ConfigMap", 1071 }, 1072 ObjectMeta: v12.ObjectMeta{ 1073 Name: "binary-bar", 1074 }, 1075 BinaryData: map[string][]byte{ 1076 "myvar": []byte("bin-bar"), 1077 }, 1078 }, 1079 { 1080 TypeMeta: v12.TypeMeta{ 1081 Kind: "ConfigMap", 1082 }, 1083 ObjectMeta: v12.ObjectMeta{ 1084 Name: "multi-item", 1085 }, 1086 Data: map[string]string{ 1087 "foo": "bar", 1088 "fizz": "buzz", 1089 }, 1090 }, 1091 { 1092 TypeMeta: v12.TypeMeta{ 1093 Kind: "ConfigMap", 1094 }, 1095 ObjectMeta: v12.ObjectMeta{ 1096 Name: "multi-binary-item", 1097 }, 1098 BinaryData: map[string][]byte{ 1099 "foo": []byte("bin-bar"), 1100 "fizz": []byte("bin-buzz"), 1101 }, 1102 }, 1103 { 1104 TypeMeta: v12.TypeMeta{ 1105 Kind: "ConfigMap", 1106 }, 1107 ObjectMeta: v12.ObjectMeta{ 1108 Name: "dupe", 1109 }, 1110 BinaryData: map[string][]byte{ 1111 "fiz": []byte("bin-buzz"), 1112 "foo": []byte("bin-bar"), 1113 }, 1114 Data: map[string]string{ 1115 "foo": "bar", 1116 }, 1117 }, 1118 } 1119 1120 optional = true 1121 1122 k8sSecrets = []v1.Secret{ 1123 { 1124 TypeMeta: v12.TypeMeta{ 1125 Kind: "Secret", 1126 }, 1127 ObjectMeta: v12.ObjectMeta{ 1128 Name: "bar", 1129 }, 1130 Data: map[string][]byte{ 1131 "myvar": []byte("bar"), 1132 }, 1133 }, 1134 { 1135 TypeMeta: v12.TypeMeta{ 1136 Kind: "Secret", 1137 }, 1138 ObjectMeta: v12.ObjectMeta{ 1139 Name: "foo", 1140 }, 1141 Data: map[string][]byte{ 1142 "myvar": []byte("foo"), 1143 }, 1144 }, 1145 { 1146 TypeMeta: v12.TypeMeta{ 1147 Kind: "Secret", 1148 }, 1149 ObjectMeta: v12.ObjectMeta{ 1150 Name: "multi-data", 1151 }, 1152 Data: map[string][]byte{ 1153 "myvar": []byte("foo"), 1154 "myvar1": []byte("foo1"), 1155 }, 1156 }, 1157 { 1158 TypeMeta: v12.TypeMeta{ 1159 Kind: "Secret", 1160 }, 1161 ObjectMeta: v12.ObjectMeta{ 1162 Name: "multi-stringdata", 1163 }, 1164 StringData: map[string]string{ 1165 "myvar": string("foo"), 1166 "myvar1": string("foo1"), 1167 }, 1168 }, 1169 { 1170 TypeMeta: v12.TypeMeta{ 1171 Kind: "Secret", 1172 }, 1173 ObjectMeta: v12.ObjectMeta{ 1174 Name: "multi-data-stringdata", 1175 }, 1176 Data: map[string][]byte{ 1177 "myvardata": []byte("foodata"), 1178 "myvar1": []byte("foo1data"), 1179 }, 1180 StringData: map[string]string{ 1181 "myvarstring": string("foostring"), 1182 "myvar1": string("foo1string"), 1183 }, 1184 }, 1185 } 1186 1187 cpuInt = 4 1188 cpuString = strconv.Itoa(cpuInt) 1189 memoryInt = 30000000 1190 memoryString = strconv.Itoa(memoryInt) 1191 container = v1.Container{ 1192 Name: "test", 1193 Resources: v1.ResourceRequirements{ 1194 Limits: v1.ResourceList{ 1195 v1.ResourceCPU: resource.MustParse(cpuString), 1196 v1.ResourceMemory: resource.MustParse(memoryString), 1197 }, 1198 Requests: v1.ResourceList{ 1199 v1.ResourceCPU: resource.MustParse(cpuString), 1200 v1.ResourceMemory: resource.MustParse(memoryString), 1201 }, 1202 }, 1203 } 1204 ) 1205 1206 func TestHttpLivenessProbe(t *testing.T) { 1207 tests := []struct { 1208 name string 1209 specGenerator specgen.SpecGenerator 1210 container v1.Container 1211 restartPolicy string 1212 succeed bool 1213 expectedURL string 1214 }{ 1215 { 1216 "HttpLivenessProbeUrlSetCorrectly", 1217 specgen.SpecGenerator{}, 1218 v1.Container{ 1219 LivenessProbe: &v1.Probe{ 1220 Handler: v1.Handler{ 1221 HTTPGet: &v1.HTTPGetAction{ 1222 Scheme: "http", 1223 Host: "127.0.0.1", 1224 Port: intstr.FromInt(8080), 1225 Path: "/health", 1226 }, 1227 }, 1228 }, 1229 }, 1230 "always", 1231 true, 1232 "http://127.0.0.1:8080/health", 1233 }, 1234 { 1235 "HttpLivenessProbeUrlUsesDefaults", 1236 specgen.SpecGenerator{}, 1237 v1.Container{ 1238 LivenessProbe: &v1.Probe{ 1239 Handler: v1.Handler{ 1240 HTTPGet: &v1.HTTPGetAction{ 1241 Port: intstr.FromInt(80), 1242 }, 1243 }, 1244 }, 1245 }, 1246 "always", 1247 true, 1248 "http://localhost:80/", 1249 }, 1250 { 1251 "HttpLivenessProbeNamedPort", 1252 specgen.SpecGenerator{}, 1253 v1.Container{ 1254 LivenessProbe: &v1.Probe{ 1255 Handler: v1.Handler{ 1256 HTTPGet: &v1.HTTPGetAction{ 1257 Port: intstr.FromString("httpPort"), 1258 }, 1259 }, 1260 }, 1261 Ports: []v1.ContainerPort{ 1262 {Name: "servicePort", ContainerPort: 7000}, 1263 {Name: "httpPort", ContainerPort: 8000}, 1264 }, 1265 }, 1266 "always", 1267 true, 1268 "http://localhost:8000/", 1269 }, 1270 } 1271 1272 for _, test := range tests { 1273 test := test 1274 t.Run(test.name, func(t *testing.T) { 1275 err := setupLivenessProbe(&test.specGenerator, test.container, test.restartPolicy) 1276 if err == nil { 1277 assert.Equal(t, err == nil, test.succeed) 1278 assert.Contains(t, test.specGenerator.ContainerHealthCheckConfig.HealthConfig.Test, test.expectedURL) 1279 } 1280 }) 1281 } 1282 } 1283 1284 func TestTCPLivenessProbe(t *testing.T) { 1285 tests := []struct { 1286 name string 1287 specGenerator specgen.SpecGenerator 1288 container v1.Container 1289 restartPolicy string 1290 succeed bool 1291 expectedHost string 1292 expectedPort string 1293 }{ 1294 { 1295 "TCPLivenessProbeNormal", 1296 specgen.SpecGenerator{}, 1297 v1.Container{ 1298 LivenessProbe: &v1.Probe{ 1299 Handler: v1.Handler{ 1300 TCPSocket: &v1.TCPSocketAction{ 1301 Host: "127.0.0.1", 1302 Port: intstr.FromInt(8080), 1303 }, 1304 }, 1305 }, 1306 }, 1307 "always", 1308 true, 1309 "127.0.0.1", 1310 "8080", 1311 }, 1312 { 1313 "TCPLivenessProbeHostUsesDefault", 1314 specgen.SpecGenerator{}, 1315 v1.Container{ 1316 LivenessProbe: &v1.Probe{ 1317 Handler: v1.Handler{ 1318 TCPSocket: &v1.TCPSocketAction{ 1319 Port: intstr.FromInt(200), 1320 }, 1321 }, 1322 }, 1323 }, 1324 "always", 1325 true, 1326 "localhost", 1327 "200", 1328 }, 1329 { 1330 "TCPLivenessProbeUseNamedPort", 1331 specgen.SpecGenerator{}, 1332 v1.Container{ 1333 LivenessProbe: &v1.Probe{ 1334 Handler: v1.Handler{ 1335 TCPSocket: &v1.TCPSocketAction{ 1336 Port: intstr.FromString("servicePort"), 1337 Host: "myservice.domain.com", 1338 }, 1339 }, 1340 }, 1341 Ports: []v1.ContainerPort{ 1342 {ContainerPort: 6000}, 1343 {Name: "servicePort", ContainerPort: 4000}, 1344 {Name: "2ndServicePort", ContainerPort: 3000}, 1345 }, 1346 }, 1347 "always", 1348 true, 1349 "myservice.domain.com", 1350 "4000", 1351 }, 1352 { 1353 "TCPLivenessProbeInvalidPortName", 1354 specgen.SpecGenerator{}, 1355 v1.Container{ 1356 LivenessProbe: &v1.Probe{ 1357 Handler: v1.Handler{ 1358 TCPSocket: &v1.TCPSocketAction{ 1359 Port: intstr.FromString("3rdservicePort"), 1360 Host: "myservice.domain.com", 1361 }, 1362 }, 1363 }, 1364 Ports: []v1.ContainerPort{ 1365 {ContainerPort: 6000}, 1366 {Name: "servicePort", ContainerPort: 4000}, 1367 {Name: "2ndServicePort", ContainerPort: 3000}, 1368 }, 1369 }, 1370 "always", 1371 false, 1372 "myservice.domain.com", 1373 "4000", 1374 }, 1375 } 1376 1377 for _, test := range tests { 1378 test := test 1379 t.Run(test.name, func(t *testing.T) { 1380 err := setupLivenessProbe(&test.specGenerator, test.container, test.restartPolicy) 1381 assert.Equal(t, err == nil, test.succeed) 1382 if err == nil { 1383 assert.Contains(t, test.specGenerator.ContainerHealthCheckConfig.HealthConfig.Test, test.expectedHost) 1384 assert.Contains(t, test.specGenerator.ContainerHealthCheckConfig.HealthConfig.Test, test.expectedPort) 1385 } 1386 }) 1387 } 1388 }