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  }