Skip to content

Commit

Permalink
feat: Skaffold post renderer (#9203)
Browse files Browse the repository at this point in the history
* feat: skaffold post render support through post render hooks

* chore: fix test issues and nits

* chore: fix windows test

* chore: fix windows test

* chore: fix test

* chore: test

* chore: test

* chore: test
  • Loading branch information
ericzzzzzzz authored Jan 2, 2024
1 parent ffe769c commit f83583b
Show file tree
Hide file tree
Showing 24 changed files with 841 additions and 93 deletions.
64 changes: 63 additions & 1 deletion docs-v2/content/en/schemas/v4beta9.json
Original file line number Diff line number Diff line change
Expand Up @@ -3445,6 +3445,68 @@
"description": "describes a resource to port forward.",
"x-intellij-html-description": "describes a resource to port forward."
},
"PostRenderHookItem": {
"properties": {
"host": {
"$ref": "#/definitions/PostRenderHostHook",
"description": "describes a single lifecycle hook to run on the host machine.",
"x-intellij-html-description": "describes a single lifecycle hook to run on the host machine."
}
},
"preferredOrder": [
"host"
],
"additionalProperties": false,
"type": "object",
"description": "describes a single lifecycle hook to execute after each render step.",
"x-intellij-html-description": "describes a single lifecycle hook to execute after each render step."
},
"PostRenderHostHook": {
"required": [
"command"
],
"properties": {
"command": {
"items": {
"type": "string"
},
"type": "array",
"description": "command to execute.",
"x-intellij-html-description": "command to execute.",
"default": "[]"
},
"dir": {
"type": "string",
"description": "specifies the working directory of the command. If empty, the command runs in the calling process's current directory.",
"x-intellij-html-description": "specifies the working directory of the command. If empty, the command runs in the calling process's current directory."
},
"os": {
"items": {
"type": "string"
},
"type": "array",
"description": "an optional slice of operating system names. If the host machine OS is different, then it skips execution.",
"x-intellij-html-description": "an optional slice of operating system names. If the host machine OS is different, then it skips execution.",
"default": "[]"
},
"withChange": {
"type": "boolean",
"description": "preserves changes made on the manifests by the hook.",
"x-intellij-html-description": "preserves changes made on the manifests by the hook.",
"default": "false"
}
},
"preferredOrder": [
"command",
"os",
"dir",
"withChange"
],
"additionalProperties": false,
"type": "object",
"description": "describes a post render hook definition to execute on the host machine.",
"x-intellij-html-description": "describes a post render hook definition to execute on the host machine."
},
"Profile": {
"required": [
"name"
Expand Down Expand Up @@ -3699,7 +3761,7 @@
"properties": {
"after": {
"items": {
"$ref": "#/definitions/RenderHookItem"
"$ref": "#/definitions/PostRenderHookItem"
},
"type": "array",
"description": "describes the list of lifecycle hooks to execute *after* each render step.",
Expand Down
2 changes: 2 additions & 0 deletions integration/examples/lifecycle-hooks/k8s-pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ apiVersion: v1
kind: Pod
metadata:
name: getting-started
labels:
tier: test-1
spec:
containers:
- name: getting-started
Expand Down
159 changes: 133 additions & 26 deletions integration/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -444,29 +444,6 @@ spec:
containers:
- image: skaffold-helm:latest
name: skaffold-helm
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: skaffold-helm
skaffold.dev/run-id: phony-run-id
name: skaffold-helm
namespace: helm-namespace-2
spec:
replicas: 2
selector:
matchLabels:
app: skaffold-helm
template:
metadata:
labels:
app: skaffold-helm
skaffold.dev/run-id: phony-run-id
spec:
containers:
- image: skaffold-helm:latest
name: skaffold-helm
`,
}, {
description: "Template with Release.namespace set from skaffold.yaml file deploy.helm.releases.namespace - v1 skaffold schema",
Expand Down Expand Up @@ -495,7 +472,8 @@ spec:
- image: skaffold-helm:latest
name: skaffold-helm
`,
}, {
},
{
description: "Template replicaCount with --set flag",
dir: "testdata/helm-render-simple",
args: []string{"--set", "replicaCount=3"},
Expand Down Expand Up @@ -523,7 +501,8 @@ spec:
- image: skaffold-helm:latest
name: skaffold-helm
`,
}, {
},
{
description: "With Helm global flags",
dir: "testdata/helm-render",
args: []string{"-p", "helm-render-with-global-flags"},
Expand Down Expand Up @@ -573,7 +552,7 @@ spec:
skaffold.dev/run-id: phony-run-id
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:sha256-nonsenselettersandnumbers
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:latest
imagePullPolicy: always
name: skaffold-helm
ports:
Expand Down Expand Up @@ -1052,6 +1031,7 @@ spec:
apiVersion: v1
kind: Pod
metadata:
namespace: mynamespace
labels:
this-is-from: kustomization.yaml
name: my-pod-1
Expand Down Expand Up @@ -1995,6 +1975,133 @@ spec:
}
}

func TestRenderWithPostRenderHook(t *testing.T) {
MarkIntegrationTest(t, CanRunWithoutGcp)

tests := []struct {
description string
projectDir string
expectedOutput string
args []string
}{
{
description: "a single module project, one hook with change",
projectDir: "testdata/post-render-hooks",
args: []string{"-m", "m1", "-p", "change1", "-t", "customtag"},
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
name: module1
labels:
app1: after-change-1
app2: before-change-2
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
name: module1
`,
},
{
description: "a single module project, two hook with change",
projectDir: "testdata/post-render-hooks",
args: []string{"-m", "m1", "-p", "two-changes", "-t", "customtag"},
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
name: module1
labels:
app1: after-change-1
app2: after-change-2
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
name: module1
`,
},
{
description: "a single module project, two hooks, one with change, one not",
projectDir: "testdata/post-render-hooks",
args: []string{"-m", "m1", "-p", "one-change-one-not", "-t", "customtag"},
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
name: module1
labels:
app1: before-change-1
app2: after-change-2
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
name: module1
`,
},
{
description: "multi-module project, two hooks, two changes",
projectDir: "testdata/post-render-hooks",
args: []string{"-m", "m1,m2", "-p", "change1", "-t", "customtag"},
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
labels:
app1: after-change-1
app2: before-change-2
name: module1
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
name: module1
---
apiVersion: v1
kind: Pod
metadata:
labels:
app1: before-change-1
name: module2
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module2:customtag
name: module2
`,
},
{
description: "multi-module project, one pipeline with two hooks have changes, one pipeline has no changes",
projectDir: "testdata/post-render-hooks",
args: []string{"-m", "m1,m2", "-p", "change1,nochange2", "-t", "customtag"},
expectedOutput: `apiVersion: v1
kind: Pod
metadata:
labels:
app1: after-change-1
app2: before-change-2
name: module1
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
name: module1
---
apiVersion: v1
kind: Pod
metadata:
labels:
app1: before-change-1
name: module2
spec:
containers:
- image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module2:customtag
name: module2
`,
},
}

for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
output := skaffold.Render(test.args...).InDir(test.projectDir).RunOrFailOutput(t.T)
t.CheckDeepEqual(test.expectedOutput, string(output), testutil.YamlObj(t.T))
})
}
}

func TestKptRender(t *testing.T) {
tests := []struct {
description string
Expand Down
13 changes: 13 additions & 0 deletions integration/testdata/post-render-hooks/module1/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM golang:1.18 as builder
WORKDIR /code
COPY main.go .
# `skaffold debug` sets SKAFFOLD_GO_GCFLAGS to disable compiler optimizations
ARG SKAFFOLD_GO_GCFLAGS
RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -trimpath -o /app main.go

FROM alpine:3
# Define GOTRACEBACK to mark this container as using the Go language runtime
# for `skaffold debug` (https://skaffold.dev/docs/workflows/debug/).
ENV GOTRACEBACK=single
CMD ["./app"]
COPY --from=builder /app .
11 changes: 11 additions & 0 deletions integration/testdata/post-render-hooks/module1/k8s/k8s-pod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: Pod
metadata:
name: module1
labels:
app1: before-change-1
app2: before-change-2
spec:
containers:
- name: module1
image: multi-config-module1
15 changes: 15 additions & 0 deletions integration/testdata/post-render-hooks/module1/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package main

import (
"fmt"
"runtime"
"time"
)

func main() {
for {
fmt.Printf("Hello module-1! Running on %s/%s\n", runtime.GOOS, runtime.GOARCH)

time.Sleep(time.Second * 1)
}
}
50 changes: 50 additions & 0 deletions integration/testdata/post-render-hooks/module1/skaffold.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
apiVersion: skaffold/v4beta9
kind: Config
metadata:
name: m1
build:
artifacts:
- image: multi-config-module1
context: .
manifests:
rawYaml:
- k8s/k8s-pod.yaml
deploy:
kubectl: {}
profiles:
- name: change1
manifests:
hooks:
after:
- host:
command:
- "sed"
- "s/before-change-1/after-change-1/g"
withChange: true
- name: two-changes
manifests:
hooks:
after:
- host:
command:
- "sed"
- "s/before-change-2/after-change-2/g"
withChange: true
- host:
command:
- "sed"
- "s/before-change-1/after-change-1/g"
withChange: true
- name: one-change-one-not
manifests:
hooks:
after:
- host:
command:
- "sed"
- "s/before-change-2/after-change-2/g"
withChange: true
- host:
command:
- "sed"
- "s/before-change-1/after-change-1/g"
13 changes: 13 additions & 0 deletions integration/testdata/post-render-hooks/module2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM golang:1.18 as builder
WORKDIR /code
COPY main.go .
# `skaffold debug` sets SKAFFOLD_GO_GCFLAGS to disable compiler optimizations
ARG SKAFFOLD_GO_GCFLAGS
RUN go build -gcflags="${SKAFFOLD_GO_GCFLAGS}" -trimpath -o /app main.go

FROM alpine:3
# Define GOTRACEBACK to mark this container as using the Go language runtime
# for `skaffold debug` (https://skaffold.dev/docs/workflows/debug/).
ENV GOTRACEBACK=single
CMD ["./app"]
COPY --from=builder /app .
Loading

0 comments on commit f83583b

Please sign in to comment.