...

Source file src/sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark/starlark_test.go

Documentation: sigs.k8s.io/kustomize/kyaml/fn/runtime/starlark

     1  // Copyright 2019 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package starlark
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"os"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/go-errors/errors"
    14  	"github.com/stretchr/testify/assert"
    15  	"sigs.k8s.io/kustomize/kyaml/kio"
    16  	"sigs.k8s.io/kustomize/kyaml/yaml"
    17  )
    18  
    19  func TestFilter_Filter(t *testing.T) {
    20  	var tests = []struct {
    21  		name                   string
    22  		input                  string
    23  		functionConfig         string
    24  		script                 string
    25  		expected               string
    26  		expectedFunctionConfig string
    27  		env                    map[string]string
    28  	}{
    29  		{
    30  			name: "add_annotation",
    31  			input: `
    32  apiVersion: apps/v1
    33  kind: Deployment
    34  metadata:
    35    name: nginx-deployment
    36  spec:
    37    template:
    38      spec:
    39        containers:
    40        - name: nginx
    41          # head comment
    42          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
    43  `,
    44  			script: `
    45  # set the foo annotation on each resource
    46  def run(r):
    47    for resource in r:
    48      resource["metadata"]["annotations"]["foo"] = "bar"
    49  
    50  run(ctx.resource_list["items"])
    51  `,
    52  			expected: `
    53  apiVersion: apps/v1
    54  kind: Deployment
    55  metadata:
    56    name: nginx-deployment
    57    annotations:
    58      foo: bar
    59      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
    60      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
    61  spec:
    62    template:
    63      spec:
    64        containers:
    65        - name: nginx
    66          # head comment
    67          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
    68  `,
    69  		},
    70  		{
    71  			name: "add_annotation_from_env",
    72  			input: `
    73  apiVersion: apps/v1
    74  kind: Deployment
    75  metadata:
    76    name: nginx-deployment
    77  spec:
    78    template:
    79      spec:
    80        containers:
    81        - name: nginx
    82          # head comment
    83          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
    84  `,
    85  			script: `
    86  def run(r):
    87    for resource in r:
    88      resource["metadata"]["annotations"]["foo"] = ctx.environment["ANNOTATION"]
    89  
    90  run(ctx.resource_list["items"])
    91  `,
    92  			env: map[string]string{"ANNOTATION": "annotation-value"},
    93  			expected: `
    94  apiVersion: apps/v1
    95  kind: Deployment
    96  metadata:
    97    name: nginx-deployment
    98    annotations:
    99      foo: annotation-value
   100      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   101      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   102  spec:
   103    template:
   104      spec:
   105        containers:
   106        - name: nginx
   107          # head comment
   108          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   109  `,
   110  		},
   111  		{
   112  			name: "add_annotation_from_open_api",
   113  			input: `
   114  apiVersion: apps/v1
   115  kind: Deployment
   116  metadata:
   117    name: nginx-deployment
   118  spec:
   119    template:
   120      spec:
   121        containers:
   122        - name: nginx
   123          # head comment
   124          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   125  `,
   126  			script: `
   127  def run(r):
   128    for resource in r:
   129      resource["metadata"]["annotations"]["foo"] = ctx.open_api["definitions"]["io.k8s.api.apps.v1.Deployment"]["description"]
   130  
   131  run(ctx.resource_list["items"])
   132  `,
   133  			expected: `
   134  apiVersion: apps/v1
   135  kind: Deployment
   136  metadata:
   137    name: nginx-deployment
   138    annotations:
   139      foo: Deployment enables declarative updates for Pods and ReplicaSets.
   140      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   141      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   142  spec:
   143    template:
   144      spec:
   145        containers:
   146        - name: nginx
   147          # head comment
   148          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   149  `,
   150  		},
   151  		{
   152  			name: "update_annotation",
   153  			input: `
   154  apiVersion: apps/v1
   155  kind: Deployment
   156  metadata:
   157    name: nginx-deployment
   158    annotations:
   159      foo: baz
   160  spec:
   161    template:
   162      spec:
   163        containers:
   164        - name: nginx
   165          # head comment
   166          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   167  `,
   168  			script: `
   169  # set the foo annotation on each resource
   170  def run(r):
   171    for resource in r:
   172      resource["metadata"]["annotations"]["foo"] = "bar"
   173  
   174  run(ctx.resource_list["items"])
   175  `,
   176  			expected: `
   177  apiVersion: apps/v1
   178  kind: Deployment
   179  metadata:
   180    name: nginx-deployment
   181    annotations:
   182      foo: bar
   183      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   184      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   185  spec:
   186    template:
   187      spec:
   188        containers:
   189        - name: nginx
   190          # head comment
   191          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   192  `,
   193  		},
   194  		{
   195  			name: "delete_annotation",
   196  			input: `
   197  apiVersion: apps/v1
   198  kind: Deployment
   199  metadata:
   200    name: nginx-deployment
   201    annotations:
   202      foo: baz
   203  spec:
   204    template:
   205      spec:
   206        containers:
   207        - name: nginx
   208          # head comment
   209          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   210  `,
   211  			script: `
   212  # set the foo annotation on each resource
   213  def run(r):
   214    for resource in r:
   215      resource["metadata"]["annotations"].pop("foo")
   216  
   217  run(ctx.resource_list["items"])
   218  `,
   219  			expected: `
   220  apiVersion: apps/v1
   221  kind: Deployment
   222  metadata:
   223    name: nginx-deployment
   224    annotations:
   225      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   226      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   227  spec:
   228    template:
   229      spec:
   230        containers:
   231        - name: nginx
   232          # head comment
   233          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   234  `,
   235  		},
   236  		{
   237  			name: "update_annotation_multiple",
   238  			input: `
   239  apiVersion: apps/v1
   240  kind: Deployment
   241  metadata:
   242    name: nginx-deployment-1
   243    annotations:
   244      foo: baz
   245  spec:
   246    template:
   247      spec:
   248        containers:
   249        - name: nginx
   250          # head comment
   251          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   252  ---
   253  apiVersion: apps/v1
   254  kind: Deployment
   255  metadata:
   256    name: nginx-deployment-2
   257  spec:
   258    template:
   259      spec:
   260        containers:
   261        - name: nginx
   262          # head comment
   263          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   264  `,
   265  			script: `
   266  # set the foo annotation on each resource
   267  def run(r):
   268    for resource in r:
   269      resource["metadata"]["annotations"]["foo"] = "bar"
   270  
   271  run(ctx.resource_list["items"])
   272  `,
   273  			expected: `
   274  apiVersion: apps/v1
   275  kind: Deployment
   276  metadata:
   277    name: nginx-deployment-1
   278    annotations:
   279      foo: bar
   280      internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   281      config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   282  spec:
   283    template:
   284      spec:
   285        containers:
   286        - name: nginx
   287          # head comment
   288          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   289  ---
   290  apiVersion: apps/v1
   291  kind: Deployment
   292  metadata:
   293    name: nginx-deployment-2
   294    annotations:
   295      foo: bar
   296      internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
   297      config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
   298  spec:
   299    template:
   300      spec:
   301        containers:
   302        - name: nginx
   303          # head comment
   304          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}`,
   305  		},
   306  		{
   307  			name: "add_resource",
   308  			input: `
   309  apiVersion: apps/v1
   310  kind: Deployment
   311  metadata:
   312    name: nginx-deployment-1
   313  spec:
   314    template:
   315      spec:
   316        containers:
   317        - name: nginx
   318          # head comment
   319          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   320  `,
   321  			script: `
   322  def run(r):
   323    d = {
   324    "apiVersion": "apps/v1",
   325    "kind": "Deployment",
   326    "metadata": {
   327      "name": "nginx-deployment-2",
   328    },
   329  }
   330    r.append(d)
   331  run(ctx.resource_list["items"])
   332  `,
   333  			expected: `
   334  apiVersion: apps/v1
   335  kind: Deployment
   336  metadata:
   337    name: nginx-deployment-1
   338    annotations:
   339      internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   340      config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   341  spec:
   342    template:
   343      spec:
   344        containers:
   345        - name: nginx
   346          # head comment
   347          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   348  ---
   349  apiVersion: apps/v1
   350  kind: Deployment
   351  metadata:
   352    name: nginx-deployment-2
   353    annotations:
   354      internal.config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
   355      config.kubernetes.io/path: 'deployment_nginx-deployment-2.yaml'
   356  `,
   357  		},
   358  		{
   359  			name: "remove_resource",
   360  			input: `
   361  apiVersion: apps/v1
   362  kind: Deployment
   363  metadata:
   364    name: nginx-deployment-1
   365  ---
   366  apiVersion: apps/v1
   367  kind: Deployment
   368  metadata:
   369    name: nginx-deployment-2
   370  `,
   371  			script: `
   372  def run(r):
   373    r.pop()
   374  run(ctx.resource_list["items"])
   375  `,
   376  			expected: `
   377  apiVersion: apps/v1
   378  kind: Deployment
   379  metadata:
   380    name: nginx-deployment-1
   381    annotations:
   382      internal.config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   383      config.kubernetes.io/path: 'deployment_nginx-deployment-1.yaml'
   384  `,
   385  		},
   386  		{
   387  			name: "functionConfig",
   388  			input: `
   389  apiVersion: apps/v1
   390  kind: Deployment
   391  metadata:
   392    name: nginx-deployment
   393  spec:
   394    template:
   395      spec:
   396        containers:
   397        - name: nginx
   398          # head comment
   399          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   400  `,
   401  			functionConfig: `
   402  kind: Script
   403  spec:
   404    value: "hello world"
   405  `,
   406  			script: `
   407  # set the foo annotation on each resource
   408  def run(r, an):
   409    for resource in r:
   410      resource["metadata"]["annotations"]["foo"] = an
   411  
   412  an = ctx.resource_list["functionConfig"]["spec"]["value"]
   413  run(ctx.resource_list["items"], an)
   414  `,
   415  			expected: `
   416  apiVersion: apps/v1
   417  kind: Deployment
   418  metadata:
   419    name: nginx-deployment
   420    annotations:
   421      foo: hello world
   422      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   423      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   424  spec:
   425    template:
   426      spec:
   427        containers:
   428        - name: nginx
   429          # head comment
   430          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   431  `,
   432  			expectedFunctionConfig: `
   433  kind: Script
   434  spec:
   435    value: "hello world"
   436  `,
   437  		},
   438  
   439  		{
   440  			name: "functionConfig_update_functionConfig",
   441  			input: `
   442  apiVersion: apps/v1
   443  kind: Deployment
   444  metadata:
   445    name: nginx-deployment
   446  spec:
   447    template:
   448      spec:
   449        containers:
   450        - name: nginx
   451          # head comment
   452          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   453  `,
   454  			functionConfig: `
   455  kind: Script
   456  spec:
   457    value: "hello world"
   458  `,
   459  			script: `
   460  # set the foo annotation on each resource
   461  def run(r, an):
   462    for resource in r:
   463      resource["metadata"]["annotations"]["foo"] = an
   464  
   465  an = ctx.resource_list["functionConfig"]["spec"]["value"]
   466  run(ctx.resource_list["items"], an)
   467  ctx.resource_list["functionConfig"]["spec"]["value"] = "updated"
   468  `,
   469  			expected: `
   470  apiVersion: apps/v1
   471  kind: Deployment
   472  metadata:
   473    name: nginx-deployment
   474    annotations:
   475      foo: hello world
   476      internal.config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   477      config.kubernetes.io/path: 'deployment_nginx-deployment.yaml'
   478  spec:
   479    template:
   480      spec:
   481        containers:
   482        - name: nginx
   483          # head comment
   484          image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image"}
   485  `,
   486  			expectedFunctionConfig: `
   487  kind: Script
   488  spec:
   489    value: "hello world"
   490  `,
   491  		},
   492  	}
   493  	for i := range tests {
   494  		test := tests[i]
   495  		t.Run(test.name, func(t *testing.T) {
   496  			for k, v := range test.env {
   497  				os.Setenv(k, v)
   498  			}
   499  			f := &Filter{Name: test.name, Program: test.script}
   500  
   501  			if test.functionConfig != "" {
   502  				fc, err := yaml.Parse(test.functionConfig)
   503  				if !assert.NoError(t, err) {
   504  					t.FailNow()
   505  				}
   506  				f.FunctionConfig = fc
   507  			}
   508  
   509  			r := &kio.ByteReader{Reader: bytes.NewBufferString(test.input)}
   510  			o := &bytes.Buffer{}
   511  			w := &kio.ByteWriter{Writer: o}
   512  			p := kio.Pipeline{
   513  				Inputs:  []kio.Reader{r},
   514  				Filters: []kio.Filter{f},
   515  				Outputs: []kio.Writer{w},
   516  			}
   517  			err := p.Execute()
   518  			if !assert.NoError(t, err) {
   519  				if e, ok := err.(*errors.Error); ok {
   520  					fmt.Fprintf(os.Stderr, "%s\n", e.Stack())
   521  				}
   522  				t.FailNow()
   523  			}
   524  			if !assert.Equal(t, strings.TrimSpace(test.expected), strings.TrimSpace(o.String())) {
   525  				t.FailNow()
   526  			}
   527  
   528  			if test.expectedFunctionConfig != "" {
   529  				if !assert.Equal(t,
   530  					strings.TrimSpace(test.expectedFunctionConfig),
   531  					strings.TrimSpace(f.FunctionConfig.MustString())) {
   532  					t.FailNow()
   533  				}
   534  			}
   535  		})
   536  	}
   537  }
   538  

View as plain text