From 94b0ccc05f1bf00e59f1f512ea9d09de4652c68d Mon Sep 17 00:00:00 2001 From: Jakub Warczarek Date: Tue, 26 Nov 2024 18:29:38 +0100 Subject: [PATCH] chore: enhance KongPluginInstallation example and document tests (#881) --- config/samples/gateway-httproute.yaml | 5 +-- ...eway-kongplugininstallation-httproute.yaml | 31 ++++++------------- .../image/image_test.go | 14 +++++++-- hack/plugin-images/README.md | 24 ++++++++++++++ hack/plugin-images/invalid-layers.Dockerfile | 5 +++ hack/plugin-images/invalid-name.Dockerfile | 9 ++++++ .../invalid-size-combined.Dockerfile | 10 ++++++ .../plugin-images/invalid-size-one.Dockerfile | 9 ++++++ hack/plugin-images/missing-file.Dockerfile | 4 +++ hack/plugin-images/myheader-2.Dockerfile | 10 ++++++ hack/plugin-images/myheader.Dockerfile | 3 ++ hack/plugin-images/myheader/handler.lua | 12 +++++++ hack/plugin-images/myheader/schema.lua | 12 +++++++ .../test_kongplugininstallation.go | 8 +++-- test/integration/utils.go | 3 ++ 15 files changed, 130 insertions(+), 29 deletions(-) create mode 100644 hack/plugin-images/README.md create mode 100644 hack/plugin-images/invalid-layers.Dockerfile create mode 100644 hack/plugin-images/invalid-name.Dockerfile create mode 100644 hack/plugin-images/invalid-size-combined.Dockerfile create mode 100644 hack/plugin-images/invalid-size-one.Dockerfile create mode 100644 hack/plugin-images/missing-file.Dockerfile create mode 100644 hack/plugin-images/myheader-2.Dockerfile create mode 100644 hack/plugin-images/myheader.Dockerfile create mode 100644 hack/plugin-images/myheader/handler.lua create mode 100644 hack/plugin-images/myheader/schema.lua diff --git a/config/samples/gateway-httproute.yaml b/config/samples/gateway-httproute.yaml index 271354a1f..2af40cf69 100644 --- a/config/samples/gateway-httproute.yaml +++ b/config/samples/gateway-httproute.yaml @@ -115,8 +115,9 @@ spec: fieldRef: fieldPath: status.podIP resources: - requests: - cpu: 10m + limits: + cpu: 100m + memory: 100Mi --- kind: GatewayConfiguration apiVersion: gateway-operator.konghq.com/v1beta1 diff --git a/config/samples/gateway-kongplugininstallation-httproute.yaml b/config/samples/gateway-kongplugininstallation-httproute.yaml index d97a9c65b..f034b6956 100644 --- a/config/samples/gateway-kongplugininstallation-httproute.yaml +++ b/config/samples/gateway-kongplugininstallation-httproute.yaml @@ -19,8 +19,6 @@ spec: apiVersion: apps/v1 kind: Deployment metadata: - labels: - app: echo name: echo spec: replicas: 1 @@ -42,26 +40,10 @@ spec: ports: - containerPort: 8080 name: http - env: - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: POD_IP - valueFrom: - fieldRef: - fieldPath: status.podIP resources: - requests: - cpu: 10m + limits: + cpu: 100m + memory: 100Mi --- kind: GatewayConfiguration apiVersion: gateway-operator.konghq.com/v1beta1 @@ -142,11 +124,14 @@ spec: kind: Service port: 80 --- +# It adds header "myheader: this-is-extra-header" to the response. apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: name: kong-custom-plugin plugin: additional-custom-plugin +config: + header_value: this-is-extra-header --- kind: KongPluginInstallation apiVersion: gateway-operator.konghq.com/v1alpha1 @@ -154,8 +139,10 @@ metadata: name: additional-custom-plugin namespace: additional spec: - image: northamerica-northeast1-docker.pkg.dev/k8s-team-playground/plugin-example/myheader + # See https://docs.konghq.com/gateway-operator/latest/guides/plugin-distribution/#create-a-custom-plugin + image: kong/plugin-example:1.0.0 --- +# It adds header "newheader: amazing" to the response. apiVersion: configuration.konghq.com/v1 kind: KongPlugin metadata: diff --git a/controller/kongplugininstallation/image/image_test.go b/controller/kongplugininstallation/image/image_test.go index 91b910d02..0d328fafb 100644 --- a/controller/kongplugininstallation/image/image_test.go +++ b/controller/kongplugininstallation/image/image_test.go @@ -58,13 +58,17 @@ func TestCredentialsStoreFromString(t *testing.T) { } func TestFetchPluginContent(t *testing.T) { + t.Log("This test accesses container registries on public internet") + t.Run("invalid image URL", func(t *testing.T) { _, err := image.FetchPlugin(context.Background(), "foo bar", nil) require.ErrorContains(t, err, "unexpected format of image url: could not parse reference: foo bar") }) + // Learn more how images were build and pushed to the registry in hack/plugin-images/README.md. const registryUrl = "northamerica-northeast1-docker.pkg.dev/k8s-team-playground/" + // Source: hack/plugin-images/myheader.Dockerfile. t.Run("valid image (Docker format)", func(t *testing.T) { plugin, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/valid:0.1.0", nil, @@ -73,6 +77,8 @@ func TestFetchPluginContent(t *testing.T) { requireExpectedContent(t, plugin) }) + // Source: hack/plugin-images/myheader.Dockerfile, but with different build tool. + // Instead of Docker Podman or Buildah is used to build the image. t.Run("valid image (OCI format)", func(t *testing.T) { plugin, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/valid-oci:0.1.0", nil, @@ -81,6 +87,7 @@ func TestFetchPluginContent(t *testing.T) { requireExpectedContent(t, plugin) }) + // Source: hack/plugin-images/myheader.Dockerfile. t.Run("valid image from private registry", func(t *testing.T) { credentials := integration.GetKongPluginImageRegistryCredentialsForTests() if credentials == "" { @@ -97,6 +104,7 @@ func TestFetchPluginContent(t *testing.T) { requireExpectedContentPrivate(t, plugin) }) + // Source: hack/plugin-images/invalid-layers.Dockerfile. t.Run("invalid image - too many layers", func(t *testing.T) { _, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/invalid-layers", nil, @@ -104,6 +112,7 @@ func TestFetchPluginContent(t *testing.T) { require.ErrorContains(t, err, "expected exactly one layer with plugin, found 2 layers") }) + // Source: hack/plugin-images/invalid-name.Dockerfile. t.Run("invalid image - invalid names of files", func(t *testing.T) { _, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/invalid-name", nil, @@ -111,6 +120,7 @@ func TestFetchPluginContent(t *testing.T) { require.ErrorContains(t, err, `file "add-header.lua" is unexpected, required files are handler.lua and schema.lua`) }) + // Source: hack/plugin-images/missing-file.Dockerfile. t.Run("invalid image - missing file", func(t *testing.T) { _, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/missing-file", nil, @@ -118,7 +128,7 @@ func TestFetchPluginContent(t *testing.T) { require.ErrorContains(t, err, `required files not found in the image: schema.lua`) }) - // Single file - handler.lua is over 1 MiB. + // Source: hack/plugin-images/invalid-size-one.Dockerfile. t.Run("invalid image - invalid too big plugin (size of single file)", func(t *testing.T) { _, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/invalid-size-one", nil, @@ -126,7 +136,7 @@ func TestFetchPluginContent(t *testing.T) { require.ErrorContains(t, err, "plugin size limit of 1.00 MiB exceeded") }) - // Each file is 512 KiB so together they are 1 MiB. + // Source: hack/plugin-images/invalid-size-combined.Dockerfile. t.Run("invalid image - invalid too big plugin (size of files combined)", func(t *testing.T) { _, err := image.FetchPlugin( context.Background(), registryUrl+"plugin-example/invalid-size-combined", nil, diff --git a/hack/plugin-images/README.md b/hack/plugin-images/README.md new file mode 100644 index 000000000..d02939b33 --- /dev/null +++ b/hack/plugin-images/README.md @@ -0,0 +1,24 @@ +# Plugin Images + +Tests + +- [test/integration/test_kongplugininstallation.go](../../test/integration/test_kongplugininstallation.go) +- [controller/kongplugininstallation/image/image_test.go](../../controller/kongplugininstallation/image/image_test.go) + +rely on images built with `Dockerfile`s in this directory and pushed to remote registries. Examine them for more details. + +The content of the directory `myheader` is based on the official documentation +[Plugin Distribution - Create a custom plugin](https://docs.konghq.com/gateway-operator/latest/guides/plugin-distribution/#create-a-custom-plugin). + +To build the images, run the following command inside this directory: + +```shell +docker build -t -f .Dockerfile . +``` + +How to configure GCP registries: + +- `northamerica-northeast1-docker.pkg.dev/k8s-team-playground/plugin-example` (public) +- `northamerica-northeast1-docker.pkg.dev/k8s-team-playground/plugin-example-private` (private) + +used for tests check [the official GCP documentation](https://cloud.google.com/artifact-registry/docs/docker). diff --git a/hack/plugin-images/invalid-layers.Dockerfile b/hack/plugin-images/invalid-layers.Dockerfile new file mode 100644 index 000000000..94cf639ad --- /dev/null +++ b/hack/plugin-images/invalid-layers.Dockerfile @@ -0,0 +1,5 @@ +FROM scratch + +COPY myheader / + +COPY README.md / diff --git a/hack/plugin-images/invalid-name.Dockerfile b/hack/plugin-images/invalid-name.Dockerfile new file mode 100644 index 000000000..a3c6853e3 --- /dev/null +++ b/hack/plugin-images/invalid-name.Dockerfile @@ -0,0 +1,9 @@ +FROM scratch AS builder + +# Rename handler.lua to an invalid name. +COPY myheader/handler.lua /myheader/add-header.lua +COPY myheader/schema.lua /myheader/schema.lua + +FROM scratch + +COPY --from=builder /myheader / diff --git a/hack/plugin-images/invalid-size-combined.Dockerfile b/hack/plugin-images/invalid-size-combined.Dockerfile new file mode 100644 index 000000000..85b222c47 --- /dev/null +++ b/hack/plugin-images/invalid-size-combined.Dockerfile @@ -0,0 +1,10 @@ +FROM busybox:1.31.1 AS builder + +RUN mkdir myheader &&\ + dd if=/dev/urandom of=/myheader/handler.lua bs=512k count=1 &&\ + dd if=/dev/urandom of=/myheader/schema.lua bs=512k count=1 + + +FROM scratch + +COPY --from=builder /myheader / diff --git a/hack/plugin-images/invalid-size-one.Dockerfile b/hack/plugin-images/invalid-size-one.Dockerfile new file mode 100644 index 000000000..3bc13e00c --- /dev/null +++ b/hack/plugin-images/invalid-size-one.Dockerfile @@ -0,0 +1,9 @@ +FROM busybox:1.31.1 AS builder + +COPY myheader/schema.lua /myheader/ +RUN dd if=/dev/urandom of=/myheader/handler.lua bs=1M count=2 + + +FROM scratch + +COPY --from=builder /myheader / diff --git a/hack/plugin-images/missing-file.Dockerfile b/hack/plugin-images/missing-file.Dockerfile new file mode 100644 index 000000000..9c91b43a9 --- /dev/null +++ b/hack/plugin-images/missing-file.Dockerfile @@ -0,0 +1,4 @@ +FROM scratch + +# File schema.lua will be missing in the final image. +COPY myheader/handler.lua / diff --git a/hack/plugin-images/myheader-2.Dockerfile b/hack/plugin-images/myheader-2.Dockerfile new file mode 100644 index 000000000..9ad0461c2 --- /dev/null +++ b/hack/plugin-images/myheader-2.Dockerfile @@ -0,0 +1,10 @@ +FROM busybox:1.31.1 AS builder + +COPY myheader /myheader/ +RUN sed -i 's/"myheader"/"newheader"/g' /myheader/** +RUN sed -i 's/"roar"/"amazing"/g' /myheader/** + + +FROM scratch + +COPY --from=builder /myheader / diff --git a/hack/plugin-images/myheader.Dockerfile b/hack/plugin-images/myheader.Dockerfile new file mode 100644 index 000000000..0839cfc73 --- /dev/null +++ b/hack/plugin-images/myheader.Dockerfile @@ -0,0 +1,3 @@ +FROM scratch + +COPY myheader / diff --git a/hack/plugin-images/myheader/handler.lua b/hack/plugin-images/myheader/handler.lua new file mode 100644 index 000000000..3983f5cb5 --- /dev/null +++ b/hack/plugin-images/myheader/handler.lua @@ -0,0 +1,12 @@ +local MyHeader = {} + +MyHeader.PRIORITY = 1000 +MyHeader.VERSION = "1.0.0" + +function MyHeader:header_filter(conf) + -- do custom logic here + kong.response.set_header("myheader", conf.header_value) +end + +return MyHeader + diff --git a/hack/plugin-images/myheader/schema.lua b/hack/plugin-images/myheader/schema.lua new file mode 100644 index 000000000..ebdb871f4 --- /dev/null +++ b/hack/plugin-images/myheader/schema.lua @@ -0,0 +1,12 @@ +return { + name = "myheader", + fields = { + { config = { + type = "record", + fields = { + { header_value = { type = "string", default = "roar", }, }, + }, + }, }, + } +} + diff --git a/test/integration/test_kongplugininstallation.go b/test/integration/test_kongplugininstallation.go index eddf8a640..146dc90b1 100644 --- a/test/integration/test_kongplugininstallation.go +++ b/test/integration/test_kongplugininstallation.go @@ -34,14 +34,16 @@ import ( func TestKongPluginInstallationEssentials(t *testing.T) { namespace, cleaner := helpers.SetupTestEnv(t, GetCtx(), GetEnv()) + t.Log("this test accesses container registries on public internet") + // Learn more how images were build and pushed to the registry in hack/plugin-images/README.md. const registryUrl = "northamerica-northeast1-docker.pkg.dev/k8s-team-playground/" - + // Source: hack/plugin-images/invalid-layers.Dockerfile. const pluginInvalidLayersImage = registryUrl + "plugin-example/invalid-layers" - + // Source: hack/plugin-images/myheader.Dockerfile. const pluginMyHeaderImage = registryUrl + "plugin-example/myheader" expectedHeadersForMyHeader := http.Header{"myheader": {"roar"}} - + // Source: hack/plugin-images/myheader-2.Dockerfile. const pluginMyHeader2Image = registryUrl + "plugin-example-private/myheader-2" expectedHeadersForMyHeader2 := http.Header{"newheader": {"amazing"}} diff --git a/test/integration/utils.go b/test/integration/utils.go index 6960ef041..26dc5f99c 100644 --- a/test/integration/utils.go +++ b/test/integration/utils.go @@ -163,6 +163,9 @@ func GetVolumeMountsByVolumeName(volumeMounts []corev1.VolumeMount, name string) return ret } +// GetKongPluginImageRegistryCredentialsForTests returns the credentials for the image registry with plugins for tests. +// The expected format is the same as ~/.docker/config.json, see +// https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#log-in-to-docker-hub func GetKongPluginImageRegistryCredentialsForTests() string { return os.Getenv("KONG_PLUGIN_IMAGE_REGISTRY_CREDENTIALS") }