...

Source file src/sigs.k8s.io/kustomize/api/krusty/fnplugin_test.go

Documentation: sigs.k8s.io/kustomize/api/krusty

     1  // Copyright 2022 The Kubernetes Authors.
     2  // SPDX-License-Identifier: Apache-2.0
     3  
     4  package krusty_test
     5  
     6  import (
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"testing"
    12  
    13  	"github.com/stretchr/testify/assert"
    14  	"github.com/stretchr/testify/require"
    15  	. "sigs.k8s.io/kustomize/api/krusty"
    16  	kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
    17  	"sigs.k8s.io/kustomize/kyaml/filesys"
    18  )
    19  
    20  const (
    21  	repoRootDir = "../../"
    22  )
    23  
    24  const generateDeploymentDotSh = `#!/bin/sh
    25  
    26  cat <<EOF
    27  apiVersion: apps/v1
    28  kind: Deployment
    29  metadata:
    30    name: nginx
    31    labels:
    32      app: nginx
    33    annotations:
    34      tshirt-size: small # this injects the resource reservations
    35  spec:
    36    selector:
    37      matchLabels:
    38        app: nginx
    39    template:
    40      metadata:
    41        labels:
    42          app: nginx
    43      spec:
    44        containers:
    45        - name: nginx
    46          image: nginx
    47  EOF
    48  `
    49  
    50  const krmTransformerDotSh = `#!/bin/bash
    51  cat << EOF
    52  apiVersion: v1
    53  kind: Secret
    54  metadata:
    55    name: dummyTransformed
    56  stringData:
    57    foo: bar
    58  type: Opaque
    59  EOF
    60  `
    61  
    62  func TestFnExecGeneratorInBase(t *testing.T) {
    63  	fSys := filesys.MakeFsOnDisk()
    64  
    65  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
    66  	o := th.MakeOptionsPluginsEnabled()
    67  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
    68  
    69  	tmpDir, err := filesys.NewTmpConfirmedDir()
    70  	require.NoError(t, err)
    71  	th.WriteK(tmpDir.String(), `
    72  resources:
    73  - short_secret.yaml
    74  generators:
    75  - gener.yaml
    76  `)
    77  
    78  	// Create some additional resource just to make sure everything is added
    79  	th.WriteF(filepath.Join(tmpDir.String(), "short_secret.yaml"),
    80  		`
    81  apiVersion: v1
    82  kind: Secret
    83  metadata:
    84    labels:
    85      airshipit.org/ephemeral-user-data: "true"
    86    name: node1-bmc-secret
    87  type: Opaque
    88  stringData:
    89    userData: |
    90      bootcmd:
    91      - mkdir /mnt/vda
    92  `)
    93  	th.WriteF(filepath.Join(tmpDir.String(), "generateDeployment.sh"), generateDeploymentDotSh)
    94  
    95  	require.NoError(t, os.Chmod(filepath.Join(tmpDir.String(), "generateDeployment.sh"), 0777))
    96  	th.WriteF(filepath.Join(tmpDir.String(), "gener.yaml"), `
    97  kind: executable
    98  metadata:
    99    name: demo
   100    annotations:
   101      config.kubernetes.io/function: |
   102        exec:
   103          path: ./generateDeployment.sh
   104  spec:
   105  `)
   106  
   107  	m := th.Run(tmpDir.String(), o)
   108  	yml, err := m.AsYaml()
   109  	require.NoError(t, err)
   110  	assert.Equal(t, `apiVersion: v1
   111  kind: Secret
   112  metadata:
   113    labels:
   114      airshipit.org/ephemeral-user-data: "true"
   115    name: node1-bmc-secret
   116  stringData:
   117    userData: |
   118      bootcmd:
   119      - mkdir /mnt/vda
   120  type: Opaque
   121  ---
   122  apiVersion: apps/v1
   123  kind: Deployment
   124  metadata:
   125    annotations:
   126      tshirt-size: small
   127    labels:
   128      app: nginx
   129    name: nginx
   130  spec:
   131    selector:
   132      matchLabels:
   133        app: nginx
   134    template:
   135      metadata:
   136        labels:
   137          app: nginx
   138      spec:
   139        containers:
   140        - image: nginx
   141          name: nginx
   142  `, string(yml))
   143  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   144  }
   145  
   146  func TestFnExecGeneratorInBaseWithOverlay(t *testing.T) {
   147  	fSys := filesys.MakeFsOnDisk()
   148  
   149  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
   150  	o := th.MakeOptionsPluginsEnabled()
   151  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
   152  
   153  	tmpDir, err := filesys.NewTmpConfirmedDir()
   154  	require.NoError(t, err)
   155  	base := filepath.Join(tmpDir.String(), "base")
   156  	prod := filepath.Join(tmpDir.String(), "prod")
   157  	require.NoError(t, fSys.Mkdir(base))
   158  	require.NoError(t, fSys.Mkdir(prod))
   159  	th.WriteK(base, `
   160  resources:
   161  - short_secret.yaml
   162  generators:
   163  - gener.yaml
   164  `)
   165  	th.WriteK(prod, `
   166  resources:
   167  - ../base
   168  `)
   169  	th.WriteF(filepath.Join(base, "short_secret.yaml"),
   170  		`
   171  apiVersion: v1
   172  kind: Secret
   173  metadata:
   174    labels:
   175      airshipit.org/ephemeral-user-data: "true"
   176    name: node1-bmc-secret
   177  type: Opaque
   178  stringData:
   179    userData: |
   180      bootcmd:
   181      - mkdir /mnt/vda
   182  `)
   183  	th.WriteF(filepath.Join(base, "generateDeployment.sh"), generateDeploymentDotSh)
   184  
   185  	require.NoError(t, os.Chmod(filepath.Join(base, "generateDeployment.sh"), 0777))
   186  	th.WriteF(filepath.Join(base, "gener.yaml"), `
   187  kind: executable
   188  metadata:
   189    name: demo
   190    annotations:
   191      config.kubernetes.io/function: |
   192        exec:
   193          path: ./generateDeployment.sh
   194  spec:
   195  `)
   196  
   197  	m := th.Run(prod, o)
   198  	require.NoError(t, err)
   199  	yml, err := m.AsYaml()
   200  	require.NoError(t, err)
   201  	assert.Equal(t, `apiVersion: v1
   202  kind: Secret
   203  metadata:
   204    labels:
   205      airshipit.org/ephemeral-user-data: "true"
   206    name: node1-bmc-secret
   207  stringData:
   208    userData: |
   209      bootcmd:
   210      - mkdir /mnt/vda
   211  type: Opaque
   212  ---
   213  apiVersion: apps/v1
   214  kind: Deployment
   215  metadata:
   216    annotations:
   217      tshirt-size: small
   218    labels:
   219      app: nginx
   220    name: nginx
   221  spec:
   222    selector:
   223      matchLabels:
   224        app: nginx
   225    template:
   226      metadata:
   227        labels:
   228          app: nginx
   229      spec:
   230        containers:
   231        - image: nginx
   232          name: nginx
   233  `, string(yml))
   234  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   235  }
   236  
   237  func TestFnExecGeneratorInOverlay(t *testing.T) {
   238  	fSys := filesys.MakeFsOnDisk()
   239  
   240  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
   241  	o := th.MakeOptionsPluginsEnabled()
   242  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
   243  
   244  	tmpDir, err := filesys.NewTmpConfirmedDir()
   245  	require.NoError(t, err)
   246  	base := filepath.Join(tmpDir.String(), "base")
   247  	prod := filepath.Join(tmpDir.String(), "prod")
   248  	require.NoError(t, fSys.Mkdir(base))
   249  	require.NoError(t, fSys.Mkdir(prod))
   250  	th.WriteK(base, `
   251  resources:
   252  - short_secret.yaml
   253  `)
   254  	th.WriteK(prod, `
   255  resources:
   256  - ../base
   257  generators:
   258  - gener.yaml
   259  `)
   260  	th.WriteF(filepath.Join(base, "short_secret.yaml"),
   261  		`
   262  apiVersion: v1
   263  kind: Secret
   264  metadata:
   265    labels:
   266      airshipit.org/ephemeral-user-data: "true"
   267    name: node1-bmc-secret
   268  type: Opaque
   269  stringData:
   270    userData: |
   271      bootcmd:
   272      - mkdir /mnt/vda
   273  `)
   274  	th.WriteF(filepath.Join(prod, "generateDeployment.sh"), generateDeploymentDotSh)
   275  
   276  	require.NoError(t, os.Chmod(filepath.Join(prod, "generateDeployment.sh"), 0777))
   277  	th.WriteF(filepath.Join(prod, "gener.yaml"), `
   278  kind: executable
   279  metadata:
   280    name: demo
   281    annotations:
   282      config.kubernetes.io/function: |
   283        exec:
   284          path: ./generateDeployment.sh
   285  spec:
   286  `)
   287  
   288  	m := th.Run(prod, o)
   289  	require.NoError(t, err)
   290  	yml, err := m.AsYaml()
   291  	require.NoError(t, err)
   292  	assert.Equal(t, `apiVersion: v1
   293  kind: Secret
   294  metadata:
   295    labels:
   296      airshipit.org/ephemeral-user-data: "true"
   297    name: node1-bmc-secret
   298  stringData:
   299    userData: |
   300      bootcmd:
   301      - mkdir /mnt/vda
   302  type: Opaque
   303  ---
   304  apiVersion: apps/v1
   305  kind: Deployment
   306  metadata:
   307    annotations:
   308      tshirt-size: small
   309    labels:
   310      app: nginx
   311    name: nginx
   312  spec:
   313    selector:
   314      matchLabels:
   315        app: nginx
   316    template:
   317      metadata:
   318        labels:
   319          app: nginx
   320      spec:
   321        containers:
   322        - image: nginx
   323          name: nginx
   324  `, string(yml))
   325  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   326  }
   327  
   328  func TestFnExecTransformerInBase(t *testing.T) {
   329  	fSys := filesys.MakeFsOnDisk()
   330  
   331  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
   332  	o := th.MakeOptionsPluginsEnabled()
   333  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
   334  
   335  	tmpDir, err := filesys.NewTmpConfirmedDir()
   336  	require.NoError(t, err)
   337  	base := filepath.Join(tmpDir.String(), "base")
   338  	require.NoError(t, fSys.Mkdir(base))
   339  	th.WriteK(base, `
   340  resources:
   341  - secret.yaml
   342  transformers:
   343  - krm-transformer.yaml
   344  `)
   345  	th.WriteF(filepath.Join(base, "secret.yaml"),
   346  		`
   347  apiVersion: v1
   348  kind: Secret
   349  metadata:
   350    name: dummy
   351  type: Opaque
   352  stringData:
   353    foo: bar
   354  `)
   355  	th.WriteF(filepath.Join(base, "krmTransformer.sh"), krmTransformerDotSh)
   356  
   357  	require.NoError(t, os.Chmod(filepath.Join(base, "krmTransformer.sh"), 0777))
   358  	th.WriteF(filepath.Join(base, "krm-transformer.yaml"), `
   359  apiVersion: examples.config.kubernetes.io/v1beta1
   360  kind: MyPlugin
   361  metadata:
   362    name: notImportantHere
   363    annotations:
   364      config.kubernetes.io/function: |
   365        exec:
   366          path: ./krmTransformer.sh
   367  `)
   368  
   369  	m := th.Run(base, o)
   370  	yml, err := m.AsYaml()
   371  	require.NoError(t, err)
   372  	assert.Equal(t, `apiVersion: v1
   373  kind: Secret
   374  metadata:
   375    name: dummyTransformed
   376  stringData:
   377    foo: bar
   378  type: Opaque
   379  `, string(yml))
   380  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   381  }
   382  
   383  func TestFnExecTransformerInBaseWithOverlay(t *testing.T) {
   384  	fSys := filesys.MakeFsOnDisk()
   385  
   386  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
   387  	o := th.MakeOptionsPluginsEnabled()
   388  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
   389  
   390  	tmpDir, err := filesys.NewTmpConfirmedDir()
   391  	require.NoError(t, err)
   392  	base := filepath.Join(tmpDir.String(), "base")
   393  	prod := filepath.Join(tmpDir.String(), "prod")
   394  	require.NoError(t, fSys.Mkdir(base))
   395  	require.NoError(t, fSys.Mkdir(prod))
   396  	th.WriteK(base, `
   397  resources:
   398  - secret.yaml
   399  transformers:
   400  - krm-transformer.yaml
   401  `)
   402  	th.WriteK(prod, `
   403  resources:
   404  - ../base
   405  `)
   406  	th.WriteF(filepath.Join(base, "secret.yaml"),
   407  		`
   408  apiVersion: v1
   409  kind: Secret
   410  metadata:
   411    name: dummy
   412  type: Opaque
   413  stringData:
   414    foo: bar
   415  `)
   416  	th.WriteF(filepath.Join(base, "krmTransformer.sh"), krmTransformerDotSh)
   417  
   418  	require.NoError(t, os.Chmod(filepath.Join(base, "krmTransformer.sh"), 0777))
   419  	th.WriteF(filepath.Join(base, "krm-transformer.yaml"), `
   420  apiVersion: examples.config.kubernetes.io/v1beta1
   421  kind: MyPlugin
   422  metadata:
   423    name: notImportantHere
   424    annotations:
   425      config.kubernetes.io/function: |
   426        exec:
   427          path: ./krmTransformer.sh
   428  `)
   429  
   430  	m := th.Run(prod, o)
   431  	yml, err := m.AsYaml()
   432  	require.NoError(t, err)
   433  	assert.Equal(t, `apiVersion: v1
   434  kind: Secret
   435  metadata:
   436    name: dummyTransformed
   437  stringData:
   438    foo: bar
   439  type: Opaque
   440  `, string(yml))
   441  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   442  }
   443  
   444  func TestFnExecTransformerInOverlay(t *testing.T) {
   445  	fSys := filesys.MakeFsOnDisk()
   446  
   447  	th := kusttest_test.MakeHarnessWithFs(t, fSys)
   448  	o := th.MakeOptionsPluginsEnabled()
   449  	o.PluginConfig.FnpLoadingOptions.EnableExec = true
   450  
   451  	tmpDir, err := filesys.NewTmpConfirmedDir()
   452  	require.NoError(t, err)
   453  	base := filepath.Join(tmpDir.String(), "base")
   454  	prod := filepath.Join(tmpDir.String(), "prod")
   455  	require.NoError(t, fSys.Mkdir(base))
   456  	require.NoError(t, fSys.Mkdir(prod))
   457  	th.WriteK(base, `
   458  resources:
   459  - secret.yaml
   460  `)
   461  	th.WriteK(prod, `
   462  resources:
   463  - ../base
   464  transformers:
   465  - krm-transformer.yaml
   466  `)
   467  	th.WriteF(filepath.Join(base, "secret.yaml"),
   468  		`
   469  apiVersion: v1
   470  kind: Secret
   471  metadata:
   472    name: dummy
   473  type: Opaque
   474  stringData:
   475    foo: bar
   476  `)
   477  	th.WriteF(filepath.Join(prod, "krmTransformer.sh"), krmTransformerDotSh)
   478  
   479  	require.NoError(t, os.Chmod(filepath.Join(prod, "krmTransformer.sh"), 0777))
   480  	th.WriteF(filepath.Join(prod, "krm-transformer.yaml"), `
   481  apiVersion: examples.config.kubernetes.io/v1beta1
   482  kind: MyPlugin
   483  metadata:
   484    name: notImportantHere
   485    annotations:
   486      config.kubernetes.io/function: |
   487        exec:
   488          path: ./krmTransformer.sh
   489  `)
   490  
   491  	m := th.Run(prod, o)
   492  	yml, err := m.AsYaml()
   493  	require.NoError(t, err)
   494  	assert.Equal(t, `apiVersion: v1
   495  kind: Secret
   496  metadata:
   497    name: dummyTransformed
   498  stringData:
   499    foo: bar
   500  type: Opaque
   501  `, string(yml))
   502  	require.NoError(t, fSys.RemoveAll(tmpDir.String()))
   503  }
   504  
   505  func skipIfNoDocker(t *testing.T) {
   506  	t.Helper()
   507  	if _, err := exec.LookPath("docker"); err != nil {
   508  		t.Skip("skipping because docker binary wasn't found in PATH")
   509  	}
   510  }
   511  
   512  func TestFnContainerGenerator(t *testing.T) {
   513  	skipIfNoDocker(t)
   514  	th := kusttest_test.MakeHarness(t)
   515  	o := th.MakeOptionsPluginsEnabled()
   516  	tmpDir, err := filesys.NewTmpConfirmedDir()
   517  	require.NoError(t, err)
   518  	th.WriteK(tmpDir.String(), `
   519  resources:
   520  - deployment.yaml
   521  generators:
   522  - service-set.yaml
   523  `)
   524  	// Create generator config
   525  	th.WriteF(filepath.Join(tmpDir.String(), "service-set.yaml"), `
   526  apiVersion: kustomize.sigs.k8s.io/v1alpha1
   527  kind: ServiceGenerator
   528  metadata:
   529    name: simplegenerator
   530    annotations:
   531      config.kubernetes.io/function: |
   532        container:
   533          image: gcr.io/kustomize-functions/e2econtainersimplegenerator
   534  spec:
   535    port: 8081
   536  `)
   537  	// Create another resource just to make sure everything is added
   538  	th.WriteF(filepath.Join(tmpDir.String(), "deployment.yaml"), `
   539  apiVersion: apps/v1
   540  kind: Deployment
   541  metadata:
   542    name: simplegenerator
   543  `)
   544  
   545  	build := exec.Command("docker", "build", ".",
   546  		"-f", "./cmd/config/internal/commands/e2e/e2econtainersimplegenerator/Dockerfile",
   547  		"-t", "gcr.io/kustomize-functions/e2econtainersimplegenerator",
   548  	)
   549  	build.Dir = repoRootDir
   550  	require.NoError(t, run(build))
   551  
   552  	m := th.Run(tmpDir.String(), o)
   553  	actual, err := m.AsYaml()
   554  	require.NoError(t, err)
   555  	require.Equal(t, `apiVersion: apps/v1
   556  kind: Deployment
   557  metadata:
   558    name: simplegenerator
   559  ---
   560  apiVersion: v1
   561  kind: Service
   562  metadata:
   563    labels:
   564      app: simplegenerator
   565    name: simplegenerator-svc
   566  spec:
   567    ports:
   568    - name: http
   569      port: 8081
   570      protocol: TCP
   571      targetPort: 8081
   572    selector:
   573      app: simplegenerator
   574  `, string(actual))
   575  }
   576  
   577  func TestFnContainerTransformer(t *testing.T) {
   578  	skipIfNoDocker(t)
   579  	th := kusttest_test.MakeHarness(t)
   580  	o := th.MakeOptionsPluginsEnabled()
   581  	tmpDir, err := filesys.NewTmpConfirmedDir()
   582  	require.NoError(t, err)
   583  	th.WriteK(tmpDir.String(), `
   584  resources:
   585  - deployment.yaml
   586  transformers:
   587  - e2econtainerconfig.yaml
   588  `)
   589  	th.WriteF(filepath.Join(tmpDir.String(), "deployment.yaml"), `
   590  apiVersion: apps/v1
   591  kind: Deployment
   592  metadata:
   593    name: foo
   594  `)
   595  	th.WriteF(filepath.Join(tmpDir.String(), "e2econtainerconfig.yaml"), `
   596  apiVersion: example.com/v1alpha1
   597  kind: Input
   598  metadata:
   599    name: foo
   600    annotations:
   601      config.kubernetes.io/function: |
   602        container:
   603          image: "gcr.io/kustomize-functions/e2econtainerconfig"
   604  `)
   605  	build := exec.Command("docker", "build", ".",
   606  		"-f", "./cmd/config/internal/commands/e2e/e2econtainerconfig/Dockerfile",
   607  		"-t", "gcr.io/kustomize-functions/e2econtainerconfig",
   608  	)
   609  	build.Dir = repoRootDir
   610  	require.NoError(t, run(build))
   611  	m := th.Run(tmpDir.String(), o)
   612  	actual, err := m.AsYaml()
   613  	require.NoError(t, err)
   614  	assert.Equal(t, `apiVersion: apps/v1
   615  kind: Deployment
   616  metadata:
   617    annotations:
   618      a-bool-value: "false"
   619      a-int-value: "0"
   620      a-string-value: ""
   621    name: foo
   622  `, string(actual))
   623  }
   624  
   625  func TestFnContainerTransformerWithConfig(t *testing.T) {
   626  	skipIfNoDocker(t)
   627  	//https://docs.docker.com/engine/reference/commandline/build/#git-repositories
   628  	build := exec.Command("docker", "build", "https://github.com/GoogleContainerTools/kpt-functions-sdk.git#go-sdk-v0.0.1:ts/hello-world",
   629  		"-f", "build/label_namespace.Dockerfile",
   630  		"-t", "gcr.io/kpt-functions/label-namespace:go-sdk-v0.0.1",
   631  	)
   632  	require.NoError(t, run(build))
   633  	th := kusttest_test.MakeHarness(t)
   634  	o := th.MakeOptionsPluginsEnabled()
   635  	fSys := filesys.MakeFsOnDisk()
   636  	b := MakeKustomizer(&o)
   637  	tmpDir, err := filesys.NewTmpConfirmedDir()
   638  	require.NoError(t, err)
   639  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
   640  resources:
   641  - data1.yaml
   642  - data2.yaml
   643  transformers:
   644  - label_namespace.yaml
   645  `)))
   646  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data1.yaml"), []byte(`
   647  apiVersion: v1
   648  kind: Namespace
   649  metadata:
   650    name: my-namespace
   651  `)))
   652  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data2.yaml"), []byte(`
   653  apiVersion: v1
   654  kind: Namespace
   655  metadata:
   656    name: another-namespace
   657  `)))
   658  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "label_namespace.yaml"), []byte(`
   659  apiVersion: v1
   660  kind: ConfigMap
   661  metadata:
   662    name: label_namespace
   663    annotations:
   664      config.kubernetes.io/function: |-
   665        container:
   666          image: gcr.io/kpt-functions/label-namespace:go-sdk-v0.0.1
   667  data:
   668    label_name: my-ns-name
   669    label_value: function-test
   670  `)))
   671  	m, err := b.Run(
   672  		fSys,
   673  		tmpDir.String())
   674  	require.NoError(t, err)
   675  	actual, err := m.AsYaml()
   676  	require.NoError(t, err)
   677  	assert.Equal(t, `apiVersion: v1
   678  kind: Namespace
   679  metadata:
   680    labels:
   681      my-ns-name: function-test
   682    name: my-namespace
   683  ---
   684  apiVersion: v1
   685  kind: Namespace
   686  metadata:
   687    labels:
   688      my-ns-name: function-test
   689    name: another-namespace
   690  `, string(actual))
   691  }
   692  
   693  func TestFnContainerEnvVars(t *testing.T) {
   694  	skipIfNoDocker(t)
   695  	th := kusttest_test.MakeHarness(t)
   696  	o := th.MakeOptionsPluginsEnabled()
   697  	fSys := filesys.MakeFsOnDisk()
   698  	b := MakeKustomizer(&o)
   699  	tmpDir, err := filesys.NewTmpConfirmedDir()
   700  	require.NoError(t, err)
   701  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
   702  generators:
   703  - gener.yaml
   704  `)))
   705  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(`
   706  apiVersion: kustomize.sigs.k8s.io/v1alpha1
   707  kind: EnvTemplateGenerator
   708  metadata:
   709    name: e2econtainerenvgenerator
   710    annotations:
   711      config.kubernetes.io/function: |
   712        container:
   713          image: gcr.io/kustomize-functions/e2econtainerenvgenerator
   714          envs:
   715          - TESTTEMPLATE=value
   716  template: |
   717    apiVersion: v1
   718    kind: ConfigMap
   719    metadata:
   720      name: env
   721    data:
   722      value: %q
   723  `)))
   724  	build := exec.Command("docker", "build", ".",
   725  		"-f", "./cmd/config/internal/commands/e2e/e2econtainerenvgenerator/Dockerfile",
   726  		"-t", "gcr.io/kustomize-functions/e2econtainerenvgenerator",
   727  	)
   728  	build.Dir = repoRootDir
   729  	require.NoError(t, run(build))
   730  
   731  	m, err := b.Run(
   732  		fSys,
   733  		tmpDir.String())
   734  	require.NoError(t, err)
   735  	actual, err := m.AsYaml()
   736  	require.NoError(t, err)
   737  	assert.Equal(t, `apiVersion: v1
   738  data:
   739    value: value
   740  kind: ConfigMap
   741  metadata:
   742    name: env
   743  `, string(actual))
   744  }
   745  
   746  func TestFnContainerFnMounts(t *testing.T) {
   747  	skipIfNoDocker(t)
   748  	th := kusttest_test.MakeHarness(t)
   749  	o := th.MakeOptionsPluginsEnabled()
   750  	fSys := filesys.MakeFsOnDisk()
   751  	b := MakeKustomizer(&o)
   752  	tmpDir, err := filesys.NewTmpConfirmedDir()
   753  	require.NoError(t, err)
   754  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
   755  generators:
   756  - gener.yaml
   757  `)))
   758  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(`
   759  apiVersion: kustomize.sigs.k8s.io/v1alpha1
   760  kind: RenderHelmChart
   761  metadata:
   762    name: demo
   763    annotations:
   764      config.kubernetes.io/function: |
   765        container:
   766          image: gcr.io/kustomize-functions/e2econtainermountbind
   767          mounts:
   768          - type: "bind"
   769            src: "./yaml"
   770            dst: "/tmp/yaml"
   771  path: /tmp/yaml/resources.yaml
   772  `)))
   773  	require.NoError(t, fSys.MkdirAll(filepath.Join(tmpDir.String(), "yaml", "tmp")))
   774  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "yaml", "resources.yaml"), []byte(`
   775  apiVersion: apps/v1
   776  kind: Deployment
   777  metadata:
   778    name: name
   779  spec:
   780    replicas: 3
   781  `)))
   782  	build := exec.Command("docker", "build", ".",
   783  		"-f", "./cmd/config/internal/commands/e2e/e2econtainermountbind/Dockerfile",
   784  		"-t", "gcr.io/kustomize-functions/e2econtainermountbind",
   785  	)
   786  	build.Dir = repoRootDir
   787  	require.NoError(t, run(build))
   788  
   789  	m, err := b.Run(
   790  		fSys,
   791  		tmpDir.String())
   792  	require.NoError(t, err)
   793  	actual, err := m.AsYaml()
   794  	require.NoError(t, err)
   795  	assert.Equal(t, `apiVersion: apps/v1
   796  kind: Deployment
   797  metadata:
   798    name: name
   799  spec:
   800    replicas: 3
   801  `, string(actual))
   802  }
   803  
   804  func TestFnContainerMountsLoadRestrictions_absolute(t *testing.T) {
   805  	skipIfNoDocker(t)
   806  	th := kusttest_test.MakeHarness(t)
   807  	o := th.MakeOptionsPluginsEnabled()
   808  	fSys := filesys.MakeFsOnDisk()
   809  	b := MakeKustomizer(&o)
   810  	tmpDir, err := filesys.NewTmpConfirmedDir()
   811  	require.NoError(t, err)
   812  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
   813  generators:
   814    - |-
   815      apiVersion: v1alpha1
   816      kind: RenderHelmChart
   817      metadata:
   818        name: demo
   819        annotations:
   820          config.kubernetes.io/function: |
   821            container:
   822              image: gcr.io/kpt-fn/render-helm-chart:v0.1.0
   823              mounts:
   824              - type: "bind"
   825                src: "/tmp/dir"
   826                dst: "/tmp/charts"
   827  `)))
   828  	_, err = b.Run(
   829  		fSys,
   830  		tmpDir.String())
   831  	require.Error(t, err)
   832  	assert.Contains(t, err.Error(), "loading generator plugins: failed to load generator: plugin RenderHelmChart."+
   833  		"v1alpha1.[noGrp]/demo.[noNs] with mount path '/tmp/dir' is not permitted; mount paths must"+
   834  		" be relative to the current kustomization directory")
   835  }
   836  
   837  func TestFnContainerMountsLoadRestrictions_outsideCurrentDir(t *testing.T) {
   838  	skipIfNoDocker(t)
   839  	th := kusttest_test.MakeHarness(t)
   840  	o := th.MakeOptionsPluginsEnabled()
   841  	fSys := filesys.MakeFsOnDisk()
   842  	b := MakeKustomizer(&o)
   843  	tmpDir, err := filesys.NewTmpConfirmedDir()
   844  	require.NoError(t, err)
   845  	require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(`
   846  generators:
   847    - |-
   848      apiVersion: v1alpha1
   849      kind: RenderHelmChart
   850      metadata:
   851        name: demo
   852        annotations:
   853          config.kubernetes.io/function: |
   854            container:
   855              image: gcr.io/kpt-fn/render-helm-chart:v0.1.0
   856              mounts:
   857              - type: "bind"
   858                src: "./tmp/../../dir"
   859                dst: "/tmp/charts"
   860  `)))
   861  	_, err = b.Run(
   862  		fSys,
   863  		tmpDir.String())
   864  	require.Error(t, err)
   865  	assert.Contains(t, err.Error(), "loading generator plugins: failed to load generator: plugin RenderHelmChart."+
   866  		"v1alpha1.[noGrp]/demo.[noNs] with mount path './tmp/../../dir' is not permitted; mount paths must "+
   867  		"be under the current kustomization directory")
   868  }
   869  
   870  func TestFnContainerMountsLoadRestrictions_root(t *testing.T) {
   871  	skipIfNoDocker(t)
   872  	th := kusttest_test.MakeHarness(t)
   873  
   874  	th.WriteK(".", `
   875  generators:
   876  - gener.yaml
   877  `)
   878  	// Create generator config
   879  	th.WriteF("gener.yaml", `
   880  apiVersion: examples.config.kubernetes.io/v1beta1
   881  kind: CockroachDB
   882  metadata:
   883    name: demo
   884    annotations:
   885      config.kubernetes.io/function: |
   886        container:
   887          image: gcr.io/kustomize-functions/example-cockroachdb:v0.1.0
   888  spec:
   889    replicas: 3
   890  `)
   891  	err := th.RunWithErr(".", th.MakeOptionsPluginsEnabled())
   892  	require.Error(t, err)
   893  	assert.EqualError(t, err, "couldn't execute function: root working directory '/' not allowed")
   894  }
   895  
   896  // run calls Cmd.Run and wraps the error to include the output to make debugging
   897  // easier. Not safe for real code, but fine for tests.
   898  func run(cmd *exec.Cmd) error {
   899  	if out, err := cmd.CombinedOutput(); err != nil {
   900  		return fmt.Errorf("%w\n--- COMMAND OUTPUT ---\n%s", err, string(out))
   901  	}
   902  	return nil
   903  }
   904  

View as plain text