diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 0dc97f9b4..aa1e19da9 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -36,102 +36,3 @@ updates:
prefix: "operator"
include: "scope"
- - package-ecosystem: "docker"
- directory: "/components/serverless/deploy/jobinit"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "jobinit"
- include: "scope"
- - package-ecosystem: "docker"
- directory: "/components/serverless/deploy/manager"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "manager"
- include: "scope"
-
- - package-ecosystem: "docker"
- directory: "/tests/gitserver"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "gitserver"
- include: "scope"
-
- - package-ecosystem: "pip"
- directory: "/components/runtimes/python/python39"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "pip-python39"
- include: "scope"
- groups:
- opentelemetry:
- patterns:
- - "opentelemetry-*"
- - package-ecosystem: "pip"
- directory: "/components/runtimes/python/python312"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "pip-python312"
- include: "scope"
- groups:
- opentelemetry:
- patterns:
- - "opentelemetry-*"
-
- - package-ecosystem: "npm"
- directory: "/components/runtimes/nodejs/nodejs18"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "npm-nodejs18"
- include: "scope"
- groups:
- opentelemetry:
- patterns:
- - "@opentelemetry/*"
- - package-ecosystem: "npm"
- directory: "/components/runtimes/nodejs/nodejs20"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "npm-nodejs20"
- include: "scope"
- groups:
- opentelemetry:
- patterns:
- - "@opentelemetry/*"
- - package-ecosystem: "npm"
- directory: "/tests/gitserver/repos/function"
- labels:
- - "area/dependency"
- - "kind/chore"
- schedule:
- interval: "weekly"
- commit-message:
- prefix: "npm-test"
- include: "scope"
diff --git a/.github/scripts/release.sh b/.github/scripts/release.sh
index 6bc4c4bce..bce252486 100755
--- a/.github/scripts/release.sh
+++ b/.github/scripts/release.sh
@@ -34,8 +34,8 @@ uploadFile() {
echo "IMG: ${IMG}"
IMG=${IMG} make -C components/operator/ render-manifest
-echo "Generated serverless-operator.yaml:"
-cat serverless-operator.yaml
+echo "Generated dockerregistry-operator.yaml:"
+cat dockerregistry-operator.yaml
echo "Fetching releases"
CURL_RESPONSE=$(curl -w "%{http_code}" -sL \
@@ -62,9 +62,9 @@ fi
echo "Updating github release with assets"
UPLOAD_URL="https://uploads.github.com/repos/kyma-project/serverless/releases/${RELEASE_ID}/assets"
-uploadFile "serverless-operator.yaml" "${UPLOAD_URL}?name=serverless-operator.yaml"
-uploadFile "config/samples/default-serverless-cr.yaml" "${UPLOAD_URL}?name=default-serverless-cr.yaml"
-uploadFile "config/samples/default-serverless-cr-k3d.yaml" "${UPLOAD_URL}?name=default-serverless-cr-k3d.yaml"
+uploadFile "dockerregistry-operator.yaml" "${UPLOAD_URL}?name=dockerregistry-operator.yaml"
+uploadFile "config/samples/default-dockerregistry-cr.yaml" "${UPLOAD_URL}?name=default-dockerregistry-cr.yaml"
+uploadFile "config/samples/default-dockerregistry-cr-k3d.yaml" "${UPLOAD_URL}?name=default-dockerregistry-cr-k3d.yaml"
diff --git a/.github/scripts/upgrade-sec-scanners-config.sh b/.github/scripts/upgrade-sec-scanners-config.sh
index b8c3975c4..a9b2fdecf 100755
--- a/.github/scripts/upgrade-sec-scanners-config.sh
+++ b/.github/scripts/upgrade-sec-scanners-config.sh
@@ -8,8 +8,8 @@ yq eval-all --inplace '
| .global.containerRegistry.path as $registryPath
| (
{
- "serverless_operator" : {
- "name" : "serverless-operator",
+ "dockerregistry_operator" : {
+ "name" : "dockerregistry-operator",
"directory" : "prod",
"version" : env(IMG_VERSION)
}
@@ -19,4 +19,4 @@ yq eval-all --inplace '
| $registryPath + "/" + .directory + "/" + .name + ":" + .version
]
| select(fileIndex == 0)
- ' sec-scanners-config.yaml config/serverless/values.yaml
\ No newline at end of file
+ ' sec-scanners-config.yaml config/docker-registry/values.yaml
\ No newline at end of file
diff --git a/.github/workflows/create-release.yaml b/.github/workflows/create-release.yaml
index 7c1a8cf2d..9c00368c4 100644
--- a/.github/workflows/create-release.yaml
+++ b/.github/workflows/create-release.yaml
@@ -41,14 +41,6 @@ jobs:
token: ${{ secrets.BOT_TOKEN }}
fetch-depth: 0
- - name: Bump values.yaml
- run: |
- ./hack/replace_serverless_chart_images.sh all .
- env:
- IMG_DIRECTORY: "prod"
- IMG_VERSION: ${{ github.event.inputs.name }}
- PROJECT_ROOT: "."
-
- name: Bump sec-scanners-config.yaml based on values.yaml
run: ./.github/scripts/upgrade-sec-scanners-config.sh
env:
diff --git a/.github/workflows/images-verify.yaml b/.github/workflows/images-verify.yaml
index c59efefe1..5bd1a746a 100644
--- a/.github/workflows/images-verify.yaml
+++ b/.github/workflows/images-verify.yaml
@@ -6,7 +6,7 @@ on:
- main
paths:
- sec-scanners-config.yaml
- - config/serverless/values.yaml
+ - config/docker-registry/values.yaml
jobs:
# check if developer doesn't change `main` images in the values.yaml and sec-scanners-config.yaml files
@@ -24,7 +24,7 @@ jobs:
echo SSC_MAIN_IMAGES=$(yq '.protecode[] | select(contains(":main")) | sub(":.*", "")' sec-scanners-config.yaml) >> $GITHUB_ENV
# export values. images with the main tag as github env
- echo VALUES_MAIN_IMAGES=$(yq '.global.images[] | select(.version == "main") | .name' config/serverless/values.yaml) >> $GITHUB_ENV
+ echo VALUES_MAIN_IMAGES=$(yq '.global.images[] | select(.version == "main") | .name' config/docker-registry/values.yaml) >> $GITHUB_ENV
- name: Checkout to context
uses: actions/checkout@v4
@@ -38,7 +38,7 @@ jobs:
- name: Verify values.yaml images
run: |
- PR_NOT_MAIN_IMAGES=$(yq '.global.images[] | select(.version != "main") | .name' config/serverless/values.yaml) \
+ PR_NOT_MAIN_IMAGES=$(yq '.global.images[] | select(.version != "main") | .name' config/docker-registry/values.yaml) \
.github/scripts/verify-image-changes.sh
env:
MAIN_IMAGES: ${{ env.VALUES_MAIN_IMAGES }}
diff --git a/.github/workflows/serverless-verify.yaml b/.github/workflows/serverless-verify.yaml
index 49765ee93..c8b1b35f7 100644
--- a/.github/workflows/serverless-verify.yaml
+++ b/.github/workflows/serverless-verify.yaml
@@ -15,28 +15,6 @@ on:
- converted_to_draft
jobs:
- #pre-serverless-controller-lint
- lint:
- if: github.event_name == 'pull_request'
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: ./.github/actions/setup-libgit2
- - uses: golangci/golangci-lint-action@v3
- with:
- version: latest
- working-directory: 'components/serverless'
-
- #pre-serverless-controller-unit-test
- unit-test:
- if: github.event_name == 'pull_request'
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: ./.github/actions/setup-libgit2
- - name: run test
- run: make -C components/serverless test
-
integration-test:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
diff --git a/.gitignore b/.gitignore
index 6ae35bd3b..0ae446cf7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,5 +44,7 @@ manifests/serverless/rendered.yaml
serverless.yaml
moduletemplate-latest.yaml
module-config.yaml
+dockerregistry-operator.yaml
+dockerregistry.yaml
examples/python-text2img/resources/secrets/deepai.env
\ No newline at end of file
diff --git a/CODEOWNERS b/CODEOWNERS
index b2757882e..4c54ff453 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,4 +1,4 @@
-# These are the default owners for the whole content of the `serverless-manager` repository. The default owners are automatically added as reviewers when you open a pull request unless different owners are specified in the file.
+# These are the default owners for the whole content of the `dockerregistry` repository. The default owners are automatically added as reviewers when you open a pull request unless different owners are specified in the file.
* @m00g3n @pPrecel @dbadura @kwiatekus @cortey @anoipm @MichalKalke
# All files and subdirectories in /docs
diff --git a/Makefile b/Makefile
index dab69a58a..f80b772ad 100644
--- a/Makefile
+++ b/Makefile
@@ -4,28 +4,28 @@ include ${PROJECT_ROOT}/hack/help.mk
include ${PROJECT_ROOT}/hack/k3d.mk
##@ Installation
-.PHONY: install-serverless-main
-install-serverless-main: ## Install serverless with operator using default serverless cr
- make -C ${OPERATOR_ROOT} deploy-main apply-default-serverless-cr check-serverless-installation
+.PHONY: install-dockerregistry-main
+install-dockerregistry-main: ## Install dockerregistry with operator using default dockerregistry cr
+ make -C ${OPERATOR_ROOT} deploy-main apply-default-dockerregistry-cr check-dockerregistry-installation
-.PHONY: install-serverless-custom-operator
-install-serverless-custom-operator: ## Install serverless with operator from IMG env using default serverless cr
+.PHONY: install-dockerregistry-custom-operator
+install-dockerregistry-custom-operator: ## Install dockerregistry with operator from IMG env using default dockerregistry cr
$(call check-var,IMG)
- make -C ${OPERATOR_ROOT} deploy apply-default-serverless-cr check-serverless-installation
+ make -C ${OPERATOR_ROOT} deploy apply-default-dockerregistry-cr check-dockerregistry-installation
-.PHONY: install-serverless-latest-release
-install-serverless-latest-release: ## Install serverless from latest release
+.PHONY: install-dockerregistry-latest-release
+install-dockerregistry-latest-release: ## Install dockerregistry from latest release
kubectl create namespace kyma-system || true
- kubectl apply -f https://github.com/kyma-project/serverless-manager/releases/latest/download/serverless-operator.yaml
- kubectl apply -f https://github.com/kyma-project/serverless-manager/releases/latest/download/default-serverless-cr.yaml -n kyma-system
- make -C ${OPERATOR_ROOT} check-serverless-installation
+ kubectl apply -f https://github.com/kyma-project/serverless-manager/releases/latest/download/dockerregistry-operator.yaml
+ kubectl apply -f https://github.com/kyma-project/serverless-manager/releases/latest/download/default-dockerregistry-cr.yaml -n kyma-system
+ make -C ${OPERATOR_ROOT} check-dockerregistry-installation
-.PHONY: remove-serverless
-remove-serverless: ## Remove serverless-cr and serverless operator
- make -C ${OPERATOR_ROOT} remove-serverless undeploy
+.PHONY: remove-dockerregistry
+remove-dockerregistry: ## Remove dockerregistry-cr and dockerregistry operator
+ make -C ${OPERATOR_ROOT} remove-dockerregistry undeploy
.PHONY: run
-run: create-k3d install-serverless-main ## Create k3d cluster and install serverless from main
+run: create-k3d install-dockerregistry-main ## Create k3d cluster and install dockerregistry from main
check-var = $(if $(strip $($1)),,$(error "$1" is not defined))
diff --git a/README.md b/README.md
index 08003a5f7..753f512b0 100644
--- a/README.md
+++ b/README.md
@@ -64,13 +64,13 @@ kubectl apply -f https://github.com/kyma-project/serverless-manager/releases/lat
- Create a Serverless instance.
```bash
- kubectl apply -f config/samples/default-serverless-cr.yaml
+ kubectl apply -f config/samples/default-dockerregistry-cr.yaml
```
- Delete a Serverless instance.
```bash
- kubectl delete -f config/samples/default-serverless-cr.yaml
+ kubectl delete -f config/samples/default-dockerregistry-cr.yaml
```
- Use external registry.
diff --git a/components/operator/.dockerignore b/components/operator/.dockerignore
index a1cc811d8..9a0486344 100644
--- a/components/operator/.dockerignore
+++ b/components/operator/.dockerignore
@@ -7,4 +7,4 @@
!components/operator/internal
!go.sum
!go.mod
-!config/serverless
+!config/docker-registry
diff --git a/components/operator/Dockerfile b/components/operator/Dockerfile
index 8f00be5b2..e1ee7c5a0 100644
--- a/components/operator/Dockerfile
+++ b/components/operator/Dockerfile
@@ -1,5 +1,5 @@
#
-# This Dockerfile is used to build serverless-operator image on every pre- and post-submit job
+# This Dockerfile is used to build dockerregistry-operator image on every pre- and post-submit job
#
@@ -23,11 +23,12 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o operator ./components/o
# Replace main images in values.yaml
-# Bumping serverless images in the values.yaml - used for building "local" and "dev" images
+# Bumping dockerregistry images in the values.yaml - used for building "local" and "dev" images
FROM alpine:3.19.1 as replacer
WORKDIR /workspace
+# TODO: remove variable PURPOSE
ARG PURPOSE
ARG IMG_DIRECTORY
ARG IMG_VERSION
@@ -39,13 +40,9 @@ ENV PROJECT_ROOT="."
RUN apk update && apk add bash yq
COPY components/operator/hack components/operator/hack
-COPY config/serverless config/serverless
+COPY config/docker-registry config/docker-registry
COPY hack/ hack/
-RUN if [[ "dev" = "$PURPOSE" ]] ; then ./hack/replace_serverless_chart_images.sh all ; fi
-RUN if [[ "local" = "$PURPOSE" ]] ; then ./hack/replace_serverless_chart_images.sh main-only ; fi
-# do nothing (keep unchanged versions) for "release"
-
# Use distroless as minimal base image to package the operator binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
@@ -53,7 +50,7 @@ FROM gcr.io/distroless/static:nonroot
WORKDIR /
COPY --chown=65532:65532 --from=builder /workspace/operator .
-COPY --chown=65532:65532 --from=replacer /workspace/config/serverless /module-chart
+COPY --chown=65532:65532 --from=replacer /workspace/config/docker-registry /module-chart
USER 65532:65532
ENTRYPOINT ["/operator"]
diff --git a/components/operator/Makefile b/components/operator/Makefile
index b64d3d147..10c134f7c 100644
--- a/components/operator/Makefile
+++ b/components/operator/Makefile
@@ -62,19 +62,19 @@ docker-push: ## Push docker image with the operator.
##@ Deployment
IGNORE_NOT_FOUND = false
-OPERATOR_NAME = serverless-operator
+OPERATOR_NAME = dockerregistry-operator
.PHONY: build-image-operator
-build-image-operator: ## Build serverless operator from local sources on k3d
+build-image-operator: ## Build dockerregistry operator from local sources on k3d
docker build -t $(OPERATOR_NAME) -f Dockerfile $(PROJECT_ROOT)
.PHONY: install-operator-k3d
-install-operator-k3d: build-image-operator ## Build and install serverless operator from local sources on k3d
+install-operator-k3d: build-image-operator ## Build and install dockerregistry operator from local sources on k3d
$(eval HASH_TAG=$(shell docker images $(OPERATOR_NAME):latest --quiet))
docker tag $(OPERATOR_NAME) $(OPERATOR_NAME):$(HASH_TAG)
k3d image import $(OPERATOR_NAME):$(HASH_TAG) -c kyma
- kubectl set image deployment serverless-operator -n kyma-system manager=$(OPERATOR_NAME):$(HASH_TAG)
+ kubectl set image deployment dockerregistry-operator -n kyma-system manager=$(OPERATOR_NAME):$(HASH_TAG)
.PHONY: install
@@ -107,38 +107,35 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi
$(KUSTOMIZE) build $(CONFIG_OPERATOR) | kubectl delete --ignore-not-found=$(IGNORE_NOT_FOUND) -f -
.PHONY: render-manifest
-render-manifest: manifests kustomize ## Render serverless-operator.yaml manifest with image from IMG env.
+render-manifest: manifests kustomize ## Render dockerregistry-operator.yaml manifest with image from IMG env.
cd $(CONFIG_OPERATOR)/deployment && $(KUSTOMIZE) edit set image controller=${IMG}
- $(KUSTOMIZE) build $(CONFIG_OPERATOR) > $(PROJECT_ROOT)/serverless-operator.yaml
+ $(KUSTOMIZE) build $(CONFIG_OPERATOR) > $(PROJECT_ROOT)/dockerregistry-operator.yaml
-.PHONY: apply-default-serverless-cr
-apply-default-serverless-cr: ## Apply the k3d serverless CR.
+.PHONY: apply-default-dockerregistry-cr
+apply-default-dockerregistry-cr: ## Apply the k3d dockerregistry CR.
kubectl apply \
- -f ${PROJECT_ROOT}/config/samples/default-serverless-cr.yaml
+ -f ${PROJECT_ROOT}/config/samples/default-dockerregistry-cr.yaml
-.PHONY: remove-serverless
-remove-serverless: ## Remove Serverless CR
- kubectl delete serverless -n kyma-system default --timeout 2m || (kubectl get serverless -n kyma-system -oyaml && false)
+.PHONY: remove-dockerregistry
+remove-dockerregistry: ## Remove Dockerregistry CR
+ kubectl delete dockerregistry -n kyma-system default --timeout 2m || (kubectl get dockerregistry -n kyma-system -oyaml && false)
-.PHONY: check-serverless-installation
-check-serverless-installation: ## Wait for Serverless CR to be in Ready state.
+.PHONY: check-dockerregistry-installation
+check-dockerregistry-installation: ## Wait for Dockerregistry CR to be in Ready state.
# wait some time to make sure operator starts the reconciliation first
sleep 10
- ./hack/verify_serverless_status.sh || \
- (make print-serverless-details && false)
+ ./hack/verify_dockerregistry_status.sh || \
+ (make print-dockerregistry-details && false)
- kubectl wait --for condition=Available -n kyma-system deployment serverless-operator --timeout=60s || \
- (make print-serverless-details && false)
+ kubectl wait --for condition=Available -n kyma-system deployment dockerregistry-operator --timeout=60s || \
+ (make print-dockerregistry-details && false)
- kubectl wait --for condition=Available -n kyma-system deployment serverless-ctrl-mngr --timeout=60s || \
- (make print-serverless-details && false)
-
-.PHONY: print-serverless-details
-print-serverless-details: ## Print all pods, deploys and serverless CRs in the kyma-system namespace.
- kubectl get serverless -n kyma-system -oyaml
+.PHONY: print-dockerregistry-details
+print-dockerregistry-details: ## Print all pods, deploys and dockerregistry CRs in the kyma-system namespace.
+ kubectl get dockerregistry -n kyma-system -oyaml
kubectl get deploy -n kyma-system -oyaml
kubectl get pods -n kyma-system -oyaml
diff --git a/components/operator/api/v1alpha1/dockerregistry_types.go b/components/operator/api/v1alpha1/dockerregistry_types.go
new file mode 100644
index 000000000..c716823f9
--- /dev/null
+++ b/components/operator/api/v1alpha1/dockerregistry_types.go
@@ -0,0 +1,160 @@
+/*
+Copyright 2022.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+ "k8s.io/apimachinery/pkg/api/meta"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type Endpoint struct {
+ Endpoint string `json:"endpoint"`
+}
+
+// DockerRegistrySpec defines the desired state of DockerRegistry
+type DockerRegistrySpec struct {
+ // Sets the timeout for the Function health check. The default value in seconds is `10`
+ HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
+}
+
+type State string
+
+type Served string
+
+type ConditionReason string
+
+type ConditionType string
+
+const (
+ StateReady State = "Ready"
+ StateProcessing State = "Processing"
+ StateWarning State = "Warning"
+ StateError State = "Error"
+ StateDeleting State = "Deleting"
+
+ ServedTrue Served = "True"
+ ServedFalse Served = "False"
+
+ // installation and deletion details
+ ConditionTypeInstalled = ConditionType("Installed")
+
+ // prerequisites and soft dependencies
+ ConditionTypeConfigured = ConditionType("Configured")
+
+ // deletion
+ ConditionTypeDeleted = ConditionType("Deleted")
+
+ ConditionReasonConfiguration = ConditionReason("Configuration")
+ ConditionReasonConfigurationErr = ConditionReason("ConfigurationErr")
+ ConditionReasonConfigured = ConditionReason("Configured")
+ ConditionReasonInstallation = ConditionReason("Installation")
+ ConditionReasonInstallationErr = ConditionReason("InstallationErr")
+ ConditionReasonInstalled = ConditionReason("Installed")
+ ConditionReasonDuplicated = ConditionReason("Duplicated")
+ ConditionReasonDeletion = ConditionReason("Deletion")
+ ConditionReasonDeletionErr = ConditionReason("DeletionErr")
+ ConditionReasonDeleted = ConditionReason("Deleted")
+
+ Finalizer = "dockerregistry-operator.kyma-project.io/deletion-hook"
+)
+
+type DockerRegistryStatus struct {
+ HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
+
+ // State signifies current state of DockerRegistry.
+ // Value can be one of ("Ready", "Processing", "Error", "Deleting").
+ // +kubebuilder:validation:Required
+ // +kubebuilder:validation:Enum=Processing;Deleting;Ready;Error;Warning
+ State State `json:"state,omitempty"`
+
+ // Served signifies that current DockerRegistry is managed.
+ // Value can be one of ("True", "False").
+ // +kubebuilder:validation:Enum=True;False
+ Served Served `json:"served"`
+
+ // Conditions associated with CustomStatus.
+ Conditions []metav1.Condition `json:"conditions,omitempty"`
+}
+
+// +k8s:deepcopy-gen=true
+
+//+kubebuilder:object:root=true
+//+kubebuilder:subresource:status
+//+kubebuilder:printcolumn:name="Configured",type="string",JSONPath=".status.conditions[?(@.type=='Configured')].status"
+//+kubebuilder:printcolumn:name="Installed",type="string",JSONPath=".status.conditions[?(@.type=='Installed')].status"
+//+kubebuilder:printcolumn:name="generation",type="integer",JSONPath=".metadata.generation"
+//+kubebuilder:printcolumn:name="age",type="date",JSONPath=".metadata.creationTimestamp"
+//+kubebuilder:printcolumn:name="state",type="string",JSONPath=".status.state"
+
+// DockerRegistry is the Schema for the dockerregistry API
+type DockerRegistry struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ObjectMeta `json:"metadata,omitempty"`
+
+ Spec DockerRegistrySpec `json:"spec,omitempty"`
+ Status DockerRegistryStatus `json:"status,omitempty"`
+}
+
+func (s *DockerRegistry) UpdateConditionFalse(c ConditionType, r ConditionReason, err error) {
+ condition := metav1.Condition{
+ Type: string(c),
+ Status: "False",
+ LastTransitionTime: metav1.Now(),
+ Reason: string(r),
+ Message: err.Error(),
+ }
+ meta.SetStatusCondition(&s.Status.Conditions, condition)
+}
+
+func (s *DockerRegistry) UpdateConditionUnknown(c ConditionType, r ConditionReason, msg string) {
+ condition := metav1.Condition{
+ Type: string(c),
+ Status: "Unknown",
+ LastTransitionTime: metav1.Now(),
+ Reason: string(r),
+ Message: msg,
+ }
+ meta.SetStatusCondition(&s.Status.Conditions, condition)
+}
+
+func (s *DockerRegistry) UpdateConditionTrue(c ConditionType, r ConditionReason, msg string) {
+ condition := metav1.Condition{
+ Type: string(c),
+ Status: "True",
+ LastTransitionTime: metav1.Now(),
+ Reason: string(r),
+ Message: msg,
+ }
+ meta.SetStatusCondition(&s.Status.Conditions, condition)
+}
+
+func (s *DockerRegistry) IsServedEmpty() bool {
+ return s.Status.Served == ""
+}
+
+//+kubebuilder:object:root=true
+
+// DockerRegistryList contains a list of DockerRegistry
+type DockerRegistryList struct {
+ metav1.TypeMeta `json:",inline"`
+ metav1.ListMeta `json:"metadata,omitempty"`
+ Items []DockerRegistry `json:"items"`
+}
+
+func init() {
+ SchemeBuilder.Register(&DockerRegistry{}, &DockerRegistryList{})
+}
diff --git a/components/operator/api/v1alpha1/groupversion_info.go b/components/operator/api/v1alpha1/groupversion_info.go
index 1c523975b..9a7c8cb23 100644
--- a/components/operator/api/v1alpha1/groupversion_info.go
+++ b/components/operator/api/v1alpha1/groupversion_info.go
@@ -25,14 +25,13 @@ import (
)
const (
- ServerlessGroup = "operator.kyma-project.io"
- ServerlessVersion = "v1alpha1"
- ServerlessKind = "Serverless"
+ DockerregistryGroup = "operator.kyma-project.io"
+ DockerregistryVersion = "v1alpha1"
)
var (
// GroupVersion is group version used to register these objects
- GroupVersion = schema.GroupVersion{Group: ServerlessGroup, Version: ServerlessVersion}
+ GroupVersion = schema.GroupVersion{Group: DockerregistryGroup, Version: DockerregistryVersion}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
diff --git a/components/operator/api/v1alpha1/serverless_helpers.go b/components/operator/api/v1alpha1/helpers.go
similarity index 77%
rename from components/operator/api/v1alpha1/serverless_helpers.go
rename to components/operator/api/v1alpha1/helpers.go
index ce0bd9358..aa792178b 100644
--- a/components/operator/api/v1alpha1/serverless_helpers.go
+++ b/components/operator/api/v1alpha1/helpers.go
@@ -5,17 +5,17 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-func (s *Serverless) IsInState(state State) bool {
+func (s *DockerRegistry) IsInState(state State) bool {
return s.Status.State == state
}
-func (s *Serverless) IsCondition(conditionType ConditionType) bool {
+func (s *DockerRegistry) IsCondition(conditionType ConditionType) bool {
return meta.FindStatusCondition(
s.Status.Conditions, string(conditionType),
) != nil
}
-func (s *Serverless) IsConditionTrue(conditionType ConditionType) bool {
+func (s *DockerRegistry) IsConditionTrue(conditionType ConditionType) bool {
condition := meta.FindStatusCondition(s.Status.Conditions, string(conditionType))
return condition != nil && condition.Status == metav1.ConditionTrue
}
diff --git a/components/operator/api/v1alpha1/serverless_types.go b/components/operator/api/v1alpha1/serverless_types.go
deleted file mode 100644
index 58f6b65a3..000000000
--- a/components/operator/api/v1alpha1/serverless_types.go
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
-Copyright 2022.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1alpha1
-
-import (
- "k8s.io/apimachinery/pkg/api/meta"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-type DockerRegistry struct {
- // When set to true, the internal Docker registry is enabled
- EnableInternal *bool `json:"enableInternal,omitempty"`
- // Secret used for configuration of the Docker registry
- SecretName *string `json:"secretName,omitempty"`
-}
-
-type Endpoint struct {
- Endpoint string `json:"endpoint"`
-}
-
-// ServerlessSpec defines the desired state of Serverless
-type ServerlessSpec struct {
- // Used Tracing endpoint
- Tracing *Endpoint `json:"tracing,omitempty"`
- // Used Eventing endpoint
- Eventing *Endpoint `json:"eventing,omitempty"`
- DockerRegistry *DockerRegistry `json:"dockerRegistry,omitempty"`
- // Sets a custom CPU utilization threshold for scaling Function Pods
- TargetCPUUtilizationPercentage string `json:"targetCPUUtilizationPercentage,omitempty"`
- // Sets the requeue duration for Function. By default, the Function associated with the default configuration is requeued every 5 minutes
- FunctionRequeueDuration string `json:"functionRequeueDuration,omitempty"`
- // Specifies the arguments passed to the Function build executor
- FunctionBuildExecutorArgs string `json:"functionBuildExecutorArgs,omitempty"`
- // A number of simultaneous jobs that can run at the same time. The default value is `5`
- FunctionBuildMaxSimultaneousJobs string `json:"functionBuildMaxSimultaneousJobs,omitempty"`
- // Sets the timeout for the Function health check. The default value in seconds is `10`
- HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
- // Used to configure the maximum size limit for the request body of a Function. The default value is `1` megabyte
- FunctionRequestBodyLimitMb string `json:"functionRequestBodyLimitMb,omitempty"`
- // Sets the maximum execution time limit for a Function. By default, the value is `180` seconds
- FunctionTimeoutSec string `json:"functionTimeoutSec,omitempty"`
- // Configures the default build Job preset to be used
- DefaultBuildJobPreset string `json:"defaultBuildJobPreset,omitempty"`
- // Configures the default runtime Pod preset to be used
- DefaultRuntimePodPreset string `json:"defaultRuntimePodPreset,omitempty"`
-}
-
-type State string
-
-type Served string
-
-type ConditionReason string
-
-type ConditionType string
-
-const (
- StateReady State = "Ready"
- StateProcessing State = "Processing"
- StateWarning State = "Warning"
- StateError State = "Error"
- StateDeleting State = "Deleting"
-
- ServedTrue Served = "True"
- ServedFalse Served = "False"
-
- // installation and deletion details
- ConditionTypeInstalled = ConditionType("Installed")
-
- // prerequisites and soft dependencies
- ConditionTypeConfigured = ConditionType("Configured")
-
- // 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")
-
- Finalizer = "serverless-operator.kyma-project.io/deletion-hook"
-)
-
-type ServerlessStatus struct {
- // Used the Eventing endpoint and the Tracing endpoint.
- EventingEndpoint string `json:"eventingEndpoint,omitempty"`
- TracingEndpoint string `json:"tracingEndpoint,omitempty"`
-
- CPUUtilizationPercentage string `json:"targetCPUUtilizationPercentage,omitempty"`
- RequeueDuration string `json:"functionRequeueDuration,omitempty"`
- BuildExecutorArgs string `json:"functionBuildExecutorArgs,omitempty"`
- BuildMaxSimultaneousJobs string `json:"functionBuildMaxSimultaneousJobs,omitempty"`
- HealthzLivenessTimeout string `json:"healthzLivenessTimeout,omitempty"`
- RequestBodyLimitMb string `json:"functionRequestBodyLimitMb,omitempty"`
- TimeoutSec string `json:"functionTimeoutSec,omitempty"`
- DefaultBuildJobPreset string `json:"defaultBuildJobPreset,omitempty"`
- DefaultRuntimePodPreset string `json:"defaultRuntimePodPreset,omitempty"`
-
- // Used registry configuration.
- // Contains registry URL or "internal"
- DockerRegistry string `json:"dockerRegistry,omitempty"`
-
- // State signifies current state of Serverless.
- // Value can be one of ("Ready", "Processing", "Error", "Deleting").
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:Enum=Processing;Deleting;Ready;Error;Warning
- State State `json:"state,omitempty"`
-
- // Served signifies that current Serverless is managed.
- // Value can be one of ("True", "False").
- // +kubebuilder:validation:Enum=True;False
- Served Served `json:"served"`
-
- // Conditions associated with CustomStatus.
- Conditions []metav1.Condition `json:"conditions,omitempty"`
-}
-
-// +k8s:deepcopy-gen=true
-
-//+kubebuilder:object:root=true
-//+kubebuilder:subresource:status
-//+kubebuilder:printcolumn:name="Configured",type="string",JSONPath=".status.conditions[?(@.type=='Configured')].status"
-//+kubebuilder:printcolumn:name="Installed",type="string",JSONPath=".status.conditions[?(@.type=='Installed')].status"
-//+kubebuilder:printcolumn:name="generation",type="integer",JSONPath=".metadata.generation"
-//+kubebuilder:printcolumn:name="age",type="date",JSONPath=".metadata.creationTimestamp"
-//+kubebuilder:printcolumn:name="state",type="string",JSONPath=".status.state"
-
-// Serverless is the Schema for the serverlesses API
-type Serverless struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ObjectMeta `json:"metadata,omitempty"`
-
- Spec ServerlessSpec `json:"spec,omitempty"`
- Status ServerlessStatus `json:"status,omitempty"`
-}
-
-func (s *Serverless) UpdateConditionFalse(c ConditionType, r ConditionReason, err error) {
- condition := metav1.Condition{
- Type: string(c),
- Status: "False",
- LastTransitionTime: metav1.Now(),
- Reason: string(r),
- Message: err.Error(),
- }
- meta.SetStatusCondition(&s.Status.Conditions, condition)
-}
-
-func (s *Serverless) UpdateConditionUnknown(c ConditionType, r ConditionReason, msg string) {
- condition := metav1.Condition{
- Type: string(c),
- Status: "Unknown",
- LastTransitionTime: metav1.Now(),
- Reason: string(r),
- Message: msg,
- }
- meta.SetStatusCondition(&s.Status.Conditions, condition)
-}
-
-func (s *Serverless) UpdateConditionTrue(c ConditionType, r ConditionReason, msg string) {
- condition := metav1.Condition{
- Type: string(c),
- Status: "True",
- LastTransitionTime: metav1.Now(),
- Reason: string(r),
- Message: msg,
- }
- meta.SetStatusCondition(&s.Status.Conditions, condition)
-}
-
-func (s *Serverless) IsServedEmpty() bool {
- return s.Status.Served == ""
-}
-
-//+kubebuilder:object:root=true
-
-// ServerlessList contains a list of Serverless
-type ServerlessList struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ListMeta `json:"metadata,omitempty"`
- Items []Serverless `json:"items"`
-}
-
-func init() {
- SchemeBuilder.Register(&Serverless{}, &ServerlessList{})
-}
diff --git a/components/operator/api/v1alpha1/zz_generated.deepcopy.go b/components/operator/api/v1alpha1/zz_generated.deepcopy.go
index dee358ae1..74d48ab77 100644
--- a/components/operator/api/v1alpha1/zz_generated.deepcopy.go
+++ b/components/operator/api/v1alpha1/zz_generated.deepcopy.go
@@ -27,65 +27,25 @@ import (
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DockerRegistry) DeepCopyInto(out *DockerRegistry) {
- *out = *in
- if in.EnableInternal != nil {
- in, out := &in.EnableInternal, &out.EnableInternal
- *out = new(bool)
- **out = **in
- }
- if in.SecretName != nil {
- in, out := &in.SecretName, &out.SecretName
- *out = new(string)
- **out = **in
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerRegistry.
-func (in *DockerRegistry) DeepCopy() *DockerRegistry {
- if in == nil {
- return nil
- }
- out := new(DockerRegistry)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Endpoint) DeepCopyInto(out *Endpoint) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint.
-func (in *Endpoint) DeepCopy() *Endpoint {
- if in == nil {
- return nil
- }
- out := new(Endpoint)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Serverless) DeepCopyInto(out *Serverless) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
- in.Spec.DeepCopyInto(&out.Spec)
+ out.Spec = in.Spec
in.Status.DeepCopyInto(&out.Status)
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Serverless.
-func (in *Serverless) DeepCopy() *Serverless {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerRegistry.
+func (in *DockerRegistry) DeepCopy() *DockerRegistry {
if in == nil {
return nil
}
- out := new(Serverless)
+ out := new(DockerRegistry)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *Serverless) DeepCopyObject() runtime.Object {
+func (in *DockerRegistry) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
@@ -93,31 +53,31 @@ func (in *Serverless) DeepCopyObject() runtime.Object {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ServerlessList) DeepCopyInto(out *ServerlessList) {
+func (in *DockerRegistryList) DeepCopyInto(out *DockerRegistryList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
- *out = make([]Serverless, len(*in))
+ *out = make([]DockerRegistry, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerlessList.
-func (in *ServerlessList) DeepCopy() *ServerlessList {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerRegistryList.
+func (in *DockerRegistryList) DeepCopy() *DockerRegistryList {
if in == nil {
return nil
}
- out := new(ServerlessList)
+ out := new(DockerRegistryList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *ServerlessList) DeepCopyObject() runtime.Object {
+func (in *DockerRegistryList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
@@ -125,37 +85,22 @@ func (in *ServerlessList) DeepCopyObject() runtime.Object {
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ServerlessSpec) DeepCopyInto(out *ServerlessSpec) {
+func (in *DockerRegistrySpec) DeepCopyInto(out *DockerRegistrySpec) {
*out = *in
- if in.Tracing != nil {
- in, out := &in.Tracing, &out.Tracing
- *out = new(Endpoint)
- **out = **in
- }
- if in.Eventing != nil {
- in, out := &in.Eventing, &out.Eventing
- *out = new(Endpoint)
- **out = **in
- }
- if in.DockerRegistry != nil {
- in, out := &in.DockerRegistry, &out.DockerRegistry
- *out = new(DockerRegistry)
- (*in).DeepCopyInto(*out)
- }
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerlessSpec.
-func (in *ServerlessSpec) DeepCopy() *ServerlessSpec {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerRegistrySpec.
+func (in *DockerRegistrySpec) DeepCopy() *DockerRegistrySpec {
if in == nil {
return nil
}
- out := new(ServerlessSpec)
+ out := new(DockerRegistrySpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ServerlessStatus) DeepCopyInto(out *ServerlessStatus) {
+func (in *DockerRegistryStatus) DeepCopyInto(out *DockerRegistryStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
@@ -166,12 +111,27 @@ func (in *ServerlessStatus) DeepCopyInto(out *ServerlessStatus) {
}
}
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServerlessStatus.
-func (in *ServerlessStatus) DeepCopy() *ServerlessStatus {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerRegistryStatus.
+func (in *DockerRegistryStatus) DeepCopy() *DockerRegistryStatus {
+ if in == nil {
+ return nil
+ }
+ out := new(DockerRegistryStatus)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Endpoint) DeepCopyInto(out *Endpoint) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Endpoint.
+func (in *Endpoint) DeepCopy() *Endpoint {
if in == nil {
return nil
}
- out := new(ServerlessStatus)
+ out := new(Endpoint)
in.DeepCopyInto(out)
return out
}
diff --git a/components/operator/controllers/serverless_controller.go b/components/operator/controllers/serverless_controller.go
index 1c52c013e..803b2dd74 100644
--- a/components/operator/controllers/serverless_controller.go
+++ b/components/operator/controllers/serverless_controller.go
@@ -34,17 +34,17 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
-// serverlessReconciler reconciles a Serverless object
-type serverlessReconciler struct {
+// dockerRegistryReconciler reconciles a DockerRegistry object
+type dockerRegistryReconciler struct {
initStateMachine func(*zap.SugaredLogger) state.StateReconciler
client client.Client
log *zap.SugaredLogger
}
-func NewServerlessReconciler(client client.Client, config *rest.Config, recorder record.EventRecorder, log *zap.SugaredLogger, chartPath string) *serverlessReconciler {
+func NewDockerRegistryReconciler(client client.Client, config *rest.Config, recorder record.EventRecorder, log *zap.SugaredLogger, chartPath string) *dockerRegistryReconciler {
cache := chart.NewSecretManifestCache(client)
- return &serverlessReconciler{
+ return &dockerRegistryReconciler{
initStateMachine: func(log *zap.SugaredLogger) state.StateReconciler {
return state.NewMachine(client, config, recorder, log, cache, chartPath)
},
@@ -54,24 +54,24 @@ func NewServerlessReconciler(client client.Client, config *rest.Config, recorder
}
// SetupWithManager sets up the controller with the Manager.
-func (sr *serverlessReconciler) SetupWithManager(mgr ctrl.Manager) error {
+func (sr *dockerRegistryReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
- For(&v1alpha1.Serverless{}, builder.WithPredicates(predicate.NoStatusChangePredicate{})).
+ For(&v1alpha1.DockerRegistry{}, builder.WithPredicates(predicate.NoStatusChangePredicate{})).
Watches(&corev1.Service{}, tracing.ServiceCollectorWatcher()).
Complete(sr)
}
-func (sr *serverlessReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
+func (sr *dockerRegistryReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
log := sr.log.With("request", req)
log.Info("reconciliation started")
- instance, err := state.GetServerlessOrServed(ctx, req, sr.client)
+ instance, err := state.GetDockerRegistryOrServed(ctx, req, sr.client)
if err != nil {
- log.Warnf("while getting serverless, got error: %s", err.Error())
- return ctrl.Result{}, errors.Wrap(err, "while fetching serverless instance")
+ log.Warnf("while getting dockerregistry, got error: %s", err.Error())
+ return ctrl.Result{}, errors.Wrap(err, "while fetching dockerregistry instance")
}
if instance == nil {
- log.Info("Couldn't find proper instance of serverless")
+ log.Info("Couldn't find proper instance of dockerregistry")
return ctrl.Result{}, nil
}
diff --git a/components/operator/controllers/serverless_controller_rbac.go b/components/operator/controllers/serverless_controller_rbac.go
index 823a03bce..b30113147 100644
--- a/components/operator/controllers/serverless_controller_rbac.go
+++ b/components/operator/controllers/serverless_controller_rbac.go
@@ -1,6 +1,6 @@
package controllers
-// TODO: serverless-manager doesn't need almost half of these rbscs. It uses them only to create another rbacs ( is there any onther option? - investigate )
+// TODO: dockerregistry-manager doesn't need almost half of these rbscs. It uses them only to create another rbacs ( is there any onther option? - investigate )
//+kubebuilder:rbac:groups="",resources=events,verbs=get;list;watch;create;patch
//+kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch;create;update;patch;delete;deletecollection
@@ -26,9 +26,9 @@ package controllers
//+kubebuilder:rbac:groups=serverless.kyma-project.io,resources=functions,verbs=get;list;watch;create;update;patch;delete;deletecollection
//+kubebuilder:rbac:groups=serverless.kyma-project.io,resources=functions/status,verbs=get;list;watch;create;update;patch;delete;deletecollection
-//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=serverlesses,verbs=get;list;watch;create;update;patch;delete;deletecollection
-//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=serverlesses/status,verbs=get;list;watch;create;update;patch;delete;deletecollection
-//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=serverlesses/finalizers,verbs=get;list;watch;create;update;patch;delete;deletecollection
+//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=dockerregistries,verbs=get;list;watch;create;update;patch;delete;deletecollection
+//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=dockerregistries/status,verbs=get;list;watch;create;update;patch;delete;deletecollection
+//+kubebuilder:rbac:groups=operator.kyma-project.io,resources=dockerregistries/finalizers,verbs=get;list;watch;create;update;patch;delete;deletecollection
//+kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingwebhookconfigurations;mutatingwebhookconfigurations,verbs=get;list;watch;create;update;patch;delete;deletecollection
diff --git a/components/operator/controllers/serverless_controller_test.go b/components/operator/controllers/serverless_controller_test.go
index ef792ebbb..8ee854122 100644
--- a/components/operator/controllers/serverless_controller_test.go
+++ b/components/operator/controllers/serverless_controller_test.go
@@ -11,61 +11,19 @@ import (
"k8s.io/utils/ptr"
)
-var _ = Describe("Serverless controller", func() {
+var _ = Describe("DockerRegistry controller", func() {
Context("When creating fresh instance", func() {
const (
- namespaceName = "kyma-system"
- serverlessName = "serverless-cr-test"
- serverlessDeploymentName = "serverless-ctrl-mngr"
- serverlessRegistrySecret = "serverless-registry-config-default"
- specSecretName = "spec-secret-name"
+ namespaceName = "kyma-system"
+ crName = "cr-test"
+ deploymentName = "internal-docker-registry"
+ registrySecret = "serverless-registry-config-default"
)
var (
- serverlessDataDefault = serverlessData{
+ defaultData = dockerRegistryData{
TraceCollectorURL: ptr.To[string](v1alpha1.EndpointDisabled),
EnableInternal: ptr.To[bool](v1alpha1.DefaultEnableInternal),
- registrySecretData: registrySecretData{
- ServerAddress: ptr.To[string](v1alpha1.DefaultServerAddress),
- RegistryAddress: ptr.To[string](v1alpha1.DefaultRegistryAddress),
- },
- }
- serverlessDataWithChangedDependencies = serverlessData{
- EventPublisherProxyURL: ptr.To[string]("test-eventing-address"),
- TraceCollectorURL: ptr.To[string]("test-tracing-address"),
- EnableInternal: ptr.To[bool](v1alpha1.DefaultEnableInternal),
- registrySecretData: registrySecretData{
- ServerAddress: ptr.To[string](v1alpha1.DefaultServerAddress),
- RegistryAddress: ptr.To[string](v1alpha1.DefaultRegistryAddress),
- },
- }
- serverlessDataExternalWithSecret = serverlessData{
- EnableInternal: ptr.To[bool](false),
- registrySecretData: registrySecretData{
- Username: ptr.To[string]("rumburak"),
- Password: ptr.To[string]("mlekota"),
- ServerAddress: ptr.To[string]("testserveraddress:5000"),
- RegistryAddress: ptr.To[string]("testregistryaddress:5000"),
- },
- }
- serverlessDataExternalWithIncompleteSecret = serverlessData{
- EnableInternal: ptr.To[bool](false),
- registrySecretData: registrySecretData{
- Username: ptr.To[string]("blekota"),
- ServerAddress: ptr.To[string]("testserveraddress:5002"),
- },
- }
- serverlessDataIncompleteFilledByDefault = serverlessData{
- EnableInternal: ptr.To[bool](v1alpha1.DefaultEnableInternal),
- registrySecretData: registrySecretData{
- Username: ptr.To[string]("blekota"),
- Password: ptr.To[string](""),
- ServerAddress: ptr.To[string]("testserveraddress:5002"),
- RegistryAddress: ptr.To[string](""),
- },
- }
- serverlessDataExternalWithoutSecret = serverlessData{
- EnableInternal: ptr.To[bool](false),
}
)
@@ -74,108 +32,44 @@ var _ = Describe("Serverless controller", func() {
ctx: context.Background(),
namespaceName: namespaceName,
}
- // TODO: implement test for enableInternal: true
-
h.createNamespace()
{
- emptyData := v1alpha1.ServerlessSpec{}
- shouldCreateServerless(h, serverlessName, serverlessDeploymentName, emptyData)
- shouldPropagateSpecProperties(h, serverlessDeploymentName, serverlessRegistrySecret, serverlessDataDefault)
- }
- {
- updateData := v1alpha1.ServerlessSpec{
- Eventing: getEndpoint(serverlessDataWithChangedDependencies.EventPublisherProxyURL),
- Tracing: getEndpoint(serverlessDataWithChangedDependencies.TraceCollectorURL),
- }
- shouldUpdateServerless(h, serverlessName, updateData)
- shouldPropagateSpecProperties(h, serverlessDeploymentName, serverlessRegistrySecret, serverlessDataWithChangedDependencies)
- }
- {
- registryData := serverlessDataExternalWithSecret
- secretName := specSecretName + "-full"
- h.createRegistrySecret(secretName, registryData.registrySecretData)
- updateData := registryData.toServerlessSpec(secretName)
- shouldUpdateServerless(h, serverlessName, updateData)
- shouldPropagateSpecProperties(h, serverlessDeploymentName, serverlessRegistrySecret, registryData)
- }
- {
- registryData := serverlessDataExternalWithIncompleteSecret
- secretName := specSecretName + "-incomplete"
- h.createRegistrySecret(secretName, registryData.registrySecretData)
- updateData := registryData.toServerlessSpec(secretName)
- shouldUpdateServerless(h, serverlessName, updateData)
- shouldPropagateSpecProperties(h, serverlessDeploymentName, serverlessRegistrySecret, serverlessDataIncompleteFilledByDefault)
- }
- {
- registryData := serverlessDataExternalWithoutSecret
- updateData := registryData.toServerlessSpec("")
- shouldUpdateServerless(h, serverlessName, updateData)
- shouldPropagateSpecProperties(h, serverlessDeploymentName, serverlessRegistrySecret, serverlessDataDefault)
+ emptyData := v1alpha1.DockerRegistrySpec{}
+ shouldCreateDockerRegistry(h, crName, deploymentName, emptyData)
+ shouldPropagateSpecProperties(h, registrySecret, defaultData)
}
- shouldDeleteServerless(h, serverlessName, serverlessDeploymentName)
+ shouldDeleteDockerRegistry(h, crName, deploymentName)
})
})
})
-func shouldCreateServerless(h testHelper, serverlessName, serverlessDeploymentName string, spec v1alpha1.ServerlessSpec) {
+func shouldCreateDockerRegistry(h testHelper, name, deploymentName string, spec v1alpha1.DockerRegistrySpec) {
// act
- h.createServerless(serverlessName, spec)
+ h.createDockerRegistry(name, spec)
// we have to update deployment status manually
- h.updateDeploymentStatus(serverlessDeploymentName)
+ h.updateDeploymentStatus(deploymentName)
// assert
- Eventually(h.createGetServerlessStatusFunc(serverlessName)).
+ Eventually(h.getDockerRegistryStatusFunc(name)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 20).
Should(ConditionTrueMatcher())
}
-func shouldPropagateSpecProperties(h testHelper, deploymentName, registrySecretName string, expected serverlessData) {
+func shouldPropagateSpecProperties(h testHelper, registrySecretName string, expected dockerRegistryData) {
Eventually(h.createCheckRegistrySecretFunc(registrySecretName, expected.registrySecretData)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 10).
Should(BeTrue())
-
- Eventually(h.createCheckOptionalDependenciesFunc(deploymentName, expected)).
- WithPolling(time.Second * 2).
- WithTimeout(time.Second * 10).
- Should(BeTrue())
-}
-
-func shouldUpdateServerless(h testHelper, serverlessName string, serverlessSpec v1alpha1.ServerlessSpec) {
- // arrange
- var serverless v1alpha1.Serverless
- Eventually(h.createGetKubernetesObjectFunc(serverlessName, &serverless)).
- WithPolling(time.Second * 2).
- WithTimeout(time.Second * 10).
- Should(BeTrue())
-
- serverless.Spec = serverlessSpec
-
- // act
- Expect(k8sClient.Update(h.ctx, &serverless)).To(Succeed())
-
- // assert
- Eventually(h.createGetKubernetesObjectFunc(serverlessName, &serverless)).
- WithPolling(time.Second * 2).
- WithTimeout(time.Second * 10).
- Should(BeTrue())
-
- Expect(serverless.Spec).To(Equal(serverlessSpec))
-
- Eventually(h.createGetServerlessStatusFunc(serverlessName)).
- WithPolling(time.Second * 2).
- WithTimeout(time.Second * 20).
- Should(ConditionTrueMatcher())
}
-func shouldDeleteServerless(h testHelper, serverlessName, serverlessDeploymentName string) {
+func shouldDeleteDockerRegistry(h testHelper, name, deploymentName string) {
// initial assert
var deployList appsv1.DeploymentList
- Eventually(h.createListKubernetesObjectFunc(&deployList)).
+ Eventually(h.listKubernetesObjectFunc(&deployList)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 10).
Should(BeTrue())
@@ -183,21 +77,21 @@ func shouldDeleteServerless(h testHelper, serverlessName, serverlessDeploymentNa
Expect(deployList.Items).To(HaveLen(1))
// act
- var serverless v1alpha1.Serverless
- Eventually(h.createGetKubernetesObjectFunc(serverlessName, &serverless)).
+ var dockerRegistry v1alpha1.DockerRegistry
+ Eventually(h.getKubernetesObjectFunc(name, &dockerRegistry)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 10).
Should(BeTrue())
- Expect(k8sClient.Delete(h.ctx, &serverless)).To(Succeed())
+ Expect(k8sClient.Delete(h.ctx, &dockerRegistry)).To(Succeed())
- Eventually(h.createGetKubernetesObjectFunc(serverlessName, &serverless)).
+ Eventually(h.getKubernetesObjectFunc(name, &dockerRegistry)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 10).
Should(BeTrue())
// assert
- Eventually(h.createGetKubernetesObjectFunc(serverlessDeploymentName, &appsv1.Deployment{})).
+ Eventually(h.getKubernetesObjectFunc(deploymentName, &appsv1.Deployment{})).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 10).
Should(BeTrue())
diff --git a/components/operator/controllers/suite_test.go b/components/operator/controllers/suite_test.go
index 5bc9297e6..a1a344082 100644
--- a/components/operator/controllers/suite_test.go
+++ b/components/operator/controllers/suite_test.go
@@ -91,8 +91,8 @@ var _ = BeforeSuite(func() {
reconcilerLogger, err := config.Build()
Expect(err).NotTo(HaveOccurred())
- chartPath := filepath.Join("..", "..", "..", "config", "serverless")
- err = (NewServerlessReconciler(
+ chartPath := filepath.Join("..", "..", "..", "config", "docker-registry")
+ err = (NewDockerRegistryReconciler(
k8sManager.GetClient(),
k8sManager.GetConfig(),
record.NewFakeRecorder(100),
diff --git a/components/operator/controllers/testhelper_test.go b/components/operator/controllers/testhelper_test.go
index cf1d38371..09cd4929e 100644
--- a/components/operator/controllers/testhelper_test.go
+++ b/components/operator/controllers/testhelper_test.go
@@ -13,7 +13,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- "k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client"
)
@@ -30,9 +29,9 @@ func ConditionTrueMatcher() gomegatypes.GomegaMatcher {
}
func (matcher *conditionMatcher) Match(actual interface{}) (success bool, err error) {
- status, ok := actual.(v1alpha1.ServerlessStatus)
+ status, ok := actual.(v1alpha1.DockerRegistryStatus)
if !ok {
- return false, fmt.Errorf("ConditionMatcher matcher expects an v1alpha1.ServerlessStatus")
+ return false, fmt.Errorf("ConditionMatcher matcher expects an v1alpha1.DockerRegistryStatus")
}
if status.State != matcher.expectedState {
@@ -66,7 +65,7 @@ type testHelper struct {
func (h *testHelper) updateDeploymentStatus(deploymentName string) {
By(fmt.Sprintf("Updating deployment status: %s", deploymentName))
var deployment appsv1.Deployment
- Eventually(h.createGetKubernetesObjectFunc(deploymentName, &deployment)).
+ Eventually(h.getKubernetesObjectFunc(deploymentName, &deployment)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 30).
Should(BeTrue())
@@ -83,7 +82,7 @@ func (h *testHelper) updateDeploymentStatus(deploymentName string) {
replicaSetName := h.createReplicaSetForDeployment(deployment)
var replicaSet appsv1.ReplicaSet
- Eventually(h.createGetKubernetesObjectFunc(replicaSetName, &replicaSet)).
+ Eventually(h.getKubernetesObjectFunc(replicaSetName, &replicaSet)).
WithPolling(time.Second * 2).
WithTimeout(time.Second * 30).
Should(BeTrue())
@@ -129,11 +128,11 @@ func (h *testHelper) createReplicaSetForDeployment(deployment appsv1.Deployment)
return replicaSetName
}
-func (h *testHelper) createServerless(serverlessName string, spec v1alpha1.ServerlessSpec) {
- By(fmt.Sprintf("Creating crd: %s", serverlessName))
- serverless := v1alpha1.Serverless{
+func (h *testHelper) createDockerRegistry(crName string, spec v1alpha1.DockerRegistrySpec) {
+ By(fmt.Sprintf("Creating cr: %s", crName))
+ dockerRegistry := v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
- Name: serverlessName,
+ Name: crName,
Namespace: h.namespaceName,
Labels: map[string]string{
"operator.kyma-project.io/kyma-name": "test",
@@ -141,8 +140,8 @@ func (h *testHelper) createServerless(serverlessName string, spec v1alpha1.Serve
},
Spec: spec,
}
- Expect(k8sClient.Create(h.ctx, &serverless)).To(Succeed())
- By(fmt.Sprintf("Crd created: %s", serverlessName))
+ Expect(k8sClient.Create(h.ctx, &dockerRegistry)).To(Succeed())
+ By(fmt.Sprintf("Crd created: %s", crName))
}
func (h *testHelper) createNamespace() {
@@ -174,13 +173,13 @@ func (h *testHelper) createRegistrySecret(name string, data registrySecretData)
h.createSecret(name, secretData)
}
-func (h *testHelper) createGetKubernetesObjectFunc(objectName string, obj client.Object) func() (bool, error) {
+func (h *testHelper) getKubernetesObjectFunc(objectName string, obj client.Object) func() (bool, error) {
return func() (bool, error) {
- return h.getKubernetesObjectFunc(objectName, obj)
+ return h.getKubernetesObject(objectName, obj)
}
}
-func (h *testHelper) getKubernetesObjectFunc(objectName string, obj client.Object) (bool, error) {
+func (h *testHelper) getKubernetesObject(objectName string, obj client.Object) (bool, error) {
key := types.NamespacedName{
Name: objectName,
Namespace: h.namespaceName,
@@ -193,13 +192,13 @@ func (h *testHelper) getKubernetesObjectFunc(objectName string, obj client.Objec
return true, err
}
-func (h *testHelper) createListKubernetesObjectFunc(list client.ObjectList) func() (bool, error) {
+func (h *testHelper) listKubernetesObjectFunc(list client.ObjectList) func() (bool, error) {
return func() (bool, error) {
- return h.listKubernetesObjectFunc(list)
+ return h.listKubernetesObject(list)
}
}
-func (h *testHelper) listKubernetesObjectFunc(list client.ObjectList) (bool, error) {
+func (h *testHelper) listKubernetesObject(list client.ObjectList) (bool, error) {
opts := client.ListOptions{
Namespace: h.namespaceName,
}
@@ -211,53 +210,32 @@ func (h *testHelper) listKubernetesObjectFunc(list client.ObjectList) (bool, err
return true, err
}
-func (h *testHelper) createGetServerlessStatusFunc(serverlessName string) func() (v1alpha1.ServerlessStatus, error) {
- return func() (v1alpha1.ServerlessStatus, error) {
- return h.getServerlessStatus(serverlessName)
+func (h *testHelper) getDockerRegistryStatusFunc(name string) func() (v1alpha1.DockerRegistryStatus, error) {
+ return func() (v1alpha1.DockerRegistryStatus, error) {
+ return h.getDockerRegistryStatus(name)
}
}
-func (h *testHelper) getServerlessStatus(serverlessName string) (v1alpha1.ServerlessStatus, error) {
- var serverless v1alpha1.Serverless
+func (h *testHelper) getDockerRegistryStatus(name string) (v1alpha1.DockerRegistryStatus, error) {
+ var dockerRegistry v1alpha1.DockerRegistry
key := types.NamespacedName{
- Name: serverlessName,
+ Name: name,
Namespace: h.namespaceName,
}
- err := k8sClient.Get(h.ctx, key, &serverless)
+ err := k8sClient.Get(h.ctx, key, &dockerRegistry)
if err != nil {
- return v1alpha1.ServerlessStatus{}, err
+ return v1alpha1.DockerRegistryStatus{}, err
}
- return serverless.Status, nil
+ return dockerRegistry.Status, nil
}
-type serverlessData struct {
+type dockerRegistryData struct {
EventPublisherProxyURL *string
TraceCollectorURL *string
EnableInternal *bool
registrySecretData
}
-func (d *serverlessData) toServerlessSpec(secretName string) v1alpha1.ServerlessSpec {
- result := v1alpha1.ServerlessSpec{
- Eventing: getEndpoint(d.EventPublisherProxyURL),
- Tracing: getEndpoint(d.TraceCollectorURL),
- DockerRegistry: &v1alpha1.DockerRegistry{
- EnableInternal: d.EnableInternal,
- },
- }
- if secretName != "" {
- result.DockerRegistry.SecretName = ptr.To[string](secretName)
- }
- return result
-}
-
-func getEndpoint(url *string) *v1alpha1.Endpoint {
- if url != nil {
- return &v1alpha1.Endpoint{Endpoint: *url}
- }
- return nil
-}
-
type registrySecretData struct {
Username *string
Password *string
@@ -282,12 +260,12 @@ func (d *registrySecretData) toMap() map[string]string {
return result
}
-func (h *testHelper) createCheckRegistrySecretFunc(serverlessRegistrySecret string, expected registrySecretData) func() (bool, error) {
+func (h *testHelper) createCheckRegistrySecretFunc(registrySecret string, expected registrySecretData) func() (bool, error) {
return func() (bool, error) {
var configurationSecret corev1.Secret
- if ok, err := h.getKubernetesObjectFunc(
- serverlessRegistrySecret, &configurationSecret); !ok || err != nil {
+ if ok, err := h.getKubernetesObject(
+ registrySecret, &configurationSecret); !ok || err != nil {
return ok, err
}
if ok, err := secretContainsSameValues(
@@ -301,10 +279,10 @@ func (h *testHelper) createCheckRegistrySecretFunc(serverlessRegistrySecret stri
}
}
-func (h *testHelper) createCheckOptionalDependenciesFunc(deploymentName string, expected serverlessData) func() (bool, error) {
+func (h *testHelper) createCheckOptionalDependenciesFunc(deploymentName string, expected dockerRegistryData) func() (bool, error) {
return func() (bool, error) {
var deploy appsv1.Deployment
- ok, err := h.getKubernetesObjectFunc(deploymentName, &deploy)
+ ok, err := h.getKubernetesObject(deploymentName, &deploy)
if !ok || err != nil {
return ok, err
}
@@ -347,7 +325,7 @@ func deploymentContainsEnv(deployment appsv1.Deployment, name, value string) err
}
func secretContainsRequired(configurationSecret corev1.Secret) (bool, error) {
- for _, k := range []string{"username", "password", "registryAddress", "serverAddress"} {
+ for _, k := range []string{"username", "password", "pullRegAddr", "pushRegAddr", ".dockerconfigjson"} {
_, ok := configurationSecret.Data[k]
if !ok {
return false, fmt.Errorf("values not propagated (%s is required)", k)
diff --git a/components/operator/hack/verify_dockerregistry_status.sh b/components/operator/hack/verify_dockerregistry_status.sh
new file mode 100755
index 000000000..5726552cf
--- /dev/null
+++ b/components/operator/hack/verify_dockerregistry_status.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+function get_dockerregistry_status () {
+ local number=1
+ while [[ $number -le 100 ]] ; do
+ echo ">--> checking dockerregistry status #$number"
+ local STATUS=$(kubectl get dockerregistry -n kyma-system default -o jsonpath='{.status.state}')
+ echo "dockerregistry status: ${STATUS:='UNKNOWN'}"
+ [[ "$STATUS" == "Ready" ]] && return 0
+ sleep 5
+ ((number = number + 1))
+ done
+
+ kubectl get all --all-namespaces
+ exit 1
+}
+
+get_dockerregistry_status
diff --git a/components/operator/hack/verify_serverless_status.sh b/components/operator/hack/verify_serverless_status.sh
deleted file mode 100755
index 475c5bac6..000000000
--- a/components/operator/hack/verify_serverless_status.sh
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-
-function get_kyma_status () {
- local number=1
- while [[ $number -le 100 ]] ; do
- echo ">--> checking serverless status #$number"
- local STATUS=$(kubectl get serverless -n kyma-system default -o jsonpath='{.status.state}')
- echo "serverless status: ${STATUS:='UNKNOWN'}"
- [[ "$STATUS" == "Ready" ]] && return 0
- sleep 5
- ((number = number + 1))
- done
-
- kubectl get all --all-namespaces
- exit 1
-}
-
-get_kyma_status
diff --git a/components/operator/internal/annotation/disclaimer.go b/components/operator/internal/annotation/disclaimer.go
index de5bcb6b1..1ed584fc6 100644
--- a/components/operator/internal/annotation/disclaimer.go
+++ b/components/operator/internal/annotation/disclaimer.go
@@ -1,19 +1,12 @@
package annotation
import (
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/cli-runtime/pkg/resource"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client"
)
const (
- reconcilerPatch = "{\"metadata\":{\"annotations\":{\"reconciler.kyma-project.io/managed-by-reconciler-disclaimer\":null}}}"
- annotation = "serverless-manager.kyma-project.io/managed-by-serverless-manager-disclaimer"
- message = "DO NOT EDIT - This resource is managed by Serverless-Manager.\nAny modifications are discarded and the resource is reverted to the original state."
+ annotation = "dockerregistry-manager.kyma-project.io/managed-by-dockerregistry-manager-disclaimer"
+ message = "DO NOT EDIT - This resource is managed by DockerRegistry-Manager.\nAny modifications are discarded and the resource is reverted to the original state."
)
func AddDoNotEditDisclaimer(obj unstructured.Unstructured) unstructured.Unstructured {
@@ -27,37 +20,3 @@ func AddDoNotEditDisclaimer(obj unstructured.Unstructured) unstructured.Unstruct
return obj
}
-
-func DeleteReconcilerDisclaimer(client client.Client, config rest.Config, obj unstructured.Unstructured) error {
- mapping, err := client.RESTMapper().RESTMapping(
- obj.GroupVersionKind().GroupKind(),
- obj.GroupVersionKind().Version,
- )
- if err != nil {
- return err
- }
-
- restClient, err := UnstructuredClientForMapping(&config, mapping)
- if err != nil {
- return err
- }
-
- helper := resource.
- NewHelper(restClient, mapping).
- DryRun(false).
- WithFieldManager("serverless-manager")
-
- _, err = helper.Patch(obj.GetNamespace(), obj.GetName(), types.MergePatchType, []byte(reconcilerPatch), nil)
- return err
-}
-
-func UnstructuredClientForMapping(config *rest.Config, mapping *metav1.RESTMapping) (resource.RESTClient, error) {
- config.APIPath = "/apis"
- if mapping.GroupVersionKind.Group == corev1.GroupName {
- config.APIPath = "/api"
- }
- gv := mapping.GroupVersionKind.GroupVersion()
- config.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
- config.GroupVersion = &gv
- return rest.RESTClientFor(config)
-}
diff --git a/components/operator/internal/annotation/disclaimer_test.go b/components/operator/internal/annotation/disclaimer_test.go
index 3cf251f21..ede058868 100644
--- a/components/operator/internal/annotation/disclaimer_test.go
+++ b/components/operator/internal/annotation/disclaimer_test.go
@@ -1,22 +1,12 @@
package annotation
import (
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
"testing"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
- "k8s.io/apimachinery/pkg/api/meta"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/client-go/rest"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
)
var (
@@ -43,40 +33,3 @@ func TestAddDoNotEditDisclaimer(t *testing.T) {
require.Equal(t, message, obj.GetAnnotations()[annotation])
})
}
-
-func TestDeleteReconcilerDisclaimer(t *testing.T) {
- t.Run("prepare good request", func(t *testing.T) {
- mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{})
- mapper.Add(appsv1.SchemeGroupVersion.WithKind("Deployment"), meta.RESTScopeNamespace)
-
- server := fixTestPatchServer(t)
- defer server.Close()
-
- client := fake.NewClientBuilder().
- WithRESTMapper(mapper).
- Build()
-
- obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(testDeployCR)
- require.NoError(t, err)
-
- err = DeleteReconcilerDisclaimer(client, rest.Config{
- Host: server.URL,
- }, unstructured.Unstructured{Object: obj})
- require.NoError(t, err)
- })
-}
-
-func fixTestPatchServer(t *testing.T) *httptest.Server {
- return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
- require.Equal(t, "PATCH", r.Method)
- bodyBytes, err := io.ReadAll(r.Body)
- require.NoError(t, err)
- require.Equal(t, reconcilerPatch, string(bodyBytes))
-
- jsonDeploy, err := json.Marshal(testDeployCR)
- require.NoError(t, err)
-
- w.Header().Add("Content-Type", "application/json")
- fmt.Fprint(w, string(jsonDeploy))
- }))
-}
diff --git a/components/operator/internal/chart/cache.go b/components/operator/internal/chart/cache.go
index 80a87c340..cf4b33642 100644
--- a/components/operator/internal/chart/cache.go
+++ b/components/operator/internal/chart/cache.go
@@ -17,16 +17,16 @@ var (
)
var (
- emptyServerlessSpecManifest = ServerlessSpecManifest{}
+ emptySpecManifest = DockerRegistrySpecManifest{}
)
type ManifestCache interface {
- Set(context.Context, client.ObjectKey, ServerlessSpecManifest) error
- Get(context.Context, client.ObjectKey) (ServerlessSpecManifest, error)
+ Set(context.Context, client.ObjectKey, DockerRegistrySpecManifest) error
+ Get(context.Context, client.ObjectKey) (DockerRegistrySpecManifest, error)
Delete(context.Context, client.ObjectKey) error
}
-// inMemoryManifestCache provides an in-memory processor to store serverless Spec and rendered chart manifest. By using sync.Map for caching,
+// inMemoryManifestCache provides an in-memory processor to store dockerregistry Spec and rendered chart manifest. By using sync.Map for caching,
// concurrent operations to the processor from diverse reconciliations are considered safe.
//
// Inside the processor is stored chart manifest with used custom flags by client.ObjectKey key.
@@ -41,18 +41,18 @@ func NewInMemoryManifestCache() *inMemoryManifestCache {
}
}
-// Get loads the ServerlessSpecManifest from inMemoryManifestCache for the passed client.ObjectKey.
-func (r *inMemoryManifestCache) Get(_ context.Context, key client.ObjectKey) (ServerlessSpecManifest, error) {
+// Get loads the DockerRegistrySpecManifest from inMemoryManifestCache for the passed client.ObjectKey.
+func (r *inMemoryManifestCache) Get(_ context.Context, key client.ObjectKey) (DockerRegistrySpecManifest, error) {
value, ok := r.processor.Load(key)
if !ok {
- return emptyServerlessSpecManifest, nil
+ return emptySpecManifest, nil
}
- return *value.(*ServerlessSpecManifest), nil
+ return *value.(*DockerRegistrySpecManifest), nil
}
// Set saves the passed flags and manifest into inMemoryManifestCache for the client.ObjectKey.
-func (r *inMemoryManifestCache) Set(_ context.Context, key client.ObjectKey, spec ServerlessSpecManifest) error {
+func (r *inMemoryManifestCache) Set(_ context.Context, key client.ObjectKey, spec DockerRegistrySpecManifest) error {
r.processor.Store(key, &spec)
return nil
@@ -64,14 +64,14 @@ func (r *inMemoryManifestCache) Delete(_ context.Context, key client.ObjectKey)
return nil
}
-// secretManifestCache - provides an Secret based processor to store serverless Spec and rendered chart manifest.
+// secretManifestCache - provides an Secret based processor to store dockerregistry Spec and rendered chart manifest.
//
// Inside the secret we store manifest and flags used to render it.
type secretManifestCache struct {
client client.Client
}
-type ServerlessSpecManifest struct {
+type DockerRegistrySpecManifest struct {
ManagerUID string
CustomFlags map[string]interface{}
Manifest string
@@ -96,28 +96,28 @@ func (m *secretManifestCache) Delete(ctx context.Context, key client.ObjectKey)
return client.IgnoreNotFound(err)
}
-// Get - loads the ServerlessSpecManifest from SecretManifestCache based on the passed client.ObjectKey.
-func (m *secretManifestCache) Get(ctx context.Context, key client.ObjectKey) (ServerlessSpecManifest, error) {
+// Get - loads the DockerRegistrySpecManifest from SecretManifestCache based on the passed client.ObjectKey.
+func (m *secretManifestCache) Get(ctx context.Context, key client.ObjectKey) (DockerRegistrySpecManifest, error) {
secret := corev1.Secret{}
err := m.client.Get(ctx, key, &secret)
if errors.IsNotFound(err) {
- return emptyServerlessSpecManifest, nil
+ return emptySpecManifest, nil
}
if err != nil {
- return emptyServerlessSpecManifest, err
+ return emptySpecManifest, err
}
- spec := ServerlessSpecManifest{}
+ spec := DockerRegistrySpecManifest{}
err = json.Unmarshal(secret.Data["spec"], &spec)
if err != nil {
- return emptyServerlessSpecManifest, err
+ return emptySpecManifest, err
}
return spec, nil
}
// Set - saves the passed flags and manifest into Secret based on the client.ObjectKey.
-func (m *secretManifestCache) Set(ctx context.Context, key client.ObjectKey, spec ServerlessSpecManifest) error {
+func (m *secretManifestCache) Set(ctx context.Context, key client.ObjectKey, spec DockerRegistrySpecManifest) error {
byteSpec, err := json.Marshal(&spec)
if err != nil {
return err
diff --git a/components/operator/internal/chart/cache_test.go b/components/operator/internal/chart/cache_test.go
index ead4e90b8..7b182399d 100644
--- a/components/operator/internal/chart/cache_test.go
+++ b/components/operator/internal/chart/cache_test.go
@@ -21,12 +21,12 @@ const testSecretNamespace = "kyma-system"
func TestManifestCache_Delete(t *testing.T) {
t.Run("delete secret", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
client := fake.NewClientBuilder().WithRuntimeObjects(
- fixSecretCache(t, key, emptyServerlessSpecManifest),
+ fixSecretCache(t, key, emptySpecManifest),
).Build()
cache := NewSecretManifestCache(client)
@@ -45,7 +45,7 @@ func TestManifestCache_Delete(t *testing.T) {
require.NoError(t, apiextensionsscheme.AddToScheme(scheme))
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -59,7 +59,7 @@ func TestManifestCache_Delete(t *testing.T) {
t.Run("do nothing when cache is not found", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -75,12 +75,12 @@ func TestManifestCache_Delete(t *testing.T) {
func TestManifestCache_Get(t *testing.T) {
t.Run("get secret value", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
client := fake.NewClientBuilder().WithRuntimeObjects(
- fixSecretCache(t, key, ServerlessSpecManifest{
+ fixSecretCache(t, key, DockerRegistrySpecManifest{
CustomFlags: map[string]interface{}{
"flag1": "val1",
"flag2": "val2",
@@ -94,7 +94,7 @@ func TestManifestCache_Get(t *testing.T) {
result, err := cache.Get(ctx, key)
require.NoError(t, err)
- expectedResult := ServerlessSpecManifest{
+ expectedResult := DockerRegistrySpecManifest{
CustomFlags: map[string]interface{}{
"flag1": "val1",
"flag2": "val2",
@@ -110,7 +110,7 @@ func TestManifestCache_Get(t *testing.T) {
require.NoError(t, apiextensionsscheme.AddToScheme(scheme))
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -120,12 +120,12 @@ func TestManifestCache_Get(t *testing.T) {
result, err := cache.Get(ctx, key)
require.Error(t, err)
- require.Equal(t, emptyServerlessSpecManifest, result)
+ require.Equal(t, emptySpecManifest, result)
})
t.Run("secret not found", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -135,12 +135,12 @@ func TestManifestCache_Get(t *testing.T) {
result, err := cache.Get(ctx, key)
require.NoError(t, err)
- require.Equal(t, emptyServerlessSpecManifest, result)
+ require.Equal(t, emptySpecManifest, result)
})
t.Run("conversion error", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -159,21 +159,21 @@ func TestManifestCache_Get(t *testing.T) {
result, err := cache.Get(ctx, key)
require.Error(t, err)
- require.Equal(t, emptyServerlessSpecManifest, result)
+ require.Equal(t, emptySpecManifest, result)
})
}
func TestManifestCache_Set(t *testing.T) {
t.Run("create secret", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
client := fake.NewClientBuilder().Build()
cache := NewSecretManifestCache(client)
- expectedSpec := ServerlessSpecManifest{
+ expectedSpec := DockerRegistrySpecManifest{
Manifest: "schmetterling",
CustomFlags: map[string]interface{}{
"flag1": "val1",
@@ -187,7 +187,7 @@ func TestManifestCache_Set(t *testing.T) {
var secret corev1.Secret
require.NoError(t, client.Get(ctx, key, &secret))
- actualSpec := ServerlessSpecManifest{}
+ actualSpec := DockerRegistrySpecManifest{}
err = json.Unmarshal(secret.Data["spec"], &actualSpec)
require.NoError(t, err)
@@ -196,16 +196,16 @@ func TestManifestCache_Set(t *testing.T) {
t.Run("update secret", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
client := fake.NewClientBuilder().WithRuntimeObjects(
- fixSecretCache(t, key, emptyServerlessSpecManifest),
+ fixSecretCache(t, key, emptySpecManifest),
).Build()
cache := NewSecretManifestCache(client)
- expectedSpec := ServerlessSpecManifest{
+ expectedSpec := DockerRegistrySpecManifest{
Manifest: "schmetterling",
CustomFlags: map[string]interface{}{
"flag1": "val1",
@@ -218,7 +218,7 @@ func TestManifestCache_Set(t *testing.T) {
var secret corev1.Secret
require.NoError(t, client.Get(ctx, key, &secret))
- actualSpec := ServerlessSpecManifest{}
+ actualSpec := DockerRegistrySpecManifest{}
err = json.Unmarshal(secret.Data["spec"], &actualSpec)
require.NoError(t, err)
@@ -227,7 +227,7 @@ func TestManifestCache_Set(t *testing.T) {
t.Run("marshal error", func(t *testing.T) {
key := types.NamespacedName{
- Name: "test-serverless",
+ Name: "test-name",
Namespace: testSecretNamespace,
}
ctx := context.TODO()
@@ -238,7 +238,7 @@ func TestManifestCache_Set(t *testing.T) {
cache := NewSecretManifestCache(client)
- err := cache.Set(ctx, key, ServerlessSpecManifest{
+ err := cache.Set(ctx, key, DockerRegistrySpecManifest{
Manifest: "",
CustomFlags: wrongFlags,
})
@@ -246,7 +246,7 @@ func TestManifestCache_Set(t *testing.T) {
})
}
-func fixSecretCache(t *testing.T, key types.NamespacedName, spec ServerlessSpecManifest) *corev1.Secret {
+func fixSecretCache(t *testing.T, key types.NamespacedName, spec DockerRegistrySpecManifest) *corev1.Secret {
byteSpec, err := json.Marshal(&spec)
require.NoError(t, err)
diff --git a/components/operator/internal/chart/chart.go b/components/operator/internal/chart/chart.go
index da103897d..330d4d928 100644
--- a/components/operator/internal/chart/chart.go
+++ b/components/operator/internal/chart/chart.go
@@ -95,7 +95,7 @@ func getCachedAndCurrentManifest(config *Config, customFlags map[string]interfac
return cachedSpecManifest.Manifest, currentRelease.Manifest, nil
}
-func shouldRenderAgain(cachedSpec ServerlessSpecManifest, config *Config, customFlags map[string]interface{}) bool {
+func shouldRenderAgain(cachedSpec DockerRegistrySpecManifest, config *Config, customFlags map[string]interface{}) bool {
// cachedSpec is up-to-date only if flags used to render and manager is the same one who rendered it before
equalFlags := reflect.DeepEqual(cachedSpec.CustomFlags, customFlags)
return !(cachedSpec.ManagerUID == config.ManagerUID && equalFlags)
diff --git a/components/operator/internal/chart/chart_test.go b/components/operator/internal/chart/chart_test.go
index 4fb2f616a..0d155da65 100644
--- a/components/operator/internal/chart/chart_test.go
+++ b/components/operator/internal/chart/chart_test.go
@@ -15,7 +15,7 @@ func Test_getOrRenderManifestWithRenderer(t *testing.T) {
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), noCRDManifestKey,
- ServerlessSpecManifest{Manifest: testDeploy})
+ DockerRegistrySpecManifest{Manifest: testDeploy})
type args struct {
config *Config
diff --git a/components/operator/internal/chart/check_test.go b/components/operator/internal/chart/check_test.go
index e092c2db4..6b0e10d98 100644
--- a/components/operator/internal/chart/check_test.go
+++ b/components/operator/internal/chart/check_test.go
@@ -57,15 +57,15 @@ func TestCheckCRDOrphanResources(t *testing.T) {
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), noCRDManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testDeploy)})
_ = cache.Set(context.Background(), noOrphanManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
_ = cache.Set(context.Background(), oneOrphanManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testOrphanCR)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testOrphanCR)})
_ = cache.Set(context.Background(), emptyManifestKey,
- ServerlessSpecManifest{Manifest: ""})
+ DockerRegistrySpecManifest{Manifest: ""})
_ = cache.Set(context.Background(), wrongManifestKey,
- ServerlessSpecManifest{Manifest: "api: test\n\tversion: test"})
+ DockerRegistrySpecManifest{Manifest: "api: test\n\tversion: test"})
type args struct {
config *Config
diff --git a/components/operator/internal/chart/flags.go b/components/operator/internal/chart/flags.go
index f412cee1b..1d5662c28 100644
--- a/components/operator/internal/chart/flags.go
+++ b/components/operator/internal/chart/flags.go
@@ -7,12 +7,10 @@ import (
type FlagsBuilder interface {
Build() map[string]interface{}
- WithControllerConfiguration(CPUUtilizationPercentage string, requeueDuration string, buildExecutorArgs string, maxSimultaneousJobs string, healthzLivenessTimeout string, requestBodyLimitMb string, timeoutSec string) *flagsBuilder
- WithDefaultPresetFlags(defaultBuildJobPreset string, defaultRuntimePodPreset string) *flagsBuilder
+ WithControllerConfiguration(healthzLivenessTimeout string) *flagsBuilder
WithOptionalDependencies(publisherURL string, traceCollectorURL string) *flagsBuilder
WithRegistryAddresses(registryAddress string, serverAddress string) *flagsBuilder
WithRegistryCredentials(username string, password string) *flagsBuilder
- WithRegistryEnableInternal(enableInternal bool) *flagsBuilder
WithRegistryHttpSecret(httpSecret string) *flagsBuilder
WithNodePort(nodePort int64) *flagsBuilder
}
@@ -62,18 +60,12 @@ func nextDeeperFlag(currentFlag map[string]interface{}, path string) map[string]
return currentFlag[path].(map[string]interface{})
}
-func (fb *flagsBuilder) WithControllerConfiguration(CPUUtilizationPercentage, requeueDuration, buildExecutorArgs, maxSimultaneousJobs, healthzLivenessTimeout, requestBodyLimitMb, timeoutSec string) *flagsBuilder {
+func (fb *flagsBuilder) WithControllerConfiguration(healthzLivenessTimeout string) *flagsBuilder {
optionalFlags := []struct {
key string
value string
}{
- {"targetCPUUtilizationPercentage", CPUUtilizationPercentage},
- {"functionRequeueDuration", requeueDuration},
- {"functionBuildExecutorArgs", buildExecutorArgs},
- {"functionBuildMaxSimultaneousJobs", maxSimultaneousJobs},
{"healthzLivenessTimeout", healthzLivenessTimeout},
- {"functionRequestBodyLimitMb", requestBodyLimitMb},
- {"functionTimeoutSec", timeoutSec},
}
for _, flag := range optionalFlags {
@@ -92,11 +84,6 @@ func (fb *flagsBuilder) WithOptionalDependencies(publisherURL, traceCollectorURL
return fb
}
-func (fb *flagsBuilder) WithRegistryEnableInternal(enableInternal bool) *flagsBuilder {
- fb.flags["dockerRegistry.enableInternal"] = enableInternal
- return fb
-}
-
func (fb *flagsBuilder) WithRegistryCredentials(username, password string) *flagsBuilder {
fb.flags["dockerRegistry.username"] = username
fb.flags["dockerRegistry.password"] = password
@@ -117,18 +104,6 @@ func (fb *flagsBuilder) WithRegistryHttpSecret(httpSecret string) *flagsBuilder
return fb
}
-func (fb *flagsBuilder) WithDefaultPresetFlags(defaultBuildJobPreset, defaultRuntimePodPreset string) *flagsBuilder {
- if defaultRuntimePodPreset != "" {
- fb.flags["containers.manager.configuration.data.resourcesConfiguration.function.resources.defaultPreset"] = defaultRuntimePodPreset
- }
-
- if defaultBuildJobPreset != "" {
- fb.flags["containers.manager.configuration.data.resourcesConfiguration.buildJob.resources.defaultPreset"] = defaultBuildJobPreset
- }
-
- return fb
-}
-
func (fb *flagsBuilder) WithNodePort(nodePort int64) *flagsBuilder {
fb.flags["global.registryNodePort"] = nodePort
return fb
diff --git a/components/operator/internal/chart/flags_test.go b/components/operator/internal/chart/flags_test.go
index 05a59f7f3..79e4f8f16 100644
--- a/components/operator/internal/chart/flags_test.go
+++ b/components/operator/internal/chart/flags_test.go
@@ -18,27 +18,9 @@ func Test_flagsBuilder_Build(t *testing.T) {
"manager": map[string]interface{}{
"configuration": map[string]interface{}{
"data": map[string]interface{}{
- "functionBuildExecutorArgs": "testBuildExecutorArgs",
- "functionBuildMaxSimultaneousJobs": "testMaxSimultaneousJobs",
- "functionPublisherProxyAddress": "testPublisherURL",
- "functionRequestBodyLimitMb": "testRequestBodyLimitMb",
- "functionRequeueDuration": "testRequeueDuration",
- "functionTimeoutSec": "testTimeoutSec",
- "functionTraceCollectorEndpoint": "testCollectorURL",
- "healthzLivenessTimeout": "testHealthzLivenessTimeout",
- "targetCPUUtilizationPercentage": "testCPUUtilizationPercentage",
- "resourcesConfiguration": map[string]interface{}{
- "function": map[string]interface{}{
- "resources": map[string]interface{}{
- "defaultPreset": "testPodPreset",
- },
- },
- "buildJob": map[string]interface{}{
- "resources": map[string]interface{}{
- "defaultPreset": "testJobPreset",
- },
- },
- },
+ "functionPublisherProxyAddress": "testPublisherURL",
+ "functionTraceCollectorEndpoint": "testCollectorURL",
+ "healthzLivenessTimeout": "testHealthzLivenessTimeout",
},
},
},
@@ -48,7 +30,6 @@ func Test_flagsBuilder_Build(t *testing.T) {
"rollme": "dontrollplease",
},
"dockerRegistry": map[string]interface{}{
- "enableInternal": false,
"password": "testPassword",
"registryAddress": "testRegistryAddress",
"serverAddress": "testServerAddress",
@@ -61,20 +42,12 @@ func Test_flagsBuilder_Build(t *testing.T) {
flags := NewFlagsBuilder().
WithNodePort(1234).
- WithDefaultPresetFlags("testJobPreset", "testPodPreset").
WithOptionalDependencies("testPublisherURL", "testCollectorURL").
WithRegistryAddresses("testRegistryAddress", "testServerAddress").
WithRegistryCredentials("testUsername", "testPassword").
- WithRegistryEnableInternal(false).
WithRegistryHttpSecret("testHttpSecret").
WithControllerConfiguration(
- "testCPUUtilizationPercentage",
- "testRequeueDuration",
- "testBuildExecutorArgs",
- "testMaxSimultaneousJobs",
"testHealthzLivenessTimeout",
- "testRequestBodyLimitMb",
- "testTimeoutSec",
).Build()
require.Equal(t, expectedFlags, flags)
@@ -104,10 +77,7 @@ func Test_flagsBuilder_Build(t *testing.T) {
"manager": map[string]interface{}{
"configuration": map[string]interface{}{
"data": map[string]interface{}{
- "functionBuildMaxSimultaneousJobs": "testMaxSimultaneousJobs",
- "functionRequestBodyLimitMb": "testRequestBodyLimitMb",
- "healthzLivenessTimeout": "testHealthzLivenessTimeout",
- "targetCPUUtilizationPercentage": "testCPUUtilizationPercentage",
+ "healthzLivenessTimeout": "testHealthzLivenessTimeout",
},
},
},
@@ -116,13 +86,7 @@ func Test_flagsBuilder_Build(t *testing.T) {
flags := NewFlagsBuilder().
WithControllerConfiguration(
- "testCPUUtilizationPercentage",
- "",
- "",
- "testMaxSimultaneousJobs",
"testHealthzLivenessTimeout",
- "testRequestBodyLimitMb",
- "",
).Build()
require.Equal(t, expectedFlags, flags)
diff --git a/components/operator/internal/chart/install.go b/components/operator/internal/chart/install.go
index dc4560fe7..91fe4a7bd 100644
--- a/components/operator/internal/chart/install.go
+++ b/components/operator/internal/chart/install.go
@@ -36,7 +36,7 @@ func install(config *Config, customFlags map[string]interface{}, renderChartFunc
return err
}
- return config.Cache.Set(config.Ctx, config.CacheKey, ServerlessSpecManifest{
+ return config.Cache.Set(config.Ctx, config.CacheKey, DockerRegistrySpecManifest{
ManagerUID: config.ManagerUID,
CustomFlags: customFlags,
Manifest: currentManifest,
@@ -76,20 +76,11 @@ func updateObjects(config *Config, objs []unstructured.Unstructured) error {
// maybe we should in this case translate applied objs into manifest and set it into cache?
err := config.Cluster.Client.Patch(config.Ctx, &u, client.Apply, &client.PatchOptions{
Force: ptr.To[bool](true),
- FieldManager: "serverless-operator",
+ FieldManager: "dockerregistry-operator",
})
if err != nil {
return fmt.Errorf("could not install object %s/%s: %s", u.GetNamespace(), u.GetName(), err.Error())
}
-
- // remove old reconciler "DO NOT EDIT" disclaimer
- // TODO: remove this functionality when all clusters are migrated to the serverless-manager
- err = annotation.DeleteReconcilerDisclaimer(
- config.Cluster.Client, *config.Cluster.Config, u)
- if err != nil {
- return fmt.Errorf("could not remove old reconciler annotation for object %s/%s: %s",
- u.GetNamespace(), u.GetName(), err.Error())
- }
}
return nil
}
diff --git a/components/operator/internal/chart/install_test.go b/components/operator/internal/chart/install_test.go
index b1ae2682c..377def8a8 100644
--- a/components/operator/internal/chart/install_test.go
+++ b/components/operator/internal/chart/install_test.go
@@ -81,7 +81,7 @@ func Test_install_delete(t *testing.T) {
}
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), testManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
client := fake.NewClientBuilder().WithObjects(testDeployCR).WithObjects(testCRDObj).Build()
customFlags := map[string]interface{}{
"flag1": "val1",
@@ -124,11 +124,11 @@ func Test_install(t *testing.T) {
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), testManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
_ = cache.Set(context.Background(), emptyManifestKey,
- ServerlessSpecManifest{Manifest: ""})
+ DockerRegistrySpecManifest{Manifest: ""})
_ = cache.Set(context.Background(), wrongManifestKey,
- ServerlessSpecManifest{Manifest: "api: test\n\tversion: test"})
+ DockerRegistrySpecManifest{Manifest: "api: test\n\tversion: test"})
type args struct {
config *Config
diff --git a/components/operator/internal/chart/pvc.go b/components/operator/internal/chart/pvc.go
index 2ad3376cb..f178c9d8d 100644
--- a/components/operator/internal/chart/pvc.go
+++ b/components/operator/internal/chart/pvc.go
@@ -13,7 +13,7 @@ import (
)
const (
- dockerRegistryPVCName = "serverless-docker-registry"
+ dockerRegistryPVCName = "internal-docker-registry"
pvcKind = "PersistentVolumeClaim"
pvcVersion = "v1"
pvcGroup = ""
diff --git a/components/operator/internal/chart/uninstall.go b/components/operator/internal/chart/uninstall.go
index af8cb70c5..b1c9e06b5 100644
--- a/components/operator/internal/chart/uninstall.go
+++ b/components/operator/internal/chart/uninstall.go
@@ -118,7 +118,7 @@ func uninstallOrphanedResources(config *Config) error {
//TODO: move this to finalizers logic in controller
var namespaces corev1.NamespaceList
if err := config.Cluster.Client.List(config.Ctx, &namespaces); err != nil {
- return errors.Wrap(err, "couldn't get namespaces during Serverless uninstallation")
+ return errors.Wrap(err, "couldn't get namespaces during Docker Registry uninstallation")
}
if err := uninstallOrphanedConfigMaps(config, namespaces); err != nil {
@@ -138,7 +138,7 @@ func uninstallOrphanedServiceAccounts(config *Config, namespaces corev1.Namespac
client.MatchingLabels{"serverless.kyma-project.io/config": "service-account"})
if err != nil {
return errors.Wrapf(err,
- "couldn't delete ServiceAccount from namespace \"%s\" during Serverless uninstallation",
+ "couldn't delete ServiceAccount from namespace \"%s\" during DockerRegistry uninstallation",
namespace.GetName())
}
}
@@ -152,7 +152,7 @@ func uninstallOrphanedConfigMaps(config *Config, namespaces corev1.NamespaceList
client.MatchingLabels{"serverless.kyma-project.io/config": "runtime"})
if err != nil {
return errors.Wrapf(err,
- "couldn't delete ConfigMap from namespace \"%s\" during Serverless uninstallation",
+ "couldn't delete ConfigMap from namespace \"%s\" during Docker Registry uninstallation",
namespace.GetName())
}
}
diff --git a/components/operator/internal/chart/uninstall_test.go b/components/operator/internal/chart/uninstall_test.go
index 367075862..17b3c8272 100644
--- a/components/operator/internal/chart/uninstall_test.go
+++ b/components/operator/internal/chart/uninstall_test.go
@@ -28,11 +28,11 @@ func Test_Uninstall(t *testing.T) {
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), testManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
_ = cache.Set(context.Background(), emptyManifestKey,
- ServerlessSpecManifest{Manifest: ""})
+ DockerRegistrySpecManifest{Manifest: ""})
_ = cache.Set(context.Background(), wrongManifestKey,
- ServerlessSpecManifest{Manifest: "api: test\n\tversion: test"})
+ DockerRegistrySpecManifest{Manifest: "api: test\n\tversion: test"})
ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}}
diff --git a/components/operator/internal/chart/verify_test.go b/components/operator/internal/chart/verify_test.go
index 8adc8c943..bd54fd372 100644
--- a/components/operator/internal/chart/verify_test.go
+++ b/components/operator/internal/chart/verify_test.go
@@ -45,11 +45,11 @@ func Test_verify(t *testing.T) {
cache := NewInMemoryManifestCache()
_ = cache.Set(context.Background(), testManifestKey,
- ServerlessSpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
+ DockerRegistrySpecManifest{Manifest: fmt.Sprint(testCRD, separator, testDeploy)})
_ = cache.Set(context.Background(), emptyManifestKey,
- ServerlessSpecManifest{Manifest: "---"})
+ DockerRegistrySpecManifest{Manifest: "---"})
_ = cache.Set(context.Background(), wrongManifestKey,
- ServerlessSpecManifest{Manifest: "api: test\n\tversion: test"})
+ DockerRegistrySpecManifest{Manifest: "api: test\n\tversion: test"})
type args struct {
config *Config
diff --git a/components/serverless/internal/controllers/kubernetes/configmap_service.go b/components/operator/internal/controllers/kubernetes/configmap_service.go
similarity index 97%
rename from components/serverless/internal/controllers/kubernetes/configmap_service.go
rename to components/operator/internal/controllers/kubernetes/configmap_service.go
index 25a03b368..219501baf 100644
--- a/components/serverless/internal/controllers/kubernetes/configmap_service.go
+++ b/components/operator/internal/controllers/kubernetes/configmap_service.go
@@ -11,7 +11,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
+ "github.com/kyma-project/serverless/components/operator/internal/resource"
)
type ConfigMapService interface {
diff --git a/components/serverless/internal/controllers/kubernetes/namespace_controller.go b/components/operator/internal/controllers/kubernetes/namespace_controller.go
similarity index 100%
rename from components/serverless/internal/controllers/kubernetes/namespace_controller.go
rename to components/operator/internal/controllers/kubernetes/namespace_controller.go
diff --git a/components/serverless/internal/controllers/kubernetes/secret_controller.go b/components/operator/internal/controllers/kubernetes/secret_controller.go
similarity index 100%
rename from components/serverless/internal/controllers/kubernetes/secret_controller.go
rename to components/operator/internal/controllers/kubernetes/secret_controller.go
diff --git a/components/serverless/internal/controllers/kubernetes/secret_service.go b/components/operator/internal/controllers/kubernetes/secret_service.go
similarity index 92%
rename from components/serverless/internal/controllers/kubernetes/secret_service.go
rename to components/operator/internal/controllers/kubernetes/secret_service.go
index 60fce07f2..c376cae0d 100644
--- a/components/serverless/internal/controllers/kubernetes/secret_service.go
+++ b/components/operator/internal/controllers/kubernetes/secret_service.go
@@ -3,8 +3,6 @@ package kubernetes
import (
"context"
"fmt"
-
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
@@ -13,10 +11,14 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
+ "github.com/kyma-project/serverless/components/operator/internal/resource"
)
-const cfgSecretFinalizerName = "serverless.kyma-project.io/finalizer-registry-config"
+const (
+ FunctionManagedByLabel = "serverless.kyma-project.io/managed-by"
+ cfgSecretFinalizerName = "serverless.kyma-project.io/finalizer-registry-config"
+ FunctionResourceLabelUserValue = "user"
+)
type SecretService interface {
IsBase(secret *corev1.Secret) bool
@@ -65,7 +67,7 @@ func (r *secretService) UpdateNamespace(ctx context.Context, logger *zap.Sugared
logger.Error(err, fmt.Sprintf("Gathering existing Secret '%s/%s' failed", namespace, baseInstance.GetName()))
return err
}
- if instance.Labels[v1alpha2.FunctionManagedByLabel] == v1alpha2.FunctionResourceLabelUserValue {
+ if instance.Labels[FunctionManagedByLabel] == FunctionResourceLabelUserValue {
return nil
}
return r.updateSecret(ctx, logger, instance, baseInstance)
@@ -141,7 +143,7 @@ func (r *secretService) deleteSecret(ctx context.Context, logger *zap.SugaredLog
if err := r.client.Get(ctx, client.ObjectKey{Namespace: namespace, Name: baseInstanceName}, instance); err != nil {
return client.IgnoreNotFound(err)
}
- if instance.Labels[v1alpha2.FunctionManagedByLabel] == v1alpha2.FunctionResourceLabelUserValue {
+ if instance.Labels[FunctionManagedByLabel] == FunctionResourceLabelUserValue {
return nil
}
if err := r.client.Delete(ctx, instance); err != nil {
diff --git a/components/serverless/internal/controllers/kubernetes/serviceaccount_service.go b/components/operator/internal/controllers/kubernetes/serviceaccount_service.go
similarity index 98%
rename from components/serverless/internal/controllers/kubernetes/serviceaccount_service.go
rename to components/operator/internal/controllers/kubernetes/serviceaccount_service.go
index 5bf12183d..986f30742 100644
--- a/components/serverless/internal/controllers/kubernetes/serviceaccount_service.go
+++ b/components/operator/internal/controllers/kubernetes/serviceaccount_service.go
@@ -12,7 +12,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
+ "github.com/kyma-project/serverless/components/operator/internal/resource"
)
type ServiceAccountService interface {
diff --git a/components/serverless/internal/controllers/kubernetes/shared.go b/components/operator/internal/controllers/kubernetes/shared.go
similarity index 100%
rename from components/serverless/internal/controllers/kubernetes/shared.go
rename to components/operator/internal/controllers/kubernetes/shared.go
diff --git a/components/operator/internal/registry/node_port.go b/components/operator/internal/registry/node_port.go
index 1c1936f89..f7c84e4ee 100644
--- a/components/operator/internal/registry/node_port.go
+++ b/components/operator/internal/registry/node_port.go
@@ -19,7 +19,7 @@ const (
)
const (
- dockerRegistryService = "serverless-docker-registry"
+ dockerRegistryService = "internal-docker-registry"
dockerRegistryPortName = "http-registry"
allNamespaces = ""
diff --git a/components/operator/internal/registry/secret.go b/components/operator/internal/registry/secret.go
index 909e13a5d..d6f5780cd 100644
--- a/components/operator/internal/registry/secret.go
+++ b/components/operator/internal/registry/secret.go
@@ -11,26 +11,26 @@ import (
)
const (
- ServerlessRegistryDefaultSecretName = "serverless-registry-config-default"
- ServerlessExternalRegistrySecretName = "serverless-registry-config"
- ServerlessExternalRegistryLabelRemoteRegistryKey = "serverless.kyma-project.io/remote-registry"
- ServerlessExternalRegistryLabelRemoteRegistryVal = "config"
- ServerlessExternalRegistryLabelConfigKey = "serverless.kyma-project.io/config"
- ServerlessExternalRegistryLabelConfigVal = "credentials"
- ServerlessRegistryIsInternalKey = "isInternal"
- ServerlessDockerRegistryDeploymentName = "serverless-docker-registry"
- RegistryHTTPEnvKey = "REGISTRY_HTTP_SECRET"
+ RegistryDefaultSecretName = "serverless-registry-config-default"
+ ExternalRegistrySecretName = "serverless-registry-config"
+ ExternalRegistryLabelRemoteRegistryKey = "serverless.kyma-project.io/remote-registry"
+ ExternalRegistryLabelRemoteRegistryVal = "config"
+ ExternalRegistryLabelConfigKey = "serverless.kyma-project.io/config"
+ ExternalRegistryLabelConfigVal = "credentials"
+ RegistryIsInternalKey = "isInternal"
+ DockerRegistryDeploymentName = "internal-docker-registry"
+ RegistryHTTPEnvKey = "REGISTRY_HTTP_SECRET"
)
func ListExternalNamespacedScopeSecrets(ctx context.Context, c client.Client) ([]corev1.Secret, error) {
// has config label
- remoteRegistryLabelRequirement, _ := labels.NewRequirement(ServerlessExternalRegistryLabelRemoteRegistryKey, selection.Equals, []string{
- ServerlessExternalRegistryLabelRemoteRegistryVal,
+ remoteRegistryLabelRequirement, _ := labels.NewRequirement(ExternalRegistryLabelRemoteRegistryKey, selection.Equals, []string{
+ ExternalRegistryLabelRemoteRegistryVal,
})
// has not credentials label
- configLabelRequirement, _ := labels.NewRequirement(ServerlessExternalRegistryLabelConfigKey, selection.DoesNotExist, []string{})
+ configLabelRequirement, _ := labels.NewRequirement(ExternalRegistryLabelConfigKey, selection.DoesNotExist, []string{})
labeledSecrets := corev1.SecretList{}
err := c.List(ctx, &labeledSecrets, &client.ListOptions{
@@ -45,7 +45,7 @@ func ListExternalNamespacedScopeSecrets(ctx context.Context, c client.Client) ([
secrets := []corev1.Secret{}
for _, secret := range labeledSecrets.Items {
- if secret.Name == ServerlessExternalRegistrySecretName {
+ if secret.Name == ExternalRegistrySecretName {
secrets = append(secrets, secret)
}
}
@@ -57,39 +57,39 @@ func GetExternalClusterWideRegistrySecret(ctx context.Context, c client.Client,
secret := corev1.Secret{}
key := client.ObjectKey{
Namespace: namespace,
- Name: ServerlessExternalRegistrySecretName,
+ Name: ExternalRegistrySecretName,
}
err := c.Get(ctx, key, &secret)
if err != nil {
return nil, client.IgnoreNotFound(err)
}
- if val, ok := secret.GetLabels()[ServerlessExternalRegistryLabelRemoteRegistryKey]; !ok || val != ServerlessExternalRegistryLabelRemoteRegistryVal {
+ if val, ok := secret.GetLabels()[ExternalRegistryLabelRemoteRegistryKey]; !ok || val != ExternalRegistryLabelRemoteRegistryVal {
return nil, nil
}
- if val, ok := secret.GetLabels()[ServerlessExternalRegistryLabelConfigKey]; !ok || val != ServerlessExternalRegistryLabelConfigVal {
+ if val, ok := secret.GetLabels()[ExternalRegistryLabelConfigKey]; !ok || val != ExternalRegistryLabelConfigVal {
return nil, nil
}
return &secret, nil
}
-func GetServerlessInternalRegistrySecret(ctx context.Context, c client.Client, namespace string) (*corev1.Secret, error) {
+func GetDockerRegistryInternalRegistrySecret(ctx context.Context, c client.Client, namespace string) (*corev1.Secret, error) {
secret := corev1.Secret{}
key := client.ObjectKey{
Namespace: namespace,
- Name: ServerlessRegistryDefaultSecretName,
+ Name: RegistryDefaultSecretName,
}
err := c.Get(ctx, key, &secret)
if err != nil {
return nil, client.IgnoreNotFound(err)
}
- if val, ok := secret.GetLabels()[ServerlessExternalRegistryLabelConfigKey]; !ok || val != ServerlessExternalRegistryLabelConfigVal {
+ if val, ok := secret.GetLabels()[ExternalRegistryLabelConfigKey]; !ok || val != ExternalRegistryLabelConfigVal {
return nil, nil
}
- if val := string(secret.Data[ServerlessRegistryIsInternalKey]); val != "true" {
+ if val := string(secret.Data[RegistryIsInternalKey]); val != "true" {
return nil, nil
}
@@ -100,7 +100,7 @@ func GetRegistryHTTPSecretEnvValue(ctx context.Context, c client.Client, namespa
deployment := appsv1.Deployment{}
key := client.ObjectKey{
Namespace: namespace,
- Name: ServerlessDockerRegistryDeploymentName,
+ Name: DockerRegistryDeploymentName,
}
err := c.Get(ctx, key, &deployment)
if err != nil {
diff --git a/components/operator/internal/registry/secret_test.go b/components/operator/internal/registry/secret_test.go
index 9bdde1889..d5d2f7fce 100644
--- a/components/operator/internal/registry/secret_test.go
+++ b/components/operator/internal/registry/secret_test.go
@@ -12,7 +12,7 @@ import (
)
var (
- testRegistryFilledSecret = FixServerlessClusterWideExternalRegistrySecret()
+ testRegistryFilledSecret = FixClusterWideExternalRegistrySecret()
)
func Test_GetExternalRegistrySecret(t *testing.T) {
@@ -56,7 +56,7 @@ func Test_GetExternalRegistrySecret(t *testing.T) {
name: "without label remote-registry",
secretInEnvironment: func() *corev1.Secret {
secret := testRegistryFilledSecret.DeepCopy()
- delete(secret.Labels, ServerlessExternalRegistryLabelRemoteRegistryKey)
+ delete(secret.Labels, ExternalRegistryLabelRemoteRegistryKey)
return secret
}(),
},
@@ -64,7 +64,7 @@ func Test_GetExternalRegistrySecret(t *testing.T) {
name: "without label config",
secretInEnvironment: func() *corev1.Secret {
secret := testRegistryFilledSecret.DeepCopy()
- delete(secret.Labels, ServerlessExternalRegistryLabelConfigKey)
+ delete(secret.Labels, ExternalRegistryLabelConfigKey)
return secret
}(),
},
@@ -101,10 +101,10 @@ func TestListExternalNamespacedScopeSecrets(t *testing.T) {
client := fake.NewClientBuilder().
WithRuntimeObjects(&corev1.Secret{
ObjectMeta: v1.ObjectMeta{
- Name: ServerlessExternalRegistrySecretName,
+ Name: ExternalRegistrySecretName,
Namespace: "default",
Labels: map[string]string{
- ServerlessExternalRegistryLabelRemoteRegistryKey: ServerlessExternalRegistryLabelRemoteRegistryVal,
+ ExternalRegistryLabelRemoteRegistryKey: ExternalRegistryLabelRemoteRegistryVal,
},
},
}).
@@ -124,7 +124,7 @@ func TestListExternalNamespacedScopeSecrets(t *testing.T) {
Name: "wrong-name",
Namespace: "default",
Labels: map[string]string{
- ServerlessExternalRegistryLabelRemoteRegistryKey: ServerlessExternalRegistryLabelRemoteRegistryVal,
+ ExternalRegistryLabelRemoteRegistryKey: ExternalRegistryLabelRemoteRegistryVal,
},
},
}).
@@ -141,11 +141,11 @@ func TestListExternalNamespacedScopeSecrets(t *testing.T) {
client := fake.NewClientBuilder().
WithRuntimeObjects(&corev1.Secret{
ObjectMeta: v1.ObjectMeta{
- Name: ServerlessExternalRegistrySecretName,
+ Name: ExternalRegistrySecretName,
Namespace: "default",
Labels: map[string]string{
- ServerlessExternalRegistryLabelRemoteRegistryKey: ServerlessExternalRegistryLabelRemoteRegistryVal,
- ServerlessExternalRegistryLabelConfigKey: ServerlessExternalRegistryLabelConfigVal,
+ ExternalRegistryLabelRemoteRegistryKey: ExternalRegistryLabelRemoteRegistryVal,
+ ExternalRegistryLabelConfigKey: ExternalRegistryLabelConfigVal,
},
},
}).
diff --git a/components/operator/internal/registry/test_helpers.go b/components/operator/internal/registry/test_helpers.go
index 22cd162c5..95c23e825 100644
--- a/components/operator/internal/registry/test_helpers.go
+++ b/components/operator/internal/registry/test_helpers.go
@@ -5,18 +5,18 @@ import (
v12 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
-func FixServerlessClusterWideExternalRegistrySecret() *v1.Secret {
+func FixClusterWideExternalRegistrySecret() *v1.Secret {
return &v1.Secret{
TypeMeta: v12.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: v12.ObjectMeta{
- Name: ServerlessExternalRegistrySecretName,
+ Name: ExternalRegistrySecretName,
Namespace: "kyma-test",
Labels: map[string]string{
- ServerlessExternalRegistryLabelRemoteRegistryKey: ServerlessExternalRegistryLabelRemoteRegistryVal,
- ServerlessExternalRegistryLabelConfigKey: ServerlessExternalRegistryLabelConfigVal,
+ ExternalRegistryLabelRemoteRegistryKey: ExternalRegistryLabelRemoteRegistryVal,
+ ExternalRegistryLabelConfigKey: ExternalRegistryLabelConfigVal,
},
},
Type: v1.SecretTypeDockerConfigJson,
diff --git a/components/serverless/internal/resource/resource.go b/components/operator/internal/resource/resource.go
similarity index 100%
rename from components/serverless/internal/resource/resource.go
rename to components/operator/internal/resource/resource.go
diff --git a/components/operator/internal/state/add_finalizer.go b/components/operator/internal/state/add_finalizer.go
index 2ce322895..9ed072955 100644
--- a/components/operator/internal/state/add_finalizer.go
+++ b/components/operator/internal/state/add_finalizer.go
@@ -28,5 +28,5 @@ func sFnAddFinalizer(ctx context.Context, r *reconciler, s *systemState) (stateF
func addFinalizer(ctx context.Context, r *reconciler, s *systemState) error {
// in case instance does not have finalizer - add it and update instance
controllerutil.AddFinalizer(&s.instance, r.finalizer)
- return updateServerlessWithoutStatus(ctx, r, s)
+ return updateDockerRegistryWithoutStatus(ctx, r, s)
}
diff --git a/components/operator/internal/state/add_finalizer_test.go b/components/operator/internal/state/add_finalizer_test.go
index 01ac503af..772b88944 100644
--- a/components/operator/internal/state/add_finalizer_test.go
+++ b/components/operator/internal/state/add_finalizer_test.go
@@ -16,7 +16,7 @@ func Test_sFnAddFinalizer(t *testing.T) {
scheme := runtime.NewScheme()
require.NoError(t, v1alpha1.AddToScheme(scheme))
- serverless := v1alpha1.Serverless{
+ dockerRegistry := v1alpha1.DockerRegistry{
ObjectMeta: v1.ObjectMeta{
Name: "test-name",
Namespace: "test-namespace",
@@ -24,7 +24,7 @@ func Test_sFnAddFinalizer(t *testing.T) {
},
}
s := &systemState{
- instance: serverless,
+ instance: dockerRegistry,
}
r := &reconciler{
cfg: cfg{
@@ -33,7 +33,7 @@ func Test_sFnAddFinalizer(t *testing.T) {
k8s: k8s{
client: fake.NewClientBuilder().
WithScheme(scheme).
- WithObjects(&serverless).
+ WithObjects(&dockerRegistry).
Build(),
},
}
@@ -48,11 +48,11 @@ func Test_sFnAddFinalizer(t *testing.T) {
require.Contains(t, s.instance.GetFinalizers(), r.cfg.finalizer)
// check finalizer in k8s
- obj := v1alpha1.Serverless{}
+ obj := v1alpha1.DockerRegistry{}
err = r.k8s.client.Get(context.Background(),
client.ObjectKey{
- Namespace: serverless.Namespace,
- Name: serverless.Name,
+ Namespace: dockerRegistry.Namespace,
+ Name: dockerRegistry.Name,
},
&obj)
require.NoError(t, err)
@@ -68,7 +68,7 @@ func Test_sFnAddFinalizer(t *testing.T) {
metaTimeNow := v1.Now()
s := &systemState{
- instance: v1alpha1.Serverless{
+ instance: v1alpha1.DockerRegistry{
ObjectMeta: v1.ObjectMeta{
DeletionTimestamp: &metaTimeNow,
},
diff --git a/components/operator/internal/state/apply.go b/components/operator/internal/state/apply.go
index e08fb93c5..e15014f0d 100644
--- a/components/operator/internal/state/apply.go
+++ b/components/operator/internal/state/apply.go
@@ -9,7 +9,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
-// run serverless chart installation
+// run dockerregistry chart installation
func sFnApplyResources(_ context.Context, r *reconciler, s *systemState) (stateFn, *ctrl.Result, error) {
// set condition Installed if it does not exist
if !s.instance.IsCondition(v1alpha1.ConditionTypeInstalled) {
diff --git a/components/operator/internal/state/apply_test.go b/components/operator/internal/state/apply_test.go
index a14c6cc1a..01b66b8d9 100644
--- a/components/operator/internal/state/apply_test.go
+++ b/components/operator/internal/state/apply_test.go
@@ -15,16 +15,16 @@ import (
func Test_buildSFnApplyResources(t *testing.T) {
t.Run("switch state and add condition when condition is missing", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{},
+ instance: v1alpha1.DockerRegistry{},
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
Release: chart.Release{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
flagsBuilder: chart.NewFlagsBuilder(),
@@ -47,16 +47,16 @@ func Test_buildSFnApplyResources(t *testing.T) {
t.Run("apply resources", func(t *testing.T) {
s := &systemState{
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
Release: chart.Release{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
flagsBuilder: chart.NewFlagsBuilder(),
@@ -72,12 +72,12 @@ func Test_buildSFnApplyResources(t *testing.T) {
t.Run("install chart error", func(t *testing.T) {
s := &systemState{
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixManifestCache("\t"),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
flagsBuilder: chart.NewFlagsBuilder(),
diff --git a/components/operator/internal/state/controller_configuration.go b/components/operator/internal/state/controller_configuration.go
index 84cb2f8fd..457d96ec2 100644
--- a/components/operator/internal/state/controller_configuration.go
+++ b/components/operator/internal/state/controller_configuration.go
@@ -4,16 +4,7 @@ import (
"context"
"github.com/kyma-project/serverless/components/operator/api/v1alpha1"
- corev1 "k8s.io/api/core/v1"
controllerruntime "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-const (
- slowBuildPreset = "slow"
- slowRuntimePreset = "XS"
- fastBuildPreset = "fast"
- fastRuntimePreset = "L"
)
func sFnControllerConfiguration(ctx context.Context, r *reconciler, s *systemState) (stateFn, *controllerruntime.Result, error) {
@@ -34,30 +25,10 @@ func sFnControllerConfiguration(ctx context.Context, r *reconciler, s *systemSta
return nextState(sFnApplyResources)
}
-func updateControllerConfigurationStatus(ctx context.Context, r *reconciler, instance *v1alpha1.Serverless) error {
- nodesLen, err := getNodesLen(ctx, r.client)
- if err != nil {
- return err
- }
-
- defaultBuildPreset := slowBuildPreset
- defaultRuntimePreset := slowRuntimePreset
- if nodesLen > 2 {
- defaultBuildPreset = fastBuildPreset
- defaultRuntimePreset = fastRuntimePreset
- }
-
+func updateControllerConfigurationStatus(ctx context.Context, r *reconciler, instance *v1alpha1.DockerRegistry) error {
spec := instance.Spec
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.FunctionRequestBodyLimitMb, &instance.Status.RequestBodyLimitMb, "Max size of request body", ""},
- {spec.FunctionTimeoutSec, &instance.Status.TimeoutSec, "Timeout", ""},
- {spec.DefaultBuildJobPreset, &instance.Status.DefaultBuildJobPreset, "Default build job preset", defaultBuildPreset},
- {spec.DefaultRuntimePodPreset, &instance.Status.DefaultRuntimePodPreset, "Default runtime pod preset", defaultRuntimePreset},
}
updateStatusFields(r.k8s, instance, fields)
@@ -67,26 +38,6 @@ func updateControllerConfigurationStatus(ctx context.Context, r *reconciler, ins
func configureControllerConfigurationFlags(s *systemState) {
s.flagsBuilder.
WithControllerConfiguration(
- s.instance.Status.CPUUtilizationPercentage,
- s.instance.Status.RequeueDuration,
- s.instance.Status.BuildExecutorArgs,
- s.instance.Status.BuildMaxSimultaneousJobs,
s.instance.Status.HealthzLivenessTimeout,
- s.instance.Status.RequestBodyLimitMb,
- s.instance.Status.TimeoutSec,
- ).
- WithDefaultPresetFlags(
- s.instance.Status.DefaultBuildJobPreset,
- s.instance.Status.DefaultRuntimePodPreset,
)
}
-
-func getNodesLen(ctx context.Context, c client.Client) (int, error) {
- nodeList := corev1.NodeList{}
- err := c.List(ctx, &nodeList)
- if err != nil {
- return 0, err
- }
-
- return len(nodeList.Items), nil
-}
diff --git a/components/operator/internal/state/controller_configuration_test.go b/components/operator/internal/state/controller_configuration_test.go
index b35459499..f48265354 100644
--- a/components/operator/internal/state/controller_configuration_test.go
+++ b/components/operator/internal/state/controller_configuration_test.go
@@ -11,7 +11,6 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/tools/record"
- "k8s.io/utils/ptr"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
@@ -30,107 +29,11 @@ const (
func Test_sFnControllerConfiguration(t *testing.T) {
configurationReadyMsg := "Configuration ready"
- t.Run("update status with slow defaults", 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(2)
- 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, slowBuildPreset, 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 build job preset set from '' to 'slow'",
- "Normal Configuration Default runtime pod preset set from '' to 'XS'",
- }
-
- for _, expectedEvent := range expectedEvents {
- require.Equal(t, expectedEvent, <-eventRecorder.Events)
- }
- })
-
- t.Run("update slow default to fast ones", func(t *testing.T) {
- s := &systemState{
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{},
- Status: v1alpha1.ServerlessStatus{
- DefaultBuildJobPreset: slowBuildPreset,
- DefaultRuntimePodPreset: slowRuntimePreset,
- },
- },
- flagsBuilder: chart.NewFlagsBuilder(),
- }
-
- c := fake.NewClientBuilder().WithObjects(
- fixTestNode("node-1"),
- fixTestNode("node-2"),
- fixTestNode("node-3"),
- fixTestNode("node-4"),
- ).Build()
- eventRecorder := record.NewFakeRecorder(2)
- 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, fastBuildPreset, status.DefaultBuildJobPreset)
- require.Equal(t, fastRuntimePreset, status.DefaultRuntimePodPreset)
-
- require.Equal(t, v1alpha1.StateProcessing, status.State)
- requireContainsCondition(t, status,
- v1alpha1.ConditionTypeConfigured,
- metav1.ConditionTrue,
- v1alpha1.ConditionReasonConfigured,
- configurationReadyMsg,
- )
-
- expectedEvents := []string{
- "Normal Configuration Default build job preset set from 'slow' to 'fast'",
- "Normal Configuration Default runtime pod preset set from 'XS' to 'L'",
- }
-
- for _, expectedEvent := range expectedEvents {
- require.Equal(t, expectedEvent, <-eventRecorder.Events)
- }
- })
-
t.Run("update status additional configuration overrides", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{
- TargetCPUUtilizationPercentage: cpuUtilizationTest,
- FunctionRequeueDuration: requeueDurationTest,
- FunctionBuildExecutorArgs: executorArgsTest,
- FunctionBuildMaxSimultaneousJobs: maxSimultaneousJobsTest,
- HealthzLivenessTimeout: healthzLivenessTimeoutTest,
- FunctionRequestBodyLimitMb: requestBodyLimitMbTest,
- FunctionTimeoutSec: timeoutSecTest,
- DefaultBuildJobPreset: buildJobPresetTest,
- DefaultRuntimePodPreset: runtimePodPresetTest,
+ instance: v1alpha1.DockerRegistry{
+ Spec: v1alpha1.DockerRegistrySpec{
+ HealthzLivenessTimeout: healthzLivenessTimeoutTest,
},
},
flagsBuilder: chart.NewFlagsBuilder(),
@@ -145,15 +48,7 @@ func Test_sFnControllerConfiguration(t *testing.T) {
requireEqualFunc(t, sFnApplyResources, next)
status := s.instance.Status
- require.Equal(t, cpuUtilizationTest, status.CPUUtilizationPercentage)
- require.Equal(t, requeueDurationTest, status.RequeueDuration)
- require.Equal(t, executorArgsTest, status.BuildExecutorArgs)
- require.Equal(t, maxSimultaneousJobsTest, status.BuildMaxSimultaneousJobs)
require.Equal(t, healthzLivenessTimeoutTest, status.HealthzLivenessTimeout)
- require.Equal(t, requestBodyLimitMbTest, status.RequestBodyLimitMb)
- require.Equal(t, timeoutSecTest, status.TimeoutSec)
- require.Equal(t, buildJobPresetTest, status.DefaultBuildJobPreset)
- require.Equal(t, runtimePodPresetTest, status.DefaultRuntimePodPreset)
require.Equal(t, v1alpha1.StateProcessing, status.State)
requireContainsCondition(t, status,
@@ -164,15 +59,7 @@ func Test_sFnControllerConfiguration(t *testing.T) {
)
expectedEvents := []string{
- "Normal Configuration CPU utilization set from '' to 'test-CPU-utilization-percentage'",
- "Normal Configuration Function requeue duration set from '' to 'test-requeue-duration'",
- "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 Max size of request body set from '' to 'test-request-body-limit-mb'",
- "Normal Configuration Timeout set from '' to 'test-timeout-sec'",
- "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'",
}
for _, expectedEvent := range expectedEvents {
@@ -182,8 +69,8 @@ func Test_sFnControllerConfiguration(t *testing.T) {
t.Run("reconcile from configurationError", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ instance: v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Conditions: []metav1.Condition{
{
Type: string(v1alpha1.ConditionTypeConfigured),
@@ -196,23 +83,11 @@ func Test_sFnControllerConfiguration(t *testing.T) {
Reason: string(v1alpha1.ConditionReasonInstallation),
},
},
- State: v1alpha1.StateError,
- EventingEndpoint: "test-event-URL",
- TracingEndpoint: v1alpha1.EndpointDisabled,
- },
- Spec: v1alpha1.ServerlessSpec{
- Eventing: &v1alpha1.Endpoint{Endpoint: "test-event-URL"},
- Tracing: &v1alpha1.Endpoint{Endpoint: v1alpha1.EndpointDisabled},
- DockerRegistry: &v1alpha1.DockerRegistry{
- EnableInternal: ptr.To[bool](false),
- SecretName: ptr.To[string]("boo"),
- },
+ State: v1alpha1.StateError,
},
},
- statusSnapshot: v1alpha1.ServerlessStatus{
- DockerRegistry: "",
- },
- flagsBuilder: chart.NewFlagsBuilder(),
+ statusSnapshot: v1alpha1.DockerRegistryStatus{},
+ flagsBuilder: chart.NewFlagsBuilder(),
}
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
@@ -239,11 +114,3 @@ func Test_sFnControllerConfiguration(t *testing.T) {
require.Equal(t, v1alpha1.StateProcessing, s.instance.Status.State)
})
}
-
-func fixTestNode(name string) *corev1.Node {
- return &corev1.Node{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- },
- }
-}
diff --git a/components/operator/internal/state/delete.go b/components/operator/internal/state/delete.go
index 3d1877f44..ab66eed81 100644
--- a/components/operator/internal/state/delete.go
+++ b/components/operator/internal/state/delete.go
@@ -22,7 +22,7 @@ const (
upstreamDeletionStrategy deletionStrategy = "upstreamDeletionStrategy"
)
-// delete serverless based on previously installed resources
+// delete dockerregistry based on previously installed resources
func sFnDeleteResources(_ context.Context, _ *reconciler, s *systemState) (stateFn, *ctrl.Result, error) {
s.setState(v1alpha1.StateDeleting)
s.instance.UpdateConditionUnknown(
@@ -91,7 +91,7 @@ func deleteResourcesWithFilter(r *reconciler, s *systemState, filterFuncs ...cha
s.instance.UpdateConditionTrue(
v1alpha1.ConditionTypeDeleted,
v1alpha1.ConditionReasonDeleted,
- "Serverless module deleted",
+ "DockerRegistry module deleted",
)
// if resources are ready to be deleted, remove finalizer
diff --git a/components/operator/internal/state/delete_test.go b/components/operator/internal/state/delete_test.go
index 0b6bdc71e..933503758 100644
--- a/components/operator/internal/state/delete_test.go
+++ b/components/operator/internal/state/delete_test.go
@@ -16,17 +16,17 @@ import (
)
var (
- testDeletingServerless = func() v1alpha1.Serverless {
- serverless := testInstalledServerless
- serverless.Status.State = v1alpha1.StateDeleting
- serverless.Status.Conditions = []metav1.Condition{
+ testDeletingDockerRegistry = func() v1alpha1.DockerRegistry {
+ dockerRegistry := testInstalledDockerRegistry
+ dockerRegistry.Status.State = v1alpha1.StateDeleting
+ dockerRegistry.Status.Conditions = []metav1.Condition{
{
Type: string(v1alpha1.ConditionTypeDeleted),
Reason: string(v1alpha1.ConditionReasonDeletion),
Status: metav1.ConditionUnknown,
},
}
- return serverless
+ return dockerRegistry
}()
)
@@ -35,7 +35,7 @@ func Test_sFnDeleteResources(t *testing.T) {
t.Run("update condition", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{},
+ instance: v1alpha1.DockerRegistry{},
}
next, result, err := sFnDeleteResources(context.Background(), nil, s)
@@ -55,7 +55,7 @@ func Test_sFnDeleteResources(t *testing.T) {
t.Run("choose deletion strategy", func(t *testing.T) {
s := &systemState{
- instance: *testDeletingServerless.DeepCopy(),
+ instance: *testDeletingDockerRegistry.DeepCopy(),
}
next, result, err := sFnDeleteResources(context.Background(), nil, s)
@@ -69,12 +69,12 @@ func Test_sFnDeleteResources(t *testing.T) {
t.Run("cascade deletion", func(t *testing.T) {
fn := deletionStrategyBuilder(cascadeDeletionStrategy)
s := &systemState{
- instance: *testDeletingServerless.DeepCopy(),
+ instance: *testDeletingDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testDeletingServerless.GetName(),
- Namespace: testDeletingServerless.GetNamespace(),
+ Name: testDeletingDockerRegistry.GetName(),
+ Namespace: testDeletingDockerRegistry.GetNamespace(),
},
Cluster: chart.Cluster{
Client: fake.NewClientBuilder().
@@ -97,7 +97,7 @@ func Test_sFnDeleteResources(t *testing.T) {
v1alpha1.ConditionTypeDeleted,
metav1.ConditionTrue,
v1alpha1.ConditionReasonDeleted,
- "Serverless module deleted",
+ "DockerRegistry module deleted",
)
})
@@ -105,12 +105,12 @@ func Test_sFnDeleteResources(t *testing.T) {
fn := deletionStrategyBuilder(upstreamDeletionStrategy)
s := &systemState{
- instance: *testDeletingServerless.DeepCopy(),
+ instance: *testDeletingDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixManifestCache("\t"),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
}
@@ -137,12 +137,12 @@ func Test_sFnDeleteResources(t *testing.T) {
wrongStrategy := deletionStrategy("test-strategy")
fn := deletionStrategyBuilder(wrongStrategy)
s := &systemState{
- instance: *testDeletingServerless.DeepCopy(),
+ instance: *testDeletingDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixManifestCache("\t"),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
}
@@ -169,12 +169,12 @@ func Test_sFnDeleteResources(t *testing.T) {
wrongStrategy := deletionStrategy("test-strategy")
fn := deletionStrategyBuilder(wrongStrategy)
s := &systemState{
- instance: *testDeletingServerless.DeepCopy(),
+ instance: *testDeletingDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testDeletingServerless.GetName(),
- Namespace: testDeletingServerless.GetNamespace(),
+ Name: testDeletingDockerRegistry.GetName(),
+ Namespace: testDeletingDockerRegistry.GetNamespace(),
},
Cluster: chart.Cluster{
Client: fake.NewClientBuilder().
@@ -199,7 +199,7 @@ func Test_sFnDeleteResources(t *testing.T) {
v1alpha1.ConditionTypeDeleted,
metav1.ConditionTrue,
v1alpha1.ConditionReasonDeleted,
- "Serverless module deleted",
+ "DockerRegistry module deleted",
)
})
}
diff --git a/components/operator/internal/state/emit_event_test.go b/components/operator/internal/state/emit_event_test.go
index 129b28bdd..be75f6a98 100644
--- a/components/operator/internal/state/emit_event_test.go
+++ b/components/operator/internal/state/emit_event_test.go
@@ -10,8 +10,8 @@ import (
)
var (
- testServerlessConditions1 = v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ testDockerRegistryConditions1 = v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Conditions: []metav1.Condition{
{
Status: metav1.ConditionUnknown,
@@ -28,8 +28,8 @@ var (
},
},
}
- testServerlessConditions2 = v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ testDockerRegistryConditions2 = v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Conditions: []metav1.Condition{
{
Status: metav1.ConditionFalse,
@@ -52,8 +52,8 @@ func Test_emitEvent(t *testing.T) {
t.Run("don't emit event", func(t *testing.T) {
eventRecorder := record.NewFakeRecorder(5)
s := &systemState{
- instance: *testServerlessConditions1.DeepCopy(),
- statusSnapshot: *testServerlessConditions1.Status.DeepCopy(),
+ instance: *testDockerRegistryConditions1.DeepCopy(),
+ statusSnapshot: *testDockerRegistryConditions1.Status.DeepCopy(),
}
r := &reconciler{
k8s: k8s{
@@ -70,8 +70,8 @@ func Test_emitEvent(t *testing.T) {
t.Run("emit events", func(t *testing.T) {
eventRecorder := record.NewFakeRecorder(5)
s := &systemState{
- instance: *testServerlessConditions2.DeepCopy(),
- statusSnapshot: *testServerlessConditions1.Status.DeepCopy(),
+ instance: *testDockerRegistryConditions2.DeepCopy(),
+ statusSnapshot: *testDockerRegistryConditions1.Status.DeepCopy(),
}
r := &reconciler{
k8s: k8s{
diff --git a/components/operator/internal/state/fsm.go b/components/operator/internal/state/fsm.go
index f6d15c757..9ce5d7f1a 100644
--- a/components/operator/internal/state/fsm.go
+++ b/components/operator/internal/state/fsm.go
@@ -21,8 +21,8 @@ import (
var (
defaultResult = ctrl.Result{}
secretCacheKey = types.NamespacedName{
- Name: "serverless-manifest-cache",
- Namespace: "kyma-system", // TODO: detect serverless-manager's namespace
+ Name: "dockerregistry-manifest-cache",
+ Namespace: "kyma-system",
}
)
@@ -35,8 +35,8 @@ type cfg struct {
}
type systemState struct {
- instance v1alpha1.Serverless
- statusSnapshot v1alpha1.ServerlessStatus
+ instance v1alpha1.DockerRegistry
+ statusSnapshot v1alpha1.DockerRegistryStatus
chartConfig *chart.Config
warningBuilder *warning.Builder
flagsBuilder chart.FlagsBuilder
@@ -45,7 +45,7 @@ type systemState struct {
func (s *systemState) saveStatusSnapshot() {
result := s.instance.Status.DeepCopy()
if result == nil {
- result = &v1alpha1.ServerlessStatus{}
+ result = &v1alpha1.DockerRegistryStatus{}
}
s.statusSnapshot = *result
}
@@ -104,7 +104,7 @@ func (m *reconciler) stateFnName() string {
return shortName
}
-func (m *reconciler) Reconcile(ctx context.Context, v v1alpha1.Serverless) (ctrl.Result, error) {
+func (m *reconciler) Reconcile(ctx context.Context, v v1alpha1.DockerRegistry) (ctrl.Result, error) {
state := systemState{
instance: v,
warningBuilder: warning.NewBuilder(),
@@ -124,7 +124,7 @@ loop:
default:
m.log.Info(fmt.Sprintf("switching state: %s", m.stateFnName()))
m.fn, result, err = m.fn(ctx, m, &state)
- if updateErr := updateServerlessStatus(ctx, m, &state); updateErr != nil {
+ if updateErr := updateDockerRegistryStatus(ctx, m, &state); updateErr != nil {
err = updateErr
}
}
diff --git a/components/operator/internal/state/fsm_test.go b/components/operator/internal/state/fsm_test.go
index 2177554f6..85994d623 100644
--- a/components/operator/internal/state/fsm_test.go
+++ b/components/operator/internal/state/fsm_test.go
@@ -45,7 +45,7 @@ func Test_reconciler_Reconcile(t *testing.T) {
}
type args struct {
ctx context.Context
- v v1alpha1.Serverless
+ v v1alpha1.DockerRegistry
}
tests := []struct {
name string
@@ -124,8 +124,8 @@ func Test_reconciler_Reconcile(t *testing.T) {
},
log: zap.NewNop().Sugar(),
}
- serverless := v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ dockerRegistry := v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Conditions: []metav1.Condition{
{
Type: "test-type",
@@ -139,7 +139,7 @@ func Test_reconciler_Reconcile(t *testing.T) {
State: v1alpha1.StateError,
},
}
- _, err := r.Reconcile(context.Background(), serverless)
+ _, err := r.Reconcile(context.Background(), dockerRegistry)
require.NoError(t, err)
})
}
diff --git a/components/operator/internal/state/initialize_test.go b/components/operator/internal/state/initialize_test.go
index 535fea459..90049c4e3 100644
--- a/components/operator/internal/state/initialize_test.go
+++ b/components/operator/internal/state/initialize_test.go
@@ -21,13 +21,12 @@ func Test_sFnInitialize(t *testing.T) {
},
}
s := &systemState{
- instance: v1alpha1.Serverless{
+ instance: v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
Finalizers: []string{
r.cfg.finalizer,
},
},
- Spec: v1alpha1.ServerlessSpec{},
},
}
@@ -49,14 +48,13 @@ func Test_sFnInitialize(t *testing.T) {
}
metaTime := metav1.Now()
s := &systemState{
- instance: v1alpha1.Serverless{
+ instance: v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
Finalizers: []string{
r.cfg.finalizer,
},
DeletionTimestamp: &metaTime,
},
- Spec: v1alpha1.ServerlessSpec{},
},
}
diff --git a/components/operator/internal/state/new.go b/components/operator/internal/state/new.go
index 3236ab783..6b91fb0e8 100644
--- a/components/operator/internal/state/new.go
+++ b/components/operator/internal/state/new.go
@@ -14,7 +14,7 @@ import (
)
type StateReconciler interface {
- Reconcile(ctx context.Context, v v1alpha1.Serverless) (ctrl.Result, error)
+ Reconcile(ctx context.Context, v v1alpha1.DockerRegistry) (ctrl.Result, error)
}
func NewMachine(client client.Client, config *rest.Config, recorder record.EventRecorder, log *zap.SugaredLogger, cache chart.ManifestCache, chartPath string) StateReconciler {
diff --git a/components/operator/internal/state/optional_dependencies.go b/components/operator/internal/state/optional_dependencies.go
deleted file mode 100644
index 0b1ebf846..000000000
--- a/components/operator/internal/state/optional_dependencies.go
+++ /dev/null
@@ -1,72 +0,0 @@
-package state
-
-import (
- "context"
-
- "github.com/kyma-project/serverless/components/operator/api/v1alpha1"
- "github.com/kyma-project/serverless/components/operator/internal/tracing"
- "github.com/pkg/errors"
- "k8s.io/client-go/tools/record"
- controllerruntime "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-// enable or disable serverless optional dependencies based on the Serverless Spec and installed module on the cluster
-func sFnOptionalDependencies(ctx context.Context, r *reconciler, s *systemState) (stateFn, *controllerruntime.Result, error) {
- // TODO: add functionality of auto-detecting these dependencies by checking Eventing CRs if user does not override these values.
- // checking these URLs manually is not possible because of lack of istio-sidecar in the serverless-operator
-
- tracingURL, err := getTracingURL(ctx, r.client, s.instance.Spec)
- if err != nil {
- wrappedErr := errors.Wrap(err, "while fetching tracing URL")
- s.setState(v1alpha1.StateError)
- s.instance.UpdateConditionFalse(
- v1alpha1.ConditionTypeConfigured,
- v1alpha1.ConditionReasonConfigurationErr,
- wrappedErr,
- )
- return nil, nil, wrappedErr
- }
- eventingURL := getEventingURL(s.instance.Spec)
-
- updateOptionalDependenciesStatus(r.k8s, &s.instance, eventingURL, tracingURL)
- configureOptionalDependenciesFlags(s)
-
- return nextState(sFnControllerConfiguration)
-}
-
-func getTracingURL(ctx context.Context, client client.Client, spec v1alpha1.ServerlessSpec) (string, error) {
- if spec.Tracing != nil {
- return spec.Tracing.Endpoint, nil
- }
-
- tracingURL, err := tracing.GetTraceCollectorURL(ctx, client)
- if err != nil {
- return "", errors.Wrap(err, "while getting trace pipeline")
- }
- return tracingURL, nil
-}
-
-func getEventingURL(spec v1alpha1.ServerlessSpec) string {
- if spec.Eventing != nil {
- return spec.Eventing.Endpoint
- }
- return v1alpha1.DefaultEventingEndpoint
-}
-
-func updateOptionalDependenciesStatus(eventRecorder record.EventRecorder, instance *v1alpha1.Serverless, eventingURL, tracingURL string) {
- fields := fieldsToUpdate{
- {eventingURL, &instance.Status.EventingEndpoint, "Eventing endpoint", ""},
- {tracingURL, &instance.Status.TracingEndpoint, "Tracing endpoint", ""},
- }
-
- updateStatusFields(eventRecorder, instance, fields)
-}
-
-func configureOptionalDependenciesFlags(s *systemState) {
- s.flagsBuilder.
- WithOptionalDependencies(
- s.instance.Status.EventingEndpoint,
- s.instance.Status.TracingEndpoint,
- )
-}
diff --git a/components/operator/internal/state/optional_dependencies_test.go b/components/operator/internal/state/optional_dependencies_test.go
deleted file mode 100644
index fb94ffd85..000000000
--- a/components/operator/internal/state/optional_dependencies_test.go
+++ /dev/null
@@ -1,149 +0,0 @@
-package state
-
-import (
- "context"
- "testing"
-
- "github.com/kyma-project/serverless/components/operator/api/v1alpha1"
- "github.com/kyma-project/serverless/components/operator/internal/chart"
- "github.com/stretchr/testify/assert"
- "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/apimachinery/pkg/runtime"
- "k8s.io/client-go/tools/record"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-func Test_sFnOptionalDependencies(t *testing.T) {
- scheme := runtime.NewScheme()
- require.NoError(t, corev1.AddToScheme(scheme))
- tracingCollectorURL := "http://telemetry-otlp-traces.some-ns.svc.cluster.local:4318/v1/traces"
- customEventingURL := "eventing-url"
- configurationReadyMsg := "Configuration ready"
-
- testCases := map[string]struct {
- tracing *v1alpha1.Endpoint
- eventing *v1alpha1.Endpoint
- extraCR []client.Object
- expectedTracingURL string
- expectedEventingURL string
- expectedStatusMessage string
- }{
- "Eventing and tracing is set manually": {
- tracing: &v1alpha1.Endpoint{Endpoint: tracingCollectorURL},
- eventing: &v1alpha1.Endpoint{Endpoint: customEventingURL},
- expectedEventingURL: customEventingURL,
- expectedTracingURL: tracingCollectorURL,
- expectedStatusMessage: configurationReadyMsg,
- },
- "Tracing is not set, TracePipeline svc is available": {
- extraCR: []client.Object{fixTracingSvc()},
- eventing: &v1alpha1.Endpoint{Endpoint: ""},
- expectedTracingURL: tracingCollectorURL,
- expectedEventingURL: v1alpha1.EndpointDisabled,
- expectedStatusMessage: configurationReadyMsg,
- },
- "Tracing is not set, TracePipeline svc is not available": {
- expectedEventingURL: v1alpha1.DefaultEventingEndpoint,
- expectedTracingURL: v1alpha1.EndpointDisabled,
- expectedStatusMessage: configurationReadyMsg,
- },
- "Tracing and eventing is disabled": {
- tracing: &v1alpha1.Endpoint{Endpoint: ""},
- eventing: &v1alpha1.Endpoint{Endpoint: ""},
- expectedEventingURL: v1alpha1.EndpointDisabled,
- expectedTracingURL: v1alpha1.EndpointDisabled,
- expectedStatusMessage: configurationReadyMsg,
- },
- }
-
- for name, testCase := range testCases {
- t.Run(name, func(t *testing.T) {
- ctx := context.TODO()
- s := &systemState{
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{
- Eventing: testCase.eventing,
- Tracing: testCase.tracing,
- },
- },
- flagsBuilder: chart.NewFlagsBuilder(),
- }
- c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(testCase.extraCR...).Build()
- r := &reconciler{log: zap.NewNop().Sugar(), k8s: k8s{client: c, EventRecorder: record.NewFakeRecorder(5)}}
- next, result, err := sFnOptionalDependencies(ctx, r, s)
- require.Nil(t, err)
- require.Nil(t, result)
- requireEqualFunc(t, sFnControllerConfiguration, next)
-
- status := s.instance.Status
- assert.Equal(t, testCase.expectedEventingURL, status.EventingEndpoint)
- assert.Equal(t, testCase.expectedTracingURL, status.TracingEndpoint)
- })
- }
-
- t.Run("configure chart flags in release if status is up-to date", func(t *testing.T) {
- s := &systemState{
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{Eventing: &v1alpha1.Endpoint{Endpoint: customEventingURL}},
- Status: v1alpha1.ServerlessStatus{
- Conditions: []metav1.Condition{
- {
- Type: string(v1alpha1.ConditionTypeConfigured),
- Status: metav1.ConditionTrue,
- },
- },
- EventingEndpoint: customEventingURL,
- TracingEndpoint: tracingCollectorURL,
- },
- },
- flagsBuilder: chart.NewFlagsBuilder(),
- }
- c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(fixTracingSvc()).Build()
- r := &reconciler{log: zap.NewNop().Sugar(), k8s: k8s{client: c}}
-
- _, _, err := sFnOptionalDependencies(context.Background(), r, s)
- require.NoError(t, err)
-
- currentFlags := s.flagsBuilder.Build()
-
- overrideURL, found := getFlagByPath(currentFlags, "containers", "manager", "configuration", "data", "functionTraceCollectorEndpoint", "value")
- require.True(t, found)
- assert.Equal(t, tracingCollectorURL, overrideURL)
-
- overrideURL, found = getFlagByPath(currentFlags, "containers", "manager", "configuration", "data", "functionPublisherProxyAddress", "value")
- require.True(t, found)
- assert.Equal(t, customEventingURL, overrideURL)
- })
-}
-
-func fixTracingSvc() *corev1.Service {
- return &corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "telemetry-otlp-traces",
- Namespace: "some-ns",
- },
- }
-}
-
-func getFlagByPath(flags map[string]interface{}, path ...string) (string, bool) {
- value := flags
- var item interface{}
- for _, pathItem := range path {
- var ok bool
- item, ok = value[pathItem]
- if !ok {
- return "", false
- }
- value, ok = item.(map[string]interface{})
- if !ok {
- break
- }
- }
-
- out, ok := item.(string)
- return out, ok
-}
diff --git a/components/operator/internal/state/registry.go b/components/operator/internal/state/registry.go
index 16257d8ef..812775684 100644
--- a/components/operator/internal/state/registry.go
+++ b/components/operator/internal/state/registry.go
@@ -2,21 +2,10 @@ package state
import (
"context"
- "fmt"
-
"github.com/kyma-project/serverless/components/operator/api/v1alpha1"
"github.com/kyma-project/serverless/components/operator/internal/registry"
"github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-const (
- extNamespacedScopeSecretsDetectedFormat = "actual registry configuration in namespace %s comes from %s/%s and it is different from spec.dockerRegistry.secretName. Reflect the %s secret in the secretName field or delete it"
- extRegSecDiffThanSpecFormat = "actual registry configuration comes from %s/%s and it is different from spec.dockerRegistry.secretName. Reflect the %s secret in the secretName field or delete it"
- extRegSecNotInSpecFormat = "actual registry configuration comes from %s/%s and it is different from spec.dockerRegistry.secretName. Reflect %s secret in the secretName field"
- internalEnabledAndSecretNameUsedMessage = "spec.dockerRegistry.enableInternal is true and spec.dockerRegistry.secretName is used. Delete the secretName field or set the enableInternal value to false"
)
func sFnRegistryConfiguration(ctx context.Context, r *reconciler, s *systemState) (stateFn, *ctrl.Result, error) {
@@ -33,88 +22,28 @@ func sFnRegistryConfiguration(ctx context.Context, r *reconciler, s *systemState
return stopWithEventualError(err)
}
- return nextState(sFnOptionalDependencies)
+ return nextState(sFnControllerConfiguration)
}
func configureRegistry(ctx context.Context, r *reconciler, s *systemState) error {
- extRegSecretClusterWide, err := registry.GetExternalClusterWideRegistrySecret(ctx, r.client, s.instance.GetNamespace())
+ err := setInternalRegistryConfig(ctx, r, s)
if err != nil {
return err
}
- extRegSecretNamespacedScope, err := registry.ListExternalNamespacedScopeSecrets(ctx, r.client)
- if err != nil {
- return err
- }
-
- switch {
- case extRegSecretClusterWide != nil:
- // case: use runtime secret (with labels)
- // doc: https://kyma-project.io/docs/kyma/latest/05-technical-reference/svls-03-switching-registries#cluster-wide-external-registry
- setRuntimeRegistryConfig(extRegSecretClusterWide, s)
- case isRegistrySecretName(s.instance.Spec.DockerRegistry):
- // case: use secret from secretName field
- err := setExternalRegistryConfig(ctx, r, s)
- if err != nil {
- return err
- }
- case getEnableInternal(s.instance.Spec.DockerRegistry):
- // case: use internal registry
- err := setInternalRegistryConfig(ctx, r, s)
- if err != nil {
- return err
- }
- default:
- // case: use k3d registry
- setK3dRegistryConfig(s)
- }
-
- addRegistryConfigurationWarnings(extRegSecretClusterWide, extRegSecretNamespacedScope, s)
return nil
}
-func addRegistryConfigurationWarnings(extRegSecretClusterWide *corev1.Secret, extRegSecretsNamespacedScope []corev1.Secret, s *systemState) {
- // runtime secrets (namespaced scope) exist
- for _, secret := range extRegSecretsNamespacedScope {
- s.warningBuilder.With(fmt.Sprintf(extNamespacedScopeSecretsDetectedFormat, secret.Namespace, secret.Namespace, secret.Name, secret.Name))
- }
-
- // runtime secret (cluster wide) exist and it's other than this under secretName
- if extRegSecretClusterWide != nil && isRegistrySecretName(s.instance.Spec.DockerRegistry) &&
- extRegSecretClusterWide.Name != *s.instance.Spec.DockerRegistry.SecretName {
- s.warningBuilder.With(fmt.Sprintf(extRegSecDiffThanSpecFormat, extRegSecretClusterWide.Namespace, extRegSecretClusterWide.Name, extRegSecretClusterWide.Name))
- }
-
- // runtime secret exist and secretName field is empty
- if extRegSecretClusterWide != nil && !isRegistrySecretName(s.instance.Spec.DockerRegistry) {
- s.warningBuilder.With(fmt.Sprintf(extRegSecNotInSpecFormat, extRegSecretClusterWide.Namespace, extRegSecretClusterWide.Name, extRegSecretClusterWide.Name))
- }
-
- // enableInternal is true and secretName is used
- if getEnableInternal(s.instance.Spec.DockerRegistry) && isRegistrySecretName(s.instance.Spec.DockerRegistry) {
- s.warningBuilder.With(internalEnabledAndSecretNameUsedMessage)
- }
-}
-
-func setRuntimeRegistryConfig(secret *corev1.Secret, s *systemState) {
- s.instance.Status.DockerRegistry = string(secret.Data["serverAddress"])
-}
-
func setInternalRegistryConfig(ctx context.Context, r *reconciler, s *systemState) error {
- s.instance.Status.DockerRegistry = "internal"
- s.flagsBuilder.WithRegistryEnableInternal(
- *s.instance.Spec.DockerRegistry.EnableInternal,
- )
-
- existingIntRegSecret, err := registry.GetServerlessInternalRegistrySecret(ctx, r.client, s.instance.Namespace)
+ existingIntRegSecret, err := registry.GetDockerRegistryInternalRegistrySecret(ctx, r.client, s.instance.Namespace)
if err != nil {
- return errors.Wrap(err, "while fetching existing serverless internal docker registry secret")
+ return errors.Wrap(err, "while fetching existing internal docker registry secret")
}
if existingIntRegSecret != nil {
r.log.Debugf("reusing existing credentials for internal docker registry to avoiding docker registry rollout")
registryHttpSecretEnvValue, getErr := registry.GetRegistryHTTPSecretEnvValue(ctx, r.client, s.instance.Namespace)
if getErr != nil {
- return errors.Wrap(getErr, "while reading env value registryHttpSecret from serverless internal docker registry deployment")
+ return errors.Wrap(getErr, "while reading env value registryHttpSecret from internal docker registry deployment")
}
s.flagsBuilder.
WithRegistryCredentials(
@@ -135,57 +64,3 @@ func setInternalRegistryConfig(ctx context.Context, r *reconciler, s *systemStat
s.flagsBuilder.WithNodePort(int64(nodePort))
return nil
}
-
-func setExternalRegistryConfig(ctx context.Context, r *reconciler, s *systemState) error {
- secret, err := getRegistrySecret(ctx, r, s)
- if err != nil {
- return err
- }
-
- s.instance.Status.DockerRegistry = string(secret.Data["serverAddress"])
- s.flagsBuilder.
- WithRegistryEnableInternal(
- getEnableInternal(s.instance.Spec.DockerRegistry),
- ).
- WithRegistryCredentials(
- string(secret.Data["username"]),
- string(secret.Data["password"]),
- ).
- WithRegistryAddresses(
- string(secret.Data["registryAddress"]),
- s.instance.Status.DockerRegistry,
- )
-
- return nil
-}
-
-func setK3dRegistryConfig(s *systemState) {
- s.instance.Status.DockerRegistry = v1alpha1.DefaultServerAddress
- s.flagsBuilder.WithRegistryEnableInternal(
- getEnableInternal(s.instance.Spec.DockerRegistry),
- ).WithRegistryAddresses(
- v1alpha1.DefaultRegistryAddress,
- s.instance.Status.DockerRegistry,
- )
-}
-
-func getRegistrySecret(ctx context.Context, r *reconciler, s *systemState) (*corev1.Secret, error) {
- var secret corev1.Secret
- key := client.ObjectKey{
- Namespace: s.instance.Namespace,
- Name: *s.instance.Spec.DockerRegistry.SecretName,
- }
- err := r.client.Get(ctx, key, &secret)
- return &secret, err
-}
-
-func isRegistrySecretName(registry *v1alpha1.DockerRegistry) bool {
- return registry != nil && registry.SecretName != nil
-}
-
-func getEnableInternal(registry *v1alpha1.DockerRegistry) bool {
- if registry != nil && registry.EnableInternal != nil {
- return *registry.EnableInternal
- }
- return v1alpha1.DefaultEnableInternal
-}
diff --git a/components/operator/internal/state/registry_test.go b/components/operator/internal/state/registry_test.go
index f5e380e1e..8221e7d43 100644
--- a/components/operator/internal/state/registry_test.go
+++ b/components/operator/internal/state/registry_test.go
@@ -2,44 +2,27 @@ 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/registry"
- "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("internal registry and update", 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(),
+ instance: v1alpha1.DockerRegistry{},
+ statusSnapshot: v1alpha1.DockerRegistryStatus{},
+ 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),
},
@@ -48,301 +31,9 @@ func Test_sFnRegistryConfiguration(t *testing.T) {
next, result, err := sFnRegistryConfiguration(context.Background(), r, s)
require.NoError(t, err)
require.Nil(t, result)
- requireEqualFunc(t, sFnOptionalDependencies, next)
+ requireEqualFunc(t, sFnControllerConfiguration, next)
require.EqualValues(t, expectedFlags, s.flagsBuilder.Build())
- 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)
-
- require.Equal(t, expectedFlags, s.flagsBuilder.Build())
- 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",
- },
- 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)
-
- require.Equal(t, expectedFlags, s.flagsBuilder.Build())
- 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",
- )
- })
-
- t.Run("overwrite docker registry status when exists serverless cluster-wide external registry secret", func(t *testing.T) {
- serverlessClusterWideExternalRegistrySecret := registry.FixServerlessClusterWideExternalRegistrySecret()
- s := &systemState{
- warningBuilder: warning.NewBuilder(),
- instance: v1alpha1.Serverless{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: serverlessClusterWideExternalRegistrySecret.Namespace,
- },
- Spec: v1alpha1.ServerlessSpec{
- DockerRegistry: &v1alpha1.DockerRegistry{
- EnableInternal: ptr.To[bool](true),
- },
- },
- },
- statusSnapshot: v1alpha1.ServerlessStatus{
- DockerRegistry: "",
- },
- flagsBuilder: chart.NewFlagsBuilder(),
- }
- client := fake.NewClientBuilder().
- WithObjects(serverlessClusterWideExternalRegistrySecret).
- Build()
- r := &reconciler{
- k8s: k8s{client: client},
- log: zap.NewNop().Sugar(),
- }
- expectedFlags := map[string]interface{}{}
-
- next, result, err := sFnRegistryConfiguration(context.Background(), r, s)
- require.NoError(t, err)
- require.Nil(t, result)
- requireEqualFunc(t, sFnOptionalDependencies, next)
-
- require.EqualValues(t, expectedFlags, s.flagsBuilder.Build())
- require.Equal(t, string(serverlessClusterWideExternalRegistrySecret.Data["serverAddress"]), s.instance.Status.DockerRegistry)
- })
-}
-
-func Test_addRegistryConfigurationWarnings(t *testing.T) {
- t.Run("external registry secret exists and it doesn't match the one set in spec", 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]("test secret"),
- },
- },
- },
- }
- extRegSecret := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "serverless-registry-config",
- Namespace: "kyma-system",
- },
- }
- addRegistryConfigurationWarnings(&extRegSecret, []corev1.Secret{}, s)
- require.Equal(t,
- fmt.Sprintf(
- fmt.Sprintf("Warning: %s", extRegSecDiffThanSpecFormat), extRegSecret.Namespace, extRegSecret.Name, extRegSecret.Name),
- s.warningBuilder.Build())
- })
-
- t.Run("external registry secret exists and secretName field is not filled", func(t *testing.T) {
- s := &systemState{
- warningBuilder: warning.NewBuilder(),
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{
- DockerRegistry: &v1alpha1.DockerRegistry{
- EnableInternal: ptr.To[bool](false),
- },
- },
- },
- }
- extRegSecret := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "serverless-registry-config",
- Namespace: "kyma-system",
- },
- }
- addRegistryConfigurationWarnings(&extRegSecret, []corev1.Secret{}, s)
- require.Equal(t,
- fmt.Sprintf(
- fmt.Sprintf("Warning: %s", extRegSecNotInSpecFormat), extRegSecret.Namespace, extRegSecret.Name, extRegSecret.Name),
- s.warningBuilder.Build())
- })
-
- 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(nil, []corev1.Secret{}, s)
- require.Equal(t, fmt.Sprintf("Warning: %s", internalEnabledAndSecretNameUsedMessage), s.warningBuilder.Build())
- })
-
- t.Run("namespaced scope secrets exist", func(t *testing.T) {
- s := &systemState{
- warningBuilder: warning.NewBuilder(),
- instance: v1alpha1.Serverless{
- Spec: v1alpha1.ServerlessSpec{
- DockerRegistry: &v1alpha1.DockerRegistry{},
- },
- },
- }
-
- testSecret1 := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-name-1",
- Namespace: "test-namespace-1",
- },
- }
- testSecret2 := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "test-name-2",
- Namespace: "test-namespace-2",
- },
- }
- namespacedScopeSecrets := []corev1.Secret{
- testSecret1,
- testSecret2,
- }
-
- addRegistryConfigurationWarnings(nil, namespacedScopeSecrets, s)
- require.Equal(t, fmt.Sprintf("Warning: %s; %s",
- fmt.Sprintf(extNamespacedScopeSecretsDetectedFormat, testSecret1.Namespace, testSecret1.Namespace, testSecret1.Name, testSecret1.Name),
- fmt.Sprintf(extNamespacedScopeSecretsDetectedFormat, testSecret2.Namespace, testSecret2.Namespace, testSecret2.Name, testSecret2.Name),
- ), 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"),
- },
- },
- },
- }
- extRegSecret := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "serverless-registry-config",
- Namespace: "kyma-system",
- },
- }
- addRegistryConfigurationWarnings(&extRegSecret, []corev1.Secret{}, s)
- require.Equal(t, "", s.warningBuilder.Build())
- })
}
diff --git a/components/operator/internal/state/remove_finalizer.go b/components/operator/internal/state/remove_finalizer.go
index c4ef0630b..e5e9c406f 100644
--- a/components/operator/internal/state/remove_finalizer.go
+++ b/components/operator/internal/state/remove_finalizer.go
@@ -12,6 +12,6 @@ func sFnRemoveFinalizer(ctx context.Context, r *reconciler, s *systemState) (sta
return requeue()
}
- err := updateServerlessWithoutStatus(ctx, r, s)
+ err := updateDockerRegistryWithoutStatus(ctx, r, s)
return stopWithEventualError(err)
}
diff --git a/components/operator/internal/state/remove_finalizer_test.go b/components/operator/internal/state/remove_finalizer_test.go
index cb0856a56..65e2e28e0 100644
--- a/components/operator/internal/state/remove_finalizer_test.go
+++ b/components/operator/internal/state/remove_finalizer_test.go
@@ -16,7 +16,7 @@ func Test_sFnRemoveFinalizer(t *testing.T) {
t.Run("remove finalizer", func(t *testing.T) {
scheme := scheme.Scheme
require.NoError(t, v1alpha1.AddToScheme(scheme))
- instance := v1alpha1.Serverless{
+ instance := v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "default",
@@ -54,7 +54,7 @@ func Test_sFnRemoveFinalizer(t *testing.T) {
},
}
s := &systemState{
- instance: v1alpha1.Serverless{
+ instance: v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{},
},
}
diff --git a/components/operator/internal/state/served_filter.go b/components/operator/internal/state/served_filter.go
index 41e812d60..d6f8aa5e7 100644
--- a/components/operator/internal/state/served_filter.go
+++ b/components/operator/internal/state/served_filter.go
@@ -22,16 +22,16 @@ func sFnServedFilter(ctx context.Context, r *reconciler, s *systemState) (stateF
}
func setInitialServed(ctx context.Context, r *reconciler, s *systemState) error {
- servedServerless, err := GetServedServerless(ctx, r.k8s.client)
+ servedDockerRegistry, err := GetServedDockerRegistry(ctx, r.k8s.client)
if err != nil {
return err
}
- return setServed(servedServerless, s)
+ return setServed(servedDockerRegistry, s)
}
-func setServed(servedServerless *v1alpha1.Serverless, s *systemState) error {
- if servedServerless == nil {
+func setServed(servedDockerRegistry *v1alpha1.DockerRegistry, s *systemState) error {
+ if servedDockerRegistry == nil {
s.setServed(v1alpha1.ServedTrue)
return nil
}
@@ -39,11 +39,11 @@ func setServed(servedServerless *v1alpha1.Serverless, s *systemState) error {
s.setServed(v1alpha1.ServedFalse)
s.setState(v1alpha1.StateWarning)
err := fmt.Errorf(
- "Only one instance of Serverless is allowed (current served instance: %s/%s). This Serverless CR is redundant. Remove it to fix the problem.",
- servedServerless.GetNamespace(), servedServerless.GetName())
+ "Only one instance of DockerRegistry is allowed (current served instance: %s/%s). This DockerRegistry CR is redundant. Remove it to fix the problem.",
+ servedDockerRegistry.GetNamespace(), servedDockerRegistry.GetName())
s.instance.UpdateConditionFalse(
v1alpha1.ConditionTypeConfigured,
- v1alpha1.ConditionReasonServerlessDuplicated,
+ v1alpha1.ConditionReasonDuplicated,
err,
)
return err
diff --git a/components/operator/internal/state/served_filter_test.go b/components/operator/internal/state/served_filter_test.go
index a4cabf39a..094891fca 100644
--- a/components/operator/internal/state/served_filter_test.go
+++ b/components/operator/internal/state/served_filter_test.go
@@ -15,8 +15,8 @@ import (
func Test_sFnServedFilter(t *testing.T) {
t.Run("skip processing when served is false", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ instance: v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Served: v1alpha1.ServedFalse,
},
},
@@ -30,8 +30,8 @@ func Test_sFnServedFilter(t *testing.T) {
t.Run("do next step when served is true", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{
+ instance: v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{
Served: v1alpha1.ServedTrue,
},
},
@@ -43,10 +43,10 @@ func Test_sFnServedFilter(t *testing.T) {
requireEqualFunc(t, sFnAddFinalizer, nextFn)
})
- t.Run("set served value from nil to true when there is no served serverless on cluster", func(t *testing.T) {
+ t.Run("set served value from nil to true when there is no served dockerregistry on cluster", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{},
+ instance: v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{},
},
}
@@ -59,10 +59,10 @@ func Test_sFnServedFilter(t *testing.T) {
client := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(
- fixServedServerless("test-1", "default", ""),
- fixServedServerless("test-2", "serverless-test", v1alpha1.ServedFalse),
- fixServedServerless("test-3", "serverless-test-2", ""),
- fixServedServerless("test-4", "default", v1alpha1.ServedFalse),
+ fixServedDockerRegistry("test-1", "default", ""),
+ fixServedDockerRegistry("test-2", "dockerregistry-test", v1alpha1.ServedFalse),
+ fixServedDockerRegistry("test-3", "dockerregistry-test-2", ""),
+ fixServedDockerRegistry("test-4", "default", v1alpha1.ServedFalse),
).Build()
return client
@@ -77,10 +77,10 @@ func Test_sFnServedFilter(t *testing.T) {
require.Equal(t, v1alpha1.ServedTrue, s.instance.Status.Served)
})
- t.Run("set served value from nil to false and set condition to error when there is at lease one served serverless on cluster", func(t *testing.T) {
+ t.Run("set served value from nil to false and set condition to error when there is at lease one served dockerregistry on cluster", func(t *testing.T) {
s := &systemState{
- instance: v1alpha1.Serverless{
- Status: v1alpha1.ServerlessStatus{},
+ instance: v1alpha1.DockerRegistry{
+ Status: v1alpha1.DockerRegistryStatus{},
},
}
@@ -93,10 +93,10 @@ func Test_sFnServedFilter(t *testing.T) {
client := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(
- fixServedServerless("test-1", "default", v1alpha1.ServedFalse),
- fixServedServerless("test-2", "serverless-test", v1alpha1.ServedTrue),
- fixServedServerless("test-3", "serverless-test-2", ""),
- fixServedServerless("test-4", "default", v1alpha1.ServedFalse),
+ fixServedDockerRegistry("test-1", "default", v1alpha1.ServedFalse),
+ fixServedDockerRegistry("test-2", "dockerregistry-test", v1alpha1.ServedTrue),
+ fixServedDockerRegistry("test-3", "dockerregistry-test-2", ""),
+ fixServedDockerRegistry("test-4", "default", v1alpha1.ServedFalse),
).Build()
return client
@@ -106,7 +106,7 @@ func Test_sFnServedFilter(t *testing.T) {
nextFn, result, err := sFnServedFilter(context.TODO(), r, s)
- expectedErrorMessage := "Only one instance of Serverless is allowed (current served instance: serverless-test/test-2). This Serverless CR is redundant. Remove it to fix the problem."
+ expectedErrorMessage := "Only one instance of DockerRegistry is allowed (current served instance: dockerregistry-test/test-2). This DockerRegistry CR is redundant. Remove it to fix the problem."
require.EqualError(t, err, expectedErrorMessage)
require.Nil(t, result)
require.Nil(t, nextFn)
@@ -117,19 +117,19 @@ func Test_sFnServedFilter(t *testing.T) {
requireContainsCondition(t, status,
v1alpha1.ConditionTypeConfigured,
metav1.ConditionFalse,
- v1alpha1.ConditionReasonServerlessDuplicated,
+ v1alpha1.ConditionReasonDuplicated,
expectedErrorMessage,
)
})
}
-func fixServedServerless(name, namespace string, served v1alpha1.Served) *v1alpha1.Serverless {
- return &v1alpha1.Serverless{
+func fixServedDockerRegistry(name, namespace string, served v1alpha1.Served) *v1alpha1.DockerRegistry {
+ return &v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
- Status: v1alpha1.ServerlessStatus{
+ Status: v1alpha1.DockerRegistryStatus{
Served: served,
},
}
diff --git a/components/operator/internal/state/serverless_utils.go b/components/operator/internal/state/serverless_utils.go
deleted file mode 100644
index cbb3c5e73..000000000
--- a/components/operator/internal/state/serverless_utils.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package state
-
-import (
- "context"
-
- "github.com/kyma-project/serverless/components/operator/api/v1alpha1"
- "github.com/pkg/errors"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func GetServerlessOrServed(ctx context.Context, req ctrl.Request, c client.Client) (*v1alpha1.Serverless, error) {
- instance := &v1alpha1.Serverless{}
- err := c.Get(ctx, req.NamespacedName, instance)
- if err == nil {
- return instance, nil
- }
- if !k8serrors.IsNotFound(err) {
- return nil, errors.Wrap(err, "while fetching serverless instance")
- }
-
- instance, err = GetServedServerless(ctx, c)
- if err != nil {
- return nil, errors.Wrap(err, "while fetching served serverless instance")
- }
- return instance, nil
-}
-
-func GetServedServerless(ctx context.Context, c client.Client) (*v1alpha1.Serverless, error) {
- var serverlessList v1alpha1.ServerlessList
-
- err := c.List(ctx, &serverlessList)
-
- if err != nil {
- return nil, err
- }
-
- for _, item := range serverlessList.Items {
- if !item.IsServedEmpty() && item.Status.Served == v1alpha1.ServedTrue {
- return &item, nil
- }
- }
-
- return nil, nil
-}
diff --git a/components/operator/internal/state/state.go b/components/operator/internal/state/state.go
index 4b911d727..b1fc34034 100644
--- a/components/operator/internal/state/state.go
+++ b/components/operator/internal/state/state.go
@@ -12,10 +12,6 @@ var requeueResult = &ctrl.Result{
Requeue: true,
}
-func stopWithErrorOrRequeue(err error) (stateFn, *ctrl.Result, error) {
- return nil, requeueResult, err
-}
-
func nextState(next stateFn) (stateFn, *ctrl.Result, error) {
return next, nil, nil
}
@@ -45,7 +41,7 @@ type fieldsToUpdate []struct {
defaultValue string
}
-func updateStatusFields(eventRecorder record.EventRecorder, instance *v1alpha1.Serverless, fields fieldsToUpdate) {
+func updateStatusFields(eventRecorder record.EventRecorder, instance *v1alpha1.DockerRegistry, fields fieldsToUpdate) {
for _, field := range fields {
// set default value if spec field is empty
if field.specField == "" {
diff --git a/components/operator/internal/state/state_test.go b/components/operator/internal/state/state_test.go
index a11ceb61d..b835ed120 100644
--- a/components/operator/internal/state/state_test.go
+++ b/components/operator/internal/state/state_test.go
@@ -12,21 +12,15 @@ import (
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
- "k8s.io/utils/ptr"
)
var (
- testInstalledServerless = v1alpha1.Serverless{
+ testInstalledDockerRegistry = v1alpha1.DockerRegistry{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "test",
},
- Spec: v1alpha1.ServerlessSpec{
- DockerRegistry: &v1alpha1.DockerRegistry{
- EnableInternal: ptr.To[bool](false),
- },
- },
- Status: v1alpha1.ServerlessStatus{
+ Status: v1alpha1.DockerRegistryStatus{
Conditions: []metav1.Condition{
{
Type: string(v1alpha1.ConditionTypeConfigured),
@@ -51,9 +45,9 @@ func fixEmptyManifestCache() chart.ManifestCache {
func fixManifestCache(manifest string) chart.ManifestCache {
cache := chart.NewInMemoryManifestCache()
_ = cache.Set(context.Background(), types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
- }, chart.ServerlessSpecManifest{Manifest: manifest, CustomFlags: map[string]interface{}{}})
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
+ }, chart.DockerRegistrySpecManifest{Manifest: manifest, CustomFlags: map[string]interface{}{}})
return cache
}
@@ -101,7 +95,7 @@ func getFnName(fn stateFn) string {
return runtime.FuncForPC(reflect.ValueOf(fn).Pointer()).Name()
}
-func requireContainsCondition(t *testing.T, status v1alpha1.ServerlessStatus,
+func requireContainsCondition(t *testing.T, status v1alpha1.DockerRegistryStatus,
conditionType v1alpha1.ConditionType, conditionStatus metav1.ConditionStatus, conditionReason v1alpha1.ConditionReason, conditionMessage string) {
hasExpectedCondition := false
for _, condition := range status.Conditions {
diff --git a/components/operator/internal/state/update_status.go b/components/operator/internal/state/update_status.go
index 8ea55b816..dffea574a 100644
--- a/components/operator/internal/state/update_status.go
+++ b/components/operator/internal/state/update_status.go
@@ -10,11 +10,11 @@ var (
requeueDuration = time.Second * 3
)
-func updateServerlessWithoutStatus(ctx context.Context, r *reconciler, s *systemState) error {
+func updateDockerRegistryWithoutStatus(ctx context.Context, r *reconciler, s *systemState) error {
return r.client.Update(ctx, &s.instance)
}
-func updateServerlessStatus(ctx context.Context, r *reconciler, s *systemState) error {
+func updateDockerRegistryStatus(ctx context.Context, r *reconciler, s *systemState) error {
if !reflect.DeepEqual(s.instance.Status, s.statusSnapshot) {
err := r.client.Status().Update(ctx, &s.instance)
emitEvent(r, s)
diff --git a/components/operator/internal/state/utils.go b/components/operator/internal/state/utils.go
new file mode 100644
index 000000000..ac0a791b6
--- /dev/null
+++ b/components/operator/internal/state/utils.go
@@ -0,0 +1,46 @@
+package state
+
+import (
+ "context"
+
+ "github.com/kyma-project/serverless/components/operator/api/v1alpha1"
+ "github.com/pkg/errors"
+ k8serrors "k8s.io/apimachinery/pkg/api/errors"
+ ctrl "sigs.k8s.io/controller-runtime"
+ "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+func GetDockerRegistryOrServed(ctx context.Context, req ctrl.Request, c client.Client) (*v1alpha1.DockerRegistry, error) {
+ instance := &v1alpha1.DockerRegistry{}
+ err := c.Get(ctx, req.NamespacedName, instance)
+ if err == nil {
+ return instance, nil
+ }
+ if !k8serrors.IsNotFound(err) {
+ return nil, errors.Wrap(err, "while fetching dockerregistry instance")
+ }
+
+ instance, err = GetServedDockerRegistry(ctx, c)
+ if err != nil {
+ return nil, errors.Wrap(err, "while fetching served dockerregistry instance")
+ }
+ return instance, nil
+}
+
+func GetServedDockerRegistry(ctx context.Context, c client.Client) (*v1alpha1.DockerRegistry, error) {
+ var dockerRegistryList v1alpha1.DockerRegistryList
+
+ err := c.List(ctx, &dockerRegistryList)
+
+ if err != nil {
+ return nil, err
+ }
+
+ for _, item := range dockerRegistryList.Items {
+ if !item.IsServedEmpty() && item.Status.Served == v1alpha1.ServedTrue {
+ return &item, nil
+ }
+ }
+
+ return nil, nil
+}
diff --git a/components/operator/internal/state/verify.go b/components/operator/internal/state/verify.go
index 05c3696b9..24974b80a 100644
--- a/components/operator/internal/state/verify.go
+++ b/components/operator/internal/state/verify.go
@@ -43,7 +43,7 @@ func sFnVerifyResources(_ context.Context, r *reconciler, s *systemState) (state
s.instance.UpdateConditionTrue(
v1alpha1.ConditionTypeInstalled,
v1alpha1.ConditionReasonInstalled,
- "Serverless installed",
+ "DockerRegistry installed",
)
return stop()
}
diff --git a/components/operator/internal/state/verify_test.go b/components/operator/internal/state/verify_test.go
index c1ba723dd..919ed82d3 100644
--- a/components/operator/internal/state/verify_test.go
+++ b/components/operator/internal/state/verify_test.go
@@ -47,12 +47,12 @@ func Test_sFnVerifyResources(t *testing.T) {
t.Run("ready", func(t *testing.T) {
s := &systemState{
warningBuilder: warning.NewBuilder(),
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
}
@@ -76,19 +76,19 @@ func Test_sFnVerifyResources(t *testing.T) {
v1alpha1.ConditionTypeInstalled,
metav1.ConditionTrue,
v1alpha1.ConditionReasonInstalled,
- "Serverless installed",
+ "DockerRegistry installed",
)
})
t.Run("warning", func(t *testing.T) {
s := &systemState{
warningBuilder: warning.NewBuilder().With("test warning"),
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixEmptyManifestCache(),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
}
@@ -114,12 +114,12 @@ func Test_sFnVerifyResources(t *testing.T) {
t.Run("verify error", func(t *testing.T) {
s := &systemState{
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: fixManifestCache("\t"),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
},
}
@@ -146,19 +146,19 @@ func Test_sFnVerifyResources(t *testing.T) {
t.Run("requeue when resources are not ready", func(t *testing.T) {
client := fake.NewClientBuilder().WithObjects(testDeployCR).Build()
s := &systemState{
- instance: *testInstalledServerless.DeepCopy(),
+ instance: *testInstalledDockerRegistry.DeepCopy(),
chartConfig: &chart.Config{
Cache: func() chart.ManifestCache {
cache := chart.NewInMemoryManifestCache()
_ = cache.Set(context.Background(), types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
- }, chart.ServerlessSpecManifest{Manifest: testDeployManifest})
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
+ }, chart.DockerRegistrySpecManifest{Manifest: testDeployManifest})
return cache
}(),
CacheKey: types.NamespacedName{
- Name: testInstalledServerless.GetName(),
- Namespace: testInstalledServerless.GetNamespace(),
+ Name: testInstalledDockerRegistry.GetName(),
+ Namespace: testInstalledDockerRegistry.GetNamespace(),
},
Cluster: chart.Cluster{
Client: client,
diff --git a/components/operator/main.go b/components/operator/main.go
index e272c86e0..700a7c08a 100644
--- a/components/operator/main.go
+++ b/components/operator/main.go
@@ -32,6 +32,8 @@ import (
uberzapcore "go.uber.org/zap/zapcore"
_ "k8s.io/client-go/plugin/pkg/client/auth"
+ k8s "github.com/kyma-project/serverless/components/operator/internal/controllers/kubernetes"
+ internalresource "github.com/kyma-project/serverless/components/operator/internal/resource"
corev1 "k8s.io/api/core/v1"
apiextensionsscheme "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/scheme"
"k8s.io/apimachinery/pkg/runtime"
@@ -127,14 +129,53 @@ func main() {
os.Exit(1)
}
- reconciler := controllers.NewServerlessReconciler(
+ reconciler := controllers.NewDockerRegistryReconciler(
mgr.GetClient(), mgr.GetConfig(),
- mgr.GetEventRecorderFor("serverless-operator"),
+ mgr.GetEventRecorderFor("dockerregistry-operator"),
reconcilerLogger.Sugar(),
cfg.ChartPath)
+ //TODO: get it from some configuration
+ configKubernetes := k8s.Config{
+ BaseNamespace: "kyma-system",
+ BaseDefaultSecretName: "serverless-registry-config-default",
+ ExcludedNamespaces: []string{"kyma-system"},
+ ConfigMapRequeueDuration: time.Minute,
+ SecretRequeueDuration: time.Minute,
+ ServiceAccountRequeueDuration: time.Minute,
+ }
+
+ resourceClient := internalresource.New(mgr.GetClient(), scheme)
+ secretSvc := k8s.NewSecretService(resourceClient, configKubernetes)
+ configMapSvc := k8s.NewConfigMapService(resourceClient, configKubernetes)
+ serviceAccountSvc := k8s.NewServiceAccountService(resourceClient, configKubernetes)
+
if err = reconciler.SetupWithManager(mgr); err != nil {
- setupLog.Error(err, "unable to create controller", "controller", "Serverless")
+ setupLog.Error(err, "unable to create controller", "controller", "DockerRegistry")
+ os.Exit(1)
+ }
+
+ namespaceLogger, err := config.Build()
+ if err != nil {
+ setupLog.Error(err, "unable to setup logger")
+ os.Exit(1)
+ }
+
+ if err := k8s.NewNamespace(mgr.GetClient(), namespaceLogger.Sugar(), configKubernetes, configMapSvc, secretSvc, serviceAccountSvc).
+ SetupWithManager(mgr); err != nil {
+ setupLog.Error(err, "unable to create Namespace controller")
+ os.Exit(1)
+ }
+
+ secretLogger, err := config.Build()
+ if err != nil {
+ setupLog.Error(err, "unable to setup logger")
+ os.Exit(1)
+ }
+
+ if err := k8s.NewSecret(mgr.GetClient(), secretLogger.Sugar(), configKubernetes, secretSvc).
+ SetupWithManager(mgr); err != nil {
+ setupLog.Error(err, "unable to create Secret controller")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
diff --git a/components/runtimes/README.md b/components/runtimes/README.md
deleted file mode 100644
index c48472ab0..000000000
--- a/components/runtimes/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# Function Runtimes
-
-## Overview
-
-This project includes Docker images which are used as a base for serverless Functions. See the [Serverless](https://kyma-project.io/#/serverless-manager/user/README) documentation for more information on serverless Functions.
diff --git a/components/runtimes/java17/.gitignore b/components/runtimes/java17/.gitignore
deleted file mode 100644
index 816f32965..000000000
--- a/components/runtimes/java17/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-target
-.idea
-opentelemetry-javaagent.jar
\ No newline at end of file
diff --git a/components/runtimes/java17/Dockerfile-jvm-function-local b/components/runtimes/java17/Dockerfile-jvm-function-local
deleted file mode 100644
index 84db71c2e..000000000
--- a/components/runtimes/java17/Dockerfile-jvm-function-local
+++ /dev/null
@@ -1,21 +0,0 @@
-FROM java-runtime:17 as builder
-
-ARG BUILD_DIR=/build
-#When kaniko build the image it has Handler.java and pom.xml in the /src, but When I work on function locally the pom.xml can be in /src, but Handler.java lies in the package deep in src.
-ARG SOURCE_DIR=/src
-ARG DEPS_DIR=/src
-WORKDIR $BUILD_DIR
-
-COPY $DEPS_DIR/pom.xml $BUILD_DIR/handler-pom.xml
-
-COPY $SOURCE_DIR/Handler.java $BUILD_DIR/src/main/java/io/project/kyma/serverless/handler/Handler.java
-RUN mvn dependency:go-offline -f handler-pom.xml
-
-RUN mvn clean && mvn package -f pom.xml
-
-FROM eclipse-temurin:17-jre-alpine
-
-COPY --from=builder /build/target/kyma-java-runtime-0.0.1.jar /app.jar
-
-ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /app.jar
-USER 1000
diff --git a/components/runtimes/java17/Dockerfile-jvm-function.tpl b/components/runtimes/java17/Dockerfile-jvm-function.tpl
deleted file mode 100644
index 8af11bf1d..000000000
--- a/components/runtimes/java17/Dockerfile-jvm-function.tpl
+++ /dev/null
@@ -1,21 +0,0 @@
-FROM ${BASE_IMAGE} as builder
-
-ARG BUILD_DIR=/build
-#When kaniko build the image it has Handler.java and pom.xml in the /src, but When I work on function locally the pom.xml can be in /src, but Handler.java lies in the package deep in src.
-ARG SOURCE_DIR=/src
-ARG DEPS_DIR=/src
-WORKDIR $BUILD_DIR
-
-COPY $DEPS_DIR/pom.xml $BUILD_DIR/handler-pom.xml
-
-COPY $SOURCE_DIR/Handler.java $BUILD_DIR/src/main/java/io/project/kyma/serverless/handler/Handler.java
-RUN mvn dependency:go-offline -f handler-pom.xml
-
-RUN mvn clean && mvn package -f pom.xml
-
-FROM eclipse-temurin:17-jre-alpine
-
-COPY --from=builder /build/target/kyma-java-runtime-0.0.1.jar /app.jar
-
-ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -jar /app.jar
-USER 1000
diff --git a/components/runtimes/java17/Dockerfile-jvm-runtime b/components/runtimes/java17/Dockerfile-jvm-runtime
deleted file mode 100644
index 3d258c9a1..000000000
--- a/components/runtimes/java17/Dockerfile-jvm-runtime
+++ /dev/null
@@ -1,13 +0,0 @@
-FROM maven:3.8-openjdk-17-slim
-WORKDIR /build
-
-#Compile and install SDK locally
-COPY serverless-java-sdk serverless-java-sdk
-RUN (cd serverless-java-sdk && mvn clean package install)
-
-COPY ./pom.xml .
-RUN mvn dependency:go-offline
-
-# Create runtime
-COPY ./src ./src
-RUN mvn compile
diff --git a/components/runtimes/java17/Makefile b/components/runtimes/java17/Makefile
deleted file mode 100644
index acad10c49..000000000
--- a/components/runtimes/java17/Makefile
+++ /dev/null
@@ -1,69 +0,0 @@
-#This is address of registry visible from k3s cluster.
-#On linux you can get this address by executing `hostname -I`
-
-#TODO: /etc/hosts and coredns patch, fetch it as optional
-#REGISTRY_ADR=k3d-kyma-registry.localhost:5000
-REGISTRY_ADR=192.168.122.1:5000
-JVM_VERSION=17
-RUNTIME_IMAGE=java-runtime:${JVM_VERSION}
-RUNTIME_IMAGE_REMOTE=${REGISTRY_ADR}/${RUNTIME_IMAGE}
-
-install-sdk:
- (cd serverless-java-sdk && mvn install)
-
-.PHONY: clean
-clean:
- mvn clean package
-
-#------------------------------------------------------JVM-------------------------------------------------------------#
-.PHONY: build-runtime
-build-runtime: install-sdk
- docker build -t ${RUNTIME_IMAGE} -f Dockerfile-jvm-runtime .
-
-.PHONY: push-runtime-k3d
-push-runtime-k3d:
- docker image tag ${RUNTIME_IMAGE} ${RUNTIME_IMAGE_REMOTE}
- docker push ${RUNTIME_IMAGE_REMOTE}
-
-#------------------------------------------------------K8s-Resources---------------------------------------------------#
-#Generate configmaps which can be used to move to serverless resources
-
-IMAGE_HELM_TPL='{{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_runtime_java${JVM_VERSION}_jvm_alpha) }}'
-.PHONY: generate-configmaps
-generate-configmaps:
- DOCKERFILE=Dockerfile-jvm-function.tpl BASE_IMAGE=${IMAGE_HELM_TPL} python3 ./resources/generate-dockerfile.py | \
- CONFIGMAP=resources/java${JVM_VERSION}-jvm-alpha.yaml RUNTIME=java${JVM_VERSION}-jvm-alpha python3 resources/generate-cm.py > ./resources/java${JVM_VERSION}-jvm-alpha.yaml
-
-generate-configmaps-local-image:
- DOCKERFILE=Dockerfile-jvm-function.tpl BASE_IMAGE=${RUNTIME_IMAGE_REMOTE} python3 ./resources/generate-dockerfile.py | \
- CONFIGMAP=resources/java${JVM_VERSION}-jvm-alpha.yaml RUNTIME=java${JVM_VERSION}-jvm-alpha python3 resources/generate-cm.py > ./resources/java${JVM_VERSION}-jvm-alpha-local.yaml
-
-
-apply-java-runtime:
- kubectl replace -f ./resources/java17-jvm-alpha.yaml
-
-apply-java-runtime-local:
- kubectl replace -f ./resources/java17-jvm-alpha-local.yaml
-
-#-------------------------------------------------Run Example function locally-----------------------------------------#
-#Example function
-#Create Dockerfile to use with example hello-world
-export BASE_IMAGE = ${RUNTIME_IMAGE}
-
-FUNCTION_IMAGE=java-jvm${JVM_VERSION}-function
-
-.PHONY: generate-local-fn-dockerfile
-generate-local-fn-dockerfile:
- DOCKERFILE=Dockerfile-jvm-function.tpl BASE_IMAGE=${RUNTIME_IMAGE} python3 ./resources/generate-dockerfile.py > Dockerfile-jvm-function-local
-
-run-jvm-hello-world: build-runtime generate-local-fn-dockerfile
- docker build --tag ${FUNCTION_IMAGE} \
- --build-arg DEPS_DIR=./examples/hello-world/ \
- --build-arg SOURCE_DIR=./examples/hello-world/src/main/java/io/project/kyma/serverless/handler \
- -f Dockerfile-jvm-function-local .
-
- docker run -ti -p 8080:8080 --rm --env PUBLISHER_PROXY_ADDRESS=http://localhost:10000/publish \
- --env TRACE_COLLECTOR_ENDPOINT=http://localhost:4318/v1/traces \
- --env SERVICE_NAMESPACE=default \
- --env HOSTNAME=emitter-local-84dd76fc94-2pnpd \
- --name java-jvm-function ${FUNCTION_IMAGE}
diff --git a/components/runtimes/java17/examples/hello-world/.Dockerignore b/components/runtimes/java17/examples/hello-world/.Dockerignore
deleted file mode 100644
index 4c3f8757e..000000000
--- a/components/runtimes/java17/examples/hello-world/.Dockerignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.project
-.settings
-.classpath
-target/
diff --git a/components/runtimes/java17/examples/hello-world/.gitignore b/components/runtimes/java17/examples/hello-world/.gitignore
deleted file mode 100644
index 4c3f8757e..000000000
--- a/components/runtimes/java17/examples/hello-world/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-.project
-.settings
-.classpath
-target/
diff --git a/components/runtimes/java17/examples/hello-world/pom.xml b/components/runtimes/java17/examples/hello-world/pom.xml
deleted file mode 100644
index b64faf860..000000000
--- a/components/runtimes/java17/examples/hello-world/pom.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
- 4.0.0
- io.project.kyma.serverless
- java-function
- 0.0.1
- jar
-
- hello-world
-
-
- UTF-8
- 11
- 11
-
-
-
-
- jakarta.ws.rs
- jakarta.ws.rs-api
- 3.1.0
- provided
-
-
- io.project.kyma.serverless
- serverless-java-sdk
- 0.0.1
- compile
-
-
-
diff --git a/components/runtimes/java17/examples/hello-world/src/main/java/io/project/kyma/serverless/handler/Handler.java b/components/runtimes/java17/examples/hello-world/src/main/java/io/project/kyma/serverless/handler/Handler.java
deleted file mode 100644
index 993dc2217..000000000
--- a/components/runtimes/java17/examples/hello-world/src/main/java/io/project/kyma/serverless/handler/Handler.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.project.kyma.serverless.handler;
-
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.core.Response;
-
-import io.project.kyma.serverless.sdk.CloudEvent;
-import io.project.kyma.serverless.sdk.Function;
-
-
-public class Handler implements Function {
-
- public static final String RETURN_STRING = "Hello World from java17 runtime with serverless SDK!";
-
- @Override
- public Response main(CloudEvent event, Context context) {
- return Response.ok(RETURN_STRING).build();
- }
-}
diff --git a/components/runtimes/java17/pom.xml b/components/runtimes/java17/pom.xml
deleted file mode 100644
index 9f831c875..000000000
--- a/components/runtimes/java17/pom.xml
+++ /dev/null
@@ -1,145 +0,0 @@
-
-
- 4.0.0
-
- io.project.kyma.serverless
- kyma-java-runtime
- 0.0.1
- jar
-
-
- 11
- 11
-
-
-
-
-
- io.opentelemetry
- opentelemetry-bom
- 1.20.0
- pom
- import
-
-
- org.junit
- junit-bom
- 5.9.1
- pom
- import
-
-
-
-
-
-
-
- org.eclipse.jetty
- jetty-server
- 11.0.13
-
-
- org.eclipse.jetty
- jetty-servlet
- 11.0.13
-
-
- org.glassfish.jersey.containers
- jersey-container-servlet-core
- 3.1.0
-
-
- org.glassfish.jersey.media
- jersey-media-json-jackson
- 3.1.0
-
-
- org.glassfish.jersey.inject
- jersey-hk2
- 3.1.0
-
-
- javax.xml.bind
- jaxb-api
- 2.1
-
-
- org.codehaus.jackson
- jackson-core-asl
- 1.9.13
-
-
- io.project.kyma.serverless
- serverless-java-sdk
- 0.0.1
- compile
-
-
- io.opentelemetry
- opentelemetry-api
-
-
- io.opentelemetry
- opentelemetry-sdk
-
-
- io.opentelemetry
- opentelemetry-exporter-otlp
-
-
- io.opentelemetry
- opentelemetry-extension-trace-propagators
-
-
- io.opentelemetry
- opentelemetry-semconv
- 1.20.0-alpha
-
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.1
-
-
- ${java.target.level}
- UTF-8
- true
- true
-
-
-
- maven-assembly-plugin
-
-
-
- io.project.kyma.serverless.Main
-
-
-
- jar-with-dependencies
-
- false
-
-
-
- package
-
- single
-
-
-
-
-
-
-
diff --git a/components/runtimes/java17/resources/.gitignore b/components/runtimes/java17/resources/.gitignore
deleted file mode 100644
index ee3c36cb2..000000000
--- a/components/runtimes/java17/resources/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-java17-jvm-alpha.yaml
-java17-jvm-alpha-local.yaml
\ No newline at end of file
diff --git a/components/runtimes/java17/resources/cm.yaml.tpl b/components/runtimes/java17/resources/cm.yaml.tpl
deleted file mode 100644
index 8aba3632e..000000000
--- a/components/runtimes/java17/resources/cm.yaml.tpl
+++ /dev/null
@@ -1,11 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: dockerfile-${RUNTIME_NAME}
- namespace: kyma-system
- labels:
- serverless.kyma-project.io/config: runtime
- serverless.kyma-project.io/runtime: ${RUNTIME_NAME}
-data:
- Dockerfile: |-
-${DOCKERFILE}
diff --git a/components/runtimes/java17/resources/generate-cm.py b/components/runtimes/java17/resources/generate-cm.py
deleted file mode 100644
index e33c6647c..000000000
--- a/components/runtimes/java17/resources/generate-cm.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import os
-import sys
-
-
-indentation = " "
-
-def append_indentation(content):
- content_builder = ""
- for line in content.split("\n"):
- content_builder += (indentation + line+ "\n")
- return content_builder
-
-runtime = os.environ['RUNTIME']
-
-dockerfile_content=""
-for line in sys.stdin:
- dockerfile_content+=line
-
-dockerfile_content= append_indentation(dockerfile_content)
-
-cm_content=""
-with open("resources/cm.yaml.tpl") as cm_tpl_file:
- cm_tpl = cm_tpl_file.read()
- cm_content = cm_tpl.replace("${DOCKERFILE}", dockerfile_content).replace("${RUNTIME_NAME}",runtime)
-print(cm_content,end="")
diff --git a/components/runtimes/java17/resources/generate-dockerfile.py b/components/runtimes/java17/resources/generate-dockerfile.py
deleted file mode 100644
index bb24f699f..000000000
--- a/components/runtimes/java17/resources/generate-dockerfile.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import os
-
-
-dockerfile_file = os.environ['DOCKERFILE']
-base_image = os.environ['BASE_IMAGE']
-dockerfile_content = ""
-with open(dockerfile_file) as dockerfile:
- dockerfile_content = dockerfile.read()
- dockerfile_content = dockerfile_content.replace("${BASE_IMAGE}", base_image)
-
-print(dockerfile_content, end="")
diff --git a/components/runtimes/java17/serverless-java-sdk/Makefile b/components/runtimes/java17/serverless-java-sdk/Makefile
deleted file mode 100644
index 53a41883f..000000000
--- a/components/runtimes/java17/serverless-java-sdk/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-.default=install
-
-.PHONY: install
-install:
- mvn clean package install
\ No newline at end of file
diff --git a/components/runtimes/java17/serverless-java-sdk/pom.xml b/components/runtimes/java17/serverless-java-sdk/pom.xml
deleted file mode 100644
index c6b191a38..000000000
--- a/components/runtimes/java17/serverless-java-sdk/pom.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
- 4.0.0
-
- io.project.kyma.serverless
- serverless-java-sdk
- 0.0.1
- jar
-
-
- 11
- 11
-
-
-
-
- jakarta.ws.rs
- jakarta.ws.rs-api
- 3.1.0
- provided
-
-
- org.glassfish.jersey.core
- jersey-client
- 3.1.0
-
-
- com.fasterxml.jackson.core
- jackson-databind
- 2.14.0
-
-
- io.opentelemetry
- opentelemetry-api
- 1.20.0
-
-
-
\ No newline at end of file
diff --git a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/CloudEvent.java b/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/CloudEvent.java
deleted file mode 100644
index 0e7287894..000000000
--- a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/CloudEvent.java
+++ /dev/null
@@ -1,150 +0,0 @@
-package io.project.kyma.serverless.sdk;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.ObjectWriter;
-import io.opentelemetry.api.OpenTelemetry;
-import io.opentelemetry.api.trace.Tracer;
-import io.opentelemetry.context.propagation.TextMapSetter;
-import jakarta.ws.rs.client.Client;
-import jakarta.ws.rs.client.ClientBuilder;
-import jakarta.ws.rs.client.Entity;
-import jakarta.ws.rs.client.Invocation;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.MultivaluedHashMap;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import org.glassfish.jersey.client.ClientConfig;
-import org.glassfish.jersey.logging.LoggingFeature;
-
-import java.io.IOException;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-public class CloudEvent {
-
- private static final CloudEventHeaders[] CLOUD_EVENT_HEADERS = {CloudEventHeaders.CE_TYPE,
- CloudEventHeaders.CE_SOURCE,
- CloudEventHeaders.CE_EVENT_TYPE_VERSION,
- CloudEventHeaders.CE_SPEC_VERSION,
- CloudEventHeaders.CE_ID,
- CloudEventHeaders.CE_TIME,};
-
- private enum CloudEventHeaders {
- CE_TYPE("ce-type"), CE_SOURCE("ce-source"), CE_EVENT_TYPE_VERSION("ce-eventtypeversion"),
- CE_SPEC_VERSION("ce-specversion"), CE_TIME("ce-time"), CE_ID("ce-id");
-
- private final String headerName;
-
- public String getHeader() {
- return this.headerName;
- }
-
- CloudEventHeaders(String name) {
- this.headerName = name;
- }
- }
-
- public ContainerRequestContext req;
- public final MultivaluedMap ceHeaders;
-
- public Tracer tracer;
-
- private final URI publishedProxyAddress;
-
- private final OpenTelemetry openTelemetry;
-
- public CloudEvent(ContainerRequestContext req, OpenTelemetry openTelemetry, Tracer tracer, URI publisherAddr) {
- this.req = req;
- this.tracer = tracer;
- this.ceHeaders = extractCloudEventHeaders(req.getHeaders());
- this.openTelemetry = openTelemetry;
- this.publishedProxyAddress = publisherAddr;
- }
-
-
- public ResponseCloudEvent buildResponseCloudEvent(String id, String type, String data) {
- var ceResponse = new ResponseCloudEvent();
- ceResponse.type = type;
- ceResponse.source = getHeaderValue(ceHeaders, CloudEventHeaders.CE_SOURCE);
- ceResponse.eventTypeVersion = getHeaderValue(ceHeaders, CloudEventHeaders.CE_EVENT_TYPE_VERSION);
- ceResponse.specVersion = getHeaderValue(ceHeaders, CloudEventHeaders.CE_SPEC_VERSION);
- ceResponse.id = id;
- ceResponse.data = data;
- ceResponse.dataContentType = resolveDataType(data);
- return ceResponse;
- }
-
- public void publishCloudEvent(ResponseCloudEvent ceEvent) throws IOException, InterruptedException {
- ObjectWriter ow = new ObjectMapper().writer();
- var outBody = ow.writeValueAsBytes(ceEvent.data);
-
- ClientConfig config = new ClientConfig();
- config.register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.INFO, LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
-
- Client client = ClientBuilder.newClient(config);
-
- Invocation.Builder reqBuilder = client.target(this.publishedProxyAddress).request().
- header("Content-Type", "application/json").
- header(CloudEventHeaders.CE_SPEC_VERSION.getHeader(), ceEvent.specVersion).
- header(CloudEventHeaders.CE_TYPE.getHeader(), ceEvent.type).
- header(CloudEventHeaders.CE_SOURCE.getHeader(), ceEvent.source).
- header(CloudEventHeaders.CE_EVENT_TYPE_VERSION.getHeader(), ceEvent.eventTypeVersion).
- header(CloudEventHeaders.CE_ID.getHeader(), ceEvent.id);
-
- injectHeaderSetter(reqBuilder);
- var res = reqBuilder.post(Entity.json(ceEvent.data));
- if (Response.Status.Family.familyOf(res.getStatus()) != Response.Status.Family.SUCCESSFUL) {
- throw new IOException("Failed to send event. The publisher responded with:" + res.getStatus() + "status code which is not in 2xx successful family");
- }
- }
-
- public Invocation.Builder getTraceableRequestBuilder(String target) {
- Client client = ClientBuilder.newClient();
- Invocation.Builder reqBuilder = client.target(target).request();
- injectHeaderSetter(reqBuilder);
- return reqBuilder;
- }
-
- private void injectHeaderSetter(Invocation.Builder reqBuilder) {
-
- TextMapSetter setter = (carrier, key, value) -> {
- // Insert the context as Header
- System.out.println("Inject->" + key + ":" + value);
- assert carrier != null;
- carrier.header(key, value);
- };
- openTelemetry.getPropagators().getTextMapPropagator().inject(io.opentelemetry.context.Context.current(), reqBuilder, setter);
- }
-
- private static MultivaluedMap extractCloudEventHeaders(MultivaluedMap headers) {
- MultivaluedMap ceHeaders = new MultivaluedHashMap<>();
- Arrays.stream(CLOUD_EVENT_HEADERS).forEach(ceHeader -> ceHeaders.add(ceHeader.getHeader(), getHeaderValue(headers, ceHeader)));
- return ceHeaders;
- }
-
- private static String getHeaderValue(MultivaluedMap headers, CloudEventHeaders ceHeader) {
- String headerValue = "";
- var headerValues = headers.get(ceHeader.getHeader());
- if (headerValues != null && headerValues.size() > 0) {
- headerValue = headerValues.get(0);
- }
- return headerValue;
- }
-
-
- private static MediaType resolveDataType(String data) {
- try {
- final ObjectMapper mapper = new ObjectMapper();
- mapper.readTree(data);
- return MediaType.APPLICATION_JSON_TYPE;
-
- } catch (IOException ignored) {
-
- }
- return MediaType.TEXT_PLAIN_TYPE;
- }
-
-}
diff --git a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/Function.java b/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/Function.java
deleted file mode 100644
index 228f404b8..000000000
--- a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/Function.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package io.project.kyma.serverless.sdk;
-
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.core.Response;
-
-
-public interface Function {
- Response main(CloudEvent event, Context context);
-}
diff --git a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/ResponseCloudEvent.java b/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/ResponseCloudEvent.java
deleted file mode 100644
index a8ca69de9..000000000
--- a/components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/ResponseCloudEvent.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.project.kyma.serverless.sdk;
-import jakarta.ws.rs.core.MediaType;
-
-public class ResponseCloudEvent {
- public String type;
- public String source;
- public String eventTypeVersion;
- public String specVersion;
- public String id;
- public String data;
- public MediaType dataContentType;
-
-}
diff --git a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Config.java b/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Config.java
deleted file mode 100644
index 7795a8df4..000000000
--- a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Config.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package io.project.kyma.serverless;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
-public class Config {
-
- private static final int DEFAULT_PORT = 8080;
- protected final URI publisherProxyAddr;
- protected final URI tracingCollectorAddr;
- protected int port;
- protected final String podName;
- protected final String serviceNamespace;
-
- protected Config() throws IllegalArgumentException {
- this.publisherProxyAddr = getURIFromEnv("PUBLISHER_PROXY_ADDRESS");
- this.tracingCollectorAddr = getURIFromEnv("TRACE_COLLECTOR_ENDPOINT");
- this.podName = System.getenv("HOSTNAME");
- this.serviceNamespace = System.getenv("SERVICE_NAMESPACE");
- this.port = getNumber("FUNCTION_PORT");
- }
-
- private int getNumber(String envName) {
- int serverPort = DEFAULT_PORT;
- String fnPort = System.getenv(envName);
- if (fnPort != null && fnPort.equals("")) {
- serverPort = Integer.parseInt(fnPort);
- }
- return serverPort;
- }
-
- private URI getURIFromEnv(String envName) throws IllegalArgumentException {
- String envValue = System.getenv(envName);
- if (envValue == null) {
- throw new IllegalArgumentException("Couldn't find env:" + envName);
- }
- try {
- return new URI(envValue);
- } catch (URISyntaxException e) {
- throw new IllegalArgumentException("Couldn't parse env:" + envName + "with value:" + envValue, e);
- }
- }
-}
diff --git a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/JerseyServer.java b/components/runtimes/java17/src/main/java/io/project/kyma/serverless/JerseyServer.java
deleted file mode 100644
index f4f932770..000000000
--- a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/JerseyServer.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package io.project.kyma.serverless;
-
-import io.opentelemetry.api.GlobalOpenTelemetry;
-import io.opentelemetry.api.OpenTelemetry;
-import io.opentelemetry.api.internal.StringUtils;
-import io.opentelemetry.api.trace.Span;
-import io.opentelemetry.api.trace.SpanKind;
-import io.opentelemetry.context.propagation.TextMapGetter;
-import io.project.kyma.serverless.handler.Handler;
-import io.project.kyma.serverless.sdk.CloudEvent;
-import io.project.kyma.serverless.sdk.Function;
-
-import jakarta.ws.rs.*;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.core.MultivaluedMap;
-import jakarta.ws.rs.core.Response;
-import java.net.URI;
-import java.util.logging.Logger;
-
-@Path("/")
-public class JerseyServer {
-
-
- private final Function fn;
-
- private static final Logger logger = Logger.getGlobal();
-
- private final URI publisherProxyAddr;
-
- private final OpenTelemetry openTelemetry;
- private final String svcName;
-
- public JerseyServer(OpenTelemetry openTelemetry, URI publisherProxyAddr, String svcName) {
- this.publisherProxyAddr = publisherProxyAddr;
- this.svcName = svcName;
- this.openTelemetry = openTelemetry;
- this.fn = new Handler();
- }
-
- @GET
- @Path("/healthz")
- public Response healthz(@Context ContainerRequestContext request) {
- return Response.ok("ok").build();
- }
-
- @GET
- public Response home(@Context ContainerRequestContext request) {
- return callUserFunction(request);
- }
-
- @POST
- public Response homePost(@Context ContainerRequestContext request) {
- return callUserFunction(request);
- }
-
- @PUT
- public Response homePut(@Context ContainerRequestContext request) {
- return callUserFunction(request);
- }
-
- @DELETE
- public Response homeDelete(@Context ContainerRequestContext request) {
- return callUserFunction(request);
- }
-
-
- private Response callUserFunction(ContainerRequestContext httpRequest) {
- var tracer = openTelemetry.getTracerProvider().get(svcName);
- var extractedContext = injectPropagatorGetter(httpRequest);
- extractedContext.makeCurrent();
- Span span = null;
- try {
- span = tracer.spanBuilder("request").setSpanKind(SpanKind.SERVER).startSpan();
- span.makeCurrent();
-
- var ceEvent = new CloudEvent(httpRequest, openTelemetry, tracer, this.publisherProxyAddr);
- return this.fn.main(ceEvent, null);
- } finally {
- if (span != null) {
- span.end();
- }
- }
- }
-
- private io.opentelemetry.context.Context injectPropagatorGetter(ContainerRequestContext httpRequest) {
- TextMapGetter getter = new TextMapGetter<>() {
- @Override
- public Iterable keys(ContainerRequestContext requestContext) {
- return requestContext.getHeaders().keySet();
- }
-
- @Override
- public String get(ContainerRequestContext requestContext, String key) {
- String value = getHeaderValue(requestContext.getHeaders(), key);
- if (StringUtils.isNullOrEmpty(value)) {
- return null;
- }
- return value;
- }
- };
- return GlobalOpenTelemetry.get().getPropagators().getTextMapPropagator().extract(io.opentelemetry.context.Context.current(), httpRequest, getter);
- }
-
- private static String getHeaderValue(MultivaluedMap headers, String key) {
- String headerValue = "";
- var headerValues = headers.get(key);
- if (headerValues != null && headerValues.size() > 0) {
- headerValue = headerValues.get(0);
- }
- return headerValue;
- }
-}
-
diff --git a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Main.java b/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Main.java
deleted file mode 100644
index b46f36776..000000000
--- a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/Main.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package io.project.kyma.serverless;
-
-import io.opentelemetry.api.OpenTelemetry;
-import io.opentelemetry.api.common.Attributes;
-import io.opentelemetry.context.propagation.ContextPropagators;
-import io.opentelemetry.context.propagation.TextMapPropagator;
-import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter;
-import io.opentelemetry.extension.trace.propagation.B3Propagator;
-import io.opentelemetry.sdk.OpenTelemetrySdk;
-import io.opentelemetry.sdk.resources.Resource;
-import io.opentelemetry.sdk.trace.SdkTracerProvider;
-import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
-import io.opentelemetry.semconv.resource.attributes.ResourceAttributes;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.servlet.ServletHolder;
-import org.glassfish.jersey.server.ResourceConfig;
-import org.glassfish.jersey.servlet.ServletContainer;
-
-import java.net.URI;
-import java.util.Arrays;
-import java.util.stream.Collectors;
-
-public class Main {
-
- public Main(Config config) throws Exception {
- String svcName = createSvcName(config.podName, config.serviceNamespace);
-
- var openTelemetry = configureTracing(config.tracingCollectorAddr, svcName);
- Server server = configureServer(config.port, openTelemetry, svcName, config.publisherProxyAddr);
- server.start();
- server.join();
- }
-
- private Server configureServer(int serverPort, OpenTelemetry openTelemetry, String svcName, URI publisherProxyAddr) {
- ResourceConfig resourceConfig = new ResourceConfig();
-
- JerseyServer jerseyServer = new JerseyServer(openTelemetry, publisherProxyAddr, svcName);
- resourceConfig.registerInstances(jerseyServer);
-
- ServletContainer servletContainer = new ServletContainer(resourceConfig);
- ServletHolder sh = new ServletHolder(servletContainer);
-
- ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
- context.addServlet(sh, "/*");
-
- Server server = new Server(serverPort);
- server.setHandler(context);
- return server;
- }
-
- static String createSvcName(String podName, String svcNamespace) {
- if ((podName == null) || (svcNamespace == null)) {
- return "generic-svc";
- }
- // remove generated pods suffix ( two last sections )
- // TODO: createSvcName based on func name, not pod name
- var svcNameBuilder = Arrays.stream(podName.split("-")).limit(2).
- collect(Collectors.joining("-"));
- return String.join(".", svcNameBuilder, svcNamespace);
- }
-
- private OpenTelemetry configureTracing(URI tracingEndpoint, String svcName) {
- Resource resource = Resource.getDefault()
- .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, svcName)));
-
- SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
- .addSpanProcessor(SimpleSpanProcessor.create(OtlpHttpSpanExporter.builder().setEndpoint(tracingEndpoint.toString()).build()))
- .setResource(resource)
- .build();
- TextMapPropagator b3Propagator = B3Propagator.injectingMultiHeaders();
- var sdk = OpenTelemetrySdk.builder().setPropagators(ContextPropagators.create(b3Propagator)).
- setTracerProvider(sdkTracerProvider).
- buildAndRegisterGlobal();
- return sdk;
- }
-
- public static void main(String[] args) throws Exception {
- Config config = new Config();
- new Main(config);
- }
-}
diff --git a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/handler/Handler.java b/components/runtimes/java17/src/main/java/io/project/kyma/serverless/handler/Handler.java
deleted file mode 100644
index 6a9453038..000000000
--- a/components/runtimes/java17/src/main/java/io/project/kyma/serverless/handler/Handler.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.project.kyma.serverless.handler;
-
-import jakarta.ws.rs.core.Context;
-import jakarta.ws.rs.core.Response;
-
-import io.project.kyma.serverless.sdk.CloudEvent;
-import io.project.kyma.serverless.sdk.Function;
-
-
-public class Handler implements Function {
-
- @Override
- public Response main(CloudEvent event, Context context) {
- throw new IllegalStateException("Not implemented stub Handler");
- }
-}
diff --git a/components/runtimes/java17/src/main/test/io/project/kyma/serverless/MainTest.java b/components/runtimes/java17/src/main/test/io/project/kyma/serverless/MainTest.java
deleted file mode 100644
index 5bede5318..000000000
--- a/components/runtimes/java17/src/main/test/io/project/kyma/serverless/MainTest.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package io.project.kyma.serverless;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-class MainTest {
-
- @org.junit.jupiter.api.Test
- void createSvcName_Success() {
- //GIVEN
- String svcName = "default";
- String podName = "emitter-qqmds-84dd76fc94-2pnpd";
- String expected = "emitter-qqmds.default";
- //WHEN
- String output = Main.createSvcName(podName, svcName);
- //THEN
- assertEquals(expected, output);
- }
-}
\ No newline at end of file
diff --git a/components/runtimes/nodejs/.gitignore b/components/runtimes/nodejs/.gitignore
deleted file mode 100644
index cb9d27e23..000000000
--- a/components/runtimes/nodejs/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-#For local debugging
-function
-package.json
-package-lock.json
-node_modules
diff --git a/components/runtimes/nodejs/README.md b/components/runtimes/nodejs/README.md
deleted file mode 100644
index da4d117d5..000000000
--- a/components/runtimes/nodejs/README.md
+++ /dev/null
@@ -1,16 +0,0 @@
-## How to locally run and debug the Node.js Function and runtime
-
-1.Copy `package.json` from the desired Node.js version
-
-2.Create the `function` directory with `handler.js` and `package.json`
-
-3.Install dependencies from the runtime and Function:
- ```bash
- npm install
- npm install function/
- ```
-
-4.Run Function from the terminal.
- ```bash
- npm start
- ```
diff --git a/components/runtimes/nodejs/lib/ce.js b/components/runtimes/nodejs/lib/ce.js
deleted file mode 100644
index 17a2f28fe..000000000
--- a/components/runtimes/nodejs/lib/ce.js
+++ /dev/null
@@ -1,136 +0,0 @@
-'use strict';
-
-const axios = require('axios');
-const { HTTP, CloudEvent } = require('cloudevents');
-const charset = 'utf-8'
-
-const publishProxyAddress = (process.env.PUBLISHER_PROXY_ADDRESS);
-
-module.exports = {
- buildEvent
-};
-
-function buildEvent(req, res, tracer) {
-
- let event = {
- tracer,
- 'extensions': { request: req, response: res },
- setResponseHeader: (key, value) => setResponseHeader(res, key, value),
- setResponseContentType: (type) => setResponseContentType(res, type),
- setResponseStatus: (status) => setResponseStatus(res, status),
- //deprecated
- publishCloudEvent: (data) => publishCloudEvent(data),
- //deprecated
- buildResponseCloudEvent: (id, type, data) => buildResponseCloudEvent(req, id, type, data),
- emitCloudEvent: (type, source, data, optionalCloudEventAttributes) => emitCloudEvent(type, source, data, optionalCloudEventAttributes),
- };
-
- if(req.body){
- if (!req.is('multipart/*')) {
- if(isCloudEvent(req)) {
- event = Object.assign(event,buildCloudEventAttributes(req));
- } else {
- event = Object.assign(event,{'data':req.body});
- }
- }
- }
- return event;
-}
-
-function setResponseHeader(res, key, value) {
- res.set(key, value);
-}
-
-function setResponseContentType(res, type) {
- res.type(type);
-}
-
-function setResponseStatus(res, status) {
- res.status(status);
-}
-
-function publishCloudEvent(data) {
- console.warn("publishCloudEvent is deprecated. Use emitCloudEvent")
- return axios({
- method: "post",
- baseURL: publishProxyAddress,
- headers: {
- "Content-Type": "application/cloudevents+json"
- },
- data: data,
- });
-}
-
-function resolvedatatype(data){
- switch(typeof data) {
- case 'object':
- return 'application/json'
- case 'string':
- return 'text/plain'
- }
-}
-
-function buildResponseCloudEvent(req, id, type, data) {
- console.warn("buildResponseCloudEvent is deprecated. Use emitCloudEvent")
- return {
- 'type': type,
- 'source': req.get('ce-source'),
- 'eventtypeversion': req.get('ce-eventtypeversion'),
- 'specversion': req.get('ce-specversion'),
- 'id': id,
- 'data': data,
- 'datacontenttype': resolvedatatype(data),
- };
-}
-
-function isCloudEvent(req) {
- return req.is('application/cloudevents+json') || hasCeHeaders(req);
-}
-
-
-function hasCeHeaders(req) {
- return req.get('ce-type') && req.get('ce-source');
-}
-
-function buildCloudEventAttributes(req) {
- const receivedEvent = HTTP.toEvent({ headers: req.headers, body: req.body });
- return {
- 'ce-type': receivedEvent.type,
- 'ce-source': receivedEvent.source,
- 'ce-eventtypeversion': receivedEvent.eventtypeversion,
- 'ce-specversion': receivedEvent.specversion,
- 'ce-id': receivedEvent.id,
- 'ce-time': receivedEvent.time,
- 'ce-datacontenttype': receivedEvent.datacontenttype,
- 'data': receivedEvent.data
- };
-}
-
-function emitCloudEvent(type, source, data, optionalCloudEventAttributes) {
-
- let optionalCloudEventAttributesInput = optionalCloudEventAttributes
- if(!optionalCloudEventAttributesInput){
- optionalCloudEventAttributesInput = {}
- }
-
- let cloudEventInput = {
- type,
- source,
- data,
- }
-
- if(!optionalCloudEventAttributesInput.datacontenttype){
- optionalCloudEventAttributesInput.datacontenttype = resolvedatatype(data);
- }
-
- cloudEventInput = Object.assign(cloudEventInput, optionalCloudEventAttributesInput)
- const ce = new CloudEvent(cloudEventInput);
- const message = HTTP.structured(ce)
-
- return axios({
- method: "post",
- baseURL: publishProxyAddress,
- headers: message.headers,
- data: message.body,
- });
-}
\ No newline at end of file
diff --git a/components/runtimes/nodejs/lib/helper.js b/components/runtimes/nodejs/lib/helper.js
deleted file mode 100644
index fe93ee99e..000000000
--- a/components/runtimes/nodejs/lib/helper.js
+++ /dev/null
@@ -1,90 +0,0 @@
-'use strict';
-
-const opentelemetry = require('@opentelemetry/api');
-
-function configureGracefulShutdown(server) {
- let nextConnectionId = 0;
- const connections = [];
- let terminating = false;
-
- server.on('connection', connection => {
- const connectionId = nextConnectionId++;
- connection.$$isIdle = true;
- connections[connectionId] = connection;
- connection.on('close', () => delete connections[connectionId]);
- });
-
- server.on('request', (request, response) => {
- const connection = request.connection;
- connection.$$isIdle = false;
-
- response.on('finish', () => {
- connection.$$isIdle = true;
- if (terminating) {
- connection.destroy();
- }
- });
- });
-
- const handleShutdown = () => {
- console.log("Shutting down..");
-
- terminating = true;
- server.close(() => console.log("Server stopped"));
-
- for (const connectionId in connections) {
- if (connections.hasOwnProperty(connectionId)) {
- const connection = connections[connectionId];
- if (connection.$$isIdle) {
- connection.destroy();
- }
- }
- }
- };
-
- process.on('SIGINT', handleShutdown);
- process.on('SIGTERM', handleShutdown);
- }
-
-function handleTimeOut(req, res, next){
- const timeout = Number(process.env.FUNC_TIMEOUT || '180');
- res.setTimeout(timeout*1000, function(){
- res.sendStatus(408);
- });
- next();
-}
-
-const isFunction = (func) => {
- return func && func.constructor && func.call && func.apply;
-};
-
-const isPromise = (promise) => {
- return typeof promise.then == "function"
-}
-
-
-function handleError(err, span, sendResponse) {
- console.error(err);
- const errTxt = resolveErrorMsg(err);
- span.setStatus({ code: opentelemetry.SpanStatusCode.ERROR, message: errTxt });
- span.setAttribute("error", errTxt);
- sendResponse(errTxt, 500);
-}
-
-function resolveErrorMsg(err) {
- let errText
- if (typeof err == "string") {
- errText = err
- } else {
- errText = "Internal server error"
- }
- return errText
-}
-
-module.exports = {
- configureGracefulShutdown,
- handleTimeOut,
- isFunction,
- isPromise,
- handleError
-};
\ No newline at end of file
diff --git a/components/runtimes/nodejs/lib/metrics.js b/components/runtimes/nodejs/lib/metrics.js
deleted file mode 100644
index c6e4984b5..000000000
--- a/components/runtimes/nodejs/lib/metrics.js
+++ /dev/null
@@ -1,57 +0,0 @@
-const opentelemetry = require('@opentelemetry/api');
-const { MeterProvider } = require('@opentelemetry/sdk-metrics');
-const { PrometheusExporter } = require('@opentelemetry/exporter-prometheus');
-const { Resource } = require( '@opentelemetry/resources');
-const { SemanticResourceAttributes } = require( '@opentelemetry/semantic-conventions');
-
-let exporter;
-
-function setupMetrics(){
-
- const resource = new Resource();
-
- const myServiceMeterProvider = new MeterProvider({
- resource,
- });
-
- exporter = new PrometheusExporter({ preventServerStart: true})
-
- myServiceMeterProvider.addMetricReader(exporter);
-
- opentelemetry.metrics.setGlobalMeterProvider(myServiceMeterProvider);
-
-}
-
-function createFunctionCallsTotalCounter(name){
- const meter = opentelemetry.metrics.getMeter(name)
- return meter.createCounter('function_calls_total',{
- description: 'Number of calls to user function',
- });
-}
-
-
-function createFunctionFailuresTotalCounter(name){
- const meter = opentelemetry.metrics.getMeter(name)
- return meter.createCounter('function_failures_total',{
- description: 'Number of exceptions in user function',
- });
-}
-
-function createFunctionDurationHistogram(name){
- const meter = opentelemetry.metrics.getMeter(name)
- return meter.createHistogram("function_duration_miliseconds",{
- description: 'Duration of user function in miliseconds',
- });
-}
-
-const getMetrics = (req, res) => {
- exporter.getMetricsRequestHandler(req, res);
-};
-
-module.exports = {
- setupMetrics,
- createFunctionCallsTotalCounter,
- createFunctionFailuresTotalCounter,
- createFunctionDurationHistogram,
- getMetrics,
-}
\ No newline at end of file
diff --git a/components/runtimes/nodejs/lib/tracer.js b/components/runtimes/nodejs/lib/tracer.js
deleted file mode 100644
index 9e38c2f23..000000000
--- a/components/runtimes/nodejs/lib/tracer.js
+++ /dev/null
@@ -1,80 +0,0 @@
-'use strict';
-
-const opentelemetry = require('@opentelemetry/api');
-const { ParentBasedSampler, AlwaysOnSampler, CompositePropagator, W3CTraceContextPropagator } = require( '@opentelemetry/core');
-const { registerInstrumentations } = require( '@opentelemetry/instrumentation');
-const { NodeTracerProvider } = require( '@opentelemetry/sdk-trace-node');
-const { SimpleSpanProcessor } = require( '@opentelemetry/sdk-trace-base');
-const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');
-const { Resource } = require( '@opentelemetry/resources');
-const { B3Propagator, B3InjectEncoding } = require("@opentelemetry/propagator-b3");
-const { ExpressInstrumentation, ExpressLayerType } = require( '@opentelemetry/instrumentation-express');
-const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
-const axios = require("axios")
-
-
-const ignoredTargets = [
- "/healthz", "/favicon.ico", "/metrics"
-]
-
-function setupTracer(){
-
- const provider = new NodeTracerProvider({
- resource: new Resource(),
- sampler: new ParentBasedSampler({
- root: new AlwaysOnSampler()
- }),
- });
-
- const propagator = new CompositePropagator({
- propagators: [
- new W3CTraceContextPropagator(),
- new B3Propagator({injectEncoding: B3InjectEncoding.MULTI_HEADER})
- ],
- })
-
- registerInstrumentations({
- tracerProvider: provider,
- instrumentations: [
- new HttpInstrumentation({
- ignoreIncomingPaths: ignoredTargets,
- }),
- new ExpressInstrumentation({
- ignoreLayersType: [ExpressLayerType.MIDDLEWARE]
- }),
- ],
- });
-
-
- const traceCollectorEndpoint = process.env.TRACE_COLLECTOR_ENDPOINT;
-
- if(traceCollectorEndpoint){
- const exporter = new OTLPTraceExporter({
- url: traceCollectorEndpoint
- });
-
- provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
- }
-
- // Initialize the OpenTelemetry APIs to use the NodeTracerProvider bindings
- provider.register({
- propagator: propagator,
- });
-
- return opentelemetry.trace.getTracer("tracer");
-};
-
-module.exports = {
- setupTracer,
- startNewSpan
-}
-
-
-function startNewSpan(name, tracer){
- const currentSpan = opentelemetry.trace.getSpan(opentelemetry.context.active());
- const ctx = opentelemetry.trace.setSpan(
- opentelemetry.context.active(),
- currentSpan
- );
- return tracer.startSpan(name, undefined, ctx);
-}
diff --git a/components/runtimes/nodejs/nodejs18/Dockerfile b/components/runtimes/nodejs/nodejs18/Dockerfile
deleted file mode 100644
index 8917f9175..000000000
--- a/components/runtimes/nodejs/nodejs18/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# image base on node:18.16.1-alpine3.17 (node:18.16.0, alpine:3.17.4)
-FROM node@sha256:56a82eb7c721b7e4c151366000a60d1f1b1ded51e55e8ff9cc106f603dfe6521
-
-ARG NODE_ENV
-ENV NODE_ENV $NODE_ENV
-ENV npm_config_cache /tmp/
-
-RUN mkdir -p /usr/src/app
-RUN mkdir -p /usr/src/app/lib
-WORKDIR /usr/src/app
-
-COPY ./nodejs18/package.json /usr/src/app/
-RUN npm install && npm cache clean --force
-COPY ./lib /usr/src/app/lib
-
-COPY ./server.js /usr/src/app/server.js
-
-CMD ["npm", "start"]
-
-EXPOSE 8888
diff --git a/components/runtimes/nodejs/nodejs18/package.json b/components/runtimes/nodejs/nodejs18/package.json
deleted file mode 100644
index b2d1f8438..000000000
--- a/components/runtimes/nodejs/nodejs18/package.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "nodejs18-runtime",
- "version": "0.1.0",
- "description": "NodeJS v18 container for kyma serverless",
- "engines": {
- "node": ">= 18.0.0"
- },
- "dependencies": {
- "@opentelemetry/api": "^1.4.0",
- "@opentelemetry/exporter-trace-otlp-http": "^0.49.1",
- "@opentelemetry/instrumentation": "^0.49.1",
- "@opentelemetry/instrumentation-express": "^0.36.0",
- "@opentelemetry/instrumentation-http": "^0.49.1",
- "@opentelemetry/propagator-b3": "^1.9.1",
- "@opentelemetry/sdk-trace-node": "^1.9.1",
- "@opentelemetry/tracing": "^0.24.0",
- "@opentelemetry/sdk-metrics": "^1.15.1",
- "@opentelemetry/exporter-prometheus": "^0.49.1",
- "axios": "^1.3.3",
- "co": "^4.6.0",
- "express": ">=4.18.2",
- "morgan": "*",
- "mz": "^2.7.0",
- "cloudevents": "^8.0.0"
- }
-}
diff --git a/components/runtimes/nodejs/nodejs20/Dockerfile b/components/runtimes/nodejs/nodejs20/Dockerfile
deleted file mode 100644
index b9256bc06..000000000
--- a/components/runtimes/nodejs/nodejs20/Dockerfile
+++ /dev/null
@@ -1,20 +0,0 @@
-# image base on node:20.11.1-alpine3.19 (node:20.11.1, alpine:3.19.1)
-FROM node@sha256:c0a3badbd8a0a760de903e00cedbca94588e609299820557e72cba2a53dbaa2c
-
-ARG NODE_ENV
-ENV NODE_ENV $NODE_ENV
-ENV npm_config_cache /tmp/
-
-RUN mkdir -p /usr/src/app
-RUN mkdir -p /usr/src/app/lib
-WORKDIR /usr/src/app
-
-COPY ./nodejs20/package.json /usr/src/app/
-RUN npm install && npm cache clean --force
-COPY ./lib /usr/src/app/lib
-
-COPY ./server.js /usr/src/app/server.js
-
-CMD ["npm", "start"]
-
-EXPOSE 8888
diff --git a/components/runtimes/nodejs/nodejs20/package.json b/components/runtimes/nodejs/nodejs20/package.json
deleted file mode 100644
index ca3a310ec..000000000
--- a/components/runtimes/nodejs/nodejs20/package.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "name": "nodejs20-runtime",
- "version": "0.1.0",
- "description": "NodeJS v20 container for kyma serverless",
- "engines": {
- "node": ">= 20.0.0"
- },
- "dependencies": {
- "@opentelemetry/api": "^1.4.0",
- "@opentelemetry/exporter-trace-otlp-http": "^0.49.1",
- "@opentelemetry/instrumentation": "^0.49.1",
- "@opentelemetry/instrumentation-express": "^0.36.0",
- "@opentelemetry/instrumentation-http": "^0.49.1",
- "@opentelemetry/propagator-b3": "^1.9.1",
- "@opentelemetry/sdk-trace-node": "^1.9.1",
- "@opentelemetry/tracing": "^0.24.0",
- "@opentelemetry/sdk-metrics": "^1.15.1",
- "@opentelemetry/exporter-prometheus": "^0.49.1",
- "axios": "^1.3.3",
- "co": "^4.6.0",
- "express": ">=4.18.2",
- "morgan": "*",
- "mz": "^2.7.0",
- "cloudevents": "^8.0.0"
- }
-}
diff --git a/components/runtimes/nodejs/server.js b/components/runtimes/nodejs/server.js
deleted file mode 100644
index e53f65e8e..000000000
--- a/components/runtimes/nodejs/server.js
+++ /dev/null
@@ -1,181 +0,0 @@
-"use strict";
-const ce = require('./lib/ce');
-const helper = require('./lib/helper');
-const bodyParser = require('body-parser');
-const process = require("process");
-const morgan = require("morgan");
-
-const { setupTracer, startNewSpan } = require('./lib/tracer')
-const { getMetrics, setupMetrics, createFunctionDurationHistogram, createFunctionCallsTotalCounter, createFunctionFailuresTotalCounter } = require('./lib/metrics')
-
-
-// To catch unhandled exceptions thrown by user code async callbacks,
-// these exceptions cannot be catched by try-catch in user function invocation code below
-process.on("uncaughtException", (err) => {
- console.error(`Caught exception: ${err}`);
-});
-
-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 tracer = setupTracer();
-setupMetrics();
-
-const callsTotalCounter = createFunctionCallsTotalCounter(functionName);
-const failuresTotalCounter = createFunctionFailuresTotalCounter(functionName);
-const durationHistogram = createFunctionDurationHistogram(functionName);
-
-//require express must be called AFTER tracer was setup!!!!!!
-const express = require("express");
-const app = express();
-
-
-// User function. Starts out undefined.
-let userFunction;
-
-const loadFunction = (modulepath, funcname) => {
- // Read and load the code. It's placed there securely by the fission runtime.
- try {
- let startTime = process.hrtime();
- // support v1 codepath and v2 entrypoint like 'foo', '', 'index.hello'
- let userFunction = funcname
- ? require(modulepath)[funcname]
- : require(modulepath);
- let elapsed = process.hrtime(startTime);
- console.log(
- `user code loaded in ${elapsed[0]}sec ${elapsed[1] / 1000000}ms`
- );
- return userFunction;
- } catch (e) {
- console.error(`user code load error: ${e}`);
- return e;
- }
-};
-
-// Request logger
-if (process.env["KYMA_INTERNAL_LOGGER_ENABLED"]) {
- app.use(morgan("combined"));
-}
-
-
-app.use(bodyParser.json({ type: ['application/json', 'application/cloudevents+json'], limit: `${bodySizeLimit}mb`, strict: false }))
-app.use(bodyParser.text({ type: ['text/*'], limit: `${bodySizeLimit}mb` }))
-app.use(bodyParser.urlencoded({ limit: `${bodySizeLimit}mb`, extended: true }));
-app.use(bodyParser.raw({limit: `${bodySizeLimit}mb`, type: () => true}))
-
-app.use(helper.handleTimeOut);
-
-app.get("/healthz", (req, res) => {
- res.status(200).send("OK")
-})
-
-app.get("/metrics", (req, res) => {
- getMetrics(req, res)
-})
-
-app.get('/favicon.ico', (req, res) => res.status(204));
-
-// Generic route -- all http requests go to the user function.
-app.all("*", (req, res, next) => {
-
-
- res.header('Access-Control-Allow-Origin', '*');
- if (req.method === 'OPTIONS') {
- // CORS preflight support (Allow any method or header requested)
- res.header('Access-Control-Allow-Methods', req.headers['access-control-request-method']);
- res.header('Access-Control-Allow-Headers', req.headers['access-control-request-headers']);
- res.end();
- } else {
-
- callsTotalCounter.add(1)
- const startTime = new Date().getTime()
-
- if (!userFunction) {
- failuresTotalCounter.add(1)
- res.status(500).send("User function not loaded");
- return;
- }
-
- const event = ce.buildEvent(req, res, tracer);
-
- const context = {
- 'function-name': functionName,
- 'runtime': process.env.FUNC_RUNTIME,
- 'namespace': serviceNamespace
- };
-
- const sendResponse = (body, status, headers) => {
- if (res.writableEnded) return;
- if (headers) {
- for (let name of Object.keys(headers)) {
- res.set(name, headers[name]);
- }
- }
- if(body){
- if(status){
- res.status(status);
- }
- switch (typeof body) {
- case 'object':
- res.json(body); // includes res.end(), null also handled
- break;
- case 'undefined':
- res.end();
- break;
- default:
- res.end(body);
- }
- // res.send(body);
- } else if(status){
- res.sendStatus(status);
- } else {
- res.end();
- }
- };
-
- const span = startNewSpan('userFunction', tracer);
-
- try {
- // Execute the user function
- const out = userFunction(event, context, sendResponse);
- if (out && helper.isPromise(out)) {
- out.then(result => {
- sendResponse(result)
- })
- .catch((err) => {
- helper.handleError(err, span, sendResponse)
- failuresTotalCounter.add(1);
- })
- .finally(()=>{
- span.end();
- })
- } else {
- sendResponse(out);
- }
- } catch (err) {
- helper.handleError(err, span, sendResponse)
- failuresTotalCounter.add(1);
- } finally {
- span.end();
- }
-
- const endTime = new Date().getTime()
- const executionTime = endTime - startTime;
- durationHistogram.record(executionTime);
- }
-});
-
-
-const server = app.listen(funcPort);
-
-helper.configureGracefulShutdown(server);
-
-
-const fn = loadFunction("./function/handler", "");
-if (helper.isFunction(fn.main)) {
- userFunction = fn.main
-} else {
- console.error("Content loaded is not a function", fn)
-}
diff --git a/components/runtimes/python/.gitignore b/components/runtimes/python/.gitignore
deleted file mode 100644
index 4c507e526..000000000
--- a/components/runtimes/python/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-#For local debugging
-function
-venv
-__pycache__
diff --git a/components/runtimes/python/README.md b/components/runtimes/python/README.md
deleted file mode 100644
index 307cbfe82..000000000
--- a/components/runtimes/python/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-## How to locally run and debug Python Function and runtime
-
-1.Create [venv](https://docs.python.org/3/library/venv.html)
-```bash
-python3 -m venv venv
-```
-
-2.Activate venv:
- ```bash
- source venv/bin/activete
- ```
-3.Create the `function` directory with `handler.py` and `requirements.txt`
-
-4. Install dependencies from specific Python Runtime Version {XYZ} and Function:
- ```bash
- pip install -r python{XYZ}/requirements.txt
- pip install -r function/requirements.txt
- ```
-
-5.Set the following envs:
- ```bash
- export FUNCTION_PATH=./function
- export MOD_NAME=handler
- export FUNC_HANDLER=main
- ```
-
-6.Run Function from the terminal.
- ```bash
- python3 kubeless/kubeless.py
- ```
-
diff --git a/components/runtimes/python/kubeless.py b/components/runtimes/python/kubeless.py
deleted file mode 100644
index 6367f7649..000000000
--- a/components/runtimes/python/kubeless.py
+++ /dev/null
@@ -1,196 +0,0 @@
-#!/usr/bin/env python
-
-import importlib
-import os
-import queue
-import sys
-import threading
-
-import bottle
-import prometheus_client as prom
-
-import lib.tracing as tracing
-from lib.ce import Event
-from lib.tracing import set_req_context
-
-
-# The reason this file has an underscore prefix in its name is to avoid a
-# name collision with the user-defined module.
-module_name = os.getenv('MOD_NAME')
-if module_name is None:
- print('MOD_NAME have to be provided', flush=True)
- exit(1)
-current_mod = os.path.basename(__file__).split('.')[0]
-if module_name == current_mod:
- print('Module cannot be named {} as current module'.format(current_mod), flush=True)
- exit(2)
-
-function_location = os.getenv('FUNCTION_PATH', default='/kubeless')
-sys.path.append(function_location)
-
-mod = importlib.import_module(module_name)
-func_name = os.getenv('FUNC_HANDLER')
-if func_name is None:
- print('FUNC_HANDLER have to be provided', flush=True)
- exit(3)
-
-func = getattr(mod, os.getenv('FUNC_HANDLER'))
-
-func_port = os.getenv('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
-
-app = application = bottle.app()
-
-function_context = {
- 'function-name': os.getenv('FUNC_NAME'),
- 'namespace': os.getenv('SERVICE_NAMESPACE'),
- 'timeout': timeout,
- 'runtime': os.getenv('FUNC_RUNTIME'),
- 'memory-limit': os.getenv('FUNC_MEMORY_LIMIT'),
-}
-
-if __name__ == "__main__":
- tracer = tracing._setup_tracer()
-
-
-def func_with_context(e, function_context):
- ex = e.ceHeaders["extensions"]
- with set_req_context(ex["request"]):
- with tracer.start_as_current_span("userFunction"):
- try:
- return func(e, function_context)
- except Exception as e:
- return e
-
-
-@app.get('/favicon.ico')
-def favicon():
- return bottle.HTTPResponse(status=204)
-
-@app.get('/healthz')
-def healthz():
- return 'OK'
-
-
-@app.get('/metrics')
-def metrics():
- bottle.response.content_type = prom.CONTENT_TYPE_LATEST
- return prom.generate_latest(prom.REGISTRY)
-
-
-@app.error(500)
-def exception_handler(err):
- return 'Internal server error'
-
-
-@app.route('/<:re:.*>', method=['GET', 'POST', 'PATCH', 'DELETE'])
-def handler():
- req = bottle.request
- event = Event(req, tracer)
-
- method = req.method
- func_calls.labels(method).inc()
- with func_errors.labels(method).count_exceptions():
- with func_hist.labels(method).time():
- que = queue.Queue()
- t = threading.Thread(target=lambda q, e: q.put(func_with_context(e, function_context)), args=(que, event))
- t.start()
- try:
- res = que.get(block=True, timeout=timeout)
- if hasattr(res, 'headers') and 'content-type' in res.headers:
- bottle.response.content_type = res.headers["content-type"]
- except queue.Empty:
- return bottle.HTTPError(408, "Timeout while processing the function")
- else:
- t.join()
- if isinstance(res, Exception):
- raise res
- return res
-
-
-def preload():
- """This is a no-op function used to start the forkserver."""
- pass
-
-
-if __name__ == '__main__':
- import logging
- import multiprocessing as mp
- from multiprocessing import util
- import requestlogger
-
- # TODO: this is workaround for: CVE-2022-42919
- # More details: https://github.com/python/cpython/issues/97514
- util.abstract_sockets_supported = False
-
- mp_context = os.getenv('MP_CONTEXT', 'forkserver')
-
- if mp_context == "fork":
- raise ValueError(
- '"fork" multiprocessing context is not supported because cheroot is a '
- 'multithreaded server and safely forking a multithreaded process is '
- 'problematic'
- )
- if mp_context not in ["forkserver", "spawn"]:
- raise ValueError(
- f'"{mp_context}" is an invalid multiprocessing context. Possible values '
- 'are "forkserver" and "spawn"'
- )
-
- try:
- ctx = mp.get_context(mp_context)
-
- if ctx.get_start_method() == 'forkserver':
- # Preload the current module and consequently also the user-defined module
- # so that all the child processes forked from the forkserver in response to
- # a request immediately have access to the global data in the user-defined
- # module without having to load it for every request.
- ctx.set_forkserver_preload([current_mod])
-
- # Start the forkserver before we start accepting requests.
- d = ctx.Process(target=preload)
- d.start()
- d.join()
-
- except ValueError:
- # Default to 'spawn' if 'forkserver' is unavailable.
- ctx = mp.get_context('spawn')
- logging.warn(
- f'"{mp_context}" multiprocessing context is unavailable. Using "spawn"'
- )
-
- func_hist = prom.Histogram(
- 'function_duration_seconds', 'Duration of user function in seconds', ['method']
- )
- func_calls = prom.Counter(
- 'function_calls_total', 'Number of calls to user function', ['method']
- )
- func_errors = prom.Counter(
- 'function_failures_total', 'Number of exceptions in user function', ['method']
- )
-
- # added by Kyma team
- if os.getenv('KYMA_INTERNAL_LOGGER_ENABLED'):
- # default that has been used so far
- loggedapp = requestlogger.WSGILogger(
- app,
- [logging.StreamHandler(stream=sys.stdout)],
- requestlogger.ApacheFormatter(),
- )
- else:
- loggedapp = app
- # end of modified section
-
- bottle.run(
- loggedapp,
- server='cheroot',
- host='0.0.0.0',
- port=func_port,
- # Set this flag to True to auto-reload the server after any source files change
- reloader=os.getenv('CHERRYPY_RELOADED', False),
- # Number of requests that can be handled in parallel (default = 50).
- numthreads=int(os.getenv('CHERRYPY_NUMTHREADS', 50)),
- quiet='KYMA_BOTTLE_QUIET_OPTION_DISABLED' not in os.environ,
- )
diff --git a/components/runtimes/python/lib/ce.py b/components/runtimes/python/lib/ce.py
deleted file mode 100644
index 139344f7c..000000000
--- a/components/runtimes/python/lib/ce.py
+++ /dev/null
@@ -1,138 +0,0 @@
-import bottle
-import io
-import json
-import logging
-import os
-
-import requests
-from cloudevents.http import from_http, CloudEvent
-from cloudevents.conversion import to_structured
-
-publisher_proxy_address = os.getenv('PUBLISHER_PROXY_ADDRESS')
-
-
-class PicklableBottleRequest(bottle.BaseRequest):
- '''Bottle request that can be pickled (serialized).
-
- `bottle.BaseRequest` is not picklable and therefore cannot be passed directly to a
- python multiprocessing `Process` when using the forkserver or spawn multiprocessing
- contexts. So, we selectively delete components that are not picklable.
- '''
-
- def __init__(self, data, *args, **kwargs):
- super().__init__(*args, **kwargs)
- # Bottle uses either `io.BytesIO` or `tempfile.TemporaryFile` to store the
- # request body depending on whether the length of the body is less than
- # `MEMFILE_MAX` or not, but `tempfile.TemporaryFile` is not picklable.
- # So, we override it to always store the body as `io.BytesIO`.
- self.environ['bottle.request.body'] = io.BytesIO(data)
-
- def __getstate__(self):
- env = self.environ.copy()
-
- # File-like objects are not picklable.
- del env['wsgi.errors']
- del env['wsgi.input']
-
- # bottle.ConfigDict is not picklable because it contains a lambda function.
- del env['bottle.app']
- del env['bottle.route']
- del env['route.handle']
-
- return env
-
- def __setstate__(self, env):
- setattr(self, 'environ', env)
-
-
-def resolve_data_type(event_data):
- if type(event_data) is dict:
- return 'application/json'
- elif type(event_data) is str:
- return 'text/plain'
-
-
-def build_cloud_event_attributes(req, data):
- event = from_http(req.headers, data)
- ceHeaders = {
- 'data': event.data,
- 'ce-type': event['type'],
- 'ce-source': event['source'],
- 'ce-id': event['id'],
- 'ce-time': event['time'],
- }
- if event.get('eventtypeversion') is not None:
- ceHeaders['ce-eventtypeversion'] = event.get('eventtypeversion')
-
- if event.get('specversion') is not None:
- ceHeaders['ce-specversion'] = event.get('specversion')
-
- return ceHeaders
-
-
-def has_ce_headers(headers):
- has = 'ce-type' in headers and 'ce-source' in headers
- return has
-
-
-def is_cloud_event(req):
- return 'application/cloudevents+json' in req.content_type.split(';') or has_ce_headers(req.headers)
-
-
-class Event:
- def __init__(self, req, tracer):
- self.ceHeaders = dict()
- self.tracer = tracer
- self.req = req
- data = req.body.read()
- picklable_req = PicklableBottleRequest(data, req.environ.copy())
- self.ceHeaders.update({
- 'extensions': {'request': picklable_req}
- })
-
- if is_cloud_event(req):
- ce_headers = build_cloud_event_attributes(req, data)
- self.ceHeaders.update(ce_headers)
- else:
- if req.get_header('content-type') == 'application/json':
- data = req.json
- self.ceHeaders.update({'data': data})
-
- def __getitem__(self, item):
- return self.ceHeaders[item]
-
- def __setitem__(self, name, value):
- self.ceHeaders[name] = value
-
- def emitCloudEvent(self, type, source, data, optionalCloudEventAttributes=None):
- attributes = {
- "type": type,
- "source": source,
- }
- if optionalCloudEventAttributes is not None:
- attributes.update(optionalCloudEventAttributes)
-
- event = CloudEvent(attributes, data)
- headers, body = to_structured(event)
-
- requests.post(publisher_proxy_address, data=body, headers=headers)
-
- def publishCloudEvent(self, data):
- logging.warn('"publishCloudEvent" is deprecated. Use "emitCloudEvent"')
- return requests.post(
- publisher_proxy_address,
- data=json.dumps(data, default=str),
- headers={"Content-Type": "application/cloudevents+json"}
- )
-
- def buildResponseCloudEvent(self, event_id, event_type, event_data):
- logging.warn('"buildResponseCloudEvent" is deprecated. Use "emitCloudEvent"')
- return {
- 'type': event_type,
- 'source': self.ceHeaders['ce-source'],
- 'eventtypeversion': self.ceHeaders['ce-eventtypeversion'],
- 'specversion': self.ceHeaders['ce-specversion'],
- 'id': event_id,
- 'data': event_data,
- 'datacontenttype': resolve_data_type(event_data)
- }
diff --git a/components/runtimes/python/lib/tracing.py b/components/runtimes/python/lib/tracing.py
deleted file mode 100644
index 0ec0e04b6..000000000
--- a/components/runtimes/python/lib/tracing.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from contextlib import contextmanager
-from typing import Iterator
-
-from opentelemetry import trace
-from opentelemetry.sdk.trace import TracerProvider, _Span
-from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
-from opentelemetry.propagate import extract
-from opentelemetry.sdk.resources import Resource
-
-from opentelemetry.sdk.trace.export import (
- SimpleSpanProcessor,
-)
-from opentelemetry.sdk.trace.sampling import (
- DEFAULT_ON,
-)
-
-from opentelemetry.trace import context_api
-from opentelemetry.trace.propagation import _SPAN_KEY
-from opentelemetry.instrumentation.requests import RequestsInstrumentor
-
-import os
-
-# Tracing propagators are configured based on OTEL_PROPAGATORS env variable set in dockerfile
-# https://opentelemetry.io/docs/instrumentation/python/manual/#using-environment-variables
-def _setup_tracer() -> trace.Tracer:
-
- provider = TracerProvider(
- resource=Resource.create(),
- sampler=DEFAULT_ON,
- )
-
- tracecollector_endpoint = os.getenv('TRACE_COLLECTOR_ENDPOINT')
-
- if tracecollector_endpoint:
- span_processor = SimpleSpanProcessor(OTLPSpanExporter(endpoint=tracecollector_endpoint))
- provider.add_span_processor(span_processor)
-
- # Sets the global default tracer provider
- trace.set_tracer_provider(provider)
-
- #Auto instrument all requests via `requests` library
- RequestsInstrumentor().instrument()
-
- # Creates a tracer from the global tracer provider
- return trace.get_tracer(__name__)
-
-
-@contextmanager # type: ignore
-def set_req_context(req) -> Iterator[trace.Span]:
- '''Propagates incoming span from the request to the current context
-
- This method allows to set up a context in any thread based on the incoming request.
- By design, span context can't be moved between threads and because we run every function
- in the separated thread we have to propagate the context manually.
- '''
- span = _Span(
- "request-span",
- trace.get_current_span(
- extract(req.headers)
- ).get_span_context()
- )
-
- token = context_api.attach(context_api.set_value(_SPAN_KEY, span))
- try:
- yield span
- finally:
- context_api.detach(token)
diff --git a/components/runtimes/python/python312/.dockerignore b/components/runtimes/python/python312/.dockerignore
deleted file mode 100644
index 6c84f66b4..000000000
--- a/components/runtimes/python/python312/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-kubeless/handler.py
diff --git a/components/runtimes/python/python312/Dockerfile b/components/runtimes/python/python312/Dockerfile
deleted file mode 100644
index a8186ef95..000000000
--- a/components/runtimes/python/python312/Dockerfile
+++ /dev/null
@@ -1,22 +0,0 @@
-FROM python:3.12.2-alpine3.19
-
-# Serverless
-LABEL source = git@github.com:kyma-project/kyma.git
-
-# build-base and linux-headers are needed to install all requirements
-RUN apk add --no-cache --virtual .build-deps build-base linux-headers
-
-COPY ./python312/requirements.txt /kubeless/requirements.txt
-
-RUN pip install --no-cache-dir -r /kubeless/requirements.txt
-
-COPY ./ /
-
-WORKDIR /
-
-USER 1000
-# Tracing propagators are configured based on OTEL_PROPAGATORS env variable https://opentelemetry.io/docs/instrumentation/python/manual/#using-environment-variables
-ENV OTEL_PROPAGATORS=tracecontext,baggage,b3multi
-ENV OTEL_PYTHON_REQUESTS_EXCLUDED_URLS="healthz,favicon.ico,metrics"
-
-CMD ["python", "/kubeless.py"]
diff --git a/components/runtimes/python/python312/requirements.txt b/components/runtimes/python/python312/requirements.txt
deleted file mode 100644
index 43509fd7b..000000000
--- a/components/runtimes/python/python312/requirements.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-setuptools==69.2.0
-requests>=2.31.0
-bottle==0.12.25
-cheroot==10.0.0
-wsgi-request-logger==0.4.6
-prometheus_client==0.20.0
-opentelemetry-api==1.24.0
-opentelemetry-sdk==1.24.0
-opentelemetry-exporter-otlp-proto-http==1.24.0
-opentelemetry-propagator-b3==1.24.0
-opentelemetry-instrumentation-requests==0.45b0
-cloudevents
diff --git a/components/runtimes/python/python39/.dockerignore b/components/runtimes/python/python39/.dockerignore
deleted file mode 100644
index 6c84f66b4..000000000
--- a/components/runtimes/python/python39/.dockerignore
+++ /dev/null
@@ -1 +0,0 @@
-kubeless/handler.py
diff --git a/components/runtimes/python/python39/Dockerfile b/components/runtimes/python/python39/Dockerfile
deleted file mode 100644
index d913c4ac3..000000000
--- a/components/runtimes/python/python39/Dockerfile
+++ /dev/null
@@ -1,22 +0,0 @@
-FROM python:3.9.18-alpine3.19
-
-# Serverless
-LABEL source = git@github.com:kyma-project/kyma.git
-
-# build-base and linux-headers are needed to install all requirements
-RUN apk add --no-cache --virtual .build-deps build-base linux-headers
-
-COPY ./python39/requirements.txt /kubeless/requirements.txt
-
-RUN pip install --no-cache-dir -r /kubeless/requirements.txt
-
-COPY ./ /
-
-WORKDIR /
-
-USER 1000
-# Tracing propagators are configured based on OTEL_PROPAGATORS env variable https://opentelemetry.io/docs/instrumentation/python/manual/#using-environment-variables
-ENV OTEL_PROPAGATORS=tracecontext,baggage,b3multi
-ENV OTEL_PYTHON_REQUESTS_EXCLUDED_URLS="healthz,favicon.ico,metrics"
-
-CMD ["python", "/kubeless.py"]
diff --git a/components/runtimes/python/python39/requirements.txt b/components/runtimes/python/python39/requirements.txt
deleted file mode 100644
index 43509fd7b..000000000
--- a/components/runtimes/python/python39/requirements.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-setuptools==69.2.0
-requests>=2.31.0
-bottle==0.12.25
-cheroot==10.0.0
-wsgi-request-logger==0.4.6
-prometheus_client==0.20.0
-opentelemetry-api==1.24.0
-opentelemetry-sdk==1.24.0
-opentelemetry-exporter-otlp-proto-http==1.24.0
-opentelemetry-propagator-b3==1.24.0
-opentelemetry-instrumentation-requests==0.45b0
-cloudevents
diff --git a/components/serverless/.gitignore b/components/serverless/.gitignore
deleted file mode 100644
index f4a4a637f..000000000
--- a/components/serverless/.gitignore
+++ /dev/null
@@ -1,33 +0,0 @@
-
-# Binaries for programs and plugins
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-bin/
-*/**/telepresence.log
-
-# Test binary, build with `go test -c`
-*.test
-
-# Output of the go coverage tool, specifically when used with LiteIDE
-*.out
-
-# Kubernetes Generated files - skip generated files, except for vendored files
-
-vendor/
-!vendor/**/zz_generated.*
-
-# editor and IDE paraphernalia
-.idea
-*.swp
-*.swo
-*~
-
-cover.out
-filered.cov
-log_config.yaml
-
-# Directory with temporary files used to do development
-hack/test_files
\ No newline at end of file
diff --git a/components/serverless/.golangci.yaml b/components/serverless/.golangci.yaml
deleted file mode 100644
index f7000cf29..000000000
--- a/components/serverless/.golangci.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-run:
- timeout: 15m
-linters:
- disable-all: true
- enable:
- - errcheck
- - gosimple
- - govet
- - ineffassign
- - staticcheck
- - unused
-issues:
- exclude:
- #exclude our internal deprecated fields
- - "^SA1019: v1alpha2.Nodejs18 is deprecated:"
- - "^SA1019: serverlessv1alpha2.Nodejs18 is deprecated:"
- - "^SA1019: serverlessv1alpha2.Python39 is deprecated:"
- - "^SA1019: status.RuntimeImageOverride is deprecated:"
- - "^SA1019: s.instance.Spec.Template is deprecated:"
- - "^SA1019: s.instance.Spec.Template.Labels is deprecated:"
- - "^SA1019: function.Status.RuntimeImageOverride is deprecated:"
diff --git a/components/serverless/Makefile b/components/serverless/Makefile
deleted file mode 100644
index 8543bcdc5..000000000
--- a/components/serverless/Makefile
+++ /dev/null
@@ -1,84 +0,0 @@
-PROJECT_ROOT = ../..
-COMPONENT_ROOT=$(PROJECT_ROOT)/components/serverless
-
-include ${PROJECT_ROOT}/hack/tools.mk
-include ${PROJECT_ROOT}/hack/help.mk
-
-# Setting SHELL to bash allows bash commands to be executed by recipes.
-# Options are set to exit when a recipe line exits non-zero or a piped command fails.
-SHELL = /usr/bin/env bash -o pipefail
-.SHELLFLAGS = -ec
-
-##@ Verification
-.PHONY: test
-test: KUBEBUILDER_CONTROLPLANE_START_TIMEOUT=2m
-test: KUBEBUILDER_CONTROLPLANE_STOP_TIMEOUT=2m
-test: manifests kubebuilder-assets ## Run unit tests.
- KUBEBUILDER_ASSETS="$(KUBEBUILDER_ASSETS)" go test -race -count=1 -coverprofile=cover.out ./...
- @echo -n "Total coverage: "
- @go tool cover -func=cover.out | grep total | awk '{print $$3}'
-
-##@ Development
-.PHONY: manifests
-manifests: kustomize controller-gen ## Render CRDs
- $(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths="./..."
- $(CONTROLLER_GEN) rbac:roleName=serverless crd webhook paths="./..." \
- object:headerFile=hack/boilerplate.go.txt \
- output:crd:artifacts:config=config/crd/bases \
- output:rbac:artifacts:config=config/rbac \
- output:webhook:artifacts:config=config/webhook
- $(KUSTOMIZE) build config/crd > config/crd/crd-serverless.yaml
- cp config/crd/crd-serverless.yaml $(PROJECT_ROOT)/config/serverless/templates/crds.yaml
- # TODO: Fix it. Now this docu is in https://kyma-project.io/#/serverless-manager/user/resources/06-10-function-cr?id=custom-resource-parameters. Remove table-gen from kyma.
- # (cd ../../hack/table-gen && make serverless-docs )
-
-##@ Deployment
-
-install: manifests ## Install CRDS into the k8s cluster specified in ~/.kube/config
- kubectl apply -f ../../config/serverless/templates/crds.yaml
-######## function manager
-MANAGER_NAME = function-controller
-
-.PHONY: build-image-function-controller
-build-image-function-controller:
- docker build -t $(MANAGER_NAME) -f $(COMPONENT_ROOT)/deploy/manager/Dockerfile $(PROJECT_ROOT)
-
-install-manager-k3d: build-image-function-controller disable-operator ## Build and install serverless manager from local sources on k3d
- $(eval HASH_TAG=$(shell docker images $(MANAGER_NAME):latest --quiet))
- docker tag $(MANAGER_NAME) $(MANAGER_NAME):$(HASH_TAG)
-
- k3d image import $(MANAGER_NAME):$(HASH_TAG) -c kyma
- kubectl set image deployment serverless-ctrl-mngr -n kyma-system manager=$(MANAGER_NAME):$(HASH_TAG)
-
-######## function webhook
-WEBHOOK_NAME = function-webhook
-
-.PHONY: build-image-function-webhook push-function-webhook
-build-image-function-webhook:
- docker build -t $(WEBHOOK_NAME) -f $(COMPONENT_ROOT)/deploy/webhook/Dockerfile $(PROJECT_ROOT)
-
-install-webhook-k3d: build-image-function-webhook disable-operator ## Build and install serverless webhook from local sources on k3d
- $(eval HASH_TAG=$(shell docker images $(WEBHOOK_NAME):latest --quiet))
- docker tag $(WEBHOOK_NAME) $(WEBHOOK_NAME):$(HASH_TAG)
-
- k3d image import $(WEBHOOK_NAME):$(HASH_TAG) -c kyma
- kubectl set image deployment serverless-webhook-svc -n kyma-system webhook=$(WEBHOOK_NAME):$(HASH_TAG)
-
-######## builder init container
-JOBINIT_NAME = function-build-init
-
-.PHONY: build-image-function-build-init push-function-build-init
-build-image-function-build-init:
- docker build -t $(JOBINIT_NAME) -f $(COMPONENT_ROOT)/deploy/jobinit/Dockerfile $(PROJECT_ROOT)
-
-######## registry-gc
-REGISTRY_GC_NAME = registry-gc
-
-.PHONY: build-image-registry-gc push-registry-gc
-build-image-registry-gc:
- docker build -t $(REGISTRY_GC_NAME) -f $(COMPONENT_ROOT)/deploy/registry-gc/Dockerfile .
-
-
-######## disable operator to prevent undo of local image update to k3d
-disable-operator:
- kubectl scale deployment serverless-operator -n kyma-system --replicas=0
diff --git a/components/serverless/README.md b/components/serverless/README.md
deleted file mode 100644
index b34dc33b4..000000000
--- a/components/serverless/README.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# Function Controller
-
-The Function Controller is a Kubernetes controller that enables Kyma to manage Function resources. It uses Kubernetes Jobs, Deployments, Services, and HorizontalPodAutoscalers (HPA) under the hood.
-
-## Prerequisites
-
-The Function Controller requires the following components to be installed:
-
-- [Istio](https://github.com/istio/istio/releases) (v1.4.3)
-- [Docker registry](https://github.com/docker/distribution) (v2.7.1)
-
-## Development
-
-To develop the Function Controller, you need:
-- [libgit2-dev](https://github.com/libgit2/libgit2) (v1.5)
-- [controller-gen](https://github.com/kubernetes-sigs/controller-tools/releases/tag/v0.6.2) (v0.6.2)
-- [kustomize](https://github.com/kubernetes-sigs/kustomize/releases/tag/kustomize%2Fv4.5.7) (v4.5.7)
-
-To develop the component, use the formulae declared in the [Makefile](./Makefile).
-
-To run the manager and set up envs correctly, source [controller.env](./hack/controller.env).
-You can customize the configuration by editing files in [hack](./hack) dir.
-
-
-### Environment Variables
-
-#### The Function Controller Uses These Environment Variables:
-
-| Variable | Description | Default value |
-| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| **APP_METRICS_ADDRESS** | Address on which controller metrics are exposed | `:8080` |
-| **APP_LEADER_ELECTION_ENABLED** | Field that enables one instance of the Function Controller to manage the traffic among all instances | `false` |
-| **APP_LEADER_ELECTION_ID** | Name of the ConfigMap that specifies the main instance of the Function Controller that manages the traffic among all instances | `serverless-controller-leader-election-helper` |
-| **APP_KUBERNETES_BASE_NAMESPACE** | Name of the namespace with the serverless configuration (such as runtime, Secret and service account for the Docker registry) propagated to other namespaces | `kyma-system` |
-| **APP_KUBERNETES_EXCLUDED_NAMESPACES** | List of namespaces to which serverless configuration is not propagated | `istio-system,knative-eventing,kube-node-lease,kube-public,kube-system,kyma-installer,kyma-system,natss` |
-| **APP_KUBERNETES_CONFIG_MAP_REQUEUE_DURATION** | Period of time after which the ConfigMap Controller refreshes the status of a ConfigMap | `1m` |
-| **APP_KUBERNETES_SECRET_REQUEUE_DURATION** | Period of time after which the Secret Controller refreshes the status of a Secret | `1m` |
-| **APP_KUBERNETES_SERVICE_ACCOUNT_REQUEUE_DURATION** | Period of time after which the ServiceAccount Controller refreshes the status of a ServiceAccount | `1m` |
-| **APP_FUNCTION_IMAGE_REGISTRY_DOCKER_CONFIG_SECRET_NAME** | Name of the secret that contains hashed credentials to the Docker registry | `serverless-image-pull-secret` |
-| **APP_FUNCTION_IMAGE_PULL_ACCOUNT_NAME** | Name of the service account that contains credentials to the Docker registry | `serverless` |
-| **APP_FUNCTION_REQUEUE_DURATION** | Period of time after which the Function Controller refreshes the status of a Function CR | `1m` |
-| **APP_FUNCTION_BUILD_EXECUTOR_ARGS** | List of arguments passed to the Kaniko executor | `--insecure,--skip-tls-verify,--skip-unused-stages,--log-format=text,--cache=true,--use-new-run,--compressed-caching=false` |
-| **APP_FUNCTION_BUILD_EXECUTOR_IMAGE** | Full name of the Kaniko executor image used for building Function images and pushing them to the Docker registry | `gcr.io/kaniko-project/executor:v0.22.0` |
-| **APP_FUNCTION_BUILD_REPOFETCHER_IMAGE** | Full name of the Repo-Fetcher init container used for cloning repository for the Kaniko executor | `europe-docker.pkg.dev/kyma-project/prod/function-build-init:305bee60` |
-| **APP_FUNCTION_BUILD_MAX_SIMULTANEOUS_JOBS** | Maximum number of build jobs running simultaneously | `5` |
-| **APP_FUNCTION_DOCKER_INTERNAL_SERVER_ADDRESS** | Internal server address of the Docker registry | `serverless-docker-registry.kyma-system.svc.cluster.local:5000` |
-| **APP_FUNCTION_DOCKER_REGISTRY_ADDRESS** | External address of the Docker registry | `registry.kyma.local` |
-| **APP_FUNCTION_TARGET_CPU_UTILIZATION_PERCENTAGE** | Average CPU usage of all the Pods in a given Deployment. It is represented as a percentage of the overall requested CPU. If the CPU consumption is higher or lower than this limit, HorizontalPodAutoscaler (HPA) scales the Deployment and increases or decreases the number of Pod replicas accordingly. | `50` |
-
-#### The Webhook Uses These Environment Variables:
-
-| Variable | Description | Default value |
-| ----------------------------------------- | ----------------------------------------------------------------------------------------- | -------------------- |
-| **SYSTEM_NAMESPACE** | Namespace which contains the ServiceAccount and the Secret | `kyma-system` |
-| **WEBHOOK_SERVICE_NAME** | Name of the ServiceAccount which is used by the webhook server | `serverless-webhook` |
-| **WEBHOOK_SECRET_NAME** | Name of the Secret which contains the certificate is used to register the webhook server | `serverless-webhook` |
-| **WEBHOOK_PORT** | Port on which the webhook server are exposed | `8443` |
-| **WEBHOOK_VALIDATION_MIN_REQUEST_CPU** | Minimum amount of requested the limits and requests CPU to pass through the validation | `10m` |
-| **WEBHOOK_VALIDATION_MIN_REQUEST_MEMORY** | Minimum amount of requested the limits and requests memory to pass through the validation | `16Mi` |
-| **WEBHOOK_VALIDATION_MIN_REPLICAS_VALUE** | Minimum amount of replicas to pass through the validation | `1` |
-| **WEBHOOK_VALIDATION_RESERVED_ENVS** | List of reserved envs | `{}` |
-| **WEBHOOK_DEFAULTING_REQUEST_CPU** | Value of the request CPU which webhook should set if origin equals null | `50m` |
-| **WEBHOOK_DEFAULTING_REQUEST_MEMORY** | Value of the request memory which webhook should set if origin equals null | `64Mi` |
-| **WEBHOOK_DEFAULTING_LIMITS_CPU** | Value of the limits CPU which webhook should set if origin equals null | `100m` |
-| **WEBHOOK_DEFAULTING_LIMITS_MEMORY** | Value of the limits memory which webhook should set if origin equals null | `128Mi` |
-| **WEBHOOK_DEFAULTING_MINREPLICAS** | Value of the minReplicas which webhook should set if origin equals null | `1` |
-| **WEBHOOK_DEFAULTING_MAXREPLICAS** | Value of the maxReplicas which webhook should set if origin equals null | `1` |
-
-## Troubleshooting
-
-
-### Symptom
-
-Function Controller tests keep failing with such an error message:
-`error: Invalid libgit2 version; this git2go supports libgit2 between vA.B.C and vX.Y.Z`
-
-### Cause
-
-Function Controller tests are failing due to the wrong version of the libgit2 binary. The required version of the binary is 1.1.
-
-### Remedy
-
-Build and install the libgit2 binary required by the Function Controller on macOS. Follow these steps:
-
-1. Navigate to the root directory and verify the version of git2go:
-
- ```bash
- cat go.mod | grep git2go
- ```
- You should get a result similar to this example:
-
- ```bash
- github.com/libgit2/git2go/v31 v31.4.14
- ```
-2. Go to the [git2go page](https://github.com/libgit2/git2go#git2go) to check which version of libgit2 you must use. For example, for git2go v34, use libigit2 in version 1.5.
-
-3. Clone the `libgit2` repository:
-
- ```bash
- git clone https://github.com/libgit2/libgit2.git
- ```
-4. Check out the sources. In this example, the sources are for git2go v31:
- ```bash
- git checkout v1.1.0
- ```
-5. Build and install the libgit2 binary:
- ```bash
- cmake -DCMAKE_OSX_ARCHITECTURES="x86_64" .
- make install
- ```
-#### Alternative Remedy
-There is an alternative method for macOS that relies on [brew](https://brew.sh/).
-If you still see the `Invalid libgit2 version` error message on macOS, follow these steps:
-
-1. Locate your brew's Cellar directory.
-
- ```bash
- find / -type d -name "Cellar"
- ```
-Alternatively, you can use **⌘⇧G** in Finder to search for `Cellar`.
-
-2. Prepare the libgit2 directory.
-
-If you already have libgit2 installed via brew you need to delete previous installations found in the `libgit2` directory.
-
-Otherwise create an empty directory named `libgit2`.
-
-3. Extract `libgit.tgz` located in `./components/serverless/hack` into `Cellar/libgit2`.
-
-
-4. Link libgit2 using:
- ```bash
- brew link libgit2
- ```
-
-### Symptom
-
-The Function Controller tests keep failing with the following error message:
-
-```
-assertion failed [!result.is_error]: Failed to create temporary file
-(ThreadContextFcntl.cpp:84 create_tempfile)
-```
-
-### Cause
-
-The Docker engine uses Rosetta for virtualization, which causes issues on M1 Mac.
-
-### Remedy
-
-Disable the `Use Rosetta for x86/amd64 emulation on Apple Silicon` option in the Docker Desktop general settings.
diff --git a/components/serverless/cmd/jobinit/README.md b/components/serverless/cmd/jobinit/README.md
deleted file mode 100644
index 2fc27b107..000000000
--- a/components/serverless/cmd/jobinit/README.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# JobInit
-
-JobInit is used as the init container for injecting a Git repository to the [Job that builds a Function](https://kyma-project.io/#/serverless-manager/user/technical-reference/07-20-function-processing-stages).
-
-### Environment variables
-
-JobInit uses these environment variables:
-
-| Variable | Description | Default value |
-| ---------------------------- | ------------------------------------------------------------------------ | ------------- |
-| **APP_MOUNT_PATH** | Path under which JobInit should clone the repository | `/workspace`
-| **APP_REPOSITORY_URL** | Address of the Git repository to clone |
-| **APP_REPOSITORY_COMMIT** | Commit to check out when cloning the repository |
-| **APP_REPOSITORY_AUTH_TYPE** | Authentication type used to clone the repository |
-| **APP_REPOSITORY_USERNAME** | Username of the account used to clone the private repository |
-| **APP_REPOSITORY_PASSWORD** | Password of the account used to clone the private repository |
-| **APP_REPOSITORY_KEY** | Private key of the account used to clone the private repository |
\ No newline at end of file
diff --git a/components/serverless/cmd/jobinit/main.go b/components/serverless/cmd/jobinit/main.go
deleted file mode 100644
index c44ee6eb4..000000000
--- a/components/serverless/cmd/jobinit/main.go
+++ /dev/null
@@ -1,79 +0,0 @@
-package main
-
-import (
- "log"
-
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- "github.com/pkg/errors"
- "github.com/vrischmann/envconfig"
- "go.uber.org/zap"
-)
-
-const envPrefix = "APP"
-
-type config struct {
- RepositoryURL string
- RepositoryCommit string
- MountPath string `envconfig:"default=/workspace"`
- RepositoryAuthType git.RepositoryAuthType `envconfig:"optional"`
- RepositoryUsername string `envconfig:"optional"`
- RepositoryPassword string `envconfig:"optional"`
- RepositoryKey string `envconfig:"optional"`
-}
-
-func main() {
- log.Println("Start repo fetcher...")
- cfg := config{}
- if err := envconfig.InitWithPrefix(&cfg, envPrefix); err != nil {
- log.Fatalf("while reading env variables: %s", err.Error())
- }
-
- logger, _ := zap.NewProduction()
- operator := git.NewGit2Go(logger.Sugar())
-
- log.Println("Get auth config...")
- gitOptions := cfg.getOptions()
-
- log.Printf("Clone repo from url: %s and commit: %s...\n", cfg.RepositoryURL, cfg.RepositoryCommit)
- commit, err := operator.Clone(cfg.MountPath, gitOptions)
- if err != nil {
- if git.IsAuthErr(err) {
- log.Printf("while cloning repository bad credentials were provided, errMsg: %s", err.Error())
- } else {
- log.Fatalln(errors.Wrapf(err, "while cloning repository: %s, from commit: %s", cfg.RepositoryURL, cfg.RepositoryCommit))
- }
- }
-
- log.Printf("Cloned repository: %s, from commit: %s, to path: %s", cfg.RepositoryURL, commit, cfg.MountPath)
-}
-
-func (c *config) getOptions() git.Options {
- return git.Options{
- URL: c.RepositoryURL,
- Reference: c.RepositoryCommit,
- Auth: c.getAuthFromType(),
- }
-}
-
-func (c *config) getAuthFromType() *git.AuthOptions {
- switch c.RepositoryAuthType {
- case git.RepositoryAuthBasic:
- return &git.AuthOptions{
- Type: git.RepositoryAuthBasic,
- Credentials: map[string]string{
- git.UsernameKey: c.RepositoryUsername,
- git.PasswordKey: c.RepositoryPassword,
- },
- }
- case git.RepositoryAuthSSHKey:
- return &git.AuthOptions{
- Type: git.RepositoryAuthSSHKey,
- Credentials: map[string]string{
- git.KeyKey: c.RepositoryKey,
- git.PasswordKey: c.RepositoryPassword,
- },
- }
- default:
- return nil
- }
-}
diff --git a/components/serverless/cmd/manager/main.go b/components/serverless/cmd/manager/main.go
deleted file mode 100644
index f28ea16e5..000000000
--- a/components/serverless/cmd/manager/main.go
+++ /dev/null
@@ -1,198 +0,0 @@
-package main
-
-import (
- "context"
- "os"
- "time"
-
- "github.com/go-logr/zapr"
- fileconfig "github.com/kyma-project/serverless/components/serverless/internal/config"
- k8s "github.com/kyma-project/serverless/components/serverless/internal/controllers/kubernetes"
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless"
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/metrics"
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- "github.com/kyma-project/serverless/components/serverless/internal/logging"
- internalresource "github.com/kyma-project/serverless/components/serverless/internal/resource"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/vrischmann/envconfig"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
-
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
- _ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
- ctrl "sigs.k8s.io/controller-runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/handler"
- "sigs.k8s.io/controller-runtime/pkg/healthz"
- ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
- "sigs.k8s.io/controller-runtime/pkg/manager"
- "sigs.k8s.io/controller-runtime/pkg/source"
- // +kubebuilder:scaffold:imports
-)
-
-var (
- scheme = runtime.NewScheme()
- setupLog = ctrlzap.New().WithName("setup")
-)
-
-// nolint
-func init() {
- _ = clientgoscheme.AddToScheme(scheme)
-
- _ = serverlessv1alpha2.AddToScheme(scheme)
- // +kubebuilder:scaffold:scheme
-}
-
-type config struct {
- MetricsAddress string `envconfig:"default=:8080"`
- Healthz healthzConfig
- LeaderElectionEnabled bool `envconfig:"default=false"`
- LeaderElectionID string `envconfig:"default=serverless-controller-leader-election-helper"`
- SecretMutatingWebhookPort int `envconfig:"default=8443"`
- Kubernetes k8s.Config
- Function serverless.FunctionConfig
- LogConfigPath string `envconfig:"default=/appconfig/log-config.yaml"`
-}
-
-type healthzConfig struct {
- Address string `envconfig:"default=:8090"`
- LivenessTimeout time.Duration `envconfig:"default=10s"`
-}
-
-func main() {
- config, err := loadConfig("APP")
- if err != nil {
- setupLog.Error(err, "unable to load config")
- os.Exit(1)
- }
-
- logCfg, err := fileconfig.LoadLogConfig(config.LogConfigPath)
- if err != nil {
- setupLog.Error(err, "unable to load configuration file")
- os.Exit(1)
- }
-
- atomic := zap.NewAtomicLevel()
- parsedLevel, err := zapcore.ParseLevel(logCfg.LogLevel)
- if err != nil {
- setupLog.Error(err, "unable to parse logger level")
- os.Exit(1)
- }
- atomic.SetLevel(parsedLevel)
-
- log, err := logging.ConfigureLogger(logCfg.LogLevel, logCfg.LogFormat, atomic)
- if err != nil {
- setupLog.Error(err, "unable to configure log")
- os.Exit(1)
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- logWithCtx := log.WithContext()
- go logging.ReconfigureOnConfigChange(ctx, logWithCtx.Named("notifier"), atomic, config.LogConfigPath)
-
- ctrl.SetLogger(zapr.NewLogger(logWithCtx.Desugar()))
-
- logWithCtx.Info("Generating Kubernetes client config")
- restConfig := ctrl.GetConfigOrDie()
-
- logWithCtx.Info("Registering Prometheus Stats Collector")
- prometheusCollector := metrics.NewPrometheusStatsCollector()
- prometheusCollector.Register()
-
- logWithCtx.Info("Initializing controller manager")
- mgr, err := manager.New(restConfig, manager.Options{
- Scheme: scheme,
- MetricsBindAddress: config.MetricsAddress,
- LeaderElection: config.LeaderElectionEnabled,
- LeaderElectionID: config.LeaderElectionID,
- Port: config.SecretMutatingWebhookPort,
- HealthProbeBindAddress: config.Healthz.Address,
- Client: ctrlclient.Options{
- Cache: &ctrlclient.CacheOptions{
- DisableFor: []ctrlclient.Object{
- &corev1.Secret{},
- &corev1.ConfigMap{},
- },
- },
- },
- })
- if err != nil {
- setupLog.Error(err, "Unable to initialize controller manager")
- os.Exit(1)
- }
-
- resourceClient := internalresource.New(mgr.GetClient(), scheme)
- configMapSvc := k8s.NewConfigMapService(resourceClient, config.Kubernetes)
- secretSvc := k8s.NewSecretService(resourceClient, config.Kubernetes)
- serviceAccountSvc := k8s.NewServiceAccountService(resourceClient, config.Kubernetes)
-
- healthHandler, healthEventsCh, healthResponseCh := serverless.NewHealthChecker(config.Healthz.LivenessTimeout, logWithCtx.Named("healthz"))
- if err := mgr.AddHealthzCheck("health check", healthHandler.Checker); err != nil {
- setupLog.Error(err, "unable to register healthz")
- os.Exit(1)
- }
-
- if err := mgr.AddReadyzCheck("readiness check", healthz.Ping); err != nil {
- setupLog.Error(err, "unable to register readyz")
- os.Exit(1)
- }
-
- fnRecon := serverless.NewFunctionReconciler(resourceClient, logWithCtx.Named("controllers.function"), config.Function, &git.GitClientFactory{}, mgr.GetEventRecorderFor(serverlessv1alpha2.FunctionControllerValue), prometheusCollector, healthResponseCh)
- fnCtrl, err := fnRecon.SetupWithManager(mgr)
- if err != nil {
- setupLog.Error(err, "unable to create Function controller")
- os.Exit(1)
- }
-
- err = fnCtrl.Watch(&source.Channel{Source: healthEventsCh}, &handler.EnqueueRequestForObject{})
- if err != nil {
- setupLog.Error(err, "unable to watch health events channel")
- os.Exit(1)
- }
-
- if err := k8s.NewConfigMap(mgr.GetClient(), logWithCtx.Named("controllers.configmap"), config.Kubernetes, configMapSvc).
- SetupWithManager(mgr); err != nil {
- setupLog.Error(err, "unable to create ConfigMap controller")
- os.Exit(1)
- }
-
- if err := k8s.NewNamespace(mgr.GetClient(), logWithCtx.Named("controllers.namespace"), config.Kubernetes, configMapSvc, secretSvc, serviceAccountSvc).
- SetupWithManager(mgr); err != nil {
- setupLog.Error(err, "unable to create Namespace controller")
- os.Exit(1)
- }
-
- if err := k8s.NewSecret(mgr.GetClient(), logWithCtx.Named("controllers.secret"), config.Kubernetes, secretSvc).
- SetupWithManager(mgr); err != nil {
- setupLog.Error(err, "unable to create Secret controller")
- os.Exit(1)
- }
-
- if err := k8s.NewServiceAccount(mgr.GetClient(), logWithCtx.Named("controllers.serviceaccount"), config.Kubernetes, serviceAccountSvc).
- SetupWithManager(mgr); err != nil {
- setupLog.Error(err, "unable to create ServiceAccount controller")
- os.Exit(1)
- }
-
- // +kubebuilder:scaffold:builder
-
- logWithCtx.Info("Running manager")
-
- if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
- setupLog.Error(err, "Unable to run the manager")
- os.Exit(1)
- }
-}
-
-func loadConfig(prefix string) (config, error) {
- cfg := config{}
- err := envconfig.InitWithPrefix(&cfg, prefix)
- if err != nil {
- return cfg, err
- }
- return cfg, nil
-}
diff --git a/components/serverless/cmd/webhook/main.go b/components/serverless/cmd/webhook/main.go
deleted file mode 100644
index b1057b739..000000000
--- a/components/serverless/cmd/webhook/main.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package main
-
-import (
- "context"
- "os"
-
- "github.com/go-logr/zapr"
- fileconfig "github.com/kyma-project/serverless/components/serverless/internal/config"
- "github.com/kyma-project/serverless/components/serverless/internal/logging"
- "github.com/kyma-project/serverless/components/serverless/internal/webhook"
- "github.com/kyma-project/serverless/components/serverless/internal/webhook/resources"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "github.com/vrischmann/envconfig"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "sigs.k8s.io/controller-runtime/pkg/manager"
-
- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/runtime"
- ctrl "sigs.k8s.io/controller-runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap"
- ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
-)
-
-var (
- scheme = runtime.NewScheme()
-)
-
-// nolint
-func init() {
- _ = serverlessv1alpha2.AddToScheme(scheme)
- _ = admissionregistrationv1.AddToScheme(scheme)
- _ = corev1.AddToScheme(scheme)
- // +kubebuilder:scaffold:scheme
-}
-
-func main() {
- setupLog := ctrlzap.New().WithName("setup")
-
- setupLog.Info("reading configuration")
- cfg := &webhook.Config{}
- if err := envconfig.InitWithPrefix(cfg, "WEBHOOK"); err != nil {
- panic(errors.Wrap(err, "while reading env variables"))
- }
-
- logCfg, err := fileconfig.LoadLogConfig(cfg.LogConfigPath)
- if err != nil {
- setupLog.Error(err, "unable to load log configuration file")
- os.Exit(1)
- }
-
- setupLog.Info("reading webhook configuration")
- webhookCfg, err := webhook.LoadWebhookCfg(cfg.ConfigPath)
- if err != nil {
- setupLog.Error(err, "unable to load webhook configuration file")
- os.Exit(1)
- }
-
- atomic := zap.NewAtomicLevel()
- parsedLevel, err := zapcore.ParseLevel(logCfg.LogLevel)
- if err != nil {
- setupLog.Error(err, "unable to parse logger level")
- os.Exit(1)
- }
- atomic.SetLevel(parsedLevel)
-
- log, err := logging.ConfigureLogger(logCfg.LogLevel, logCfg.LogFormat, atomic)
- if err != nil {
- setupLog.Error(err, "unable to configure log")
- os.Exit(1)
- }
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- logWithCtx := log.WithContext()
- go logging.ReconfigureOnConfigChange(ctx, logWithCtx.Named("notifier"), atomic, cfg.ConfigPath)
-
- logrZap := zapr.NewLogger(logWithCtx.Desugar())
- ctrl.SetLogger(logrZap)
-
- // manager setup
- logWithCtx.Info("setting up controller-manager")
-
- mgr, err := manager.New(ctrl.GetConfigOrDie(), manager.Options{
- Scheme: scheme,
- Port: cfg.Port,
- MetricsBindAddress: ":9090",
- Logger: logrZap,
- Client: ctrlclient.Options{
- Cache: &ctrlclient.CacheOptions{
- DisableFor: []ctrlclient.Object{
- &corev1.Secret{},
- &corev1.ConfigMap{},
- },
- },
- },
- })
- if err != nil {
- logWithCtx.Error(err, "failed to setup controller-manager")
- os.Exit(1)
- }
-
- logWithCtx.Info("setting up webhook certificates and webhook secret")
- // we need to ensure the certificates and the webhook secret as early as possible
- // because the webhook server needs to read it from disk to start.
- result, err := resources.SetupCertificates(context.Background(), cfg.SecretName, cfg.SystemNamespace, cfg.ServiceName,
- logWithCtx.Named("setup-certificates"))
- if err != nil {
- logWithCtx.Error(err, "failed to setup certificates and webhook secret")
- os.Exit(1)
- }
- if result == resources.Updated {
- setupLog.Info("certificate updated successfully, restarting")
- //This is not an elegant solution, but the webhook need to reconfigure itself to use updated certificate.
- //Cert-watcher from controller-runtime should refresh the certificate, but it doesn't work.
- os.Exit(0)
- }
-
- logWithCtx.Info("setting up webhook server")
- // webhook server setup
- whs := ctrlwebhook.NewServer(ctrlwebhook.Options{
- CertName: resources.CertFile,
- KeyName: resources.KeyFile})
- err = whs.Start(ctx)
- if err != nil {
- logWithCtx.Error(err, "failed to start webhook server")
- os.Exit(1)
- }
-
- whs.Register(resources.FunctionDefaultingWebhookPath, &ctrlwebhook.Admission{
- Handler: webhook.NewDefaultingWebhook(
- mgr.GetClient(),
- logWithCtx.Named("defaulting-webhook")),
- })
-
- validationCfg := webhookCfg.ToValidationConfig()
- whs.Register(resources.FunctionValidationWebhookPath, &ctrlwebhook.Admission{
- Handler: webhook.NewValidatingWebhook(
- &validationCfg,
- mgr.GetClient(),
- logWithCtx.Named("validating-webhook")),
- })
-
- logWithCtx.Info("setting up webhook resources controller")
- // apply and monitor configuration
- if err := resources.SetupResourcesController(
- context.Background(),
- mgr,
- cfg.ServiceName,
- cfg.SystemNamespace,
- cfg.SecretName,
- logWithCtx); err != nil {
- logWithCtx.Error(err, "failed to setup webhook resources controller")
- os.Exit(1)
- }
-
- logWithCtx.Info("starting the controller-manager")
- // start the server manager
- err = mgr.Start(ctrl.SetupSignalHandler())
- if err != nil {
- logWithCtx.Error(err, "failed to start controller-manager")
- os.Exit(1)
- }
-}
diff --git a/components/serverless/config/crd/.gitignore b/components/serverless/config/crd/.gitignore
deleted file mode 100644
index d0859de7c..000000000
--- a/components/serverless/config/crd/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-crd-serverless.yaml
diff --git a/components/serverless/config/crd/bases/serverless.kyma-project.io_functions.yaml b/components/serverless/config/crd/bases/serverless.kyma-project.io_functions.yaml
deleted file mode 100644
index 7117d46c3..000000000
--- a/components/serverless/config/crd/bases/serverless.kyma-project.io_functions.yaml
+++ /dev/null
@@ -1,611 +0,0 @@
----
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
- annotations:
- controller-gen.kubebuilder.io/version: v0.14.0
- name: functions.serverless.kyma-project.io
-spec:
- group: serverless.kyma-project.io
- names:
- kind: Function
- listKind: FunctionList
- plural: functions
- singular: function
- scope: Namespaced
- versions:
- - additionalPrinterColumns:
- - jsonPath: .status.conditions[?(@.type=='ConfigurationReady')].status
- name: Configured
- type: string
- - jsonPath: .status.conditions[?(@.type=='BuildReady')].status
- name: Built
- type: string
- - jsonPath: .status.conditions[?(@.type=='Running')].status
- name: Running
- type: string
- - jsonPath: .spec.runtime
- name: Runtime
- type: string
- - jsonPath: .metadata.generation
- name: Version
- type: integer
- - jsonPath: .metadata.creationTimestamp
- name: Age
- type: date
- name: v1alpha2
- schema:
- openAPIV3Schema:
- description: |-
- A simple code snippet that you can run without provisioning or managing servers.
- It implements the exact business logic you define.
- A Function is based on the Function custom resource (CR) and can be written in either Node.js or Python.
- A Function can perform a business logic of its own. You can also bind it to an instance of a service
- and configure it to be triggered whenever it receives a particular event type from the service
- or a call is made to the service's API.
- Functions are executed only if they are triggered by an event or an API call.
- properties:
- apiVersion:
- description: |-
- APIVersion defines the versioned schema of this representation of an object.
- Servers should convert recognized schemas to the latest internal value, and
- may reject unrecognized values.
- More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
- type: string
- kind:
- description: |-
- Kind is a string value representing the REST resource this object represents.
- Servers may infer this from the endpoint the client submits requests to.
- Cannot be updated.
- In CamelCase.
- More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
- type: string
- metadata:
- type: object
- spec:
- description: Defines the desired state of the Function
- properties:
- annotations:
- additionalProperties:
- type: string
- description: Defines annotations used in Deployment's PodTemplate
- and applied on the Function's runtime Pod.
- type: object
- x-kubernetes-validations:
- - message: Annotations has key starting with serverless.kyma-project.io/
- which is not allowed
- rule: '!(self.exists(e, e.startsWith(''serverless.kyma-project.io/'')))'
- env:
- description: |-
- Specifies an array of key-value pairs to be used as environment variables for the Function.
- You can define values as static strings or reference values from ConfigMaps or Secrets.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/).
- items:
- description: EnvVar represents an environment variable present in
- a Container.
- properties:
- name:
- description: Name of the environment variable. Must be a C_IDENTIFIER.
- type: string
- value:
- description: |-
- Variable references $(VAR_NAME) are expanded
- using the previously defined environment variables in the container and
- any service environment variables. If a variable cannot be resolved,
- the reference in the input string will be unchanged. Double $$ are reduced
- to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
- "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
- Escaped references will never be expanded, regardless of whether the variable
- exists or not.
- Defaults to "".
- type: string
- valueFrom:
- description: Source for the environment variable's value. Cannot
- be used if value is not empty.
- properties:
- configMapKeyRef:
- description: Selects a key of a ConfigMap.
- properties:
- key:
- description: The key to select.
- type: string
- name:
- description: |-
- Name of the referent.
- More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
- TODO: Add other useful fields. apiVersion, kind, uid?
- type: string
- optional:
- description: Specify whether the ConfigMap or its key
- must be defined
- type: boolean
- required:
- - key
- type: object
- x-kubernetes-map-type: atomic
- fieldRef:
- description: |-
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`,
- spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
- properties:
- apiVersion:
- description: Version of the schema the FieldPath is
- written in terms of, defaults to "v1".
- type: string
- fieldPath:
- description: Path of the field to select in the specified
- API version.
- type: string
- required:
- - fieldPath
- type: object
- x-kubernetes-map-type: atomic
- resourceFieldRef:
- description: |-
- Selects a resource of the container: only resources limits and requests
- (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
- properties:
- containerName:
- description: 'Container name: required for volumes,
- optional for env vars'
- type: string
- divisor:
- anyOf:
- - type: integer
- - type: string
- description: Specifies the output format of the exposed
- resources, defaults to "1"
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- resource:
- description: 'Required: resource to select'
- type: string
- required:
- - resource
- type: object
- x-kubernetes-map-type: atomic
- secretKeyRef:
- description: Selects a key of a secret in the pod's namespace
- properties:
- key:
- description: The key of the secret to select from. Must
- be a valid secret key.
- type: string
- name:
- description: |-
- Name of the referent.
- More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
- TODO: Add other useful fields. apiVersion, kind, uid?
- type: string
- optional:
- description: Specify whether the Secret or its key must
- be defined
- type: boolean
- required:
- - key
- type: object
- x-kubernetes-map-type: atomic
- type: object
- required:
- - name
- type: object
- type: array
- x-kubernetes-validations:
- - message: 'Following envs are reserved and cannot be used: [''FUNC_RUNTIME'',''FUNC_HANDLER'',''FUNC_PORT'',''MOD_NAME'',''NODE_PATH'',''PYTHONPATH'']'
- rule: (self.all(e, !(e.name in ['FUNC_RUNTIME','FUNC_HANDLER','FUNC_PORT','MOD_NAME','NODE_PATH','PYTHONPATH'])))
- labels:
- additionalProperties:
- type: string
- description: Defines labels used in Deployment's PodTemplate and applied
- on the Function's runtime Pod.
- type: object
- x-kubernetes-validations:
- - message: Labels has key starting with serverless.kyma-project.io/
- which is not allowed
- rule: '!(self.exists(e, e.startsWith(''serverless.kyma-project.io/'')))'
- - message: Label value cannot be longer than 63
- rule: self.all(e, size(e)<64)
- replicas:
- default: 1
- description: |-
- Defines the exact number of Function's Pods to run at a time.
- If **ScaleConfig** is configured, or if the Function is targeted by an external scaler,
- then the **Replicas** field is used by the relevant HorizontalPodAutoscaler to control the number of active replicas.
- format: int32
- minimum: 0
- type: integer
- resourceConfiguration:
- description: Specifies resources requested by the Function and the
- build Job.
- properties:
- build:
- description: Specifies resources requested by the build Job's
- Pod.
- properties:
- profile:
- description: |-
- Defines the name of the predefined set of values of the resource.
- Can't be used together with **Resources**.
- type: string
- resources:
- description: |-
- Defines the amount of resources available for the Pod.
- Can't be used together with **Profile**.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
- properties:
- claims:
- description: |-
- Claims lists the names of resources, defined in spec.resourceClaims,
- that are used by this container.
-
-
- This is an alpha field and requires enabling the
- DynamicResourceAllocation feature gate.
-
-
- This field is immutable. It can only be set for containers.
- items:
- description: ResourceClaim references one entry in PodSpec.ResourceClaims.
- properties:
- name:
- description: |-
- Name must match the name of one entry in pod.spec.resourceClaims of
- the Pod where this field is used. It makes that resource available
- inside a container.
- type: string
- required:
- - name
- type: object
- type: array
- x-kubernetes-list-map-keys:
- - name
- x-kubernetes-list-type: map
- limits:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Limits describes the maximum amount of compute resources allowed.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- requests:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Requests describes the minimum amount of compute resources required.
- If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
- otherwise to an implementation-defined value. Requests cannot exceed Limits.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use profile or resources
- rule: has(self.profile) && !has(self.resources) || !has(self.profile)
- && has(self.resources)
- - message: 'Invalid profile, please use one of: [''local-dev'',''slow'',''normal'',''fast'']'
- rule: (!has(self.profile) || self.profile in ['local-dev','slow','normal','fast'])
- function:
- description: Specifies resources requested by the Function's Pod.
- properties:
- profile:
- description: |-
- Defines the name of the predefined set of values of the resource.
- Can't be used together with **Resources**.
- type: string
- resources:
- description: |-
- Defines the amount of resources available for the Pod.
- Can't be used together with **Profile**.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
- properties:
- claims:
- description: |-
- Claims lists the names of resources, defined in spec.resourceClaims,
- that are used by this container.
-
-
- This is an alpha field and requires enabling the
- DynamicResourceAllocation feature gate.
-
-
- This field is immutable. It can only be set for containers.
- items:
- description: ResourceClaim references one entry in PodSpec.ResourceClaims.
- properties:
- name:
- description: |-
- Name must match the name of one entry in pod.spec.resourceClaims of
- the Pod where this field is used. It makes that resource available
- inside a container.
- type: string
- required:
- - name
- type: object
- type: array
- x-kubernetes-list-map-keys:
- - name
- x-kubernetes-list-type: map
- limits:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Limits describes the maximum amount of compute resources allowed.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- requests:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Requests describes the minimum amount of compute resources required.
- If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
- otherwise to an implementation-defined value. Requests cannot exceed Limits.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use profile or resources
- rule: has(self.profile) && !has(self.resources) || !has(self.profile)
- && has(self.resources)
- - message: 'Invalid profile, please use one of: [''XS'',''S'',''M'',''L'',''XL'']'
- rule: (!has(self.profile) || self.profile in ['XS','S','M','L','XL'])
- type: object
- runtime:
- description: Specifies the runtime of the Function. The available
- values are `nodejs18` - deprecated, `nodejs20`, `python39` - deprecated,
- and `python312`.
- enum:
- - nodejs18
- - nodejs20
- - python39
- - python312
- type: string
- runtimeImageOverride:
- description: Specifies the runtime image used instead of the default
- one.
- type: string
- scaleConfig:
- description: |-
- Defines the minimum and maximum number of Function's Pods to run at a time.
- When it is configured, a HorizontalPodAutoscaler will be deployed and will control the **Replicas** field
- to scale the Function based on the CPU utilisation.
- properties:
- maxReplicas:
- description: Defines the maximum number of Function's Pods to
- run at a time.
- format: int32
- minimum: 1
- type: integer
- minReplicas:
- description: Defines the minimum number of Function's Pods to
- run at a time.
- format: int32
- minimum: 1
- type: integer
- required:
- - maxReplicas
- - minReplicas
- type: object
- x-kubernetes-validations:
- - message: minReplicas should be less than or equal maxReplicas
- rule: self.minReplicas <= self.maxReplicas
- secretMounts:
- description: Specifies Secrets to mount into the Function's container
- filesystem.
- items:
- properties:
- mountPath:
- description: Specifies the path within the container where the
- Secret should be mounted.
- minLength: 1
- type: string
- secretName:
- description: Specifies the name of the Secret in the Function's
- Namespace.
- maxLength: 253
- minLength: 1
- type: string
- required:
- - mountPath
- - secretName
- type: object
- type: array
- source:
- description: Contains the Function's source code configuration.
- properties:
- gitRepository:
- description: Defines the Function as git-sourced. Can't be used
- together with **Inline**.
- properties:
- auth:
- description: Specifies the authentication method. Required
- for SSH.
- properties:
- secretName:
- description: |-
- Specifies the name of the Secret with credentials used by the Function Controller
- to authenticate to the Git repository in order to fetch the Function's source code and dependencies.
- This Secret must be stored in the same Namespace as the Function CR.
- type: string
- x-kubernetes-validations:
- - message: SecretName is required and cannot be empty
- rule: self.trim().size() != 0
- type:
- description: |-
- Defines the repository authentication method. The value is either `basic` if you use a password or token,
- or `key` if you use an SSH key.
- enum:
- - basic
- - key
- type: string
- required:
- - secretName
- - type
- type: object
- baseDir:
- description: |-
- Specifies the relative path to the Git directory that contains the source code
- from which the Function is built.
- type: string
- reference:
- description: |-
- Specifies either the branch name, tag or commit revision from which the Function Controller
- automatically fetches the changes in the Function's code and dependencies.
- type: string
- url:
- description: |-
- Specifies the URL of the Git repository with the Function's code and dependencies.
- Depending on whether the repository is public or private and what authentication method is used to access it,
- the URL must start with the `http(s)`, `git`, or `ssh` prefix.
- type: string
- required:
- - url
- type: object
- x-kubernetes-validations:
- - message: BaseDir is required and cannot be empty
- rule: has(self.baseDir) && (self.baseDir.trim().size() != 0)
- - message: Reference is required and cannot be empty
- rule: has(self.reference) && (self.reference.trim().size() !=
- 0)
- inline:
- description: Defines the Function as the inline Function. Can't
- be used together with **GitRepository**.
- properties:
- dependencies:
- description: Specifies the Function's dependencies.
- type: string
- source:
- description: Specifies the Function's full source code.
- minLength: 1
- type: string
- required:
- - source
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use GitRepository or Inline source
- rule: has(self.gitRepository) && !has(self.inline) || !has(self.gitRepository)
- && has(self.inline)
- template:
- description: 'Deprecated: Use **Labels** and **Annotations** to label
- and/or annotate Function''s Pods.'
- properties:
- annotations:
- additionalProperties:
- type: string
- description: 'Deprecated: Use **FunctionSpec.Annotations** to
- annotate Function''s Pods.'
- type: object
- labels:
- additionalProperties:
- type: string
- description: 'Deprecated: Use **FunctionSpec.Labels** to label
- Function''s Pods.'
- type: object
- type: object
- x-kubernetes-validations:
- - message: 'Not supported: Use spec.labels and spec.annotations to
- label and/or annotate Function''s Pods.'
- rule: '!has(self.labels) && !has(self.annotations)'
- required:
- - runtime
- - source
- type: object
- status:
- description: FunctionStatus defines the observed state of the Function
- properties:
- baseDir:
- description: |-
- Specifies the relative path to the Git directory that contains the source code
- from which the Function is built.
- type: string
- buildResourceProfile:
- description: Specifies the preset used for the build job
- type: string
- commit:
- description: Specifies the commit hash used to build the Function.
- type: string
- conditions:
- description: Specifies an array of conditions describing the status
- of the parser.
- items:
- properties:
- lastTransitionTime:
- description: Specifies the last time the condition transitioned
- from one status to another.
- format: date-time
- type: string
- message:
- description: Provides a human-readable message indicating details
- about the transition.
- type: string
- reason:
- description: Specifies the reason for the condition's last transition.
- type: string
- status:
- description: Specifies the status of the condition. The value
- is either `True`, `False`, or `Unknown`.
- type: string
- type:
- description: Specifies the type of the Function's condition.
- type: string
- required:
- - status
- type: object
- type: array
- functionResourceProfile:
- description: Specifies the preset used for the function
- type: string
- podSelector:
- description: Specifies the Pod selector used to match Pods in the
- Function's Deployment.
- type: string
- reference:
- description: |-
- Specifies either the branch name, tag or commit revision from which the Function Controller
- automatically fetches the changes in the Function's code and dependencies.
- type: string
- replicas:
- description: Specifies the total number of non-terminated Pods targeted
- by this Function.
- format: int32
- type: integer
- runtime:
- description: Specifies the **Runtime** type of the Function.
- type: string
- runtimeImage:
- description: Specifies the image version used to build and run the
- Function's Pods.
- type: string
- runtimeImageOverride:
- description: |-
- Deprecated: Specifies the runtime image version which overrides the **RuntimeImage** status parameter.
- **RuntimeImageOverride** exists for historical compatibility
- and should be removed with v1alpha3 version.
- type: string
- type: object
- type: object
- served: true
- storage: true
- subresources:
- scale:
- labelSelectorPath: .status.podSelector
- specReplicasPath: .spec.replicas
- statusReplicasPath: .status.replicas
- status: {}
diff --git a/components/serverless/config/crd/kustomization.yaml b/components/serverless/config/crd/kustomization.yaml
deleted file mode 100644
index 5a820fef3..000000000
--- a/components/serverless/config/crd/kustomization.yaml
+++ /dev/null
@@ -1,21 +0,0 @@
-# This kustomization.yaml is not intended to be run by itself,
-# since it depends on service name and namespace that are out of this kustomize package.
-# It should be run by config/default
-resources:
-- bases/serverless.kyma-project.io_functions.yaml
-# +kubebuilder:scaffold:crdkustomizeresource
-
-# patchesStrategicMerge:
-# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
-# patches here are for enabling the conversion webhook for each CRD
-#- patches/webhook_in_functions.yaml
-# +kubebuilder:scaffold:crdkustomizewebhookpatch
-
-# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.
-# patches here are for enabling the CA injection for each CRD
-#- patches/cainjection_in_functions.yaml
-# +kubebuilder:scaffold:crdkustomizecainjectionpatch
-
-# the following config is for teaching kustomize how to do kustomization for CRDs.
-configurations:
-- kustomizeconfig.yaml
diff --git a/components/serverless/config/crd/kustomizeconfig.yaml b/components/serverless/config/crd/kustomizeconfig.yaml
deleted file mode 100644
index 6f83d9a94..000000000
--- a/components/serverless/config/crd/kustomizeconfig.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is for teaching kustomize how to substitute name and namespace reference in CRD
-nameReference:
-- kind: Service
- version: v1
- fieldSpecs:
- - kind: CustomResourceDefinition
- group: apiextensions.k8s.io
- path: spec/conversion/webhookClientConfig/service/name
-
-namespace:
-- kind: CustomResourceDefinition
- group: apiextensions.k8s.io
- path: spec/conversion/webhookClientConfig/service/namespace
- create: false
-
-varReference:
-- path: metadata/annotations
diff --git a/components/serverless/config/crd/patches/cainjection_in_functions.yaml b/components/serverless/config/crd/patches/cainjection_in_functions.yaml
deleted file mode 100644
index 71bd62d58..000000000
--- a/components/serverless/config/crd/patches/cainjection_in_functions.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# The following patch adds a directive for certmanager to inject CA into the CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
- annotations:
- cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
- name: functions.serverless.kyma-project.io
diff --git a/components/serverless/config/crd/patches/webhook_in_functions.yaml b/components/serverless/config/crd/patches/webhook_in_functions.yaml
deleted file mode 100644
index 358fcc04b..000000000
--- a/components/serverless/config/crd/patches/webhook_in_functions.yaml
+++ /dev/null
@@ -1,17 +0,0 @@
-# The following patch enables conversion webhook for CRD
-# CRD conversion requires k8s 1.13 or later.
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
- name: functions.serverless.kyma-project.io
-spec:
- conversion:
- strategy: Webhook
- webhookClientConfig:
- # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank,
- # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager)
- caBundle: Cg==
- service:
- namespace: system
- name: webhook-service
- path: /convert
diff --git a/components/serverless/config/default/kustomization.yaml b/components/serverless/config/default/kustomization.yaml
deleted file mode 100644
index f248480c7..000000000
--- a/components/serverless/config/default/kustomization.yaml
+++ /dev/null
@@ -1,74 +0,0 @@
-# Adds namespace to all resources.
-namespace: serverless-system
-
-# Value of this field is prepended to the
-# names of all resources, e.g. a deployment named
-# "wordpress" becomes "alices-wordpress".
-# Note that it should also match with the prefix (text before '-') of the namespace
-# field above.
-namePrefix: function-
-
-# Labels to add to all resources and selectors.
-#commonLabels:
-# someName: someValue
-
-bases:
- - ../crd
- - ../rbac
- - ../manager
-# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml
-# - ../webhook
-# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
-# - ../certmanager
-# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
-#- ../prometheus
-
-patchesStrategicMerge:
- # Protect the /metrics endpoint by putting it behind auth.
- # Only one of manager_auth_proxy_patch.yaml and
- # manager_prometheus_metrics_patch.yaml should be enabled.
- - manager_auth_proxy_patch.yaml
- # If you want your controller-manager to expose the /metrics
- # endpoint w/o any authn/z, uncomment the following line and
- # comment manager_auth_proxy_patch.yaml.
- # Only one of manager_auth_proxy_patch.yaml and
- # manager_prometheus_metrics_patch.yaml should be enabled.
- #- manager_prometheus_metrics_patch.yaml
-
- # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in crd/kustomization.yaml
- - manager_webhook_patch.yaml
-
- # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
- # Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
- # 'CERTMANAGER' needs to be enabled to use ca injection
- - webhookcainjection_patch.yaml
-
-# the following config is for teaching kustomize how to do var substitution
-vars:
- # [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
- - name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
- objref:
- kind: Certificate
- group: cert-manager.io
- version: v1alpha2
- name: serving-cert # this name should match the one in certificate.yaml
- fieldref:
- fieldpath: metadata.namespace
- - name: CERTIFICATE_NAME
- objref:
- kind: Certificate
- group: cert-manager.io
- version: v1alpha2
- name: serving-cert # this name should match the one in certificate.yaml
- - name: SERVICE_NAMESPACE # namespace of the service
- objref:
- kind: Service
- version: v1
- name: webhook-service
- fieldref:
- fieldpath: metadata.namespace
- - name: SERVICE_NAME
- objref:
- kind: Service
- version: v1
- name: webhook-service
diff --git a/components/serverless/config/default/manager_auth_proxy_patch.yaml b/components/serverless/config/default/manager_auth_proxy_patch.yaml
deleted file mode 100644
index dfe5cfe42..000000000
--- a/components/serverless/config/default/manager_auth_proxy_patch.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-# This patch inject a sidecar container which is a HTTP proxy for the controller manager,
-# it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: controller-manager
- namespace: system
-spec:
- template:
- spec:
- containers:
- - name: kube-rbac-proxy
- image: gcr.io/kubebuilder/kube-rbac-proxy:v0.5.0
- args:
- - "--secure-listen-address=0.0.0.0:8443"
- - "--upstream=http://127.0.0.1:8080/"
- - "--logtostderr=true"
- - "--v=10"
- ports:
- - containerPort: 8443
- name: https
- - name: manager
- args:
- - "--metrics-addr=127.0.0.1:8080"
- - "--enable-leader-election"
diff --git a/components/serverless/config/default/manager_webhook_patch.yaml b/components/serverless/config/default/manager_webhook_patch.yaml
deleted file mode 100644
index 738de350b..000000000
--- a/components/serverless/config/default/manager_webhook_patch.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: controller-manager
- namespace: system
-spec:
- template:
- spec:
- containers:
- - name: manager
- ports:
- - containerPort: 9443
- name: webhook-server
- protocol: TCP
- volumeMounts:
- - mountPath: /tmp/k8s-webhook-server/serving-certs
- name: cert
- readOnly: true
- volumes:
- - name: cert
- secret:
- defaultMode: 420
- secretName: webhook-server-cert
diff --git a/components/serverless/config/default/webhookcainjection_patch.yaml b/components/serverless/config/default/webhookcainjection_patch.yaml
deleted file mode 100644
index fa5f19936..000000000
--- a/components/serverless/config/default/webhookcainjection_patch.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-# This patch add annotation to admission webhook config and
-# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
-apiVersion: admissionregistration.k8s.io/v1beta1
-kind: MutatingWebhookConfiguration
-metadata:
- name: mutating-webhook-configuration
- annotations:
- cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
-
diff --git a/components/serverless/config/manager/kustomization.yaml b/components/serverless/config/manager/kustomization.yaml
deleted file mode 100644
index aa3c73e70..000000000
--- a/components/serverless/config/manager/kustomization.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-resources:
-- manager.yaml
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-images:
-- name: controller
- newName: function-controller
- newTag: latest
diff --git a/components/serverless/config/manager/manager.yaml b/components/serverless/config/manager/manager.yaml
deleted file mode 100644
index b676b8932..000000000
--- a/components/serverless/config/manager/manager.yaml
+++ /dev/null
@@ -1,40 +0,0 @@
-apiVersion: v1
-kind: Namespace
-metadata:
- labels:
- control-plane: controller-manager
- name: system
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: controller-manager
- namespace: system
- labels:
- control-plane: controller-manager
-spec:
- selector:
- matchLabels:
- control-plane: controller-manager
- replicas: 1
- template:
- metadata:
- labels:
- control-plane: controller-manager
- spec:
- containers:
- - command:
- - /manager
- args:
- - --enable-leader-election
- image: controller:latest
- name: manager
- imagePullPolicy: IfNotPresent
- resources:
- limits:
- cpu: 100m
- memory: 30Mi
- requests:
- cpu: 100m
- memory: 20Mi
- terminationGracePeriodSeconds: 10
diff --git a/components/serverless/config/prometheus/kustomization.yaml b/components/serverless/config/prometheus/kustomization.yaml
deleted file mode 100644
index ed137168a..000000000
--- a/components/serverless/config/prometheus/kustomization.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-resources:
-- monitor.yaml
diff --git a/components/serverless/config/prometheus/monitor.yaml b/components/serverless/config/prometheus/monitor.yaml
deleted file mode 100644
index e2d9b087f..000000000
--- a/components/serverless/config/prometheus/monitor.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-
-# Prometheus Monitor Service (Metrics)
-apiVersion: monitoring.coreos.com/v1
-kind: ServiceMonitor
-metadata:
- labels:
- control-plane: controller-manager
- name: controller-manager-metrics-monitor
- namespace: system
-spec:
- endpoints:
- - path: /metrics
- port: https
- selector:
- control-plane: controller-manager
diff --git a/components/serverless/config/rbac/auth_proxy_role.yaml b/components/serverless/config/rbac/auth_proxy_role.yaml
deleted file mode 100644
index 618f5e417..000000000
--- a/components/serverless/config/rbac/auth_proxy_role.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: proxy-role
-rules:
-- apiGroups: ["authentication.k8s.io"]
- resources:
- - tokenreviews
- verbs: ["create"]
-- apiGroups: ["authorization.k8s.io"]
- resources:
- - subjectaccessreviews
- verbs: ["create"]
diff --git a/components/serverless/config/rbac/auth_proxy_role_binding.yaml b/components/serverless/config/rbac/auth_proxy_role_binding.yaml
deleted file mode 100644
index 48ed1e4b8..000000000
--- a/components/serverless/config/rbac/auth_proxy_role_binding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: proxy-rolebinding
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: proxy-role
-subjects:
-- kind: ServiceAccount
- name: default
- namespace: system
diff --git a/components/serverless/config/rbac/auth_proxy_service.yaml b/components/serverless/config/rbac/auth_proxy_service.yaml
deleted file mode 100644
index 6cf656be1..000000000
--- a/components/serverless/config/rbac/auth_proxy_service.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- labels:
- control-plane: controller-manager
- name: controller-manager-metrics-service
- namespace: system
-spec:
- ports:
- - name: https
- port: 8443
- targetPort: https
- selector:
- control-plane: controller-manager
diff --git a/components/serverless/config/rbac/function_editor_role.yaml b/components/serverless/config/rbac/function_editor_role.yaml
deleted file mode 100644
index d2db1387f..000000000
--- a/components/serverless/config/rbac/function_editor_role.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-# permissions to do edit functions.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: function-editor-role
-rules:
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions/status
- verbs:
- - get
- - patch
- - update
diff --git a/components/serverless/config/rbac/function_viewer_role.yaml b/components/serverless/config/rbac/function_viewer_role.yaml
deleted file mode 100644
index 2f175fa55..000000000
--- a/components/serverless/config/rbac/function_viewer_role.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# permissions to do viewer functions.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: function-viewer-role
-rules:
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions
- verbs:
- - get
- - list
- - watch
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions/status
- verbs:
- - get
diff --git a/components/serverless/config/rbac/kustomization.yaml b/components/serverless/config/rbac/kustomization.yaml
deleted file mode 100644
index 817f1fe61..000000000
--- a/components/serverless/config/rbac/kustomization.yaml
+++ /dev/null
@@ -1,11 +0,0 @@
-resources:
-- role.yaml
-- role_binding.yaml
-- leader_election_role.yaml
-- leader_election_role_binding.yaml
-# Comment the following 3 lines if you want to disable
-# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
-# which protects your /metrics endpoint.
-- auth_proxy_service.yaml
-- auth_proxy_role.yaml
-- auth_proxy_role_binding.yaml
diff --git a/components/serverless/config/rbac/leader_election_role.yaml b/components/serverless/config/rbac/leader_election_role.yaml
deleted file mode 100644
index eaa79158f..000000000
--- a/components/serverless/config/rbac/leader_election_role.yaml
+++ /dev/null
@@ -1,32 +0,0 @@
-# permissions to do leader election.
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
- name: leader-election-role
-rules:
-- apiGroups:
- - ""
- resources:
- - configmaps
- verbs:
- - get
- - list
- - watch
- - create
- - update
- - patch
- - delete
-- apiGroups:
- - ""
- resources:
- - configmaps/status
- verbs:
- - get
- - update
- - patch
-- apiGroups:
- - ""
- resources:
- - events
- verbs:
- - create
diff --git a/components/serverless/config/rbac/leader_election_role_binding.yaml b/components/serverless/config/rbac/leader_election_role_binding.yaml
deleted file mode 100644
index eed16906f..000000000
--- a/components/serverless/config/rbac/leader_election_role_binding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
- name: leader-election-rolebinding
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: Role
- name: leader-election-role
-subjects:
-- kind: ServiceAccount
- name: default
- namespace: system
diff --git a/components/serverless/config/rbac/role.yaml b/components/serverless/config/rbac/role.yaml
deleted file mode 100644
index 143f77885..000000000
--- a/components/serverless/config/rbac/role.yaml
+++ /dev/null
@@ -1,152 +0,0 @@
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: serverless
-rules:
-- apiGroups:
- - ""
- resources:
- - configmaps
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - configmaps
- - secrets
- - serviceaccounts
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - events
- verbs:
- - create
- - patch
-- apiGroups:
- - ""
- resources:
- - namespaces
- verbs:
- - get
- - list
- - watch
-- apiGroups:
- - ""
- resources:
- - secrets
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - serviceaccounts
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - services
- verbs:
- - create
- - delete
- - get
- - list
- - update
- - watch
-- apiGroups:
- - apps
- resources:
- - deployments
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - apps
- resources:
- - deployments/status
- verbs:
- - get
-- apiGroups:
- - autoscaling
- resources:
- - horizontalpodautoscalers
- verbs:
- - create
- - deletecollection
- - get
- - list
- - update
- - watch
-- apiGroups:
- - batch
- resources:
- - jobs
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - batch
- resources:
- - jobs/status
- verbs:
- - get
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions/status
- verbs:
- - get
- - patch
- - update
diff --git a/components/serverless/config/rbac/role_binding.yaml b/components/serverless/config/rbac/role_binding.yaml
deleted file mode 100644
index 8f2658702..000000000
--- a/components/serverless/config/rbac/role_binding.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: manager-rolebinding
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: manager-role
-subjects:
-- kind: ServiceAccount
- name: default
- namespace: system
diff --git a/components/serverless/deploy/jobinit/Dockerfile b/components/serverless/deploy/jobinit/Dockerfile
deleted file mode 100644
index b171fb94a..000000000
--- a/components/serverless/deploy/jobinit/Dockerfile
+++ /dev/null
@@ -1,35 +0,0 @@
-FROM golang:1.22.1-alpine3.19 as builder
-
-ENV BASE_APP_DIR=/workspace/go/src/github.com/kyma-project/serverless \
- CGO_ENABLED=1 \
- GOOS=linux \
- GOARCH=amd64 \
- LIBGIT2_VERSION=1.5.2-r0
-
-RUN apk add --no-cache gcc libc-dev
-RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.18/community libgit2-dev=${LIBGIT2_VERSION}
-
-WORKDIR ${BASE_APP_DIR}
-
-#
-# copy files allowed in .dockerignore
-#
-COPY . ${BASE_APP_DIR}/
-
-RUN go build -ldflags "-s -w" -a -o jobinit ./components/serverless/cmd/jobinit/main.go \
- && mkdir /app \
- && mv ./jobinit /app/jobinit
-
-FROM europe-docker.pkg.dev/kyma-project/prod/external/alpine:3.19.1
-ENV LIBGIT2_VERSION=1.5.2-r0
-
-LABEL source = git@github.com:kyma-project/kyma.git
-
-RUN apk update --no-cache && apk upgrade --no-cache
-RUN apk add --no-cache ca-certificates
-RUN apk add --no-cache --update --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main openssh-client openssl
-RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.18/community libgit2=${LIBGIT2_VERSION}
-
-COPY --from=builder /app /app
-
-ENTRYPOINT ["/app/jobinit"]
diff --git a/components/serverless/deploy/jobinit/Dockerfile.dockerignore b/components/serverless/deploy/jobinit/Dockerfile.dockerignore
deleted file mode 100644
index a149b20a2..000000000
--- a/components/serverless/deploy/jobinit/Dockerfile.dockerignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ignore all
-**
-# Allow
-!components/serverless
-!go.sum
-!go.mod
diff --git a/components/serverless/deploy/manager/Dockerfile b/components/serverless/deploy/manager/Dockerfile
deleted file mode 100644
index 6529e7078..000000000
--- a/components/serverless/deploy/manager/Dockerfile
+++ /dev/null
@@ -1,41 +0,0 @@
-FROM golang:1.22.1-alpine3.19 as builder
-
-ENV BASE_APP_DIR=/workspace/go/src/github.com/kyma-project/serverless \
- CGO_ENABLED=1 \
- GOOS=linux \
- GOARCH=amd64 \
- LIBGIT2_VERSION=1.5.2-r0
-
-RUN apk add --no-cache gcc libc-dev
-RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.18/community libgit2-dev=${LIBGIT2_VERSION}
-
-WORKDIR ${BASE_APP_DIR}
-
-#
-# copy files allowed in .dockerignore
-#
-COPY . ${BASE_APP_DIR}/
-
-RUN go build -ldflags "-s -w" -a -o manager ./components/serverless/cmd/manager/main.go \
- && mkdir /app \
- && mv ./manager /app/manager
-
-FROM europe-docker.pkg.dev/kyma-project/prod/external/alpine:3.19.1 as certs
-
-RUN apk add --no-cache ca-certificates
-
-FROM europe-docker.pkg.dev/kyma-project/prod/external/alpine:3.19.1
-
-ENV LIBGIT2_VERSION=1.5.2-r0
-
-RUN apk update --no-cache && apk upgrade --no-cache
-RUN apk add --no-cache --update --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main openssl
-RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.18/community libgit2=${LIBGIT2_VERSION}
-
-LABEL source = git@github.com:kyma-project/kyma.git
-
-COPY --from=builder /app /app
-COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
-
-ENTRYPOINT ["/app/manager"]
-
diff --git a/components/serverless/deploy/manager/Dockerfile.dockerignore b/components/serverless/deploy/manager/Dockerfile.dockerignore
deleted file mode 100644
index a149b20a2..000000000
--- a/components/serverless/deploy/manager/Dockerfile.dockerignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ignore all
-**
-# Allow
-!components/serverless
-!go.sum
-!go.mod
diff --git a/components/serverless/deploy/webhook/Dockerfile b/components/serverless/deploy/webhook/Dockerfile
deleted file mode 100644
index 4167116ac..000000000
--- a/components/serverless/deploy/webhook/Dockerfile
+++ /dev/null
@@ -1,31 +0,0 @@
-# image builder base on golang:1.21.4-alpine3.18
-FROM golang@sha256:f475434ea2047a83e9ba02a1da8efc250fa6b2ed0e9e8e4eb8c5322ea6997795 as builder
-
-ENV BASE_APP_DIR=/workspace/go/src/github.com/kyma-project/serverless \
- CGO_ENABLED=0 \
- GOOS=linux \
- GOARCH=amd64
-
-WORKDIR ${BASE_APP_DIR}
-
-# Copy the go source
-COPY . ${BASE_APP_DIR}/
-
-# Build
-RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o webhook-server ./components/serverless/cmd/webhook/main.go \
-&& mkdir /app \
-&& mv ./webhook-server /app/webhook-server
-
-# get latest CA certs from alpine:3.17.4
-FROM europe-docker.pkg.dev/kyma-project/prod/external/alpine@sha256:e95676db9e4a4f16f6cc01a8915368f82b018cc07aba951c1bd1db586c081388 as certs
-RUN apk add --no-cache ca-certificates
-
-FROM scratch
-
-LABEL source = git@github.com:kyma-project/kyma.git
-
-COPY --from=builder /app /app
-COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
-USER 1000
-
-ENTRYPOINT ["/app/webhook-server"]
diff --git a/components/serverless/deploy/webhook/Dockerfile.dockerignore b/components/serverless/deploy/webhook/Dockerfile.dockerignore
deleted file mode 100644
index a149b20a2..000000000
--- a/components/serverless/deploy/webhook/Dockerfile.dockerignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Ignore all
-**
-# Allow
-!components/serverless
-!go.sum
-!go.mod
diff --git a/components/serverless/design/assets/kubebuilder-architecture.png b/components/serverless/design/assets/kubebuilder-architecture.png
deleted file mode 100644
index 8c9f12d9e..000000000
Binary files a/components/serverless/design/assets/kubebuilder-architecture.png and /dev/null differ
diff --git a/components/serverless/design/extend_function_spec_proposal.md b/components/serverless/design/extend_function_spec_proposal.md
deleted file mode 100644
index 3ce7ab41f..000000000
--- a/components/serverless/design/extend_function_spec_proposal.md
+++ /dev/null
@@ -1,525 +0,0 @@
-# Extending CRD spec for Serverless v1alpha2
-
-## Summary
-
-The current Serverless API allows for limited configuration of the generated Function's deployment.
-Currently, users can only use ENVs to pass 3rd party service credentials but it doesn't allow for volume-mounted Secrets (which become the industry standard for [service bindings](https://servicebinding.io/application-developer/)).
-Moreover, users have no control over the annotations applied on the function runtime pod. This excludes Function's Pods from features enabled by annotations (i.e., custom log parsers via `fluentbit.io/parser: my-regex-parser`).
-
-
-
-## Motivation
-
-Give Serverless users the ability to:
-- Configure volume-mounted Secrets for Function's subresources.
-- Configure labels and annotations for the Function's runtime Pod.
-
-### Goals
-
-- Add more flexibility to the Serverless API - enable volume-mounted Secrets and Pod annotations.
-- Organise spec attributes belonging to runtime and build-time configuration (?)
-- Propose sample Function CR visualising different variants
-
-## Discussion points
-
-### Runtime, build-time separation
-
-Since Function CR is managing two workloads (Deployment for runtime and Job for build-time) we need to separate them in the spec in order to make it clear where the mounts and annotations belong.
-
-We can either make a clear separation, i.e.:
-
-```yaml
-spec:
- source:
- runtimeSpec:
- # mounts
- # resources
- # envs
- # metadata
- buildSpec:
- # resources
- # envs (?)
- # metadata (?)
-```
-
-Alternatively, we could promote runtime fields to the root (as they belong to kind: Function) and extract only the build-time fields
-
-```yaml
-spec:
- source:
- # mounts
- # resources
- # envs
- # metadata
- buildSpec:
- # resources
- # envs (?)
- # metadata (?)
-```
-
-### Mounts - own structure or k8s inherited
-
-Under the hood, the Secret mount becomes a volume mount in the runtime Pod.
-We could:
-
-A) expose the k8s volume mount spec in the Function spec
-
-Pros:
- - Generic solution - Allows mounting anything: Secrets, ConfigMaps, any volumes
- - very easy to achieve (rewriting from the Function spec to Pod template spec)
-
-Cons:
- - Does not represent the service binding use case. User needs to translate service bindings into volume mounts by themselves
- - Less compact (elegant) to configure requested service binding use case
- - Noone has requested it yet
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-spec:
- volumeMounts:
- - name: foo
- mountPath: "/etc/foo"
- readOnly: true
- volumes:
- - name: foo
- secret:
- secretName: mysecret
-```
- B) focus on [service binding case](https://servicebinding.io/application-developer/).
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-spec:
- secretBindings: #serviceBindings will cause name clash with https://github.com/SAP/sap-btp-service-operator#service-binding
- - source: my-secret
- mountPath: /bar # optional mount path
- env:
- - name: SERVICE_BINDING_ROOT # default mount path for service bindings
- value: /foo
-```
- Pros:
- - Purpose focused
- - Compact configuration - easy to adopt
- - Less confusing (as volume mounts confuse Serverless Functions are considered stateless and should not claim any persistence volumes )
- - Enables using service binding natively with dedicated SDKs (i.e @sap/xsenv) - [related read](https://blogs.sap.com/2022/07/12/the-new-way-to-consume-service-bindings-on-kyma-runtime/)
-
-Cons:
- - Not allows mounting anything besides Secrets
-
-A) and B) are not exclusive
-
-We could separate those cases. (See last 'compromise' option)
-
-
-### Metadata for Function's Pod
-
-Define runtime labels and annotations on the root level or under a `metadata` field
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- ...
- annotations:
- ...
-spec:
- metadata:
- labels: ...
- annotations: ...
-```
-OR
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- ...
- annotations:
- ...
-spec:
- labels: ...
- annotations: ...
-```
-
-## Samples:
-
-### Option 1
-
-- simplified mounts serving just for service binding purpose
-- stretch: volume mounts could be added as a separate feature
-- extract `build` object for any build-time specific config
-- runtime labels and annotations on the spec root level
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function
-spec:
- runtime: nodejs20
- source:
- ...
- secretBindings:
- - source: my-secret
- mountPath: "/foo" # optional.. read from SERVICE_BINDING_ROOT ENV
-
- profile: S / M / L / XL / ... / Custom #optional
- resources: # optional... required if spec.profile==Custom
- limits: ... #if_custom
- requests: ... #if_custom
-​
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
-​
- env:
- - name: SERVICE_BINDING_ROOT
- value: /service_bindings
-​​
- build:
- profile: S / M / L / XL / ... / Custom
- resources: # optional... required if spec.build.profile==Custom
- limits: ... #if_custom
- requests: ... #if_custom
- labels: #optional
- annotations: #optional
-```
-
-### Option 2
-
-- almost the same as `Option 1` (same pros)
-- dif1: move some fields from `.spec` to the new struct `.spec.runtimeSpec` to clearly distinguish fields desired to be used in the `build` and `running` phases. For example in `Option 1` users may have questions after seeing `.spec.env` and `.spec.build.env` fields for example "is .spec.env dedicated for the running Function's Pod? Would the field be merged with .spec.build.env for the building job?"
-- dif2: rename the `.spec.profile` to the `.spec.resourcesProfile` to make this field more intuitive
-- dif3: this solution is simple but not as simple as `Option 1`
-
->NOTE: the main idea is to close a specific configuration in a field that represents the specific phase of the Function's lifecycle. It would be intuitive and easy to understand for a user that the `.spec.build` field contains configuration for the building phase and `.spec.runtimeSpec` for the running phase.
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function
-spec:
- runtime: nodejs20
- source:
- ...
- runtimeSpec: # this name is not perfect
- serviceBindings:
- - source: my-secret
- mountPath: "/foo" # optional.. read from SERVICE_BINDING_ROOT ENV
-
- resourcesProfile: S / M / L / XL / ... / Custom #optional
- resources: # optional... required if spec.profile==Custom
- limits: ... #if_custom
- requests: ... #if_custom
-
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
-
- env:
- - name: SERVICE_BINDING_ROOT
- value: /service_bindings
-
- buildSpec: # this name is not perfect
- resourcesProfile: S / M / L / XL / ... / Custom
- resources: # optional... required if spec.build.profile==Custom
- limits: ... #if_custom
- requests: ... #if_custom
-```
-
-### Option 3
-
-This option exposes runtime pod configuration over the build Pod because the runtime Pod is the final result, and the build is a transient phase.
-Additionaly:
-- It allows to use full k8s volume api the similar way to k8s pods.
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha3
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function
-spec:
- sources:
- inline:
- source: aaaa
- dependency: bbbb
- replicas: 1
- scalingConfig:
- min: 1
- max: 2
-
- resourcesProfile: S / M / L / XL / ... | (empty)-> resources field has to be filled
- resources: #k8s limits and requests
-
- envs:
- - name: PASSWORD
- valueFrom:
- secretRef:
- name: mysvc-passwords
- key: password
- - name: EXTERNAL_API_URL
- valueFrom:
- configmapRef:
- name: mysvc-configuration
- key: URL
- volumeMounts:
- - name: config
- mountPath: /etc/config/
- - name: search-index
- mountPath: /etc/index
- volumes:
- - name: search-index
- nfs:
- path: /path-to-index
- readOnly: true
- server: localhost
- - name: config
- configmap:
- name: function-configuration
- items:
- - key: config
- path: config.yaml
-
- metadata:
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
-
- #build can share the same configuration options as function:
- # metadata, volumes, volumeMounts, envs, resourceProfile, resources,
- build:
- metadata:
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
- resourcesProfile: S / M / L / XL / ... | (empty)-> resources field has to be filled
- resources: #k8s limits and requests
- envs:
- - name: RUNTIME_CACHE_OFF
- value: true
- volumes:
- - name: private-deps-repo-configuration
- secret:
- secretName: private-repo
- volumeMounts:
- - name: private-deps-repo-configuration
- path: /etc/my-dep-resolver.config
-```
-### Option 4
-
-Option presented before with separated configurations (templates) for build and function.
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function
-spec:
- runtime: nodejs20
- source:
- ...
- resourceProfiles:
- function: S / M / L / XL / ... | (empty)-> resources field has to be filled
- build: S / M / L / XL / ... | (empty)-> resources field has to be filled
- replicas: 1
- scalingConfig:
- min: 1
- max: 2
- templates:
- functionPod:
- metadata: # labels and annotations only for function pod
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
- spec:
- resources: # optional... required if spec.resourceProfiles.function is empty
- limits: ... #if_custom
- requests: ... #if_custom
- env: # function pod envs
- - name: PASSWORD
- valueFrom:
- secretRef:
- name: mysvc-passwords
- key: password
- - name: EXTERNAL_API_URL
- valueFrom:
- configmapRef:
- name: mysvc-configuration
- key: URL
- volumeMounts: ...
- - name: config
- mountPath: /etc/config/
- - name: search-index
- mountPath: /etc/index
- volumes:
- - name: search-index
- nfs:
- path: /path-to-index
- readOnly: true
- server: localhost
- - name: config
- configmap:
- name: function-configuration
- items:
- - key: config
- path: config.yaml
- buildPod:
- metadata: ...# labels and annotations only for build pod
- spec:
- resources: # optional... required if spec.resourceProfiles.build is empty
- limits: ... #if_custom
- requests: ... #if_custom
- env: ...
- volumeMounts: ...
- volumes: ...
-```
-
-
-### Final version - the compromise
-
- - clearly separate configuration of the build stage in the spec (treating `build` stage as second class citizen and keeping the main spec dedicated to the more important runtime stage).
- - add convenient way to mount Secrets (w/o polluting function API with dependencies to service bindings)
- - volume mounts as a separate, more advanced case (implemented once requested)
- - don't group labels and annotations under metadata.
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function
-spec: #Contains spec of Function and run stage (deployments, hpa)
- runtime: nodejs20
- source:
- ...
- replicas: 1
- scalingConfig:
- min: 1
- max: 2
-
- labels:
- app: my-app
- annotations:
- fluentbit.io/parser: my-regex-parser
- istio-injection: enabled
-
- secretMounts:
- - secretName: my-secret
- mountPath: "/foo" #required.. no assumptions/validations towards SERVICE_BINDING_ROOT env value
-
- - secretName: my-redis-secret
- mountPath: "/bar" # this matches SERVICE_BINDING_ROOT env value. Its a soft indication that redis will be consumed as service binding
-
- profile: S / M / L / XL / ... #optional
- resources: # optional... required if spec.profile is empty
- limits: ... #if profile empty
- requests: ... #if profile empty
-​
- env:
- - name: SERVICE_BINDING_ROOT #set explicitely by user if he wants to use a specialised library that expects the ENV (and allows consumption of mounted secrets as service bindings)
- value: /bar
- - name: MODE
- value: modeA
-
- # volumeMounts: (add when requested by users)
- # - name: config
- # mountPath: /etc/config/
- # - name: search-index
- # mountPath: /etc/index
-
- # volumes:
- # - name: search-index
- # nfs:
- # path: /path-to-index
- # readOnly: true
- # server: localhost
- # - name: config
- # configmap:
- # name: function-configuration
- # items:
- # - key: config
- # path: config.yaml
-​​
-
- # optional
- build: #Contains spec of build stage : build is a "second class citizen" here. Users should make no assumptions that anything from main spec is inherited here (i.e ENVs or secretMounts)
- labels:
- annotations:
- profile: S / M / L / XL / ... #optional
- resources: # optional... required if spec.profile is empty
- limits: ... #if profile empty
- requests: ... #if profile empty
-```
-
-### Precedence, defaulting and validation
-
-`profile` takes precedence over `resources`. If the profile field is not set there should be no defaulting happening for the resources. The controller should fill the pod template resources according to the selected profile preset.
-If the profile field is set to "Custom", the user must then (and only then) set the values for resources manually.
-Custom resource values together with non-custom profile should be rejected by the validation webhook.
-
-
-### Labels and annotations
-
-Function CR may have own labels and annotations as defined in it's metadata section. Those labels and annotations are automatically inherited by the resources managed directly by the function CR.
-This direct, first-line inheritance of labels and annotations apply to:
- - Deployment
- - Job
- - HPA
- - ConfigMap
-
-The same labels and annotation are NOT inherited by the Pods controlled by Deployment and Job (second-line inheritance of labels and annotation doesn't apply).
-In order to control the labels and annotations on the runtime and build-time Pods user must define those in the spec:
-
-```yaml
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- name: my-function
- namespace: default
- labels:
- app.kubernetes.io/name: my-function # <-- this label will be inherited by deployment, job, HPA and config map
-spec:
- ...
- labels:
- app: my-app # <-- this label will be used in Deployment's PodTemplate and will be applied on the function's runtime pod
- annotations:
- fluentbit.io/parser: my-regex-parser # <-- those annotations will be used in Deployment's PodTemplate and will be applied on the function's runtime pod
- istio-injection: enabled
-
- ...
- build:
- labels: # <-- those labels will be used in Job's PodTemplate and will be applied on the function's build-time pod
- annotations: # <-- those annotations will be used in Job's PodTemplate and will be applied on the function's build-time pod
-```
diff --git a/components/serverless/design/glossary_proposal.md b/components/serverless/design/glossary_proposal.md
deleted file mode 100644
index b422ecbec..000000000
--- a/components/serverless/design/glossary_proposal.md
+++ /dev/null
@@ -1,104 +0,0 @@
-# Serverless naming convention
-
-## Problem overview
-
-Currently, Serverless in Kyma consists of two projects:
-
-- [function-controller](../README.md)() -
- responsible for running a Function in a Kubernetes cluster
-- [serverless-manager](https://github.com/kyma-project/serverless-manager) - responsible for installation and
- configuration of Serverless
-
-Additionally, we have 3rd-party components, such as [KEDA](https://keda.sh/).
-
-In Serverless, we overuse the word "controller" which causes confusion and requires clarification. Saying "controller", we refer to:
-
-- Serverless reconcile loop
-- Serverless Pod with the reconcile loop
-- the Function Controller component in the `kyma` directory
-
-## Goal
-
-The goal of this document is to clarify the naming convention in Serverless and define its elements to avoid confusion and make it more logical.
-
-## Proposal
-
-The proposed naming conventions refer to different architecture layers of the whole project. See the [architecture](./assets/kubebuilder-architecture.png) diagram for details.
-
-### Project naming convention
-
-This section refers to the high-level architecture elements, namely to the main projects:
-
-- Serverless - the new naming convention for the `function-controller`. Serverless is responsible for running a Function in a Kubernetes cluster. It can contain its own
- CRD.
-- Serverless-operator - the new naming convention for `serverless-manager`. Serverless-operator installs and configures Serverless.
-- Kyma-Keda-operator - the operator which installs and configures [KEDA](https://keda.sh/).
-
-### Component naming convention
-
-This section refers to the Serverless components:
-
-- Controller - responsible for creating and configuring k8s resources to finally run a function in a cluster. It is responsible for the reconciliation of the Function CR.
-- Webhook - responsible for defaulting, validation, and conversion of the Function CR, mutating the external registry Secret, and reconciling certificates.
-
-Proposed naming convention:
-
-Deployment with the controller in charge:
-
-- ${component_name}-controller
-
-In the case of introducing a separate CRD and a separate deployment:
-
-- ${component_name}-{crd_name}-controller
-
-Deployment with the webhook as main responsibility:
-
-- ${component_name}-webhook
-
-Deployment with both controller and webhook:
-
-- ${component_name}
-
-> **NOTE:** I decided to go with the pure component name as it contains both the controller and webhook responsibilities and from the technical perspective it's very similar to the component itself. It might be confusing, and I am open to other proposals.
-
-### Kubebuilder component naming convention
-
-Serverless uses Kubebuilder to build a controller and/or webhook. This section describes the naming convention of the most detailed project layer, namely Kubebuilder components.
-
-Looking at the [architecture](./assets/kubebuilder-architecture.png) diagram, you can see that a program consists of a **process** which includes a **manager**.
-The **manager** can include 2 components:
-
-- Controller, which focuses on the reconciliation of a given Kubernetes resource. It uses predicates and the reconciler.
-- Webhook, which works with `AdmissionRequests`.
-
-Proposed naming convention:
-
-For the controller reconcile loop inside the manager:
-
-- ${crd_name}-reconcile
-- ${component_name}-${crd_name}-reconcile
-
-For the webhook inside the manager:
-
-- ${component_name}-validaton-webhook
-- ${component_name}-${crd_name}-validaton-webhook
-- ${crd_name}-validaton-webhook
-
-For serverless runtimes:
-
-- ${runtime_name}, eg.: `python310`
-
-## Summary
-
-The table lists the terms from the most general to the most detailed ones:
-
-| component name | responsibility |
-|-------------------------------|------------------------------------------------|
-| serverless | the product, such as Keda |
-| serverless-operator | serverless installer |
-| serverless-controller | serverless main reconciliation loop deployment |
-| serverless-webhook | serverless webhook deployment |
-| serverless-reconciler | serverless reconciliation loop |
-| serverless-validation-webhook | serverless validation webhook |
-| serverless-defaulting-webhook | serverless defaulting webhook |
-| serverless-conversion-webhook | serverless conversion webhook |
\ No newline at end of file
diff --git a/components/serverless/design/internal_registry_garbage_collection.md b/components/serverless/design/internal_registry_garbage_collection.md
deleted file mode 100644
index 4fcb21306..000000000
--- a/components/serverless/design/internal_registry_garbage_collection.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Internal Registry Garbage Collection
-
-
-## Summary
-
-The current implementation for the Internal Registry deployed with Kyma Functions doesn't include any garbage collection logic. In dynamic environments with several Functions with multiple versions, if the Internal Registry is used with a cluster PVC storage backend, the volume disk space can fill up very quickly, resulting in build failures for new Function versions.
-
-In addition to the space consumed by the Function images, the Function build process pushes the build cache layers to the registry for later, faster builds.
-
-Alternatively, if cloud storage like S3 is used as a storage backend, the old image and cache blobs will increase S3 cost overtime.
-
-This is a proposal to implement garbage collection logic to avoid these issues.
-
-
-### Goals
-- Implement simple garbage collection logic to be used with the Functions Internal Registry.
-
-### Non-goals
-- Implement garbage collection for external registries.
-
-
-## Proposal
-The Docker registry already has a [garbage collection mechanism](https://docs.docker.com/registry/garbage-collection/). However, it's not very flexible. It's only possible to delete blobs that are not referenced by any manifests.
-
-To utilize this, we need to implement custom logic that will periodically run and:
-- Identify existing Functions running in the cluster.
-- Identify current images used by those Functions' runtimes.
-- List all tags for the used images.
-- Identify unused tags and use the Registry API to delete them.
-- List all cache layers on the registry.
-- Identify unused cache layers and use the Registry API to delete corresponding tags.
-
-One caveat with this approach is that it's possible to miss some images for Functions created and deleted between runs. It's technically possible to simply list _all_ images on the Registry and delete all images that are not currently used by a Function, but this approach has a wider blast radius. The more conservative approach is preferred.
-
-Separately, we need to run the garbage collection tool provided by the Registry to do the actual garbage collection and remove the blobs from the file system.
-
-
-## Implementation details
-The garbage collection process is implemented in three phases:
-
-### Registry API-level image garbage collection
-
-For this phase, a simple command line tool will perform the following steps:
-#### Function image garbage collection
-
-- Identify existing Functions running in the cluster.
-- Identify current images used by those Functions' runtimes.
-- List all tags for the used images.
-- Identify unused tags and use the Registry API to delete them.
-
-#### Cache image garbage collection
-- List all non-cache layers on the Registry. This is done after applying the Function image garbage collection to make sure only referenced images are listed.
-- List all the cache layers. Each layer is mapped to its referencing tag.
-- Cross check the image layers and the cached layers list. Layers referenced in both lists should be kept.
-- Tags referencing the remaining cache layers are deleted using the Registry API.
-
-This tools runs as a Kubernetes Cronjob and is deployed as part of the Internal Registry manifest.
-
-### Unreferenced blob deletion
-The simplest way to perform this is to use the `registry garbage-collection` command.
-
-This is implemented as a simple loop in a side-car container in the registry Pod. It will run periodically and independently from the Function image garbage collection tool to remove unreferenced blobs.
-
diff --git a/components/serverless/design/scaling_functions.md b/components/serverless/design/scaling_functions.md
deleted file mode 100644
index a49b08e00..000000000
--- a/components/serverless/design/scaling_functions.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# Serverless Functions Scaling Modes
-
-## Summary
-Initially, the Serverless API supported the `spec.ScaleConfig` field only. The workflow was as follows:
-- Function resources were defaulted to min/max replicas = 1
-- If you set a different scaling config, Function Controller created HPA resources with the user-defined min/max values.
-- The HPA resource target ref was the Function runtime deployment.
-- The Function Controller did not enforce the runtime deployment `spec.Replicas` anymore and it was handled by the HPA resources.
-
-
-Later, the Serverless API was extended by the `Scale` subresource, which allows for direct scaling of the Function resources through the Kubernetes API.
-
-However, there are some implementation conflicts between the two features. This is a design and an implementation plan to unify the UX while using Functions as scaled resources.
-
-### Goals
-- Support Function scale subresource and `spec.ScaleConfig` without conflicts.
-- Provide frictionless UX for the feature.
-
-## Proposal
-Describe and implement two different scaling configuration. Both configurations already work to some extent. The point here is have an ergonomic UX and flow.
-
-### External scaling configuration
-This is managed and configured using `spec.Replicas`. It describes the scale subresource use case. It supports:
-- Manual scaling of the Function up and down through the API.
-- Configuring an HPA resource with the Function resources as a target.
-- Using an external scaler like [KEDA](https://keda.sh/).
-
-### Built-in scaling configuration
-This is managed and enabled by setting `spec.ScaleConfig`. It is configurable using Busola and it provides the most basic scaling configuration for the Function.
-
-This configuration is disabled by removing `spec.ScaleConfig`. The Busola UI can be extended to allow you to add or remove `spec.ScaleConfig` to manage built-in scaling with minimal effort.
-
-## Implementation details
-
-- The controller should support and accept both `spec.Replicas` and `spec.ScaleConfig`. Current validation rule to block this will be removed.
-- `spec.Replicas` is the only source of truth for scaling the Function/runtime deployment.
-- `spec.ScaleConfig` is only used to configure the controller internal HPA.
-- The internal HPA is removed if `spec.ScaleConfig == nil`
-- The HPA resource created by the controller still targets the Function resources.
-- The current Function status update logic must be fixed to reflect the Function's current scale.
\ No newline at end of file
diff --git a/components/serverless/hack/boilerplate.go.txt b/components/serverless/hack/boilerplate.go.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/components/serverless/hack/config.yaml b/components/serverless/hack/config.yaml
deleted file mode 100644
index 21cb6fbdc..000000000
--- a/components/serverless/hack/config.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-logLevel: info
-logFormat: text
diff --git a/components/serverless/hack/controller.env b/components/serverless/hack/controller.env
deleted file mode 100644
index ac72f210d..000000000
--- a/components/serverless/hack/controller.env
+++ /dev/null
@@ -1,3 +0,0 @@
-APP_LOG_CONFIG_PATH=./hack/config.yaml
-APP_FUNCTION_RESOURCE_CONFIG="buildJob:\n resources:\n defaultPreset: fast\n minRequestCpu: 200m\n minRequestMemory: 200Mi\n presets:\n fast:\n limitCpu: 1700m\n limitMemory: 1100Mi\n requestCpu: 1100m\n requestMemory: 1100Mi\n local-dev:\n limitCpu: 400m\n limitMemory: 400Mi\n requestCpu: 200m\n requestMemory: 200Mi\n normal:\n limitCpu: 1100m\n limitMemory: 1100Mi\n requestCpu: 700m\n requestMemory: 700Mi\n slow:\n limitCpu: 700m\n limitMemory: 700Mi\n requestCpu: 200m\n requestMemory: 200Mi\nfunction:\n resources:\n defaultPreset: L\n minRequestCpu: 10m\n minRequestMemory: 16Mi\n presets:\n L:\n limitCpu: 800m\n limitMemory: 1024Mi\n requestCpu: 400m\n requestMemory: 512Mi\n M:\n limitCpu: 400m\n limitMemory: 512Mi\n requestCpu: 200m\n requestMemory: 256Mi\n S:\n limitCpu: 200m\n limitMemory: 256Mi\n requestCpu: 100m\n requestMemory: 128Mi\n XL:\n limitCpu: 1600m\n limitMemory: 2048Mi\n requestCpu: 800m\n requestMemory: 1024Mi\n XS:\n limitCpu: 100m\n limitMemory: 128Mi\n requestCpu: 50m\n requestMemory: 64Mi\n runtimePresets:\n python39:\n XL:\n limitCpu: 1600m\n limitMemory: 2048Mi\n requestCpu: 800m\n requestMemory: 1024Mi\n python312:\n XL:\n limitCpu: 1600m\n limitMemory: 2048Mi\n requestCpu: 800m\n requestMemory: 1024Mi"
-APP_FUNCTION_BUILD_EXECUTOR_ARGS=--insecure,--skip-tls-verify,--skip-unused-stages,--log-format=text,--cache=true,--force,--use-new-run,--compressed-caching=false
diff --git a/components/serverless/hack/libgit.tgz b/components/serverless/hack/libgit.tgz
deleted file mode 100644
index bc90b0401..000000000
Binary files a/components/serverless/hack/libgit.tgz and /dev/null differ
diff --git a/components/serverless/hack/run-linters.sh b/components/serverless/hack/run-linters.sh
deleted file mode 100755
index d17f6dd6f..000000000
--- a/components/serverless/hack/run-linters.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-
-set -euo pipefail
-IFS=$'\n\t'
-
-readonly SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-readonly BIN_DIR="${SCRIPT_DIR}/../bin"
-readonly GOLANGCI_LINT_BINARY="${BIN_DIR}/golangci-lint"
-
-readonly GOLANGCI_LINT_VERSION="latest"
-
-main(){
- if [[ ! -x "${GOLANGCI_LINT_BINARY}" ]]; then
- echo "Downloading golangci-lint..."
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b "${BIN_DIR}" "${GOLANGCI_LINT_VERSION}"
- echo "Done!"
- fi
-
- "${GOLANGCI_LINT_BINARY}" run --config "${SCRIPT_DIR}/../.golangci.yaml"
-}
-
-main
\ No newline at end of file
diff --git a/components/serverless/internal/config/file.go b/components/serverless/internal/config/file.go
deleted file mode 100644
index 0f7aebb75..000000000
--- a/components/serverless/internal/config/file.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package config
-
-import (
- "context"
- "errors"
- "time"
-
- "github.com/kyma-project/serverless/components/serverless/internal/file"
- "go.uber.org/zap"
-)
-
-const (
- notificationDelay = 1 * time.Second
-)
-
-type CallbackFn func(Config)
-
-// RunOnConfigChange - run callback functions when config is changed
-func RunOnConfigChange(ctx context.Context, log *zap.SugaredLogger, path string, callbacks ...CallbackFn) {
- log.Info("config notifier started")
-
- for {
- // wait 1 sec not to burn out the container for example when any method below always ends with an error
- time.Sleep(notificationDelay)
-
- err := fireCallbacksOnConfigChange(ctx, log, path, callbacks...)
- if err != nil && errors.Is(err, context.Canceled) {
- log.Info("context canceled")
- return
- }
- if err != nil {
- log.Error(err)
- }
- }
-}
-
-func fireCallbacksOnConfigChange(ctx context.Context, log *zap.SugaredLogger, path string, callbacks ...CallbackFn) error {
- err := file.NotifyModification(ctx, path)
- if err != nil {
- return err
- }
-
- log.Info("config file change detected")
-
- cfg, err := LoadLogConfig(path)
- if err != nil {
- return err
- }
-
- log.Debugf("firing '%d' callbacks", len(callbacks))
-
- fireCallbacks(cfg, callbacks...)
- return nil
-}
-
-func fireCallbacks(cfg Config, funcs ...CallbackFn) {
- for i := range funcs {
- fn := funcs[i]
- fn(cfg)
- }
-}
diff --git a/components/serverless/internal/config/file_test.go b/components/serverless/internal/config/file_test.go
deleted file mode 100644
index 9f7791b35..000000000
--- a/components/serverless/internal/config/file_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package config
-
-import (
- "context"
- "os"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "go.uber.org/zap"
- "gopkg.in/yaml.v2"
-)
-
-func TestRunOnConfigChange(t *testing.T) {
- t.Run("run on config change and cancel context", func(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- cfgFile := fixConfig(t)
- defer os.Remove(cfgFile.Name())
-
- callbackChan := make(chan bool)
- done := make(chan bool)
- go func() {
- RunOnConfigChange(ctx, zap.NewNop().Sugar(), cfgFile.Name(), func(c Config) {
- callbackChan <- true
- })
-
- done <- true
- }()
-
- quitChan := modifyFileEveryTick(t, cfgFile, 500*time.Millisecond)
-
- assert.Equal(t, true, <-callbackChan)
-
- quitChan <- true
- cancel()
-
- assert.Equal(t, true, <-done)
- })
-}
-
-func modifyFileEveryTick(t *testing.T, file *os.File, interval time.Duration) chan interface{} {
- ticker := time.NewTicker(interval)
-
- quit := make(chan interface{})
- go func() {
- for {
- select {
- case <-ticker.C:
- err := os.WriteFile(file.Name(), []byte("{}"), 0o644)
- assert.NoError(t, err)
- case <-quit:
- ticker.Stop()
- return
- }
- }
- }()
-
- return quit
-}
-
-func fixConfig(t *testing.T) *os.File {
- file, err := os.CreateTemp(os.TempDir(), "test-*")
- assert.NoError(t, err)
-
- bytes, err := yaml.Marshal(&Config{
- LogLevel: "debug",
- LogFormat: "json",
- })
- assert.NoError(t, err)
-
- _, err = file.Write(bytes)
- assert.NoError(t, err)
-
- return file
-}
diff --git a/components/serverless/internal/config/log.go b/components/serverless/internal/config/log.go
deleted file mode 100644
index c4b327b9b..000000000
--- a/components/serverless/internal/config/log.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package config
-
-import (
- "gopkg.in/yaml.v2"
- "os"
- "path/filepath"
-)
-
-type Config struct {
- LogLevel string `yaml:"logLevel"`
- LogFormat string `yaml:"logFormat"`
-}
-
-// LoadLogConfig - return cfg struct based on given path
-func LoadLogConfig(path string) (Config, error) {
- cfg := Config{}
-
- cleanPath := filepath.Clean(path)
- yamlFile, err := os.ReadFile(cleanPath)
- if err != nil {
- return cfg, err
- }
-
- err = yaml.Unmarshal(yamlFile, &cfg)
- return cfg, err
-}
diff --git a/components/serverless/internal/controllers/kubernetes/configmap_controller.go b/components/serverless/internal/controllers/kubernetes/configmap_controller.go
deleted file mode 100644
index 1bcff7788..000000000
--- a/components/serverless/internal/controllers/kubernetes/configmap_controller.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package kubernetes
-
-import (
- "context"
-
- "go.uber.org/zap"
-
- corev1 "k8s.io/api/core/v1"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/event"
- "sigs.k8s.io/controller-runtime/pkg/predicate"
-)
-
-type ConfigMapReconciler struct {
- Log *zap.SugaredLogger
- client client.Client
- config Config
- svc ConfigMapService
-}
-
-func NewConfigMap(client client.Client, log *zap.SugaredLogger, config Config, service ConfigMapService) *ConfigMapReconciler {
- return &ConfigMapReconciler{
- client: client,
- Log: log,
- config: config,
- svc: service,
- }
-}
-
-func (r *ConfigMapReconciler) SetupWithManager(mgr ctrl.Manager) error {
- return ctrl.NewControllerManagedBy(mgr).
- Named("configmap-controller").
- For(&corev1.ConfigMap{}).
- WithEventFilter(r.predicate()).
- Complete(r)
-}
-
-func (r *ConfigMapReconciler) predicate() predicate.Predicate {
- return predicate.Funcs{
- CreateFunc: func(e event.CreateEvent) bool {
- runtime, ok := e.Object.(*corev1.ConfigMap)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- UpdateFunc: func(e event.UpdateEvent) bool {
- runtime, ok := e.ObjectNew.(*corev1.ConfigMap)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- GenericFunc: func(e event.GenericEvent) bool {
- runtime, ok := e.Object.(*corev1.ConfigMap)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- DeleteFunc: func(e event.DeleteEvent) bool {
- return false
- },
- }
-}
-
-// Reconcile reads that state of the cluster for a ConfigMap object and makes changes based
-// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;patch;delete
-// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
-
-func (r *ConfigMapReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
- instance := &corev1.ConfigMap{}
- if err := r.client.Get(ctx, request.NamespacedName, instance); err != nil {
- return ctrl.Result{}, client.IgnoreNotFound(err)
- }
- r.client.Status()
-
- logger := r.Log.With("namespace", instance.GetNamespace(), "name", instance.GetName())
-
- namespaces, err := getNamespaces(ctx, r.client, r.config.BaseNamespace, r.config.ExcludedNamespaces)
- if err != nil {
- return ctrl.Result{}, err
- }
-
- for _, namespace := range namespaces {
- if err = r.svc.UpdateNamespace(ctx, logger, namespace, instance); err != nil {
- return ctrl.Result{}, err
- }
- }
-
- return ctrl.Result{RequeueAfter: r.config.ConfigMapRequeueDuration}, nil
-}
diff --git a/components/serverless/internal/controllers/kubernetes/configmap_controller_test.go b/components/serverless/internal/controllers/kubernetes/configmap_controller_test.go
deleted file mode 100644
index 055901af2..000000000
--- a/components/serverless/internal/controllers/kubernetes/configmap_controller_test.go
+++ /dev/null
@@ -1,156 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "github.com/kyma-project/serverless/components/serverless/internal/testenv"
- "testing"
-
- "go.uber.org/zap"
-
- "k8s.io/client-go/kubernetes/scheme"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/internal/resource/automock"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func TestConfigMapReconciler_Reconcile(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
- resourceClient := resource.New(k8sClient, scheme.Scheme)
- testCfg := setUpControllerConfig(g)
- configMapSvc := NewConfigMapService(resourceClient, testCfg)
-
- baseNamespace := newFixNamespace(testCfg.BaseNamespace)
- g.Expect(k8sClient.Create(context.TODO(), baseNamespace)).To(gomega.Succeed())
-
- userNamespace := newFixNamespace("tam")
- g.Expect(k8sClient.Create(context.TODO(), userNamespace)).To(gomega.Succeed())
-
- baseConfigMap := newFixBaseConfigMap(testCfg.BaseNamespace, "ah-tak-przeciez")
- g.Expect(k8sClient.Create(context.TODO(), baseConfigMap)).To(gomega.Succeed())
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: baseConfigMap.GetNamespace(), Name: baseConfigMap.GetName()}}
- reconciler := NewConfigMap(k8sClient, zap.NewNop().Sugar(), testCfg, configMapSvc)
- namespace := userNamespace.GetName()
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- //WHEN
- t.Log("reconciling ConfigMap that doesn't exist")
- _, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Namespace: baseConfigMap.GetNamespace(), Name: "not-existing-cm"}})
- g.Expect(err).To(gomega.BeNil(), "should not throw error on non existing configmap")
-
- t.Log("reconciling the ConfigMap")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ConfigMapRequeueDuration))
-
- configMap := &corev1.ConfigMap{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseConfigMap.GetName()}, configMap)).To(gomega.Succeed())
- compareConfigMaps(g, configMap, baseConfigMap)
-
- t.Log("updating the base ConfigMap")
- cmCopy := baseConfigMap.DeepCopy()
- cmCopy.Labels["test"] = "value"
- cmCopy.Data["test123"] = "321tset"
- g.Expect(k8sClient.Update(context.TODO(), cmCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ConfigMapRequeueDuration))
-
- configMap = &corev1.ConfigMap{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseConfigMap.GetName()}, configMap)).To(gomega.Succeed())
- compareConfigMaps(g, configMap, cmCopy)
-
- t.Log("updating the modified ConfigMap in user namespace")
- userCopy := configMap.DeepCopy()
- userCopy.Data["4213"] = "142343"
- g.Expect(k8sClient.Update(context.TODO(), userCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ConfigMapRequeueDuration))
-
- configMap = &corev1.ConfigMap{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseConfigMap.GetName()}, configMap)).To(gomega.Succeed())
- compareConfigMaps(g, configMap, cmCopy)
-}
-
-func TestConfigMapReconciler_predicate(t *testing.T) {
- baseNs := "base_ns"
-
- r := &ConfigMapReconciler{svc: NewConfigMapService(resource.New(&automock.K8sClient{}, runtime.NewScheme()), Config{BaseNamespace: baseNs})}
- preds := r.predicate()
-
- correctMeta := metav1.ObjectMeta{
- Namespace: baseNs,
- Labels: map[string]string{ConfigLabel: RuntimeLabelValue},
- }
-
- pod := &corev1.Pod{ObjectMeta: correctMeta}
- labelledConfigmap := &corev1.ConfigMap{ObjectMeta: correctMeta}
- unlabelledConfigMap := &corev1.ConfigMap{}
-
- t.Run("deleteFunc", func(t *testing.T) {
- g := gomega.NewWithT(t)
- deleteEventPod := event.DeleteEvent{Object: pod}
- deleteEventPod.Object = pod
- deleteEventLabelledSrvAcc := event.DeleteEvent{Object: labelledConfigmap}
- deleteEventUnlabelledSrvAcc := event.DeleteEvent{Object: unlabelledConfigMap}
-
- g.Expect(preds.Delete(deleteEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Delete(deleteEventLabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Delete(deleteEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Delete(event.DeleteEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("createFunc", func(t *testing.T) {
- g := gomega.NewWithT(t)
- createEventPod := event.CreateEvent{Object: pod}
- createEventLabelledSrvAcc := event.CreateEvent{Object: labelledConfigmap}
- createEventUnlabelledSrvAcc := event.CreateEvent{Object: unlabelledConfigMap}
-
- g.Expect(preds.Create(createEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Create(createEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Create(createEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Create(event.CreateEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("genericFunc", func(t *testing.T) {
- g := gomega.NewWithT(t)
- genericEventPod := event.GenericEvent{Object: pod}
- genericEventLabelledSrvAcc := event.GenericEvent{Object: labelledConfigmap}
- genericEventUnlabelledSrvAcc := event.GenericEvent{Object: unlabelledConfigMap}
-
- g.Expect(preds.Generic(genericEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Generic(genericEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Generic(genericEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Generic(event.GenericEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("updateFunc", func(t *testing.T) {
- g := gomega.NewWithT(t)
- updateEventPod := event.UpdateEvent{ObjectNew: pod}
- updateEventLabelledSrvAcc := event.UpdateEvent{ObjectNew: labelledConfigmap}
- updateEventUnlabelledSrvAcc := event.UpdateEvent{ObjectNew: unlabelledConfigMap}
-
- g.Expect(preds.Update(updateEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Update(updateEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Update(updateEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Update(event.UpdateEvent{})).To(gomega.BeFalse())
- })
-}
diff --git a/components/serverless/internal/controllers/kubernetes/configmap_service_test.go b/components/serverless/internal/controllers/kubernetes/configmap_service_test.go
deleted file mode 100644
index 9cca42d00..000000000
--- a/components/serverless/internal/controllers/kubernetes/configmap_service_test.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package kubernetes
-
-import (
- "testing"
-
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_configMapService_IsBase(t *testing.T) {
- baseNs := "base-ns"
-
- type args struct {
- configmap *corev1.ConfigMap
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should correctly return if ConfigMap is base one",
- args: args{configmap: &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs, Labels: map[string]string{
- ConfigLabel: RuntimeLabelValue,
- }},
- }},
- want: true,
- },
- {
- name: "should correctly return false for ConfigMap in wrong ns",
- args: args{configmap: &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{Namespace: "not-base-ns", Labels: map[string]string{
- ConfigLabel: RuntimeLabelValue,
- }},
- }},
- want: false,
- },
- {
- name: "should correctly return false for ConfigMap has wrong label value",
- args: args{configmap: &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs, Labels: map[string]string{
- ConfigLabel: "some-random-value",
- }},
- }},
- want: false,
- },
- {
- name: "should correctly return false for ConfigMap with no labels",
- args: args{configmap: &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs},
- }},
- want: false,
- },
- {
- name: "should correctly return false for ConfigMap with no labels and in wrong namespace",
- args: args{configmap: &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{Namespace: "not-base"},
- }},
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r := &configMapService{
- config: Config{
- BaseNamespace: baseNs,
- },
- }
- if got := r.IsBase(tt.args.configmap); got != tt.want {
- t.Errorf("IsBase() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/components/serverless/internal/controllers/kubernetes/fixtures_test.go b/components/serverless/internal/controllers/kubernetes/fixtures_test.go
deleted file mode 100644
index 13df9b6dc..000000000
--- a/components/serverless/internal/controllers/kubernetes/fixtures_test.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "fmt"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-func newFixBaseConfigMap(namespace, name string) *corev1.ConfigMap {
- return &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-", name),
- Namespace: namespace,
- Labels: map[string]string{ConfigLabel: RuntimeLabelValue},
- },
- Data: map[string]string{"test_1": "value_!", "test_2": "value_2"},
- BinaryData: map[string][]byte{"test_1_b": []byte("value"), "test_2_b": []byte("value_2")},
- }
-}
-
-func newFixBaseSecret(namespace, name string) *corev1.Secret {
- return &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- Labels: map[string]string{ConfigLabel: CredentialsLabelValue},
- },
- Data: map[string][]byte{"key_1_b": []byte("value_1_b"), "key_2_b": []byte("value_2_b")},
- StringData: map[string]string{"key_1": "value_1", "key_2": "value_2"},
- Type: "test",
- }
-}
-
-func newFixBaseSecretWithManagedLabel(namespace, name string) *corev1.Secret {
- return &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-", name),
- Namespace: namespace,
- Labels: map[string]string{ConfigLabel: CredentialsLabelValue, v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionResourceLabelUserValue},
- },
- Data: map[string][]byte{"key_1_b": []byte("value_1_b"), "key_2_b": []byte("value_2_b")},
- StringData: map[string]string{"key_1": "value_1", "key_2": "value_2"},
- Type: "test",
- }
-}
-
-func newFixBaseServiceAccount(namespace, name string) *corev1.ServiceAccount {
- falseValue := false
- return &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-", name),
- Namespace: namespace,
- Labels: map[string]string{ConfigLabel: ServiceAccountLabelValue},
- },
- Secrets: []corev1.ObjectReference{{Name: "test1"}, {Name: "test2"}},
- ImagePullSecrets: []corev1.LocalObjectReference{{Name: "test-ips-1"}, {Name: "test-ips-2"}},
- AutomountServiceAccountToken: &falseValue,
- }
-}
-
-func newFixNamespace(name string) *corev1.Namespace {
- return &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- },
- }
-}
-
-func createSecret(g *gomega.WithT, resourceClient resource.Client, secret *corev1.Secret) {
- g.Expect(resourceClient.Create(context.TODO(), secret)).To(gomega.Succeed())
-}
-
-func deleteSecret(g *gomega.WithT, k8sClient client.Client, secret *corev1.Secret) {
- g.Expect(k8sClient.Delete(context.TODO(), secret)).To(gomega.Succeed())
-}
diff --git a/components/serverless/internal/controllers/kubernetes/helpers_test.go b/components/serverless/internal/controllers/kubernetes/helpers_test.go
deleted file mode 100644
index 1dafa7c3d..000000000
--- a/components/serverless/internal/controllers/kubernetes/helpers_test.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package kubernetes
-
-import (
- "github.com/onsi/gomega"
- "github.com/vrischmann/envconfig"
- corev1 "k8s.io/api/core/v1"
-)
-
-func setUpControllerConfig(g *gomega.GomegaWithT) Config {
- var testCfg Config
- err := envconfig.InitWithPrefix(&testCfg, "TEST")
- g.Expect(err).To(gomega.BeNil())
- return testCfg
-}
-
-func compareConfigMaps(g *gomega.WithT, actual, expected *corev1.ConfigMap) {
- g.Expect(actual.GetLabels()).To(gomega.Equal(expected.GetLabels()))
- g.Expect(actual.GetAnnotations()).To(gomega.Equal(expected.GetAnnotations()))
- g.Expect(actual.Data).To(gomega.Equal(expected.Data))
- g.Expect(actual.BinaryData).To(gomega.Equal(expected.BinaryData))
-}
-
-func compareSecrets(g *gomega.WithT, actual, expected *corev1.Secret) {
- g.Expect(actual.GetLabels()).To(gomega.Equal(expected.GetLabels()))
- g.Expect(actual.GetAnnotations()).To(gomega.Equal(expected.GetAnnotations()))
- g.Expect(actual.Data).To(gomega.Equal(expected.Data))
-}
-
-func compareServiceAccounts(g *gomega.WithT, actual, expected *corev1.ServiceAccount) {
- g.Expect(actual.GetLabels()).To(gomega.Equal(expected.GetLabels()))
- g.Expect(actual.GetAnnotations()).To(gomega.Equal(expected.GetAnnotations()))
- g.Expect(actual.Secrets).To(gomega.Equal(expected.Secrets))
- g.Expect(actual.ImagePullSecrets).To(gomega.Equal(expected.ImagePullSecrets))
- g.Expect(actual.AutomountServiceAccountToken).To(gomega.Equal(expected.AutomountServiceAccountToken))
-}
diff --git a/components/serverless/internal/controllers/kubernetes/namespace_controller_test.go b/components/serverless/internal/controllers/kubernetes/namespace_controller_test.go
deleted file mode 100644
index 4f87fc09f..000000000
--- a/components/serverless/internal/controllers/kubernetes/namespace_controller_test.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "github.com/kyma-project/serverless/components/serverless/internal/testenv"
- "testing"
- "time"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "k8s.io/client-go/kubernetes/scheme"
-
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func TestNamespaceReconciler_Reconcile(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
- resourceClient := resource.New(k8sClient, scheme.Scheme)
- testCfg := setUpControllerConfig(g)
-
- configMapSvc := NewConfigMapService(resourceClient, testCfg)
- secretSvc := NewSecretService(resourceClient, testCfg)
- serviceAccountSvc := NewServiceAccountService(resourceClient, testCfg)
-
- cfgNamespace := newFixNamespace(testCfg.BaseNamespace)
- g.Expect(k8sClient.Create(context.TODO(), cfgNamespace)).To(gomega.Succeed())
-
- userNamespace := newFixNamespace("tam")
- g.Expect(k8sClient.Create(context.TODO(), userNamespace)).To(gomega.Succeed())
-
- baseConfigMap := newFixBaseConfigMap(testCfg.BaseNamespace, "ah-tak-przeciez")
- g.Expect(k8sClient.Create(context.TODO(), baseConfigMap)).To(gomega.Succeed())
-
- baseSecret := newFixBaseSecret(testCfg.BaseNamespace, testCfg.BaseDefaultSecretName)
- g.Expect(k8sClient.Create(context.TODO(), baseSecret)).To(gomega.Succeed())
-
- baseServiceAccount := newFixBaseServiceAccount(testCfg.BaseNamespace, "ah-tak-przeciez")
- g.Expect(k8sClient.Create(context.TODO(), baseServiceAccount)).To(gomega.Succeed())
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Name: userNamespace.GetName()}}
- reconciler := NewNamespace(k8sClient, zap.NewNop().Sugar(), testCfg, configMapSvc, secretSvc, serviceAccountSvc)
- namespace := userNamespace.GetName()
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- //WHEN
- t.Log("reconciling Namespace that doesn't exist")
- _, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Name: "not-existing-ns"}})
- g.Expect(err).To(gomega.BeNil(), "should not throw error on non existing namespace")
-
- t.Log("reconciling the Namespace")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(0 * time.Second))
-
- configMap := &corev1.ConfigMap{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseConfigMap.GetName()}, configMap)).To(gomega.Succeed())
- compareConfigMaps(g, configMap, baseConfigMap)
-
- secret := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, baseSecret)
-
- serviceAccount := &corev1.ServiceAccount{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseServiceAccount.GetName()}, serviceAccount)).To(gomega.Succeed())
- compareServiceAccounts(g, serviceAccount, baseServiceAccount)
-
- t.Log("one more time reconciling the Namespace")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(0 * time.Second))
-
- configMap = &corev1.ConfigMap{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseConfigMap.GetName()}, configMap)).To(gomega.Succeed())
- compareConfigMaps(g, configMap, baseConfigMap)
-
- secret = &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, baseSecret)
-
- serviceAccount = &corev1.ServiceAccount{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseServiceAccount.GetName()}, serviceAccount)).To(gomega.Succeed())
- compareServiceAccounts(g, serviceAccount, baseServiceAccount)
-}
-
-func TestNamespaceReconciler_predicate(t *testing.T) {
- baseNs := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "base-ns"}}
- excludedNs := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "excluded-1"}}
- normalNs := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "normal-1"}}
- pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod-name"}}
-
- r := &NamespaceReconciler{config: Config{
- BaseNamespace: baseNs.Name,
- ExcludedNamespaces: []string{excludedNs.Name},
- }}
- preds := r.predicate()
-
- t.Run("deleteFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.DeleteEvent{Object: pod}
- eventBaseNs := event.DeleteEvent{Object: baseNs}
- eventExcludedNs := event.DeleteEvent{Object: excludedNs}
- normalNsEvent := event.DeleteEvent{Object: normalNs}
-
- g.Expect(preds.Delete(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Delete(eventBaseNs)).To(gomega.BeFalse())
- g.Expect(preds.Delete(eventExcludedNs)).To(gomega.BeFalse())
- g.Expect(preds.Delete(normalNsEvent)).To(gomega.BeFalse())
- g.Expect(preds.Delete(event.DeleteEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("createFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.CreateEvent{Object: pod}
- eventBaseNs := event.CreateEvent{Object: baseNs}
- eventExcludedNs := event.CreateEvent{Object: excludedNs}
- normalNsEvent := event.CreateEvent{Object: normalNs}
-
- g.Expect(preds.Create(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Create(eventBaseNs)).To(gomega.BeFalse())
- g.Expect(preds.Create(eventExcludedNs)).To(gomega.BeFalse())
- g.Expect(preds.Create(event.CreateEvent{})).To(gomega.BeFalse())
-
- g.Expect(preds.Create(normalNsEvent)).To(gomega.BeTrue(), "should be true for non-base, non-excluded ns")
- })
-
- t.Run("genericFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.GenericEvent{Object: pod}
- eventBaseNs := event.GenericEvent{Object: baseNs}
- eventExcludedNs := event.GenericEvent{Object: excludedNs}
- normalNsEvent := event.GenericEvent{Object: normalNs}
-
- g.Expect(preds.Generic(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Generic(eventBaseNs)).To(gomega.BeFalse())
- g.Expect(preds.Generic(eventExcludedNs)).To(gomega.BeFalse())
- g.Expect(preds.Generic(event.GenericEvent{})).To(gomega.BeFalse())
- g.Expect(preds.Generic(normalNsEvent)).To(gomega.BeFalse())
- })
-
- t.Run("updateFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.UpdateEvent{ObjectNew: pod}
- eventBaseNs := event.UpdateEvent{ObjectNew: baseNs}
- eventExcludedNs := event.UpdateEvent{ObjectNew: excludedNs}
- normalNsEvent := event.UpdateEvent{ObjectNew: normalNs}
-
- g.Expect(preds.Update(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Update(eventBaseNs)).To(gomega.BeFalse())
- g.Expect(preds.Update(eventExcludedNs)).To(gomega.BeFalse())
- g.Expect(preds.Update(event.UpdateEvent{})).To(gomega.BeFalse())
- g.Expect(preds.Update(normalNsEvent)).To(gomega.BeFalse())
- })
-}
diff --git a/components/serverless/internal/controllers/kubernetes/secret_controller_test.go b/components/serverless/internal/controllers/kubernetes/secret_controller_test.go
deleted file mode 100644
index a3af6da03..000000000
--- a/components/serverless/internal/controllers/kubernetes/secret_controller_test.go
+++ /dev/null
@@ -1,276 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "github.com/kyma-project/serverless/components/serverless/internal/testenv"
- "testing"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "k8s.io/client-go/kubernetes/scheme"
-
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func TestSecretReconciler_Reconcile(t *testing.T) {
- t.Parallel()
- g := gomega.NewGomegaWithT(t)
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
- resourceClient := resource.New(k8sClient, scheme.Scheme)
- testCfg := setUpControllerConfig(g)
-
- baseNamespace := newFixNamespace(testCfg.BaseNamespace)
- g.Expect(k8sClient.Create(context.TODO(), baseNamespace)).To(gomega.Succeed())
-
- userNamespace := newFixNamespace("tam")
- g.Expect(resourceClient.Create(context.TODO(), userNamespace)).To(gomega.Succeed())
-
- secretSvc := NewSecretService(resourceClient, testCfg)
- reconciler := NewSecret(k8sClient, zap.NewNop().Sugar(), testCfg, secretSvc)
-
- namespace := userNamespace.GetName()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("should successfully propagate base Secret to user namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- t.Log("reconciling non-existing secret")
- baseSecret := newFixBaseSecret(testCfg.BaseNamespace, "successful-propagation")
- createSecret(g, resourceClient, baseSecret)
- defer deleteSecret(g, k8sClient, baseSecret)
- _, err := reconciler.Reconcile(ctx, ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: baseSecret.GetNamespace(),
- Name: "not-existing-secret",
- },
- })
- g.Expect(err).To(gomega.BeNil())
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: testCfg.BaseNamespace, Name: baseSecret.GetName()}}
-
- //WHEN
- t.Log("reconciling the Secret")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- updatedBase := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: baseSecret.GetNamespace(), Name: baseSecret.GetName()}, updatedBase)).To(gomega.Succeed())
- g.Expect(updatedBase.Finalizers).To(gomega.ContainElement(cfgSecretFinalizerName), "created base secret should have finalizer applied")
- secret := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, baseSecret)
-
- t.Log("updating the base Secret")
- updateBaseSecretCopy := updatedBase.DeepCopy()
- updateBaseSecretCopy.Labels["test"] = "value"
- updateBaseSecretCopy.Data["test123"] = []byte("321tset")
- g.Expect(k8sClient.Update(context.TODO(), updateBaseSecretCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- secret = &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, updateBaseSecretCopy)
-
- t.Log("updating the modified Secret in user namespace")
- userCopy := secret.DeepCopy()
- userCopy.Data["test123"] = []byte("321tset")
- g.Expect(k8sClient.Update(context.TODO(), userCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- secret = &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, updateBaseSecretCopy)
- })
-
- t.Run("should not successfully propagate Secret managed by user to user namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- t.Log("reconciling non-existing secret")
-
- baseSecretWithManagedLabel := newFixBaseSecretWithManagedLabel(testCfg.BaseNamespace, "secret-with-managed-label")
- g.Expect(resourceClient.Create(context.TODO(), baseSecretWithManagedLabel)).To(gomega.Succeed())
- requestForSecretWithManagedLabel := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: baseSecretWithManagedLabel.GetNamespace(), Name: baseSecretWithManagedLabel.GetName()}}
-
- baseSecret := newFixBaseSecret(testCfg.BaseNamespace, "unsuccessful-propagation")
- createSecret(g, resourceClient, baseSecret)
- defer deleteSecret(g, k8sClient, baseSecret)
- _, err := reconciler.Reconcile(ctx, ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: baseSecretWithManagedLabel.GetNamespace(),
- Name: "not-existing-secret",
- },
- })
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("reconciling the Secret")
- result, err := reconciler.Reconcile(ctx, requestForSecretWithManagedLabel)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- updatedBase := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: baseSecretWithManagedLabel.GetNamespace(), Name: baseSecretWithManagedLabel.GetName()}, updatedBase)).To(gomega.Succeed())
- secret := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecretWithManagedLabel.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, updatedBase)
-
- t.Log("updating the base Secret")
- updateBaseSecretCopy := updatedBase.DeepCopy()
- updateBaseSecretCopy.Data["test123"] = []byte("321tset")
- g.Expect(k8sClient.Update(context.TODO(), updateBaseSecretCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, requestForSecretWithManagedLabel)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- secret = &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecretWithManagedLabel.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, updatedBase)
- })
-
- t.Run("should successfully delete propagated Secrets from user namespace when base Secret is deleted", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- t.Log("reconciling the Secret")
- baseSecret := newFixBaseSecret(testCfg.BaseNamespace, "successful-deletion")
- createSecret(g, resourceClient, baseSecret)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: testCfg.BaseNamespace, Name: baseSecret.GetName()}}
-
- //WHEN
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- updatedBase := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: baseSecret.GetNamespace(), Name: baseSecret.GetName()}, updatedBase)).To(gomega.Succeed())
- g.Expect(updatedBase.Finalizers).To(gomega.ContainElement(cfgSecretFinalizerName), "created base secret should have finalizer applied")
- secret := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecret.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, baseSecret)
-
- t.Log("deleting base Secret")
- g.Expect(k8sClient.Delete(context.TODO(), updatedBase)).To(gomega.Succeed())
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.BeZero())
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: updatedBase.GetNamespace(), Name: updatedBase.GetName()}, updatedBase)).To(gomega.HaveOccurred())
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: secret.GetNamespace(), Name: secret.GetName()}, secret)).To(gomega.HaveOccurred())
- })
-
- t.Run("should not successfully delete propagated Secrets from user namespace managed by user when base Secret is deleted", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- t.Log("reconciling the Secret")
- baseSecret := newFixBaseSecret(testCfg.BaseNamespace, "unsuccessful-deletion")
- createSecret(g, resourceClient, baseSecret)
- defer deleteSecret(g, k8sClient, baseSecret)
-
- baseSecretWithManagedLabel := newFixBaseSecretWithManagedLabel(testCfg.BaseNamespace, "secret-with-managed-label")
- g.Expect(resourceClient.Create(context.TODO(), baseSecretWithManagedLabel)).To(gomega.Succeed())
- requestForSecretWithManagedLabel := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: baseSecretWithManagedLabel.GetNamespace(), Name: baseSecretWithManagedLabel.GetName()}}
-
- result, err := reconciler.Reconcile(ctx, requestForSecretWithManagedLabel)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.SecretRequeueDuration))
-
- updatedBase := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: baseSecretWithManagedLabel.GetNamespace(), Name: baseSecretWithManagedLabel.GetName()}, updatedBase)).To(gomega.Succeed())
- secret := &corev1.Secret{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseSecretWithManagedLabel.GetName()}, secret)).To(gomega.Succeed())
- compareSecrets(g, secret, updatedBase)
-
- t.Log("deleting base Secret")
- g.Expect(k8sClient.Delete(context.TODO(), updatedBase)).To(gomega.Succeed())
- result, err = reconciler.Reconcile(ctx, requestForSecretWithManagedLabel)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.BeZero())
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: updatedBase.GetNamespace(), Name: updatedBase.GetName()}, updatedBase)).To(gomega.HaveOccurred())
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: secret.GetNamespace(), Name: secret.GetName()}, secret)).To(gomega.Succeed())
- })
-}
-
-func TestSecretReconciler_predicate(t *testing.T) {
- baseSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: "base-ns", Labels: map[string]string{ConfigLabel: CredentialsLabelValue}}}
- nonBaseSecret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{Namespace: "some-other-ns"}}
- pod := &corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod-name"}}
-
- r := &SecretReconciler{svc: &secretService{
- config: Config{
- BaseNamespace: "base-ns",
- },
- }}
- preds := r.predicate()
-
- t.Run("deleteFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.DeleteEvent{Object: pod}
- eventBaseSecret := event.DeleteEvent{Object: baseSecret}
- eventNonBaseSecret := event.DeleteEvent{Object: nonBaseSecret}
-
- g.Expect(preds.Delete(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Delete(eventBaseSecret)).To(gomega.BeTrue(), "should be true for base secret")
- g.Expect(preds.Delete(eventNonBaseSecret)).To(gomega.BeFalse())
- g.Expect(preds.Delete(event.DeleteEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("createFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.CreateEvent{Object: pod}
- eventBaseSecret := event.CreateEvent{Object: baseSecret}
- eventNonBaseSecret := event.CreateEvent{Object: nonBaseSecret}
-
- g.Expect(preds.Create(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Create(eventNonBaseSecret)).To(gomega.BeFalse())
- g.Expect(preds.Create(event.CreateEvent{})).To(gomega.BeFalse())
-
- g.Expect(preds.Create(eventBaseSecret)).To(gomega.BeTrue(), "should be true for base secret")
- })
-
- t.Run("genericFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.GenericEvent{Object: pod}
- eventBaseSecret := event.GenericEvent{Object: baseSecret}
- eventNonBaseSecret := event.GenericEvent{Object: nonBaseSecret}
-
- g.Expect(preds.Generic(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Generic(eventNonBaseSecret)).To(gomega.BeFalse())
- g.Expect(preds.Generic(event.GenericEvent{})).To(gomega.BeFalse())
-
- g.Expect(preds.Generic(eventBaseSecret)).To(gomega.BeTrue(), "should be true for base secret")
- })
-
- t.Run("updateFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- podEvent := event.UpdateEvent{ObjectNew: pod}
- eventBaseSecret := event.UpdateEvent{ObjectNew: baseSecret}
- eventNonBaseSecret := event.UpdateEvent{ObjectNew: nonBaseSecret}
-
- g.Expect(preds.Update(podEvent)).To(gomega.BeFalse())
- g.Expect(preds.Update(eventNonBaseSecret)).To(gomega.BeFalse())
- g.Expect(preds.Update(event.UpdateEvent{})).To(gomega.BeFalse())
-
- g.Expect(preds.Update(eventBaseSecret)).To(gomega.BeTrue(), "should be true for base secret")
- })
-}
diff --git a/components/serverless/internal/controllers/kubernetes/secret_service_test.go b/components/serverless/internal/controllers/kubernetes/secret_service_test.go
deleted file mode 100644
index 6d13ab7ba..000000000
--- a/components/serverless/internal/controllers/kubernetes/secret_service_test.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package kubernetes
-
-import (
- "testing"
-
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_secretService_IsBase(t *testing.T) {
- baseNs := "base-ns"
- baseSecretName := "base-name"
-
- tests := []struct {
- name string
-
- secret *corev1.Secret
- want bool
- }{
- {
- name: "should properly detect base secret",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: baseSecretName,
- Namespace: baseNs,
- Labels: map[string]string{
- ConfigLabel: CredentialsLabelValue,
- }},
- },
- want: true,
- },
- {
- name: "should return false for secret without needed labels",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: baseNs,
- }},
- want: false,
- },
- {
- name: "should return false for secret in wrong namespace",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: baseSecretName,
- Namespace: "some-other-ns",
- Labels: map[string]string{
- ConfigLabel: CredentialsLabelValue,
- }},
- },
- want: false,
- },
- {
- name: "should return false for secret in some other namespace and with no labels",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: baseSecretName,
- Namespace: "blabla-other-ns",
- }},
- want: false,
- },
- {
- name: "should return false for secret with wrong label value",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: baseSecretName,
- Namespace: baseNs,
- Labels: map[string]string{
- ConfigLabel: "wrong-label-value",
- }},
- },
- want: false,
- },
- {
- name: "should return false for secret with wrong label key",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: baseNs,
- Labels: map[string]string{
- "some-weird-label-key": CredentialsLabelValue,
- }},
- },
- want: false,
- },
- {
- name: "should return false for secret with wrong name",
- secret: &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "wrong-name",
- Namespace: baseNs,
- Labels: map[string]string{
- ConfigLabel: CredentialsLabelValue,
- }},
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r := &secretService{
- config: Config{
- BaseNamespace: baseNs,
- BaseDefaultSecretName: baseSecretName,
- },
- }
- if got := r.IsBase(tt.secret); got != tt.want {
- t.Errorf("IsBase() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/components/serverless/internal/controllers/kubernetes/serviceaccount_controller.go b/components/serverless/internal/controllers/kubernetes/serviceaccount_controller.go
deleted file mode 100644
index 9cafea178..000000000
--- a/components/serverless/internal/controllers/kubernetes/serviceaccount_controller.go
+++ /dev/null
@@ -1,92 +0,0 @@
-package kubernetes
-
-import (
- "context"
-
- "go.uber.org/zap"
-
- corev1 "k8s.io/api/core/v1"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/event"
- "sigs.k8s.io/controller-runtime/pkg/predicate"
-)
-
-type ServiceAccountReconciler struct {
- Log *zap.SugaredLogger
- client client.Client
- svc ServiceAccountService
- config Config
-}
-
-func NewServiceAccount(client client.Client, log *zap.SugaredLogger, config Config, serviceAccountSvc ServiceAccountService) *ServiceAccountReconciler {
- return &ServiceAccountReconciler{
- client: client,
- Log: log,
- config: config,
- svc: serviceAccountSvc,
- }
-}
-
-func (r *ServiceAccountReconciler) SetupWithManager(mgr ctrl.Manager) error {
- return ctrl.NewControllerManagedBy(mgr).
- Named("serviceaccount-controller").
- For(&corev1.ServiceAccount{}).
- WithEventFilter(r.predicate()).
- Complete(r)
-}
-
-func (r *ServiceAccountReconciler) predicate() predicate.Predicate {
- return predicate.Funcs{
- CreateFunc: func(e event.CreateEvent) bool {
- runtime, ok := e.Object.(*corev1.ServiceAccount)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- UpdateFunc: func(e event.UpdateEvent) bool {
- runtime, ok := e.ObjectNew.(*corev1.ServiceAccount)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- GenericFunc: func(e event.GenericEvent) bool {
- runtime, ok := e.Object.(*corev1.ServiceAccount)
- if !ok {
- return false
- }
- return r.svc.IsBase(runtime)
- },
- DeleteFunc: func(e event.DeleteEvent) bool {
- return false
- },
- }
-}
-
-// Reconcile reads that state of the cluster for a ServiceAccount object and makes changes based
-// +kubebuilder:rbac:groups="",resources=serviceaccounts,verbs=get;list;watch;create;update;patch;delete
-// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch
-
-func (r *ServiceAccountReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
- instance := &corev1.ServiceAccount{}
- if err := r.client.Get(ctx, request.NamespacedName, instance); err != nil {
- return ctrl.Result{}, client.IgnoreNotFound(err)
- }
-
- logger := r.Log.With("namespace", instance.GetNamespace(), "name", instance.GetName())
-
- namespaces, err := getNamespaces(ctx, r.client, r.config.BaseNamespace, r.config.ExcludedNamespaces)
- if err != nil {
- return ctrl.Result{}, err
- }
-
- for _, namespace := range namespaces {
- if err = r.svc.UpdateNamespace(ctx, logger, namespace, instance); err != nil {
- return ctrl.Result{}, err
- }
- }
-
- return ctrl.Result{RequeueAfter: r.config.ServiceAccountRequeueDuration}, nil
-}
diff --git a/components/serverless/internal/controllers/kubernetes/serviceaccount_controller_test.go b/components/serverless/internal/controllers/kubernetes/serviceaccount_controller_test.go
deleted file mode 100644
index 0c3631a48..000000000
--- a/components/serverless/internal/controllers/kubernetes/serviceaccount_controller_test.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "github.com/kyma-project/serverless/components/serverless/internal/testenv"
- "testing"
-
- "go.uber.org/zap"
-
- "k8s.io/client-go/kubernetes/scheme"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/internal/resource/automock"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func TestServiceAccountReconciler_Reconcile(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
- resourceClient := resource.New(k8sClient, scheme.Scheme)
- testCfg := setUpControllerConfig(g)
- serviceAccountSvc := NewServiceAccountService(resourceClient, testCfg)
-
- baseNamespace := newFixNamespace(testCfg.BaseNamespace)
- g.Expect(k8sClient.Create(context.TODO(), baseNamespace)).To(gomega.Succeed())
-
- userNamespace := newFixNamespace("tam")
- g.Expect(resourceClient.Create(context.TODO(), userNamespace)).To(gomega.Succeed())
-
- baseServiceAccount := newFixBaseServiceAccount(testCfg.BaseNamespace, "ah-tak-przeciez")
- g.Expect(resourceClient.Create(context.TODO(), baseServiceAccount)).To(gomega.Succeed())
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: baseServiceAccount.GetNamespace(), Name: baseServiceAccount.GetName()}}
- reconciler := NewServiceAccount(k8sClient, zap.NewNop().Sugar(), testCfg, serviceAccountSvc)
- namespace := userNamespace.GetName()
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("should successfully propagate base ServiceAccount to user namespace", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- t.Log("reconciling the non existing Service Account")
- _, err := reconciler.Reconcile(ctx, ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: baseServiceAccount.GetNamespace(),
- Name: "non-existing-svc-acc",
- },
- })
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("reconciling the Service Account")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ServiceAccountRequeueDuration))
-
- serviceAccount := &corev1.ServiceAccount{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseServiceAccount.GetName()}, serviceAccount)).To(gomega.Succeed())
- compareServiceAccounts(g, serviceAccount, baseServiceAccount)
-
- t.Log("updating the base ServiceAccount")
- baseServiceAccountCopy := baseServiceAccount.DeepCopy()
- baseServiceAccountCopy.Labels["test"] = "value"
- baseServiceAccountCopy.AutomountServiceAccountToken = nil
- g.Expect(k8sClient.Update(context.TODO(), baseServiceAccountCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ServiceAccountRequeueDuration))
-
- serviceAccount = &corev1.ServiceAccount{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseServiceAccount.GetName()}, serviceAccount)).To(gomega.Succeed())
- compareServiceAccounts(g, serviceAccount, baseServiceAccountCopy)
-
- t.Log("updating the modified ServiceAccount in user namespace")
- userCopy := serviceAccount.DeepCopy()
- trueValue := true
- userCopy.AutomountServiceAccountToken = &trueValue
- g.Expect(k8sClient.Update(context.TODO(), userCopy)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(testCfg.ServiceAccountRequeueDuration))
-
- serviceAccount = &corev1.ServiceAccount{}
- g.Expect(k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: namespace, Name: baseServiceAccount.GetName()}, serviceAccount)).To(gomega.Succeed())
- compareServiceAccounts(g, serviceAccount, baseServiceAccountCopy)
- })
-}
-
-func TestServiceAccountReconciler_getPredicates(t *testing.T) {
- baseNs := "base_ns"
-
- r := &ServiceAccountReconciler{svc: NewServiceAccountService(resource.New(&automock.K8sClient{}, runtime.NewScheme()), Config{BaseNamespace: baseNs})}
- preds := r.predicate()
-
- correctMeta := metav1.ObjectMeta{
- Namespace: baseNs,
- Labels: map[string]string{ConfigLabel: ServiceAccountLabelValue},
- }
-
- pod := &corev1.Pod{ObjectMeta: correctMeta}
- labelledSrvAcc := &corev1.ServiceAccount{ObjectMeta: correctMeta}
- unlabelledSrvAcc := &corev1.ServiceAccount{}
-
- t.Run("deleteFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- deleteEventPod := event.DeleteEvent{Object: pod}
- deleteEventLabelledSrvAcc := event.DeleteEvent{Object: labelledSrvAcc}
- deleteEventUnlabelledSrvAcc := event.DeleteEvent{Object: unlabelledSrvAcc}
-
- g.Expect(preds.Delete(deleteEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Delete(deleteEventLabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Delete(deleteEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Delete(event.DeleteEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("createFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- createEventPod := event.CreateEvent{Object: pod}
- createEventLabelledSrvAcc := event.CreateEvent{Object: labelledSrvAcc}
- createEventUnlabelledSrvAcc := event.CreateEvent{Object: unlabelledSrvAcc}
-
- g.Expect(preds.Create(createEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Create(createEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Create(createEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Create(event.CreateEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("genericFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- genericEventPod := event.GenericEvent{Object: pod}
- genericEventLabelledSrvAcc := event.GenericEvent{Object: labelledSrvAcc}
- genericEventUnlabelledSrvAcc := event.GenericEvent{Object: unlabelledSrvAcc}
-
- g.Expect(preds.Generic(genericEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Generic(genericEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Generic(genericEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Generic(event.GenericEvent{})).To(gomega.BeFalse())
- })
-
- t.Run("updateFunc", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- updateEventPod := event.UpdateEvent{ObjectNew: pod}
- updateEventLabelledSrvAcc := event.UpdateEvent{ObjectNew: labelledSrvAcc}
- updateEventUnlabelledSrvAcc := event.UpdateEvent{ObjectNew: unlabelledSrvAcc}
-
- g.Expect(preds.Update(updateEventPod)).To(gomega.BeFalse())
- g.Expect(preds.Update(updateEventUnlabelledSrvAcc)).To(gomega.BeFalse())
- g.Expect(preds.Update(updateEventLabelledSrvAcc)).To(gomega.BeTrue())
- g.Expect(preds.Update(event.UpdateEvent{})).To(gomega.BeFalse())
- })
-}
diff --git a/components/serverless/internal/controllers/kubernetes/serviceaccount_service_test.go b/components/serverless/internal/controllers/kubernetes/serviceaccount_service_test.go
deleted file mode 100644
index b1776e3f3..000000000
--- a/components/serverless/internal/controllers/kubernetes/serviceaccount_service_test.go
+++ /dev/null
@@ -1,379 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "errors"
- "reflect"
- "testing"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/internal/resource/automock"
- "github.com/onsi/gomega"
- "github.com/stretchr/testify/mock"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_serviceAccountService_extractSecretTokens(t *testing.T) {
- type args struct {
- serviceAccount *corev1.ServiceAccount
- }
- tests := []struct {
- name string
- args args
- want []corev1.ObjectReference
- }{
- {
- name: "should return secret with the same prefix",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "test-name-token-123"}},
- }},
- want: []corev1.ObjectReference{{Name: "test-name-token-123"}},
- },
- {
- name: "should not return secret with improper prefix",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "super-secret-secret"}},
- }},
- want: []corev1.ObjectReference{},
- },
- {
- name: "should return multiple correct secrets",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "test-name-token-123-blah1"}, {Name: "test-name-token-123-blah2"}, {Name: "random-one"}},
- }},
- want: []corev1.ObjectReference{{Name: "test-name-token-123-blah1"}, {Name: "test-name-token-123-blah2"}},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- se := &serviceAccountService{}
- if got := se.extractSecretTokens(tt.args.serviceAccount); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("extractSecretTokens() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func Test_serviceAccountService_shiftSecretTokens(t *testing.T) {
- type args struct {
- serviceAccount *corev1.ServiceAccount
- }
- tests := []struct {
- name string
- args args
- want []corev1.ObjectReference
- }{
- {
- name: "should not return secret with the same prefix",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "test-name-token-123"}},
- }},
- want: []corev1.ObjectReference{},
- },
- {
- name: "should return secret with prefix that doesn't match",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "super-secret-secret"}},
- }},
- want: []corev1.ObjectReference{{Name: "super-secret-secret"}},
- },
-
- {
- name: "should return multiple correct secrets",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "test-name"},
- Secrets: []corev1.ObjectReference{{Name: "test-name-token-123-blah1"}, {Name: "test-name-token-123-blah2"}, {Name: "random-one"}, {Name: "random-two"}},
- }},
- want: []corev1.ObjectReference{{Name: "random-one"}, {Name: "random-two"}},
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- se := &serviceAccountService{}
- if got := se.shiftSecretTokens(tt.args.serviceAccount); !reflect.DeepEqual(got, tt.want) {
- t.Errorf("shiftSecretTokens() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestServiceAccountService_updateServiceAccount(t *testing.T) {
- ctx := context.TODO()
-
- t.Run("should update serviceAccount merging two svcAcc together", func(t *testing.T) {
- g := gomega.NewWithT(t)
- client := new(automock.Client)
-
- var obj resource.Object
-
- client.On("Update", mock.Anything, mock.Anything).Return(nil).Once().Run(func(args mock.Arguments) {
- obj = args.Get(1).(resource.Object)
- })
- defer client.AssertExpectations(t)
-
- r := &serviceAccountService{client: client}
-
- truethy := true
-
- base := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "base",
- Labels: map[string]string{
- "base-label-1": "label-1",
- "base-label-2": "label-2",
- },
- Annotations: map[string]string{
- "base-anno-key-1": "anno-1",
- },
- },
- Secrets: []corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-1"}},
- ImagePullSecrets: []corev1.LocalObjectReference{{Name: "base-image-pull-secret"}, {Name: "base-image-pull-secret-2"}},
- AutomountServiceAccountToken: &truethy,
- }
-
- falsy := false
-
- instance := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "instance",
- Labels: map[string]string{
- "instance-label-1": "label-1",
- "instance-label-2": "label-2",
- },
- Annotations: map[string]string{
- "instance-anno-key-1": "anno-1",
- },
- },
- Secrets: []corev1.ObjectReference{{Name: "instance-secret-1"}, {Name: "instance-secret-1"}},
- ImagePullSecrets: []corev1.LocalObjectReference{{Name: "instance-image-pull-secret"}, {Name: "instance-image-pull-secret-2"}},
- AutomountServiceAccountToken: &falsy,
- }
-
- err := r.updateServiceAccount(ctx, zap.NewNop().Sugar(), instance, base)
- g.Expect(err).To(gomega.Succeed())
-
- g.Expect(obj).NotTo(gomega.BeNil())
-
- updatedServiceAcc := obj.(*corev1.ServiceAccount)
-
- // inherited from instance
- g.Expect(updatedServiceAcc.Name).To(gomega.Equal(instance.GetName()))
-
- // inherited from base
- g.Expect(updatedServiceAcc.Annotations).To(gomega.And(gomega.Equal(base.GetAnnotations()), gomega.Not(gomega.BeNil())))
- g.Expect(updatedServiceAcc.Labels).To(gomega.And(gomega.Equal(base.GetLabels()), gomega.Not(gomega.BeNil())))
- g.Expect(updatedServiceAcc.ImagePullSecrets).To(gomega.And(gomega.Equal(base.ImagePullSecrets), gomega.Not(gomega.BeNil())))
- g.Expect(updatedServiceAcc.AutomountServiceAccountToken).To(gomega.And(gomega.Equal(base.AutomountServiceAccountToken), gomega.Not(gomega.BeNil())))
- g.Expect(updatedServiceAcc.Secrets).To(gomega.And(gomega.Equal(base.Secrets), gomega.Not(gomega.BeNil())))
- g.Expect(updatedServiceAcc.Secrets).NotTo(gomega.Equal(instance.Secrets))
-
- g.Expect(updatedServiceAcc.AutomountServiceAccountToken).NotTo(gomega.Equal(instance.AutomountServiceAccountToken))
- })
- t.Run("should correctly extract token and normal secrets", func(t *testing.T) {
- g := gomega.NewWithT(t)
- client := new(automock.Client)
-
- var obj resource.Object
-
- client.On("Update", mock.Anything, mock.Anything).Return(nil).Once().Run(func(args mock.Arguments) {
- obj = args.Get(1).(resource.Object)
- })
-
- defer client.AssertExpectations(t)
-
- r := &serviceAccountService{client: client}
-
- base := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "base"},
- Secrets: []corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-2"}},
- }
-
- instance := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "instance"},
- Secrets: []corev1.ObjectReference{{Name: "instance-token-1"}, {Name: "instance-token-2"}},
- }
-
- err := r.updateServiceAccount(ctx, zap.NewNop().Sugar(), instance, base)
- g.Expect(err).To(gomega.Succeed())
-
- g.Expect(obj).NotTo(gomega.BeNil())
-
- updatedServiceAcc := obj.(*corev1.ServiceAccount)
-
- g.Expect(updatedServiceAcc.Name).To(gomega.Equal(instance.GetName()))
- g.Expect(updatedServiceAcc.Secrets).To(gomega.Equal([]corev1.ObjectReference{
- {Name: "base-secret-1"},
- {Name: "base-secret-2"},
- {Name: "instance-token-1"},
- {Name: "instance-token-2"},
- }))
- })
- t.Run("should return error on update error", func(t *testing.T) {
- g := gomega.NewWithT(t)
- client := new(automock.Client)
-
- client.On("Update", mock.Anything, mock.Anything).Return(errors.New("update err")).Once()
-
- r := &serviceAccountService{client: client}
-
- base := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "base"},
- Secrets: []corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-2"}},
- }
-
- instance := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "instance"},
- Secrets: []corev1.ObjectReference{{Name: "instance-token-1"}, {Name: "instance-token-2"}},
- }
-
- err := r.updateServiceAccount(ctx, zap.NewNop().Sugar(), instance, base)
- g.Expect(err).To(gomega.HaveOccurred())
- })
-}
-
-func Test_serviceAccountService_IsBase(t *testing.T) {
- baseNs := "base-ns"
-
- type args struct {
- serviceAccount *corev1.ServiceAccount
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should correctly return if service account is base one",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs, Labels: map[string]string{
- ConfigLabel: ServiceAccountLabelValue,
- }},
- }},
- want: true,
- },
- {
- name: "should correctly return false for service account in wrong ns",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Namespace: "not-base-ns", Labels: map[string]string{
- ConfigLabel: ServiceAccountLabelValue,
- }},
- }},
- want: false,
- },
- {
- name: "should correctly return false for service account has wrong label value",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs, Labels: map[string]string{
- ConfigLabel: "some-random-value",
- }},
- }},
- want: false,
- },
- {
- name: "should correctly return false for service account with no labels",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Namespace: baseNs},
- }},
- want: false,
- },
- {
- name: "should correctly return false for service account with no labels and in wrong namespace",
- args: args{serviceAccount: &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Namespace: "not-base"},
- }},
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r := &serviceAccountService{
- config: Config{
- BaseNamespace: baseNs,
- },
- }
- if got := r.IsBase(tt.args.serviceAccount); got != tt.want {
- t.Errorf("IsBase() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestServiceAccountService_createServiceAccount(t *testing.T) {
- ctx := context.TODO()
- t.Run("should create configmap correctly", func(t *testing.T) {
- g := gomega.NewWithT(t)
- client := new(automock.Client)
-
- var obj resource.Object
-
- client.On("Create", mock.Anything, mock.Anything).Return(nil).Once().Run(func(args mock.Arguments) {
- obj = args.Get(1).(resource.Object)
- })
- defer client.AssertExpectations(t)
-
- r := &serviceAccountService{client: client}
-
- truethy := true
-
- base := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{
- Name: "base",
- Namespace: "original-ns",
- Labels: map[string]string{
- "base-label-1": "label-1",
- "base-label-2": "label-2",
- },
- Annotations: map[string]string{
- "base-anno-key-1": "anno-1",
- },
- },
- Secrets: []corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-1"}, {Name: "base-token-1"}, {Name: "base-token-2"}, {Name: "base-token-3"}},
- ImagePullSecrets: []corev1.LocalObjectReference{{Name: "base-image-pull-secret"}, {Name: "base-image-pull-secret-2"}},
- AutomountServiceAccountToken: &truethy,
- }
-
- namespace := "some-ns"
-
- err := r.createServiceAccount(ctx, zap.NewNop().Sugar(), namespace, base)
- g.Expect(err).To(gomega.Succeed())
-
- g.Expect(obj).NotTo(gomega.BeNil())
-
- createdServiceAcc := obj.(*corev1.ServiceAccount)
-
- g.Expect(createdServiceAcc.Name).To(gomega.Equal(base.GetName()))
- g.Expect(createdServiceAcc.Namespace).To(gomega.Equal(namespace))
- g.Expect(createdServiceAcc.Namespace).NotTo(gomega.Equal(base.Namespace))
- g.Expect(createdServiceAcc.Annotations).To(gomega.And(gomega.Equal(base.GetAnnotations()), gomega.Not(gomega.BeNil())))
- g.Expect(createdServiceAcc.Labels).To(gomega.And(gomega.Equal(base.GetLabels()), gomega.Not(gomega.BeNil())))
- g.Expect(createdServiceAcc.ImagePullSecrets).To(gomega.And(gomega.Equal(base.ImagePullSecrets), gomega.Not(gomega.BeNil())))
- g.Expect(createdServiceAcc.AutomountServiceAccountToken).To(gomega.And(gomega.Equal(base.AutomountServiceAccountToken), gomega.Not(gomega.BeNil())))
- g.Expect(createdServiceAcc.Secrets).NotTo(gomega.BeNil())
- g.Expect(createdServiceAcc.Secrets).NotTo(gomega.Equal(base.Secrets), "there should be not tokens here, as they are autogenerated by k8s")
- g.Expect(createdServiceAcc.Secrets).To(gomega.Equal([]corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-1"}}))
- })
- t.Run("should return error on update error", func(t *testing.T) {
- g := gomega.NewWithT(t)
- client := new(automock.Client)
-
- client.On("Create", mock.Anything, mock.Anything).Return(errors.New("update err")).Once()
-
- r := &serviceAccountService{client: client}
-
- base := &corev1.ServiceAccount{
- ObjectMeta: metav1.ObjectMeta{Name: "base"},
- Secrets: []corev1.ObjectReference{{Name: "base-secret-1"}, {Name: "base-secret-2"}},
- }
-
- err := r.createServiceAccount(ctx, zap.NewNop().Sugar(), "random-ns", base)
- g.Expect(err).To(gomega.HaveOccurred())
- })
-}
diff --git a/components/serverless/internal/controllers/kubernetes/shared_test.go b/components/serverless/internal/controllers/kubernetes/shared_test.go
deleted file mode 100644
index 63c04138f..000000000
--- a/components/serverless/internal/controllers/kubernetes/shared_test.go
+++ /dev/null
@@ -1,151 +0,0 @@
-package kubernetes
-
-import (
- "context"
- "testing"
-
- "github.com/onsi/gomega"
- "github.com/vrischmann/envconfig"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes/scheme"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-func Test_isExcludedNamespace(t *testing.T) {
- type args struct {
- name string
- base string
- excluded []string
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should exclude base namespace",
- args: args{
- name: "the-same-as-base",
- base: "the-same-as-base",
- excluded: nil,
- },
- want: true,
- },
- {
- name: "should exclude namespace if it's in excluded list",
- args: args{
- name: "not-the-same-as-base",
- base: "the-same-as-base",
- excluded: []string{"data", "tada", "not-the-same-as-base"},
- },
- want: true,
- },
- {
- name: "should exclude namespace if it's in excluded list more than 1 time",
- args: args{
- name: "not-the-same-as-base",
- base: "the-same-as-base",
- excluded: []string{"data", "tada", "not-the-same-as-base", "not-the-same-as-base", "not-the-same-as-base"},
- },
- want: true,
- },
- {
- name: "should not exclude otherwise",
- args: args{
- name: "some-random-value",
- base: "the-same-as-base",
- excluded: []string{"data", "tada", "not-the-same-as-base"},
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := isExcludedNamespace(tt.args.name, tt.args.base, tt.args.excluded); got != tt.want {
- t.Errorf("isExcludedNamespace() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestConfigStruct_ExcludedNamespaceDefaultValue(t *testing.T) {
- t.Run("Excluded namespaces should not have length of 1", func(t *testing.T) {
- g := gomega.NewWithT(t)
- // this test is just to be sure than someone used ";" instead of ","
- // I assume that we have more than 1 namespace we need to exclude by default
-
- cfg := Config{}
- err := envconfig.Init(&cfg)
- g.Expect(err).To(gomega.Succeed())
-
- g.Expect(cfg.ExcludedNamespaces).To(gomega.HaveLen(1))
- })
-}
-
-func TestGetNamespaces(t *testing.T) {
- baseNs := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "baseNs"}}
- excludedNamespaces := []string{"excluded1", "excluded2"}
- excludedNs1 := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "excluded1"}}
- ctx := context.TODO()
- ns1 := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test1"}}
- ns2 := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test2"}}
-
- t.Run("should successfully return non base, non excluded namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(&ns1).Build()
-
- //WHEN
- namespaces, err := getNamespaces(ctx, fakeClient, baseNs.Name, excludedNamespaces)
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(namespaces).To(gomega.HaveLen(1))
- g.Expect(namespaces[0]).To(gomega.Equal("test1"))
- })
-
- t.Run("should successfully omit terminating namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- nsTerminating := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "terminating"}, Status: corev1.NamespaceStatus{
- Phase: corev1.NamespaceTerminating,
- }}
- fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(&ns1, &ns2, &nsTerminating).Build()
-
- //WHEN
- namespaces, err := getNamespaces(ctx, fakeClient, baseNs.Name, excludedNamespaces)
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(namespaces).To(gomega.HaveLen(2))
- g.Expect(namespaces).To(gomega.ConsistOf("test1", "test2"))
- g.Expect(namespaces).NotTo(gomega.ConsistOf("terminating"))
- })
-
- t.Run("should successfully omit base namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(&baseNs).Build()
-
- //WHEN
- namespaces, err := getNamespaces(ctx, fakeClient, baseNs.Name, []string{"random"})
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(namespaces).To(gomega.HaveLen(0))
- })
-
- t.Run("should successfully excluded namespace", func(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- fakeClient := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(&excludedNs1).Build()
-
- //WHEN
- namespaces, err := getNamespaces(ctx, fakeClient, baseNs.Name, []string{excludedNs1.Name})
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(namespaces).To(gomega.HaveLen(0))
- })
-}
diff --git a/components/serverless/internal/controllers/serverless/automock/git_client.go b/components/serverless/internal/controllers/serverless/automock/git_client.go
deleted file mode 100644
index 98c7a0318..000000000
--- a/components/serverless/internal/controllers/serverless/automock/git_client.go
+++ /dev/null
@@ -1,83 +0,0 @@
-// Code generated by mockery v2.40.1. DO NOT EDIT.
-
-package automock
-
-import (
- git "github.com/kyma-project/serverless/components/serverless/internal/git"
- mock "github.com/stretchr/testify/mock"
-)
-
-// GitClient is an autogenerated mock type for the GitClient type
-type GitClient struct {
- mock.Mock
-}
-
-// Clone provides a mock function with given fields: path, options
-func (_m *GitClient) Clone(path string, options git.Options) (string, error) {
- ret := _m.Called(path, options)
-
- if len(ret) == 0 {
- panic("no return value specified for Clone")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func(string, git.Options) (string, error)); ok {
- return rf(path, options)
- }
- if rf, ok := ret.Get(0).(func(string, git.Options) string); ok {
- r0 = rf(path, options)
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func(string, git.Options) error); ok {
- r1 = rf(path, options)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// LastCommit provides a mock function with given fields: options
-func (_m *GitClient) LastCommit(options git.Options) (string, error) {
- ret := _m.Called(options)
-
- if len(ret) == 0 {
- panic("no return value specified for LastCommit")
- }
-
- var r0 string
- var r1 error
- if rf, ok := ret.Get(0).(func(git.Options) (string, error)); ok {
- return rf(options)
- }
- if rf, ok := ret.Get(0).(func(git.Options) string); ok {
- r0 = rf(options)
- } else {
- r0 = ret.Get(0).(string)
- }
-
- if rf, ok := ret.Get(1).(func(git.Options) error); ok {
- r1 = rf(options)
- } else {
- r1 = ret.Error(1)
- }
-
- return r0, r1
-}
-
-// NewGitClient creates a new instance of GitClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewGitClient(t interface {
- mock.TestingT
- Cleanup(func())
-}) *GitClient {
- mock := &GitClient{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/components/serverless/internal/controllers/serverless/automock/git_client_factory.go b/components/serverless/internal/controllers/serverless/automock/git_client_factory.go
deleted file mode 100644
index ceff6ee0e..000000000
--- a/components/serverless/internal/controllers/serverless/automock/git_client_factory.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// Code generated by mockery v2.40.1. DO NOT EDIT.
-
-package automock
-
-import (
- git "github.com/kyma-project/serverless/components/serverless/internal/git"
- mock "github.com/stretchr/testify/mock"
-
- zap "go.uber.org/zap"
-)
-
-// GitClientFactory is an autogenerated mock type for the GitClientFactory type
-type GitClientFactory struct {
- mock.Mock
-}
-
-// GetGitClient provides a mock function with given fields: logger
-func (_m *GitClientFactory) GetGitClient(logger *zap.SugaredLogger) git.GitClient {
- ret := _m.Called(logger)
-
- if len(ret) == 0 {
- panic("no return value specified for GetGitClient")
- }
-
- var r0 git.GitClient
- if rf, ok := ret.Get(0).(func(*zap.SugaredLogger) git.GitClient); ok {
- r0 = rf(logger)
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(git.GitClient)
- }
- }
-
- return r0
-}
-
-// NewGitClientFactory creates a new instance of GitClientFactory. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewGitClientFactory(t interface {
- mock.TestingT
- Cleanup(func())
-}) *GitClientFactory {
- mock := &GitClientFactory{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/components/serverless/internal/controllers/serverless/automock/stats_collector.go b/components/serverless/internal/controllers/serverless/automock/stats_collector.go
deleted file mode 100644
index 9de9d9e6c..000000000
--- a/components/serverless/internal/controllers/serverless/automock/stats_collector.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Code generated by mockery v2.40.1. DO NOT EDIT.
-
-package automock
-
-import (
- mock "github.com/stretchr/testify/mock"
-
- v1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-// StatsCollector is an autogenerated mock type for the StatsCollector type
-type StatsCollector struct {
- mock.Mock
-}
-
-// UpdateReconcileStats provides a mock function with given fields: f, cond
-func (_m *StatsCollector) UpdateReconcileStats(f *v1alpha2.Function, cond v1alpha2.Condition) {
- _m.Called(f, cond)
-}
-
-// NewStatsCollector creates a new instance of StatsCollector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewStatsCollector(t interface {
- mock.TestingT
- Cleanup(func())
-}) *StatsCollector {
- mock := &StatsCollector{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/components/serverless/internal/controllers/serverless/build_resources.go b/components/serverless/internal/controllers/serverless/build_resources.go
deleted file mode 100644
index 5875e3644..000000000
--- a/components/serverless/internal/controllers/serverless/build_resources.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package serverless
-
-import (
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/util/intstr"
-)
-
-const (
- destinationArg = "--destination"
- functionContainerName = "function"
- baseDir = "/workspace/src/"
- workspaceMountPath = "/workspace"
-)
-
-var (
- istioSidecarInjectFalse = map[string]string{
- "sidecar.istio.io/inject": "false",
- }
- svcTargetPort = intstr.FromInt(8080)
-)
-
-func buildRepoFetcherEnvVars(instance *serverlessv1alpha2.Function, gitOptions git.Options) []corev1.EnvVar {
- vars := []corev1.EnvVar{
- {
- Name: "APP_REPOSITORY_URL",
- Value: gitOptions.URL,
- },
- {
- Name: "APP_REPOSITORY_COMMIT",
- Value: instance.Status.Commit,
- },
- {
- Name: "APP_MOUNT_PATH",
- Value: workspaceMountPath,
- },
- }
-
- if gitOptions.Auth != nil {
- vars = append(vars, corev1.EnvVar{
- Name: "APP_REPOSITORY_AUTH_TYPE",
- Value: string(gitOptions.Auth.Type),
- })
-
- switch gitOptions.Auth.Type {
- case git.RepositoryAuthBasic:
- vars = append(vars, []corev1.EnvVar{
- {
- Name: "APP_REPOSITORY_USERNAME",
- ValueFrom: &corev1.EnvVarSource{
- SecretKeyRef: &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: gitOptions.Auth.SecretName,
- },
- Key: git.UsernameKey,
- },
- },
- },
- {
- Name: "APP_REPOSITORY_PASSWORD",
- ValueFrom: &corev1.EnvVarSource{
- SecretKeyRef: &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: gitOptions.Auth.SecretName,
- },
- Key: git.PasswordKey,
- },
- },
- },
- }...)
- case git.RepositoryAuthSSHKey:
- vars = append(vars, corev1.EnvVar{
- Name: "APP_REPOSITORY_KEY",
- ValueFrom: &corev1.EnvVarSource{
- SecretKeyRef: &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: gitOptions.Auth.SecretName,
- },
- Key: git.KeyKey,
- },
- },
- })
- if _, ok := gitOptions.Auth.Credentials[git.PasswordKey]; ok {
- vars = append(vars, corev1.EnvVar{
- Name: "APP_REPOSITORY_PASSWORD",
- ValueFrom: &corev1.EnvVarSource{
- SecretKeyRef: &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: gitOptions.Auth.SecretName,
- },
- Key: git.PasswordKey,
- },
- },
- })
- }
- }
- }
-
- return vars
-}
-
-// TODO:is used only in tests - probably to remove (after move tests in proper place)
-func (r *FunctionReconciler) internalFunctionLabels(instance *serverlessv1alpha2.Function) map[string]string {
- labels := make(map[string]string, 3)
-
- labels[serverlessv1alpha2.FunctionNameLabel] = instance.Name
- labels[serverlessv1alpha2.FunctionManagedByLabel] = serverlessv1alpha2.FunctionControllerValue
- labels[serverlessv1alpha2.FunctionUUIDLabel] = string(instance.GetUID())
-
- return labels
-}
diff --git a/components/serverless/internal/controllers/serverless/build_resources_test.go b/components/serverless/internal/controllers/serverless/build_resources_test.go
deleted file mode 100644
index cff0c89e2..000000000
--- a/components/serverless/internal/controllers/serverless/build_resources_test.go
+++ /dev/null
@@ -1,659 +0,0 @@
-package serverless
-
-import (
- "fmt"
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/runtime"
- fnRuntime "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/runtime"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- "github.com/stretchr/testify/require"
- v1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/validation"
-)
-
-var (
- rtmNodeJS18 = fnRuntime.GetRuntimeConfig(serverlessv1alpha2.NodeJs18)
- rtmNodeJS20 = fnRuntime.GetRuntimeConfig(serverlessv1alpha2.NodeJs20)
- rtmPython39 = fnRuntime.GetRuntimeConfig(serverlessv1alpha2.Python39)
- rtmPython312 = fnRuntime.GetRuntimeConfig(serverlessv1alpha2.Python312)
-)
-
-func TestFunctionReconciler_buildConfigMap(t *testing.T) {
- tests := []struct {
- name string
- fn *serverlessv1alpha2.Function
- want corev1.ConfigMap
- }{
- {
- name: "should properly build configmap",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "fn-ns",
- UID: "fn-uuid",
- Name: "function-name",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- },
- },
- want: corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Namespace: "fn-ns",
- GenerateName: "function-name-",
- Labels: map[string]string{
- serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue,
- serverlessv1alpha2.FunctionNameLabel: "function-name",
- serverlessv1alpha2.FunctionUUIDLabel: "fn-uuid",
- },
- },
- Data: map[string]string{
- "source": "fn-source",
- "dependencies": "{}",
- },
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewWithT(t)
- s := systemState{
- //TODO: https://github.com/kyma-project/kyma/issues/14079
- instance: *tt.fn,
- }
- got := s.buildConfigMap()
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_buildDeployment(t *testing.T) {
- type args struct {
- instance *serverlessv1alpha2.Function
- }
- rtmCfg := runtime.GetRuntimeConfig(serverlessv1alpha2.NodeJs20)
- resourceCfg := fixResources()
-
- tests := []struct {
- name string
- args args
- }{
- {
- name: "deployment should contain needed elements",
- args: args{
- instance: newFixFunction("ns", "name", 1, 2),
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *tt.args.instance,
- }
-
- got := s.buildDeployment(buildDeploymentArgs{}, resourceCfg)
-
- // deployment selector labels are equal with pod labels
- for key, value := range got.Spec.Selector.MatchLabels {
- g.Expect(got.Spec.Template.Labels[key]).To(gomega.Equal(value))
- }
- g.Expect(got.Spec.Template.Spec.Containers).To(gomega.HaveLen(1))
- g.Expect(got.Spec.Template.Spec.Containers[0].Env).To(gomega.ContainElements(rtmCfg.RuntimeEnvs))
-
- // pod labels & annotations
- g.Expect(got.Spec.Template.ObjectMeta.Labels).To(gomega.HaveLen(5 + 3))
- g.Expect(got.Spec.Template.ObjectMeta.Labels).To(gomega.HaveKeyWithValue("foo", "bar"))
- g.Expect(got.Spec.Template.ObjectMeta.Labels).To(gomega.HaveKeyWithValue(testBindingLabel1, "foobar"))
- g.Expect(got.Spec.Template.ObjectMeta.Labels).To(gomega.HaveKeyWithValue(testBindingLabel2, testBindingLabelValue))
-
- g.Expect(got.Spec.Template.ObjectMeta.Annotations).To(gomega.HaveLen(1 + 1))
- g.Expect(got.Spec.Template.ObjectMeta.Annotations).To(gomega.HaveKeyWithValue("foo", "bar"))
-
- // volumes
- const expectedVolumeCount = 3
- g.Expect(got.Spec.Template.Spec.Volumes).To(gomega.HaveLen(expectedVolumeCount))
- g.Expect(got.Spec.Template.Spec.Containers[0].VolumeMounts).To(gomega.HaveLen(expectedVolumeCount))
-
- for i := 0; i < expectedVolumeCount; i++ {
- g.Expect(got.Spec.Template.Spec.Volumes[i].Name).To(gomega.Equal(got.Spec.Template.Spec.Containers[0].VolumeMounts[i].Name))
- errs := validation.IsDNS1123Subdomain(got.Spec.Template.Spec.Volumes[i].Name)
- g.Expect(errs).To(gomega.HaveLen(0))
-
- checkSecretVolume(g, tt.args.instance.Spec.SecretMounts,
- got.Spec.Template.Spec.Volumes[i], got.Spec.Template.Spec.Containers[0].VolumeMounts[i])
- }
-
- g.Expect(got.Spec.Template.Spec.Containers[0].StartupProbe.SuccessThreshold).To(gomega.BeEquivalentTo(1), "documentation states that this value has to be set to 1")
- })
- }
-}
-
-func checkSecretVolume(g *gomega.WithT, secretMounts []serverlessv1alpha2.SecretMount, volume corev1.Volume, volumeMount corev1.VolumeMount) {
- if volume.Secret != nil {
- var matchingSecretMount *serverlessv1alpha2.SecretMount = nil
- for _, secretMount := range secretMounts {
- if secretMount.SecretName == volume.Secret.SecretName {
- matchingSecretMount = secretMount.DeepCopy()
- break
- }
- }
- g.Expect(matchingSecretMount).ToNot(gomega.BeNil())
- g.Expect(volumeMount.MountPath).To(gomega.Equal(matchingSecretMount.MountPath))
- }
-}
-
-func TestFunctionReconciler_buildDeploymentWithResources(t *testing.T) {
- resourceCfg := fixResources()
- resources := resourceCfg.Presets.ToResourceRequirements()
- python312Resources := resourceCfg.RuntimePresets[string(serverlessv1alpha2.Python312)].ToResourceRequirements()
-
- customResources := &corev1.ResourceRequirements{
- Limits: corev1.ResourceList{
- corev1.ResourceCPU: resource.MustParse("378m"),
- corev1.ResourceMemory: resource.MustParse("378Mi"),
- },
- Requests: corev1.ResourceList{
- corev1.ResourceCPU: resource.MustParse("157m"),
- corev1.ResourceMemory: resource.MustParse("157Mi"),
- },
- }
-
- type args struct {
- instance *serverlessv1alpha2.Function
- expectedResources corev1.ResourceRequirements
- }
-
- tests := []struct {
- name string
- args args
- }{
- {
- name: "deployment should use set resources preset",
- args: args{
- instance: newFixFunctionWithFunctionResourceProfile("ns", "name", "M"),
- expectedResources: resources["M"],
- },
- },
- {
- name: "deployment should use default runtime preset",
- args: args{
- instance: newFixFunctionWithRuntime("ns", "name", serverlessv1alpha2.Python312),
- expectedResources: python312Resources["L"],
- },
- },
- {
- name: "deployment should use default resource preset",
- args: args{
- instance: newFixFunctionWithCustomFunctionResource("ns", "name", customResources),
- expectedResources: *customResources,
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- s := systemState{instance: *tt.args.instance}
-
- got := s.buildDeployment(buildDeploymentArgs{}, resourceCfg)
-
- require.Len(t, got.Spec.Template.Spec.Containers, 1)
- require.Equal(t, tt.args.expectedResources, got.Spec.Template.Spec.Containers[0].Resources)
- })
- }
-}
-
-func TestFunctionReconciler_buildHorizontalPodAutoscaler(t *testing.T) {
- type args struct {
- instance *serverlessv1alpha2.Function
- }
- type wants struct {
- minReplicas int32
- maxReplicas int32
- }
-
- nilCase1 := newFixFunction("ns", "name", 2, 2)
- nilCase1.Spec.ScaleConfig.MinReplicas = nil
- nilCase1.Spec.ScaleConfig.MaxReplicas = nil
- nilCase2 := newFixFunction("ns", "name", 2, 2)
- nilCase2.Spec.ScaleConfig.MinReplicas = nil
- nilCase3 := newFixFunction("ns", "name", 2, 2)
- nilCase3.Spec.ScaleConfig.MaxReplicas = nil
-
- tests := []struct {
- name string
- args args
- wants wants
- }{
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values - 0 in spec",
- args: args{instance: newFixFunction("ns", "name", 0, 0)},
- wants: wants{
- minReplicas: 1,
- maxReplicas: 1,
- },
- },
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values - nil in spec",
- args: args{instance: nilCase1},
- wants: wants{
- minReplicas: 1,
- maxReplicas: 1,
- },
- },
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values, when min is set to 0",
- args: args{instance: newFixFunction("ns", "name", 2, 0)},
- wants: wants{
- minReplicas: 2,
- maxReplicas: 2,
- },
- },
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values, when min is nil",
- args: args{instance: nilCase2},
- wants: wants{
- minReplicas: 1,
- maxReplicas: 2,
- },
- },
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values, when max is set to 0",
- args: args{instance: newFixFunction("ns", "name", 0, 3)},
- wants: wants{
- minReplicas: 1,
- maxReplicas: 3,
- },
- },
- {
- name: "spec.minReplicas and spec.maxReplicas fields should contain fixed (from Function spec or default) values, when max is nil",
- args: args{instance: nilCase3},
- wants: wants{
- minReplicas: 2,
- maxReplicas: 2,
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- instance: *tt.args.instance,
- deployments: v1.DeploymentList{
- Items: []v1.Deployment{
- {
- ObjectMeta: metav1.ObjectMeta{},
- },
- },
- },
- }
-
- got := s.buildHorizontalPodAutoscaler(0)
-
- g.Expect(*got.Spec.MinReplicas).To(gomega.Equal(tt.wants.minReplicas))
- g.Expect(got.Spec.MaxReplicas).To(gomega.Equal(tt.wants.maxReplicas))
- })
- }
-}
-
-func TestFunctionReconciler_internalFunctionLabels(t *testing.T) {
- type args struct {
- instance *serverlessv1alpha2.Function
- }
- tests := []struct {
- name string
- args args
- want map[string]string
- }{
- {
- name: "should return only 3 correct labels",
- args: args{instance: &serverlessv1alpha2.Function{ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- }}},
- want: map[string]string{
- serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue,
- serverlessv1alpha2.FunctionNameLabel: "fn-name",
- serverlessv1alpha2.FunctionUUIDLabel: "fn-uuid",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- r := &FunctionReconciler{}
- got := r.internalFunctionLabels(tt.args.instance)
- g.Expect(got).To(gomega.Equal(tt.want))
- g.Expect(got).To(gomega.HaveLen(3))
- })
- }
-}
-
-func TestFunctionReconciler_functionLabels(t *testing.T) {
- type args struct {
- instance *serverlessv1alpha2.Function
- }
- tests := []struct {
- name string
- args args
- want map[string]string
- }{
- {
- name: "should return fn labels + 3 internal ones",
- args: args{
- instance: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- Labels: map[string]string{
- "some-key": "whatever-value",
- }},
- },
- },
- want: map[string]string{
- serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue,
- serverlessv1alpha2.FunctionNameLabel: "fn-name",
- serverlessv1alpha2.FunctionUUIDLabel: "fn-uuid",
- "some-key": "whatever-value",
- },
- }, {
- name: "should return 3 internal ones if there's no labels on fn",
- args: args{
- instance: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- },
- }},
- want: map[string]string{
- serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue,
- serverlessv1alpha2.FunctionNameLabel: "fn-name",
- serverlessv1alpha2.FunctionUUIDLabel: "fn-uuid",
- },
- },
- {
- name: "should not be able to override our internal labels",
- args: args{
- instance: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- Labels: map[string]string{
- serverlessv1alpha2.FunctionUUIDLabel: "whatever-value",
- }},
- },
- },
- want: map[string]string{
- serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue,
- serverlessv1alpha2.FunctionNameLabel: "fn-name",
- serverlessv1alpha2.FunctionUUIDLabel: "fn-uuid",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *tt.args.instance,
- }
- got := s.functionLabels()
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_buildJob(t *testing.T) {
- g := gomega.NewWithT(t)
-
- // GIVEN
- cmName := "test-configmap"
-
- dockerCfg := DockerConfig{
- ActiveRegistryConfigSecretName: "docker-secret-name",
- }
- //nolint:gosec
- packageRegistryConfigSecretName := "pkg-config-secret"
-
- testCases := []struct {
- Name string
- Runtime serverlessv1alpha2.Runtime
- ExpectedVolumesLen int
- ExpectedVolumes []expectedVolume
- ExpectedMountsLen int
- ExpectedVolumeMounts []corev1.VolumeMount
- }{
- {
- Name: "Success Node18",
- Runtime: serverlessv1alpha2.NodeJs18,
- ExpectedVolumesLen: 4,
- ExpectedVolumes: []expectedVolume{
- {name: "sources", localObjectReference: cmName},
- {name: "runtime", localObjectReference: rtmNodeJS18.DockerfileConfigMapName},
- {name: "credentials", localObjectReference: dockerCfg.ActiveRegistryConfigSecretName},
- {name: "registry-config", localObjectReference: packageRegistryConfigSecretName},
- },
- ExpectedMountsLen: 5,
- ExpectedVolumeMounts: []corev1.VolumeMount{
- {Name: "sources", MountPath: "/workspace/src/package.json", SubPath: FunctionDepsKey, ReadOnly: true},
- {Name: "sources", MountPath: "/workspace/src/handler.js", SubPath: FunctionSourceKey, ReadOnly: true},
- {Name: "runtime", MountPath: "/workspace/Dockerfile", SubPath: "Dockerfile", ReadOnly: true},
- {Name: "credentials", MountPath: "/docker", ReadOnly: true},
- {Name: "registry-config", MountPath: "/workspace/registry-config/.npmrc", SubPath: ".npmrc", ReadOnly: true},
- },
- },
- {
- Name: "Success Node20",
- Runtime: serverlessv1alpha2.NodeJs20,
- ExpectedVolumesLen: 4,
- ExpectedVolumes: []expectedVolume{
- {name: "sources", localObjectReference: cmName},
- {name: "runtime", localObjectReference: rtmNodeJS20.DockerfileConfigMapName},
- {name: "credentials", localObjectReference: dockerCfg.ActiveRegistryConfigSecretName},
- {name: "registry-config", localObjectReference: packageRegistryConfigSecretName},
- },
- ExpectedMountsLen: 5,
- ExpectedVolumeMounts: []corev1.VolumeMount{
- {Name: "sources", MountPath: "/workspace/src/package.json", SubPath: FunctionDepsKey, ReadOnly: true},
- {Name: "sources", MountPath: "/workspace/src/handler.js", SubPath: FunctionSourceKey, ReadOnly: true},
- {Name: "runtime", MountPath: "/workspace/Dockerfile", SubPath: "Dockerfile", ReadOnly: true},
- {Name: "credentials", MountPath: "/docker", ReadOnly: true},
- {Name: "registry-config", MountPath: "/workspace/registry-config/.npmrc", SubPath: ".npmrc", ReadOnly: true},
- },
- },
- {
- Name: "Success Python39",
- Runtime: serverlessv1alpha2.Python39,
- ExpectedVolumesLen: 4,
- ExpectedVolumes: []expectedVolume{
- {name: "sources", localObjectReference: cmName},
- {name: "runtime", localObjectReference: rtmPython39.DockerfileConfigMapName},
- {name: "credentials", localObjectReference: dockerCfg.ActiveRegistryConfigSecretName},
- {name: "registry-config", localObjectReference: packageRegistryConfigSecretName},
- },
- ExpectedMountsLen: 5,
- ExpectedVolumeMounts: []corev1.VolumeMount{
- {Name: "sources", MountPath: "/workspace/src/requirements.txt", SubPath: FunctionDepsKey, ReadOnly: true},
- {Name: "sources", MountPath: "/workspace/src/handler.py", SubPath: FunctionSourceKey, ReadOnly: true},
- {Name: "runtime", MountPath: "/workspace/Dockerfile", SubPath: "Dockerfile", ReadOnly: true},
- {Name: "credentials", MountPath: "/docker", ReadOnly: true},
- {Name: "registry-config", MountPath: "/workspace/registry-config/pip.conf", SubPath: "pip.conf", ReadOnly: true},
- },
- },
- {
- Name: "Success Python312",
- Runtime: serverlessv1alpha2.Python312,
- ExpectedVolumesLen: 4,
- ExpectedVolumes: []expectedVolume{
- {name: "sources", localObjectReference: cmName},
- {name: "runtime", localObjectReference: rtmPython312.DockerfileConfigMapName},
- {name: "credentials", localObjectReference: dockerCfg.ActiveRegistryConfigSecretName},
- {name: "registry-config", localObjectReference: packageRegistryConfigSecretName},
- },
- ExpectedMountsLen: 5,
- ExpectedVolumeMounts: []corev1.VolumeMount{
- {Name: "sources", MountPath: "/workspace/src/requirements.txt", SubPath: FunctionDepsKey, ReadOnly: true},
- {Name: "sources", MountPath: "/workspace/src/handler.py", SubPath: FunctionSourceKey, ReadOnly: true},
- {Name: "runtime", MountPath: "/workspace/Dockerfile", SubPath: "Dockerfile", ReadOnly: true},
- {Name: "credentials", MountPath: "/docker", ReadOnly: true},
- {Name: "registry-config", MountPath: "/workspace/registry-config/pip.conf", SubPath: "pip.conf", ReadOnly: true},
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.Name, func(t *testing.T) {
-
- functionName := "my-function"
- s := systemState{
- instance: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{Name: functionName},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: testCase.Runtime,
- Source: serverlessv1alpha2.Source{Inline: &serverlessv1alpha2.InlineSource{}},
- },
- },
- }
-
- // when
- job := s.buildJob(cmName, cfg{
- docker: dockerCfg,
- fn: FunctionConfig{
- PackageRegistryConfigSecretName: "pkg-config-secret",
- },
- })
-
- // then
- g.Expect(job.ObjectMeta.GenerateName).To(gomega.Equal(fmt.Sprintf("%s-build-", functionName)))
- g.Expect(job.Spec.Template.Spec.Volumes).To(gomega.HaveLen(testCase.ExpectedVolumesLen))
- assertVolumes(g, job.Spec.Template.Spec.Volumes, testCase.ExpectedVolumes)
-
- g.Expect(job.Spec.Template.Spec.Containers).To(gomega.HaveLen(1))
- g.Expect(job.Spec.Template.Spec.Containers[0].VolumeMounts).To(gomega.HaveLen(testCase.ExpectedMountsLen))
- g.Expect(job.Spec.Template.Spec.Containers[0].VolumeMounts).To(gomega.Equal(testCase.ExpectedVolumeMounts))
- })
- }
-}
-
-func TestFunctionReconciler_buildJobWithResources(t *testing.T) {
- resourceCfg := fixResources()
- cfg := cfg{
- fn: FunctionConfig{
- ResourceConfig: ResourceConfig{BuildJob: BuildJobResourceConfig{resourceCfg}},
- },
- }
-
- resources := resourceCfg.Presets.ToResourceRequirements()
- python312Resources := resourceCfg.RuntimePresets[string(serverlessv1alpha2.Python312)].ToResourceRequirements()
-
- customResources := &corev1.ResourceRequirements{
- Limits: corev1.ResourceList{
- corev1.ResourceCPU: resource.MustParse("378m"),
- corev1.ResourceMemory: resource.MustParse("378Mi"),
- },
- Requests: corev1.ResourceList{
- corev1.ResourceCPU: resource.MustParse("157m"),
- corev1.ResourceMemory: resource.MustParse("157Mi"),
- },
- }
-
- type args struct {
- instance *serverlessv1alpha2.Function
- expectedResources corev1.ResourceRequirements
- }
-
- tests := []struct {
- name string
- args args
- }{
- {
- name: "job should have resources profile preset",
- args: args{
- instance: newFixFunctionWithBuildResourceProfile("ns", "name", "M"),
- expectedResources: resources["M"],
- },
- },
- {
- name: "job should have default runtime preset",
- args: args{
- instance: newFixFunctionWithRuntime("ns", "name", serverlessv1alpha2.Python312),
- expectedResources: python312Resources["L"],
- },
- },
- {
- name: "job should have custom resources",
- args: args{
- instance: newFixFunctionWithCustomBuildResource("ns", "name", customResources),
- expectedResources: *customResources,
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- s := systemState{instance: *tt.args.instance}
-
- got := s.buildJob("configmap", cfg)
-
- require.Len(t, got.Spec.Template.Spec.Containers, 1)
- require.Equal(t, tt.args.expectedResources, got.Spec.Template.Spec.Containers[0].Resources)
- })
- }
-}
-
-type expectedVolume struct {
- name string
- localObjectReference string
-}
-
-func assertVolumes(g *gomega.WithT, actual []corev1.Volume, expected []expectedVolume) {
- for _, expVol := range expected {
- found := false
- for _, actualVol := range actual {
- if actualVol.Name == expVol.name &&
- (actualVol.Secret != nil && actualVol.Secret.SecretName == expVol.localObjectReference) ||
- (actualVol.ConfigMap != nil && actualVol.ConfigMap.LocalObjectReference.Name == expVol.localObjectReference) {
- found = true
- }
- }
- g.Expect(found).To(gomega.BeTrue(), "Volume with name: %s, referencing object: %s not found", expVol.name, expVol.localObjectReference)
- }
-}
-
-func fixResources() Resources {
- return Resources{
- Presets: map[string]Resource{
- "L": {
- RequestCPU: Quantity{resource.MustParse("100m")},
- RequestMemory: Quantity{resource.MustParse("100Mi")},
- LimitCPU: Quantity{resource.MustParse("200m")},
- LimitMemory: Quantity{resource.MustParse("200Mi")},
- },
- "M": {
- RequestCPU: Quantity{resource.MustParse("50m")},
- RequestMemory: Quantity{resource.MustParse("50Mi")},
- LimitCPU: Quantity{resource.MustParse("100m")},
- LimitMemory: Quantity{resource.MustParse("100Mi")},
- },
- },
- DefaultPreset: "L",
- RuntimePresets: map[string]Preset{
- string(serverlessv1alpha2.Python312): map[string]Resource{
- "L": {
- RequestCPU: Quantity{resource.MustParse("135m")},
- RequestMemory: Quantity{resource.MustParse("135Mi")},
- LimitCPU: Quantity{resource.MustParse("246m")},
- LimitMemory: Quantity{resource.MustParse("246Mi")},
- },
- },
- },
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/config.go b/components/serverless/internal/controllers/serverless/config.go
deleted file mode 100644
index 164d02f6a..000000000
--- a/components/serverless/internal/controllers/serverless/config.go
+++ /dev/null
@@ -1,113 +0,0 @@
-package serverless
-
-import (
- "time"
-
- "github.com/pkg/errors"
- "github.com/vrischmann/envconfig"
- "gopkg.in/yaml.v2"
- v1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
-)
-
-type FunctionConfig struct {
- PublisherProxyAddress string `envconfig:"optional"`
- TraceCollectorEndpoint string `envconfig:"optional"`
- ImageRegistryDefaultDockerConfigSecretName string `envconfig:"default=serverless-registry-config-default"`
- ImageRegistryExternalDockerConfigSecretName string `envconfig:"default=serverless-registry-config"`
- PackageRegistryConfigSecretName string `envconfig:"default=serverless-package-registry-config"`
- ImagePullAccountName string `envconfig:"default=serverless-function"`
- TargetCPUUtilizationPercentage int32 `envconfig:"default=50"`
- RequeueDuration time.Duration `envconfig:"default=1m"`
- FunctionReadyRequeueDuration time.Duration `envconfig:"default=5m"`
- GitFetchRequeueDuration time.Duration `envconfig:"default=30s"`
- ResourceConfig ResourceConfig `envconfig:"optional"`
- Build BuildConfig
-}
-
-type BuildConfig struct {
- ExecutorArgs []string `envconfig:"default=--insecure;--skip-tls-verify;--skip-unused-stages;--log-format=text;--cache=true;--use-new-run;--compressed-caching=false"`
- ExecutorImage string `envconfig:"default=gcr.io/kaniko-project/executor:v1.9.2"`
- RepoFetcherImage string `envconfig:"default=europe-docker.pkg.dev/kyma-project/prod/function-build-init:v20230426-37b02524"`
- MaxSimultaneousJobs int `envconfig:"default=5"`
-}
-
-type DockerConfig struct {
- ActiveRegistryConfigSecretName string
- PushAddress string
- PullAddress string
-}
-
-type ResourceConfig struct {
- Function FunctionResourceConfig `yaml:"function"`
- BuildJob BuildJobResourceConfig `yaml:"buildJob"`
-}
-
-var _ envconfig.Unmarshaler = &ResourceConfig{}
-
-func (rc *ResourceConfig) Unmarshal(input string) error {
- err := yaml.Unmarshal([]byte(input), rc)
- return err
-}
-
-type FunctionResourceConfig struct {
- Resources Resources `yaml:"resources"`
-}
-
-type BuildJobResourceConfig struct {
- Resources Resources `yaml:"resources"`
-}
-
-type Resources struct {
- Presets Preset `yaml:"presets"`
- RuntimePresets RuntimePresets `yaml:"runtimePresets"`
- DefaultPreset string `yaml:"defaultPreset"`
- MinRequestedCPU Quantity `yaml:"minRequestedCPU"`
- MinRequestedMemory Quantity `yaml:"minRequestedMemory"`
-}
-
-type RuntimePresets map[string]Preset
-
-type Preset map[string]Resource
-
-type Resource struct {
- RequestCPU Quantity `yaml:"requestCpu"`
- RequestMemory Quantity `yaml:"requestMemory"`
- LimitCPU Quantity `yaml:"limitCpu"`
- LimitMemory Quantity `yaml:"limitMemory"`
-}
-
-func (p Preset) ToResourceRequirements() map[string]v1.ResourceRequirements {
- resources := map[string]v1.ResourceRequirements{}
- for k, v := range p {
- resources[k] = v1.ResourceRequirements{
- Limits: v1.ResourceList{
- v1.ResourceCPU: v.LimitCPU.Quantity,
- v1.ResourceMemory: v.LimitMemory.Quantity,
- },
- Requests: v1.ResourceList{
- v1.ResourceCPU: v.RequestCPU.Quantity,
- v1.ResourceMemory: v.RequestMemory.Quantity,
- },
- }
- }
- return resources
-}
-
-type Quantity struct {
- resource.Quantity
-}
-
-func (q *Quantity) UnmarshalYAML(unmarshal func(interface{}) error) error {
- quantity := ""
- err := unmarshal(&quantity)
- if err != nil {
- return errors.Wrap(err, "while unmarshalling quantity")
- }
- out, err := resource.ParseQuantity(quantity)
- if err != nil {
- return errors.Wrap(err, "while parsing quantity")
- }
- q.Quantity = out
- return nil
-}
diff --git a/components/serverless/internal/controllers/serverless/configmap.go b/components/serverless/internal/controllers/serverless/configmap.go
deleted file mode 100644
index d0fdb7270..000000000
--- a/components/serverless/internal/controllers/serverless/configmap.go
+++ /dev/null
@@ -1,119 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
-
- corev1 "k8s.io/api/core/v1"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- apilabels "k8s.io/apimachinery/pkg/labels"
-)
-
-func stateFnInlineCheckSources(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
-
- labels := internalFunctionLabels(s.instance)
-
- err := r.client.ListByLabel(ctx, s.instance.GetNamespace(), labels, &s.configMaps)
- if err != nil {
- return nil, errors.Wrap(err, "while listing configMaps")
- }
-
- err = r.client.ListByLabel(ctx, s.instance.GetNamespace(), labels, &s.deployments)
- if err != nil {
- return nil, errors.Wrap(err, "while listing deployments")
- }
-
- srcChanged := s.inlineFnSrcChanged(r.cfg.docker.PullAddress)
- if !srcChanged {
- cfgStatus := getConditionStatus(s.instance.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)
- if cfgStatus == corev1.ConditionTrue {
- expectedJob := s.buildJob(s.configMaps.Items[0].GetName(), r.cfg)
- return buildStateFnCheckImageJob(expectedJob), nil
- }
- currentCondition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonFunctionSpec,
- Message: "Function configured",
- }
- return buildStatusUpdateStateFnWithCondition(currentCondition), nil
- }
-
- cfgMapCount := len(s.configMaps.Items)
-
- // TODO create issue to refactor the way how function controller is handling status
- next := stateFnInlineDeleteConfigMap
-
- if cfgMapCount == 0 {
- next = stateFnInlineCreateConfigMap
- }
-
- if cfgMapCount == 1 {
- next = stateFnInlineUpdateConfigMap
- }
-
- return next, nil
-}
-
-func stateFnInlineDeleteConfigMap(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("delete all ConfigMaps")
-
- labels := internalFunctionLabels(s.instance)
- selector := apilabels.SelectorFromSet(labels)
-
- err := r.client.DeleteAllBySelector(ctx, &corev1.ConfigMap{}, s.instance.GetNamespace(), selector)
- if err != nil {
- return nil, errors.Wrap(err, "while deleting configMaps")
- }
-
- return nil, nil
-}
-
-func stateFnInlineCreateConfigMap(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- configMap := s.buildConfigMap()
-
- err := r.client.CreateWithReference(ctx, &s.instance, &configMap)
- if err != nil {
- return nil, errors.Wrap(err, "while creating configMaps")
- }
-
- currentCondition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonConfigMapCreated,
- Message: fmt.Sprintf("ConfigMap %s created", configMap.GetName()),
- }
-
- return buildStatusUpdateStateFnWithCondition(currentCondition), nil
-}
-
-func stateFnInlineUpdateConfigMap(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- expectedConfigMap := s.buildConfigMap()
-
- s.configMaps.Items[0].Data = expectedConfigMap.Data
- s.configMaps.Items[0].Labels = expectedConfigMap.Labels
-
- cmName := s.configMaps.Items[0].GetName()
-
- r.log.Info(fmt.Sprintf("updating ConfigMap %s", cmName))
-
- err := r.client.Update(ctx, &s.configMaps.Items[0])
- if err != nil {
- return nil, errors.Wrap(err, "while updating configMap")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated,
- Message: fmt.Sprintf("Updated ConfigMap: %q", cmName),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
-}
diff --git a/components/serverless/internal/controllers/serverless/deployment.go b/components/serverless/internal/controllers/serverless/deployment.go
deleted file mode 100644
index 4d8f27b3b..000000000
--- a/components/serverless/internal/controllers/serverless/deployment.go
+++ /dev/null
@@ -1,216 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "gopkg.in/yaml.v2"
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- apilabels "k8s.io/apimachinery/pkg/labels"
- ctrl "sigs.k8s.io/controller-runtime"
-)
-
-const (
- // Progressing:
- // 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"
-
- // Available:
- // MinimumReplicasAvailable is added in a deployment when it has its minimum replicas required available.
- MinimumReplicasAvailable = "MinimumReplicasAvailable"
- MinimumReplicasUnavailable = "MinimumReplicasUnavailable"
-)
-
-func stateFnCheckDeployments(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- labels := internalFunctionLabels(s.instance)
-
- err := r.client.ListByLabel(ctx, s.instance.GetNamespace(), labels, &s.deployments)
- if err != nil {
- return nil, errors.Wrap(err, "while Listing deployments")
- }
-
- if err = ctx.Err(); err != nil {
- return nil, errors.Wrap(err, "context error")
- }
-
- args := buildDeploymentArgs{
- DockerPullAddress: r.cfg.docker.PullAddress,
- TraceCollectorEndpoint: r.cfg.fn.TraceCollectorEndpoint,
- PublisherProxyAddress: r.cfg.fn.PublisherProxyAddress,
- ImagePullAccountName: r.cfg.fn.ImagePullAccountName,
- }
-
- expectedDeployment := s.buildDeployment(args, r.cfg.fn.ResourceConfig.Function.Resources)
- if len(s.deployments.Items) == 0 {
- return buildStateFnCreateDeployment(expectedDeployment), nil
- }
-
- if len(s.deployments.Items) > 1 {
- return stateFnDeleteDeployments, nil
- }
-
- if !equalDeployments(s.deployments.Items[0], expectedDeployment) {
- return buildStateFnUpdateDeployment(expectedDeployment.Spec, expectedDeployment.Labels), nil
- }
- return stateFnCheckService, nil
-}
-
-func buildStateFnCreateDeployment(d appsv1.Deployment) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- err := r.client.CreateWithReference(ctx, &s.instance, &d)
- if err != nil {
- return handleDeploymentOperationError(err, "while creating deployment")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonDeploymentCreated,
- Message: fmt.Sprintf("Deployment %s created", d.GetName()),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func stateFnDeleteDeployments(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("deleting function")
-
- labels := internalFunctionLabels(s.instance)
- selector := apilabels.SelectorFromSet(labels)
-
- err := r.client.DeleteAllBySelector(ctx, &appsv1.Deployment{}, s.instance.GetNamespace(), selector)
- return nil, errors.Wrap(err, "while deleting delpoyments")
-}
-
-func buildStateFnUpdateDeployment(expectedSpec appsv1.DeploymentSpec, expectedLabels map[string]string) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
-
- s.deployments.Items[0].Spec = expectedSpec
- s.deployments.Items[0].Labels = expectedLabels
- deploymentName := s.deployments.Items[0].GetName()
-
- r.log.Info(fmt.Sprintf("updating Deployment %s", deploymentName))
-
- err := r.client.Update(ctx, &s.deployments.Items[0])
- if err != nil {
- return handleDeploymentOperationError(err, "while updating deployment")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonDeploymentUpdated,
- Message: fmt.Sprintf("Deployment %s updated", deploymentName),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func stateFnUpdateDeploymentStatus(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- if err := ctx.Err(); err != nil {
- return nil, errors.Wrap(err, "context error")
- }
-
- deploymentName := s.deployments.Items[0].GetName()
-
- // ready deployment
- if s.isDeploymentReady() {
- r.log.Info(fmt.Sprintf("deployment ready %q", deploymentName))
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonDeploymentReady,
- Message: fmt.Sprintf("Deployment %s is ready", deploymentName),
- }
-
- r.result = ctrl.Result{
- RequeueAfter: r.cfg.fn.FunctionReadyRequeueDuration,
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- // unhealthy deployment
- if s.hasDeploymentConditionFalseStatusWithReason(appsv1.DeploymentAvailable, MinimumReplicasUnavailable) {
- r.log.Info(fmt.Sprintf("deployment unhealthy: %q", deploymentName))
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonMinReplicasNotAvailable,
- Message: fmt.Sprintf("Minimum replicas not available for deployment %s", deploymentName),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- // deployment not ready
- if s.hasDeploymentConditionTrueStatus(appsv1.DeploymentProgressing) {
- r.log.Info(fmt.Sprintf("deployment %q not ready", deploymentName))
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonDeploymentWaiting,
- Message: fmt.Sprintf("Deployment %s is not ready yet", deploymentName),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- // deployment failed
- r.log.Info(fmt.Sprintf("deployment %q failed", deploymentName))
-
- yamlConditions, err := yaml.Marshal(s.deployments.Items[0].Status.Conditions)
- if err != nil {
- return nil, errors.Wrap(err, "while parsing deployment status")
- }
-
- msg := fmt.Sprintf("Deployment %s failed with condition: \n%s", deploymentName, yamlConditions)
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonDeploymentFailed,
- Message: msg,
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
-}
-
-func handleDeploymentOperationError(err error, msg string) (stateFn, error) {
- if k8serrors.IsInvalid(err) {
- return handleInvalidDeploymentStateFn(err), nil
- }
- return nil, errors.Wrap(err, msg)
-}
-
-func handleInvalidDeploymentStateFn(err error) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionFalse,
- Reason: serverlessv1alpha2.ConditionReasonDeploymentFailed,
- LastTransitionTime: metav1.Now(),
- Message: err.Error(),
- }
- r.result = ctrl.Result{Requeue: false}
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/deployment_test.go b/components/serverless/internal/controllers/serverless/deployment_test.go
deleted file mode 100644
index 47a7e5528..000000000
--- a/components/serverless/internal/controllers/serverless/deployment_test.go
+++ /dev/null
@@ -1,1103 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- "github.com/onsi/gomega"
- appsv1 "k8s.io/api/apps/v1"
- corev1 "k8s.io/api/core/v1"
- k8sresource "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/utils/ptr"
-)
-
-func TestFunctionReconciler_equalDeployments(t *testing.T) {
-
- ten := int32(10)
- zero := int32(0)
- type args struct {
- existing appsv1.Deployment
- expected appsv1.Deployment
- scalingEnabled bool
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "simple case - false on empty structs",
- args: args{
- existing: appsv1.Deployment{},
- expected: appsv1.Deployment{},
- scalingEnabled: true,
- },
- want: false, // yes, false, as we can't compare services without spec.template.containers, it makes no sense
- },
- {
- name: "equal deployments",
- args: args{
- existing: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "some-template-label-key": "some-template-label-val",
- },
- Annotations: map[string]string{
- "some-template-annotation-key": "some-template-annotation-val",
- },
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{
- Name: "env-name1",
- Value: "env-value1",
- }},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- expected: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "some-template-label-key": "some-template-label-val",
- },
- Annotations: map[string]string{
- "some-template-annotation-key": "some-template-annotation-val",
- },
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{
- Name: "env-name1",
- Value: "env-value1",
- }},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- scalingEnabled: true,
- },
- want: true,
- },
- {
- name: "different labels on pods",
- args: args{
- existing: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "some-template-label-key": "some-template-label-val",
- },
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{
- Name: "env-name1",
- Value: "env-value1",
- }},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- expected: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "some-template-label-key": "different-value", // that's different
- },
- },
- Spec: corev1.PodSpec{
-
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{
- Name: "env-name1",
- Value: "env-value1",
- }},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- scalingEnabled: true,
- },
- want: false,
- },
- {
- name: "different pod annotations",
- args: args{
- existing: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Image: "container-image1"}},
- },
- },
- },
- },
- expected: appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label-key": "label-value",
- },
- },
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Annotations: map[string]string{
- "here's something": "that should be different than in 'existing'",
- },
- },
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Image: "container-image1"}}},
- },
- },
- },
- scalingEnabled: true,
- },
- want: false,
- },
- {
- name: "different resources",
- args: args{
- existing: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
-
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- expected: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
-
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("400m"),
- corev1.ResourceMemory: k8sresource.MustParse("40Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- scalingEnabled: true,
- },
- want: false,
- },
- {
- name: "different env",
- args: args{
- existing: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
-
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{Name: "AAA", Value: "BBB"}},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("20m"),
- corev1.ResourceMemory: k8sresource.MustParse("20Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- expected: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
-
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
-
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- Env: []corev1.EnvVar{{Name: "CCC", Value: "DDD"}},
- Resources: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceCPU: k8sresource.MustParse("400m"),
- corev1.ResourceMemory: k8sresource.MustParse("40Mi"),
- },
- },
- },
- },
- },
- },
- },
- },
- scalingEnabled: false,
- },
- want: false,
- },
- {
- name: "different fn-image",
- args: args{
- existing: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Image: "container-image1",
- },
- },
- },
- },
- },
- },
- expected: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{
- {
- Image: "different-fn-image",
- },
- },
- },
- },
- },
- },
- scalingEnabled: true,
- },
- want: false,
- },
- {
- name: "scaling enabled and replicas differ",
- args: args{
- existing: fixDeploymentWithReplicas(1),
- expected: fixDeploymentWithReplicas(2),
- scalingEnabled: true,
- },
- want: false,
- },
- {
- name: "scaling enabled and replicas match",
- args: args{
- existing: fixDeploymentWithReplicas(3),
- expected: fixDeploymentWithReplicas(3),
- scalingEnabled: true,
- },
- want: true,
- },
- {
- name: "scaling disabled and replicas differ",
- args: args{
- existing: fixDeploymentWithReplicas(1),
- expected: fixDeploymentWithReplicas(2),
- scalingEnabled: false,
- },
- want: false,
- },
- {
- name: "scaling disabled and replicas match",
- args: args{
- existing: fixDeploymentWithReplicas(3),
- expected: fixDeploymentWithReplicas(3),
- scalingEnabled: false,
- },
- want: true,
- },
- {
- name: "different secret volumes",
- args: args{
- existing: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: podSpecWithSecretVolume(),
- },
- },
- },
- expected: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- Template: corev1.PodTemplateSpec{
- Spec: func() corev1.PodSpec {
- volumeName := "another-volume-name"
- podSpec := podSpecWithSecretVolume()
- podSpec.Volumes[0].Name = volumeName
- podSpec.Volumes[0].Secret.SecretName = "another-secret-name"
- podSpec.Containers[0].VolumeMounts[0].Name = volumeName
- podSpec.Containers[0].VolumeMounts[0].MountPath = "/another/mount/path"
- return podSpec
- }(),
- },
- },
- },
- },
- want: false,
- },
- {
- name: "different revision history limit",
- args: args{
- existing: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- RevisionHistoryLimit: &ten,
- },
- },
- expected: appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- RevisionHistoryLimit: &zero,
- },
- },
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalDeployments(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func Test_equalResources(t *testing.T) {
- type args struct {
- existing corev1.ResourceRequirements
- expected corev1.ResourceRequirements
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should work in easy case",
- args: args{
- existing: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("51Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("51m"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- },
- },
- expected: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("51Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("51m"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- },
- }},
- want: true,
- },
- {
- name: "should return false if cpu values do not match ",
- args: args{
- existing: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("51Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("51m"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- },
- },
- expected: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("51Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("52m"), // this one is different
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- },
- }},
- want: false,
- },
- {
- name: "should return false if no values are provided for existing",
- args: args{
- existing: corev1.ResourceRequirements{},
- expected: corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("50Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("50m"),
- },
- Requests: map[corev1.ResourceName]k8sresource.Quantity{
- corev1.ResourceMemory: k8sresource.MustParse("51Mi"),
- corev1.ResourceCPU: k8sresource.MustParse("51m"),
- },
- }},
- want: false,
- },
- {
- name: "should return true for two empty structs",
- args: args{
- existing: corev1.ResourceRequirements{},
- expected: corev1.ResourceRequirements{}},
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalResources(tt.args.expected, tt.args.existing)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func Test_equalSecretMounts(t *testing.T) {
- type args struct {
- existing corev1.PodSpec
- expected corev1.PodSpec
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should work in easy equal case",
- args: args{
- existing: podSpecWithSecretVolume(),
- expected: podSpecWithSecretVolume(),
- },
- want: true,
- },
- {
- name: "should return true for empty structs",
- args: args{
- existing: corev1.PodSpec{
- Volumes: []corev1.Volume{},
- Containers: []corev1.Container{
- {
- VolumeMounts: []corev1.VolumeMount{},
- },
- },
- },
- expected: corev1.PodSpec{
- Volumes: []corev1.Volume{},
- Containers: []corev1.Container{
- {
- VolumeMounts: []corev1.VolumeMount{},
- },
- },
- },
- },
- want: true,
- },
- {
- name: "should detect difference between secret names",
- args: args{
- existing: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Volumes[0].Secret.SecretName = "secret-name-1"
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Volumes[0].Secret.SecretName = "secret-name-2"
- return podSpec
- }(),
- },
- want: false,
- },
- {
- name: "should detect difference between mount path",
- args: args{
- existing: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Containers[0].VolumeMounts[0].MountPath = "/mount/path/1"
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Containers[0].VolumeMounts[0].MountPath = "/mount/path/2"
- return podSpec
- }(),
- },
- want: false,
- },
- {
- name: "should ignore volumes without secret",
- args: args{
- existing: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Volumes = append(podSpec.Volumes, notSecretVolume())
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- anotherNotSecretVolume := notSecretVolume()
- anotherNotSecretVolume.Name = "another-not-secret-volume"
- podSpec.Volumes = append(podSpec.Volumes, anotherNotSecretVolume)
- return podSpec
- }(),
- },
- want: true,
- },
- {
- name: "should detect difference for new secret volume",
- args: args{
- existing: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- newVolume := secretVolume()
- newVolume.Name = "new-volume"
- podSpec.Volumes = append(podSpec.Volumes, newVolume)
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- podSpec.Volumes[0].Secret.SecretName = "secret-name-2"
- return podSpec
- }(),
- },
- want: false,
- },
- {
- name: "should ignore volume mounts not connected with secret volumes",
- args: args{
- existing: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- notSecretVolume := notSecretVolume()
- podSpec.Volumes = append(podSpec.Volumes, notSecretVolume)
- notSecretVolumeMount := corev1.VolumeMount{
- Name: notSecretVolume.Name,
- MountPath: "/not/secret/volume/mount/path",
- }
- podSpec.Containers[0].VolumeMounts = append(podSpec.Containers[0].VolumeMounts, notSecretVolumeMount)
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- podSpec := podSpecWithSecretVolume()
- sizeLimit := k8sresource.MustParse("350Mi")
- podSpec.Volumes = append(podSpec.Volumes,
- corev1.Volume{
- Name: "another-not-secret-volume",
- VolumeSource: corev1.VolumeSource{
- EmptyDir: &corev1.EmptyDirVolumeSource{
- SizeLimit: &sizeLimit,
- },
- },
- })
- return podSpec
- }(),
- },
- want: true,
- },
- {
- name: "should ignore different order of volumes",
- args: func() args {
- firstVolume := secretVolume()
- firstVolume.Name = "first"
- secondVolume := secretVolume()
- secondVolume.Name = "second"
-
- existing := podSpecWithSecretVolume()
- existing.Volumes = []corev1.Volume{
- firstVolume,
- secondVolume,
- }
-
- expected := podSpecWithSecretVolume()
- expected.Volumes = []corev1.Volume{
- secondVolume,
- firstVolume,
- }
-
- return args{
- existing: existing,
- expected: expected,
- }
- }(),
- want: true,
- },
- {
- name: "should ignore different order of volumes",
- args: func() args {
- firstVolume := secretVolume()
- firstVolume.Name = "first"
- secondVolume := secretVolume()
- secondVolume.Name = "second"
- volumes := []corev1.Volume{
- firstVolume,
- secondVolume,
- }
-
- firstMount := secretVolumeMount()
- firstMount.Name = firstVolume.Name
- secondMount := secretVolumeMount()
- secondMount.Name = secondVolume.Name
-
- existing := podSpecWithSecretVolume()
- existing.Volumes = volumes
- existing.Containers[0].VolumeMounts = []corev1.VolumeMount{
- firstMount,
- secondMount,
- }
-
- expected := podSpecWithSecretVolume()
- expected.Volumes = volumes
- expected.Containers[0].VolumeMounts = []corev1.VolumeMount{
- secondMount,
- firstMount,
- }
-
- return args{
- existing: existing,
- expected: expected,
- }
- }(),
- want: true,
- },
- {
- name: "should ignore different volume mounts in not first container",
- // now we works only with single container
- args: args{
- existing: func() corev1.PodSpec {
- someSecretVolumeMount := secretVolumeMount()
- someSecretVolumeMount.MountPath = "/some/secret/volume/mount"
- someSecondContainer := corev1.Container{
- VolumeMounts: []corev1.VolumeMount{
- someSecretVolumeMount,
- },
- }
- podSpec := podSpecWithSecretVolume()
- podSpec.Containers = append(podSpec.Containers, someSecondContainer)
- return podSpec
- }(),
- expected: func() corev1.PodSpec {
- anotherSecretVolumeMount := secretVolumeMount()
- anotherSecretVolumeMount.MountPath = "/another/secret/volume/mount"
- anotherSecondContainer := corev1.Container{
- VolumeMounts: []corev1.VolumeMount{
- anotherSecretVolumeMount,
- },
- }
- podSpec := podSpecWithSecretVolume()
- podSpec.Containers = append(podSpec.Containers, anotherSecondContainer)
- return podSpec
- }(),
- },
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalSecretMounts(tt.args.expected, tt.args.existing)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_hasDeploymentConditionTrueStatus(t *testing.T) {
- type args struct {
- conditions []appsv1.DeploymentCondition
- conditionType appsv1.DeploymentConditionType
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "simple case",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- }}, conditionType: appsv1.DeploymentProgressing},
- want: true,
- },
- {
- name: "simple case - 2 conditions",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentReplicaFailure,
- Status: corev1.ConditionFalse,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- }},
- conditionType: appsv1.DeploymentProgressing},
- want: true,
- },
- {
- name: "fails on empty condition",
- args: args{conditions: []appsv1.DeploymentCondition{}, conditionType: appsv1.DeploymentProgressing},
- want: false,
- },
- {
- name: "fails if there is no proper condition",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentReplicaFailure,
- Status: corev1.ConditionFalse,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionFalse,
- }},
- conditionType: appsv1.DeploymentAvailable,
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- deployments: appsv1.DeploymentList{
- Items: []appsv1.Deployment{
- {Status: appsv1.DeploymentStatus{Conditions: tt.args.conditions}},
- },
- },
- }
-
- got := s.hasDeploymentConditionTrueStatus(tt.args.conditionType)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_hasDeploymentConditionTrueStatusWithReason(t *testing.T) {
- type args struct {
- conditions []appsv1.DeploymentCondition
- conditionType appsv1.DeploymentConditionType
- conditionReason string
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "simple case",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: "SomeReason",
- }}, conditionType: appsv1.DeploymentProgressing, conditionReason: "SomeReason"},
- want: true,
- },
- {
- name: "simple case - 2 conditions",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentReplicaFailure,
- Status: corev1.ConditionFalse,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: "SomeReason",
- }},
- conditionType: appsv1.DeploymentProgressing, conditionReason: "SomeReason"},
- want: true,
- },
- {
- name: "fails on empty condition",
- args: args{conditions: []appsv1.DeploymentCondition{}, conditionType: appsv1.DeploymentProgressing},
- want: false,
- },
- {
- name: "fails if there is no proper condition",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentReplicaFailure,
- Status: corev1.ConditionFalse,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: "SomeReason",
- }},
- conditionType: appsv1.DeploymentAvailable, conditionReason: "SomeReason",
- },
- want: false,
- },
- {
- name: "fails if there is proper condition with wrong reason",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentReplicaFailure,
- Status: corev1.ConditionFalse,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: "SomeReason",
- }},
- conditionType: appsv1.DeploymentProgressing, conditionReason: "AnotherReason",
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- deployments: appsv1.DeploymentList{
- Items: []appsv1.Deployment{
- {
- Status: appsv1.DeploymentStatus{Conditions: tt.args.conditions},
- },
- },
- },
- }
- got := s.hasDeploymentConditionTrueStatusWithReason(tt.args.conditionType, tt.args.conditionReason)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_isDeploymentReady(t *testing.T) {
- type args struct {
- conditions []appsv1.DeploymentCondition
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "fail on 1 good condition",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: NewRSAvailableReason,
- }}},
- want: false,
- },
- {
- name: "2 good conditions",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentAvailable,
- Status: corev1.ConditionTrue,
- Reason: MinimumReplicasAvailable,
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: NewRSAvailableReason,
- }}},
- want: true,
- },
- {
- name: "Fails on empty condition",
- args: args{conditions: []appsv1.DeploymentCondition{}},
- want: false,
- },
- {
- name: "fails if there is one condition with wrong reason",
- args: args{conditions: []appsv1.DeploymentCondition{{
- Type: appsv1.DeploymentAvailable,
- Status: corev1.ConditionTrue,
- Reason: "WrongReason",
- }, {
- Type: appsv1.DeploymentProgressing,
- Status: corev1.ConditionTrue,
- Reason: NewRSAvailableReason,
- }}},
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- deployments: appsv1.DeploymentList{
- Items: []appsv1.Deployment{
- {
- Status: appsv1.DeploymentStatus{Conditions: tt.args.conditions},
- },
- },
- }}
- got := s.isDeploymentReady()
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func fixDeploymentWithReplicas(replicas int32) appsv1.Deployment {
- zero := int32(0)
- return appsv1.Deployment{
- Spec: appsv1.DeploymentSpec{
- RevisionHistoryLimit: &zero,
- Replicas: &replicas,
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{}},
- },
- },
- },
- }
-}
-
-func secretVolume() corev1.Volume {
- return corev1.Volume{
- Name: "volume-name",
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: "secret-name",
- DefaultMode: ptr.To[int32](0644),
- Optional: ptr.To[bool](false),
- },
- },
- }
-}
-
-func notSecretVolume() corev1.Volume {
- sizeLimit := k8sresource.MustParse("50Mi")
- return corev1.Volume{
- Name: "not-secret-volume",
- VolumeSource: corev1.VolumeSource{
- EmptyDir: &corev1.EmptyDirVolumeSource{
- SizeLimit: &sizeLimit,
- },
- },
- }
-}
-
-func secretVolumeMount() corev1.VolumeMount {
- return corev1.VolumeMount{
- Name: "volume-name",
- ReadOnly: false,
- MountPath: "/mount/path",
- }
-}
-
-func podSpecWithSecretVolume() corev1.PodSpec {
- return corev1.PodSpec{
- Volumes: []corev1.Volume{
- secretVolume(),
- },
- Containers: []corev1.Container{
- {
- VolumeMounts: []corev1.VolumeMount{
- secretVolumeMount(),
- },
- },
- },
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/event_filter.go b/components/serverless/internal/controllers/serverless/event_filter.go
deleted file mode 100644
index b4efd078a..000000000
--- a/components/serverless/internal/controllers/serverless/event_filter.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package serverless
-
-import (
- "reflect"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "go.uber.org/zap"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func IsNotFunctionStatusUpdate(log *zap.SugaredLogger) func(event.UpdateEvent) bool {
- return func(event event.UpdateEvent) bool {
- if event.ObjectOld == nil || event.ObjectNew == nil {
- return true
- }
-
- log.Debug("old: ", event.ObjectOld.GetName())
- log.Debug("new: ", event.ObjectNew.GetName())
-
- oldFn, ok := event.ObjectOld.(*serverlessv1alpha2.Function)
- if !ok {
- v := reflect.ValueOf(event.ObjectOld)
- log.Debug("Can't cast to function from type: ", v.Type())
- return true
- }
-
- newFn, ok := event.ObjectNew.(*serverlessv1alpha2.Function)
- if !ok {
- v := reflect.ValueOf(event.ObjectNew)
- log.Debug("Can't cast to function from type: ", v.Type())
- return true
- }
-
- equalStatus := equalFunctionStatus(oldFn.Status, newFn.Status)
- log.Debug("Statuses are equal: ", equalStatus)
-
- return equalStatus
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/event_filter_test.go b/components/serverless/internal/controllers/serverless/event_filter_test.go
deleted file mode 100644
index e0cbb6812..000000000
--- a/components/serverless/internal/controllers/serverless/event_filter_test.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/assert"
- "go.uber.org/zap"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "sigs.k8s.io/controller-runtime/pkg/event"
-)
-
-func TestIsFunctionStatusUpdate(t *testing.T) {
- //GIVEN
-
- nopLogger := zap.NewNop().Sugar()
-
- testCases := map[string]struct {
- event event.UpdateEvent
- result bool
- }{
- "Function status is not updated": {
- result: true,
- event: event.UpdateEvent{
- ObjectOld: &serverlessv1alpha2.Function{},
- ObjectNew: &serverlessv1alpha2.Function{},
- },
- },
- "Function status is updated": {
- result: false,
- event: event.UpdateEvent{
- ObjectOld: &serverlessv1alpha2.Function{},
- ObjectNew: &serverlessv1alpha2.Function{
- Status: serverlessv1alpha2.FunctionStatus{
- Conditions: []serverlessv1alpha2.Condition{
- {
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Time{},
- Reason: "test reason",
- Message: "test message",
- },
- },
- },
- },
- },
- },
- "Not function update event": {
- result: true,
- event: event.UpdateEvent{
- ObjectOld: &corev1.Pod{},
- ObjectNew: &corev1.Pod{},
- },
- },
- }
-
- for name, testCase := range testCases {
- t.Run(name, func(t *testing.T) {
- fn := IsNotFunctionStatusUpdate(nopLogger)
- //WHEN
- actual := fn(testCase.event)
- //THEN
- assert.Equal(t, testCase.result, actual)
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/fixtures_test.go b/components/serverless/internal/controllers/serverless/fixtures_test.go
deleted file mode 100644
index 1d9269d08..000000000
--- a/components/serverless/internal/controllers/serverless/fixtures_test.go
+++ /dev/null
@@ -1,188 +0,0 @@
-package serverless
-
-import (
- "fmt"
- "math/rand"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func newTestGitFunction(namespace, name string, auth *serverlessv1alpha2.RepositoryAuth, minReplicas, maxReplicas int, continuousGitCheckout bool) *serverlessv1alpha2.Function {
- one := int32(minReplicas)
- two := int32(maxReplicas)
- //nolint:gosec
- suffix := rand.Int()
- annotations := map[string]string{}
- if continuousGitCheckout {
- annotations[continuousGitCheckoutAnnotation] = "true"
- }
-
- return &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("%s-%d", name, suffix),
- Namespace: namespace,
- Annotations: annotations,
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "https://mock.repo/kyma/test",
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "/",
- Reference: "main",
- },
- Auth: auth,
- },
- },
- Runtime: serverlessv1alpha2.NodeJs20,
- Env: []corev1.EnvVar{
- {
- Name: "TEST_1",
- Value: "VAL_1",
- },
- {
- Name: "TEST_2",
- Value: "VAL_2",
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Resources: &corev1.ResourceRequirements{},
- },
- },
- ScaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: &one,
- MaxReplicas: &two,
- },
- Labels: map[string]string{
- testBindingLabel1: "foobar",
- testBindingLabel2: testBindingLabelValue,
- "foo": "bar",
- },
- Annotations: map[string]string{
- "foo": "bar",
- },
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {
- SecretName: "secret-name-1",
- MountPath: "/mount/path/1",
- },
- {
- SecretName: "secret-name-2",
- MountPath: "/mount/path/2",
- },
- },
- },
- }
-}
-
-func newFixFunction(namespace, name string, minReplicas, maxReplicas int) *serverlessv1alpha2.Function {
- one := int32(minReplicas)
- two := int32(maxReplicas)
- //nolint:gosec
- suffix := rand.Int()
-
- return &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("%s-%d", name, suffix),
- Namespace: namespace,
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "module.exports = {main: function(event, context) {return 'Hello World.'}}",
- Dependencies: " ",
- },
- },
- Runtime: serverlessv1alpha2.NodeJs20,
- Env: []corev1.EnvVar{
- {
- Name: "TEST_1",
- Value: "VAL_1",
- },
- {
- Name: "TEST_2",
- Value: "VAL_2",
- },
- },
- ScaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: &one,
- MaxReplicas: &two,
- },
- Labels: map[string]string{
- testBindingLabel1: "foobar",
- testBindingLabel2: testBindingLabelValue,
- "foo": "bar",
- },
- Annotations: map[string]string{
- "foo": "bar",
- },
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {
- SecretName: "secret-name-1",
- MountPath: "/mount/path/1",
- },
- {
- SecretName: "secret-name-2",
- MountPath: "/mount/path/2",
- },
- },
- },
- }
-}
-
-func newFixFunctionWithCustomImage(namespace, name, runtimeImageOverride string, minReplicas, maxReplicas int) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, minReplicas, maxReplicas)
- fn.Spec.RuntimeImageOverride = runtimeImageOverride
- return fn
-}
-
-func newFixFunctionWithFunctionResourceProfile(namespace, name, profile string) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, 1, 1)
- fn.Spec.ResourceConfiguration = &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Profile: profile},
- }
- return fn
-}
-
-func newFixFunctionWithBuildResourceProfile(namespace, name, profile string) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, 1, 1)
- fn.Spec.ResourceConfiguration = &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Profile: profile},
- }
- return fn
-}
-
-func newFixFunctionWithRuntime(namespace, name string, runtime serverlessv1alpha2.Runtime) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, 1, 1)
- fn.Spec.Runtime = runtime
- return fn
-}
-
-func newFixFunctionWithCustomFunctionResource(namespace, name string, resources *corev1.ResourceRequirements) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, 1, 1)
- fn.Spec.ResourceConfiguration = &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: resources},
- }
- return fn
-}
-
-func newFixFunctionWithCustomBuildResource(namespace, name string, resources *corev1.ResourceRequirements) *serverlessv1alpha2.Function {
- fn := newFixFunction(namespace, name, 1, 1)
- fn.Spec.ResourceConfiguration = &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: resources},
- }
- return fn
-}
-
-func newTestSecret(name, namespace string, stringData map[string]string) *corev1.Secret {
- return &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- StringData: stringData,
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/fsm.go b/components/serverless/internal/controllers/serverless/fsm.go
deleted file mode 100644
index f98fc9587..000000000
--- a/components/serverless/internal/controllers/serverless/fsm.go
+++ /dev/null
@@ -1,300 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- "reflect"
- "runtime"
- "strings"
- "time"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/client-go/tools/record"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-type stateFn func(context.Context, *reconciler, *systemState) (stateFn, error)
-
-type k8s struct {
- client resource.Client
- recorder record.EventRecorder
- statsCollector StatsCollector
-}
-
-type cfg struct {
- docker DockerConfig
- fn FunctionConfig
-}
-
-// nolint
-type out struct {
- result ctrl.Result
-}
-
-type reconciler struct {
- cfg cfg
- fn stateFn
- log *zap.SugaredLogger
- gitClient GitClient
- k8s
- out
-}
-
-const (
- continuousGitCheckoutAnnotation = "serverless.kyma-project.io/continuousGitCheckout"
-)
-
-func (m *reconciler) reconcile(ctx context.Context, f serverlessv1alpha2.Function) (ctrl.Result, error) {
- state := systemState{instance: f}
- var err error
-loop:
- for m.fn != nil {
- select {
- case <-ctx.Done():
- err = ctx.Err()
- break loop
-
- default:
- m.log.With("stateFn", m.stateFnName()).Debug("next state")
- m.fn, err = m.fn(ctx, m, &state)
- }
- }
-
- m.log.With("requeueAfter", m.result.RequeueAfter).
- With("requeue", m.result.Requeue).
- With("error", err).
- Info("reconciliation result")
-
- return m.result, err
-}
-
-func (m *reconciler) stateFnName() string {
- fullName := runtime.FuncForPC(reflect.ValueOf(m.fn).Pointer()).Name()
- splitFullName := strings.Split(fullName, ".")
-
- if len(splitFullName) < 3 {
- return fullName
- }
- shortName := splitFullName[2]
- return shortName
-}
-
-var (
- // ErrBuildReconcilerFailed is returned if it is impossible to create reconciler build function
- ErrBuildReconcilerFailed = errors.New("build reconciler failed")
-)
-
-// this function is a terminator
-func buildGenericStatusUpdateStateFn(condition serverlessv1alpha2.Condition, repo *serverlessv1alpha2.Repository, commit string) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- if condition.LastTransitionTime.IsZero() {
- return nil, fmt.Errorf("LastTransitionTime for condition %s is not set", condition.Type)
- }
- existingFunction := &serverlessv1alpha2.Function{}
-
- err := r.client.Get(ctx, types.NamespacedName{Namespace: s.instance.Namespace, Name: s.instance.Name}, existingFunction)
- if err != nil {
- return nil, errors.Wrap(client.IgnoreNotFound(err), "while getting function instance")
- }
-
- updatedStatus := existingFunction.Status.DeepCopy()
- updatedStatus.Conditions = updateCondition(existingFunction.Status.Conditions, condition)
-
- r.populateStatusFromResourceConfiguration(updatedStatus, s)
- if err := r.populateStatusFromSystemState(updatedStatus, s); err != nil {
- return nil, errors.Wrap(err, "while setting up Status")
- }
-
- isGitType := s.instance.TypeOf(serverlessv1alpha2.FunctionTypeGit)
- if isGitType && repo != nil {
- updatedStatus.Repository = *repo
- updatedStatus.Commit = commit
- }
-
- if err := r.updateFunctionStatusWithEvent(ctx, existingFunction, updatedStatus, condition); err != nil {
- r.log.Warnf("while updating function status: %s", err)
- return nil, errors.Wrap(err, "while updating function status")
- }
- r.statsCollector.UpdateReconcileStats(&s.instance, condition)
- return nil, nil
- }
-}
-
-func (m *reconciler) populateStatusFromSystemState(status *serverlessv1alpha2.FunctionStatus, s *systemState) error {
- status.Runtime = s.instance.Spec.Runtime
- status.RuntimeImage = s.instance.Status.RuntimeImage
- if s.instance.Spec.RuntimeImageOverride != "" {
- status.RuntimeImage = s.instance.Spec.RuntimeImageOverride
- }
- status.RuntimeImageOverride = s.instance.Spec.RuntimeImageOverride
-
- // set scale sub-resource
- selector, err := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: s.deploymentSelectorLabels()})
- if err != nil {
- m.log.Warnf("failed to get selector for labelSelector: %w", err)
- return errors.Wrap(err, "while getting selectors")
- }
- status.PodSelector = selector.String()
-
- if len(s.deployments.Items) > 0 {
- status.Replicas = s.deployments.Items[0].Status.Replicas
- }
- return nil
-}
-
-func (m *reconciler) populateStatusFromResourceConfiguration(status *serverlessv1alpha2.FunctionStatus, s *systemState) {
- defaultJobPreset := m.cfg.fn.ResourceConfig.BuildJob.Resources.DefaultPreset
- defaultFunctionPreset := m.cfg.fn.ResourceConfig.Function.Resources.DefaultPreset
-
- if s.instance.Spec.ResourceConfiguration == nil {
- status.BuildResourceProfile = defaultJobPreset
- status.FunctionResourceProfile = defaultFunctionPreset
- return
- }
-
- status.BuildResourceProfile = getUsedResourcePreset(s.instance.Spec.ResourceConfiguration.Build, defaultJobPreset)
- status.FunctionResourceProfile = getUsedResourcePreset(s.instance.Spec.ResourceConfiguration.Function, defaultFunctionPreset)
-}
-
-func getUsedResourcePreset(resourceRequirements *serverlessv1alpha2.ResourceRequirements, defaultPreset string) string {
- if resourceRequirements == nil {
- return defaultPreset
- }
-
- if resourceRequirements.Resources != nil {
- return "custom"
- }
-
- return resourceRequirements.Profile
-}
-
-func (m *reconciler) updateFunctionStatusWithEvent(ctx context.Context, f *serverlessv1alpha2.Function, s *serverlessv1alpha2.FunctionStatus, condition serverlessv1alpha2.Condition) error {
-
- if reflect.DeepEqual(f.Status, s) {
- return nil
- }
- f.Status = *s
- if err := m.client.Status().Update(ctx, f); err != nil {
- return errors.Wrap(err, "while updating function status")
- }
- eventType := "Normal"
- if condition.Status == corev1.ConditionFalse {
- eventType = "Warning"
- }
-
- m.recorder.Event(f, eventType, string(condition.Reason), condition.Message)
- return nil
-}
-
-func buildStatusUpdateStateFnWithCondition(condition serverlessv1alpha2.Condition) stateFn {
- return buildGenericStatusUpdateStateFn(condition, nil, "")
-}
-
-func stateFnGitCheckSources(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- var auth *git.AuthOptions
- if s.instance.Spec.Source.GitRepository.Auth != nil {
- var secret corev1.Secret
- key := client.ObjectKey{
- Namespace: s.instance.Namespace,
- Name: s.instance.Spec.Source.GitRepository.Auth.SecretName,
- }
-
- if err := r.client.Get(ctx, key, &secret); err != nil {
- return nil, errors.Wrap(err, "while getting secret")
- }
-
- auth = &git.AuthOptions{
- Type: git.RepositoryAuthType(s.instance.Spec.Source.GitRepository.Auth.Type),
- Credentials: readSecretData(secret.Data),
- SecretName: s.instance.Spec.Source.GitRepository.Auth.SecretName,
- }
- }
-
- options := git.Options{
- URL: s.instance.Spec.Source.GitRepository.URL,
- Reference: s.instance.Spec.Source.GitRepository.Reference,
- Auth: auth,
- }
-
- if skipGitSourceCheck(s.instance, r.cfg) {
- r.log.Info(fmt.Sprintf("skipping function [%s] source check", s.instance.Name))
- expectedJob := s.buildGitJob(options, r.cfg)
- return buildStateFnCheckImageJob(expectedJob), nil
- }
-
- var revision string
- var err error
- revision, err = r.gitClient.LastCommit(options)
- if err != nil {
- r.log.Error(err, " while fetching last commit")
- var errMsg string
- r.result, errMsg = NextRequeue(err)
- // TODO: This return masks the error from r.syncRevision() and doesn't pass it to the controller. This should be fixed in a follow up PR.
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonSourceUpdateFailed,
- Message: errMsg,
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- srcChanged := s.gitFnSrcChanged(revision)
- if !srcChanged {
- expectedJob := s.buildGitJob(options, r.cfg)
- return buildStateFnCheckImageJob(expectedJob), nil
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonSourceUpdated,
- Message: fmt.Sprintf("Sources %s updated", s.instance.Name),
- }
-
- repository := serverlessv1alpha2.Repository{
- Reference: s.instance.Spec.Source.GitRepository.Reference,
- BaseDir: s.instance.Spec.Source.GitRepository.BaseDir,
- }
-
- return buildGenericStatusUpdateStateFn(condition, &repository, revision), nil
-}
-
-func stateFnInitialize(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- if err := ctx.Err(); err != nil {
- return nil, errors.Wrap(err, "context error")
- }
-
- isGitType := s.instance.TypeOf(serverlessv1alpha2.FunctionTypeGit)
- if isGitType {
- return stateFnGitCheckSources, nil
- }
-
- return stateFnInlineCheckSources, nil
-}
-
-func skipGitSourceCheck(f serverlessv1alpha2.Function, cfg cfg) bool {
- if v, ok := f.Annotations[continuousGitCheckoutAnnotation]; ok && strings.ToLower(v) == "true" {
- return false
- }
-
- // ConditionConfigurationReady is set to true for git functions when the source is updated.
- // if not, this is a new function, we need to do git check.
- configured := f.Status.Condition(serverlessv1alpha2.ConditionConfigurationReady)
- if configured == nil || !configured.IsTrue() {
- return false
- }
-
- return time.Since(configured.LastTransitionTime.Time) < cfg.fn.FunctionReadyRequeueDuration
-}
diff --git a/components/serverless/internal/controllers/serverless/fsm_test.go b/components/serverless/internal/controllers/serverless/fsm_test.go
deleted file mode 100644
index dbd34dded..000000000
--- a/components/serverless/internal/controllers/serverless/fsm_test.go
+++ /dev/null
@@ -1,289 +0,0 @@
-package serverless
-
-import (
- "context"
- "errors"
- "fmt"
- "testing"
- "time"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/automock"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/mock"
- "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/apimachinery/pkg/types"
- "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/tools/record"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-var (
- testResult ctrl.Result
- errTest = errors.New("test error")
-
- testStateFn1 = func(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("test state function #1")
- return testStateFn2, nil
- }
-
- testStateFn2 = func(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("test state function #2")
- return nil, nil
- }
-
- testStateFn3 = func(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("test state function #3")
- return testStateFnErr, nil
- }
-
- testStateFnErr = func(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("test error state")
- return nil, errTest
- }
-)
-
-func Test_reconciler_reconcile(t *testing.T) {
- type fields struct {
- fn stateFn
- }
- tests := []struct {
- name string
- fields fields
- want ctrl.Result
- wantErr error
- }{
- {
- name: "happy path",
- fields: fields{
- fn: testStateFn2,
- },
- },
- {
- name: "expect error",
- fields: fields{
- fn: testStateFnErr,
- },
- wantErr: errTest,
- },
- {
- name: "happy path nested",
- fields: fields{
- fn: testStateFn1,
- },
- },
- {
- name: "expect error nested",
- fields: fields{
- fn: testStateFn3,
- },
- wantErr: errTest,
- want: testResult,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- ctx := context.Background()
- log := zap.NewNop().Sugar()
- m := &reconciler{
- fn: tt.fields.fn,
- log: log,
- }
-
- m.log.Info("starting...")
-
- got, err := m.reconcile(ctx, v1alpha2.Function{})
-
- m.log.Info("done")
-
- if err != nil {
- require.EqualError(t, tt.wantErr, err.Error())
- }
-
- require.Equal(t, tt.want, got)
- })
- }
-}
-
-func dummyFunctionForTest_stateFnName(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- return nil, nil
-}
-
-func dummyInlineFunctionForTest_stateFnName() stateFn {
- return func(ctx context.Context, r *reconciler, ss *systemState) (stateFn, error) {
- return nil, nil
- }
-}
-
-func Test_stateFnName(t *testing.T) {
- tests := []struct {
- name string
- fn stateFn
- want string
- wantErr error
- }{
- {
- name: "function name is short",
- fn: dummyFunctionForTest_stateFnName,
- want: "dummyFunctionForTest_stateFnName",
- },
- {
- name: "function is returned from an inline function",
- fn: dummyInlineFunctionForTest_stateFnName(),
- want: "Test_stateFnName",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- m := &reconciler{
- fn: tt.fn,
- }
-
- got := m.stateFnName()
-
- require.Equal(t, tt.want, got)
- })
- }
-}
-
-func Test_buildStateFnGenericUpdateStatus(t *testing.T) {
- ctx := context.Background()
- // used in two tests, so defined here.
- testFunction := newFixFunction("test-namespace", "test-func", 1, 1)
- state := &systemState{instance: *testFunction}
-
- stateReconciler := createFakeStateReconcilerWithTestFunction(t, testFunction)
-
- t.Run("ConfigMapCreated", func(t *testing.T) {
- givenCondition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now().Rfc3339Copy(),
- Reason: serverlessv1alpha2.ConditionReasonConfigMapCreated,
- Message: "ConfigMap test-configmap created",
- }
-
- statusUpdateFunc := buildGenericStatusUpdateStateFn(givenCondition, nil, "")
- nextStateFunc, err := statusUpdateFunc(ctx, stateReconciler, state)
-
- require.Nil(t, nextStateFunc)
- require.NoError(t, err)
-
- err = stateReconciler.client.Get(ctx, types.NamespacedName{Namespace: "test-namespace", Name: testFunction.Name}, testFunction)
-
- require.NoError(t, err)
- require.NotEmpty(t, testFunction.Status)
-
- gotCondition := testFunction.Status.Condition(serverlessv1alpha2.ConditionConfigurationReady)
- require.NotNil(t, gotCondition)
-
- require.True(t, equalConditions([]serverlessv1alpha2.Condition{givenCondition},
- []serverlessv1alpha2.Condition{*gotCondition}))
- })
-
- t.Run("ConfigMapUpdated", func(t *testing.T) {
- err := stateReconciler.client.Get(ctx, types.NamespacedName{Namespace: "test-namespace", Name: testFunction.Name}, testFunction)
- require.NoError(t, err)
- require.NotNil(t, testFunction.Status)
-
- existingCondition := testFunction.Status.Condition(serverlessv1alpha2.ConditionConfigurationReady)
- require.NotNil(t, existingCondition)
-
- updatedCondition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Time{Time: time.Now().Add(5 * time.Minute)}.Rfc3339Copy(),
- Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated,
- Message: "ConfigMap test-configmap Updated",
- }
-
- statusUpdateFunc := buildGenericStatusUpdateStateFn(updatedCondition, nil, "")
- nextStateFunc, err := statusUpdateFunc(ctx, stateReconciler, state)
- require.Nil(t, nextStateFunc)
- require.NoError(t, err)
-
- err = stateReconciler.client.Get(ctx, types.NamespacedName{Namespace: "test-namespace", Name: testFunction.Name}, testFunction)
- require.NoError(t, err)
- require.NotEmpty(t, testFunction.Status)
-
- gotCondition := testFunction.Status.Condition(serverlessv1alpha2.ConditionConfigurationReady)
- require.NotNil(t, gotCondition)
-
- // The existing condition has been updated
- require.False(t, equalConditions([]serverlessv1alpha2.Condition{*existingCondition},
- []serverlessv1alpha2.Condition{*gotCondition}))
-
- // The given condition has been set correctly
- require.True(t, equalConditions([]serverlessv1alpha2.Condition{updatedCondition},
- []serverlessv1alpha2.Condition{*gotCondition}))
- })
-
- t.Run("SourceUpdated", func(t *testing.T) {
- testFunction := newTestGitFunction("test-namespace", "test-git-func", nil, 1, 1, true)
- state := &systemState{instance: *testFunction}
-
- stateReconciler := createFakeStateReconcilerWithTestFunction(t, testFunction)
-
- givenCondition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now().Rfc3339Copy(),
- Reason: serverlessv1alpha2.ConditionReasonSourceUpdated,
- Message: fmt.Sprintf("Sources %s updated", state.instance.Name),
- }
-
- statusUpdateFunc := buildGenericStatusUpdateStateFn(givenCondition, &testFunction.Spec.Source.GitRepository.Repository, "123456")
- nextStateFunc, err := statusUpdateFunc(ctx, stateReconciler, state)
-
- require.Nil(t, nextStateFunc)
- require.NoError(t, err)
-
- err = stateReconciler.client.Get(ctx, types.NamespacedName{Namespace: "test-namespace", Name: testFunction.Name}, testFunction)
- require.NoError(t, err)
- require.NotEmpty(t, testFunction.Status)
-
- gotCondition := testFunction.Status.Condition(serverlessv1alpha2.ConditionConfigurationReady)
- require.NotNil(t, gotCondition)
- require.True(t, equalConditions([]serverlessv1alpha2.Condition{givenCondition}, []serverlessv1alpha2.Condition{*gotCondition}))
-
- require.Equal(t, testFunction.Spec.Source.GitRepository.BaseDir, testFunction.Status.BaseDir)
- })
-
-}
-
-func createFakeStateReconcilerWithTestFunction(t *testing.T, testFunction *serverlessv1alpha2.Function) *reconciler {
- require.NoError(t, scheme.AddToScheme(scheme.Scheme))
- require.NoError(t, serverlessv1alpha2.AddToScheme(scheme.Scheme))
- client := fake.NewClientBuilder().WithScheme(scheme.Scheme).WithObjects(testFunction).WithStatusSubresource(&serverlessv1alpha2.Function{}).Build()
-
- resourceClient := resource.New(client, scheme.Scheme)
-
- log := zap.NewNop().Sugar()
-
- gitFactory := &automock.GitClientFactory{}
- gitFactory.On("GetGitClient", mock.Anything).Return(nil)
-
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- functionReconciler := NewFunctionReconciler(resourceClient, log, FunctionConfig{}, gitFactory, record.NewFakeRecorder(100), statsCollector, make(chan bool))
- return &reconciler{
- fn: functionReconciler.initStateFunction,
- log: log,
- k8s: k8s{
- client: functionReconciler.client,
- recorder: functionReconciler.recorder,
- statsCollector: functionReconciler.statsCollector,
- },
- cfg: cfg{
- fn: functionReconciler.config,
- docker: DockerConfig{},
- },
- gitClient: functionReconciler.gitFactory.GetGitClient(log),
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/function_controller_test.go b/components/serverless/internal/controllers/serverless/function_controller_test.go
deleted file mode 100644
index 1d19a5b00..000000000
--- a/components/serverless/internal/controllers/serverless/function_controller_test.go
+++ /dev/null
@@ -1,363 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
-)
-
-func TestFunctionReconciler_getConditionStatus(t *testing.T) {
- type args struct {
- conditions []serverlessv1alpha2.Condition
- conditionType serverlessv1alpha2.ConditionType
- }
- tests := []struct {
- name string
- args args
- want corev1.ConditionStatus
- }{
- {
- name: "Should correctly return proper status given slice of conditions",
- args: args{
- conditions: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue},
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- },
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: corev1.ConditionTrue,
- },
- {
- name: "Should correctly return status unknown if there's no needed conditionType",
- args: args{
- conditions: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- },
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: corev1.ConditionUnknown,
- },
- {
- name: "Should correctly return status unknown if slice is empty",
- args: args{
- conditions: []serverlessv1alpha2.Condition{},
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: corev1.ConditionUnknown,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := getConditionStatus(tt.args.conditions, tt.args.conditionType)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_equalConditions(t *testing.T) {
- type args struct {
- existing []serverlessv1alpha2.Condition
- expected []serverlessv1alpha2.Condition
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should work on the same slices",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue, Reason: serverlessv1alpha2.ConditionReasonServiceCreated, Message: "some message"},
- {Type: serverlessv1alpha2.ConditionBuildReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonJobFinished, Message: "blabla"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue, Reason: serverlessv1alpha2.ConditionReasonServiceCreated, Message: "some message"},
- {Type: serverlessv1alpha2.ConditionBuildReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonJobFinished, Message: "blabla"}},
- },
- want: true,
- },
- {
- name: "should return false on slices with different lengths",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue, Reason: serverlessv1alpha2.ConditionReasonServiceCreated, Message: "some message"},
- {Type: serverlessv1alpha2.ConditionBuildReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonJobFinished, Message: "blabla"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue, Reason: serverlessv1alpha2.ConditionReasonServiceCreated, Message: "some message"},
- },
- },
- want: false,
- },
- {
- name: "should return false on different conditions",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionBuildReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- },
- want: false,
- },
- {
- name: "should return false on different Statuses",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionUnknown, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- },
- want: false,
- },
- {
- name: "should return false on different Reasons",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapCreated, Message: "msg"}},
- },
- want: false,
- },
- {
- name: "should return false on different messages",
- args: args{
- existing: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg"}},
- expected: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapUpdated, Message: "msg-different"}},
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalConditions(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_mapsEqual(t *testing.T) {
- type args struct {
- existing map[string]string
- expected map[string]string
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "two empty maps are the same",
- args: args{
- expected: map[string]string{},
- existing: map[string]string{},
- },
- want: true,
- },
- {
- name: "two maps with different len are different",
- args: args{
- expected: map[string]string{"some": "things"},
- existing: map[string]string{},
- },
- want: false,
- },
- {
- name: "two maps with same content are same",
- args: args{
- expected: map[string]string{"some": "things"},
- existing: map[string]string{"some": "things"},
- },
- want: true,
- },
- {
- name: "two maps with same content, but in different order, are same",
- args: args{
- expected: map[string]string{
- "some": "things",
- "should not": "be seen",
- },
- existing: map[string]string{
- "should not": "be seen",
- "some": "things",
- },
- },
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := mapsEqual(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_envsEqual(t *testing.T) {
- envVarSrc := &corev1.EnvVarSource{
- ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: "some-name",
- },
- Key: "some-key",
- Optional: nil,
- },
- }
-
- envVarSrc2 := &corev1.EnvVarSource{
- ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: "some-name",
- },
- Key: "some-key",
- Optional: nil,
- },
- }
-
- differentEnvVarSrc := &corev1.EnvVarSource{
- ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: "some-name",
- },
- Key: "some-key-that-is-different",
- Optional: nil,
- },
- }
-
- type args struct {
- existing []corev1.EnvVar
- expected []corev1.EnvVar
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "simple case",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "val2"}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "val2"}},
- },
- want: true,
- },
- {
- name: "different length case",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "val2"}},
- },
- want: false,
- },
- {
- name: "different length case",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "val2"}},
- },
- want: false,
- },
- {
- name: "different value in one env",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "different-value"}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", Value: "val2"}},
- },
- want: false,
- },
- {
- name: "same valueFrom in one env - same reference",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: envVarSrc}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: envVarSrc}},
- },
- want: true,
- },
- {
- name: "same valueFrom in one env - same object, different reference",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: envVarSrc}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: envVarSrc2}},
- },
- want: true,
- },
- {
- name: "different valueFrom in one env",
- args: args{
- existing: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: envVarSrc}},
- expected: []corev1.EnvVar{{Name: "env1", Value: "val1"}, {Name: "env2", ValueFrom: differentEnvVarSrc}},
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := envsEqual(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_getConditionReason(t *testing.T) {
- type args struct {
- conditions []serverlessv1alpha2.Condition
- conditionType serverlessv1alpha2.ConditionType
- }
- tests := []struct {
- name string
- args args
- want serverlessv1alpha2.ConditionReason
- }{
- {
- name: "Should correctly return proper status given slice of conditions",
- args: args{
- conditions: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonConfigMapCreated},
- {Type: serverlessv1alpha2.ConditionRunning, Status: corev1.ConditionTrue, Reason: serverlessv1alpha2.ConditionReasonServiceCreated},
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse, Reason: serverlessv1alpha2.ConditionReasonDeploymentWaiting},
- },
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: serverlessv1alpha2.ConditionReasonServiceCreated,
- },
- {
- name: "Should correctly return status unknown if there's no needed conditionType",
- args: args{
- conditions: []serverlessv1alpha2.Condition{
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- {Type: serverlessv1alpha2.ConditionConfigurationReady, Status: corev1.ConditionFalse},
- },
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: "",
- },
- {
- name: "Should correctly return status unknown if slice is empty",
- args: args{
- conditions: []serverlessv1alpha2.Condition{},
- conditionType: serverlessv1alpha2.ConditionRunning,
- },
- want: "",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := getConditionReason(tt.args.conditions, tt.args.conditionType)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile.go b/components/serverless/internal/controllers/serverless/function_reconcile.go
deleted file mode 100644
index 7b589311e..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package serverless
-
-import (
- "context"
- "time"
-
- "github.com/pkg/errors"
- "go.uber.org/zap"
- "golang.org/x/time/rate"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/client-go/tools/record"
- "k8s.io/client-go/util/workqueue"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/builder"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller"
- "sigs.k8s.io/controller-runtime/pkg/predicate"
-
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-const (
- healthCheckTimeout = time.Second
- keyRegistryPullAddr = "pullRegAddr"
- keyRegistryPushAddr = "pushRegAddr"
- keyRegistryAddress = "registryAddress"
- keyIsInternal = "isInternal"
-)
-
-//go:generate mockery --name=GitClient --output=automock --outpkg=automock --case=underscore
-type GitClient interface {
- LastCommit(options git.Options) (string, error)
- Clone(path string, options git.Options) (string, error)
-}
-
-//go:generate mockery --name=GitClientFactory --output=automock --outpkg=automock --case=underscore
-type GitClientFactory interface {
- GetGitClient(logger *zap.SugaredLogger) git.GitClient
-}
-
-//go:generate mockery --name=StatsCollector --output=automock --outpkg=automock --case=underscore
-type StatsCollector interface {
- UpdateReconcileStats(f *serverlessv1alpha2.Function, cond serverlessv1alpha2.Condition)
-}
-
-type FunctionReconciler struct {
- Log *zap.SugaredLogger
- client resource.Client
- recorder record.EventRecorder
- config FunctionConfig
- gitFactory GitClientFactory
- statsCollector StatsCollector
- healthCh chan bool
- initStateFunction stateFn
-}
-
-func NewFunctionReconciler(client resource.Client, log *zap.SugaredLogger, config FunctionConfig, gitFactory GitClientFactory, recorder record.EventRecorder, statsCollector StatsCollector, healthCh chan bool) *FunctionReconciler {
- return &FunctionReconciler{
- Log: log,
- client: client,
- recorder: recorder,
- config: config,
- gitFactory: gitFactory,
- healthCh: healthCh,
- statsCollector: statsCollector,
- initStateFunction: stateFnValidateFunction,
- }
-}
-
-func (r *FunctionReconciler) SetupWithManager(mgr ctrl.Manager) (controller.Controller, error) {
- return ctrl.NewControllerManagedBy(mgr).
- Named("function-controller").
- For(&serverlessv1alpha2.Function{}, builder.WithPredicates(predicate.Funcs{UpdateFunc: IsNotFunctionStatusUpdate(r.Log)})).
- Owns(&corev1.ConfigMap{}).
- Owns(&appsv1.Deployment{}).
- Owns(&corev1.Service{}).
- Owns(&autoscalingv1.HorizontalPodAutoscaler{}).
- WithOptions(controller.Options{
- RateLimiter: workqueue.NewMaxOfRateLimiter(
- workqueue.NewItemExponentialFailureRateLimiter(r.config.GitFetchRequeueDuration, 300*time.Second),
- // 10 qps, 100 bucket size. This is only for retry speed and its only the overall factor (not per item)
- &workqueue.BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
- ),
- MaxConcurrentReconciles: 1, // Build job scheduling mechanism requires this parameter to be set to 1. The mechanism is based on getting active and stateless jobs, concurrent reconciles makes it non deterministic . Value 1 removes data races while fetching list of jobs. https://github.com/kyma-project/kyma/issues/10037
- }).
- Build(r)
-}
-
-// Reconcile reads that state of the cluster for a Function object and makes changes based on the state read and what is in the Function.Spec
-// +kubebuilder:rbac:groups="serverless.kyma-project.io",resources=functions,verbs=get;list;watch;create;update;patch;delete
-// +kubebuilder:rbac:groups="serverless.kyma-project.io",resources=functions/status,verbs=get;update;patch
-// +kubebuilder:rbac:groups="apps",resources=deployments,verbs=get;list;watch;create;update;patch;delete;deletecollection
-// +kubebuilder:rbac:groups="apps",resources=deployments/status,verbs=get
-// +kubebuilder:rbac:groups="batch",resources=jobs,verbs=get;list;watch;create;update;patch;delete;deletecollection
-// +kubebuilder:rbac:groups="batch",resources=jobs/status,verbs=get
-// +kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch;create;update;deletecollection
-// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
-// +kubebuilder:rbac:groups="",resources=services,verbs=get;list;watch;create;update;delete
-// +kubebuilder:rbac:groups="autoscaling",resources=horizontalpodautoscalers,verbs=get;list;watch;create;update;deletecollection
-// +kubebuilder:rbac:groups="",resources=events,verbs=create;patch
-
-func (r *FunctionReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) {
- if IsHealthCheckRequest(request) {
- r.sendHealthCheck()
- return ctrl.Result{}, nil
- }
-
- r.Log.With(
- "name", request.Name,
- "namespace", request.Namespace).
- Debug("starting pre-reconciliation steps")
-
- var instance serverlessv1alpha2.Function
-
- err := r.client.Get(ctx, request.NamespacedName, &instance)
- if err != nil {
- return ctrl.Result{}, client.IgnoreNotFound(err)
- }
-
- if !instance.DeletionTimestamp.IsZero() {
- return ctrl.Result{}, nil
- }
-
- contextLogger := r.Log.With(
- "kind", instance.GetObjectKind().GroupVersionKind().Kind,
- "name", instance.GetName(),
- "namespace", instance.GetNamespace(),
- "version", instance.GetGeneration())
-
- dockerCfg, err := r.readDockerConfig(ctx, &instance)
- if err != nil {
- return ctrl.Result{}, err
- }
-
- contextLogger.Debug("starting state machine")
-
- stateReconciler := reconciler{
- fn: r.initStateFunction,
- log: contextLogger,
- k8s: k8s{
- client: r.client,
- recorder: r.recorder,
- statsCollector: r.statsCollector,
- },
- cfg: cfg{
- fn: r.config,
- docker: dockerCfg,
- },
- gitClient: r.gitFactory.GetGitClient(contextLogger),
- }
-
- stateReconciler.result = ctrl.Result{
- RequeueAfter: time.Second * 1,
- }
-
- return stateReconciler.reconcile(ctx, instance)
-}
-
-func (r *FunctionReconciler) sendHealthCheck() {
- r.Log.Debug("health check request received")
-
- select {
- case r.healthCh <- true:
- r.Log.Debug("health check request responded")
- case <-time.After(healthCheckTimeout):
- r.Log.Warn(errors.New("timeout when responding to health check"))
- }
-}
-
-func (r *FunctionReconciler) readDockerConfig(ctx context.Context, instance *serverlessv1alpha2.Function) (DockerConfig, error) {
- var secret corev1.Secret
- // try reading user config
- // DEPRECATED - this feature will be supported but we can disable it by removing lines below
- // TODO: remove it in April 2024 - https://github.com/kyma-project/serverless/issues/400
- if err := r.client.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: r.config.ImageRegistryExternalDockerConfigSecretName}, &secret); err == nil {
- data := readSecretData(secret.Data)
- return DockerConfig{
- ActiveRegistryConfigSecretName: r.config.ImageRegistryExternalDockerConfigSecretName,
- PushAddress: data[keyRegistryAddress],
- PullAddress: data[keyRegistryAddress],
- }, nil
- }
-
- // try reading default config
- if err := r.client.Get(ctx, client.ObjectKey{Namespace: instance.Namespace, Name: r.config.ImageRegistryDefaultDockerConfigSecretName}, &secret); err != nil {
- return DockerConfig{}, errors.Wrapf(err, "docker registry configuration not found, none of configuration secrets (%s, %s) found in function namespace", r.config.ImageRegistryDefaultDockerConfigSecretName, r.config.ImageRegistryExternalDockerConfigSecretName)
- }
- data := readSecretData(secret.Data)
- if data[keyIsInternal] == "true" {
- return DockerConfig{
- ActiveRegistryConfigSecretName: r.config.ImageRegistryDefaultDockerConfigSecretName,
- PushAddress: data[keyRegistryPushAddr],
- PullAddress: data[keyRegistryPullAddr],
- }, nil
- } else {
- return DockerConfig{
- ActiveRegistryConfigSecretName: r.config.ImageRegistryDefaultDockerConfigSecretName,
- PushAddress: data[keyRegistryAddress],
- PullAddress: data[keyRegistryAddress],
- }, nil
- }
-
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile_asserts_test.go b/components/serverless/internal/controllers/serverless/function_reconcile_asserts_test.go
deleted file mode 100644
index 53740cbbd..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile_asserts_test.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package serverless
-
-import (
- "context"
- "testing"
- "time"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
-
- "github.com/onsi/gomega"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/util/intstr"
- ctrl "sigs.k8s.io/controller-runtime"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-func assertSuccessfulFunctionBuild(t *testing.T, resourceClient resource.Client, reconciler *FunctionReconciler, request ctrl.Request, fnLabels map[string]string, rebuilding bool) {
- g := gomega.NewGomegaWithT(t)
-
- initialDeploymentCondition := corev1.ConditionUnknown
- initialConditionsCount := 2
- if rebuilding {
- initialDeploymentCondition = corev1.ConditionTrue
- initialConditionsCount = 3
- }
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Log("creating the Job")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(initialConditionsCount))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(initialDeploymentCondition))
-
- jobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("build in progress")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(initialConditionsCount))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(initialDeploymentCondition))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobRunning))
-
- t.Log("build finished")
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(initialConditionsCount))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(initialDeploymentCondition))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobFinished))
-}
-
-func assertSuccessfulFunctionDeployment(t *testing.T, resourceClient resource.Client, reconciler *FunctionReconciler, request ctrl.Request, fnLabels map[string]string, regPullAddr string, redeployment bool) {
- g := gomega.NewGomegaWithT(t)
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Log("deploy started")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
- g.Expect(deployment).ToNot(gomega.BeNil())
- g.Expect(deployment.Spec.Template.Spec.Containers).To(gomega.HaveLen(1))
-
- s := systemState{
- // TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *function,
- }
-
- g.Expect(deployment.Spec.Template.Spec.Containers[0].Image).To(gomega.Equal(s.buildImageAddress(regPullAddr)))
- g.Expect(deployment.Spec.Template.Labels).To(gomega.HaveLen(8))
- g.Expect(deployment.Spec.Template.Labels[serverlessv1alpha2.FunctionNameLabel]).To(gomega.Equal(function.Name))
- g.Expect(deployment.Spec.Template.Labels[serverlessv1alpha2.PodAppNameLabel]).To(gomega.Equal(function.Name))
- g.Expect(deployment.Spec.Template.Labels[serverlessv1alpha2.FunctionManagedByLabel]).To(gomega.Equal(serverlessv1alpha2.FunctionControllerValue))
- g.Expect(deployment.Spec.Template.Labels[serverlessv1alpha2.FunctionUUIDLabel]).To(gomega.Equal(string(function.UID)))
- g.Expect(deployment.Spec.Template.Labels[serverlessv1alpha2.FunctionResourceLabel]).To(gomega.Equal(serverlessv1alpha2.FunctionResourceLabelDeploymentValue))
- g.Expect(deployment.Spec.Template.Labels[testBindingLabel1]).To(gomega.Equal("foobar"))
- g.Expect(deployment.Spec.Template.Labels[testBindingLabel2]).To(gomega.Equal(testBindingLabelValue))
- g.Expect(deployment.Spec.Template.Labels["foo"]).To(gomega.Equal("bar"))
-
- if !redeployment {
- t.Log("service creation")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonServiceCreated))
- }
-
- t.Log("service ready")
- jobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
-
- svc := &corev1.Service{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, svc)).To(gomega.Succeed())
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(svc.Spec.Ports).To(gomega.HaveLen(1))
- g.Expect(svc.Spec.Ports[0].Name).To(gomega.Equal("http"))
- g.Expect(svc.Spec.Ports[0].TargetPort).To(gomega.Equal(intstr.FromInt(8080)))
-
- g.Expect(isSubset(svc.Spec.Selector, job.Spec.Template.Labels)).To(gomega.BeFalse(), "svc selector should not catch job pods")
- g.Expect(svc.Spec.Selector).To(gomega.Equal(deployment.Spec.Selector.MatchLabels))
-
- if !redeployment {
- t.Log("hpa creation")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonHorizontalPodAutoscalerCreated))
- }
-
- t.Log("hpa ready")
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- hpaSpec := hpaList.Items[0].Spec
-
- g.Expect(hpaSpec.ScaleTargetRef.Name).To(gomega.Equal(function.GetName()))
- g.Expect(hpaSpec.ScaleTargetRef.Kind).To(gomega.Equal(serverlessv1alpha2.FunctionKind))
- g.Expect(hpaSpec.ScaleTargetRef.APIVersion).To(gomega.Equal(serverlessv1alpha2.GroupVersion.String()))
-
- t.Log("deployment ready")
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Minute * 5))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
-
- t.Log("should not change state on reconcile")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Minute * 5))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile_gitops_test.go b/components/serverless/internal/controllers/serverless/function_reconcile_gitops_test.go
deleted file mode 100644
index 9a59cef78..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile_gitops_test.go
+++ /dev/null
@@ -1,859 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- "log"
- "testing"
-
- "go.uber.org/zap"
-
- "github.com/stretchr/testify/mock"
-
- git2go "github.com/libgit2/git2go/v34"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/automock"
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/client-go/tools/record"
- ctrl "sigs.k8s.io/controller-runtime"
-)
-
-type testDataScenario struct {
- info string
- authType *string
- stringData map[string]string
-}
-
-var (
- authTypeBasic = "basic"
- authTypeKey = "key"
-)
-
-var testDataScenarios = []testDataScenario{
- {
- info: "auth-key-with-pw",
- authType: &authTypeKey,
- stringData: map[string]string{
- "user": "test",
- "password": "test",
- },
- },
- {
- info: "auth-basic",
- authType: &authTypeBasic,
- stringData: map[string]string{
- "user": "test",
- "password": "test",
- },
- },
- {
- info: "auth-key",
- authType: &authTypeKey,
- stringData: map[string]string{
- "authTypeKey": "123",
- },
- },
- {
- info: "no-auth",
- authType: nil,
- stringData: nil,
- },
-}
-
-var newMockedGitClient = func(auth *git.AuthOptions) *automock.GitClient {
- options := git.Options{
- URL: "https://mock.repo/kyma/test",
- Reference: "main",
- }
-
- options.Auth = auth
- log.Println(options)
- m := new(automock.GitClient)
-
- m.On("LastCommit", options).Return("pierwszy-hash", nil)
- options.Reference = "newone"
- m.On("LastCommit", options).Return("a376218bdcd705cc39aa7ce7f310769fab6d51c9", nil)
-
- return m
-}
-
-func TestGitOpsWithContinuousGitCheckout(t *testing.T) {
- //GIVEN
- continuousGitCheckout := true
-
- g := gomega.NewGomegaWithT(t)
- rtm := serverlessv1alpha2.NodeJs20
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
- testCfg := setUpControllerConfig(g)
- initializeServerlessResources(g, resourceClient)
- createDockerfileForRuntime(g, resourceClient, rtm)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- for i, testData := range testDataScenarios {
- t.Run(fmt.Sprintf("[%s] should successfully update Function]", testData.info), func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- name := fmt.Sprintf("test-me-plz-%d", i)
-
- var auth *serverlessv1alpha2.RepositoryAuth
- if testData.authType != nil {
- auth = &serverlessv1alpha2.RepositoryAuth{
- Type: serverlessv1alpha2.RepositoryAuthType(*testData.authType),
- SecretName: name,
- }
- secret := newTestSecret(name, testNamespace, testData.stringData)
- g.Expect(resourceClient.Create(context.TODO(), secret)).To(gomega.Succeed())
-
- }
-
- inFunction := newTestGitFunction(testNamespace, name, auth, 1, 2, continuousGitCheckout)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
-
- request := ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: inFunction.GetNamespace(),
- Name: inFunction.GetName(),
- },
- }
-
- var gitAuthOpts *git.AuthOptions
- if testData.authType != nil {
- gitAuthOpts = &git.AuthOptions{
- Type: git.RepositoryAuthType(*testData.authType),
- Credentials: testData.stringData,
- SecretName: name,
- }
- }
-
- gitClient := newMockedGitClient(gitAuthOpts)
- factory := automock.NewGitClientFactory(t)
- factory.On("GetGitClient", mock.Anything).Return(gitClient)
- defer factory.AssertExpectations(t)
-
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- reconciler := &FunctionReconciler{
- Log: zap.NewNop().Sugar(),
- client: resourceClient,
- recorder: record.NewFakeRecorder(100),
- config: testCfg,
- gitFactory: factory,
- statsCollector: statsCollector,
- initStateFunction: stateFnGitCheckSources,
- }
-
- fnLabels := reconciler.internalFunctionLabels(inFunction)
-
- //WHEN
- t.Log("creating the Function")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
- // verify function
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(1))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonSourceUpdated)
-
- t.Log("creating the Job")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- jobList := &batchv1.JobList{}
- err := reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("build in progress")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobRunning)
-
- t.Log("build finished")
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{
- Namespace: jobList.Items[0].GetNamespace(),
- Name: jobList.Items[0].GetName(),
- }, job)).To(gomega.Succeed())
-
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobFinished)
-
- t.Log("change function branch")
- function.Spec.Source.GitRepository.Reference = "newone"
- g.Expect(resourceClient.Update(context.TODO(), function)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- // check if status was updated
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveStatusReference("newone"))
- g.Expect(function).To(haveStatusCommit("a376218bdcd705cc39aa7ce7f310769fab6d51c9"))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- t.Log("delete the old Job")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- jobList = &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(0))
-
- t.Log("creating the Job")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- jobList = &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("build in progress")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobRunning)
-
- t.Log("build finished")
- job = &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{
- Namespace: jobList.Items[0].GetNamespace(),
- Name: jobList.Items[0].GetName(),
- }, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now = metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobFinished)
-
- t.Log("deploy started")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).
- To(gomega.Succeed())
-
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
-
- deployment := &deployments.Items[0]
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *function,
- }
-
- expectedImage := s.buildImageAddress("localhost:32132")
- g.Expect(deployment).To(gomega.Not(gomega.BeNil()))
- g.Expect(deployment).To(haveSpecificContainer0Image(expectedImage))
- g.Expect(deployment).To(haveLabelLen(8))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionNameLabel, function.Name))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.PodAppNameLabel, function.Name))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionManagedByLabel, serverlessv1alpha2.FunctionControllerValue))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionUUIDLabel, string(function.UID)))
- g.Expect(deployment).To(haveLabelWithValue(
- serverlessv1alpha2.FunctionResourceLabel, serverlessv1alpha2.FunctionResourceLabelDeploymentValue))
-
- g.Expect(deployment).To(haveLabelWithValue(testBindingLabel1, "foobar"))
- g.Expect(deployment).To(haveLabelWithValue(testBindingLabel2, testBindingLabelValue))
- g.Expect(deployment).To(haveLabelWithValue("foo", "bar"))
-
- t.Log("service creation")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonServiceCreated)
-
- svc := &corev1.Service{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, svc)).To(gomega.Succeed())
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(svc.Spec.Ports).To(gomega.HaveLen(1))
- g.Expect(svc.Spec.Ports[0].Name).To(gomega.Equal("http"))
- g.Expect(svc.Spec.Ports[0].TargetPort).To(gomega.Equal(intstr.FromInt(8080)))
-
- g.Expect(isSubset(svc.Spec.Selector, job.Spec.Template.Labels)).
- To(gomega.BeFalse(), "svc selector should not catch job pods")
-
- g.Expect(svc.Spec.Selector).To(gomega.Equal(deployment.Spec.Selector.MatchLabels))
-
- t.Log("HPA creation")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonHorizontalPodAutoscalerCreated)
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- hpaSpec := hpaList.Items[0].Spec
-
- g.Expect(hpaSpec.ScaleTargetRef.Name).To(gomega.Equal(function.GetName()))
- g.Expect(hpaSpec.ScaleTargetRef.Kind).To(gomega.Equal(serverlessv1alpha2.FunctionKind))
- g.Expect(hpaSpec.ScaleTargetRef.APIVersion).To(gomega.Equal(serverlessv1alpha2.GroupVersion.String()))
-
- t.Log("deployment ready")
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beFinishedReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveConditionRunning)
- g.Expect(function).To(haveConditionReasonDeploymentReady)
-
- t.Log("should not change state on reconcile")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beFinishedReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveConditionRunning)
- g.Expect(function).To(haveConditionReasonDeploymentReady)
- })
- }
-}
-
-func TestGitOpsWithoutContinuousGitCheckout(t *testing.T) {
- //GIVEN
- continuousGitCheckout := false
-
- g := gomega.NewGomegaWithT(t)
- rtm := serverlessv1alpha2.NodeJs20
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
- testCfg := setUpControllerConfig(g)
- initializeServerlessResources(g, resourceClient)
- createDockerfileForRuntime(g, resourceClient, rtm)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- for i, testData := range testDataScenarios {
- t.Run(fmt.Sprintf("[%s] should successfully update Function]", testData.info), func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- name := fmt.Sprintf("test-me-plz-%d", i)
-
- var auth *serverlessv1alpha2.RepositoryAuth
- if testData.authType != nil {
- auth = &serverlessv1alpha2.RepositoryAuth{
- Type: serverlessv1alpha2.RepositoryAuthType(*testData.authType),
- SecretName: name,
- }
- secret := newTestSecret(name, testNamespace, testData.stringData)
- g.Expect(resourceClient.Create(context.TODO(), secret)).To(gomega.Succeed())
-
- }
-
- inFunction := newTestGitFunction(testNamespace, name, auth, 1, 2, continuousGitCheckout)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
-
- request := ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: inFunction.GetNamespace(),
- Name: inFunction.GetName(),
- },
- }
-
- var gitAuthOpts *git.AuthOptions
- if testData.authType != nil {
- gitAuthOpts = &git.AuthOptions{
- Type: git.RepositoryAuthType(*testData.authType),
- Credentials: testData.stringData,
- SecretName: name,
- }
- }
-
- gitClient := newMockedGitClient(gitAuthOpts)
- factory := automock.NewGitClientFactory(t)
- factory.On("GetGitClient", mock.Anything).Return(gitClient)
- defer factory.AssertExpectations(t)
-
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- reconciler := &FunctionReconciler{
- Log: zap.NewNop().Sugar(),
- client: resourceClient,
- recorder: record.NewFakeRecorder(100),
- config: testCfg,
- gitFactory: factory,
- statsCollector: statsCollector,
- initStateFunction: stateFnGitCheckSources,
- }
-
- fnLabels := reconciler.internalFunctionLabels(inFunction)
-
- //WHEN
- t.Log("creating the Function")
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
- // verify function
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(1))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonSourceUpdated)
-
- t.Log("creating the Job")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- jobList := &batchv1.JobList{}
- err := reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("build in progress")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobRunning)
-
- t.Log("build finished")
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{
- Namespace: jobList.Items[0].GetNamespace(),
- Name: jobList.Items[0].GetName(),
- }, job)).To(gomega.Succeed())
-
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(2))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonJobFinished)
-
- t.Log("Deployment is created")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).
- To(gomega.Succeed())
-
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
-
- deployment := &deployments.Items[0]
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *function,
- }
-
- expectedImage := s.buildImageAddress("localhost:32132")
- g.Expect(deployment).To(gomega.Not(gomega.BeNil()))
- g.Expect(deployment).To(haveSpecificContainer0Image(expectedImage))
- g.Expect(deployment).To(haveLabelLen(8))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionNameLabel, function.Name))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.PodAppNameLabel, function.Name))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionManagedByLabel, serverlessv1alpha2.FunctionControllerValue))
- g.Expect(deployment).To(haveLabelWithValue(serverlessv1alpha2.FunctionUUIDLabel, string(function.UID)))
- g.Expect(deployment).To(haveLabelWithValue(
- serverlessv1alpha2.FunctionResourceLabel, serverlessv1alpha2.FunctionResourceLabelDeploymentValue))
-
- g.Expect(deployment).To(haveLabelWithValue(testBindingLabel1, "foobar"))
- g.Expect(deployment).To(haveLabelWithValue(testBindingLabel2, testBindingLabelValue))
- g.Expect(deployment).To(haveLabelWithValue("foo", "bar"))
-
- t.Log("change function branch")
- function.Spec.Source.GitRepository.Reference = "newone"
- g.Expect(resourceClient.Update(context.TODO(), function)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- // check if status was updated
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(3))
- g.Expect(function).To(haveStatusReference("main"))
- g.Expect(function).To(haveStatusCommit("pierwszy-hash"))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- t.Log("Build job shouldn't be deleted")
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(3))
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
-
- jobList = &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("Service is created")
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonServiceCreated)
-
- svc := &corev1.Service{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, svc)).To(gomega.Succeed())
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(svc.Spec.Ports).To(gomega.HaveLen(1))
- g.Expect(svc.Spec.Ports[0].Name).To(gomega.Equal("http"))
- g.Expect(svc.Spec.Ports[0].TargetPort).To(gomega.Equal(intstr.FromInt(8080)))
-
- g.Expect(isSubset(svc.Spec.Selector, job.Spec.Template.Labels)).
- To(gomega.BeFalse(), "svc selector should not catch job pods")
-
- g.Expect(svc.Spec.Selector).To(gomega.Equal(deployment.Spec.Selector.MatchLabels))
-
- t.Log("HPA is created")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beOKReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveUnknownConditionRunning)
- g.Expect(function).To(haveConditionReasonHorizontalPodAutoscalerCreated)
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- hpaSpec := hpaList.Items[0].Spec
-
- g.Expect(hpaSpec.ScaleTargetRef.Name).To(gomega.Equal(function.GetName()))
- g.Expect(hpaSpec.ScaleTargetRef.Kind).To(gomega.Equal(serverlessv1alpha2.FunctionKind))
- g.Expect(hpaSpec.ScaleTargetRef.APIVersion).To(gomega.Equal(serverlessv1alpha2.GroupVersion.String()))
-
- t.Log("Deployment is ready")
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- g.Expect(reconciler.Reconcile(ctx, request)).To(beFinishedReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveConditionRunning)
- g.Expect(function).To(haveConditionReasonDeploymentReady)
-
- t.Log("should not change state on reconcile")
- g.Expect(reconciler.Reconcile(ctx, request)).To(beFinishedReconcileResult)
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function).To(haveConditionLen(conditionLen))
- g.Expect(function).To(haveConditionCfgRdy)
- g.Expect(function).To(haveConditionBuildRdy)
- g.Expect(function).To(haveConditionRunning)
- g.Expect(function).To(haveConditionReasonDeploymentReady)
-
- })
- }
-}
-
-func TestGitOps_GitErrorHandling(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- rtm := serverlessv1alpha2.NodeJs20
-
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
-
- testCfg := setUpControllerConfig(g)
-
- initializeServerlessResources(g, resourceClient)
-
- createDockerfileForRuntime(g, resourceClient, rtm)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("Check if Requeue is set to true in case of recoverable error", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
-
- function := &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{Name: "git-fn", Namespace: testNamespace},
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- },
- },
- Runtime: rtm,
- },
- }
-
- g.Expect(resourceClient.Create(context.TODO(), function)).To(gomega.Succeed())
- // We don't use MakeGitError2 function because: https://github.com/libgit2/git2go/issues/873
- gitErr := &git2go.GitError{Message: "NotFound", Class: 0, Code: git2go.ErrorCodeNotFound}
- gitOpts := git.Options{URL: "", Reference: "ref"}
- gitClient := &automock.GitClient{}
- gitClient.On("LastCommit", gitOpts).Return("", gitErr)
- defer gitClient.AssertExpectations(t)
-
- factory := automock.NewGitClientFactory(t)
- factory.On("GetGitClient", mock.Anything).Return(gitClient)
- defer factory.AssertExpectations(t)
-
- prometheusCollector := &automock.StatsCollector{}
- prometheusCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
- request := ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: function.GetNamespace(),
- Name: function.GetName(),
- },
- }
-
- reconciler := &FunctionReconciler{
- Log: zap.NewNop().Sugar(),
- client: resourceClient,
- recorder: record.NewFakeRecorder(100),
- config: testCfg,
- gitFactory: factory,
- statsCollector: prometheusCollector,
- initStateFunction: stateFnGitCheckSources,
- }
-
- //WHEN
- res, err := reconciler.Reconcile(ctx, request)
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(res.Requeue).To(gomega.BeFalse())
-
- var updatedFn serverlessv1alpha2.Function
- err = resourceClient.Get(context.TODO(), request.NamespacedName, &updatedFn)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(updatedFn.Status.Conditions).To(gomega.HaveLen(1))
- g.Expect(updatedFn.Status.Conditions[0].Message).To(gomega.Equal("Stop reconciliation, reason: NotFound"))
- })
-}
-
-func Test_stateFnGitCheckSources(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- rtm := serverlessv1alpha2.NodeJs20
-
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
-
- testCfg := setUpControllerConfig(g)
-
- initializeServerlessResources(g, resourceClient)
-
- createDockerfileForRuntime(g, resourceClient, rtm)
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- //TODO
- t.Run("Check if requeue in-case of non-existing git-repo-cr", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
-
- function := &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{Name: "git-fn", Namespace: testNamespace},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- },
- },
- },
- }
- g.Expect(resourceClient.Create(context.TODO(), function)).To(gomega.Succeed())
-
- prometheusCollector := &automock.StatsCollector{}
- prometheusCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
- request := ctrl.Request{
- NamespacedName: types.NamespacedName{
- Namespace: function.GetNamespace(),
- Name: function.GetName(),
- },
- }
-
- gitClient := new(automock.GitClient)
- gitClient.On("LastCommit", mock.Anything).Return("", fmt.Errorf("test error")).Once()
- defer gitClient.AssertExpectations(t)
-
- factory := automock.NewGitClientFactory(t)
- factory.On("GetGitClient", mock.Anything).Return(gitClient)
- defer factory.AssertExpectations(t)
-
- reconciler := &FunctionReconciler{
- Log: zap.NewNop().Sugar(),
- client: resourceClient,
- recorder: record.NewFakeRecorder(100),
- gitFactory: factory,
- config: testCfg,
- statsCollector: prometheusCollector,
- initStateFunction: stateFnGitCheckSources,
- }
-
- //WHEN
- res, err := reconciler.Reconcile(ctx, request)
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- // this is expected to be false, because returning an error is enough to requeue
- g.Expect(res.Requeue).To(gomega.BeTrue())
- })
-}
-
-func isSubset(subSet, superSet map[string]string) bool {
- if len(superSet) == 0 {
- return true
- }
- for k, v := range subSet {
- value, ok := superSet[k]
- if !ok || value != v {
- return false
- }
- }
- return true
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile_health_test.go b/components/serverless/internal/controllers/serverless/function_reconcile_health_test.go
deleted file mode 100644
index 7a110a0ef..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile_health_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package serverless
-
-import (
- "context"
- "testing"
-
- "github.com/onsi/gomega"
- "go.uber.org/zap"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
-)
-
-func TestFunctionReconciler_Reconcile_HealthCheck(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- t.Run("should receive health check and notify to health channel", func(t *testing.T) {
- healthCh := make(chan bool)
- reconciler := NewFunctionReconciler(nil, zap.NewNop().Sugar(), FunctionConfig{}, nil, nil, nil, healthCh)
-
- healthRequest := ctrl.Request{NamespacedName: types.NamespacedName{
- Name: HealthEvent,
- }}
-
- go func() {
- result, err := reconciler.Reconcile(context.Background(), healthRequest)
-
- g.Expect(result).To(gomega.Equal(ctrl.Result{}))
- g.Expect(err).To(gomega.BeNil())
- }()
-
- g.Expect(<-healthCh).To(gomega.BeTrue())
- })
-
- t.Run("should receive health check and return nil after timeout", func(t *testing.T) {
- reconciler := NewFunctionReconciler(nil, zap.NewNop().Sugar(), FunctionConfig{}, nil, nil, nil, make(chan bool))
-
- healthRequest := ctrl.Request{NamespacedName: types.NamespacedName{
- Name: HealthEvent,
- }}
-
- result, err := reconciler.Reconcile(context.Background(), healthRequest)
-
- g.Expect(result).To(gomega.Equal(ctrl.Result{}))
- g.Expect(err).To(gomega.BeNil())
- })
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile_matchers_test.go b/components/serverless/internal/controllers/serverless/function_reconcile_matchers_test.go
deleted file mode 100644
index 99b3302f5..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile_matchers_test.go
+++ /dev/null
@@ -1,111 +0,0 @@
-package serverless
-
-import (
- "time"
-
- v1 "k8s.io/api/apps/v1"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- "github.com/onsi/gomega/gstruct"
- gtypes "github.com/onsi/gomega/types"
- corev1 "k8s.io/api/core/v1"
-)
-
-var beOKReconcileResult = recResultMatcher(false, time.Second*1)
-var beFinishedReconcileResult = recResultMatcher(false, time.Minute*5)
-
-func recResultMatcher(requeue bool, requeueAfter time.Duration) gtypes.GomegaMatcher {
- return gstruct.MatchAllFields(gstruct.Fields{
- "RequeueAfter": gomega.Equal(requeueAfter),
- "Requeue": gomega.Equal(requeue),
- })
-}
-
-var (
- haveConditionReasonSourceUpdated = haveConditionReason(
- serverlessv1alpha2.ConditionConfigurationReady,
- serverlessv1alpha2.ConditionReasonSourceUpdated,
- )
-
- haveConditionReasonJobRunning = haveConditionReason(
- serverlessv1alpha2.ConditionBuildReady,
- serverlessv1alpha2.ConditionReasonJobRunning)
-
- haveConditionReasonJobFinished = haveConditionReason(
- serverlessv1alpha2.ConditionBuildReady,
- serverlessv1alpha2.ConditionReasonJobFinished)
-
- haveConditionReasonServiceCreated = haveConditionReason(
- serverlessv1alpha2.ConditionRunning,
- serverlessv1alpha2.ConditionReasonServiceCreated)
-
- haveConditionReasonDeploymentReady = haveConditionReason(
- serverlessv1alpha2.ConditionRunning,
- serverlessv1alpha2.ConditionReasonDeploymentReady)
-
- haveConditionReasonHorizontalPodAutoscalerCreated = haveConditionReason(
- serverlessv1alpha2.ConditionRunning,
- serverlessv1alpha2.ConditionReasonHorizontalPodAutoscalerCreated)
-)
-
-func haveConditionReason(t serverlessv1alpha2.ConditionType, expected serverlessv1alpha2.ConditionReason) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(fn *serverlessv1alpha2.Function) serverlessv1alpha2.ConditionReason {
- return getConditionReason(fn.Status.Conditions, t)
- }, gomega.Equal(expected))
-}
-
-var (
- haveConditionCfgRdy = haveCondition(serverlessv1alpha2.ConditionConfigurationReady, corev1.ConditionTrue)
- haveConditionBuildRdy = haveCondition(serverlessv1alpha2.ConditionBuildReady, corev1.ConditionTrue)
- haveUnknownConditionBuildRdy = haveCondition(serverlessv1alpha2.ConditionBuildReady, corev1.ConditionUnknown)
- haveConditionRunning = haveCondition(serverlessv1alpha2.ConditionRunning, corev1.ConditionTrue)
- haveUnknownConditionRunning = haveCondition(serverlessv1alpha2.ConditionRunning, corev1.ConditionUnknown)
-)
-
-func haveCondition(t serverlessv1alpha2.ConditionType, expected corev1.ConditionStatus) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(fn *serverlessv1alpha2.Function) corev1.ConditionStatus {
- return getConditionStatus(fn.Status.Conditions, t)
- }, gomega.Equal(expected))
-}
-
-func haveConditionLen(expected int) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(fn *serverlessv1alpha2.Function) int {
- return len(fn.Status.Conditions)
- }, gomega.Equal(expected))
-}
-
-func haveStatusReference(expected string) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(fn *serverlessv1alpha2.Function) string {
- return fn.Status.Reference
- }, gomega.Equal(expected))
-}
-
-func haveStatusCommit(expected string) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(fn *serverlessv1alpha2.Function) string {
- return fn.Status.Commit
- }, gomega.Equal(expected))
-}
-
-func haveSpecificContainer0Image(expected string) gtypes.GomegaMatcher {
- return gomega.And(
- gomega.WithTransform(func(d *v1.Deployment) int {
- return len(d.Spec.Template.Spec.Containers)
- }, gomega.BeNumerically(">=", 0)),
- gomega.WithTransform(func(d *v1.Deployment) string {
- return d.Spec.Template.Spec.Containers[0].Image
- }, gomega.Equal(expected)),
- )
-}
-
-func haveLabelWithValue(key, value interface{}) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(d *v1.Deployment) map[string]string {
- return d.Spec.Template.Labels
- }, gomega.HaveKeyWithValue(key, value))
-}
-
-func haveLabelLen(expected int) gtypes.GomegaMatcher {
- return gomega.WithTransform(func(d *v1.Deployment) int {
- return len(d.Spec.Template.Labels)
- }, gomega.Equal(expected))
-}
diff --git a/components/serverless/internal/controllers/serverless/function_reconcile_test.go b/components/serverless/internal/controllers/serverless/function_reconcile_test.go
deleted file mode 100644
index 82edc657d..000000000
--- a/components/serverless/internal/controllers/serverless/function_reconcile_test.go
+++ /dev/null
@@ -1,1634 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- "testing"
- "time"
-
- k8sresource "k8s.io/apimachinery/pkg/api/resource"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/automock"
- "github.com/stretchr/testify/mock"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/onsi/gomega"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/client-go/tools/record"
- "k8s.io/utils/ptr"
- ctrl "sigs.k8s.io/controller-runtime"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-const (
- testBindingLabel1 = "use-ec7cd950-9c2b-45a4-9f63-556fd8ea07f4"
- testBindingLabel2 = "use-ec7cd950-9c2b-45a4-9f63-556fd8ea07f5"
- testBindingLabelValue = "146000"
- conditionLen = 3
- addedLabelKey = "that-label"
- addedLabelValue = "wasnt-here"
-)
-
-func TestFunctionReconciler_Reconcile_Scaling(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- rtm := serverlessv1alpha2.NodeJs20
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
- testCfg := setUpControllerConfig(g)
- initializeServerlessResources(g, resourceClient)
- createDockerfileForRuntime(g, resourceClient, rtm)
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- gitFactory := &automock.GitClientFactory{}
- gitFactory.On("GetGitClient", mock.Anything).Return(nil)
- reconciler := NewFunctionReconciler(resourceClient, zap.NewNop().Sugar(), testCfg, gitFactory, record.NewFakeRecorder(100), statsCollector, make(chan bool))
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("should use HPA only when needed", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "hpa", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating the ConfigMap")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(1))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonConfigMapCreated))
-
- configMapList := &corev1.ConfigMapList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
- g.Expect(configMapList.Items[0].Data[FunctionSourceKey]).To(gomega.Equal(function.Spec.Source.Inline.Source))
- g.Expect(configMapList.Items[0].Data[FunctionDepsKey]).To(gomega.Equal("{}"))
-
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, false)
-
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "localhost:32132", false)
- two := int32(2)
- four := int32(4)
-
- t.Log("updating function to use fixed replicas number")
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.ScaleConfig.MaxReplicas = &two
- function.Spec.ScaleConfig.MinReplicas = &two
- // TODO: This should be applied by the defaulting webhook
- function.Spec.Replicas = &two
- g.Expect(resourceClient.Update(context.TODO(), function)).To(gomega.Succeed())
-
- t.Log("updating deployment with new number of replicas")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentUpdated))
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
- g.Expect(deployment).ToNot(gomega.BeNil())
- g.Expect(deployment.Spec.Replicas).To(gomega.Equal(&two))
-
- t.Log("HPA is removed")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(0))
-
- t.Log("deployment ready")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Minute * 5))
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
-
- t.Log("replicas increased by an external scaler")
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.Replicas = &four
- g.Expect(resourceClient.Update(context.TODO(), function)).To(gomega.Succeed())
-
- t.Log("Updating deployment")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentUpdated))
-
- // we scale the deployment directly using spec.Replicas, a new HPA shouldn't be created
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(0))
-
- t.Log("deployment ready")
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment = &deployments.Items[0]
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Minute * 5))
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
- })
-
- t.Run("should propagate spec.replicas value to deployment", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "replicas", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating cm")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, false)
-
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "localhost:32132", false)
-
- t.Log("update function")
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.ScaleConfig).NotTo(gomega.BeNil())
- g.Expect(function.Spec.Replicas).NotTo(gomega.BeNil())
-
- functionWithReplicas := function.DeepCopy()
- functionWithReplicas.Spec.ScaleConfig = nil
- functionWithReplicas.Spec.Replicas = ptr.To[int32](3)
-
- g.Expect(resourceClient.Update(context.TODO(), functionWithReplicas)).To(gomega.Succeed())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.ScaleConfig).To(gomega.BeNil())
- g.Expect(function.Spec.Replicas).NotTo(gomega.BeNil())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("remove hpa")
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- hpaList = &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(0))
-
- t.Log("deployment ready")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
- g.Expect(deployment).ToNot(gomega.BeNil())
- g.Expect(deployment.Spec.Replicas).To(gomega.Equal(ptr.To[int32](3)))
- })
-}
-
-func TestFunctionReconciler_ResourceConfig(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- rtm := serverlessv1alpha2.NodeJs20
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
- testCfg := setUpControllerConfig(g)
- initializeServerlessResources(g, resourceClient)
- createDockerfileForRuntime(g, resourceClient, rtm)
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- gitFactory := &automock.GitClientFactory{}
- gitFactory.On("GetGitClient", mock.Anything).Return(nil)
- reconciler := NewFunctionReconciler(resourceClient, zap.NewNop().Sugar(), testCfg, gitFactory, record.NewFakeRecorder(100), statsCollector, make(chan bool))
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("should reflect used resource profiles in status", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "function-with-resources", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("should reflect default profiles settings")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.FunctionResourceProfile).To(gomega.Equal(testResourceConfig.Function.Resources.DefaultPreset))
- g.Expect(function.Status.BuildResourceProfile).To(gomega.Equal(testResourceConfig.BuildJob.Resources.DefaultPreset))
-
- t.Log("should reflect custom settings")
- customResourceConfiguration := serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Resources: &corev1.ResourceRequirements{
- Limits: corev1.ResourceList{
- corev1.ResourceCPU: k8sresource.MustParse("200m"),
- corev1.ResourceMemory: k8sresource.MustParse("200Mi"),
- },
- Requests: corev1.ResourceList{
- corev1.ResourceCPU: k8sresource.MustParse("70m"),
- corev1.ResourceMemory: k8sresource.MustParse("70Mi"),
- },
- },
- },
- Function: &serverlessv1alpha2.ResourceRequirements{
- Resources: &corev1.ResourceRequirements{
- Limits: corev1.ResourceList{
- corev1.ResourceCPU: k8sresource.MustParse("200m"),
- corev1.ResourceMemory: k8sresource.MustParse("200Mi"),
- },
- Requests: corev1.ResourceList{
- corev1.ResourceCPU: k8sresource.MustParse("70m"),
- corev1.ResourceMemory: k8sresource.MustParse("70Mi"),
- },
- },
- },
- }
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.ResourceConfiguration = &customResourceConfiguration
- g.Expect(resourceClient.Update(ctx, function)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.FunctionResourceProfile).To(gomega.Equal("custom"))
- g.Expect(function.Status.BuildResourceProfile).To(gomega.Equal("custom"))
-
- t.Log("should reflect settings from profile")
- customResourceConfigurationWithProfile := serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: testBuildPresetName2,
- },
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: testFunctionPresetName2,
- },
- }
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.ResourceConfiguration = &customResourceConfigurationWithProfile
- g.Expect(resourceClient.Update(ctx, function)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.FunctionResourceProfile).To(gomega.Equal(testFunctionPresetName2))
- g.Expect(function.Status.BuildResourceProfile).To(gomega.Equal(testBuildPresetName2))
-
- t.Log("should reflect default resource settings after settings deletion")
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.ResourceConfiguration = nil
- g.Expect(resourceClient.Update(ctx, function)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.FunctionResourceProfile).To(gomega.Equal(testResourceConfig.Function.Resources.DefaultPreset))
- g.Expect(function.Status.BuildResourceProfile).To(gomega.Equal(testResourceConfig.BuildJob.Resources.DefaultPreset))
- })
-}
-
-func TestFunctionReconciler_Reconcile(t *testing.T) {
- // WARNING: This test function don't allow creating next test cases because of job limit in reconciler's configuration.
- // New test cases should be created in separated test functions.
- // TODO: Fix it
-
- t.Parallel()
- g := gomega.NewGomegaWithT(t)
- rtm := serverlessv1alpha2.NodeJs20
- resourceClient, testEnv := setUpTestEnv(g)
- defer tearDownTestEnv(g, testEnv)
- testCfg := setUpControllerConfig(g)
- initializeServerlessResources(g, resourceClient)
- createDockerfileForRuntime(g, resourceClient, rtm)
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- gitFactory := &automock.GitClientFactory{}
- gitFactory.On("GetGitClient", mock.Anything).Return(nil)
- reconciler := NewFunctionReconciler(resourceClient, zap.NewNop().Sugar(), testCfg, gitFactory, record.NewFakeRecorder(100), statsCollector, make(chan bool))
-
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- t.Run("should successfully create Function", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "success", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO: https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating the ConfigMap")
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(1))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonConfigMapCreated))
-
- configMapList := &corev1.ConfigMapList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
- g.Expect(configMapList.Items[0].Data[FunctionSourceKey]).To(gomega.Equal(function.Spec.Source.Inline.Source))
- g.Expect(configMapList.Items[0].Data[FunctionDepsKey]).To(gomega.Equal("{}"))
-
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, false)
-
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "localhost:32132", false)
-
- t.Log("should detect registry configuration change and rebuild function")
- customDockerRegistryConfiguration := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "serverless-registry-config",
- Namespace: testNamespace,
- },
- StringData: map[string]string{
- "registryAddress": "registry.external.host",
- },
- }
- g.Expect(resourceClient.Create(context.TODO(), &customDockerRegistryConfiguration)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobsDeleted))
-
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, true)
-
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "registry.external.host", true)
-
- t.Log("should detect registry configuration rollback to default configuration")
- g.Expect(resourceClient.Delete(context.TODO(), &customDockerRegistryConfiguration)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobsDeleted))
-
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, true)
-
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "localhost:32132", true)
- })
- t.Run("should set proper status on deployment fail", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "deployment-fail", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating cm")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- jobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- t.Log("job finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating svc")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("deployment failed")
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentReplicaFailure, Status: corev1.ConditionTrue, Message: "Some random message", Reason: "some reason"},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionFalse, Message: "Deployment doesn't have minimum availability."},
- }
-
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionFalse))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentFailed))
- })
-
- t.Run("should properly handle apiserver lags, when two resources are created by accident", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "apiserver-lags", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating cm")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- configMapList := &corev1.ConfigMapList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
-
- cm := configMapList.Items[0].DeepCopy()
- cm.Name = "" // generateName will create this
- cm.ResourceVersion = ""
- cm.UID = ""
- cm.CreationTimestamp = metav1.Time{}
- g.Expect(resourceClient.Create(context.TODO(), cm)).To(gomega.Succeed())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(2))
-
- t.Log("deleting all configMaps")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(0))
-
- t.Log("creating configMap again")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
-
- t.Log("creating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- jobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("accidentally creating second job")
- excessJob := jobList.Items[0].DeepCopy()
- excessJob.Name = "" // generateName will create this
- excessJob.ResourceVersion = ""
- excessJob.UID = ""
- excessJob.CreationTimestamp = metav1.Time{}
- excessJob.Spec.Selector = nil
- excessJob.Spec.Template.ObjectMeta.Labels = map[string]string{"label": "value"}
- g.Expect(resourceClient.Create(context.TODO(), excessJob)).To(gomega.Succeed())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(2))
-
- t.Log("deleting all jobs")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(0))
-
- t.Log("creating job again")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- t.Log("job finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- deployList := &appsv1.DeploymentList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
-
- t.Log("creating next deployment by accident")
-
- excessDeploy := deployList.Items[0].DeepCopy()
- excessDeploy.Name = "" // generateName will create this
- excessDeploy.ResourceVersion = ""
- excessDeploy.UID = ""
- excessDeploy.CreationTimestamp = metav1.Time{}
- g.Expect(resourceClient.Create(context.TODO(), excessDeploy)).To(gomega.Succeed())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(2))
-
- t.Log("deleting excess deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(0))
-
- t.Log("creating new deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
-
- t.Log("creating svc")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- svcList := &corev1.ServiceList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, svcList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(svcList.Items).To(gomega.HaveLen(1))
-
- t.Log("somehow there's been created a new svc with labels we use")
- excessSvc := corev1.Service{}
-
- excessSvc.Name = fmt.Sprintf("%s-%s", svcList.Items[0].Name, "2")
- excessSvc.Namespace = svcList.Items[0].Namespace
- excessSvc.Labels = svcList.Items[0].Labels
-
- excessSvc.Spec.Ports = svcList.Items[0].Spec.Ports
- excessSvc.Spec.Selector = svcList.Items[0].Spec.Selector
-
- err = resourceClient.Create(context.TODO(), &excessSvc)
-
- g.Expect(err).To(gomega.Succeed())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, svcList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(svcList.Items).To(gomega.HaveLen(2))
-
- t.Log("deleting that svc")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, svcList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(svcList.Items).To(gomega.HaveLen(1))
-
- t.Log("creating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
- t.Log("creating next hpa by accident - apiserver lag")
-
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
- excessHpa := hpaList.Items[0].DeepCopy()
- excessHpa.Name = "" // generateName will create this
- excessHpa.ResourceVersion = ""
- excessHpa.UID = ""
- excessHpa.CreationTimestamp = metav1.Time{}
- g.Expect(resourceClient.Create(context.TODO(), excessHpa)).To(gomega.Succeed())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(2))
-
- t.Log("deleting excess hpa 🔫")
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(0))
-
- t.Log("creating new hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- t.Log("deployment ready")
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
-
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(hpaList.Items[0].Spec.ScaleTargetRef.Name).To(gomega.Equal(inFunction.GetName()), "hpa should target the function")
-
- t.Log("deleting deployment by 'accident' to check proper hpa-deployment reference")
-
- err = resourceClient.DeleteAllBySelector(context.TODO(), &appsv1.Deployment{}, request.Namespace, labels.SelectorFromSet(fnLabels))
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("recreating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("updating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
-
- g.Expect(hpaList.Items[0].Spec.ScaleTargetRef.Name).To(gomega.Equal(function.GetName()), "hpa should target function")
- })
-
- t.Run("should requeue before creating a job", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "requeue-before-job", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- // Create new reconciler as this test modify reconciler configuration MaxSimultaneousJobs value
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- gitFactory := &automock.GitClientFactory{}
- gitFactory.On("GetGitClient", mock.Anything).Return(nil)
-
- reconciler := NewFunctionReconciler(resourceClient, zap.NewNop().Sugar(), testCfg, gitFactory, record.NewFakeRecorder(100), statsCollector, make(chan bool))
- reconciler.config.Build.MaxSimultaneousJobs = 1
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- secondFunction := newFixFunction(testNamespace, "second-function", 1, 2)
- secondRequest := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: secondFunction.GetNamespace(), Name: secondFunction.GetName()}}
- g.Expect(resourceClient.Create(context.TODO(), secondFunction)).To(gomega.Succeed())
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating 2 cms")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- _, err = reconciler.Reconcile(ctx, secondRequest)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating 2 jobs")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- result, err := reconciler.Reconcile(ctx, secondRequest)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.RequeueAfter).To(gomega.BeIdenticalTo(time.Second * 5))
-
- t.Log("handling first job")
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- jobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- t.Log("first job finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("handling second job")
- secFunction := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, secFunction)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, secondRequest)
- g.Expect(err).To(gomega.BeNil())
-
- secJobList := &batchv1.JobList{}
- err = reconciler.client.ListByLabel(context.TODO(), secFunction.GetNamespace(), reconciler.internalFunctionLabels(secondFunction), secJobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(secJobList.Items).To(gomega.HaveLen(1))
-
- secJob := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, secJob)).To(gomega.Succeed())
- g.Expect(secJob).ToNot(gomega.BeNil())
- secJob.Status.Succeeded = 1
- now = metav1.Now()
- secJob.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), secJob)).To(gomega.Succeed())
-
- t.Log("second job finished")
- _, err = reconciler.Reconcile(ctx, secondRequest)
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("should behave correctly on label addition and subtraction", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "labels-operations", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating cm")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- t.Log("creating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- jobList := &batchv1.JobList{}
- err = resourceClient.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- t.Log("job finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating svc")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("deployment ready")
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
-
- deployment := &deployments.Items[0]
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("updating function metadata.labels")
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).To(gomega.BeNil())
-
- functionWithLabels := function.DeepCopy()
- functionWithLabels.Labels = map[string]string{
- addedLabelKey: addedLabelValue,
- }
-
- g.Expect(resourceClient.Update(context.TODO(), functionWithLabels)).To(gomega.Succeed())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).NotTo(gomega.BeNil())
-
- t.Log("updating configmap")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- configMapList := &corev1.ConfigMapList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
- g.Expect(configMapList.Items[0].Labels).To(gomega.HaveLen(4))
-
- cmLabelVal, ok := configMapList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeTrue())
- g.Expect(cmLabelVal).To(gomega.Equal(addedLabelValue))
-
- t.Log("updating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobUpdated))
-
- jobList = &batchv1.JobList{}
- err = resourceClient.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
- g.Expect(jobList.Items[0].Labels).To(gomega.HaveLen(4))
-
- jobLabelVal, ok := jobList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeTrue())
- g.Expect(jobLabelVal).To(gomega.Equal(addedLabelValue))
-
- t.Log("reconciling job to make sure it's already finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobFinished))
-
- t.Log("updating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- deployList := &appsv1.DeploymentList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
- g.Expect(deployList.Items[0].Labels).To(gomega.HaveLen(4))
-
- deployLabelVal, ok := deployList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeTrue())
- g.Expect(deployLabelVal).To(gomega.Equal(addedLabelValue))
-
- t.Log("updating service")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- svcList := &corev1.ServiceList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, svcList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(svcList.Items).To(gomega.HaveLen(1))
- g.Expect(svcList.Items[0].Labels).To(gomega.HaveLen(4))
-
- svcLabelVal, ok := svcList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeTrue())
- g.Expect(svcLabelVal).To(gomega.Equal(addedLabelValue))
-
- t.Log("updating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- hpaList := &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
- g.Expect(hpaList.Items[0].Labels).To(gomega.HaveLen(4))
-
- hpaLabelVal, ok := hpaList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeTrue())
- g.Expect(hpaLabelVal).To(gomega.Equal(addedLabelValue))
-
- t.Log("status ready")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
-
- t.Log("getting rid of formerly added labels")
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).NotTo(gomega.BeNil())
-
- functionWithoutLabels := function.DeepCopy()
- functionWithoutLabels.Labels = nil
- g.Expect(resourceClient.Update(context.TODO(), functionWithoutLabels)).To(gomega.Succeed())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).To(gomega.BeNil())
-
- t.Log("reconciling again -> configmap")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- configMapList = &corev1.ConfigMapList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, configMapList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(configMapList.Items).To(gomega.HaveLen(1))
-
- _, ok = configMapList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeFalse())
-
- t.Log("reconciling again -> job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- jobList = &batchv1.JobList{}
- err = resourceClient.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- _, ok = jobList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeFalse())
-
- t.Log("reconciling again -> job finished")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("reconciling again -> deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- deployList = &appsv1.DeploymentList{}
- err = resourceClient.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, deployList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(deployList.Items).To(gomega.HaveLen(1))
-
- _, ok = deployList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeFalse())
-
- t.Log("reconciling again -> service")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- svcList = &corev1.ServiceList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, svcList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(svcList.Items).To(gomega.HaveLen(1))
-
- _, ok = svcList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeFalse())
-
- t.Log("reconciling again -> hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- hpaList = &autoscalingv1.HorizontalPodAutoscalerList{}
- err = reconciler.client.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, hpaList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(hpaList.Items).To(gomega.HaveLen(1))
-
- _, ok = hpaList.Items[0].Labels[addedLabelKey]
- g.Expect(ok).To(gomega.BeFalse())
-
- t.Log("reconciling again -> deployment ready")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
-
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
- })
-
- t.Run("should behave correctly on label addition when job is in building phase", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "add-label-while-building", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("creating cm")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
-
- jobList := &batchv1.JobList{}
- err = resourceClient.ListByLabel(context.TODO(), function.GetNamespace(), fnLabels, jobList)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(jobList.Items).To(gomega.HaveLen(1))
-
- t.Log("updating function metadata.labels")
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).To(gomega.BeNil())
-
- functionWithLabels := function.DeepCopy()
- functionWithLabels.Labels = map[string]string{
- "that-label": "wasnt-here",
- }
- g.Expect(resourceClient.Update(context.TODO(), functionWithLabels)).To(gomega.Succeed())
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Labels).NotTo(gomega.BeNil())
-
- t.Log("updating configmap")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("updating job")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("job's finished")
-
- job := &batchv1.Job{}
- g.Expect(resourceClient.Get(context.TODO(), types.NamespacedName{Namespace: jobList.Items[0].GetNamespace(), Name: jobList.Items[0].GetName()}, job)).To(gomega.Succeed())
- g.Expect(job).ToNot(gomega.BeNil())
- job.Status.Succeeded = 1
- now := metav1.Now()
- job.Status.CompletionTime = &now
- g.Expect(resourceClient.Status().Update(context.TODO(), job)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating deployment")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating svc")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("creating hpa")
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("deployment ready")
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
-
- deployment := &deployments.Items[0]
- deployment.Status.Conditions = []appsv1.DeploymentCondition{
- {Type: appsv1.DeploymentAvailable, Status: corev1.ConditionTrue, Reason: MinimumReplicasAvailable},
- {Type: appsv1.DeploymentProgressing, Status: corev1.ConditionTrue, Reason: NewRSAvailableReason},
- }
- g.Expect(resourceClient.Status().Update(context.TODO(), deployment)).To(gomega.Succeed())
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("should handle reconciliation lags", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
-
- //WHEN
- t.Log("handling not existing Function")
- result, err := reconciler.Reconcile(ctx, ctrl.Request{NamespacedName: types.NamespacedName{Namespace: "nope", Name: "noooooopppeee"}})
-
- //THEN
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 0))
- })
-
- t.Run("should return error when desired dockerfile runtime configmap not found", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- testNamespace := "test-namespace"
- fnName := "function"
- function := newFixFunction(testNamespace, fnName, 1, 2)
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: function.GetNamespace(), Name: function.GetName()}}
- g.Expect(resourceClient.Create(context.TODO(), &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{
- Name: testNamespace,
- }})).To(gomega.Succeed())
- g.Expect(resourceClient.Create(context.TODO(), function)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, function)
-
- //WHEN
- _, err := reconciler.Reconcile(ctx, request)
-
- //THEN
- g.Expect(err).To(gomega.HaveOccurred())
- g.Expect(err.Error()).To(gomega.ContainSubstring("docker registry configuration not found"))
-
- })
-
- t.Run("should properly handle `kubectl rollout restart` changing annotations in deployment", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunction(testNamespace, "rollout-restart-fn", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- s := systemState{
- //TODO https://github.com/kyma-project/kyma/issues/14079
- instance: *inFunction,
- }
-
- fnLabels := s.functionLabels()
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("successfully deploying a function")
- _, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- assertSuccessfulFunctionBuild(t, resourceClient, reconciler, request, fnLabels, false)
- assertSuccessfulFunctionDeployment(t, resourceClient, reconciler, request, fnLabels, "localhost:32132", false)
-
- t.Log("updating deployment.spec.template.metadata.annotations, e.g. by using kubectl rollout restart command")
- deployments := &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment := &deployments.Items[0]
- g.Expect(deployment).ToNot(gomega.BeNil())
-
- g.Expect(deployment.Spec.Template.Annotations).To(gomega.HaveKeyWithValue(
- "proxy.istio.io/config", "{ \"holdApplicationUntilProxyStarts\": true }"))
- copiedDeploy := deployment.DeepCopy()
- const restartedAtAnnotationKey = "kubectl.kubernetes.io/restartedAt"
- const restartedAtAnnotationValue = "2021-03-10T11:28:01+01:00"
- restartedAtAnnotation := map[string]string{
- restartedAtAnnotationKey: restartedAtAnnotationValue, // example annotation added by kubectl
- }
- copiedDeploy.Spec.Template.Annotations = restartedAtAnnotation
- g.Expect(resourceClient.Update(context.Background(), copiedDeploy))
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentUpdated))
-
- _, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
-
- t.Log("making sure function is ready")
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.Conditions).To(gomega.HaveLen(conditionLen))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(corev1.ConditionTrue))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionRunning)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonDeploymentReady))
-
- t.Log("checking whether that added annotation is still there")
- deployments = &appsv1.DeploymentList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), request.Namespace, fnLabels, deployments)).To(gomega.Succeed())
- g.Expect(len(deployments.Items)).To(gomega.Equal(1))
- deployment = &deployments.Items[0]
- g.Expect(deployment).ToNot(gomega.BeNil())
-
- g.Expect(deployment.Spec.Template.Annotations).To(gomega.HaveKeyWithValue(restartedAtAnnotationKey, restartedAtAnnotationValue))
- })
-
- t.Run("should reconcile function with RuntimeImageOverride", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- runtimeImageOverride := "any-custom-fn-image"
- inFunction := newFixFunctionWithCustomImage(testNamespace, "custom-runtime-fn-image", runtimeImageOverride, 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("should configure function")
-
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- t.Log("should create build job with custom runtime image")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, &function)).To(gomega.Succeed())
- g.Expect(function.Spec.RuntimeImageOverride).To(gomega.Equal(runtimeImageOverride))
- g.Expect(function.Status.RuntimeImageOverride).To(gomega.Equal(runtimeImageOverride))
- g.Expect(function.Status.RuntimeImage).To(gomega.Equal(runtimeImageOverride))
-
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobCreated))
-
- jobs := &batchv1.JobList{}
- g.Expect(resourceClient.ListByLabel(context.TODO(), inFunction.GetNamespace(), internalFunctionLabels(*inFunction), jobs))
- g.Expect(jobs.Items).To(gomega.HaveLen(1))
- buildContainers := jobs.Items[0].Spec.Template.Spec.Containers
- g.Expect(buildContainers).To(gomega.HaveLen(1))
- buildArgs := buildContainers[0].Args
- g.Expect(buildArgs).To(gomega.ContainElement(fmt.Sprintf("--build-arg=base_image=%s", runtimeImageOverride)))
-
- //https://github.com/kyma-project/kyma/issues/17552
- t.Log("should wait for function's build and don't change anything related to job")
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, &function)).To(gomega.Succeed())
- g.Expect(getConditionStatus(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(corev1.ConditionUnknown))
- g.Expect(getConditionReason(function.Status.Conditions, serverlessv1alpha2.ConditionBuildReady)).To(gomega.Equal(serverlessv1alpha2.ConditionReasonJobRunning))
- })
-
- t.Run("should reconcile function with added RuntimeImageOverride removed", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- runtimeImageOverride := "any-custom-fn-image"
- inFunction := newFixFunctionWithCustomImage(testNamespace, "custom-runtime-fn-image", "initial-custom-fn-image", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("should detect runtimeImageOverride change")
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.RuntimeImageOverride = runtimeImageOverride
- g.Expect((resourceClient.Update(ctx, function))).To(gomega.Succeed())
-
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.RuntimeImageOverride).To(gomega.Equal(runtimeImageOverride))
- g.Expect(function.Status.RuntimeImageOverride).To(gomega.Equal(runtimeImageOverride))
- g.Expect(function.Status.RuntimeImage).To(gomega.Equal(runtimeImageOverride))
-
- t.Log("should detect runtimeImageOverride rollback")
-
- function.Spec.RuntimeImageOverride = ""
- g.Expect((resourceClient.Update(ctx, function))).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.RuntimeImageOverride).To(gomega.Equal(""))
- g.Expect(function.Status.RuntimeImageOverride).To(gomega.Equal(""))
- g.Expect(function.Status.RuntimeImage).To(gomega.Equal("some_image"))
- })
- t.Run("should reconcile function with new runtimeImage from Dockerfile", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- inFunction := newFixFunctionWithCustomImage(testNamespace, "custom-runtime-fn-image", "", 1, 2)
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- t.Log("should detect runtimeImage change")
-
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.RuntimeImage).To(gomega.Equal("some_image"))
-
- configMap := changeDockerfileForRuntime(rtm)
-
- g.Expect(resourceClient.Update(ctx, configMap)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Status.RuntimeImage).To(gomega.Equal("other_image"))
- })
- t.Run("should reconcile function with SecretMounts", func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- someSecretMount := serverlessv1alpha2.SecretMount{
- SecretName: "some-secret-name",
- MountPath: "/some/secret/mount/path",
- }
- inFunction := newFixFunction(testNamespace, "function-with-secret-mounts", 1, 2)
- inFunction.Spec.SecretMounts = []serverlessv1alpha2.SecretMount{
- someSecretMount,
- }
- g.Expect(resourceClient.Create(context.TODO(), inFunction)).To(gomega.Succeed())
- defer deleteFunction(g, resourceClient, inFunction)
-
- request := ctrl.Request{NamespacedName: types.NamespacedName{Namespace: inFunction.GetNamespace(), Name: inFunction.GetName()}}
-
- //WHEN
- function := &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.SecretMounts).To(gomega.HaveLen(1))
- g.Expect(function.Spec.SecretMounts[0]).To(gomega.Equal(someSecretMount))
-
- t.Log("should detect SecretMount change")
-
- anotherSecretMount := serverlessv1alpha2.SecretMount{
- SecretName: "another-secret-name",
- MountPath: "/another/secret/mount/path",
- }
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- function.Spec.SecretMounts[0] = anotherSecretMount
- g.Expect(resourceClient.Update(ctx, function)).To(gomega.Succeed())
-
- result, err := reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.SecretMounts).To(gomega.HaveLen(1))
- g.Expect(function.Spec.SecretMounts[0]).To(gomega.Equal(anotherSecretMount))
-
- t.Log("should detect SecretMount delete")
-
- function.Spec.SecretMounts = []serverlessv1alpha2.SecretMount{}
- g.Expect(resourceClient.Update(ctx, function)).To(gomega.Succeed())
-
- result, err = reconciler.Reconcile(ctx, request)
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.Requeue).To(gomega.BeFalse())
- g.Expect(result.RequeueAfter).To(gomega.Equal(time.Second * 1))
-
- function = &serverlessv1alpha2.Function{}
- g.Expect(resourceClient.Get(context.TODO(), request.NamespacedName, function)).To(gomega.Succeed())
- g.Expect(function.Spec.SecretMounts).To(gomega.HaveLen(0))
- })
-}
-
-func deleteFunction(g *gomega.GomegaWithT, resourceClient resource.Client, function *serverlessv1alpha2.Function) {
- err := resourceClient.Delete(context.TODO(), function)
- g.Expect(err).To(gomega.BeNil())
-}
diff --git a/components/serverless/internal/controllers/serverless/gitops.go b/components/serverless/internal/controllers/serverless/gitops.go
deleted file mode 100644
index d06d6b284..000000000
--- a/components/serverless/internal/controllers/serverless/gitops.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package serverless
-
-import (
- "fmt"
-
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- ctrl "sigs.k8s.io/controller-runtime"
-)
-
-func NextRequeue(err error) (res ctrl.Result, errMsg string) {
- if git.IsNotRecoverableError(err) {
- return ctrl.Result{Requeue: false}, fmt.Sprintf("Stop reconciliation, reason: %s", err.Error())
- }
-
- errMsg = fmt.Sprintf("Sources update failed, reason: %v", err)
- if git.IsAuthErr(err) {
- errMsg = "Authorization to git server failed"
- }
-
- // use exponential delay
- return ctrl.Result{Requeue: true}, errMsg
-}
diff --git a/components/serverless/internal/controllers/serverless/gitops_test.go b/components/serverless/internal/controllers/serverless/gitops_test.go
deleted file mode 100644
index 5789d6c70..000000000
--- a/components/serverless/internal/controllers/serverless/gitops_test.go
+++ /dev/null
@@ -1,237 +0,0 @@
-package serverless
-
-import (
- "errors"
- "strings"
- "testing"
-
- git2go "github.com/libgit2/git2go/v34"
- "github.com/stretchr/testify/assert"
- ctrl "sigs.k8s.io/controller-runtime"
-
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
-)
-
-func Test_isOnSourceChange(t *testing.T) {
- testCases := []struct {
- desc string
- fn v1alpha2.Function
- revision string
- expectedResult bool
- }{
- {
- desc: "new function",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{},
- },
- Runtime: v1alpha2.NodeJs20,
- },
- },
- expectedResult: true,
- },
- {
- desc: "new function fixed on commit",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- },
- },
- Runtime: v1alpha2.NodeJs20,
- },
- },
- expectedResult: true,
- },
- {
- desc: "new function follow head",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- },
- },
- Runtime: v1alpha2.NodeJs20,
- },
- },
- expectedResult: true,
- },
- {
- desc: "function did not change",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- },
- },
- Runtime: v1alpha2.NodeJs20,
- },
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- Commit: "1",
- Runtime: v1alpha2.NodeJs20,
- },
- },
- revision: "1",
- expectedResult: false,
- },
- {
- desc: "function change fixed revision",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "2",
- },
- },
- },
- Runtime: v1alpha2.NodeJs20,
- },
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- },
- },
- expectedResult: true,
- },
- {
- desc: "function change",
- fn: v1alpha2.Function{
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "1",
- },
- },
- },
- revision: "2",
- expectedResult: true,
- },
- {
- desc: "function change base dir",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "2",
- BaseDir: "base_dir",
- },
- },
- },
- },
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "2",
- },
- },
- },
- expectedResult: true,
- },
- {
- desc: "function change branch",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "branch",
- },
- },
- },
- },
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "2",
- },
- },
- },
- expectedResult: true,
- },
- {
- desc: "function change dockerfile",
- fn: v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Source: v1alpha2.Source{
- GitRepository: &v1alpha2.GitRepositorySource{
- Repository: v1alpha2.Repository{
- Reference: "2",
- },
- },
- },
- Runtime: v1alpha2.NodeJs20,
- },
- Status: v1alpha2.FunctionStatus{
- Repository: v1alpha2.Repository{
- Reference: "2",
- },
- },
- },
- expectedResult: true,
- },
- }
-
- for _, tC := range testCases {
- t.Run(tC.desc, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- s := systemState{
- instance: tC.fn,
- }
- actual := s.gitFnSrcChanged(tC.revision)
- g.Expect(actual).To(gomega.Equal(tC.expectedResult))
- })
- }
-}
-
-func TestNextRequeue(t *testing.T) {
- //GIVEN
- testCases := []struct {
- name string
- inputErr error
- expectedErrMsg string
- expectedResult ctrl.Result
- }{
- {
- name: "Git unrecoverable error",
- inputErr: git2go.MakeGitError2(int(git2go.ErrorCodeNotFound)),
- expectedErrMsg: "Stop reconciliation, reason:",
- expectedResult: ctrl.Result{Requeue: false},
- },
- {
- name: "Git authorization error",
- inputErr: errors.New("unexpected http status code: 403"),
- expectedErrMsg: "Authorization to git server failed",
- expectedResult: ctrl.Result{Requeue: true},
- }, {
- name: "Git generic error",
- inputErr: git2go.MakeGitError2(int(git2go.ErrorCodeAmbiguous)),
- expectedErrMsg: "Sources update failed, reason:",
- expectedResult: ctrl.Result{Requeue: true},
- },
- }
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- //WHEN
- result, errMsg := NextRequeue(testCase.inputErr)
-
- //THEN
- assert.Equal(t, testCase.expectedResult, result)
- assert.NotEmpty(t, testCase.expectedErrMsg)
- assert.True(t, strings.HasPrefix(errMsg, testCase.expectedErrMsg), "errMsg: %s, doesn't start with: %s", errMsg, testCase.expectedErrMsg)
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/health.go b/components/serverless/internal/controllers/serverless/health.go
deleted file mode 100644
index 26b3dc911..000000000
--- a/components/serverless/internal/controllers/serverless/health.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package serverless
-
-import (
- "errors"
- "net/http"
- "time"
-
- "go.uber.org/zap"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- ctrl "sigs.k8s.io/controller-runtime"
- "sigs.k8s.io/controller-runtime/pkg/event"
- "sigs.k8s.io/controller-runtime/pkg/healthz"
-)
-
-// This const should be longer than 253 characters to avoid collisions with real k8s objects.
-// https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#dns-subdomain-names
-// This event is artificial and it's only used to check if reconciliation loop didn't stop reconciling
-// The event is not fully validated, that's why we can use invalid name.
-const HealthEvent = "HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT_HEALTH_EVENT"
-
-var _ healthz.Checker = HealthChecker{}.Checker
-
-type HealthChecker struct {
- checkCh chan event.GenericEvent
- healthCh chan bool
- timeout time.Duration
- log *zap.SugaredLogger
-}
-
-func getHealthChannels() (chan event.GenericEvent, chan bool) {
- checkCh := make(chan event.GenericEvent)
- returnCh := make(chan bool)
- return checkCh, returnCh
-}
-
-func NewHealthChecker(timeout time.Duration, logger *zap.SugaredLogger) (HealthChecker, chan event.GenericEvent, chan bool) {
- checkCh, returnCh := getHealthChannels()
- return HealthChecker{checkCh: checkCh, healthCh: returnCh, timeout: timeout, log: logger}, checkCh, returnCh
-}
-
-func (h HealthChecker) Checker(req *http.Request) error {
- h.log.Debug("Liveness handler triggered")
-
- checkEvent := event.GenericEvent{
- Object: &corev1.Event{
- ObjectMeta: metav1.ObjectMeta{
- Name: HealthEvent,
- },
- },
- }
- select {
- case h.checkCh <- checkEvent:
- case <-time.After(h.timeout):
- return errors.New("timeout when sending check event")
- }
-
- h.log.Debug("check event send to reconcile loop")
- select {
- case <-h.healthCh:
- h.log.Debug("reconcile loop is healthy")
- return nil
- case <-time.After(h.timeout):
- h.log.Debug("reconcile timeout")
- return errors.New("reconcile didn't send confirmation")
- }
-}
-
-func IsHealthCheckRequest(req ctrl.Request) bool {
- return req.Name == HealthEvent
-}
diff --git a/components/serverless/internal/controllers/serverless/health_test.go b/components/serverless/internal/controllers/serverless/health_test.go
deleted file mode 100644
index ef6676775..000000000
--- a/components/serverless/internal/controllers/serverless/health_test.go
+++ /dev/null
@@ -1,69 +0,0 @@
-package serverless_test
-
-import (
- "testing"
- "time"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap"
-)
-
-func TestHealthChecker_Checker(t *testing.T) {
- log := zap.NewNop().Sugar()
- t.Run("Success", func(t *testing.T) {
- //GIVEN
- timeout := 10 * time.Second
- checker, inCh, outCh := serverless.NewHealthChecker(timeout, log)
-
- //WHEN
- go func() {
- check := <-inCh
- require.Equal(t, check.Object.GetName(), serverless.HealthEvent)
- outCh <- true
- }()
- err := checker.Checker(nil)
-
- //THEN
- require.NoError(t, err)
- })
-
- t.Run("Timeout", func(t *testing.T) {
- //GIVEN
- timeout := time.Second
- checker, inCh, _ := serverless.NewHealthChecker(timeout, log)
-
- //WHEN
- go func() {
- check := <-inCh
- require.Equal(t, check.Object.GetName(), serverless.HealthEvent)
- }()
- err := checker.Checker(nil)
-
- //THEN
- require.Error(t, err)
- require.Contains(t, err.Error(), "reconcile didn't send confirmation")
-
- })
-
- t.Run("Can't send check event", func(t *testing.T) {
- //GIVEN
- timeout := time.Second
- checker, _, _ := serverless.NewHealthChecker(timeout, log)
-
- //WHEN
- err := checker.Checker(nil)
-
- //THEN
- require.Error(t, err)
- require.Contains(t, err.Error(), "timeout when sending check event")
- })
-}
-
-func TestHealthName(t *testing.T) {
- //GIVEN
- //WHEN
- // This const is longer than 253 characters to avoid collisions with real k8s objects.
- require.Greater(t, len(serverless.HealthEvent), 253)
- //THEN
-}
diff --git a/components/serverless/internal/controllers/serverless/job.go b/components/serverless/internal/controllers/serverless/job.go
deleted file mode 100644
index ec4f75beb..000000000
--- a/components/serverless/internal/controllers/serverless/job.go
+++ /dev/null
@@ -1,259 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- "regexp"
- "strings"
- "time"
-
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- apilabels "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
-)
-
-var fcManagedByLabel = map[string]string{serverlessv1alpha2.FunctionManagedByLabel: serverlessv1alpha2.FunctionControllerValue}
-
-var backoffLimitExceeded = func(reason string) bool {
- return reason == "BackoffLimitExceeded"
-}
-
-// build state function that will check if a job responsible for building function fnImage succeeded or failed;
-// if a job is not running start one
-func buildStateFnCheckImageJob(expectedJob batchv1.Job) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- labels := internalFunctionLabels(s.instance)
-
- err := r.client.ListByLabel(ctx, s.instance.GetNamespace(), labels, &s.jobs)
- if err != nil {
- return nil, errors.Wrap(err, "while listing jobs")
- }
-
- jobLen := len(s.jobs.Items)
-
- if jobLen == 0 {
- return buildStateFnRunJob(expectedJob), nil
- }
-
- jobFailed := s.jobFailed(backoffLimitExceeded)
-
- conditionStatus := getConditionStatus(
- s.instance.Status.Conditions,
- serverlessv1alpha2.ConditionBuildReady,
- )
-
- if jobFailed && conditionStatus == corev1.ConditionFalse {
- return stateFnInlineDeleteJobs, nil
- }
-
- if jobFailed {
- r.result = ctrl.Result{
- RequeueAfter: time.Minute * 5,
- Requeue: true,
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobFailed,
- Message: fmt.Sprintf("Job %s failed, it will be re-run", s.jobs.Items[0].Name),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- s.fnImage = s.buildImageAddress(r.cfg.docker.PullAddress)
-
- diffRuntimeImage, err := functionRuntimeChanged(ctx, r, s)
- if err != nil {
- return nil, errors.Wrap(err, "while checking runtime image change")
- }
-
- if diffRuntimeImage {
- return stateFnInlineDeleteJobs, nil
- }
-
- jobChanged := s.fnJobChanged(expectedJob)
- if !jobChanged {
- return stateFnCheckDeployments, nil
- }
-
- if jobLen > 1 || !equalJobs(s.jobs.Items[0], expectedJob) {
- return stateFnInlineDeleteJobs, nil
- }
-
- expectedLabels := expectedJob.GetLabels()
-
- if !mapsEqual(s.jobs.Items[0].GetLabels(), expectedLabels) {
- return buildStateFnInlineUpdateJobLabels(expectedLabels), nil
- }
-
- return stateFnUpdateJobStatus, nil
- }
-}
-
-func functionRuntimeChanged(ctx context.Context, r *reconciler, s *systemState) (bool, error) {
- functionRuntimeImage := s.instance.Status.RuntimeImage
- if functionRuntimeImage == "" {
- return false, nil
- }
- if s.instance.Spec.RuntimeImageOverride != "" {
- result := functionRuntimeImage == s.instance.Spec.RuntimeImageOverride
- return !result, nil
- }
-
- latestRuntimeImage, err := getRuntimeImageFromConfigMap(ctx, r, s)
- if err != nil {
- return false, errors.Wrap(err, "while fetching runtime image from config map")
- }
- result := latestRuntimeImage == functionRuntimeImage
- return !result, nil
-}
-
-func buildStateFnRunJob(expectedJob batchv1.Job) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- // validate if the max number of running jobs
- // didn't exceed max simultaneous jobs number
-
- var allJobs batchv1.JobList
-
- err := r.client.ListByLabel(ctx, "", fcManagedByLabel, &allJobs)
- if err != nil {
- return nil, errors.Wrap(err, "while listing jobs")
- }
-
- activeJobsCount := countJobs(allJobs, didNotFail, didNotSucceed)
- if activeJobsCount >= r.cfg.fn.Build.MaxSimultaneousJobs {
- r.result = ctrl.Result{
- RequeueAfter: time.Second * 5,
- }
- return nil, nil
- }
-
- err = r.client.CreateWithReference(ctx, &s.instance, &expectedJob)
- if err != nil {
- return nil, errors.Wrap(err, "while creating job")
- }
-
- runtimeImage, err := getRuntimeImageFromConfigMap(ctx, r, s)
- if err != nil {
- return nil, errors.Wrap(err, "while extracting runtime fn-image from config map")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobCreated,
- Message: fmt.Sprintf("Job %s created", expectedJob.GetName()),
- }
-
- s.instance.Status.RuntimeImage = runtimeImage
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func getRuntimeImageFromConfigMap(ctx context.Context, r *reconciler, s *systemState) (string, error) {
- instance := &corev1.ConfigMap{}
- dockerfileConfigMapName := fmt.Sprintf("dockerfile-%s", s.instance.Status.Runtime)
- err := r.client.Get(ctx, types.NamespacedName{Namespace: s.instance.Namespace, Name: dockerfileConfigMapName}, instance)
- if err != nil {
- return "", errors.Wrap(err, "while extracting correct config map for given runtime")
- }
- baseImage := instance.Data["Dockerfile"]
- re := regexp.MustCompile(`base_image=.*`)
- matchedLines := re.FindStringSubmatch(baseImage)
- if len(matchedLines) == 0 {
- return "", errors.Errorf("could not find the base image from %s", dockerfileConfigMapName)
- }
- runtimeImage := strings.TrimPrefix(matchedLines[0], "base_image=")
- return runtimeImage, err
-}
-
-func stateFnInlineDeleteJobs(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("delete Jobs")
-
- labels := internalFunctionLabels(s.instance)
- selector := apilabels.SelectorFromSet(labels)
-
- err := r.client.DeleteAllBySelector(ctx, &batchv1.Job{}, s.instance.GetNamespace(), selector)
- if err != nil {
- return nil, errors.Wrap(err, "while deleting jobs")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobsDeleted,
- Message: "Old Jobs deleted",
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
-}
-
-func buildStateFnInlineUpdateJobLabels(m map[string]string) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- s.jobs.Items[0].Labels = m
-
- jobName := s.jobs.Items[0].GetName()
-
- r.log.Info(fmt.Sprintf("updating Job %q labels", jobName))
-
- err := r.client.Update(ctx, &s.jobs.Items[0])
- if err != nil {
- return nil, errors.Wrap(err, "while updating job")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobUpdated,
- Message: fmt.Sprintf("Job %s updated", jobName),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func stateFnUpdateJobStatus(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- if err := ctx.Err(); err != nil {
- return nil, errors.Wrap(err, "context error")
- }
-
- job := &s.jobs.Items[0]
- jobName := job.GetName()
-
- if job.Status.CompletionTime != nil {
- r.log.Info(fmt.Sprintf("job finished %q", jobName))
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionTrue,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobFinished,
- Message: fmt.Sprintf("Job %s finished", jobName),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- if job.Status.Failed < 1 {
- r.log.Info(fmt.Sprintf("job in progress %q", jobName))
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionBuildReady,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonJobRunning,
- Message: fmt.Sprintf("Job %s is still in progress", jobName),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- return nil, nil
-}
diff --git a/components/serverless/internal/controllers/serverless/job_test.go b/components/serverless/internal/controllers/serverless/job_test.go
deleted file mode 100644
index 0425e166d..000000000
--- a/components/serverless/internal/controllers/serverless/job_test.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- "github.com/onsi/gomega"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
-)
-
-func TestFunctionReconciler_equalJobs(t *testing.T) {
- type args struct {
- existing batchv1.Job
- expected batchv1.Job
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "two jobs with same container args are same",
- args: args{
- existing: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=123"}}},
- },
- },
- }},
- expected: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=123"}}},
- },
- },
- }},
- },
- want: true,
- },
- {
- name: "two jobs with same, multiple container args are same",
- args: args{
- existing: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "arg2", "--destination=123"}}},
- },
- },
- }},
- expected: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "arg2", "--destination=123"}}},
- },
- },
- }},
- },
- want: true,
- },
- {
- name: "two jobs with different length of args are same when destination is same",
- args: args{
- existing: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=123"}}},
- },
- },
- }},
- expected: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "args2", "--destination=123"}}},
- },
- },
- }},
- },
- want: true,
- },
- {
- name: "two jobs with different arg are the same when destination is same",
- args: args{
- existing: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=123"}}},
- },
- },
- }},
- expected: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"argument-number-1", "--destination=123"}}},
- },
- },
- }},
- },
- want: true,
- },
- {
- name: "two jobs with different destination arg are the not same",
- args: args{
- existing: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=1223"}}},
- },
- },
- }},
- expected: batchv1.Job{Spec: batchv1.JobSpec{
- Template: corev1.PodTemplateSpec{
- Spec: corev1.PodSpec{
- Containers: []corev1.Container{{Args: []string{"arg1", "--destination=123"}}},
- },
- },
- }},
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalJobs(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_getArg(t *testing.T) {
- tests := []struct {
- name string
- args []string
- arg string
- want string
- }{
- {
- name: "return argument when exist",
- args: []string{"--arg1=123", "--arg2", "--destination=1234"},
- arg: "--destination",
- want: "--destination=1234",
- },
- {
- name: "return empty when not exist",
- args: []string{"--arg1=123", "--arg2"},
- arg: "--destination",
- want: "",
- },
- {
- name: "return empty when no arguments passed",
- args: nil,
- arg: "--destination",
- want: "",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := getArg(tt.args, tt.arg)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/metrics/function_metrics.go b/components/serverless/internal/controllers/serverless/metrics/function_metrics.go
deleted file mode 100644
index ddbfb1e61..000000000
--- a/components/serverless/internal/controllers/serverless/metrics/function_metrics.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package metrics
-
-import (
- "fmt"
- "time"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/prometheus/client_golang/prometheus"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
- "sigs.k8s.io/controller-runtime/pkg/metrics"
-)
-
-const (
- NameLabelKey = "name"
- NamespaceLabelKey = "namespace"
- TypeLabelKey = "type"
- RuntimeLabelKey = "runtime"
-)
-
-type PrometheusStatsCollector struct {
- conditionGaugeSet map[string]bool
- conditionGauges map[serverlessv1alpha2.ConditionType]*prometheus.GaugeVec
- FunctionConfiguredStatusGaugeVec *prometheus.GaugeVec
- FunctionBuiltStatusGaugeVec *prometheus.GaugeVec
- FunctionRunningStatusGaugeVec *prometheus.GaugeVec
-}
-
-func NewPrometheusStatsCollector() *PrometheusStatsCollector {
- functionConfiguredStatusGaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{
- Name: "function_configured_status_duration_millisecond",
- Help: "time passed per function from creation until Configured state",
- }, []string{
- NameLabelKey,
- NamespaceLabelKey,
- TypeLabelKey,
- RuntimeLabelKey,
- })
- functionBuiltStatusGaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{
- Name: "function_built_status_duration_millisecond",
- Help: "time passed per function from creation until Built state",
- }, []string{
- NameLabelKey,
- NamespaceLabelKey,
- TypeLabelKey,
- RuntimeLabelKey,
- })
-
- functionRunningStatusGaugeVec := prometheus.NewGaugeVec(prometheus.GaugeOpts{
- Name: "function_running_status_duration_millisecond",
- Help: "time passed per function from creation until Running state",
- }, []string{
- NameLabelKey,
- NamespaceLabelKey,
- TypeLabelKey,
- RuntimeLabelKey,
- })
-
- instance := &PrometheusStatsCollector{
- conditionGaugeSet: map[string]bool{},
- conditionGauges: map[serverlessv1alpha2.ConditionType]*prometheus.GaugeVec{
- serverlessv1alpha2.ConditionRunning: functionRunningStatusGaugeVec,
- serverlessv1alpha2.ConditionBuildReady: functionBuiltStatusGaugeVec,
- serverlessv1alpha2.ConditionConfigurationReady: functionConfiguredStatusGaugeVec,
- },
- FunctionConfiguredStatusGaugeVec: functionConfiguredStatusGaugeVec,
- FunctionBuiltStatusGaugeVec: functionBuiltStatusGaugeVec,
- FunctionRunningStatusGaugeVec: functionRunningStatusGaugeVec,
- }
-
- return instance
-}
-
-func (p *PrometheusStatsCollector) Register() {
- metrics.Registry.MustRegister(
- p.FunctionConfiguredStatusGaugeVec,
- p.FunctionBuiltStatusGaugeVec,
- p.FunctionRunningStatusGaugeVec)
-}
-
-func (p *PrometheusStatsCollector) UpdateReconcileStats(f *serverlessv1alpha2.Function, cond serverlessv1alpha2.Condition) {
- if _, ok := p.conditionGauges[cond.Type]; !ok { // we don't have a gauge for this condition type
- return
- }
- // a trick to avoid overriding the initial gauge values, since those are
- // what we are interested in. If the function is updated, it initial
- // metrics are _probably_ already collected.
- if f.Generation > 1 {
- return
- }
- gaugeID := p.createGaugeID(f.UID, cond.Type)
- if p.conditionGaugeSet[gaugeID] { // the gauge for this function condition type is already set
- return
- }
-
- // If the condition status is not true, yet, we will try later.
- // Except for the ConfigReady condition, we always push the metric for it.
- if cond.Status != corev1.ConditionTrue && cond.Type != serverlessv1alpha2.ConditionConfigurationReady {
- return
- }
-
- labels := p.createLabels(f)
- p.conditionGauges[cond.Type].With(labels).Set(float64(time.Since(f.CreationTimestamp.Time).Milliseconds()))
- p.conditionGaugeSet[gaugeID] = true
-}
-
-func (p *PrometheusStatsCollector) createGaugeID(uid types.UID, conditionType serverlessv1alpha2.ConditionType) string {
- return fmt.Sprintf("%s-%s", uid, conditionType)
-}
-
-func (p *PrometheusStatsCollector) createLabels(f *serverlessv1alpha2.Function) prometheus.Labels {
- functionType := serverlessv1alpha2.FunctionTypeInline
-
- if f.TypeOf(serverlessv1alpha2.FunctionTypeGit) {
- functionType = serverlessv1alpha2.FunctionTypeGit
- }
-
- return prometheus.Labels{
- NameLabelKey: f.Name,
- NamespaceLabelKey: f.Namespace,
- RuntimeLabelKey: string(f.Spec.Runtime),
- TypeLabelKey: string(functionType),
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/metrics/function_metrics_test.go b/components/serverless/internal/controllers/serverless/metrics/function_metrics_test.go
deleted file mode 100644
index 61a5d1c69..000000000
--- a/components/serverless/internal/controllers/serverless/metrics/function_metrics_test.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package metrics
-
-import (
- "testing"
- "time"
-
- corev1 "k8s.io/api/core/v1"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/require"
-
- //"github.com/prometheus/client_golang/testutil"
- "github.com/prometheus/client_golang/prometheus/testutil"
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_UpdateFunctionStatusGauge(t *testing.T) {
- t.Run("Check if gauge is not updated second generation", func(t *testing.T) {
- //GIVEN
- stas := NewPrometheusStatsCollector()
- startTimestamp := v1.NewTime(time.Date(2000, 01, 01, 00, 00, 0, 0, time.Local))
- f := &serverlessv1alpha2.Function{
- ObjectMeta: v1.ObjectMeta{
- Name: "test-fn",
- Namespace: "test-namespace",
- Generation: 1,
- CreationTimestamp: startTimestamp,
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "repo-url",
- },
- },
- },
- }
- cond := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionTrue,
- }
-
- //WHEN
- stas.UpdateReconcileStats(f, cond)
-
- //THEN
- value := testutil.ToFloat64(stas.FunctionRunningStatusGaugeVec.With(stas.createLabels(f)))
- require.InDelta(t, time.Since(startTimestamp.Time).Milliseconds(), value, 1, "The gauge value wasn't set")
- require.True(t, stas.conditionGaugeSet[stas.createGaugeID(f.UID, cond.Type)])
-
- // The next update of stats within the same condition shouldn't update gauge value,
- // that's why creationTimestamp is increased to proof, that gauge value didn't change.
- //GIVEN
- f.ObjectMeta.Generation = f.ObjectMeta.Generation + 1
- f.ObjectMeta.CreationTimestamp = v1.NewTime(startTimestamp.Add(10 * time.Second))
-
- //WHEN
- stas.UpdateReconcileStats(f, cond)
-
- //THEN
- value = testutil.ToFloat64(stas.FunctionRunningStatusGaugeVec.With(stas.createLabels(f)))
- require.InDelta(t, time.Since(startTimestamp.Time).Milliseconds(), value, 1, "The gauge value was updated but shouldn't")
- })
-
- t.Run("Always collect metrics for Configuration ready condition", func(t *testing.T) {
- //GIVEN
- stas := NewPrometheusStatsCollector()
- startTimestamp := v1.NewTime(time.Date(2000, 01, 01, 00, 00, 0, 0, time.Local))
- f := &serverlessv1alpha2.Function{
- ObjectMeta: v1.ObjectMeta{
- Name: "test-fn",
- Namespace: "test-namespace",
- Generation: 1,
- CreationTimestamp: startTimestamp,
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "repo-url",
- },
- },
- },
- }
- cond := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionFalse,
- }
-
- //WHEN
- stas.UpdateReconcileStats(f, cond)
-
- //THEN
- value := testutil.ToFloat64(stas.FunctionConfiguredStatusGaugeVec.With(stas.createLabels(f)))
- require.InDelta(t, time.Since(startTimestamp.Time).Milliseconds(), value, 1, "The gauge value wasn't set")
- require.True(t, stas.conditionGaugeSet[stas.createGaugeID(f.UID, cond.Type)])
- })
- t.Run("Don't collect metrics for condition status false", func(t *testing.T) {
- //GIVEN
- stas := NewPrometheusStatsCollector()
- startTimestamp := v1.NewTime(time.Date(2000, 01, 01, 00, 00, 0, 0, time.Local))
- f := &serverlessv1alpha2.Function{
- ObjectMeta: v1.ObjectMeta{
- Name: "test-fn",
- Namespace: "test-namespace",
- Generation: 1,
- CreationTimestamp: startTimestamp,
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "repo-url",
- },
- },
- },
- }
- cond := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionFalse,
- }
-
- //WHEN
- stas.UpdateReconcileStats(f, cond)
-
- //THEN
- value := testutil.ToFloat64(stas.FunctionRunningStatusGaugeVec.With(stas.createLabels(f)))
- require.InDelta(t, 0, value, 1, "The gauge value was updated but shouldn't")
- require.False(t, stas.conditionGaugeSet[stas.createGaugeID(f.UID, cond.Type)])
- })
-}
diff --git a/components/serverless/internal/controllers/serverless/runtime/nodejs.go b/components/serverless/internal/controllers/serverless/runtime/nodejs.go
deleted file mode 100644
index 8e6bdd9b8..000000000
--- a/components/serverless/internal/controllers/serverless/runtime/nodejs.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package runtime
-
-import (
- "strings"
-)
-
-type nodejs struct {
- Config
-}
-
-func (n nodejs) SanitizeDependencies(dependencies string) string {
- result := "{}"
- if strings.Trim(dependencies, " ") != "" {
- result = dependencies
- }
-
- return result
-}
-
-var _ Runtime = nodejs{}
diff --git a/components/serverless/internal/controllers/serverless/runtime/nodejs_test.go b/components/serverless/internal/controllers/serverless/runtime/nodejs_test.go
deleted file mode 100644
index c84f70666..000000000
--- a/components/serverless/internal/controllers/serverless/runtime/nodejs_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package runtime_test
-
-import (
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/runtime"
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
-)
-
-func TestNodejs_SanitizeDependencies(t *testing.T) {
- tests := []struct {
- name string
- deps string
- want string
- }{
- {
- name: "Should not touch empty deps - {}",
- deps: "{}",
- want: "{}",
- },
- {
- name: "Should not touch empty deps",
- deps: "",
- want: "{}",
- },
- {
- name: "Should not touch empty deps - empty string",
- deps: "random-string",
- want: "random-string",
- },
- {
- name: "Should not touch empty deps - empty string",
- deps: " ",
- want: "{}",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- r := runtime.GetRuntime(v1alpha2.NodeJs20)
- got := r.SanitizeDependencies(tt.deps)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/runtime/python.go b/components/serverless/internal/controllers/serverless/runtime/python.go
deleted file mode 100644
index 47d2ade00..000000000
--- a/components/serverless/internal/controllers/serverless/runtime/python.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package runtime
-
-type python struct {
- Config
-}
-
-func (p python) SanitizeDependencies(dependencies string) string {
- return dependencies
-}
-
-var _ Runtime = python{}
diff --git a/components/serverless/internal/controllers/serverless/runtime/runtime.go b/components/serverless/internal/controllers/serverless/runtime/runtime.go
deleted file mode 100644
index e62ddc016..000000000
--- a/components/serverless/internal/controllers/serverless/runtime/runtime.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package runtime
-
-import (
- "fmt"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- corev1 "k8s.io/api/core/v1"
-)
-
-type Runtime interface {
- SanitizeDependencies(dependencies string) string
-}
-
-type Config struct {
- Runtime serverlessv1alpha2.Runtime
- DependencyFile string
- FunctionFile string
- DockerfileConfigMapName string
- RuntimeEnvs []corev1.EnvVar
-}
-
-func GetRuntimeConfig(runtime serverlessv1alpha2.Runtime) Config {
- config := Config{
- Runtime: runtime,
- DockerfileConfigMapName: fmt.Sprintf("dockerfile-%s", runtime),
- RuntimeEnvs: []corev1.EnvVar{
- {Name: "FUNC_RUNTIME", Value: string(runtime)},
- },
- }
- fillConfigFileNames(runtime, &config)
- fillConfigEnvVars(runtime, &config)
- return config
-}
-
-func fillConfigEnvVars(runtime serverlessv1alpha2.Runtime, config *Config) {
- switch runtime {
- case serverlessv1alpha2.Python39:
- config.RuntimeEnvs = append(config.RuntimeEnvs,
- []corev1.EnvVar{
- // https://github.com/kubeless/runtimes/blob/master/stable/python/python.jsonnet#L45
- {Name: "PYTHONPATH", Value: "$(KUBELESS_INSTALL_VOLUME)/lib.python3.9/site-packages:$(KUBELESS_INSTALL_VOLUME)"},
- {Name: "PYTHONUNBUFFERED", Value: "TRUE"}}...)
- return
- case serverlessv1alpha2.Python312:
- config.RuntimeEnvs = append(config.RuntimeEnvs,
- []corev1.EnvVar{
- // https://github.com/kubeless/runtimes/blob/master/stable/python/python.jsonnet#L45
- {Name: "PYTHONPATH", Value: "$(KUBELESS_INSTALL_VOLUME)/lib.python3.12/site-packages:$(KUBELESS_INSTALL_VOLUME)"},
- {Name: "PYTHONUNBUFFERED", Value: "TRUE"}}...)
- return
- }
-}
-
-func fillConfigFileNames(runtime serverlessv1alpha2.Runtime, config *Config) {
- switch runtime {
- case serverlessv1alpha2.NodeJs18, serverlessv1alpha2.NodeJs20:
- config.DependencyFile = "package.json"
- config.FunctionFile = "handler.js"
- return
- case serverlessv1alpha2.Python39, serverlessv1alpha2.Python312:
- config.DependencyFile = "requirements.txt"
- config.FunctionFile = "handler.py"
- return
- }
-}
-
-func GetRuntime(r serverlessv1alpha2.Runtime) Runtime {
- switch r {
- case serverlessv1alpha2.Python39, serverlessv1alpha2.Python312:
- return python{}
- default:
- return nodejs{}
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/runtime/runtime_test.go b/components/serverless/internal/controllers/serverless/runtime/runtime_test.go
deleted file mode 100644
index 1b966d080..000000000
--- a/components/serverless/internal/controllers/serverless/runtime/runtime_test.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package runtime_test
-
-import (
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/runtime"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
-)
-
-func TestGetRuntimeConfig(t *testing.T) {
- for testName, testData := range map[string]struct {
- name string
- runtime serverlessv1alpha2.Runtime
- want runtime.Config
- }{
- "python39": {
- name: "python39",
- runtime: serverlessv1alpha2.Python39,
- want: runtime.Config{
- Runtime: serverlessv1alpha2.Python39,
- DependencyFile: "requirements.txt",
- FunctionFile: "handler.py",
- DockerfileConfigMapName: "dockerfile-python39",
- RuntimeEnvs: []corev1.EnvVar{{Name: "PYTHONPATH", Value: "$(KUBELESS_INSTALL_VOLUME)/lib.python3.9/site-packages:$(KUBELESS_INSTALL_VOLUME)"},
- {Name: "FUNC_RUNTIME", Value: "python39"},
- {Name: "PYTHONUNBUFFERED", Value: "TRUE"}},
- },
- },
- "python312": {
- name: "python312",
- runtime: serverlessv1alpha2.Python312,
- want: runtime.Config{
- Runtime: serverlessv1alpha2.Python312,
- DependencyFile: "requirements.txt",
- FunctionFile: "handler.py",
- DockerfileConfigMapName: "dockerfile-python312",
- RuntimeEnvs: []corev1.EnvVar{{Name: "PYTHONPATH", Value: "$(KUBELESS_INSTALL_VOLUME)/lib.python3.12/site-packages:$(KUBELESS_INSTALL_VOLUME)"},
- {Name: "FUNC_RUNTIME", Value: "python312"},
- {Name: "PYTHONUNBUFFERED", Value: "TRUE"}},
- },
- },
- "nodejs18": {
- name: "nodejs18 config",
- runtime: serverlessv1alpha2.NodeJs18,
- want: runtime.Config{
- Runtime: serverlessv1alpha2.NodeJs18,
- DependencyFile: "package.json",
- FunctionFile: "handler.js",
- DockerfileConfigMapName: "dockerfile-nodejs18",
- RuntimeEnvs: []corev1.EnvVar{
- {Name: "FUNC_RUNTIME", Value: "nodejs18"}},
- },
- },
- "nodejs20": {
- name: "nodejs20 config",
- runtime: serverlessv1alpha2.NodeJs20,
- want: runtime.Config{
- Runtime: serverlessv1alpha2.NodeJs20,
- DependencyFile: "package.json",
- FunctionFile: "handler.js",
- DockerfileConfigMapName: "dockerfile-nodejs20",
- RuntimeEnvs: []corev1.EnvVar{
- {Name: "FUNC_RUNTIME", Value: "nodejs20"}},
- },
- }} {
- t.Run(testName, func(t *testing.T) {
- //given
- g := gomega.NewWithT(t)
-
- // when
- config := runtime.GetRuntimeConfig(testData.runtime)
-
- // then
- // `RuntimeEnvs` may be in a different order, so I convert them to a map before comparing them
- configEnvMap := make(map[string]corev1.EnvVar)
- for _, ev := range config.RuntimeEnvs {
- configEnvMap[ev.Name] = ev
- }
- wantEnvMap := make(map[string]corev1.EnvVar)
- for _, ev := range testData.want.RuntimeEnvs {
- wantEnvMap[ev.Name] = ev
- }
- g.Expect(configEnvMap).To(gomega.BeEquivalentTo(wantEnvMap))
-
- // `RuntimeEnvs` were compared before, and now I want to compare the rest of `config`
- config.RuntimeEnvs = nil
- testData.want.RuntimeEnvs = nil
- g.Expect(config).To(gomega.BeEquivalentTo(testData.want))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/scaling.go b/components/serverless/internal/controllers/serverless/scaling.go
deleted file mode 100644
index f36c825cb..000000000
--- a/components/serverless/internal/controllers/serverless/scaling.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- apilabels "k8s.io/apimachinery/pkg/labels"
-)
-
-func stateFnCheckScaling(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- namespace := s.instance.GetNamespace()
- labels := internalFunctionLabels(s.instance)
-
- err := r.client.ListByLabel(ctx, namespace, labels, &s.hpas)
- if err != nil {
- return nil, errors.Wrap(err, "while listing HPAs")
- }
-
- if !isScalingEnabled(&s.instance) {
- return stateFnCheckReplicas(ctx, r, s)
- }
-
- return stateFnCheckHPA(ctx, r, s)
-}
-
-func stateFnCheckReplicas(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- numHpa := len(s.hpas.Items)
-
- if numHpa > 0 {
- return stateFnDeleteAllHorizontalPodAutoscalers, nil
- }
-
- return stateFnUpdateDeploymentStatus, nil
-}
-
-func stateFnCheckHPA(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- if !s.hpaEqual(r.cfg.fn.TargetCPUUtilizationPercentage) {
- return stateFnUpdateDeploymentStatus, nil
- }
-
- numHpa := len(s.hpas.Items)
- expectedHPA := s.buildHorizontalPodAutoscaler(r.cfg.fn.TargetCPUUtilizationPercentage)
-
- if numHpa == 0 {
- if !equalInt32Pointer(s.instance.Spec.ScaleConfig.MinReplicas, s.instance.Spec.ScaleConfig.MaxReplicas) {
- return buildStateFnCreateHorizontalPodAutoscaler(expectedHPA), nil
- }
- return nil, nil
- }
-
- if numHpa > 1 {
- return stateFnDeleteAllHorizontalPodAutoscalers, nil
- }
-
- if numHpa == 1 && !isScalingEnabled(&s.instance) {
- // this case is when we previously created HPA with maxReplicas > minReplicas, but now user changed
- // function spec and NOW maxReplicas == minReplicas, so hpa is not needed anymore
- return stateFnDeleteAllHorizontalPodAutoscalers, nil
- }
-
- if !s.equalHorizontalPodAutoscalers(expectedHPA) {
- return buildStateFnUpdateHorizontalPodAutoscaler(expectedHPA), nil
- }
-
- return nil, nil
-}
-
-func buildStateFnCreateHorizontalPodAutoscaler(hpa autoscalingv1.HorizontalPodAutoscaler) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("Creating HorizontalPodAutoscaler")
-
- err := r.client.CreateWithReference(ctx, &s.instance, &hpa)
- if err != nil {
- return nil, errors.Wrap(err, "while creating HPA")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonHorizontalPodAutoscalerCreated,
- Message: fmt.Sprintf("HorizontalPodAutoscaler %s created", hpa.GetName()),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func stateFnDeleteAllHorizontalPodAutoscalers(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info("Deleting all HorizontalPodAutoscalers attached to function")
- selector := apilabels.SelectorFromSet(internalFunctionLabels(s.instance))
-
- err := r.client.DeleteAllBySelector(ctx, &autoscalingv1.HorizontalPodAutoscaler{}, s.instance.GetNamespace(), selector)
- return nil, errors.Wrap(err, "while deleting HPAs")
-}
-
-func buildStateFnUpdateHorizontalPodAutoscaler(expectd autoscalingv1.HorizontalPodAutoscaler) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- hpa := &s.hpas.Items[0]
-
- hpa.Spec = expectd.Spec
- hpa.Labels = expectd.GetLabels()
-
- hpaName := hpa.GetName()
-
- r.log.Info(fmt.Sprintf("Updating HorizontalPodAutoscaler %s", hpaName))
-
- err := r.client.Update(ctx, hpa)
- if err != nil {
- return nil, errors.Wrap(err, "while updating HPA")
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonHorizontalPodAutoscalerUpdated,
- Message: fmt.Sprintf("HorizontalPodAutoscaler %s updated", hpaName),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/scaling_test.go b/components/serverless/internal/controllers/serverless/scaling_test.go
deleted file mode 100644
index b08ff8170..000000000
--- a/components/serverless/internal/controllers/serverless/scaling_test.go
+++ /dev/null
@@ -1,476 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- appsv1 "k8s.io/api/apps/v1"
- "k8s.io/utils/ptr"
-
- "github.com/onsi/gomega"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_equalInt32Pointer(t *testing.T) {
- one := int32(1)
- two := int32(2)
-
- type args struct {
- first *int32
- second *int32
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "two nils",
- args: args{
- first: nil,
- second: nil,
- },
- want: true,
- },
- {
- name: "one nil, one value",
- args: args{
- first: &one,
- second: nil,
- },
- want: false,
- },
- {
- name: "two same values",
- args: args{
- first: &one,
- second: &one,
- },
- want: true,
- },
- {
- name: "two different values",
- args: args{
- first: &one,
- second: &two,
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- if got := equalInt32Pointer(tt.args.first, tt.args.second); got != tt.want {
- t.Errorf("equalInt32Pointer() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestFunctionReconciler_equalHorizontalPodAutoscalers(t *testing.T) {
- fifty := int32(50)
- two := int32(2)
-
- type args struct {
- existing autoscalingv1.HorizontalPodAutoscaler
- expected autoscalingv1.HorizontalPodAutoscaler
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "should be equal in simple case",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- },
- want: true,
- },
- {
- name: "should be equal when labels are provided",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label1": "value",
- },
- },
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label1": "value",
- },
- },
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- },
- want: true,
- },
- {
- name: "should return false if labels are different",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label1": "value",
- },
- },
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- "label2": "value",
- },
- },
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- },
- want: false,
- },
- {
- name: "should be false if minReplicas are different",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &fifty,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- },
- want: false,
- },
- {
- name: "should be false if cpuUtil is different",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &two,
- },
- },
- },
- want: false,
- },
- {
- name: "should be false if ref name is different",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Kind: "Deployment",
- Name: "deploy2",
- APIVersion: "apps/v1",
- },
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Kind: "Deployment",
- Name: "deploy1",
- APIVersion: "apps/v1",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "should be true if ref name is the same",
- args: args{
- existing: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Kind: "Deployment",
- Name: "deploy-name",
- APIVersion: "apps/v1",
- },
- },
- },
- expected: autoscalingv1.HorizontalPodAutoscaler{
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- MinReplicas: &two,
- MaxReplicas: 10,
- TargetCPUUtilizationPercentage: &fifty,
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Kind: "Deployment",
- Name: "deploy-name",
- APIVersion: "apps/v1",
- },
- },
- },
- },
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- s := systemState{
- hpas: autoscalingv1.HorizontalPodAutoscalerList{
- Items: []autoscalingv1.HorizontalPodAutoscaler{
- tt.args.existing,
- },
- },
- }
-
- got := s.equalHorizontalPodAutoscalers(tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func Test_isScalingEnabled(t *testing.T) {
- tests := []struct {
- name string
- scaleConfig *serverlessv1alpha2.ScaleConfig
- want bool
- }{
- {
- name: "scaling enabled",
- scaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: ptr.To[int32](1),
- MaxReplicas: ptr.To[int32](2),
- },
- want: true,
- },
- {
- name: "scaling disabled",
- scaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: ptr.To[int32](1),
- MaxReplicas: ptr.To[int32](1),
- },
- want: false,
- },
- {
- name: "scaling disabled with multiple replicas",
- scaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: ptr.To[int32](5),
- MaxReplicas: ptr.To[int32](5),
- },
- want: false,
- },
- {
- name: "scaling disabled with no scaleConfig",
- scaleConfig: nil,
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- instance := &serverlessv1alpha2.Function{
- Spec: serverlessv1alpha2.FunctionSpec{
- ScaleConfig: tt.scaleConfig,
- },
- }
-
- if got := isScalingEnabled(instance); got != tt.want {
- t.Errorf("isScalingEnabled() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestFunctionReconciler_isOnHorizontalPodAutoscalerChange(t *testing.T) {
- testName := "test"
-
- deploys := []appsv1.Deployment{
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: testName,
- },
- },
- }
-
- equalFunction := newFixFunction(testName, testName, 1, 2)
-
- s := systemState{
- instance: *equalFunction,
- deployments: appsv1.DeploymentList{
- Items: deploys,
- },
- }
-
- equalHPA := s.buildHorizontalPodAutoscaler(0)
-
- type args struct {
- instance *serverlessv1alpha2.Function
- hpas []autoscalingv1.HorizontalPodAutoscaler
- deployments []appsv1.Deployment
- }
-
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "scaling enabled and equal HPA",
- args: args{
- deployments: deploys,
- instance: equalFunction,
- hpas: []autoscalingv1.HorizontalPodAutoscaler{
- equalHPA,
- },
- },
- want: false,
- },
- {
- name: "scaling disabled and no HPA",
- args: args{
- deployments: deploys,
- instance: newFixFunction(testName, testName, 2, 2),
- hpas: []autoscalingv1.HorizontalPodAutoscaler{},
- },
- want: false,
- },
- {
- name: "no deployments",
- args: args{
- deployments: []appsv1.Deployment{}, //FIXME tutaj!
- },
- want: false,
- },
- {
- name: "scaling enabled and no HPA",
- args: args{
- deployments: deploys,
- instance: newFixFunction(testName, testName, 1, 2),
- hpas: []autoscalingv1.HorizontalPodAutoscaler{},
- },
- want: true,
- },
- {
- name: "scaling enabled and more than one HPA",
- args: args{
- deployments: deploys,
- instance: newFixFunction(testName, testName, 1, 2),
- hpas: []autoscalingv1.HorizontalPodAutoscaler{
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "hpa-1",
- },
- },
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "hpa-2",
- },
- },
- },
- },
- want: true,
- },
- {
- name: "scaling enabled and unequal HPA",
- args: args{
- deployments: deploys,
- instance: newFixFunction(testName, testName, 1, 2),
- hpas: []autoscalingv1.HorizontalPodAutoscaler{
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "hpa-1",
- },
- },
- },
- },
- want: true,
- },
- {
- name: "scaling disabled and HPA exists",
- args: args{
- deployments: deploys,
- instance: newFixFunction(testName, testName, 2, 2),
- hpas: []autoscalingv1.HorizontalPodAutoscaler{
- {
- ObjectMeta: metav1.ObjectMeta{
- Name: "hpa-1",
- },
- },
- },
- },
- want: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
-
- var instance serverlessv1alpha2.Function
- if tt.args.instance != nil {
- instance = *tt.args.instance
- }
-
- s := systemState{
- instance: instance,
- deployments: appsv1.DeploymentList{
- Items: tt.args.deployments,
- },
- hpas: autoscalingv1.HorizontalPodAutoscalerList{
- Items: tt.args.hpas,
- },
- }
-
- if got := s.hpaEqual(0); got != tt.want {
- t.Errorf("isOnHorizontalPodAutoscalerChange() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/service.go b/components/serverless/internal/controllers/serverless/service.go
deleted file mode 100644
index de2a95c45..000000000
--- a/components/serverless/internal/controllers/serverless/service.go
+++ /dev/null
@@ -1,134 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func stateFnCheckService(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- err := r.client.ListByLabel(
- ctx,
- s.instance.GetNamespace(),
- internalFunctionLabels(s.instance),
- &s.services)
-
- if err != nil {
- return nil, errors.Wrap(err, "while listing services")
- }
-
- expectedSvc := s.buildService()
-
- if len(s.services.Items) == 0 {
- return buildStateFnCreateNewService(expectedSvc), nil
- }
-
- if len(s.services.Items) > 1 {
- return stateFnDeleteServices, nil
- }
-
- if s.svcChanged(expectedSvc) {
- return buildStateFnUpdateService(expectedSvc), nil
- }
-
- return stateFnCheckScaling, nil
-}
-
-func buildStateFnUpdateService(newService corev1.Service) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
-
- svc := &s.services.Items[0]
-
- // manually change fields that interest us, as clusterIP is immutable
- svc.Spec.Ports = newService.Spec.Ports
- svc.Spec.Selector = newService.Spec.Selector
- svc.Spec.Type = newService.Spec.Type
-
- svc.ObjectMeta.Labels = newService.GetLabels()
- if svc.ObjectMeta.Annotations == nil {
- svc.ObjectMeta.Annotations = make(map[string]string)
- }
- mergeMapWithNewValues(svc.ObjectMeta.Annotations, newService.GetAnnotations())
-
- r.log.Info(fmt.Sprintf("Updating Service %s", svc.GetName()))
-
- err := r.client.Update(ctx, svc)
- if err != nil {
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonServiceFailed,
- Message: fmt.Sprintf("Service %s update error: %s", svc.GetName(), err.Error()),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonServiceUpdated,
- Message: fmt.Sprintf("Service %s updated", svc.GetName()),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func buildStateFnCreateNewService(svc corev1.Service) stateFn {
- return func(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- r.log.Info(fmt.Sprintf("Creating Service %s", svc.GetName()))
-
- err := r.client.CreateWithReference(ctx, &s.instance, &svc)
- if err != nil {
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonServiceFailed,
- Message: fmt.Sprintf("Service %s create error: %s", svc.GetName(), err.Error()),
- }
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-
- condition := serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionRunning,
- Status: corev1.ConditionUnknown,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonServiceCreated,
- Message: fmt.Sprintf("Service %s created", svc.GetName()),
- }
-
- return buildStatusUpdateStateFnWithCondition(condition), nil
- }
-}
-
-func stateFnDeleteServices(ctx context.Context, r *reconciler, s *systemState) (stateFn, error) {
- // services do not support deletecollection
- // you can check this by `kubectl api-resources -o wide | grep services`
- // also https://github.com/kubernetes/kubernetes/issues/68468#issuecomment-419981870
-
- r.log.Info("deleting Services")
-
- for i := range s.services.Items {
- svc := s.services.Items[i]
- if svc.GetName() == s.instance.GetName() {
- continue
- }
-
- r.log.Info(fmt.Sprintf("deleting Service %s", svc.GetName()))
-
- // TODO consider implementing mechanism to collect errors
- err := r.client.Delete(ctx, &s.services.Items[i])
- if err != nil {
- return nil, errors.Wrap(err, "while deleting service")
- }
- }
-
- return nil, nil
-}
diff --git a/components/serverless/internal/controllers/serverless/service_test.go b/components/serverless/internal/controllers/serverless/service_test.go
deleted file mode 100644
index 5574ef9bd..000000000
--- a/components/serverless/internal/controllers/serverless/service_test.go
+++ /dev/null
@@ -1,604 +0,0 @@
-package serverless
-
-import (
- "context"
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
- "testing"
-
- "go.uber.org/zap"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource/automock"
- "github.com/onsi/gomega"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/intstr"
- "k8s.io/client-go/kubernetes/scheme"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-func TestFunctionReconciler_equalServices(t *testing.T) {
- type args struct {
- existing corev1.Service
- expected corev1.Service
- }
- tests := []struct {
- name string
- args args
- want bool
- }{
- {
- name: "simple equal case",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Annotations: prometheusSvcAnnotations(),
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- Annotations: prometheusSvcAnnotations(),
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: true,
- },
- {
- name: "fails on different labels",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "different": "label-different",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails on different port",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 8000,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails on different port name",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "httpzzzz",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails on different targetPort",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(666)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails on different selector",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value-DIFFERENT",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails if there is 0 ports in existing",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{},
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http",
- Port: 80,
- TargetPort: intstr.FromInt(80)},
- },
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails if there is 0 ports in expected",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "test",
- }},
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{},
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- {
- name: "fails if there is 0 ports in either case",
- args: args{
- existing: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- expected: corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: "svc-name",
- Namespace: "svc-ns",
- Labels: map[string]string{
- "label1": "label1",
- },
- },
- Spec: corev1.ServiceSpec{
- Selector: map[string]string{
- "selector": "sel-value",
- },
- },
- },
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
- got := equalServices(tt.args.existing, tt.args.expected)
- g.Expect(got).To(gomega.Equal(tt.want))
- })
- }
-}
-
-func TestFunctionReconciler_deleteExcessServices(t *testing.T) {
- t.Run("simple", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- instance := &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{Name: "fn-name"},
- }
-
- services := []corev1.Service{
- {ObjectMeta: metav1.ObjectMeta{Name: "fn-name"}},
- {ObjectMeta: metav1.ObjectMeta{Name: "fn-some-other-name"}},
- }
-
- client := new(automock.Client)
- client.On("Delete", context.TODO(), &services[1]).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- s := systemState{
- instance: *instance,
- services: corev1.ServiceList{
- Items: services,
- },
- }
-
- r := reconciler{
- log: zap.NewNop().Sugar(),
- k8s: k8s{
- client: client,
- },
- }
-
- _, err := stateFnDeleteServices(context.TODO(), &r, &s)
-
- g.Expect(err).To(gomega.Succeed())
- g.Expect(client.Calls).To(gomega.HaveLen(1), "delete should happen only for service which has different name than it's parent fn")
- })
-
- t.Run("should delete both svc that have different name than fn", func(t *testing.T) {
- g := gomega.NewGomegaWithT(t)
-
- instance := &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{Name: "fn-name"},
- }
-
- services := []corev1.Service{
- {ObjectMeta: metav1.ObjectMeta{Name: "fn-other-name"}},
- {ObjectMeta: metav1.ObjectMeta{Name: "fn-some-other-name"}},
- }
-
- client := new(automock.Client)
- client.On("Delete", context.TODO(), &services[0]).Return(nil).Once()
- client.On("Delete", context.TODO(), &services[1]).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- s := systemState{
- instance: *instance,
- services: corev1.ServiceList{
- Items: services,
- },
- }
-
- r := reconciler{
- log: zap.NewNop().Sugar(),
- k8s: k8s{
- client: client,
- },
- }
-
- _, err := stateFnDeleteServices(context.TODO(), &r, &s)
-
- g.Expect(err).To(gomega.Succeed())
- g.Expect(client.Calls).To(gomega.HaveLen(2), "delete should happen only for service which has different name than it's parent fn")
- })
-}
-
-func TestFunctionReconciler_buildStateFnUpdateService(t *testing.T) {
- //GIVEN
- ctx := context.TODO()
- oldAnnotationKey := "old"
- updatedAnnotationKey := "updated"
- newAnnotationKey := "new"
-
- testCases := map[string]struct {
- oldSvcAnnotations map[string]string
- newSvcAnnotations map[string]string
- expectedSvcAnnotations map[string]string
- }{
- "Svc is updated with merged annotations": {
- oldSvcAnnotations: map[string]string{
- oldAnnotationKey: "old-value",
- updatedAnnotationKey: "old-value-to-update",
- },
- newSvcAnnotations: map[string]string{
- updatedAnnotationKey: "updated-value",
- newAnnotationKey: "new-value",
- },
- expectedSvcAnnotations: map[string]string{
- oldAnnotationKey: "old-value",
- updatedAnnotationKey: "updated-value",
- newAnnotationKey: "new-value",
- },
- },
- "Svc is updated when old svc annotations are empty": {
- newSvcAnnotations: map[string]string{
- updatedAnnotationKey: "updated-value",
- newAnnotationKey: "new-value",
- },
- expectedSvcAnnotations: map[string]string{
- updatedAnnotationKey: "updated-value",
- newAnnotationKey: "new-value",
- },
- },
- }
-
- for testName, testData := range testCases {
- t.Run(testName, func(t *testing.T) {
- oldSvc, newSvc := fixSvc()
- oldSvc.Annotations = testData.oldSvcAnnotations
- newSvc.Annotations = testData.newSvcAnnotations
-
- builder := &fake.ClientBuilder{}
- k8sClient := resource.New(builder.WithObjects(&oldSvc).Build(), scheme.Scheme)
- r := &reconciler{k8s: k8s{client: k8sClient}, log: zap.NewNop().Sugar()}
- s := &systemState{services: corev1.ServiceList{Items: []corev1.Service{oldSvc}}}
- //WHEN
- fn := buildStateFnUpdateService(newSvc)
- _, err := fn(ctx, r, s)
-
- //THEN
- require.NoError(t, err)
- updatedSvc := corev1.Service{}
- require.NoError(t, k8sClient.Get(ctx, client.ObjectKey{Namespace: oldSvc.GetNamespace(), Name: oldSvc.GetName()}, &updatedSvc))
- assert.Equal(t, newSvc.Spec.Ports, updatedSvc.Spec.Ports)
- assert.Equal(t, newSvc.Spec.Selector, updatedSvc.Spec.Selector)
- assert.Equal(t, newSvc.Spec.Type, updatedSvc.Spec.Type)
- assert.EqualValues(t, newSvc.GetLabels(), updatedSvc.GetLabels())
- assert.EqualValues(t, testData.expectedSvcAnnotations, updatedSvc.GetAnnotations())
- })
- }
-
-}
-
-func fixSvc() (old corev1.Service, new corev1.Service) {
-
- oldSvc := corev1.Service{
- ObjectMeta: metav1.ObjectMeta{Name: "test-service",
- Labels: map[string]string{
- "A": "B",
- "C": "D",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {Name: "old-port", Port: int32(1234)},
- {Name: "another-port", Port: int32(4321)},
- },
- Selector: map[string]string{
- "selA": "B",
- "selC": "D",
- },
- Type: corev1.ServiceTypeClusterIP},
- }
-
- newSvc := corev1.Service{
- ObjectMeta: metav1.ObjectMeta{Name: "test-service",
- Labels: map[string]string{
- "X": "Y",
- "W": "Z",
- },
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{
- {Name: "new-port", Port: int32(9876)},
- {Name: "another=new-port", Port: int32(6789)},
- },
- Selector: map[string]string{
- "selX": "Y",
- "selW": "Z",
- },
- Type: corev1.ServiceTypeLoadBalancer},
- }
- return oldSvc, newSvc
-}
diff --git a/components/serverless/internal/controllers/serverless/suite_test.go b/components/serverless/internal/controllers/serverless/suite_test.go
deleted file mode 100644
index 1cf8408f1..000000000
--- a/components/serverless/internal/controllers/serverless/suite_test.go
+++ /dev/null
@@ -1,168 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- k8sresource "k8s.io/apimachinery/pkg/api/resource"
- "path/filepath"
-
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/kubernetes"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- "github.com/vrischmann/envconfig"
- "k8s.io/client-go/kubernetes/scheme"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
-)
-
-const (
- testNamespace = "test-namespace-name"
- fakeDockerfile = `ARG base_image=some_image
- FROM ${base_image}
- USER root
- ENV KUBELESS_INSTALL_VOLUME=/kubeless`
- changedFakeDockerfile = `ARG base_image=other_image`
- testFunctionPresetName = "M"
- testFunctionPresetName2 = "L"
- testBuildPresetName = "slow"
- testBuildPresetName2 = "fast"
-)
-
-var (
- testResourceConfig = ResourceConfig{
- Function: FunctionResourceConfig{
- Resources: Resources{
- Presets: map[string]Resource{
- testFunctionPresetName: {
- RequestCPU: Quantity{k8sresource.MustParse("50m")},
- RequestMemory: Quantity{k8sresource.MustParse("50Mi")},
- LimitCPU: Quantity{k8sresource.MustParse("50m")},
- LimitMemory: Quantity{k8sresource.MustParse("50Mi")},
- },
- testFunctionPresetName2: {
- RequestCPU: Quantity{k8sresource.MustParse("100m")},
- RequestMemory: Quantity{k8sresource.MustParse("100Mi")},
- LimitCPU: Quantity{k8sresource.MustParse("100m")},
- LimitMemory: Quantity{k8sresource.MustParse("100Mi")},
- },
- },
- DefaultPreset: testFunctionPresetName,
- },
- },
- BuildJob: BuildJobResourceConfig{
- Resources: Resources{
- Presets: map[string]Resource{
- testBuildPresetName: {
- RequestCPU: Quantity{k8sresource.MustParse("50m")},
- RequestMemory: Quantity{k8sresource.MustParse("50Mi")},
- LimitCPU: Quantity{k8sresource.MustParse("50m")},
- LimitMemory: Quantity{k8sresource.MustParse("50Mi")},
- },
- testBuildPresetName2: {
- RequestCPU: Quantity{k8sresource.MustParse("100m")},
- RequestMemory: Quantity{k8sresource.MustParse("100Mi")},
- LimitCPU: Quantity{k8sresource.MustParse("100m")},
- LimitMemory: Quantity{k8sresource.MustParse("100Mi")},
- },
- },
- DefaultPreset: testBuildPresetName,
- },
- },
- }
-)
-
-func setUpTestEnv(g *gomega.GomegaWithT) (cl resource.Client, env *envtest.Environment) {
- testEnv := &envtest.Environment{
- CRDDirectoryPaths: []string{
- filepath.Join("..", "..", "..", "config", "crd", "bases"),
- },
- ErrorIfCRDPathMissing: true,
- BinaryAssetsDirectory: filepath.Join("..", "..", "..", "..", "..", "bin", "k8s", "kubebuilder_assets"),
- }
- cfg, err := testEnv.Start()
- g.Expect(err).To(gomega.BeNil())
- g.Expect(cfg).ToNot(gomega.BeNil())
-
- err = scheme.AddToScheme(scheme.Scheme)
- g.Expect(err).NotTo(gomega.HaveOccurred())
-
- err = serverlessv1alpha2.AddToScheme(scheme.Scheme)
- g.Expect(err).NotTo(gomega.HaveOccurred())
-
- k8sClient, err := client.New(cfg, client.Options{Scheme: scheme.Scheme})
- g.Expect(err).ToNot(gomega.HaveOccurred())
- g.Expect(k8sClient).ToNot(gomega.BeNil())
-
- resourceClient := resource.New(k8sClient, scheme.Scheme)
- g.Expect(resourceClient).ToNot(gomega.BeNil())
- return resourceClient, testEnv
-}
-
-func tearDownTestEnv(g *gomega.GomegaWithT, testEnv *envtest.Environment) {
- g.Expect(testEnv.Stop()).To(gomega.Succeed())
-}
-
-func setUpControllerConfig(g *gomega.GomegaWithT) FunctionConfig {
- var testCfg FunctionConfig
- err := envconfig.InitWithPrefix(&testCfg, "TEST")
- g.Expect(err).To(gomega.BeNil())
-
- testCfg.ResourceConfig = testResourceConfig
- return testCfg
-}
-
-func initializeServerlessResources(g *gomega.GomegaWithT, client resource.Client) {
- ns := corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: testNamespace,
- },
- }
- dockerRegistryConfiguration := corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "serverless-registry-config-default",
- Namespace: testNamespace,
- },
- StringData: map[string]string{
- keyIsInternal: "true",
- keyRegistryPullAddr: "localhost:32132",
- keyRegistryPushAddr: "registry.kyma.local",
- },
- }
- g.Expect(client.Create(context.TODO(), &ns)).To(gomega.Succeed())
- g.Expect(client.Create(context.TODO(), &dockerRegistryConfiguration)).To(gomega.Succeed())
-}
-
-func createDockerfileForRuntime(g *gomega.GomegaWithT, client resource.Client, rtm serverlessv1alpha2.Runtime) {
- runtimeDockerfileConfigMap := corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("dockerfile-%s", string(rtm)),
- Labels: map[string]string{kubernetes.ConfigLabel: "runtime",
- kubernetes.RuntimeLabel: string(rtm)},
- Namespace: testNamespace,
- },
- Data: map[string]string{
- "Dockerfile": fakeDockerfile,
- },
- }
- g.Expect(client.Create(context.TODO(), &runtimeDockerfileConfigMap)).To(gomega.Succeed())
-}
-
-func changeDockerfileForRuntime(rtm serverlessv1alpha2.Runtime) *corev1.ConfigMap {
- runtimeDockerfileConfigMap := corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: fmt.Sprintf("dockerfile-%s", string(rtm)),
- Labels: map[string]string{kubernetes.ConfigLabel: "runtime",
- kubernetes.RuntimeLabel: string(rtm)},
- Namespace: testNamespace,
- },
- Data: map[string]string{
- "Dockerfile": changedFakeDockerfile,
- },
- }
- return &runtimeDockerfileConfigMap
-}
diff --git a/components/serverless/internal/controllers/serverless/system_state.go b/components/serverless/internal/controllers/serverless/system_state.go
deleted file mode 100644
index d25660051..000000000
--- a/components/serverless/internal/controllers/serverless/system_state.go
+++ /dev/null
@@ -1,780 +0,0 @@
-package serverless
-
-import (
- "fmt"
- "path"
- "strings"
-
- fnRuntime "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/runtime"
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- appsv1 "k8s.io/api/apps/v1"
- autoscalingv1 "k8s.io/api/autoscaling/v1"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/utils/ptr"
-)
-
-const DefaultDeploymentReplicas int32 = 1
-
-const istioConfigLabelKey = "proxy.istio.io/config"
-const istioEnableHoldUntilProxyStartLabelValue = "{ \"holdApplicationUntilProxyStarts\": true }"
-
-type SystemState interface{}
-
-// TODO extract interface
-type systemState struct {
- instance serverlessv1alpha2.Function
- fnImage string // TODO make sure this is needed
- configMaps corev1.ConfigMapList // TODO create issue to refactor this (only 1 config map should be here)
- deployments appsv1.DeploymentList
- jobs batchv1.JobList
- services corev1.ServiceList
- hpas autoscalingv1.HorizontalPodAutoscalerList
-}
-
-var _ SystemState = systemState{}
-
-func internalFunctionLabels(fn serverlessv1alpha2.Function) map[string]string {
- intLabels := make(map[string]string, 3)
-
- intLabels[serverlessv1alpha2.FunctionNameLabel] = fn.Name
- intLabels[serverlessv1alpha2.FunctionManagedByLabel] = serverlessv1alpha2.FunctionControllerValue
- intLabels[serverlessv1alpha2.FunctionUUIDLabel] = string(fn.GetUID())
-
- return intLabels
-}
-
-func (s *systemState) functionLabels() map[string]string {
- internalLabels := internalFunctionLabels(s.instance)
- functionLabels := s.instance.GetLabels()
-
- return labels.Merge(functionLabels, internalLabels)
-}
-
-func (s *systemState) functionAnnotations() map[string]string {
- return prometheusSvcAnnotations()
-}
-
-func prometheusSvcAnnotations() map[string]string {
- return map[string]string{
- "prometheus.io/port": "8080",
- "prometheus.io/path": "/metrics",
- "prometheus.io/scrape": "true",
- }
-}
-func (s *systemState) buildImageAddress(registryAddress string) string {
- var imageTag string
- isGitType := s.instance.TypeOf(serverlessv1alpha2.FunctionTypeGit)
- if isGitType {
- imageTag = calculateGitImageTag(&s.instance)
- } else {
- imageTag = calculateInlineImageTag(&s.instance)
- }
- return fmt.Sprintf("%s/%s-%s:%s", registryAddress, s.instance.Namespace, s.instance.Name, imageTag)
-}
-
-// TODO to self - create issue to refactor this
-func (s *systemState) inlineFnSrcChanged(dockerPullAddress string) bool {
- image := s.buildImageAddress(dockerPullAddress)
- configurationStatus := getConditionStatus(s.instance.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)
- rtm := fnRuntime.GetRuntime(s.instance.Spec.Runtime)
- fnLabels := s.functionLabels()
-
- if len(s.deployments.Items) == 1 &&
- len(s.configMaps.Items) == 1 &&
- s.deployments.Items[0].Spec.Template.Spec.Containers[0].Image == image &&
- s.instance.Spec.Source.Inline.Source == s.configMaps.Items[0].Data[FunctionSourceKey] &&
- rtm.SanitizeDependencies(s.instance.Spec.Source.Inline.Dependencies) == s.configMaps.Items[0].Data[FunctionDepsKey] &&
- configurationStatus != corev1.ConditionUnknown &&
- mapsEqual(s.configMaps.Items[0].Labels, fnLabels) {
- return false
- }
-
- return !(len(s.configMaps.Items) == 1 &&
- s.instance.Spec.Source.Inline.Source == s.configMaps.Items[0].Data[FunctionSourceKey] &&
- rtm.SanitizeDependencies(s.instance.Spec.Source.Inline.Dependencies) == s.configMaps.Items[0].Data[FunctionDepsKey] &&
- configurationStatus == corev1.ConditionTrue &&
- mapsEqual(s.configMaps.Items[0].Labels, fnLabels))
-}
-
-func (s *systemState) buildConfigMap() corev1.ConfigMap {
- rtm := fnRuntime.GetRuntime(s.instance.Spec.Runtime)
- data := map[string]string{
- FunctionSourceKey: s.instance.Spec.Source.Inline.Source,
- FunctionDepsKey: rtm.SanitizeDependencies(s.instance.Spec.Source.Inline.Dependencies),
- }
- fnLabels := s.functionLabels()
-
- return corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Labels: fnLabels,
- GenerateName: fmt.Sprintf("%s-", s.instance.GetName()),
- Namespace: s.instance.GetNamespace(),
- },
- Data: data,
- }
-}
-
-func (s *systemState) fnJobChanged(expectedJob batchv1.Job) bool {
- conditionStatus := getConditionStatus(
- s.instance.Status.Conditions,
- serverlessv1alpha2.ConditionBuildReady,
- )
-
- if len(s.deployments.Items) == 1 &&
- s.deployments.Items[0].Spec.Template.Spec.Containers[0].Image == s.fnImage &&
- conditionStatus != corev1.ConditionUnknown &&
- len(s.jobs.Items) > 0 &&
- mapsEqual(expectedJob.GetLabels(), s.jobs.Items[0].GetLabels()) {
-
- return conditionStatus == corev1.ConditionFalse
- }
-
- return len(s.jobs.Items) != 1 ||
- len(s.jobs.Items[0].Spec.Template.Spec.Containers) != 1 ||
- // Compare fnImage argument
- !equalJobs(s.jobs.Items[0], expectedJob) ||
- !mapsEqual(expectedJob.GetLabels(), s.jobs.Items[0].GetLabels()) ||
- conditionStatus == corev1.ConditionUnknown ||
- conditionStatus == corev1.ConditionFalse
-}
-
-var (
- rootUser = int64(0)
- rootUserGroup = int64(0)
- functionUser = int64(10001)
- functionUserGroup = int64(10001)
-)
-
-func (s *systemState) buildGitJob(gitOptions git.Options, cfg cfg) batchv1.Job {
- templateSpec := corev1.PodSpec{
- Volumes: []corev1.Volume{
- buildJobCredentialsVolume(cfg),
- buildRegistryConfigVolume(cfg),
- s.buildJobRuntimeVolume(),
- {
- Name: "workspace",
- VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
- },
- },
- InitContainers: []corev1.Container{
- s.buildGitJobRepoFetcherContainer(gitOptions, cfg),
- },
- Containers: []corev1.Container{
- s.buildJobExecutorContainer(cfg, s.getGitBuildJobVolumeMounts()),
- },
- RestartPolicy: corev1.RestartPolicyNever,
- }
- enrichPodSpecWithSecurityContext(&templateSpec, rootUser, rootUserGroup)
-
- return s.buildJobJob(templateSpec)
-}
-
-func (s *systemState) buildJob(configMapName string, cfg cfg) batchv1.Job {
- templateSpec := corev1.PodSpec{
- Volumes: []corev1.Volume{
- buildJobCredentialsVolume(cfg),
- buildRegistryConfigVolume(cfg),
- s.buildJobRuntimeVolume(),
- {
- Name: "sources",
- VolumeSource: corev1.VolumeSource{
- ConfigMap: &corev1.ConfigMapVolumeSource{
- LocalObjectReference: corev1.LocalObjectReference{Name: configMapName},
- },
- },
- },
- },
- Containers: []corev1.Container{
- s.buildJobExecutorContainer(cfg, s.getBuildJobVolumeMounts()),
- },
- RestartPolicy: corev1.RestartPolicyNever,
- }
- enrichPodSpecWithSecurityContext(&templateSpec, rootUser, rootUserGroup)
-
- return s.buildJobJob(templateSpec)
-}
-
-func (s *systemState) buildJobJob(templateSpec corev1.PodSpec) batchv1.Job {
- fnLabels := s.functionLabels()
- return batchv1.Job{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-build-", s.instance.GetName()),
- Namespace: s.instance.GetNamespace(),
- Labels: fnLabels,
- },
- Spec: batchv1.JobSpec{
- Parallelism: ptr.To[int32](1),
- Completions: ptr.To[int32](1),
- ActiveDeadlineSeconds: nil,
- BackoffLimit: ptr.To[int32](0),
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: fnLabels,
- Annotations: istioSidecarInjectFalse,
- },
- Spec: templateSpec,
- },
- },
- }
-}
-
-func (s *systemState) buildGitJobRepoFetcherContainer(gitOptions git.Options, cfg cfg) corev1.Container {
- return corev1.Container{
- Name: "repo-fetcher",
- Image: cfg.fn.Build.RepoFetcherImage,
- Env: buildRepoFetcherEnvVars(&s.instance, gitOptions),
- ImagePullPolicy: corev1.PullAlways,
- VolumeMounts: []corev1.VolumeMount{
- {
- Name: "workspace",
- MountPath: workspaceMountPath,
- },
- },
- SecurityContext: restrictiveContainerSecurityContext(),
- }
-}
-
-func (s *systemState) buildJobExecutorContainer(cfg cfg, volumeMounts []corev1.VolumeMount) corev1.Container {
- imageName := s.buildImageAddress(cfg.docker.PushAddress)
- args := append(cfg.fn.Build.ExecutorArgs,
- fmt.Sprintf("%s=%s", destinationArg, imageName),
- fmt.Sprintf("--context=dir://%s", workspaceMountPath))
- if s.instance.Spec.RuntimeImageOverride != "" {
- args = append(args,
- fmt.Sprintf("--build-arg=base_image=%s", s.instance.Spec.RuntimeImageOverride))
- }
-
- resourceRequirements := getBuildResourceRequirements(s.instance, cfg)
-
- return corev1.Container{
- Name: "executor",
- Image: cfg.fn.Build.ExecutorImage,
- Args: args,
- Resources: resourceRequirements,
- VolumeMounts: volumeMounts,
- ImagePullPolicy: corev1.PullIfNotPresent,
- Env: []corev1.EnvVar{
- {Name: "DOCKER_CONFIG", Value: "/docker/.docker/"},
- // GOOGLE_APPLICATION_CREDENTIALS is set to file which does not exist to prevent GCE credential helper creation
- // this is required because Kaniko does not work on clusters run on GKE with the default GCE ServiceAccount
- // with bound bearer token to it. When such SA exists then Kaniko uses this token to pull any image
- // from the pkg.dev registry - even public ones - which causes 401 UNAUTHORIZED status during runtime
- // base pull because we store our runtime bases on the pkg.dev registry
- {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/dev/null"},
- },
- SecurityContext: buildJobContainerSecurityContext(),
- }
-}
-
-func getBuildResourceRequirements(instance serverlessv1alpha2.Function, cfg cfg) corev1.ResourceRequirements {
- rtmPresets, found := cfg.fn.ResourceConfig.BuildJob.Resources.RuntimePresets[string(instance.Spec.Runtime)]
- var presets map[string]corev1.ResourceRequirements
- if found {
- presets = rtmPresets.ToResourceRequirements()
- } else {
- presets = cfg.fn.ResourceConfig.BuildJob.Resources.Presets.ToResourceRequirements()
- }
- if instance.Spec.ResourceConfiguration != nil {
- return instance.Spec.ResourceConfiguration.Build.EffectiveResource(
- cfg.fn.ResourceConfig.BuildJob.Resources.DefaultPreset,
- presets)
- }
- return presets[cfg.fn.ResourceConfig.BuildJob.Resources.DefaultPreset]
-}
-
-func (s *systemState) getBuildJobVolumeMounts() []corev1.VolumeMount {
- rtmCfg := fnRuntime.GetRuntimeConfig(s.instance.Spec.Runtime)
- volumeMounts := []corev1.VolumeMount{
- // Must be mounted with SubPath otherwise files are symlinks and it is not possible to use COPY in Dockerfile
- // If COPY is not used, then the cache will not work
- {Name: "sources", ReadOnly: true, MountPath: path.Join(baseDir, rtmCfg.DependencyFile), SubPath: FunctionDepsKey},
- {Name: "sources", ReadOnly: true, MountPath: path.Join(baseDir, rtmCfg.FunctionFile), SubPath: FunctionSourceKey},
- {Name: "runtime", ReadOnly: true, MountPath: path.Join(workspaceMountPath, "Dockerfile"), SubPath: "Dockerfile"},
- {Name: "credentials", ReadOnly: true, MountPath: "/docker"},
- }
- // add package registry config volume mount depending on the used runtime
- volumeMounts = append(volumeMounts, getPackageConfigVolumeMountsForRuntime(rtmCfg.Runtime)...)
- return volumeMounts
-}
-
-func (s *systemState) getGitBuildJobVolumeMounts() []corev1.VolumeMount {
- rtmCfg := fnRuntime.GetRuntimeConfig(s.instance.Spec.Runtime)
- volumeMounts := []corev1.VolumeMount{
- {Name: "credentials", ReadOnly: true, MountPath: "/docker"},
- // Must be mounted with SubPath otherwise files are symlinks and it is not possible to use COPY in Dockerfile
- // If COPY is not used, then the cache will not work
- {Name: "workspace", MountPath: path.Join(workspaceMountPath, "src"), SubPath: strings.TrimPrefix(s.instance.Spec.Source.GitRepository.BaseDir, "/")},
- {Name: "runtime", ReadOnly: true, MountPath: path.Join(workspaceMountPath, "Dockerfile"), SubPath: "Dockerfile"},
- }
- // add package registry config volume mount depending on the used runtime
- volumeMounts = append(volumeMounts, getPackageConfigVolumeMountsForRuntime(rtmCfg.Runtime)...)
- return volumeMounts
-}
-
-func buildJobCredentialsVolume(cfg cfg) corev1.Volume {
- return corev1.Volume{
- Name: "credentials",
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: cfg.docker.ActiveRegistryConfigSecretName,
- Items: []corev1.KeyToPath{
- {
- Key: ".dockerconfigjson",
- Path: ".docker/config.json",
- },
- },
- },
- },
- }
-}
-
-func buildRegistryConfigVolume(cfg cfg) corev1.Volume {
- return corev1.Volume{
- Name: "registry-config",
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: cfg.fn.PackageRegistryConfigSecretName,
- Optional: ptr.To[bool](true),
- },
- },
- }
-}
-func (s *systemState) buildJobRuntimeVolume() corev1.Volume {
- rtmCfg := fnRuntime.GetRuntimeConfig(s.instance.Spec.Runtime)
- return corev1.Volume{
- Name: "runtime",
- VolumeSource: corev1.VolumeSource{
- ConfigMap: &corev1.ConfigMapVolumeSource{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: rtmCfg.DockerfileConfigMapName,
- },
- },
- },
- }
-}
-
-func (s *systemState) deploymentSelectorLabels() map[string]string {
- return labels.Merge(
- map[string]string{
- serverlessv1alpha2.FunctionResourceLabel: serverlessv1alpha2.FunctionResourceLabelDeploymentValue,
- },
- internalFunctionLabels(s.instance),
- )
-}
-
-func (s *systemState) podLabels() map[string]string {
- result := s.deploymentSelectorLabels()
- if s.instance.Spec.Labels != nil {
- result = labels.Merge(s.instance.Spec.Labels, result)
- }
- return labels.Merge(result, map[string]string{serverlessv1alpha2.PodAppNameLabel: s.instance.Name})
-}
-
-func (s *systemState) defaultAnnotations() map[string]string {
- return map[string]string{
- istioConfigLabelKey: istioEnableHoldUntilProxyStartLabelValue,
- }
-}
-
-func (s *systemState) podAnnotations() map[string]string {
- result := s.defaultAnnotations()
- if s.instance.Spec.Annotations != nil {
- result = labels.Merge(s.instance.Spec.Annotations, result)
- }
- result = labels.Merge(s.specialDeploymentAnnotations(), result)
- return result
-}
-
-func (s *systemState) specialDeploymentAnnotations() map[string]string {
- deployments := s.deployments.Items
- if len(deployments) == 0 {
- return map[string]string{}
- }
- deploymentAnnotations := deployments[0].Spec.Template.GetAnnotations()
- specialDeploymentAnnotations := map[string]string{}
- for _, k := range []string{
- "kubectl.kubernetes.io/restartedAt",
- } {
- if v, found := deploymentAnnotations[k]; found {
- specialDeploymentAnnotations[k] = v
- }
- }
- return specialDeploymentAnnotations
-}
-
-type buildDeploymentArgs struct {
- DockerPullAddress string
- TraceCollectorEndpoint string
- PublisherProxyAddress string
- ImagePullAccountName string
-}
-
-func (s *systemState) buildDeployment(cfg buildDeploymentArgs, resourceConfig Resources) appsv1.Deployment {
- imageName := s.buildImageAddress(cfg.DockerPullAddress)
-
- const volumeName = "tmp-dir"
- emptyDirVolumeSize := resource.MustParse("100Mi")
-
- rtmCfg := fnRuntime.GetRuntimeConfig(s.instance.Spec.Runtime)
-
- envs := append(s.instance.Spec.Env, rtmCfg.RuntimeEnvs...)
-
- deploymentEnvs := buildDeploymentEnvs(
- s.instance.GetName(),
- s.instance.GetNamespace(),
- cfg.TraceCollectorEndpoint,
- cfg.PublisherProxyAddress,
- )
- envs = append(envs, deploymentEnvs...)
-
- secretVolumes, secretVolumeMounts := buildDeploymentSecretVolumes(s.instance.Spec.SecretMounts)
-
- volumes := []corev1.Volume{
- {
- Name: volumeName,
- VolumeSource: corev1.VolumeSource{
- EmptyDir: &corev1.EmptyDirVolumeSource{
- Medium: corev1.StorageMediumDefault,
- SizeLimit: &emptyDirVolumeSize,
- },
- },
- },
- }
- volumes = append(volumes, secretVolumes...)
-
- volumeMounts := []corev1.VolumeMount{
- {
- Name: volumeName,
- /* needed in order to have python functions working:
- python functions need writable /tmp dir, but we disable writing to root filesystem via
- security context below. That's why we override this whole /tmp directory with emptyDir volume.
- We've decided to add this directory to be writable by all functions, as it may come in handy
- */
- MountPath: "/tmp",
- ReadOnly: false,
- },
- }
- volumeMounts = append(volumeMounts, secretVolumeMounts...)
-
- templateSpec := corev1.PodSpec{
- Volumes: volumes,
- Containers: []corev1.Container{
- {
- Name: functionContainerName,
- Image: imageName,
- Env: envs,
- Resources: getDeploymentResources(s.instance, resourceConfig),
- VolumeMounts: volumeMounts,
- /*
- In order to mark pod as ready we need to ensure the function is actually running and ready to serve traffic.
- We do this but first ensuring that sidecar is ready by using "proxy.istio.io/config": "{ \"holdApplicationUntilProxyStarts\": true }", annotation
- Second thing is setting that probe which continuously
- */
- StartupProbe: &corev1.Probe{
- ProbeHandler: corev1.ProbeHandler{
- HTTPGet: &corev1.HTTPGetAction{
- Path: "/healthz",
- Port: svcTargetPort,
- },
- },
- InitialDelaySeconds: 0,
- PeriodSeconds: 5,
- SuccessThreshold: 1,
- FailureThreshold: 30, // FailureThreshold * PeriodSeconds = 150s in this case, this should be enough for any function pod to start up
- },
- ReadinessProbe: &corev1.Probe{
- ProbeHandler: corev1.ProbeHandler{
- HTTPGet: &corev1.HTTPGetAction{
- Path: "/healthz",
- Port: svcTargetPort,
- },
- },
- InitialDelaySeconds: 0, // startup probe exists, so delaying anything here doesn't make sense
- FailureThreshold: 1,
- PeriodSeconds: 5,
- TimeoutSeconds: 2,
- },
- LivenessProbe: &corev1.Probe{
- ProbeHandler: corev1.ProbeHandler{
- HTTPGet: &corev1.HTTPGetAction{
- Path: "/healthz",
- Port: svcTargetPort,
- },
- },
- FailureThreshold: 3,
- PeriodSeconds: 5,
- TimeoutSeconds: 4,
- },
- ImagePullPolicy: corev1.PullIfNotPresent,
- SecurityContext: restrictiveContainerSecurityContext(),
- },
- },
- ServiceAccountName: cfg.ImagePullAccountName,
- }
- enrichPodSpecWithSecurityContext(&templateSpec, functionUser, functionUserGroup)
-
- zero := int32(0)
- return appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-", s.instance.GetName()),
- Namespace: s.instance.GetNamespace(),
- Labels: s.functionLabels(),
- },
- Spec: appsv1.DeploymentSpec{
- RevisionHistoryLimit: &zero,
- Replicas: s.getReplicas(DefaultDeploymentReplicas),
- Selector: &metav1.LabelSelector{
- MatchLabels: s.deploymentSelectorLabels(), // this has to match spec.template.objectmeta.Labels
- // and also it has to be immutable
- },
- Template: corev1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: s.podLabels(), // podLabels contains InternalFnLabels, so it's ok
- Annotations: s.podAnnotations(),
- },
- Spec: templateSpec,
- },
- },
- }
-}
-
-func getDeploymentResources(instance serverlessv1alpha2.Function, resourceCfg Resources) corev1.ResourceRequirements {
- rtmPresets, found := resourceCfg.RuntimePresets[string(instance.Spec.Runtime)]
- var presets map[string]corev1.ResourceRequirements
- if found {
- presets = rtmPresets.ToResourceRequirements()
- } else {
- presets = resourceCfg.Presets.ToResourceRequirements()
- }
- if instance.Spec.ResourceConfiguration != nil {
- return instance.Spec.ResourceConfiguration.Function.EffectiveResource(
- resourceCfg.DefaultPreset,
- presets)
- }
-
- return presets[resourceCfg.DefaultPreset]
-}
-
-func buildDeploymentSecretVolumes(secretMounts []serverlessv1alpha2.SecretMount) (volumes []corev1.Volume, volumeMounts []corev1.VolumeMount) {
- volumes = []corev1.Volume{}
- volumeMounts = []corev1.VolumeMount{}
- for _, secretMount := range secretMounts {
- volumeName := secretMount.SecretName
-
- volume := corev1.Volume{
- Name: volumeName,
- VolumeSource: corev1.VolumeSource{
- Secret: &corev1.SecretVolumeSource{
- SecretName: secretMount.SecretName,
- DefaultMode: ptr.To[int32](0666), //read and write only for everybody
- Optional: ptr.To[bool](false),
- },
- },
- }
- volumes = append(volumes, volume)
-
- volumeMount := corev1.VolumeMount{
- Name: volumeName,
- ReadOnly: true,
- MountPath: secretMount.MountPath,
- }
- volumeMounts = append(volumeMounts, volumeMount)
- }
- return volumes, volumeMounts
-}
-
-func (s *systemState) getReplicas(defaultVal int32) *int32 {
- if s.instance.Spec.Replicas != nil {
- return s.instance.Spec.Replicas
- }
- return &defaultVal
-}
-
-func (s *systemState) hasDeploymentConditionTrueStatusWithReason(conditionType appsv1.DeploymentConditionType, reason string) bool {
- for _, condition := range s.deployments.Items[0].Status.Conditions {
- if condition.Type == conditionType {
- return condition.Status == corev1.ConditionTrue &&
- condition.Reason == reason
- }
- }
- return false
-}
-
-func (s *systemState) isDeploymentReady() bool {
- return s.hasDeploymentConditionTrueStatusWithReason(appsv1.DeploymentAvailable, MinimumReplicasAvailable) &&
- s.hasDeploymentConditionTrueStatusWithReason(appsv1.DeploymentProgressing, NewRSAvailableReason)
-}
-
-func (s *systemState) hasDeploymentConditionFalseStatusWithReason(conditionType appsv1.DeploymentConditionType, reason string) bool {
- for _, condition := range s.deployments.Items[0].Status.Conditions {
- if condition.Type == conditionType {
- return condition.Status == corev1.ConditionFalse &&
- condition.Reason == reason
- }
- }
- return false
-}
-
-func (s *systemState) hasDeploymentConditionTrueStatus(conditionType appsv1.DeploymentConditionType) bool {
- for _, condition := range s.deployments.Items[0].Status.Conditions {
- if condition.Type == conditionType {
- return condition.Status == corev1.ConditionTrue
- }
- }
- return false
-}
-
-func (s *systemState) buildService() corev1.Service {
- return corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: s.instance.GetName(),
- Namespace: s.instance.GetNamespace(),
- Labels: s.functionLabels(),
- Annotations: s.functionAnnotations(),
- },
- Spec: corev1.ServiceSpec{
- Ports: []corev1.ServicePort{{
- Name: "http", // it has to be here for istio to work properly
- TargetPort: svcTargetPort,
- Port: 80,
- Protocol: corev1.ProtocolTCP,
- }},
- Selector: s.deploymentSelectorLabels(),
- },
- }
-}
-
-func (s *systemState) svcChanged(expectedSvc corev1.Service) bool {
- return !equalServices(s.services.Items[0], expectedSvc)
-}
-
-func (s *systemState) hpaEqual(targetCPUUtilizationPercentage int32) bool {
- if len(s.deployments.Items) == 0 {
- return false
- }
-
- expected := s.buildHorizontalPodAutoscaler(targetCPUUtilizationPercentage)
-
- scalingEnabled := isScalingEnabled(&s.instance)
-
- numHpa := len(s.hpas.Items)
- return (scalingEnabled && numHpa != 1) ||
- (scalingEnabled && !s.equalHorizontalPodAutoscalers(expected)) ||
- (!scalingEnabled && numHpa != 0)
-}
-
-func (s *systemState) defaultReplicas() (int32, int32) {
- var min = int32(1)
- var max int32
- if s.instance.Spec.ScaleConfig == nil {
- return min, min
- }
- spec := s.instance.Spec
- if spec.ScaleConfig.MinReplicas != nil && *spec.ScaleConfig.MinReplicas > 0 {
- min = *spec.ScaleConfig.MinReplicas
- }
- // special case
- if spec.ScaleConfig.MaxReplicas == nil || min > *spec.ScaleConfig.MaxReplicas {
- max = min
- } else {
- max = *spec.ScaleConfig.MaxReplicas
- }
- return min, max
-}
-
-func (s *systemState) buildHorizontalPodAutoscaler(targetCPUUtilizationPercentage int32) autoscalingv1.HorizontalPodAutoscaler {
- minReplicas, maxReplicas := s.defaultReplicas()
- return autoscalingv1.HorizontalPodAutoscaler{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: fmt.Sprintf("%s-", s.instance.GetName()),
- Namespace: s.instance.GetNamespace(),
- Labels: s.functionLabels(),
- },
- Spec: autoscalingv1.HorizontalPodAutoscalerSpec{
- ScaleTargetRef: autoscalingv1.CrossVersionObjectReference{
- Kind: serverlessv1alpha2.FunctionKind,
- Name: s.instance.Name,
- APIVersion: serverlessv1alpha2.GroupVersion.String(),
- },
- MinReplicas: &minReplicas,
- MaxReplicas: maxReplicas,
- TargetCPUUtilizationPercentage: &targetCPUUtilizationPercentage,
- },
- }
-}
-
-func (s *systemState) equalHorizontalPodAutoscalers(expected autoscalingv1.HorizontalPodAutoscaler) bool {
- existing := s.hpas.Items[0]
- return equalInt32Pointer(existing.Spec.TargetCPUUtilizationPercentage, expected.Spec.TargetCPUUtilizationPercentage) &&
- equalInt32Pointer(existing.Spec.MinReplicas, expected.Spec.MinReplicas) &&
- existing.Spec.MaxReplicas == expected.Spec.MaxReplicas &&
- mapsEqual(existing.Labels, expected.Labels) &&
- existing.Spec.ScaleTargetRef.Name == expected.Spec.ScaleTargetRef.Name
-}
-
-func (s *systemState) gitFnSrcChanged(commit string) bool {
- return s.instance.Status.Commit == "" ||
- commit != s.instance.Status.Commit ||
- s.instance.Spec.Source.GitRepository.Reference != s.instance.Status.Reference ||
- s.instance.Spec.Runtime != s.instance.Status.Runtime ||
- s.instance.Spec.Source.GitRepository.BaseDir != s.instance.Status.BaseDir ||
- getConditionStatus(s.instance.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady) == corev1.ConditionFalse
-
-}
-
-func (s *systemState) jobFailed(p func(reason string) bool) bool {
- if len(s.jobs.Items) == 0 {
- return false
- }
-
- return jobFailed(s.jobs.Items[0], p)
-}
-
-// security context is set to fulfill the baseline security profile
-// based on https://raw.githubusercontent.com/kyma-project/community/main/concepts/psp-replacement/baseline-pod-spec.yaml
-func restrictiveContainerSecurityContext() *corev1.SecurityContext {
- defaultProcMount := corev1.DefaultProcMount
- return &corev1.SecurityContext{
- Privileged: ptr.To[bool](false),
- Capabilities: &corev1.Capabilities{
- Drop: []corev1.Capability{
- "ALL",
- },
- },
- ProcMount: &defaultProcMount,
- ReadOnlyRootFilesystem: ptr.To[bool](true),
- }
-}
-
-// build job requires additional permissions some than the restrictive version
-func buildJobContainerSecurityContext() *corev1.SecurityContext {
- securityContext := restrictiveContainerSecurityContext()
- securityContext.Capabilities.Add = []corev1.Capability{
- "CHOWN", // for "chown"
- "FOWNER", // for "chmod"
- "SETGID", // for "fork"
- "DAC_OVERRIDE", // for "open"
- }
- securityContext.ReadOnlyRootFilesystem = ptr.To[bool](false)
- return securityContext
-}
-
-// security context is set to fulfill the baseline security profile
-// based on https://raw.githubusercontent.com/kyma-project/community/main/concepts/psp-replacement/baseline-pod-spec.yaml
-func enrichPodSpecWithSecurityContext(ps *corev1.PodSpec, user int64, userGroup int64) {
- ps.SecurityContext = &corev1.PodSecurityContext{
- RunAsUser: &user,
- RunAsGroup: &userGroup,
- SeccompProfile: &corev1.SeccompProfile{
- Type: corev1.SeccompProfileTypeRuntimeDefault,
- },
- }
- ps.HostNetwork = false
- ps.HostPID = false
- ps.HostIPC = false
-}
diff --git a/components/serverless/internal/controllers/serverless/system_state_test.go b/components/serverless/internal/controllers/serverless/system_state_test.go
deleted file mode 100644
index fd84aea7b..000000000
--- a/components/serverless/internal/controllers/serverless/system_state_test.go
+++ /dev/null
@@ -1,196 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/onsi/gomega"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_systemState_podLabels(t *testing.T) {
- type args struct {
- instance *v1alpha2.Function
- }
- tests := []struct {
- name string
- args args
- want map[string]string
- }{
- {
- name: "Should create internal labels",
- args: args{instance: &v1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- }},
- },
- want: map[string]string{
- v1alpha2.PodAppNameLabel: "fn-name",
- v1alpha2.FunctionUUIDLabel: "fn-uuid",
- v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionControllerValue,
- v1alpha2.FunctionNameLabel: "fn-name",
- v1alpha2.FunctionResourceLabel: v1alpha2.FunctionResourceLabelDeploymentValue,
- },
- },
- {
- name: "Should create internal and additional labels",
- args: args{instance: &v1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- },
- Spec: v1alpha2.FunctionSpec{
- Labels: map[string]string{
- "test-another": "test-another-label",
- },
- }}},
- want: map[string]string{
- v1alpha2.PodAppNameLabel: "fn-name",
- v1alpha2.FunctionUUIDLabel: "fn-uuid",
- v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionControllerValue,
- v1alpha2.FunctionNameLabel: "fn-name",
- v1alpha2.FunctionResourceLabel: v1alpha2.FunctionResourceLabelDeploymentValue,
- "test-another": "test-another-label",
- },
- },
- {
- name: "Should create internal labels without not supported `spec.template.labels`",
- args: args{instance: &v1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- },
- Spec: v1alpha2.FunctionSpec{
- Template: &v1alpha2.Template{
- Labels: map[string]string{
- "test-some": "not-supported",
- },
- },
- }}},
- want: map[string]string{
- v1alpha2.PodAppNameLabel: "fn-name",
- v1alpha2.FunctionUUIDLabel: "fn-uuid",
- v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionControllerValue,
- v1alpha2.FunctionNameLabel: "fn-name",
- v1alpha2.FunctionResourceLabel: v1alpha2.FunctionResourceLabelDeploymentValue,
- },
- },
- {
- name: "Should create internal and from `spec.labels` labels",
- args: args{instance: &v1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- },
- Spec: v1alpha2.FunctionSpec{
- Labels: map[string]string{
- "test-some": "test-label",
- },
- }}},
- want: map[string]string{
- v1alpha2.PodAppNameLabel: "fn-name",
- v1alpha2.FunctionUUIDLabel: "fn-uuid",
- v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionControllerValue,
- v1alpha2.FunctionNameLabel: "fn-name",
- v1alpha2.FunctionResourceLabel: v1alpha2.FunctionResourceLabelDeploymentValue,
- "test-some": "test-label",
- },
- },
- {
- name: "Should not overwrite internal labels",
- args: args{instance: &v1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "fn-name",
- UID: "fn-uuid",
- },
- Spec: v1alpha2.FunctionSpec{
- Labels: map[string]string{
- "test-another": "test-label",
- v1alpha2.FunctionResourceLabel: "another-job",
- v1alpha2.FunctionNameLabel: "another-name",
- },
- }}},
- want: map[string]string{
- v1alpha2.PodAppNameLabel: "fn-name",
- v1alpha2.FunctionUUIDLabel: "fn-uuid",
- v1alpha2.FunctionManagedByLabel: v1alpha2.FunctionControllerValue,
- v1alpha2.FunctionNameLabel: "fn-name",
- v1alpha2.FunctionResourceLabel: v1alpha2.FunctionResourceLabelDeploymentValue,
- "test-another": "test-label",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- s := &systemState{
- instance: *tt.args.instance,
- }
- //WHEN
- got := s.podLabels()
- //THEN
- g.Expect(tt.want).To(gomega.Equal(got))
- })
- }
-}
-
-func Test_systemState_podAnnotations(t *testing.T) {
- type args struct {
- instance *v1alpha2.Function
- }
- tests := []struct {
- name string
- args args
- want map[string]string
- }{
- {
- name: "Should create internal annotations",
- args: args{instance: &v1alpha2.Function{}},
- want: map[string]string{
- istioConfigLabelKey: istioEnableHoldUntilProxyStartLabelValue,
- },
- },
- {
- name: "Should create internal and from `.spec.annotations` annotations",
- args: args{instance: &v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "test-some": "test-annotation",
- },
- }}},
- want: map[string]string{
- istioConfigLabelKey: istioEnableHoldUntilProxyStartLabelValue,
- "test-some": "test-annotation",
- },
- },
- {
- name: "Should not overwrite internal annotations",
- args: args{instance: &v1alpha2.Function{
- Spec: v1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "test-some": "test-annotation",
- "proxy.istio.io/config": "another-config",
- },
- }}},
- want: map[string]string{
- istioConfigLabelKey: istioEnableHoldUntilProxyStartLabelValue,
- "test-some": "test-annotation",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- //GIVEN
- g := gomega.NewGomegaWithT(t)
- s := &systemState{
- instance: *tt.args.instance,
- }
- //WHEN
- got := s.podAnnotations()
- //THEN
- g.Expect(tt.want).To(gomega.Equal(got))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/utils.go b/components/serverless/internal/controllers/serverless/utils.go
deleted file mode 100644
index cc466454e..000000000
--- a/components/serverless/internal/controllers/serverless/utils.go
+++ /dev/null
@@ -1,398 +0,0 @@
-package serverless
-
-import (
- "crypto/sha256"
- "fmt"
- "path"
- "reflect"
- "sort"
- "strings"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- appsv1 "k8s.io/api/apps/v1"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
-)
-
-const (
- FunctionSourceKey = "source"
- FunctionDepsKey = "dependencies"
-)
-
-func getConditionStatus(conditions []serverlessv1alpha2.Condition, conditionType serverlessv1alpha2.ConditionType) corev1.ConditionStatus {
- for _, condition := range conditions {
- if condition.Type == conditionType {
- return condition.Status
- }
- }
-
- return corev1.ConditionUnknown
-}
-
-func updateCondition(conditions []serverlessv1alpha2.Condition, condition serverlessv1alpha2.Condition) []serverlessv1alpha2.Condition {
- conditionTypes := make(map[serverlessv1alpha2.ConditionType]interface{}, 3)
- var result []serverlessv1alpha2.Condition
-
- result = append(result, condition)
- conditionTypes[condition.Type] = nil
-
- for _, value := range conditions {
- if _, ok := conditionTypes[value.Type]; !ok {
- result = append(result, value)
- conditionTypes[value.Type] = nil
- }
- }
-
- return result
-}
-
-func equalConditions(existing, expected []serverlessv1alpha2.Condition) bool {
- if len(existing) != len(expected) {
- return false
- }
-
- existingMap := make(map[serverlessv1alpha2.ConditionType]serverlessv1alpha2.Condition, len(existing))
- for _, value := range existing {
- existingMap[value.Type] = value
- }
-
- for _, expectedCondition := range expected {
- existingCondition := existingMap[expectedCondition.Type]
- if !existingCondition.Equal(&expectedCondition) {
- return false
- }
- }
- return true
-}
-
-func equalFunctionStatus(left, right serverlessv1alpha2.FunctionStatus) bool {
- if !equalConditions(left.Conditions, right.Conditions) {
- return false
- }
-
- if left.Repository != right.Repository ||
- left.Commit != right.Commit ||
- left.Runtime != right.Runtime {
- return false
- }
- return true
-}
-
-func equalJobs(existing batchv1.Job, expected batchv1.Job) bool {
- existingArgs := existing.Spec.Template.Spec.Containers[0].Args
- expectedArgs := expected.Spec.Template.Spec.Containers[0].Args
-
- // Compare destination argument as it contains fnImage tag
- existingDst := getArg(existingArgs, destinationArg)
- expectedDst := getArg(expectedArgs, destinationArg)
-
- return existingDst == expectedDst
-}
-
-func getArg(args []string, arg string) string {
- for _, item := range args {
- if strings.HasPrefix(item, arg) {
- return item
- }
- }
- return ""
-}
-
-func getPackageConfigVolumeMountsForRuntime(rtm serverlessv1alpha2.Runtime) []corev1.VolumeMount {
- switch rtm {
- case serverlessv1alpha2.NodeJs18, serverlessv1alpha2.NodeJs20:
- return []corev1.VolumeMount{
- {
- Name: "registry-config",
- ReadOnly: true,
- MountPath: path.Join(workspaceMountPath, "registry-config/.npmrc"),
- SubPath: ".npmrc",
- },
- }
- case serverlessv1alpha2.Python39, serverlessv1alpha2.Python312:
- return []corev1.VolumeMount{
- {
- Name: "registry-config",
- ReadOnly: true,
- MountPath: path.Join(workspaceMountPath, "registry-config/pip.conf"),
- SubPath: "pip.conf"},
- }
- }
- return nil
-}
-
-func didNotSucceed(j batchv1.Job) bool {
- return j.Status.Succeeded == 0
-}
-
-func didNotFail(j batchv1.Job) bool {
- return j.Status.Failed == 0
-}
-
-func countJobs(l batchv1.JobList, predicates ...func(batchv1.Job) bool) int {
- var out int
-
-processingNextItem:
- for _, j := range l.Items {
- for _, p := range predicates {
- if !p(j) {
- continue processingNextItem
- }
- }
- out++
- }
-
- return out
-}
-
-func buildDeploymentEnvs(name, namespace, traceCollectorEndpoint, publisherProxyAddress string) []corev1.EnvVar {
- return []corev1.EnvVar{
- {Name: "FUNC_NAME", Value: name},
- {Name: "SERVICE_NAMESPACE", Value: namespace},
- {Name: "TRACE_COLLECTOR_ENDPOINT", Value: traceCollectorEndpoint},
- {Name: "PUBLISHER_PROXY_ADDRESS", Value: publisherProxyAddress},
- {Name: "FUNC_HANDLER", Value: "main"},
- {Name: "MOD_NAME", Value: "handler"},
- {Name: "FUNC_PORT", Value: "8080"},
- }
-}
-
-func envsEqual(existing, expected []corev1.EnvVar) bool {
- if len(existing) != len(expected) {
- return false
- }
- for key, value := range existing {
- expectedValue := expected[key]
-
- if expectedValue.Name != value.Name || expectedValue.Value != value.Value || expectedValue.ValueFrom.String() != value.ValueFrom.String() { // valueFrom check is by string representation
- return false
- }
- }
-
- return true
-}
-
-func mapsEqual(existing, expected map[string]string) bool {
- if len(existing) != len(expected) {
- return false
- }
-
- for key, value := range existing {
- if v, ok := expected[key]; !ok || v != value {
- return false
- }
- }
-
- return true
-}
-
-func mapsContains(mapSet, mapSubset map[string]string) bool {
- if len(mapSet) < len(mapSubset) {
- return false
- }
-
- for key, value := range mapSubset {
- if v, ok := mapSet[key]; !ok || v != value {
- return false
- }
- }
-
- return true
-}
-
-func mergeMapWithNewValues(existing, newValues map[string]string) {
- for key, value := range newValues {
- existing[key] = value
- }
-}
-
-// TODO refactor to make this code more readable
-func equalDeployments(existing appsv1.Deployment, expected appsv1.Deployment) bool {
- result := true
- result = result && len(existing.Spec.Template.Spec.Containers) == 1
- result = result && len(existing.Spec.Template.Spec.Containers) == len(expected.Spec.Template.Spec.Containers)
-
- result = result && existing.Spec.Template.Spec.Containers[0].Image == expected.Spec.Template.Spec.Containers[0].Image
- result = result && envsEqual(existing.Spec.Template.Spec.Containers[0].Env, expected.Spec.Template.Spec.Containers[0].Env)
- result = result && equalResources(existing.Spec.Template.Spec.Containers[0].Resources, expected.Spec.Template.Spec.Containers[0].Resources)
-
- result = result && mapsEqual(existing.GetLabels(), expected.GetLabels())
- result = result && mapsEqual(existing.Spec.Template.GetLabels(), expected.Spec.Template.GetLabels())
- result = result && equalInt32Pointer(existing.Spec.Replicas, expected.Spec.Replicas)
-
- result = result && mapsEqual(existing.Spec.Template.GetAnnotations(), expected.Spec.Template.GetAnnotations())
- result = result && equalSecretMounts(existing.Spec.Template.Spec, expected.Spec.Template.Spec)
- result = result && equalInt32Pointer(existing.Spec.RevisionHistoryLimit, expected.Spec.RevisionHistoryLimit)
- return result
-}
-
-func equalServices(existing corev1.Service, expected corev1.Service) bool {
- return mapsEqual(existing.Spec.Selector, expected.Spec.Selector) &&
- mapsContains(existing.Annotations, prometheusSvcAnnotations()) &&
- mapsEqual(existing.Labels, expected.Labels) &&
- len(existing.Spec.Ports) == len(expected.Spec.Ports) &&
- len(expected.Spec.Ports) > 0 &&
- len(existing.Spec.Ports) > 0 &&
- existing.Spec.Ports[0].String() == expected.Spec.Ports[0].String()
-}
-
-func readSecretData(data map[string][]byte) map[string]string {
- output := make(map[string]string)
- for k, v := range data {
- output[k] = string(v)
- }
- return output
-}
-
-func equalResources(existing, expected corev1.ResourceRequirements) bool {
- return existing.Requests.Memory().Equal(*expected.Requests.Memory()) &&
- existing.Requests.Cpu().Equal(*expected.Requests.Cpu()) &&
- existing.Limits.Memory().Equal(*expected.Limits.Memory()) &&
- existing.Limits.Cpu().Equal(*expected.Limits.Cpu())
-}
-
-func equalInt32Pointer(first *int32, second *int32) bool {
- if first == nil && second == nil {
- return true
- }
- if (first != nil && second == nil) || (first == nil && second != nil) {
- return false
- }
-
- return *first == *second
-}
-
-func equalSecretMounts(existing, expected corev1.PodSpec) bool {
- existingSecretVolumes := filterOnlySecretVolumes(existing.Volumes)
- expectedSecretVolumes := filterOnlySecretVolumes(expected.Volumes)
- if !equalSecretVolumes(existingSecretVolumes, expectedSecretVolumes) {
- return false
- }
-
- existingSecretVolumeMounts := filterOnlyKnownVolumes(existing.Containers[0].VolumeMounts, existingSecretVolumes)
- expectedSecretVolumeMounts := filterOnlyKnownVolumes(expected.Containers[0].VolumeMounts, expectedSecretVolumes)
- return equalVolumeMounts(existingSecretVolumeMounts, expectedSecretVolumeMounts)
-}
-
-type secretVolumeMountSorter []corev1.VolumeMount
-
-func (s secretVolumeMountSorter) Len() int { return len(s) }
-func (s secretVolumeMountSorter) Less(i, j int) bool { return s[i].Name < s[j].Name }
-func (s secretVolumeMountSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-func equalVolumeMounts(existing []corev1.VolumeMount, expected []corev1.VolumeMount) bool {
- sort.Stable(secretVolumeMountSorter(existing))
- sort.Stable(secretVolumeMountSorter(expected))
- return reflect.DeepEqual(existing, expected)
-}
-
-type secretVolumeSorter []corev1.Volume
-
-func (s secretVolumeSorter) Len() int { return len(s) }
-func (s secretVolumeSorter) Less(i, j int) bool { return s[i].Name < s[j].Name }
-func (s secretVolumeSorter) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
-func equalSecretVolumes(existing []corev1.Volume, expected []corev1.Volume) bool {
- sort.Stable(secretVolumeSorter(existing))
- sort.Stable(secretVolumeSorter(expected))
- return reflect.DeepEqual(existing, expected)
-}
-
-func filterOnlyKnownVolumes(mounts []corev1.VolumeMount, knownVolumes []corev1.Volume) []corev1.VolumeMount {
- knownVolumeNames := getVolumeNames(knownVolumes)
- var knownVolumeMounts []corev1.VolumeMount
- for _, mount := range mounts {
- if stringInSlice(mount.Name, knownVolumeNames) {
- knownVolumeMounts = append(knownVolumeMounts, mount)
- }
- }
- return knownVolumeMounts
-}
-
-func stringInSlice(a string, list []string) bool {
- for _, b := range list {
- if b == a {
- return true
- }
- }
- return false
-}
-
-func getVolumeNames(volumes []corev1.Volume) []string {
- var names []string
- for _, volume := range volumes {
- names = append(names, volume.Name)
- }
- return names
-}
-
-func filterOnlySecretVolumes(volumes []corev1.Volume) []corev1.Volume {
- var secretVolumes []corev1.Volume
- for _, volume := range volumes {
- if volume.Secret != nil {
- secretVolumes = append(secretVolumes, volume)
- }
- }
- return secretVolumes
-}
-
-func isScalingEnabled(instance *serverlessv1alpha2.Function) bool {
- if instance.Spec.ScaleConfig == nil {
- return false
- }
- return !equalInt32Pointer(instance.Spec.ScaleConfig.MinReplicas, instance.Spec.ScaleConfig.MaxReplicas)
-}
-
-func getConditionReason(conditions []serverlessv1alpha2.Condition, conditionType serverlessv1alpha2.ConditionType) serverlessv1alpha2.ConditionReason {
- for _, condition := range conditions {
- if condition.Type == conditionType {
- return condition.Reason
- }
- }
-
- return ""
-}
-
-func getCondition(conditions []serverlessv1alpha2.Condition, conditionType serverlessv1alpha2.ConditionType) serverlessv1alpha2.Condition {
- for _, condition := range conditions {
- if condition.Type == conditionType {
- return condition
- }
- }
-
- return serverlessv1alpha2.Condition{}
-}
-
-func calculateInlineImageTag(instance *serverlessv1alpha2.Function) string {
- hash := sha256.Sum256([]byte(strings.Join([]string{
- string(instance.GetUID()),
- fmt.Sprintf("%v", *instance.Spec.Source.Inline),
- instance.EffectiveRuntime(),
- }, "-")))
-
- return fmt.Sprintf("%x", hash)
-}
-
-func calculateGitImageTag(instance *serverlessv1alpha2.Function) string {
- data := strings.Join([]string{
- string(instance.GetUID()),
- instance.Status.Commit,
- instance.Status.BaseDir,
- instance.EffectiveRuntime(),
- }, "-")
- hash := sha256.Sum256([]byte(data))
- return fmt.Sprintf("%x", hash)
-}
-
-func jobFailed(job batchv1.Job, p func(reason string) bool) bool {
- for _, condition := range job.Status.Conditions {
- isFailedType := condition.Type == batchv1.JobFailed
- isStatusTrue := condition.Status == corev1.ConditionTrue
-
- if isFailedType && isStatusTrue {
- return p(condition.Reason)
- }
- }
-
- return false
-}
diff --git a/components/serverless/internal/controllers/serverless/utils_test.go b/components/serverless/internal/controllers/serverless/utils_test.go
deleted file mode 100644
index 6e1f3838e..000000000
--- a/components/serverless/internal/controllers/serverless/utils_test.go
+++ /dev/null
@@ -1,167 +0,0 @@
-package serverless
-
-import (
- "testing"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/assert"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_calculateGitImageTag(t *testing.T) {
- tests := []struct {
- name string
- fn *serverlessv1alpha2.Function
- want string
- }{
- {
- name: "should use runtime",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs20",
- },
- },
- want: "5e62e84b27afdcf23e9ea682a8ce44b693c4a3258e5b26bd038c60cd41eb60ee",
- },
- {
- name: "should use runtimeOverride",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs18",
- RuntimeImageOverride: "nodejs20",
- },
- },
- want: "5e62e84b27afdcf23e9ea682a8ce44b693c4a3258e5b26bd038c60cd41eb60ee",
- },
- {
- name: "should use runtime when runtimeOverride is empty",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs20",
- RuntimeImageOverride: "",
- },
- },
- want: "5e62e84b27afdcf23e9ea682a8ce44b693c4a3258e5b26bd038c60cd41eb60ee",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- assert.Equal(t, tt.want, calculateGitImageTag(tt.fn))
- })
- }
-}
-
-func Test_calculateInlineImageTag(t *testing.T) {
- tests := []struct {
- name string
- fn *serverlessv1alpha2.Function
- want string
- }{
- {
- name: "should use runtime",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs20",
- },
- Status: serverlessv1alpha2.FunctionStatus{
- Commit: "commit",
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "baseDir",
- },
- },
- },
- want: "9f131e00ad3c6cfc5ca36f27df299eeeb2b08bcc4328782e79b69440b1b7aa2b",
- },
- {
- name: "should use runtimeOverride",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs18",
- RuntimeImageOverride: "nodejs20",
- },
- Status: serverlessv1alpha2.FunctionStatus{
- Commit: "commit",
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "baseDir",
- },
- },
- },
- want: "9f131e00ad3c6cfc5ca36f27df299eeeb2b08bcc4328782e79b69440b1b7aa2b",
- },
- {
- name: "should use runtime instead of runtimeOverride",
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- UID: "fn-uuid",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "fn-source",
- Dependencies: "",
- },
- },
- Runtime: "nodejs20",
- RuntimeImageOverride: "",
- },
- Status: serverlessv1alpha2.FunctionStatus{
- Commit: "commit",
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "baseDir",
- },
- },
- },
- want: "9f131e00ad3c6cfc5ca36f27df299eeeb2b08bcc4328782e79b69440b1b7aa2b",
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- assert.Equal(t, tt.want, calculateInlineImageTag(tt.fn))
- })
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/validation.go b/components/serverless/internal/controllers/serverless/validation.go
deleted file mode 100644
index 94d8ebfd8..000000000
--- a/components/serverless/internal/controllers/serverless/validation.go
+++ /dev/null
@@ -1,245 +0,0 @@
-package serverless
-
-import (
- "context"
- "fmt"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- corev1 "k8s.io/api/core/v1"
- resource "k8s.io/apimachinery/pkg/api/resource"
- "k8s.io/apimachinery/pkg/api/validation"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
- utilvalidation "k8s.io/apimachinery/pkg/util/validation"
- "k8s.io/apimachinery/pkg/util/validation/field"
- "strings"
-)
-
-var _ stateFn = stateFnValidateFunction
-
-type validationFn func() []string
-
-func stateFnValidateFunction(_ context.Context, r *reconciler, s *systemState) (stateFn, error) {
- rc := s.instance.Spec.ResourceConfiguration
- fnResourceCfg := r.cfg.fn.ResourceConfig.Function.Resources
- validateFunctionResources := validateFunctionResourcesFn(rc, fnResourceCfg.MinRequestedCPU.Quantity, fnResourceCfg.MinRequestedMemory.Quantity)
- buildResourceCfg := r.cfg.fn.ResourceConfig.BuildJob.Resources
- validateBuildResources := validateBuildResourcesFn(rc, buildResourceCfg.MinRequestedCPU.Quantity, buildResourceCfg.MinRequestedMemory.Quantity)
-
- spec := s.instance.Spec
- validationFns := []validationFn{
- validateFunctionResources,
- validateBuildResources,
- validateEnvs(spec.Env, "spec.env"),
- validateSecretMounts(spec.SecretMounts),
- validateInlineDeps(spec.Runtime, spec.Source.Inline),
- validateFunctionLabels(spec.Labels, "spec.labels"),
- validateFunctionAnnotations(spec.Annotations, "spec.annotations"),
- validateGitRepoURL(spec.Source),
- }
- validationResults := []string{}
- for _, validationFn := range validationFns {
- result := validationFn()
- validationResults = append(validationResults, result...)
- }
-
- if len(validationResults) != 0 {
- msg := strings.Join(validationResults, ". ")
- cond := createValidationFailedCondition(msg)
- r.result.Requeue = false
- return buildStatusUpdateStateFnWithCondition(cond), nil
- }
- return stateFnInitialize, nil
-}
-
-func validateGitRepoURL(source serverlessv1alpha2.Source) validationFn {
- return func() []string {
- var result []string
- if source.GitRepository == nil {
- return result
- }
- if err := serverlessv1alpha2.ValidateGitRepoURL(source.GitRepository); err != nil {
- result = append(result, err.Error())
- }
- return result
- }
-}
-
-func validateFunctionResourcesFn(rc *serverlessv1alpha2.ResourceConfiguration, minCPU resource.Quantity, minMemory resource.Quantity) validationFn {
- return func() []string {
- if rc != nil && rc.Function != nil && rc.Function.Resources != nil {
- vrLimits := validateLimits(*rc.Function.Resources, minMemory, minCPU, "Function")
- vrRequests := validateRequests(*rc.Function.Resources, minMemory, minCPU, "Function")
- vr := append(vrLimits, vrRequests...)
- return vr
- }
- return []string{}
- }
-}
-
-func validateBuildResourcesFn(rc *serverlessv1alpha2.ResourceConfiguration, minCPU resource.Quantity, minMemory resource.Quantity) validationFn {
- return func() []string {
- if rc != nil && rc.Build != nil && rc.Build.Resources != nil {
- vrLimits := validateLimits(*rc.Build.Resources, minMemory, minCPU, "Build")
- vrRequests := validateRequests(*rc.Build.Resources, minMemory, minCPU, "Build")
- vr := append(vrLimits, vrRequests...)
- return vr
- }
- return []string{}
- }
-}
-
-func validateEnvs(envs []corev1.EnvVar, path string) validationFn {
- return func() []string {
- for _, env := range envs {
- vr := utilvalidation.IsEnvVarName(env.Name)
- if len(vr) != 0 {
- return enrichErrors(vr, path, env.Name)
- }
- }
- return []string{}
- }
-}
-
-func validateSecretMounts(secretMounts []serverlessv1alpha2.SecretMount) validationFn {
- return func() []string {
- var allErrs []string
- for _, secretMount := range secretMounts {
- allErrs = append(allErrs,
- utilvalidation.IsDNS1123Subdomain(secretMount.SecretName)...)
- }
- if !secretNamesAreUnique(secretMounts) {
- allErrs = append(allErrs, "secretNames should be unique")
- }
- if len(allErrs) == 0 {
- return []string{}
- }
- return []string{
- fmt.Sprintf("invalid spec.secretMounts: %s", allErrs),
- }
- }
-}
-
-func secretNamesAreUnique(secretMounts []serverlessv1alpha2.SecretMount) bool {
- uniqueSecretNames := make(map[string]bool)
- for _, secretMount := range secretMounts {
- uniqueSecretNames[secretMount.SecretName] = true
- }
- return len(uniqueSecretNames) == len(secretMounts)
-}
-
-func validateInlineDeps(runtime serverlessv1alpha2.Runtime, inlineSource *serverlessv1alpha2.InlineSource) validationFn {
- return func() []string {
- if inlineSource == nil {
- return []string{}
- }
- if err := serverlessv1alpha2.ValidateDependencies(runtime, inlineSource.Dependencies); err != nil {
- return []string{
- fmt.Sprintf("invalid source.inline.dependencies value: %s", err.Error()),
- }
- }
- return []string{}
- }
-}
-
-func validateFunctionLabels(labels map[string]string, path string) validationFn {
- return func() []string {
- errs := field.ErrorList{}
- fieldPath := field.NewPath(path)
- errs = append(errs, v1validation.ValidateLabels(labels, fieldPath)...)
- if len(errs) == 0 {
- return []string{}
- }
- result := []string{}
- for _, err := range errs {
- if err != nil {
- result = append(result, err.Error())
- }
- }
- return result
- }
-}
-
-func validateFunctionAnnotations(annotations map[string]string, path string) validationFn {
- return func() []string {
- errs := field.ErrorList{}
- fieldPath := field.NewPath(path)
- errs = append(errs, validation.ValidateAnnotations(annotations, fieldPath)...)
- if len(errs) == 0 {
- return []string{}
- }
- result := []string{}
- for _, err := range errs {
- if err != nil {
- result = append(result, err.Error())
- }
- }
- return result
- }
-}
-
-func enrichErrors(errs []string, path string, value string) []string {
- enrichedErrs := []string{}
- for _, err := range errs {
- enrichedErrs = append(enrichedErrs, fmt.Sprintf("%s: %s. Err: %s", path, value, err))
- }
- return enrichedErrs
-}
-
-func validateRequests(resources corev1.ResourceRequirements, minMemory, minCPU resource.Quantity, resourceType string) []string {
- limits := resources.Limits
- requests := resources.Requests
- allErrs := []string{}
-
- if requests != nil {
- if requests.Cpu().Cmp(minCPU) == -1 {
- allErrs = append(allErrs, fmt.Sprintf("%s request cpu(%s) should be higher than minimal value (%s)",
- resourceType, requests.Cpu().String(), minCPU.String()))
- }
- if requests.Memory().Cmp(minMemory) == -1 {
- allErrs = append(allErrs, fmt.Sprintf("%s request memory(%s) should be higher than minimal value (%s)",
- resourceType, requests.Memory().String(), minMemory.String()))
- }
- }
-
- if limits == nil {
- return allErrs
- }
-
- if requests.Cpu().Cmp(*limits.Cpu()) == 1 {
- allErrs = append(allErrs, fmt.Sprintf("%s limits cpu(%s) should be higher than requests cpu(%s)",
- resourceType, limits.Cpu().String(), requests.Cpu().String()))
- }
- if requests.Memory().Cmp(*limits.Memory()) == 1 {
- allErrs = append(allErrs, fmt.Sprintf("%s limits memory(%s) should be higher than requests memory(%s)",
- resourceType, limits.Memory().String(), requests.Memory().String()))
- }
-
- return allErrs
-}
-
-func validateLimits(resources corev1.ResourceRequirements, minMemory, minCPU resource.Quantity, resourceType string) []string {
- limits := resources.Limits
- allErrs := []string{}
-
- if limits != nil {
- if limits.Cpu().Cmp(minCPU) == -1 {
- allErrs = append(allErrs, fmt.Sprintf("%s limits cpu(%s) should be higher than minimal value (%s)",
- resourceType, limits.Cpu().String(), minCPU.String()))
- }
- if limits.Memory().Cmp(minMemory) == -1 {
- allErrs = append(allErrs, fmt.Sprintf("%s limits memory(%s) should be higher than minimal value (%s)",
- resourceType, limits.Memory().String(), minMemory.String()))
- }
- }
- return allErrs
-}
-
-func createValidationFailedCondition(msg string) serverlessv1alpha2.Condition {
- return serverlessv1alpha2.Condition{
- Type: serverlessv1alpha2.ConditionConfigurationReady,
- Status: corev1.ConditionFalse,
- LastTransitionTime: metav1.Now(),
- Reason: serverlessv1alpha2.ConditionReasonFunctionSpec,
- Message: msg,
- }
-}
diff --git a/components/serverless/internal/controllers/serverless/validation_test.go b/components/serverless/internal/controllers/serverless/validation_test.go
deleted file mode 100644
index 49dc8996e..000000000
--- a/components/serverless/internal/controllers/serverless/validation_test.go
+++ /dev/null
@@ -1,608 +0,0 @@
-package serverless
-
-import (
- "context"
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/controllers/serverless/automock"
- serverlessResource "github.com/kyma-project/serverless/components/serverless/internal/resource"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/mock"
- "github.com/stretchr/testify/require"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/client-go/kubernetes/scheme"
- "k8s.io/client-go/tools/record"
- controllerruntime "sigs.k8s.io/controller-runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-var (
- minResourcesCfg = ResourceConfig{
- Function: FunctionResourceConfig{
- Resources: Resources{
- MinRequestedCPU: Quantity{resource.MustParse("10m")},
- MinRequestedMemory: Quantity{resource.MustParse("10Mi")},
- },
- },
- BuildJob: BuildJobResourceConfig{
- Resources: Resources{
- MinRequestedCPU: Quantity{resource.MustParse("20m")},
- MinRequestedMemory: Quantity{resource.MustParse("20Mi")},
- },
- },
- }
-)
-
-func TestValidation_Invalid(t *testing.T) {
- //GIVEN
- ctx := context.TODO()
-
- k8sClient := fake.NewClientBuilder().WithStatusSubresource(&serverlessv1alpha2.Function{}).Build()
- require.NoError(t, serverlessv1alpha2.AddToScheme(scheme.Scheme))
- resourceClient := serverlessResource.New(k8sClient, scheme.Scheme)
-
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- testCases := map[string]struct {
- fn serverlessv1alpha2.Function
- expectedCondMsg string
- }{
- "Function requests cpu are bigger than limits": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("150m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Function limits cpu(120m) should be higher than requests cpu(150m)",
- },
- "Function requests memory are bigger than limits": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("50m"),
- corev1.ResourceMemory: resource.MustParse("150Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Function limits memory(120Mi) should be higher than requests memory(150Mi)",
- },
- "Function requests cpu are smaller than minimum value": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("5m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Function request cpu(5m) should be higher than minimal value (10m)",
- },
- "Function requests memory are smaller than minimum value": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("50m"),
- corev1.ResourceMemory: resource.MustParse("5Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Function request memory(5Mi) should be higher than minimal value (10Mi)",
- },
- "Function limits cpu are smaller than minimum without requests": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("2m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- }},
- },
- },
- },
- expectedCondMsg: "Function limits cpu(2m) should be higher than minimal value (10m)",
- },
- "Function limits memory are smaller than minimum without requests": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("20m"),
- corev1.ResourceMemory: resource.MustParse("2Mi"),
- },
- }},
- },
- },
- },
- expectedCondMsg: "Function limits memory(2Mi) should be higher than minimal value (10Mi)",
- },
- //Build validation
- "Build requests cpu are bigger than limits": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("150m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Build limits cpu(120m) should be higher than requests cpu(150m)",
- },
- "Build requests memory are bigger than limits": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("50m"),
- corev1.ResourceMemory: resource.MustParse("150Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Build limits memory(120Mi) should be higher than requests memory(150Mi)",
- },
- "Build requests cpu are smaller than minimum value": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("5m"),
- corev1.ResourceMemory: resource.MustParse("50Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Build request cpu(5m) should be higher than minimal value (20m)",
- },
- "Build requests memory are smaller than minimum value": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("50m"),
- corev1.ResourceMemory: resource.MustParse("5Mi"),
- }}},
- },
- },
- },
- expectedCondMsg: "Build request memory(5Mi) should be higher than minimal value (20Mi)",
- },
- "Build limits cpu are smaller than minimum without requests": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("2m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- }},
- },
- },
- },
- expectedCondMsg: "Build limits cpu(2m) should be higher than minimal value (20m)",
- },
- "Build limits memory are smaller than minimum without requests": {
- fn: serverlessv1alpha2.Function{ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("30m"),
- corev1.ResourceMemory: resource.MustParse("2Mi"),
- },
- }},
- },
- },
- },
- expectedCondMsg: "Build limits memory(2Mi) should be higher than minimal value (20Mi)",
- },
- "Invalid env": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Env: []corev1.EnvVar{
- {Name: "1ENV"},
- {Name: "2ENV"},
- },
- },
- },
- expectedCondMsg: "spec.env: 1ENV. Err: a valid environment variable name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit (e.g. 'my.env-name', or 'MY_ENV.NAME', or 'MyEnvName1', regex used for validation is '[-._a-zA-Z][-._a-zA-Z0-9]*')",
- },
- "Invalid secretMount name": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {
- SecretName: "secret-name-1",
- MountPath: "/mount/path/1",
- },
- {
- SecretName: "invalid secret name - not DNS subdomain name as defined in RFC 1123",
- MountPath: "/mount/path/2",
- },
- },
- },
- },
- expectedCondMsg: "invalid spec.secretMounts: [a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character (e.g. 'example.com', regex used for validation is '[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*')]",
- },
- "Non unique secretMount name": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {
- SecretName: "secret-name-1",
- MountPath: "/mount/path/1",
- },
- {
- SecretName: "non-unique-secret-name",
- MountPath: "/mount/path/2",
- },
- {
- SecretName: "non-unique-secret-name",
- MountPath: "/mount/path/3",
- },
- },
- },
- },
- expectedCondMsg: "invalid spec.secretMounts: [secretNames should be unique]",
- },
- "Improper dependencies for JS": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "source code",
- Dependencies: "invalid dependencies",
- },
- },
- },
- },
- expectedCondMsg: "invalid source.inline.dependencies value: deps should start with '{' and end with '}'",
- },
- "Invalid label name": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- ".invalid-name": "value",
- },
- },
- },
- expectedCondMsg: "spec.labels: Invalid value: \".invalid-name\": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')",
- },
- "Invalid label value": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "name": ".invalid-value",
- },
- },
- },
- expectedCondMsg: "spec.labels: Invalid value: \".invalid-value\": a valid label must be an empty string or consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyValue', or 'my_value', or '12345', regex used for validation is '(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])?')",
- },
- "Invalid annotation name": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- ".invalid-name": "value",
- },
- },
- },
- expectedCondMsg: "spec.annotations: Invalid value: \".invalid-name\": name part must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character (e.g. 'MyName', or 'my.name', or '123-abc', regex used for validation is '([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]')",
- },
- "Invalid Git repository url": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "abc",
- },
- },
- },
- },
- expectedCondMsg: "source.gitRepository.URL: parse \"abc\": invalid URI for request",
- },
- "Invalid Git repository http url": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "github.com/kyma-project/kyma.git",
- },
- },
- },
- },
- expectedCondMsg: "source.gitRepository.URL: parse \"github.com/kyma-project/kyma.git\": invalid URI for request",
- },
- "Invalid Git repository ssh url": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "g0t@github.com:kyma-project/kyma.git",
- },
- },
- },
- },
- expectedCondMsg: "source.gitRepository.URL: parse \"g0t@github.com:kyma-project/kyma.git\": invalid URI for request",
- },
- }
-
- //WHEN
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- require.NoError(t, resourceClient.Create(ctx, &tc.fn))
- s := &systemState{instance: tc.fn}
- r := &reconciler{out: out{result: controllerruntime.Result{Requeue: true}},
- k8s: k8s{client: resourceClient, recorder: record.NewFakeRecorder(100), statsCollector: statsCollector},
- cfg: cfg{fn: FunctionConfig{ResourceConfig: minResourcesCfg}}}
-
- //WHEN
- nextFn, err := stateFnValidateFunction(ctx, r, s)
- require.NoError(t, err)
- _, err = nextFn(context.TODO(), r, s)
-
- //THEN
- require.NoError(t, err)
- updatedFn := serverlessv1alpha2.Function{}
- require.NoError(t, resourceClient.Get(ctx, ctrlclient.ObjectKey{Name: tc.fn.Name}, &updatedFn))
- cond := getCondition(updatedFn.Status.Conditions, serverlessv1alpha2.ConditionConfigurationReady)
- assert.Equal(t, serverlessv1alpha2.ConditionReasonFunctionSpec, cond.Reason)
- assert.Equal(t, corev1.ConditionFalse, cond.Status)
- assert.NotEmpty(t, tc.expectedCondMsg, "expected message shouldn't be empty")
- assert.Equal(t, tc.expectedCondMsg, cond.Message)
- assert.False(t, r.result.Requeue)
- })
- }
-}
-
-func TestValidation_Valid(t *testing.T) {
- //GIVEN
- ctx := context.TODO()
-
- k8sClient := fake.NewClientBuilder().Build()
- require.NoError(t, serverlessv1alpha2.AddToScheme(scheme.Scheme))
- resourceClient := serverlessResource.New(k8sClient, scheme.Scheme)
-
- statsCollector := &automock.StatsCollector{}
- statsCollector.On("UpdateReconcileStats", mock.Anything, mock.Anything).Return()
-
- testCases := map[string]struct {
- fn serverlessv1alpha2.Function
- }{
- "Valid function": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- GenerateName: "test-fn",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("120m"),
- corev1.ResourceMemory: resource.MustParse("120Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- corev1.ResourceCPU: resource.MustParse("100m"),
- corev1.ResourceMemory: resource.MustParse("100Mi"),
- }}},
- },
- Env: []corev1.EnvVar{
- {Name: "_CORRECT_ENV"},
- {Name: "ANOTHER_CORRECT_ENV"},
- },
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {
- SecretName: "secret-name",
- MountPath: "mount-path",
- },
- },
- Labels: map[string]string{
- "name1": "value1",
- "name2": "value2",
- "name3": "",
- },
- Annotations: map[string]string{
- "name1": "value1",
- "name2": "value2",
- },
- },
- },
- },
- "Dependencies for JS": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "source code",
- Dependencies: "{valid javascript dependencies}",
- },
- },
- },
- },
- },
- "Dependencies for Python": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "source code",
- Dependencies: "valid python dependencies",
- },
- },
- },
- },
- },
- "Empty dependencies": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "source code",
- },
- },
- },
- },
- },
- "Git repository URL SSH": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "git@github.com:kyma-project/serverless.git",
- },
- },
- },
- },
- },
- "Git repository URL HTTPS": {
- fn: serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{GenerateName: "test-fn"},
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- URL: "https://github.com/kyma-project/serverless.git",
- },
- },
- },
- },
- },
- }
-
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- require.NoError(t, resourceClient.Create(ctx, &tc.fn))
- s := &systemState{instance: tc.fn}
- r := &reconciler{out: out{result: controllerruntime.Result{Requeue: true}},
- k8s: k8s{client: resourceClient, recorder: record.NewFakeRecorder(100), statsCollector: statsCollector},
- cfg: cfg{fn: FunctionConfig{ResourceConfig: minResourcesCfg}}}
-
- //WHEN
- nextFn, err := stateFnValidateFunction(ctx, r, s)
- require.NoError(t, err)
- _, err = nextFn(context.TODO(), r, s)
-
- //THEN
- require.NoError(t, err)
- updatedFn := serverlessv1alpha2.Function{}
- require.NoError(t, resourceClient.Get(ctx, ctrlclient.ObjectKey{Name: tc.fn.Name}, &updatedFn))
- assert.True(t, r.result.Requeue)
-
- })
- }
-}
diff --git a/components/serverless/internal/docker/registry.go b/components/serverless/internal/docker/registry.go
deleted file mode 100644
index a82e204b2..000000000
--- a/components/serverless/internal/docker/registry.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package docker
-
-import (
- "bytes"
- "encoding/base64"
- "encoding/json"
- "errors"
- "io"
-)
-
-const (
- keyUsername = "username"
- keyPassword = "password"
- keyServerAddress = "serverAddress"
-)
-
-var (
- errUsernameNotFound = errors.New("username field not found")
- errPasswordNotFound = errors.New("password field not found")
- errServerAddressNotFound = errors.New("serverAddress field not found")
-)
-
-type registryCfgCredentials struct {
- username, password, serverAddress []byte
- provideEncoder
-}
-
-type provideEncoder func(enc *base64.Encoding, w io.Writer) io.WriteCloser
-
-func (e provideEncoder) encodeUserAndPassword(username, password []byte) (string, error) {
- var buff bytes.Buffer
- base64encoder := e(base64.StdEncoding, &buff)
- // encode username:password to buffer
- for _, bytes := range [3][]byte{
- username,
- []byte(":"),
- password,
- } {
- if _, err := base64encoder.Write(bytes); err != nil {
- return "", err
- }
- }
- // close to flush
- if err := base64encoder.Close(); err != nil {
- return "", err
- }
- return buff.String(), nil
-}
-
-func createAuthMap(usernameAndPassword string) map[string]interface{} {
- return map[string]interface{}{
- "auth": usernameAndPassword,
- }
-}
-
-func (r *registryCfgCredentials) MarshalJSON() ([]byte, error) {
- userAndPassword, err := r.provideEncoder.encodeUserAndPassword(r.username, r.password)
- if err != nil {
- return nil, err
- }
- config := map[string]interface{}{
- "auths": map[string]interface{}{
- string(r.serverAddress): createAuthMap(userAndPassword),
- },
- }
-
- return json.Marshal(&config)
-}
-
-// NewRegistryCfgMarshaler creates registry configuration marshaler
-func NewRegistryCfgMarshaler(data map[string][]byte) (json.Marshaler, error) {
- result := registryCfgCredentials{
- provideEncoder: base64.NewEncoder,
- }
- var found bool
-
- result.username, found = data[keyUsername]
- if !found {
- return nil, errUsernameNotFound
- }
-
- result.password, found = data[keyPassword]
- if !found {
- return nil, errPasswordNotFound
- }
-
- result.serverAddress, found = data[keyServerAddress]
- if !found {
- return nil, errServerAddressNotFound
- }
-
- return &result, nil
-}
diff --git a/components/serverless/internal/docker/registry_test.go b/components/serverless/internal/docker/registry_test.go
deleted file mode 100644
index 7b62bd54f..000000000
--- a/components/serverless/internal/docker/registry_test.go
+++ /dev/null
@@ -1,182 +0,0 @@
-package docker
-
-import (
- "encoding/base64"
- "errors"
- "io"
- "testing"
-
- "github.com/onsi/gomega"
-)
-
-func Test_registryCfgCredentials_MarshalJSON(t *testing.T) {
- type args struct {
- username []byte
- password []byte
- serverAddress []byte
- provideEncoder provideEncoder
- }
- tests := []struct {
- name string
- args args
- want []byte
- wantErr bool
- }{
- {
- name: "OK",
- args: args{
- username: []byte("Z1d6dDZveUU1dHhIQ3dlYWtPV2M="),
- password: []byte("eHVwNE5GRkpIRzZvTWVZd094b09xWmpBeE92QzBOWTBOZ0lzUlVYTg=="),
- serverAddress: []byte("registry.35.246.34.254.xip.io"),
- provideEncoder: base64.NewEncoder,
- },
- want: []byte(`{
- "auths": {
- "registry.35.246.34.254.xip.io": {
- "auth": "WjFkNmREWnZlVVUxZEhoSVEzZGxZV3RQVjJNPTplSFZ3TkU1R1JrcElSelp2VFdWWmQwOTRiMDl4V21wQmVFOTJRekJPV1RCT1owbHpVbFZZVGc9PQ=="
- }
- }
- }`),
- wantErr: false,
- },
- {
- name: "encoder write error",
- args: args{
- username: []byte("Z1d6dDZveUU1dHhIQ3dlYWtPV2M="),
- password: []byte("eHVwNE5GRkpIRzZvTWVZd094b09xWmpBeE92QzBOWTBOZ0lzUlVYTg=="),
- serverAddress: []byte("registry.35.246.34.254.xip.io"),
- provideEncoder: func(enc *base64.Encoding, w io.Writer) io.WriteCloser {
- return &failingWriterCloser{
- failType: failWrite,
- }
- },
- },
- wantErr: true,
- },
- {
- name: "encoder close error",
- args: args{
- username: []byte("Z1d6dDZveUU1dHhIQ3dlYWtPV2M="),
- password: []byte("eHVwNE5GRkpIRzZvTWVZd094b09xWmpBeE92QzBOWTBOZ0lzUlVYTg=="),
- serverAddress: []byte("registry.35.246.34.254.xip.io"),
- provideEncoder: func(enc *base64.Encoding, w io.Writer) io.WriteCloser {
- return &failingWriterCloser{
- failType: failClose,
- }
- },
- },
- wantErr: true,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- r := ®istryCfgCredentials{
- username: tt.args.username,
- password: tt.args.password,
- serverAddress: tt.args.serverAddress,
- provideEncoder: tt.args.provideEncoder,
- }
- got, err := r.MarshalJSON()
- if (err != nil) != tt.wantErr {
- t.Errorf("registryCfgCredentials.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- if len(tt.want) == 0 {
- return
- }
- gomega.NewWithT(t).Expect(got).To(gomega.MatchJSON(tt.want))
- })
- }
-}
-
-func TestNewRegistryCfgMarshaller(t *testing.T) {
- type args struct {
- data map[string][]byte
- }
- tests := []struct {
- name string
- args args
- wantErr bool
- }{
- {
- name: "err missing username",
- args: args{
- data: map[string][]byte{
- keyPassword: []byte("-"),
- keyServerAddress: []byte("-"),
- },
- },
- wantErr: true,
- },
- {
- name: "err missing password",
- args: args{
- data: map[string][]byte{
- keyUsername: []byte("-"),
- keyServerAddress: []byte("-"),
- },
- },
- wantErr: true,
- },
- {
- name: "err missing url",
- args: args{
- data: map[string][]byte{
- keyUsername: []byte("-"),
- keyPassword: []byte("-"),
- },
- },
- wantErr: true,
- },
- {
- name: "OK",
- args: args{
- data: map[string][]byte{
- keyUsername: []byte("-"),
- keyPassword: []byte("-"),
- keyServerAddress: []byte("-"),
- },
- },
- wantErr: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- _, err := NewRegistryCfgMarshaler(tt.args.data)
- if (err != nil) != tt.wantErr {
- t.Errorf("NewRegistryCfgMarshaler() error = %v, wantErr %v", err, tt.wantErr)
- return
- }
- })
- }
-}
-
-var (
- errWrite = errors.New("test write error")
- errClose = errors.New("test close error")
-)
-
-type failType int
-
-const (
- failWrite failType = iota
- failClose
-)
-
-type failingWriterCloser struct {
- failType
-}
-
-func (f *failingWriterCloser) Write(p []byte) (n int, err error) {
- if f.failType != failWrite {
- return len(p), nil
- }
- return -1, errWrite
-}
-
-func (f *failingWriterCloser) Close() error {
- if f.failType != failClose {
- return nil
- }
- return errClose
-}
diff --git a/components/serverless/internal/file/notify.go b/components/serverless/internal/file/notify.go
deleted file mode 100644
index 208fc2b57..000000000
--- a/components/serverless/internal/file/notify.go
+++ /dev/null
@@ -1,33 +0,0 @@
-package file
-
-import (
- "context"
-
- "github.com/fsnotify/fsnotify"
- "github.com/pkg/errors"
-)
-
-func NotifyModification(ctx context.Context, path string) error {
- watcher, err := fsnotify.NewWatcher()
- if err != nil {
- return errors.Wrap(err, "unable to create file watcher")
- }
- defer watcher.Close()
-
- if err = watcher.Add(path); err != nil {
- return errors.Wrap(err, "unable to add file to watcher")
- }
-
- return selectModification(ctx, watcher)
-}
-
-func selectModification(ctx context.Context, watcher *fsnotify.Watcher) error {
- select {
- case <-ctx.Done():
- return context.Canceled
- case <-watcher.Events:
- return nil
- case watcherError := <-watcher.Errors:
- return watcherError
- }
-}
diff --git a/components/serverless/internal/file/notify_test.go b/components/serverless/internal/file/notify_test.go
deleted file mode 100644
index 357f76af5..000000000
--- a/components/serverless/internal/file/notify_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package file
-
-import (
- "context"
- "os"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestNotifyModification(t *testing.T) {
- t.Run("react to file modification", func(t *testing.T) {
- file, err := os.CreateTemp(os.TempDir(), "test-*")
- assert.NoError(t, err)
-
- notifyErr := make(chan error)
- go func() {
- notifyErr <- NotifyModification(context.Background(), file.Name())
- }()
-
- quit := modifyFileEveryTick(t, file, 500*time.Millisecond)
-
- assert.NoError(t, <-notifyErr)
- quit <- true
- })
-
- t.Run("file does not exist", func(t *testing.T) {
- notifyErr := make(chan error)
- go func() {
- notifyErr <- NotifyModification(context.Background(), "/path/does/not/exist")
- }()
-
- err := <-notifyErr
- assert.Contains(t, err.Error(), "no such file or directory")
- })
-
- t.Run("cancel context", func(t *testing.T) {
- file, err := os.CreateTemp(os.TempDir(), "test-*")
- assert.NoError(t, err)
- defer os.Remove(file.Name())
-
- ctx, cancel := context.WithCancel(context.Background())
-
- notifyErr := make(chan error)
- go func() {
- notifyErr <- NotifyModification(ctx, file.Name())
- }()
-
- cancel()
-
- assert.Equal(t, <-notifyErr, context.Canceled)
- })
-}
-
-func modifyFileEveryTick(t *testing.T, file *os.File, interval time.Duration) chan interface{} {
- ticker := time.NewTicker(interval)
-
- quit := make(chan interface{})
- go func() {
- for {
- select {
- case <-ticker.C:
- err := os.WriteFile(file.Name(), []byte("{}"), 0o644)
- assert.NoError(t, err)
- case <-quit:
- ticker.Stop()
- return
- }
- }
- }()
-
- return quit
-}
diff --git a/components/serverless/internal/git/auth.go b/components/serverless/internal/git/auth.go
deleted file mode 100644
index 110ba7cad..000000000
--- a/components/serverless/internal/git/auth.go
+++ /dev/null
@@ -1,124 +0,0 @@
-package git
-
-import (
- "fmt"
- "strings"
-
- git2go "github.com/libgit2/git2go/v34"
- "github.com/pkg/errors"
- "golang.org/x/crypto/ssh"
-)
-
-const (
- UsernameKey = "username"
- PasswordKey = "password"
- KeyKey = "key"
-)
-
-type RepositoryAuthType string
-
-const (
- RepositoryAuthBasic RepositoryAuthType = "basic"
- RepositoryAuthSSHKey RepositoryAuthType = "key"
-)
-
-type AuthOptions struct {
- Type RepositoryAuthType
- Credentials map[string]string
- SecretName string
-}
-
-func GetAuth(options *AuthOptions) (git2go.RemoteCallbacks, error) {
- if options == nil {
- return git2go.RemoteCallbacks{}, nil
- }
-
- switch authType := options.Type; authType {
- case RepositoryAuthBasic:
- {
- username, ok := options.Credentials[UsernameKey]
- if !ok {
- return git2go.RemoteCallbacks{}, fmt.Errorf("missing field %s", UsernameKey)
-
- }
- password, ok := options.Credentials[PasswordKey]
- if !ok {
- return git2go.RemoteCallbacks{}, fmt.Errorf("missing field %s", PasswordKey)
- }
-
- return git2go.RemoteCallbacks{
- CredentialsCallback: authBasicCallback(username, password),
- }, nil
- }
- case RepositoryAuthSSHKey:
- {
- key, ok := options.Credentials[KeyKey]
- if !ok {
- return git2go.RemoteCallbacks{}, fmt.Errorf("missing field %s", KeyKey)
- }
- passphrase := options.Credentials[PasswordKey]
- var err error
- if passphrase == "" {
- _, err = ssh.ParsePrivateKey([]byte(key))
- } else {
- _, err = ssh.ParseRawPrivateKeyWithPassphrase([]byte(key), []byte(passphrase))
- }
-
- if err != nil {
- return git2go.RemoteCallbacks{}, errors.Wrapf(err, "while validation of key with passphrase set to: %t", passphrase != "")
- }
- cred, err := git2go.NewCredentialSSHKeyFromMemory("git", "", key, passphrase)
- if err != nil {
- return git2go.RemoteCallbacks{}, errors.Wrap(err, "while creating ssh credential in git2go")
- }
- return git2go.RemoteCallbacks{
- CredentialsCallback: authSSHCallback(cred),
- CertificateCheckCallback: sshCheckCallback(),
- }, nil
-
- }
- }
- return git2go.RemoteCallbacks{}, errors.Errorf("unknown authentication type: %s", options.Type)
-}
-
-func authSSHCallback(cred *git2go.Credential) func(url, username string, allowed_types git2go.CredentialType) (*git2go.Credential, error) {
- return func(url string, username_from_url string, allowed_types git2go.CredentialType) (*git2go.Credential, error) {
- return cred, nil
- }
-}
-
-func authBasicCallback(username, password string) func(url, username string, allowed_types git2go.CredentialType) (*git2go.Credential, error) {
- return func(url string, username_from_url string, allowed_types git2go.CredentialType) (*git2go.Credential, error) {
- cred, err := git2go.NewCredentialUserpassPlaintext(username, password)
- if err != nil {
- return nil, errors.Wrap(err, "while creating credentials with user and password")
- }
- return cred, nil
- }
-}
-
-func sshCheckCallback() func(cert *git2go.Certificate, valid bool, hostname string) error {
- return func(cert *git2go.Certificate, valid bool, hostname string) error {
- return nil
- }
-}
-
-func IsAuthErr(err error) bool {
- if err == nil {
- return false
- }
-
- errMsg := err.Error()
- if strings.Contains(errMsg, "unexpected http status code: 403") {
- return true
- }
-
- /*
- When using invalid personal access token with basic auth, libgit2 return such error.
- */
-
- if strings.Contains(errMsg, "too many redirects or authentication replays") {
- return true
- }
- return false
-}
diff --git a/components/serverless/internal/git/auth_test.go b/components/serverless/internal/git/auth_test.go
deleted file mode 100644
index c3a6023d3..000000000
--- a/components/serverless/internal/git/auth_test.go
+++ /dev/null
@@ -1,166 +0,0 @@
-package git_test
-
-import (
- "errors"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- "github.com/kyma-project/serverless/components/serverless/internal/git"
- "github.com/onsi/gomega"
-)
-
-func TestAuthOptions_ToAuthMethod(t *testing.T) {
- // given
- for testName, testData := range map[string]struct {
- authType git.RepositoryAuthType
- credentials map[string]string
-
- expectedCallback gomega.OmegaMatcher
- expectedCertCheck gomega.OmegaMatcher
- expectedErr gomega.OmegaMatcher
- }{
- "should be ok when basic": {
- authType: git.RepositoryAuthBasic,
- credentials: map[string]string{
- git.UsernameKey: "user",
- git.PasswordKey: "password",
- },
- expectedCallback: gomega.Not(gomega.BeNil()),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.BeNil(),
- },
- "should be ok when ssh without passphrase": {
- authType: git.RepositoryAuthSSHKey,
- credentials: map[string]string{
- git.KeyKey: testSSHPrivateKey,
- },
- expectedCallback: gomega.Not(gomega.BeNil()),
- expectedCertCheck: gomega.Not(gomega.BeNil()),
- expectedErr: gomega.BeNil(),
- },
- "should be ok when ssh with passphrase": {
- authType: git.RepositoryAuthSSHKey,
- credentials: map[string]string{
- git.PasswordKey: "test",
- git.KeyKey: testSSHPrivateKeyPassphrase,
- },
- expectedCallback: gomega.Not(gomega.BeNil()),
- expectedCertCheck: gomega.Not(gomega.BeNil()),
- expectedErr: gomega.BeNil(),
- },
- "error when invalid auth type": {
- authType: "invalid",
- credentials: map[string]string{
- git.UsernameKey: "user",
- git.PasswordKey: "password",
- },
- expectedCallback: gomega.BeNil(),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.HaveOccurred(),
- },
- "error when invalid key format": {
- authType: git.RepositoryAuthSSHKey,
- credentials: map[string]string{
- git.KeyKey: "invalid format",
- },
- expectedCallback: gomega.BeNil(),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.HaveOccurred(),
- },
- "error when missing field username in basic auth": {
- authType: git.RepositoryAuthBasic,
- credentials: map[string]string{},
- expectedCallback: gomega.BeNil(),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.HaveOccurred(),
- },
- "error when missing field password in basic auth": {
- authType: git.RepositoryAuthBasic,
- credentials: map[string]string{
- git.UsernameKey: "test",
- },
- expectedCallback: gomega.BeNil(),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.HaveOccurred(),
- },
- "error when missing fields in key auth": {
- authType: git.RepositoryAuthSSHKey,
- credentials: map[string]string{},
- expectedCallback: gomega.BeNil(),
- expectedCertCheck: gomega.BeNil(),
- expectedErr: gomega.HaveOccurred(),
- },
- } {
- t.Run(testName, func(t *testing.T) {
- g := gomega.NewWithT(t)
- options := git.AuthOptions{
- Type: testData.authType,
- Credentials: testData.credentials,
- }
-
- // when
- result, err := git.GetAuth(&options)
-
- //then
- g.Expect(err).To(testData.expectedErr)
- g.Expect(result.CredentialsCallback).To(testData.expectedCallback)
- })
- }
-
- t.Run("should return nil when AuthOptions is nil", func(t *testing.T) {
- // given
- g := gomega.NewWithT(t)
- var authOptions *git.AuthOptions
-
- // when
- result, err := git.GetAuth(authOptions)
-
- // then
- g.Expect(err).To(gomega.BeNil())
- g.Expect(result.CredentialsCallback).To(gomega.BeNil())
- g.Expect(result.CertificateCheckCallback).To(gomega.BeNil())
-
- })
-}
-
-func TestIsAuthErr(t *testing.T) {
- // GIVEN
- testCases := []struct {
- name string
- err error
- expected bool
- }{
- {
- name: "err is nil",
- err: nil,
- expected: false,
- },
- {
- name: "different error",
- err: errors.New("Internet Server Error"),
- expected: false,
- },
- {
- name: "err contains 403 error code",
- err: errors.New("nobody expected unexpected http status code: 403 while doing inquisition"),
- expected: true,
- },
- {
- name: "error contains too many redirects",
- err: errors.New("too many redirects or authentication replays while cloning repository"),
- expected: true,
- },
- }
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- //WHEN
- result := git.IsAuthErr(testCase.err)
-
- //THEN
- require.Equal(t, testCase.expected, result)
- })
-
- }
-
-}
diff --git a/components/serverless/internal/git/cloner.go b/components/serverless/internal/git/cloner.go
deleted file mode 100644
index dba9425de..000000000
--- a/components/serverless/internal/git/cloner.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package git
-
-import (
- git2go "github.com/libgit2/git2go/v34"
-)
-
-type git2goCloner struct {
-}
-
-func (g *git2goCloner) git2goClone(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error) {
- return git2go.Clone(url, outputPath, &git2go.CloneOptions{
- FetchOptions: git2go.FetchOptions{
- RemoteCallbacks: remoteCallbacks,
- DownloadTags: git2go.DownloadTagsAll,
- },
- })
-}
diff --git a/components/serverless/internal/git/const_test.go b/components/serverless/internal/git/const_test.go
deleted file mode 100644
index c00f97e5f..000000000
--- a/components/serverless/internal/git/const_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package git_test
-
-const (
- testSSHPrivateKey = `
------BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
-NhAAAAAwEAAQAAAYEA4AIFs1TeN6OT14BIMHHQ/qfmnre04VDtXLAbHO7JWEIqgQSe2uv/
-TeYal4RKoRCveb7SP0V+CWOR8HuirWnDzgZFJQy+dTyKWNpYz57dfx7VfDkzBKcGUujBzV
-1WhghlUezmm2GLS0TBpEPej6CfqZN4mD5momy2jCD6xLoCyf9G0g+yVOau+7oZZxmDn6Mr
-0YfEnqKOSoJnoJfbrxtQrJ1m4Q6ec0WbujQfEuYD91Zl9otOEL/pps4WOU7ZjBNkUeqDnT
-6QvAhemBM3/FlBHsYN4DKwlJ5vSHPfs7KOZKVmKDLTQpSkndd6/p3X6x+X/HSlkoYqUnmV
-x2/MZvWRKxNWefiMi99eSthPzViHkbyMKJl9NF0WvbEeusYhZ0rmmzI3z+6dqQKL/WDl33
-t+wKC0EO++Kkf3eHv0B2nHFrnvigHqH/RU0Atgbp++nh7h+2BTB/kuQdUTFrXnsTkgf9ZB
-e6BtLCQpooN0H1qDT0EN4yMqgpdWd8U/uOQizP4HAAAFiLVkk0u1ZJNLAAAAB3NzaC1yc2
-EAAAGBAOACBbNU3jejk9eASDBx0P6n5p63tOFQ7VywGxzuyVhCKoEEntrr/03mGpeESqEQ
-r3m+0j9FfgljkfB7oq1pw84GRSUMvnU8iljaWM+e3X8e1Xw5MwSnBlLowc1dVoYIZVHs5p
-thi0tEwaRD3o+gn6mTeJg+ZqJstowg+sS6Asn/RtIPslTmrvu6GWcZg5+jK9GHxJ6ijkqC
-Z6CX268bUKydZuEOnnNFm7o0HxLmA/dWZfaLThC/6abOFjlO2YwTZFHqg50+kLwIXpgTN/
-xZQR7GDeAysJSeb0hz37OyjmSlZigy00KUpJ3Xev6d1+sfl/x0pZKGKlJ5lcdvzGb1kSsT
-Vnn4jIvfXkrYT81Yh5G8jCiZfTRdFr2xHrrGIWdK5psyN8/unakCi/1g5d97fsCgtBDvvi
-pH93h79Adpxxa574oB6h/0VNALYG6fvp4e4ftgUwf5LkHVExa157E5IH/WQXugbSwkKaKD
-dB9ag09BDeMjKoKXVnfFP7jkIsz+BwAAAAMBAAEAAAGAZOWkSa0tVmRQgB2g5mktmLZpsw
-3N5Dr+XuRXogWQHTfYSzqYjsUDvsOpMJv+vWN1lmGz85nKdlIp9ubJVFCySEcct95wnv/A
-1NqsbAADhnGN+SEOcMcGmyuJt4WWJlL7yBXrnQsnoaR7kBCd25WetNPe2rwooHpVEvL74M
-Zj4TYhYRZ+3az2Hh4puP2OAsaNQxhjIIzZiIgKQxSDd/DWupk/MJnUFtnAlfNKF8oQ+UQq
-Mw12ASdgB6kF65Qvet90VYuRadTbSsl19qYzkPOQhDre609TYxa0/xoys02nUr3WldtbTO
-k7EqgtSY0CRaNng7UqFaWynFr+BpMNHdO9WW1a5HH9kt3AXDa3H/SPM2XQnjaArXxBGCc/
-MHQuGR39JOuE32+2BtH3Bm106no6TZpOMPBOIBn8d2kfxs+bcH2aZmvjW+McVQthoWoQBw
-R1wVD3Yy9GhIsTP/UkCis3HPDtSTpPAy/n2bEH3FbZpumgiGQ4fbQnre8GaXN9onRBAAAA
-wQCkwkR4gFgnDa7WUNO+aJQ+enpJ63C+IDudyYUOpUXup6vTbrEmMtsDBngxWWCswvb+Sn
-uNMC8Xl1PhovuMaZMTDqCDw1mTQfhNc16cI4nBpbO0O6i0Pm0iL7jH3vtT6sZUdx6SGht+
-CXfy6fvQtQXANdyziGRaQ2zDpvLdskLhxd7ibJN97VvJ14eJ6HHTo5xGHRFmaqC072QaeZ
-3mXuAVTlXcNOXNsNW07ohbmTbwx0NYWXYV0HoDGevy7JqMAVgAAADBAPOEqZwZwyb66pTY
-1K+gr66o+PJ48gPYN3uNs70zlaaL8WZ0R+4oTAcfNyM267DIrkXyB9dFB+PN0tCo21pNJ4
-FqkkRQy03BGJYpwDZADJ0E+NfqhjioxU84bCF5jBAyver6/WtXetfhVVJ2obWqrcHUPIHG
-MlG5M03FVhmNvuY2IBVmZsEfSVrmSUt1sUBR8zqNCofeeJsdVQCYxYbgtGGnMabaU0ThW0
-slHDAHBpXEpF2FfowSjtnr8lss2C19pwAAAMEA631apagO92ZE6XYEbmLR+sXe+eZDKaIC
-kisGAhi4Bp3R3bsH1AG16cgcKEENUOqg1oObSZiaFa2sxDUyPaQF4rM2wZFc047SCuSzG0
-G7w9bkKuNfd9mfJCVuYDSmxx1goEC3rK3Gi/5cT6AdS1eEiEtEh2D8/a7kfEEuvbl2MqOl
-yw0fjaRCviAdgTFgZSRM14GKN+jhcsYSMxN/m41s7E8CSJab8QAxca567LoXGFDoXS/5zp
-Ft70sxjuyFlkihAAAAEXJvb3RAMTA3NTNiZTU0YjdlAQ==
------END OPENSSH PRIVATE KEY-----`
-
- testSSHPrivateKeyPassphrase = `-----BEGIN OPENSSH PRIVATE KEY-----
-b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDf/A2W5C
-+KuGRpT9FmrZ2HAAAAEAAAAAEAAAGXAAAAB3NzaC1yc2EAAAADAQABAAABgQCq0K+d9T/p
-/BQadSYZlNMUyfdXcK5wLyN+Evpb4hJchtGMLtiTEbJ3kzC4yZ7QpwWFM+9jNa0oNbb5QJ
-pvx15tcxBJMqqaBcKqCBi0tUVNQhMmf4hz79GHpDLc6aHbGRYuV4QRWWpo9aSmWkk2o5wM
-rcxsorTTstpfxmyVEEPcybwPHbSFi1Zxwj38lUnbemLAkCLbMAxJlpyfQXvc07pcQD4/tI
-DgidtNYVS11/a3jsTQ0lEj0FMxWLgDIQo839gD27LXK6UADSdibl1cECSIhN5nyYoe3jHn
-BxJACSpTYuSKI3MErR799i+yxYgeq7jI7haMtFvRTWkrbKq/WcKlfOZE02HS2YfqoM0g7k
-Ue493/1UEcisMk2OsDbcaDDFfB59DS3t+7pP4lpxzpJ1E6HAajMAHuDQwJkb/Hw/fBqoky
-GepGxNPWxgvB0OS4/biIf6OtVjQ4JQdRFJtioj61axLfs8zmtFTt3ew7OhHCDL2haV79ws
-b9UDkl+KB5A9kAAAWQV+LfWheYgnF/2l2gmVk/XSXLZPyciXlJ92lxmBbKLfH2jhViSNox
-cRz2g7PnkkcJyZx7+H6v3+cf3vxcNCQhmTF5vRgabqY1CdFDQ8HzhUeXHsnUuTNSvex/YT
-uvydpX6pZo6P4XojXiuaDWg4zKKbDTtYzKO2CswN7z9VNvtrYyqtm2Q33uXyFp8e72R+mK
-C8gbK4q3sl327aystkaepl0il+EbnCfmcy/nuIL6Nhs8XSxa47whYJoOdI20iVWFRAnSmy
-FzlzmzrSbDEH0TDcZzYn2DSYw3hY9yjcPEN52x1VM0Sv/0myfsasQXKyp9thgbK6RcYdba
-VBcvxws1ob5L21u1tol5ZXjIG+CwVsFZ6Dpiv1S20fqtRxt3tXljeIp/zjdFzHZZ2D0u1V
-djlD5+NEAX8Gg5YuPyrjUaCEz3cvAPD8NJxQMwSACGHk8lBqBlFwD2YRFJUvOL2OhApOtT
-PmJC7/ClZt0WX16MJINpAKmcv2ICvcybWoPIhGuj2LvzgfWrIXTWFQ8qejy4d90vx0lHTg
-2pss/qdkefS5lrSZ2pBEo4+fEBoGPbBgy0IcjvWUh8w6ekN8SKGRt/DFfy6Tyu2cbpDPYU
-eZaLMlq1HoiU4RJu7N5ajUSXb/QJkWrtawg9zGLZ+8Lp0tVTv4Klh1S6mAtxn0Q+ZyW7WX
-EkzYPdhUQIZd8YYKzC7TxTtEoR62a7OCx/3dFKy4BJu+hsZLUqBsq6+/5UbBVwMcnTLlcZ
-5yd9sbDBzNT5S+rVblvit+Ew7x8IQXKNxGrN7te8QU4zHIJye8jjb32WHdENLLZj3pP1Sa
-q+KrcRp3uiRxIXT/TYACrJdgtHOAEoaR0Js5ED3eqDdXUHjOXsjX09zeAnDzw+7riSdTDq
-7GLHnn1Wa6XszZL0LjrgL/kqhZJfxOBfZ2R1AoDemjHUMzp4u77B9/zDcXt5aATJT2iFD5
-yAlBBER28hRDMOjF56Nxquutcb5e1bC9AjUucCMx8yRwjoOYQCDH2XgdogIG+ApuaVWmQP
-XjaCNkvzxcABgso9yLnLFD3HlpEOcs2AUlndckvnVBGLsuek+6EXH6nHzyTpI1wtuUHT6J
-IlAhqi951J/QFnkYLzFtt/SYY1ylD85Wz6IiY83lDG2nCWpgun3WyjjYpR3waevIuTgN7U
-CCfKJx4UwlBMLYPG/73xhgJfpqZQUNU7Pf080MIAdKnkoFgAuHJlmD7iwvV9OSAcQYmp6Q
-PdFmfXqH91qfsovhE5RJE5YuGL/A+AFLEQzjIRSTzkX8BawkTzH+Z3tyYVIyGSCMhwjsc4
-DnHLHfivygDXXUHXheZYq1KNHl+8OslZBK4RSc0dBhVJQYqN1AHe1Wgjn1um7RHNN3j1e1
-fhkBoIE2bqBDE5EGCV3+I79OOr68+6+Er11+LLPVsdmD2vHnoQcOqpcIYsFzWccjMMbWMB
-ntXKzLgrFiEFelAfl9daQFgdkfapdJSRAcI6/0+HrEiLKMDbOhEShNXUzqhyuHLS+IaKGj
-nwjC/ffWNDkjzSnl6pR7/MGQT2VH5wL8xBuhyVOfRsN5CYbgFDvqgX8A4OdGJD2d8iiR7/
-5/MhFmwPQ+QS8roFhPGSOvmx0opPZSyEEV5Iq7gLTEJLpZHMMoAZlbTYZ5LEf1BjIVMSuc
-Inn7pR1V190FbQRUydWVXPLHbY8gaGKeXyetKTIHLRq0DCS+xtepZ7rQYlCP5WcAAZ+S/P
-PBm9+i69vLWwWJK+FsEJv2jdkcYa1EBj1EqLyRFSYMCGdGXN2J3GjwMbKrpWNiIWoRb/Gi
-1hGrLFK26NngO9w0gwYObhqsEXWJkWQUhkperQL56ZST41lRCA/wWHQh63Z1Gou5BEfl9m
-bJOkA627VTiLKjoJTfnnYQ6KcnM=
------END OPENSSH PRIVATE KEY-----`
-)
diff --git a/components/serverless/internal/git/errors.go b/components/serverless/internal/git/errors.go
deleted file mode 100644
index c27ab8aea..000000000
--- a/components/serverless/internal/git/errors.go
+++ /dev/null
@@ -1,39 +0,0 @@
-package git
-
-import (
- "errors"
-
- git2go "github.com/libgit2/git2go/v34"
-)
-
-// Unrecoverable means that something is wrong with configuration of git function CR
-// and cannot be fixed without changing the function cr. For example, branch doesn't exist.
-var notRecoverableErrors = []git2go.ErrorCode{
- git2go.ErrorCodeNotFound, git2go.ErrorCodeInvalidSpec,
-}
-
-func IsNotRecoverableError(err error) bool {
- gitErr := getGitErr(err)
- if gitErr == nil {
- return false
- }
-
- for _, errCode := range notRecoverableErrors {
- if gitErr.Code == errCode {
- return true
- }
- }
- return false
-}
-
-func getGitErr(err error) *git2go.GitError {
- gitErr, ok := err.(*git2go.GitError)
- if ok {
- return gitErr
- }
- unwrappedErr := errors.Unwrap(err)
- if unwrappedErr != nil {
- return getGitErr(unwrappedErr)
- }
- return nil
-}
diff --git a/components/serverless/internal/git/errors_test.go b/components/serverless/internal/git/errors_test.go
deleted file mode 100644
index 9f584fa9a..000000000
--- a/components/serverless/internal/git/errors_test.go
+++ /dev/null
@@ -1,38 +0,0 @@
-package git
-
-import (
- "testing"
-
- git2go "github.com/libgit2/git2go/v34"
- "github.com/pkg/errors"
- "github.com/stretchr/testify/require"
-)
-
-func TestIsNotRecoverableError(t *testing.T) {
- t.Run("Error is unrecoverable", func(t *testing.T) {
- //GIVEN
- err := git2go.MakeGitError2(int(git2go.ErrorCodeNotFound))
- err = errors.Wrap(err, "first")
- err = errors.Wrap(err, "second")
- err = errors.Wrap(err, "third")
- //WHEN
-
- res := IsNotRecoverableError(err)
-
- //THEN
- require.True(t, res)
- })
-
- t.Run("Generic recoverable error", func(t *testing.T) {
- //GIVEN
- err := errors.New("first")
- err = errors.Wrap(err, "second")
- err = errors.Wrap(err, "third")
-
- //WHEN
- res := IsNotRecoverableError(err)
-
- //THEN
- require.False(t, res)
- })
-}
diff --git a/components/serverless/internal/git/fetcher.go b/components/serverless/internal/git/fetcher.go
deleted file mode 100644
index 7baedfcdf..000000000
--- a/components/serverless/internal/git/fetcher.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package git
-
-import (
- git2go "github.com/libgit2/git2go/v34"
- "github.com/pkg/errors"
- "go.uber.org/zap"
-)
-
-type git2goFetcher struct {
- logger *zap.SugaredLogger
-}
-
-func (g *git2goFetcher) git2goFetch(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error) {
- repo, err := g.openInitRepo(outputPath)
- if err != nil {
- return nil, errors.Wrap(err, "while initializing/opening repository")
- }
-
- remote, err := g.lookupCreateRemote(repo, url, outputPath)
- if err != nil {
- return nil, errors.Wrap(err, "while creating/using remote")
- }
- defer remote.Free()
-
- err = remote.Fetch(nil,
- &git2go.FetchOptions{
- RemoteCallbacks: remoteCallbacks,
- DownloadTags: git2go.DownloadTagsAll,
- }, "")
- if err != nil {
- return nil, errors.Wrap(err, "while fetching remote")
- }
- return repo, nil
-}
-
-func (g *git2goFetcher) openInitRepo(outputPath string) (*git2go.Repository, error) {
- var repo *git2go.Repository
- var err error
- repo, err = git2go.OpenRepository(outputPath)
- if err == nil {
- return repo, nil
- }
- g.logger.Errorf("failed to open existing repo at [%s]: %v", outputPath, err)
- return git2go.InitRepository(outputPath, true)
-}
-
-func (g *git2goFetcher) lookupCreateRemote(repo *git2go.Repository, url, outputPath string) (*git2go.Remote, error) {
- remote, err := repo.Remotes.Lookup("origin")
- if err == nil {
- return remote, nil
- }
- g.logger.Errorf("failed to use existing origin remote at [%s]: %v", outputPath, err)
- return repo.Remotes.Create("origin", url)
-}
diff --git a/components/serverless/internal/git/go2git.go b/components/serverless/internal/git/go2git.go
deleted file mode 100644
index 697d9aefc..000000000
--- a/components/serverless/internal/git/go2git.go
+++ /dev/null
@@ -1,205 +0,0 @@
-package git
-
-import (
- "crypto/md5"
- "fmt"
- "os"
- "path"
- "strings"
-
- git2go "github.com/libgit2/git2go/v34"
- "github.com/pkg/errors"
- "go.uber.org/zap"
-)
-
-const (
- tempDir = "/tmp"
- branchRefPattern = "refs/remotes/origin"
-)
-
-type GitClient interface {
- LastCommit(options Options) (string, error)
- Clone(path string, options Options) (string, error)
-}
-
-var _ GitClient = &git2GoClient{}
-
-type GitClientFactory struct {
-}
-
-func (f GitClientFactory) GetGitClient(logger *zap.SugaredLogger) GitClient {
- return NewGit2Go(logger)
-}
-
-type Options struct {
- URL string
- Reference string
- Auth *AuthOptions
-}
-
-type cloner interface {
- git2goClone(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error)
-}
-
-type fetcher interface {
- git2goFetch(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error)
-}
-
-type git2GoClient struct {
- cloner
- fetcher
-}
-
-func NewGit2Go(logger *zap.SugaredLogger) *git2GoClient {
- return &git2GoClient{
- cloner: &git2goCloner{},
- fetcher: &git2goFetcher{logger: logger},
- }
-}
-
-func mkRepoDir(options Options) (string, error) {
- nameHash := md5.Sum([]byte(options.URL))
- repoPath := path.Join(tempDir, fmt.Sprintf("%x", nameHash))
-
- err := os.MkdirAll(repoPath, 0700)
- return repoPath, err
-}
-
-func (g *git2GoClient) LastCommit(options Options) (string, error) {
- //commit
- _, err := git2go.NewOid(options.Reference)
- if err == nil {
- return options.Reference, nil
- }
-
- // TODO: This is NOT thread safe. If we ever decide to go with more than one worker, we need to refactor this. But for now it's fine.
- repoDir, err := mkRepoDir(options)
- if err != nil {
- return "", errors.Wrap(err, "while creating temporary directory")
- }
- repo, err := g.fetchRepo(options, repoDir)
- if err != nil {
- return "", errors.Wrap(err, "while fetching the repository")
- }
- defer repo.Free()
- //branch
- ref, err := g.lookupBranch(repo, options.Reference)
- if err == nil {
- return ref.Target().String(), nil
- }
- if !git2go.IsErrorCode(err, git2go.ErrorCodeNotFound) {
- return "", errors.Wrap(err, "while lookup branch")
- }
- //tag
- commit, err := g.lookupTag(repo, options.Reference)
- if err != nil {
- return "", errors.Wrap(err, "while lookup tag")
- }
- return commit.Id().String(), nil
-}
-
-func (g *git2GoClient) Clone(path string, options Options) (string, error) {
- repo, err := g.cloneRepo(options, path)
- if err != nil {
- return "", errors.Wrap(err, "while cloning the repository")
- }
- defer repo.Free()
-
- oid, err := git2go.NewOid(options.Reference)
- if err != nil {
- return "", errors.Wrap(err, "while creating oid from reference")
- }
-
- commit, err := repo.LookupCommit(oid)
- if err != nil {
- return "", errors.Wrap(err, "while lookup for commit")
- }
-
- err = repo.ResetToCommit(commit, git2go.ResetHard, &git2go.CheckoutOptions{})
- if err != nil {
- return "", errors.Wrap(err, "while resetting to commit")
- }
-
- ref, err := repo.Head()
- if err != nil {
- return "", errors.Wrap(err, "while getting head")
- }
-
- return ref.Target().String(), nil
-}
-
-func (g *git2GoClient) cloneRepo(opts Options, path string) (*git2go.Repository, error) {
- authCallbacks, err := GetAuth(opts.Auth)
- if err != nil {
- return nil, errors.Wrap(err, "while getting authentication opts")
- }
- return g.git2goClone(opts.URL, path, authCallbacks)
-}
-func (g *git2GoClient) fetchRepo(opts Options, path string) (*git2go.Repository, error) {
- authCallbacks, err := GetAuth(opts.Auth)
- if err != nil {
- return nil, errors.Wrap(err, "while getting authentication opts")
- }
- return g.git2goFetch(opts.URL, path, authCallbacks)
-}
-
-func (g *git2GoClient) lookupBranch(repo *git2go.Repository, branchName string) (*git2go.Reference, error) {
- iter, err := repo.NewReferenceIterator()
- if err != nil {
- return nil, errors.Wrap(err, "while creating reference iterator")
- }
- for {
- item, err := iter.Next()
- if err != nil {
- if git2go.IsErrorCode(err, git2go.ErrorCodeIterOver) {
- return nil, git2go.MakeGitError2(int(git2go.ErrorCodeNotFound))
- }
- return nil, errors.Wrap(err, "while listing reference")
- }
- if g.isBranch(item, branchName) {
- return item, nil
- }
- }
-}
-
-func (g *git2GoClient) isBranch(ref *git2go.Reference, branchName string) bool {
- if strings.Contains(ref.Name(), branchRefPattern) {
- splittedName := strings.Split(ref.Name(), "/")
- if len(splittedName) < 4 {
- return false
- }
- return splittedName[3] == branchName
- }
- return false
-}
-
-/*
-Some repositories like bitbucket set tags in different way.
-The tag has reference to object, not to commit.
-Using this reference we can checkout head to it. From head we can extract commit id.
-This method will also works with repositories like GitLab in which the tag is reference to the commit.
-The reference has the same id as commit and won't produce errors
-*/
-func (g *git2GoClient) lookupTag(repo *git2go.Repository, tagName string) (*git2go.Commit, error) {
- ref, err := repo.References.Dwim(tagName)
- if err != nil {
- if git2go.IsErrorCode(err, git2go.ErrorCodeNotFound) {
- return nil, err
- }
- return nil, errors.Wrap(err, "while creating dwim from tag name")
- }
-
- if err = repo.SetHeadDetached(ref.Target()); err != nil {
- return nil, errors.Wrapf(err, "while checkout to ref: %s", ref.Target().String())
- }
- head, err := repo.Head()
- if err != nil {
- return nil, errors.Wrap(err, "while getting head")
- }
-
- commit, err := repo.LookupCommit(head.Target())
- if err != nil {
- return nil, errors.Wrap(err, "while getting commit from head")
- }
- return commit, nil
-}
diff --git a/components/serverless/internal/git/go2git_test.go b/components/serverless/internal/git/go2git_test.go
deleted file mode 100644
index 4f90a050b..000000000
--- a/components/serverless/internal/git/go2git_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package git
-
-import (
- "archive/tar"
- "errors"
- "io"
- "os"
- "path/filepath"
- "testing"
-
- git2go "github.com/libgit2/git2go/v34"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap"
-)
-
-const (
- tarGitRepoPath = "./testdata"
- tarGitName = "test-repo.tar"
- branchName = "branch2"
- branchCommit = "728c47705dabc65c12583ff5feb2e5300983afc3"
- tagName = "tag1"
- trickyTagName = "tricky1"
- tagCommit = "6eff122e8afb57a6f270285dc3bfcc9a4ef4b8ad"
- secondCommitID = "8b27a9d6f148533773ae0666dc27c5b359b46553"
-
- azureRepo = "https://kyma-wookiee@dev.azure.com/kyma-wookiee/kyma-function/_git/kyma-function"
- azureTag = "python-tag"
- azureCommit = "6dac23dd3b697970cf351101ff5c3e9733c2bdfc"
-)
-
-func TestNewGit2Go_LastCommit(t *testing.T) {
- //GIVEN
- testCases := []struct {
- name string
- refName string
- expectedCommitID string
- expectedError error
- }{
- {
- name: "Success branch name",
- refName: branchName,
- expectedCommitID: branchCommit,
- },
- {
- name: "Success tag name",
- refName: tagName,
- expectedCommitID: tagCommit,
- },
- {
- name: "Success commit",
- refName: tagCommit,
- expectedCommitID: tagCommit,
- },
- {
- name: "Success, tricky tag name from bitbucket",
- refName: trickyTagName,
- expectedCommitID: branchCommit,
- },
- {
- name: "Return error when not found",
- refName: "testcase",
- expectedCommitID: "11111705dabc65c12583ff5feb2e5300983afc3",
- expectedError: errors.New("while lookup tag: no reference found for shorthand 'testcase'"),
- },
- }
-
- for _, testcase := range testCases {
- t.Run(testcase.name, func(t *testing.T) {
- repoPath := prepareRepo(t)
- defer deleteTmpRepo(t, repoPath)
- fetcher := &git2goFetcherMock{repoPath: repoPath}
-
- opts := Options{Reference: testcase.refName, URL: repoPath}
- client := git2GoClient{fetcher: fetcher}
- //WHEN
- commitID, err := client.LastCommit(opts)
-
- //THEN
- if testcase.expectedError == nil {
- require.NoError(t, err)
- assert.Equal(t, testcase.expectedCommitID, commitID)
- } else {
- require.Error(t, err)
- assert.EqualError(t, testcase.expectedError, err.Error())
- }
- })
- }
-}
-
-func TestNewGit2Go_LastCommitWithAzureTag(t *testing.T) {
- //GIVEN
- client := NewGit2Go(zap.L().Sugar())
-
- //WHEN
- commitID, err := client.LastCommit(Options{
- URL: azureRepo,
- Reference: azureTag,
- })
- //THEN
- require.NoError(t, err)
- assert.Equal(t, azureCommit, commitID)
-}
-
-func TestGo2GitClient_Clone(t *testing.T) {
- //GIVEN
- repoPath := prepareRepo(t)
- defer deleteTmpRepo(t, repoPath)
- cloner := &git2goClonerMock{repoPath: repoPath}
- assertHeadCommitNotEqual(t, repoPath, secondCommitID)
-
- client := git2GoClient{cloner: cloner}
- opts := Options{Reference: secondCommitID}
- //WHEN
- commitID, err := client.Clone("", opts)
-
- // THEN
- require.NoError(t, err)
- assert.Equal(t, secondCommitID, commitID)
-}
-
-type git2goClonerMock struct {
- repoPath string
-}
-
-func (g *git2goClonerMock) git2goClone(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error) {
- return git2go.OpenRepository(g.repoPath)
-}
-
-type git2goFetcherMock struct {
- repoPath string
-}
-
-func (g *git2goFetcherMock) git2goFetch(url, outputPath string, remoteCallbacks git2go.RemoteCallbacks) (*git2go.Repository, error) {
- return git2go.OpenRepository(g.repoPath)
-}
-
-func prepareRepo(t *testing.T) string {
- f, err := os.Open(filepath.Join(tarGitRepoPath, tarGitName))
- require.NoError(t, err)
- defer closeAssert(t, f.Close)
- r := tar.NewReader(f)
- for {
- h, err := r.Next()
- if err == io.EOF {
- break
- } else {
- require.NoError(t, err)
- }
- //nolint:gosec
- path := filepath.Join(tarGitRepoPath, h.Name)
- info := h.FileInfo()
- if info.IsDir() {
- err = os.Mkdir(path, info.Mode())
- require.NoError(t, err)
- continue
- }
- f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, info.Mode())
- require.NoError(t, err)
- defer closeAssert(t, f.Close)
- //nolint:gosec
- _, err = io.Copy(f, r)
- require.NoError(t, err)
- }
-
- return filepath.Join(tarGitRepoPath, "test-repo")
-}
-
-func closeAssert(t *testing.T, fn func() error) {
- require.NoError(t, fn())
-}
-
-func deleteTmpRepo(t *testing.T, tmpPath string) {
- err := os.RemoveAll(tmpPath)
- require.NoError(t, err)
-}
-
-func assertHeadCommitNotEqual(t *testing.T, repoPath, commit string) {
- cloner := &git2goClonerMock{repoPath: repoPath}
- repo, err := cloner.git2goClone("", "", git2go.RemoteCallbacks{})
- require.NoError(t, err)
- head, err := repo.Head()
- require.NoError(t, err)
- assert.NotEqual(t, head.Target().String(), commit)
-}
diff --git a/components/serverless/internal/git/testdata/test-repo.tar b/components/serverless/internal/git/testdata/test-repo.tar
deleted file mode 100644
index 6a1c43b83..000000000
Binary files a/components/serverless/internal/git/testdata/test-repo.tar and /dev/null differ
diff --git a/components/serverless/internal/logging/dynamic.go b/components/serverless/internal/logging/dynamic.go
deleted file mode 100644
index 9789b0613..000000000
--- a/components/serverless/internal/logging/dynamic.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package logging
-
-import (
- "context"
-
- "github.com/kyma-project/serverless/components/serverless/internal/config"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
-)
-
-func ReconfigureOnConfigChange(ctx context.Context, log *zap.SugaredLogger, atomic zap.AtomicLevel, cfgPath string) {
- config.RunOnConfigChange(ctx, log, cfgPath, func(cfg config.Config) {
- level, err := zapcore.ParseLevel(cfg.LogLevel)
- if err != nil {
- log.Error(err)
- return
- }
-
- atomic.SetLevel(level)
- log.Infof("loggers reconfigured with level '%s' and format '%s'", cfg.LogLevel, cfg.LogFormat)
- })
-}
diff --git a/components/serverless/internal/logging/logger/format.go b/components/serverless/internal/logging/logger/format.go
deleted file mode 100644
index 032e614e8..000000000
--- a/components/serverless/internal/logging/logger/format.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package logger
-
-import (
- "errors"
- "fmt"
-
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
-)
-
-type Format string
-
-const (
- JSON Format = "json"
- TEXT Format = "text"
-)
-
-var allFormats = []Format{JSON, TEXT}
-
-func MapFormat(input string) (Format, error) {
- var format = Format(input)
- switch format {
- case JSON, TEXT:
- return format, nil
- default:
- return format, fmt.Errorf("given log format: %s, doesn't match with any of %v", format, allFormats)
- }
-}
-
-func (f Format) ToZapEncoder() (zapcore.Encoder, error) {
- encoderConfig := zap.NewProductionEncoderConfig()
- encoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder
- encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
- encoderConfig.TimeKey = "timestamp"
- encoderConfig.MessageKey = "message"
- switch f {
- case JSON:
- return zapcore.NewJSONEncoder(encoderConfig), nil
- case TEXT:
- return zapcore.NewConsoleEncoder(encoderConfig), nil
- default:
- return nil, errors.New("unknown encoder")
- }
-}
diff --git a/components/serverless/internal/logging/logger/format_test.go b/components/serverless/internal/logging/logger/format_test.go
deleted file mode 100644
index 20d9f0b29..000000000
--- a/components/serverless/internal/logging/logger/format_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package logger_test
-
-import (
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/logging/logger"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestFormatMapping(t *testing.T) {
-
- testCases := []struct {
- name string
- input string
- expected logger.Format
- expectedErr bool
- }{
- {
- name: "text format",
- input: "text",
- expected: logger.TEXT,
- expectedErr: false,
- },
- {
- name: "json format",
- input: "json",
- expected: logger.JSON,
- expectedErr: false,
- },
- {
- name: "not existing format",
- input: "csv",
- expectedErr: true,
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- //WHEN
-
- output, err := logger.MapFormat(testCase.input)
-
- //THEN
- if !testCase.expectedErr {
- assert.Equal(t, testCase.expected, output)
- require.NoError(t, err)
- } else {
- require.Error(t, err)
- }
-
- })
- }
-}
diff --git a/components/serverless/internal/logging/logger/level.go b/components/serverless/internal/logging/logger/level.go
deleted file mode 100644
index 089013835..000000000
--- a/components/serverless/internal/logging/logger/level.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package logger
-
-import (
- "errors"
- "fmt"
-
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
-)
-
-type Level string
-
-const (
- DEBUG Level = "debug"
- INFO Level = "info"
- WARN Level = "warn"
- ERROR Level = "error"
- FATAL Level = "fatal"
-)
-
-var allLevels = []Level{DEBUG, INFO, WARN, ERROR, FATAL}
-
-func MapLevel(level string) (Level, error) {
- var lvl = Level(level)
-
- switch lvl {
- case DEBUG, INFO, WARN, ERROR, FATAL:
- return lvl, nil
- default:
- return lvl, fmt.Errorf("given log level: %s, doesn't match with any of %v", level, allLevels)
- }
-}
-
-func (l Level) ToZapLevel() (zapcore.Level, error) {
- switch l {
- case DEBUG:
- return zap.DebugLevel, nil
- case INFO:
- return zap.InfoLevel, nil
- case WARN:
- return zap.WarnLevel, nil
- case ERROR:
- return zap.ErrorLevel, nil
- case FATAL:
- return zap.FatalLevel, nil
- default:
- return zap.DebugLevel, errors.New("unknown level")
- }
-}
diff --git a/components/serverless/internal/logging/logger/level_test.go b/components/serverless/internal/logging/logger/level_test.go
deleted file mode 100644
index 8803786c8..000000000
--- a/components/serverless/internal/logging/logger/level_test.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package logger_test
-
-import (
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/logging/logger"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestLevelMapping(t *testing.T) {
-
- testCases := []struct {
- name string
- input string
- expected logger.Level
- expectedErr bool
- }{
- {
- name: "debug level",
- input: "debug",
- expected: logger.DEBUG,
- expectedErr: false,
- },
- {
- name: "info level",
- input: "info",
- expected: logger.INFO,
- expectedErr: false,
- },
- {
- name: "warn level",
- input: "warn",
- expected: logger.WARN,
- expectedErr: false,
- },
- {
- name: "error level",
- input: "error",
- expected: logger.ERROR,
- expectedErr: false,
- },
- {
- name: "not existing level",
- input: "level",
- expectedErr: true,
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- //WHEN
-
- output, err := logger.MapLevel(testCase.input)
-
- //THEN
- if !testCase.expectedErr {
- assert.Equal(t, testCase.expected, output)
- require.NoError(t, err)
- } else {
- require.Error(t, err)
- }
-
- })
- }
-}
diff --git a/components/serverless/internal/logging/logger/logger.go b/components/serverless/internal/logging/logger/logger.go
deleted file mode 100644
index 395cf937d..000000000
--- a/components/serverless/internal/logging/logger/logger.go
+++ /dev/null
@@ -1,96 +0,0 @@
-package logger
-
-import (
- "context"
- "os"
-
- "github.com/pkg/errors"
-
- "github.com/go-logr/zapr"
- "github.com/kyma-project/serverless/components/serverless/internal/logging/tracing"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "k8s.io/klog/v2"
-)
-
-type Logger struct {
- zapLogger *zap.SugaredLogger
-}
-
-/*
-This function creates logger structure based on given format, atomicLevel and additional cores
-AtomicLevel structure allows to change level dynamically
-*/
-func NewWithAtomicLevel(format Format, atomicLevel zap.AtomicLevel, additionalCores ...zapcore.Core) (*Logger, error) {
- return new(format, atomicLevel, additionalCores...)
-}
-
-/*
-This function creates logger structure based on given format, level and additional cores
-*/
-func New(format Format, level Level, additionalCores ...zapcore.Core) (*Logger, error) {
- filterLevel, err := level.ToZapLevel()
- if err != nil {
- return nil, errors.Wrap(err, "while getting zap log level")
- }
-
- levelEnabler := zap.LevelEnablerFunc(func(incomingLevel zapcore.Level) bool {
- return incomingLevel >= filterLevel
- })
-
- return new(format, levelEnabler, additionalCores...)
-}
-
-func new(format Format, levelEnabler zapcore.LevelEnabler, additionalCores ...zapcore.Core) (*Logger, error) {
- encoder, err := format.ToZapEncoder()
- if err != nil {
- return nil, errors.Wrapf(err, "while getting encoding configuration for %s format", format)
- }
-
- defaultCore := zapcore.NewCore(
- encoder,
- zapcore.Lock(os.Stderr),
- levelEnabler,
- )
- cores := append(additionalCores, defaultCore)
- return &Logger{zap.New(zapcore.NewTee(cores...), zap.AddCaller()).Sugar()}, nil
-}
-
-func (l *Logger) WithTracing(ctx context.Context) *zap.SugaredLogger {
- newLogger := *l
- for key, val := range tracing.GetMetadata(ctx) {
- newLogger.zapLogger = newLogger.zapLogger.With(key, val)
- }
-
- return newLogger.WithContext()
-}
-
-func (l *Logger) WithContext() *zap.SugaredLogger {
- return l.zapLogger.With(zap.Namespace("context"))
-}
-
-/*
-By default the Fatal Error log will be in json format, because it's production default.
-*/
-func LogFatalError(format string, args ...interface{}) error {
- logger, err := New(JSON, ERROR)
- if err != nil {
- return errors.Wrap(err, "while getting Error Json Logger")
- }
- logger.zapLogger.Fatalf(format, args...)
- return nil
-}
-
-/*
-This function initialize klog which is used in k8s/go-client
-*/
-func InitKlog(log *Logger, level Level) error {
- zaprLogger := zapr.NewLogger(log.WithContext().Desugar())
- lvl, err := level.ToZapLevel()
- if err != nil {
- return errors.Wrap(err, "while getting zap log level")
- }
- zaprLogger.V((int)(lvl))
- klog.SetLogger(zaprLogger)
- return nil
-}
diff --git a/components/serverless/internal/logging/logger/logger_test.go b/components/serverless/internal/logging/logger/logger_test.go
deleted file mode 100644
index c30f53901..000000000
--- a/components/serverless/internal/logging/logger/logger_test.go
+++ /dev/null
@@ -1,207 +0,0 @@
-package logger_test
-
-import (
- "bytes"
- "context"
- "encoding/json"
- "io"
- "os"
- "strings"
- "testing"
- "time"
-
- "github.com/kyma-project/serverless/components/serverless/internal/logging/logger"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.uber.org/zap"
- "go.uber.org/zap/zapcore"
- "go.uber.org/zap/zaptest/observer"
-)
-
-type logEntry struct {
- Context map[string]string `json:"context"`
- Msg string `json:"message"`
- TraceID string `json:"traceid"`
- SpanID string `json:"spanid"`
- Timestamp string `json:"timestamp"`
- Level string `json:"level"`
- Caller string `json:"caller"`
-}
-
-func TestLogger(t *testing.T) {
- t.Run("should log anything", func(t *testing.T) {
- // given
- core, observedLogs := observer.New(zap.DebugLevel)
- log, err := logger.New(logger.JSON, logger.DEBUG, core)
- require.NoError(t, err)
- zapLogger := log.WithContext()
- // when
- zapLogger.Desugar().WithOptions(zap.AddCaller())
- zapLogger.Debug("something")
-
- // then
- require.NotEqual(t, 0, observedLogs.Len())
- t.Log(observedLogs.All())
- })
-
- t.Run("should log debug log after changing atomic level", func(t *testing.T) {
- // given
- atomic := zap.NewAtomicLevel()
- atomic.SetLevel(zapcore.WarnLevel)
- core, observedLogs := observer.New(atomic)
- log, err := logger.NewWithAtomicLevel(logger.JSON, atomic, core)
- require.NoError(t, err)
- zapLogger := log.WithContext()
-
- // when
- zapLogger.Info("log anything")
- require.Equal(t, 0, observedLogs.Len())
-
- atomic.SetLevel(zapcore.InfoLevel)
- zapLogger.Info("log anything 2")
-
- // then
- require.Equal(t, 1, observedLogs.Len())
- })
-
- t.Run("should log in the right json format", func(t *testing.T) {
- // GIVEN
- oldStdErr := os.Stderr
- defer rollbackStderr(oldStdErr)
- r, w, err := os.Pipe()
- require.NoError(t, err)
- os.Stderr = w
-
- log, err := logger.New(logger.JSON, logger.DEBUG)
- require.NoError(t, err)
-
- ctx := fixContext(map[string]string{"traceid": "trace", "spanid": "span"})
- // WHEN
- log.WithTracing(ctx).With("key", "value").Info("example message")
-
- // THEN
- err = w.Close()
- require.NoError(t, err)
- var buf bytes.Buffer
- _, err = io.Copy(&buf, r)
- require.NoError(t, err)
-
- require.NotEqual(t, 0, buf.Len())
- var entry = logEntry{}
- strictEncoder := json.NewDecoder(strings.NewReader(buf.String()))
- strictEncoder.DisallowUnknownFields()
- err = strictEncoder.Decode(&entry)
- require.NoError(t, err)
-
- assert.Equal(t, "INFO", entry.Level)
- assert.Equal(t, "example message", entry.Msg)
- assert.Equal(t, "trace", entry.TraceID)
- assert.Equal(t, "span", entry.SpanID)
- assert.Contains(t, entry.Caller, "logger_test.go")
-
- assert.NotEmpty(t, entry.Timestamp)
- _, err = time.Parse(time.RFC3339, entry.Timestamp)
- assert.NoError(t, err)
- })
-
- t.Run("should log in total separation", func(t *testing.T) {
- oldStdErr := os.Stderr
- defer rollbackStderr(oldStdErr)
- r, w, err := os.Pipe()
- require.NoError(t, err)
- os.Stderr = w
-
- log, err := logger.New(logger.JSON, logger.DEBUG)
- require.NoError(t, err)
- ctx := fixContext(map[string]string{"traceid": "trace", "spanid": "span"})
-
- // WHEN
- log.WithTracing(ctx).With("key", "first").Info("first message")
- log.WithContext().With("key", "second").Error("second message")
-
- // THEN
- err = w.Close()
- require.NoError(t, err)
- var buf bytes.Buffer
- _, err = io.Copy(&buf, r)
- require.NoError(t, err)
-
- require.NotEqual(t, 0, buf.Len())
-
- logs := strings.Split(buf.String(), "\n")
-
- require.Len(t, logs, 3) // 3rd line is new empty line
-
- var infoEntry = logEntry{}
- strictEncoder := json.NewDecoder(strings.NewReader(logs[0]))
- strictEncoder.DisallowUnknownFields()
- err = strictEncoder.Decode(&infoEntry)
- require.NoError(t, err)
-
- assert.Equal(t, "INFO", infoEntry.Level)
- assert.Equal(t, "first message", infoEntry.Msg)
- assert.EqualValues(t, map[string]string{"key": "first"}, infoEntry.Context, 0.0)
- assert.Equal(t, "span", infoEntry.SpanID)
- assert.Equal(t, "trace", infoEntry.TraceID)
-
- assert.NotEmpty(t, infoEntry.Timestamp)
- _, err = time.Parse(time.RFC3339, infoEntry.Timestamp)
- assert.NoError(t, err)
-
- strictEncoder = json.NewDecoder(strings.NewReader(logs[1]))
- strictEncoder.DisallowUnknownFields()
-
- var errorEntry = logEntry{}
- err = strictEncoder.Decode(&errorEntry)
- require.NoError(t, err)
- assert.Equal(t, "ERROR", errorEntry.Level)
- assert.Equal(t, "second message", errorEntry.Msg)
- assert.EqualValues(t, map[string]string{"key": "second"}, errorEntry.Context, 0.0)
- assert.Empty(t, errorEntry.SpanID)
- assert.Empty(t, errorEntry.TraceID)
-
- assert.NotEmpty(t, errorEntry.Timestamp)
- _, err = time.Parse(time.RFC3339, errorEntry.Timestamp)
- assert.NoError(t, err)
- })
-
- t.Run("with context should create new logger", func(t *testing.T) {
- //GIVEN
- log, err := logger.New(logger.TEXT, logger.INFO)
- require.NoError(t, err)
- //WHEN
- firstLogger := log.WithContext()
- secondLogger := log.WithContext()
-
- //THEN
- assert.NotSame(t, firstLogger, secondLogger)
- })
-
- t.Run("with tracing should create new logger", func(t *testing.T) {
- //GIVEN
- log, err := logger.New(logger.TEXT, logger.INFO)
- require.NoError(t, err)
- ctx := fixContext(map[string]string{"traceid": "trace", "spanid": "span"})
-
- //WHEN
- firstLogger := log.WithTracing(ctx)
- secondLogger := log.WithTracing(ctx)
-
- //THEN
- assert.NotSame(t, firstLogger, secondLogger)
- })
-}
-
-func fixContext(values map[string]string) context.Context {
- ctx := context.TODO()
- for k, v := range values {
- //nolint:staticcheck
- ctx = context.WithValue(ctx, k, v)
- }
-
- return ctx
-}
-
-func rollbackStderr(oldStdErr *os.File) {
- os.Stderr = oldStdErr
-}
diff --git a/components/serverless/internal/logging/setup.go b/components/serverless/internal/logging/setup.go
deleted file mode 100644
index ef7f7fb17..000000000
--- a/components/serverless/internal/logging/setup.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package logging
-
-import (
- "github.com/kyma-project/serverless/components/serverless/internal/logging/logger"
- "github.com/pkg/errors"
- "go.uber.org/zap"
-)
-
-// ConfigureLogger - builds logger based on logLevel and logFormat
-func ConfigureLogger(logLevel, logFormat string, atomic zap.AtomicLevel) (*logger.Logger, error) {
- parsedLogLevel, err := logger.MapLevel(logLevel)
- if err != nil {
- return nil, errors.Wrap(err, "unable to parse logging level")
- }
-
- format, err := logger.MapFormat(logFormat)
- if err != nil {
- return nil, errors.Wrap(err, "unable to set logging format")
- }
-
- l, err := logger.NewWithAtomicLevel(format, atomic)
- if err != nil {
- return nil, errors.Wrap(err, "unable to set logger")
- }
-
- if err := logger.InitKlog(l, parsedLogLevel); err != nil {
- return nil, errors.Wrap(err, "unable to init Klog")
- }
-
- return l, nil
-}
diff --git a/components/serverless/internal/logging/tracing/helper.go b/components/serverless/internal/logging/tracing/helper.go
deleted file mode 100644
index a554f2185..000000000
--- a/components/serverless/internal/logging/tracing/helper.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package tracing
-
-import "context"
-
-func GetMetadata(ctx context.Context) map[string]string {
- m := map[string]string{
- TRACE_KEY: UNKNOWN_VALUE,
- SPAN_KEY: UNKNOWN_VALUE,
- }
- if val, ok := ctx.Value(TRACE_KEY).(string); ok {
- m[TRACE_KEY] = val
- }
- if val, ok := ctx.Value(SPAN_KEY).(string); ok {
- m[SPAN_KEY] = val
- }
- return m
-}
diff --git a/components/serverless/internal/logging/tracing/helper_test.go b/components/serverless/internal/logging/tracing/helper_test.go
deleted file mode 100644
index 40de9999b..000000000
--- a/components/serverless/internal/logging/tracing/helper_test.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package tracing_test
-
-import (
- "context"
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/logging/tracing"
-
- "github.com/bmizerany/assert"
-)
-
-func TestGetMetadata(t *testing.T) {
- t.Run("context with values", func(t *testing.T) {
- //GIVEN
- ctx := fixContext(map[string]string{tracing.TRACE_KEY: "mytrace", tracing.SPAN_KEY: "myspan"})
-
- //WHEN
- out := tracing.GetMetadata(ctx)
-
- //THEN
- assert.Equal(t, "mytrace", out[tracing.TRACE_KEY])
- assert.Equal(t, "myspan", out[tracing.SPAN_KEY])
- })
-
- t.Run("context without values", func(t *testing.T) {
- ctx := context.TODO()
-
- //WHEN
- out := tracing.GetMetadata(ctx)
-
- //THEN
- assert.Equal(t, tracing.UNKNOWN_VALUE, out[tracing.TRACE_KEY])
- assert.Equal(t, tracing.UNKNOWN_VALUE, out[tracing.SPAN_KEY])
- })
-
-}
-
-func fixContext(values map[string]string) context.Context {
- ctx := context.TODO()
- for k, v := range values {
- //nolint:staticcheck
- ctx = context.WithValue(ctx, k, v)
- }
-
- return ctx
-}
diff --git a/components/serverless/internal/logging/tracing/middleware.go b/components/serverless/internal/logging/tracing/middleware.go
deleted file mode 100644
index e00ee4d33..000000000
--- a/components/serverless/internal/logging/tracing/middleware.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package tracing
-
-import (
- "context"
- "net/http"
- "strings"
-)
-
-const (
- SPAN_HEADER_KEY = "X-B3-Spanid"
- TRACE_HEADER_KEY = "X-B3-Traceid"
- TRACE_KEY = "traceid"
- SPAN_KEY = "spanid"
- UNKNOWN_VALUE = "unknown"
-)
-
-type tracingMiddleware struct {
- handler func(w http.ResponseWriter, r *http.Request)
-}
-
-func NewTracingMiddleware(handler func(w http.ResponseWriter, r *http.Request)) http.Handler {
- return &tracingMiddleware{
- handler: handler,
- }
-}
-
-func (m *tracingMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- newCtx := addHeaderToCtx(r.Context(), r.Header, TRACE_HEADER_KEY, TRACE_KEY)
- newCtx = addHeaderToCtx(newCtx, r.Header, SPAN_HEADER_KEY, SPAN_KEY)
-
- m.handler(w, r.WithContext(newCtx))
-}
-
-func addHeaderToCtx(ctx context.Context, headers http.Header, key string, desiredKey string) context.Context {
- header, ok := headers[key]
- if !ok {
- return ctx
- }
- value := strings.Join(header, ";")
- //nolint:staticcheck
- return context.WithValue(ctx, desiredKey, value)
-}
diff --git a/components/serverless/internal/logging/tracing/middleware_test.go b/components/serverless/internal/logging/tracing/middleware_test.go
deleted file mode 100644
index 24a4b6a0d..000000000
--- a/components/serverless/internal/logging/tracing/middleware_test.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package tracing_test
-
-import (
- "net/http"
- "net/http/httptest"
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/logging/tracing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestMiddleware(t *testing.T) {
- t.Run("with trace and span in header, should put traceid and spanid to context", func(t *testing.T) {
- //GIVEN
- var outRequest *http.Request
- middleware := tracing.NewTracingMiddleware(func(w http.ResponseWriter, r *http.Request) {
- outRequest = r
- })
- resp := httptest.NewRecorder()
-
- r, err := http.NewRequest(http.MethodGet, "", nil)
- require.NoError(t, err)
- r.Header[tracing.TRACE_HEADER_KEY] = []string{"mytrace"}
- r.Header[tracing.SPAN_HEADER_KEY] = []string{"myspan"}
-
- //WHEN
- middleware.ServeHTTP(resp, r)
-
- //THEN
- ctx := outRequest.Context()
- assert.Equal(t, "myspan", ctx.Value(tracing.SPAN_KEY))
- assert.Equal(t, "mytrace", ctx.Value(tracing.TRACE_KEY))
- })
-
- t.Run("wihtout trace and span should not change the context", func(t *testing.T) {
- //GIVEN
- var enhancedRequest *http.Request
- middleware := tracing.NewTracingMiddleware(func(w http.ResponseWriter, r *http.Request) {
- enhancedRequest = r
- })
- resp := httptest.NewRecorder()
-
- r, err := http.NewRequest(http.MethodGet, "", nil)
- require.NoError(t, err)
-
- //WHEN
- middleware.ServeHTTP(resp, r)
-
- //THEN
- ctx := enhancedRequest.Context()
- assert.Equal(t, ctx, r.Context())
- })
-}
diff --git a/components/serverless/internal/resource/automock/client.go b/components/serverless/internal/resource/automock/client.go
deleted file mode 100644
index 0f3446673..000000000
--- a/components/serverless/internal/resource/automock/client.go
+++ /dev/null
@@ -1,182 +0,0 @@
-// Code generated by mockery v2.40.1. DO NOT EDIT.
-
-package automock
-
-import (
- context "context"
-
- client "sigs.k8s.io/controller-runtime/pkg/client"
-
- labels "k8s.io/apimachinery/pkg/labels"
-
- mock "github.com/stretchr/testify/mock"
-
- resource "github.com/kyma-project/serverless/components/serverless/internal/resource"
-
- types "k8s.io/apimachinery/pkg/types"
-)
-
-// Client is an autogenerated mock type for the Client type
-type Client struct {
- mock.Mock
-}
-
-// Create provides a mock function with given fields: ctx, object
-func (_m *Client) Create(ctx context.Context, object resource.Object) error {
- ret := _m.Called(ctx, object)
-
- if len(ret) == 0 {
- panic("no return value specified for Create")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, resource.Object) error); ok {
- r0 = rf(ctx, object)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// CreateWithReference provides a mock function with given fields: ctx, parent, object
-func (_m *Client) CreateWithReference(ctx context.Context, parent resource.Object, object resource.Object) error {
- ret := _m.Called(ctx, parent, object)
-
- if len(ret) == 0 {
- panic("no return value specified for CreateWithReference")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, resource.Object, resource.Object) error); ok {
- r0 = rf(ctx, parent, object)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Delete provides a mock function with given fields: ctx, resourceType
-func (_m *Client) Delete(ctx context.Context, resourceType resource.Object) error {
- ret := _m.Called(ctx, resourceType)
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, resource.Object) error); ok {
- r0 = rf(ctx, resourceType)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// DeleteAllBySelector provides a mock function with given fields: ctx, resourceType, namespace, selector
-func (_m *Client) DeleteAllBySelector(ctx context.Context, resourceType resource.Object, namespace string, selector labels.Selector) error {
- ret := _m.Called(ctx, resourceType, namespace, selector)
-
- if len(ret) == 0 {
- panic("no return value specified for DeleteAllBySelector")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, resource.Object, string, labels.Selector) error); ok {
- r0 = rf(ctx, resourceType, namespace, selector)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Get provides a mock function with given fields: ctx, key, object
-func (_m *Client) Get(ctx context.Context, key types.NamespacedName, object resource.Object) error {
- ret := _m.Called(ctx, key, object)
-
- if len(ret) == 0 {
- panic("no return value specified for Get")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, types.NamespacedName, resource.Object) error); ok {
- r0 = rf(ctx, key, object)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// ListByLabel provides a mock function with given fields: ctx, namespace, _a2, object
-func (_m *Client) ListByLabel(ctx context.Context, namespace string, _a2 map[string]string, object client.ObjectList) error {
- ret := _m.Called(ctx, namespace, _a2, object)
-
- if len(ret) == 0 {
- panic("no return value specified for ListByLabel")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, string, map[string]string, client.ObjectList) error); ok {
- r0 = rf(ctx, namespace, _a2, object)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Status provides a mock function with given fields:
-func (_m *Client) Status() client.SubResourceWriter {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Status")
- }
-
- var r0 client.SubResourceWriter
- if rf, ok := ret.Get(0).(func() client.SubResourceWriter); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(client.SubResourceWriter)
- }
- }
-
- return r0
-}
-
-// Update provides a mock function with given fields: ctx, object
-func (_m *Client) Update(ctx context.Context, object resource.Object) error {
- ret := _m.Called(ctx, object)
-
- if len(ret) == 0 {
- panic("no return value specified for Update")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, resource.Object) error); ok {
- r0 = rf(ctx, object)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// NewClient creates a new instance of Client. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewClient(t interface {
- mock.TestingT
- Cleanup(func())
-}) *Client {
- mock := &Client{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/components/serverless/internal/resource/automock/k8s_client.go b/components/serverless/internal/resource/automock/k8s_client.go
deleted file mode 100644
index d83175dbf..000000000
--- a/components/serverless/internal/resource/automock/k8s_client.go
+++ /dev/null
@@ -1,202 +0,0 @@
-// Code generated by mockery v2.40.1. DO NOT EDIT.
-
-package automock
-
-import (
- context "context"
-
- client "sigs.k8s.io/controller-runtime/pkg/client"
-
- mock "github.com/stretchr/testify/mock"
-
- types "k8s.io/apimachinery/pkg/types"
-)
-
-// K8sClient is an autogenerated mock type for the K8sClient type
-type K8sClient struct {
- mock.Mock
-}
-
-// Create provides a mock function with given fields: _a0, _a1, _a2
-func (_m *K8sClient) Create(_a0 context.Context, _a1 client.Object, _a2 ...client.CreateOption) error {
- _va := make([]interface{}, len(_a2))
- for _i := range _a2 {
- _va[_i] = _a2[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, _a0, _a1)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Create")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.CreateOption) error); ok {
- r0 = rf(_a0, _a1, _a2...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Delete provides a mock function with given fields: ctx, obj, opts
-func (_m *K8sClient) Delete(ctx context.Context, obj client.Object, opts ...client.DeleteOption) error {
- _va := make([]interface{}, len(opts))
- for _i := range opts {
- _va[_i] = opts[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, ctx, obj)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Delete")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteOption) error); ok {
- r0 = rf(ctx, obj, opts...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// DeleteAllOf provides a mock function with given fields: _a0, _a1, _a2
-func (_m *K8sClient) DeleteAllOf(_a0 context.Context, _a1 client.Object, _a2 ...client.DeleteAllOfOption) error {
- _va := make([]interface{}, len(_a2))
- for _i := range _a2 {
- _va[_i] = _a2[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, _a0, _a1)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for DeleteAllOf")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.DeleteAllOfOption) error); ok {
- r0 = rf(_a0, _a1, _a2...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Get provides a mock function with given fields: ctx, key, obj, opts
-func (_m *K8sClient) Get(ctx context.Context, key types.NamespacedName, obj client.Object, opts ...client.GetOption) error {
- _va := make([]interface{}, len(opts))
- for _i := range opts {
- _va[_i] = opts[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, ctx, key, obj)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Get")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, types.NamespacedName, client.Object, ...client.GetOption) error); ok {
- r0 = rf(ctx, key, obj, opts...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// List provides a mock function with given fields: _a0, _a1, _a2
-func (_m *K8sClient) List(_a0 context.Context, _a1 client.ObjectList, _a2 ...client.ListOption) error {
- _va := make([]interface{}, len(_a2))
- for _i := range _a2 {
- _va[_i] = _a2[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, _a0, _a1)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for List")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, client.ObjectList, ...client.ListOption) error); ok {
- r0 = rf(_a0, _a1, _a2...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Status provides a mock function with given fields:
-func (_m *K8sClient) Status() client.SubResourceWriter {
- ret := _m.Called()
-
- if len(ret) == 0 {
- panic("no return value specified for Status")
- }
-
- var r0 client.SubResourceWriter
- if rf, ok := ret.Get(0).(func() client.SubResourceWriter); ok {
- r0 = rf()
- } else {
- if ret.Get(0) != nil {
- r0 = ret.Get(0).(client.SubResourceWriter)
- }
- }
-
- return r0
-}
-
-// Update provides a mock function with given fields: ctx, obj, opts
-func (_m *K8sClient) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
- _va := make([]interface{}, len(opts))
- for _i := range opts {
- _va[_i] = opts[_i]
- }
- var _ca []interface{}
- _ca = append(_ca, ctx, obj)
- _ca = append(_ca, _va...)
- ret := _m.Called(_ca...)
-
- if len(ret) == 0 {
- panic("no return value specified for Update")
- }
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, client.Object, ...client.UpdateOption) error); ok {
- r0 = rf(ctx, obj, opts...)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// NewK8sClient creates a new instance of K8sClient. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
-// The first argument is typically a *testing.T value.
-func NewK8sClient(t interface {
- mock.TestingT
- Cleanup(func())
-}) *K8sClient {
- mock := &K8sClient{}
- mock.Mock.Test(t)
-
- t.Cleanup(func() { mock.AssertExpectations(t) })
-
- return mock
-}
diff --git a/components/serverless/internal/resource/resource_test.go b/components/serverless/internal/resource/resource_test.go
deleted file mode 100644
index f4d7e1f77..000000000
--- a/components/serverless/internal/resource/resource_test.go
+++ /dev/null
@@ -1,227 +0,0 @@
-package resource_test
-
-import (
- "context"
- "testing"
-
- "github.com/onsi/gomega"
- "github.com/stretchr/testify/mock"
- batchv1 "k8s.io/api/batch/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/errors"
- apilabels "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/runtime"
- clientgoscheme "k8s.io/client-go/kubernetes/scheme"
- controllerruntime "sigs.k8s.io/controller-runtime"
-
- "github.com/kyma-project/serverless/components/serverless/internal/resource"
- "github.com/kyma-project/serverless/components/serverless/internal/resource/automock"
-)
-
-func TestClient_CreateWithReference(t *testing.T) {
- ctx := context.TODO()
-
- t.Run("Success", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- scheme := runtime.NewScheme()
- g.Expect(clientgoscheme.AddToScheme(scheme)).To(gomega.BeNil())
-
- parent := &batchv1.Job{}
- object := &corev1.Pod{}
-
- client := new(automock.K8sClient)
- client.On("Create", ctx, object).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, scheme)
-
- // When
- err := resourceClient.CreateWithReference(ctx, parent, object)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("WithoutParent", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- scheme := runtime.NewScheme()
- g.Expect(clientgoscheme.AddToScheme(scheme)).To(gomega.BeNil())
-
- object := &corev1.Pod{}
-
- client := new(automock.K8sClient)
- client.On("Create", ctx, object).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, scheme)
-
- // When
- err := resourceClient.CreateWithReference(ctx, nil, object)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("AlreadyExists", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- scheme := runtime.NewScheme()
- g.Expect(clientgoscheme.AddToScheme(scheme)).To(gomega.BeNil())
-
- parent := &batchv1.Job{}
- object := &corev1.Pod{}
-
- client := new(automock.K8sClient)
- client.On("Create", ctx, object).Return(errors.NewAlreadyExists(controllerruntime.GroupResource{}, "test")).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, scheme)
-
- // When
- err := resourceClient.CreateWithReference(ctx, parent, object)
-
- // Then
- g.Expect(errors.IsAlreadyExists(err)).To(gomega.BeTrue())
- })
-
- t.Run("SetReferenceError", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- scheme := runtime.NewScheme()
-
- parent := &batchv1.Job{}
- object := &corev1.Pod{}
-
- resourceClient := resource.New(nil, scheme)
-
- // When
- err := resourceClient.CreateWithReference(ctx, parent, object)
-
- // Then
- g.Expect(runtime.IsNotRegisteredError(err)).To(gomega.BeTrue())
- })
-}
-
-func TestClient_ListByLabel(t *testing.T) {
- ctx := context.TODO()
-
- t.Run("Success", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- list := &batchv1.JobList{}
- labels := map[string]string{"test": "test"}
-
- client := new(automock.K8sClient)
- client.On("List", ctx, list, mock.Anything).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.ListByLabel(ctx, "test", labels, list)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("NoLabels", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- list := &batchv1.JobList{}
-
- client := new(automock.K8sClient)
- client.On("List", ctx, list, mock.Anything).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.ListByLabel(ctx, "test", nil, list)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("Error", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- list := &batchv1.JobList{}
- labels := map[string]string{"test": "test"}
-
- client := new(automock.K8sClient)
- client.On("List", ctx, list, mock.Anything).Return(errors.NewBadRequest("bad")).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.ListByLabel(ctx, "test", labels, list)
-
- // Then
- g.Expect(errors.IsBadRequest(err)).To(gomega.BeTrue())
- })
-}
-
-func TestClient_DeleteAllBySelector(t *testing.T) {
- ctx := context.TODO()
-
- t.Run("Success", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- resourceType := &batchv1.Job{}
- labels := map[string]string{"test": "test"}
- selector := apilabels.SelectorFromSet(labels)
-
- client := new(automock.K8sClient)
- client.On("DeleteAllOf", ctx, resourceType, mock.Anything).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.DeleteAllBySelector(ctx, resourceType, "test", selector)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("NoLabels", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- resourceType := &batchv1.Job{}
-
- client := new(automock.K8sClient)
- client.On("DeleteAllOf", ctx, resourceType, mock.Anything).Return(nil).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.DeleteAllBySelector(ctx, resourceType, "test", nil)
-
- // Then
- g.Expect(err).To(gomega.BeNil())
- })
-
- t.Run("Error", func(t *testing.T) {
- // Given
- g := gomega.NewGomegaWithT(t)
- resourceType := &batchv1.Job{}
- labels := map[string]string{"test": "test"}
- selector := apilabels.SelectorFromSet(labels)
-
- client := new(automock.K8sClient)
- client.On("DeleteAllOf", ctx, resourceType, mock.Anything).Return(errors.NewBadRequest("bad")).Once()
- defer client.AssertExpectations(t)
-
- resourceClient := resource.New(client, nil)
-
- // When
- err := resourceClient.DeleteAllBySelector(ctx, resourceType, "test", selector)
-
- // Then
- g.Expect(errors.IsBadRequest(err)).To(gomega.BeTrue())
- })
-}
diff --git a/components/serverless/internal/testenv/testenv.go b/components/serverless/internal/testenv/testenv.go
deleted file mode 100644
index a37ed9985..000000000
--- a/components/serverless/internal/testenv/testenv.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package testenv
-
-import (
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/require"
- "k8s.io/client-go/kubernetes/scheme"
- "os"
- "path/filepath"
- "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/envtest"
- "strings"
- "testing"
-)
-
-func Start(t *testing.T) (cl client.Client, env *envtest.Environment) {
- wdPath, err := os.Getwd()
- require.NoError(t, err)
- crdPath := buildCrdPath(wdPath)
-
- testEnv := &envtest.Environment{
- CRDDirectoryPaths: []string{crdPath},
- ErrorIfCRDPathMissing: true,
- }
- cfg, err := testEnv.Start()
- require.NoError(t, err)
- require.NotNil(t, cfg)
-
- require.NoError(t, scheme.AddToScheme(scheme.Scheme))
- require.NoError(t, serverlessv1alpha2.AddToScheme(scheme.Scheme))
-
- k8sClient, err := client.New(cfg, client.Options{Scheme: scheme.Scheme})
- require.NoError(t, err)
- require.NotNil(t, k8sClient)
-
- return k8sClient, testEnv
-}
-
-func Stop(t *testing.T, testEnv *envtest.Environment) {
- require.NoError(t, testEnv.Stop())
-}
-
-func buildCrdPath(wd string) string {
- wdPath := strings.Split(wd, "/")
-
- crdPath := []string{"/"}
- for _, path := range wdPath {
- crdPath = append(crdPath, path)
- if path == "components" {
- break
- }
- }
- crdPath = append(crdPath, "serverless", "config", "crd", "bases")
- return filepath.Join(crdPath...)
-}
diff --git a/components/serverless/internal/webhook/config.go b/components/serverless/internal/webhook/config.go
deleted file mode 100644
index 01c366761..000000000
--- a/components/serverless/internal/webhook/config.go
+++ /dev/null
@@ -1,10 +0,0 @@
-package webhook
-
-type Config struct {
- SystemNamespace string `envconfig:"default=kyma-system"`
- ServiceName string `envconfig:"default=serverless-webhook"`
- SecretName string `envconfig:"default=serverless-webhook"`
- Port int `envconfig:"default=8443"`
- LogConfigPath string `envconfig:"default=/appconfig/log_config.yaml"`
- ConfigPath string `envconfig:"default=/appconfig/config.yaml"`
-}
diff --git a/components/serverless/internal/webhook/defaulting_webhook.go b/components/serverless/internal/webhook/defaulting_webhook.go
deleted file mode 100644
index e3bcbf198..000000000
--- a/components/serverless/internal/webhook/defaulting_webhook.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package webhook
-
-import (
- "context"
- "encoding/json"
- "fmt"
-
- "github.com/pkg/errors"
- "go.uber.org/zap"
-
- "net/http"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-)
-
-type DefaultingWebHook struct {
- client ctrlclient.Client
- decoder *admission.Decoder
- log *zap.SugaredLogger
-}
-
-func NewDefaultingWebhook(client ctrlclient.Client, log *zap.SugaredLogger) *DefaultingWebHook {
- return &DefaultingWebHook{
- client: client,
- log: log,
- }
-}
-
-func (w *DefaultingWebHook) Handle(_ context.Context, req admission.Request) admission.Response {
- log := w.log.With("name", req.Name, "namespace", req.Namespace, "kind", req.Kind.Kind)
- log.Debug("starting defaulting")
-
- if req.Kind.Kind == "Function" {
- res := w.handleFunctionDefaulting(req)
- log.Debug("defaulting finished for function")
- return res
- }
-
- log.Debug("request object invalid kind")
- return admission.Errored(http.StatusBadRequest, fmt.Errorf("invalid kind: %v", req.Kind.Kind))
-}
-
-func (w *DefaultingWebHook) InjectDecoder(decoder *admission.Decoder) error {
- w.decoder = decoder
- return nil
-}
-
-func (w *DefaultingWebHook) handleFunctionDefaulting(req admission.Request) admission.Response {
- var f interface{}
- switch req.Kind.Version {
- case serverlessv1alpha2.FunctionVersion:
- {
- fn := &serverlessv1alpha2.Function{}
- if err := w.decoder.Decode(req, fn); err != nil {
- return admission.Errored(http.StatusBadRequest, err)
- }
- f = fn
- }
- default:
- return admission.Errored(http.StatusBadRequest, errors.Errorf("Invalid resource version provided: %s", req.Kind.Version))
- }
-
- fBytes, err := json.Marshal(f)
- if err != nil {
- return admission.Errored(http.StatusInternalServerError, err)
- }
- return admission.PatchResponseFromRaw(req.Object.Raw, fBytes)
-}
diff --git a/components/serverless/internal/webhook/fixtures_test.go b/components/serverless/internal/webhook/fixtures_test.go
deleted file mode 100644
index a81cfe42f..000000000
--- a/components/serverless/internal/webhook/fixtures_test.go
+++ /dev/null
@@ -1,71 +0,0 @@
-package webhook
-
-import (
- "encoding/json"
- "testing"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/require"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-var one int32 = 1
-var two int32 = 2
-
-func ValidV1Alpha2Function() serverlessv1alpha2.Function {
- f := serverlessv1alpha2.Function{
- TypeMeta: metav1.TypeMeta{
- Kind: serverlessv1alpha2.FunctionKind,
- APIVersion: serverlessv1alpha2.FunctionApiVersion,
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: "testfunc",
- Namespace: "default",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- "cpu": resource.MustParse("700m"),
- "memory": resource.MustParse("700Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- "cpu": resource.MustParse("200m"),
- "memory": resource.MustParse("200Mi"),
- },
- },
- },
- Function: &serverlessv1alpha2.ResourceRequirements{
- Resources: &corev1.ResourceRequirements{
- Limits: map[corev1.ResourceName]resource.Quantity{
- "cpu": resource.MustParse("400m"),
- "memory": resource.MustParse("512Mi"),
- },
- Requests: map[corev1.ResourceName]resource.Quantity{
- "cpu": resource.MustParse("200m"),
- "memory": resource.MustParse("256Mi"),
- },
- },
- },
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: `def main(event, context):\n return \"hello world\"\n`,
- }},
- ScaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: &one,
- MaxReplicas: &two,
- },
- Runtime: serverlessv1alpha2.Python312,
- }}
- return f
-}
-
-func Marshall(t *testing.T, obj interface{}) string {
- out, err := json.Marshal(obj)
- require.NoError(t, err)
- return string(out)
-}
diff --git a/components/serverless/internal/webhook/resources/certificates.go b/components/serverless/internal/webhook/resources/certificates.go
deleted file mode 100644
index f7165ce55..000000000
--- a/components/serverless/internal/webhook/resources/certificates.go
+++ /dev/null
@@ -1,202 +0,0 @@
-package resources
-
-import (
- "context"
- "crypto/x509"
- "encoding/pem"
- "fmt"
- "strings"
- "time"
-
- "go.uber.org/zap"
-
- apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
-
- "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
- apiErrors "k8s.io/apimachinery/pkg/api/errors"
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "k8s.io/client-go/util/cert"
- ctrl "sigs.k8s.io/controller-runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-const (
- CertFile = "server-cert.pem"
- KeyFile = "server-key.pem"
- DefaultCertDir = "/tmp/k8s-webhook-server/serving-certs"
- FunctionCRDName = "functions.serverless.kyma-project.io"
-)
-
-type Result int
-
-const (
- NoResult Result = iota
- Updated Result = iota
-)
-
-const TimeToExpire = 10 * 24 * time.Hour
-
-func SetupCertificates(ctx context.Context, secretName, secretNamespace, serviceName string, logger *zap.SugaredLogger) (Result, error) {
- // We are going to talk to the API server _before_ we start the manager.
- // Since the default manager client reads from cache, we will get an error.
- // So, we create a "serverClient" that would read from the API directly.
- // We only use it here, this only runs at start up, so it shouldn't be to much for the API
- serverClient, err := ctrlclient.New(ctrl.GetConfigOrDie(), ctrlclient.Options{})
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to create a server client")
- }
- if err := apiextensionsv1.AddToScheme(serverClient.Scheme()); err != nil {
- return NoResult, errors.Wrap(err, "while adding apiextensions.v1 schema to k8s client")
- }
- result, err := EnsureWebhookSecret(ctx, serverClient, secretName, secretNamespace, serviceName, logger)
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to ensure webhook secret")
- }
- return result, nil
-}
-
-func EnsureWebhookSecret(ctx context.Context, client ctrlclient.Client, secretName, secretNamespace, serviceName string, log *zap.SugaredLogger) (Result, error) {
- secret := &corev1.Secret{}
- log.Info("ensuring webhook secret")
- err := client.Get(ctx, types.NamespacedName{Name: secretName, Namespace: secretNamespace}, secret)
- if err != nil && !apiErrors.IsNotFound(err) {
- return NoResult, errors.Wrap(err, "failed to get webhook secret")
- }
-
- if apiErrors.IsNotFound(err) {
- log.Info("creating webhook secret")
- return createSecret(ctx, client, secretName, secretNamespace, serviceName)
- }
-
- log.Info("updating pre-exiting webhook secret")
- result, err := updateSecret(ctx, client, log, secret, serviceName)
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to update secret")
- }
- return result, nil
-}
-
-func createSecret(ctx context.Context, client ctrlclient.Client, name, namespace, serviceName string) (Result, error) {
- secret, err := buildSecret(name, namespace, serviceName)
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to create secret object")
- }
- if err := client.Create(ctx, secret); err != nil {
- return NoResult, errors.Wrap(err, "failed to create secret")
- }
- return Updated, nil
-}
-
-func updateSecret(ctx context.Context, client ctrlclient.Client, log *zap.SugaredLogger, secret *corev1.Secret, serviceName string) (Result, error) {
- valid, err := isValidSecret(secret)
- if valid {
- return NoResult, nil
- }
- if err != nil {
- log.Error(err, "invalid certificate")
- }
-
- newSecret, err := buildSecret(secret.Name, secret.Namespace, serviceName)
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to create secret object")
- }
-
- secret.Data = newSecret.Data
- if err := client.Update(ctx, secret); err != nil {
- return NoResult, errors.Wrap(err, "failed to update secret")
- }
- return Updated, nil
-}
-
-func isValidSecret(s *corev1.Secret) (bool, error) {
- if !hasRequiredKeys(s.Data) {
- return false, nil
- }
- if err := verifyCertificate(s.Data[CertFile]); err != nil {
- return false, err
- }
- if err := verifyKey(s.Data[KeyFile]); err != nil {
- return false, err
- }
-
- return true, nil
-}
-
-func verifyCertificate(c []byte) error {
- certificate, err := cert.ParseCertsPEM(c)
- if err != nil {
- return errors.Wrap(err, "failed to parse certificate data")
- }
- // certificate is self signed. So we use it as a root cert
- root, err := cert.NewPoolFromBytes(c)
- if err != nil {
- return errors.Wrap(err, "failed to parse root certificate data")
- }
- // make sure the certificate is valid for the next 10 days. Otherwise it will be recreated.
- _, err = certificate[0].Verify(x509.VerifyOptions{CurrentTime: time.Now().Add(TimeToExpire), Roots: root})
- if err != nil {
- return errors.Wrap(err, "certificate verification failed")
- }
- return nil
-}
-
-func verifyKey(k []byte) error {
- b, _ := pem.Decode(k)
- key, err := x509.ParsePKCS1PrivateKey(b.Bytes)
- if err != nil {
- return errors.Wrap(err, "failed to parse key data")
- }
- if err = key.Validate(); err != nil {
- return errors.Wrap(err, "key verification failed")
- }
- return nil
-}
-
-func hasRequiredKeys(data map[string][]byte) bool {
- if data == nil {
- return false
- }
- for _, key := range []string{CertFile, KeyFile} {
- if _, ok := data[key]; !ok {
- return false
- }
- }
- return true
-}
-
-func buildSecret(name, namespace, serviceName string) (*corev1.Secret, error) {
- cert, key, err := generateWebhookCertificates(serviceName, namespace)
- if err != nil {
- return nil, errors.Wrap(err, "failed to generate webhook certificates")
- }
- return &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- Data: map[string][]byte{
- CertFile: cert,
- KeyFile: key,
- },
- }, nil
-}
-
-func generateWebhookCertificates(serviceName, namespace string) ([]byte, []byte, error) {
- altNames := serviceAltNames(serviceName, namespace)
- return cert.GenerateSelfSignedCertKey(altNames[0], nil, altNames)
-}
-
-func serviceAltNames(serviceName, namespace string) []string {
- namespacedServiceName := strings.Join([]string{serviceName, namespace}, ".")
- commonName := strings.Join([]string{namespacedServiceName, "svc"}, ".")
- serviceHostname := fmt.Sprintf("%s.%s.svc.cluster.local", serviceName, namespace)
-
- return []string{
- commonName,
- serviceName,
- namespacedServiceName,
- serviceHostname,
- }
-}
diff --git a/components/serverless/internal/webhook/resources/certificates_test.go b/components/serverless/internal/webhook/resources/certificates_test.go
deleted file mode 100644
index 038d0874a..000000000
--- a/components/serverless/internal/webhook/resources/certificates_test.go
+++ /dev/null
@@ -1,299 +0,0 @@
-package resources
-
-import (
- "bytes"
- "context"
- "crypto/rand"
- "crypto/x509"
- "crypto/x509/pkix"
- "encoding/pem"
- "math/big"
- "reflect"
- "testing"
- "time"
-
- "go.uber.org/zap"
-
- "github.com/stretchr/testify/require"
- corev1 "k8s.io/api/core/v1"
- v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-const (
- testSecretName = "test-secret"
- testNamespaceName = "test-namespace"
- testServiceName = "test-service"
-)
-
-func Test_serviceAltNames(t *testing.T) {
- type args struct {
- serviceName string
- namespace string
- }
- tests := []struct {
- name string
- args args
- want []string
- }{
- {
- name: "service AltNames are generated correctly",
- args: args{serviceName: "test-service", namespace: "test-namespace"},
- // not using consts here to make it as readable as possible.
- want: []string{
- "test-service.test-namespace.svc",
- "test-service",
- "test-service.test-namespace",
- "test-service.test-namespace.svc.cluster.local",
- },
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- got := serviceAltNames(tt.args.serviceName, tt.args.namespace)
- if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("invalid serviec altNames: serviceAltNames() = %v, want %v", got, tt.want)
- }
- })
- }
-}
-
-func TestEnsureWebhookSecret(t *testing.T) {
- ctx := context.Background()
- cert, key, err := generateWebhookCertificates(testServiceName, testNamespaceName)
- require.NoError(t, err)
- fakeLogger := zap.NewNop().Sugar()
-
- t.Run("can ensure the secret if it doesn't exist", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, Updated, result)
-
- secret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, secret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, secret.Name)
- require.Equal(t, testNamespaceName, secret.Namespace)
- require.Contains(t, secret.Data, KeyFile)
- require.Contains(t, secret.Data, CertFile)
- })
-
- t.Run("can ensure the secret is updated if it exists", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
- secret := &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: testSecretName,
- Namespace: testNamespaceName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- }
- err := client.Create(ctx, secret)
- require.NoError(t, err)
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, Updated, result)
-
- updatedSecret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, updatedSecret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, updatedSecret.Name)
- require.Equal(t, testNamespaceName, updatedSecret.Namespace)
- require.Contains(t, updatedSecret.Data, KeyFile)
- require.Contains(t, updatedSecret.Data, CertFile)
- require.Contains(t, updatedSecret.Labels, "dont-remove-me")
- })
-
- t.Run("can ensure the secret is updated if it's missing a value", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
- secret := &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: testSecretName,
- Namespace: testNamespaceName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Data: map[string][]byte{
- KeyFile: key,
- },
- }
- err := client.Create(ctx, secret)
- require.NoError(t, err)
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, Updated, result)
-
- updatedSecret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, updatedSecret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, updatedSecret.Name)
- require.Equal(t, testNamespaceName, updatedSecret.Namespace)
- // make sure the test is updated
- require.NotEqual(t, secret.ResourceVersion, updatedSecret.ResourceVersion)
- require.Contains(t, updatedSecret.Data, KeyFile)
- require.Contains(t, updatedSecret.Data, CertFile)
- require.Contains(t, updatedSecret.Labels, "dont-remove-me")
- })
-
- t.Run("doesn't update the secret if it's ok", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
- secret := &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: testSecretName,
- Namespace: testNamespaceName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Data: map[string][]byte{
- KeyFile: key,
- CertFile: cert,
- },
- }
- err := client.Create(ctx, secret)
- require.NoError(t, err)
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, NoResult, result)
-
- updatedSecret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, updatedSecret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, updatedSecret.Name)
- require.Equal(t, testNamespaceName, updatedSecret.Namespace)
- // make sure it's not updated
- require.Equal(t, secret.ResourceVersion, updatedSecret.ResourceVersion)
- require.Contains(t, updatedSecret.Data, KeyFile)
- require.Contains(t, updatedSecret.Data, CertFile)
- require.Equal(t, key, updatedSecret.Data[KeyFile])
- require.Equal(t, cert, updatedSecret.Data[CertFile])
- require.Contains(t, updatedSecret.Labels, "dont-remove-me")
- })
-
- t.Run("should update if the cert will expire in 10 days", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
-
- tenDaysCert, err := generateShortLivedCertWithKey(key, testServiceName, 10*24*time.Hour)
- require.NoError(t, err)
-
- secret := &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: testSecretName,
- Namespace: testNamespaceName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Data: map[string][]byte{
- KeyFile: key,
- CertFile: tenDaysCert,
- },
- }
- err = client.Create(ctx, secret)
- require.NoError(t, err)
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, Updated, result)
-
- updatedSecret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, updatedSecret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, updatedSecret.Name)
- require.Equal(t, testNamespaceName, updatedSecret.Namespace)
- require.Contains(t, updatedSecret.Data, KeyFile)
- require.Contains(t, updatedSecret.Data, CertFile)
- // make sure it's updated, not overridden.
- require.NotEqual(t, secret.ResourceVersion, updatedSecret.ResourceVersion)
- require.NotEqual(t, key, updatedSecret.Data[KeyFile])
- require.NotEqual(t, cert, updatedSecret.Data[CertFile])
- require.Contains(t, updatedSecret.Labels, "dont-remove-me")
- })
-
- t.Run("should not update if the cert will expire in more than 10 days", func(t *testing.T) {
- client := fake.NewClientBuilder().Build()
-
- elevenDaysCert, err := generateShortLivedCertWithKey(key, testServiceName, 11*24*time.Hour)
- require.NoError(t, err)
-
- secret := &corev1.Secret{
- ObjectMeta: v1.ObjectMeta{
- Name: testSecretName,
- Namespace: testNamespaceName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Data: map[string][]byte{
- KeyFile: key,
- CertFile: elevenDaysCert,
- },
- }
- err = client.Create(ctx, secret)
- require.NoError(t, err)
-
- result, err := EnsureWebhookSecret(ctx, client, testSecretName, testNamespaceName, testServiceName, fakeLogger)
- require.NoError(t, err)
- require.Equal(t, NoResult, result)
-
- updatedSecret := &corev1.Secret{}
- err = client.Get(ctx, types.NamespacedName{Name: testSecretName, Namespace: testNamespaceName}, updatedSecret)
-
- require.NoError(t, err)
- require.NotNil(t, secret)
- require.Equal(t, testSecretName, updatedSecret.Name)
- require.Equal(t, testNamespaceName, updatedSecret.Namespace)
- require.Contains(t, updatedSecret.Data, KeyFile)
- require.Contains(t, updatedSecret.Data, CertFile)
- // make sure it's NOT updated, not overridden.
- require.Equal(t, secret.ResourceVersion, updatedSecret.ResourceVersion)
- require.Equal(t, key, updatedSecret.Data[KeyFile])
- require.Equal(t, elevenDaysCert, updatedSecret.Data[CertFile])
- require.Contains(t, updatedSecret.Labels, "dont-remove-me")
- })
-}
-
-func generateShortLivedCertWithKey(keyBytes []byte, host string, age time.Duration) ([]byte, error) {
- pemKey, _ := pem.Decode(keyBytes)
- key, err := x509.ParsePKCS1PrivateKey(pemKey.Bytes)
- if err != nil {
- return nil, err
- }
- t := x509.Certificate{
- SerialNumber: big.NewInt(1),
- Subject: pkix.Name{
- CommonName: host,
- },
- NotBefore: time.Now(),
- NotAfter: time.Now().Add(age),
- }
-
- certBytes, err := x509.CreateCertificate(rand.Reader, &t, &t, &key.PublicKey, key)
- if err != nil {
- return nil, err
- }
- buf := bytes.Buffer{}
- if err := pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: certBytes}); err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
diff --git a/components/serverless/internal/webhook/resources/resources.go b/components/serverless/internal/webhook/resources/resources.go
deleted file mode 100644
index aec1c89fd..000000000
--- a/components/serverless/internal/webhook/resources/resources.go
+++ /dev/null
@@ -1,148 +0,0 @@
-package resources
-
-import (
- "context"
- "os"
- "path"
- "time"
-
- "go.uber.org/zap"
-
- "github.com/pkg/errors"
- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/types"
- ctrl "sigs.k8s.io/controller-runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/controller"
- "sigs.k8s.io/controller-runtime/pkg/handler"
- "sigs.k8s.io/controller-runtime/pkg/reconcile"
- "sigs.k8s.io/controller-runtime/pkg/source"
-)
-
-func SetupResourcesController(ctx context.Context, mgr ctrl.Manager, serviceName, serviceNamespace, secretName string, log *zap.SugaredLogger) error {
- logger := log.Named("resource-ctrl")
- certPath := path.Join(DefaultCertDir, CertFile)
- certBytes, err := os.ReadFile(certPath)
- if err != nil {
- return errors.Wrapf(err, "failed to read caBundle file: %s", certPath)
- }
-
- webhookConfig := WebhookConfig{
- CABundle: certBytes,
- ServiceName: serviceName,
- ServiceNamespace: serviceNamespace,
- }
- // We are going to talk to the API server _before_ we start the manager.
- // Since the default manager client reads from cache, we will get an error.
- // So, we create a "serverClient" that would read from the API directly.
- // We only use it here, this only runs at start up, so it shouldn't be to much for the API
- serverClient, err := ctrlclient.New(ctrl.GetConfigOrDie(), ctrlclient.Options{})
- if err != nil {
- return errors.Wrap(err, "failed to create a server client")
- }
-
- logger.Info("initializing the defaulting webhook configuration")
- if err := InjectCABundleIntoWebhooks(ctx, serverClient, webhookConfig, MutatingWebhook); err != nil {
- return errors.Wrap(err, "failed to ensure defaulting webhook configuration")
- }
-
- logger.Info("initializing the validation webhook configuration")
- if err := InjectCABundleIntoWebhooks(ctx, serverClient, webhookConfig, ValidatingWebHook); err != nil {
- return errors.Wrap(err, "failed to ensure validating webhook configuration")
- }
- // watch over the configuration
- logger.Info("creating webhook resources controller")
- c, err := controller.New("webhook-resources-controller", mgr, controller.Options{
- Reconciler: &resourceReconciler{
- webhookConfig: webhookConfig,
- client: mgr.GetClient(),
- secretName: secretName,
- logger: log.Named("webhook-resource-controller"),
- },
- })
- if err != nil {
- return errors.Wrap(err, "failed to create webhook-config-controller")
- }
-
- if err := c.Watch(source.Kind(mgr.GetCache(), &admissionregistrationv1.ValidatingWebhookConfiguration{}),
- &handler.EnqueueRequestForObject{},
- ); err != nil {
- return errors.Wrap(err, "failed to watch ValidatingWebhookConfiguration")
- }
-
- if err := c.Watch(source.Kind(mgr.GetCache(), &admissionregistrationv1.MutatingWebhookConfiguration{}),
- &handler.EnqueueRequestForObject{},
- ); err != nil {
- return errors.Wrap(err, "failed to watch MutatingWebhookConfiguration")
- }
- if err := c.Watch(source.Kind(mgr.GetCache(), &corev1.Secret{}),
- &handler.EnqueueRequestForObject{},
- ); err != nil {
- return errors.Wrap(err, "failed to watch Secrets")
- }
- return nil
-}
-
-type resourceReconciler struct {
- webhookConfig WebhookConfig
- secretName string
- client ctrlclient.Client
- logger *zap.SugaredLogger
-}
-
-func (r *resourceReconciler) Reconcile(ctx context.Context, request reconcile.Request) (reconcile.Result, error) {
- // if the request is not one of our managed resources, we bail.
- secretNamespaced := types.NamespacedName{Name: r.secretName, Namespace: r.webhookConfig.ServiceNamespace}
- if request.Name != DefaultingWebhookName &&
- request.Name != ValidationWebhookName &&
- request.NamespacedName.String() != secretNamespaced.String() {
- return reconcile.Result{}, nil
- }
-
- r.logger.With("name", request.Name).Info("reconciling webhook resources")
- if err := r.reconcilerWebhooks(ctx, request); err != nil {
- return reconcile.Result{}, errors.Wrap(err, "failed to reconcile webhook resources")
- }
- result, err := r.reconcilerSecret(ctx, request)
- if err != nil {
- return reconcile.Result{}, errors.Wrap(err, "failed to reconcile webhook resources")
- }
- if result == Updated {
- r.logger.Info("certificate updated successfully, restarting")
- //This is not an elegant solution, but the webhook need to reconfigure itself to use updated certificate.
- //Cert-watcher from controller-runtime should refresh the certificate, but it doesn't work.
- os.Exit(0)
- }
- r.logger.With("name", request.Name).Info("webhook resources reconciled successfully")
- return reconcile.Result{RequeueAfter: 1 * time.Hour}, nil
-}
-
-func (r *resourceReconciler) reconcilerWebhooks(ctx context.Context, request reconcile.Request) error {
- if request.Name == DefaultingWebhookName {
- r.logger.Info("reconciling webhook defaulting webhook configuration")
- if err := InjectCABundleIntoWebhooks(ctx, r.client, r.webhookConfig, MutatingWebhook); err != nil {
- return errors.Wrap(err, "failed to ensure defaulting webhook configuration")
- }
- }
- if request.Name == ValidationWebhookName {
- r.logger.Info("reconciling webhook validating webhook configuration")
- if err := InjectCABundleIntoWebhooks(ctx, r.client, r.webhookConfig, ValidatingWebHook); err != nil {
- return errors.Wrap(err, "failed to ensure validating webhook configuration")
- }
- }
- return nil
-}
-
-func (r *resourceReconciler) reconcilerSecret(ctx context.Context, request reconcile.Request) (Result, error) {
- ctrl.LoggerFrom(ctx).Info("reconciling webhook secret")
- secretNamespaced := types.NamespacedName{Name: r.secretName, Namespace: r.webhookConfig.ServiceNamespace}
- if request.NamespacedName.String() != secretNamespaced.String() {
- return NoResult, nil
- }
- result, err := EnsureWebhookSecret(ctx, r.client, request.Name, request.Namespace, r.webhookConfig.ServiceName, r.logger)
- if err != nil {
- return NoResult, errors.Wrap(err, "failed to reconcile webhook secret")
- }
- return result, nil
-}
diff --git a/components/serverless/internal/webhook/resources/resources_test.go b/components/serverless/internal/webhook/resources/resources_test.go
deleted file mode 100644
index 80dcbe066..000000000
--- a/components/serverless/internal/webhook/resources/resources_test.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package resources
-
-import (
- "context"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- "testing"
-
- "go.uber.org/zap"
-
- "github.com/stretchr/testify/require"
- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
- "sigs.k8s.io/controller-runtime/pkg/reconcile"
-)
-
-func Test_resourceReconciler_Reconcile(t *testing.T) {
- fakeLogger := zap.NewNop().Sugar()
- t.Run("should not reconcile not owned resources", func(t *testing.T) {
- ctx := context.Background()
- client := fake.NewClientBuilder().Build()
- namespacedName := types.NamespacedName{Namespace: "", Name: DefaultingWebhookName}
- webhookConfig := WebhookConfig{
- CABundle: []byte("certificate content"),
- ServiceName: "test-webhook-service",
- ServiceNamespace: "test-namespace",
- }
- r := &resourceReconciler{
- webhookConfig: webhookConfig,
- secretName: "test-secret-name",
- client: client,
- logger: fakeLogger,
- }
- err := createTestResources(ctx, client)
- require.NoError(t, err)
-
- _, err = r.Reconcile(ctx, reconcile.Request{NamespacedName: namespacedName})
- require.Error(t, err)
- require.True(t, k8serrors.IsNotFound(err))
-
- for _, res := range getTestResources() {
- r := res
- err := client.Get(ctx, types.NamespacedName{Name: res.GetName(), Namespace: res.GetNamespace()}, r)
- require.NoError(t, err)
- require.Equal(t, r.GetResourceVersion(), "1")
- }
- })
-
-}
-
-func createTestResources(ctx context.Context, client ctrlclient.Client) error {
- resources := getTestResources()
- for _, res := range resources {
- r := res
- err := client.Create(ctx, r)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func getTestResources() []ctrlclient.Object {
- return []ctrlclient.Object{
- &admissionregistrationv1.MutatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: "not-my-mutationwebhookconfig",
- }},
- &admissionregistrationv1.ValidatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: "not-my-validationwebhookconfig",
- }},
- &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: "not-my-secret",
- Namespace: "default",
- },
- },
- }
-}
diff --git a/components/serverless/internal/webhook/resources/webhook_config.go b/components/serverless/internal/webhook/resources/webhook_config.go
deleted file mode 100644
index 6fbde728b..000000000
--- a/components/serverless/internal/webhook/resources/webhook_config.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package resources
-
-import (
- "bytes"
- "context"
- "github.com/pkg/errors"
- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
- "k8s.io/apimachinery/pkg/types"
- ctlrclient "sigs.k8s.io/controller-runtime/pkg/client"
-)
-
-type WebhookConfig struct {
- CABundle []byte
- ServiceName string
- ServiceNamespace string
-}
-type WebHookType string
-
-const (
- MutatingWebhook WebHookType = "Mutating"
- ValidatingWebHook WebHookType = "Validating"
-
- DefaultingWebhookName = "defaulting.webhook.serverless.kyma-project.io"
- ValidationWebhookName = "validation.webhook.serverless.kyma-project.io"
-
- FunctionDefaultingWebhookPath = "/defaulting/functions"
- FunctionValidationWebhookPath = "/validation/function"
-)
-
-func InjectCABundleIntoWebhooks(ctx context.Context, client ctlrclient.Client, config WebhookConfig, wt WebHookType) error {
- switch wt {
- case MutatingWebhook:
- return injectCAIntoMutatingWebhook(ctx, client, config.CABundle)
- case ValidatingWebHook:
- return injectCAIntoValidationWebhook(ctx, client, config.CABundle)
- default:
- return errors.Errorf("Unknow webhook type: %s", wt)
- }
-}
-
-func injectCAIntoMutatingWebhook(ctx context.Context, client ctlrclient.Client, CABundle []byte) error {
- mwhc := &admissionregistrationv1.MutatingWebhookConfiguration{}
- if err := client.Get(ctx, types.NamespacedName{Name: DefaultingWebhookName}, mwhc); err != nil {
- return errors.Wrapf(err, "failed to get defaulting MutatingWebhookConfiguration: %s", DefaultingWebhookName)
- }
- var updatedWebhooks []admissionregistrationv1.MutatingWebhook
- shouldBeUpdated := false
- for _, webhook := range mwhc.Webhooks {
- if !bytes.Equal(webhook.ClientConfig.CABundle, CABundle) {
- shouldBeUpdated = true
- webhook.ClientConfig.CABundle = CABundle
- updatedWebhooks = append(updatedWebhooks, webhook)
- }
- }
-
- if shouldBeUpdated {
- mwhc.Webhooks = updatedWebhooks
- return errors.Wrap(client.Update(ctx, mwhc), "while injecting CA Bundle into mutation webhook configuration")
- }
- return nil
-}
-
-func injectCAIntoValidationWebhook(ctx context.Context, client ctlrclient.Client, CABundle []byte) error {
- vwhc := &admissionregistrationv1.ValidatingWebhookConfiguration{}
- if err := client.Get(ctx, types.NamespacedName{Name: ValidationWebhookName}, vwhc); err != nil {
- return errors.Wrapf(err, "failed to get validation ValidatingWebhookConfiguration: %s", ValidationWebhookName)
- }
-
- var updatedWebhooks []admissionregistrationv1.ValidatingWebhook
- shouldBeUpdated := false
- for _, webhook := range vwhc.Webhooks {
- if !bytes.Equal(webhook.ClientConfig.CABundle, CABundle) {
- shouldBeUpdated = true
- webhook.ClientConfig.CABundle = CABundle
- updatedWebhooks = append(updatedWebhooks, webhook)
- }
-
- }
-
- if shouldBeUpdated {
- vwhc.Webhooks = updatedWebhooks
- return errors.Wrap(client.Update(ctx, vwhc), "while injecting CA Bundle into validation webhook configuration")
- }
- return nil
-}
diff --git a/components/serverless/internal/webhook/resources/webhook_config_test.go b/components/serverless/internal/webhook/resources/webhook_config_test.go
deleted file mode 100644
index 489cd0728..000000000
--- a/components/serverless/internal/webhook/resources/webhook_config_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package resources
-
-import (
- "context"
- "testing"
-
- "github.com/stretchr/testify/require"
- admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/types"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
-)
-
-var (
- caBundle = []byte("LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUVEakNDQW5ZQ0NRRE5vZFh6bERqdk9qQU5CZ2txaGtpRzl3MEJBUXNGQURCSk1SVXdFd1lEVlFRS0RBeGoKWlhKMExXMWhibUZuWlhJeEZUQVRCZ05WQkFzTURHTmxjblF0YldGdVlXZGxjakVaTUJjR0ExVUVBd3dRYTNsdApZUzFsZUdGdGNHeGxMbU52YlRBZUZ3MHlNVEE1TWpreE5ERXhOVGRhRncweU1qQTVNamt4TkRFeE5UZGFNRWt4CkZUQVRCZ05WQkFvTURHTmxjblF0YldGdVlXZGxjakVWTUJNR0ExVUVDd3dNWTJWeWRDMXRZVzVoWjJWeU1Sa3cKRndZRFZRUUREQkJyZVcxaExXVjRZVzF3YkdVdVkyOXRNSUlCb2pBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVk4QQpNSUlCaWdLQ0FZRUFvMHNzdEtYZ01sR0FvV0F6WmxCZVNHMTVJZ0VBRkZwbWFTcnArQ0Y1bGdjTXVSZFNBamlXCk1tS0F5OWlzdy9meTN3YmFWUWNoSWFLZXJvZzVFcnYyR1hlMmZaK0Q2anJpbFp4SG01ZURxZmtxdmQrcXh6K3IKN25Dd1JOS2t0Q093YmJqOWtMSWduQkdUVGZQL1NiVUMxd2R5R3BuYnpwVXo1b3RvbVJRMWlsWi9OZFl2T2UwYworK21zZ2xSUVpNWmNtZVI0RWJhZlNwRTdWT1M2L0srbTZpMzRZMzdmSTBhSUlUV2lVR1RuMzRVMEZhTG9DSTF5CjVNaFhSYUhyQTAyWVBsNmhUMlJFVVlRUTBuNUMxVnpQYm02VHkvUjdoOXI2RnoxQWxPQ0I5NnZtalNPemR2dmsKaHdMcVRqdHArbFNNcW1iRExEV2ZVY2JpVFIwbzliQ3Rxam1aUjQwcXhqa1hieW5hYU42TzFnbm9Fem50a1J3Sgo1cytZaVVtTHpvVFIyV2V1bHc5VVZaZXdiQm85Zk1FSFVRa1RJOEd0aWVjUDhNMGF4R1RSSVFCWUc0bTBYcEF1CmFrd2ZPNlRlZzR2T1FTQmpVanE0Rm1nYkZkVVZsUkZrVm95NXkra3JrV2FpT21hSFlqWHViMkduVWQ1WFBiamgKeG56a1R4UlE3UFh6QWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnR0JBRCs5QlExWERXY0pkZ2Jma2ZJeApNa1ZLc3pXRWdvUC9GWWNmcVVEc1drcTNkR3M0Q1Z4ODRzTjNRd0hSY2JkV2trVTd1WXh3VmE0NVZWbVZrZjhmClZGN3ZiblhWWUoydHp5K2lTb0JDcVFjMUNHV1ZwQmdIOGlFVWdYb2hwdTczWjhtSkJhNUhQT1lXTHM5dEVlVTUKdy9VOG9HOUJZRHRsclBGSzZLWkJpYU8veERMQXlFOFRxUEc3U3oxUXJFdC9HbE1wS1RHakFUYXNNQ2hzT0IrMgpuc2xLdExuNXZoS3hOdkRIYjJ4Y1pGZHlOdGQ5Vk9mcFQvNXZ2VE4wb3ozcERJd2RhUkNyTTMwU0tCZVl1OFdGClJPb1NsNUE5dDl3S08vZ0xwcFJ1WW9IdzU4Z1VudWpCOUoyT1oxaUp2YUFLTXZMNGFFbTE4VjVCYkZaUVdPUFkKcWRYZGRnYk80R0VsUFRXdUxFb01HZTM5UnBITmVtMmcrNFdUcjl1K2FkSVN3MnBQbjFRYXhqbzJmb0ZiUUpUcgpXeXR5MnVLU2diU3RzNzEvOUZ4bUIvM3Z6Y21oOUhLdzJWb0FQSzY4ckdhUkhvTjdqZ0dCR3JtdDdHZ01UeGlqCmRuOEt1OHBhRERWSTFldUx6RlJwUlBvdVVwOEVDdmRHTkxoRTJrc0dsdEk3WEE9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==")
-)
-
-func TestInjectCABundleIntoMutatingWebhooks(t *testing.T) {
- testCases := []struct {
- name string
- webhooks []admissionregistrationv1.MutatingWebhook
- }{
- {
- name: "ensure a Mutating Webhook CABundles are updated if empty",
- webhooks: []admissionregistrationv1.MutatingWebhook{{}, {}},
- },
- {
- name: "ca bundle is already present in mutating webhook's configs",
- webhooks: []admissionregistrationv1.MutatingWebhook{
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: caBundle}},
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: caBundle}},
- },
- },
- {
- name: "ca bundle is different in mutating webhook's configs",
- webhooks: []admissionregistrationv1.MutatingWebhook{
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: []byte("aaaa")}},
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: []byte("bbbb")}},
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- ctx := context.TODO()
- client := fake.NewClientBuilder().Build()
- mwh := &admissionregistrationv1.MutatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: DefaultingWebhookName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Webhooks: testCase.webhooks,
- }
- err := client.Create(ctx, mwh)
- require.NoError(t, err)
-
- wc := WebhookConfig{
- CABundle: caBundle,
- ServiceName: testServiceName,
- ServiceNamespace: testNamespaceName,
- }
- err = InjectCABundleIntoWebhooks(ctx, client, wc, MutatingWebhook)
- require.NoError(t, err)
-
- updatedWh := &admissionregistrationv1.MutatingWebhookConfiguration{}
- err = client.Get(ctx, types.NamespacedName{Name: DefaultingWebhookName}, updatedWh)
-
- require.NoError(t, err)
- require.NotNil(t, updatedWh)
- require.Equal(t, updatedWh.Name, DefaultingWebhookName)
- require.NotNil(t, updatedWh.Webhooks)
- require.Contains(t, updatedWh.Labels, "dont-remove-me")
- require.Len(t, updatedWh.Webhooks, 2)
- require.Equal(t, wc.CABundle, updatedWh.Webhooks[0].ClientConfig.CABundle)
- require.Equal(t, wc.CABundle, updatedWh.Webhooks[1].ClientConfig.CABundle)
- })
- }
-}
-func TestInjectCABundleIntoValidationWebhooks(t *testing.T) {
- testCases := []struct {
- name string
- webhooks []admissionregistrationv1.ValidatingWebhook
- }{
- {
- name: "ensure a Validating Webhook CABundles are updated if empty",
- webhooks: []admissionregistrationv1.ValidatingWebhook{{}, {}},
- },
- {
- name: "ca bundle is already present in validation webhook's configs",
- webhooks: []admissionregistrationv1.ValidatingWebhook{{
- ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: caBundle}},
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: caBundle}},
- },
- },
- {
- name: "ca bundle is different in validation webhook's configs",
- webhooks: []admissionregistrationv1.ValidatingWebhook{{
- ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: []byte("cccc")}},
- {ClientConfig: admissionregistrationv1.WebhookClientConfig{CABundle: []byte("dddd")}},
- },
- },
- }
-
- for _, testCase := range testCases {
- t.Run(testCase.name, func(t *testing.T) {
- ctx := context.TODO()
- client := fake.NewClientBuilder().Build()
- vwh := &admissionregistrationv1.ValidatingWebhookConfiguration{
- ObjectMeta: metav1.ObjectMeta{
- Name: ValidationWebhookName,
- Labels: map[string]string{
- "dont-remove-me": "true",
- },
- },
- Webhooks: testCase.webhooks,
- }
- err := client.Create(ctx, vwh)
- require.NoError(t, err)
-
- wc := WebhookConfig{
- CABundle: caBundle,
- ServiceName: testServiceName,
- ServiceNamespace: testNamespaceName,
- }
- err = InjectCABundleIntoWebhooks(ctx, client, wc, ValidatingWebHook)
- require.NoError(t, err)
-
- updatedWh := &admissionregistrationv1.ValidatingWebhookConfiguration{}
- err = client.Get(ctx, types.NamespacedName{Name: ValidationWebhookName}, updatedWh)
-
- require.NoError(t, err)
- require.Len(t, updatedWh.Webhooks, 2)
- require.Equal(t, wc.CABundle, updatedWh.Webhooks[0].ClientConfig.CABundle)
- require.Equal(t, wc.CABundle, updatedWh.Webhooks[1].ClientConfig.CABundle)
- })
- }
-}
diff --git a/components/serverless/internal/webhook/validating_webhook.go b/components/serverless/internal/webhook/validating_webhook.go
deleted file mode 100644
index 782ee59fc..000000000
--- a/components/serverless/internal/webhook/validating_webhook.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package webhook
-
-import (
- "context"
- "fmt"
- "net/http"
-
- "github.com/pkg/errors"
- "go.uber.org/zap"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- v1 "k8s.io/api/admission/v1"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-)
-
-type ValidatingWebHook struct {
- configv1alpha2 *serverlessv1alpha2.ValidationConfig
- client ctrlclient.Client
- decoder *admission.Decoder
- log *zap.SugaredLogger
-}
-
-func NewValidatingWebhook(configV1alpha2 *serverlessv1alpha2.ValidationConfig, client ctrlclient.Client, log *zap.SugaredLogger) *ValidatingWebHook {
- return &ValidatingWebHook{
- configv1alpha2: configV1alpha2,
- client: client,
- log: log,
- }
-}
-func (w *ValidatingWebHook) Handle(_ context.Context, req admission.Request) admission.Response {
- log := w.log.With("name", req.Name, "namespace", req.Namespace, "kind", req.Kind.Kind)
- log.Debug("starting validation")
-
- // We don't currently have any delete validation logic
- if req.Operation == v1.Delete {
- res := admission.Allowed("")
- log.Debug("validation finished for deletion")
- return res
- }
-
- if req.Kind.Kind == "Function" {
- res := w.handleFunctionValidation(req)
- log.Debug("validation finished for function")
- return res
- }
-
- log.Debug("request object invalid kind")
- return admission.Errored(http.StatusBadRequest, fmt.Errorf("invalid kind: %v", req.Kind.Kind))
-}
-
-func (w *ValidatingWebHook) InjectDecoder(decoder *admission.Decoder) error {
- w.decoder = decoder
- return nil
-}
-
-func (w *ValidatingWebHook) handleFunctionValidation(req admission.Request) admission.Response {
- switch req.Kind.Version {
- case serverlessv1alpha2.FunctionVersion:
- {
- fn := &serverlessv1alpha2.Function{}
- if err := w.decoder.Decode(req, fn); err != nil {
- return admission.Errored(http.StatusBadRequest, err)
- }
- }
- default:
- return admission.Errored(http.StatusBadRequest, errors.Errorf("Invalid resource version provided: %s", req.Kind.Version))
- }
- return admission.Allowed("")
-}
diff --git a/components/serverless/internal/webhook/validating_webhook_test.go b/components/serverless/internal/webhook/validating_webhook_test.go
deleted file mode 100644
index b01b518aa..000000000
--- a/components/serverless/internal/webhook/validating_webhook_test.go
+++ /dev/null
@@ -1,206 +0,0 @@
-package webhook
-
-import (
- "context"
- "net/http"
- "testing"
-
- "go.uber.org/zap"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/require"
- v1 "k8s.io/api/admission/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/runtime"
- ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
- "sigs.k8s.io/controller-runtime/pkg/client/fake"
- "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
-)
-
-func TestValidatingWebHook_Handle(t *testing.T) {
- type fields struct {
- configV1Alpha2 serverlessv1alpha2.ValidationConfig
- client ctrlclient.Client
- decoder *admission.Decoder
- }
- type args struct {
- ctx context.Context
- req admission.Request
- }
-
- scheme := runtime.NewScheme()
- _ = serverlessv1alpha2.AddToScheme(scheme)
- decoder := admission.NewDecoder(scheme)
-
- tests := []struct {
- name string
- fields fields
- args args
- responseCode int32
- }{
- {
- name: "Accept valid git function",
- fields: fields{
- configV1Alpha2: fixValidationConfig(),
- client: fake.NewClientBuilder().Build(),
- decoder: decoder,
- },
- args: args{
- ctx: context.Background(),
- req: admission.Request{
- AdmissionRequest: v1.AdmissionRequest{
- Kind: metav1.GroupVersionKind{Kind: "Function", Version: serverlessv1alpha2.FunctionVersion},
- Object: runtime.RawExtension{
- Raw: []byte(`{
- "apiVersion": "serverless.kyma-project.io/v1alpha2",
- "kind": "Function",
- "metadata": {
- "name": "testfuncgit",
- "namespace": "default"
- },
- "spec": {
- "resourceConfiguration": {
- "build": {
- "resources": {
- "limits": {
- "cpu": "700m",
- "memory": "700Mi"
- },
- "requests": {
- "cpu": "200m",
- "memory": "200Mi"
- }
- }
- },
- "function": {
- "resources": {
- "limits": {
- "cpu": "400m",
- "memory": "512Mi"
- },
- "requests": {
- "cpu": "200m",
- "memory": "256Mi"
- }
- }
- }
- },
- "scaleConfig": {
- "maxReplicas": 1,
- "minReplicas": 1
- },
- "runtime": "python312",
- "source": {
- "gitRepository": {
- "url": "test-url",
- "baseDir": "/py-handler",
- "reference": "test-ref"
- }
- }
- }
-}`),
- },
- },
- },
- },
- responseCode: http.StatusOK,
- },
- {
- name: "Accept valid v1alpha2 function",
- fields: fields{
- configV1Alpha2: fixValidationConfig(),
- client: fake.NewClientBuilder().Build(),
- decoder: decoder,
- },
- args: args{
- ctx: context.Background(),
- req: admission.Request{
- AdmissionRequest: v1.AdmissionRequest{
- Kind: metav1.GroupVersionKind{Kind: serverlessv1alpha2.FunctionKind, Version: serverlessv1alpha2.FunctionVersion},
- Object: runtime.RawExtension{
- Raw: []byte(Marshall(t, ValidV1Alpha2Function())),
- },
- },
- },
- },
- responseCode: http.StatusOK,
- },
- {
- name: "Bad request",
- fields: fields{
- configV1Alpha2: fixValidationConfig(),
- client: fake.NewClientBuilder().Build(),
- decoder: decoder,
- },
- args: args{
- ctx: context.Background(),
- req: admission.Request{
- AdmissionRequest: v1.AdmissionRequest{
- Kind: metav1.GroupVersionKind{Kind: "Function", Version: serverlessv1alpha2.FunctionVersion},
- Object: runtime.RawExtension{
- Raw: []byte(`{"bad request"`),
- },
- },
- },
- },
- responseCode: http.StatusBadRequest,
- },
- {
- name: "Deny on invalid kind",
- fields: fields{
- configV1Alpha2: fixValidationConfig(),
- client: fake.NewClientBuilder().Build(),
- decoder: decoder,
- },
- args: args{
- ctx: context.Background(),
- req: admission.Request{
- AdmissionRequest: v1.AdmissionRequest{
- Kind: metav1.GroupVersionKind{Kind: "Function", Version: serverlessv1alpha2.FunctionVersion},
- Object: runtime.RawExtension{
- Raw: []byte(`{
- "apiVersion": "serverless.kyma-project.io/v1alpha2",
- "kind": "NotFunction",
- "metadata": {
- "name": "testfunc",
- "namespace": "default"
- },
- "spec": {
- "runtime": "python312"
- }
- }`),
- },
- },
- },
- },
- responseCode: http.StatusBadRequest,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- w := &ValidatingWebHook{
- configv1alpha2: &tt.fields.configV1Alpha2,
- client: tt.fields.client,
- decoder: tt.fields.decoder,
- log: zap.NewNop().Sugar(),
- }
- got := w.Handle(tt.args.ctx, tt.args.req)
- require.Equal(t, tt.responseCode, got.Result.Code)
- })
- }
-}
-
-func fixValidationConfig() serverlessv1alpha2.ValidationConfig {
- return serverlessv1alpha2.ValidationConfig{
- Function: serverlessv1alpha2.MinFunctionValues{
- Resources: serverlessv1alpha2.MinFunctionResourcesValues{
- MinRequestCPU: "10m",
- MinRequestMemory: "16Mi",
- },
- },
- BuildJob: serverlessv1alpha2.MinBuildJobValues{Resources: serverlessv1alpha2.MinBuildJobResourcesValues{
- MinRequestCPU: "200m",
- MinRequestMemory: "200Mi",
- }},
- }
-}
diff --git a/components/serverless/internal/webhook/webhook_config.go b/components/serverless/internal/webhook/webhook_config.go
deleted file mode 100644
index ec5509653..000000000
--- a/components/serverless/internal/webhook/webhook_config.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package webhook
-
-import (
- "os"
- "path/filepath"
-
- "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "gopkg.in/yaml.v2"
-)
-
-type FunctionResources struct {
- MinRequestCpu string `yaml:"minRequestCpu"`
- MinRequestMemory string `yaml:"minRequestMemory"`
-}
-
-type FunctionCfg struct {
- Resources FunctionResources `yaml:"resources"`
-}
-
-type BuildResources struct {
- MinRequestCpu string `yaml:"minRequestCpu"`
- MinRequestMemory string `yaml:"minRequestMemory"`
-}
-
-type BuildJob struct {
- Resources BuildResources `yaml:"resources"`
-}
-
-type WebhookConfig struct {
- DefaultRuntime string `yaml:"defaultRuntime"`
- Function FunctionCfg `yaml:"function"`
- BuildJob BuildJob `yaml:"buildJob"`
- ReservedEnvs []string `yaml:"reservedEnvs"`
-}
-
-func LoadWebhookCfg(path string) (WebhookConfig, error) {
- cfg := WebhookConfig{DefaultRuntime: string(v1alpha2.NodeJs20)}
-
- cleanPath := filepath.Clean(path)
- yamlFile, err := os.ReadFile(cleanPath)
- if err != nil {
- return WebhookConfig{}, err
- }
-
- err = yaml.Unmarshal(yamlFile, &cfg)
- return cfg, errors.Wrap(err, "while unmarshalling yaml")
-}
-
-func (wc WebhookConfig) ToValidationConfig() v1alpha2.ValidationConfig {
- return v1alpha2.ValidationConfig{
- ReservedEnvs: wc.ReservedEnvs,
- Function: v1alpha2.MinFunctionValues{
- Resources: v1alpha2.MinFunctionResourcesValues{
- MinRequestCPU: wc.Function.Resources.MinRequestCpu,
- MinRequestMemory: wc.Function.Resources.MinRequestMemory,
- },
- },
- BuildJob: v1alpha2.MinBuildJobValues{
- Resources: v1alpha2.MinBuildJobResourcesValues{
- MinRequestCPU: wc.BuildJob.Resources.MinRequestCpu,
- MinRequestMemory: wc.BuildJob.Resources.MinRequestMemory,
- },
- },
- }
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/function_resources_test.go b/components/serverless/pkg/apis/serverless/v1alpha2/function_resources_test.go
deleted file mode 100644
index 863cedd43..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/function_resources_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package v1alpha2_test
-
-import (
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "testing"
-
- "github.com/stretchr/testify/require"
-
- corev1 "k8s.io/api/core/v1"
- "k8s.io/apimachinery/pkg/api/resource"
-)
-
-func Test_EffectiveResource(t *testing.T) {
-
- MRuntimeResourcesBuilder := ResourceRequirementsBuilder{}.Limits("100m", "128Mi").Requests("50m", "64Mi")
- LRuntimeResources := ResourceRequirementsBuilder{}.Limits("200m", "256Mi").Requests("100m", "128Mi").BuildCoreV1()
- MRuntimeResources := MRuntimeResourcesBuilder.BuildCoreV1()
-
- testCases := map[string]struct {
- given *serverlessv1alpha2.ResourceRequirements
- expected corev1.ResourceRequirements
- }{
- "Should choose custom": {
- given: ResourceRequirementsBuilder{}.Limits("150m", "158Mi").Requests("90m", "84Mi").Build(),
- expected: ResourceRequirementsBuilder{}.Limits("150m", "158Mi").Requests("90m", "84Mi").BuildCoreV1(),
- },
- "Should choose default profile": {
- given: nil,
- expected: MRuntimeResources,
- },
- "Should choose declared profile ": {
- given: &serverlessv1alpha2.ResourceRequirements{Profile: "L"},
- expected: LRuntimeResources,
- },
- "Should choose default profile in case of not existing profile": {
- given: &serverlessv1alpha2.ResourceRequirements{Profile: "NOT EXISTS"},
- expected: MRuntimeResources,
- },
- }
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- // given
- presets, defaultPreset := fixPresetsConfig()
-
- // when
- effectiveResource := tc.given.EffectiveResource(defaultPreset, presets)
-
- // then
- require.EqualValues(t, tc.expected, effectiveResource)
- })
- }
-}
-
-func fixPresetsConfig() (map[string]corev1.ResourceRequirements, string) {
- return map[string]corev1.ResourceRequirements{
- "S": {
- Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("50m"), corev1.ResourceMemory: resource.MustParse("64Mi")},
- Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("25m"), corev1.ResourceMemory: resource.MustParse("32Mi")},
- },
- "M": {
- Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("128Mi")},
- Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("50m"), corev1.ResourceMemory: resource.MustParse("64Mi")},
- },
- "L": {
- Limits: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("200m"), corev1.ResourceMemory: resource.MustParse("256Mi")},
- Requests: corev1.ResourceList{corev1.ResourceCPU: resource.MustParse("100m"), corev1.ResourceMemory: resource.MustParse("128Mi")},
- },
- }, "M"
-}
-
-type ResourceRequirementsBuilder struct {
- limitsCpu, limitsMemory, requestsCpu, requestsMemory, profile string
-}
-
-func (b ResourceRequirementsBuilder) Limits(cpu, memory string) ResourceRequirementsBuilder {
- b.limitsCpu = cpu
- b.limitsMemory = memory
- return b
-}
-
-func (b ResourceRequirementsBuilder) Requests(cpu, memory string) ResourceRequirementsBuilder {
- b.requestsCpu = cpu
- b.requestsMemory = memory
- return b
-}
-
-func (b ResourceRequirementsBuilder) Profile(profile string) ResourceRequirementsBuilder {
- b.profile = profile
- return b
-}
-
-func (b ResourceRequirementsBuilder) BuildCoreV1() corev1.ResourceRequirements {
- limits := corev1.ResourceList{}
- if b.limitsCpu != "" {
- limits[corev1.ResourceCPU] = resource.MustParse(b.limitsCpu)
- }
- if b.limitsMemory != "" {
- limits[corev1.ResourceMemory] = resource.MustParse(b.limitsMemory)
- }
- if len(limits) == 0 {
- limits = nil
- }
- requests := corev1.ResourceList{}
- if b.requestsCpu != "" {
- requests[corev1.ResourceCPU] = resource.MustParse(b.requestsCpu)
- }
- if b.requestsMemory != "" {
- requests[corev1.ResourceMemory] = resource.MustParse(b.requestsMemory)
- }
- if len(requests) == 0 {
- requests = nil
- }
- return corev1.ResourceRequirements{
- Limits: limits,
- Requests: requests,
- }
-}
-
-func (b ResourceRequirementsBuilder) Build() *serverlessv1alpha2.ResourceRequirements {
- res := b.BuildCoreV1()
- return &serverlessv1alpha2.ResourceRequirements{
- Resources: &res,
- Profile: b.profile,
- }
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/function_types.go b/components/serverless/pkg/apis/serverless/v1alpha2/function_types.go
deleted file mode 100644
index 9a1fbdc9b..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/function_types.go
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
-Copyright 2022.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package v1alpha2
-
-import (
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-// Runtime specifies the name of the Function's runtime.
-type Runtime string
-
-const (
- // Deprecated: Python39 will be removed soon
- Python39 Runtime = "python39"
- Python312 Runtime = "python312"
- // Deprecated: Nodejs18 will be removed soon
- NodeJs18 Runtime = "nodejs18"
- NodeJs20 Runtime = "nodejs20"
-)
-
-type FunctionType string
-
-const (
- FunctionTypeInline FunctionType = "inline"
- FunctionTypeGit FunctionType = "git"
-)
-
-type Source struct {
- // Defines the Function as git-sourced. Can't be used together with **Inline**.
- // +optional
- GitRepository *GitRepositorySource `json:"gitRepository,omitempty"`
-
- // Defines the Function as the inline Function. Can't be used together with **GitRepository**.
- // +optional
- Inline *InlineSource `json:"inline,omitempty"`
-}
-
-type InlineSource struct {
- // Specifies the Function's full source code.
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:MinLength=1
- Source string `json:"source"`
-
- // Specifies the Function's dependencies.
- //+optional
- Dependencies string `json:"dependencies,omitempty"`
-}
-
-type GitRepositorySource struct {
- // +kubebuilder:validation:Required
-
- // Specifies the URL of the Git repository with the Function's code and dependencies.
- // Depending on whether the repository is public or private and what authentication method is used to access it,
- // the URL must start with the `http(s)`, `git`, or `ssh` prefix.
- URL string `json:"url"`
-
- // Specifies the authentication method. Required for SSH.
- // +optional
- Auth *RepositoryAuth `json:"auth,omitempty"`
-
- // +kubebuilder:validation:XValidation:message="BaseDir is required and cannot be empty",rule="has(self.baseDir) && (self.baseDir.trim().size() != 0)"
- // +kubebuilder:validation:XValidation:message="Reference is required and cannot be empty",rule="has(self.reference) && (self.reference.trim().size() != 0)"
- Repository `json:",inline"`
-}
-
-// RepositoryAuth defines authentication method used for repository operations
-type RepositoryAuth struct {
- // +kubebuilder:validation:Required
- // Defines the repository authentication method. The value is either `basic` if you use a password or token,
- // or `key` if you use an SSH key.
- Type RepositoryAuthType `json:"type"`
-
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:XValidation:message="SecretName is required and cannot be empty",rule="self.trim().size() != 0"
-
- // Specifies the name of the Secret with credentials used by the Function Controller
- // to authenticate to the Git repository in order to fetch the Function's source code and dependencies.
- // This Secret must be stored in the same Namespace as the Function CR.
- SecretName string `json:"secretName"`
-}
-
-// RepositoryAuthType is the enum of available authentication types
-// +kubebuilder:validation:Enum=basic;key
-type RepositoryAuthType string
-
-const (
- RepositoryAuthBasic RepositoryAuthType = "basic"
- RepositoryAuthSSHKey RepositoryAuthType = "key"
-)
-
-type Template struct {
- // Deprecated: Use **FunctionSpec.Labels** to label Function's Pods.
- // +optional
- Labels map[string]string `json:"labels,omitempty"`
- // Deprecated: Use **FunctionSpec.Annotations** to annotate Function's Pods.
- // +optional
- Annotations map[string]string `json:"annotations,omitempty"`
-}
-
-type ResourceRequirements struct {
- // Defines the name of the predefined set of values of the resource.
- // Can't be used together with **Resources**.
- // +optional
- Profile string `json:"profile,omitempty"`
-
- // Defines the amount of resources available for the Pod.
- // Can't be used together with **Profile**.
- // For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
- // +optional
- Resources *v1.ResourceRequirements `json:"resources,omitempty"`
-}
-
-type ScaleConfig struct {
- // Defines the minimum number of Function's Pods to run at a time.
- // +kubebuilder:validation:Minimum:=1
- MinReplicas *int32 `json:"minReplicas"`
-
- // Defines the maximum number of Function's Pods to run at a time.
- // +kubebuilder:validation:Minimum:=1
- MaxReplicas *int32 `json:"maxReplicas"`
-}
-
-type ResourceConfiguration struct {
- // Specifies resources requested by the build Job's Pod.
- // +optional
- // +kubebuilder:validation:XValidation:message="Use profile or resources",rule="has(self.profile) && !has(self.resources) || !has(self.profile) && has(self.resources)"
- // +kubebuilder:validation:XValidation:message="Invalid profile, please use one of: ['local-dev','slow','normal','fast']",rule="(!has(self.profile) || self.profile in ['local-dev','slow','normal','fast'])"
- Build *ResourceRequirements `json:"build,omitempty"`
-
- // Specifies resources requested by the Function's Pod.
- // +optional
- // +kubebuilder:validation:XValidation:message="Use profile or resources",rule="has(self.profile) && !has(self.resources) || !has(self.profile) && has(self.resources)"
- // +kubebuilder:validation:XValidation:message="Invalid profile, please use one of: ['XS','S','M','L','XL']",rule="(!has(self.profile) || self.profile in ['XS','S','M','L','XL'])"
- Function *ResourceRequirements `json:"function,omitempty"`
-}
-
-type SecretMount struct {
- // Specifies the name of the Secret in the Function's Namespace.
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:MaxLength=253
- // +kubebuilder:validation:MinLength=1
- SecretName string `json:"secretName"`
-
- // Specifies the path within the container where the Secret should be mounted.
- // +kubebuilder:validation:Required
- // +kubebuilder:validation:MinLength=1
- MountPath string `json:"mountPath"`
-}
-
-const (
- FunctionResourcesPresetLabel = "serverless.kyma-project.io/function-resources-preset"
- BuildResourcesPresetLabel = "serverless.kyma-project.io/build-resources-preset"
-)
-
-// Defines the desired state of the Function
-type FunctionSpec struct {
- // Specifies the runtime of the Function. The available values are `nodejs18` - deprecated, `nodejs20`, `python39` - deprecated, and `python312`.
- // +kubebuilder:validation:Enum=nodejs18;nodejs20;python39;python312;
- Runtime Runtime `json:"runtime"`
-
- // Specifies the runtime image used instead of the default one.
- // +optional
- RuntimeImageOverride string `json:"runtimeImageOverride,omitempty"`
-
- // Contains the Function's source code configuration.
- // +kubebuilder:validation:XValidation:message="Use GitRepository or Inline source",rule="has(self.gitRepository) && !has(self.inline) || !has(self.gitRepository) && has(self.inline)"
- // +kubebuilder:validation:Required
- Source Source `json:"source"`
-
- // Specifies an array of key-value pairs to be used as environment variables for the Function.
- // You can define values as static strings or reference values from ConfigMaps or Secrets.
- // For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/).
- // +kubebuilder:validation:XValidation:message="Following envs are reserved and cannot be used: ['FUNC_RUNTIME','FUNC_HANDLER','FUNC_PORT','MOD_NAME','NODE_PATH','PYTHONPATH']",rule="(self.all(e, !(e.name in ['FUNC_RUNTIME','FUNC_HANDLER','FUNC_PORT','MOD_NAME','NODE_PATH','PYTHONPATH'])))"
- Env []v1.EnvVar `json:"env,omitempty"`
-
- // Specifies resources requested by the Function and the build Job.
- // +optional
- ResourceConfiguration *ResourceConfiguration `json:"resourceConfiguration,omitempty"`
-
- // Defines the minimum and maximum number of Function's Pods to run at a time.
- // When it is configured, a HorizontalPodAutoscaler will be deployed and will control the **Replicas** field
- // to scale the Function based on the CPU utilisation.
- // +optional
- // +kubebuilder:validation:XValidation:message="minReplicas should be less than or equal maxReplicas",rule="self.minReplicas <= self.maxReplicas"
- ScaleConfig *ScaleConfig `json:"scaleConfig,omitempty"`
-
- // Defines the exact number of Function's Pods to run at a time.
- // If **ScaleConfig** is configured, or if the Function is targeted by an external scaler,
- // then the **Replicas** field is used by the relevant HorizontalPodAutoscaler to control the number of active replicas.
- // +kubebuilder:validation:Minimum=0
- // +kubebuilder:default:=1
- // +optional
- Replicas *int32 `json:"replicas,omitempty"`
-
- // Deprecated: Use **Labels** and **Annotations** to label and/or annotate Function's Pods.
- // +optional
- // +kubebuilder:validation:XValidation:message="Not supported: Use spec.labels and spec.annotations to label and/or annotate Function's Pods.",rule="!has(self.labels) && !has(self.annotations)"
- Template *Template `json:"template,omitempty"`
-
- // Specifies Secrets to mount into the Function's container filesystem.
- SecretMounts []SecretMount `json:"secretMounts,omitempty"`
-
- // Defines labels used in Deployment's PodTemplate and applied on the Function's runtime Pod.
- // +optional
- // +kubebuilder:validation:XValidation:message="Labels has key starting with serverless.kyma-project.io/ which is not allowed",rule="!(self.exists(e, e.startsWith('serverless.kyma-project.io/')))"
- // +kubebuilder:validation:XValidation:message="Label value cannot be longer than 63",rule="self.all(e, size(e)<64)"
- Labels map[string]string `json:"labels,omitempty"`
-
- // Defines annotations used in Deployment's PodTemplate and applied on the Function's runtime Pod.
- // +optional
- // +kubebuilder:validation:XValidation:message="Annotations has key starting with serverless.kyma-project.io/ which is not allowed",rule="!(self.exists(e, e.startsWith('serverless.kyma-project.io/')))"
- Annotations map[string]string `json:"annotations,omitempty"`
-}
-
-// TODO: Status related things needs to be developed.
-type ConditionType string
-
-const (
- ConditionRunning ConditionType = "Running"
- ConditionConfigurationReady ConditionType = "ConfigurationReady"
- ConditionBuildReady ConditionType = "BuildReady"
-)
-
-type ConditionReason string
-
-const (
- ConditionReasonFunctionSpec ConditionReason = "InvalidFunctionSpec"
- ConditionReasonConfigMapCreated ConditionReason = "ConfigMapCreated"
- ConditionReasonConfigMapUpdated ConditionReason = "ConfigMapUpdated"
- ConditionReasonSourceUpdated ConditionReason = "SourceUpdated"
- ConditionReasonSourceUpdateFailed ConditionReason = "SourceUpdateFailed"
- ConditionReasonJobFailed ConditionReason = "JobFailed"
- ConditionReasonJobCreated ConditionReason = "JobCreated"
- ConditionReasonJobUpdated ConditionReason = "JobUpdated"
- ConditionReasonJobRunning ConditionReason = "JobRunning"
- ConditionReasonJobsDeleted ConditionReason = "JobsDeleted"
- ConditionReasonJobFinished ConditionReason = "JobFinished"
- ConditionReasonDeploymentCreated ConditionReason = "DeploymentCreated"
- ConditionReasonDeploymentUpdated ConditionReason = "DeploymentUpdated"
- ConditionReasonDeploymentFailed ConditionReason = "DeploymentFailed"
- ConditionReasonDeploymentWaiting ConditionReason = "DeploymentWaiting"
- ConditionReasonDeploymentReady ConditionReason = "DeploymentReady"
- ConditionReasonServiceCreated ConditionReason = "ServiceCreated"
- ConditionReasonServiceUpdated ConditionReason = "ServiceUpdated"
- ConditionReasonServiceFailed ConditionReason = "ServiceFailed"
- ConditionReasonHorizontalPodAutoscalerCreated ConditionReason = "HorizontalPodAutoscalerCreated"
- ConditionReasonHorizontalPodAutoscalerUpdated ConditionReason = "HorizontalPodAutoscalerUpdated"
- ConditionReasonMinReplicasNotAvailable ConditionReason = "MinReplicasNotAvailable"
-)
-
-type Condition struct {
- // Specifies the type of the Function's condition.
- Type ConditionType `json:"type,omitempty"`
- // Specifies the status of the condition. The value is either `True`, `False`, or `Unknown`.
- Status v1.ConditionStatus `json:"status"`
- // Specifies the last time the condition transitioned from one status to another.
- LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
- // Specifies the reason for the condition's last transition.
- Reason ConditionReason `json:"reason,omitempty"`
- // Provides a human-readable message indicating details about the transition.
- Message string `json:"message,omitempty"`
-}
-
-type Repository struct {
- // Specifies the relative path to the Git directory that contains the source code
- // from which the Function is built.
- BaseDir string `json:"baseDir,omitempty"`
-
- // Specifies either the branch name, tag or commit revision from which the Function Controller
- // automatically fetches the changes in the Function's code and dependencies.
- Reference string `json:"reference,omitempty"`
-}
-
-// FunctionStatus defines the observed state of the Function
-type FunctionStatus struct {
- // Specifies the **Runtime** type of the Function.
- Runtime Runtime `json:"runtime,omitempty"`
- // Specifies the preset used for the function
- FunctionResourceProfile string `json:"functionResourceProfile,omitempty"`
- // Specifies the preset used for the build job
- BuildResourceProfile string `json:"buildResourceProfile,omitempty"`
- // Specifies an array of conditions describing the status of the parser.
- Conditions []Condition `json:"conditions,omitempty"`
- // Specify the repository which was used to build the function.
- Repository `json:",inline,omitempty"`
- // Specifies the total number of non-terminated Pods targeted by this Function.
- Replicas int32 `json:"replicas,omitempty"`
- // Specifies the Pod selector used to match Pods in the Function's Deployment.
- PodSelector string `json:"podSelector,omitempty"`
- // Specifies the commit hash used to build the Function.
- Commit string `json:"commit,omitempty"`
- // Specifies the image version used to build and run the Function's Pods.
- RuntimeImage string `json:"runtimeImage,omitempty"`
- // Deprecated: Specifies the runtime image version which overrides the **RuntimeImage** status parameter.
- // **RuntimeImageOverride** exists for historical compatibility
- // and should be removed with v1alpha3 version.
- RuntimeImageOverride string `json:"runtimeImageOverride,omitempty"`
-}
-
-const (
- FunctionNameLabel = "serverless.kyma-project.io/function-name"
- FunctionManagedByLabel = "serverless.kyma-project.io/managed-by"
- FunctionControllerValue = "function-controller"
- FunctionUUIDLabel = "serverless.kyma-project.io/uuid"
- FunctionResourceLabel = "serverless.kyma-project.io/resource"
- FunctionResourceLabelDeploymentValue = "deployment"
- FunctionResourceLabelUserValue = "user"
- PodAppNameLabel = "app.kubernetes.io/name"
-)
-
-//+kubebuilder:object:root=true
-//+kubebuilder:subresource:status
-//+kubebuilder:storageversion
-//+kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.podSelector
-//+kubebuilder:printcolumn:name="Configured",type="string",JSONPath=".status.conditions[?(@.type=='ConfigurationReady')].status"
-//+kubebuilder:printcolumn:name="Built",type="string",JSONPath=".status.conditions[?(@.type=='BuildReady')].status"
-//+kubebuilder:printcolumn:name="Running",type="string",JSONPath=".status.conditions[?(@.type=='Running')].status"
-//+kubebuilder:printcolumn:name="Runtime",type="string",JSONPath=".spec.runtime"
-//+kubebuilder:printcolumn:name="Version",type="integer",JSONPath=".metadata.generation"
-//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
-
-// A simple code snippet that you can run without provisioning or managing servers.
-// It implements the exact business logic you define.
-// A Function is based on the Function custom resource (CR) and can be written in either Node.js or Python.
-// A Function can perform a business logic of its own. You can also bind it to an instance of a service
-// and configure it to be triggered whenever it receives a particular event type from the service
-// or a call is made to the service's API.
-// Functions are executed only if they are triggered by an event or an API call.
-type Function struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ObjectMeta `json:"metadata,omitempty"`
-
- Spec FunctionSpec `json:"spec,omitempty"`
- Status FunctionStatus `json:"status,omitempty"`
-}
-
-func (f *Function) TypeOf(t FunctionType) bool {
- switch t {
-
- case FunctionTypeInline:
- return f.Spec.Source.Inline != nil
-
- case FunctionTypeGit:
- return f.Spec.Source.GitRepository != nil
-
- default:
- return false
- }
-}
-
-func (f *Function) EffectiveRuntime() string {
- if f.Spec.RuntimeImageOverride != "" {
- return f.Spec.RuntimeImageOverride
- }
- return string(f.Spec.Runtime)
-}
-
-//+kubebuilder:object:root=true
-
-// FunctionList contains a list of Function
-type FunctionList struct {
- metav1.TypeMeta `json:",inline"`
- metav1.ListMeta `json:"metadata,omitempty"`
- Items []Function `json:"items"`
-}
-
-// nolint
-func init() {
- SchemeBuilder.Register(
- &Function{},
- &FunctionList{},
- )
-}
-
-func (f Function) IsUpdating() bool {
- conditions := []ConditionType{ConditionBuildReady, ConditionConfigurationReady, ConditionRunning}
- status := f.Status
- for _, c := range conditions {
- if !status.Condition(c).IsTrue() {
- return true
- }
- }
- return false
-}
-
-func (s *FunctionStatus) Condition(c ConditionType) *Condition {
- for _, cond := range s.Conditions {
- if cond.Type == c {
- return &cond
- }
- }
- return nil
-}
-
-func (c *Condition) IsTrue() bool {
- return c.Status == v1.ConditionTrue
-}
-
-func (l *Condition) Equal(r *Condition) bool {
- if l == nil && r == nil {
- return true
- }
-
- if l.Type != r.Type ||
- l.Status != r.Status ||
- l.Reason != r.Reason ||
- l.Message != r.Message ||
- !l.LastTransitionTime.Equal(&r.LastTransitionTime) {
- return false
- }
- return true
-}
-
-func (rc *ResourceRequirements) EffectiveResource(defaultProfile string, profiles map[string]v1.ResourceRequirements) v1.ResourceRequirements {
- if rc == nil {
- return profiles[defaultProfile]
- }
- profileResources, found := profiles[rc.Profile]
- if found {
- return profileResources
- }
- if rc.Resources != nil {
- return *rc.Resources
- }
- return profiles[defaultProfile]
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/function_types_test.go b/components/serverless/pkg/apis/serverless/v1alpha2/function_types_test.go
deleted file mode 100644
index d8381805f..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/function_types_test.go
+++ /dev/null
@@ -1,139 +0,0 @@
-package v1alpha2
-
-import (
- "testing"
-
- v1 "k8s.io/api/core/v1"
-)
-
-func TestFunction_TypeOf(t *testing.T) {
- testCases := map[string]struct {
- function *Function
- args FunctionType
- want bool
- }{
- "Have Inline Function want Inline Function": {
- args: FunctionTypeInline,
- function: &Function{Spec: FunctionSpec{Source: Source{Inline: &InlineSource{
- Source: "aaa",
- Dependencies: "bbb",
- }}}},
- want: true,
- },
- "Have Git function want Git function": {
- args: FunctionTypeGit,
- function: &Function{Spec: FunctionSpec{Source: Source{GitRepository: &GitRepositorySource{
- URL: "bbb",
- }}}},
- want: true,
- },
- "Have Inline Function want Git Function": {
- args: FunctionTypeGit,
- function: &Function{Spec: FunctionSpec{Source: Source{Inline: &InlineSource{
- Source: "aaa",
- Dependencies: "bbb",
- }}}},
- want: false,
- },
- "Have Git Function want Inline Function": {
- args: FunctionTypeInline,
- function: &Function{Spec: FunctionSpec{Source: Source{GitRepository: &GitRepositorySource{
- URL: "bbb",
- }}}},
- want: false,
- },
- }
-
- for testName, testCase := range testCases {
- t.Run(testName, func(t *testing.T) {
-
- if got := testCase.function.TypeOf(testCase.args); got != testCase.want {
- t.Errorf("TypeOf() = %v, want %v", got, testCase.want)
- }
- })
- }
-}
-
-func TestFunction_IsUpdating(t *testing.T) {
-
- tests := []struct {
- name string
- function *Function
- want bool
- }{
- {
- name: "Function is updating - running",
- function: &Function{
- Status: FunctionStatus{
- Conditions: []Condition{
- {
- Type: ConditionBuildReady,
- Status: v1.ConditionTrue,
- },
- {
- Type: ConditionConfigurationReady,
- Status: v1.ConditionTrue,
- },
- {
- Type: ConditionRunning,
- Status: v1.ConditionFalse,
- },
- },
- },
- },
- want: true,
- },
- {
- name: "Function is updating - building",
- function: &Function{
- Status: FunctionStatus{
- Conditions: []Condition{
- {
- Type: ConditionBuildReady,
- Status: v1.ConditionFalse,
- },
- {
- Type: ConditionConfigurationReady,
- Status: v1.ConditionTrue,
- },
- {
- Type: ConditionRunning,
- Status: v1.ConditionTrue,
- },
- },
- },
- },
- want: true,
- },
- {
- name: "Function is not updating",
- function: &Function{
- Status: FunctionStatus{
- Conditions: []Condition{
- {
- Type: ConditionBuildReady,
- Status: v1.ConditionTrue,
- },
- {
- Type: ConditionConfigurationReady,
- Status: v1.ConditionTrue,
- },
- {
- Type: ConditionRunning,
- Status: v1.ConditionTrue,
- },
- },
- },
- },
- want: false,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
-
- if got := tt.function.IsUpdating(); got != tt.want {
- t.Errorf("Function.IsUpdating() = %v, want %v", got, tt.want)
- }
- })
- }
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/function_validation.go b/components/serverless/pkg/apis/serverless/v1alpha2/function_validation.go
deleted file mode 100644
index f2678dec9..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/function_validation.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package v1alpha2
-
-import (
- "fmt"
- "net/url"
- "regexp"
-)
-
-type MinFunctionResourcesValues struct {
- MinRequestCPU string
- MinRequestMemory string
-}
-
-type MinBuildJobResourcesValues struct {
- MinRequestCPU string
- MinRequestMemory string
-}
-
-type MinFunctionValues struct {
- Resources MinFunctionResourcesValues
-}
-
-type MinBuildJobValues struct {
- Resources MinBuildJobResourcesValues
-}
-
-type ValidationConfig struct {
- ReservedEnvs []string
- Function MinFunctionValues
- BuildJob MinBuildJobValues
-}
-
-func urlIsSSH(repoURL string) bool {
- exp, err := regexp.Compile(`((git|ssh)|(git@[\w\.]+))(:(//)?)([\w\.@\:/\-~]+)(/)?`)
- if err != nil {
- panic(err)
- }
-
- return exp.MatchString(repoURL)
-}
-
-func ValidateGitRepoURL(gitRepo *GitRepositorySource) error {
- if urlIsSSH(gitRepo.URL) {
- return nil
- } else if _, err := url.ParseRequestURI(gitRepo.URL); err != nil {
- return fmt.Errorf("source.gitRepository.URL: %v", err)
- }
- return nil
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/function_x_validation_test.go b/components/serverless/pkg/apis/serverless/v1alpha2/function_x_validation_test.go
deleted file mode 100644
index c7e448372..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/function_x_validation_test.go
+++ /dev/null
@@ -1,1027 +0,0 @@
-package v1alpha2_test
-
-import (
- "context"
- "strings"
- "testing"
-
- "github.com/kyma-project/serverless/components/serverless/internal/testenv"
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- corev1 "k8s.io/api/core/v1"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-func Test_XKubernetesValidations_Valid(t *testing.T) {
- fixMetadata := metav1.ObjectMeta{
- GenerateName: "test",
- Namespace: "test",
- }
- ctx := context.TODO()
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
-
- testNs := corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- }
- err := k8sClient.Create(ctx, &testNs)
- require.NoError(t, err)
- //GIVEN
- testCases := map[string]struct {
- fn *serverlessv1alpha2.Function
- }{
- "Profile set only for function": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "XS",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Profile set only for buildJob": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Build profile local-dev": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "local-dev",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Build profile slow": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "slow",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Build profile normal": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "normal",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Build profile fast": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Function profile S": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "S",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Function profile M": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Function profile L": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Function profile XL": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "XL",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Resource set only for buildJob": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{}}},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "Resource set only for function": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{Resources: &corev1.ResourceRequirements{}}},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "labels has value with special characters similar to restricted one ": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "serverless$kyma-project#io/abc": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "labels has value restricted domain without path ": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "serverless.kyma-project.io": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "labels not use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "my.label.com": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "similar label not use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "serverless.kyma-project.label.com": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "annotations has value with special characters similar to restricted one ": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "serverless$kyma-project#io/abc": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "annotations has value restricted domain without path ": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "serverless.kyma-project.io": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "annotations not use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "my.label.com": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "annotations label not use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "serverless.kyma-project.label.com": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- },
- "allowed runtime: nodejs18": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs18,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- },
- },
- },
- "allowed runtime: nodejs20": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.NodeJs20,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- },
- },
- },
- "allowed runtime: python39": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python39,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- },
- },
- },
- "allowed runtime: python312": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- },
- },
- },
- "allowed envs": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Env: []corev1.EnvVar{{Name: "TEST_ENV"}, {Name: "MY_ENV"}},
- },
- },
- },
- "gitRepository used as source": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "base-dir",
- Reference: "ref",
- },
- },
- },
- },
- },
- },
- "Git source has auth with key Type": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- Auth: &serverlessv1alpha2.RepositoryAuth{
- Type: "key",
- SecretName: "secret",
- },
- },
- },
- },
- },
- },
- "Git source has auth with basic Type": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- Auth: &serverlessv1alpha2.RepositoryAuth{
- Type: "basic",
- SecretName: "secret",
- },
- },
- },
- },
- },
- },
- "label value length is 63": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "abc"}},
- Labels: map[string]string{
- strings.Repeat("a", 63): "test",
- },
- },
- },
- },
- "secretMount": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "abc"}},
- SecretMounts: []serverlessv1alpha2.SecretMount{{MountPath: "/path", SecretName: "secret-name"}},
- },
- },
- },
- }
-
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- //WHEN
- err := k8sClient.Create(ctx, tc.fn)
- //THEN
- require.NoError(t, err)
- })
- }
-}
-func Test_XKubernetesValidations_Invalid(t *testing.T) {
- fixMetadata := metav1.ObjectMeta{
- GenerateName: "test",
- Namespace: "test",
- }
- ctx := context.TODO()
- k8sClient, testEnv := testenv.Start(t)
- defer testenv.Stop(t, testEnv)
- testNs := corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{Name: "test"},
- }
- err := k8sClient.Create(ctx, &testNs)
- require.NoError(t, err)
-
- //GIVEN
- testCases := map[string]struct {
- fn *serverlessv1alpha2.Function
- expectedErrMsg string
- fieldPath string
- expectedCause metav1.CauseType
- }{
- "Invalid metadata.name": {
- // metadata use kubernetes default validator - this test is to make sure it works
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: ".invalid-name",
- Namespace: "test",
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "some-source",
- },
- },
- },
- },
- expectedErrMsg: "Invalid value: \".invalid-name\"",
- fieldPath: "metadata.name",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Invalid metadata.label": {
- // metadata use kubernetes default validator - this test is to make sure it works
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: metav1.ObjectMeta{
- Name: "function-name",
- Namespace: "test",
- Labels: map[string]string{
- ".invalid-label": "value",
- },
- },
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: "some-source",
- },
- },
- },
- },
- expectedErrMsg: "Invalid value: \".invalid-label\": name part must consist of alphanumeric characters",
- fieldPath: "metadata.labels",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Resource and Profiles used together in function": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- Resources: &corev1.ResourceRequirements{},
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- expectedErrMsg: "Use profile or resources",
- fieldPath: "spec.resourceConfiguration.function",
- },
- "Resource and Profiles used together in buildJob": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- Resources: &corev1.ResourceRequirements{},
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- expectedErrMsg: "Use profile or resources",
- fieldPath: "spec.resourceConfiguration.build",
- },
- "Invalid profile in build": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "LL",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- expectedErrMsg: "Invalid profile, please use one of: [",
- fieldPath: "spec.resourceConfiguration.build",
- },
- "Invalid profile in function": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "SS",
- }},
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- expectedErrMsg: "Invalid profile, please use one of: [",
- fieldPath: "spec.resourceConfiguration.function",
- },
- "labels use exact restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "serverless.kyma-project.io/": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.labels",
- expectedErrMsg: "Labels has key starting with ",
- },
- "labels use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "serverless.kyma-project.io/abc": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.labels",
- expectedErrMsg: "Labels has key starting with ",
- },
- "labels has many values with incorrect one": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Labels: map[string]string{
- "app": "mySuperApp",
- "serverless.kyma-project.io/abc": "labelValue",
- "service": "mySvc",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.labels",
- expectedErrMsg: "Labels has key starting with ",
- },
- "template.labels is not supported": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Template: &serverlessv1alpha2.Template{
- Labels: map[string]string{
- "app": "mySuperApp",
- "serverless.kyma-project.io/abc": "labelValue",
- "service": "mySvc",
- },
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.template",
- expectedErrMsg: "Not supported: Use spec.labels and spec.annotations to label and/or annotate Function's Pods.",
- },
- "annotations use exact restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "serverless.kyma-project.io/": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.annotations",
- expectedErrMsg: "Annotations has key starting with ",
- },
- "annotations has many values with incorrect one": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "app": "mySuperApp",
- "serverless.kyma-project.io/abc": "labelValue",
- "service": "mySvc",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.annotations",
- expectedErrMsg: "Annotations has key starting with ",
- },
- "annotations use restricted domain": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Annotations: map[string]string{
- "serverless.kyma-project.io/abc": "labelValue",
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.annotations",
- expectedErrMsg: "Annotations has key starting with ",
- },
- "template.annotations is not supported": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Template: &serverlessv1alpha2.Template{
- Annotations: map[string]string{
- "app": "mySuperApp",
- "serverless.kyma-project.io/abc": "labelValue",
- "service": "mySvc",
- },
- },
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- },
- },
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- fieldPath: "spec.template",
- expectedErrMsg: "Not supported: Use spec.labels and spec.annotations to label and/or annotate Function's Pods.",
- },
- "disallowed runtime: custom": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Runtime("custom"),
- },
- },
- expectedCause: metav1.CauseTypeFieldValueNotSupported,
- fieldPath: "spec.runtime",
- expectedErrMsg: `Unsupported value: "custom"`,
- },
- "reserved env: FUNC_RUNTIME": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "FUNC_RUNTIME"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "reserved env: FUNC_HANDLER": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "FUNC_HANDLER"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "reserved env: FUNC_PORT": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "FUNC_PORT"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "reserved env: MOD_NAME": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "MOD_NAME"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "reserved env: NODE_PATH": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "NODE_PATH"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "reserved env: PYTHONPATH": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Runtime: serverlessv1alpha2.Python312,
- Env: []corev1.EnvVar{
- {Name: "TEST2"},
- {Name: "PYTHONPATH"},
- {Name: "TEST"},
- },
- },
- },
- expectedErrMsg: "Following envs are reserved",
- fieldPath: "spec.env",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "GitRepository and Inline source used together": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: nil,
- Inline: nil,
- },
- },
- },
- expectedErrMsg: "Use GitRepository or Inline source",
- fieldPath: "spec.source",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Neither GitRepository nor Inline source was used": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{},
- },
- },
- expectedErrMsg: "Use GitRepository or Inline source",
- fieldPath: "spec.source",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Secret Mount name is empty": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {SecretName: "", MountPath: "/path"},
- },
- },
- },
- expectedErrMsg: "should be at least 1 chars long",
- fieldPath: "spec.secretMounts[0].secretName",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Secret Mount path is empty": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- SecretMounts: []serverlessv1alpha2.SecretMount{
- {SecretName: "my-secret", MountPath: ""},
- },
- },
- },
- expectedErrMsg: "should be at least 1 chars long",
- fieldPath: "spec.secretMounts[0].mountPath",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Label value is longer than 63 charts": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{Inline: &serverlessv1alpha2.InlineSource{Source: "a"}},
- Labels: map[string]string{
- strings.Repeat("a", 64): "test",
- },
- },
- },
- expectedErrMsg: "Label value cannot be longer than 63",
- fieldPath: "spec.labels",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Inline source is empty": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{},
- },
- },
- },
- expectedErrMsg: "should be at least 1 chars long",
- fieldPath: "spec.source.inline.source",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Git source has empty BaseDir": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: " ",
- Reference: "ref",
- },
- },
- },
- },
- },
- expectedErrMsg: "BaseDir is required and cannot be empty",
- fieldPath: "spec.source.gitRepository",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Git source has empty Reference": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: " ",
- },
- },
- },
- },
- },
- expectedErrMsg: "Reference is required and cannot be empty",
- fieldPath: "spec.source.gitRepository",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Git source has empty SecretName": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- Auth: &serverlessv1alpha2.RepositoryAuth{
- Type: "key",
- SecretName: " ",
- },
- },
- },
- },
- },
- expectedErrMsg: "SecretName is required and cannot be empty",
- fieldPath: "spec.source.gitRepository.auth.secretName",
- expectedCause: metav1.CauseTypeFieldValueInvalid,
- },
- "Git source auth has incorrect Type": {
- fn: &serverlessv1alpha2.Function{
- ObjectMeta: fixMetadata,
- Spec: serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- GitRepository: &serverlessv1alpha2.GitRepositorySource{
- Repository: serverlessv1alpha2.Repository{
- BaseDir: "dir",
- Reference: "ref",
- },
- Auth: &serverlessv1alpha2.RepositoryAuth{
- Type: "custom",
- SecretName: "secret",
- },
- },
- },
- },
- },
- expectedErrMsg: `Unsupported value: "custom"`,
- fieldPath: "spec.source.gitRepository.auth.type",
- expectedCause: metav1.CauseTypeFieldValueNotSupported,
- },
- }
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- //WHEN
- err := k8sClient.Create(ctx, tc.fn)
-
- //THEN
- require.Error(t, err)
- errStatus, ok := err.(*k8serrors.StatusError)
- require.True(t, ok)
- causes := errStatus.Status().Details.Causes
- require.Len(t, causes, 1)
- cause := causes[0]
- assert.Equal(t, tc.expectedCause, cause.Type)
- assert.Equal(t, tc.fieldPath, cause.Field)
- assert.NotEmpty(t, tc.expectedErrMsg, "cause message: %s", cause.Message)
- //TODO: better will be Equal comparison
- assert.Contains(t, cause.Message, tc.expectedErrMsg)
- })
- }
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/groupversion_info.go b/components/serverless/pkg/apis/serverless/v1alpha2/groupversion_info.go
deleted file mode 100644
index 3b7b20f30..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/groupversion_info.go
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-// Package v1alpha2 contains API Schema definitions for the serverless v1alpha2 API group
-// +k8s:openapi-gen=true
-// +k8s:deepcopy-gen=package,register
-// +k8s:conversion-gen=github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless
-// +k8s:defaulter-gen=TypeMeta
-// +groupName=serverless.kyma-project.io
-// +kubebuilder:object:generate=true
-// +groupName=serverless.kyma-project.io
-package v1alpha2
-
-import (
- "k8s.io/apimachinery/pkg/runtime/schema"
- "sigs.k8s.io/controller-runtime/pkg/scheme"
-)
-
-const (
- FunctionKind = "Function"
- FunctionVersion = "v1alpha2"
- FunctionGroup = "serverless.kyma-project.io"
- FunctionApiVersion = FunctionGroup + "/" + FunctionVersion
-)
-
-var (
- // GroupVersion is group version used to register these objects
- GroupVersion = schema.GroupVersion{Group: FunctionGroup, Version: FunctionVersion}
-
- // SchemeBuilder is used to add go types to the GroupVersionKind scheme
- SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
-
- // AddToScheme adds the types in this group-version to the given scheme.
- AddToScheme = SchemeBuilder.AddToScheme
-)
-
-// Resource is required by pkg/client/listers/...
-func Resource(resource string) schema.GroupResource {
- return GroupVersion.WithResource(resource).GroupResource()
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/runtime_validation.go b/components/serverless/pkg/apis/serverless/v1alpha2/runtime_validation.go
deleted file mode 100644
index aecaef477..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/runtime_validation.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package v1alpha2
-
-import (
- "errors"
- "fmt"
- "strings"
-)
-
-func ValidateDependencies(runtime Runtime, dependencies string) error {
- switch runtime {
- case NodeJs18, NodeJs20:
- return validateNodeJSDependencies(dependencies)
- case Python39, Python312:
- return nil
- }
- return fmt.Errorf("cannot find runtime: %s", runtime)
-}
-
-func validateNodeJSDependencies(dependencies string) error {
- if deps := strings.TrimSpace(dependencies); deps != "" && (deps[0] != '{' || deps[len(deps)-1] != '}') {
- return errors.New("deps should start with '{' and end with '}'")
- }
- return nil
-}
diff --git a/components/serverless/pkg/apis/serverless/v1alpha2/zz_generated.deepcopy.go b/components/serverless/pkg/apis/serverless/v1alpha2/zz_generated.deepcopy.go
deleted file mode 100644
index 7b07a7469..000000000
--- a/components/serverless/pkg/apis/serverless/v1alpha2/zz_generated.deepcopy.go
+++ /dev/null
@@ -1,459 +0,0 @@
-//go:build !ignore_autogenerated
-
-// Code generated by controller-gen. DO NOT EDIT.
-
-package v1alpha2
-
-import (
- "k8s.io/api/core/v1"
- runtime "k8s.io/apimachinery/pkg/runtime"
-)
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Condition) DeepCopyInto(out *Condition) {
- *out = *in
- in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Condition.
-func (in *Condition) DeepCopy() *Condition {
- if in == nil {
- return nil
- }
- out := new(Condition)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Function) DeepCopyInto(out *Function) {
- *out = *in
- out.TypeMeta = in.TypeMeta
- in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
- in.Spec.DeepCopyInto(&out.Spec)
- in.Status.DeepCopyInto(&out.Status)
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Function.
-func (in *Function) DeepCopy() *Function {
- if in == nil {
- return nil
- }
- out := new(Function)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *Function) DeepCopyObject() runtime.Object {
- if c := in.DeepCopy(); c != nil {
- return c
- }
- return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FunctionList) DeepCopyInto(out *FunctionList) {
- *out = *in
- out.TypeMeta = in.TypeMeta
- in.ListMeta.DeepCopyInto(&out.ListMeta)
- if in.Items != nil {
- in, out := &in.Items, &out.Items
- *out = make([]Function, len(*in))
- for i := range *in {
- (*in)[i].DeepCopyInto(&(*out)[i])
- }
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionList.
-func (in *FunctionList) DeepCopy() *FunctionList {
- if in == nil {
- return nil
- }
- out := new(FunctionList)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
-func (in *FunctionList) DeepCopyObject() runtime.Object {
- if c := in.DeepCopy(); c != nil {
- return c
- }
- return nil
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FunctionSpec) DeepCopyInto(out *FunctionSpec) {
- *out = *in
- in.Source.DeepCopyInto(&out.Source)
- if in.Env != nil {
- in, out := &in.Env, &out.Env
- *out = make([]v1.EnvVar, len(*in))
- for i := range *in {
- (*in)[i].DeepCopyInto(&(*out)[i])
- }
- }
- if in.ResourceConfiguration != nil {
- in, out := &in.ResourceConfiguration, &out.ResourceConfiguration
- *out = new(ResourceConfiguration)
- (*in).DeepCopyInto(*out)
- }
- if in.ScaleConfig != nil {
- in, out := &in.ScaleConfig, &out.ScaleConfig
- *out = new(ScaleConfig)
- (*in).DeepCopyInto(*out)
- }
- if in.Replicas != nil {
- in, out := &in.Replicas, &out.Replicas
- *out = new(int32)
- **out = **in
- }
- if in.Template != nil {
- in, out := &in.Template, &out.Template
- *out = new(Template)
- (*in).DeepCopyInto(*out)
- }
- if in.SecretMounts != nil {
- in, out := &in.SecretMounts, &out.SecretMounts
- *out = make([]SecretMount, len(*in))
- copy(*out, *in)
- }
- if in.Labels != nil {
- in, out := &in.Labels, &out.Labels
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
- }
- if in.Annotations != nil {
- in, out := &in.Annotations, &out.Annotations
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionSpec.
-func (in *FunctionSpec) DeepCopy() *FunctionSpec {
- if in == nil {
- return nil
- }
- out := new(FunctionSpec)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *FunctionStatus) DeepCopyInto(out *FunctionStatus) {
- *out = *in
- if in.Conditions != nil {
- in, out := &in.Conditions, &out.Conditions
- *out = make([]Condition, len(*in))
- for i := range *in {
- (*in)[i].DeepCopyInto(&(*out)[i])
- }
- }
- out.Repository = in.Repository
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FunctionStatus.
-func (in *FunctionStatus) DeepCopy() *FunctionStatus {
- if in == nil {
- return nil
- }
- out := new(FunctionStatus)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *GitRepositorySource) DeepCopyInto(out *GitRepositorySource) {
- *out = *in
- if in.Auth != nil {
- in, out := &in.Auth, &out.Auth
- *out = new(RepositoryAuth)
- **out = **in
- }
- out.Repository = in.Repository
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitRepositorySource.
-func (in *GitRepositorySource) DeepCopy() *GitRepositorySource {
- if in == nil {
- return nil
- }
- out := new(GitRepositorySource)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *InlineSource) DeepCopyInto(out *InlineSource) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InlineSource.
-func (in *InlineSource) DeepCopy() *InlineSource {
- if in == nil {
- return nil
- }
- out := new(InlineSource)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MinBuildJobResourcesValues) DeepCopyInto(out *MinBuildJobResourcesValues) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MinBuildJobResourcesValues.
-func (in *MinBuildJobResourcesValues) DeepCopy() *MinBuildJobResourcesValues {
- if in == nil {
- return nil
- }
- out := new(MinBuildJobResourcesValues)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MinBuildJobValues) DeepCopyInto(out *MinBuildJobValues) {
- *out = *in
- out.Resources = in.Resources
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MinBuildJobValues.
-func (in *MinBuildJobValues) DeepCopy() *MinBuildJobValues {
- if in == nil {
- return nil
- }
- out := new(MinBuildJobValues)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MinFunctionResourcesValues) DeepCopyInto(out *MinFunctionResourcesValues) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MinFunctionResourcesValues.
-func (in *MinFunctionResourcesValues) DeepCopy() *MinFunctionResourcesValues {
- if in == nil {
- return nil
- }
- out := new(MinFunctionResourcesValues)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *MinFunctionValues) DeepCopyInto(out *MinFunctionValues) {
- *out = *in
- out.Resources = in.Resources
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MinFunctionValues.
-func (in *MinFunctionValues) DeepCopy() *MinFunctionValues {
- if in == nil {
- return nil
- }
- out := new(MinFunctionValues)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Repository) DeepCopyInto(out *Repository) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Repository.
-func (in *Repository) DeepCopy() *Repository {
- if in == nil {
- return nil
- }
- out := new(Repository)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *RepositoryAuth) DeepCopyInto(out *RepositoryAuth) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RepositoryAuth.
-func (in *RepositoryAuth) DeepCopy() *RepositoryAuth {
- if in == nil {
- return nil
- }
- out := new(RepositoryAuth)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ResourceConfiguration) DeepCopyInto(out *ResourceConfiguration) {
- *out = *in
- if in.Build != nil {
- in, out := &in.Build, &out.Build
- *out = new(ResourceRequirements)
- (*in).DeepCopyInto(*out)
- }
- if in.Function != nil {
- in, out := &in.Function, &out.Function
- *out = new(ResourceRequirements)
- (*in).DeepCopyInto(*out)
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceConfiguration.
-func (in *ResourceConfiguration) DeepCopy() *ResourceConfiguration {
- if in == nil {
- return nil
- }
- out := new(ResourceConfiguration)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ResourceRequirements) DeepCopyInto(out *ResourceRequirements) {
- *out = *in
- if in.Resources != nil {
- in, out := &in.Resources, &out.Resources
- *out = new(v1.ResourceRequirements)
- (*in).DeepCopyInto(*out)
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRequirements.
-func (in *ResourceRequirements) DeepCopy() *ResourceRequirements {
- if in == nil {
- return nil
- }
- out := new(ResourceRequirements)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ScaleConfig) DeepCopyInto(out *ScaleConfig) {
- *out = *in
- if in.MinReplicas != nil {
- in, out := &in.MinReplicas, &out.MinReplicas
- *out = new(int32)
- **out = **in
- }
- if in.MaxReplicas != nil {
- in, out := &in.MaxReplicas, &out.MaxReplicas
- *out = new(int32)
- **out = **in
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleConfig.
-func (in *ScaleConfig) DeepCopy() *ScaleConfig {
- if in == nil {
- return nil
- }
- out := new(ScaleConfig)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *SecretMount) DeepCopyInto(out *SecretMount) {
- *out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretMount.
-func (in *SecretMount) DeepCopy() *SecretMount {
- if in == nil {
- return nil
- }
- out := new(SecretMount)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Source) DeepCopyInto(out *Source) {
- *out = *in
- if in.GitRepository != nil {
- in, out := &in.GitRepository, &out.GitRepository
- *out = new(GitRepositorySource)
- (*in).DeepCopyInto(*out)
- }
- if in.Inline != nil {
- in, out := &in.Inline, &out.Inline
- *out = new(InlineSource)
- **out = **in
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Source.
-func (in *Source) DeepCopy() *Source {
- if in == nil {
- return nil
- }
- out := new(Source)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *Template) DeepCopyInto(out *Template) {
- *out = *in
- if in.Labels != nil {
- in, out := &in.Labels, &out.Labels
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
- }
- if in.Annotations != nil {
- in, out := &in.Annotations, &out.Annotations
- *out = make(map[string]string, len(*in))
- for key, val := range *in {
- (*out)[key] = val
- }
- }
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Template.
-func (in *Template) DeepCopy() *Template {
- if in == nil {
- return nil
- }
- out := new(Template)
- in.DeepCopyInto(out)
- return out
-}
-
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *ValidationConfig) DeepCopyInto(out *ValidationConfig) {
- *out = *in
- if in.ReservedEnvs != nil {
- in, out := &in.ReservedEnvs, &out.ReservedEnvs
- *out = make([]string, len(*in))
- copy(*out, *in)
- }
- out.Function = in.Function
- out.BuildJob = in.BuildJob
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidationConfig.
-func (in *ValidationConfig) DeepCopy() *ValidationConfig {
- if in == nil {
- return nil
- }
- out := new(ValidationConfig)
- in.DeepCopyInto(out)
- return out
-}
diff --git a/config/serverless/.helmignore b/config/docker-registry/.helmignore
similarity index 100%
rename from config/serverless/.helmignore
rename to config/docker-registry/.helmignore
diff --git a/config/serverless/Chart.yaml b/config/docker-registry/Chart.yaml
similarity index 63%
rename from config/serverless/Chart.yaml
rename to config/docker-registry/Chart.yaml
index 2db2279a3..e1f9f36ab 100644
--- a/config/serverless/Chart.yaml
+++ b/config/docker-registry/Chart.yaml
@@ -5,7 +5,4 @@ version: 1.0.0
home: https://kyma-project.io
icon: https://github.com/kyma-project/kyma/blob/main/logo.png?raw=true
dependencies:
- - name: docker-registry
- condition: dockerRegistry.enableInternal
- - name: webhook
- condition: webhook.enabled
\ No newline at end of file
+ - name: docker-registry
\ No newline at end of file
diff --git a/config/serverless/README.md b/config/docker-registry/README.md
similarity index 100%
rename from config/serverless/README.md
rename to config/docker-registry/README.md
diff --git a/config/serverless/charts/docker-registry/.helmignore b/config/docker-registry/charts/docker-registry/.helmignore
similarity index 100%
rename from config/serverless/charts/docker-registry/.helmignore
rename to config/docker-registry/charts/docker-registry/.helmignore
diff --git a/config/serverless/charts/docker-registry/Chart.yaml b/config/docker-registry/charts/docker-registry/Chart.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/Chart.yaml
rename to config/docker-registry/charts/docker-registry/Chart.yaml
diff --git a/config/serverless/charts/docker-registry/README.md b/config/docker-registry/charts/docker-registry/README.md
similarity index 100%
rename from config/serverless/charts/docker-registry/README.md
rename to config/docker-registry/charts/docker-registry/README.md
diff --git a/config/serverless/charts/docker-registry/templates/_helpers.tpl b/config/docker-registry/charts/docker-registry/templates/_helpers.tpl
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/_helpers.tpl
rename to config/docker-registry/charts/docker-registry/templates/_helpers.tpl
diff --git a/config/serverless/charts/docker-registry/templates/configmap.yaml b/config/docker-registry/charts/docker-registry/templates/configmap.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/configmap.yaml
rename to config/docker-registry/charts/docker-registry/templates/configmap.yaml
diff --git a/config/serverless/charts/docker-registry/templates/deployment.yaml b/config/docker-registry/charts/docker-registry/templates/deployment.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/deployment.yaml
rename to config/docker-registry/charts/docker-registry/templates/deployment.yaml
diff --git a/config/serverless/charts/docker-registry/templates/ingress.yaml b/config/docker-registry/charts/docker-registry/templates/ingress.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/ingress.yaml
rename to config/docker-registry/charts/docker-registry/templates/ingress.yaml
diff --git a/config/serverless/charts/docker-registry/templates/poddisruptionbudget.yaml b/config/docker-registry/charts/docker-registry/templates/poddisruptionbudget.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/poddisruptionbudget.yaml
rename to config/docker-registry/charts/docker-registry/templates/poddisruptionbudget.yaml
diff --git a/config/serverless/charts/docker-registry/templates/pvc.yaml b/config/docker-registry/charts/docker-registry/templates/pvc.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/pvc.yaml
rename to config/docker-registry/charts/docker-registry/templates/pvc.yaml
diff --git a/config/serverless/charts/docker-registry/templates/secret.yaml b/config/docker-registry/charts/docker-registry/templates/secret.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/secret.yaml
rename to config/docker-registry/charts/docker-registry/templates/secret.yaml
diff --git a/config/serverless/charts/docker-registry/templates/service.yaml b/config/docker-registry/charts/docker-registry/templates/service.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/templates/service.yaml
rename to config/docker-registry/charts/docker-registry/templates/service.yaml
diff --git a/config/serverless/charts/docker-registry/values.yaml b/config/docker-registry/charts/docker-registry/values.yaml
similarity index 100%
rename from config/serverless/charts/docker-registry/values.yaml
rename to config/docker-registry/charts/docker-registry/values.yaml
diff --git a/config/serverless/charts/webhook/templates/_helpers.tpl b/config/docker-registry/templates/_helpers.tpl
similarity index 59%
rename from config/serverless/charts/webhook/templates/_helpers.tpl
rename to config/docker-registry/templates/_helpers.tpl
index 3de4eb031..8fc39071e 100644
--- a/config/serverless/charts/webhook/templates/_helpers.tpl
+++ b/config/docker-registry/templates/_helpers.tpl
@@ -1,17 +1,9 @@
-{{/* vim: set filetype=mustache: */}}
-{{/*
-Expand the name of the chart.
-*/}}
-{{- define "webhook.name" -}}
-{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
-{{- define "webhook.fullname" -}}
+{{- define "fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
@@ -36,3 +28,22 @@ Usage:
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+*/}}
+{{- define "registry-fullname" -}}
+{{- "internal-docker-registry" -}}
+{{- end -}}
+
+
+{{/*
+Create a URL for container images
+*/}}
+{{- define "imageurl" -}}
+{{- $registry := default $.reg.path $.img.containerRegistryPath -}}
+{{- $path := ternary (print $registry) (print $registry "/" $.img.directory) (empty $.img.directory) -}}
+{{- $version := ternary (print ":" $.img.version) (print "@sha256:" $.img.sha) (empty $.img.sha) -}}
+{{- print $path "/" $.img.name $version -}}
+{{- end -}}
diff --git a/config/serverless/templates/registry-config.yaml b/config/docker-registry/templates/registry-config.yaml
similarity index 71%
rename from config/serverless/templates/registry-config.yaml
rename to config/docker-registry/templates/registry-config.yaml
index a1ff64e9c..0cf87481f 100644
--- a/config/serverless/templates/registry-config.yaml
+++ b/config/docker-registry/templates/registry-config.yaml
@@ -15,13 +15,7 @@ metadata:
data:
username: "{{ $username | b64enc }}"
password: "{{ $password | b64enc }}"
- isInternal: "{{ .Values.dockerRegistry.enableInternal | toString | b64enc }}"
- {{- if .Values.dockerRegistry.enableInternal }}
+ isInternal: {{ "true" | b64enc }}
pullRegAddr: {{ $internalRegPullAddr | b64enc }}
pushRegAddr: "{{ $internalRegPushAddr | b64enc }}"
.dockerconfigjson: "{{- (printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}, \"%s\": {\"auth\": \"%s\"}}}" $internalRegPushAddr $encodedUsernamePassword $internalRegPullAddr $encodedUsernamePassword) | b64enc }}"
- {{- else }}
- serverAddress: "{{ .Values.dockerRegistry.serverAddress | b64enc }}"
- registryAddress: "{{ .Values.dockerRegistry.registryAddress | b64enc }}"
- .dockerconfigjson: "{{- (printf "{\"auths\": {\"%s\": {\"auth\": \"%s\"}}}" .Values.dockerRegistry.serverAddress $encodedUsernamePassword) | b64enc }}"
- {{- end }}
diff --git a/config/docker-registry/values.yaml b/config/docker-registry/values.yaml
new file mode 100644
index 000000000..0e0fd61fd
--- /dev/null
+++ b/config/docker-registry/values.yaml
@@ -0,0 +1,45 @@
+# Default values for dockerregistry.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+fullnameOverride: "serverless"
+global:
+ registryServicePort: 5000
+ registryNodePort: 32137
+ containerRegistry:
+ path: europe-docker.pkg.dev/kyma-project
+ images:
+ registry:
+ name: "tpi/registry"
+ version: "2.8.1-1ae4c190"
+ directory: "prod"
+dockerRegistry:
+ username: "{{ randAlphaNum 20 | b64enc }}" # for gcr "_json_key"
+ password: "{{ randAlphaNum 40 | b64enc }}" # for gcr data from json key
+ # This is the registry address, for dockerhub it's username, for other it's url.
+ registryAddress: ""
+ # This is the server address of the registry which will be used to create docker configuration.
+ serverAddress: ""
+docker-registry:
+ fullnameOverride: "internal-docker-registry"
+ destinationRule:
+ enabled: true
+ secrets:
+ haSharedSecret: "secret"
+ htpasswd: "generated-in-init-container"
+ extraVolumeMounts:
+ - name: htpasswd-data
+ mountPath: /data
+ extraVolumes:
+ - name: registry-credentials
+ secret:
+ secretName: serverless-registry-config-default #TODO: change to internal-dockerregistry-config
+ items:
+ - key: username
+ path: username.txt
+ - key: password
+ path: password.txt
+ - name: htpasswd-data
+ emptyDir: {}
+ rollme: "{{ randAlphaNum 5}}"
+ registryHTTPSecret: "{{ randAlphaNum 16 | b64enc }}"
diff --git a/config/operator/base/crd/bases/operator.kyma-project.io_serverlesses.yaml b/config/operator/base/crd/bases/operator.kyma-project.io_dockerregistries.yaml
similarity index 64%
rename from config/operator/base/crd/bases/operator.kyma-project.io_serverlesses.yaml
rename to config/operator/base/crd/bases/operator.kyma-project.io_dockerregistries.yaml
index 0232ead03..04c91ce8e 100644
--- a/config/operator/base/crd/bases/operator.kyma-project.io_serverlesses.yaml
+++ b/config/operator/base/crd/bases/operator.kyma-project.io_dockerregistries.yaml
@@ -4,14 +4,14 @@ kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.14.0
- name: serverlesses.operator.kyma-project.io
+ name: dockerregistries.operator.kyma-project.io
spec:
group: operator.kyma-project.io
names:
- kind: Serverless
- listKind: ServerlessList
- plural: serverlesses
- singular: serverless
+ kind: DockerRegistry
+ listKind: DockerRegistryList
+ plural: dockerregistries
+ singular: dockerregistry
scope: Namespaced
versions:
- additionalPrinterColumns:
@@ -33,7 +33,7 @@ spec:
name: v1alpha1
schema:
openAPIV3Schema:
- description: Serverless is the Schema for the serverlesses API
+ description: DockerRegistry is the Schema for the dockerregistry API
properties:
apiVersion:
description: |-
@@ -53,69 +53,12 @@ spec:
metadata:
type: object
spec:
- description: ServerlessSpec defines the desired state of Serverless
+ description: DockerRegistrySpec defines the desired state of DockerRegistry
properties:
- defaultBuildJobPreset:
- description: Configures the default build Job preset to be used
- type: string
- defaultRuntimePodPreset:
- description: Configures the default runtime Pod preset to be used
- type: string
- dockerRegistry:
- properties:
- enableInternal:
- description: When set to true, the internal Docker registry is
- enabled
- type: boolean
- secretName:
- description: Secret used for configuration of the Docker registry
- type: string
- type: object
- eventing:
- description: Used Eventing endpoint
- properties:
- endpoint:
- type: string
- required:
- - endpoint
- type: object
- functionBuildExecutorArgs:
- description: Specifies the arguments passed to the Function build
- executor
- type: string
- functionBuildMaxSimultaneousJobs:
- description: A number of simultaneous jobs that can run at the same
- time. The default value is `5`
- type: string
- functionRequestBodyLimitMb:
- description: Used to configure the maximum size limit for the request
- body of a Function. The default value is `1` megabyte
- type: string
- functionRequeueDuration:
- description: Sets the requeue duration for Function. By default, the
- Function associated with the default configuration is requeued every
- 5 minutes
- type: string
- functionTimeoutSec:
- description: Sets the maximum execution time limit for a Function.
- By default, the value is `180` seconds
- type: string
healthzLivenessTimeout:
description: Sets the timeout for the Function health check. The default
value in seconds is `10`
type: string
- targetCPUUtilizationPercentage:
- description: Sets a custom CPU utilization threshold for scaling Function
- Pods
- type: string
- tracing:
- description: Used Tracing endpoint
- properties:
- endpoint:
- type: string
- required:
- - endpoint
- type: object
type: object
status:
properties:
@@ -189,33 +132,11 @@ spec:
- type
type: object
type: array
- defaultBuildJobPreset:
- type: string
- defaultRuntimePodPreset:
- type: string
- dockerRegistry:
- description: |-
- Used registry configuration.
- Contains registry URL or "internal"
- type: string
- eventingEndpoint:
- description: Used the Eventing endpoint and the Tracing endpoint.
- type: string
- functionBuildExecutorArgs:
- type: string
- functionBuildMaxSimultaneousJobs:
- type: string
- functionRequestBodyLimitMb:
- type: string
- functionRequeueDuration:
- type: string
- functionTimeoutSec:
- type: string
healthzLivenessTimeout:
type: string
served:
description: |-
- Served signifies that current Serverless is managed.
+ Served signifies that current DockerRegistry is managed.
Value can be one of ("True", "False").
enum:
- "True"
@@ -223,7 +144,7 @@ spec:
type: string
state:
description: |-
- State signifies current state of Serverless.
+ State signifies current state of DockerRegistry.
Value can be one of ("Ready", "Processing", "Error", "Deleting").
enum:
- Processing
@@ -232,10 +153,6 @@ spec:
- Error
- Warning
type: string
- targetCPUUtilizationPercentage:
- type: string
- tracingEndpoint:
- type: string
required:
- served
type: object
diff --git a/config/operator/base/crd/kustomization.yaml b/config/operator/base/crd/kustomization.yaml
index f85c25cc7..db1457e08 100644
--- a/config/operator/base/crd/kustomization.yaml
+++ b/config/operator/base/crd/kustomization.yaml
@@ -2,7 +2,7 @@
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
-- bases/operator.kyma-project.io_serverlesses.yaml
+- bases/operator.kyma-project.io_dockerregistries.yaml
#+kubebuilder:scaffold:crdkustomizeresource
# the following config is for teaching kustomize how to do kustomization for CRDs.
diff --git a/config/operator/base/deployment/deployment.yaml b/config/operator/base/deployment/deployment.yaml
index 7e1f964d7..00b5a65bd 100644
--- a/config/operator/base/deployment/deployment.yaml
+++ b/config/operator/base/deployment/deployment.yaml
@@ -6,10 +6,10 @@ metadata:
labels:
control-plane: operator
app.kubernetes.io/name: deployment
- app.kubernetes.io/instance: serverless-operator
+ app.kubernetes.io/instance: dockerregistry-operator
app.kubernetes.io/component: operator
- app.kubernetes.io/created-by: serverless-operator
- app.kubernetes.io/part-of: serverless-operator
+ app.kubernetes.io/created-by: dockerregistry-operator
+ app.kubernetes.io/part-of: dockerregistry-operator
app.kubernetes.io/managed-by: kustomize
spec:
selector:
diff --git a/config/operator/base/deployment/kustomization.yaml b/config/operator/base/deployment/kustomization.yaml
index 479613aaf..2d833f825 100644
--- a/config/operator/base/deployment/kustomization.yaml
+++ b/config/operator/base/deployment/kustomization.yaml
@@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
- newName: europe-docker.pkg.dev/kyma-project/prod/serverless-operator
- newTag: main
+ newName: dockerregistry-operator
+ newTag: 2d332b272e2a
diff --git a/config/operator/base/kustomization.yaml b/config/operator/base/kustomization.yaml
index ed38c42f5..95f2c7013 100644
--- a/config/operator/base/kustomization.yaml
+++ b/config/operator/base/kustomization.yaml
@@ -6,11 +6,11 @@ namespace: kyma-system
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
-namePrefix: serverless-
+namePrefix: dockerregistry-
# Labels to add to all resources and selectors.
commonLabels:
- app.kubernetes.io/component: serverless-operator.kyma-project.io
+ app.kubernetes.io/component: dockerregistry-operator.kyma-project.io
resources:
diff --git a/config/operator/base/rbac/role.yaml b/config/operator/base/rbac/role.yaml
index 34d01f70b..3d4bce2a6 100644
--- a/config/operator/base/rbac/role.yaml
+++ b/config/operator/base/rbac/role.yaml
@@ -4,6 +4,20 @@ kind: ClusterRole
metadata:
name: operator-role
rules:
+- apiGroups:
+ - ""
+ resources:
+ - configmaps
+ - secrets
+ - serviceaccounts
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- ""
resources:
@@ -64,6 +78,18 @@ rules:
- patch
- update
- watch
+- apiGroups:
+ - ""
+ resources:
+ - secrets
+ verbs:
+ - create
+ - delete
+ - get
+ - list
+ - patch
+ - update
+ - watch
- apiGroups:
- admissionregistration.k8s.io
resources:
@@ -177,7 +203,7 @@ rules:
- apiGroups:
- operator.kyma-project.io
resources:
- - serverlesses
+ - dockerregistries
verbs:
- create
- delete
@@ -190,7 +216,7 @@ rules:
- apiGroups:
- operator.kyma-project.io
resources:
- - serverlesses/finalizers
+ - dockerregistries/finalizers
verbs:
- create
- delete
@@ -203,7 +229,7 @@ rules:
- apiGroups:
- operator.kyma-project.io
resources:
- - serverlesses/status
+ - dockerregistries/status
verbs:
- create
- delete
diff --git a/config/operator/base/rbac/role_binding.yaml b/config/operator/base/rbac/role_binding.yaml
index a2e72ae98..3a699c7dd 100644
--- a/config/operator/base/rbac/role_binding.yaml
+++ b/config/operator/base/rbac/role_binding.yaml
@@ -3,10 +3,10 @@ kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/name: clusterrolebinding
- app.kubernetes.io/instance: serverless-operator-rolebinding
+ app.kubernetes.io/instance: dockerregistry-operator-rolebinding
app.kubernetes.io/component: rbac
- app.kubernetes.io/created-by: serverless-operator
- app.kubernetes.io/part-of: serverless-operator
+ app.kubernetes.io/created-by: dockerregistry-operator
+ app.kubernetes.io/part-of: dockerregistry-operator
app.kubernetes.io/managed-by: kustomize
name: operator-rolebinding
roleRef:
diff --git a/config/operator/base/rbac/serverless_editor_role.yaml b/config/operator/base/rbac/serverless_editor_role.yaml
index 357b6f06f..f7ad1b399 100644
--- a/config/operator/base/rbac/serverless_editor_role.yaml
+++ b/config/operator/base/rbac/serverless_editor_role.yaml
@@ -4,10 +4,10 @@ kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
- app.kubernetes.io/instance: serverless-operator-editor-role
+ app.kubernetes.io/instance: dockerregistry-operator-editor-role
app.kubernetes.io/component: rbac
- app.kubernetes.io/created-by: serverless-operator
- app.kubernetes.io/part-of: serverless-operator
+ app.kubernetes.io/created-by: dockerregistry-operator
+ app.kubernetes.io/part-of: dockerregistry-operator
app.kubernetes.io/managed-by: kustomize
name: operator-editor-role
rules:
diff --git a/config/operator/base/rbac/serverless_viewer_role.yaml b/config/operator/base/rbac/serverless_viewer_role.yaml
index 8f20681e5..49846ba22 100644
--- a/config/operator/base/rbac/serverless_viewer_role.yaml
+++ b/config/operator/base/rbac/serverless_viewer_role.yaml
@@ -4,10 +4,10 @@ kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
- app.kubernetes.io/instance: serverless-operator-viewer-role
+ app.kubernetes.io/instance: dockerregistry-operator-viewer-role
app.kubernetes.io/component: rbac
- app.kubernetes.io/created-by: serverless-operator
- app.kubernetes.io/part-of: serverless-operator
+ app.kubernetes.io/created-by: dockerregistry-operator
+ app.kubernetes.io/part-of: dockerregistry-operator
app.kubernetes.io/managed-by: kustomize
name: operator-viewer-role
rules:
diff --git a/config/operator/base/rbac/service_account.yaml b/config/operator/base/rbac/service_account.yaml
index b8c9361ff..c60ca4da5 100644
--- a/config/operator/base/rbac/service_account.yaml
+++ b/config/operator/base/rbac/service_account.yaml
@@ -3,10 +3,10 @@ kind: ServiceAccount
metadata:
labels:
app.kubernetes.io/name: serviceaccount
- app.kubernetes.io/instance: serverless-operator-sa
+ app.kubernetes.io/instance: dockerregistry-operator-sa
app.kubernetes.io/component: rbac
- app.kubernetes.io/created-by: serverless-operator
- app.kubernetes.io/part-of: serverless-operator
+ app.kubernetes.io/created-by: dockerregistry-operator
+ app.kubernetes.io/part-of: dockerregistry-operator
app.kubernetes.io/managed-by: kustomize
name: operator
namespace: system
diff --git a/config/operator/base/ui-extensions/serverless/general b/config/operator/base/ui-extensions/serverless/general
index 8fe8b5993..dff327b13 100644
--- a/config/operator/base/ui-extensions/serverless/general
+++ b/config/operator/base/ui-extensions/serverless/general
@@ -11,5 +11,5 @@ features:
disableCreate: true
disableDelete: true
description: >-
- {{[Serverless CR](https://github.com/kyma-project/serverless-manager/blob/main/config/samples/default-serverless-cr.yaml)}}
+ {{[Serverless CR](https://github.com/kyma-project/serverless-manager/blob/main/config/samples/default-dockerregistry-cr.yaml)}}
specifies serverless module.
diff --git a/config/samples/default-serverless-cr-k3d.yaml b/config/samples/default-dockerregistry-cr.yaml
similarity index 83%
rename from config/samples/default-serverless-cr-k3d.yaml
rename to config/samples/default-dockerregistry-cr.yaml
index 7b431c0c8..9f9f1a1cd 100644
--- a/config/samples/default-serverless-cr-k3d.yaml
+++ b/config/samples/default-dockerregistry-cr.yaml
@@ -1,5 +1,5 @@
apiVersion: operator.kyma-project.io/v1alpha1
-kind: Serverless
+kind: DockerRegistry
metadata:
name: default
namespace: kyma-system
diff --git a/config/samples/default-serverless-cr-k3d-explicit.yaml b/config/samples/default-serverless-cr-k3d-explicit.yaml
deleted file mode 100644
index 0e4625230..000000000
--- a/config/samples/default-serverless-cr-k3d-explicit.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: operator.kyma-project.io/v1alpha1
-kind: Serverless
-metadata:
- name: default
- namespace: kyma-system
-spec:
- dockerRegistry:
- enableInternal: false
diff --git a/config/samples/default-serverless-cr.yaml b/config/samples/default-serverless-cr.yaml
deleted file mode 100644
index 8526919d8..000000000
--- a/config/samples/default-serverless-cr.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: operator.kyma-project.io/v1alpha1
-kind: Serverless
-metadata:
- name: default
- namespace: kyma-system
-spec:
- dockerRegistry:
- enableInternal: true
diff --git a/config/serverless/charts/webhook/Chart.yaml b/config/serverless/charts/webhook/Chart.yaml
deleted file mode 100644
index cf1fcf708..000000000
--- a/config/serverless/charts/webhook/Chart.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-apiVersion: v1
-appVersion: 0.1.0
-description: Helm chart for installing the Webhook for the Function Controller
-name: webhook
-version: 0.1.0
diff --git a/config/serverless/charts/webhook/README.md b/config/serverless/charts/webhook/README.md
deleted file mode 100644
index 3d30a3f4b..000000000
--- a/config/serverless/charts/webhook/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# Webhook
-
-## Overview
-
-This project contains the chart for the Webhook.
-
-## Details
-
-For more information, read the Webhooks [README](../../../../components/serverless/README.md) file.
diff --git a/config/serverless/charts/webhook/templates/cluster-role-binding.yaml b/config/serverless/charts/webhook/templates/cluster-role-binding.yaml
deleted file mode 100644
index c2bf63dfe..000000000
--- a/config/serverless/charts/webhook/templates/cluster-role-binding.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: {{ template "webhook.fullname" . }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-subjects:
- - kind: ServiceAccount
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
-roleRef:
- kind: ClusterRole
- name: {{ template "webhook.fullname" . }}
- apiGroup: rbac.authorization.k8s.io
\ No newline at end of file
diff --git a/config/serverless/charts/webhook/templates/cluster-role.yaml b/config/serverless/charts/webhook/templates/cluster-role.yaml
deleted file mode 100644
index b08850080..000000000
--- a/config/serverless/charts/webhook/templates/cluster-role.yaml
+++ /dev/null
@@ -1,47 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: {{ template "webhook.fullname" . }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-rules:
- - apiGroups:
- - ""
- resources:
- - configmaps
- - secrets
- - namespaces
- verbs:
- - get
- - list
- - watch
- - update
- - apiGroups:
- - admissionregistration.k8s.io
- resources:
- - mutatingwebhookconfigurations
- - validatingwebhookconfigurations
- verbs:
- - create
- - delete
- - get
- - update
- - list
- - watch
- - delete
- - apiGroups:
- - coordination.k8s.io
- resources:
- - leases
- verbs:
- - get
- - list
- - create
- - update
- - apiGroups:
- - apiextensions.k8s.io
- resources:
- - customresourcedefinitions
- verbs:
- - get
- - update
diff --git a/config/serverless/charts/webhook/templates/config-observability.yaml b/config/serverless/charts/webhook/templates/config-observability.yaml
deleted file mode 100644
index b6038b184..000000000
--- a/config/serverless/charts/webhook/templates/config-observability.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: {{ template "webhook.fullname" . }}-config-observability
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-data:
- content: ""
diff --git a/config/serverless/charts/webhook/templates/configmap.yaml b/config/serverless/charts/webhook/templates/configmap.yaml
deleted file mode 100644
index fb5cf4820..000000000
--- a/config/serverless/charts/webhook/templates/configmap.yaml
+++ /dev/null
@@ -1,15 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: {{ template "webhook.fullname" . }}-envs
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-data:
- WEBHOOK_SYSTEM_NAMESPACE: {{ .Release.Namespace }}
- WEBHOOK_LOG_CONFIG_PATH: {{ include "tplValue" ( dict "value" .Values.container.envs.logConfigPath.value "context" . ) | quote }}
- WEBHOOK_CONFIG_PATH: {{ include "tplValue" ( dict "value" .Values.container.envs.configPath.value "context" . ) | quote }}
- WEBHOOK_SERVICE_NAME: {{ include "tplValue" ( dict "value" .Values.container.envs.webhookServiceName.value "context" . ) | quote }}
- WEBHOOK_SECRET_NAME: {{ include "tplValue" ( dict "value" .Values.container.envs.webhookSecretName.value "context" . ) | quote }}
- WEBHOOK_PORT: {{ include "tplValue" ( dict "value" .Values.container.envs.webhookPort.value "context" . ) | quote }}
- {{ .Values.global.configuration.filename }}: {{ include "tplValue" ( dict "value" .Values.values "context" . ) | quote }}
diff --git a/config/serverless/charts/webhook/templates/deployment.yaml b/config/serverless/charts/webhook/templates/deployment.yaml
deleted file mode 100644
index 3c66abd38..000000000
--- a/config/serverless/charts/webhook/templates/deployment.yaml
+++ /dev/null
@@ -1,117 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: {{ template "webhook.fullname" . }}-svc
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
- {{- if .Values.deployment.labels }}
- {{ include "tplValue" ( dict "value" .Values.deployment.labels "context" . ) | nindent 4 }}
- {{- end }}
- {{- if .Values.deployment.annotations }}
- annotations:
- {{ include "tplValue" ( dict "value" .Values.deployment.annotations "context" . ) | nindent 4 }}
- {{- end }}
-spec:
- selector:
- matchLabels:
- app: {{ template "webhook.fullname" . }}
- app.kubernetes.io/name: {{ template "webhook.fullname" . }}
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- role: webhook
- replicas: {{ .Values.deployment.replicas }}
- {{- if .Values.deployment.extraProperties }}
- {{ include "tplValue" ( dict "value" .Values.deployment.extraProperties "context" . ) | nindent 2 }}
- {{- end }}
- template:
- metadata:
- {{- if .Values.pod.annotations }}
- annotations:
- {{ include "tplValue" ( dict "value" .Values.pod.annotations "context" . ) | nindent 8 }}
- {{- end }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 8 }}
- spec:
- serviceAccountName: {{ template "webhook.fullname" . }}
- volumes:
- - name: log-configuration
- configMap:
- name: "{{ .Values.global.configuration.configmapName }}"
- items:
- - key: {{ .Values.global.configuration.logFilename }}
- path: {{ .Values.global.configuration.filename }}
- - name: configuration
- configMap:
- name: {{ template "webhook.fullname" . }}-envs
- items:
- - key: {{ .Values.global.configuration.filename }}
- path: {{ .Values.global.configuration.filename }}
- - name: serverless-webhook
- secret:
- secretName: {{ .Values.container.envs.webhookSecretName.value }}
- {{- if .Values.pod.extraProperties }}
- {{ include "tplValue" ( dict "value" .Values.pod.extraProperties "context" . ) | nindent 6 }}
- {{- end }}
- initContainers:
- - name: remove-old-mutating-secret
- image: rancher/kubectl:v1.26.11
- command:
- - "kubectl"
- args:
- - "delete"
- - "mutatingwebhookconfigurations"
- - "mutating.secrets"
- - "--ignore-not-found=true"
- {{- if .Values.initContainer.securityContext }}
- securityContext:
- {{- include "tplValue" ( dict "value" .Values.initContainer.securityContext "context" . ) | nindent 12 }}
- {{- end }}
- containers:
- - name: webhook
- volumeMounts:
- - name: log-configuration
- mountPath: {{ .Values.global.configuration.targetDir }}/{{ .Values.global.configuration.logFilename }}
- subPath: config.yaml
- - name: configuration
- mountPath: {{ .Values.global.configuration.targetDir }}/{{ .Values.global.configuration.filename }}
- subPath: config.yaml
- - name: serverless-webhook
- mountPath: /tmp/k8s-webhook-server/serving-certs
- image: "{{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_webhook) }}"
- imagePullPolicy: "{{ .Values.image.pullPolicy }}"
- livenessProbe:
- httpGet:
- port: {{ .Values.service.ports.httpMetrics.targetPort }}
- path: "/metrics"
- initialDelaySeconds: {{ .Values.deployment.livenessProbe.initialDelaySeconds }}
- timeoutSeconds: {{ .Values.deployment.livenessProbe.timeoutSeconds }}
- periodSeconds: {{.Values.deployment.livenessProbe.periodSeconds }}
- readinessProbe:
- httpGet:
- port: {{ .Values.service.ports.httpMetrics.targetPort }}
- path: "/metrics"
- initialDelaySeconds: {{ .Values.deployment.readinessProbe.initialDelaySeconds }}
- timeoutSeconds: {{ .Values.deployment.readinessProbe.timeoutSeconds }}
- periodSeconds: {{.Values.deployment.readinessProbe.periodSeconds }}
- resources:
- requests:
- cpu: {{ .Values.deployment.resources.requests.cpu }}
- memory: {{ .Values.deployment.resources.requests.memory }}
- limits:
- cpu: {{ .Values.deployment.resources.limits.cpu }}
- memory: {{ .Values.deployment.resources.limits.memory }}
- {{- if .Values.container.securityContext }}
- securityContext:
- {{- include "tplValue" ( dict "value" .Values.container.securityContext "context" . ) | nindent 12 }}
- {{- end }}
- ports:
- - name: {{ .Values.service.ports.httpMetrics.name }}
- containerPort: {{ .Values.service.ports.httpMetrics.targetPort }}
- - name: {{ .Values.service.ports.httpProfiling.name }}
- containerPort: {{ .Values.service.ports.httpProfiling.targetPort }}
- - name: {{ .Values.service.ports.httpsWebhook.name }}
- containerPort: {{ .Values.service.ports.httpsWebhook.targetPort }}
- envFrom:
- - configMapRef:
- name: {{ template "webhook.fullname" . }}-envs
- priorityClassName: {{ .Values.global.serverlessPriorityClassName }}
diff --git a/config/serverless/charts/webhook/templates/secret.yaml b/config/serverless/charts/webhook/templates/secret.yaml
deleted file mode 100644
index 776a655ef..000000000
--- a/config/serverless/charts/webhook/templates/secret.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-# this stub is created to allow the reconciler to track this/these resource(s). It should not be deleted. The actual content of this resource and managed and reconciled by the function-webhook.
-apiVersion: v1
-kind: Secret
-metadata:
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
\ No newline at end of file
diff --git a/config/serverless/charts/webhook/templates/service-account.yaml b/config/serverless/charts/webhook/templates/service-account.yaml
deleted file mode 100644
index 6973743e8..000000000
--- a/config/serverless/charts/webhook/templates/service-account.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
diff --git a/config/serverless/charts/webhook/templates/service.yaml b/config/serverless/charts/webhook/templates/service.yaml
deleted file mode 100644
index 51aa1ed64..000000000
--- a/config/serverless/charts/webhook/templates/service.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-spec:
- ports:
- - name: {{ .Values.service.ports.httpMetrics.name }}
- port: {{ .Values.service.ports.httpMetrics.port }}
- targetPort: {{ .Values.service.ports.httpMetrics.targetPort }}
- - name: {{ .Values.service.ports.httpProfiling.name }}
- port: {{ .Values.service.ports.httpProfiling.port }}
- targetPort: {{ .Values.service.ports.httpProfiling.targetPort }}
- - name: {{ .Values.service.ports.httpsWebhook.name }}
- port: {{ .Values.service.ports.httpsWebhook.port }}
- targetPort: {{ .Values.service.ports.httpsWebhook.targetPort }}
- selector:
- app: {{ template "webhook.fullname" . }}
- app.kubernetes.io/name: {{ template "webhook.fullname" . }}
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- role: webhook
diff --git a/config/serverless/charts/webhook/templates/webhooks.yaml b/config/serverless/charts/webhook/templates/webhooks.yaml
deleted file mode 100644
index 0f3e0dd53..000000000
--- a/config/serverless/charts/webhook/templates/webhooks.yaml
+++ /dev/null
@@ -1,76 +0,0 @@
-# this stub is created to allow the reconciler to track this/these resource(s). It should not be deleted. The actual content of this resource and managed and reconciled by the function-webhook.
-apiVersion: admissionregistration.k8s.io/v1
-kind: ValidatingWebhookConfiguration
-metadata:
- name: validation.webhook.serverless.kyma-project.io
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-webhooks:
- - name: validation.webhook.serverless.kyma-project.io
- clientConfig:
- service:
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
- path: "/validation/function"
- port: {{ .Values.service.ports.httpsWebhook.port}}
- failurePolicy: Fail
- sideEffects: None
- matchPolicy: Exact
- timeoutSeconds: 10
- admissionReviewVersions: [ "v1beta1", "v1" ]
- namespaceSelector:
- matchExpressions:
- - key: gardener.cloud/purpose
- operator: NotIn
- values:
- - kube-system
- rules:
- - apiGroups:
- - serverless.kyma-project.io
- apiVersions:
- - v1alpha2
- operations:
- - CREATE
- - UPDATE
- resources:
- - functions
- - functions/status
- scope: '*'
----
-apiVersion: admissionregistration.k8s.io/v1
-kind: MutatingWebhookConfiguration
-metadata:
- name: defaulting.webhook.serverless.kyma-project.io
- labels:
- {{- include "tplValue" ( dict "value" .Values.commonLabels "context" . ) | nindent 4 }}
-webhooks:
- - name: defaulting.webhook.serverless.kyma-project.io
- clientConfig:
- service:
- name: {{ template "webhook.fullname" . }}
- namespace: {{ .Release.Namespace }}
- path: "/defaulting/functions"
- port: {{ .Values.service.ports.httpsWebhook.port}}
- failurePolicy: Fail
- sideEffects: None
- matchPolicy: Exact
- timeoutSeconds: 10
- admissionReviewVersions: [ "v1beta1", "v1" ]
- namespaceSelector:
- matchExpressions:
- - key: gardener.cloud/purpose
- operator: NotIn
- values:
- - kube-system
- rules:
- - apiGroups:
- - serverless.kyma-project.io
- apiVersions:
- - v1alpha2
- operations:
- - CREATE
- - UPDATE
- resources:
- - functions
- - functions/status
- scope: '*'
diff --git a/config/serverless/charts/webhook/values.yaml b/config/serverless/charts/webhook/values.yaml
deleted file mode 100644
index e36380f65..000000000
--- a/config/serverless/charts/webhook/values.yaml
+++ /dev/null
@@ -1,115 +0,0 @@
-# Default values for webhook.
-# This is a YAML-formatted file.
-# Declare variables to be passed into your templates.
-
-nameOverride:
-fullnameOverride:
-image:
- pullPolicy: IfNotPresent
-
-commonLabels:
- app: '{{ template "webhook.fullname" . }}'
- app.kubernetes.io/name: '{{ template "webhook.fullname" . }}'
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- role: webhook
-
-deployment:
- replicas: 1
- labels: {}
- annotations: {}
- extraProperties: {}
- resources:
- requests:
- cpu: 10m
- memory: 50Mi
- limits:
- cpu: 300m
- memory: 300Mi
- livenessProbe:
- initialDelaySeconds: 50
- timeoutSeconds: 1
- periodSeconds: 10
- readinessProbe:
- initialDelaySeconds: 10
- timeoutSeconds: 1
- periodSeconds: 2
-
-pod:
- annotations:
- sidecar.istio.io/inject: "false"
- extraProperties:
- # the following guidelines should be followed for this https://github.com/kyma-project/community/tree/main/concepts/psp-replacement
- securityContext:
- runAsNonRoot: true
- runAsUser: 1000 # Optional. Use this setting only when necessary, otherwise delete it. Never set to 0 because this is the ID of root.
- runAsGroup: 1000 # Optional. Use this setting only when necessary, otherwise delete it. Never set to 0 because this is the ID of root.
- seccompProfile: # Optional. This option can also be set on container level but it is recommended to set it on Pod level and leave it undefined on container level.
- type: RuntimeDefault
- hostNetwork: false # Optional. The default is false if the entry is not there.
- hostPID: false # Optional. The default is false if the entry is not there.
- hostIPC: false # Optional. The default is false if the entry is not there.
-
-service:
- ports:
- httpMetrics:
- name: "http-metrics"
- port: 9090
- targetPort: 9090
- httpProfiling:
- name: "http-profiling"
- port: 8008
- targetPort: 8008
- httpsWebhook:
- name: "https-webhook"
- port: 443
- targetPort: 8443
-
-container:
- # the following guidelines should be followed for this https://github.com/kyma-project/community/tree/main/concepts/psp-replacement
- securityContext:
- allowPrivilegeEscalation: false
- privileged: false
- capabilities:
- drop: ["ALL"]
- procMount: default # Optional. The default is false if the entry is not there.
- readOnlyRootFilesystem: true # Mandatory
- envs:
- logConfigPath:
- value: "{{ .Values.global.configuration.targetDir }}/{{ .Values.global.configuration.logFilename }}"
- configPath:
- value: "{{ .Values.global.configuration.targetDir }}/{{ .Values.global.configuration.filename }}"
- webhookServiceName:
- value: serverless-webhook
- webhookSecretName:
- value: serverless-webhook
- webhookPort:
- value: "{{ .Values.service.ports.httpsWebhook.targetPort }}"
-
-initContainer:
- # the following guidelines should be followed for this https://github.com/kyma-project/community/tree/main/concepts/psp-replacement
- securityContext:
- allowPrivilegeEscalation: false
- privileged: false
- capabilities:
- drop: ["ALL"]
- procMount: default # Optional. The default is false if the entry is not there.
- readOnlyRootFilesystem: true # Mandatory
-
-values:
- reservedEnvs:
- - "FUNC_RUNTIME"
- - "FUNC_HANDLER"
- - "FUNC_PORT"
- - "MOD_NAME"
- - "NODE_PATH"
- - "PYTHONPATH" # https://github.com/kubeless/runtimes/blob/master/stable/nodejs/kubeless.js;https://github.com/kubeless/runtimes/tree/master/stable/python
- function:
- resources:
- minRequestCpu: "10m"
- minRequestMemory: "16Mi"
-
- buildJob:
- resources:
- minRequestCpu: "200m"
- minRequestMemory: "200Mi"
-
diff --git a/config/serverless/templates/_helpers.tpl b/config/serverless/templates/_helpers.tpl
deleted file mode 100644
index f68ec1b65..000000000
--- a/config/serverless/templates/_helpers.tpl
+++ /dev/null
@@ -1,105 +0,0 @@
-{{/* vim: set filetype=mustache: */}}
-{{/*
-Expand the name of the chart.
-*/}}
-{{- define "name" -}}
-{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{/*
-Create a default fully qualified app name.
-We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
-If release name contains chart name it will be used as a full name.
-*/}}
-{{- define "fullname" -}}
-{{- if .Values.fullnameOverride -}}
-{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
-{{- else -}}
-{{- $name := default .Chart.Name .Values.nameOverride -}}
-{{- if contains $name .Release.Name -}}
-{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
-{{- else -}}
-{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-{{- end -}}
-{{- end -}}
-
-{{- define "fn-psp.name" -}}
-{{- printf "000-%s-function" (include "name" .) | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{- define "build-psp.name" -}}
-{{- printf "000-%s-build" (include "name" .) | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{/*
-Create chart name and version as used by the chart label.
-*/}}
-{{- define "chart" -}}
-{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{/*
-Expand the name of the tests resources.
-*/}}
-{{- define "tests.name" -}}
-{{- printf "%s-tests" (include "name" .) | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{/*
-Expand the fullname of the tests resources.
-*/}}
-{{- define "tests.fullname" -}}
-{{- printf "%s-tests" (include "fullname" .) | trunc 63 | trimSuffix "-" -}}
-{{- end -}}
-
-{{/*
-Renders a value that contains template.
-Usage:
-{{- include "tplValue" ( dict "value" .Values.path.to.the.Value "context" $ ) }}
-*/}}
-{{- define "tplValue" -}}
- {{- if typeIs "string" .value }}
- {{- tpl .value .context }}
- {{- else }}
- {{- tpl (.value | toYaml) .context }}
- {{- end }}
-{{- end -}}
-
-{{/*
-Renders a proper env in container
-Usage:
-{{ include "createEnv" ( dict "name" "APP_FOO_BAR" "value" .Values.path.to.the.Value "context" $ ) }}
-*/}}
-{{- define "createEnv" -}}
-{{- if and .name .value }}
-{{- printf "- name: %s" .name -}}
-{{- include "tplValue" ( dict "value" .value "context" .context ) | nindent 2 }}
-{{- end }}
-{{- end -}}
-
-{{/*
-Expand the name of the chart.
-*/}}
-{{- define "registry-name" -}}
-{{- "docker-registry" -}}
-{{- end -}}
-
-{{/*
-Create a default fully qualified app name.
-We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
-*/}}
-{{- define "registry-fullname" -}}
-{{- "serverless-docker-registry" -}}
-{{- end -}}
-
-
-{{/*
-Create a URL for container images
-*/}}
-{{- define "imageurl" -}}
-{{- $registry := default $.reg.path $.img.containerRegistryPath -}}
-{{- $path := ternary (print $registry) (print $registry "/" $.img.directory) (empty $.img.directory) -}}
-{{- $version := ternary (print ":" $.img.version) (print "@sha256:" $.img.sha) (empty $.img.sha) -}}
-{{- print $path "/" $.img.name $version -}}
-{{- end -}}
diff --git a/config/serverless/templates/busola-serverless-extension.yaml b/config/serverless/templates/busola-serverless-extension.yaml
deleted file mode 100644
index ba12508e1..000000000
--- a/config/serverless/templates/busola-serverless-extension.yaml
+++ /dev/null
@@ -1,587 +0,0 @@
-kind: ConfigMap
-apiVersion: v1
-metadata:
- name: functions
- namespace: kube-public
- labels:
- app.kubernetes.io/name: functions
- busola.io/extension: resource
- busola.io/extension-version: '0.5'
-data:
- details: |-
- header:
- - name: Replicas
- widget: Badge
- source: "$string($count($filter($replicas().items, function($r){
- $r.status.phase = 'Running'}))) & '/' & $string($count($replicas().items))"
- highlights:
- negative: "$count($replicas().items) != $count($filter($replicas().items, function($r){
- $r.status.phase = 'Running'}))"
- warning: "$count($replicas().items) = 0 and $count($filter($replicas().items, function($r){
- $r.status.phase = 'Running'}) = 0)" # this condition needs to be above 'positive'
- positive: "$count($replicas().items) = $count($filter($replicas().items, function($r){
- $r.status.phase = 'Running'}))"
- - name: header.status
- widget: Badge
- highlights:
- positive:
- - RUNNING
- negative:
- - FAILED
- - ERROR
- informative:
- - INITIALIZING
- critical:
- - DEPLOYING
- - BUILDING
- - PENDING
- source: >-
- ($.status = undefined or $.status.conditions = undefined or
- $count($.status.conditions) = 0) ? 'INITIALIZING' :
- $count($filter($.status.conditions, function($v) { $v.status = 'False' }))
- != 0 ? $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'True' })) != 0 ? 'ERROR' : 'FAILED' :
- $count($filter($.status.conditions, function($v) { $v.type =
- 'ConfigurationReady' and $v.status = 'True' })) != 0 ?
- $count($filter($.status.conditions, function($v) { $v.type = 'BuildReady'
- and $v.status = 'True' })) != 0 ? $count($filter($.status.conditions,
- function($v) { $v.type = 'Running' and $v.status = 'True' })) != 0 ?
- 'RUNNING' : $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'Unknown' and $v.reason =
- 'MinReplicasNotAvailable' })) != 0 ? 'PENDING' : 'DEPLOYING' : 'BUILDING'
- : 'INITIALIZING'
- description: >-
- ($.status = undefined or $.status.conditions = undefined or
- $count($.status.conditions) = 0) ? null :
- $count($filter($.status.conditions, function($v) { $v.status = 'False' }))
- != 0 ? $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'True' })) != 0 ? 'New revision error: ' &
- $filter($.status.conditions, function($v) { $v.status = 'False'
- })[0].message : 'Error: ' & $filter($.status.conditions, function($v) {
- $v.status = 'False' })[0].message : null
- - name: header.sourceType
- source: 'spec.source.gitRepository ? "Git Repository" : "Inline Editor"'
- - name: header.runtime
- source: >-
- spec.runtime = 'python39' ? 'Python 3.9 - deprecated' : (spec.runtime = 'nodejs18' ? 'Node.js 18 - deprecated' : (spec.runtime = 'python312' ? 'Python 3.12' : (spec.runtime = 'nodejs20' ? 'Node.js 20' : spec.runtime)))
- body:
- - widget: Tabs
- children:
- - name: tabs.code
- children:
- - source: spec.source.inline.source
- widget: CodeViewer
- name: code.source
- language: '$contains($root.spec.runtime, "python") ? "python": "javascript"'
- visibility: $exists($value)
- - source: spec.source.inline.dependencies
- widget: CodeViewer
- name: code.dependencies
- language: '"json"'
- visibility: $exists($value)
- - source: spec.source.gitRepository
- widget: Panel
- name: code.gitRepositoryConfig
- visibility: $exists($value)
- children:
- - name: code.gitRepository.url
- source: url
- - name: code.gitRepository.reference
- source: reference
- - name: code.gitRepository.baseDir
- source: baseDir
- - name: code.gitRepository.auth
- visibility: $exists($value)
- widget: Panel
- source: auth
- children:
- - name: code.gitRepository.auth.secretName
- widget: ResourceLink
- source: secretName
- resource:
- kind: "'Secret'"
- name: secretName
- namespace: $root.metadata.namespace
- - name: code.gitRepository.auth.type
- source: type
- - source: spec.env
- widget: Table
- name: code.env
- children:
- - source: $item.name
- name: code.env.name
- - source: $item.value
- name: code.env.value
- - name: code.env.valueFrom
- widget: ResourceLink
- source: >-
- $exists($item.valueFrom.configMapKeyRef)?
- $item.valueFrom.configMapKeyRef.name :
- $item.valueFrom.secretKeyRef.name
- resource:
- name: >-
- $exists($item.valueFrom.configMapKeyRef) ?
- $item.valueFrom.configMapKeyRef.name :
- $item.valueFrom.secretKeyRef.name
- namespace: $root.metadata.namespace
- kind: >-
- $exists($item.valueFrom.configMapKeyRef) ? 'ConfigMap' :
- 'Secret'
- - name: code.env.source
- widget: Badge
- source: >-
- $exists($item.value) ? 'CUSTOM' :
- $exists($item.valueFrom.configMapKeyRef) ? 'CONFIG MAP' : 'SECRET'
- - name: code.env.key
- source: >-
- $exists($item.valueFrom.configMapKeyRef) ?
- $item.valueFrom.configMapKeyRef.key :
- $exists($item.valueFrom.secretKeyRef) ?
- $item.valueFrom.secretKeyRef.key : 'N/A'
- - widget: ResourceList
- source: $replicas()
- name: code.replicas
- disableCreate: true
- - widget: EventList
- filter: $matchEvents($item, $root.kind, $root.metadata.name)
- name: events
- defaultType: information
- hideInvolvedObjects: true
- - name: tabs.configuration
- children:
- - widget: ResourceList
- source: $apiRules()
- name: configuration.apiRules
- disableCreate: true
- - widget: ResourceList
- source: $subscriptions()
- name: configuration.subscriptions
- disableCreate: true
- - name: tabs.resources
- children:
- - widget: Panel
- description: resources.description
- name: resources.scalingOptions
- visibility: $exists(spec.scaleConfig.minReplicas) or $exists(spec.scaleConfig.maxReplicas)
- children:
- - name: resources.minReplicas
- source: spec.scaleConfig.minReplicas
- - name: resources.maxReplicas
- source: spec.scaleConfig.maxReplicas
- - widget: Columns
- inline: false
- children:
- - name: resources.runtimeProfile
- widget: Panel
- children:
- - name: resources.requests.memory
- source: >-
- spec.resourceConfiguration.function.resources.requests.memory
- - name: resources.requests.cpu
- source: spec.resourceConfiguration.function.resources.requests.cpu
- - name: resources.limits.memory
- source: >-
- spec.resourceConfiguration.function.resources.limits.memory
- - name: resources.limits.cpu
- source: spec.resourceConfiguration.function.resources.limits.cpu
- - name: resources.buildProfile
- widget: Panel
- children:
- - name: resources.requests.memory
- source: spec.resourceConfiguration.build.resources.requests.memory
- - name: resources.requests.cpu
- source: spec.resourceConfiguration.build.resources.requests.cpu
- - name: resources.limits.memory
- source: spec.resourceConfiguration.build.resources.limits.memory
- - name: resources.limits.cpu
- source: spec.resourceConfiguration.build.resources.limits.cpu
- form: |-
- - var: sourceType
- widget: Text
- enum:
- - Inline
- - Git Repository
- dynamicValue: '$exists(spec.source.gitRepository) ? "Git Repository" : "Inline"'
- name: header.sourceType
- trigger: [sourceType]
- - simple: true
- type: string
- name: Language
- var: language
- required: true
- enum: [JavaScript, Python]
- trigger: [language]
- dynamicValue: |
- spec.runtime in ['nodejs18', 'nodejs20'] ? 'JavaScript' :
- spec.runtime in ['python39', 'python312'] ? 'Python' :
- ''
- - simple: true
- path: spec.runtime
- placeholder: placeholders.spec.runtime
- enum: |
- $language = 'JavaScript' ? ['nodejs18', 'nodejs20'] :
- $language = 'Python' ? ['python39', 'python312'] :
- []
- subscribe:
- language: |
- $language = 'JavaScript' ? ($exists($root.spec.runtime) and $root.spec.runtime != 'python39') ? $root.spec.runtime : 'nodejs20' :
- $language = 'Python' ? 'python39' :
- ''
- - path: spec.resourceConfiguration.function.profile
- simple: true
- enum: ['XS', 'S', 'M', 'L', 'XL']
- - path: spec.source.inline
- visibility: $sourceType = 'Inline'
- simple: true
- children:
- - path: source
- widget: CodeEditor
- simple: true
- language: '$contains($root.spec.runtime, "node") ? "javascript" : "python"'
- defaultExpanded: true
- subscribe:
- sourceType: |-
- $sourceType = 'Inline' ? $language = 'JavaScript' ? $exists($root.metadata.creationTimestamp) ? $root.spec.source.inline.source : "module.exports = {
- main: async function (event, context) {
- var queryParams = event['extensions']['request']['query'];
-
- //read query param, for example `?greeting=Hi`
- var greetingMsg = queryParams['greeting'];
- if(!greetingMsg) {
- greetingMsg = 'Hello world';
- }
- const message = greetingMsg
- + ` from the Kyma Function ${context['function-name']}`
- + ` running on ${context.runtime}!`;
- console.log(message);
- return message;
- }
- }" :
- $language = 'Python' ? $exists($root.metadata.creationTimestamp) ? $root.spec.source.inline.source : "def main(event, context):
- request = event['extensions']['request']
- greetingMsg = request.query.get('greeting')
- if not greetingMsg:
- greetingMsg = 'Hello world'
- message = greetingMsg + ' from the Kyma Function '+context['function-name']+' running on '+context['runtime']+ '!';
- print(message)
- return message" :
- '' : ''
- language: |-
- $language = 'JavaScript' ? $exists($root.metadata.creationTimestamp) ? $root.spec.source.inline.source : "module.exports = {
- main: async function (event, context) {
- var queryParams = event['extensions']['request']['query'];
-
- //read query param, for example `?greeting=Hi`
- var greetingMsg = queryParams['greeting'];
- if(!greetingMsg) {
- greetingMsg = 'Hello world';
- }
- const message = greetingMsg
- + ` from the Kyma Function ${context['function-name']}`
- + ` running on ${context.runtime}!`;
- console.log(message);
- return message;
- }
- }" :
- $language = 'Python' ? $exists($root.metadata.creationTimestamp) ? $root.spec.source.inline.source : "def main(event, context):
- request = event['extensions']['request']
- greetingMsg = request.query.get('greeting')
- if not greetingMsg:
- greetingMsg = 'Hello world'
- message = greetingMsg + ' from the Kyma Function '+context['function-name']+' running on '+context['runtime']+ '!';
- print(message)
- return message" :
- ''
- - path: dependencies
- widget: CodeEditor
- language: '$contains($root.spec.runtime, "node") ? "json" : "plaintext"'
- - path: spec.source.gitRepository
- widget: FormGroup
- visibility: $sourceType = 'Git Repository'
- defaultExpanded: true
- children:
- - path: url
- - path: baseDir
- required: true
- - path: reference
- required: true
- - var: useAuthorization
- type: boolean
- name: code.gitRepository.auth
- dynamicValue: $exists($.spec.source.gitRepository.auth)
- - widget: FormGroup
- path: auth
- visibility: $useAuthorization
- children:
- - path: secretName
- widget: Resource
- resource:
- kind: Secret
- version: v1
- scope: namespace
- - path: type
- - path: spec.scaleConfig
- widget: FormGroup
- columns: '2'
- children:
- - advanced: true
- path: minReplicas
- required: false
- min: '1'
- - advanced: true
- path: maxReplicas
- required: false
- min: '1'
- - path: spec.resourceConfiguration.function
- widget: FormGroup
- children:
- - path: resources.limits
- widget: KeyValuePair
- - visibility: $boolean($root.spec.resourceConfiguration.function.profile)
- severity: warning
- alert: "'alert.resources.limits'"
- widget: Alert
- - path: resources.requests
- widget: KeyValuePair
- - visibility: $boolean($root.spec.resourceConfiguration.function.profile)
- severity: warning
- alert: "'alert.resources.requests'"
- widget: Alert
- - path: spec.resourceConfiguration.build
- widget: FormGroup
- children:
- - path: resources.limits
- widget: KeyValuePair
- - path: resources.requests
- widget: KeyValuePair
- - path: spec.env
- widget: GenericList
- children:
- - path: '[]'
- children:
- - var: envType
- widget: Text
- name: spec.env.source
- enum:
- - Custom
- - From Config Map
- - From Secret
- dynamicValue: >-
- $exists($item.valueFrom.secretKeyRef) ? 'From Secret' :
- ($exists($item.valueFrom.configMapKeyRef) ? 'From Config Map' :
- 'Custom')
- - path: name
- - path: value
- visibility: $envType = 'Custom'
- - path: valueFrom.secretKeyRef.name
- widget: Resource
- resource:
- kind: Secret
- version: v1
- scope: namespace
- provideVar: secret
- visibility: $envType = 'From Secret'
- - path: valueFrom.secretKeyRef.key
- widget: Text
- enum: $keys($secret.data)
- visibility: $envType = 'From Secret'
- - path: valueFrom.configMapKeyRef.name
- widget: Resource
- resource:
- kind: ConfigMap
- version: v1
- scope: namespace
- provideVar: configMap
- visibility: $envType = 'From Config Map'
- - path: valueFrom.configMapKeyRef.key
- widget: Text
- enum: $keys($configMap.data)
- visibility: $envType = 'From Config Map'
- - path: spec
- widget: FormGroup
- children:
- - path: labels
- widget: KeyValuePair
- defaultExpanded: false
- - path: annotations
- widget: KeyValuePair
- defaultExpanded: false
- general: |-
- resource:
- kind: Function
- group: serverless.kyma-project.io
- version: v1alpha2
- name: Functions
- category: Workloads
- urlPath: functions
- scope: namespace
- description: >-
- {{"{{[Function](https://kyma-project.io/docs/kyma/latest/05-technical-reference/00-custom-resources/svls-01-function/#documentation-content/)}}"}}
- is a simple code snippet that you can run without provisioning or managing
- servers.
- list: |-
- - name: header.runtime
- source: >-
- spec.runtime = 'python39' ? 'Python 3.9 - deprecated' : (spec.runtime = 'nodejs18' ? 'Node.js 18 - deprecated' : (spec.runtime = 'python312' ? 'Python 3.12' : (spec.runtime = 'nodejs20' ? 'Node.js 20' : spec.runtime)))
- - name: header.sourceType
- source: 'spec.source.gitRepository ? "Git Repository" : "Inline Editor"'
- - name: header.status
- widget: Badge
- highlights:
- positive:
- - RUNNING
- negative:
- - FAILED
- - ERROR
- informative:
- - INITIALIZING
- critical:
- - DEPLOYING
- - BUILDING
- - PENDING
- source: >-
- ($.status = undefined or $.status.conditions = undefined or
- $count($.status.conditions) = 0) ? 'INITIALIZING' :
- $count($filter($.status.conditions, function($v) { $v.status = 'False' }))
- != 0 ? $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'True' })) != 0 ? 'ERROR' : 'FAILED' :
- $count($filter($.status.conditions, function($v) { $v.type =
- 'ConfigurationReady' and $v.status = 'True' })) != 0 ?
- $count($filter($.status.conditions, function($v) { $v.type = 'BuildReady'
- and $v.status = 'True' })) != 0 ? $count($filter($.status.conditions,
- function($v) { $v.type = 'Running' and $v.status = 'True' })) != 0 ?
- 'RUNNING' : $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'Unknown' and $v.reason =
- 'MinReplicasNotAvailable' })) != 0 ? 'PENDING' : 'DEPLOYING' : 'BUILDING' :
- 'INITIALIZING'
- description: >-
- ($.status = undefined or $.status.conditions = undefined or
- $count($.status.conditions) = 0) ? null :
- $count($filter($.status.conditions, function($v) { $v.status = 'False' }))
- != 0 ? $count($filter($.status.conditions, function($v) { $v.type =
- 'Running' and $v.status = 'True' })) != 0 ? 'New revision error: ' &
- $filter($.status.conditions, function($v) { $v.status = 'False'
- })[0].message : 'Error: ' & $filter($.status.conditions, function($v) {
- $v.status = 'False' })[0].message : null
- dataSources: |-
- replicas:
- resource:
- kind: Pod
- version: v1
- filter: >-
- ($item.metadata.labels.'serverless.kyma-project.io/function-name' =
- $root.metadata.name) and
- ($item.metadata.labels.'serverless.kyma-project.io/resource' = 'deployment')
- apiRules:
- resource:
- kind: APIRule
- version: v1beta1
- group: gateway.kyma-project.io
- filter: $contains($item.spec.service.name, $root.metadata.name)
- subscriptions:
- resource:
- kind: Subscription
- version: v1alpha2
- group: eventing.kyma-project.io
- filter: $contains($item.spec.sink, $root.metadata.name)
- translations: |
- en:
- tabs.code: Code
- tabs.configuration: Configuration
- tabs.resources: Resources
- code.gitRepositoryConfig: Repository Configuration
- code.replicas: Replicas of the Function
- code.source: Source
- code.dependencies: Dependencies
- code.gitRepository.url: URL
- code.gitRepository.reference: Reference
- code.gitRepository.baseDir: Base Directory
- code.gitRepository.auth: Auth
- code.gitRepository.auth.secretName: Secret name
- code.gitRepository.auth.type: Type
- code.env: Environment Variables
- code.env.name: Name
- code.env.value: Value
- code.env.valueFrom: Value From
- code.env.source: Source
- code.env.key: Key
- events: Events
- configuration.apiRules: API Rules
- configuration.subscriptions: Subscriptions
- header.runtime: Runtime
- header.status: Status
- header.sourceType: Source Type
- resources.scalingOptions: Scaling Options
- resources.minReplicas: Minimum Replicas
- resources.maxReplicas: Maximum Replicas
- resources.description: Minimum and maximum number of running Replicas.
- resources.runtimeProfile: Runtime Profile
- resources.buildProfile: Build Job Profile
- resources.requests.memory: Memory Requests
- resources.requests.cpu: CPU Requests
- resources.limits.memory: Memory Limits
- resources.limits.cpu: CPU Limits
- spec.scaleConfig: Scale Config
- spec.scaleConfig.maxReplicas: Max Replicas
- spec.scaleConfig.minReplicas: Min Replicas
- spec.source.inline.dependencies: Dependencies
- spec.source.inline.source: Source
- spec.env: Environment Variables
- Requests: Requests
- Limits: Limits
- spec.runtime: Runtime
- Status: Status
- Runtime: Runtime
- 'Source Type': Source Type
- spec.runtime.nodejs18: Node.js 18 - deprecated
- spec.runtime.nodejs20: Node.js 20
- spec.runtime.python39: Python 3.9 - deprecated
- spec.runtime.python312: Python 3.12
- spec.resourceConfiguration.build: Build
- spec.resourceConfiguration.function: Function
- spec.resourceConfiguration.function.profile: Function profile
- placeholders.spec.runtime: Choose Function runtime
- spec.env.name: Variable Name
- spec.env.source: Source
- envType: Variable Type
- 'Node.js Function': Node.js Function
- 'Python Function': Python Function
- alert.resources.requests: If you want to provide your own requests configuration, leave the Function profile field empty.
- alert.resources.limits: If you want to provide your own limits configuration, leave the Function profile field empty.
- spec.labels: Runtime Labels
- spec.annotations: Runtime Annotations
- presets: |-
- - name: Default
- default: true
- value:
- spec:
- resourceConfiguration:
- function:
- profile: XS
- - name: Node.js Function
- value:
- spec:
- runtime: nodejs20
- source:
- inline:
- source: |-
- module.exports = {
- main: async function (event, context) {
- const message = `Hello World`
- + ` from the Kyma Function ${context["function-name"]}`
- + ` running on ${context.runtime}!`;
- console.log(message);
- return message;
- }
- }
- - name: Python Function
- value:
- spec:
- runtime: python312
- source:
- inline:
- source: |-
- def main(event, context):
- message = "Hello World from the Kyma Function "+context['function-name']+" running on "+context['runtime']+ "!";
- print(message)
- return message
diff --git a/config/serverless/templates/cluster-role-binding.yaml b/config/serverless/templates/cluster-role-binding.yaml
deleted file mode 100644
index 9e4b4809e..000000000
--- a/config/serverless/templates/cluster-role-binding.yaml
+++ /dev/null
@@ -1,14 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: {{ template "fullname" . }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: {{ template "fullname" . }}
-subjects:
-- kind: ServiceAccount
- name: {{ template "fullname" . }}-controller-manager
- namespace: {{ .Release.Namespace }}
diff --git a/config/serverless/templates/cluster-role.yaml b/config/serverless/templates/cluster-role.yaml
deleted file mode 100644
index c06fbf349..000000000
--- a/config/serverless/templates/cluster-role.yaml
+++ /dev/null
@@ -1,173 +0,0 @@
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: {{ template "fullname" . }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
-rules:
-- apiGroups:
- - ""
- resources:
- - configmaps
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - configmaps
- - secrets
- - serviceaccounts
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - events
- verbs:
- - create
- - patch
-- apiGroups:
- - ""
- resources:
- - namespaces
- verbs:
- - get
- - list
- - watch
-- apiGroups:
- - ""
- resources:
- - secrets
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - serviceaccounts
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - ""
- resources:
- - services
- verbs:
- - create
- - delete
- - get
- - list
- - update
- - watch
-- apiGroups:
- - apps
- resources:
- - deployments
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - apps
- resources:
- - deployments/status
- verbs:
- - get
-- apiGroups:
- - autoscaling
- resources:
- - horizontalpodautoscalers
- verbs:
- - create
- - deletecollection
- - get
- - list
- - update
- - watch
-- apiGroups:
- - batch
- resources:
- - jobs
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - batch
- resources:
- - jobs/status
- verbs:
- - get
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions
- verbs:
- - create
- - delete
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - serverless.kyma-project.io
- resources:
- - functions/status
- verbs:
- - get
- - patch
- - update
-- apiGroups:
- - rbac.authorization.k8s.io
- resources:
- - roles
- - rolebindings
- verbs:
- - create
- - delete
- - deletecollection
- - get
- - list
- - patch
- - update
- - watch
-- apiGroups:
- - policy
- resources:
- - podsecuritypolicies
- verbs:
- - use
diff --git a/config/serverless/templates/configmap.yaml b/config/serverless/templates/configmap.yaml
deleted file mode 100644
index 7cac1b924..000000000
--- a/config/serverless/templates/configmap.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: "{{ .Values.global.configuration.configmapName }}"
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
-data:
- {{ .Values.global.configuration.logFilename }}: {{ include "tplValue" ( dict "value" .Values.containers.manager.logConfiguration.data "context" . ) | quote }}
diff --git a/config/serverless/templates/crds.yaml b/config/serverless/templates/crds.yaml
deleted file mode 100644
index 9f7c29d01..000000000
--- a/config/serverless/templates/crds.yaml
+++ /dev/null
@@ -1,610 +0,0 @@
-apiVersion: apiextensions.k8s.io/v1
-kind: CustomResourceDefinition
-metadata:
- annotations:
- controller-gen.kubebuilder.io/version: v0.14.0
- name: functions.serverless.kyma-project.io
-spec:
- group: serverless.kyma-project.io
- names:
- kind: Function
- listKind: FunctionList
- plural: functions
- singular: function
- scope: Namespaced
- versions:
- - additionalPrinterColumns:
- - jsonPath: .status.conditions[?(@.type=='ConfigurationReady')].status
- name: Configured
- type: string
- - jsonPath: .status.conditions[?(@.type=='BuildReady')].status
- name: Built
- type: string
- - jsonPath: .status.conditions[?(@.type=='Running')].status
- name: Running
- type: string
- - jsonPath: .spec.runtime
- name: Runtime
- type: string
- - jsonPath: .metadata.generation
- name: Version
- type: integer
- - jsonPath: .metadata.creationTimestamp
- name: Age
- type: date
- name: v1alpha2
- schema:
- openAPIV3Schema:
- description: |-
- A simple code snippet that you can run without provisioning or managing servers.
- It implements the exact business logic you define.
- A Function is based on the Function custom resource (CR) and can be written in either Node.js or Python.
- A Function can perform a business logic of its own. You can also bind it to an instance of a service
- and configure it to be triggered whenever it receives a particular event type from the service
- or a call is made to the service's API.
- Functions are executed only if they are triggered by an event or an API call.
- properties:
- apiVersion:
- description: |-
- APIVersion defines the versioned schema of this representation of an object.
- Servers should convert recognized schemas to the latest internal value, and
- may reject unrecognized values.
- More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
- type: string
- kind:
- description: |-
- Kind is a string value representing the REST resource this object represents.
- Servers may infer this from the endpoint the client submits requests to.
- Cannot be updated.
- In CamelCase.
- More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
- type: string
- metadata:
- type: object
- spec:
- description: Defines the desired state of the Function
- properties:
- annotations:
- additionalProperties:
- type: string
- description: Defines annotations used in Deployment's PodTemplate
- and applied on the Function's runtime Pod.
- type: object
- x-kubernetes-validations:
- - message: Annotations has key starting with serverless.kyma-project.io/
- which is not allowed
- rule: '!(self.exists(e, e.startsWith(''serverless.kyma-project.io/'')))'
- env:
- description: |-
- Specifies an array of key-value pairs to be used as environment variables for the Function.
- You can define values as static strings or reference values from ConfigMaps or Secrets.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/).
- items:
- description: EnvVar represents an environment variable present in
- a Container.
- properties:
- name:
- description: Name of the environment variable. Must be a C_IDENTIFIER.
- type: string
- value:
- description: |-
- Variable references $(VAR_NAME) are expanded
- using the previously defined environment variables in the container and
- any service environment variables. If a variable cannot be resolved,
- the reference in the input string will be unchanged. Double $$ are reduced
- to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e.
- "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)".
- Escaped references will never be expanded, regardless of whether the variable
- exists or not.
- Defaults to "".
- type: string
- valueFrom:
- description: Source for the environment variable's value. Cannot
- be used if value is not empty.
- properties:
- configMapKeyRef:
- description: Selects a key of a ConfigMap.
- properties:
- key:
- description: The key to select.
- type: string
- name:
- description: |-
- Name of the referent.
- More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
- TODO: Add other useful fields. apiVersion, kind, uid?
- type: string
- optional:
- description: Specify whether the ConfigMap or its key
- must be defined
- type: boolean
- required:
- - key
- type: object
- x-kubernetes-map-type: atomic
- fieldRef:
- description: |-
- Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`,
- spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.
- properties:
- apiVersion:
- description: Version of the schema the FieldPath is
- written in terms of, defaults to "v1".
- type: string
- fieldPath:
- description: Path of the field to select in the specified
- API version.
- type: string
- required:
- - fieldPath
- type: object
- x-kubernetes-map-type: atomic
- resourceFieldRef:
- description: |-
- Selects a resource of the container: only resources limits and requests
- (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.
- properties:
- containerName:
- description: 'Container name: required for volumes,
- optional for env vars'
- type: string
- divisor:
- anyOf:
- - type: integer
- - type: string
- description: Specifies the output format of the exposed
- resources, defaults to "1"
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- resource:
- description: 'Required: resource to select'
- type: string
- required:
- - resource
- type: object
- x-kubernetes-map-type: atomic
- secretKeyRef:
- description: Selects a key of a secret in the pod's namespace
- properties:
- key:
- description: The key of the secret to select from. Must
- be a valid secret key.
- type: string
- name:
- description: |-
- Name of the referent.
- More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
- TODO: Add other useful fields. apiVersion, kind, uid?
- type: string
- optional:
- description: Specify whether the Secret or its key must
- be defined
- type: boolean
- required:
- - key
- type: object
- x-kubernetes-map-type: atomic
- type: object
- required:
- - name
- type: object
- type: array
- x-kubernetes-validations:
- - message: 'Following envs are reserved and cannot be used: [''FUNC_RUNTIME'',''FUNC_HANDLER'',''FUNC_PORT'',''MOD_NAME'',''NODE_PATH'',''PYTHONPATH'']'
- rule: (self.all(e, !(e.name in ['FUNC_RUNTIME','FUNC_HANDLER','FUNC_PORT','MOD_NAME','NODE_PATH','PYTHONPATH'])))
- labels:
- additionalProperties:
- type: string
- description: Defines labels used in Deployment's PodTemplate and applied
- on the Function's runtime Pod.
- type: object
- x-kubernetes-validations:
- - message: Labels has key starting with serverless.kyma-project.io/
- which is not allowed
- rule: '!(self.exists(e, e.startsWith(''serverless.kyma-project.io/'')))'
- - message: Label value cannot be longer than 63
- rule: self.all(e, size(e)<64)
- replicas:
- default: 1
- description: |-
- Defines the exact number of Function's Pods to run at a time.
- If **ScaleConfig** is configured, or if the Function is targeted by an external scaler,
- then the **Replicas** field is used by the relevant HorizontalPodAutoscaler to control the number of active replicas.
- format: int32
- minimum: 0
- type: integer
- resourceConfiguration:
- description: Specifies resources requested by the Function and the
- build Job.
- properties:
- build:
- description: Specifies resources requested by the build Job's
- Pod.
- properties:
- profile:
- description: |-
- Defines the name of the predefined set of values of the resource.
- Can't be used together with **Resources**.
- type: string
- resources:
- description: |-
- Defines the amount of resources available for the Pod.
- Can't be used together with **Profile**.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
- properties:
- claims:
- description: |-
- Claims lists the names of resources, defined in spec.resourceClaims,
- that are used by this container.
-
-
- This is an alpha field and requires enabling the
- DynamicResourceAllocation feature gate.
-
-
- This field is immutable. It can only be set for containers.
- items:
- description: ResourceClaim references one entry in PodSpec.ResourceClaims.
- properties:
- name:
- description: |-
- Name must match the name of one entry in pod.spec.resourceClaims of
- the Pod where this field is used. It makes that resource available
- inside a container.
- type: string
- required:
- - name
- type: object
- type: array
- x-kubernetes-list-map-keys:
- - name
- x-kubernetes-list-type: map
- limits:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Limits describes the maximum amount of compute resources allowed.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- requests:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Requests describes the minimum amount of compute resources required.
- If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
- otherwise to an implementation-defined value. Requests cannot exceed Limits.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use profile or resources
- rule: has(self.profile) && !has(self.resources) || !has(self.profile)
- && has(self.resources)
- - message: 'Invalid profile, please use one of: [''local-dev'',''slow'',''normal'',''fast'']'
- rule: (!has(self.profile) || self.profile in ['local-dev','slow','normal','fast'])
- function:
- description: Specifies resources requested by the Function's Pod.
- properties:
- profile:
- description: |-
- Defines the name of the predefined set of values of the resource.
- Can't be used together with **Resources**.
- type: string
- resources:
- description: |-
- Defines the amount of resources available for the Pod.
- Can't be used together with **Profile**.
- For configuration details, see the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/).
- properties:
- claims:
- description: |-
- Claims lists the names of resources, defined in spec.resourceClaims,
- that are used by this container.
-
-
- This is an alpha field and requires enabling the
- DynamicResourceAllocation feature gate.
-
-
- This field is immutable. It can only be set for containers.
- items:
- description: ResourceClaim references one entry in PodSpec.ResourceClaims.
- properties:
- name:
- description: |-
- Name must match the name of one entry in pod.spec.resourceClaims of
- the Pod where this field is used. It makes that resource available
- inside a container.
- type: string
- required:
- - name
- type: object
- type: array
- x-kubernetes-list-map-keys:
- - name
- x-kubernetes-list-type: map
- limits:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Limits describes the maximum amount of compute resources allowed.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- requests:
- additionalProperties:
- anyOf:
- - type: integer
- - type: string
- pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
- x-kubernetes-int-or-string: true
- description: |-
- Requests describes the minimum amount of compute resources required.
- If Requests is omitted for a container, it defaults to Limits if that is explicitly specified,
- otherwise to an implementation-defined value. Requests cannot exceed Limits.
- More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
- type: object
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use profile or resources
- rule: has(self.profile) && !has(self.resources) || !has(self.profile)
- && has(self.resources)
- - message: 'Invalid profile, please use one of: [''XS'',''S'',''M'',''L'',''XL'']'
- rule: (!has(self.profile) || self.profile in ['XS','S','M','L','XL'])
- type: object
- runtime:
- description: Specifies the runtime of the Function. The available
- values are `nodejs18` - deprecated, `nodejs20`, `python39` - deprecated,
- and `python312`.
- enum:
- - nodejs18
- - nodejs20
- - python39
- - python312
- type: string
- runtimeImageOverride:
- description: Specifies the runtime image used instead of the default
- one.
- type: string
- scaleConfig:
- description: |-
- Defines the minimum and maximum number of Function's Pods to run at a time.
- When it is configured, a HorizontalPodAutoscaler will be deployed and will control the **Replicas** field
- to scale the Function based on the CPU utilisation.
- properties:
- maxReplicas:
- description: Defines the maximum number of Function's Pods to
- run at a time.
- format: int32
- minimum: 1
- type: integer
- minReplicas:
- description: Defines the minimum number of Function's Pods to
- run at a time.
- format: int32
- minimum: 1
- type: integer
- required:
- - maxReplicas
- - minReplicas
- type: object
- x-kubernetes-validations:
- - message: minReplicas should be less than or equal maxReplicas
- rule: self.minReplicas <= self.maxReplicas
- secretMounts:
- description: Specifies Secrets to mount into the Function's container
- filesystem.
- items:
- properties:
- mountPath:
- description: Specifies the path within the container where the
- Secret should be mounted.
- minLength: 1
- type: string
- secretName:
- description: Specifies the name of the Secret in the Function's
- Namespace.
- maxLength: 253
- minLength: 1
- type: string
- required:
- - mountPath
- - secretName
- type: object
- type: array
- source:
- description: Contains the Function's source code configuration.
- properties:
- gitRepository:
- description: Defines the Function as git-sourced. Can't be used
- together with **Inline**.
- properties:
- auth:
- description: Specifies the authentication method. Required
- for SSH.
- properties:
- secretName:
- description: |-
- Specifies the name of the Secret with credentials used by the Function Controller
- to authenticate to the Git repository in order to fetch the Function's source code and dependencies.
- This Secret must be stored in the same Namespace as the Function CR.
- type: string
- x-kubernetes-validations:
- - message: SecretName is required and cannot be empty
- rule: self.trim().size() != 0
- type:
- description: |-
- Defines the repository authentication method. The value is either `basic` if you use a password or token,
- or `key` if you use an SSH key.
- enum:
- - basic
- - key
- type: string
- required:
- - secretName
- - type
- type: object
- baseDir:
- description: |-
- Specifies the relative path to the Git directory that contains the source code
- from which the Function is built.
- type: string
- reference:
- description: |-
- Specifies either the branch name, tag or commit revision from which the Function Controller
- automatically fetches the changes in the Function's code and dependencies.
- type: string
- url:
- description: |-
- Specifies the URL of the Git repository with the Function's code and dependencies.
- Depending on whether the repository is public or private and what authentication method is used to access it,
- the URL must start with the `http(s)`, `git`, or `ssh` prefix.
- type: string
- required:
- - url
- type: object
- x-kubernetes-validations:
- - message: BaseDir is required and cannot be empty
- rule: has(self.baseDir) && (self.baseDir.trim().size() != 0)
- - message: Reference is required and cannot be empty
- rule: has(self.reference) && (self.reference.trim().size() !=
- 0)
- inline:
- description: Defines the Function as the inline Function. Can't
- be used together with **GitRepository**.
- properties:
- dependencies:
- description: Specifies the Function's dependencies.
- type: string
- source:
- description: Specifies the Function's full source code.
- minLength: 1
- type: string
- required:
- - source
- type: object
- type: object
- x-kubernetes-validations:
- - message: Use GitRepository or Inline source
- rule: has(self.gitRepository) && !has(self.inline) || !has(self.gitRepository)
- && has(self.inline)
- template:
- description: 'Deprecated: Use **Labels** and **Annotations** to label
- and/or annotate Function''s Pods.'
- properties:
- annotations:
- additionalProperties:
- type: string
- description: 'Deprecated: Use **FunctionSpec.Annotations** to
- annotate Function''s Pods.'
- type: object
- labels:
- additionalProperties:
- type: string
- description: 'Deprecated: Use **FunctionSpec.Labels** to label
- Function''s Pods.'
- type: object
- type: object
- x-kubernetes-validations:
- - message: 'Not supported: Use spec.labels and spec.annotations to
- label and/or annotate Function''s Pods.'
- rule: '!has(self.labels) && !has(self.annotations)'
- required:
- - runtime
- - source
- type: object
- status:
- description: FunctionStatus defines the observed state of the Function
- properties:
- baseDir:
- description: |-
- Specifies the relative path to the Git directory that contains the source code
- from which the Function is built.
- type: string
- buildResourceProfile:
- description: Specifies the preset used for the build job
- type: string
- commit:
- description: Specifies the commit hash used to build the Function.
- type: string
- conditions:
- description: Specifies an array of conditions describing the status
- of the parser.
- items:
- properties:
- lastTransitionTime:
- description: Specifies the last time the condition transitioned
- from one status to another.
- format: date-time
- type: string
- message:
- description: Provides a human-readable message indicating details
- about the transition.
- type: string
- reason:
- description: Specifies the reason for the condition's last transition.
- type: string
- status:
- description: Specifies the status of the condition. The value
- is either `True`, `False`, or `Unknown`.
- type: string
- type:
- description: Specifies the type of the Function's condition.
- type: string
- required:
- - status
- type: object
- type: array
- functionResourceProfile:
- description: Specifies the preset used for the function
- type: string
- podSelector:
- description: Specifies the Pod selector used to match Pods in the
- Function's Deployment.
- type: string
- reference:
- description: |-
- Specifies either the branch name, tag or commit revision from which the Function Controller
- automatically fetches the changes in the Function's code and dependencies.
- type: string
- replicas:
- description: Specifies the total number of non-terminated Pods targeted
- by this Function.
- format: int32
- type: integer
- runtime:
- description: Specifies the **Runtime** type of the Function.
- type: string
- runtimeImage:
- description: Specifies the image version used to build and run the
- Function's Pods.
- type: string
- runtimeImageOverride:
- description: |-
- Deprecated: Specifies the runtime image version which overrides the **RuntimeImage** status parameter.
- **RuntimeImageOverride** exists for historical compatibility
- and should be removed with v1alpha3 version.
- type: string
- type: object
- type: object
- served: true
- storage: true
- subresources:
- scale:
- labelSelectorPath: .status.podSelector
- specReplicasPath: .spec.replicas
- statusReplicasPath: .status.replicas
- status: {}
diff --git a/config/serverless/templates/deployment.yaml b/config/serverless/templates/deployment.yaml
deleted file mode 100644
index 8fed92960..000000000
--- a/config/serverless/templates/deployment.yaml
+++ /dev/null
@@ -1,158 +0,0 @@
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: {{ template "fullname" . }}-ctrl-mngr
- namespace: {{ .Release.Namespace }}
- labels:
- kyma-project.io/component: controller
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
- {{- if .Values.deployment.labels }}
- {{- include "tplValue" ( dict "value" .Values.deployment.labels "context" . ) | nindent 4 }}
- {{- end }}
- {{- if .Values.deployment.annotations }}
- annotations:
- {{ include "tplValue" ( dict "value" .Values.deployment.annotations "context" . ) | nindent 4 }}
- {{- end }}
-spec:
- selector:
- matchLabels:
- app: {{ template "name" . }}
- app.kubernetes.io/name: {{ template "name" . }}
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- replicas: {{ .Values.deployment.replicas }}
- {{- if .Values.deployment.extraProperties }}
- {{ include "tplValue" ( dict "value" .Values.deployment.extraProperties "context" . ) | nindent 2 }}
- {{- end }}
- template:
- metadata:
- labels:
- app: {{ template "name" . }}
- app.kubernetes.io/name: {{ template "name" . }}
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- kyma-project.io/component: controller
- {{- if .Values.pod.labels }}
- {{ include "tplValue" ( dict "value" .Values.pod.labels "context" . ) | nindent 8 }}
- {{- end }}
- {{- if or .Values.pod.annotations (and .Values.metrics.enabled .Values.metrics.pod.annotations) }}
- annotations:
- {{- if .Values.pod.annotations }}
- {{ include "tplValue" ( dict "value" .Values.pod.annotations "context" . ) | nindent 8 }}
- {{- end }}
- {{- if and .Values.metrics.enabled .Values.metrics.pod.annotations }}
- {{ include "tplValue" ( dict "value" .Values.metrics.pod.annotations "context" . ) | nindent 8 }}
- {{- end }}
- {{- end }}
- spec:
- volumes:
- - name: configuration
- configMap:
- name: "{{ .Values.global.configuration.configmapName }}"
- - name: tmpdir # Needed to allow git repo fetching with read-only rootfs enabled
- emptyDir: { }
- serviceAccountName: {{ template "fullname" . }}-controller-manager
- {{- if .Values.pod.extraProperties }}
- {{ include "tplValue" ( dict "value" .Values.pod.extraProperties "context" . ) | nindent 6 }}
- {{- end }}
- containers:
- - name: manager
- volumeMounts:
- - name: configuration
- mountPath: {{ .Values.global.configuration.targetDir }}
- - name: tmpdir # Needed to allow git repo fetching with read-only rootfs enabled
- mountPath: "/tmp"
- image: "{{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_controller) }}"
- imagePullPolicy: {{ .Values.images.function_controller.pullPolicy }}
- command:
- - /app/manager
- {{- if .Values.containers.manager.resources }}
- resources:
- {{- include "tplValue" ( dict "value" .Values.containers.manager.resources "context" . ) | nindent 12 }}
- {{- end }}
- {{- if .Values.containers.manager.containerSecurityContext }}
- securityContext:
- {{- include "tplValue" ( dict "value" .Values.containers.manager.containerSecurityContext "context" . ) | nindent 12 }}
- {{- end }}
- ports:
- - containerPort: {{ .Values.services.manager.https.targetPort }}
- name: "webhook"
- protocol: TCP
- {{- if .Values.metrics.enabled }}
- - containerPort: {{ .Values.metrics.manager.port.port }}
- name: {{ .Values.metrics.manager.port.name }}
- protocol: {{ .Values.metrics.manager.port.protocol }}
- {{- end }}
- - containerPort: {{ .Values.containers.manager.healthz.port }}
- name: "health"
- protocol: TCP
- livenessProbe:
- httpGet:
- port: {{ .Values.containers.manager.healthz.port }}
- path: "/healthz/"
- initialDelaySeconds: {{ .Values.deployment.livenessProbe.initialDelaySeconds }}
- timeoutSeconds: {{ .Values.deployment.livenessProbe.timeoutSeconds }}
- periodSeconds: {{.Values.deployment.livenessProbe.periodSeconds }}
- failureThreshold: {{.Values.deployment.livenessProbe.failureThreshold }}
- successThreshold: {{.Values.deployment.livenessProbe.successThreshold }}
- readinessProbe:
- httpGet:
- port: {{ .Values.containers.manager.healthz.port }}
- path: "/readyz/"
- initialDelaySeconds: {{ .Values.deployment.readinessProbe.initialDelaySeconds }}
- timeoutSeconds: {{ .Values.deployment.readinessProbe.timeoutSeconds }}
- periodSeconds: {{.Values.deployment.readinessProbe.periodSeconds }}
- failureThreshold: {{.Values.deployment.readinessProbe.failureThreshold }}
- successThreshold: {{.Values.deployment.readinessProbe.successThreshold }}
- env:
- {{- if .Values.metrics.enabled }}
- - name: APP_METRICS_ADDRESS
- value: ":{{ .Values.metrics.manager.port.port }}"
- {{- end }}
- {{- if gt (int .Values.deployment.replicas) 1 }}
- - name: APP_LEADER_ELECTION_ENABLED
- value: "true"
- {{- end }}
- - name: APP_HEALTHZ_ADDRESS
- value: ":{{ .Values.containers.manager.healthz.port }}"
- - name: APP_KUBERNETES_BASE_NAMESPACE
- value: "{{- tpl ( .Values.containers.manager.configuration.data.baseNamespace) . }}"
- - name: APP_KUBERNETES_BASE_DEFAULT_SECRET_NAME
- value: "{{- tpl ( .Values.containers.manager.configuration.data.imageRegistryDefaultDockerConfigSecretName) . }}"
- - name: APP_KUBERNETES_CONFIG_MAP_REQUEUE_DURATION
- value: "{{ .Values.containers.manager.configuration.data.configMapRequeueDuration }}"
- - name: APP_KUBERNETES_SECRET_REQUEUE_DURATION
- value: {{.Values.containers.manager.configuration.data.secretRequeueDuration }}
- - name: APP_KUBERNETES_SERVICE_ACCOUNT_REQUEUE_DURATION
- value: {{.Values.containers.manager.configuration.data.serviceAccountRequeueDuration }}
- - name: APP_KUBERNETES_EXCLUDED_NAMESPACES
- value: "{{ .Release.Namespace }}"
- - name: APP_FUNCTION_TRACE_COLLECTOR_ENDPOINT
- value: "{{.Values.containers.manager.configuration.data.functionTraceCollectorEndpoint }}"
- - name: APP_FUNCTION_PUBLISHER_PROXY_ADDRESS
- value: "{{.Values.containers.manager.configuration.data.functionPublisherProxyAddress }}"
- - name: APP_FUNCTION_IMAGE_REGISTRY_DEFAULT_DOCKER_CONFIG_SECRET_NAME
- value: "{{- tpl ( .Values.containers.manager.configuration.data.imageRegistryDefaultDockerConfigSecretName) . }}"
- - name: APP_FUNCTION_IMAGE_REGISTRY_EXTERNAL_DOCKER_CONFIG_SECRET_NAME
- value: "{{- tpl ( .Values.containers.manager.configuration.data.imageRegistryExternalDockerConfigSecretName) . }}"
- - name: APP_FUNCTION_PACKAGE_REGISTRY_CONFIG_SECRET_NAME
- value: "{{- tpl ( .Values.containers.manager.configuration.data.packageRegistryConfigSecretName) . }}"
- - name: APP_FUNCTION_IMAGE_PULL_ACCOUNT_NAME
- value: "{{- tpl ( .Values.containers.manager.configuration.data.imagePullAccountName ) . }}"
- - name: APP_FUNCTION_REQUEUE_DURATION
- value: "{{.Values.containers.manager.configuration.data.functionRequeueDuration }}"
- - name: APP_FUNCTION_BUILD_EXECUTOR_ARGS
- value: "{{.Values.containers.manager.configuration.data.functionBuildExecutorArgs }}"
- - name: APP_FUNCTION_BUILD_EXECUTOR_IMAGE
- value: "{{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.kaniko_executor) }}"
- - name: APP_FUNCTION_TARGET_CPU_UTILIZATION_PERCENTAGE
- value: "{{.Values.containers.manager.configuration.data.targetCPUUtilizationPercentage }}"
- - name: APP_FUNCTION_BUILD_REPO_FETCHER_IMAGE
- value: "{{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_build_init)}}"
- - name: APP_FUNCTION_BUILD_MAX_SIMULTANEOUS_JOBS
- value: "{{.Values.containers.manager.configuration.data.functionBuildMaxSimultaneousJobs }}"
- - name: APP_HEALTHZ_LIVENESS_TIMEOUT
- value: "{{.Values.containers.manager.configuration.data.healthzLivenessTimeout }}"
- - name: APP_FUNCTION_RESOURCE_CONFIG
- value: {{ .Values.containers.manager.configuration.data.resourcesConfiguration | toYaml | quote }}
- - name: APP_LOG_CONFIG_PATH
- value: "{{ .Values.global.configuration.targetDir }}/{{ .Values.global.configuration.logFilename }}"
- priorityClassName: {{ .Values.global.serverlessPriorityClassName }}
diff --git a/config/serverless/templates/leader-election-role-binding.yaml b/config/serverless/templates/leader-election-role-binding.yaml
deleted file mode 100644
index a93981777..000000000
--- a/config/serverless/templates/leader-election-role-binding.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-{{- if gt (int .Values.deployment.replicas) 1 }}
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
- name: {{ template "fullname" . }}-leader-election
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: Role
- name: {{ template "fullname" . }}-leader-election
-subjects:
-- kind: ServiceAccount
- name: {{ template "fullname" . }}-controller-manager
- namespace: {{ .Release.Namespace }}
-{{- end }}
diff --git a/config/serverless/templates/leader-election-role.yaml b/config/serverless/templates/leader-election-role.yaml
deleted file mode 100644
index a7adda52b..000000000
--- a/config/serverless/templates/leader-election-role.yaml
+++ /dev/null
@@ -1,35 +0,0 @@
-{{- if gt (int .Values.deployment.replicas) 1 }}
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
- name: {{ template "fullname" . }}-leader-election
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
-rules:
-- apiGroups:
- - ""
- resources:
- - configmaps
- verbs:
- - get
- - list
- - watch
- - create
- - update
- - patch
- - delete
-- apiGroups:
- - ""
- resources:
- - configmaps/status
- verbs:
- - get
- - update
- - patch
-- apiGroups:
- - ""
- resources:
- - events
- verbs:
- - create
-{{- end }}
diff --git a/config/serverless/templates/priorityclass.yaml b/config/serverless/templates/priorityclass.yaml
deleted file mode 100644
index b1910ea99..000000000
--- a/config/serverless/templates/priorityclass.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-apiVersion: scheduling.k8s.io/v1
-kind: PriorityClass
-metadata:
- name: {{ .Values.global.serverlessPriorityClassName }}
-value: {{ .Values.global.serverlessPriorityClassValue }}
-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
diff --git a/config/serverless/templates/runtimes.yaml b/config/serverless/templates/runtimes.yaml
deleted file mode 100644
index 5fb10930a..000000000
--- a/config/serverless/templates/runtimes.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: dockerfile-nodejs18
- namespace: {{ .Release.Namespace }}
- labels:
- serverless.kyma-project.io/config: runtime
- serverless.kyma-project.io/runtime: nodejs18
-data:
- Dockerfile: |-
- ARG base_image={{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_runtime_nodejs18) }}
- FROM ${base_image}
- USER root
- ARG SRC_DIR=/src
-
- RUN mkdir -p /usr/src/app/function
- WORKDIR /usr/src/app/function
-
- COPY /registry-config/* /usr/src/app/function/
- COPY $SRC_DIR/package.json /usr/src/app/function/package.json
-
- RUN npm install --omit=dev
- COPY $SRC_DIR /usr/src/app/function
- RUN ls -l /usr/src/app/function
- WORKDIR /usr/src/app
-
- USER 1000
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: dockerfile-nodejs20
- namespace: {{ .Release.Namespace }}
- labels:
- serverless.kyma-project.io/config: runtime
- serverless.kyma-project.io/runtime: nodejs20
-data:
- Dockerfile: |-
- ARG base_image={{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_runtime_nodejs20) }}
- FROM ${base_image}
- USER root
- ARG SRC_DIR=/src
-
- RUN mkdir -p /usr/src/app/function
- WORKDIR /usr/src/app/function
-
- COPY /registry-config/* /usr/src/app/function/
- COPY $SRC_DIR/package.json /usr/src/app/function/package.json
-
- RUN npm install --omit=dev
- COPY $SRC_DIR /usr/src/app/function
- RUN ls -l /usr/src/app/function
- WORKDIR /usr/src/app
-
- USER 1000
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: dockerfile-python39
- namespace: {{ .Release.Namespace }}
- labels:
- serverless.kyma-project.io/config: runtime
- serverless.kyma-project.io/runtime: python39
-data:
- Dockerfile: |-
- ARG base_image={{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_runtime_python39) }}
- FROM ${base_image}
- USER root
- ENV KUBELESS_INSTALL_VOLUME=/kubeless
-
- COPY /src/requirements.txt $KUBELESS_INSTALL_VOLUME/requirements.txt
- COPY /registry-config/* /etc/
- RUN pip install --no-cache-dir -r $KUBELESS_INSTALL_VOLUME/requirements.txt
- COPY /src $KUBELESS_INSTALL_VOLUME
-
- RUN rm -rf /etc/pip.conf
-
- USER 1000
----
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: dockerfile-python312
- namespace: {{ .Release.Namespace }}
- labels:
- serverless.kyma-project.io/config: runtime
- serverless.kyma-project.io/runtime: python312
-data:
- Dockerfile: |-
- ARG base_image={{ include "imageurl" (dict "reg" .Values.global.containerRegistry "img" .Values.global.images.function_runtime_python312) }}
- FROM ${base_image}
- USER root
- ENV KUBELESS_INSTALL_VOLUME=/kubeless
-
- COPY /src/requirements.txt $KUBELESS_INSTALL_VOLUME/requirements.txt
- COPY /registry-config/* /etc/
- RUN pip install --no-cache-dir -r $KUBELESS_INSTALL_VOLUME/requirements.txt
- COPY /src $KUBELESS_INSTALL_VOLUME
-
- RUN rm -rf /etc/pip.conf
-
- USER 1000
diff --git a/config/serverless/templates/service-accounts.yaml b/config/serverless/templates/service-accounts.yaml
deleted file mode 100644
index 2bd00d0c9..000000000
--- a/config/serverless/templates/service-accounts.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: {{ template "fullname" . }}-controller-manager
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: {{ template "fullname" . }}-function
- namespace: {{ .Release.Namespace }}
- labels:
- serverless.kyma-project.io/config: service-account
-automountServiceAccountToken: false
-imagePullSecrets:
- - name: {{ template "fullname" . }}-registry-config
- - name: {{ template "fullname" . }}-registry-config-default
diff --git a/config/serverless/templates/service.yaml b/config/serverless/templates/service.yaml
deleted file mode 100644
index 35ba0c216..000000000
--- a/config/serverless/templates/service.yaml
+++ /dev/null
@@ -1,29 +0,0 @@
-apiVersion: v1
-kind: Service
-metadata:
- name: {{ template "fullname" . }}-controller-manager
- namespace: {{ .Release.Namespace }}
- labels:
- {{- include "tplValue" ( dict "value" .Values.global.commonLabels "context" . ) | nindent 4 }}
- {{- if .Values.services.manager.labels }}
- {{- include "tplValue" ( dict "value" .Values.services.manager.labels "context" . ) | nindent 4 }}
- {{- end }}
- {{- if .Values.services.manager.annotations }}
- annotations:
- {{- include "tplValue" ( dict "value" .Values.services.manager.annotations "context" . ) | nindent 4 }}
- {{- end }}
-spec:
- type: {{ .Values.services.manager.type }}
- ports:
- - name: {{ .Values.metrics.manager.port.name }}
- port: {{ .Values.metrics.manager.port.port }}
- protocol: {{ .Values.metrics.manager.port.protocol }}
- targetPort: {{ .Values.metrics.manager.port.targerPort }}
- - name: "https"
- port: {{ .Values.services.manager.https.port }}
- protocol: TCP
- targetPort: {{ .Values.services.manager.https.targetPort }}
- selector:
- app: {{ template "name" . }}
- app.kubernetes.io/name: {{ template "name" . }}
- app.kubernetes.io/instance: "{{ .Release.Name }}"
diff --git a/config/serverless/values.yaml b/config/serverless/values.yaml
deleted file mode 100644
index 9ae6607ae..000000000
--- a/config/serverless/values.yaml
+++ /dev/null
@@ -1,313 +0,0 @@
-# Default values for serverless.
-# This is a YAML-formatted file.
-# Declare variables to be passed into your templates.
-
-fullnameOverride: "serverless"
-injectCerts:
- image:
- pullPolicy: IfNotPresent
-migration:
- image:
- pullPolicy: IfNotPresent
-tests:
- enabled: true
- labels:
- integration: true
- after-upgrade: true
- e2e-skr: true
- long:
- waitTimeout: 180s
- resources:
- requests:
- memory: 128Mi
- cpu: 10m
- limits:
- memory: 256Mi
- cpu: 200m
- image:
- pullPolicy: IfNotPresent
- namespace: "long-running-function-test"
- name: longrun
- image:
- pullPolicy: IfNotPresent
- disableConcurrency: false
- restartPolicy: Never
- resources:
- requests:
- memory: 32Mi
- cpu: 10m
- limits:
- memory: 64Mi
- cpu: 200m
- envs:
- waitTimeout: 15m
- verifySSL: "false"
- verbose: "false"
- gitServer:
- repoName: "function"
- pkgRegistryConfig:
- secretName: "serverless-package-registry-config"
- URLNode: "https://pkgs.dev.azure.com/kyma-wookiee/public-packages/_packaging/public-packages%40Release/npm/registry/"
- URLPython: "https://pkgs.dev.azure.com/kyma-wookiee/public-packages/_packaging/public-packages%40Release/pypi/simple/"
-global:
- domainName: "kyma.example.com"
- commonLabels:
- app: '{{ template "name" . }}'
- version: "{{ .Values.global.images.function_controller.version }}"
- app.kubernetes.io/name: '{{ template "name" . }}'
- app.kubernetes.io/instance: "{{ .Release.Name }}"
- app.kubernetes.io/version: "{{ .Values.global.images.function_controller.version }}"
- helm.sh/chart: '{{ include "chart" . }}'
- registryServicePort: 5000
- registryNodePort: 32137
- configuration:
- configmapName: "serverless-configuration"
- targetDir: "/appconfig"
- logFilename: "log-config.yaml"
- filename: "config.yaml"
- ingress:
- domainName:
- containerRegistry:
- path: europe-docker.pkg.dev/kyma-project
- images:
- function_controller:
- name: "function-controller"
- version: "main"
- directory: "prod"
- function_build_init:
- name: "function-build-init"
- version: "main"
- directory: "prod"
- function_runtime_nodejs18:
- name: "function-runtime-nodejs18"
- version: "main"
- directory: "prod"
- function_runtime_nodejs20:
- name: "function-runtime-nodejs20"
- version: "main"
- directory: "prod"
- function_runtime_python39:
- name: "function-runtime-python39"
- version: "main"
- directory: "prod"
- function_runtime_python312:
- name: "function-runtime-python312"
- version: "main"
- directory: "prod"
- kaniko_executor:
- name: "tpi/kaniko-executor"
- version: "1.9.2-ea54c1c7"
- directory: "prod"
- registry:
- name: "tpi/registry"
- version: "2.8.1-1ae4c190"
- directory: "prod"
- serverlessPriorityClassValue: 2000000
- serverlessPriorityClassName: "serverless-priority"
-images:
- function_controller:
- pullPolicy: IfNotPresent
-deployment:
- replicas: 1
- labels: {}
- annotations: {}
- extraProperties: {}
- livenessProbe:
- successThreshold: 1
- failureThreshold: 3
- initialDelaySeconds: 50
- timeoutSeconds: 60
- periodSeconds: 120
- readinessProbe:
- successThreshold: 1
- failureThreshold: 3
- initialDelaySeconds: 10
- timeoutSeconds: 10
- periodSeconds: 30
-pod:
- labels: {}
- annotations:
- sidecar.istio.io/inject: "false"
- prometheus.io/scrape: "false"
- extraProperties:
- terminationGracePeriodSeconds: 10
- # the following guidelines should be followed for this https://github.com/kyma-project/community/tree/main/concepts/psp-replacement
- securityContext:
- runAsNonRoot: true
- runAsUser: 1000 # Optional. Use this setting only when necessary, otherwise delete it. Never set to 0 because this is the ID of root.
- runAsGroup: 1000 # Optional. Use this setting only when necessary, otherwise delete it. Never set to 0 because this is the ID of root.
- seccompProfile: # Optional. This option can also be set on container level but it is recommended to set it on Pod level and leave it undefined on container level.
- type: RuntimeDefault
- hostNetwork: false # Optional. The default is false if the entry is not there.
- hostPID: false # Optional. The default is false if the entry is not there.
- hostIPC: false # Optional. The default is false if the entry is not there.
-containers:
- daemonset:
- initContainerSecurityContext:
- privileged: false
- allowPrivilegeEscalation: false
- runAsUser: 0
- containerSecurityContext:
- privileged: false
- allowPrivilegeEscalation: false
- manager:
- resources:
- limits:
- cpu: 600m
- memory: 1Gi
- requests:
- cpu: 10m
- memory: 32Mi
- # the following guidelines should be followed for this https://github.com/kyma-project/community/tree/main/concepts/psp-replacement
- containerSecurityContext:
- privileged: false
- allowPrivilegeEscalation: false
- capabilities:
- drop: ["ALL"]
- procMount: default # Optional. The default is false if the entry is not there.
- readOnlyRootFilesystem: true # Mandatory
- healthz:
- port: "8090"
- logConfiguration:
- data:
- logLevel: "info"
- logFormat: "json"
- configuration:
- data:
- baseNamespace: "{{ .Release.Namespace }}"
- configMapRequeueDuration: 5m
- secretRequeueDuration: 5m
- serviceAccountRequeueDuration: 5m
- imageRegistryExternalDockerConfigSecretName: '{{ template "fullname" . }}-registry-config'
- imageRegistryDefaultDockerConfigSecretName: '{{ template "fullname" . }}-registry-config-default'
- packageRegistryConfigSecretName: '{{ template "fullname" . }}-package-registry-config'
- imagePullAccountName: '{{ template "fullname" . }}-function'
- targetCPUUtilizationPercentage: "50"
- functionTraceCollectorEndpoint: "http://telemetry-otlp-traces.kyma-system.svc.cluster.local:4318/v1/traces"
- functionPublisherProxyAddress: "http://eventing-publisher-proxy.kyma-system.svc.cluster.local/publish"
- functionRequeueDuration: 5m
- functionBuildExecutorArgs: "--insecure,--skip-tls-verify,--skip-unused-stages,--log-format=text,--cache=true,--use-new-run,--compressed-caching=false"
- functionBuildMaxSimultaneousJobs: "5"
- healthzLivenessTimeout: "10s"
- resourcesConfiguration:
- function:
- resources:
- minRequestCpu: "10m"
- minRequestMemory: "16Mi"
- defaultPreset: "L"
- presets:
- XS:
- requestCpu: "50m"
- requestMemory: "64Mi"
- limitCpu: "100m"
- limitMemory: "128Mi"
- S:
- requestCpu: "100m"
- requestMemory: "128Mi"
- limitCpu: "200m"
- limitMemory: "256Mi"
- M:
- requestCpu: "200m"
- requestMemory: "256Mi"
- limitCpu: "400m"
- limitMemory: "512Mi"
- L:
- requestCpu: "400m"
- requestMemory: "512Mi"
- limitCpu: "800m"
- limitMemory: "1024Mi"
- XL:
- requestCpu: "800m"
- requestMemory: "1024Mi"
- limitCpu: "1600m"
- limitMemory: "2048Mi"
- # runtimePresets:
-
- buildJob:
- resources:
- minRequestCpu: "200m"
- minRequestMemory: "200Mi"
- defaultPreset: "fast"
- presets:
- local-dev:
- requestCpu: "200m"
- requestMemory: "200Mi"
- limitCpu: "400m"
- limitMemory: "400Mi"
- slow:
- requestCpu: "200m"
- requestMemory: "200Mi"
- limitCpu: "700m"
- limitMemory: "700Mi"
- normal:
- requestCpu: "700m"
- requestMemory: "700Mi"
- limitCpu: "1100m"
- limitMemory: "1100Mi"
- fast:
- requestCpu: "1100m"
- requestMemory: "1100Mi"
- limitCpu: "1700m"
- limitMemory: "1100Mi"
-services:
- manager:
- type: ClusterIP
- labels: {}
- annotations:
- prometheus.io/scrape: "true"
- prometheus.io/port: "8080"
- prometheus.io/path: "/metrics"
- https:
- port: 443
- targetPort: 8443
-metrics:
- enabled: true
- manager:
- port:
- name: http-metrics
- port: 8080
- targerPort: 8080
- protocol: TCP
- pod:
- labels: {}
- annotations: {}
-backendModule:
- enabled: true
-clusterMicroFrontend:
- enabled: true
-dockerRegistry:
- enableInternal: true
- gateway: "kyma-system/kyma-gateway"
- gatewayCert: "kyma-gateway-certs"
- username: "{{ randAlphaNum 20 | b64enc }}" # for gcr "_json_key"
- password: "{{ randAlphaNum 40 | b64enc }}" # for gcr data from json key
- # This is the registry address, for dockerhub it's username, for other it's url.
- registryAddress: ""
- # This is the server address of the registry which will be used to create docker configuration.
- serverAddress: ""
-docker-registry:
- fullnameOverride: "serverless-docker-registry"
- destinationRule:
- enabled: true
- secrets:
- haSharedSecret: "secret"
- htpasswd: "generated-in-init-container"
- extraVolumeMounts:
- - name: htpasswd-data
- mountPath: /data
- extraVolumes:
- - name: registry-credentials
- secret:
- secretName: serverless-registry-config-default
- items:
- - key: username
- path: username.txt
- - key: password
- path: password.txt
- - name: htpasswd-data
- emptyDir: {}
- rollme: "{{ randAlphaNum 5}}"
- registryHTTPSecret: "{{ randAlphaNum 16 | b64enc }}"
-webhook:
- enabled: false
- fullnameOverride: "serverless-webhook"
diff --git a/docs/user/resources/06-20-serverless-cr.md b/docs/user/resources/06-20-serverless-cr.md
index 103c89044..de0b562b2 100644
--- a/docs/user/resources/06-20-serverless-cr.md
+++ b/docs/user/resources/06-20-serverless-cr.md
@@ -15,7 +15,7 @@ The following Serverless custom resource (CR) shows configuration of Serverless
kind: Serverless
metadata:
finalizers:
- - serverless-operator.kyma-project.io/deletion-hook
+ - dockerregistry-operator.kyma-project.io/deletion-hook
name: default
namespace: kyma-system
spec:
diff --git a/go.mod b/go.mod
index 675db6605..2729ba3b6 100644
--- a/go.mod
+++ b/go.mod
@@ -5,30 +5,12 @@ go 1.21
toolchain go1.21.3
require (
- github.com/avast/retry-go v3.0.0+incompatible
- github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
- github.com/cloudevents/sdk-go/v2 v2.15.2
- github.com/fsnotify/fsnotify v1.7.0
- github.com/go-git/go-billy/v5 v5.5.0
- github.com/go-git/go-git/v5 v5.11.0
- github.com/go-logr/zapr v1.3.0
- github.com/google/uuid v1.6.0
- github.com/hashicorp/errwrap v1.1.0
- github.com/hashicorp/go-multierror v1.1.1
- github.com/libgit2/git2go/v34 v34.0.0
github.com/onsi/ginkgo/v2 v2.17.1
github.com/onsi/gomega v1.32.0
github.com/pkg/errors v0.9.1
- github.com/prometheus/client_golang v1.19.0
- github.com/sirupsen/logrus v1.9.3
- github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/vrischmann/envconfig v1.3.0
go.uber.org/zap v1.27.0
- golang.org/x/crypto v0.21.0
- golang.org/x/sync v0.6.0
- golang.org/x/time v0.5.0
- gopkg.in/yaml.v2 v2.4.0
gopkg.in/yaml.v3 v3.0.1
helm.sh/helm/v3 v3.14.3
k8s.io/api v0.29.0
@@ -36,13 +18,11 @@ require (
k8s.io/apimachinery v0.29.0
k8s.io/cli-runtime v0.29.0
k8s.io/client-go v0.29.0
- k8s.io/klog/v2 v2.110.1
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/controller-runtime v0.15.3
)
require (
- dario.cat/mergo v1.0.0 // indirect
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
@@ -51,14 +31,11 @@ require (
github.com/Masterminds/semver/v3 v3.2.1 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
- github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
- github.com/cloudflare/circl v1.3.7 // indirect
github.com/containerd/containerd v1.7.12 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
@@ -71,17 +48,17 @@ require (
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
- github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch v5.7.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/felixge/httpsnoop v1.0.3 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
- github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
@@ -96,21 +73,20 @@ require (
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gosuri/uitable v0.0.4 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmoiron/sqlx v1.3.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.16.0 // indirect
- github.com/kr/pretty v0.3.1 // indirect
- github.com/kr/text v0.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lib/pq v1.10.9 // indirect
@@ -134,21 +110,19 @@ require (
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
- github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
+ github.com/prometheus/client_golang v1.19.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/rubenv/sql-migrate v1.5.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
- github.com/sergi/go-diff v1.1.0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
- github.com/skeema/knownhosts v1.2.1 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.8.0 // indirect
- github.com/stretchr/objx v0.5.2 // indirect
- github.com/xanzy/ssh-agent v0.3.3 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
@@ -159,12 +133,14 @@ require (
go.opentelemetry.io/otel/trace v1.19.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
- golang.org/x/mod v0.14.0 // indirect
+ golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/oauth2 v0.16.0 // indirect
+ golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
+ golang.org/x/time v0.5.0 // indirect
golang.org/x/tools v0.17.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
@@ -172,9 +148,10 @@ require (
google.golang.org/grpc v1.58.3 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/warnings.v0 v0.1.2 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/apiserver v0.29.0 // indirect
k8s.io/component-base v0.29.0 // indirect
+ k8s.io/klog/v2 v2.110.1 // indirect
k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect
k8s.io/kubectl v0.29.0 // indirect
oras.land/oras-go v1.2.4 // indirect
diff --git a/go.sum b/go.sum
index 676919079..14d3a1ad4 100644
--- a/go.sum
+++ b/go.sum
@@ -1,6 +1,4 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
-dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
@@ -21,31 +19,22 @@ github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj
github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
-github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.11.4 h1:68vKo2VN8DE9AdN4tnkWnmdhqdbpUFM8OF3Airm7fz8=
github.com/Microsoft/hcsshim v0.11.4/go.mod h1:smjE4dvqPX9Zldna+t5FG3rnoHhaB7QYxPRqGcpAD9w=
-github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg=
-github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
-github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
-github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
-github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
@@ -54,7 +43,6 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -64,11 +52,6 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cloudevents/sdk-go/v2 v2.15.2 h1:54+I5xQEnI73RBhWHxbI1XJcqOFOVJN85vb41+8mHUc=
-github.com/cloudevents/sdk-go/v2 v2.15.2/go.mod h1:lL7kSWAE/V8VI4Wh0jbL2v/jvqsm6tjmaQBSvxcv4uE=
-github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
-github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
-github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw=
github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0=
@@ -106,12 +89,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
-github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
-github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
-github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI=
@@ -130,18 +109,8 @@ github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
-github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
-github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
-github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
-github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
-github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
-github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
-github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4=
-github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY=
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -244,8 +213,6 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
-github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g=
github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -257,15 +224,12 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
-github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
-github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4=
github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -280,8 +244,6 @@ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6Fm
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/libgit2/git2go/v34 v34.0.0 h1:UKoUaKLmiCRbOCD3PtUi2hD6hESSXzME/9OUZrGcgu8=
-github.com/libgit2/git2go/v34 v34.0.0/go.mod h1:blVco2jDAw6YTXkErMMqzHLcAjKkwF0aWIRHBqiJkZ0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -353,9 +315,6 @@ github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+v
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
-github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
-github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -382,7 +341,6 @@ github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsT
github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0=
@@ -395,11 +353,8 @@ github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFR
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ=
-github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
@@ -415,7 +370,6 @@ github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -424,12 +378,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/vrischmann/envconfig v1.3.0 h1:4XIvQTXznxmWMnjouj0ST5lFo/WAYf5Exgl3x82crEk=
github.com/vrischmann/envconfig v1.3.0/go.mod h1:bbvxFYJdRSpXrhS63mBFtKJzkDiNkyArOLXtY6q0kuI=
-github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
-github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -470,12 +420,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -485,7 +431,6 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -500,11 +445,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -517,7 +459,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -526,15 +467,11 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -543,28 +480,19 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
@@ -578,7 +506,6 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -613,17 +540,13 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
-gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
diff --git a/hack/Makefile b/hack/Makefile
deleted file mode 100644
index 8bf0b4382..000000000
--- a/hack/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# local variables
-PROJECT_ROOT=..
-TEST_ROOT=${PROJECT_ROOT}/tests/serverless
-OPERATOR_ROOT=${PROJECT_ROOT}/components/operator
-
-include ${PROJECT_ROOT}/hack/help.mk
-include ${PROJECT_ROOT}/hack/gardener.mk
-
-##@ CI Tests
-.PHONY: integration-test
-integration-test: ## Run integration tests on self-prepared k3d cluster.
- make -C ${TEST_ROOT} serverless-integration serverless-contract-tests
-
-.PHONY: integration-test-on-cluster
-integration-test-on-cluster: ## Install serverless with default serverless-cr, run integration tests and remove serverless-cr
- make -C ${PROJECT_ROOT} install-serverless-custom-operator
- make integration-test
- make -C ${PROJECT_ROOT} remove-serverless
-
-.PHONY: git-auth-test-on-cluster
-git-auth-test-on-cluster: ## Install serverless with default serverless-cr, run git auth integration and remove serverless-cr
- make -C ${PROJECT_ROOT} install-serverless-custom-operator
- make -C ${TEST_ROOT} git-auth-integration
- make -C ${PROJECT_ROOT} remove-serverless
-
-.PHONY: upgrade-test
-upgrade-test: ## Installs Serverless from latest, upgrades to version specified in IMG and run integration tests
- make -C ${PROJECT_ROOT} install-serverless-latest-release install-serverless-custom-operator
- make integration-test
- make -C ${PROJECT_ROOT} remove-serverless
diff --git a/hack/replace_serverless_chart_images.sh b/hack/replace_serverless_chart_images.sh
deleted file mode 100755
index 73bad3932..000000000
--- a/hack/replace_serverless_chart_images.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-
-# if you only need replace images with version set to "main" specify "main-only" argument
-REPLACE_SCOPE=$1
-
-REQUIRED_ENV_VARIABLES=('IMG_DIRECTORY' 'IMG_VERSION' 'PROJECT_ROOT')
-for VAR in "${REQUIRED_ENV_VARIABLES[@]}"; do
- if [ -z "${!VAR}" ]; then
- echo "${VAR} is undefined"
- exit 1
- fi
-done
-
-MAIN_ONLY_SELECTOR=""
-if [[ ${REPLACE_SCOPE} == "main-only" ]]; then
- MAIN_ONLY_SELECTOR="| select(.version == \"main\")"
-fi
-
-IMAGES_SELECTOR=".global.images[] | select(key == \"function_*\") ${MAIN_ONLY_SELECTOR}"
-VALUES_FILE=${PROJECT_ROOT}/config/serverless/values.yaml
-
-yq -i "(${IMAGES_SELECTOR} | .directory) = \"${IMG_DIRECTORY}\"" ${VALUES_FILE}
-yq -i "(${IMAGES_SELECTOR} | .version) = \"${IMG_VERSION}\"" ${VALUES_FILE}
-echo "==== Local Changes ===="
-yq '.global.images' ${VALUES_FILE}
-echo "==== End of Local Changes ===="
diff --git a/module-config-template.yaml b/module-config-template.yaml
index 73a7a3180..829ad9a95 100644
--- a/module-config-template.yaml
+++ b/module-config-template.yaml
@@ -1,8 +1,8 @@
name: {{.Name}}
channel: {{.Channel}}
version: {{.Version}}
-defaultCR: config/samples/default-serverless-cr.yaml
-manifest: serverless-operator.yaml
+defaultCR: config/samples/default-dockerregistry-cr.yaml
+manifest: dockerregistry-operator.yaml
annotations:
"operator.kyma-project.io/doc-url": "https://kyma-project.io/#/serverless-manager/user/README"
moduleRepo: https://github.com/kyma-project/serverless-manager.git
diff --git a/tests/gitserver/Dockerfile b/tests/gitserver/Dockerfile
deleted file mode 100644
index fcd1f5c0b..000000000
--- a/tests/gitserver/Dockerfile
+++ /dev/null
@@ -1,24 +0,0 @@
-FROM alpine:3.19
-
-RUN apk add --no-cache git-daemon apache2 apache2-utils && \
- apk upgrade --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/community \
- expat
-
-COPY ./etc/git.conf /etc/apache2/conf.d/git.conf
-COPY ./etc/httpd.conf /etc/apache2/httpd.conf
-RUN git config --system http.receivepack true &&\
- git config --system http.uploadpack true &&\
- git config --global user.email "gitserver@kyma-project.io" &&\
- git config --global user.name "Git Server"
-ENV APACHE_LOG_DIR /var/log/apache2
-ENV APACHE_LOCK_DIR /var/lock/apache2
-ENV APACHE_PID_FILE /var/run/apache2.pid
-
-COPY ./etc/init_repos.sh /tmp/init_repos.sh
-COPY ./repos /tmp/repos
-RUN /tmp/init_repos.sh
-
-CMD ["/usr/sbin/httpd", "-D", "FOREGROUND", "-f", "/etc/apache2/httpd.conf"]
-
-EXPOSE 80/tcp
-
diff --git a/tests/gitserver/Makefile b/tests/gitserver/Makefile
deleted file mode 100644
index 52e61b6ff..000000000
--- a/tests/gitserver/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-PROJECT_ROOT = ../..
-include ${PROJECT_ROOT}/hack/help.mk
-
-APP_NAME = gitserver
-APP_PATH = tools/$(APP_NAME)
-IMG_NAME := $(DOCKER_PUSH_REPOSITORY)$(DOCKER_PUSH_DIRECTORY)/$(APP_NAME)
-TAG := $(DOCKER_TAG)
-
-.PHONY: build-image
-build-image:
- docker build -t $(APP_NAME):latest .
-
-.PHONY: push-image
-push-image:
- docker tag $(APP_NAME) $(IMG_NAME):$(TAG)
- docker push $(IMG_NAME):$(TAG)
-
-release: build-image push-image
\ No newline at end of file
diff --git a/tests/gitserver/README.md b/tests/gitserver/README.md
deleted file mode 100644
index bf7eac513..000000000
--- a/tests/gitserver/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Git Server
-
-Git Server is a tool that exposes an HTTP server with a Git repository. It can be used in e2e tests to avoid connections with external Git providers.
-
-You can add additional Git repositories simply by creating a new directory in `/repos/`.
-The name of the created directory will be used as the repository name.
diff --git a/tests/gitserver/etc/git.conf b/tests/gitserver/etc/git.conf
deleted file mode 100644
index a9ce9ea8f..000000000
--- a/tests/gitserver/etc/git.conf
+++ /dev/null
@@ -1,24 +0,0 @@
-
-ServerAdmin webmaster@localhost
-
-SetEnv GIT_PROJECT_ROOT /var/www/git
-SetEnv GIT_HTTP_EXPORT_ALL
-ScriptAlias / /usr/libexec/git-core/git-http-backend/
-
-Alias / /var/www/git
-
-
-Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
-AllowOverride None
-Require all granted
-
-
-
-Options Indexes FollowSymLinks MultiViews
-AllowOverride None
-Require all granted
-
-ErrorLog ${APACHE_LOG_DIR}/error.log
-LogLevel warn
-CustomLog ${APACHE_LOG_DIR}/access.log combined
-
\ No newline at end of file
diff --git a/tests/gitserver/etc/httpd.conf b/tests/gitserver/etc/httpd.conf
deleted file mode 100644
index b797368a9..000000000
--- a/tests/gitserver/etc/httpd.conf
+++ /dev/null
@@ -1,481 +0,0 @@
-#
-# This is the main Apache HTTP server configuration file. It contains the
-# configuration directives that give the server its instructions.
-# See for detailed information.
-# In particular, see
-#
-# for a discussion of each configuration directive.
-#
-# Do NOT simply read the instructions in here without understanding
-# what they do. They're here only as hints or reminders. If you are unsure
-# consult the online docs. You have been warned.
-#
-# Configuration and logfile names: If the filenames you specify for many
-# of the server's control files begin with "/" (or "drive:/" for Win32), the
-# server will use that explicit path. If the filenames do *not* begin
-# with "/", the value of ServerRoot is prepended -- so "logs/access_log"
-# with ServerRoot set to "/usr/local/apache2" will be interpreted by the
-# server as "/usr/local/apache2/logs/access_log", whereas "/logs/access_log"
-# will be interpreted as '/logs/access_log'.
-
-#
-# ServerTokens
-# This directive configures what you return as the Server HTTP response
-# Header. The default is 'Full' which sends information about the OS-Type
-# and compiled in modules.
-# Set to one of: Full | OS | Minor | Minimal | Major | Prod
-# where Full conveys the most information, and Prod the least.
-#
-ServerTokens OS
-
-#
-# ServerRoot: The top of the directory tree under which the server's
-# configuration, error, and log files are kept.
-#
-# Do not add a slash at the end of the directory path. If you point
-# ServerRoot at a non-local disk, be sure to specify a local disk on the
-# Mutex directive, if file-based mutexes are used. If you wish to share the
-# same ServerRoot for multiple httpd daemons, you will need to change at
-# least PidFile.
-#
-ServerRoot /var/www
-
-#
-# Mutex: Allows you to set the mutex mechanism and mutex file directory
-# for individual mutexes, or change the global defaults
-#
-# Uncomment and change the directory if mutexes are file-based and the default
-# mutex file directory is not on a local disk or is not appropriate for some
-# other reason.
-#
-# Mutex default:/run/apache2
-
-#
-# Listen: Allows you to bind Apache to specific IP addresses and/or
-# ports, instead of the default. See also the
-# directive.
-#
-# Change this to Listen on specific IP addresses as shown below to
-# prevent Apache from glomming onto all bound IP addresses.
-#
-#Listen 12.34.56.78:80
-Listen 80
-
-#
-# Dynamic Shared Object (DSO) Support
-#
-# To be able to use the functionality of a module which was built as a DSO you
-# have to place corresponding `LoadModule' lines at this location so the
-# directives contained in it are actually available _before_ they are used.
-# Statically compiled modules (those listed by `httpd -l') do not need
-# to be loaded here.
-#
-# Example:
-# LoadModule foo_module modules/mod_foo.so
-#
-#LoadModule mpm_event_module modules/mod_mpm_event.so
-LoadModule mpm_prefork_module modules/mod_mpm_prefork.so
-#LoadModule mpm_worker_module modules/mod_mpm_worker.so
-LoadModule authn_file_module modules/mod_authn_file.so
-#LoadModule authn_dbm_module modules/mod_authn_dbm.so
-#LoadModule authn_anon_module modules/mod_authn_anon.so
-#LoadModule authn_dbd_module modules/mod_authn_dbd.so
-#LoadModule authn_socache_module modules/mod_authn_socache.so
-LoadModule authn_core_module modules/mod_authn_core.so
-LoadModule authz_host_module modules/mod_authz_host.so
-LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
-LoadModule authz_user_module modules/mod_authz_user.so
-#LoadModule authz_dbm_module modules/mod_authz_dbm.so
-#LoadModule authz_owner_module modules/mod_authz_owner.so
-#LoadModule authz_dbd_module modules/mod_authz_dbd.so
-LoadModule authz_core_module modules/mod_authz_core.so
-LoadModule access_compat_module modules/mod_access_compat.so
-LoadModule auth_basic_module modules/mod_auth_basic.so
-#LoadModule auth_form_module modules/mod_auth_form.so
-#LoadModule auth_digest_module modules/mod_auth_digest.so
-#LoadModule allowmethods_module modules/mod_allowmethods.so
-#LoadModule file_cache_module modules/mod_file_cache.so
-#LoadModule cache_module modules/mod_cache.so
-#LoadModule cache_disk_module modules/mod_cache_disk.so
-#LoadModule cache_socache_module modules/mod_cache_socache.so
-#LoadModule socache_shmcb_module modules/mod_socache_shmcb.so
-#LoadModule socache_dbm_module modules/mod_socache_dbm.so
-#LoadModule socache_memcache_module modules/mod_socache_memcache.so
-#LoadModule socache_redis_module modules/mod_socache_redis.so
-#LoadModule watchdog_module modules/mod_watchdog.so
-#LoadModule macro_module modules/mod_macro.so
-#LoadModule dbd_module modules/mod_dbd.so
-#LoadModule dumpio_module modules/mod_dumpio.so
-#LoadModule echo_module modules/mod_echo.so
-#LoadModule buffer_module modules/mod_buffer.so
-#LoadModule data_module modules/mod_data.so
-#LoadModule ratelimit_module modules/mod_ratelimit.so
-LoadModule reqtimeout_module modules/mod_reqtimeout.so
-#LoadModule ext_filter_module modules/mod_ext_filter.so
-#LoadModule request_module modules/mod_request.so
-#LoadModule include_module modules/mod_include.so
-LoadModule filter_module modules/mod_filter.so
-#LoadModule reflector_module modules/mod_reflector.so
-#LoadModule substitute_module modules/mod_substitute.so
-#LoadModule sed_module modules/mod_sed.so
-#LoadModule charset_lite_module modules/mod_charset_lite.so
-#LoadModule deflate_module modules/mod_deflate.so
-LoadModule mime_module modules/mod_mime.so
-LoadModule log_config_module modules/mod_log_config.so
-#LoadModule log_debug_module modules/mod_log_debug.so
-#LoadModule log_forensic_module modules/mod_log_forensic.so
-#LoadModule logio_module modules/mod_logio.so
-LoadModule env_module modules/mod_env.so
-#LoadModule mime_magic_module modules/mod_mime_magic.so
-#LoadModule expires_module modules/mod_expires.so
-LoadModule headers_module modules/mod_headers.so
-#LoadModule usertrack_module modules/mod_usertrack.so
-#LoadModule unique_id_module modules/mod_unique_id.so
-LoadModule setenvif_module modules/mod_setenvif.so
-LoadModule version_module modules/mod_version.so
-#LoadModule remoteip_module modules/mod_remoteip.so
-#LoadModule session_module modules/mod_session.so
-#LoadModule session_cookie_module modules/mod_session_cookie.so
-#LoadModule session_crypto_module modules/mod_session_crypto.so
-#LoadModule session_dbd_module modules/mod_session_dbd.so
-#LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
-#LoadModule slotmem_plain_module modules/mod_slotmem_plain.so
-#LoadModule dialup_module modules/mod_dialup.so
-#LoadModule http2_module modules/mod_http2.so
-LoadModule unixd_module modules/mod_unixd.so
-#LoadModule heartbeat_module modules/mod_heartbeat.so
-#LoadModule heartmonitor_module modules/mod_heartmonitor.so
-LoadModule status_module modules/mod_status.so
-LoadModule autoindex_module modules/mod_autoindex.so
-#LoadModule asis_module modules/mod_asis.so
-#LoadModule info_module modules/mod_info.so
-#LoadModule suexec_module modules/mod_suexec.so
-
- LoadModule cgid_module modules/mod_cgid.so
-
-
- LoadModule cgi_module modules/mod_cgi.so
-
-#LoadModule vhost_alias_module modules/mod_vhost_alias.so
-#LoadModule negotiation_module modules/mod_negotiation.so
-LoadModule dir_module modules/mod_dir.so
-#LoadModule actions_module modules/mod_actions.so
-#LoadModule speling_module modules/mod_speling.so
-#LoadModule userdir_module modules/mod_userdir.so
-LoadModule alias_module modules/mod_alias.so
-LoadModule rewrite_module modules/mod_rewrite.so
-
-LoadModule negotiation_module modules/mod_negotiation.so
-
-
-#
-# If you wish httpd to run as a different user or group, you must run
-# httpd as root initially and it will switch.
-#
-# User/Group: The name (or #number) of the user/group to run httpd as.
-# It is usually good practice to create a dedicated user and group for
-# running httpd, as with most system services.
-#
-User apache
-Group apache
-
-
-
-# 'Main' server configuration
-#
-# The directives in this section set up the values used by the 'main'
-# server, which responds to any requests that aren't handled by a
-# definition. These values also provide defaults for
-# any containers you may define later in the file.
-#
-# All of these directives may appear inside containers,
-# in which case these default settings will be overridden for the
-# virtual host being defined.
-#
-
-#
-# ServerAdmin: Your address, where problems with the server should be
-# e-mailed. This address appears on some server-generated pages, such
-# as error documents. e.g. admin@your-domain.com
-#
-ServerAdmin you@example.com
-
-#
-# Optionally add a line containing the server version and virtual host
-# name to server-generated pages (internal error documents, FTP directory
-# listings, mod_status and mod_info output etc., but not CGI generated
-# documents or custom error documents).
-# Set to "EMail" to also include a mailto: link to the ServerAdmin.
-# Set to one of: On | Off | EMail
-#
-ServerSignature On
-
-#
-# ServerName gives the name and port that the server uses to identify itself.
-# This can often be determined automatically, but we recommend you specify
-# it explicitly to prevent problems during startup.
-#
-# If your host doesn't have a registered DNS name, enter its IP address here.
-#
-#ServerName www.example.com:80
-
-#
-# Deny access to the entirety of your server's filesystem. You must
-# explicitly permit access to web content directories in other
-# blocks below.
-#
-
- AllowOverride none
- Require all denied
-
-
-#
-# Note that from this point forward you must specifically allow
-# particular features to be enabled - so if something's not working as
-# you might expect, make sure that you have specifically enabled it
-# below.
-#
-
-#
-# DocumentRoot: The directory out of which you will serve your
-# documents. By default, all requests are taken from this directory, but
-# symbolic links and aliases may be used to point to other locations.
-#
-DocumentRoot "/var/www/localhost/htdocs"
-
- #
- # Possible values for the Options directive are "None", "All",
- # or any combination of:
- # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
- #
- # Note that "MultiViews" must be named *explicitly* --- "Options All"
- # doesn't give it to you.
- #
- # The Options directive is both complicated and important. Please see
- # http://httpd.apache.org/docs/2.4/mod/core.html#options
- # for more information.
- #
- Options Indexes FollowSymLinks
-
- #
- # AllowOverride controls what directives may be placed in .htaccess files.
- # It can be "All", "None", or any combination of the keywords:
- # AllowOverride FileInfo AuthConfig Limit
- #
- AllowOverride None
-
- #
- # Controls who can get stuff from this server.
- #
- Require all granted
-
-
-#
-# DirectoryIndex: sets the file that Apache will serve if a directory
-# is requested.
-#
-
- DirectoryIndex index.html
-
-
-#
-# The following lines prevent .htaccess and .htpasswd files from being
-# viewed by Web clients.
-#
-
- Require all denied
-
-
-#
-# ErrorLog: The location of the error log file.
-# If you do not specify an ErrorLog directive within a
-# container, error messages relating to that virtual host will be
-# logged here. If you *do* define an error logfile for a
-# container, that host's errors will be logged there and not here.
-#
-ErrorLog logs/error.log
-
-#
-# LogLevel: Control the number of messages logged to the error_log.
-# Possible values include: debug, info, notice, warn, error, crit,
-# alert, emerg.
-#
-LogLevel warn
-
-
- #
- # The following directives define some format nicknames for use with
- # a CustomLog directive (see below).
- #
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
- LogFormat "%h %l %u %t \"%r\" %>s %b" common
-
-
- # You need to enable mod_logio.c to use %I and %O
- LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
-
-
- #
- # The location and format of the access logfile (Common Logfile Format).
- # If you do not define any access logfiles within a
- # container, they will be logged here. Contrariwise, if you *do*
- # define per- access logfiles, transactions will be
- # logged therein and *not* in this file.
- #
- #CustomLog logs/access.log common
-
- #
- # If you prefer a logfile with access, agent, and referer information
- # (Combined Logfile Format) you can use the following directive.
- #
- CustomLog logs/access.log combined
-
-
-
- #
- # Redirect: Allows you to tell clients about documents that used to
- # exist in your server's namespace, but do not anymore. The client
- # will make a new request for the document at its new location.
- # Example:
- # Redirect permanent /foo http://www.example.com/bar
-
- #
- # Alias: Maps web paths into filesystem paths and is used to
- # access content that does not live under the DocumentRoot.
- # Example:
- # Alias /webpath /full/filesystem/path
- #
- # If you include a trailing / on /webpath then the server will
- # require it to be present in the URL. You will also likely
- # need to provide a section to allow access to
- # the filesystem path.
-
- #
- # ScriptAlias: This controls which directories contain server scripts.
- # ScriptAliases are essentially the same as Aliases, except that
- # documents in the target directory are treated as applications and
- # run by the server when requested rather than as documents sent to the
- # client. The same rules about trailing "/" apply to ScriptAlias
- # directives as to Alias.
- #
- ScriptAlias /cgi-bin/ "/var/www/localhost/cgi-bin/"
-
-
-
-
- #
- # ScriptSock: On threaded servers, designate the path to the UNIX
- # socket used to communicate with the CGI daemon of mod_cgid.
- #
- #Scriptsock cgisock
-
-
-#
-# "/var/www/localhost/cgi-bin" should be changed to whatever your ScriptAliased
-# CGI directory exists, if you have that configured.
-#
-
- AllowOverride None
- Options None
- Require all granted
-
-
-
- #
- # Avoid passing HTTP_PROXY environment to CGI's on this or any proxied
- # backend servers which have lingering "httpoxy" defects.
- # 'Proxy' request header is undefined by the IETF, not listed by IANA
- #
- RequestHeader unset Proxy early
-
-
-
- #
- # TypesConfig points to the file containing the list of mappings from
- # filename extension to MIME-type.
- #
- TypesConfig /etc/apache2/mime.types
-
- #
- # AddType allows you to add to or override the MIME configuration
- # file specified in TypesConfig for specific file types.
- #
- #AddType application/x-gzip .tgz
- #
- # AddEncoding allows you to have certain browsers uncompress
- # information on the fly. Note: Not all browsers support this.
- #
- #AddEncoding x-compress .Z
- #AddEncoding x-gzip .gz .tgz
- #
- # If the AddEncoding directives above are commented-out, then you
- # probably should define those extensions to indicate media types:
- #
- AddType application/x-compress .Z
- AddType application/x-gzip .gz .tgz
-
- #
- # AddHandler allows you to map certain file extensions to "handlers":
- # actions unrelated to filetype. These can be either built into the server
- # or added with the Action directive (see below)
- #
- # To use CGI scripts outside of ScriptAliased directories:
- # (You will also need to add "ExecCGI" to the "Options" directive.)
- #
- #AddHandler cgi-script .cgi
-
- # For type maps (negotiated resources):
- #AddHandler type-map var
-
- #
- # Filters allow you to process content before it is sent to the client.
- #
- # To parse .shtml files for server-side includes (SSI):
- # (You will also need to add "Includes" to the "Options" directive.)
- #
- #AddType text/html .shtml
- #AddOutputFilter INCLUDES .shtml
-
-
-#
-# The mod_mime_magic module allows the server to use various hints from the
-# contents of the file itself to determine its type. The MIMEMagicFile
-# directive tells the module where the hint definitions are located.
-#
-
- MIMEMagicFile /etc/apache2/magic
-
-
-#
-# Customizable error responses come in three flavors:
-# 1) plain text 2) local redirects 3) external redirects
-#
-# Some examples:
-#ErrorDocument 500 "The server made a boo boo."
-#ErrorDocument 404 /missing.html
-#ErrorDocument 404 "/cgi-bin/missing_handler.pl"
-#ErrorDocument 402 http://www.example.com/subscription_info.html
-#
-
-#
-# MaxRanges: Maximum number of Ranges in a request before
-# returning the entire resource, or one of the special
-# values 'default', 'none' or 'unlimited'.
-# Default setting is to accept 200 Ranges.
-#MaxRanges unlimited
-
-#
-# EnableMMAP and EnableSendfile: On systems that support it,
-# memory-mapping or the sendfile syscall may be used to deliver
-# files. This usually improves server performance, but must
-# be turned off when serving from networked-mounted
-# filesystems or if support for these functions is otherwise
-# broken on your system.
-# Defaults: EnableMMAP On, EnableSendfile Off
-#
-#EnableMMAP off
-#EnableSendfile on
-
-# Load config files from the config directory "/etc/apache2/conf.d".
-#
-IncludeOptional /etc/apache2/conf.d/*.conf
diff --git a/tests/gitserver/etc/init_repos.sh b/tests/gitserver/etc/init_repos.sh
deleted file mode 100755
index 296cabd1f..000000000
--- a/tests/gitserver/etc/init_repos.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env sh
-
-readonly REPOS_DIR="/var/www/git"
-
-mkdir "$REPOS_DIR"
-
-for d in /tmp/repos/*/ ; do
- cd "$d" || exit 1
- git init && git add --all && git commit -m"initial commit"
- cd "$REPOS_DIR" || exit 1
- git clone --bare "$d"
-done
-
-chown -Rfv apache:apache /var/www/git
diff --git a/tests/gitserver/repos/function/handler.js b/tests/gitserver/repos/function/handler.js
deleted file mode 100644
index 4f4732bb1..000000000
--- a/tests/gitserver/repos/function/handler.js
+++ /dev/null
@@ -1,5 +0,0 @@
-module.exports = {
- main: function (event, context) {
- return 'GITOPS 1'
- }
-}
\ No newline at end of file
diff --git a/tests/gitserver/repos/function/package.json b/tests/gitserver/repos/function/package.json
deleted file mode 100644
index 65ba76c5e..000000000
--- a/tests/gitserver/repos/function/package.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "hello",
- "version": "0.0.1"
-}
\ No newline at end of file
diff --git a/tests/serverless-bench/Dockerfile b/tests/serverless-bench/Dockerfile
deleted file mode 100644
index 806e707ed..000000000
--- a/tests/serverless-bench/Dockerfile
+++ /dev/null
@@ -1,10 +0,0 @@
-FROM python:alpine3.15
-WORKDIR /home/locust
-
-RUN apk add --no-cache bash curl jq miller git build-base linux-headers c-ares coreutils mysql-client
-RUN apk add --no-cache --update --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main openssl
-
-COPY requirements.txt /home/locust/
-RUN pip3 install --no-cache-dir -r requirements.txt
-
-COPY locust.py run-benchmarks.sh /home/locust/
diff --git a/tests/serverless-bench/Makefile b/tests/serverless-bench/Makefile
deleted file mode 100644
index 673a36079..000000000
--- a/tests/serverless-bench/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-PROJECT_ROOT = ../..
-include ${PROJECT_ROOT}/hack/help.mk
-
-APP_NAME ?= serverless-bench
-APP_VERSION = $(shell date +'%Y%m%d')
-TAG = $(APP_VERSION)-$(DOCKER_TAG)
-IMG = $(DOCKER_PUSH_REPOSITORY)$(DOCKER_PUSH_DIRECTORY)/$(APP_NAME):$(TAG)
-IMG_DOCKER_TAG = $(DOCKER_PUSH_REPOSITORY)$(DOCKER_PUSH_DIRECTORY)/$(APP_NAME):$(DOCKER_TAG)
-
-# Use generic makefile
-COMMON_DIR = $(realpath $(shell pwd)/../..)/common/makefiles
-include $(COMMON_DIR)/docker.mk
diff --git a/tests/serverless-bench/README.md b/tests/serverless-bench/README.md
deleted file mode 100644
index 60309286c..000000000
--- a/tests/serverless-bench/README.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Serverless-Bench
-
-The Serverless-Bench image is based on the `locustio/locust` image. It also includes a locust test configuration and a simple script to run the test, and output the results in JSON to stdout. The logs are collected with a log sink and are pushed to Google Cloud BigQuery for further analysis.
-
-## Running Serverless benchmarks Locally
-
-This a quick guide to simplify running the Function Controller benchmarks' tests in a development environment. This can be useful in several scenarios, such as benchmarking a new runtime implementation.
-
-To run the these tests, apply the following steps:
-
-1. Start with a fresh Kyma cluster. The following minimum components are required:
-
- ```yaml
- ---
- defaultNamespace: kyma-system
- prerequisites:
- - name: "cluster-essentials"
- - name: "istio"
- namespace: "istio-system"
- - name: "certificates"
- namespace: "istio-system"
- components:
- - name: "monitoring"
- - name: "serverless"
- ```
-
-2. Apply the Functions you need to benchmark from the test the [Function fixtures](./fixtures/functions/). If you need to benchmark a new Function runtime or configuration, you must create a similar Function manifest with the same naming pattern.
-
-3. Wait for the Functions to be ready.
-4. Apply the [local-test](./fixtures/local-test/) manifests. This will deploy the following resources:
- - A MySQL Pod and service to store the benchmarking data
- - A Grafana datasource to read the benchmark data from the MySQL backend.
- - The Grafana dashboard configuration to present the data.
-5. Edit the [test job spec](./fixtures/serverless-benchmark-job.yaml) to set `USE_LOCAL_MYSQL` to `true`. You can also use `CUSTOM_FUNCTIONS` to test specific Functions instead of testing the full list.
-6. Apply the test job. Each test run creates a data point for each defined Function.
-
-7. Once the first test run is done, you can access Grafana and find the `Serverless Controller Benchmarks` dashboard to check the data.
diff --git a/tests/serverless-bench/fixtures/functions/nodejs18-l.yaml b/tests/serverless-bench/fixtures/functions/nodejs18-l.yaml
deleted file mode 100644
index 8b8e7feef..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs18-l.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: L
- name: nodejs18-l
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs18
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs18-l",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs18-m.yaml b/tests/serverless-bench/fixtures/functions/nodejs18-m.yaml
deleted file mode 100644
index 7663feb57..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs18-m.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: M
- name: nodejs18-m
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs18
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs18-m",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs18-s.yaml b/tests/serverless-bench/fixtures/functions/nodejs18-s.yaml
deleted file mode 100644
index 891ac3132..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs18-s.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: S
- name: nodejs18-s
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs18
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs18-s",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs18-xl.yaml b/tests/serverless-bench/fixtures/functions/nodejs18-xl.yaml
deleted file mode 100644
index 3bce45d70..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs18-xl.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XL
- name: nodejs18-xl
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs18
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs18-xl",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs18-xs.yaml b/tests/serverless-bench/fixtures/functions/nodejs18-xs.yaml
deleted file mode 100644
index d5ee2537a..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs18-xs.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XS
- name: nodejs18-xs
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs18
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs18-xs",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs20-l.yaml b/tests/serverless-bench/fixtures/functions/nodejs20-l.yaml
deleted file mode 100644
index 740b0813b..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs20-l.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: L
- name: nodejs20-l
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs20
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs20-l",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs20-m.yaml b/tests/serverless-bench/fixtures/functions/nodejs20-m.yaml
deleted file mode 100644
index b2a6c8dff..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs20-m.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: M
- name: nodejs20-m
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs20
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs20-m",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs20-s.yaml b/tests/serverless-bench/fixtures/functions/nodejs20-s.yaml
deleted file mode 100644
index 992a85093..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs20-s.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: S
- name: nodejs20-s
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs20
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs20-s",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs20-xl.yaml b/tests/serverless-bench/fixtures/functions/nodejs20-xl.yaml
deleted file mode 100644
index 4bcc8a641..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs20-xl.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XL
- name: nodejs20-xl
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs20
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs20-xl",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/nodejs20-xs.yaml b/tests/serverless-bench/fixtures/functions/nodejs20-xs.yaml
deleted file mode 100644
index f0ea77480..000000000
--- a/tests/serverless-bench/fixtures/functions/nodejs20-xs.yaml
+++ /dev/null
@@ -1,26 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XS
- name: nodejs20-xs
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: nodejs20
- source:
- inline:
- dependencies: |-
- {
- "name": "nodejs20-xs",
- "version": "0.0.1",
- "dependencies": {}
- }
- source: |-
- module.exports = {
- main: function (event, context) {
- return 'Hello Serverless'
- }
- }
-
diff --git a/tests/serverless-bench/fixtures/functions/python312-l.yaml b/tests/serverless-bench/fixtures/functions/python312-l.yaml
deleted file mode 100644
index a1af2c119..000000000
--- a/tests/serverless-bench/fixtures/functions/python312-l.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: L
- name: python312-l
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python312
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python312-m.yaml b/tests/serverless-bench/fixtures/functions/python312-m.yaml
deleted file mode 100644
index ee7d38c44..000000000
--- a/tests/serverless-bench/fixtures/functions/python312-m.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: M
- name: python312-m
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python312
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python312-s.yaml b/tests/serverless-bench/fixtures/functions/python312-s.yaml
deleted file mode 100644
index 715edcf6b..000000000
--- a/tests/serverless-bench/fixtures/functions/python312-s.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: S
- name: python312-s
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python312
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python312-xl.yaml b/tests/serverless-bench/fixtures/functions/python312-xl.yaml
deleted file mode 100644
index 41598efa4..000000000
--- a/tests/serverless-bench/fixtures/functions/python312-xl.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XL
- name: python312-xl
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python312
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python39-l.yaml b/tests/serverless-bench/fixtures/functions/python39-l.yaml
deleted file mode 100644
index c58b19073..000000000
--- a/tests/serverless-bench/fixtures/functions/python39-l.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: L
- name: python39-l
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python39
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python39-m.yaml b/tests/serverless-bench/fixtures/functions/python39-m.yaml
deleted file mode 100644
index a17eee4bf..000000000
--- a/tests/serverless-bench/fixtures/functions/python39-m.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: M
- name: python39-m
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python39
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python39-s.yaml b/tests/serverless-bench/fixtures/functions/python39-s.yaml
deleted file mode 100644
index ef78438b8..000000000
--- a/tests/serverless-bench/fixtures/functions/python39-s.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: S
- name: python39-s
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python39
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/functions/python39-xl.yaml b/tests/serverless-bench/fixtures/functions/python39-xl.yaml
deleted file mode 100644
index c0313ddb2..000000000
--- a/tests/serverless-bench/fixtures/functions/python39-xl.yaml
+++ /dev/null
@@ -1,16 +0,0 @@
-apiVersion: serverless.kyma-project.io/v1alpha2
-kind: Function
-metadata:
- labels:
- serverless.kyma-project.io/function-resources-preset: XL
- name: python39-xl
-spec:
- scaleConfig:
- maxReplicas: 1
- minReplicas: 1
- runtime: python39
- source:
- inline:
- source: |-
- def main(event, context):
- return "Hello Serverless"
diff --git a/tests/serverless-bench/fixtures/local-test/grafana-datasource.yaml b/tests/serverless-bench/fixtures/local-test/grafana-datasource.yaml
deleted file mode 100644
index 949d41fad..000000000
--- a/tests/serverless-bench/fixtures/local-test/grafana-datasource.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: serverless-bench-grafana-datasource
- namespace: kyma-system
- labels:
- grafana_datasource: "1"
- app: serverless-bench
- chart: serverless-bench
-data:
- serverless-bench-datasource.yaml: |-
- apiVersion: 1
- datasources:
- - name: mysql
- type: mysql
- user: root
- password: secret
- database: mysql_bench_db
- url: mysql-bench-db.default.svc.cluster.local:3306
-
\ No newline at end of file
diff --git a/tests/serverless-bench/fixtures/local-test/local-mysql.yaml b/tests/serverless-bench/fixtures/local-test/local-mysql.yaml
deleted file mode 100644
index 405e19e02..000000000
--- a/tests/serverless-bench/fixtures/local-test/local-mysql.yaml
+++ /dev/null
@@ -1,48 +0,0 @@
----
-apiVersion: v1
-kind: Service
-metadata:
- name: mysql-bench-db
- namespace: default
- labels:
- name: mysql-bench-db
- app: serverless-benchmark
-spec:
- ports:
- - port: 3306
- selector:
- name: mysql-bench-db
- type: ClusterIP
----
-apiVersion: v1
-kind: Pod
-metadata:
- annotations:
- sidecar.istio.io/inject: "false"
- name: mysql-bench-db
- namespace: default
- labels:
- name: mysql-bench-db
- app: serverless-benchmark
-spec:
- containers:
- - name: mysql
- image: mysql:latest
- args:
- - "--default-authentication-plugin=mysql_native_password"
- - "--secure-file-priv=/"
- - "--local-infile=1"
- env:
- - name: MYSQL_ROOT_PASSWORD
- value: secret
- ports:
- - name: mysql
- containerPort: 3306
- protocol: TCP
- volumeMounts:
- - name: mysql-bench-db-storage
- mountPath: /var/lib/mysql
- volumes:
- - name: mysql-bench-db-storage
- emptyDir: {}
-
diff --git a/tests/serverless-bench/fixtures/local-test/serverless-bench-grafana-dashboard.yaml b/tests/serverless-bench/fixtures/local-test/serverless-bench-grafana-dashboard.yaml
deleted file mode 100644
index 2921dda18..000000000
--- a/tests/serverless-bench/fixtures/local-test/serverless-bench-grafana-dashboard.yaml
+++ /dev/null
@@ -1,877 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: serverless-bench-grafana-dashboard
- labels:
- grafana_dashboard: "1"
- app: serverless-bench-grafana
-data:
- serverless-bench-dashboard.json: |-
- {
- "annotations": {
- "list": [
- {
- "builtIn": 1,
- "datasource": "-- Grafana --",
- "enable": true,
- "hide": true,
- "iconColor": "rgba(0, 211, 255, 1)",
- "name": "Annotations & Alerts",
- "type": "dashboard"
- }
- ]
- },
- "editable": true,
- "gnetId": null,
- "graphTooltip": 0,
- "id": 8,
- "links": [],
- "panels": [
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "ms"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 0
- },
- "hiddenSeries": false,
- "id": 18,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "percentile99"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "99 Percentile",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "ms",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "ms"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 0
- },
- "hiddenSeries": false,
- "id": 10,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "avg_response"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Average Response Time",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "ms",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "ms"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 8
- },
- "hiddenSeries": false,
- "id": 16,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "percentile95"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "95 Percentile",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "ms",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "short"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 8
- },
- "hiddenSeries": false,
- "id": 4,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "rqs"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Requests per second",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "ms"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 0,
- "y": 16
- },
- "hiddenSeries": false,
- "id": 14,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "percentile90"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "90th Percentile",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "ms",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {},
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 16
- },
- "hiddenSeries": false,
- "id": 12,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "failure_count"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Failure Count",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- },
- {
- "aliasColors": {},
- "bars": false,
- "dashLength": 10,
- "dashes": false,
- "datasource": "mysql",
- "fieldConfig": {
- "defaults": {
- "unit": "ms"
- },
- "overrides": []
- },
- "fill": 0,
- "fillGradient": 0,
- "gridPos": {
- "h": 8,
- "w": 12,
- "x": 12,
- "y": 24
- },
- "hiddenSeries": false,
- "id": 20,
- "legend": {
- "avg": false,
- "current": false,
- "max": false,
- "min": false,
- "show": true,
- "total": false,
- "values": false
- },
- "lines": true,
- "linewidth": 1,
- "nullPointMode": "null",
- "options": {
- "alertThreshold": true
- },
- "percentage": false,
- "pluginVersion": "7.5.15",
- "pointradius": 2,
- "points": true,
- "renderer": "flot",
- "seriesOverrides": [],
- "spaceLength": 10,
- "stack": false,
- "steppedLine": false,
- "targets": [
- {
- "dataset": "serverless_benchmark_stats",
- "format": "time_series",
- "group": [],
- "metricColumn": "function_name",
-
-
-
-
-
-
- "rawQuery": false,
- "rawSql": "SELECT\n time_column,\n value1\nFROM\n metric_table\nWHERE\n $__timeFilter(time_column)\n",
- "refId": "A",
- "select": [
- [
- {
- "params": [
- "request_count"
- ],
- "type": "column"
- }
- ]
- ],
-
- "table": "serverless_bench",
- "timeColumn": "timestamp",
- "timeColumnType": "TIMESTAMP",
- "where": []
- }
- ],
- "thresholds": [],
- "timeFrom": null,
- "timeRegions": [],
- "timeShift": null,
- "title": "Request Count",
- "tooltip": {
- "shared": true,
- "sort": 0,
- "value_type": "individual"
- },
- "type": "graph",
- "xaxis": {
- "buckets": null,
- "mode": "time",
- "name": null,
- "show": true,
- "values": []
- },
- "yaxes": [
- {
- "format": "ms",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- },
- {
- "format": "short",
- "label": null,
- "logBase": 1,
- "max": null,
- "min": null,
- "show": true
- }
- ],
- "yaxis": {
- "align": false,
- "alignLevel": null
- }
- }
- ],
- "schemaVersion": 27,
- "style": "dark",
- "tags": [],
- "templating": {
- "list": []
- },
- "time": {
- "from": "now-24h",
- "to": "now"
- },
- "timepicker": {},
- "timezone": "",
- "title": "Serverless Controller Benchmarks",
- "uid": "CdzgqX1nz",
- "version": 1
- }
\ No newline at end of file
diff --git a/tests/serverless-bench/fixtures/serverless-benchmark-job.yaml b/tests/serverless-bench/fixtures/serverless-benchmark-job.yaml
deleted file mode 100644
index df47731d2..000000000
--- a/tests/serverless-bench/fixtures/serverless-benchmark-job.yaml
+++ /dev/null
@@ -1,45 +0,0 @@
-apiVersion: batch/v1
-kind: Job
-metadata:
- labels:
- jobName: serverless-benchmark
- name: serverless-benchmark
-spec:
- template:
- metadata:
- labels:
- jobName: serverless-benchmark
- app: serverless-benchmark
- name: serverless-benchmark
- spec:
- shareProcessNamespace: true
- containers:
- - command:
- - bash
- - -c
- - |
- echo "--------------------------------------------------------------------------------"
- echo "Collecting Serverless benchmarks..."
- echo "--------------------------------------------------------------------------------"
- /home/locust/run-benchmarks.sh
- pkill -f /usr/local/bin/pilot-agent
- env:
- - name: "NAMESPACE"
- valueFrom:
- fieldRef:
- fieldPath: metadata.namespace
- - name: "CONCURRENCY"
- value: "50"
- - name: "DURATION"
- value: "1m"
- - name: "SPAWN_RATE"
- value: "50"
- - name: "USE_LOCAL_MYSQL"
- value: "false"
- image: eu.gcr.io/kyma-project/serverless-bench:347b49eb
- imagePullPolicy: Always
- name: serverless-benchmark
- resources: {}
- dnsPolicy: ClusterFirst
- restartPolicy: Never
-
diff --git a/tests/serverless-bench/locust.py b/tests/serverless-bench/locust.py
deleted file mode 100644
index d75de9e73..000000000
--- a/tests/serverless-bench/locust.py
+++ /dev/null
@@ -1,13 +0,0 @@
-import logging
-from locust import HttpUser, task, constant, events
-
-expected_string = "Hello Serverless"
-
-class StressTest(HttpUser):
- wait_time = constant(1)
-
- @task
- def hello_word(self):
- with self.client.get("/data", catch_response=True) as response:
- if expected_string not in response.text:
- response.failure("Got wrong response, expected {} ..., got: {}".format(expected_string,response.text))
diff --git a/tests/serverless-bench/requirements.txt b/tests/serverless-bench/requirements.txt
deleted file mode 100644
index 12bc79922..000000000
--- a/tests/serverless-bench/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-locust==2.6
diff --git a/tests/serverless-bench/run-benchmarks.sh b/tests/serverless-bench/run-benchmarks.sh
deleted file mode 100755
index 6f1507e89..000000000
--- a/tests/serverless-bench/run-benchmarks.sh
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env bash
-
-set -o pipefail # Fail a pipe if any sub-command fails.
-
-
-ALL_FUNCTIONS="nodejs18-xs nodejs18-s nodejs18-m nodejs18-l nodejs18-xl nodejs20-xs nodejs20-s nodejs20-m nodejs20-l nodejs20-xl python39-s python39-m python39-l python39-xl python312-s python312-m python312-l python312-xl"
-
-export TEST_NAMESPACE="${NAMESPACE:-serverless-benchmarks}"
-export TEST_CONCURRENCY="${CONCURRENCY:-50}"
-export TEST_DURATION="${DURATION:-1m}"
-export TEST_SPAWN_RATE="${SPAWN_RATE:-50}"
-export TEST_USE_LOCAL_MYSQL="${USE_LOCAL_MYSQL:-false}"
-export TEST_LOCAL_MYSQL_HOST="${LOCAL_MYSQL_HOST:-mysql-bench-db.default.svc.cluster.local}"
-export TEST_LOCAL_MYSQL_USER="${LOCAL_MYSQL_USER:-root}"
-export TEST_LOCAL_MYSQL_PASS="${LOCAL_MYSQL_PASS:-secret}"
-export TEST_LOCAL_MYSQL_DB="${LOCAL_MYSQL_DB:-mysql_bench_db}"
-
-export TEST_CUSTOM_FUNCTIONS="${CUSTOM_FUNCTIONS:-""}"
-
-if [ ! -z "${TEST_CUSTOM_FUNCTIONS}" ]; then
- ALL_FUNCTIONS="${TEST_CUSTOM_FUNCTIONS}"
-fi
-
- echo "--------------------------------------------------------------------------------"
- echo "Benchmarking functions: ${ALL_FUNCTIONS}"
- echo "Using local MySQL backend: ${TEST_USE_LOCAL_MYSQL}"
- echo "--------------------------------------------------------------------------------"
-# running benchmarks
-for FUNCTION in ${ALL_FUNCTIONS}; do
- echo "--------------------------------------------------------------------------------"
- echo "Benchmarking function ${FUNCTION} at URL: http://${FUNCTION}.${TEST_NAMESPACE}.svc.cluster.local"
- echo "--------------------------------------------------------------------------------"
-
- locust --headless --users ${TEST_CONCURRENCY} \
- -r ${SPAWN_RATE} -t ${TEST_DURATION} \
- -H "http://${FUNCTION}.${TEST_NAMESPACE}.svc.cluster.local" \
- -f /home/locust/locust.py --csv "${FUNCTION}" --logfile /dev/null
-
-done
-
- echo "--------------------------------------------------------------------------------"
- echo "Collecting Serverless benchmarks..."
- echo "--------------------------------------------------------------------------------"
-for FUNCTION in ${ALL_FUNCTIONS}; do
- export NAME=${FUNCTION}
- if [ "${TEST_USE_LOCAL_MYSQL}" = "false" ]; then
- mlr --ojson --icsv head -n 1 \
- then put '$Timestamp=system("date --rfc-3339=seconds")' \
- then put '${Function Name} = system("echo $NAME")' \
- then cut -o \
- -f "Timestamp","Function Name","Request Count","Failure Count","Average Response Time","Requests/s","90%","95%","99%" \
- "${FUNCTION}_stats.csv" | jq '{"serverlessBenchmarkStats": .}' -c
- else
- mlr --ocsv --headerless-csv-output --icsv head -n 1 \
- then put '$Timestamp=system("date --rfc-3339=seconds")' \
- then put '${Function Name} = system("echo $NAME")' \
- then cut -o \
- -f "Function Name","Request Count","Failure Count","Average Response Time","Requests/s","90%","95%","99%","Timestamp" \
- "${FUNCTION}_stats.csv" >> local_mysql_data.csv
- fi
-done
-
-if [ "${USE_LOCAL_MYSQL}" = "true" ]; then
- echo "--------------------------------------------------------------------------------"
- echo "Importing data into local MySQL database..."
- echo "--------------------------------------------------------------------------------"
- mysql -u "${TEST_LOCAL_MYSQL_USER}" \
- -p"${TEST_LOCAL_MYSQL_PASS}" \
- -h "${TEST_LOCAL_MYSQL_HOST}" \
- -e "CREATE DATABASE IF NOT EXISTS "${TEST_LOCAL_MYSQL_DB}"; \
- USE "${TEST_LOCAL_MYSQL_DB}"; \
- CREATE TABLE IF NOT EXISTS serverless_bench (function_name VARCHAR(128),\
- request_count INT, failure_count INT, avg_response FLOAT, rqs FLOAT, percentile90 FLOAT,percentile95 FLOAT,percentile99 FLOAT, timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP);"
-
- mysql -u "${TEST_LOCAL_MYSQL_USER}" \
- -p"${TEST_LOCAL_MYSQL_PASS}" \
- -h "${TEST_LOCAL_MYSQL_HOST}" \
- "$TEST_LOCAL_MYSQL_DB" \
- -e "LOAD DATA LOCAL INFILE '/home/locust/local_mysql_data.csv' INTO TABLE serverless_bench FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n';"
-fi
diff --git a/tests/serverless/.gitignore b/tests/serverless/.gitignore
deleted file mode 100644
index 85ac3f590..000000000
--- a/tests/serverless/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-main.test
-cover.out
\ No newline at end of file
diff --git a/tests/serverless/Makefile b/tests/serverless/Makefile
deleted file mode 100644
index 22bf2458e..000000000
--- a/tests/serverless/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-PROJECT_ROOT = ../..
-include ${PROJECT_ROOT}/hack/help.mk
-
-test: ## Run unit test of integration test engine
- GO111MODULE=on go test -count=1 -v ./internal/...
-
-compile:
- CGO_ENABLED=0 go build -o main.test ./cmd/main.go
-
-.PHONY: serverless-integration
-serverless-integration: ## Run serverless integration scenario with kubectl proxy
- ./run-local.sh serverless-integration
-
-.PHONY: git-auth-integration
-git-auth-integration: ## Run git authorization integration scenario with kubectl proxy
- ./run-local.sh git-auth-integration
-
-.PHONY: serverless-contract-tests
-serverless-contract-tests: ## Run serverless contract tests with kubectl proxy
- ./run-local.sh serverless-contract-tests
diff --git a/tests/serverless/README.md b/tests/serverless/README.md
deleted file mode 100644
index 4808a1a2d..000000000
--- a/tests/serverless/README.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Function Controller Integration Tests
-
-## Overview
-
-The project is a test scenario for the Function Controller. It creates a sample Function, exposes it using an APIRule, and sends `GET` requests to the Function to check if it is accessible from the cluster and outside of the cluster.
-
-## Prerequisites
-
-Use the following tools to set up the project:
-
-- [Go v1.19](https://golang.org)
-- [Kyma CLI](https://github.com/kyma-project/cli)
-
-## Usage
-
-### Run a Local Version
-
-To run integration tests, follow these instructions:
-
-1. Install [Serverless](https://github.com/kyma-project/serverless/blob/main/README.md#install).
-2. Enable kubectl proxy:
-
- ```bash
- kubectl proxy
- ```
-
-3. Run test with given scenario. You can also specify test suite to run. If not specified, all test suites are run within scenario.
- ```bash
- go run cmd/main.go {scenario} --test-suite {test-suite}
- ```
-
-### Environment Variables
-
-Use the following environment variables to configure the application:
-
-| Name | Required | Default | Description |
-|-----------------------------------------| -------- |------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
-| **APP_TEST_WAIT_TIMEOUT** | No | `5m` | The period of time for which the application waits for the resources to meet defined conditions |
-| **APP_TEST_NAMESPACE_BASE_NAME** | No | `serverless` | The name of the namespace used during integration tests |
-| **APP_TEST_FUNCTION_NAME** | No | `test-function` | The name of the Function created and deleted during integration tests |
-| **APP_TEST_APIRULE_NAME** | No | `test-apirule` | The name of the APIRule created and deleted during integration tests |
-| **APP_TEST_TRIGGER_NAME** | No | `test-trigger` | The name of the Trigger created and deleted during integration tests |
-| **APP_TEST_SERVICE_INSTANCE_NAME** | No | `test-service-instance` | The name of the ServiceInstance created and deleted during integration tests |
-| **APP_TEST_SERVICE_BINDING_NAME** | No | `test-service-binding` | The name of the ServiceBinding created and deleted during integration tests |
-| **APP_TEST_SERVICE_BINDING_USAGE_NAME** | No | `test-service-binding-usage` | The name of the ServiceBindingUsage created and deleted during integration tests |
-| **APP_TEST_DOMAIN_NAME** | No | `test-function` | The domain name used in the APIRule CR |
-| **APP_TEST_INGRESS_HOST** | No | `kyma.local` | The Ingress host address |
-| **APP_TEST_DOMAIN_PORT** | No | `80` | The port of the Service exposed by the APIRule in a given domain |
-| **APP_TEST_INSECURE_SKIP_VERIFY** | No | `true` | The flag that controls whether tests use verification of the server's certificate and the host name to reach the Function |
-| **APP_TEST_VERBOSE** | No | `true` | The value that controls whether tests log resources that are subject to change |
-| **APP_TEST_MAX_POLLING_TIME** | No | `5m` | The maximum period of time in which the Function must reconfigure after an update |
-| **APP_TEST_KUBECTL_PROXY_ENABLED** | No | `false` | It enables running test locally with `kubectl proxy`. Run `kubectl proxy --proxy 8001` in the background and set the env to `true` |
-
-## Development
-
-### Install Dependencies
-
-This project uses `go modules` as a dependency manager. To install all required dependencies, use the following command:
-
-```bash
-go mod download
-```
diff --git a/tests/serverless/cmd/main.go b/tests/serverless/cmd/main.go
deleted file mode 100644
index 011256c71..000000000
--- a/tests/serverless/cmd/main.go
+++ /dev/null
@@ -1,164 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
- "math/rand"
- "os"
- "os/user"
- "path/filepath"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/testsuite"
- "github.com/sirupsen/logrus"
- "github.com/vrischmann/envconfig"
- "golang.org/x/sync/errgroup"
- "k8s.io/client-go/rest"
- "k8s.io/client-go/tools/clientcmd"
- clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
-)
-
-func loadRestConfig(context string) (*rest.Config, error) {
- // If the recommended kubeconfig env variable is not specified,
- // try the in-cluster config.
- kubeconfigPath := os.Getenv(clientcmd.RecommendedConfigPathEnvVar)
- if len(kubeconfigPath) == 0 {
- if c, err := rest.InClusterConfig(); err == nil {
- return c, nil
- }
- }
-
- loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
- if _, ok := os.LookupEnv("HOME"); !ok {
- u, err := user.Current()
- if err != nil {
- return nil, fmt.Errorf("could not get current user: %w", err)
- }
- loadingRules.Precedence = append(loadingRules.Precedence, filepath.Join(u.HomeDir, clientcmd.RecommendedHomeDir, clientcmd.RecommendedFileName))
- }
-
- return loadRestConfigWithContext("", loadingRules, context)
-}
-
-func loadRestConfigWithContext(apiServerURL string, loader clientcmd.ClientConfigLoader, context string) (*rest.Config, error) {
- return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
- loader,
- &clientcmd.ConfigOverrides{
- ClusterInfo: clientcmdapi.Cluster{
- Server: apiServerURL,
- },
- CurrentContext: context,
- }).ClientConfig()
-}
-
-type testSuite struct {
- name string
- test test
-}
-
-var availableScenarios = map[string][]testSuite{
- "serverless-integration": {
- {name: "simple", test: testsuite.SimpleFunctionTest},
- {name: "gitops", test: testsuite.GitopsSteps},
- },
- "git-auth-integration": {{name: "gitauth", test: testsuite.GitAuthTestSteps}},
- "serverless-contract-tests": {
- {name: "tracing", test: testsuite.FunctionTracingTest},
- {name: "api-gateway", test: testsuite.FunctionAPIGatewayTest},
- {name: "cloud-events", test: testsuite.FunctionCloudEventsTest},
- },
-}
-
-type config struct {
- Test internal.Config
-}
-
-func main() {
- logf := logrus.New()
- logf.SetFormatter(&logrus.JSONFormatter{})
- logf.SetReportCaller(false)
-
- if len(os.Args) < 2 {
- logf.Errorf("Scenario not specified. Specify it as the first argument")
- os.Exit(1)
- }
-
- cfg, err := loadConfig("APP")
- failOnError(err, logf)
- logf.Printf("loaded config")
-
- scenarioName := os.Args[1]
- logf.Printf("Scenario: %s", scenarioName)
- os.Args = os.Args[1:]
- pickedScenario, exists := availableScenarios[scenarioName]
- if !exists {
- logf.Errorf("Scenario %s not exist", scenarioName)
- os.Exit(1)
- }
-
- restConfig, err := loadRestConfig("")
- if err != nil {
- logf.Errorf("Unable to get rest config: %s", err.Error())
- os.Exit(1)
- }
-
- suite := flag.String("test-suite", "", "Choose test-suite to run from scenario")
- flag.Parse()
- if suite != nil && *suite == "" {
- suite = nil
- }
- rand.Seed(time.Now().UnixNano())
-
- g, _ := errgroup.WithContext(context.Background())
- for _, ts := range pickedScenario {
- if suite != nil && ts.name != *suite {
- logf.Infof("Skip test suite suite: %s", ts.name)
- continue
- }
- // https://eli.thegreenplace.net/2019/go-internals-capturing-loop-variables-in-closures/
- testName := fmt.Sprintf("%s-%s", scenarioName, ts.name)
- func(ts test, name string) {
- g.Go(func() error {
- return runTestSuite(ts, name, logf, cfg, restConfig)
- })
- }(ts.test, testName)
- }
- failOnError(g.Wait(), logf)
-}
-
-type test func(*rest.Config, internal.Config, *logrus.Entry) (executor.Step, error)
-
-func runTestSuite(testToRun test, testSuiteName string, logf *logrus.Logger, cfg config, restConfig *rest.Config) error {
- testSuiteLogger := logf.WithField("test", testSuiteName)
- steps, err := testToRun(restConfig, cfg.Test, testSuiteLogger)
- if err != nil {
- logf.Error(err)
- return err
- }
-
- runner := executor.NewRunner(executor.WithCleanupDefault(cfg.Test.Cleanup), executor.WithLogger(logf))
-
- err = runner.Execute(steps)
- if err != nil {
- testSuiteLogger.Error(err)
- return err
- }
- testSuiteLogger.Infof("Test suite succeeded: %s", testSuiteName)
- return nil
-}
-
-func loadConfig(prefix string) (config, error) {
- cfg := config{}
- err := envconfig.InitWithPrefix(&cfg, prefix)
- return cfg, err
-}
-
-func failOnError(err error, logf *logrus.Logger) {
- if err != nil {
- logf.Error(err)
- os.Exit(1)
- }
-}
diff --git a/tests/serverless/collect_logs.sh b/tests/serverless/collect_logs.sh
deleted file mode 100755
index fa4ce1393..000000000
--- a/tests/serverless/collect_logs.sh
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env bash
-
-collect_logs(){
- set +o errexit
- echo "####################"
- echo "kubectl get pods -A"
- echo "###################"
- kubectl get pods -A
-
- echo "########################"
- echo "kubectl get functions -A"
- echo "########################"
- kubectl get functions -A
-
- echo "########################################################"
- echo "kubectl logs -n kyma-system -l app=serverless --tail=-1"
- echo "########################################################"
- kubectl logs -n kyma-system -l app=serverless --tail=-1
-
-
- echo "########################################################"
- echo "kubectl logs -n kyma-system -l app=serverless-webhook --tail=-1"
- echo "########################################################"
- kubectl logs -n kyma-system -l app=serverless-webhook --tail=-1
-
-
- echo "########################################################"
- echo "Get logs from all function build jobs and runtime"
- echo "########################################################"
- ALL_NAMESPACES=$(kubectl get namespace --no-headers -o custom-columns=name:.metadata.name)
- # shellcheck disable=SC2206
- ALL=($ALL_NAMESPACES)
- for NAMESPACE in "${ALL[@]}"
- do
- kubectl logs --namespace "${NAMESPACE}" --all-containers --selector serverless.kyma-project.io/function-name --ignore-errors --prefix=true --tail=-1
- done
- echo ""
- set -o errexit
-}
diff --git a/tests/serverless/internal/assertion/check.go b/tests/serverless/internal/assertion/check.go
deleted file mode 100644
index 56c951c24..000000000
--- a/tests/serverless/internal/assertion/check.go
+++ /dev/null
@@ -1,298 +0,0 @@
-package assertion
-
-import (
- "context"
- "encoding/json"
- goerrors "errors"
- "fmt"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "io"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- v1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "net/http"
- "net/url"
- "time"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/client-go/util/retry"
-)
-
-type HTTPCheck struct {
- name string
- log *logrus.Entry
- endpoint string
- expectedMsg string
- poll utils.Poller
-}
-
-var _ executor.Step = HTTPCheck{}
-
-const (
- publisherURL = "http://eventing-event-publisher-proxy.kyma-system/publish"
-)
-
-func NewHTTPCheck(log *logrus.Entry, name string, url *url.URL, poller utils.Poller, expectedMsg string) *HTTPCheck {
- return &HTTPCheck{
- name: name,
- log: log.WithField(executor.LogStepKey, name),
- endpoint: url.String(),
- expectedMsg: expectedMsg,
- poll: poller.WithLogger(log),
- }
-
-}
-
-func (h HTTPCheck) Name() string {
- return h.name
-}
-
-func (h HTTPCheck) Run() error {
- // backoff is needed because even tough the deployment may be ready
- // the language specific server may not start yet
- // there may also be some problems with istio sidecars etc
- backoff := wait.Backoff{
- Steps: 10,
- Duration: 500 * time.Millisecond,
- Factor: 2.0,
- Jitter: 0.1,
- }
- return retry.OnError(backoff, func(err error) bool {
- return true
- }, func() error {
- err := errors.Wrap(h.poll.PollForAnswer(h.endpoint, "", h.expectedMsg), "while checking connection to function")
- if err != nil {
- h.log.Warn(err)
- }
- return err
- })
-}
-
-func (h HTTPCheck) Cleanup() error {
- return nil
-}
-
-func (h HTTPCheck) OnError() error {
- return nil
-}
-
-var _ executor.Step = &tracingHTTPCheck{}
-
-type tracingHTTPCheck struct {
- name string
- log *logrus.Entry
- endpoint string
- poll utils.Poller
-}
-
-type tracingResponse struct {
- TraceParent string `json:"traceparent"`
- TraceID string `json:"x-b3-traceid"`
- SpanID string `json:"x-b3-spanid"`
-}
-
-func TracingHTTPCheck(log *logrus.Entry, name string, url *url.URL, poller utils.Poller) *tracingHTTPCheck {
- return &tracingHTTPCheck{
- name: name,
- log: log.WithField(executor.LogStepKey, name),
- endpoint: url.String(),
- poll: poller.WithLogger(log),
- }
-
-}
-
-func (t tracingHTTPCheck) Name() string {
- return t.name
-}
-
-func (t tracingHTTPCheck) Run() error {
- req, err := http.NewRequest(http.MethodGet, t.endpoint, nil)
- if err != nil {
- return err
- }
-
- req.Header.Add("X-B3-Sampled", "1")
-
- resp, err := t.doRetrievableHttpCall(req, 5)
- if err != nil {
- return errors.Wrap(err, "while doing http call")
- }
-
- out, err := io.ReadAll(resp.Body)
- if err != nil {
- return errors.Wrap(err, "while reading response body")
- }
-
- trResponse := tracingResponse{}
- err = json.Unmarshal(out, &trResponse)
- if err != nil {
- return errors.Wrapf(err, "while unmarshalling response to json")
- }
-
- err = t.assertTracingResponse(trResponse)
- if err != nil {
- return errors.Wrapf(err, "Got following headers: %s", out)
- }
- t.log.Info("headers are okay")
- return nil
-}
-
-func (t tracingHTTPCheck) doRetrievableHttpCall(req *http.Request, retries int) (*http.Response, error) {
- client := &http.Client{Timeout: 5 * time.Second}
- var finalResp *http.Response = nil
-
- var backoff = wait.Backoff{
- Steps: retries,
- Duration: 2 * time.Second,
- Factor: 1.0,
- }
-
- err := retry.OnError(backoff, func(err error) bool {
- t.log.Warnf("Got error: %s", err.Error())
- return true
- }, func() error {
- resp, err := client.Do(req)
- if err != nil {
- return err
- }
-
- if resp.StatusCode != http.StatusOK {
- return errors.Errorf(" expected status code: %d, got: %d", http.StatusOK, resp.StatusCode)
- }
- finalResp = resp
- return nil
- })
- return finalResp, errors.Wrap(err, "while trying to call function")
-}
-
-func (t tracingHTTPCheck) Cleanup() error {
- return nil
-}
-
-func (t tracingHTTPCheck) OnError() error {
- return nil
-}
-
-func (t tracingHTTPCheck) assertTracingResponse(response tracingResponse) error {
- if response.TraceID == "" {
- return errors.New("No trace ID")
- }
- if response.TraceParent == "" {
- return errors.New("No TraceParent")
- }
- if response.SpanID == "" {
- return errors.New("No span ID")
- }
-
- return nil
-}
-
-const (
- resourceLabel = "serverless.kyma-project.io/resource"
- functionNameLabel = "serverless.kyma-project.io/function-name"
- manageByLabel = "serverless.kyma-project.io/managed-by"
- uuidLabel = "serverless.kyma-project.io/uuid"
-)
-
-type apiGatewayFunctionCheck struct {
- name string
- fn *function.Function
- client *v1.CoreV1Client
- namespace string
- runtime string
-}
-
-func APIGatewayFunctionCheck(name string, fn *function.Function, coreV1 *v1.CoreV1Client, ns string, rt string) *apiGatewayFunctionCheck {
- return &apiGatewayFunctionCheck{
- name: name,
- fn: fn,
- client: coreV1,
- namespace: ns,
- runtime: rt,
- }
-}
-
-func (d apiGatewayFunctionCheck) Name() string {
- return d.name
-}
-
-func (d apiGatewayFunctionCheck) Run() error {
-
- svc, err := d.client.Services(d.namespace).Get(context.Background(), d.name, metav1.GetOptions{})
- if err != nil {
- return errors.Wrap(err, "while trying to get service")
- }
-
- pod, err := d.client.Pods(d.namespace).List(context.Background(), metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=deployment,%s=%s", resourceLabel, functionNameLabel, d.name)})
- if err != nil {
- return errors.Wrap(err, "while trying to get pod")
- }
-
- err = checkIfRequiredLabelsExists(svc.Spec.Selector, true)
- if err != nil {
- return errors.Wrap(err, " while checking the service labels")
- }
- err = checkIfRequiredLabelsExists(pod.Items[0].ObjectMeta.Labels, false)
- if err != nil {
- return errors.Wrap(err, " while checking the pod labels")
- }
-
- err = checkIfContractIsFulfilled(pod.Items[0], *svc)
- if err != nil {
- return errors.Wrap(err, " while checking labels")
- }
-
- if len(svc.Spec.Selector) != 0 {
- return errors.New("The labels are not matching")
- }
-
- return nil
-}
-
-func (d apiGatewayFunctionCheck) Cleanup() error {
- return nil
-}
-
-func (d apiGatewayFunctionCheck) OnError() error {
- return nil
-}
-
-func checkIfContractIsFulfilled(pod corev1.Pod, service corev1.Service) error {
- var errJoined error
-
- for k, v := range pod.Labels {
- if val, exists := service.Spec.Selector[k]; exists {
- if val == v {
- delete(service.Spec.Selector, k)
- } else {
- err := errors.Errorf("Expected %s but got %s", v, val)
- errJoined = goerrors.Join(err)
- }
- }
- }
- return errJoined
-}
-
-func checkIfRequiredLabelsExists(labels map[string]string, isService bool) error {
- requiredLabels := []string{resourceLabel, functionNameLabel, manageByLabel, uuidLabel}
-
- if isService {
- if len(labels) != 4 {
- return errors.New(fmt.Sprintf("Service has got %d instead of 4 labels", len(labels)))
- }
- }
-
- var errJoined error
-
- for _, label := range requiredLabels {
- if _, exists := labels[label]; !exists {
- err := errors.New(fmt.Sprintf("Label %s is missing", label))
- errJoined = goerrors.Join(err)
- }
- }
- return errJoined
-}
diff --git a/tests/serverless/internal/assertion/check_test.go b/tests/serverless/internal/assertion/check_test.go
deleted file mode 100644
index ee19612ea..000000000
--- a/tests/serverless/internal/assertion/check_test.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package assertion
-
-import (
- "net/url"
- "testing"
-
- cloudevents "github.com/cloudevents/sdk-go/v2"
- "github.com/sirupsen/logrus"
-)
-
-func TestCloudEventCheckLocally(t *testing.T) {
- t.Skip("Used only to local development")
- t.Run("cloud event check", func(t *testing.T) {
- testCases := map[string]struct {
- cloudevents.Encoding
- }{
- "Structured": {
- cloudevents.EncodingStructured,
- },
- "Binary": {
- cloudevents.EncodingBinary,
- },
- }
- for name, tc := range testCases {
- t.Run(name, func(t *testing.T) {
- //GIVEN
- log := logrus.New().WithField("test", "cloud event")
- fnURL, err := url.Parse("http://localhost:8091")
- if err != nil {
- panic(err)
- }
-
- //WHEN
- check := CloudEventReceiveCheck(log, "test", tc.Encoding, fnURL)
-
- //THEN
- err = check.Run()
- if err != nil {
- panic(err)
- }
- })
- }
-
- })
-
- t.Run("cloud event send check", func(t *testing.T) {
- //GIVEN
- log := logrus.New().WithField("test", "cloud event")
- fnURL, err := url.Parse("http://localhost:8080")
- if err != nil {
- panic(err)
- }
-
- //WHEN
- check := CloudEventSendCheck(log, "test", "test-runtime", fnURL, fnURL)
-
- //THEN
- err = check.Run()
- if err != nil {
- panic(err)
- }
- })
-}
diff --git a/tests/serverless/internal/assertion/cloud_events.go b/tests/serverless/internal/assertion/cloud_events.go
deleted file mode 100644
index 629353ee3..000000000
--- a/tests/serverless/internal/assertion/cloud_events.go
+++ /dev/null
@@ -1,317 +0,0 @@
-package assertion
-
-import (
- "bytes"
- "context"
- "encoding/json"
- goerrors "errors"
- "fmt"
- "io"
- "net/http"
- "net/url"
- "time"
-
- cloudevents "github.com/cloudevents/sdk-go/v2"
- "github.com/google/uuid"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/util/retry"
-)
-
-const EventTypeParam = "type"
-
-/*
-*
-https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md
-*/
-type cloudEventResponse struct {
- // Required
- CeType string `json:"ce-type"`
- // Required
- CeSource string `json:"ce-source"`
- // Required
- CeSpecVersion string `json:"ce-specversion"`
- // Required
- CeID string `json:"ce-id"`
- // Optional
- CeTime string `json:"ce-time"`
- // Optional
- CeDataContentType string `json:"ce-datacontenttype"`
- // Extension field, optional.
- CeEventTypeVersion string `json:"ce-eventtypeversion"`
- Data cloudEventData `json:"data"`
-}
-
-type cloudEventData struct {
- Hello string `json:"hello"`
-}
-
-type cloudEventCheck struct {
- name string
- log *logrus.Entry
- endpoint string
- encoding cloudevents.Encoding
-}
-
-var _ executor.Step = &cloudEventCheck{}
-
-func CloudEventReceiveCheck(log *logrus.Entry, name string, encoding cloudevents.Encoding, target *url.URL) *cloudEventCheck {
- return &cloudEventCheck{
- encoding: encoding,
- name: name,
- log: log.WithField(executor.LogStepKey, name),
- endpoint: target.String(),
- }
-}
-
-func (ce cloudEventCheck) Name() string {
- return ce.name
-}
-
-func (ce cloudEventCheck) Run() error {
- ceEventType := fmt.Sprintf("test-%s", ce.encoding)
- expResp := cloudEventResponse{
- CeType: ceEventType,
- CeSource: "contract-test",
- CeSpecVersion: cloudevents.VersionV1,
- CeEventTypeVersion: "v1alpha2",
- }
- ceCtx, data, err := ce.createCECtx()
- if err != nil {
- return err
- }
- expResp.Data = cloudEventData{Hello: data}
-
- err = sentCloudEvent(ceCtx, expResp)
- if err != nil {
- return errors.Wrap(err, "while setting cloud event data")
- }
-
- ceResp, err := getCloudEventFromFunction(ce.endpoint, ceEventType)
- if err != nil {
- return errors.Wrap(err, "while fetching cloud event from function")
- }
- err = assertCloudEvent(ceResp, expResp)
- if err != nil {
- return errors.Wrapf(err, "while validating cloud event")
- }
- ce.log.Info("cloud event is okay")
- return nil
-}
-
-func (ce cloudEventCheck) Cleanup() error {
- return nil
-}
-
-func (ce cloudEventCheck) OnError() error {
- resp, err := getEventData(ce.endpoint)
- if err != nil {
- return errors.Wrap(err, "while getting all cloud events")
- }
- ce.log.Infof("All received events from function: %s", resp)
- return nil
-}
-
-func (ce cloudEventCheck) createCECtx() (context.Context, string, error) {
- ceCtx := cloudevents.ContextWithTarget(context.Background(), ce.endpoint)
- var data = ""
- switch ce.encoding {
- case cloudevents.EncodingStructured:
- ceCtx = cloudevents.WithEncodingStructured(ceCtx)
- data = fmt.Sprintf("structured-from-%s", ce.endpoint)
- case cloudevents.EncodingBinary:
- ceCtx = cloudevents.WithEncodingBinary(ceCtx)
- data = fmt.Sprintf("binary-from-%s", ce.endpoint)
- default:
- return nil, "", errors.Errorf("Encoding not supported: %s", ce.encoding)
- }
- return ceCtx, data, nil
-}
-
-type cloudEventSendCheck struct {
- name string
- ceSource string
- log *logrus.Entry
- endpoint string
- publisherProxy string
-}
-
-var _ executor.Step = &cloudEventSendCheck{}
-
-func CloudEventSendCheck(log *logrus.Entry, name, ceSource string, target *url.URL, publisherProxy *url.URL) executor.Step {
- return cloudEventSendCheck{
- name: name,
- ceSource: ceSource,
- log: log,
- endpoint: target.String(),
- publisherProxy: publisherProxy.String(),
- }
-}
-
-func (s cloudEventSendCheck) Name() string {
- return s.name
-}
-
-func (s cloudEventSendCheck) Run() error {
- eventData := cloudEventData{
- Hello: "send-event",
- }
-
- out, err := json.Marshal(&eventData)
- if err != nil {
- return errors.Wrap(err, "while marshaling eventData to send")
- }
-
- resp, err := http.DefaultClient.Post(s.endpoint, "application/json", bytes.NewReader(out))
- if err != nil {
- return errors.Wrap(err, "while sending eventData")
- }
- if resp.StatusCode != http.StatusOK {
- return errors.Errorf("Expected: %d, got: %d status code from eventData request", http.StatusAccepted, resp.StatusCode)
- }
-
- expected := cloudEventResponse{
- CeType: "send-check",
- CeSource: s.ceSource,
- CeSpecVersion: cloudevents.VersionV1,
- CeEventTypeVersion: "v1alpha2",
- Data: eventData,
- }
-
- // retry GET request to cover situations when a POST request will reach publisher-proxy after GET
- // this situation is possible because the k8s cluster is not a synchronous environment
- return retry.OnError(retry.DefaultRetry, func(err error) bool {
- return true
- },
- func() error {
- event, err := getCloudEventFromFunction(s.endpoint, "send-check")
- if err != nil {
- return errors.Wrap(err, "while getting saved cloud event")
- }
-
- err = assertCloudEvent(event, expected)
- if err != nil {
- return errors.Wrap(err, "while doing assertion on cloud event")
- }
-
- return nil
- })
-}
-
-func (s cloudEventSendCheck) Cleanup() error {
- return nil
-}
-
-func (s cloudEventSendCheck) OnError() error {
- resp, err := getEventData(s.publisherProxy)
- if err != nil {
- return errors.Wrap(err, "while getting all sent events")
- }
- s.log.Infof("All sent events from publisher proxy: %s", resp)
- return nil
-}
-
-func sentCloudEvent(ceCtx context.Context, expResp cloudEventResponse) error {
- c, err := cloudevents.NewClientHTTP()
- if err != nil {
- return errors.Wrap(err, "while creating cloud event client")
- }
- event := cloudevents.NewEvent()
- err = event.SetData(cloudevents.ApplicationJSON, expResp.Data)
- if err != nil {
- return errors.Wrap(err, "while setting data on cloud event")
- }
- event.SetSource(expResp.CeSource)
- event.SetType(expResp.CeType)
- event.SetSpecVersion(expResp.CeSpecVersion)
- event.SetExtension("eventtypeversion", expResp.CeEventTypeVersion)
-
- result := c.Send(ceCtx, event)
- if cloudevents.IsUndelivered(result) {
- return errors.Wrap(result, "while sending cloud event")
- }
- return nil
-}
-
-func getCloudEventFromFunction(endpoint, eventType string) (cloudEventResponse, error) {
- req := &http.Request{}
- fnURL, err := url.Parse(endpoint)
- if err != nil {
- return cloudEventResponse{}, errors.Wrap(err, "while parsing function url")
- }
- q := fnURL.Query()
- q.Add(EventTypeParam, eventType)
- fnURL.RawQuery = q.Encode()
-
- req.URL = fnURL
- res, err := http.DefaultClient.Do(req)
- if err != nil {
- return cloudEventResponse{}, errors.Wrap(err, "while doing GET request to function")
- }
- out, err := io.ReadAll(res.Body)
- if err != nil {
- return cloudEventResponse{}, errors.Wrapf(err, "while reading response body: %s", string(out))
- }
-
- ceResp := cloudEventResponse{}
- err = json.Unmarshal(out, &ceResp)
- if err != nil {
- return cloudEventResponse{}, errors.Wrapf(err, "while unmarshalling response, got: %s", out)
- }
- return ceResp, nil
-}
-
-func getEventData(endpoint string) (string, error) {
- req := &http.Request{}
- fnURL, err := url.Parse(endpoint)
- if err != nil {
- return "", errors.Wrap(err, "while parsing function url")
- }
- req.URL = fnURL
- res, err := http.DefaultClient.Do(req)
- if err != nil {
- return "", errors.Wrap(err, "while doing request")
- }
- out, err := io.ReadAll(res.Body)
- if err != nil {
- return "", errors.Wrap(err, "while reading response body")
- }
- return string(out), nil
-}
-
-func assertCloudEvent(response cloudEventResponse, expectedResponse cloudEventResponse) error {
- var errJoined error
-
- if expectedResponse.Data.Hello != response.Data.Hello {
- err := errors.Errorf("Expected %s, got %s in cloud event data", expectedResponse.Data.Hello, response.Data.Hello)
- errJoined = goerrors.Join(err)
- }
-
- _, err := time.Parse(time.RFC3339, response.CeTime)
- if err != nil {
- errJoined = goerrors.Join(errors.Wrap(err, "while validating date"))
- }
-
- if response.CeSource != expectedResponse.CeSource {
- errJoined = goerrors.Join(errors.Errorf("expected source %s, got: %s", expectedResponse.CeSource, response.CeSource))
- }
-
- if response.CeType != expectedResponse.CeType {
- errJoined = goerrors.Join(errors.Errorf("expected type %s, got: %s", expectedResponse.CeType, response.CeType))
- }
-
- if response.CeSpecVersion != expectedResponse.CeSpecVersion {
- errJoined = goerrors.Join(errors.Errorf("expected spec version %s, got: %s", expectedResponse.CeSpecVersion, response.CeSpecVersion))
- }
-
- if response.CeEventTypeVersion != expectedResponse.CeEventTypeVersion {
- errJoined = goerrors.Join(errors.Errorf("expected event type version %s, got: %s", expectedResponse.CeEventTypeVersion, response.CeEventTypeVersion))
- }
-
- _, err = uuid.Parse(response.CeID)
- if err != nil {
- errJoined = goerrors.Join(errors.Errorf("expected UUID, got: %s", response.CeID))
- }
- return errJoined
-}
diff --git a/tests/serverless/internal/config.go b/tests/serverless/internal/config.go
deleted file mode 100644
index f5ea3556e..000000000
--- a/tests/serverless/internal/config.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package internal
-
-import (
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
-)
-
-const (
- TestDataKey = "testData"
-)
-
-type Config struct {
- Namespace string `envconfig:"default=test-function"`
- KubectlProxyEnabled bool `envconfig:"default=false"`
- Verbose bool `envconfig:"default=false"`
- WaitTimeout time.Duration `envconfig:"default=15m"`
- MaxPollingTime time.Duration `envconfig:"default=5m"`
- InsecureSkipVerify bool `envconfig:"default=true"`
- Cleanup executor.CleanupMode `envconfig:"default=yes"`
- GitServerImage string `envconfig:"default=europe-docker.pkg.dev/kyma-project/prod/gitserver:main"`
- GitServerRepoName string `envconfig:"default=function"`
- IstioEnabled bool `envconfig:"default=false"`
- PackageRegistryConfigSecretName string `envconfig:"default=serverless-package-registry-config"`
- PackageRegistryConfigURLNode string `envconfig:"default=https://pkgs.dev.azure.com/kyma-wookiee/public-packages/_packaging/public-packages%40Release/npm/registry/"`
- PackageRegistryConfigURLPython string `envconfig:"default=https://pkgs.dev.azure.com/kyma-wookiee/public-packages/_packaging/public-packages%40Release/pypi/simple/"`
-}
diff --git a/tests/serverless/internal/executor/cli.go b/tests/serverless/internal/executor/cli.go
deleted file mode 100644
index 40e0e40ff..000000000
--- a/tests/serverless/internal/executor/cli.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package executor
-
-import (
- "github.com/pkg/errors"
- "github.com/spf13/pflag"
-)
-
-// Execute behavior is based on chose cleanup method. It is intended to be used with AddFlags
-func (r *Runner) Execute(step Step) error {
- r.log.Infof("Cleanup mode: %s", r.cleanup)
- var err error
- switch r.cleanup {
- case CleanupModeNo:
- err = r.Run(step, true)
- case CleanupModeOnly:
- return step.Cleanup()
- case CleanupModeYes:
- err = r.Run(step, false)
- case CleanupModeOnErrorOnly:
- err = r.Run(step, true)
- if err != nil {
- return step.Cleanup()
- }
- case CleanupModeOnSuccessOnly:
- err = r.Run(step, true)
- if err == nil {
- return step.Cleanup()
- }
- default:
- err = errors.Errorf("couldn't find cleanup mode: %s", r.cleanup)
- }
- return err
-}
-
-// AddFlags add CLI flags so user may control runner behaviour easily
-func (r *Runner) AddFlags(set *pflag.FlagSet) {
- set.Var(&r.cleanup, "cleanup", "Cleanup mode. Allowed values: yes/no/only")
-}
-
-// CleanupMode says how runner should execute cleanup
-type CleanupMode string
-
-const (
- // CleanupModeNo - Don't execute cleanup
- CleanupModeNo CleanupMode = "no"
- // CleanupModeOnly - Don't run Steps, only cleanup
- CleanupModeOnly CleanupMode = "only"
- // Execute both Steps and cleanup
- CleanupModeYes CleanupMode = "yes"
- // Execute Steps. If Steps fail then run cleanup. Keep resources in case of success
- CleanupModeOnErrorOnly CleanupMode = "onErrorOnly"
- CleanupModeOnSuccessOnly CleanupMode = "onSuccessOnly"
-)
-
-// String implements pflag.Value.String
-func (m CleanupMode) String() string {
- return string(m)
-}
-
-// Set implements pflag.Value.Set
-func (m *CleanupMode) Set(v string) error {
- switch CleanupMode(v) {
- case CleanupModeNo, CleanupModeYes, CleanupModeOnly, CleanupModeOnErrorOnly:
- default:
- return errors.Errorf("invalid cleanup value: %s", v)
- }
- *m = CleanupMode(v)
- return nil
-}
-
-// Type implements pflag.Value.Type
-func (m CleanupMode) Type() string {
- return "runner mode"
-}
diff --git a/tests/serverless/internal/executor/consts.go b/tests/serverless/internal/executor/consts.go
deleted file mode 100644
index eb2a68459..000000000
--- a/tests/serverless/internal/executor/consts.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package executor
-
-const LogStepKey = "step"
diff --git a/tests/serverless/internal/executor/fixtures_test.go b/tests/serverless/internal/executor/fixtures_test.go
deleted file mode 100644
index 3864afeba..000000000
--- a/tests/serverless/internal/executor/fixtures_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package executor_test
-
-import (
- "strings"
-
- "github.com/sirupsen/logrus"
-)
-
-type testStep struct {
- err error
- name string
- counter *int
- logf *logrus.Entry
-}
-
-func (e testStep) Name() string {
- return e.name
-}
-
-func (e testStep) Run() error {
- e.logf = e.logf.WithField("Step", e.name)
- return e.err
-}
-
-func (e testStep) Cleanup() error {
- return nil
-}
-
-func (e testStep) OnError() error {
- *e.counter++
- e.logf.Infof("Called on Error, resource: %s", e.name)
- return nil
-}
-
-func getLogsContains(entries []*logrus.Entry, text string) []*logrus.Entry {
- filteredEntries := []*logrus.Entry{}
-
- for _, entry := range entries {
- if strings.Contains(entry.Message, text) {
- filteredEntries = append(filteredEntries, entry)
- }
- }
-
- return filteredEntries
-}
-
-func getLogs(entries []*logrus.Entry, key, value string) []*logrus.Entry {
- var foundLogs []*logrus.Entry
- for _, entry := range entries {
- field, ok := entry.Data[key]
- if ok {
- logValue, ok := field.(string)
- if ok {
- if logValue == value {
- foundLogs = append(foundLogs, entry)
- }
- }
- }
- }
- return foundLogs
-}
-
-func getFirstMatchingLog(entries []*logrus.Entry, text string, startIdx int) (*logrus.Entry, int) {
- for i := startIdx; i < len(entries); i++ {
- if strings.Contains(entries[i].Message, text) {
- return entries[i], i
- }
- }
- return nil, -1
-}
-
-func getLogsWithLevel(entries []*logrus.Entry, level logrus.Level) []*logrus.Entry {
- filtered := []*logrus.Entry{}
- for _, entry := range entries {
- if entry.Level == level {
- filtered = append(filtered, entry)
- }
- }
- return filtered
-}
diff --git a/tests/serverless/internal/executor/parallel.go b/tests/serverless/internal/executor/parallel.go
deleted file mode 100644
index 2d86ab9f8..000000000
--- a/tests/serverless/internal/executor/parallel.go
+++ /dev/null
@@ -1,82 +0,0 @@
-package executor
-
-import (
- "fmt"
- "strings"
- "sync"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-
- "github.com/hashicorp/go-multierror"
-)
-
-type Parallelized struct {
- steps []Step
- name string
- logf *logrus.Entry
-}
-
-func NewParallelRunner(logf *logrus.Entry, name string, steps ...Step) *Parallelized {
- return &Parallelized{logf: logf, name: name, steps: steps}
-}
-
-func (p *Parallelized) Name() string {
- names := make([]string, len(p.steps))
- for i, step := range p.steps {
- names[i] = step.Name()
- }
- joined := strings.Join(names, ", ")
- return fmt.Sprintf("Parallel: %s, %s", p.name, joined)
-}
-
-func (p *Parallelized) Run() error {
- return p.inParallel(func(step Step) error {
- p.logf.Infof("Run in parallel: %s", step.Name())
- err := step.Run()
- if err != nil {
- p.logf.Errorf("Step: %s, returned error: %s", step.Name(), err.Error())
- if callbackErr := step.OnError(); callbackErr != nil {
- p.logf.Errorf("while executing OnError on %s, err: %s", step.Name(), callbackErr.Error())
- }
- return errors.Wrapf(err, "while executing step: %s", step.Name())
- }
- return nil
- })
-}
-
-func (p *Parallelized) Cleanup() error {
- return p.inParallel(func(step Step) error {
- return step.Cleanup()
- })
-}
-
-func (p *Parallelized) OnError() error {
- return nil
-}
-
-func (p *Parallelized) inParallel(f func(step Step) error) error {
- wg := &sync.WaitGroup{}
- wg.Add(len(p.steps))
- errs := make(chan error, len(p.steps))
- for _, s := range p.steps {
- go p.runStepInParallel(wg, errs, s, f)
- }
- wg.Wait()
- close(errs)
- var errAll *multierror.Error
- for err := range errs {
- errAll = multierror.Append(errAll, err)
- }
- return errAll.ErrorOrNil()
-}
-
-func (p *Parallelized) runStepInParallel(wg *sync.WaitGroup, errs chan<- error, step Step, f func(step Step) error) {
- defer wg.Done()
- defer func() {
- if err := recover(); err != nil {
- errs <- err.(error)
- }
- }()
- errs <- f(step)
-}
diff --git a/tests/serverless/internal/executor/parallel_test.go b/tests/serverless/internal/executor/parallel_test.go
deleted file mode 100644
index e4832c287..000000000
--- a/tests/serverless/internal/executor/parallel_test.go
+++ /dev/null
@@ -1,132 +0,0 @@
-package executor_test
-
-import (
- "errors"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "testing"
-
- "github.com/sirupsen/logrus"
-
- "github.com/onsi/gomega"
- "github.com/sirupsen/logrus/hooks/test"
-)
-
-func TestParallelRunner(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- logger, hook := test.NewNullLogger()
- logf := logger.WithField("Test", "Test")
- idx := 0
-
- steps := executor.NewSerialTestRunner(logf, "Test1",
- testStep{name: "start 0", counter: &idx, logf: logf},
- executor.NewParallelRunner(logf, "Parallel Step",
- testStep{name: "step 1", counter: &idx, logf: logf},
- testStep{name: "step 2", counter: &idx, logf: logf},
- testStep{name: "step 3", counter: &idx, logf: logf},
- testStep{name: "step 4", err: errors.New("Error Attention"), counter: &idx, logf: logf},
- testStep{name: "step 5", counter: &idx, logf: logf},
- ),
- )
- runner := executor.NewRunner(executor.WithCleanupDefault(executor.CleanupModeYes), executor.WithLogger(logger))
-
- //WHEN
- err := runner.Execute(steps)
-
- //THEN
- g.Expect(err).ToNot(gomega.BeNil())
- g.Expect(idx).To(gomega.Equal(2))
- g.Expect(err.Error()).To(gomega.ContainSubstring("while executing step: step 4"))
-
- logEntries := hook.AllEntries()
- entry, nextLogIdx := getFirstMatchingLog(logEntries, "Step: step 4, returned error: Error Attention", 0)
- g.Expect(entry).ToNot(gomega.BeNil())
-
- entry, nextLogIdx = getFirstMatchingLog(logEntries, "Called on Error, resource: step 4", nextLogIdx)
- g.Expect(entry).ToNot(gomega.BeNil())
-
- entry, nextLogIdx = getFirstMatchingLog(logEntries, "Called on Error, resource: start 0", nextLogIdx)
- g.Expect(entry).ToNot(gomega.BeNil())
-
- entry, nextLogIdx = getFirstMatchingLog(logEntries, "Cleanup Serial Step: Parallel: Parallel Step", nextLogIdx)
- g.Expect(entry).ToNot(gomega.BeNil())
-
- entry, nextLogIdx = getFirstMatchingLog(logEntries, "Cleanup Serial Step: start 0", nextLogIdx)
- g.Expect(entry).ToNot(gomega.BeNil())
- hook.Reset()
-}
-
-func TestMixedRunners(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- logger, hook := test.NewNullLogger()
- logf := logger.WithField("TestSuite", "Test")
- log1 := logf.WithField("Test", "suite1")
- log2 := logf.WithField("Test", "suite2")
- log3 := logf.WithField("Test", "suite3")
- idx := 0
-
- steps := executor.NewSerialTestRunner(logf, "Suite",
- testStep{name: "Init Step", counter: &idx, logf: logf},
- executor.NewParallelRunner(logf, "test",
- executor.NewSerialTestRunner(log1, "Test Serial Runner",
- testStep{name: "step 1.1", counter: &idx, logf: log1},
- testStep{name: "step 1.2", counter: &idx, logf: log1},
- testStep{name: "step 1.3", counter: &idx, logf: log1},
- testStep{name: "step 1.4", counter: &idx, logf: log1},
- ),
- executor.NewSerialTestRunner(log2, "Fault Serial Runner",
- testStep{name: "step 2.1", counter: &idx, logf: log2},
- testStep{name: "step 2.2", counter: &idx, logf: log2},
- testStep{name: "step 2.3", counter: &idx, logf: log2},
- testStep{name: "step 2.4", err: errors.New("Error Attention"), counter: &idx, logf: log2},
- testStep{name: "step 2.5", counter: &idx, logf: log2},
- ),
- executor.NewSerialTestRunner(log3, "Test Serial Runner",
- testStep{name: "step 3.1", counter: &idx, logf: log3},
- testStep{name: "step 3.2", counter: &idx, logf: log3},
- testStep{name: "step 3.3", counter: &idx, logf: log3},
- testStep{name: "step 3.4", counter: &idx, logf: logf},
- ),
- ),
- testStep{name: "Finish Step", counter: &idx, logf: logf})
- runner := executor.NewRunner(executor.WithCleanupDefault(executor.CleanupModeYes), executor.WithLogger(logger))
-
- //WHEN
- err := runner.Execute(steps)
-
- //THEN
- g.Expect(err).ToNot(gomega.BeNil())
- g.Expect(err.Error()).To(gomega.ContainSubstring("while executing step: step 2.4"))
- g.Expect(idx).To(gomega.Equal(5))
-
- allLogs := hook.AllEntries()
-
- step2Logs := getLogs(allLogs, "Test", "suite2")
- g.Expect(len(step2Logs)).To(gomega.Equal(13))
- g.Expect(step2Logs[0].Message).To(gomega.Equal("Running Step 0: step 2.1"))
- g.Expect(step2Logs[1].Message).To(gomega.Equal("Running Step 1: step 2.2"))
- g.Expect(step2Logs[2].Message).To(gomega.Equal("Running Step 2: step 2.3"))
- g.Expect(step2Logs[3].Message).To(gomega.Equal("Running Step 3: step 2.4"))
-
- g.Expect(step2Logs[4].Message).To(gomega.Equal("Error in step 2.4, error: Error Attention"))
-
- g.Expect(step2Logs[5].Message).To(gomega.Equal("Called on Error, resource: step 2.4"))
- g.Expect(step2Logs[6].Message).To(gomega.Equal("Called on Error, resource: step 2.3"))
- g.Expect(step2Logs[7].Message).To(gomega.Equal("Called on Error, resource: step 2.2"))
- g.Expect(step2Logs[8].Message).To(gomega.Equal("Called on Error, resource: step 2.1"))
-
- g.Expect(step2Logs[9].Message).To(gomega.Equal("Cleanup Serial Step: step 2.4"))
- g.Expect(step2Logs[10].Message).To(gomega.Equal("Cleanup Serial Step: step 2.3"))
- g.Expect(step2Logs[11].Message).To(gomega.Equal("Cleanup Serial Step: step 2.2"))
- g.Expect(step2Logs[12].Message).To(gomega.Equal("Cleanup Serial Step: step 2.1"))
-
- errorLogs := getLogsWithLevel(allLogs, logrus.ErrorLevel)
-
- g.Expect(len(errorLogs)).To(gomega.Equal(3))
- g.Expect(errorLogs[0].Message).To(gomega.Equal("Error in step 2.4, error: Error Attention"))
- g.Expect(errorLogs[1].Message).To(gomega.ContainSubstring("Fault Serial Runner, Steps: 0:step 2.1, 1:step 2.2, 2:step 2.3, 3:step 2.4, 4:step 2.5., returned error: while executing step: step 2.4: Error Attention"))
- g.Expect(errorLogs[2].Message).To(gomega.ContainSubstring("Error in Parallel: test"))
-
- hook.Reset()
-}
diff --git a/tests/serverless/internal/executor/retry.go b/tests/serverless/internal/executor/retry.go
deleted file mode 100644
index 855e805bc..000000000
--- a/tests/serverless/internal/executor/retry.go
+++ /dev/null
@@ -1,77 +0,0 @@
-package executor
-
-import (
- "fmt"
- "strings"
- "time"
-
- "github.com/avast/retry-go"
- "github.com/hashicorp/go-multierror"
-)
-
-type Retried struct {
- steps []Step
- options []Option
-}
-
-func (r *Retried) Name() string {
- names := make([]string, len(r.steps))
- for i, step := range r.steps {
- names[i] = step.Name()
- }
- joined := strings.Join(names, ", ")
- return fmt.Sprintf("Retried: %s", joined)
-}
-
-func (r *Retried) Run() error {
- return retry.Do(func() error {
- for _, step := range r.steps {
- err := step.Run()
- if err != nil {
- return err
- }
- }
- return nil
- }, r.options...)
-}
-
-func (r *Retried) Cleanup() error {
- var errAll *multierror.Error
- for i := len(r.steps) - 1; i >= 0; i-- {
- err := r.steps[i].Cleanup()
- errAll = multierror.Append(errAll, err)
- }
- return errAll.ErrorOrNil()
-}
-
-func Retry(steps ...Step) *Retried {
- return &Retried{steps: steps}
-}
-
-func (r *Retried) WithRetryOptions(options ...Option) *Retried {
- r.options = options
- return r
-}
-
-const retryAttemptsCount = 120
-const retryDelay = 1 * time.Second
-
-type Option = retry.Option
-
-var Attempts = retry.Attempts
-var Delay = retry.Delay
-var DelayType = retry.DelayType
-var OnRetry = retry.OnRetry
-var FixedDelay = retry.FixedDelay
-var BackOffDelay = retry.BackOffDelay
-
-var defaultOpts = []retry.Option{
- Attempts(retryAttemptsCount),
- Delay(retryDelay),
- DelayType(FixedDelay),
-}
-
-func Do(fn retry.RetryableFunc, opts ...retry.Option) error {
- allOpts := append(defaultOpts, opts...)
- return retry.Do(fn, allOpts...)
-}
diff --git a/tests/serverless/internal/executor/runner.go b/tests/serverless/internal/executor/runner.go
deleted file mode 100644
index 82fa7f4ef..000000000
--- a/tests/serverless/internal/executor/runner.go
+++ /dev/null
@@ -1,97 +0,0 @@
-package executor
-
-import (
- "github.com/hashicorp/errwrap"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
-)
-
-// Runner executes Steps in safe manner
-type Runner struct {
- log *logrus.Logger
- cleanup CleanupMode
-}
-
-type RunnerOption func(runner *Runner)
-
-func WithCleanupDefault(mode CleanupMode) RunnerOption {
- return func(runner *Runner) {
- runner.cleanup = mode
- }
-}
-
-func WithLogger(logger *logrus.Logger) RunnerOption {
- return func(runner *Runner) {
- runner.log = logger
- }
-}
-
-// NewRunner returns new runner
-func NewRunner(opts ...RunnerOption) *Runner {
- log := logrus.New()
- log.SetReportCaller(false)
-
- runner := &Runner{
- log: log,
- cleanup: CleanupModeYes,
- }
- for _, opt := range opts {
- opt(runner)
- }
-
- return runner
-}
-
-// Run executes Steps in specified order. If skipCleanup is false it also executes Step.Cleanup in reverse order
-// starting from last executed step
-func (r *Runner) Run(step Step, skipCleanup bool) error {
- var err error
-
- defer func() {
- if !skipCleanup {
- if err = step.Cleanup(); err != nil {
- r.log.Error("while executing clean up", err)
- }
- }
- }()
- err = step.Run()
- if err == nil {
- return nil
- }
- callbackErr := step.OnError()
- if callbackErr != nil {
- r.log.Errorf("while executing on Error for step: %s, error: %s", step.Name(), err.Error())
- }
- return err
-}
-
-// runStep allows to recover in case of panic in step
-func (r *Runner) runStep(step Step) (err error) {
- defer func() {
- if e := recover(); e != nil {
- err = errors.WithStack(e.(error))
- }
- }()
- return step.Run()
-}
-
-// Cleanup cleans up given steps in reverse order
-func (r *Runner) Cleanup(steps []Step) {
- for i := len(steps) - 1; i >= 0; i-- {
- r.log.Infof("Cleanup: '%s'", steps[i].Name())
- if err := steps[i].Cleanup(); err != nil && !isNotFound(err) {
- r.log.Warnf("Error during '%s' cleanup: %s", steps[i].Name(), err)
- }
- }
-}
-
-func isNotFound(err error) bool {
- isNotFound := true
- errwrap.Walk(err, func(e error) {
- if isNotFound && !k8serrors.IsNotFound(e) {
- isNotFound = false
- }
- })
- return isNotFound
-}
diff --git a/tests/serverless/internal/executor/serial.go b/tests/serverless/internal/executor/serial.go
deleted file mode 100644
index ce7fb7571..000000000
--- a/tests/serverless/internal/executor/serial.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package executor
-
-import (
- "fmt"
- "strings"
-
- "github.com/hashicorp/go-multierror"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-type SerialRunner struct {
- steps []Step
- lastStepIdx int
- name string
- log *logrus.Entry
-}
-
-func NewSerialTestRunner(log *logrus.Entry, name string, steps ...Step) *SerialRunner {
- return &SerialRunner{log: log, steps: steps, name: name}
-}
-
-func (s SerialRunner) Name() string {
- builder := strings.Builder{}
- builder.WriteString(fmt.Sprintf("%s, Steps: ", s.name))
- for i, v := range s.steps {
- builder.WriteString(fmt.Sprintf("%d:%s", i, v.Name()))
- if len(s.steps) != i+1 {
- builder.WriteString(", ")
- }
- }
- builder.WriteString(".")
- return builder.String()
-}
-
-func (s *SerialRunner) Run() error {
- for i, serialStep := range s.steps {
- s.log.Infof("Running Step %d: %s", i, serialStep.Name())
- if err := serialStep.Run(); err != nil {
- s.log.Errorf("Error in %s, error: %s", serialStep.Name(), err.Error())
- if callBackErr := s.stepsOnError(i); callBackErr != nil {
- s.log.Errorf("while executing OnError on %s,, err: %s", serialStep.Name(), callBackErr.Error())
- }
- s.lastStepIdx = i
- return errors.Wrapf(err, "while executing step: %s", serialStep.Name())
- }
- }
- s.lastStepIdx = len(s.steps) - 1
- return nil
-}
-
-func (s SerialRunner) stepsOnError(stepIdx int) error {
- var errAll *multierror.Error
-
- for i := stepIdx; i >= 0; i-- {
- err := s.steps[i].OnError()
- if err != nil {
- errAll = multierror.Append(errAll, err)
- }
- }
- return errAll.ErrorOrNil()
-}
-
-func (s SerialRunner) Cleanup() error {
- for i := s.lastStepIdx; i >= 0; i-- {
- serialStep := s.steps[i]
- s.log.Infof("Cleanup Serial Step: %s", serialStep.Name())
- if err := serialStep.Cleanup(); err != nil {
- s.log.Errorf("while clean up step: %s, error: %s", serialStep.Name(), err.Error())
- }
- }
- return nil
-}
-
-func (s SerialRunner) OnError() error {
- return nil
-}
-
-var _ Step = &SerialRunner{}
diff --git a/tests/serverless/internal/executor/serial_test.go b/tests/serverless/internal/executor/serial_test.go
deleted file mode 100644
index eec74c1b8..000000000
--- a/tests/serverless/internal/executor/serial_test.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package executor_test
-
-import (
- "errors"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "testing"
-
- "github.com/onsi/gomega"
- "github.com/sirupsen/logrus/hooks/test"
-)
-
-func TestSerialTestRunner(t *testing.T) {
- //GIVEN
- g := gomega.NewWithT(t)
- logger, hook := test.NewNullLogger()
- logf := logger.WithField("Test", "Test")
- idx := 0
-
- steps := executor.NewSerialTestRunner(logf, "Test Serial Runner",
- testStep{name: "step 1", counter: &idx, logf: logf},
- testStep{name: "step 2", counter: &idx, logf: logf},
- testStep{name: "step 3", counter: &idx, logf: logf},
- testStep{name: "step 4", err: errors.New("Error Attention"), counter: &idx, logf: logf},
- testStep{name: "step 3", counter: &idx, logf: logf},
- )
- runner := executor.NewRunner(executor.WithCleanupDefault(executor.CleanupModeYes), executor.WithLogger(logger))
-
- //WHEN
- err := runner.Execute(steps)
-
- //THEN
- g.Expect(err).ToNot(gomega.BeNil())
- g.Expect(err.Error()).To(gomega.ContainSubstring("while executing step: step 4"))
- g.Expect(idx).To(gomega.Equal(4))
-
- errLog := getLogsContains(hook.AllEntries(), "Called on Error")
- g.Expect(len(errLog)).To(gomega.Equal(4))
- g.Expect(errLog[0].Message).To(gomega.Equal("Called on Error, resource: step 4"))
- g.Expect(errLog[1].Message).To(gomega.Equal("Called on Error, resource: step 3"))
- g.Expect(errLog[2].Message).To(gomega.Equal("Called on Error, resource: step 2"))
- g.Expect(errLog[3].Message).To(gomega.Equal("Called on Error, resource: step 1"))
-
- hook.Reset()
-}
diff --git a/tests/serverless/internal/executor/step.go b/tests/serverless/internal/executor/step.go
deleted file mode 100644
index 522e19fb5..000000000
--- a/tests/serverless/internal/executor/step.go
+++ /dev/null
@@ -1,13 +0,0 @@
-package executor
-
-// Step represents a single action in test scenario
-type Step interface {
- // Name returns Name of the step
- Name() string
- // Run executes the step
- Run() error
- // Cleanup removes all resources that may possibly created by the step
- Cleanup() error
- // OnError is callback in case of error
- OnError() error
-}
diff --git a/tests/serverless/internal/resources/app/app.go b/tests/serverless/internal/resources/app/app.go
deleted file mode 100644
index 516f63ea3..000000000
--- a/tests/serverless/internal/resources/app/app.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package app
-
-import (
- "context"
- "github.com/hashicorp/go-multierror"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- appsCli "k8s.io/client-go/kubernetes/typed/apps/v1"
- coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
-)
-
-var _ executor.Step = &Application{}
-
-/*
-Application consist of deployment and service
-*/
-type Application struct {
- deployment Deployment
- svc Service
- name string
- stepName string
- namespace string
- log *logrus.Entry
- port int32
- image string
-}
-
-func NewApplication(stepName, name string, image string, port int32, appCli appsCli.DeploymentInterface, coreCli coreclient.ServiceInterface, c utils.Container) executor.Step {
- return &Application{
- deployment: NewDeployment(name, c.Namespace, image, port, appCli, c.Log),
- svc: NewService(name, c.Namespace, port, coreCli, c.Log),
- name: name,
- stepName: stepName,
- namespace: c.Namespace,
- log: c.Log,
- port: port,
- image: image,
- }
-}
-
-func (a Application) Name() string {
- return a.name
-}
-
-func (a Application) Run() error {
- err := a.deployment.Create()
- if err != nil {
- return errors.Wrap(err, "while creating deployment for application")
- }
- err = a.svc.Create()
- if err != nil {
- return errors.Wrap(err, "while creating service for application ")
- }
- return nil
-}
-
-func (a Application) Cleanup() error {
- ctx := context.Background()
- deploymentErr := a.deployment.Delete(ctx, metav1.DeleteOptions{})
- svcErr := a.svc.Delete(ctx, metav1.DeleteOptions{})
- err := multierror.Append(deploymentErr, svcErr)
- return err.ErrorOrNil()
-}
-
-func (a Application) OnError() error {
- err := a.svc.LogResource()
- if err != nil {
- return errors.Wrap(err, "while logging application service status")
- }
-
- err = a.deployment.LogResource()
- if err != nil {
- return errors.Wrap(err, "while logging application deployment status")
- }
-
- return nil
-}
diff --git a/tests/serverless/internal/resources/app/deployment.go b/tests/serverless/internal/resources/app/deployment.go
deleted file mode 100644
index 9652e644f..000000000
--- a/tests/serverless/internal/resources/app/deployment.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package app
-
-import (
- "context"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- appsv1 "k8s.io/api/apps/v1"
- v1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
-)
-
-const (
- componentLabel = "component"
-)
-
-type Deployment struct {
- name string
- namespace string
- image string
- port int32
- appsCli appsclient.DeploymentInterface
- log *logrus.Entry
-}
-
-func NewDeployment(name, namespace, image string, port int32, apps appsclient.DeploymentInterface, log *logrus.Entry) Deployment {
- return Deployment{
- name: name,
- namespace: namespace,
- image: image,
- port: port,
- appsCli: apps,
- log: log,
- }
-}
-
-func (d Deployment) Create() error {
- rs := int32(1)
- deployment := &appsv1.Deployment{
- ObjectMeta: metav1.ObjectMeta{
- Name: d.name,
- Labels: map[string]string{
- componentLabel: d.name,
- },
- },
- Spec: appsv1.DeploymentSpec{
- Replicas: &rs,
- Selector: &metav1.LabelSelector{
- MatchLabels: map[string]string{
- componentLabel: d.name,
- },
- },
- Template: v1.PodTemplateSpec{
- ObjectMeta: metav1.ObjectMeta{
- Labels: map[string]string{
- componentLabel: d.name,
- },
- Annotations: map[string]string{
- "sidecar.istio.io/inject": "false",
- },
- },
- Spec: v1.PodSpec{
- Containers: []v1.Container{
- {
- Name: d.name,
- Image: d.image,
- Ports: []v1.ContainerPort{
- {ContainerPort: d.port},
- },
- ImagePullPolicy: v1.PullAlways,
- },
- },
- },
- },
- },
- }
- _, err := d.appsCli.Create(context.Background(), deployment, metav1.CreateOptions{})
- return errors.Wrapf(err, "while creating Deployment %s in namespace %s", d.name, d.namespace)
-}
-
-func (d Deployment) Delete(ctx context.Context, options metav1.DeleteOptions) error {
- return d.appsCli.Delete(ctx, d.name, options)
-}
-
-func (d Deployment) Get(ctx context.Context, options metav1.GetOptions) (*appsv1.Deployment, error) {
- deployment, err := d.appsCli.Get(ctx, d.name, options)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting deployment %s in namespace %s", d.name, d.namespace)
- }
- return deployment, nil
-}
-func (d Deployment) LogResource() error {
- deployment, err := d.Get(context.TODO(), metav1.GetOptions{})
- if err != nil {
- return errors.Wrap(err, "while getting deployment")
- }
- out, err := utils.PrettyMarshall(deployment)
- if err != nil {
- return errors.Wrap(err, "while marshalling deployment")
- }
- d.log.Info(out)
- return nil
-}
diff --git a/tests/serverless/internal/resources/app/service.go b/tests/serverless/internal/resources/app/service.go
deleted file mode 100644
index 3af650ead..000000000
--- a/tests/serverless/internal/resources/app/service.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package app
-
-import (
- "context"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/intstr"
- coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
-)
-
-type Service struct {
- name string
- namespace string
- image string
- port int32
- coreCli coreclient.ServiceInterface
- log *logrus.Entry
-}
-
-func NewService(name, namespace string, port int32, coreCli coreclient.ServiceInterface, log *logrus.Entry) Service {
- return Service{
- name: name,
- namespace: namespace,
- port: port,
- coreCli: coreCli,
- log: log,
- }
-}
-
-func (s Service) Create() error {
- service := &corev1.Service{
- ObjectMeta: metav1.ObjectMeta{
- Name: s.name,
- },
- Spec: corev1.ServiceSpec{
- Type: "ClusterIP",
- Ports: []corev1.ServicePort{
- {
- Name: s.name,
- Port: s.port,
- Protocol: "TCP",
- TargetPort: intstr.FromInt(int(s.port)),
- },
- },
- Selector: map[string]string{
- componentLabel: s.name,
- },
- },
- }
-
- _, err := s.coreCli.Create(context.Background(), service, metav1.CreateOptions{})
- return errors.Wrapf(err, "while creating service %s in namespace %s", s.name, s.namespace)
-}
-
-func (s Service) Delete(ctx context.Context, options metav1.DeleteOptions) error {
- return s.coreCli.Delete(ctx, s.name, options)
-}
-
-func (s Service) Get(ctx context.Context, options metav1.GetOptions) (*corev1.Service, error) {
- svc, err := s.coreCli.Get(ctx, s.name, options)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting service %s in namespace %s", s.name, s.namespace)
- }
- return svc, nil
-}
-func (s Service) LogResource() error {
- svc, err := s.Get(context.TODO(), metav1.GetOptions{})
- if err != nil {
- return errors.Wrap(err, "while getting service")
- }
- out, err := utils.PrettyMarshall(svc)
- if err != nil {
- return errors.Wrap(err, "while marshalling service")
- }
- s.log.Info(out)
- return nil
-}
diff --git a/tests/serverless/internal/resources/configmap/configmap.go b/tests/serverless/internal/resources/configmap/configmap.go
deleted file mode 100644
index d3f3da415..000000000
--- a/tests/serverless/internal/resources/configmap/configmap.go
+++ /dev/null
@@ -1,85 +0,0 @@
-package configmap
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/resources"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "k8s.io/apimachinery/pkg/runtime"
-
- "github.com/sirupsen/logrus"
-
- "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-type ConfigMap struct {
- resCli *resources.Resource
- name string
- namespace string
- log *logrus.Entry
-}
-
-func NewConfigMap(name string, c utils.Container) *ConfigMap {
- return &ConfigMap{
- resCli: resources.New(c.DynamicCli, corev1.SchemeGroupVersion.WithResource("configmaps"), c.Namespace, c.Log, c.Verbose),
- name: name,
- namespace: c.Namespace,
- log: c.Log,
- }
-}
-
-func (c *ConfigMap) Name() string {
- return c.name
-}
-
-func (c *ConfigMap) Create(data map[string]string) error {
- cm := &corev1.ConfigMap{
- ObjectMeta: metav1.ObjectMeta{
- Name: c.name,
- Namespace: c.namespace,
- },
- Data: data,
- }
-
- _, err := c.resCli.Create(cm)
- if err != nil {
- return errors.Wrapf(err, "while creating ConfigMap %s in namespace %s", c.name, c.namespace)
- }
- return err
-}
-
-func (c *ConfigMap) Delete() error {
- err := c.resCli.Delete(c.name)
- if err != nil {
- return errors.Wrapf(err, "while deleting ConfigMap %s in namespace %s", c.name, c.namespace)
- }
-
- return nil
-}
-
-func (c *ConfigMap) Get() (*corev1.ConfigMap, error) {
- u, err := c.resCli.Get(c.name)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting ConfigMap %s in namespace %s", c.name, c.namespace)
- }
- cm := corev1.ConfigMap{}
- if err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &cm); err != nil {
- return nil, errors.Wrap(err, "while constructing ConfigMap from unstructured")
- }
-
- return &cm, nil
-}
-func (c *ConfigMap) LogResource() error {
- cm, err := c.Get()
- if err != nil {
- return errors.Wrap(err, "while getting ConfigMap")
- }
-
- out, err := utils.PrettyMarshall(cm)
- if err != nil {
- return err
- }
-
- c.log.Infof("ConfigMap: %s", out)
- return nil
-}
diff --git a/tests/serverless/internal/resources/configmap/step.go b/tests/serverless/internal/resources/configmap/step.go
deleted file mode 100644
index 225a7f4a7..000000000
--- a/tests/serverless/internal/resources/configmap/step.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package configmap
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-type ConfigMaps struct {
- name string
- configMap *ConfigMap
- data map[string]string
- log *logrus.Entry
-}
-
-func CreateConfigMap(log *logrus.Entry, cm *ConfigMap, stepName string, data map[string]string) executor.Step {
- return &ConfigMaps{
- name: stepName,
- data: data,
- log: log.WithField(executor.LogStepKey, stepName),
- configMap: cm,
- }
-}
-
-func (c ConfigMaps) Name() string {
- return c.name
-}
-
-func (c ConfigMaps) Run() error {
- return errors.Wrap(c.configMap.Create(c.data), "while creating configmap")
-}
-
-func (c ConfigMaps) Cleanup() error {
- return errors.Wrap(c.configMap.Delete(), "while deleting configmap")
-}
-
-func (c ConfigMaps) OnError() error {
- return c.configMap.LogResource()
-}
-
-var _ executor.Step = ConfigMaps{}
diff --git a/tests/serverless/internal/resources/function/function.go b/tests/serverless/internal/resources/function/function.go
deleted file mode 100644
index 5f45b4ad5..000000000
--- a/tests/serverless/internal/resources/function/function.go
+++ /dev/null
@@ -1,200 +0,0 @@
-package function
-
-import (
- "context"
- "fmt"
- "net/url"
- "time"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/watch"
-)
-
-type Function struct {
- resCli *resources.Resource
- function *serverlessv1alpha2.Function
- FunctionURL *url.URL
- waitTimeout time.Duration
- log *logrus.Entry
- verbose bool
-}
-
-func NewFunction(name, namespace string, proxyEnabled bool, c utils.Container) *Function {
- function := &serverlessv1alpha2.Function{
- TypeMeta: metav1.TypeMeta{
- Kind: serverlessv1alpha2.FunctionKind,
- APIVersion: serverlessv1alpha2.GroupVersion.String(),
- },
- ObjectMeta: metav1.ObjectMeta{
- Name: name,
- Namespace: namespace,
- },
- }
-
- fnURL, err := utils.GetSvcURL(name, namespace, proxyEnabled)
- if err != nil {
- panic(err)
- }
-
- return &Function{
- resCli: resources.New(c.DynamicCli, serverlessv1alpha2.GroupVersion.WithResource("functions"), namespace, c.Log, c.Verbose),
- waitTimeout: c.WaitTimeout,
- log: c.Log,
- verbose: c.Verbose,
- function: function,
- FunctionURL: fnURL,
- }
-}
-
-func (f *Function) Create(spec serverlessv1alpha2.FunctionSpec) error {
- f.function.Spec = spec
- _, err := f.resCli.Create(f.function)
- if err != nil {
- return errors.Wrapf(err, "while creating %s", f.toString())
- }
- return err
-}
-
-func (f *Function) WaitForStatusRunning() error {
- fn, err := f.Get()
- if err != nil {
- return err
- }
-
- if f.isConditionReady(*fn) {
- return nil
- }
-
- ctx, cancel := context.WithTimeout(context.Background(), f.waitTimeout)
- defer cancel()
- condition := f.isFunctionReady()
- err = resources.WaitUntilConditionSatisfied(ctx, f.resCli.ResCli, condition)
- if err == nil {
- return nil
- }
- return err
-}
-
-func (f *Function) Delete() error {
- err := f.resCli.Delete(f.function.Name)
- if err != nil {
- return errors.Wrapf(err, "while deleting %s", f.toString())
- }
-
- return nil
-}
-
-func (f *Function) Update(spec serverlessv1alpha2.FunctionSpec) error {
- err := utils.RetryOnConflict(utils.DefaultRetry, func() error {
- // correct update must first perform get
- fn, err := f.Get()
- if err != nil {
- // RetryOnConflict doesn't work with wrapped errors
- // https://github.com/kubernetes/client-go/blob/9927afa2880713c4332723b7f0865adee5e63a7b/util/retry/util.go#L89-L93
- return err
- }
-
- fnCopy := fn.DeepCopy()
- fnCopy.Spec = spec
-
- _, err = f.resCli.Update(fnCopy)
- // RetryOnConflict doesn't work with wrapped errors
- // https://github.com/kubernetes/client-go/blob/9927afa2880713c4332723b7f0865adee5e63a7b/util/retry/util.go#L89-L93
- return err
- }, f.log)
- return errors.Wrapf(err, "while updating %s", f.toString())
-}
-
-func (f *Function) Get() (*serverlessv1alpha2.Function, error) {
- u, err := f.resCli.Get(f.function.Name)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting %s", f.toString())
- }
-
- function, err := convertFromUnstructuredToFunction(u)
- if err != nil {
- return nil, err
- }
-
- return &function, nil
-}
-
-func (f Function) LogResource() error {
- fn, err := f.Get()
- if err != nil {
- return err
- }
-
- out, err := utils.PrettyMarshall(fn)
- if err != nil {
- return err
- }
-
- f.log.Infof("%s", out)
- return nil
-}
-
-func (f *Function) isFunctionReady() func(event watch.Event) (bool, error) {
- return func(event watch.Event) (bool, error) {
- if event.Type != watch.Modified {
- return false, nil
- }
-
- function, err := f.Get()
-
- if err != nil {
- return false, err
- }
- return f.isConditionReady(*function), nil
- }
-}
-
-func (f Function) isConditionReady(fn serverlessv1alpha2.Function) bool {
- conditions := fn.Status.Conditions
- if len(conditions) == 0 {
- f.logReadiness(false)
- return false
- }
-
- var ready bool
- for i := range conditions {
- condition := conditions[i]
- if condition.Type == serverlessv1alpha2.ConditionRunning {
- ready = (condition.Status == corev1.ConditionTrue)
- }
- }
-
- f.logReadiness(ready)
-
- return ready
-}
-
-func convertFromUnstructuredToFunction(u *unstructured.Unstructured) (serverlessv1alpha2.Function, error) {
- fn := serverlessv1alpha2.Function{}
- err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &fn)
- return fn, err
-}
-
-func (f Function) toString() string {
- return fmt.Sprintf("Function %s in namespace %s", f.function.Name, f.function.Namespace)
-}
-
-func (f Function) logReadiness(ready bool) {
- if ready {
- f.log.Debugf("%s is ready", f.toString())
- } else {
- f.log.Debugf("%s is not ready", f.toString())
- }
-
- if f.verbose {
- f.log.Infof("%+v", f.function)
- }
-}
diff --git a/tests/serverless/internal/resources/function/steps.go b/tests/serverless/internal/resources/function/steps.go
deleted file mode 100644
index 80530af57..000000000
--- a/tests/serverless/internal/resources/function/steps.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package function
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-type newFunction struct {
- name string
- spec serverlessv1alpha2.FunctionSpec
- fn *Function
- log *logrus.Entry
-}
-
-func CreateFunction(log *logrus.Entry, fn *Function, name string, spec serverlessv1alpha2.FunctionSpec) executor.Step {
- return newFunction{
- fn: fn,
- name: name,
- spec: spec,
- log: log.WithField(executor.LogStepKey, name),
- }
-}
-
-func (f newFunction) Name() string {
- return f.name
-}
-
-func (f newFunction) Run() error {
- if err := f.fn.Create(f.spec); err != nil {
- return errors.Wrapf(err, "while creating function: %s", f.name)
- }
-
- f.log.Infof("Function Created, Waiting for ready status")
- return errors.Wrapf(f.fn.WaitForStatusRunning(), "while waiting for function: %s, to be ready:", f.fn.function.GetName())
-}
-
-func (f newFunction) Cleanup() error {
- return errors.Wrapf(f.fn.Delete(), "while deleting function: %s", f.name)
-}
-
-func (f newFunction) OnError() error {
- return f.fn.LogResource()
-}
-
-var _ executor.Step = newFunction{}
-
-type updateFunc struct {
- name string
- fn *Function
- spec serverlessv1alpha2.FunctionSpec
- log *logrus.Entry
-}
-
-func UpdateFunction(log *logrus.Entry, fn *Function, name string, spec serverlessv1alpha2.FunctionSpec) executor.Step {
- return updateFunc{
- fn: fn,
- spec: spec,
- name: name,
- log: log.WithField(executor.LogStepKey, name),
- }
-}
-
-func (u updateFunc) Name() string {
- return u.name
-}
-
-func (u updateFunc) Run() error {
- if err := u.fn.Update(u.spec); err != nil {
- return errors.Wrapf(err, "while updating function: %s", u.name)
- }
-
- return errors.Wrapf(u.fn.WaitForStatusRunning(), "while waiting for status ready function: %s", u.name)
-}
-
-func (u updateFunc) Cleanup() error {
- return nil
-}
-
-func (u updateFunc) OnError() error {
- return nil
-}
-
-var _ executor.Step = updateFunc{}
diff --git a/tests/serverless/internal/resources/git/client.go b/tests/serverless/internal/resources/git/client.go
deleted file mode 100644
index ed7794643..000000000
--- a/tests/serverless/internal/resources/git/client.go
+++ /dev/null
@@ -1,137 +0,0 @@
-package git
-
-import (
- "io"
- "strings"
- "time"
-
- "github.com/go-git/go-billy/v5"
- "github.com/go-git/go-billy/v5/memfs"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing/object"
- "github.com/go-git/go-git/v5/storage/memory"
- "github.com/pkg/errors"
-)
-
-type Client struct {
- url string
-}
-
-func NewGitClient(repoURL string) Client {
- return Client{
- url: repoURL,
- }
-}
-
-func (c Client) TryCloning() error {
- _, _, err := c.cloneToMemory()
- return err
-}
-
-func (c Client) PullRemote(filePath string) (string, error) {
- _, fs, err := c.cloneToMemory()
- if err != nil {
- return "", errors.Wrap(err, "while cloning repository")
- }
-
- return c.readFileContent(fs, filePath)
-}
-
-func (c Client) ReplaceInRemoteFile(filePath, oldValue, newValue string) error {
- r, fs, err := c.cloneToMemory()
- if err != nil {
- return err
- }
-
- content, err := c.readFileContent(fs, filePath)
- if err != nil {
- return err
- }
- newContent := strings.Replace(content, oldValue, newValue, -1)
-
- err = c.replaceFileContent(fs, filePath, newContent)
- if err != nil {
- return err
- }
-
- err = c.commitAndPush(r, filePath)
- if err != nil {
- return err
- }
-
- return nil
-}
-
-func (c Client) cloneToMemory() (*git.Repository, billy.Filesystem, error) {
- fs := memfs.New()
- storer := memory.NewStorage()
-
- r, err := git.Clone(storer, fs, &git.CloneOptions{
- URL: c.url,
- })
- if err != nil {
- return nil, nil, errors.Wrap(err, "while cloning repository")
- }
-
- return r, fs, nil
-}
-
-func (c Client) readFileContent(fs billy.Filesystem, filePath string) (string, error) {
- file, err := fs.Open(filePath)
- if err != nil {
- return "", errors.Wrap(err, "while opening file from memory")
- }
- defer file.Close()
-
- content, err := io.ReadAll(file)
- if err != nil {
- return "", errors.Wrap(err, "while reading file")
- }
-
- return string(content), nil
-}
-
-func (c Client) replaceFileContent(fs billy.Filesystem, filePath, newContent string) error {
- file, err := fs.Create(filePath)
- if err != nil {
- return errors.Wrap(err, "while creating file in memory")
- }
-
- _, err = file.Write([]byte(newContent))
- if err != nil {
- return errors.Wrap(err, "while writing new content to file in memory")
- }
-
- return nil
-}
-
-func (c Client) commitAndPush(repository *git.Repository, filePath string) error {
- w, err := repository.Worktree()
- if err != nil {
- return errors.Wrap(err, "while accessing repository worktree")
- }
-
- _, err = w.Add(filePath)
- if err != nil {
- return errors.Wrap(err, "while adding modified file to the staging area")
- }
-
- _, err = w.Commit("Replace values", &git.CommitOptions{
- All: false,
- Author: &object.Signature{
- Name: "Chewbacca",
- Email: "chewbacca@kashyyyk.sw",
- When: time.Time{},
- },
- })
- if err != nil {
- return errors.Wrap(err, "while committing changes")
- }
-
- err = repository.Push(&git.PushOptions{})
- if err != nil {
- return errors.Wrap(err, "while pushing changes")
- }
-
- return nil
-}
diff --git a/tests/serverless/internal/resources/git/commitchanges.go b/tests/serverless/internal/resources/git/commitchanges.go
deleted file mode 100644
index e6a104cac..000000000
--- a/tests/serverless/internal/resources/git/commitchanges.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package git
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-const (
- filePath = "handler.js"
- oldValue = "GITOPS 1"
- newValue = "GITOPS 2"
-)
-
-type commitChanges struct {
- name string
- gitClient Client
- log *logrus.Entry
-}
-
-var _ executor.Step = commitChanges{}
-
-func NewCommitChanges(log *logrus.Entry, stepName, repoURL string) executor.Step {
- return commitChanges{
- name: stepName,
- gitClient: NewGitClient(repoURL),
- log: log.WithField(executor.LogStepKey, stepName),
- }
-}
-
-func (c commitChanges) Name() string {
- return c.name
-}
-
-func (c commitChanges) Run() error {
- err := c.gitClient.ReplaceInRemoteFile(filePath, oldValue, newValue)
- return errors.Wrap(err, "while replacing file content in git repository")
-}
-
-func (c commitChanges) OnError() error {
- out, err := c.gitClient.PullRemote(filePath)
- if err != nil {
- return errors.Wrap(err, "while pulling from remote repository")
- }
- c.log.Infof("Code from git repository: %s", out)
- return nil
-}
-
-func (c commitChanges) Cleanup() error {
- return nil
-}
diff --git a/tests/serverless/internal/resources/git/git_cfg.go b/tests/serverless/internal/resources/git/git_cfg.go
deleted file mode 100644
index 24e517488..000000000
--- a/tests/serverless/internal/resources/git/git_cfg.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package git
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-)
-
-type GitopsConfig struct {
- FnName string
- RepoName string
- GitServerImage string
- GitServerServiceName string
- GitServerServicePort int32
- GitServerRepoName string
- Toolbox utils.Container
-}
-
-const (
- gitServerServiceName = "gitserver"
- gitServerServicePort int32 = 80
-)
-
-func NewGitopsConfig(fnName, gitServerImage, gitServerRepoName string, toolbox utils.Container) (GitopsConfig, error) {
- return GitopsConfig{
- FnName: fnName,
- GitServerImage: gitServerImage,
- GitServerServicePort: gitServerServicePort,
- GitServerServiceName: gitServerServiceName,
- GitServerRepoName: gitServerRepoName,
- Toolbox: toolbox,
- }, nil
-}
-
-func (c *GitopsConfig) GetGitServerURL(useProxy bool) string {
- gitURL, err := utils.GetGitURL(c.GitServerServiceName, c.Toolbox.Namespace, c.GitServerRepoName, useProxy)
- if err != nil {
- panic(err)
- }
- return gitURL.String()
-}
-
-func (c *GitopsConfig) GetGitServerInClusterURL() string {
- return c.GetGitServerURL(false)
-
-}
diff --git a/tests/serverless/internal/resources/git/gitserver.go b/tests/serverless/internal/resources/git/gitserver.go
deleted file mode 100644
index aa29a81d2..000000000
--- a/tests/serverless/internal/resources/git/gitserver.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package git
-
-import (
- "context"
- "fmt"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/app"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/runtime/schema"
-
- "github.com/hashicorp/go-multierror"
- "github.com/sirupsen/logrus"
-
- "github.com/pkg/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- appsclient "k8s.io/client-go/kubernetes/typed/apps/v1"
- coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
-)
-
-type GitServer struct {
- deployment app.Deployment
- services app.Service
- resCli *resources.Resource
- istioEnabled bool
- name string
- namespace string
- image string
- port int32
- log *logrus.Entry
-}
-
-func New(c utils.Container, name string, image string, port int32, deployments appsclient.DeploymentInterface, services coreclient.ServiceInterface, istioEnabled bool) *GitServer {
- return &GitServer{
- deployment: app.NewDeployment(name, c.Namespace, image, port, deployments, c.Log),
- services: app.NewService(name, c.Namespace, port, services, c.Log),
- resCli: resources.New(c.DynamicCli, schema.GroupVersionResource{
- Group: "networking.istio.io",
- Version: "v1alpha3",
- Resource: "destinationrules"}, c.Namespace, c.Log, c.Verbose),
- name: name,
- image: image,
- port: port,
- namespace: c.Namespace,
- log: c.Log,
- istioEnabled: istioEnabled,
- }
-}
-
-func (gs *GitServer) Create() error {
- err := gs.deployment.Create()
- if err != nil {
- return err
- }
-
- err = gs.services.Create()
- if err != nil {
- return err
- }
-
- if gs.istioEnabled {
- return gs.createDestinationRule()
- }
- return nil
-}
-
-func (gs *GitServer) createDestinationRule() error {
- destRule := unstructured.Unstructured{
- Object: map[string]interface{}{
- "apiVersion": "networking.istio.io/v1alpha3",
- "kind": "DestinationRule",
- "metadata": map[string]interface{}{
- "name": gs.name,
- "namespace": gs.namespace,
- },
- "spec": map[string]interface{}{
- "host": fmt.Sprintf("%s.%s.svc.cluster.local", gs.name, gs.namespace),
- "trafficPolicy": map[string]interface{}{
- "tls": map[string]interface{}{
- "mode": "DISABLE",
- },
- },
- },
- },
- }
-
- _, err := gs.resCli.Create(&destRule)
- return errors.Wrapf(err, "while creating DestinationRule %s in namespace %s", gs.name, gs.namespace)
-}
-
-func (gs *GitServer) Delete() error {
- var errDestRule error = nil
- if gs.istioEnabled {
- errDestRule = gs.resCli.Delete(gs.name)
- }
-
- errService := gs.services.Delete(context.Background(), metav1.DeleteOptions{})
- errDeployment := gs.deployment.Delete(context.Background(), metav1.DeleteOptions{})
- err := multierror.Append(errDeployment, errService, errDestRule)
- return err.ErrorOrNil()
-}
-
-func (gs *GitServer) LogResource() error {
- if gs.istioEnabled {
- obj, err := gs.resCli.Get(gs.name)
- if err != nil {
- return errors.Wrap(err, "while getting destination rule")
- }
- out, err := utils.PrettyMarshall(obj)
- if err != nil {
- return errors.Wrap(err, "while marshalling destination rule")
- }
- gs.log.Info(out)
- }
-
- err := gs.services.LogResource()
- if err != nil {
- return errors.Wrap(err, "while logging service status")
- }
-
- err = gs.deployment.LogResource()
- if err != nil {
- return errors.Wrap(err, "while logging deployment status")
- }
-
- return nil
-}
diff --git a/tests/serverless/internal/resources/git/step.go b/tests/serverless/internal/resources/git/step.go
deleted file mode 100644
index 78820b654..000000000
--- a/tests/serverless/internal/resources/git/step.go
+++ /dev/null
@@ -1,58 +0,0 @@
-package git
-
-import (
- "github.com/avast/retry-go"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- appsCli "k8s.io/client-go/kubernetes/typed/apps/v1"
- coreclient "k8s.io/client-go/kubernetes/typed/core/v1"
-)
-
-type newGitServer struct {
- name string
- gs *GitServer
- gitClient Client
- log *logrus.Entry
-}
-
-var _ executor.Step = newGitServer{}
-
-func NewGitServer(cfg GitopsConfig, stepName string, deployments appsCli.DeploymentInterface, services coreclient.ServiceInterface, useProxy, istioEnabled bool) executor.Step {
- repoURL, err := utils.GetGitURL(cfg.GitServerServiceName, cfg.Toolbox.Namespace, cfg.GitServerRepoName, useProxy)
- if err != nil {
- panic(err)
- }
- return newGitServer{
- name: stepName,
- gs: New(cfg.Toolbox, cfg.GitServerServiceName, cfg.GitServerImage, cfg.GitServerServicePort, deployments, services, istioEnabled),
- gitClient: NewGitClient(repoURL.String()),
- log: cfg.Toolbox.Log.WithField(executor.LogStepKey, stepName),
- }
-}
-
-func (r newGitServer) Name() string {
- return r.name
-}
-
-func (r newGitServer) Run() error {
- err := r.gs.Create()
- if err != nil {
- return errors.Wrap(err, "while creating in-cluster Git server")
- }
-
- err = retry.Do(r.gitClient.TryCloning)
- if err != nil {
- return errors.Wrap(err, "while waiting for in-cluster Git Server to be ready")
- }
- return nil
-}
-
-func (r newGitServer) Cleanup() error {
- return errors.Wrap(r.gs.Delete(), "while deleting in-cluster Git server")
-}
-
-func (r newGitServer) OnError() error {
- return r.gs.LogResource()
-}
diff --git a/tests/serverless/internal/resources/namespace/namespace.go b/tests/serverless/internal/resources/namespace/namespace.go
deleted file mode 100644
index cc5bbfcd8..000000000
--- a/tests/serverless/internal/resources/namespace/namespace.go
+++ /dev/null
@@ -1,95 +0,0 @@
-package namespace
-
-import (
- "context"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "time"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- corev1 "k8s.io/api/core/v1"
- apierrors "k8s.io/apimachinery/pkg/api/errors"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/util/wait"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- k8sretry "k8s.io/client-go/util/retry"
-)
-
-const (
- TestNamespaceLabelKey = "created-by"
- TestNamespaceLabelValue = "serverless-controller-manager-test"
-)
-
-type Namespace struct {
- coreCli typedcorev1.CoreV1Interface
- namespace string
- log *logrus.Entry
-}
-
-func New(log *logrus.Entry, coreCli typedcorev1.CoreV1Interface, namespace string) *Namespace {
- return &Namespace{coreCli: coreCli, namespace: namespace, log: log}
-}
-
-func (n Namespace) LogResource() error {
- ns, err := n.get()
- if err != nil {
- return err
- }
- ns.TypeMeta.Kind = "namespace"
- out, err := utils.PrettyMarshall(ns)
- if err != nil {
- return err
- }
-
- n.log.Infof("%s", out)
- return nil
-}
-
-func (n Namespace) get() (*corev1.Namespace, error) {
- return n.coreCli.Namespaces().Get(context.Background(), n.namespace, metav1.GetOptions{})
-}
-
-func (n *Namespace) Create() (string, error) {
- ns := &corev1.Namespace{
- ObjectMeta: metav1.ObjectMeta{
- Name: n.namespace,
- Labels: map[string]string{
- TestNamespaceLabelKey: TestNamespaceLabelValue, // convenience for cleaning up stale namespaces during development
- },
- },
- }
-
- backoff := wait.Backoff{
- Duration: 500 * time.Millisecond,
- Factor: 2,
- Jitter: 0.1,
- Steps: 4,
- }
-
- err := k8sretry.OnError(backoff, func(err error) bool {
- return true
- }, func() error {
- _, err := n.coreCli.Namespaces().Create(context.Background(), ns, metav1.CreateOptions{})
- if apierrors.IsAlreadyExists(err) {
- return nil
- }
-
- return err
- })
- if err != nil {
- return n.namespace, errors.Wrapf(err, "while creating namespace %s", n.namespace)
- }
-
- n.log.Infof("Create: namespace %s", n.namespace)
- return n.namespace, nil
-}
-
-func (n *Namespace) Delete() error {
- err := utils.WithIgnoreOnNotFound(utils.DefaultBackoff, func() error {
- return n.coreCli.Namespaces().Delete(context.Background(), n.namespace, metav1.DeleteOptions{})
- }, n.log)
- if err != nil {
- return errors.Wrapf(err, "while deleting namespace %s", n.namespace)
- }
- return nil
-}
diff --git a/tests/serverless/internal/resources/namespace/step.go b/tests/serverless/internal/resources/namespace/step.go
deleted file mode 100644
index 0f3277f7e..000000000
--- a/tests/serverless/internal/resources/namespace/step.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package namespace
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
-)
-
-type NamespaceStep struct {
- ns *Namespace
- name string
-}
-
-func (n NamespaceStep) Name() string {
- return n.name
-}
-
-func (n NamespaceStep) Run() error {
- _, err := n.ns.Create()
- return errors.Wrap(err, "while creating namespace")
-}
-
-func (n NamespaceStep) Cleanup() error {
- return errors.Wrap(n.ns.Delete(), "while deleting namespace")
-}
-
-func (n NamespaceStep) OnError() error {
- return n.ns.LogResource()
-}
-
-func NewNamespaceStep(log *logrus.Entry, stepName, namespace string, coreCli typedcorev1.CoreV1Interface) NamespaceStep {
- ns := New(log, coreCli, namespace)
- return NamespaceStep{name: stepName, ns: ns}
-}
-
-var _ executor.Step = NamespaceStep{}
diff --git a/tests/serverless/internal/resources/resource.go b/tests/serverless/internal/resources/resource.go
deleted file mode 100644
index fda0f4dcd..000000000
--- a/tests/serverless/internal/resources/resource.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package resources
-
-import (
- "context"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
- "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
- "k8s.io/apimachinery/pkg/labels"
- "k8s.io/apimachinery/pkg/runtime"
- "k8s.io/apimachinery/pkg/runtime/schema"
- "k8s.io/apimachinery/pkg/watch"
- "k8s.io/client-go/dynamic"
-)
-
-type Resource struct {
- ResCli dynamic.ResourceInterface
- namespace string
- kind string
- verbose bool
- log *logrus.Entry
-}
-
-func New(dynamicCli dynamic.Interface, s schema.GroupVersionResource, namespace string, log *logrus.Entry, verbose bool) *Resource {
- resCli := dynamicCli.Resource(s).Namespace(namespace)
- return &Resource{ResCli: resCli, namespace: namespace, kind: s.Resource, log: log, verbose: verbose}
-}
-
-func (r *Resource) Create(res interface{}) (string, error) {
- var resourceVersion string
- u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(res)
- if err != nil {
- return resourceVersion, errors.Wrapf(err, "while converting resource %s %+v to unstructured", r.kind, res)
- }
- unstructuredObj := &unstructured.Unstructured{
- Object: u,
- }
- err = utils.OnTimeout(utils.DefaultBackoff, func() error {
- var resource *unstructured.Unstructured
-
- resource, err = r.ResCli.Create(context.Background(), unstructuredObj, metav1.CreateOptions{})
- if err != nil {
- return err
- }
- resourceVersion = resource.GetResourceVersion()
- return nil
- }, r.log)
- if err != nil {
- return resourceVersion, errors.Wrapf(err, "while creating resource %s", unstructuredObj.GetKind())
- }
-
- if r.verbose {
- r.log.Infof("[CREATE]: name %s, namespace %s, resource %v", unstructuredObj.GetName(), unstructuredObj.GetNamespace(), unstructuredObj)
- }
-
- return resourceVersion, nil
-}
-
-func (r *Resource) List(set map[string]string) (*unstructured.UnstructuredList, error) {
- var result *unstructured.UnstructuredList
-
- selector := labels.SelectorFromSet(set).String()
-
- err := utils.OnTimeout(utils.DefaultBackoff, func() error {
- var err error
- result, err = r.ResCli.List(context.Background(), metav1.ListOptions{
- LabelSelector: selector,
- })
- return err
- }, r.log)
- if err != nil {
- return nil, errors.Wrapf(err, "while listing resource %s in namespace %s", r.kind, r.namespace)
- }
- namespace := "-"
- if r.namespace != "" {
- namespace = r.namespace
- }
-
- if r.verbose {
- r.log.Infof("LIST %s: namespace:%s kind:%s\n%v", selector, namespace, r.kind, result)
- }
-
- return result, nil
-}
-
-func (r *Resource) Get(name string) (*unstructured.Unstructured, error) {
- var result *unstructured.Unstructured
- err := utils.OnTimeout(utils.DefaultBackoff, func() error {
- var err error
- result, err = r.ResCli.Get(context.Background(), name, metav1.GetOptions{})
- return err
- }, r.log)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting resource %s '%s'", r.kind, name)
- }
- namespace := "-"
- if r.namespace != "" {
- namespace = r.namespace
- }
-
- if r.verbose {
- r.log.Infof("GET name:%s: namespace:%s kind:%s\n%v", name, namespace, r.kind, result)
- }
-
- return result, nil
-}
-
-func WaitUntilConditionSatisfied(ctx context.Context, resCli dynamic.ResourceInterface, isReady func(event watch.Event) (bool, error)) error {
- watcher, err := resCli.Watch(ctx, metav1.ListOptions{})
- defer func() {
- if watcher != nil {
- watcher.Stop()
- }
- }()
- if err != nil {
-
- return err
- }
-
- for {
- select {
- case <-ctx.Done():
- return ctx.Err()
- case result := <-watcher.ResultChan():
- ready, err := isReady(result)
- if err != nil {
- return err
- }
- if ready {
- return nil
- }
- }
- }
-}
-
-func (r *Resource) Delete(name string) error {
- return utils.WithIgnoreOnNotFound(utils.DefaultBackoff, func() error {
- namespace := "-"
- if r.namespace != "" {
- namespace = r.namespace
- }
-
- if r.verbose {
- r.log.Infof("DELETE %s: namespace:%s name:%s", r.kind, namespace, name)
- }
-
- // if the DeletePropagationForeground is not enough then we'll need to somehow watch specified resource
- // and make sure that it was deleted manually
- // in the moment of writing this comment we do not have such a case in those tests
- // that's why we'll just hope DeletePropagationForeground is enough
- deletePropagationPolicy := metav1.DeletePropagationForeground
- return r.ResCli.Delete(context.Background(), name, metav1.DeleteOptions{
- PropagationPolicy: &deletePropagationPolicy,
- })
- }, r.log)
-}
-
-func (r *Resource) Update(res interface{}) (*unstructured.Unstructured, error) {
- // https://github.com/kubernetes/client-go/blob/kubernetes-1.17.4/examples/dynamic-create-update-delete-deployment/main.go#L119-L166
-
- u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(res)
- if err != nil {
- return nil, errors.Wrapf(err, "while converting resource %s %s to unstructured", r.kind, res)
- }
-
- unstructuredObj := &unstructured.Unstructured{
- Object: u,
- }
-
- var result *unstructured.Unstructured
-
- result, err = r.ResCli.Update(context.Background(), unstructuredObj, metav1.UpdateOptions{})
- if err != nil {
- // upstream caller RetryOnConflict doesn't work with wrapped errors
- // https://github.com/kubernetes/client-go/blob/9927afa2880713c4332723b7f0865adee5e63a7b/util/retry/util.go#L89-L93
- return nil, err
- }
-
- namespace := "-"
- if r.namespace != "" {
- namespace = r.namespace
- }
-
- r.log.Infof("UPDATE %s: namespace:%s kind:%s", result.GetName(), namespace, r.kind)
- if r.verbose {
- r.log.Infof("%+v", result)
- }
-
- return result, nil
-}
diff --git a/tests/serverless/internal/resources/runtimes/git_function.go b/tests/serverless/internal/resources/runtimes/git_function.go
deleted file mode 100644
index aedc0401d..000000000
--- a/tests/serverless/internal/resources/runtimes/git_function.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package runtimes
-
-import (
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-func GitopsFunction(repoURL, baseDir, reference string, rtm serverlessv1alpha2.Runtime, auth *serverlessv1alpha2.RepositoryAuth) serverlessv1alpha2.FunctionSpec {
- if baseDir == "" {
- baseDir = "/"
- }
-
- if reference == "" {
- reference = "main"
- }
-
- var minReplicas int32 = 1
- var maxReplicas int32 = 2
-
- gitRepo := &serverlessv1alpha2.GitRepositorySource{
- URL: repoURL,
- Repository: serverlessv1alpha2.Repository{
- BaseDir: baseDir,
- Reference: reference,
- },
- }
- if auth != nil {
- gitRepo.Auth = auth
- }
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- GitRepository: gitRepo,
- },
- ScaleConfig: &serverlessv1alpha2.ScaleConfig{
- MinReplicas: &minReplicas,
- MaxReplicas: &maxReplicas,
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
diff --git a/tests/serverless/internal/resources/runtimes/nodejs.go b/tests/serverless/internal/resources/runtimes/nodejs.go
deleted file mode 100644
index 817ce9d71..000000000
--- a/tests/serverless/internal/resources/runtimes/nodejs.go
+++ /dev/null
@@ -1,257 +0,0 @@
-package runtimes
-
-import (
- "fmt"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- corev1 "k8s.io/api/core/v1"
- v1 "k8s.io/api/core/v1"
-)
-
-func BasicNodeJSFunction(msg string, rtm serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: fmt.Sprintf(`module.exports = { main: function(event, context) { return "%s" } }`, msg),
- Dependencies: `{ "name": "hellobasic", "version": "0.0.1", "dependencies": {} }`,
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func BasicTracingNodeFunction(rtm serverlessv1alpha2.Runtime, externalSvcURL string) serverlessv1alpha2.FunctionSpec {
- dpd := `{
- "name": "sanitise-fn",
- "version": "0.0.1",
- "dependencies": {
- "axios":"0.26.1"
- }
-}`
- src := fmt.Sprintf(`const axios = require("axios")
-
-
-module.exports = {
- main: async function (event, context) {
- console.log("event: ", event)
- let resp = await axios("%s",{timeout: 1000});
- let interceptedHeaders = resp.request._header
- let tracingHeaders = getTracingHeaders(interceptedHeaders)
- console.log("return: ", JSON.stringify(tracingHeaders, null, 4))
- return tracingHeaders
- }
-}
-
-function getTracingHeaders(textHeaders) {
- tracingHeaders = textHeaders.split('\n')
- .filter(val => {
- let out = val.split(":")
- return out.length === 2;
- })
- .map(item => {
- let stringHeader = item.split(":")
- return {
- key: stringHeader[0],
- value: stringHeader[1]
- }
- })
- .filter(item => {
- return item.key.startsWith("x-b3") || item.key.startsWith("traceparent");
- })
- .map(val => {
- return {
- [val.key]: val.value
- }
- })
- .reduce((prev, current) => {
- return Object.assign(prev, current)
- })
- return tracingHeaders
-}`, externalSvcURL)
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func BasicNodeJSFunctionWithCustomDependency(msg string, rtm serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: fmt.Sprintf(`module.exports = { main: function(event, context) { return "%s" } }`, msg),
- Dependencies: `{ "name": "hellobasic", "version": "0.0.1", "dependencies": { "camelcase": "^7.0.0" } }`,
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func NodeJSFunctionWithEnvFromConfigMapAndSecret(configMapName, cmEnvKey, secretName, secretEnvKey string, rtm serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- mappedCmEnvKey := "CM_KEY"
- mappedSecretEnvKey := "SECRET_KEY"
-
- src := fmt.Sprintf(`module.exports = { main: function(event, context) { return process.env["%s"] + "-" + process.env["%s"]; } }`, mappedCmEnvKey, mappedSecretEnvKey)
- dpd := `{ "name": "hellowithconfigmapsecretenvs", "version": "0.0.1", "dependencies": { } }`
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- Env: []corev1.EnvVar{
- {
- Name: mappedCmEnvKey,
- ValueFrom: &corev1.EnvVarSource{
- ConfigMapKeyRef: &corev1.ConfigMapKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: configMapName,
- },
- Key: cmEnvKey,
- },
- },
- },
- {
- Name: mappedSecretEnvKey,
- ValueFrom: &corev1.EnvVarSource{
- SecretKeyRef: &corev1.SecretKeySelector{
- LocalObjectReference: corev1.LocalObjectReference{
- Name: secretName,
- },
- Key: secretEnvKey,
- },
- },
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func NodeJSFunctionWithCloudEvent(rtm serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- src := `const process = require("process");
-const axios = require('axios');
-
-let cloudevent = {}
-
-send_check_event_type = "send-check"
-
-runtime = process.env.CE_SOURCE
-
-module.exports = {
- main: async function (event, context) {
- console.log("event: ", event)
- switch (event.extensions.request.method) {
- case "POST":
- res = handlePost(event)
- return res
- case "GET":
- res = handleGet(event.extensions.request)
- return res
- default:
- event.extensions.response.statusCode = 405
- console.log("Unexpected call, return: 405")
- return ""
- }
- }
-}
-
-function handlePost(event) {
- if (!Object.keys(event).includes("ce-type")) {
- event.emitCloudEvent(send_check_event_type, runtime, event.data, {'eventtypeversion': 'v1alpha2'})
- console.log("publishing CE, type: ", send_check_event_type, ", source: ", runtime, ", data: ", event.data, ", attr: {eventtypeversion: v1alpha2}")
- return ""
- }
- Object.keys(event).filter((val) => {
- return val.startsWith("ce-")
- }).forEach((item) => {
- cloudevent[item] = event[item]
- })
- cloudevent.data = event.data
- console.log("saving received cloud event, type: ", event["ce-type"], "data: ", cloudevent.data)
- return ""
-}
-
-async function handleGet(req) {
- if (req.query.type === 'send-check') {
- let data = {}
- let publisherProxy = process.env.PUBLISHER_PROXY_ADDRESS
- await axios.get(publisherProxy, {
- params: {
- type: req.query.type,
- source: runtime
- }
- }).then((res) => {
- data = res.data
- }).catch((error) => {
- data = error
- })
- console.log("getting saved events from publisher proxy, type: ", req.query.type, ", source: ", runtime, ", returning: ", JSON.stringify(data, null, 4))
- return data
- }
-
- console.log("getting saved event from memory for type: ", req.query.type, ", returning: ", JSON.stringify(cloudevent, null, 4))
- return cloudevent
-}
-`
- return serverlessv1alpha2.FunctionSpec{
- Runtime: rtm,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: `{ "name": "cloudevent", "version": "0.0.1", "dependencies": {} }`,
- },
- },
- Env: []v1.EnvVar{
- {
- Name: "CE_SOURCE",
- Value: string(rtm),
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
diff --git a/tests/serverless/internal/resources/runtimes/python.go b/tests/serverless/internal/resources/runtimes/python.go
deleted file mode 100644
index 09e144e5e..000000000
--- a/tests/serverless/internal/resources/runtimes/python.go
+++ /dev/null
@@ -1,248 +0,0 @@
-package runtimes
-
-import (
- "fmt"
-
- v1 "k8s.io/api/core/v1"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-)
-
-func BasicPythonFunction(msg string, runtime serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- src := fmt.Sprintf(`import arrow
-def main(event, context):
- return "%s"`, msg)
-
- dpd := `requests==2.31.0
-arrow==0.15.8`
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: runtime,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func BasicTracingPythonFunction(runtime serverlessv1alpha2.Runtime, externalURL string) serverlessv1alpha2.FunctionSpec {
-
- dpd := `opentelemetry-instrumentation==0.43b0
-opentelemetry-instrumentation-requests==0.43b0
-requests>=2.31.0`
-
- src := fmt.Sprintf(`import json
-
-import requests
-from opentelemetry.instrumentation.requests import RequestsInstrumentor
-
-
-def main(event, context):
- print("event headers: ", vars(event['extensions']['request'].headers))
- print("event data: ", vars(event['extensions']['request'].body))
- print("event method: ", event['extensions']['request'].method)
- RequestsInstrumentor().instrument()
- response = requests.get('%s', timeout=1)
- headers = response.request.headers
- tracingHeaders = {}
- for key, value in headers.items():
- if key.startswith("x-b3") or key.startswith("traceparent"):
- tracingHeaders[key] = value
- print("response: ", json.dumps(tracingHeaders))
- return json.dumps(tracingHeaders)`, externalURL)
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: runtime,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- }
-}
-
-func BasicPythonFunctionWithCustomDependency(msg string, runtime serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- src := fmt.Sprintf(
- `import arrow
-def main(event, context):
- return "%s"`, msg)
-
- dpd := `requests==2.31.0
-arrow==0.15.8
-kyma-pypi-test==1.0.0`
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: runtime,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "M",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func PythonPublisherProxyMock() serverlessv1alpha2.FunctionSpec {
- dpd := ``
-
- src := `import json
-
-import bottle
-
-event_data = {}
-
-
-def main(event, context):
- print("event headers: ", vars(event['extensions']['request'].headers))
- print("event data: ", vars(event['extensions']['request'].body))
- print("event method: ", event['extensions']['request'].method)
- global event_data
- req = event.ceHeaders['extensions']['request']
-
- if req.method == 'GET':
- event_type = req.query.get(key='type')
- if event_type is None:
- print("type is not specified, returning all event data: ", json.dumps(event_data))
- return json.dumps(event_data)
- source = req.query.get(key='source')
- runtime_events = event_data.get(source, {})
- saved_event = runtime_events.get(event_type, "")
- print("getting saved event from memory for type:", event_type, ", for source: ", source, ", returning: ", json.dumps(saved_event))
- return json.dumps(saved_event)
-
- elif req.method == 'POST':
- event_ce_headers = event.ceHeaders
- event_ce_headers.pop('extensions')
- event_data[str(event_ce_headers['ce-source'])] = {
- event_ce_headers['ce-type']: event_ce_headers
- }
- print("saving CE headers in-memory, source: ", event_ce_headers['ce-source'], ", headers: ", event_data[str(event_ce_headers['ce-source'])], ", returning: 201")
- print("current event_data: ", event_data)
- return bottle.HTTPResponse(status=201)
-
- print("Unexpected call, returning: 405")
- return bottle.HTTPResponse(status=405)
-`
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: serverlessv1alpha2.Python312,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- Env: []v1.EnvVar{
- {
- Name: "PUBLISHER_PROXY_ADDRESS",
- Value: "localhost:8080",
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
-
-func PythonCloudEvent(runtime serverlessv1alpha2.Runtime) serverlessv1alpha2.FunctionSpec {
- dpd := ``
-
- src := `import json
-import os
-
-import requests
-
-event_data = {}
-
-send_check_event_type = "send-check"
-
-runtime = os.getenv("CE_SOURCE")
-
-
-def main(event, context):
- print("event headers: ", vars(event['extensions']['request'].headers))
- print("event data: ", vars(event['extensions']['request'].body))
- print("event method: ", event['extensions']['request'].method)
- global event_data
- req = event.ceHeaders['extensions']['request']
-
- if req.method == 'GET':
- event_type = req.query.get(key='type')
- if event_type == send_check_event_type:
- publisher_proxy = os.getenv("PUBLISHER_PROXY_ADDRESS")
- resp = requests.get(publisher_proxy, params={
- "type": event_type,
- "source": runtime
- })
- print("getting saved events from publisher proxy, type: ", send_check_event_type, ", source: ", runtime, ", returning: ", resp.json())
- return resp.json()
-
- saved_event = event_data.get(event_type, {})
- print("getting saved event from memory for type: ", event_type, ", returning: ", json.dumps(saved_event))
- return json.dumps(saved_event)
-
- if 'ce-type' not in event.ceHeaders:
- event.emitCloudEvent(send_check_event_type, runtime, req.json, {'eventtypeversion': 'v1alpha2'})
- print("publishing CE, type: ", send_check_event_type, ", source: ", runtime, ", data: ", req.json, ", attr: ", {'eventtypeversion': 'v1alpha2'})
- return ""
-
- event_ce_headers = event.ceHeaders
- event_ce_headers.pop('extensions')
-
- event_data[event_ce_headers['ce-type']] = event_ce_headers
- print("saving received cloud event, type: ", event_ce_headers['ce-type'], " headers: ", event_data[event_ce_headers['ce-type']])
- return ""
-`
-
- return serverlessv1alpha2.FunctionSpec{
- Runtime: runtime,
- Source: serverlessv1alpha2.Source{
- Inline: &serverlessv1alpha2.InlineSource{
- Source: src,
- Dependencies: dpd,
- },
- },
- Env: []v1.EnvVar{
- {
- Name: "PUBLISHER_PROXY_ADDRESS",
- Value: "localhost:8080",
- },
- {
- Name: "CE_SOURCE",
- Value: string(runtime),
- },
- },
- ResourceConfiguration: &serverlessv1alpha2.ResourceConfiguration{
- Function: &serverlessv1alpha2.ResourceRequirements{
- Profile: "L",
- },
- Build: &serverlessv1alpha2.ResourceRequirements{
- Profile: "fast",
- },
- },
- }
-}
diff --git a/tests/serverless/internal/resources/secret/secret.go b/tests/serverless/internal/resources/secret/secret.go
deleted file mode 100644
index a00cf488e..000000000
--- a/tests/serverless/internal/resources/secret/secret.go
+++ /dev/null
@@ -1,93 +0,0 @@
-package secret
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/resources"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "k8s.io/apimachinery/pkg/runtime"
-
- "github.com/sirupsen/logrus"
-
- "github.com/pkg/errors"
- corev1 "k8s.io/api/core/v1"
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-)
-
-type Secret struct {
- resCli *resources.Resource
- name string
- namespace string
- log *logrus.Entry
-}
-
-func NewSecret(name string, c utils.Container) *Secret {
- return &Secret{
- resCli: resources.New(c.DynamicCli, corev1.SchemeGroupVersion.WithResource("secrets"), c.Namespace, c.Log, c.Verbose),
- name: name,
- namespace: c.Namespace,
- log: c.Log,
- }
-}
-
-func (s *Secret) Name() string {
- return s.name
-}
-
-func (s *Secret) Create(data map[string]string) error {
- cm := &corev1.Secret{
- ObjectMeta: metav1.ObjectMeta{
- Name: s.name,
- Namespace: s.namespace,
- },
- StringData: data,
- }
-
- _, err := s.resCli.Create(cm)
- if err != nil {
- return errors.Wrapf(err, "while creating Secret %s in namespace %s", s.name, s.namespace)
- }
- return err
-}
-
-func (s *Secret) Delete() error {
- err := s.resCli.Delete(s.name)
- if err != nil {
- return errors.Wrapf(err, "while deleting Secret %s in namespace %s", s.name, s.namespace)
- }
-
- return nil
-}
-
-func (s *Secret) Get() (*corev1.Secret, error) {
- u, err := s.resCli.Get(s.name)
- if err != nil {
- return nil, errors.Wrapf(err, "while getting Secret %s in namespace %s", s.name, s.namespace)
- }
- secret := corev1.Secret{}
- if err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &secret); err != nil {
- return nil, errors.Wrap(err, "while constructing Secret from unstructured")
- }
-
- return &secret, nil
-}
-func (s *Secret) LogResource() error {
- secret, err := s.Get()
- if err != nil {
- return errors.Wrap(err, "while getting Secret")
- }
-
- redactSecretData(secret)
-
- out, err := utils.PrettyMarshall(secret)
- if err != nil {
- return err
- }
-
- s.log.Infof("Secret: %s", out)
- return nil
-}
-
-func redactSecretData(secret *corev1.Secret) {
- for k := range secret.Data {
- secret.Data[k] = []byte("REDACTED")
- }
-}
diff --git a/tests/serverless/internal/resources/secret/step.go b/tests/serverless/internal/resources/secret/step.go
deleted file mode 100644
index 3af11713c..000000000
--- a/tests/serverless/internal/resources/secret/step.go
+++ /dev/null
@@ -1,41 +0,0 @@
-package secret
-
-import (
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-type Secrets struct {
- name string
- secret *Secret
- data map[string]string
- log *logrus.Entry
-}
-
-func CreateSecret(log *logrus.Entry, sec *Secret, stepName string, data map[string]string) executor.Step {
- return &Secrets{
- name: stepName,
- data: data,
- log: log.WithField(executor.LogStepKey, stepName),
- secret: sec,
- }
-}
-
-func (s Secrets) Name() string {
- return s.name
-}
-
-func (s Secrets) Run() error {
- return errors.Wrap(s.secret.Create(s.data), "while creating secret")
-}
-
-func (s Secrets) Cleanup() error {
- return errors.Wrap(s.secret.Delete(), "while deleting secret")
-}
-
-func (s Secrets) OnError() error {
- return nil
-}
-
-var _ executor.Step = Secrets{}
diff --git a/tests/serverless/internal/testsuite/api_gateway.go b/tests/serverless/internal/testsuite/api_gateway.go
deleted file mode 100644
index 6b545b64b..000000000
--- a/tests/serverless/internal/testsuite/api_gateway.go
+++ /dev/null
@@ -1,88 +0,0 @@
-package testsuite
-
-import (
- "fmt"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- "github.com/pkg/errors"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-const (
- nodejs18 = "nodejs18"
- nodejs20 = "nodejs20"
- python39 = "python39"
- python312 = "python312"
-)
-
-func FunctionAPIGatewayTest(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-api-gateway", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating dynamic client")
- }
-
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrap(err, "while creating k8s CoreV1Client")
- }
-
- python312Logger := logf.WithField(runtimeKey, "python312")
- python39Logger := logf.WithField(runtimeKey, "python39")
- nodejs18Logger := logf.WithField(runtimeKey, "nodejs18")
- nodejs20Logger := logf.WithField(runtimeKey, "nodejs20")
-
- genericContainer := utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }
-
- python39Fn := function.NewFunction("python39", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python39Logger))
-
- python312Fn := function.NewFunction("python312", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python312Logger))
-
- nodejs18Fn := function.NewFunction("nodejs18", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs18Logger))
-
- nodejs20Fn := function.NewFunction("nodejs20", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs20Logger))
-
- logf.Infof("Testing function in namespace: %s", cfg.Namespace)
-
- return executor.NewSerialTestRunner(logf, "Runtime test",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- executor.NewParallelRunner(logf, "Fn tests",
- executor.NewSerialTestRunner(python39Logger, "Python39 test",
- function.CreateFunction(python39Logger, python39Fn, "Create Python39 Function", runtimes.BasicPythonFunction("Hello from python39", serverlessv1alpha2.Python39)),
- assertion.APIGatewayFunctionCheck("python39", python39Fn, coreCli, genericContainer.Namespace, python39),
- ),
- executor.NewSerialTestRunner(python312Logger, "Python312 test",
- function.CreateFunction(python312Logger, python312Fn, "Create Python312 Function", runtimes.BasicPythonFunction("Hello from python312", serverlessv1alpha2.Python312)),
- assertion.APIGatewayFunctionCheck("python312", python312Fn, coreCli, genericContainer.Namespace, python312),
- ),
- executor.NewSerialTestRunner(nodejs18Logger, "NodeJS18 test",
- function.CreateFunction(nodejs18Logger, nodejs18Fn, "Create NodeJS18 Function", runtimes.BasicNodeJSFunction("Hello from nodejs18", serverlessv1alpha2.NodeJs18)),
- assertion.APIGatewayFunctionCheck("nodejs18", nodejs18Fn, coreCli, genericContainer.Namespace, nodejs18),
- ),
- executor.NewSerialTestRunner(nodejs20Logger, "NodeJS20 test",
- function.CreateFunction(nodejs20Logger, nodejs20Fn, "Create NodeJS20 Function", runtimes.BasicNodeJSFunction("Hello from nodejs20", serverlessv1alpha2.NodeJs20)),
- assertion.APIGatewayFunctionCheck("nodejs20", nodejs20Fn, coreCli, genericContainer.Namespace, nodejs20),
- ),
- ),
- ), nil
-}
diff --git a/tests/serverless/internal/testsuite/cloud_events.go b/tests/serverless/internal/testsuite/cloud_events.go
deleted file mode 100644
index eb2b86dfe..000000000
--- a/tests/serverless/internal/testsuite/cloud_events.go
+++ /dev/null
@@ -1,89 +0,0 @@
-package testsuite
-
-import (
- "fmt"
- "time"
-
- cloudevents "github.com/cloudevents/sdk-go/v2"
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-func FunctionCloudEventsTest(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-cloud-events", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating dynamic client")
- }
-
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrap(err, "while creating k8s CoreV1Client")
- }
-
- python39Logger := logf.WithField(runtimeKey, "python39")
- python312Logger := logf.WithField(runtimeKey, "python312")
- nodejs18Logger := logf.WithField(runtimeKey, "nodejs18")
- nodejs20Logger := logf.WithField(runtimeKey, "nodejs20")
-
- genericContainer := utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }
-
- publisherProxyMock := function.NewFunction("eventing-publisher-proxy", "kyma-system", cfg.KubectlProxyEnabled, genericContainer.WithLogger(python312Logger))
- python39Fn := function.NewFunction("python39", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python39Logger))
- python312Fn := function.NewFunction("python312", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python312Logger))
- nodejs18Fn := function.NewFunction("nodejs18", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs18Logger))
- nodejs20Fn := function.NewFunction("nodejs20", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs20Logger))
-
- logf.Infof("Testing function in namespace: %s", cfg.Namespace)
-
- return executor.NewSerialTestRunner(logf, "Runtime test",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- function.CreateFunction(logf, publisherProxyMock, "Create publisher proxy mock", runtimes.PythonPublisherProxyMock()),
- executor.NewParallelRunner(logf, "Fn tests",
- executor.NewSerialTestRunner(python39Logger, "Python39 test",
- function.CreateFunction(python39Logger, python39Fn, "Create Python39 Function", runtimes.PythonCloudEvent(serverlessv1alpha2.Python39)),
- assertion.CloudEventReceiveCheck(python39Logger, "Python39 cloud event structured check", cloudevents.EncodingStructured, python39Fn.FunctionURL),
- assertion.CloudEventReceiveCheck(python39Logger, "Python39 cloud event binary check", cloudevents.EncodingBinary, python39Fn.FunctionURL),
- assertion.CloudEventSendCheck(python39Logger, "Python39 cloud event sent check", string(serverlessv1alpha2.Python39), python39Fn.FunctionURL, publisherProxyMock.FunctionURL),
- ),
- executor.NewSerialTestRunner(python312Logger, "Python312 test",
- function.CreateFunction(python312Logger, python312Fn, "Create Python312 Function", runtimes.PythonCloudEvent(serverlessv1alpha2.Python312)),
- assertion.CloudEventReceiveCheck(python312Logger, "Python312 cloud event structured check", cloudevents.EncodingStructured, python312Fn.FunctionURL),
- assertion.CloudEventReceiveCheck(python312Logger, "Python312 cloud event binary check", cloudevents.EncodingBinary, python312Fn.FunctionURL),
- assertion.CloudEventSendCheck(python312Logger, "Python312 cloud event sent check", string(serverlessv1alpha2.Python312), python312Fn.FunctionURL, publisherProxyMock.FunctionURL),
- ),
- executor.NewSerialTestRunner(nodejs18Logger, "NodeJS18 test",
- function.CreateFunction(nodejs18Logger, nodejs18Fn, "Create NodeJS18 Function", runtimes.NodeJSFunctionWithCloudEvent(serverlessv1alpha2.NodeJs18)),
- assertion.CloudEventReceiveCheck(nodejs18Logger, "NodeJS18 cloud event structured check", cloudevents.EncodingStructured, nodejs18Fn.FunctionURL),
- assertion.CloudEventReceiveCheck(nodejs18Logger, "NodeJS18 cloud event binary check", cloudevents.EncodingBinary, nodejs18Fn.FunctionURL),
- assertion.CloudEventSendCheck(nodejs18Logger, "NodeJS18 cloud event sent check", string(serverlessv1alpha2.NodeJs18), nodejs18Fn.FunctionURL, publisherProxyMock.FunctionURL),
- ),
- executor.NewSerialTestRunner(nodejs20Logger, "NodeJS20 test",
- function.CreateFunction(nodejs20Logger, nodejs20Fn, "Create NodeJS20 Function", runtimes.NodeJSFunctionWithCloudEvent(serverlessv1alpha2.NodeJs20)),
- assertion.CloudEventReceiveCheck(nodejs20Logger, "NodeJS20 cloud event structured check", cloudevents.EncodingStructured, nodejs20Fn.FunctionURL),
- assertion.CloudEventReceiveCheck(nodejs20Logger, "NodeJS20 cloud event binary check", cloudevents.EncodingBinary, nodejs20Fn.FunctionURL),
- assertion.CloudEventSendCheck(nodejs20Logger, "NodeJS20 cloud event sent check", string(serverlessv1alpha2.NodeJs20), nodejs20Fn.FunctionURL, publisherProxyMock.FunctionURL),
- ),
- ),
- ), nil
-}
diff --git a/tests/serverless/internal/testsuite/gitauth.go b/tests/serverless/internal/testsuite/gitauth.go
deleted file mode 100644
index 4c01ed0d1..000000000
--- a/tests/serverless/internal/testsuite/gitauth.go
+++ /dev/null
@@ -1,180 +0,0 @@
-package testsuite
-
-import (
- "encoding/base64"
- "fmt"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/secret"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-
- "github.com/vrischmann/envconfig"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-type testRepo struct {
- name string
- provider string
- url string
- baseDir string
- expectedResponse string
- reference string
- secretData map[string]string
- runtime serverlessv1alpha2.Runtime
- auth *serverlessv1alpha2.RepositoryAuth
-}
-
-type config struct {
- Azure AzureRepo `envconfig:"AZURE"`
- Github GithubRepo `envconfig:"GITHUB"`
-}
-
-type SSHAuth struct {
- Key string
-}
-
-type BasicAuth struct {
- Username string
- Password string
-}
-
-type GithubRepo struct {
- Reference string `envconfig:"default=main"`
- URL string `envconfig:"default=git@github.com:kyma-project/private-fn-for-e2e-serverless-tests.git"`
- BaseDir string `envconfig:"default=/"`
- SSHAuth
-}
-
-type AzureRepo struct {
- Reference string `envconfig:"default=main"`
- URL string `envconfig:"default=https://kyma-wookiee@dev.azure.com/kyma-wookiee/kyma-function/_git/kyma-function"`
- BaseDir string `envconfig:"default=/code"`
- BasicAuth
-}
-
-func GitAuthTestSteps(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- testCfg := &config{}
- if err := envconfig.InitWithPrefix(testCfg, "APP_TEST"); err != nil {
- return nil, errors.Wrap(err, "while loading git auth test config")
- }
-
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating k8s core client")
- }
-
- genericContainer, err := setupSharedContainer(restConfig, cfg, logf)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating Shared Container")
- }
- poll := utils.Poller{
- MaxPollingTime: cfg.MaxPollingTime,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- Log: genericContainer.Log,
- DataKey: internal.TestDataKey,
- }
-
- azureTC := getAzureDevopsTestcase(testCfg)
- azureSecret := secret.NewSecret(azureTC.auth.SecretName, genericContainer)
- azureFn := function.NewFunction(azureTC.name, genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer)
-
- githubTC, err := getGithubTestcase(testCfg)
- if err != nil {
- return nil, errors.Wrapf(err, "while setting github testcase")
- }
- githubSecret := secret.NewSecret(githubTC.auth.SecretName, genericContainer)
- githubFn := function.NewFunction(githubTC.name, genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer)
-
- return executor.NewSerialTestRunner(logf, "Test Git function authentication",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- executor.NewParallelRunner(logf, "Providers tests",
- executor.NewSerialTestRunner(genericContainer.Log, fmt.Sprintf("%s Function auth test", azureTC.provider),
- secret.CreateSecret(genericContainer.Log, azureSecret, "Create Azure Auth Secret", azureTC.secretData),
- function.CreateFunction(genericContainer.Log, azureFn, "Create Azure Function", runtimes.GitopsFunction(azureTC.url, azureTC.baseDir, azureTC.reference, azureTC.runtime, azureTC.auth)),
- assertion.NewHTTPCheck(genericContainer.Log, "Git Function simple check through gateway", azureFn.FunctionURL, poll, azureTC.expectedResponse)),
- executor.NewSerialTestRunner(genericContainer.Log, fmt.Sprintf("%s Function auth test", githubTC.provider),
- secret.CreateSecret(genericContainer.Log, githubSecret, "Create Github Auth Secret", githubTC.secretData),
- function.CreateFunction(genericContainer.Log, githubFn, "Create Github Function", runtimes.GitopsFunction(githubTC.url, githubTC.baseDir, githubTC.reference, githubTC.runtime, githubTC.auth)),
- assertion.NewHTTPCheck(genericContainer.Log, "Git Function simple check through gateway", githubFn.FunctionURL, poll, githubTC.expectedResponse)))), nil
-}
-
-func setupSharedContainer(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (utils.Container, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-serverless-gitauth", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return utils.Container{}, errors.Wrapf(err, "while creating dynamic client")
- }
-
- return utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }, nil
-}
-
-func createBasicAuthSecretData(basicAuth BasicAuth) map[string]string {
- return map[string]string{
- "username": basicAuth.Username,
- "password": basicAuth.Password,
- }
-}
-
-func createSSHAuthSecretData(auth SSHAuth) (map[string]string, error) {
- // this value will be base64 encoded since it's passed as an environment variable.
- // we have to decode it first before it's passed to the secret creator since it will re-encode it again.
- decoded, err := base64.StdEncoding.DecodeString(auth.Key)
-
- return map[string]string{"key": string(decoded)}, err
-}
-
-func getAzureDevopsTestcase(cfg *config) testRepo {
- return testRepo{name: "azure-devops-func",
- provider: "AzureDevOps",
- url: cfg.Azure.URL,
- baseDir: cfg.Azure.BaseDir,
- reference: cfg.Azure.Reference,
- expectedResponse: "Hello azure",
- runtime: serverlessv1alpha2.NodeJs20,
- auth: &serverlessv1alpha2.RepositoryAuth{
- Type: serverlessv1alpha2.RepositoryAuthBasic,
- SecretName: "azure-devops-auth-secret",
- },
- secretData: createBasicAuthSecretData(cfg.Azure.BasicAuth)}
-}
-
-func getGithubTestcase(cfg *config) (testRepo, error) {
- secretData, err := createSSHAuthSecretData(cfg.Github.SSHAuth)
- if err != nil {
- return testRepo{}, errors.Wrapf(err, "while decoding ssh key")
- }
- return testRepo{
- name: "github-func",
- provider: "Github",
- url: cfg.Github.URL,
- baseDir: cfg.Github.BaseDir,
- reference: cfg.Github.Reference,
- expectedResponse: "hello github",
- runtime: serverlessv1alpha2.Python312,
- auth: &serverlessv1alpha2.RepositoryAuth{
- Type: serverlessv1alpha2.RepositoryAuthSSHKey,
- SecretName: "github-auth-secret",
- },
- secretData: secretData,
- }, nil
-}
diff --git a/tests/serverless/internal/testsuite/gitops.go b/tests/serverless/internal/testsuite/gitops.go
deleted file mode 100644
index 38c97d394..000000000
--- a/tests/serverless/internal/testsuite/gitops.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package testsuite
-
-import (
- "fmt"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/git"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-func GitopsSteps(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-serverless-gitops", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating dynamic client")
- }
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating k8s core client")
- }
- appsCli, err := typedappsv1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating k8s apps client")
- }
-
- genericContainer := utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }
-
- gitFnName := "gitfunc"
- gitCfg, err := git.NewGitopsConfig(gitFnName, cfg.GitServerImage, cfg.GitServerRepoName, genericContainer)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating Git config")
- }
-
- gitFn := function.NewFunction(gitFnName, genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer)
- logf.Infof("Testing Git Function in namespace: %s", cfg.Namespace)
-
- poll := utils.Poller{
- MaxPollingTime: cfg.MaxPollingTime,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- Log: logf,
- DataKey: internal.TestDataKey,
- }
- return executor.NewSerialTestRunner(logf, "Create git func",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- git.NewGitServer(gitCfg, "Start in-cluster Git Server", appsCli.Deployments(genericContainer.Namespace), coreCli.Services(genericContainer.Namespace), cfg.KubectlProxyEnabled, cfg.IstioEnabled),
- function.CreateFunction(logf, gitFn, "Create Git Function", runtimes.GitopsFunction(gitCfg.GetGitServerInClusterURL(), "/", "master", serverlessv1alpha2.NodeJs20, nil)),
- assertion.NewHTTPCheck(logf, "Git Function pre update simple check through service", gitFn.FunctionURL, poll, "GITOPS 1"),
- git.NewCommitChanges(logf, "Commit changes to Git Function", gitCfg.GetGitServerURL(cfg.KubectlProxyEnabled)),
- assertion.NewHTTPCheck(logf, "Git Function post update simple check through service", gitFn.FunctionURL, poll, "GITOPS 2")), nil
-}
diff --git a/tests/serverless/internal/testsuite/light_runtimes.go b/tests/serverless/internal/testsuite/light_runtimes.go
deleted file mode 100644
index df8a1f6a6..000000000
--- a/tests/serverless/internal/testsuite/light_runtimes.go
+++ /dev/null
@@ -1,120 +0,0 @@
-package testsuite
-
-import (
- "fmt"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/configmap"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/secret"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-const runtimeKey = "runtime"
-
-func SimpleFunctionTest(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-serverless-simple", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating dynamic client")
- }
-
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrap(err, "while creating k8s CoreV1Client")
- }
-
- python39Logger := logf.WithField(runtimeKey, "python39")
- python312Logger := logf.WithField(runtimeKey, "python312")
- nodejs18Logger := logf.WithField(runtimeKey, "nodejs18")
- nodejs20Logger := logf.WithField(runtimeKey, "nodejs20")
-
- genericContainer := utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }
-
- python39Fn := function.NewFunction("python39", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python39Logger))
-
- python312Fn := function.NewFunction("python312", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python312Logger))
-
- nodejs18Fn := function.NewFunction("nodejs18", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs18Logger))
-
- nodejs20Fn := function.NewFunction("nodejs20", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs20Logger))
-
- cm := configmap.NewConfigMap("test-serverless-configmap", genericContainer.WithLogger(nodejs20Logger))
- cmEnvKey := "CM_ENV_KEY"
- cmEnvValue := "Value taken as env from ConfigMap"
- cmData := map[string]string{
- cmEnvKey: cmEnvValue,
- }
- sec := secret.NewSecret("test-serverless-secret", genericContainer.WithLogger(nodejs20Logger))
- secEnvKey := "SECRET_ENV_KEY"
- secEnvValue := "Value taken as env from Secret"
- secretData := map[string]string{
- secEnvKey: secEnvValue,
- }
-
- pkgCfgSecret := secret.NewSecret(cfg.PackageRegistryConfigSecretName, genericContainer)
- pkgCfgSecretData := map[string]string{
- ".npmrc": fmt.Sprintf("@kyma:registry=%s\nalways-auth=true", cfg.PackageRegistryConfigURLNode),
- "pip.conf": fmt.Sprintf("[global]\nextra-index-url = %s", cfg.PackageRegistryConfigURLPython),
- }
-
- logf.Infof("Testing function in namespace: %s", cfg.Namespace)
-
- poll := utils.Poller{
- MaxPollingTime: cfg.MaxPollingTime,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- DataKey: internal.TestDataKey,
- }
- return executor.NewSerialTestRunner(logf, "Runtime test",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- secret.CreateSecret(logf, pkgCfgSecret, "Create package configuration secret", pkgCfgSecretData),
- executor.NewParallelRunner(logf, "Fn tests",
- executor.NewSerialTestRunner(python39Logger, "Python39 test",
- function.CreateFunction(python39Logger, python39Fn, "Create Python39 Function", runtimes.BasicPythonFunction("Hello From python", serverlessv1alpha2.Python39)),
- assertion.NewHTTPCheck(python39Logger, "Python39 pre update simple check through service", python39Fn.FunctionURL, poll, "Hello From python"),
- function.UpdateFunction(python39Logger, python39Fn, "Update Python39 Function", runtimes.BasicPythonFunctionWithCustomDependency("Hello From updated python", serverlessv1alpha2.Python39)),
- assertion.NewHTTPCheck(python39Logger, "Python39 post update simple check through service", python39Fn.FunctionURL, poll, "Hello From updated python"),
- ),
- executor.NewSerialTestRunner(python312Logger, "Python312 test",
- function.CreateFunction(python312Logger, python312Fn, "Create Python312 Function", runtimes.BasicPythonFunction("Hello From python", serverlessv1alpha2.Python312)),
- assertion.NewHTTPCheck(python312Logger, "Python312 pre update simple check through service", python312Fn.FunctionURL, poll, "Hello From python"),
- function.UpdateFunction(python312Logger, python312Fn, "Update Python312 Function", runtimes.BasicPythonFunctionWithCustomDependency("Hello From updated python", serverlessv1alpha2.Python312)),
- assertion.NewHTTPCheck(python312Logger, "Python312 post update simple check through service", python312Fn.FunctionURL, poll, "Hello From updated python"),
- ),
- executor.NewSerialTestRunner(nodejs18Logger, "NodeJS18 test",
- configmap.CreateConfigMap(nodejs18Logger, cm, "Create Test ConfigMap", cmData),
- secret.CreateSecret(nodejs18Logger, sec, "Create Test Secret", secretData),
- function.CreateFunction(nodejs18Logger, nodejs18Fn, "Create NodeJS18 Function", runtimes.NodeJSFunctionWithEnvFromConfigMapAndSecret(cm.Name(), cmEnvKey, sec.Name(), secEnvKey, serverlessv1alpha2.NodeJs18)),
- assertion.NewHTTPCheck(nodejs18Logger, "NodeJS18 pre update simple check through service", nodejs18Fn.FunctionURL, poll, fmt.Sprintf("%s-%s", cmEnvValue, secEnvValue)),
- function.UpdateFunction(nodejs18Logger, nodejs18Fn, "Update NodeJS18 Function", runtimes.BasicNodeJSFunctionWithCustomDependency("Hello from updated nodejs18", serverlessv1alpha2.NodeJs18)),
- assertion.NewHTTPCheck(nodejs18Logger, "NodeJS18 post update simple check through service", nodejs18Fn.FunctionURL, poll, "Hello from updated nodejs18"),
- ),
- executor.NewSerialTestRunner(nodejs20Logger, "NodeJS20 test",
- function.CreateFunction(nodejs20Logger, nodejs20Fn, "Create NodeJS20 Function", runtimes.NodeJSFunctionWithEnvFromConfigMapAndSecret(cm.Name(), cmEnvKey, sec.Name(), secEnvKey, serverlessv1alpha2.NodeJs20)),
- assertion.NewHTTPCheck(nodejs20Logger, "NodeJS20 pre update simple check through service", nodejs20Fn.FunctionURL, poll, fmt.Sprintf("%s-%s", cmEnvValue, secEnvValue)),
- function.UpdateFunction(nodejs20Logger, nodejs20Fn, "Update NodeJS20 Function", runtimes.BasicNodeJSFunctionWithCustomDependency("Hello from updated nodejs20", serverlessv1alpha2.NodeJs20)),
- assertion.NewHTTPCheck(nodejs20Logger, "NodeJS20 post update simple check through service", nodejs20Fn.FunctionURL, poll, "Hello from updated nodejs20"),
- ),
- ),
- ), nil
-}
diff --git a/tests/serverless/internal/testsuite/tracing.go b/tests/serverless/internal/testsuite/tracing.go
deleted file mode 100644
index b4ce96187..000000000
--- a/tests/serverless/internal/testsuite/tracing.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package testsuite
-
-import (
- "fmt"
- "time"
-
- "github.com/kyma-project/serverless/tests/serverless/internal"
- "github.com/kyma-project/serverless/tests/serverless/internal/assertion"
- "github.com/kyma-project/serverless/tests/serverless/internal/executor"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/app"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/function"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/namespace"
- "github.com/kyma-project/serverless/tests/serverless/internal/resources/runtimes"
- "github.com/kyma-project/serverless/tests/serverless/internal/utils"
- typedappsv1 "k8s.io/client-go/kubernetes/typed/apps/v1"
-
- serverlessv1alpha2 "github.com/kyma-project/serverless/components/serverless/pkg/apis/serverless/v1alpha2"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
- typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1"
- "k8s.io/client-go/rest"
-)
-
-const (
- HTTPAppName = "http-server"
- HTTPAppImage = "nginx"
-)
-
-func FunctionTracingTest(restConfig *rest.Config, cfg internal.Config, logf *logrus.Entry) (executor.Step, error) {
- now := time.Now()
- cfg.Namespace = fmt.Sprintf("%s-%02dh%02dm%02ds", "test-tracing", now.Hour(), now.Minute(), now.Second())
-
- dynamicCli, err := dynamic.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating dynamic client")
- }
-
- coreCli, err := typedcorev1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrap(err, "while creating k8s CoreV1Client")
- }
-
- appsCli, err := typedappsv1.NewForConfig(restConfig)
- if err != nil {
- return nil, errors.Wrapf(err, "while creating k8s apps client")
- }
-
- python39Logger := logf.WithField(runtimeKey, "python39")
- python312Logger := logf.WithField(runtimeKey, "python312")
- nodejs18Logger := logf.WithField(runtimeKey, "nodejs18")
- nodejs20Logger := logf.WithField(runtimeKey, "nodejs20")
-
- genericContainer := utils.Container{
- DynamicCli: dynamicCli,
- Namespace: cfg.Namespace,
- WaitTimeout: cfg.WaitTimeout,
- Verbose: cfg.Verbose,
- Log: logf,
- }
-
- python39Fn := function.NewFunction("python39", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python39Logger))
-
- python312Fn := function.NewFunction("python312", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(python312Logger))
-
- nodejs18Fn := function.NewFunction("nodejs18", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs18Logger))
-
- nodejs20Fn := function.NewFunction("nodejs20", genericContainer.Namespace, cfg.KubectlProxyEnabled, genericContainer.WithLogger(nodejs20Logger))
-
- logf.Infof("Testing function in namespace: %s", cfg.Namespace)
-
- httpAppURL, err := utils.GetSvcURL(HTTPAppName, genericContainer.Namespace, false)
- if err != nil {
- return nil, errors.Wrap(err, "while creating http application URL")
- }
-
- poll := utils.Poller{
- MaxPollingTime: cfg.MaxPollingTime,
- InsecureSkipVerify: cfg.InsecureSkipVerify,
- DataKey: internal.TestDataKey,
- }
- return executor.NewSerialTestRunner(logf, "Runtime test",
- namespace.NewNamespaceStep(logf, fmt.Sprintf("Create %s namespace", genericContainer.Namespace), genericContainer.Namespace, coreCli),
- app.NewApplication("Create HTTP basic application", HTTPAppName, HTTPAppImage, int32(80), appsCli.Deployments(genericContainer.Namespace), coreCli.Services(genericContainer.Namespace), genericContainer),
- executor.NewParallelRunner(logf, "Fn tests",
- executor.NewSerialTestRunner(python39Logger, "Python39 test",
- function.CreateFunction(python39Logger, python39Fn, "Create Python39 Function", runtimes.BasicTracingPythonFunction(serverlessv1alpha2.Python39, httpAppURL.String())),
- assertion.TracingHTTPCheck(python39Logger, "Python39 tracing headers check", python39Fn.FunctionURL, poll),
- ),
- executor.NewSerialTestRunner(python312Logger, "Python312 test",
- function.CreateFunction(python312Logger, python312Fn, "Create Python312 Function", runtimes.BasicTracingPythonFunction(serverlessv1alpha2.Python312, httpAppURL.String())),
- assertion.TracingHTTPCheck(python312Logger, "Python312 tracing headers check", python312Fn.FunctionURL, poll),
- ),
- executor.NewSerialTestRunner(nodejs18Logger, "NodeJS18 test",
- function.CreateFunction(nodejs18Logger, nodejs18Fn, "Create NodeJS18 Function", runtimes.BasicTracingNodeFunction(serverlessv1alpha2.NodeJs18, httpAppURL.String())),
- assertion.TracingHTTPCheck(nodejs18Logger, "NodeJS18 tracing headers check", nodejs18Fn.FunctionURL, poll),
- ),
- executor.NewSerialTestRunner(nodejs20Logger, "NodeJS20 test",
- function.CreateFunction(nodejs20Logger, nodejs20Fn, "Create NodeJS20 Function", runtimes.BasicTracingNodeFunction(serverlessv1alpha2.NodeJs20, httpAppURL.String())),
- assertion.TracingHTTPCheck(nodejs20Logger, "NodeJS20 tracing headers check", nodejs20Fn.FunctionURL, poll),
- ),
- ),
- ), nil
-}
diff --git a/tests/serverless/internal/utils/container.go b/tests/serverless/internal/utils/container.go
deleted file mode 100644
index c59ecb7d3..000000000
--- a/tests/serverless/internal/utils/container.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package utils
-
-import (
- "time"
-
- "github.com/sirupsen/logrus"
- "k8s.io/client-go/dynamic"
-)
-
-type Container struct {
- DynamicCli dynamic.Interface
- Namespace string
- WaitTimeout time.Duration
- Verbose bool
- Log *logrus.Entry
-}
-
-func (c Container) WithLogger(l *logrus.Entry) Container {
- c.Log = l
- return c
-}
diff --git a/tests/serverless/internal/utils/poller.go b/tests/serverless/internal/utils/poller.go
deleted file mode 100644
index 2b103edee..000000000
--- a/tests/serverless/internal/utils/poller.go
+++ /dev/null
@@ -1,81 +0,0 @@
-package utils
-
-import (
- "crypto/tls"
- "fmt"
- "io/ioutil"
- "net/http"
- "strings"
- "time"
-
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
- "k8s.io/apimachinery/pkg/util/wait"
-)
-
-type Poller struct {
- MaxPollingTime time.Duration
- InsecureSkipVerify bool
- Log *logrus.Entry
- DataKey string
-}
-
-func (p Poller) WithLogger(l *logrus.Entry) Poller {
- p.Log = l
- return p
-}
-
-func (p Poller) PollForAnswer(url, payloadStr, expected string) error {
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: p.InsecureSkipVerify},
- }
- client := &http.Client{Transport: tr}
-
- done := make(chan struct{})
-
- go func() {
- time.Sleep(p.MaxPollingTime)
- close(done)
- }()
-
- return wait.PollImmediateUntil(10*time.Second,
- func() (done bool, err error) {
- payload := strings.NewReader(fmt.Sprintf(`{ "%s": "%s" }`, p.DataKey, payloadStr))
- req, err := http.NewRequest(http.MethodGet, url, payload)
- if err != nil {
- return false, errors.Wrapf(err, "while creating new request to ping url %s with payload %s", url, payloadStr)
- }
-
- req.Header.Add("content-type", "application/json")
- res, err := client.Do(req)
- if err != nil {
- return false, err
- }
- defer func() {
- errClose := res.Body.Close()
- if errClose != nil {
- p.Log.Infof("Error closing body in request to %s: %v", url, errClose)
- }
- }()
-
- if res.StatusCode != http.StatusOK {
- p.Log.Infof("Expected status %s, got %s, retrying...", http.StatusText(http.StatusOK), res.Status)
- return false, nil
- }
-
- byteRes, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return false, errors.Wrap(err, "while reading response")
- }
-
- body := string(byteRes)
-
- if body != expected {
- p.Log.Infof("Got: %q, expected: %s, retrying...", body, expected)
- return false, nil
- }
-
- p.Log.Infof("Got: %q, correct...", body)
- return true, nil
- }, done)
-}
diff --git a/tests/serverless/internal/utils/pretty.go b/tests/serverless/internal/utils/pretty.go
deleted file mode 100644
index 6b63b5602..000000000
--- a/tests/serverless/internal/utils/pretty.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package utils
-
-import "encoding/json"
-
-func PrettyMarshall(object interface{}) (string, error) {
- out, err := json.MarshalIndent(object, "", " ")
- return string(out), err
-}
diff --git a/tests/serverless/internal/utils/retry.go b/tests/serverless/internal/utils/retry.go
deleted file mode 100644
index f655b1246..000000000
--- a/tests/serverless/internal/utils/retry.go
+++ /dev/null
@@ -1,62 +0,0 @@
-package utils
-
-import (
- goerrors "errors"
-
- "github.com/sirupsen/logrus"
- "k8s.io/apimachinery/pkg/api/errors"
- "k8s.io/apimachinery/pkg/util/wait"
- "k8s.io/client-go/util/retry"
-)
-
-var (
- DefaultBackoff = retry.DefaultBackoff
- DefaultRetry = retry.DefaultRetry
- ErrInvalidFunc = goerrors.New("invalid function")
-)
-
-func fnWithIgnore(fn func() error, ignoreErr func(error) bool, log *logrus.Entry) func() error {
- return func() error {
- if fn == nil {
- return ErrInvalidFunc
- }
- err := fn()
- if ignoreErr == nil {
- return err
- }
- if ignoreErr(err) {
- log.Infof("ignoring: %s", err)
- return nil
- }
- return err
- }
-}
-
-func errorFn(log *logrus.Entry) func(error) bool {
- return func(err error) bool {
- if errors.IsTimeout(err) ||
- errors.IsServerTimeout(err) ||
- errors.IsTooManyRequests(err) ||
- errors.IsConflict(err) {
- log.Infof("retrying due to: %s", err)
- return true
- }
- return false
- }
-}
-
-func WithIgnoreOnNotFound(backoff wait.Backoff, fn func() error, log *logrus.Entry) error {
- return retry.OnError(backoff, errorFn(log), fnWithIgnore(fn, errors.IsNotFound, log))
-}
-
-func WithIgnoreOnConflict(backoff wait.Backoff, fn func() error, log *logrus.Entry) error {
- return retry.OnError(backoff, errorFn(log), fnWithIgnore(fn, errors.IsConflict, log))
-}
-
-func OnTimeout(backoff wait.Backoff, fn func() error, log *logrus.Entry) error {
- return retry.OnError(backoff, errorFn(log), fn)
-}
-
-func RetryOnConflict(backoff wait.Backoff, fn func() error, log *logrus.Entry) error {
- return retry.OnError(backoff, errorFn(log), fn)
-}
diff --git a/tests/serverless/internal/utils/url.go b/tests/serverless/internal/utils/url.go
deleted file mode 100644
index 157f7b545..000000000
--- a/tests/serverless/internal/utils/url.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package utils
-
-import (
- "fmt"
- "net/url"
-
- "github.com/pkg/errors"
-)
-
-func GetSvcURL(name, namespace string, useProxy bool) (*url.URL, error) {
- var svcURL = fmt.Sprintf("http://%s.%s.svc.cluster.local", name, namespace)
- if useProxy {
- svcURL = fmt.Sprintf("http://127.0.0.1:8001/api/v1/namespaces/%s/services/%s:80/proxy/", namespace, name)
- }
- parsedURL, err := url.Parse(svcURL)
- if err != nil {
- return nil, errors.Wrapf(err, "while parsing function access URL")
- }
- return parsedURL, nil
-}
-
-func GetGitURL(name, namespace, repoName string, useProxy bool) (*url.URL, error) {
- svcURL, err := GetSvcURL(name, namespace, useProxy)
- if err != nil {
- return nil, errors.Wrap(err, "while calculating svc url")
- }
- svcURL = svcURL.JoinPath("", fmt.Sprintf("%s.git", repoName))
- return svcURL, nil
-}
diff --git a/tests/serverless/run-local.sh b/tests/serverless/run-local.sh
deleted file mode 100755
index 270cdf0a7..000000000
--- a/tests/serverless/run-local.sh
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/bin/bash
-
-source "collect_logs.sh"
-
-kubectl proxy &
-KUBECTL_PID=$!
-
-APP_TEST_KUBECTL_PROXY_ENABLED=true APP_TEST_CLEANUP=onSuccessOnly go run ./cmd/main.go "$1"
-EXIT_CODE=$?
-kill $KUBECTL_PID
-
-if [[ $EXIT_CODE -ne 0 ]]; then
- echo "test failed"
- collect_logs
-fi
-exit ${EXIT_CODE}