github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/specgen/generate/kube/play_test.go (about) 1 package kube 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math" 7 "runtime" 8 "strconv" 9 "testing" 10 11 "github.com/containers/common/pkg/secrets" 12 v1 "github.com/hanks177/podman/v4/pkg/k8s.io/api/core/v1" 13 "github.com/hanks177/podman/v4/pkg/k8s.io/apimachinery/pkg/api/resource" 14 v12 "github.com/hanks177/podman/v4/pkg/k8s.io/apimachinery/pkg/apis/meta/v1" 15 "github.com/docker/docker/pkg/system" 16 "github.com/stretchr/testify/assert" 17 ) 18 19 func createSecrets(t *testing.T, d string) *secrets.SecretsManager { 20 secretsManager, err := secrets.NewManager(d) 21 assert.NoError(t, err) 22 23 driver := "file" 24 driverOpts := map[string]string{ 25 "path": d, 26 } 27 28 for _, s := range k8sSecrets { 29 data, err := json.Marshal(s.Data) 30 assert.NoError(t, err) 31 32 _, err = secretsManager.Store(s.ObjectMeta.Name, data, driver, driverOpts) 33 assert.NoError(t, err) 34 } 35 36 return secretsManager 37 } 38 39 func TestEnvVarsFrom(t *testing.T) { 40 d := t.TempDir() 41 secretsManager := createSecrets(t, d) 42 43 tests := []struct { 44 name string 45 envFrom v1.EnvFromSource 46 options CtrSpecGenOptions 47 succeed bool 48 expected map[string]string 49 }{ 50 { 51 "ConfigMapExists", 52 v1.EnvFromSource{ 53 ConfigMapRef: &v1.ConfigMapEnvSource{ 54 LocalObjectReference: v1.LocalObjectReference{ 55 Name: "foo", 56 }, 57 }, 58 }, 59 CtrSpecGenOptions{ 60 ConfigMaps: configMapList, 61 }, 62 true, 63 map[string]string{ 64 "myvar": "foo", 65 }, 66 }, 67 { 68 "ConfigMapDoesNotExist", 69 v1.EnvFromSource{ 70 ConfigMapRef: &v1.ConfigMapEnvSource{ 71 LocalObjectReference: v1.LocalObjectReference{ 72 Name: "doesnotexist", 73 }, 74 }, 75 }, 76 CtrSpecGenOptions{ 77 ConfigMaps: configMapList, 78 }, 79 false, 80 nil, 81 }, 82 { 83 "OptionalConfigMapDoesNotExist", 84 v1.EnvFromSource{ 85 ConfigMapRef: &v1.ConfigMapEnvSource{ 86 LocalObjectReference: v1.LocalObjectReference{ 87 Name: "doesnotexist", 88 }, 89 Optional: &optional, 90 }, 91 }, 92 CtrSpecGenOptions{ 93 ConfigMaps: configMapList, 94 }, 95 true, 96 map[string]string{}, 97 }, 98 { 99 "EmptyConfigMapList", 100 v1.EnvFromSource{ 101 ConfigMapRef: &v1.ConfigMapEnvSource{ 102 LocalObjectReference: v1.LocalObjectReference{ 103 Name: "foo", 104 }, 105 }, 106 }, 107 CtrSpecGenOptions{ 108 ConfigMaps: []v1.ConfigMap{}, 109 }, 110 false, 111 nil, 112 }, 113 { 114 "OptionalEmptyConfigMapList", 115 v1.EnvFromSource{ 116 ConfigMapRef: &v1.ConfigMapEnvSource{ 117 LocalObjectReference: v1.LocalObjectReference{ 118 Name: "foo", 119 }, 120 Optional: &optional, 121 }, 122 }, 123 CtrSpecGenOptions{ 124 ConfigMaps: []v1.ConfigMap{}, 125 }, 126 true, 127 map[string]string{}, 128 }, 129 { 130 "SecretExists", 131 v1.EnvFromSource{ 132 SecretRef: &v1.SecretEnvSource{ 133 LocalObjectReference: v1.LocalObjectReference{ 134 Name: "foo", 135 }, 136 }, 137 }, 138 CtrSpecGenOptions{ 139 SecretsManager: secretsManager, 140 }, 141 true, 142 map[string]string{ 143 "myvar": "foo", 144 }, 145 }, 146 { 147 "SecretDoesNotExist", 148 v1.EnvFromSource{ 149 SecretRef: &v1.SecretEnvSource{ 150 LocalObjectReference: v1.LocalObjectReference{ 151 Name: "doesnotexist", 152 }, 153 }, 154 }, 155 CtrSpecGenOptions{ 156 SecretsManager: secretsManager, 157 }, 158 false, 159 nil, 160 }, 161 { 162 "OptionalSecretDoesNotExist", 163 v1.EnvFromSource{ 164 SecretRef: &v1.SecretEnvSource{ 165 LocalObjectReference: v1.LocalObjectReference{ 166 Name: "doesnotexist", 167 }, 168 Optional: &optional, 169 }, 170 }, 171 CtrSpecGenOptions{ 172 SecretsManager: secretsManager, 173 }, 174 true, 175 map[string]string{}, 176 }, 177 } 178 179 for _, test := range tests { 180 test := test 181 t.Run(test.name, func(t *testing.T) { 182 result, err := envVarsFrom(test.envFrom, &test.options) 183 assert.Equal(t, err == nil, test.succeed) 184 assert.Equal(t, test.expected, result) 185 }) 186 } 187 } 188 189 func TestEnvVarValue(t *testing.T) { 190 d := t.TempDir() 191 secretsManager := createSecrets(t, d) 192 stringNumCPUs := strconv.Itoa(runtime.NumCPU()) 193 194 mi, err := system.ReadMemInfo() 195 assert.Nil(t, err) 196 stringMemTotal := strconv.FormatInt(mi.MemTotal, 10) 197 198 tests := []struct { 199 name string 200 envVar v1.EnvVar 201 options CtrSpecGenOptions 202 succeed bool 203 expected string 204 }{ 205 { 206 "ConfigMapExists", 207 v1.EnvVar{ 208 Name: "FOO", 209 ValueFrom: &v1.EnvVarSource{ 210 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 211 LocalObjectReference: v1.LocalObjectReference{ 212 Name: "foo", 213 }, 214 Key: "myvar", 215 }, 216 }, 217 }, 218 CtrSpecGenOptions{ 219 ConfigMaps: configMapList, 220 }, 221 true, 222 "foo", 223 }, 224 { 225 "ContainerKeyDoesNotExistInConfigMap", 226 v1.EnvVar{ 227 Name: "FOO", 228 ValueFrom: &v1.EnvVarSource{ 229 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 230 LocalObjectReference: v1.LocalObjectReference{ 231 Name: "foo", 232 }, 233 Key: "doesnotexist", 234 }, 235 }, 236 }, 237 CtrSpecGenOptions{ 238 ConfigMaps: configMapList, 239 }, 240 false, 241 nilString, 242 }, 243 { 244 "OptionalContainerKeyDoesNotExistInConfigMap", 245 v1.EnvVar{ 246 Name: "FOO", 247 ValueFrom: &v1.EnvVarSource{ 248 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 249 LocalObjectReference: v1.LocalObjectReference{ 250 Name: "foo", 251 }, 252 Key: "doesnotexist", 253 Optional: &optional, 254 }, 255 }, 256 }, 257 CtrSpecGenOptions{ 258 ConfigMaps: configMapList, 259 }, 260 true, 261 nilString, 262 }, 263 { 264 "ConfigMapDoesNotExist", 265 v1.EnvVar{ 266 Name: "FOO", 267 ValueFrom: &v1.EnvVarSource{ 268 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 269 LocalObjectReference: v1.LocalObjectReference{ 270 Name: "doesnotexist", 271 }, 272 Key: "myvar", 273 }, 274 }, 275 }, 276 CtrSpecGenOptions{ 277 ConfigMaps: configMapList, 278 }, 279 false, 280 nilString, 281 }, 282 { 283 "OptionalConfigMapDoesNotExist", 284 v1.EnvVar{ 285 Name: "FOO", 286 ValueFrom: &v1.EnvVarSource{ 287 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 288 LocalObjectReference: v1.LocalObjectReference{ 289 Name: "doesnotexist", 290 }, 291 Key: "myvar", 292 Optional: &optional, 293 }, 294 }, 295 }, 296 CtrSpecGenOptions{ 297 ConfigMaps: configMapList, 298 }, 299 true, 300 nilString, 301 }, 302 { 303 "EmptyConfigMapList", 304 v1.EnvVar{ 305 Name: "FOO", 306 ValueFrom: &v1.EnvVarSource{ 307 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 308 LocalObjectReference: v1.LocalObjectReference{ 309 Name: "foo", 310 }, 311 Key: "myvar", 312 }, 313 }, 314 }, 315 CtrSpecGenOptions{ 316 ConfigMaps: []v1.ConfigMap{}, 317 }, 318 false, 319 nilString, 320 }, 321 { 322 "OptionalEmptyConfigMapList", 323 v1.EnvVar{ 324 Name: "FOO", 325 ValueFrom: &v1.EnvVarSource{ 326 ConfigMapKeyRef: &v1.ConfigMapKeySelector{ 327 LocalObjectReference: v1.LocalObjectReference{ 328 Name: "foo", 329 }, 330 Key: "myvar", 331 Optional: &optional, 332 }, 333 }, 334 }, 335 CtrSpecGenOptions{ 336 ConfigMaps: []v1.ConfigMap{}, 337 }, 338 true, 339 nilString, 340 }, 341 { 342 "SecretExists", 343 v1.EnvVar{ 344 Name: "FOO", 345 ValueFrom: &v1.EnvVarSource{ 346 SecretKeyRef: &v1.SecretKeySelector{ 347 LocalObjectReference: v1.LocalObjectReference{ 348 Name: "foo", 349 }, 350 Key: "myvar", 351 }, 352 }, 353 }, 354 CtrSpecGenOptions{ 355 SecretsManager: secretsManager, 356 }, 357 true, 358 "foo", 359 }, 360 { 361 "ContainerKeyDoesNotExistInSecret", 362 v1.EnvVar{ 363 Name: "FOO", 364 ValueFrom: &v1.EnvVarSource{ 365 SecretKeyRef: &v1.SecretKeySelector{ 366 LocalObjectReference: v1.LocalObjectReference{ 367 Name: "foo", 368 }, 369 Key: "doesnotexist", 370 }, 371 }, 372 }, 373 CtrSpecGenOptions{ 374 SecretsManager: secretsManager, 375 }, 376 false, 377 nilString, 378 }, 379 { 380 "OptionalContainerKeyDoesNotExistInSecret", 381 v1.EnvVar{ 382 Name: "FOO", 383 ValueFrom: &v1.EnvVarSource{ 384 SecretKeyRef: &v1.SecretKeySelector{ 385 LocalObjectReference: v1.LocalObjectReference{ 386 Name: "foo", 387 }, 388 Key: "doesnotexist", 389 Optional: &optional, 390 }, 391 }, 392 }, 393 CtrSpecGenOptions{ 394 SecretsManager: secretsManager, 395 }, 396 true, 397 nilString, 398 }, 399 { 400 "SecretDoesNotExist", 401 v1.EnvVar{ 402 Name: "FOO", 403 ValueFrom: &v1.EnvVarSource{ 404 SecretKeyRef: &v1.SecretKeySelector{ 405 LocalObjectReference: v1.LocalObjectReference{ 406 Name: "doesnotexist", 407 }, 408 Key: "myvar", 409 }, 410 }, 411 }, 412 CtrSpecGenOptions{ 413 SecretsManager: secretsManager, 414 }, 415 false, 416 nilString, 417 }, 418 { 419 "OptionalSecretDoesNotExist", 420 v1.EnvVar{ 421 Name: "FOO", 422 ValueFrom: &v1.EnvVarSource{ 423 SecretKeyRef: &v1.SecretKeySelector{ 424 LocalObjectReference: v1.LocalObjectReference{ 425 Name: "doesnotexist", 426 }, 427 Key: "myvar", 428 Optional: &optional, 429 }, 430 }, 431 }, 432 CtrSpecGenOptions{ 433 SecretsManager: secretsManager, 434 }, 435 true, 436 nilString, 437 }, 438 { 439 "FieldRefMetadataName", 440 v1.EnvVar{ 441 Name: "FOO", 442 ValueFrom: &v1.EnvVarSource{ 443 FieldRef: &v1.ObjectFieldSelector{ 444 FieldPath: "metadata.name", 445 }, 446 }, 447 }, 448 CtrSpecGenOptions{ 449 PodName: "test", 450 }, 451 true, 452 "test", 453 }, 454 { 455 "FieldRefMetadataUID", 456 v1.EnvVar{ 457 Name: "FOO", 458 ValueFrom: &v1.EnvVarSource{ 459 FieldRef: &v1.ObjectFieldSelector{ 460 FieldPath: "metadata.uid", 461 }, 462 }, 463 }, 464 CtrSpecGenOptions{ 465 PodID: "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977", 466 }, 467 true, 468 "ec71ff37c67b688598c0008187ab0960dc34e1dfdcbf3a74e3d778bafcfe0977", 469 }, 470 { 471 "FieldRefMetadataLabelsExist", 472 v1.EnvVar{ 473 Name: "FOO", 474 ValueFrom: &v1.EnvVarSource{ 475 FieldRef: &v1.ObjectFieldSelector{ 476 FieldPath: "metadata.labels['label']", 477 }, 478 }, 479 }, 480 CtrSpecGenOptions{ 481 Labels: map[string]string{"label": "label"}, 482 }, 483 true, 484 "label", 485 }, 486 { 487 "FieldRefMetadataLabelsEmpty", 488 v1.EnvVar{ 489 Name: "FOO", 490 ValueFrom: &v1.EnvVarSource{ 491 FieldRef: &v1.ObjectFieldSelector{ 492 FieldPath: "metadata.labels['label']", 493 }, 494 }, 495 }, 496 CtrSpecGenOptions{ 497 Labels: map[string]string{"label": ""}, 498 }, 499 true, 500 "", 501 }, 502 { 503 "FieldRefMetadataLabelsNotExist", 504 v1.EnvVar{ 505 Name: "FOO", 506 ValueFrom: &v1.EnvVarSource{ 507 FieldRef: &v1.ObjectFieldSelector{ 508 FieldPath: "metadata.labels['label']", 509 }, 510 }, 511 }, 512 CtrSpecGenOptions{}, 513 true, 514 "", 515 }, 516 { 517 "FieldRefMetadataAnnotationsExist", 518 v1.EnvVar{ 519 Name: "FOO", 520 ValueFrom: &v1.EnvVarSource{ 521 FieldRef: &v1.ObjectFieldSelector{ 522 FieldPath: "metadata.annotations['annotation']", 523 }, 524 }, 525 }, 526 CtrSpecGenOptions{ 527 Annotations: map[string]string{"annotation": "annotation"}, 528 }, 529 true, 530 "annotation", 531 }, 532 { 533 "FieldRefMetadataAnnotationsEmpty", 534 v1.EnvVar{ 535 Name: "FOO", 536 ValueFrom: &v1.EnvVarSource{ 537 FieldRef: &v1.ObjectFieldSelector{ 538 FieldPath: "metadata.annotations['annotation']", 539 }, 540 }, 541 }, 542 CtrSpecGenOptions{ 543 Annotations: map[string]string{"annotation": ""}, 544 }, 545 true, 546 "", 547 }, 548 { 549 "FieldRefMetadataAnnotationsNotExist", 550 v1.EnvVar{ 551 Name: "FOO", 552 ValueFrom: &v1.EnvVarSource{ 553 FieldRef: &v1.ObjectFieldSelector{ 554 FieldPath: "metadata.annotations['annotation']", 555 }, 556 }, 557 }, 558 CtrSpecGenOptions{}, 559 true, 560 "", 561 }, 562 { 563 "FieldRefInvalid1", 564 v1.EnvVar{ 565 Name: "FOO", 566 ValueFrom: &v1.EnvVarSource{ 567 FieldRef: &v1.ObjectFieldSelector{ 568 FieldPath: "metadata.annotations['annotation]", 569 }, 570 }, 571 }, 572 CtrSpecGenOptions{}, 573 false, 574 nilString, 575 }, 576 { 577 "FieldRefInvalid2", 578 v1.EnvVar{ 579 Name: "FOO", 580 ValueFrom: &v1.EnvVarSource{ 581 FieldRef: &v1.ObjectFieldSelector{ 582 FieldPath: "metadata.dummy['annotation']", 583 }, 584 }, 585 }, 586 CtrSpecGenOptions{}, 587 false, 588 nilString, 589 }, 590 { 591 "FieldRefNotSupported", 592 v1.EnvVar{ 593 Name: "FOO", 594 ValueFrom: &v1.EnvVarSource{ 595 FieldRef: &v1.ObjectFieldSelector{ 596 FieldPath: "metadata.namespace", 597 }, 598 }, 599 }, 600 CtrSpecGenOptions{}, 601 false, 602 nilString, 603 }, 604 { 605 "ResourceFieldRefNotSupported", 606 v1.EnvVar{ 607 Name: "FOO", 608 ValueFrom: &v1.EnvVarSource{ 609 ResourceFieldRef: &v1.ResourceFieldSelector{ 610 Resource: "limits.dummy", 611 }, 612 }, 613 }, 614 CtrSpecGenOptions{}, 615 false, 616 nilString, 617 }, 618 { 619 "ResourceFieldRefMemoryDivisorNotValid", 620 v1.EnvVar{ 621 Name: "FOO", 622 ValueFrom: &v1.EnvVarSource{ 623 ResourceFieldRef: &v1.ResourceFieldSelector{ 624 Resource: "limits.memory", 625 Divisor: resource.MustParse("2M"), 626 }, 627 }, 628 }, 629 CtrSpecGenOptions{}, 630 false, 631 nilString, 632 }, 633 { 634 "ResourceFieldRefCpuDivisorNotValid", 635 v1.EnvVar{ 636 Name: "FOO", 637 ValueFrom: &v1.EnvVarSource{ 638 ResourceFieldRef: &v1.ResourceFieldSelector{ 639 Resource: "limits.cpu", 640 Divisor: resource.MustParse("2m"), 641 }, 642 }, 643 }, 644 CtrSpecGenOptions{}, 645 false, 646 nilString, 647 }, 648 { 649 "ResourceFieldRefNoDivisor", 650 v1.EnvVar{ 651 Name: "FOO", 652 ValueFrom: &v1.EnvVarSource{ 653 ResourceFieldRef: &v1.ResourceFieldSelector{ 654 Resource: "limits.memory", 655 }, 656 }, 657 }, 658 CtrSpecGenOptions{ 659 Container: container, 660 }, 661 true, 662 memoryString, 663 }, 664 { 665 "ResourceFieldRefMemoryDivisor", 666 v1.EnvVar{ 667 Name: "FOO", 668 ValueFrom: &v1.EnvVarSource{ 669 ResourceFieldRef: &v1.ResourceFieldSelector{ 670 Resource: "limits.memory", 671 Divisor: resource.MustParse("1Mi"), 672 }, 673 }, 674 }, 675 CtrSpecGenOptions{ 676 Container: container, 677 }, 678 true, 679 strconv.Itoa(int(math.Ceil(float64(memoryInt) / 1024 / 1024))), 680 }, 681 { 682 "ResourceFieldRefCpuDivisor", 683 v1.EnvVar{ 684 Name: "FOO", 685 ValueFrom: &v1.EnvVarSource{ 686 ResourceFieldRef: &v1.ResourceFieldSelector{ 687 Resource: "requests.cpu", 688 Divisor: resource.MustParse("1m"), 689 }, 690 }, 691 }, 692 CtrSpecGenOptions{ 693 Container: container, 694 }, 695 true, 696 strconv.Itoa(int(float64(cpuInt) / 0.001)), 697 }, 698 { 699 "ResourceFieldRefNoLimitMemory", 700 v1.EnvVar{ 701 Name: "FOO", 702 ValueFrom: &v1.EnvVarSource{ 703 ResourceFieldRef: &v1.ResourceFieldSelector{ 704 Resource: "limits.memory", 705 }, 706 }, 707 }, 708 CtrSpecGenOptions{ 709 Container: v1.Container{ 710 Name: "test", 711 }, 712 }, 713 true, 714 stringMemTotal, 715 }, 716 { 717 "ResourceFieldRefNoRequestMemory", 718 v1.EnvVar{ 719 Name: "FOO", 720 ValueFrom: &v1.EnvVarSource{ 721 ResourceFieldRef: &v1.ResourceFieldSelector{ 722 Resource: "requests.memory", 723 }, 724 }, 725 }, 726 CtrSpecGenOptions{ 727 Container: v1.Container{ 728 Name: "test", 729 }, 730 }, 731 true, 732 stringMemTotal, 733 }, 734 { 735 "ResourceFieldRefNoLimitCPU", 736 v1.EnvVar{ 737 Name: "FOO", 738 ValueFrom: &v1.EnvVarSource{ 739 ResourceFieldRef: &v1.ResourceFieldSelector{ 740 Resource: "limits.cpu", 741 }, 742 }, 743 }, 744 CtrSpecGenOptions{ 745 Container: v1.Container{ 746 Name: "test", 747 }, 748 }, 749 true, 750 stringNumCPUs, 751 }, 752 { 753 "ResourceFieldRefNoRequestCPU", 754 v1.EnvVar{ 755 Name: "FOO", 756 ValueFrom: &v1.EnvVarSource{ 757 ResourceFieldRef: &v1.ResourceFieldSelector{ 758 Resource: "requests.cpu", 759 }, 760 }, 761 }, 762 CtrSpecGenOptions{ 763 Container: v1.Container{ 764 Name: "test", 765 }, 766 }, 767 true, 768 stringNumCPUs, 769 }, 770 } 771 772 for _, test := range tests { 773 test := test 774 t.Run(test.name, func(t *testing.T) { 775 result, err := envVarValue(test.envVar, &test.options) 776 assert.Equal(t, err == nil, test.succeed) 777 if test.expected == nilString { 778 assert.Nil(t, result) 779 } else { 780 fmt.Println(*result, test.expected) 781 assert.Equal(t, &(test.expected), result) 782 } 783 }) 784 } 785 } 786 787 var ( 788 nilString = "<nil>" 789 configMapList = []v1.ConfigMap{ 790 { 791 TypeMeta: v12.TypeMeta{ 792 Kind: "ConfigMap", 793 }, 794 ObjectMeta: v12.ObjectMeta{ 795 Name: "bar", 796 }, 797 Data: map[string]string{ 798 "myvar": "bar", 799 }, 800 }, 801 { 802 TypeMeta: v12.TypeMeta{ 803 Kind: "ConfigMap", 804 }, 805 ObjectMeta: v12.ObjectMeta{ 806 Name: "foo", 807 }, 808 Data: map[string]string{ 809 "myvar": "foo", 810 }, 811 }, 812 } 813 814 optional = true 815 816 k8sSecrets = []v1.Secret{ 817 { 818 TypeMeta: v12.TypeMeta{ 819 Kind: "Secret", 820 }, 821 ObjectMeta: v12.ObjectMeta{ 822 Name: "bar", 823 }, 824 Data: map[string][]byte{ 825 "myvar": []byte("bar"), 826 }, 827 }, 828 { 829 TypeMeta: v12.TypeMeta{ 830 Kind: "Secret", 831 }, 832 ObjectMeta: v12.ObjectMeta{ 833 Name: "foo", 834 }, 835 Data: map[string][]byte{ 836 "myvar": []byte("foo"), 837 }, 838 }, 839 } 840 841 cpuInt = 4 842 cpuString = strconv.Itoa(cpuInt) 843 memoryInt = 30000000 844 memoryString = strconv.Itoa(memoryInt) 845 container = v1.Container{ 846 Name: "test", 847 Resources: v1.ResourceRequirements{ 848 Limits: v1.ResourceList{ 849 v1.ResourceCPU: resource.MustParse(cpuString), 850 v1.ResourceMemory: resource.MustParse(memoryString), 851 }, 852 Requests: v1.ResourceList{ 853 v1.ResourceCPU: resource.MustParse(cpuString), 854 v1.ResourceMemory: resource.MustParse(memoryString), 855 }, 856 }, 857 } 858 )