From 6ccb4939c7be67288da942b804b57d5c16887ad7 Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Thu, 24 Feb 2022 18:25:05 -0800 Subject: [PATCH 1/5] fix containerized function mounts issue --- api/internal/plugins/loader/loader.go | 15 +- api/krusty/fnplugin_test.go | 227 ++++++++++++++++++ .../charts/helloworld-chart/Chart.yaml | 6 + .../helloworld-chart/templates/NOTES.txt | 21 ++ .../helloworld-chart/templates/_helpers.tpl | 63 +++++ .../templates/deployment.yaml | 55 +++++ .../helloworld-chart/templates/ingress.yaml | 41 ++++ .../helloworld-chart/templates/service.yaml | 15 ++ .../templates/serviceaccount.yaml | 12 + .../templates/tests/test-connection.yaml | 15 ++ .../charts/helloworld-chart/values.yaml | 27 +++ .../charts/helloworld-values/values.yaml | 68 ++++++ kyaml/fn/runtime/container/container.go | 19 +- kyaml/fn/runtime/container/container_test.go | 8 +- kyaml/fn/runtime/runtimeutil/functiontypes.go | 5 - kyaml/runfn/runfn.go | 9 +- .../hashtransformer/HashTransformer_test.go | 2 +- 17 files changed, 590 insertions(+), 18 deletions(-) create mode 100644 api/krusty/testdata/charts/helloworld-chart/Chart.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/service.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml create mode 100644 api/krusty/testdata/charts/helloworld-chart/values.yaml create mode 100644 api/krusty/testdata/charts/helloworld-values/values.yaml diff --git a/api/internal/plugins/loader/loader.go b/api/internal/plugins/loader/loader.go index 93c8559d23..86557a457a 100644 --- a/api/internal/plugins/loader/loader.go +++ b/api/internal/plugins/loader/loader.go @@ -49,7 +49,9 @@ func (l *Loader) Config() *types.PluginConfig { // SetWorkDir sets the working directory for this loader's plugins func (l *Loader) SetWorkDir(wd string) { - l.pc.FnpLoadingOptions.WorkingDir = wd + if wd != string(filepath.Separator) { + l.pc.FnpLoadingOptions.WorkingDir = wd + } } func (l *Loader) LoadGenerators( @@ -228,6 +230,17 @@ func (l *Loader) makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) { func (l *Loader) loadPlugin(res *resource.Resource) (resmap.Configurable, error) { spec := fnplugin.GetFunctionSpec(res) if spec != nil { + // validation check that function mounts are under the current kustomization directory + for _, mount := range spec.Container.StorageMounts { + if filepath.IsAbs(mount.Src) { + return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+ + "mount paths must be relative to the current kustomization directory", res.OrgId(), mount.Src)) + } + if strings.HasPrefix(filepath.Clean(mount.Src), "../") { + return nil, errors.New(fmt.Sprintf("plugin %s with mount path '%s' is not permitted; "+ + "mount paths must be under the current kustomization directory", res.OrgId(), mount.Src)) + } + } return fnplugin.NewFnPlugin(&l.pc.FnpLoadingOptions), nil } return l.loadExecOrGoPlugin(res.OrgId()) diff --git a/api/krusty/fnplugin_test.go b/api/krusty/fnplugin_test.go index b865a7e46f..758d1a4f15 100644 --- a/api/krusty/fnplugin_test.go +++ b/api/krusty/fnplugin_test.go @@ -7,9 +7,11 @@ import ( "os" "os/exec" "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/assert" + . "sigs.k8s.io/kustomize/api/krusty" kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest" "sigs.k8s.io/kustomize/kyaml/filesys" ) @@ -633,3 +635,228 @@ metadata: name: env `) } + +func TestFnContainerMounts(t *testing.T) { + skipIfNoDocker(t) + + th := kusttest_test.MakeHarness(t) + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() + assert.NoError(t, err) + + path, err := os.Getwd() + assert.NoError(t, err) + + src := filepath.Join(path, "testdata", "charts") + string(filepath.Separator) + dst := filepath.Join(tmpDir.String(), "testdata", "charts") + string(filepath.Separator) + assert.NoError(t, os.MkdirAll(dst, 0777)) + + switch runtime.GOOS { + case "darwin": + cmd := exec.Command("cp", "-r", src, dst) + assert.NoError(t, cmd.Run()) + case "linux": + d := dst + "." + cmd := exec.Command("cp", "-r", src, d) + assert.NoError(t, cmd.Run()) + default: + t.SkipNow() + } + + chartPath, err := filepath.Rel(tmpDir.String(), dst) + assert.NoError(t, err) + + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` +generators: + - |- + apiVersion: v1alpha1 + kind: RenderHelmChart + metadata: + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 + mounts: + - type: "bind" + src: "`+chartPath+`" + dst: "/tmp/charts" + helmCharts: + - name: helloworld-chart + releaseName: test + valuesFile: /tmp/charts/helloworld-values/values.yaml +`))) + m, err := b.Run( + fSys, + tmpDir.String()) + assert.NoError(t, err) + yml, err := m.AsYaml() + assert.NoError(t, err) + assert.Equal(t, `apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/instance: test + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: helloworld-chart + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: helloworld-chart-0.1.0 + name: test-helloworld-chart +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/instance: test + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: helloworld-chart + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: helloworld-chart-0.1.0 + name: test-helloworld-chart +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: http + selector: + app.kubernetes.io/instance: test + app.kubernetes.io/name: helloworld-chart + type: ClusterIP +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/instance: test + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: helloworld-chart + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: helloworld-chart-0.1.0 + name: test-helloworld-chart +spec: + replicas: 5 + selector: + matchLabels: + app.kubernetes.io/instance: test + app.kubernetes.io/name: helloworld-chart + template: + metadata: + labels: + app.kubernetes.io/instance: test + app.kubernetes.io/name: helloworld-chart + spec: + containers: + - image: nginx:1.16.0 + imagePullPolicy: Always + livenessProbe: + httpGet: + path: / + port: http + name: helloworld-chart + ports: + - containerPort: 80 + name: http + protocol: TCP + readinessProbe: + httpGet: + path: / + port: http + resources: {} + securityContext: {} + securityContext: {} + serviceAccountName: test-helloworld-chart +--- +apiVersion: v1 +kind: Pod +metadata: + annotations: + helm.sh/hook: test-success + labels: + app.kubernetes.io/instance: test + app.kubernetes.io/managed-by: Helm + app.kubernetes.io/name: helloworld-chart + app.kubernetes.io/version: 1.16.0 + helm.sh/chart: helloworld-chart-0.1.0 + name: test-helloworld-chart-test-connection +spec: + containers: + - args: + - test-helloworld-chart:80 + command: + - wget + image: busybox + name: wget + restartPolicy: Never +`, string(yml)) + + assert.NoError(t, fSys.RemoveAll(tmpDir.String())) +} + +func TestFnContainerMountsLoadRestrictions_absolute(t *testing.T) { + skipIfNoDocker(t) + th := kusttest_test.MakeHarness(t) + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() + assert.NoError(t, err) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` +generators: + - |- + apiVersion: v1alpha1 + kind: RenderHelmChart + metadata: + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 + mounts: + - type: "bind" + src: "/tmp/dir" + dst: "/tmp/charts" +`))) + _, err = b.Run( + fSys, + tmpDir.String()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "loading generator plugins: plugin RenderHelmChart."+ + "v1alpha1.[noGrp]/demo.[noNs] with mount path '/tmp/dir' is not permitted; mount paths must"+ + " be relative to the current kustomization directory") +} + +func TestFnContainerMountsLoadRestrictions_outsideCurrentDir(t *testing.T) { + skipIfNoDocker(t) + th := kusttest_test.MakeHarness(t) + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() + assert.NoError(t, err) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` +generators: + - |- + apiVersion: v1alpha1 + kind: RenderHelmChart + metadata: + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 + mounts: + - type: "bind" + src: "./tmp/../../dir" + dst: "/tmp/charts" +`))) + _, err = b.Run( + fSys, + tmpDir.String()) + assert.Error(t, err) + assert.Contains(t, err.Error(), "loading generator plugins: plugin RenderHelmChart."+ + "v1alpha1.[noGrp]/demo.[noNs] with mount path './tmp/../../dir' is not permitted; mount paths must "+ + "be under the current kustomization directory") +} diff --git a/api/krusty/testdata/charts/helloworld-chart/Chart.yaml b/api/krusty/testdata/charts/helloworld-chart/Chart.yaml new file mode 100644 index 0000000000..de4012af9d --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: helloworld-chart +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: 1.16.0 diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt b/api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt new file mode 100644 index 0000000000..af17e53fbc --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "helloworld-chart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "helloworld-chart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "helloworld-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "helloworld-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl b/api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl new file mode 100644 index 0000000000..3a62dfa0f2 --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl @@ -0,0 +1,63 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "helloworld-chart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "helloworld-chart.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "helloworld-chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "helloworld-chart.labels" -}} +helm.sh/chart: {{ include "helloworld-chart.chart" . }} +{{ include "helloworld-chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "helloworld-chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "helloworld-chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "helloworld-chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "helloworld-chart.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml b/api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml new file mode 100644 index 0000000000..ca686e89ec --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml @@ -0,0 +1,55 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "helloworld-chart.fullname" . }} + labels: + {{- include "helloworld-chart.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "helloworld-chart.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "helloworld-chart.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "helloworld-chart.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml b/api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml new file mode 100644 index 0000000000..76e1dd91d7 --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "helloworld-chart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "helloworld-chart.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/service.yaml b/api/krusty/testdata/charts/helloworld-chart/templates/service.yaml new file mode 100644 index 0000000000..a80cf8cd64 --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "helloworld-chart.fullname" . }} + labels: + {{- include "helloworld-chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "helloworld-chart.selectorLabels" . | nindent 4 }} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml b/api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml new file mode 100644 index 0000000000..bf9a8e1544 --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "helloworld-chart.serviceAccountName" . }} + labels: + {{- include "helloworld-chart.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end -}} diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml b/api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..a71342a0d0 --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "helloworld-chart.fullname" . }}-test-connection" + labels: + {{- include "helloworld-chart.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "helloworld-chart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/api/krusty/testdata/charts/helloworld-chart/values.yaml b/api/krusty/testdata/charts/helloworld-chart/values.yaml new file mode 100644 index 0000000000..e81d4bf57d --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-chart/values.yaml @@ -0,0 +1,27 @@ +replicaCount: 1 +image: + repository: nginx + pullPolicy: IfNotPresent +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +serviceAccount: + create: true + annotations: {} + name: +podSecurityContext: {} +securityContext: {} +service: + type: ClusterIP + port: 80 +ingress: + enabled: false + annotations: {} + hosts: + - host: chart-example.local + paths: [] + tls: [] +resources: {} +nodeSelector: {} +tolerations: [] +affinity: {} diff --git a/api/krusty/testdata/charts/helloworld-values/values.yaml b/api/krusty/testdata/charts/helloworld-values/values.yaml new file mode 100644 index 0000000000..d178c72a8a --- /dev/null +++ b/api/krusty/testdata/charts/helloworld-values/values.yaml @@ -0,0 +1,68 @@ +# Default values for helloworld-chart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 5 + +image: + repository: nginx + pullPolicy: Always + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + +podSecurityContext: {} +# fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true +# runAsUser: 1000 + +service: + type: ClusterIP + port: 80 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m +# memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} diff --git a/kyaml/fn/runtime/container/container.go b/kyaml/fn/runtime/container/container.go index c7cda7dbda..76b51a8c50 100644 --- a/kyaml/fn/runtime/container/container.go +++ b/kyaml/fn/runtime/container/container.go @@ -6,10 +6,11 @@ package container import ( "fmt" "os" + "path/filepath" + "sigs.k8s.io/kustomize/kyaml/errors" runtimeexec "sigs.k8s.io/kustomize/kyaml/fn/runtime/exec" "sigs.k8s.io/kustomize/kyaml/fn/runtime/runtimeutil" - "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -151,11 +152,14 @@ func (c *Filter) setupExec() error { if c.Exec.Path != "" { return nil } - wd, err := os.Getwd() - if err != nil { - return err + + if c.Exec.WorkingDir == "" { + wd, err := os.Getwd() + if err != nil { + return errors.Wrap(err) + } + c.Exec.WorkingDir = wd } - c.Exec.WorkingDir = wd path, args := c.getCommand() c.Exec.Path = path @@ -183,8 +187,11 @@ func (c *Filter) getCommand() (string, []string) { // note: don't make fs readonly because things like heredoc rely on writing tmp files } - // TODO(joncwong): Allow StorageMount fields to have default values. for _, storageMount := range c.StorageMounts { + // convert declarative relative paths to absolute (otherwise docker will throw an error) + if !filepath.IsAbs(storageMount.Src) { + storageMount.Src = filepath.Join(c.Exec.WorkingDir, storageMount.Src) + } args = append(args, "--mount", storageMount.String()) } diff --git a/kyaml/fn/runtime/container/container_test.go b/kyaml/fn/runtime/container/container_test.go index 06c3a7dd23..18f00b0c28 100644 --- a/kyaml/fn/runtime/container/container_test.go +++ b/kyaml/fn/runtime/container/container_test.go @@ -83,16 +83,16 @@ metadata: "--security-opt=no-new-privileges", "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "bind", "/mount/path", "/local/"), "--mount", fmt.Sprintf("type=%s,source=%s,target=%s", "bind", "/mount/pathrw", "/localrw/"), - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "volume", "myvol", "/local/"), - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "tmpfs", "", "/local/"), + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "volume", "/myvol", "/local/"), + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "tmpfs", "/", "/local/"), }, containerSpec: runtimeutil.ContainerSpec{ Image: "example.com:version", StorageMounts: []runtimeutil.StorageMount{ {MountType: "bind", Src: "/mount/path", DstPath: "/local/"}, {MountType: "bind", Src: "/mount/pathrw", DstPath: "/localrw/", ReadWriteMode: true}, - {MountType: "volume", Src: "myvol", DstPath: "/local/"}, - {MountType: "tmpfs", Src: "", DstPath: "/local/"}, + {MountType: "volume", Src: "/myvol", DstPath: "/local/"}, + {MountType: "tmpfs", Src: "/", DstPath: "/local/"}, }, }, UIDGID: "nobody", diff --git a/kyaml/fn/runtime/runtimeutil/functiontypes.go b/kyaml/fn/runtime/runtimeutil/functiontypes.go index 83e7ff0eca..39cb241959 100644 --- a/kyaml/fn/runtime/runtimeutil/functiontypes.go +++ b/kyaml/fn/runtime/runtimeutil/functiontypes.go @@ -136,9 +136,6 @@ type FunctionSpec struct { // ExecSpec is the spec for running a function as an executable Exec ExecSpec `json:"exec,omitempty" yaml:"exec,omitempty"` - - // Mounts are the storage or directories to mount into the container - StorageMounts []StorageMount `json:"mounts,omitempty" yaml:"mounts,omitempty"` } type ExecSpec struct { @@ -208,9 +205,7 @@ func GetFunctionSpec(n *yaml.RNode) *FunctionSpec { if err != nil { return nil } - if fn := getFunctionSpecFromAnnotation(n, meta); fn != nil { - fn.StorageMounts = []StorageMount{} return fn } diff --git a/kyaml/runfn/runfn.go b/kyaml/runfn/runfn.go index eda2c29025..c2cf073061 100644 --- a/kyaml/runfn/runfn.go +++ b/kyaml/runfn/runfn.go @@ -330,6 +330,7 @@ func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) ( } cf, ok := c.(*container.Filter) if global && ok { + cf.Exec.WorkingDir = r.WorkingDir cf.Exec.GlobalScope = true } fltrs = append(fltrs, c) @@ -468,11 +469,17 @@ func (r *RunFns) ffp(spec runtimeutil.FunctionSpec, api *yaml.RNode, currentUser if err != nil { return nil, err } + + // Storage mounts can either come from kustomize fn run --mounts, + // or from the declarative function mounts field. + storageMounts := spec.Container.StorageMounts + storageMounts = append(storageMounts, r.StorageMounts...) + c := container.NewContainer( runtimeutil.ContainerSpec{ Image: spec.Container.Image, Network: spec.Container.Network, - StorageMounts: r.StorageMounts, + StorageMounts: storageMounts, Env: spec.Container.Env, }, uidgid, diff --git a/plugin/builtin/hashtransformer/HashTransformer_test.go b/plugin/builtin/hashtransformer/HashTransformer_test.go index 3d62541ac0..27972250cd 100644 --- a/plugin/builtin/hashtransformer/HashTransformer_test.go +++ b/plugin/builtin/hashtransformer/HashTransformer_test.go @@ -6,7 +6,7 @@ package main_test import ( "testing" - "sigs.k8s.io/kustomize/api/testutils/kusttest" + kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest" ) func TestHashTransformer(t *testing.T) { From 4fdbebf348b8401227c3c2fdaed625f955892472 Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Mon, 11 Apr 2022 16:05:29 -0700 Subject: [PATCH 2/5] skip path test on windows --- kyaml/fn/runtime/container/container_test.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/kyaml/fn/runtime/container/container_test.go b/kyaml/fn/runtime/container/container_test.go index 18f00b0c28..bf9e2483a8 100644 --- a/kyaml/fn/runtime/container/container_test.go +++ b/kyaml/fn/runtime/container/container_test.go @@ -7,6 +7,7 @@ import ( "bytes" "fmt" "os" + "runtime" "testing" "github.com/stretchr/testify/assert" @@ -23,6 +24,7 @@ func TestFilter_setupExec(t *testing.T) { expectedArgs []string containerSpec runtimeutil.ContainerSpec UIDGID string + skipOnWindows bool }{ { name: "command", @@ -68,7 +70,8 @@ metadata: }, { - name: "storage_mounts", + name: "storage_mounts", + skipOnWindows: true, // the fieldpaths are different on Windows functionConfig: `apiVersion: apps/v1 kind: Deployment metadata: @@ -122,6 +125,9 @@ metadata: for i := range tests { tt := tests[i] t.Run(tt.name, func(t *testing.T) { + if tt.skipOnWindows && runtime.GOOS == "windows" { + t.SkipNow() + } cfg, err := yaml.Parse(tt.functionConfig) if !assert.NoError(t, err) { t.FailNow() From 96977a163d97eeaddf6b5802025aa4c4436e3fe0 Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Mon, 11 Apr 2022 16:17:57 -0700 Subject: [PATCH 3/5] move test out of temp dir --- Makefile | 4 +- api/krusty/fnplugin_test.go | 65 +++---------------- .../charts/helloworld-chart/Chart.yaml | 0 .../helloworld-chart/templates/NOTES.txt | 0 .../helloworld-chart/templates/_helpers.tpl | 0 .../templates/deployment.yaml | 0 .../helloworld-chart/templates/ingress.yaml | 0 .../helloworld-chart/templates/service.yaml | 0 .../templates/serviceaccount.yaml | 0 .../templates/tests/test-connection.yaml | 0 .../charts/helloworld-chart/values.yaml | 0 .../charts/helloworld-values/values.yaml | 0 .../testdata/fnmounts/kustomization.yaml | 20 ++++++ 13 files changed, 32 insertions(+), 57 deletions(-) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/Chart.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/NOTES.txt (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/_helpers.tpl (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/deployment.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/ingress.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/service.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/serviceaccount.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/templates/tests/test-connection.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-chart/values.yaml (100%) rename api/krusty/testdata/{ => fnmounts}/charts/helloworld-values/values.yaml (100%) create mode 100644 api/krusty/testdata/fnmounts/kustomization.yaml diff --git a/Makefile b/Makefile index 8709fa0fe0..63ae4eb564 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ kustomize: $(MYGOBIN)/kustomize # Used to add non-default compilation flags when experimenting with # plugin-to-api compatibility checks. .PHONY: build-kustomize-api -build-kustomize-api: $(builtinplugins) +build-kustomize-api: $(MYGOBIN)/goimports $(builtinplugins) cd api; $(MAKE) build .PHONY: generate-kustomize-api @@ -132,7 +132,7 @@ test-unit-all: \ # This target is used by our Github Actions CI to run unit tests for all non-plugin modules in multiple GOOS environments. .PHONY: test-unit-non-plugin -test-unit-non-plugin: +test-unit-non-plugin: kustomize ./hack/for-each-module.sh "make test" "./plugin/*" 15 .PHONY: build-non-plugin-all diff --git a/api/krusty/fnplugin_test.go b/api/krusty/fnplugin_test.go index 758d1a4f15..28294e286f 100644 --- a/api/krusty/fnplugin_test.go +++ b/api/krusty/fnplugin_test.go @@ -4,10 +4,10 @@ package krusty_test import ( + "bytes" "os" "os/exec" "path/filepath" - "runtime" "testing" "github.com/stretchr/testify/assert" @@ -639,61 +639,18 @@ metadata: func TestFnContainerMounts(t *testing.T) { skipIfNoDocker(t) - th := kusttest_test.MakeHarness(t) - o := th.MakeOptionsPluginsEnabled() - fSys := filesys.MakeFsOnDisk() - b := MakeKustomizer(&o) - tmpDir, err := filesys.NewTmpConfirmedDir() - assert.NoError(t, err) - path, err := os.Getwd() assert.NoError(t, err) - src := filepath.Join(path, "testdata", "charts") + string(filepath.Separator) - dst := filepath.Join(tmpDir.String(), "testdata", "charts") + string(filepath.Separator) - assert.NoError(t, os.MkdirAll(dst, 0777)) - - switch runtime.GOOS { - case "darwin": - cmd := exec.Command("cp", "-r", src, dst) - assert.NoError(t, cmd.Run()) - case "linux": - d := dst + "." - cmd := exec.Command("cp", "-r", src, d) - assert.NoError(t, cmd.Run()) - default: - t.SkipNow() - } + testDir := filepath.Join(path, "testdata", "fnmounts") + command := exec.Command("kustomize", "build", testDir, "--enable-alpha-plugins") + var stdout bytes.Buffer + var stderr bytes.Buffer + command.Stdout = &stdout + command.Stderr = &stderr + t.Log(stderr.String()) - chartPath, err := filepath.Rel(tmpDir.String(), dst) - assert.NoError(t, err) - - assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` -generators: - - |- - apiVersion: v1alpha1 - kind: RenderHelmChart - metadata: - name: demo - annotations: - config.kubernetes.io/function: | - container: - image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 - mounts: - - type: "bind" - src: "`+chartPath+`" - dst: "/tmp/charts" - helmCharts: - - name: helloworld-chart - releaseName: test - valuesFile: /tmp/charts/helloworld-values/values.yaml -`))) - m, err := b.Run( - fSys, - tmpDir.String()) - assert.NoError(t, err) - yml, err := m.AsYaml() - assert.NoError(t, err) + assert.NoError(t, command.Run()) assert.Equal(t, `apiVersion: v1 kind: ServiceAccount metadata: @@ -790,9 +747,7 @@ spec: image: busybox name: wget restartPolicy: Never -`, string(yml)) - - assert.NoError(t, fSys.RemoveAll(tmpDir.String())) +`, stdout.String()) } func TestFnContainerMountsLoadRestrictions_absolute(t *testing.T) { diff --git a/api/krusty/testdata/charts/helloworld-chart/Chart.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/Chart.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/NOTES.txt rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/_helpers.tpl rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/deployment.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/ingress.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/service.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/service.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/serviceaccount.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/templates/tests/test-connection.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml diff --git a/api/krusty/testdata/charts/helloworld-chart/values.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-chart/values.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml diff --git a/api/krusty/testdata/charts/helloworld-values/values.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml similarity index 100% rename from api/krusty/testdata/charts/helloworld-values/values.yaml rename to api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml diff --git a/api/krusty/testdata/fnmounts/kustomization.yaml b/api/krusty/testdata/fnmounts/kustomization.yaml new file mode 100644 index 0000000000..1a24bc7c75 --- /dev/null +++ b/api/krusty/testdata/fnmounts/kustomization.yaml @@ -0,0 +1,20 @@ +# Test file for TestFnContainerMounts + +generators: + - |- + apiVersion: v1alpha1 + kind: RenderHelmChart + metadata: + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 + mounts: + - type: "bind" + src: "./charts" + dst: "/tmp/charts" + helmCharts: + - name: helloworld-chart + releaseName: test + valuesFile: /tmp/charts/helloworld-values/values.yaml \ No newline at end of file From dfaa43c52f0f5fb6416259a42f474f701bb9b618 Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Thu, 14 Apr 2022 09:51:44 -0700 Subject: [PATCH 4/5] update tests to deal with new working dir restrictions --- api/internal/plugins/loader/loader.go | 4 +- api/krusty/fnplugin_test.go | 74 +++++++++++++++------------ 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/api/internal/plugins/loader/loader.go b/api/internal/plugins/loader/loader.go index 86557a457a..82cb93965c 100644 --- a/api/internal/plugins/loader/loader.go +++ b/api/internal/plugins/loader/loader.go @@ -49,9 +49,7 @@ func (l *Loader) Config() *types.PluginConfig { // SetWorkDir sets the working directory for this loader's plugins func (l *Loader) SetWorkDir(wd string) { - if wd != string(filepath.Separator) { - l.pc.FnpLoadingOptions.WorkingDir = wd - } + l.pc.FnpLoadingOptions.WorkingDir = wd } func (l *Loader) LoadGenerators( diff --git a/api/krusty/fnplugin_test.go b/api/krusty/fnplugin_test.go index 28294e286f..c762aad725 100644 --- a/api/krusty/fnplugin_test.go +++ b/api/krusty/fnplugin_test.go @@ -537,30 +537,33 @@ spec: func TestFnContainerTransformerWithConfig(t *testing.T) { skipIfNoDocker(t) - - // Function plugins should not need the env setup done by MakeEnhancedHarness th := kusttest_test.MakeHarness(t) - - th.WriteK(".", ` + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() + assert.NoError(t, err) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` resources: - data1.yaml - data2.yaml transformers: - label_namespace.yaml -`) - - th.WriteF("data1.yaml", `apiVersion: v1 +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data1.yaml"), []byte(` +apiVersion: v1 kind: Namespace metadata: name: my-namespace -`) - th.WriteF("data2.yaml", `apiVersion: v1 +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "data2.yaml"), []byte(` +apiVersion: v1 kind: Namespace metadata: name: another-namespace -`) - - th.WriteF("label_namespace.yaml", `apiVersion: v1 +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "label_namespace.yaml"), []byte(` +apiVersion: v1 kind: ConfigMap metadata: name: label_namespace @@ -571,11 +574,14 @@ metadata: data: label_name: my-ns-name label_value: function-test -`) - - m := th.Run(".", th.MakeOptionsPluginsEnabled()) - th.AssertActualEqualsExpected(m, ` -apiVersion: v1 +`))) + m, err := b.Run( + fSys, + tmpDir.String()) + assert.NoError(t, err) + actual, err := m.AsYaml() + assert.NoError(t, err) + assert.Equal(t, `apiVersion: v1 kind: Namespace metadata: labels: @@ -588,24 +594,22 @@ metadata: labels: my-ns-name: function-test name: another-namespace -`) +`, string(actual)) } func TestFnContainerEnvVars(t *testing.T) { skipIfNoDocker(t) - - // Function plugins should not need the env setup done by MakeEnhancedHarness th := kusttest_test.MakeHarness(t) - - th.WriteK(".", ` + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() + assert.NoError(t, err) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` generators: - gener.yaml -`) - - // TODO: cheange image to gcr.io/kpt-functions/templater:stable - // when https://github.com/GoogleContainerTools/kpt-functions-catalog/pull/103 - // is merged - th.WriteF("gener.yaml", ` +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(` apiVersion: v1 kind: ConfigMap metadata: @@ -624,16 +628,20 @@ data: name: env data: value: '{{ env "TESTTEMPLATE" }}' -`) - m := th.Run(".", th.MakeOptionsPluginsEnabled()) - th.AssertActualEqualsExpected(m, ` -apiVersion: v1 +`))) + m, err := b.Run( + fSys, + tmpDir.String()) + assert.NoError(t, err) + actual, err := m.AsYaml() + assert.NoError(t, err) + assert.Equal(t, `apiVersion: v1 data: value: value kind: ConfigMap metadata: name: env -`) +`, string(actual)) } func TestFnContainerMounts(t *testing.T) { From e0166b5e8d7775d4c8b49be2303234ceda79f1de Mon Sep 17 00:00:00 2001 From: natasha41575 Date: Fri, 15 Apr 2022 10:12:35 -0700 Subject: [PATCH 5/5] code review --- Makefile | 2 +- api/krusty/fnplugin_test.go | 185 ++++++++---------- .../charts/helloworld-chart/Chart.yaml | 6 - .../helloworld-chart/templates/NOTES.txt | 21 -- .../helloworld-chart/templates/_helpers.tpl | 63 ------ .../templates/deployment.yaml | 55 ------ .../helloworld-chart/templates/ingress.yaml | 41 ---- .../helloworld-chart/templates/service.yaml | 15 -- .../templates/serviceaccount.yaml | 12 -- .../templates/tests/test-connection.yaml | 15 -- .../charts/helloworld-chart/values.yaml | 27 --- .../charts/helloworld-values/values.yaml | 68 ------- .../testdata/fnmounts/kustomization.yaml | 20 -- kyaml/fn/runtime/container/container_test.go | 31 +-- kyaml/runfn/runfn.go | 6 +- 15 files changed, 102 insertions(+), 465 deletions(-) delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml delete mode 100644 api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml delete mode 100644 api/krusty/testdata/fnmounts/kustomization.yaml diff --git a/Makefile b/Makefile index 63ae4eb564..05cd90c4a8 100644 --- a/Makefile +++ b/Makefile @@ -132,7 +132,7 @@ test-unit-all: \ # This target is used by our Github Actions CI to run unit tests for all non-plugin modules in multiple GOOS environments. .PHONY: test-unit-non-plugin -test-unit-non-plugin: kustomize +test-unit-non-plugin: ./hack/for-each-module.sh "make test" "./plugin/*" 15 .PHONY: build-non-plugin-all diff --git a/api/krusty/fnplugin_test.go b/api/krusty/fnplugin_test.go index c762aad725..173d9e4b1e 100644 --- a/api/krusty/fnplugin_test.go +++ b/api/krusty/fnplugin_test.go @@ -4,7 +4,6 @@ package krusty_test import ( - "bytes" "os" "os/exec" "path/filepath" @@ -644,118 +643,70 @@ metadata: `, string(actual)) } -func TestFnContainerMounts(t *testing.T) { +func TestFnContainerFnMounts(t *testing.T) { skipIfNoDocker(t) - - path, err := os.Getwd() + th := kusttest_test.MakeHarness(t) + o := th.MakeOptionsPluginsEnabled() + fSys := filesys.MakeFsOnDisk() + b := MakeKustomizer(&o) + tmpDir, err := filesys.NewTmpConfirmedDir() assert.NoError(t, err) - - testDir := filepath.Join(path, "testdata", "fnmounts") - command := exec.Command("kustomize", "build", testDir, "--enable-alpha-plugins") - var stdout bytes.Buffer - var stderr bytes.Buffer - command.Stdout = &stdout - command.Stderr = &stderr - t.Log(stderr.String()) - - assert.NoError(t, command.Run()) - assert.Equal(t, `apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/instance: test - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: helloworld-chart - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: helloworld-chart-0.1.0 - name: test-helloworld-chart ---- -apiVersion: v1 -kind: Service + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(` +generators: +- gener.yaml +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "gener.yaml"), []byte(` +apiVersion: v1alpha1 +kind: RenderHelmChart metadata: - labels: - app.kubernetes.io/instance: test - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: helloworld-chart - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: helloworld-chart-0.1.0 - name: test-helloworld-chart -spec: - ports: - - name: http - port: 80 - protocol: TCP - targetPort: http - selector: - app.kubernetes.io/instance: test - app.kubernetes.io/name: helloworld-chart - type: ClusterIP ---- + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 + mounts: + - type: "bind" + src: "./charts" + dst: "/tmp/charts" +helmCharts: +- name: helloworld-chart + releaseName: test + valuesFile: /tmp/charts/helloworld-values/values.yaml +`))) + assert.NoError(t, fSys.MkdirAll(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "templates"))) + assert.NoError(t, fSys.MkdirAll(filepath.Join(tmpDir.String(), "charts", "helloworld-values"))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "Chart.yaml"), []byte(` +apiVersion: v2 +name: helloworld-chart +description: A Helm chart for Kubernetes +type: application +version: 0.1.0 +appVersion: 1.16.0 +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-chart", "templates", "deployment.yaml"), []byte(` apiVersion: apps/v1 kind: Deployment metadata: - labels: - app.kubernetes.io/instance: test - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: helloworld-chart - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: helloworld-chart-0.1.0 - name: test-helloworld-chart + name: name spec: - replicas: 5 - selector: - matchLabels: - app.kubernetes.io/instance: test - app.kubernetes.io/name: helloworld-chart - template: - metadata: - labels: - app.kubernetes.io/instance: test - app.kubernetes.io/name: helloworld-chart - spec: - containers: - - image: nginx:1.16.0 - imagePullPolicy: Always - livenessProbe: - httpGet: - path: / - port: http - name: helloworld-chart - ports: - - containerPort: 80 - name: http - protocol: TCP - readinessProbe: - httpGet: - path: / - port: http - resources: {} - securityContext: {} - securityContext: {} - serviceAccountName: test-helloworld-chart ---- -apiVersion: v1 -kind: Pod + replicas: {{ .Values.replicaCount }} +`))) + assert.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "charts", "helloworld-values", "values.yaml"), []byte(` +replicaCount: 5 +`))) + m, err := b.Run( + fSys, + tmpDir.String()) + assert.NoError(t, err) + actual, err := m.AsYaml() + assert.NoError(t, err) + assert.Equal(t, `apiVersion: apps/v1 +kind: Deployment metadata: - annotations: - helm.sh/hook: test-success - labels: - app.kubernetes.io/instance: test - app.kubernetes.io/managed-by: Helm - app.kubernetes.io/name: helloworld-chart - app.kubernetes.io/version: 1.16.0 - helm.sh/chart: helloworld-chart-0.1.0 - name: test-helloworld-chart-test-connection + name: name spec: - containers: - - args: - - test-helloworld-chart:80 - command: - - wget - image: busybox - name: wget - restartPolicy: Never -`, stdout.String()) + replicas: 5 +`, string(actual)) } func TestFnContainerMountsLoadRestrictions_absolute(t *testing.T) { @@ -823,3 +774,29 @@ generators: "v1alpha1.[noGrp]/demo.[noNs] with mount path './tmp/../../dir' is not permitted; mount paths must "+ "be under the current kustomization directory") } + +func TestFnContainerMountsLoadRestrictions_root(t *testing.T) { + skipIfNoDocker(t) + th := kusttest_test.MakeHarness(t) + + th.WriteK(".", ` +generators: +- gener.yaml +`) + // Create generator config + th.WriteF("gener.yaml", ` +apiVersion: examples.config.kubernetes.io/v1beta1 +kind: CockroachDB +metadata: + name: demo + annotations: + config.kubernetes.io/function: | + container: + image: gcr.io/kustomize-functions/example-cockroachdb:v0.1.0 +spec: + replicas: 3 +`) + err := th.RunWithErr(".", th.MakeOptionsPluginsEnabled()) + assert.Error(t, err) + assert.EqualError(t, err, "couldn't execute function: root working directory '/' not allowed") +} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml deleted file mode 100644 index de4012af9d..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/Chart.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v2 -name: helloworld-chart -description: A Helm chart for Kubernetes -type: application -version: 0.1.0 -appVersion: 1.16.0 diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt deleted file mode 100644 index af17e53fbc..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/NOTES.txt +++ /dev/null @@ -1,21 +0,0 @@ -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "helloworld-chart.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "helloworld-chart.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "helloworld-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "helloworld-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - echo "Visit http://127.0.0.1:8080 to use your application" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 -{{- end }} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl deleted file mode 100644 index 3a62dfa0f2..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/_helpers.tpl +++ /dev/null @@ -1,63 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "helloworld-chart.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "helloworld-chart.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "helloworld-chart.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "helloworld-chart.labels" -}} -helm.sh/chart: {{ include "helloworld-chart.chart" . }} -{{ include "helloworld-chart.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Selector labels -*/}} -{{- define "helloworld-chart.selectorLabels" -}} -app.kubernetes.io/name: {{ include "helloworld-chart.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "helloworld-chart.serviceAccountName" -}} -{{- if .Values.serviceAccount.create -}} - {{ default (include "helloworld-chart.fullname" .) .Values.serviceAccount.name }} -{{- else -}} - {{ default "default" .Values.serviceAccount.name }} -{{- end -}} -{{- end -}} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml deleted file mode 100644 index ca686e89ec..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/deployment.yaml +++ /dev/null @@ -1,55 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "helloworld-chart.fullname" . }} - labels: - {{- include "helloworld-chart.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - {{- include "helloworld-chart.selectorLabels" . | nindent 6 }} - template: - metadata: - labels: - {{- include "helloworld-chart.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "helloworld-chart.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - ports: - - name: http - containerPort: 80 - protocol: TCP - livenessProbe: - httpGet: - path: / - port: http - readinessProbe: - httpGet: - path: / - port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml deleted file mode 100644 index 76e1dd91d7..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/ingress.yaml +++ /dev/null @@ -1,41 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "helloworld-chart.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "helloworld-chart.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: -{{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} -{{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ . }} - backend: - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} -{{- end }} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml deleted file mode 100644 index a80cf8cd64..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "helloworld-chart.fullname" . }} - labels: - {{- include "helloworld-chart.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "helloworld-chart.selectorLabels" . | nindent 4 }} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml deleted file mode 100644 index bf9a8e1544..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "helloworld-chart.serviceAccountName" . }} - labels: - {{- include "helloworld-chart.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end -}} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml deleted file mode 100644 index a71342a0d0..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/templates/tests/test-connection.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Pod -metadata: - name: "{{ include "helloworld-chart.fullname" . }}-test-connection" - labels: - {{- include "helloworld-chart.labels" . | nindent 4 }} - annotations: - "helm.sh/hook": test-success -spec: - containers: - - name: wget - image: busybox - command: ['wget'] - args: ['{{ include "helloworld-chart.fullname" . }}:{{ .Values.service.port }}'] - restartPolicy: Never diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml deleted file mode 100644 index e81d4bf57d..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-chart/values.yaml +++ /dev/null @@ -1,27 +0,0 @@ -replicaCount: 1 -image: - repository: nginx - pullPolicy: IfNotPresent -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" -serviceAccount: - create: true - annotations: {} - name: -podSecurityContext: {} -securityContext: {} -service: - type: ClusterIP - port: 80 -ingress: - enabled: false - annotations: {} - hosts: - - host: chart-example.local - paths: [] - tls: [] -resources: {} -nodeSelector: {} -tolerations: [] -affinity: {} diff --git a/api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml b/api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml deleted file mode 100644 index d178c72a8a..0000000000 --- a/api/krusty/testdata/fnmounts/charts/helloworld-values/values.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# Default values for helloworld-chart. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 5 - -image: - repository: nginx - pullPolicy: Always - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: - -podSecurityContext: {} -# fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true -# runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -ingress: - enabled: false - annotations: {} - # kubernetes.io/ingress.class: nginx - # kubernetes.io/tls-acme: "true" - hosts: - - host: chart-example.local - paths: [] - tls: [] - # - secretName: chart-example-tls - # hosts: - # - chart-example.local - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m -# memory: 128Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} diff --git a/api/krusty/testdata/fnmounts/kustomization.yaml b/api/krusty/testdata/fnmounts/kustomization.yaml deleted file mode 100644 index 1a24bc7c75..0000000000 --- a/api/krusty/testdata/fnmounts/kustomization.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# Test file for TestFnContainerMounts - -generators: - - |- - apiVersion: v1alpha1 - kind: RenderHelmChart - metadata: - name: demo - annotations: - config.kubernetes.io/function: | - container: - image: gcr.io/kpt-fn/render-helm-chart:v0.1.0 - mounts: - - type: "bind" - src: "./charts" - dst: "/tmp/charts" - helmCharts: - - name: helloworld-chart - releaseName: test - valuesFile: /tmp/charts/helloworld-values/values.yaml \ No newline at end of file diff --git a/kyaml/fn/runtime/container/container_test.go b/kyaml/fn/runtime/container/container_test.go index bf9e2483a8..f5ff0259b2 100644 --- a/kyaml/fn/runtime/container/container_test.go +++ b/kyaml/fn/runtime/container/container_test.go @@ -7,7 +7,7 @@ import ( "bytes" "fmt" "os" - "runtime" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -24,7 +24,6 @@ func TestFilter_setupExec(t *testing.T) { expectedArgs []string containerSpec runtimeutil.ContainerSpec UIDGID string - skipOnWindows bool }{ { name: "command", @@ -70,8 +69,7 @@ metadata: }, { - name: "storage_mounts", - skipOnWindows: true, // the fieldpaths are different on Windows + name: "storage_mounts", functionConfig: `apiVersion: apps/v1 kind: Deployment metadata: @@ -84,18 +82,19 @@ metadata: "--network", "none", "--user", "nobody", "--security-opt=no-new-privileges", - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "bind", "/mount/path", "/local/"), - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s", "bind", "/mount/pathrw", "/localrw/"), - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "volume", "/myvol", "/local/"), - "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "tmpfs", "/", "/local/"), + // use filepath.Join for Windows filepath handling + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "bind", getAbsFilePath(string(filepath.Separator), "mount", "path"), "/local/"), + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s", "bind", getAbsFilePath(string(filepath.Separator), "mount", "pathrw"), "/localrw/"), + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "volume", getAbsFilePath(string(filepath.Separator), "myvol"), "/local/"), + "--mount", fmt.Sprintf("type=%s,source=%s,target=%s,readonly", "tmpfs", getAbsFilePath(string(filepath.Separator)), "/local/"), }, containerSpec: runtimeutil.ContainerSpec{ Image: "example.com:version", StorageMounts: []runtimeutil.StorageMount{ - {MountType: "bind", Src: "/mount/path", DstPath: "/local/"}, - {MountType: "bind", Src: "/mount/pathrw", DstPath: "/localrw/", ReadWriteMode: true}, - {MountType: "volume", Src: "/myvol", DstPath: "/local/"}, - {MountType: "tmpfs", Src: "/", DstPath: "/local/"}, + {MountType: "bind", Src: getAbsFilePath(string(filepath.Separator), "mount", "path"), DstPath: "/local/"}, + {MountType: "bind", Src: getAbsFilePath(string(filepath.Separator), "mount", "pathrw"), DstPath: "/localrw/", ReadWriteMode: true}, + {MountType: "volume", Src: getAbsFilePath(string(filepath.Separator), "myvol"), DstPath: "/local/"}, + {MountType: "tmpfs", Src: getAbsFilePath(string(filepath.Separator)), DstPath: "/local/"}, }, }, UIDGID: "nobody", @@ -125,9 +124,6 @@ metadata: for i := range tests { tt := tests[i] t.Run(tt.name, func(t *testing.T) { - if tt.skipOnWindows && runtime.GOOS == "windows" { - t.SkipNow() - } cfg, err := yaml.Parse(tt.functionConfig) if !assert.NoError(t, err) { t.FailNow() @@ -253,3 +249,8 @@ func getWorkingDir(t *testing.T) string { require.NoError(t, err) return wd } + +func getAbsFilePath(args ...string) string { + path, _ := filepath.Abs(filepath.Join(args...)) + return path +} diff --git a/kyaml/runfn/runfn.go b/kyaml/runfn/runfn.go index c2cf073061..c855144d73 100644 --- a/kyaml/runfn/runfn.go +++ b/kyaml/runfn/runfn.go @@ -329,9 +329,11 @@ func (r RunFns) getFunctionFilters(global bool, fns ...*yaml.RNode) ( continue } cf, ok := c.(*container.Filter) - if global && ok { + if ok { + if global { + cf.Exec.GlobalScope = true + } cf.Exec.WorkingDir = r.WorkingDir - cf.Exec.GlobalScope = true } fltrs = append(fltrs, c) }