From 4830d92c719589ba365afdfa319b3fd7b64d3d44 Mon Sep 17 00:00:00 2001 From: ottersbot Date: Mon, 24 Nov 2025 11:12:38 +0000 Subject: [PATCH 01/13] upgrade dependencies --- config/buildless-serverless/Chart.yaml | 2 +- config/buildless-serverless/values.yaml | 10 +++++----- config/operator/base/deployment/deployment.yaml | 14 +++++++------- .../operator/base/deployment/kustomization.yaml | 2 +- config/operator/base/kustomization.yaml | 3 +++ config/serverless/values.yaml | 10 +++++----- libgit2 | 1 + sec-scanners-config.yaml | 16 ++++++++-------- 8 files changed, 31 insertions(+), 27 deletions(-) create mode 160000 libgit2 diff --git a/config/buildless-serverless/Chart.yaml b/config/buildless-serverless/Chart.yaml index 4ce728c46..b1a45956b 100644 --- a/config/buildless-serverless/Chart.yaml +++ b/config/buildless-serverless/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 description: Kyma component 'buildless serverless' name: buildless-serverless version: 1.0.0 -appVersion: "main" +appVersion: "1.9.0" home: https://kyma-project.io icon: https://github.com/kyma-project/kyma/blob/main/logo.png?raw=true dependencies: diff --git a/config/buildless-serverless/values.yaml b/config/buildless-serverless/values.yaml index 5d43dbde2..49d1f2a65 100644 --- a/config/buildless-serverless/values.yaml +++ b/config/buildless-serverless/values.yaml @@ -11,11 +11,11 @@ global: targetDir: "/logconfig" filename: "log-config.yaml" images: - function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:main - function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:main - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:main - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:main - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:main + function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 + function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 containers: manager: logConfiguration: diff --git a/config/operator/base/deployment/deployment.yaml b/config/operator/base/deployment/deployment.yaml index 599c3aaf4..5052f3205 100644 --- a/config/operator/base/deployment/deployment.yaml +++ b/config/operator/base/deployment/deployment.yaml @@ -40,25 +40,25 @@ spec: fieldRef: fieldPath: metadata.uid - name: IMAGE_FUNCTION_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-controller:main + value: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 - name: IMAGE_FUNCTION_BUILD_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:main + value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 - name: IMAGE_REGISTRY_INIT value: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - name: IMAGE_FUNCTION_RUNTIME_NODEJS20 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:main + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 - name: IMAGE_FUNCTION_RUNTIME_NODEJS22 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:main + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 - name: IMAGE_FUNCTION_RUNTIME_PYTHON312 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:main + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 - name: IMAGE_KANIKO_EXECUTOR value: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - name: IMAGE_REGISTRY value: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - name: IMAGE_FUNCTION_BUILDLESS_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:main + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 - name: IMAGE_FUNCTION_BUILDLESS_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:main + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/config/operator/base/deployment/kustomization.yaml b/config/operator/base/deployment/kustomization.yaml index 479613aaf..679e39237 100644 --- a/config/operator/base/deployment/kustomization.yaml +++ b/config/operator/base/deployment/kustomization.yaml @@ -5,4 +5,4 @@ kind: Kustomization images: - name: controller newName: europe-docker.pkg.dev/kyma-project/prod/serverless-operator - newTag: main + newTag: 1.9.0 diff --git a/config/operator/base/kustomization.yaml b/config/operator/base/kustomization.yaml index dbb0ca6e7..384c960db 100644 --- a/config/operator/base/kustomization.yaml +++ b/config/operator/base/kustomization.yaml @@ -20,6 +20,9 @@ labels: app.kubernetes.io/part-of: serverless-operator app.kubernetes.io/version: main kyma-project.io/module: serverless +- includeTemplates: true + pairs: + app.kubernetes.io/version: 1.9.0 resources: - ./crd diff --git a/config/serverless/values.yaml b/config/serverless/values.yaml index 35399a061..1a956b6a9 100644 --- a/config/serverless/values.yaml +++ b/config/serverless/values.yaml @@ -71,13 +71,13 @@ global: ingress: domainName: images: - function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:main - function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:main + function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 + function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 # https://github.com/kyma-project/docker-registry/tree/main/components/registry-init registry_init: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:main - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:main - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:main + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 kaniko_executor: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 registry: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 serverlessPriorityClassValue: 2000000 diff --git a/libgit2 b/libgit2 new file mode 160000 index 000000000..26c68a273 --- /dev/null +++ b/libgit2 @@ -0,0 +1 @@ +Subproject commit 26c68a273939acc329416c3ef5aa9e61647bbb78 diff --git a/sec-scanners-config.yaml b/sec-scanners-config.yaml index 6412f0b01..1da1525ff 100644 --- a/sec-scanners-config.yaml +++ b/sec-scanners-config.yaml @@ -1,17 +1,17 @@ module-name: serverless kind: kyma bdba: - - europe-docker.pkg.dev/kyma-project/prod/function-controller:main - - europe-docker.pkg.dev/kyma-project/prod/function-build-init:main + - europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 - europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:main - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:main - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:main + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 - europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:main - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:main - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:main + - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 mend: language: golang-mod exclude: From b35bea53732eed75a5bab5c4b1bdbcc1ba71696a Mon Sep 17 00:00:00 2001 From: Krzysztof Kwiatosz Date: Tue, 25 Nov 2025 12:53:54 +0100 Subject: [PATCH 02/13] Fix automated version promotion branch name (#2062) (#2063) --- .github/workflows/promote-to-release-channel.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/promote-to-release-channel.yaml b/.github/workflows/promote-to-release-channel.yaml index 745fb5cae..829eb51f1 100644 --- a/.github/workflows/promote-to-release-channel.yaml +++ b/.github/workflows/promote-to-release-channel.yaml @@ -55,7 +55,7 @@ jobs: working-directory: module-manifests run: | git fetch upstream - git checkout -B "${MODULE_VERSION}" upstream/main + git checkout -B "serverless-${MODULE_VERSION}" upstream/main mkdir -p modules/serverless/${MODULE_VERSION} cp ../module-config.yaml modules/serverless/${MODULE_VERSION}/module-config.yaml @@ -64,20 +64,20 @@ jobs: git add . git commit -m "promote serverless ${MODULE_VERSION}" - git push origin "${MODULE_VERSION}" -f + git push origin "serverless-${MODULE_VERSION}" -f - name: Create PullRequest to module-manifests working-directory: module-manifests run: | prs=$(gh pr list -R "https://${GH_TOOLS_REPO_URL}/kyma/module-manifests" -A "${BOT_USERNAME}" --state open --json headRefName) - if echo $prs | jq -e ".[] | select(.headRefName==\"${MODULE_VERSION}\")"; then + if echo $prs | jq -e ".[] | select(.headRefName==\"serverless-${MODULE_VERSION}\")"; then echo "opened PR already exists, no need to create new one, PR will be updated by push from previous step" exit 0 fi gh pr create -B main --fill \ - -H "${BOT_USERNAME}:${MODULE_VERSION}" \ + -H "${BOT_USERNAME}:serverless-${MODULE_VERSION}" \ -R "https://${GH_TOOLS_REPO_URL}/kyma/module-manifests/" \ --title "Promote Serverless ${MODULE_VERSION}" \ - --body "https://github.com/kyma-project/serverless/actions/${{github.run_id}}" \ No newline at end of file + --body "Adding Serverless [${MODULE_VERSION}](https://github.com/kyma-project/serverless/releases/tag/${MODULE_VERSION})" \ No newline at end of file From b7620d96ec551708cc1d38b699d2b11479186864 Mon Sep 17 00:00:00 2001 From: Krzysztof Kwiatosz Date: Tue, 25 Nov 2025 15:20:43 +0100 Subject: [PATCH 03/13] Add missing priority class (#2066) --- .../buildless-serverless/templates/deployment.yaml | 1 + .../templates/priority-class.yaml | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 config/buildless-serverless/templates/priority-class.yaml diff --git a/config/buildless-serverless/templates/deployment.yaml b/config/buildless-serverless/templates/deployment.yaml index 6c50b7909..9a0c9adc5 100644 --- a/config/buildless-serverless/templates/deployment.yaml +++ b/config/buildless-serverless/templates/deployment.yaml @@ -91,3 +91,4 @@ spec: runAsUser: 1000 serviceAccountName: serverless-controller-manager terminationGracePeriodSeconds: 10 + priorityClassName: serverless-priority diff --git a/config/buildless-serverless/templates/priority-class.yaml b/config/buildless-serverless/templates/priority-class.yaml new file mode 100644 index 000000000..beb0bb06b --- /dev/null +++ b/config/buildless-serverless/templates/priority-class.yaml @@ -0,0 +1,14 @@ +apiVersion: scheduling.k8s.io/v1 +kind: PriorityClass +metadata: + name: serverless-priority + labels: + kyma-project.io/module: serverless + app.kubernetes.io/name: serverless + app.kubernetes.io/instance: serverless-priority-class + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/component: controller + app.kubernetes.io/part-of: serverless +value: 2000000 +globalDefault: false +description: "Scheduling priority of serverless components. By default, serverless components should not be blocked by unschedulable user workloads." \ No newline at end of file From b88050f29c0968759099690e6d2b9ddd76342545 Mon Sep 17 00:00:00 2001 From: ottersbot Date: Tue, 25 Nov 2025 14:25:18 +0000 Subject: [PATCH 04/13] upgrade dependencies --- config/buildless-serverless/Chart.yaml | 2 +- config/buildless-serverless/values.yaml | 10 +++++----- config/operator/base/deployment/deployment.yaml | 14 +++++++------- .../operator/base/deployment/kustomization.yaml | 2 +- config/operator/base/kustomization.yaml | 3 +++ config/serverless/values.yaml | 10 +++++----- sec-scanners-config.yaml | 16 ++++++++-------- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/config/buildless-serverless/Chart.yaml b/config/buildless-serverless/Chart.yaml index b1a45956b..38c8dbef0 100644 --- a/config/buildless-serverless/Chart.yaml +++ b/config/buildless-serverless/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 description: Kyma component 'buildless serverless' name: buildless-serverless version: 1.0.0 -appVersion: "1.9.0" +appVersion: "1.9.1" home: https://kyma-project.io icon: https://github.com/kyma-project/kyma/blob/main/logo.png?raw=true dependencies: diff --git a/config/buildless-serverless/values.yaml b/config/buildless-serverless/values.yaml index 49d1f2a65..c44d89aa5 100644 --- a/config/buildless-serverless/values.yaml +++ b/config/buildless-serverless/values.yaml @@ -11,11 +11,11 @@ global: targetDir: "/logconfig" filename: "log-config.yaml" images: - function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 - function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 + function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 + function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 containers: manager: logConfiguration: diff --git a/config/operator/base/deployment/deployment.yaml b/config/operator/base/deployment/deployment.yaml index 5052f3205..bd89b96ca 100644 --- a/config/operator/base/deployment/deployment.yaml +++ b/config/operator/base/deployment/deployment.yaml @@ -40,25 +40,25 @@ spec: fieldRef: fieldPath: metadata.uid - name: IMAGE_FUNCTION_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 - name: IMAGE_FUNCTION_BUILD_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 - name: IMAGE_REGISTRY_INIT value: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - name: IMAGE_FUNCTION_RUNTIME_NODEJS20 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 - name: IMAGE_FUNCTION_RUNTIME_NODEJS22 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 - name: IMAGE_FUNCTION_RUNTIME_PYTHON312 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 - name: IMAGE_KANIKO_EXECUTOR value: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - name: IMAGE_REGISTRY value: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - name: IMAGE_FUNCTION_BUILDLESS_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 - name: IMAGE_FUNCTION_BUILDLESS_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/config/operator/base/deployment/kustomization.yaml b/config/operator/base/deployment/kustomization.yaml index 679e39237..5d1e9e840 100644 --- a/config/operator/base/deployment/kustomization.yaml +++ b/config/operator/base/deployment/kustomization.yaml @@ -5,4 +5,4 @@ kind: Kustomization images: - name: controller newName: europe-docker.pkg.dev/kyma-project/prod/serverless-operator - newTag: 1.9.0 + newTag: 1.9.1 diff --git a/config/operator/base/kustomization.yaml b/config/operator/base/kustomization.yaml index 384c960db..e1a34b0d1 100644 --- a/config/operator/base/kustomization.yaml +++ b/config/operator/base/kustomization.yaml @@ -23,6 +23,9 @@ labels: - includeTemplates: true pairs: app.kubernetes.io/version: 1.9.0 +- includeTemplates: true + pairs: + app.kubernetes.io/version: 1.9.1 resources: - ./crd diff --git a/config/serverless/values.yaml b/config/serverless/values.yaml index 1a956b6a9..f44e3d08c 100644 --- a/config/serverless/values.yaml +++ b/config/serverless/values.yaml @@ -71,13 +71,13 @@ global: ingress: domainName: images: - function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 - function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 + function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 + function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 # https://github.com/kyma-project/docker-registry/tree/main/components/registry-init registry_init: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 kaniko_executor: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 registry: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 serverlessPriorityClassValue: 2000000 diff --git a/sec-scanners-config.yaml b/sec-scanners-config.yaml index 1da1525ff..d57d35520 100644 --- a/sec-scanners-config.yaml +++ b/sec-scanners-config.yaml @@ -1,17 +1,17 @@ module-name: serverless kind: kyma bdba: - - europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.0 - - europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 - europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.0 - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.0 - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 - europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:1.9.0 - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.0 - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.0 + - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 mend: language: golang-mod exclude: From f2950c272640ed0a9321749b66479c90637f9914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kalke?= <56382792+MichalKalke@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:36:46 +0100 Subject: [PATCH 05/13] Fix wrt. git fetching (#2076) (#2088) --- .../internal/controller/resources/deployment.go | 4 ++-- .../internal/controller/resources/deployment_test.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/buildless-serverless/internal/controller/resources/deployment.go b/components/buildless-serverless/internal/controller/resources/deployment.go index 695977d94..d5d3356ef 100644 --- a/components/buildless-serverless/internal/controller/resources/deployment.go +++ b/components/buildless-serverless/internal/controller/resources/deployment.go @@ -373,7 +373,7 @@ func (d *Deployment) initContainerCommand() string { var arr []string arr = append(arr, "/app/gitcloner") arr = append(arr, - fmt.Sprintf("mkdir /git-repository/src;cp /git-repository/repo/%s/* /git-repository/src;", + fmt.Sprintf("mkdir /git-repository/src;cp -r /git-repository/repo/%s/* /git-repository/src;", strings.Trim(gitRepo.BaseDir, "/ "))) return strings.Join(arr, "\n") } @@ -521,7 +521,7 @@ func runtimeCommandGitSources(f *serverlessv1alpha2.Function) string { if f.HasNodejsRuntime() { result = append(result, `echo "{}" > package.json;`) } - result = append(result, `cp /git-repository/src/* .;`) + result = append(result, `cp -r /git-repository/src/* .;`) return strings.Join(result, "\n") } diff --git a/components/buildless-serverless/internal/controller/resources/deployment_test.go b/components/buildless-serverless/internal/controller/resources/deployment_test.go index 439bacdae..ad8dc0b53 100644 --- a/components/buildless-serverless/internal/controller/resources/deployment_test.go +++ b/components/buildless-serverless/internal/controller/resources/deployment_test.go @@ -332,7 +332,7 @@ fi`, c := r.Spec.Template.Spec.InitContainers[0] expectedCommand := []string{"sh", "-c", `/app/gitcloner -mkdir /git-repository/src;cp /git-repository/repo/recursing-mcnulty/* /git-repository/src;`} +mkdir /git-repository/src;cp -r /git-repository/repo/recursing-mcnulty/* /git-repository/src;`} require.Equal(t, expectedCommand, c.Command) }) } @@ -1306,7 +1306,7 @@ fi`, }, }, }, - want: `cp /git-repository/src/* .; + want: `cp -r /git-repository/src/* .; PIP_CONFIG_FILE=package-registry-config/pip.conf pip install --user --no-cache-dir -r requirements.txt; cd ..; if [ -f "./kubeless.py" ]; then @@ -1371,7 +1371,7 @@ npm start;`, }, }, want: `echo "{}" > package.json; -cp /git-repository/src/* .; +cp -r /git-repository/src/* .; npm install --prefer-offline --no-audit --progress=false; cd ..; npm start;`, @@ -1431,7 +1431,7 @@ npm start;`, }, }, want: `echo "{}" > package.json; -cp /git-repository/src/* .; +cp -r /git-repository/src/* .; npm install --prefer-offline --no-audit --progress=false; cd ..; npm start;`, From 718e72509d36d09a0dffa0ae680d865ea6ed2da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kalke?= <56382792+MichalKalke@users.noreply.github.com> Date: Thu, 4 Dec 2025 13:00:08 +0100 Subject: [PATCH 06/13] Patch r1.9v2 (#2092) --- components/runtimes/nodejs20/server.mjs | 2 +- components/runtimes/nodejs22/server.mjs | 2 +- components/runtimes/python312/server.py | 2 +- docs/user/technical-reference/05-20-env-variables.md | 1 - examples/custom-serverless-runtime-image/kubeless.py | 2 +- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/components/runtimes/nodejs20/server.mjs b/components/runtimes/nodejs20/server.mjs index 33465bf33..78564c662 100644 --- a/components/runtimes/nodejs20/server.mjs +++ b/components/runtimes/nodejs20/server.mjs @@ -18,7 +18,7 @@ const handlerPath = process.env.HANDLER_PATH || './handler.js'; const serviceNamespace = process.env.SERVICE_NAMESPACE; const functionName = process.env.FUNC_NAME; const bodySizeLimit = Number(process.env.REQ_MB_LIMIT || '1'); -const funcPort = Number(process.env.FUNC_PORT || '8080'); +const funcPort = 8080; const timeout = Number(process.env.FUNC_TIMEOUT || '180'); // Default to 180 seconds const tracer = setupTracer(functionName); diff --git a/components/runtimes/nodejs22/server.mjs b/components/runtimes/nodejs22/server.mjs index 33465bf33..78564c662 100644 --- a/components/runtimes/nodejs22/server.mjs +++ b/components/runtimes/nodejs22/server.mjs @@ -18,7 +18,7 @@ const handlerPath = process.env.HANDLER_PATH || './handler.js'; const serviceNamespace = process.env.SERVICE_NAMESPACE; const functionName = process.env.FUNC_NAME; const bodySizeLimit = Number(process.env.REQ_MB_LIMIT || '1'); -const funcPort = Number(process.env.FUNC_PORT || '8080'); +const funcPort = 8080; const timeout = Number(process.env.FUNC_TIMEOUT || '180'); // Default to 180 seconds const tracer = setupTracer(functionName); diff --git a/components/runtimes/python312/server.py b/components/runtimes/python312/server.py index 5cd17ff18..a51711ce3 100644 --- a/components/runtimes/python312/server.py +++ b/components/runtimes/python312/server.py @@ -30,7 +30,7 @@ func = getattr(mod, func_name) -func_port = os.getenv('FUNC_PORT', 8080) +func_port = 8080 timeout = float(os.getenv('FUNC_TIMEOUT', 180)) memfile_max = int(os.getenv('FUNC_MEMFILE_MAX', 100 * 1024 * 1024)) bottle.BaseRequest.MEMFILE_MAX = memfile_max diff --git a/docs/user/technical-reference/05-20-env-variables.md b/docs/user/technical-reference/05-20-env-variables.md index 833ecdb0f..c3ea4fd04 100644 --- a/docs/user/technical-reference/05-20-env-variables.md +++ b/docs/user/technical-reference/05-20-env-variables.md @@ -12,7 +12,6 @@ Every runtime provides its own unique environment configuration which can be rea |---------------|-----------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | **FUNC_HANDLER** | `main` | The name of the exported Function inside the `MOD_NAME` file. | | **MOD_NAME** | `handler` | The name of the main exported file. It must have an extension of `.py` for the Python runtimes and `.js` for the Node.js ones. The extension must be added on the server side. | -| **FUNC_PORT** | `8080` | The right port a server listens to. | | **SERVICE_NAMESPACE** | None | The namespace where the right Function exists in a cluster. | | **KUBELESS_INSTALL_VOLUME** | `/kubeless` | Full path to volume mount with users source code. | | **FUNC_RUNTIME** | None | The name of the actual runtime. Possible values: `nodejs20` and `python312`. | diff --git a/examples/custom-serverless-runtime-image/kubeless.py b/examples/custom-serverless-runtime-image/kubeless.py index bff5878db..08fdac5b2 100644 --- a/examples/custom-serverless-runtime-image/kubeless.py +++ b/examples/custom-serverless-runtime-image/kubeless.py @@ -36,7 +36,7 @@ func = getattr(mod, func_name) -func_port = os.getenv('FUNC_PORT', 8080) +func_port = 8080 timeout = float(os.getenv('FUNC_TIMEOUT', 180)) memfile_max = int(os.getenv('FUNC_MEMFILE_MAX', 100 * 1024 * 1024)) bottle.BaseRequest.MEMFILE_MAX = memfile_max From c9f2d846d9e4e1b712883880cf148893ccc56999 Mon Sep 17 00:00:00 2001 From: Filip Strozik Date: Mon, 8 Dec 2025 11:16:26 +0100 Subject: [PATCH 07/13] Cherry-pick: Serverless-operator sets Serverless CR to Ready state in case the new version of controller did not progress (#2104) Co-authored-by: Marcin Dobrochowski <39153236+anoipm@users.noreply.github.com> --- .../actions/collect-cluster-info/action.yaml | 51 +++++++++- .../operator/api/v1alpha1/serverless_types.go | 28 ++++-- .../controllers/serverless_controller.go | 18 +++- .../controllers/serverless_controller_test.go | 5 +- .../operator/controllers/testhelper_test.go | 56 ++++++++--- .../operator/internal/chart/install_test.go | 8 +- components/operator/internal/chart/verify.go | 97 ++++++++++++++----- .../operator/internal/chart/verify_test.go | 61 +++++++++--- .../operator/internal/predicate/predicate.go | 39 ++++++++ components/operator/internal/state/verify.go | 20 +++- .../base/ui-extensions/serverless/details | 8 ++ docs/user/resources/06-20-serverless-cr.md | 29 +++--- tests/operator/Makefile | 14 --- tests/operator/main.go | 7 +- 14 files changed, 337 insertions(+), 104 deletions(-) diff --git a/.github/actions/collect-cluster-info/action.yaml b/.github/actions/collect-cluster-info/action.yaml index fb5a1d69c..84033afaa 100644 --- a/.github/actions/collect-cluster-info/action.yaml +++ b/.github/actions/collect-cluster-info/action.yaml @@ -6,5 +6,54 @@ runs: steps: - name: collect cluster-info if: ${{ always() }} - run: make -C tests/operator cluster-info + run: | + echo "####################" + echo "kubectl get pods -A" + echo "####################" + kubectl get pods -A || true + + echo "########################" + echo "kubectl get functions -A" + echo "########################" + kubectl get functions -A || true + + echo "################################" + echo "kubectl get serverless -A -oyaml" + echo "################################" + kubectl get serverless -A -oyaml || true + + echo "##########################################################" + echo "Describe serverless operator deploy" + echo "kubectl describe deploy -A -l app.kubernetes.io/name=serverless-operator" + echo "##########################################################" + kubectl describe deploy -A -l app.kubernetes.io/name=serverless-operator || true + + echo "####################################################################" + echo "Describe serverless controller deploy" + echo "kubectl describe deploy -A -l app.kubernetes.io/name=serverless" + echo "####################################################################" + kubectl describe deploy -A -l app.kubernetes.io/name=serverless || true + + echo "##########################################################" + echo "Get serverless operator pod" + echo "kubectl get pod -A -l app.kubernetes.io/name=serverless-operator -oyaml" + echo "##########################################################" + kubectl get pod -A -l app.kubernetes.io/name=serverless-operator -oyaml || true + + echo "####################################################################" + echo "Get serverless controller pod" + echo "kubectl get pod -A -l app.kubernetes.io/name=serverless -oyaml" + echo "####################################################################" + kubectl get pod -A -l app.kubernetes.io/name=serverless -oyaml || true + + echo "########################################################################################################" + echo "Serverless operator logs" + echo "kubectl logs -n kyma-system -l app.kubernetes.io/name=serverless-operator --tail=-1" + echo "########################################################################################################" + kubectl logs -n kyma-system -l app.kubernetes.io/name=serverless-operator --tail=-1 || true + + echo "########################################################" + echo "Serverless controller logs across all namespaces" + echo "########################################################" + for n in `kubectl get namespaces -o json | jq -r ".items[].metadata.name"`; do kubectl logs -l app.kubernetes.io/name=serverless --tail=-1 -n $n; done || true shell: bash diff --git a/components/operator/api/v1alpha1/serverless_types.go b/components/operator/api/v1alpha1/serverless_types.go index 7b58d1b7d..8853c9723 100644 --- a/components/operator/api/v1alpha1/serverless_types.go +++ b/components/operator/api/v1alpha1/serverless_types.go @@ -91,19 +91,23 @@ const ( // prerequisites and soft dependencies ConditionTypeConfigured = ConditionType("Configured") + // serverless controller deployment failure details + ConditionTypeDeploymentFailure = ConditionType("DeploymentFailure") + // deletion ConditionTypeDeleted = ConditionType("Deleted") - ConditionReasonConfiguration = ConditionReason("Configuration") - ConditionReasonConfigurationErr = ConditionReason("ConfigurationErr") - ConditionReasonConfigured = ConditionReason("Configured") - ConditionReasonInstallation = ConditionReason("Installation") - ConditionReasonInstallationErr = ConditionReason("InstallationErr") - ConditionReasonInstalled = ConditionReason("Installed") - ConditionReasonServerlessDuplicated = ConditionReason("ServerlessDuplicated") - ConditionReasonDeletion = ConditionReason("Deletion") - ConditionReasonDeletionErr = ConditionReason("DeletionErr") - ConditionReasonDeleted = ConditionReason("Deleted") + ConditionReasonConfiguration = ConditionReason("Configuration") + ConditionReasonConfigurationErr = ConditionReason("ConfigurationErr") + ConditionReasonConfigured = ConditionReason("Configured") + ConditionReasonInstallation = ConditionReason("Installation") + ConditionReasonInstallationErr = ConditionReason("InstallationErr") + ConditionReasonInstalled = ConditionReason("Installed") + ConditionReasonDeploymentReplicaFailure = ConditionReason("DeploymentReplicaFailure") + ConditionReasonServerlessDuplicated = ConditionReason("ServerlessDuplicated") + ConditionReasonDeletion = ConditionReason("Deletion") + ConditionReasonDeletionErr = ConditionReason("DeletionErr") + ConditionReasonDeleted = ConditionReason("Deleted") Finalizer = "serverless-operator.kyma-project.io/deletion-hook" ) @@ -199,6 +203,10 @@ func (s *Serverless) UpdateConditionTrue(c ConditionType, r ConditionReason, msg meta.SetStatusCondition(&s.Status.Conditions, condition) } +func (s *Serverless) RemoveCondition(c ConditionType) { + _ = meta.RemoveStatusCondition(&s.Status.Conditions, string(c)) +} + func (s *Serverless) IsServedEmpty() bool { return s.Status.Served == "" } diff --git a/components/operator/controllers/serverless_controller.go b/components/operator/controllers/serverless_controller.go index a9cc97b6b..c05690855 100644 --- a/components/operator/controllers/serverless_controller.go +++ b/components/operator/controllers/serverless_controller.go @@ -26,6 +26,7 @@ import ( "github.com/kyma-project/serverless/components/operator/internal/tracing" "github.com/pkg/errors" "go.uber.org/zap" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/record" @@ -63,9 +64,14 @@ func (sr *serverlessReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&v1alpha1.Serverless{}, &handler.Funcs{ // retrigger all Serverless CRs reconciliations when one is deleted // this should ensure at least one Serverless CR is served - DeleteFunc: sr.retriggerAllServerlessCRs, + DeleteFunc: sr.retriggerAllServerlessCRsOnDelete, }). Watches(&corev1.Service{}, tracing.ServiceCollectorWatcher()). + Watches(&appsv1.Deployment{}, &handler.Funcs{ + // retrigger all Serverless CRs reconciliations when a serverless-controller Deployment is updated or deleted + UpdateFunc: sr.retriggerAllServerlessCRsOnUpdate, + DeleteFunc: sr.retriggerAllServerlessCRsOnDelete, + }, builder.WithPredicates(predicate.NewExactLabelPredicate("app.kubernetes.io/managed-by", "serverless-operator"))). Complete(sr) } @@ -87,7 +93,15 @@ func (sr *serverlessReconciler) Reconcile(ctx context.Context, req ctrl.Request) return r.Reconcile(ctx, *instance) } -func (sr *serverlessReconciler) retriggerAllServerlessCRs(ctx context.Context, e event.DeleteEvent, q workqueue.TypedRateLimitingInterface[ctrl.Request]) { +func (sr *serverlessReconciler) retriggerAllServerlessCRsOnUpdate(ctx context.Context, _ event.TypedUpdateEvent[client.Object], q workqueue.TypedRateLimitingInterface[ctrl.Request]) { + sr.retriggerAllServerlessCRs(ctx, q) +} + +func (sr *serverlessReconciler) retriggerAllServerlessCRsOnDelete(ctx context.Context, _ event.TypedDeleteEvent[client.Object], q workqueue.TypedRateLimitingInterface[ctrl.Request]) { + sr.retriggerAllServerlessCRs(ctx, q) +} + +func (sr *serverlessReconciler) retriggerAllServerlessCRs(ctx context.Context, q workqueue.TypedRateLimitingInterface[ctrl.Request]) { log := sr.log.With("deletion_watcher") list := &v1alpha1.ServerlessList{} diff --git a/components/operator/controllers/serverless_controller_test.go b/components/operator/controllers/serverless_controller_test.go index 4ac5a545c..219aaf993 100644 --- a/components/operator/controllers/serverless_controller_test.go +++ b/components/operator/controllers/serverless_controller_test.go @@ -128,9 +128,10 @@ func shouldCreateServerless(h testHelper, serverlessName, serverlessDeploymentNa // we have to update deployment status manually h.updateDeploymentStatus(serverlessDeploymentName) + h.updateReplicaSetStatus(serverlessDeploymentName) // assert - Eventually(h.createGetServerlessStatusFunc(serverlessName)). + Eventually(h.createGetServerlessStatusFunc(serverlessName, serverlessDeploymentName)). WithPolling(time.Second * 2). WithTimeout(time.Second * 20). Should(ConditionTrueMatcher()) @@ -169,7 +170,7 @@ func shouldUpdateServerless(h testHelper, serverlessSpec v1alpha1.ServerlessSpec Expect(serverless.Spec).To(Equal(serverlessSpec)) - Eventually(h.createGetServerlessStatusFunc(serverlessName)). + Eventually(h.createGetServerlessStatusFunc(serverlessName, serverlessDeploymentName)). WithPolling(time.Second * 2). WithTimeout(time.Second * 20). Should(ConditionTrueMatcher()) diff --git a/components/operator/controllers/testhelper_test.go b/components/operator/controllers/testhelper_test.go index 65c1e424d..4fdb59474 100644 --- a/components/operator/controllers/testhelper_test.go +++ b/components/operator/controllers/testhelper_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/kyma-project/serverless/components/operator/api/v1alpha1" + "github.com/kyma-project/serverless/components/operator/internal/chart" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" gomegatypes "github.com/onsi/gomega/types" @@ -63,24 +64,18 @@ type testHelper struct { namespaceName string } -func (h *testHelper) updateDeploymentStatus(deploymentName string) { - By(fmt.Sprintf("Updating deployment status: %s", deploymentName)) +func (h *testHelper) updateReplicaSetStatus(deploymentName string) { + replicaSetName := fmt.Sprintf("%s-replica-set", deploymentName) + + By(fmt.Sprintf("Updating ReplicaSet status: %s", replicaSetName)) + var deployment appsv1.Deployment Eventually(h.createGetKubernetesObjectFunc(deploymentName, &deployment)). WithPolling(time.Second * 2). WithTimeout(time.Second * 30). Should(BeTrue()) - deployment.Status.Conditions = append(deployment.Status.Conditions, appsv1.DeploymentCondition{ - Type: appsv1.DeploymentAvailable, - Status: corev1.ConditionTrue, - Reason: "test-reason", - Message: "test-message", - }) - deployment.Status.Replicas = 1 - Expect(k8sClient.Status().Update(h.ctx, &deployment)).To(Succeed()) - - replicaSetName := h.createReplicaSetForDeployment(deployment) + h.createReplicaSetForDeployment(replicaSetName, deployment) var replicaSet appsv1.ReplicaSet Eventually(h.createGetKubernetesObjectFunc(replicaSetName, &replicaSet)). @@ -92,11 +87,39 @@ func (h *testHelper) updateDeploymentStatus(deploymentName string) { replicaSet.Status.Replicas = 1 Expect(k8sClient.Status().Update(h.ctx, &replicaSet)).To(Succeed()) + By(fmt.Sprintf("ReplicaSet status updated: %s", replicaSetName)) +} + +func (h *testHelper) updateDeploymentStatus(deploymentName string) { + By(fmt.Sprintf("Updating deployment status: %s", deploymentName)) + var deployment appsv1.Deployment + Eventually(h.createGetKubernetesObjectFunc(deploymentName, &deployment)). + WithPolling(time.Second * 2). + WithTimeout(time.Second * 30). + Should(BeTrue()) + + deployment.Status.Conditions = []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionTrue, + Reason: chart.MinimumReplicasAvailable, + Message: "test-message", + }, + { + Type: appsv1.DeploymentProgressing, + Status: corev1.ConditionTrue, + Reason: chart.NewRSAvailableReason, + Message: "test-message", + }, + } + deployment.Status.ObservedGeneration = deployment.Generation + deployment.Status.UnavailableReplicas = 0 + Expect(k8sClient.Status().Update(h.ctx, &deployment)).To(Succeed()) + By(fmt.Sprintf("Deployment status updated: %s", deploymentName)) } -func (h *testHelper) createReplicaSetForDeployment(deployment appsv1.Deployment) string { - replicaSetName := fmt.Sprintf("%s-replica-set", deployment.Name) +func (h *testHelper) createReplicaSetForDeployment(replicaSetName string, deployment appsv1.Deployment) { By(fmt.Sprintf("Creating replica set (for deployment): %s", replicaSetName)) var ( trueValue = true @@ -126,7 +149,6 @@ func (h *testHelper) createReplicaSetForDeployment(deployment appsv1.Deployment) } Expect(k8sClient.Create(h.ctx, &replicaSet)).To(Succeed()) By(fmt.Sprintf("Replica set (for deployment) created: %s", replicaSetName)) - return replicaSetName } func (h *testHelper) createServerless(serverlessName string, spec v1alpha1.ServerlessSpec) { @@ -211,8 +233,10 @@ func (h *testHelper) listKubernetesObjectFunc(list client.ObjectList) (bool, err return true, err } -func (h *testHelper) createGetServerlessStatusFunc(serverlessName string) func() (v1alpha1.ServerlessStatus, error) { +func (h *testHelper) createGetServerlessStatusFunc(serverlessName, deploymentName string) func() (v1alpha1.ServerlessStatus, error) { return func() (v1alpha1.ServerlessStatus, error) { + // update deployment status to make sure .status.observedGeneration is up to date + h.updateDeploymentStatus(deploymentName) return h.getServerlessStatus(serverlessName) } } diff --git a/components/operator/internal/chart/install_test.go b/components/operator/internal/chart/install_test.go index b1ae2682c..aff66968f 100644 --- a/components/operator/internal/chart/install_test.go +++ b/components/operator/internal/chart/install_test.go @@ -62,7 +62,13 @@ var ( Conditions: []appsv1.DeploymentCondition{ { Type: appsv1.DeploymentAvailable, - Status: corev1.ConditionStatus(v1.ConditionTrue), + Status: corev1.ConditionTrue, + Reason: MinimumReplicasAvailable, + }, + { + Type: appsv1.DeploymentProgressing, + Status: corev1.ConditionTrue, + Reason: NewRSAvailableReason, }, }, }, diff --git a/components/operator/internal/chart/verify.go b/components/operator/internal/chart/verify.go index bf92f7c42..2b5195d79 100644 --- a/components/operator/internal/chart/verify.go +++ b/components/operator/internal/chart/verify.go @@ -4,69 +4,114 @@ import ( "fmt" appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" ) -func Verify(config *Config) (bool, error) { +const ( + // VerificationCompleted indicates that the verification has been completed + VerificationCompleted = "OK" + + // DeploymentVerificationProcessing indicates that the deployment is still being processed + DeploymentVerificationProcessing = "DeploymentProcessing" +) + +type VerificationResult struct { + Ready bool + Reason string +} + +func Verify(config *Config) (*VerificationResult, error) { spec, err := config.Cache.Get(config.Ctx, config.CacheKey) if err != nil { - return false, fmt.Errorf("could not render manifest from chart: %s", err.Error()) + return nil, fmt.Errorf("could not render manifest from chart: %s", err.Error()) } // sometimes cache is not created yet if len(spec.Manifest) == 0 { - return false, nil + return &VerificationResult{Ready: false}, nil } objs, err := parseManifest(spec.Manifest) if err != nil { - return false, fmt.Errorf("could not parse chart manifest: %s", err.Error()) + return nil, fmt.Errorf("could not parse chart manifest: %s", err.Error()) } for i := range objs { u := objs[i] - var verifyFunc verifyFunc - switch u.GetKind() { - case "Deployment": - verifyFunc = verifyDeployment - case "DaemonSet": - // TODO: right now we don't support internal docker registry - default: + if u.GetKind() != "Deployment" { continue } - ready, err := verifyFunc(config, u) + reason, err := verifyDeployment(config, u) if err != nil { - return false, fmt.Errorf("could not verify object %s/%s: %s", u.GetNamespace(), u.GetName(), err.Error()) + return nil, fmt.Errorf("could not verify deployment %s/%s: %s", u.GetNamespace(), u.GetName(), err.Error()) } - if !ready { - return false, nil + if reason != VerificationCompleted { + return &VerificationResult{Ready: false, Reason: reason}, nil } } - return true, nil + return &VerificationResult{Ready: true, Reason: VerificationCompleted}, nil } -type verifyFunc func(*Config, unstructured.Unstructured) (bool, error) - -func verifyDeployment(config *Config, u unstructured.Unstructured) (bool, error) { +func verifyDeployment(config *Config, u unstructured.Unstructured) (string, error) { var deployment appsv1.Deployment err := config.Cluster.Client.Get(config.Ctx, types.NamespacedName{ Name: u.GetName(), Namespace: u.GetNamespace(), }, &deployment) if err != nil { - return false, err + return "", err } - for _, cond := range deployment.Status.Conditions { - if cond.Type == appsv1.DeploymentAvailable && cond.Status == v1.ConditionTrue { - return true, nil - } + if isDeploymentReady(deployment) { + return VerificationCompleted, nil + } + + if hasDeploymentConditionTrueStatus(deployment.Status.Conditions, appsv1.DeploymentReplicaFailure) { + return fmt.Sprintf("deployment %s/%s has replica failure: %s", u.GetNamespace(), u.GetName(), + getDeploymentCondition(deployment.Status.Conditions, appsv1.DeploymentReplicaFailure).Message), nil } - return false, nil + return DeploymentVerificationProcessing, nil +} + +const ( + // NewRSAvailableReason is added in a deployment when its newest replica set is made available + // ie. the number of new pods that have passed readiness checks and run for at least minReadySeconds + // is at least the minimum available pods that need to run for the deployment. + NewRSAvailableReason = "NewReplicaSetAvailable" + + // MinimumReplicasAvailable is added in a deployment when it has its minimum replicas required available. + MinimumReplicasAvailable = "MinimumReplicasAvailable" +) + +func isDeploymentReady(deployment appsv1.Deployment) bool { + conditions := deployment.Status.Conditions + return hasDeploymentConditionTrueStatusWithReason(conditions, appsv1.DeploymentAvailable, MinimumReplicasAvailable) && + hasDeploymentConditionTrueStatusWithReason(conditions, appsv1.DeploymentProgressing, NewRSAvailableReason) && + deployment.Generation == deployment.Status.ObservedGeneration && // spec changes are observed + deployment.Status.UnavailableReplicas == 0 // all replicas are available +} + +func hasDeploymentConditionTrueStatus(conditions []appsv1.DeploymentCondition, conditionType appsv1.DeploymentConditionType) bool { + condition := getDeploymentCondition(conditions, conditionType) + return condition.Status == corev1.ConditionTrue +} + +func hasDeploymentConditionTrueStatusWithReason(conditions []appsv1.DeploymentCondition, conditionType appsv1.DeploymentConditionType, reason string) bool { + condition := getDeploymentCondition(conditions, conditionType) + return condition.Status == corev1.ConditionTrue && condition.Reason == reason +} + +func getDeploymentCondition(conditions []appsv1.DeploymentCondition, conditionType appsv1.DeploymentConditionType) appsv1.DeploymentCondition { + for _, condition := range conditions { + if condition.Type == conditionType { + return condition + } + } + return appsv1.DeploymentCondition{} } diff --git a/components/operator/internal/chart/verify_test.go b/components/operator/internal/chart/verify_test.go index 8adc8c943..d85ece2f3 100644 --- a/components/operator/internal/chart/verify_test.go +++ b/components/operator/internal/chart/verify_test.go @@ -5,6 +5,7 @@ import ( "fmt" "testing" + "github.com/stretchr/testify/require" "go.uber.org/zap" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -28,6 +29,26 @@ var ( }, }, } + + testDeployReplicaFailureCR = &appsv1.Deployment{ + ObjectMeta: v1.ObjectMeta{ + Name: "test-deploy", + Namespace: "default", + }, + Status: appsv1.DeploymentStatus{ + Conditions: []appsv1.DeploymentCondition{ + { + Type: appsv1.DeploymentAvailable, + Status: corev1.ConditionStatus(v1.ConditionFalse), + }, + { + Type: appsv1.DeploymentReplicaFailure, + Message: "Replica failure because of test reason", + Status: corev1.ConditionStatus(v1.ConditionTrue), + }, + }, + }, + } ) func Test_verify(t *testing.T) { @@ -57,7 +78,7 @@ func Test_verify(t *testing.T) { tests := []struct { name string args args - want bool + want *VerificationResult wantErr bool }{ { @@ -68,7 +89,7 @@ func Test_verify(t *testing.T) { CacheKey: emptyManifestKey, }, }, - want: true, + want: &VerificationResult{Ready: true, Reason: VerificationCompleted}, wantErr: false, }, { @@ -79,7 +100,7 @@ func Test_verify(t *testing.T) { CacheKey: wrongManifestKey, }, }, - want: false, + want: nil, wantErr: true, }, { @@ -95,7 +116,7 @@ func Test_verify(t *testing.T) { }, }, }, - want: true, + want: &VerificationResult{Ready: true, Reason: VerificationCompleted}, wantErr: false, }, { @@ -111,7 +132,26 @@ func Test_verify(t *testing.T) { }, }, }, - want: false, + want: &VerificationResult{Ready: false, Reason: DeploymentVerificationProcessing}, + wantErr: false, + }, + { + name: "obj replica failure", + args: args{ + config: &Config{ + Ctx: context.Background(), + Log: log, + Cache: cache, + CacheKey: testManifestKey, + Cluster: Cluster{ + Client: fake.NewClientBuilder().WithObjects(testDeployReplicaFailureCR).Build(), + }, + }, + }, + want: &VerificationResult{ + Ready: false, + Reason: "deployment default/test-deploy has replica failure: Replica failure because of test reason", + }, wantErr: false, }, { @@ -127,20 +167,15 @@ func Test_verify(t *testing.T) { }, }, }, - want: false, + want: nil, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Verify(tt.args.config) - if (err != nil) != tt.wantErr { - t.Errorf("verify() error = %v, wantErr %v", err, tt.wantErr) - return - } - if got != tt.want { - t.Errorf("verify() = %v, want %v", got, tt.want) - } + require.Equal(t, tt.want, got) + require.Equal(t, tt.wantErr, err != nil) }) } } diff --git a/components/operator/internal/predicate/predicate.go b/components/operator/internal/predicate/predicate.go index 63bc04a13..bff0add2f 100644 --- a/components/operator/internal/predicate/predicate.go +++ b/components/operator/internal/predicate/predicate.go @@ -2,6 +2,8 @@ package predicate import ( "reflect" + + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/predicate" ) @@ -38,3 +40,40 @@ func isAnnotationUpdate(e event.UpdateEvent) bool { newAnnotations := e.ObjectNew.GetAnnotations() return !reflect.DeepEqual(oldAnnotations, newAnnotations) } + +type ExactLabelPredicate struct { + expectedKey string + expectedValue string + predicate.Funcs +} + +func NewExactLabelPredicate(key, value string) ExactLabelPredicate { + return ExactLabelPredicate{ + expectedKey: key, + expectedValue: value, + } +} + +func (p ExactLabelPredicate) Create(e event.CreateEvent) bool { + return isObjectExactLabel(e.Object, p.expectedKey, p.expectedValue) +} + +func (p ExactLabelPredicate) Update(e event.UpdateEvent) bool { + return isObjectExactLabel(e.ObjectNew, p.expectedKey, p.expectedValue) +} + +func (p ExactLabelPredicate) Delete(e event.DeleteEvent) bool { + return isObjectExactLabel(e.Object, p.expectedKey, p.expectedValue) +} + +func (p ExactLabelPredicate) Generic(e event.GenericEvent) bool { + return isObjectExactLabel(e.Object, p.expectedKey, p.expectedValue) +} + +func isObjectExactLabel(obj client.Object, key, value string) bool { + if obj == nil { + return false + } + + return obj.GetLabels() != nil && obj.GetLabels()[key] == value +} diff --git a/components/operator/internal/state/verify.go b/components/operator/internal/state/verify.go index 05c3696b9..bb3990e88 100644 --- a/components/operator/internal/state/verify.go +++ b/components/operator/internal/state/verify.go @@ -2,6 +2,7 @@ package state import ( "context" + "errors" "github.com/kyma-project/serverless/components/operator/api/v1alpha1" "github.com/kyma-project/serverless/components/operator/internal/chart" @@ -11,7 +12,7 @@ import ( // verify if all workloads are in ready state func sFnVerifyResources(_ context.Context, r *reconciler, s *systemState) (stateFn, *ctrl.Result, error) { - ready, err := chart.Verify(s.chartConfig) + result, err := chart.Verify(s.chartConfig) if err != nil { r.log.Warnf("error while verifying resource %s: %s", client.ObjectKeyFromObject(&s.instance), err.Error()) @@ -24,10 +25,25 @@ func sFnVerifyResources(_ context.Context, r *reconciler, s *systemState) (state return stopWithEventualError(err) } - if !ready { + if !result.Ready && result.Reason == chart.DeploymentVerificationProcessing { + // still processing return requeueAfter(requeueDuration) } + if !result.Ready { + // verification failed + s.setState(v1alpha1.StateError) + s.instance.UpdateConditionTrue( + v1alpha1.ConditionTypeDeploymentFailure, + v1alpha1.ConditionReasonDeploymentReplicaFailure, + result.Reason, + ) + return stopWithEventualError(errors.New(result.Reason)) + } + + // remove possible previous DeploymentFailure condition + s.instance.RemoveCondition(v1alpha1.ConditionTypeDeploymentFailure) + warning := s.warningBuilder.Build() if warning != "" { s.setState(v1alpha1.StateWarning) diff --git a/config/operator/base/ui-extensions/serverless/details b/config/operator/base/ui-extensions/serverless/details index b909153df..d6a69464a 100644 --- a/config/operator/base/ui-extensions/serverless/details +++ b/config/operator/base/ui-extensions/serverless/details @@ -7,6 +7,14 @@ status: - name: Condition details widget: ConditionList source: status.conditions + highlights: + - type: DeploymentFailure + positive: + - 'False' + critical: + - 'True' + informative: + - unknown - name: status.networkPoliciesEnabled source: status.networkPoliciesEnabled body: diff --git a/docs/user/resources/06-20-serverless-cr.md b/docs/user/resources/06-20-serverless-cr.md index 551e35f45..da76b36d1 100644 --- a/docs/user/resources/06-20-serverless-cr.md +++ b/docs/user/resources/06-20-serverless-cr.md @@ -95,17 +95,18 @@ Processing of a Serverless CR can succeed, continue, or fail for one of these re ## Serverless CR Conditions -This section describes the possible states of the Serverless CR. Three condition types, `Installed`, `Configured` and `Deleted`, are used. - -| No | CR State | Condition type | Condition status | Condition reason | Remark | -|----|------------|----------------|------------------|-----------------------|-----------------------------------------------| -| 1 | Processing | Configured | true | Configured | Serverless configuration verified | -| 2 | Processing | Configured | unknown | ConfigurationCheck | Serverless configuration verification ongoing | -| 3 | Error | Configured | false | ConfigurationCheckErr | Serverless configuration verification error | -| 7 | Error | Configured | false | ServerlessDuplicated | Only one Serverless CR is allowed | -| 4 | Ready | Installed | true | Installed | Serverless workloads deployed | -| 5 | Processing | Installed | unknown | Installation | Deploying serverless workloads | -| 6 | Error | Installed | false | InstallationErr | Deployment error | -| 8 | Deleting | Deleted | unknown | Deletion | Deletion in progress | -| 9 | Deleting | Deleted | true | Deleted | Serverless module deleted | -| 10 | Error | Deleted | false | DeletionErr | Deletion failed | +This section describes the possible states of the Serverless CR. Three condition types, `Installed`, `Configured`, `DeploymentFailure` and `Deleted`, are used. + +| No | CR State | Condition type | Condition status | Condition reason | Remark | +|----|------------|-------------------|------------------|--------------------------|-----------------------------------------------------| +| 1 | Processing | Configured | true | Configured | Serverless configuration verified | +| 2 | Processing | Configured | unknown | ConfigurationCheck | Serverless configuration verification ongoing | +| 3 | Error | Configured | false | ConfigurationCheckErr | Serverless configuration verification error | +| 4 | Error | Configured | false | ServerlessDuplicated | Only one Serverless CR is allowed | +| 5 | Ready | Installed | true | Installed | Serverless workloads deployed | +| 6 | Processing | Installed | unknown | Installation | Deploying serverless workloads | +| 7 | Error | Installed | false | InstallationErr | Serverless resources installation error | +| 8 | Error | DeploymentFailure | true | DeploymentReplicaFailure | Serverless manager has the ReplicaFailure condition | +| 9 | Deleting | Deleted | unknown | Deletion | Deletion in progress | +| 10 | Deleting | Deleted | true | Deleted | Serverless module deleted | +| 11 | Error | Deleted | false | DeletionErr | Deletion failed | diff --git a/tests/operator/Makefile b/tests/operator/Makefile index cdba34593..67516c045 100644 --- a/tests/operator/Makefile +++ b/tests/operator/Makefile @@ -4,17 +4,3 @@ include ${PROJECT_ROOT}/hack/help.mk .PHONY: test test: ## Run integration test. go run main.go - -.PHONY: cluster-info -cluster-info: ## Print useful info about the cluster regarding integration run - @echo "####################### Operator Logs #######################" - @kubectl logs -n kyma-system -l app.kubernetes.io/component=serverless-operator.kyma-project.io --tail=-1 || true - @echo "" - - @echo "####################### Serverless CR #######################" - @kubectl get serverless -A -oyaml || true - @echo "" - - @echo "####################### Pods #######################" - @kubectl get pods -A || true - @echo "" diff --git a/tests/operator/main.go b/tests/operator/main.go index 4ff9b1c50..30ca9f720 100644 --- a/tests/operator/main.go +++ b/tests/operator/main.go @@ -3,10 +3,11 @@ package main import ( "context" "fmt" - "github.com/kyma-project/serverless/tests/operator/function" "os" "time" + "github.com/kyma-project/serverless/tests/operator/function" + "github.com/google/uuid" "github.com/kyma-project/serverless/components/operator/api/v1alpha1" "github.com/kyma-project/serverless/tests/operator/logger" @@ -64,7 +65,7 @@ func main() { FunctionRequeueDuration: "19m", FunctionBuildExecutorArgs: "executor-args", FunctionBuildMaxSimultaneousJobs: "10", - HealthzLivenessTimeout: "20", + HealthzLivenessTimeout: "20s", DefaultBuildJobPreset: "normal", DefaultRuntimePodPreset: "M", EnableNetworkPolicies: true, @@ -98,7 +99,7 @@ func main() { Endpoint: "http://eventing-endpoint", }, FunctionRequeueDuration: "19m", - HealthzLivenessTimeout: "20", + HealthzLivenessTimeout: "20s", DefaultRuntimePodPreset: "M", EnableNetworkPolicies: true, }, From 3fa44fc47c198556134d9a78b6cfda6dbe6416e3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kwiatosz Date: Mon, 8 Dec 2025 13:21:32 +0100 Subject: [PATCH 08/13] Fix for paths with whitespaces in BaseDir (#2089) (#2105) Co-authored-by: Antoni --- .../controller/resources/deployment.go | 2 +- .../controller/resources/deployment_test.go | 22 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/components/buildless-serverless/internal/controller/resources/deployment.go b/components/buildless-serverless/internal/controller/resources/deployment.go index d5d3356ef..ae0101a8f 100644 --- a/components/buildless-serverless/internal/controller/resources/deployment.go +++ b/components/buildless-serverless/internal/controller/resources/deployment.go @@ -373,7 +373,7 @@ func (d *Deployment) initContainerCommand() string { var arr []string arr = append(arr, "/app/gitcloner") arr = append(arr, - fmt.Sprintf("mkdir /git-repository/src;cp -r /git-repository/repo/%s/* /git-repository/src;", + fmt.Sprintf("mkdir /git-repository/src;cp -r '/git-repository/repo/%s'/* /git-repository/src;", strings.Trim(gitRepo.BaseDir, "/ "))) return strings.Join(arr, "\n") } diff --git a/components/buildless-serverless/internal/controller/resources/deployment_test.go b/components/buildless-serverless/internal/controller/resources/deployment_test.go index ad8dc0b53..cf1abf72a 100644 --- a/components/buildless-serverless/internal/controller/resources/deployment_test.go +++ b/components/buildless-serverless/internal/controller/resources/deployment_test.go @@ -332,7 +332,27 @@ fi`, c := r.Spec.Template.Spec.InitContainers[0] expectedCommand := []string{"sh", "-c", `/app/gitcloner -mkdir /git-repository/src;cp -r /git-repository/repo/recursing-mcnulty/* /git-repository/src;`} +mkdir /git-repository/src;cp -r '/git-repository/repo/recursing-mcnulty'/* /git-repository/src;`} + require.Equal(t, expectedCommand, c.Command) + }) + t.Run("create init container for git function with baseDir containing whitespaces", func(t *testing.T) { + d := minimalDeployment() + d.commit = "test-commit" + d.function.Spec.Source = serverlessv1alpha2.Source{ + GitRepository: &serverlessv1alpha2.GitRepositorySource{ + URL: "wonderful-germain", + Repository: serverlessv1alpha2.Repository{ + BaseDir: "git functions/nodejs12", + Reference: "main"}}} + + r := d.construct() + + require.NotNil(t, r) + require.Len(t, r.Spec.Template.Spec.InitContainers, 1) + c := r.Spec.Template.Spec.InitContainers[0] + expectedCommand := []string{"sh", "-c", + `/app/gitcloner +mkdir /git-repository/src;cp -r '/git-repository/repo/git functions/nodejs12'/* /git-repository/src;`} require.Equal(t, expectedCommand, c.Command) }) } From 30652c2619c0b32d43dd0cde36c524d9c607ce91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kalke?= <56382792+MichalKalke@users.noreply.github.com> Date: Mon, 8 Dec 2025 15:46:26 +0100 Subject: [PATCH 09/13] Cleanup svs CR from legacy fields (#2096) (#2108) Co-authored-by: Marcin Dobrochowski <39153236+anoipm@users.noreply.github.com> --- .../state/controller_configuration.go | 31 ++++++++- .../state/controller_configuration_test.go | 65 ++++++++++++++++++- .../operator/internal/state/registry.go | 7 +- .../operator/internal/state/registry_test.go | 45 +++++++++++++ 4 files changed, 143 insertions(+), 5 deletions(-) diff --git a/components/operator/internal/state/controller_configuration.go b/components/operator/internal/state/controller_configuration.go index cd1f8a043..0af23d5a5 100644 --- a/components/operator/internal/state/controller_configuration.go +++ b/components/operator/internal/state/controller_configuration.go @@ -60,23 +60,42 @@ func updateControllerConfigurationStatus(ctx context.Context, r *reconciler, ins } spec := instance.Spec + + // Common fields for both legacy and buildless modes fields := fieldsToUpdate{ {spec.TargetCPUUtilizationPercentage, &instance.Status.CPUUtilizationPercentage, "CPU utilization", ""}, {spec.FunctionRequeueDuration, &instance.Status.RequeueDuration, "Function requeue duration", ""}, {spec.FunctionBuildExecutorArgs, &instance.Status.BuildExecutorArgs, "Function build executor args", ""}, {spec.FunctionBuildMaxSimultaneousJobs, &instance.Status.BuildMaxSimultaneousJobs, "Max number of simultaneous jobs", ""}, {spec.HealthzLivenessTimeout, &instance.Status.HealthzLivenessTimeout, "Duration of health check", ""}, - {spec.DefaultBuildJobPreset, &instance.Status.DefaultBuildJobPreset, "Default build job preset", defaultBuildPreset}, {spec.DefaultRuntimePodPreset, &instance.Status.DefaultRuntimePodPreset, "Default runtime pod preset", defaultRuntimePreset}, {spec.LogLevel, &instance.Status.LogLevel, "Log level", defaultLogLevel}, {spec.LogFormat, &instance.Status.LogFormat, "Log format", defaultLogFormat}, } + // Add build preset only in legacy mode + // TODO: This is a temporary solution, delete it after removing legacy serverless + if isLegacyEnabled(instance.Annotations) { + fields = append(fields, struct { + specField string + statusField *string + fieldName string + defaultValue string + }{spec.DefaultBuildJobPreset, &instance.Status.DefaultBuildJobPreset, "Default build job preset", defaultBuildPreset}) + } else { + instance.Status.DefaultBuildJobPreset = "" + } + updateStatusFields(r.k8s, instance, fields) return nil } func configureControllerConfigurationFlags(s *systemState) { + // TODO: This is a temporary solution, delete it after removing legacy serverless, clear flag when buildless mode is enabled + if !isLegacyEnabled(s.instance.Annotations) { + s.instance.Status.DefaultBuildJobPreset = "" + } + s.flagsBuilder. WithControllerConfiguration( s.instance.Status.CPUUtilizationPercentage, @@ -120,8 +139,18 @@ func configureChartPath(s *systemState, log *zap.SugaredLogger) { } if val == buildlessModeDisabled { log.Info("Chart path is set to old serverless module chart") + if s.chartConfig == nil { + log.Warn("Chart config is empty, cannot set chart path") + return + } s.chartConfig.Release.ChartPath = oldServerlessChartPath } log.Infof("Using chart path: %s", s.chartConfig.Release.ChartPath) // we use default value from environment variable if annotation has unexpected value } + +// TODO: remove this method when buildless is enabled by default +func isLegacyEnabled(annotations map[string]string) bool { + val, ok := annotations[buildlessModeAnnotation] + return ok && val == buildlessModeDisabled +} diff --git a/components/operator/internal/state/controller_configuration_test.go b/components/operator/internal/state/controller_configuration_test.go index 3f5f9c88d..e49ce824e 100644 --- a/components/operator/internal/state/controller_configuration_test.go +++ b/components/operator/internal/state/controller_configuration_test.go @@ -30,10 +30,55 @@ const ( func Test_sFnControllerConfiguration(t *testing.T) { configurationReadyMsg := "Configuration ready" + t.Run("update status in buildless mode", func(t *testing.T) { + s := &systemState{ + instance: v1alpha1.Serverless{ + Spec: v1alpha1.ServerlessSpec{}, + }, + flagsBuilder: chart.NewFlagsBuilder(), + } + + c := fake.NewClientBuilder().WithObjects( + fixTestNode("node-1"), + fixTestNode("node-2"), + ).Build() + eventRecorder := record.NewFakeRecorder(4) + r := &reconciler{log: zap.NewNop().Sugar(), k8s: k8s{client: c, EventRecorder: eventRecorder}} + next, result, err := sFnControllerConfiguration(context.TODO(), r, s) + require.Nil(t, err) + require.Nil(t, result) + requireEqualFunc(t, sFnApplyResources, next) + + status := s.instance.Status + require.Equal(t, "", status.DefaultBuildJobPreset) + require.Equal(t, slowRuntimePreset, status.DefaultRuntimePodPreset) + + require.Equal(t, v1alpha1.StateProcessing, status.State) + requireContainsCondition(t, status, + v1alpha1.ConditionTypeConfigured, + metav1.ConditionTrue, + v1alpha1.ConditionReasonConfigured, + configurationReadyMsg, + ) + + expectedEvents := []string{ + "Normal Configuration Default runtime pod preset set from '' to 'XS'", + } + + for _, expectedEvent := range expectedEvents { + require.Equal(t, expectedEvent, <-eventRecorder.Events) + } + }) + t.Run("update status with slow defaults", func(t *testing.T) { s := &systemState{ instance: v1alpha1.Serverless{ Spec: v1alpha1.ServerlessSpec{}, + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + buildlessModeAnnotation: buildlessModeDisabled, + }, + }, }, flagsBuilder: chart.NewFlagsBuilder(), } @@ -62,8 +107,10 @@ func Test_sFnControllerConfiguration(t *testing.T) { ) expectedEvents := []string{ - "Normal Configuration Default build job preset set from '' to 'slow'", "Normal Configuration Default runtime pod preset set from '' to 'XS'", + "Normal Configuration Log level set from '' to 'info'", + "Normal Configuration Log format set from '' to 'json'", + "Normal Configuration Default build job preset set from '' to 'slow'", } for _, expectedEvent := range expectedEvents { @@ -74,6 +121,11 @@ func Test_sFnControllerConfiguration(t *testing.T) { t.Run("update slow default to normal ones", func(t *testing.T) { s := &systemState{ instance: v1alpha1.Serverless{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + buildlessModeAnnotation: buildlessModeDisabled, + }, + }, Spec: v1alpha1.ServerlessSpec{}, Status: v1alpha1.ServerlessStatus{ DefaultBuildJobPreset: slowBuildPreset, @@ -109,8 +161,10 @@ func Test_sFnControllerConfiguration(t *testing.T) { ) expectedEvents := []string{ - "Normal Configuration Default build job preset set from 'slow' to 'normal'", "Normal Configuration Default runtime pod preset set from 'XS' to 'L'", + "Normal Configuration Log level set from '' to 'info'", + "Normal Configuration Log format set from '' to 'json'", + "Normal Configuration Default build job preset set from 'slow' to 'normal'", } for _, expectedEvent := range expectedEvents { @@ -121,6 +175,11 @@ func Test_sFnControllerConfiguration(t *testing.T) { t.Run("update status additional configuration overrides", func(t *testing.T) { s := &systemState{ instance: v1alpha1.Serverless{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + buildlessModeAnnotation: buildlessModeDisabled, + }, + }, Spec: v1alpha1.ServerlessSpec{ TargetCPUUtilizationPercentage: cpuUtilizationTest, FunctionRequeueDuration: requeueDurationTest, @@ -169,10 +228,10 @@ func Test_sFnControllerConfiguration(t *testing.T) { "Normal Configuration Function build executor args set from '' to 'test-build-executor-args'", "Normal Configuration Max number of simultaneous jobs set from '' to 'test-max-simultaneous-jobs'", "Normal Configuration Duration of health check set from '' to 'test-healthz-liveness-timeout'", - "Normal Configuration Default build job preset set from '' to 'test=default-build-job-preset'", "Normal Configuration Default runtime pod preset set from '' to 'test-default-runtime-pod-preset'", "Normal Configuration Log level set from '' to 'test-log-level'", "Normal Configuration Log format set from '' to 'test-log-format'", + "Normal Configuration Default build job preset set from '' to 'test=default-build-job-preset'", } for _, expectedEvent := range expectedEvents { diff --git a/components/operator/internal/state/registry.go b/components/operator/internal/state/registry.go index e805ff79f..e36bfb650 100644 --- a/components/operator/internal/state/registry.go +++ b/components/operator/internal/state/registry.go @@ -67,7 +67,12 @@ func addRegistryConfigurationWarnings(s *systemState) { } func setInternalRegistryConfig(ctx context.Context, r *reconciler, s *systemState) error { - s.instance.Status.DockerRegistry = "internal" + // TODO: this is a temporary solution, delete it after removing legacy serverless + if isLegacyEnabled(s.instance.Annotations) { + s.instance.Status.DockerRegistry = "internal" + } else { + s.instance.Status.DockerRegistry = "" + } s.flagsBuilder.WithRegistryEnableInternal( *s.instance.Spec.DockerRegistry.EnableInternal, ) diff --git a/components/operator/internal/state/registry_test.go b/components/operator/internal/state/registry_test.go index 49002e79b..0515bad22 100644 --- a/components/operator/internal/state/registry_test.go +++ b/components/operator/internal/state/registry_test.go @@ -17,9 +17,54 @@ import ( ) func Test_sFnRegistryConfiguration(t *testing.T) { + t.Run("no internal registry status", func(t *testing.T) { + s := &systemState{ + instance: v1alpha1.Serverless{ + Spec: v1alpha1.ServerlessSpec{ + DockerRegistry: &v1alpha1.DockerRegistry{ + EnableInternal: ptr.To[bool](true), + }, + }, + }, + statusSnapshot: v1alpha1.ServerlessStatus{ + DockerRegistry: "", + }, + flagsBuilder: chart.NewFlagsBuilder(), + } + r := &reconciler{ + k8s: k8s{client: fake.NewClientBuilder().Build()}, + log: zap.NewNop().Sugar(), + } + expectedFlags := map[string]interface{}{ + "dockerRegistry": map[string]interface{}{ + "enableInternal": true, + }, + "global": map[string]interface{}{ + "registryNodePort": int64(32_137), + }, + } + + next, result, err := sFnRegistryConfiguration(context.Background(), r, s) + require.NoError(t, err) + require.Nil(t, result) + requireEqualFunc(t, sFnOptionalDependencies, next) + + flags, err := s.flagsBuilder.Build() + require.NoError(t, err) + + require.EqualValues(t, expectedFlags, flags) + require.Equal(t, "", s.instance.Status.DockerRegistry) + require.Equal(t, v1alpha1.StateProcessing, s.instance.Status.State) + }) + t.Run("internal registry and update", func(t *testing.T) { s := &systemState{ instance: v1alpha1.Serverless{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + buildlessModeAnnotation: buildlessModeDisabled, + }, + }, Spec: v1alpha1.ServerlessSpec{ DockerRegistry: &v1alpha1.DockerRegistry{ EnableInternal: ptr.To[bool](true), From cb971f45ac12bf1dcdd202768e1e753d0e9f6bb4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kwiatosz Date: Tue, 9 Dec 2025 09:13:55 +0100 Subject: [PATCH 10/13] Remove docker registry from default serverless CR spec (#2109) (#2110) --- config/samples/default-serverless-cr.yaml | 4 +--- config/samples/serverless-with-networkpolicies-enabled.yaml | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/config/samples/default-serverless-cr.yaml b/config/samples/default-serverless-cr.yaml index 8526919d8..7b431c0c8 100644 --- a/config/samples/default-serverless-cr.yaml +++ b/config/samples/default-serverless-cr.yaml @@ -3,6 +3,4 @@ kind: Serverless metadata: name: default namespace: kyma-system -spec: - dockerRegistry: - enableInternal: true +spec: {} diff --git a/config/samples/serverless-with-networkpolicies-enabled.yaml b/config/samples/serverless-with-networkpolicies-enabled.yaml index 5d951cffb..a8173cbb9 100644 --- a/config/samples/serverless-with-networkpolicies-enabled.yaml +++ b/config/samples/serverless-with-networkpolicies-enabled.yaml @@ -4,6 +4,4 @@ metadata: name: default namespace: kyma-system spec: - dockerRegistry: - enableInternal: true enableNetworkPolicies: true From b6a505659c2b5b704733069d4b54dcc95d9e1742 Mon Sep 17 00:00:00 2001 From: ottersbot Date: Tue, 9 Dec 2025 09:34:06 +0000 Subject: [PATCH 11/13] upgrade dependencies --- config/buildless-serverless/Chart.yaml | 2 +- config/buildless-serverless/values.yaml | 10 +++++----- config/operator/base/deployment/deployment.yaml | 14 +++++++------- .../operator/base/deployment/kustomization.yaml | 2 +- config/operator/base/kustomization.yaml | 3 +++ config/serverless/values.yaml | 10 +++++----- sec-scanners-config.yaml | 16 ++++++++-------- 7 files changed, 30 insertions(+), 27 deletions(-) diff --git a/config/buildless-serverless/Chart.yaml b/config/buildless-serverless/Chart.yaml index 38c8dbef0..0995181d3 100644 --- a/config/buildless-serverless/Chart.yaml +++ b/config/buildless-serverless/Chart.yaml @@ -2,7 +2,7 @@ apiVersion: v1 description: Kyma component 'buildless serverless' name: buildless-serverless version: 1.0.0 -appVersion: "1.9.1" +appVersion: "1.9.2" home: https://kyma-project.io icon: https://github.com/kyma-project/kyma/blob/main/logo.png?raw=true dependencies: diff --git a/config/buildless-serverless/values.yaml b/config/buildless-serverless/values.yaml index c44d89aa5..8dc48d82f 100644 --- a/config/buildless-serverless/values.yaml +++ b/config/buildless-serverless/values.yaml @@ -11,11 +11,11 @@ global: targetDir: "/logconfig" filename: "log-config.yaml" images: - function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 - function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 + function_controller: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.2 + function_init: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.2 + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.2 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.2 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.2 containers: manager: logConfiguration: diff --git a/config/operator/base/deployment/deployment.yaml b/config/operator/base/deployment/deployment.yaml index bd89b96ca..6018450d2 100644 --- a/config/operator/base/deployment/deployment.yaml +++ b/config/operator/base/deployment/deployment.yaml @@ -40,25 +40,25 @@ spec: fieldRef: fieldPath: metadata.uid - name: IMAGE_FUNCTION_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.2 - name: IMAGE_FUNCTION_BUILD_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.2 - name: IMAGE_REGISTRY_INIT value: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - name: IMAGE_FUNCTION_RUNTIME_NODEJS20 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.2 - name: IMAGE_FUNCTION_RUNTIME_NODEJS22 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.2 - name: IMAGE_FUNCTION_RUNTIME_PYTHON312 - value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.2 - name: IMAGE_KANIKO_EXECUTOR value: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - name: IMAGE_REGISTRY value: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - name: IMAGE_FUNCTION_BUILDLESS_CONTROLLER - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.2 - name: IMAGE_FUNCTION_BUILDLESS_INIT - value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 + value: europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.2 securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/config/operator/base/deployment/kustomization.yaml b/config/operator/base/deployment/kustomization.yaml index 5d1e9e840..16ebdb022 100644 --- a/config/operator/base/deployment/kustomization.yaml +++ b/config/operator/base/deployment/kustomization.yaml @@ -5,4 +5,4 @@ kind: Kustomization images: - name: controller newName: europe-docker.pkg.dev/kyma-project/prod/serverless-operator - newTag: 1.9.1 + newTag: 1.9.2 diff --git a/config/operator/base/kustomization.yaml b/config/operator/base/kustomization.yaml index e1a34b0d1..09ed1da45 100644 --- a/config/operator/base/kustomization.yaml +++ b/config/operator/base/kustomization.yaml @@ -26,6 +26,9 @@ labels: - includeTemplates: true pairs: app.kubernetes.io/version: 1.9.1 +- includeTemplates: true + pairs: + app.kubernetes.io/version: 1.9.2 resources: - ./crd diff --git a/config/serverless/values.yaml b/config/serverless/values.yaml index f44e3d08c..2b3979f4c 100644 --- a/config/serverless/values.yaml +++ b/config/serverless/values.yaml @@ -71,13 +71,13 @@ global: ingress: domainName: images: - function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 - function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 + function_buildful_controller: europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.2 + function_build_init: europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.2 # https://github.com/kyma-project/docker-registry/tree/main/components/registry-init registry_init: europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 - function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 - function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 + function_runtime_nodejs20: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.2 + function_runtime_nodejs22: europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.2 + function_runtime_python312: europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.2 kaniko_executor: europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 registry: europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 serverlessPriorityClassValue: 2000000 diff --git a/sec-scanners-config.yaml b/sec-scanners-config.yaml index d57d35520..be481f9da 100644 --- a/sec-scanners-config.yaml +++ b/sec-scanners-config.yaml @@ -1,17 +1,17 @@ module-name: serverless kind: kyma bdba: - - europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.1 - - europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-controller:1.9.2 + - europe-docker.pkg.dev/kyma-project/prod/function-build-init:1.9.2 - europe-docker.pkg.dev/kyma-project/prod/registry-init:v20240506-57d31b1d - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.1 - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.1 - - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs20:1.9.2 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-nodejs22:1.9.2 + - europe-docker.pkg.dev/kyma-project/prod/function-runtime-python312:1.9.2 - europe-docker.pkg.dev/kyma-project/prod/external/gcr.io/kaniko-project/executor:v1.24.0 - europe-docker.pkg.dev/kyma-project/prod/external/library/registry:3.0.0 - - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:1.9.1 - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.1 - - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.1 + - europe-docker.pkg.dev/kyma-project/prod/serverless-operator:1.9.2 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-controller:1.9.2 + - europe-docker.pkg.dev/kyma-project/prod/function-buildless-init:1.9.2 mend: language: golang-mod exclude: From 9225fda99daee78f47c386cde3cd66ef31377ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kalke?= <56382792+MichalKalke@users.noreply.github.com> Date: Wed, 10 Dec 2025 15:04:52 +0100 Subject: [PATCH 12/13] In default buildless mode do not configure registry (#2114) --- components/operator/internal/state/registry.go | 6 ++++-- components/operator/internal/state/registry_test.go | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/components/operator/internal/state/registry.go b/components/operator/internal/state/registry.go index e36bfb650..dd63625cc 100644 --- a/components/operator/internal/state/registry.go +++ b/components/operator/internal/state/registry.go @@ -131,12 +131,14 @@ func setExternalRegistryConfig(ctx context.Context, r *reconciler, s *systemStat } func setK3dRegistryConfig(s *systemState) { - s.instance.Status.DockerRegistry = v1alpha1.DefaultServerAddress + if isLegacyEnabled(s.instance.Annotations) { + s.instance.Status.DockerRegistry = v1alpha1.DefaultServerAddress + } s.flagsBuilder.WithRegistryEnableInternal( getEnableInternal(s.instance.Spec.DockerRegistry), ).WithRegistryAddresses( v1alpha1.DefaultRegistryAddress, - s.instance.Status.DockerRegistry, + v1alpha1.DefaultServerAddress, ) } diff --git a/components/operator/internal/state/registry_test.go b/components/operator/internal/state/registry_test.go index 0515bad22..5c4d0c50d 100644 --- a/components/operator/internal/state/registry_test.go +++ b/components/operator/internal/state/registry_test.go @@ -167,6 +167,9 @@ func Test_sFnRegistryConfiguration(t *testing.T) { instance: v1alpha1.Serverless{ ObjectMeta: metav1.ObjectMeta{ Namespace: "some-namespace", + Annotations: map[string]string{ + buildlessModeAnnotation: buildlessModeDisabled, + }, }, Spec: v1alpha1.ServerlessSpec{ DockerRegistry: &v1alpha1.DockerRegistry{ From 03254f7427142a28a6815b463dfa52eb35cf80f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Kalke?= <56382792+MichalKalke@users.noreply.github.com> Date: Thu, 11 Dec 2025 14:16:23 +0100 Subject: [PATCH 13/13] Cleanup dockerRegistry status when buildless enabled (#2116) --- .../controllers/serverless_controller_test.go | 5 - .../operator/controllers/testhelper_test.go | 42 --- .../operator/internal/state/registry.go | 12 +- .../operator/internal/state/registry_test.go | 279 ------------------ 4 files changed, 9 insertions(+), 329 deletions(-) delete mode 100644 components/operator/internal/state/registry_test.go diff --git a/components/operator/controllers/serverless_controller_test.go b/components/operator/controllers/serverless_controller_test.go index 219aaf993..aa6c1c0a2 100644 --- a/components/operator/controllers/serverless_controller_test.go +++ b/components/operator/controllers/serverless_controller_test.go @@ -138,11 +138,6 @@ func shouldCreateServerless(h testHelper, serverlessName, serverlessDeploymentNa } func shouldPropagateSpecProperties(h testHelper, expected serverlessData) { - Eventually(h.createCheckRegistrySecretFunc(serverlessRegistrySecret, expected.registrySecretData)). - WithPolling(time.Second * 2). - WithTimeout(time.Second * 10). - Should(BeTrue()) - Eventually(h.createCheckOptionalDependenciesFunc(serverlessDeploymentName, expected)). WithPolling(time.Second * 2). WithTimeout(time.Second * 10). diff --git a/components/operator/controllers/testhelper_test.go b/components/operator/controllers/testhelper_test.go index 4fdb59474..ea5242a57 100644 --- a/components/operator/controllers/testhelper_test.go +++ b/components/operator/controllers/testhelper_test.go @@ -306,25 +306,6 @@ func (d *registrySecretData) toMap() map[string]string { return result } -func (h *testHelper) createCheckRegistrySecretFunc(serverlessRegistrySecret string, expected registrySecretData) func() (bool, error) { - return func() (bool, error) { - var configurationSecret corev1.Secret - - if ok, err := h.getKubernetesObjectFunc( - serverlessRegistrySecret, &configurationSecret); !ok || err != nil { - return ok, err - } - if err := secretContainsSameValues( - expected.toMap(), configurationSecret); err != nil { - return false, err - } - if err := secretContainsRequired(configurationSecret); err != nil { - return false, err - } - return true, nil - } -} - func (h *testHelper) createCheckOptionalDependenciesFunc(deploymentName string, expected serverlessData) func() (bool, error) { return func() (bool, error) { var deploy appsv1.Deployment @@ -369,26 +350,3 @@ func deploymentContainsEnv(deployment appsv1.Deployment, name, value string) err return fmt.Errorf("env %s does not exist", name) } - -func secretContainsRequired(configurationSecret corev1.Secret) error { - for _, k := range []string{"username", "password", "registryAddress", "serverAddress"} { - _, ok := configurationSecret.Data[k] - if !ok { - return fmt.Errorf("values not propagated (%s is required)", k) - } - } - return nil -} - -func secretContainsSameValues(expected map[string]string, configurationSecret corev1.Secret) error { - for k, expectedV := range expected { - v, okV := configurationSecret.Data[k] - if okV == false { - return fmt.Errorf("values not propagated (%s: nil != %s )", k, expectedV) - } - if expectedV != string(v) { - return fmt.Errorf("values not propagated (%s: %s != %s )", k, string(v), expectedV) - } - } - return nil -} diff --git a/components/operator/internal/state/registry.go b/components/operator/internal/state/registry.go index dd63625cc..786d15c65 100644 --- a/components/operator/internal/state/registry.go +++ b/components/operator/internal/state/registry.go @@ -37,6 +37,13 @@ func sFnRegistryConfiguration(ctx context.Context, r *reconciler, s *systemState func configureRegistry(ctx context.Context, r *reconciler, s *systemState) error { + //TODO: This is a temporary solution, delete it when legacy serverless is removed + if !isLegacyEnabled(s.instance.Annotations) { + setK3dRegistryConfig(s) + s.instance.Status.DockerRegistry = "" + return nil + } + switch { case isRegistrySecretName(s.instance.Spec.DockerRegistry): // case: use secret from secretName field @@ -131,9 +138,8 @@ func setExternalRegistryConfig(ctx context.Context, r *reconciler, s *systemStat } func setK3dRegistryConfig(s *systemState) { - if isLegacyEnabled(s.instance.Annotations) { - s.instance.Status.DockerRegistry = v1alpha1.DefaultServerAddress - } + s.instance.Status.DockerRegistry = v1alpha1.DefaultServerAddress + s.flagsBuilder.WithRegistryEnableInternal( getEnableInternal(s.instance.Spec.DockerRegistry), ).WithRegistryAddresses( diff --git a/components/operator/internal/state/registry_test.go b/components/operator/internal/state/registry_test.go deleted file mode 100644 index 5c4d0c50d..000000000 --- a/components/operator/internal/state/registry_test.go +++ /dev/null @@ -1,279 +0,0 @@ -package state - -import ( - "context" - "fmt" - "testing" - - "github.com/kyma-project/serverless/components/operator/api/v1alpha1" - "github.com/kyma-project/serverless/components/operator/internal/chart" - "github.com/kyma-project/serverless/components/operator/internal/warning" - "github.com/stretchr/testify/require" - "go.uber.org/zap" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/utils/ptr" - "sigs.k8s.io/controller-runtime/pkg/client/fake" -) - -func Test_sFnRegistryConfiguration(t *testing.T) { - t.Run("no internal registry status", func(t *testing.T) { - s := &systemState{ - instance: v1alpha1.Serverless{ - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](true), - }, - }, - }, - statusSnapshot: v1alpha1.ServerlessStatus{ - DockerRegistry: "", - }, - flagsBuilder: chart.NewFlagsBuilder(), - } - r := &reconciler{ - k8s: k8s{client: fake.NewClientBuilder().Build()}, - log: zap.NewNop().Sugar(), - } - expectedFlags := map[string]interface{}{ - "dockerRegistry": map[string]interface{}{ - "enableInternal": true, - }, - "global": map[string]interface{}{ - "registryNodePort": int64(32_137), - }, - } - - next, result, err := sFnRegistryConfiguration(context.Background(), r, s) - require.NoError(t, err) - require.Nil(t, result) - requireEqualFunc(t, sFnOptionalDependencies, next) - - flags, err := s.flagsBuilder.Build() - require.NoError(t, err) - - require.EqualValues(t, expectedFlags, flags) - require.Equal(t, "", s.instance.Status.DockerRegistry) - require.Equal(t, v1alpha1.StateProcessing, s.instance.Status.State) - }) - - t.Run("internal registry and update", func(t *testing.T) { - s := &systemState{ - instance: v1alpha1.Serverless{ - ObjectMeta: metav1.ObjectMeta{ - Annotations: map[string]string{ - buildlessModeAnnotation: buildlessModeDisabled, - }, - }, - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](true), - }, - }, - }, - statusSnapshot: v1alpha1.ServerlessStatus{ - DockerRegistry: "", - }, - flagsBuilder: chart.NewFlagsBuilder(), - } - r := &reconciler{ - k8s: k8s{client: fake.NewClientBuilder().Build()}, - log: zap.NewNop().Sugar(), - } - expectedFlags := map[string]interface{}{ - "dockerRegistry": map[string]interface{}{ - "enableInternal": true, - }, - "global": map[string]interface{}{ - "registryNodePort": int64(32_137), - }, - } - - next, result, err := sFnRegistryConfiguration(context.Background(), r, s) - require.NoError(t, err) - require.Nil(t, result) - requireEqualFunc(t, sFnOptionalDependencies, next) - - flags, err := s.flagsBuilder.Build() - require.NoError(t, err) - - require.EqualValues(t, expectedFlags, flags) - require.Equal(t, "internal", s.instance.Status.DockerRegistry) - require.Equal(t, v1alpha1.StateProcessing, s.instance.Status.State) - }) - - t.Run("external registry and go to next state", func(t *testing.T) { - secret := &corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: "test-secret", - Namespace: "kyma-test", - }, - Data: map[string][]byte{ - "username": []byte("username"), - "password": []byte("password"), - "registryAddress": []byte("registryAddress"), - "serverAddress": []byte("serverAddress"), - }, - } - s := &systemState{ - instance: v1alpha1.Serverless{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "kyma-test", - }, - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](false), - SecretName: ptr.To[string]("test-secret"), - }, - }, - }, - statusSnapshot: v1alpha1.ServerlessStatus{ - DockerRegistry: string(secret.Data["serverAddress"]), - }, - flagsBuilder: chart.NewFlagsBuilder(), - } - r := &reconciler{ - k8s: k8s{ - client: fake.NewClientBuilder(). - WithRuntimeObjects(secret). - Build(), - }, - } - expectedFlags := map[string]interface{}{ - "dockerRegistry": map[string]interface{}{ - "enableInternal": false, - "username": string(secret.Data["username"]), - "password": string(secret.Data["password"]), - "registryAddress": string(secret.Data["registryAddress"]), - "serverAddress": string(secret.Data["serverAddress"]), - }, - } - - next, result, err := sFnRegistryConfiguration(context.Background(), r, s) - require.NoError(t, err) - require.Nil(t, result) - requireEqualFunc(t, sFnOptionalDependencies, next) - - flags, err := s.flagsBuilder.Build() - require.NoError(t, err) - - require.Equal(t, expectedFlags, flags) - require.Equal(t, string(secret.Data["serverAddress"]), s.instance.Status.DockerRegistry) - require.Equal(t, v1alpha1.StateProcessing, s.instance.Status.State) - }) - - t.Run("k3d registry and update", func(t *testing.T) { - s := &systemState{ - instance: v1alpha1.Serverless{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "some-namespace", - Annotations: map[string]string{ - buildlessModeAnnotation: buildlessModeDisabled, - }, - }, - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](false), - }, - }, - }, - statusSnapshot: v1alpha1.ServerlessStatus{ - DockerRegistry: "", - }, - flagsBuilder: chart.NewFlagsBuilder(), - } - r := &reconciler{ - k8s: k8s{ - client: fake.NewClientBuilder().Build(), - }, - } - expectedFlags := map[string]interface{}{ - "dockerRegistry": map[string]interface{}{ - "enableInternal": false, - "registryAddress": v1alpha1.DefaultRegistryAddress, - "serverAddress": v1alpha1.DefaultRegistryAddress, - }, - } - - next, result, err := sFnRegistryConfiguration(context.Background(), r, s) - require.NoError(t, err) - require.Nil(t, result) - requireEqualFunc(t, sFnOptionalDependencies, next) - - flags, err := s.flagsBuilder.Build() - require.NoError(t, err) - - require.Equal(t, expectedFlags, flags) - require.Equal(t, v1alpha1.DefaultRegistryAddress, s.instance.Status.DockerRegistry) - }) - - t.Run("external registry secret not found error", func(t *testing.T) { - s := &systemState{ - instance: v1alpha1.Serverless{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "some-namespace", - }, - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](false), - SecretName: ptr.To[string]("test-secret-not-found"), - }, - }, - }, - } - r := &reconciler{ - k8s: k8s{ - client: fake.NewClientBuilder().Build(), - }, - } - - next, result, err := sFnRegistryConfiguration(context.Background(), r, s) - require.EqualError(t, err, "secrets \"test-secret-not-found\" not found") - require.Nil(t, result) - require.Nil(t, next) - - status := s.instance.Status - require.Equal(t, v1alpha1.StateError, status.State) - requireContainsCondition(t, status, - v1alpha1.ConditionTypeConfigured, - metav1.ConditionFalse, - v1alpha1.ConditionReasonConfigurationErr, - "secrets \"test-secret-not-found\" not found", - ) - }) -} - -func Test_addRegistryConfigurationWarnings(t *testing.T) { - - t.Run("enable internal is true and secret name exists", func(t *testing.T) { - s := &systemState{ - warningBuilder: warning.NewBuilder(), - instance: v1alpha1.Serverless{ - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](true), - SecretName: ptr.To[string]("test-secret"), - }, - }, - }, - } - addRegistryConfigurationWarnings(s) - require.Equal(t, fmt.Sprintf("Warning: %s", internalEnabledAndSecretNameUsedMessage), s.warningBuilder.Build()) - }) - - t.Run("do not build warning", func(t *testing.T) { - s := &systemState{ - warningBuilder: warning.NewBuilder(), - instance: v1alpha1.Serverless{ - Spec: v1alpha1.ServerlessSpec{ - DockerRegistry: &v1alpha1.DockerRegistry{ - EnableInternal: ptr.To[bool](false), - SecretName: ptr.To[string]("serverless-registry-config"), - }, - }, - }, - } - addRegistryConfigurationWarnings(s) - require.Equal(t, "", s.warningBuilder.Build()) - }) -}