github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/caas/kubernetes/provider/specs/container_env_test.go (about)

     1  // Copyright 2020 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package specs_test
     5  
     6  import (
     7  	jc "github.com/juju/testing/checkers"
     8  	gc "gopkg.in/check.v1"
     9  	core "k8s.io/api/core/v1"
    10  	"k8s.io/apimachinery/pkg/api/resource"
    11  	"k8s.io/utils/pointer"
    12  
    13  	k8sspecs "github.com/juju/juju/caas/kubernetes/provider/specs"
    14  	"github.com/juju/juju/testing"
    15  )
    16  
    17  type containerEnvSuite struct {
    18  	testing.BaseSuite
    19  }
    20  
    21  var _ = gc.Suite(&containerEnvSuite{})
    22  
    23  func (s *containerEnvSuite) TestContainerConfigToK8sEnvConfig(c *gc.C) {
    24  
    25  	specStr := version3Header + `
    26  containers:
    27    - name: gitlab
    28      image: gitlab/latest
    29      envConfig:
    30        attr: foo=bar; name["fred"]="blogs";
    31        foo: bar
    32        brackets: '["hello", "world"]'
    33        restricted: 'yes'
    34        switch: on
    35        bar: true
    36        special: p@ssword's
    37        foo: bar
    38        float: 111.11111111
    39        int: 111
    40        MY_NODE_NAME:
    41          field:
    42            path: spec.nodeName
    43            api-version: v1
    44        my-resource-limit:
    45          resource:
    46            container-name: container1
    47            resource: requests.cpu
    48            divisor: 1m
    49        thing:
    50          secret:
    51            name: foo
    52            key: bar
    53        a-secret:
    54          secret:
    55            name: secret1
    56            optional: true
    57        another-secret:
    58          secret:
    59            name: secret2
    60        thing1:
    61          config-map:
    62            name: foo
    63            key: bar
    64        a-configmap:
    65          config-map:
    66            name: configmap1
    67            optional: true
    68        another-configmap:
    69          config-map:
    70            name: configmap2
    71  `[1:]
    72  
    73  	envVarThing := core.EnvVar{
    74  		Name: "thing",
    75  		ValueFrom: &core.EnvVarSource{
    76  			SecretKeyRef: &core.SecretKeySelector{Key: "bar"},
    77  		},
    78  	}
    79  	envVarThing.ValueFrom.SecretKeyRef.Name = "foo"
    80  
    81  	envVarThing1 := core.EnvVar{
    82  		Name: "thing1",
    83  		ValueFrom: &core.EnvVarSource{
    84  			ConfigMapKeyRef: &core.ConfigMapKeySelector{Key: "bar"},
    85  		},
    86  	}
    87  	envVarThing1.ValueFrom.ConfigMapKeyRef.Name = "foo"
    88  
    89  	envFromSourceSecret1 := core.EnvFromSource{
    90  		SecretRef: &core.SecretEnvSource{Optional: pointer.BoolPtr(true)},
    91  	}
    92  	envFromSourceSecret1.SecretRef.Name = "secret1"
    93  
    94  	envFromSourceSecret2 := core.EnvFromSource{
    95  		SecretRef: &core.SecretEnvSource{},
    96  	}
    97  	envFromSourceSecret2.SecretRef.Name = "secret2"
    98  
    99  	envFromSourceConfigmap1 := core.EnvFromSource{
   100  		ConfigMapRef: &core.ConfigMapEnvSource{Optional: pointer.BoolPtr(true)},
   101  	}
   102  	envFromSourceConfigmap1.ConfigMapRef.Name = "configmap1"
   103  
   104  	envFromSourceConfigmap2 := core.EnvFromSource{
   105  		ConfigMapRef: &core.ConfigMapEnvSource{},
   106  	}
   107  	envFromSourceConfigmap2.ConfigMapRef.Name = "configmap2"
   108  
   109  	specs, err := k8sspecs.ParsePodSpec(specStr)
   110  	c.Assert(err, jc.ErrorIsNil)
   111  	envVars, envFromSource, err := k8sspecs.ContainerConfigToK8sEnvConfig(specs.Containers[0].EnvConfig)
   112  	c.Assert(err, jc.ErrorIsNil)
   113  	expectedEnvVar := []core.EnvVar{
   114  		{
   115  			Name: "MY_NODE_NAME",
   116  			ValueFrom: &core.EnvVarSource{
   117  				FieldRef: &core.ObjectFieldSelector{
   118  					FieldPath:  "spec.nodeName",
   119  					APIVersion: "v1",
   120  				},
   121  			},
   122  		},
   123  		{Name: "attr", Value: `foo=bar; name["fred"]="blogs";`},
   124  		{Name: "bar", Value: "true"},
   125  		{Name: "brackets", Value: `["hello", "world"]`},
   126  		{Name: "float", Value: "111.11111111"},
   127  		{Name: "foo", Value: "bar"},
   128  		{Name: "int", Value: "111"},
   129  		{
   130  			Name: "my-resource-limit",
   131  			ValueFrom: &core.EnvVarSource{
   132  				ResourceFieldRef: &core.ResourceFieldSelector{
   133  					ContainerName: "container1",
   134  					Resource:      "requests.cpu",
   135  					Divisor:       resource.MustParse("1m"),
   136  				},
   137  			},
   138  		},
   139  		{Name: "restricted", Value: "yes"},
   140  		{Name: "special", Value: "p@ssword's"},
   141  		{Name: "switch", Value: "true"},
   142  		envVarThing,
   143  		envVarThing1,
   144  	}
   145  	expectedEnvFromSource := []core.EnvFromSource{
   146  		envFromSourceConfigmap1,
   147  		envFromSourceConfigmap2,
   148  		envFromSourceSecret1,
   149  		envFromSourceSecret2,
   150  	}
   151  	for i := range envVars {
   152  		c.Check(envVars[i], jc.DeepEquals, expectedEnvVar[i])
   153  	}
   154  	for i := range envFromSource {
   155  		c.Check(envFromSource[i], jc.DeepEquals, expectedEnvFromSource[i])
   156  	}
   157  }
   158  
   159  func (s *containerEnvSuite) TestContainerConfigToK8sEnvConfigSliceNotSupported(c *gc.C) {
   160  	_, _, err := k8sspecs.ContainerConfigToK8sEnvConfig(map[string]interface{}{
   161  		"a-slice": []interface{}{},
   162  	})
   163  	c.Assert(err, gc.ErrorMatches, `config "a-slice" with type .* not supported`)
   164  }
   165  
   166  func (s *containerEnvSuite) TestContainerConfigToK8sEnvConfigFailedBadField(c *gc.C) {
   167  	_, _, err := k8sspecs.ContainerConfigToK8sEnvConfig(map[string]interface{}{
   168  		"a-bad-config-map": map[string]interface{}{
   169  			"config-map": map[string]interface{}{
   170  				"a-bad-field": "",
   171  			},
   172  		},
   173  	})
   174  	c.Assert(err, gc.ErrorMatches, `json: unknown field "a-bad-field"`)
   175  }
   176  
   177  func (s *containerEnvSuite) TestContainerConfigToK8sEnvConfigFailedRequiredFieldMissing(c *gc.C) {
   178  	type tc struct {
   179  		resourceType  string
   180  		optionalField string
   181  	}
   182  	for i, t := range []tc{
   183  		{resourceType: "secret", optionalField: "key"},
   184  		{resourceType: "config-map", optionalField: "key"},
   185  		{resourceType: "resource", optionalField: "container-name"},
   186  		{resourceType: "field", optionalField: "api-version"},
   187  	} {
   188  		c.Logf("checking %d: %q", i, t.resourceType)
   189  		_, _, err := k8sspecs.ContainerConfigToK8sEnvConfig(map[string]interface{}{
   190  			"empty": map[string]interface{}{
   191  				t.resourceType: map[string]interface{}{},
   192  			},
   193  		})
   194  		c.Check(err, gc.ErrorMatches, `config format of "empty" not supported`)
   195  
   196  		_, _, err = k8sspecs.ContainerConfigToK8sEnvConfig(map[string]interface{}{
   197  			"empty": map[string]interface{}{
   198  				t.resourceType: map[string]interface{}{
   199  					t.optionalField: "foo",
   200  				},
   201  			},
   202  		})
   203  		c.Check(err, gc.ErrorMatches, `config format of "empty" not supported`)
   204  	}
   205  }