From b1d886784a43c3c4a46aa66855ba07a34530ad42 Mon Sep 17 00:00:00 2001 From: MichalKalke Date: Fri, 5 Apr 2024 12:59:25 +0200 Subject: [PATCH] Delete serverless and runtime from components --- components/runtimes/README.md | 5 - components/runtimes/java17/.gitignore | 3 - .../java17/Dockerfile-jvm-function-local | 21 - .../java17/Dockerfile-jvm-function.tpl | 21 - .../runtimes/java17/Dockerfile-jvm-runtime | 13 - components/runtimes/java17/Makefile | 69 - .../java17/examples/hello-world/.Dockerignore | 4 - .../java17/examples/hello-world/.gitignore | 4 - .../java17/examples/hello-world/pom.xml | 33 - .../kyma/serverless/handler/Handler.java | 18 - components/runtimes/java17/pom.xml | 145 -- .../runtimes/java17/resources/.gitignore | 2 - .../runtimes/java17/resources/cm.yaml.tpl | 11 - .../runtimes/java17/resources/generate-cm.py | 25 - .../java17/resources/generate-dockerfile.py | 11 - .../java17/serverless-java-sdk/Makefile | 5 - .../java17/serverless-java-sdk/pom.xml | 40 - .../kyma/serverless/sdk/CloudEvent.java | 150 -- .../project/kyma/serverless/sdk/Function.java | 9 - .../serverless/sdk/ResponseCloudEvent.java | 13 - .../io/project/kyma/serverless/Config.java | 43 - .../project/kyma/serverless/JerseyServer.java | 114 -- .../java/io/project/kyma/serverless/Main.java | 82 - .../kyma/serverless/handler/Handler.java | 16 - .../io/project/kyma/serverless/MainTest.java | 18 - components/runtimes/nodejs/.gitignore | 5 - components/runtimes/nodejs/README.md | 16 - components/runtimes/nodejs/lib/ce.js | 136 -- components/runtimes/nodejs/lib/helper.js | 90 - components/runtimes/nodejs/lib/metrics.js | 57 - components/runtimes/nodejs/lib/tracer.js | 80 - .../runtimes/nodejs/nodejs18/Dockerfile | 20 - .../runtimes/nodejs/nodejs18/package.json | 26 - .../runtimes/nodejs/nodejs20/Dockerfile | 20 - .../runtimes/nodejs/nodejs20/package.json | 26 - components/runtimes/nodejs/server.js | 181 -- components/runtimes/python/.gitignore | 4 - components/runtimes/python/README.md | 31 - components/runtimes/python/kubeless.py | 196 -- components/runtimes/python/lib/ce.py | 138 -- components/runtimes/python/lib/tracing.py | 67 - .../runtimes/python/python312/.dockerignore | 1 - .../runtimes/python/python312/Dockerfile | 22 - .../python/python312/requirements.txt | 12 - .../runtimes/python/python39/.dockerignore | 1 - .../runtimes/python/python39/Dockerfile | 22 - .../runtimes/python/python39/requirements.txt | 12 - components/serverless/.gitignore | 33 - components/serverless/.golangci.yaml | 21 - components/serverless/Makefile | 84 - components/serverless/README.md | 151 -- components/serverless/cmd/jobinit/README.md | 17 - components/serverless/cmd/jobinit/main.go | 79 - components/serverless/cmd/manager/main.go | 198 -- components/serverless/cmd/webhook/main.go | 168 -- components/serverless/config/crd/.gitignore | 1 - .../serverless.kyma-project.io_functions.yaml | 611 ------ .../serverless/config/crd/kustomization.yaml | 21 - .../config/crd/kustomizeconfig.yaml | 17 - .../crd/patches/cainjection_in_functions.yaml | 8 - .../crd/patches/webhook_in_functions.yaml | 17 - .../config/default/kustomization.yaml | 74 - .../default/manager_auth_proxy_patch.yaml | 25 - .../config/default/manager_webhook_patch.yaml | 23 - .../default/webhookcainjection_patch.yaml | 9 - .../config/manager/kustomization.yaml | 8 - .../serverless/config/manager/manager.yaml | 40 - .../config/prometheus/kustomization.yaml | 2 - .../serverless/config/prometheus/monitor.yaml | 15 - .../config/rbac/auth_proxy_role.yaml | 13 - .../config/rbac/auth_proxy_role_binding.yaml | 12 - .../config/rbac/auth_proxy_service.yaml | 14 - .../config/rbac/function_editor_role.yaml | 26 - .../config/rbac/function_viewer_role.yaml | 20 - .../serverless/config/rbac/kustomization.yaml | 11 - .../config/rbac/leader_election_role.yaml | 32 - .../rbac/leader_election_role_binding.yaml | 12 - components/serverless/config/rbac/role.yaml | 152 -- .../serverless/config/rbac/role_binding.yaml | 12 - .../serverless/deploy/jobinit/Dockerfile | 35 - .../deploy/jobinit/Dockerfile.dockerignore | 6 - .../serverless/deploy/manager/Dockerfile | 41 - .../deploy/manager/Dockerfile.dockerignore | 6 - .../serverless/deploy/webhook/Dockerfile | 31 - .../deploy/webhook/Dockerfile.dockerignore | 6 - .../assets/kubebuilder-architecture.png | Bin 100523 -> 0 bytes .../design/extend_function_spec_proposal.md | 525 ------ .../serverless/design/glossary_proposal.md | 104 -- .../internal_registry_garbage_collection.md | 63 - .../serverless/design/scaling_functions.md | 40 - components/serverless/hack/boilerplate.go.txt | 0 components/serverless/hack/config.yaml | 2 - components/serverless/hack/controller.env | 3 - components/serverless/hack/libgit.tgz | Bin 1231242 -> 0 bytes components/serverless/hack/run-linters.sh | 22 - components/serverless/internal/config/file.go | 61 - .../serverless/internal/config/file_test.go | 75 - components/serverless/internal/config/log.go | 26 - .../kubernetes/configmap_controller.go | 93 - .../kubernetes/configmap_controller_test.go | 156 -- .../kubernetes/configmap_service.go | 98 - .../kubernetes/configmap_service_test.go | 75 - .../controllers/kubernetes/fixtures_test.go | 81 - .../controllers/kubernetes/helpers_test.go | 35 - .../kubernetes/namespace_controller.go | 116 -- .../kubernetes/namespace_controller_test.go | 166 -- .../kubernetes/secret_controller.go | 103 -- .../kubernetes/secret_controller_test.go | 276 --- .../controllers/kubernetes/secret_service.go | 173 -- .../kubernetes/secret_service_test.go | 110 -- .../kubernetes/serviceaccount_controller.go | 92 - .../serviceaccount_controller_test.go | 163 -- .../kubernetes/serviceaccount_service.go | 130 -- .../kubernetes/serviceaccount_service_test.go | 379 ---- .../internal/controllers/kubernetes/shared.go | 57 - .../controllers/kubernetes/shared_test.go | 151 -- .../serverless/automock/git_client.go | 83 - .../serverless/automock/git_client_factory.go | 49 - .../serverless/automock/stats_collector.go | 33 - .../controllers/serverless/build_resources.go | 112 -- .../serverless/build_resources_test.go | 659 ------- .../internal/controllers/serverless/config.go | 113 -- .../controllers/serverless/configmap.go | 119 -- .../controllers/serverless/deployment.go | 216 --- .../controllers/serverless/deployment_test.go | 1103 ----------- .../controllers/serverless/event_filter.go | 39 - .../serverless/event_filter_test.go | 67 - .../controllers/serverless/fixtures_test.go | 188 -- .../internal/controllers/serverless/fsm.go | 300 --- .../controllers/serverless/fsm_test.go | 289 --- .../serverless/function_controller_test.go | 363 ---- .../serverless/function_reconcile.go | 207 --- .../function_reconcile_asserts_test.go | 234 --- .../function_reconcile_gitops_test.go | 859 --------- .../function_reconcile_health_test.go | 46 - .../function_reconcile_matchers_test.go | 111 -- .../serverless/function_reconcile_test.go | 1634 ----------------- .../internal/controllers/serverless/gitops.go | 22 - .../controllers/serverless/gitops_test.go | 237 --- .../internal/controllers/serverless/health.go | 71 - .../controllers/serverless/health_test.go | 69 - .../internal/controllers/serverless/job.go | 259 --- .../controllers/serverless/job_test.go | 164 -- .../serverless/metrics/function_metrics.go | 124 -- .../metrics/function_metrics_test.go | 131 -- .../controllers/serverless/runtime/nodejs.go | 20 - .../serverless/runtime/nodejs_test.go | 46 - .../controllers/serverless/runtime/python.go | 11 - .../controllers/serverless/runtime/runtime.go | 74 - .../serverless/runtime/runtime_test.go | 93 - .../controllers/serverless/scaling.go | 127 -- .../controllers/serverless/scaling_test.go | 476 ----- .../controllers/serverless/service.go | 134 -- .../controllers/serverless/service_test.go | 604 ------ .../controllers/serverless/suite_test.go | 168 -- .../controllers/serverless/system_state.go | 780 -------- .../serverless/system_state_test.go | 196 -- .../internal/controllers/serverless/utils.go | 398 ---- .../controllers/serverless/utils_test.go | 167 -- .../controllers/serverless/validation.go | 245 --- .../controllers/serverless/validation_test.go | 608 ------ .../serverless/internal/docker/registry.go | 93 - .../internal/docker/registry_test.go | 182 -- components/serverless/internal/file/notify.go | 33 - .../serverless/internal/file/notify_test.go | 74 - components/serverless/internal/git/auth.go | 124 -- .../serverless/internal/git/auth_test.go | 166 -- components/serverless/internal/git/cloner.go | 17 - .../serverless/internal/git/const_test.go | 83 - components/serverless/internal/git/errors.go | 39 - .../serverless/internal/git/errors_test.go | 38 - components/serverless/internal/git/fetcher.go | 54 - components/serverless/internal/git/go2git.go | 205 --- .../serverless/internal/git/go2git_test.go | 185 -- .../internal/git/testdata/test-repo.tar | Bin 81920 -> 0 bytes .../serverless/internal/logging/dynamic.go | 22 - .../internal/logging/logger/format.go | 44 - .../internal/logging/logger/format_test.go | 54 - .../internal/logging/logger/level.go | 49 - .../internal/logging/logger/level_test.go | 66 - .../internal/logging/logger/logger.go | 96 - .../internal/logging/logger/logger_test.go | 207 --- .../serverless/internal/logging/setup.go | 31 - .../internal/logging/tracing/helper.go | 17 - .../internal/logging/tracing/helper_test.go | 46 - .../internal/logging/tracing/middleware.go | 42 - .../logging/tracing/middleware_test.go | 55 - .../internal/resource/automock/client.go | 182 -- .../internal/resource/automock/k8s_client.go | 202 -- .../serverless/internal/resource/resource.go | 107 -- .../internal/resource/resource_test.go | 227 --- .../serverless/internal/testenv/testenv.go | 54 - .../serverless/internal/webhook/config.go | 10 - .../internal/webhook/defaulting_webhook.go | 70 - .../internal/webhook/fixtures_test.go | 71 - .../webhook/resources/certificates.go | 202 -- .../webhook/resources/certificates_test.go | 299 --- .../internal/webhook/resources/resources.go | 148 -- .../webhook/resources/resources_test.go | 83 - .../webhook/resources/webhook_config.go | 85 - .../webhook/resources/webhook_config_test.go | 139 -- .../internal/webhook/validating_webhook.go | 70 - .../webhook/validating_webhook_test.go | 206 --- .../internal/webhook/webhook_config.go | 66 - .../v1alpha2/function_resources_test.go | 125 -- .../serverless/v1alpha2/function_types.go | 441 ----- .../v1alpha2/function_types_test.go | 139 -- .../v1alpha2/function_validation.go | 49 - .../v1alpha2/function_x_validation_test.go | 1027 ----------- .../serverless/v1alpha2/groupversion_info.go | 52 - .../serverless/v1alpha2/runtime_validation.go | 24 - .../v1alpha2/zz_generated.deepcopy.go | 459 ----- 212 files changed, 26071 deletions(-) delete mode 100644 components/runtimes/README.md delete mode 100644 components/runtimes/java17/.gitignore delete mode 100644 components/runtimes/java17/Dockerfile-jvm-function-local delete mode 100644 components/runtimes/java17/Dockerfile-jvm-function.tpl delete mode 100644 components/runtimes/java17/Dockerfile-jvm-runtime delete mode 100644 components/runtimes/java17/Makefile delete mode 100644 components/runtimes/java17/examples/hello-world/.Dockerignore delete mode 100644 components/runtimes/java17/examples/hello-world/.gitignore delete mode 100644 components/runtimes/java17/examples/hello-world/pom.xml delete mode 100644 components/runtimes/java17/examples/hello-world/src/main/java/io/project/kyma/serverless/handler/Handler.java delete mode 100644 components/runtimes/java17/pom.xml delete mode 100644 components/runtimes/java17/resources/.gitignore delete mode 100644 components/runtimes/java17/resources/cm.yaml.tpl delete mode 100644 components/runtimes/java17/resources/generate-cm.py delete mode 100644 components/runtimes/java17/resources/generate-dockerfile.py delete mode 100644 components/runtimes/java17/serverless-java-sdk/Makefile delete mode 100644 components/runtimes/java17/serverless-java-sdk/pom.xml delete mode 100644 components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/CloudEvent.java delete mode 100644 components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/Function.java delete mode 100644 components/runtimes/java17/serverless-java-sdk/src/main/java/io/project/kyma/serverless/sdk/ResponseCloudEvent.java delete mode 100644 components/runtimes/java17/src/main/java/io/project/kyma/serverless/Config.java delete mode 100644 components/runtimes/java17/src/main/java/io/project/kyma/serverless/JerseyServer.java delete mode 100644 components/runtimes/java17/src/main/java/io/project/kyma/serverless/Main.java delete mode 100644 components/runtimes/java17/src/main/java/io/project/kyma/serverless/handler/Handler.java delete mode 100644 components/runtimes/java17/src/main/test/io/project/kyma/serverless/MainTest.java delete mode 100644 components/runtimes/nodejs/.gitignore delete mode 100644 components/runtimes/nodejs/README.md delete mode 100644 components/runtimes/nodejs/lib/ce.js delete mode 100644 components/runtimes/nodejs/lib/helper.js delete mode 100644 components/runtimes/nodejs/lib/metrics.js delete mode 100644 components/runtimes/nodejs/lib/tracer.js delete mode 100644 components/runtimes/nodejs/nodejs18/Dockerfile delete mode 100644 components/runtimes/nodejs/nodejs18/package.json delete mode 100644 components/runtimes/nodejs/nodejs20/Dockerfile delete mode 100644 components/runtimes/nodejs/nodejs20/package.json delete mode 100644 components/runtimes/nodejs/server.js delete mode 100644 components/runtimes/python/.gitignore delete mode 100644 components/runtimes/python/README.md delete mode 100644 components/runtimes/python/kubeless.py delete mode 100644 components/runtimes/python/lib/ce.py delete mode 100644 components/runtimes/python/lib/tracing.py delete mode 100644 components/runtimes/python/python312/.dockerignore delete mode 100644 components/runtimes/python/python312/Dockerfile delete mode 100644 components/runtimes/python/python312/requirements.txt delete mode 100644 components/runtimes/python/python39/.dockerignore delete mode 100644 components/runtimes/python/python39/Dockerfile delete mode 100644 components/runtimes/python/python39/requirements.txt delete mode 100644 components/serverless/.gitignore delete mode 100644 components/serverless/.golangci.yaml delete mode 100644 components/serverless/Makefile delete mode 100644 components/serverless/README.md delete mode 100644 components/serverless/cmd/jobinit/README.md delete mode 100644 components/serverless/cmd/jobinit/main.go delete mode 100644 components/serverless/cmd/manager/main.go delete mode 100644 components/serverless/cmd/webhook/main.go delete mode 100644 components/serverless/config/crd/.gitignore delete mode 100644 components/serverless/config/crd/bases/serverless.kyma-project.io_functions.yaml delete mode 100644 components/serverless/config/crd/kustomization.yaml delete mode 100644 components/serverless/config/crd/kustomizeconfig.yaml delete mode 100644 components/serverless/config/crd/patches/cainjection_in_functions.yaml delete mode 100644 components/serverless/config/crd/patches/webhook_in_functions.yaml delete mode 100644 components/serverless/config/default/kustomization.yaml delete mode 100644 components/serverless/config/default/manager_auth_proxy_patch.yaml delete mode 100644 components/serverless/config/default/manager_webhook_patch.yaml delete mode 100644 components/serverless/config/default/webhookcainjection_patch.yaml delete mode 100644 components/serverless/config/manager/kustomization.yaml delete mode 100644 components/serverless/config/manager/manager.yaml delete mode 100644 components/serverless/config/prometheus/kustomization.yaml delete mode 100644 components/serverless/config/prometheus/monitor.yaml delete mode 100644 components/serverless/config/rbac/auth_proxy_role.yaml delete mode 100644 components/serverless/config/rbac/auth_proxy_role_binding.yaml delete mode 100644 components/serverless/config/rbac/auth_proxy_service.yaml delete mode 100644 components/serverless/config/rbac/function_editor_role.yaml delete mode 100644 components/serverless/config/rbac/function_viewer_role.yaml delete mode 100644 components/serverless/config/rbac/kustomization.yaml delete mode 100644 components/serverless/config/rbac/leader_election_role.yaml delete mode 100644 components/serverless/config/rbac/leader_election_role_binding.yaml delete mode 100644 components/serverless/config/rbac/role.yaml delete mode 100644 components/serverless/config/rbac/role_binding.yaml delete mode 100644 components/serverless/deploy/jobinit/Dockerfile delete mode 100644 components/serverless/deploy/jobinit/Dockerfile.dockerignore delete mode 100644 components/serverless/deploy/manager/Dockerfile delete mode 100644 components/serverless/deploy/manager/Dockerfile.dockerignore delete mode 100644 components/serverless/deploy/webhook/Dockerfile delete mode 100644 components/serverless/deploy/webhook/Dockerfile.dockerignore delete mode 100644 components/serverless/design/assets/kubebuilder-architecture.png delete mode 100644 components/serverless/design/extend_function_spec_proposal.md delete mode 100644 components/serverless/design/glossary_proposal.md delete mode 100644 components/serverless/design/internal_registry_garbage_collection.md delete mode 100644 components/serverless/design/scaling_functions.md delete mode 100644 components/serverless/hack/boilerplate.go.txt delete mode 100644 components/serverless/hack/config.yaml delete mode 100644 components/serverless/hack/controller.env delete mode 100644 components/serverless/hack/libgit.tgz delete mode 100755 components/serverless/hack/run-linters.sh delete mode 100644 components/serverless/internal/config/file.go delete mode 100644 components/serverless/internal/config/file_test.go delete mode 100644 components/serverless/internal/config/log.go delete mode 100644 components/serverless/internal/controllers/kubernetes/configmap_controller.go delete mode 100644 components/serverless/internal/controllers/kubernetes/configmap_controller_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/configmap_service.go delete mode 100644 components/serverless/internal/controllers/kubernetes/configmap_service_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/fixtures_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/helpers_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/namespace_controller.go delete mode 100644 components/serverless/internal/controllers/kubernetes/namespace_controller_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/secret_controller.go delete mode 100644 components/serverless/internal/controllers/kubernetes/secret_controller_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/secret_service.go delete mode 100644 components/serverless/internal/controllers/kubernetes/secret_service_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/serviceaccount_controller.go delete mode 100644 components/serverless/internal/controllers/kubernetes/serviceaccount_controller_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/serviceaccount_service.go delete mode 100644 components/serverless/internal/controllers/kubernetes/serviceaccount_service_test.go delete mode 100644 components/serverless/internal/controllers/kubernetes/shared.go delete mode 100644 components/serverless/internal/controllers/kubernetes/shared_test.go delete mode 100644 components/serverless/internal/controllers/serverless/automock/git_client.go delete mode 100644 components/serverless/internal/controllers/serverless/automock/git_client_factory.go delete mode 100644 components/serverless/internal/controllers/serverless/automock/stats_collector.go delete mode 100644 components/serverless/internal/controllers/serverless/build_resources.go delete mode 100644 components/serverless/internal/controllers/serverless/build_resources_test.go delete mode 100644 components/serverless/internal/controllers/serverless/config.go delete mode 100644 components/serverless/internal/controllers/serverless/configmap.go delete mode 100644 components/serverless/internal/controllers/serverless/deployment.go delete mode 100644 components/serverless/internal/controllers/serverless/deployment_test.go delete mode 100644 components/serverless/internal/controllers/serverless/event_filter.go delete mode 100644 components/serverless/internal/controllers/serverless/event_filter_test.go delete mode 100644 components/serverless/internal/controllers/serverless/fixtures_test.go delete mode 100644 components/serverless/internal/controllers/serverless/fsm.go delete mode 100644 components/serverless/internal/controllers/serverless/fsm_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_controller_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile_asserts_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile_gitops_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile_health_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile_matchers_test.go delete mode 100644 components/serverless/internal/controllers/serverless/function_reconcile_test.go delete mode 100644 components/serverless/internal/controllers/serverless/gitops.go delete mode 100644 components/serverless/internal/controllers/serverless/gitops_test.go delete mode 100644 components/serverless/internal/controllers/serverless/health.go delete mode 100644 components/serverless/internal/controllers/serverless/health_test.go delete mode 100644 components/serverless/internal/controllers/serverless/job.go delete mode 100644 components/serverless/internal/controllers/serverless/job_test.go delete mode 100644 components/serverless/internal/controllers/serverless/metrics/function_metrics.go delete mode 100644 components/serverless/internal/controllers/serverless/metrics/function_metrics_test.go delete mode 100644 components/serverless/internal/controllers/serverless/runtime/nodejs.go delete mode 100644 components/serverless/internal/controllers/serverless/runtime/nodejs_test.go delete mode 100644 components/serverless/internal/controllers/serverless/runtime/python.go delete mode 100644 components/serverless/internal/controllers/serverless/runtime/runtime.go delete mode 100644 components/serverless/internal/controllers/serverless/runtime/runtime_test.go delete mode 100644 components/serverless/internal/controllers/serverless/scaling.go delete mode 100644 components/serverless/internal/controllers/serverless/scaling_test.go delete mode 100644 components/serverless/internal/controllers/serverless/service.go delete mode 100644 components/serverless/internal/controllers/serverless/service_test.go delete mode 100644 components/serverless/internal/controllers/serverless/suite_test.go delete mode 100644 components/serverless/internal/controllers/serverless/system_state.go delete mode 100644 components/serverless/internal/controllers/serverless/system_state_test.go delete mode 100644 components/serverless/internal/controllers/serverless/utils.go delete mode 100644 components/serverless/internal/controllers/serverless/utils_test.go delete mode 100644 components/serverless/internal/controllers/serverless/validation.go delete mode 100644 components/serverless/internal/controllers/serverless/validation_test.go delete mode 100644 components/serverless/internal/docker/registry.go delete mode 100644 components/serverless/internal/docker/registry_test.go delete mode 100644 components/serverless/internal/file/notify.go delete mode 100644 components/serverless/internal/file/notify_test.go delete mode 100644 components/serverless/internal/git/auth.go delete mode 100644 components/serverless/internal/git/auth_test.go delete mode 100644 components/serverless/internal/git/cloner.go delete mode 100644 components/serverless/internal/git/const_test.go delete mode 100644 components/serverless/internal/git/errors.go delete mode 100644 components/serverless/internal/git/errors_test.go delete mode 100644 components/serverless/internal/git/fetcher.go delete mode 100644 components/serverless/internal/git/go2git.go delete mode 100644 components/serverless/internal/git/go2git_test.go delete mode 100644 components/serverless/internal/git/testdata/test-repo.tar delete mode 100644 components/serverless/internal/logging/dynamic.go delete mode 100644 components/serverless/internal/logging/logger/format.go delete mode 100644 components/serverless/internal/logging/logger/format_test.go delete mode 100644 components/serverless/internal/logging/logger/level.go delete mode 100644 components/serverless/internal/logging/logger/level_test.go delete mode 100644 components/serverless/internal/logging/logger/logger.go delete mode 100644 components/serverless/internal/logging/logger/logger_test.go delete mode 100644 components/serverless/internal/logging/setup.go delete mode 100644 components/serverless/internal/logging/tracing/helper.go delete mode 100644 components/serverless/internal/logging/tracing/helper_test.go delete mode 100644 components/serverless/internal/logging/tracing/middleware.go delete mode 100644 components/serverless/internal/logging/tracing/middleware_test.go delete mode 100644 components/serverless/internal/resource/automock/client.go delete mode 100644 components/serverless/internal/resource/automock/k8s_client.go delete mode 100644 components/serverless/internal/resource/resource.go delete mode 100644 components/serverless/internal/resource/resource_test.go delete mode 100644 components/serverless/internal/testenv/testenv.go delete mode 100644 components/serverless/internal/webhook/config.go delete mode 100644 components/serverless/internal/webhook/defaulting_webhook.go delete mode 100644 components/serverless/internal/webhook/fixtures_test.go delete mode 100644 components/serverless/internal/webhook/resources/certificates.go delete mode 100644 components/serverless/internal/webhook/resources/certificates_test.go delete mode 100644 components/serverless/internal/webhook/resources/resources.go delete mode 100644 components/serverless/internal/webhook/resources/resources_test.go delete mode 100644 components/serverless/internal/webhook/resources/webhook_config.go delete mode 100644 components/serverless/internal/webhook/resources/webhook_config_test.go delete mode 100644 components/serverless/internal/webhook/validating_webhook.go delete mode 100644 components/serverless/internal/webhook/validating_webhook_test.go delete mode 100644 components/serverless/internal/webhook/webhook_config.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/function_resources_test.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/function_types.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/function_types_test.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/function_validation.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/function_x_validation_test.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/groupversion_info.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/runtime_validation.go delete mode 100644 components/serverless/pkg/apis/serverless/v1alpha2/zz_generated.deepcopy.go 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.source.level} - ${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 8c9f12d9e86e0412ee870e978c43b7fca9f5884f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100523 zcmeFZcTiN#*Dk7p0tTWA3Jf`iAxRu^&XRM^NRT{36hU&343aYpIfFzcGXjbr8DwC{ zX@;Ed_4=)KI|X^+_-3P5%uC9TCUvzpoNnjvb?$t$=n^P5TWrwQ1CWhU;H{ z#Bn=Pw&~yB2JT`{9ZZq)_5XcGU=6h?l3#mb=ktd*IH|v1VqTc6fY#+z-M@#+p^a|n zhki8D{diV;yynPYm`YuLTzwI5dY5&znjXCRd-C%H)!^-zbc?j#yGDQR(nU9r zm2G;ODgXH>r5vFFO#9|r3>=xAFlapB1)#^*zR>E8!;VZ92VNW3Lv`tmb z+l_yjva5t}y%hX~YS_E~3%r#$O9;Ac$o{Y4lio=nj0MiQy`n2gI;mtHG4?j9xsJWj z%kVvIJG?owz!<;#uVJduekDd?Gh(iUr}$Q+p8XJIxke5t%Eo2FEdMoE$sA|6%h4zR zDB?P!M<)kiBuE^+*@+anr)6~*t)$4lY6QqH&7=kgMF%W1~mf4kdMQkW0Ya8;(slbOoZ5C@3Kn3buxUR zjGZOd@3fvffzdaQ3LqWt7q=ZNW$5oR&8Ki%;OeM~MS6y)^Lmnt1db9S&MM8Y<<3+Lnb@7Y}-ka}ZF-L>+)2Qg)Y?kB92A^ld z1~s{v)ie{Xh9rL)7`@TarXsofgrU+Ou|h;2CVS0qv&5jNy5QD%;m7HmJ^c=p6xQeV zlw9kY-sO0Z&V*UoMkx}65AKP*U_QH|kuRV=99Uj&aZ?C9Ns(n|y(wEvJf4PCvUK?E zVGxb|h@ZvVt}#Fk*NxipU|+?g`mTgnA@(L0yk%WH3ERN5DYUH~km+6BBO2l#e;f{( ztgeC{iwSZ5t(((++CJ?UZGo|Kua&zE7)LE02U1^#yLD(@c6Y~W1FD18XRpF66k@6K z9wF&n8vBJjnLE6eAVkdf#ak{29+19$d8dlmgnBo5%vzvgtYf9`38HoergH5r*~5%6 zmKVi*0e9!XhZ*Gashi1%!m#c|`-(C@7$CGUrmgPh^B(BWKV&cb?euh&5Tz!99qxr9 zpeb~*`Nv#@+VC2M#GU=PZpBY$k$Vfe0?6xax|9@v1O%6kw`^=^N4-NIkiM95OH-e) z2>Xp>JeK?7O5hv~TUo_NR5gX)jWN*>X!Fqk;sSUlOm;@{P&+;Lw+`RnMBNXR50_1j z?0a>-Wn#iE-OHUy!A#U^krX!Ty4Yf+?vZ`-p6{iirUA}p+mvHqBecHxQp;S+1wS5p z!0%+L{m{0rjG1)_y%`LUfrln0-QsUjh`~wId@yn4db74AR{7P>`NJr?YoUV*=d_ni z+YmpdUPJ`&xm?12J%zFVPbM2tCm~|wK(>E_$Ba*_-FcO9-|N`J>Nv#2v3sNBxY_S6 zfnL&79bTidKJjc^Y5zzAWUt3eoik0FE+3FFMT4#T7B*NV$QoL!<>z0(&Wg2FT`)2E zlgM;&r_ip2E0mUM=Gt{FQ-L%5Bu%&(T+(7I34Ue=oLM{Hl>gibOcCn$7ysZ}8`9oZ ze>YjUU%1^vGwfurJ~6#ofzP||EQa|4LdS7)c5e0beb8c$L+=0B@!^ZWK%!U=n07Fc9Qv6%KwZ49Zn7-ySl>qt$j$A2ccv#Z`Z1J6E(yLvV;@C@A2;tW}StXyp6C4 z!?}{Td&W-WO24dH^j*J75zy^>=Gft@ZFVpk_TG~ne4!Pt(!_^}A3P4k;*iIbA?WwR zm4(-_foUP)aXyP>J^5oj3fIblXH=>XoPA5<6ja`$F;C(Uc zcdiQ!3uQ2-5ZEbqMFB@G>Z-wE0|sv=qhD9!)DyT<#?FUmx^E@AK^;-Ro5l9~1F$$NZuQIGiUO-6qNPf0F$#^F_;Xm>g=d7V= zUM#wHOn z6Hru+p=eNeEI)HShunX;5JzVYOFn(In*Mlu%*NIt4k zB;BBeGoA$=l@QZ!Q6(_u7f1+(1uC0vVpp#`SsLi&nzCMG%oHrkNcim-bTt#AvCQNL zua-Z$L*tqp3^ZgR?{a`lKt=RXk1T?~z7Fm!S4|7Q#Rv#*yG z&{)Rs)dGU|Z!ClRYnZpt{_ig&Won3{3yOI)+&cIB$@um8>+Rc-{kWzAC4cuG#e!~d zseq)+{t?2^E>V!u6ghR973*IR#f1(HFe_i|xu*XG@x-vu<`#N`$oac>j>=yEvtiZ9 z>2I^Fzd-{`tZK6HzkBaXLIcd^A8jzlzs*99j|P~xl7s$+xBquh{(o4Mu7cj>k1030 z4vm9be9t?hGjC*Anz;e|cbpF@;_~y^LQI1zpMsv;=IRlM+f_`L)^vk@@B2h6ERq6;z2YIxl zu+I>01);JshbkI#1ba046dyRi-{N)paktNvSV;2^DP@k~cE+{&LeAkcUk>C1aOHtO z6$Qt{)41%P-?edQRQ8wQg;>5z8QkiAr4+-yTiGdB;adgWYcGsvdQR&l$0Cl{NoStK z{=)LpxYZ{;iXGY@*X~*wQk3ZLU{EQ?0@>UxiwpdfgOMg2g}uJO12XQmZ`Qg}Uk%c7 zAu=u1y;TWaz>RQW`b(vvo24aL7>=+1)i9Fb$uDSJh$RKn+-pZo93tJh2Bl5q`0=w} zfAHl_yE%7c+T)S$fBIP(skktAF*L}K_!}g+qwE;K(y-YW#Sm-7*qN8F>waVSF-NJ6wI}I8fM=#j%IIhZD|pKiF3w?^+u| zS6)IS^$?Pkxh=%N)>IHhNWhBql(_oH06H(M~!DC&Z!#5YXLWVR^)E6jpD{F zlez$h8T=H`>(|$EsHmY167~~T3n5>E!s___CkK1<>5N25_=c~0WZ+bArhpYq2Efq; z-_vZh`$E^i3+hP2=D`J3a-QNt?Xj$yP|(S|#Yu=GE5oo}uRkV6>Px^3;|c!c8JDKR zrw~Wp#kQ%<7lCXS)pQ|?S7GlET!tju$)NZ3{Z1+3KDNJy9TMR?!Ci?y&9sp z@HO{E+VT2;cwbkukW8gH0!t)RpS`Sk&Vrhvmq;;?K)E3Fefdm&T4b4EoH_$Qp0o-v zIOubfA~c%OCB$wZ%^$G#){XS!;QV`S-^blI*s|EtNLb`M*|Ay`kb#yDw)}%Y*#+$H z!V5JT`NsH5Q-Jow`n&D?VzfhwGNe*D76)iBlV1IpudzLYU42}(1+7%c%lDcn@?d|PR-Hf)? z&sDo`QayWV-WJ)L5O1gh+T@j>H)m_AiRSmy@VH7 zcs<}XM!!r`6Uo!#*{K(x2XLni%oUE+vP%3}Y*>NLc)8^LB_FQ>pQ4=P&Is5!rW_KK z6^y~L4UYvvZo~*n#>0D<72_v%X+vE1iX29t4Z@;N;@arS&zS&BEFR)Q>Aa5mlGRNt zfP)l{;T{Vulkg?80d>1}#@wtDEQ*X}tarbomtV8hGwx?f_{J@5p26EPL3&evh^wXC zOb3`fvi)ggfoC=6^(2LgSIDT|2pQ%@Kw#*xuHrzgv|pus=bp>ECTyTxS%N$PC-zGS z%>C3EcJ#YiceBDb)2o#{TPq& zMcn=dMZ_sY@>FL>4*Ii`of%OlHBZGCi<8i=6;QxrItvt+jx#k(%Wf~xMM`3pLwJNgy%wF1NRJQumoDP5 z@3$FOB=6(;7~$q!VJnJo=Z((&Z0WgJ$8fq=)9CP9judqdomYrVSR5)HGd*AsTE*PA z-MokeCnH_}+*sK=emlrw+30NM7^ghpcaQ&zEDu!s#bhfqY}EciW22Lf|9i{-eir-M z2nN{?-t9#*a*)KK-G8lVmmJ}gSL}R5{@Tcf-SiA$>`jf6AE(;_K`%}yg|P$bu*Dd+!DRrO%)-$J5w+onrR5-}dT%65hiMbj~^&Cn)|KRR1T(|3Cf~ zNd~~p{+MF#Xtw{y^6+8a=>l-S=j@A$BohC0wnoNwazf_X>q!hG>IoEj{L8K;nzellI;SMfTG2i2$FacjmPh+LEYlaxWt3!gmg$vj{-JCHa2!C0E3_mIC!iEs4LOx3@SkOxj(+0{Kb|Gc#*4$3 zdQ1^8Wfpz7r4p4yA_W2}AFq$=jhQ4~7tN{NVgccFt0)FsoyC`u)0I#d3m&HXoT*bm zdebvy=CR zjeTt4ZhM=x^0SO^8bzsm9d7Nswk$#yCFANAg)fAvOBTH3JJ5v~`QC9MI9 zu!xKH(Rwr}bakd*ulJa_vZVh>-Ou%^(rHNMqCnL!wZ}sgc_dvP-{LQwnzed!AAM0U_wi6@op=y!942cl)*--l5nCqgt@X6n z;=dwFzKrR5FU^x$*$=kWz?T62a9TE;3L@pO7NC)jBhyolsfQaI+?1C>#Ia}U+Apvn z_bg67VnECRI}x&M-AR-`)Tce4Te9Hp6fAM<5WQ?wPnVc`6%M6e)&kg(SM~&_r94)P z`q^s@WO0NVQ4#j$AEWH?IPNH1Ndu|#CNH5+Se|1^NMCF*4tyWEg4PcD?=BbwuXz+Nhme#Qa7Hot`)Z<4C34?I*c=tQ2Z&P^O-XQ_}wkMT}0L#D5-n^5P~j@3o@ae`<75ndyQ zHpqbr1c^5R;VXM63zWjv&te=|_D+xh7nI;QchNj&?v>gXs{dl(az1p)g~{Tu?Ce<( z4h8bgz;v4&j=pNB*paDpcc(OsDq){`bv%6Hd--6sp2(uf@yp8}8IW^F1%i`PSJ>RLKDQpkWvdRxwNTpvc zsJd$2{uccOXXOsI|Y zvn;(Hrp-)I3+@Mu6)z54fB)`0^>}Ab69nIp_(`6PV%DLi{lt7x6MIQOzpZCg9_Ew3 zwR!7;Kz2&T7ZV@pItyQXu7i(Q={2^S+IJqq7i}PIxLc8zL-tzDfJ(TB$Ql8!ufNIxz2U;% z#KNHBj+37Gpu*kFd)n1OI6z|jW^)Mx`-U$~O*EMr-2WgX**i2;fCiy%%#BL%sSa^KYHIw1B7pUtf@JxI zWNcULiH!PeZQ~@B60M|1ocNBD1tJk4P`buLwV`w%11;XUBxwD9dRoa=Z)_V>>v){a zV7R?z9EaE3;PBcGXz}{|d^NWMCfT9TB?!5?CW_+KIbHjo0&#w~;W` zrS!EiUPW?+_Pc(WO$iV|LM``?bp9UB#!Ba}SelEduNu7X)({epW2$qnx|Cq=EUuu+ z-$#?#jpy(^Id5!5mkzA@Im`Q;C+zAu_e5L3#K6zeS&-HsazD*%{V~`h9KGvT$f-eF zMD;%!%RD{_4pQz@gZmR?A>Xb`sp+muf(@rAPEtMX<*8Q_ye92sBwQ0-vy1t|H;)4E z%QyKtt?ZevmiJVHao?hKl%hy?K&X5s2m>rvZ>h?prTiYz()CK}LM*38*yJ+0*xGL< zUH3%!+nhRm_PA*10VomIKcW~35AP9*kiDxqGnx%4a^Zh`mU3K-b78_D{&wHt#Bxfo z=Bcm^B=sYP;^wh~HiDpA#$~D$Tt4$a-g~o{qmqbU>yG4GN)!81zxOpG;J9~Fc8xk( zpS6&AZz_m-(L_>xD=}PcV-SE!0Vn1}B4Vt5iuf?PRaI)+tz05nx-sMgTXYCw*)8ae z9d|gLC-7=g>hrFciHy&M#=>U~vDz~d!ro=hs5;OPqV7}R>A)9#P_+jQ{-bqk;g&3Z zNrx!nH|HbHENY8qB?yxL605!f0^m6?%Fl`bNn2^az`Pi&Y;p<9js$TxnV5VD!V{19WM4qA43dXa_L=E~WV0 z`Rd{}Qi5aypK#{cPUQKw+klzLUT3IcxcFzn(CW*RdLHp)F9~x^qT$o4Z;TSDa-C-9 zhpuNOZF5rvo<~)s^ZkQtoiKkkEaK?PH_ZN3%%pbfJd+5~Q}Jm}Bz|Ugn_wGH+)2@{ zr82|N8UJ_i4WWTeM1wmuK;mXw|t*Je%$^IzD5g~fhC!{~IXVI#$XroF8 z(Fb|*@d_pXCvojs!FiYo9;a>Cl#=yxr4;?7njoZX{f(Q!`{`<@3PwU7%Q6|)GAnZ)^t4&*YOzTW05rRX1)I+xyalP6E{zwKUMQHRPW>pZkOS#HKDSJ; zQzi5yS>E^Xao?e4$JEGpw(G?Kh9XM400Vp~JR^}tAhD_AQk9Zi5-G3^zxtS9X3;hm z!-#+IUD{&42W6)eX4l({6!DG$*z5$=cVYc)=yf#Sks^=!|gG_^4at|%> zd`pBHBqt2EDb7lZIgQ3X-J3A8lr!o(FU+t{2MY-BMi+Cpo0qZI=@!kI=KZ}tE<`Tu` z>nDBi9mf$O-zQ3GiD8a(Vb$rV*GL#L_Vsaj52EK zwr>?!I*VeFg}d6#kV6_;Q<~;MLXT1?A`*ZuJ3PXn|0{(cLOW`{CEo9ogF&pq6MX%T zwHB9_9lbifK!;bz9lCISrkTcnv3xp;;ZcF1d2h}=-R6!T-PZ~*ZI(z}pll*t6YG5R z1>nLSOd7s+)dAwWM;$WWOgo7JjyY@k;$N={R2@7{b3tqE82fNtJO zbJqBskVb!&Nkt3uZ?q~Gq+adeuWob^c18oLhiV1>(EK@MehL01wMLqMXW;9}X!4|K zg>3ZCe6I_$FAV)$60OF_f7Lg1a}3bj&3wGu z?_%md_=5)BV4*q94*i?daaTlFVHmi^{8q^G&x|aj&{Y^w%(K$}q9>iu#TK55BgnrD zq+}X}CNyKztXfO{u*t6~3^p_=>NF^j^>^=41n34%r~~oD-)8xUF1DCr6X^d3KmAV) zaUka}a#SX1C-3h%2(c!#?OW;Az<>At|M8-bC?HSkinEwI+;p7QH&{@4ZY=Wl#1;M)qc$v{#9h8zo82p_vymm&vh04SLF7 z%nGYf8yG_^%rC%e_(ktLEIH|@e)03W-nCePqQ}i0|5_&9UygBZ;|)ecp-pysAc;Y0 z53TXQgM@0SE*Ieocw}!To``OU@a|VhQjg#@*E2l-m)Gq#K8pq{+q6pZp*&A%@u-R6 z?{8@CpY04AIO$zqI}a|0$tGT&WnP5IqWswlKkbDUE)ukV+?6}NqQqHrjK|_GlGerK zob*{Zs>E@@hs`ZQW*uSmWuQv1%wpWG#)yZ!X#isq_bTakll@%07g8LZ77us{WUVyL zn(@}sciY^8E|VAlOK6^p$^Y*chyw;G5SBVOXf8 zjUP-v)bumN$>}|%^C9pGGnSe`C8o4x#K~t>^{^wP>XCfBuHjh6sMemnYbJ-sMVJ1z z@KHju?G#&sc3(&u?q@)5WW^lA_F+#d%B~c-+_Y$1BrkF)lNm+|3$P-!GC4uPh#Y9H zfZ6WqOc6)wrs+KeF%vl+ytDtE%Kx+RyOm5!dMr9FYw`Y+vobodjoOjwP1&(;}inruK8>YR?r9BoYK@u2|LWH-1 zMa;(R)Ulq212bo$F+W+F#4HM?$O960p1JBtJu?>DUIQ%5u5(H^Q!g;`z2#R$ClRN6 zaXs0=TsO&%S`rj-LjX0*>WFMJ+Ri(af-)RHDswuU~Q(z#Dt?qs$FHj@A7!=OurpL^^-K^6f zTc-f}9A3Qwbau%6S^xqQA(qNfsoK*asnR*rv}mQ;<8n(gq%7foi%DyGjZb=2Ks@Tu|;r31OvC+r5Cn$vD^FgrO&;7@3YQLz5!nLTfG;oii$9Z8& z@`CU&2<4TeJC@bosce34l-TFNbZ4XC{EsVK1K?;@$#2a>_G*}m!oVExEZNOOYv+ey;`%?Qu zkU5_5pxyVPq(=3TgM>*9MXiP=LehPig;c4cW6)5eMP|$?9>t+-9wKKN(iV- zSIs6{@#x`b>18mC(%pXc&$mjhC^_8W1lWS6h{dsMv0!obYxfywvhixb@)OC#_qYpf zg1{sdgNpmb7`9O6cZjs95RS1=?E1{G4w>z-#W3JD4ED+SGP{ky*X3Dha$UR(DEGw- zH6BY|G!M!z&f}r`jQzxzF`I$(_RuPLhQ$h|7jYK>Qw@o>8dd$EHJv|Sn?{VS&#ahM zrdztZsgl1VYvcOij{w6lgc+g^igA5+2z9tR?XaxFi1fB<`p)?e5BlG~NtDn5I7kne z(5R5jFo-vqrt}$nefTVXuwc3QkH?wb=|;cf;c~k9<>}vLhFythK$PLSGV=BBXb}>N z#t{1xX>5P^Ky=@MObqB~i5STIt)%)NQSl+gFZ||_Jz#sh5#>#o`8=-8U_ zDJY_91iNc@`Y`;%sb1QM`V@zI=PZRlU&rK@izOGL>ijTztn4|EK7rV!`0bIU?LP^NiJk|QD_Iv%zqs7?k1*e7O$1!`>2bVU0Ph>x< z52H7uk22S%7}EVDDpHQPpX?|tJ683DS|hTzeXF0$Msq%O7t(HGRxCaVRRKBG!q|IZ zuYNeZ9Qn8?bT@AwS@)R7lf7e>f4Ypl0;>9o^%71D+mm9KyL0?GLA7%D!)wB*f`F4+ ztArPI1f3~XRa{Ww?3*x;Q7<|^#l^&JZLtHt0liRi?Q)e3hw@Mvp`^)J)tdSQ=Q{sB zFQKzaTi|)P!-m%dP4+}iWHGXa9Ke}r9K|`GtmW~&+(f15`a^G~(tM*rQ_8_RGGW(7 zYTa98ia8r?9VO38d#xhRz1RY_+r(;pFN0Phn@l<{yO@Uf27fz1JJYhc8`j zur^LIo8}uIGEgP!Jl!C|jYFa7&R3tiBtDK7xu3QVT})JhX=8t}_`2x$h5RHP8L>tI z&Z$+YNxOHsLhhvm9_W*QzCgK6fVE4ow>ApWsC}dMSfQ=L>}zn)f~&3T8>2bcvUFpC ziI(SBo(gq3^mgzf)ZvE|b&q&J?J*F_;pRG}^Oo_ltG)mo@Ri$R zK#a6%w6pV~_G7mvw5hYT8~Z{kuiu`KTSLxDWKjbb)E;6!Ipu~BQXPYplV9ZEedDo_ zcT!KVjwr^8zMPSC`AwvpKMCj;A(#yt>XKw{B(1Sl8oWrSPq61c+YAfYJ*=vZ$g?C=TR1*!(>`qRhpVWgwLaZ+t|!N=U#-ZH32saxOV z$Hp;7(t({^VW|JXajy6H)hX*xKOuNSfas#L5Az6Nd|YR3LGGwG8alZ)`&*bCrOs#!Px@f0^&+xf|)@=UXyf3mhT0qRfVsldK zs@1+jj2ua}YP_ILm$g3Y5;b<3?*i=8Fc_Zgn9(4slDqjO?y>W46v(tXya*^I73~qq zw!k;;v?GhWGC*Pz_j_%g6-~Ciffj39U|Nl4N7{Q;L(>xoLTX}9S=d`FgOJn|O$U&| ztcvPh>&m(6g6e!S7$O9_T zVBusYhDgmQ5hgQmdimDU1Yn?<^d8=1RaQlb5O+HzE%SR#0!#Z!t9W`+HUg&fK9y}} ztEk&}#De$nXdLp(!F&iin852;-*CmYvyB}?){EM@QFe;1#7J@bwWiMYhuJCVm&Oo8 z(%4gB-K7LP%DShlCH2pKy#D$oEVJgz6hol6?sZY6f{#g=#*l=cy3Q1=TY)I1jqPQ? zSrDzKOnYfTE_i z^j-EW^`gka%&|VX*c*+L#JI9F9pOfn)HvLYR{|~k>sHu6gJyip=Wpz=Mz4>X5RoL6 z1A2H%g{9FhAaScOr;2~_;vav}N7xcy7<*8F5o%x8-iOeOVr zw8uO@L`Me~M}O-uljtBMzZ_0|gu#AJcSOLDcNX+=&JqL9V)Kn}2?cyJu>4rM^}74~ z$V#t8*6%xRdPCA+{cQ(rUsRrdv2wb0GFyQ7M7c7DQ;G8!J-(INYf+br9Xi#cyXROA z4fcgjN?}R|{xakm6yuLT2OYlRn^@Jc3%PBM8@>5ixpO+5RnPM``@k-=nW@?5RGwYI zHZIqou}JdhJ%z{{E|Hf&m(NPGuMpw0=ydA&vi^K?ce6q(EW7wn8l?9e#?$fH8ZEi2 zk_5?LTj5W-?b_MLioQT7JUv_Rz5GIgL5RS2EgT$W&M6b&ARO#xSvw zX6yVrml#y9P18BnMm*lh;dW7mx3#N@8)NF%%mkpBx|)m%j3BoW5;Spn3=E}xX2|g)_BA|MpDF^34iUy>sjt$BObi> zT|>S3r`p3hrIXrj_ul3Dy0k?eIBx4FPI29n-|uUAbVW@8{Q3T*Y)X|5AaCHtu_<}b zIgq?)+x?;6qHZ<6W(0^U1`*am+U8!xg%3y{1JtY*r;cCA}jA??@hH$pC~y zcnm>_hH(TzcQ6DX+=COQaol;^F8gMblmW^!P{D_Gro>in;@IgULGC4_5ODf5S+BcO zz~NJAz?nM5BaYgpN;cct#}vU3zc^Jx++1;W7ur*Tdmp}biRbB9O))+4R61`-nMB5H zWYOmR>$X5i5Ln6PKJ^sS)B!O)DVDAlY&FPe|dmyUek| zjtW4^W<2gJHgD@5{~s!uGPo^%aW)QBE*(L`9*9uVJ37GqFdYQMf%oK<&B#l>h29Rp z+IXTsj0-2(396HZCbiOUr?=@`b)j$enIfvi{u(s7*<|g8@)sVhx{v1dOCu-@nn2E*FzHE}T#7qC0fto)deti?dpN110rOpx!-;N3y@SVkq3 zxIN2lxjUB~1B2M_2?SFSCrHwt7;YsD^!$KY`9Ri!tlH!f2KDMj`hdgWd<$_z%%F}eR2bn3X|?Z-z;S$d9xdKnOcsgpgYo`OXv?N~gO6>({lYC`Jk5(O?8M2(Y zZ>KQdAaOABbA)s*;xSgK~{pjQ2WNQ%=jdo8PvrH`ErV`8e9vnccIfrlX4LQE^WDt%>gxT>cS>d0KhA38YeC!&p5_MC9z5{W$8j$F18 z8L!D- zq#p#4shv+Mp=2*;*&^+a-~VX8tl%_f=>%6J6fa2%8Za4W$QHHNHdapZ);Q5@jk9cO zhF5J$Lfb);>bERUN2g=!;*o>YNv(`i-d7LYT|sZXTQ#-%&q$}3`yP5@KW}HNAdE$U zEew1miv#5`Aa(Njs6MAQBPFm~m0c?wt?NQsHg&ghOT#U%-+%cYSD`PV#W(OG-LOl= zXEkiplIw($*=U+v=f37qyY&*(VZ2)prfN&A#Rq%kS^x1z$$Tg#qumQqQiE{WBqKk~Bi&xZECsf`XtO+G&JKjrkIF4{ zZN0%p!6P1`mV*4kR{b$3-M2GTXR1vrye5;As%TaL)Q4lWD;(x0B0>QjQZNU@umsFzFrqYuSF9A+M=9a+(CYwCzIlNnuEmO&|brI?3Lcr%M4X|12D-?2N_`8T8 z1Z>Wqq~<5&toodYkqBsl+QHKT5}Kb!-6rH5%Ac;QB|=V(kP!6uLPfHxn$?TTzyt+9`LB<8fR(V7I3+14u0ou3yj}Hr}*qt-74Gob#Kxu z4#-1cB$PHD1u~bc!V0KWPtYPVs zwOy@IH&h<`hvC7pELn}C*@1A`d$K?5UOiKA59NDBsYwgqZ=>_pDE2djFsynleBqW$ zpisQmU?a!iF@aO`vFRRiNz5Wz(Zu#4$e|2(Bzyzm?5(F?fOzx}aE>Y6@g)Lwa{==G(C&Y#{FI2-=n(OS=py()8U7@`i|nyPcJ)eD>_HM zFbgIkBJvP)P&Y!7A}r+r&YwRtyc^*B;k=y~yyQr7Y#Z>z`BoZs-=Mc4SAqMBPw^?i zxAmfUT*6NdUxpDSPZ^Vx4-gA&20Npd6k55iipuLBgw$b)J|q#N%fL~59%iuMADNbX z_lJv9vaByDE0s2a>Rt9dQ{*=h+vfK%*D*``_j-9Fi{q~NdX^#-zbtc6HxLaSwv5Yw zzpJKycNIMjSf|5>yjr}Ago_w%rh?XeykE)dAEu*)X9^ez-#*ALmH_yDz1y(AR)=AG zRBbW$3Q3r!kYjd`Zu5n)y^RnZOlm#wy(dhl##=z7$WwS!0pGTu_gh z!y8iG9-KREX+H-q2)7b0!?9q3NZkoyK}QUwq8ddXlLOT2>?G#rvg4CljZj{-7q~s> z{{>?sLT?MZgZPn34)GjInO^M4V%zbGAmX^LumLWx3rjZi3+|nKyLS}p8)aiSfeDI` zZTNQTs&ZAEgw{w^fIBN2$^2tW3|eKOwid)iHaHf6S+JSSxTZpDKTdXm7-0PPF1%xm zU#9n(c-G%AesC{LV@6~dfArOkg{1G0q!Nj;>kFAzqgvNoM2*9%w?1}WVu{+8XT3D3 z^3g`uhm3QQLHoj>PwuOcty=i8XIRV<9SGR%HvE*NVD7i^`)$K(D>aW)k2=xxk#;*1jA4?8Fw?q_j!Li~u-c^?dTqU* zQ#ZCx5acdHE+x4Zg?t>t|6y)p9|!VKZ{|}@3UCniUHzQ}x1!Or>V{A*=Z7vP3A?=> zSLnAzLgm>UA{Wx^`V*uIu>s0OyIB{FeYxKXI&|!+3W1s#fJJI`u?ON|@tm zFuq;K88U_p$U*^2Y`DsBL^k_3OOwxPLCQu3VV_Mrj6A~LN>OicPzBvBpGq9=Y}k|b zP@Jy0doeL$&cDM~@Tf~fmBu@>A@MD5{_v5x0fKx)Ko*&KLID}6ku=_E&UowkJ=wjs zLN@_xhyECN9(0a#To$EopUMcW)l=^Pa>NLI__^WOsg1cFO~-4GS2~lZeS76-&~JvsZuPhn&!V-j3MwMr zq1B(U#@m0meEL2%+Iw2kxIkR=+Y$!!#x{ZeHsQVt=*yOvqp{*z>g5(?neN{6p!F(N zx*t?TEtKCE6C5#W6a3Y5hy_WM5wNp9mq_pEWibaV4~siinM$G>vjZ1goojx^7B1Hh zwX(nKGWnov41KLP&OX-}jy8ZgJ+oz9$iC$Q6)4gnx#)v7(b0Wc{)5ULlBqqcYHkvR zwP<%4QS1bDTCNkbsOl?e^RsmY_6bToNUmSDUVh?sAJboeQ~72BHu>@F!NbkeG81m5 zk!*2qZF}}S8-qGzdnPBfv*^swtvcwMvTxC<%MrEGs4cm7{#x@4J(4>6a{9x~a4Md` zG5z-#t=J(^R8;7SH1FAIrN8#km#~d~0fl;jj?^eJ)SAMjfn9GN2PO~1!E@7POOuS6(DcsKmUB%EwHZz&cwm+>`McF~)jQyM{hc7d3oh(7e%VT) zap&=&`6?9pt&GU+$3?K>%R>t6i8Htof!Bf+w9vry=JWilVyBN zO{4>DU*@Dg{w!lzxBW=A*!+K9hX|6mwNz3#A7uWWW5x{0AJt%;{)aw-mc>mY(2BJR z=WCmPiQL_CXs(^))iCeBxc0|H=mN6=zzf`{(sS^YC3v$APo&qK>oNJ{pX9sgW9+D4 z@E1|_8K>Tr#k9fY7Z>|}tq}f7&y5sg{q4)+rj$;q z{TR{1uc+40mj8#dw~mVHYyXB7kT5``RA4}mE)gV$P(VaVx*0-1T6%^d1W}ri29c2N zX2=0)>Fyr78ER;r!}q@L-}5}b-@D#-t@ocusXeki9ljDV( zd~jG~14EC~*fj=0+n%sNNT=*{SODaSa(Z3U52)EO0ee!v)^T?pIbPJiAS$^@w|Z^9 zxZ5UzVI2sp8uEX0lK`h@zuuVH<>t67m*-|1k^;ARJMDHxQCSwfGhRvdaD0OA^S9xe zi)fsJ3Zm~WA$PD6%*`&tWeNU;cEB{Mf)kpL!w1#Ws_m-1H87)s4QA=0-|t!AG%L+x zfrB*U_Tx){Lq7(Yb5VJ0S~+Q5WHRP(dvv*d5f)kDQFAv?)+K?jjp z#BR;FcnYQ7@cm)LpNhG< z)RXlz67ot{R*?6>#X)N?0j>H)1L7j{WcT{g1;w9}Wl4+rWQg%Gm;+9&sO8G=s-soR z#$F4$G4ImOwk5MHP~Kr!aOVPH-=%8IN>4n){C%ktQ+rbYp7BZlg@w{7)|bRHTR$}@ zyBxaZ(BT)-?Mc`22o^2;e7fHfGDgOC>I|WCl%; zu@ zC=r+GqBWKz(a@H~fQQ4ajRI86;hHX1xnKk#-&JVw;`~orKe0)aS+RW*ZyNaG zd$W_ac~Ai3Y=WA$UovsGPSmjm17Y>M&6V-p2vFZ`l8NeWa8!zQeOnieM*ItagkOIZ{oJB7lk{9!n7} zvNbxO3g@b1o7oJg(#aMM0}dKW5CIcXu1QNkwl1!X+Ctu&W5%iSm4@-$m4NxJzGI0_ zX?VOTW_p#LZ1Jt8kYW)PvNd5~2uX~I>b{hS$fni5z{+{v;II&6oBjZxHy#5d z4*rDs|0b~>ILvP5IO8KF!n1KhS}|o6s0o6HIja)sf|c$jGXiS<&<7X-T}s&N2%sYB zLkEg8_5Y0uz|10d)-r7|LNzW^u@O4p<2!j|uY8hjO4Eb~<(NKUgxEa7Y=BiJ09M)a ziwM4)E;#Hp6Sg#f5`juzFIPzM28M9nj!cN+0@eOr5dvm*`5c(p|6k%BtAYy+58hc$ z<{P-~W&{E(r$B#G50-D<&w;7(x~xIRDod!?RJUrjYVskU4J$BH17L9i=;qs*f(ToBQMU-7>Ky=??3RJ8n{De6WQG>>LPy-JU#9_=T63-y6u|f zWv)xtja0HAHH4V)`^IoLyTz!d^W6$5iol$0eSfAJMUo;2+c;tj^{26a#9AjS`jm=K z=5bf4+Id7^@4qdL71n20p*Mnq8^n&I&_nG>A~JZ1p#bX?0pfc6a}Anqfe`{7O_!;< za)8DPAP^eZU`fW_;+y-u({}z^tw#Hj;+SEcP5_GF^N*Irc&a2V{W4(OScyxGKB&ku zvNbAzeZ0cAxo7NJ7kRu+p%_dWG52UgdEvP8(0VKJR1c@?l#6ELZiB~0pvm^VK8hj1 znf#Mcmr8O`8;LT}MUfCQ%=ohx1cE-dZ%}?xDEQ{hb-={XI}d)sW`bnv{0SQqBaG@6 zO7ntk&23)&{^V9rQz^9HV%jxVsEm~mf+uTzGyAqm`s@t)C_&F&*z~LOS;uBd8YMYr zMFn(=#Vl*)2GkM7Fp=O~LyG8Q;aQxPnuXkLuO{f`5ci&}ZarL2P<*lGWRdh?+Wov! zRdV)h`#iG+7f_7}0t@O2My3GEO^?5N@#|C%Ol*O&<S+OSeBb}l_ zJ(&mB7zZqP^fvk=*am2BDb%S#THveEgvV zYj{qn<$3g7cTxPfqq;TCT2p!Ar7EBiD#)^IaMa`gEy8YzP%;EWRxMUdHNviCaSKKe z1*hSGIKJk+{zEc087PYhSn{0aw#iAQnM^WYV zan+Z^trxiB`rV@Q^F*g@{MzDhOleWHLsfv&p|PyMu>gDi;BZpAUc=P}NCCq9A^;dJ zL7t`v1p-QoowXk;eTbdA)K)_<;2ezZ7IDUwl@h!(gfdlQJ#=R~y*g&xX3FA9mPaej zpX(5x7c7raHb6HpOBj8KO>|SQ*k{A_(_xC%MZ4N=_GXE*@ePxq+S$AUxB^#W3lyniyX{kb2 zlD$+nUGkfUJCbB!+;Z|PRpM8}k(M}zs%$Swi)u`2IAs#+*E20iR>E4Hc)-b54aoc7 zg``;-Kz#}zm5hvXmoI$*8YRJe4F61(L6ia^I1N?AxKSl(1m!hcw-wM*eV1|-zXGsg z!oO=TUF#E8#zwH_>#n$WVYSFDejUZXoIak~R{yR7m0pkSy|jWUqr=5wcs-9HRwU;2 ze#iA1Zn2hScv_Ym;B}A9%}Q-aSN*OqBb-P^fYXJ&7N1Vtz-`rcIRX=78q_X5TdegS zcPIo7czu(?n~jm4>)v+bJctk^^Lb3Nr~+-8j|T4!^HDb)4_PE?erDhDf}h4_?IWv%)Zsum%3D83xJwq=p;TUqLIScMlzlO+!$OYDiqu=Q%-MH#WbKQFRM#Kg zbtJtqmF?joSzW+l`(}%Pqm6V!0hWu37ftJ{(UvW!g!fVbSs{Z{B1LPKTeW1|YpoW1?TZD~E&bz2GfMcQOdz344Uzf0p67VHI zRMaZuvw8JJ`NjdYpKJ&N%_+aX9~-D;*V|$QuT1+*mtoHuZ#31byPc0MkLzorKwX+$ zPNHlLH)Yc0%z&Ez87^f5I2i*4sf;*Z*+FwBy_M0+*?Lbo7Amclw==X<(Y#phyZGy^ zU*RV+=#sQd^dIW@8}b!?;XGGrHRaz9jE?;JO9oNRl zRqCqN&WH*m(<@kHef1W~&l=HKKC+=`#{v#l4Nzz_E>`Oh1{eXo6>~BZ03UzEAh8!R zuuq|NUOlB^2Tcb-Ky6q?r24AT-orMg^y#L0QKP(r~pn&Vb!~n%%8%lIv5ZD_Q3L8SrP_2t?3=-+5u8g1xx{}^57IGE5 zl`eSzWf0wUFka|3gm!pGozi2M09Xi9*_qFcve2Yy&uetKm`2!g2%9yq`D|T`$|fVK zABehGK_nMzTZ2-tsmk4=i|#fGEr`C?T|c2jcaW&gBT=U41qHy(c@Ip+j&SA%x$XPp z!iB(KZD1D+S)V3p$ioaf3{Hke5YHzecBF$TF6dLpnHU|n=EI6XM9RNLy8y$zO zV<3r;_sP*ASM;;b6Y;EkHhtw!(d$^aN&*$>U zGiJ76!}T311*Wmq{Dd|N80f%=9KC{ka--bkFEez_hF6xiI2Ju=GFt1F-0wD35cn<2 z8ws6?vFGd+->Gs_`?+(3UE;-mCNPAmWI$ny4{DG0S^vU*~* zBNsB~7=l(In4uTKI7iTFT^N46$_c9x3p!1b9emqe>ii1p*9j6QEnWF-ky&T>>o-vd zpHB`Yq7M2q=E|-Aw!ebVothoDHh-!?Y~{h;_UObw@CpUp_)+3NZkB7BkUlk_6Q;f_ z(O=7?=waU7J@ZOcUF09K7)nVAw&ypjUur^sEyG&goVtAOi^qN)1NE@mo_vW&L{9y_ zxMDPvEwlq8sxPf~+&?$9jBmH#;RpU{BS+}IO=|d*b8g_TQlUF(*zTs@n%0s~UzWXJ zM)DFQ8F^2(sbk9j@yBYm>&sR(L@dE-G4{t-=Z66S@&+o}R=dB6Cj$+emBbL~bVJOL zt;VT$XN0nTMR=R^M~qV@IB5z-xvgo2R?G63O|Rsw2sdEkE;j^zKGRO9voL~ud}A@G z8L?D-sA7T3YardRWiicnc^!90R-h&ER_W4FcW^I{IWxv>7J!(O*sMHV-%B_p@Pgu4 zOE0|YYKX^M%v5^ysf9o_*W@K=;pHEszOS zzwS7HH?v!J0=vk8kZX9>&?3_~K^k5$VGMuvW--+djs+Q>o*tXbta1_dSqMK2^_w%U zjc=XCU5%EP(#h+bSq?R+&?KF zN(29bZ-k>JZDbnM&c<%SnBedbq1H2e3Y@YC5x?m~O>r1qBGJMHI&XIQs8#``naFi% zd>aDjWFw7Ff^fhb!9%tIL8alF(+;|!N{TQ}P}cW@ze^?aMrS3vI*yPRLp?mp{o-@8tc62xW0ei%ab9RFWPCca!_$GQs+$TT& zvFz`b{g*ons1w|OA&pOsw*j%Ssa&^4|9_1w?tlAvP-p6YBbc`d#I!DsYohLnfBeV1 zXu2_{#BBiE8`vqP{*8<-fGhz{tsplH_MY9C1lknlz|WDfHK4#aK{NO@z{PRe%97BL z0%+Z*_2t$Xl4&jQRToRJEpj?nXl0Kv*p!k+n4IRua{qN>_$|wGuXP%tC9q8gt$^{c z#qK2-uIX_NZ#`7ZqN4kSQpRjeu68{~#+PWE&I#5Z*tYI^pXDJVmvMK-I2-E!v8ikX zJlz>VbRH1YO8EY6kE$VG<=k%}vjw8oq}m-r@ZmV)9T%@DmoCA-tA!d^%3vOm2I%oC z=JV~NEA+4oOSvrq7kT50iz%s5u*%9dRpkE;a%7NV1Hpi9H*@+Zn2Yb}WS7P2e< z!C(?QW#Up9;60gK%5Mf0nA@nmP1E0sl-2)%;{%lqBsv;1N*xx_rzQd)Z-jJtFcu+LwtvUXOs%<&}ZOkpI*Dw zW=}~404O?KcTPoW8|txvV6e|0tVr@SXH|l9CUF>?jNQXuM5AjU(*$e=!R@beLsNm> ztx){o(|}lII{3z0Qp9#p^=nGRjp5X>*IA?w3Hpq8`k(;;f-!m?mJD-K<*KJvw z?G+_Cy>{sPip}6}(CU6uRku>YKzGGFeHJ?!YY9%k>#h(qfMmjUav-dW9KY&5V|L^4 zlbX^eZ~@*GMN=8xH|uxwf;Dhx^u2%IgZ@hp!8dDUL=d%tPg?U zpyaftX!Miad0v0ofrm-~9MKgDj0e4r$&MY|er!|>yfGx0%uTdeQIPD`FYkGO`MyO! zW(-Rk>z$NO-xPdSyG)Edp@pFxT7TBk*`y}~%i8TF2x-7TB~&~+xzAs07Dnfw`Y9a+ z#$WOUjz_yq>)KSb#+adUr`biZq`#M>5>mNnB03Wf+|lchC?5WK-rU$5wP4fGviLyI zP;L4eaL;d?1rLwL0Wz@j&vFLJLTz^kOjlMC>k3Gy2nzyf0CZPTN7mtV8a@O^{vdj5+)_U%x0e79~(l-{~ z6&Wb^RvIVtY%hp(r!ym#+!_Kc>|O*y0)k+~xF1#>B!_1F!dk|?&-eglAC0&Qv;3n1 zLN*vUzt?%Y0}0=s6I)Ju`8FnMJD?fCRu*~kP(Gs(RUMmfi*J61R`IT$HECipuogvv$cJx6PAGW3hEyF@#(-@8`OJPUJLiLo^00f|c!c8QkU6Md+(yg&U>^bOTipXgEdAU@a`A#oHu z$lTJCMU`ym!NnDrL9;u%i!zHxDmetof(97gqP|Bu@UD$pe+=^Si1&mL82nXD!ne-p1+6W9)cO_ zFyNceXnvlj8cP1J=`BOmn6jq3Z!HX+4LiQR816Gqu>0A0xX|L-hQ}*kQ?}Z}CiXLk zKn-tAhwTBHo?ecw&`OGTH%z4IAs!Og)822q1v3<Kd-@y*&_wyNE9u5-@6>dGTFdPe0z zGy`1=QKS{~b$VlK#A_lD9-d)JU$U!RJhMQ!IQrc}+;h|BkSBVvAekmc&VXjIt4xn^ zUqVT|2tm#zPlo%k;0VHOSvoxf_d#dg)2k^m36<&N?enhWfLhC^WaZtCV`7zDI}PV0 zrQkhN-(G3j1g)8}%xNk%Yb?8V|YRLuq+ zbBHBRlpvC5l6l>j4(W8=wQ6XH#O?eW9W09xS}bQ`f=JJpT7$T!_^Co9yiNwlCV5@t zVQH(OB5yvZ*q7hKi<^|(y63JVDQqgnD8fbs(ik`PpVY}pd(VLh@C<)&zk`Z0O6pR5 zI}twKCI%gZyvHQO>4NRFMP+$@YIzuqxltycj<<^xi1^#T0rYN9+Kt|A*Uw*$UwHP0 z9=x|L`m|EqbJQ~9mel9B12H_;-QSXr$Cek+r9GNx-kpJ9V>5zT9=ye|Uesq?JHp3c zUHziE{oKlkLr1tae$7fD0rjlL4&$eH2e!MX!RU*jUUnIcX~<)~sm&k487b&Dj~$+E z?8QW|ym=W@JyJSS1K@$Y#+xYeI=qg8y*td^+JlJ)ZWREP6}x00mG3|7km^)Qb$IjF z#nZxpE1Nv18cv>NEwA)I|6?LQSKXJ>`8y`4hs4S`(t@WY3O{T9>NpRd_;VKD*ml~2 z=9VU>{1&UH9g`721Y<^zD5fMYLYHJDWDj z7p?py(5cmI&L%*Cd3?#|F+FGMGb&WF=z-th6f4j3w(eQC*ug7(!k6)HmsG=Q%<>dc zB(8EuSP+w@X4OUx7pakg4-E*soL$*UtKy6zcjh2&)@*(DtZ%t(52e9p?7!z}is11rGLZ4@$| zCf33cRI54LF(HRHhup9K?ir=yQH?Dq@-7-M+!%Z#Bv;-+yrIm%Z=nE}t=czvT_=|y z{;2h(EeQgy0r?;v{=2S!06x9_Y4APRYWWtApGmS0Ef2@i1hcnxKO%1u!2Z%4`vDwk z=Bk8&|Lt!8PCs<9s#kQo`#p02F0nx%b`j6Jzr{51L^5UGMbvB{tILrgWUpQ$P`1<0 z|D|Do+2c9(IEQ*87doaY9uCsodR|Mz@m+vQ>rn6m|j&7xI;vUAROtk zf2&v7Pz>xlAT_xou3VK^92a{>G$!doUBpFgkRmt8Qj{Zd?Jeh`59;CLT)b5}Q zU2VSToyvqF352UoB+6@Ww=ho^mAElE%6Z%BM@In-Coky&xM|i)P?7i6Mf|Jdfeu6XAUpMuo#fg;04RFm({X zI&M3rlfe~`%=#nRpLwB_bRYmr>d^d=b~mcdU14}(uYkJ97JBW7c_$ng32{NI7;2zf z@4fbG58!aG*l58wtOUIJns8}yqn?&D0AkmFQo3=ZC#hXKDOaE|LRs2rmU*Mabe8zt zbyXjY%3W5Nc3Mj4LbNQcJ#5wTtA=6AuVbq)P?gd~U)hBkCbjR4^JT4p5rmq53EO=!2Tse?;p?d^2UJ5)QX zq<_rmsQxYOA?v-G_7nRI1?dpyT*7okL9dnUiBqEm9o>j5N+^xQzU5Pw^nd@ zL*WBkk}Fb*ut&u(rLOY>qT#XAN)p&=)8y9>7qMd8o)wHt8_De9#pKBlq~?O%4gW~2CEB> zF>HqICeLpNCOuZvjrRa0$JljB`G@+MqT`d7f*wnKkg+FNI3W6bh`(%BNcQrPyGB!< z9wva$xMALPYG?eRZ?)Kd5L)BoIs=(oU3!DZSqFaYwBFOMAMo^zm@fhc;FVdK3GIqu zWY`=xydG5!kq3^V+AxC__uIASF6uYoNUm5BE?as2%?t{34 zR%@8qz9ShGqB15q!p^2hg>ZrZx;?f2q`*I_H00wZs<9MnXhVW$!dFii5ya8H7MUy>q*LDti zBIS4NDIz_O|CC7lFbg5%=Q7={SS2;iy>wmrMz#CBD@Nd03aN{H4|~W<$iLnE>u6`@ zDf~qjnOP)Nm{`~ric!q(rGL+_gcj1-SDo#@g*Y+KIh!oxM9T5Qzf;*=`OsNjfJoqh zJtPBum8x)Boz6}syK3l1VJ?DOB@kXnrf!9ehRZP!ITrdovdKqH^GnUeC=6!|2(5WD zZ)4KA<~=jGrYkn+sNq^UB*ZPo6Kqu5Z{>CKS{Rr8=m;3r_o(;3FTyNOc|3Af6Ol8& zOIE|3NgI|b#9?Z+Vlr<1{(^p4hZM4i}9vG>wVOeo!yp;X~$9) zLbT#g^=0^KQzn2%eFqZGgm^Nj%&@cGTBbT?b?uJw8*kxHOm)iL zNQj|*^{yi_(dT-3okeCjgl>M_d07R9dRs9u?3?8yHz6+}AyG~?kofR>@F2cWR8Fp9 z3w+$G%a-FkUmkIHAb7qj$&l-H1}Mkh^Z3eWVz#KkL1&RZWep}(tdcw|-yoU5Lu4#C27&*)qfF1m_piVv;Ymxs5*xc6T+8D4&M9z=%`Ab9}UH?oG+u!?U28J>SpjI84bxWW&l^L#-y*J`!N>@XTA>^+!<6Qn&+B?|k zm}7ckPH)1*T}!@p5_o@5(&pXsC687 z-%qyM=AeR1lr)fLwE5dRY4Ao;6XOpyxBK!}B7XQ&!dw2qeWq(s{dEhi$_}4-BwSwc z@ZoT9TZa1PZ16pYo$-1%ErzFaYlEIDgEgw^h)piWDNhp1Q?;H>9bLW?vJ$rOQss8Y zQSOYn_eUfwT)tM`+P`AxCX(9Y!Vbz)BFm6I-Tm3`$m5kuPtyK8IZ;g!f0u<}Ll9lo(nF+ohWenE=&efMNx$}@Foh?Zlgf$z>P14rKWN979HS>90drVfc1Kk52lrgbR5<|%Cre$D@Kz~}8LTPb^N%-)Lr=H&aO z*W#R!88-S$Ov*<2MUPn~l^;uMM6YT){H!3VQ0qk8%9qazv$r|7(knr&b_p1#maZi4 z^`ok?UKFi9etUGs+s{y+d$O06tSf3Pv6D&f;OdP|#k6Q4;otMe3pK*S?O6p#wXejH zK*G>DVJ$!sK*LH?pc%)@{Bp||gwbQ^&-&w6Z*Ghk*Q%psnazQ234P@a`QUCbI5-1+ z-1XSx@g~C%eid_Bx%02vKqT5}+YRCx+`cmrYNim}UXt%h2tZX;ej)C%|965l^d{%P=u^}&3REX- zG>-yh0p#C+w8iWHN?QQYj;eiw!+&zt+9PKF&%r3*GE!sLm*mMm(Y6==6>T%ZtO@kf z0vC6xLTx#L0T;MadHe-pb;O$AfQ+uD=QxlLzxlS{zrT!UYhw!V#c3Um)&<_%qJ>1* z0&H23>NLIiCeUK1IEPpwBleiH?^ha(@72#){kX#(UsLKQjwSejTsyL{M{j z-2B|^D*zb%*EQBI3mv|T@?1DPsOjQtK^r{@!>oQF71#Q``$$P-ftzez4{`PdUer0B z!A2{yIP^gObO9W-8gxhsuTSf^W8c(Pv*^TtDFbOdX?`>91vz_2d*)DDuk;J0;zwXCW1%v`Xt;W%a+CK1jI8qLo%yn6Ehpom*DidWa4l= zBhlk|QZdJFRR+0KJB{ndMG#hN)=M675~1PzSRH(~S+`Q;F#5g(OV-kHI4$GKmb zgqFJlk$hsnGmPmeRvx=NL%zAr2KESa>-J^jn9?(N`hpPzl9`lSqOShnrf18WW04;Z z&Fn`;1QGyV)-CJ1zCh7M7s4;gegb2BbQAjAbNI}CRgkw+S?!;0Pj8<3t^8!I3cVOw zeeDAedcud~KK7ccCj);X>^-Ne%hIkrt~MDnIA(2SSm@Kfh#&kKsOa&D)}Gi<@ruJI z&6!leZ)ijTY(jt`KS9TIr^sfjhfRPY zdBb%-`2i)OS<8ZY1Pz2_gQgl{{rbf%O;Az}1A|@izuRAG)_sH`S7`SZRPX0sVbWT2 zqbp;Vr9M7O3TWRST7~HAamz0M6x;n`vdM+CnTA7q(pt4*^+$k*2s7-$Wlo z(oYmfw(N`I5be@Lo--5-YRHe~{w>Zo#`fp$Nw zJL=xTdlAA6cm%zU6ZWf_Ca0NnK5f}N8532f$EBH;);<&n4aVgEl~<6XQtA0ttUB?0 zNi!W@$@G1R13xNSXk5~BPt>(f*`h#| z4W;D13VWpXm7eEU-+z~3rz%cH#~K7*f0+He_$q@wB0GnjB1x|4ne+SKhw}h}dO=+g z`7?#8>LnGaKR;L)Hh}m%H!9YNV{W=$b{{zKtj5HtVXY&pXDB0tR^dqZ~5IzqXS52}53NcHw{ zoh5;f&kzSbV0cD!x168I*GSoyh+&4Fl1L)4vZftxt#VeP=DVBcXpfTzQ2CV%aZ65c z>bu;@Ro@YVZ&xH88T5&}c^)6+R}3VTu33AY%;v%eg;RpWRkB_`*Bv5&Q!%d!Wgl#6 z86=b+k@9oM!iW3L`ATTv+1F>*_SR>apYRaFvQyH{mnXkzx6!*Nw~(oV?t6S*k`j9o zos=@YnBQ2M-9bgt;dVKXdYefts3cpGfc zVLf==dU2xM2wt5s@4!Ryht<|_Pv|{?oqhZaG1w$e@i2H$`!*T#u$qK`n9U_-Ww-*2 z8uB7|ZdYS^L|=vb?&_?|TZ0PZd6q%YRYs++{*`F5m6G{DX7AH#3596(fu7c-EgN`n zHMLxW0YT|gDvs+833|A{mq=|Tb)M06&EVrN!+D*&-8a??^StP*7dyib(DmcTJ{g*k zZQL){_$n)TFT2d)xh}rK)!6_GS)7jW+d>#->S0zBBr+*;?PeI z^4BF?u3&iY=|`|)V+p*=#s<_9~n_{8fDP$*sjV*Y|yc zw{oz>>4YGl2#jvq^Qw*y-_jI$Qi7F8NUEIMZ$_3|$&4vQQ-EFHPs|o-?Tt?@>cMt% z{bZS!rHjQujIYyub@?BpbxOX1@t=LCK6%?gke~DV(VXQRU)6N`% zc%NDmb^r8{ZXfBC5-y>s7r^C-=x$CR|({oR3p`-vdRGoijgMx0=r ztns<(h5ME_AHCj++pw~8(&6}lsk^I20+t7edv@NVX3*VP6$B`Pfdpb$;Brn+fr}RM;;$ zXCb*3lIed(mtRTQPw&S{O2C#YEmXp^n?`^u*;k~OPk_K@2q7Y6+q&%)NSs8zKrG49 z`8KMv2#y!?&Vi{kb_(6j0y$W-?HGIHIAazIiTESBi+fqQKYZKI^g!zx-T9jOHmNYP zXOvfYO`|F)c;DztHhoU5fS2^cfu=T+ekL<2)?@Kof1F;dr2jy#db_I3rLc;wmOOz6 z3pBI&%8J7md&USV{O82ahp(R=e(|a4njh#TRb(FQ8c!ShB!Y)Xvn;P^*K9P!hO}lE zr@x0jPd)sgfGTIDA(alkAKm!qkKEl9%a+VuTr+@+q)|;A~(nPw6u6V34vds(l2JZ*DgM*yhcR;at1SJdxA@s~O14dW zDCPF~>S|KXx?FM~dqk3z$^=6kAKXdr0xIY$YoFE7E1PY*_s>&B=l=fQ&g!0O? zAE+*^4Hn><8SY%F-;^M@TS9=kRqQ?>Qz*4*-|pf+Ykvx+v#^Ie0iR`;@gz&IW)mP> z6JMW?Xc=g&7gi-+QIdgObr)vyA$#Kqi<2dW8bk<%lt6u6m0p%9vtsE(tBv-ocIN^6 z%nGagvGd6}Lk&Gqi?LVKu=1lHV_YZ^aUYskRTG~fux)gpSh4XY_ifU`44Myn(2!Jv z+Cyr~=BI;?12-mW1iu8nvXyk4fywn;VFym;Ek__@{Rl4evOVcCeP zy~o<_o|X(st`BecU2=Iv2-1A`&*13CGncgdC+Resm;JsjUg?ek3CO!Arig;YkBQF{ zF8G7MI4=3JcsK*GM+h4QHS%py_=3zUh~&Mt?@@ycDM#*3R}mansrXZd1m)+EeckV^ zNdrSvcPGcG;Qb4m#$wNFiZdT2k_0CF;H=-1@5t)6KMLB6Y@h~*&Dl4Q`&2lX+cI5( zg$ff67w38(a6xTkD|!uvh{5%%d)SfDq;Pz>sJ77-o${T-s@n<^JK=v;Yc4%hrdo0TWnV(gk0`N6FF+@ePa7@G(W&#n+|p~ND`1AejsXXO-VaX zAp^Q?KtDdZI58Ur-r%NO2*tNQNZ>>4^^$(C>!%v(0H@5!AVhH@Vq(wnb#YN=KO?W2(0!r7tB~ zu7ig-{()=zMbnGmm<>V#+P*Ds+hcynHS|2xZ8*s_a9Ut6*J)0mXN(hSW5^MGfx_{X zg-OZZEx(I6g@Z14Z$0^pQw~TRd$jEJ#jY#udW21V#O!J1su)5u?4^z7n{rlfo)ih$ z)j)<)6(ZMS6@_}cUOWcXHoJrJ)ad&d@0uY{(&GR8hh_WX+TU7 zLH6Dz#pb$kLeDMwqTLCN(b>Gf*|k5$18*m9M+to)Cm!l!$UP(x5`4ghYeZ@$<-J*kN8c^U!_uC}{vHOq>bdb1fgBGS#zC0_H~**fCe#VLDGM47T%7AEG6Ku) zdO8P0^aE$>p2XDJrq-kf9v9m*$!h)+O}KcQ$=-cwp~-Yg-wxOu++Kw$cp9GKo0Q*$e zDs?-eQ+mqPts=0l!g#%4*wWK%Ka?x|)yl5op^KWo3?gXIOp(N<@(MTca75r3v#WWy zE1pg(zuf||DcKBi?j7q_VMbhF;@1-qcLXN!g-)TXyRh!Lfwj%Y%7x2dM3O0nJi`oVI z#5wG~lQGU-i6LgSxN;RG9!#@A(jS-=Q=H4)Tamn1gj(-Hbx8d*FW)$!QvQmMhk(QJ z-ddddwhsu~!Fx6|7aWS7Onz)u*b}~w7oc7u?r7gYS1Na)(aqM+dgPWL$OKfbklIs# zsC9PL6sV&|U~Kev(j~(IUOJT#y-Nt1Qn9@c8M5B{wAszP1-qWrv;P*CbQ1b{*N~>U zSuD4P8%hJ#_if*CoMT@IKNL!(w)v}y94)GK=dn)zLcaF)4jy7gh<(OBa=zreJv)zc z>lKvWVY`CDfC(8Aj??@>a!=?!M&z?)^xmhU#I-N+xvF>H`S7NHnRmGV!1bE}1z3}H zMLRoJYr%mtB=JlLN&XP*ItJAuLd=Zt=`h|&|MN)$=t5W4Zg-LkI$e8)s2RP306s(W zaqltEFm8a$156O}OFBAYtbT1NldvK5bouk}FJa@UJ_w=riT|~m z{8-q>g#(^51)=2zCE{4G9Vf;Ko4!hbNT<&Vkzak=t&Y@fRa4Xe!iZ+rz>n^NriK)? zoji^<~`6#gg4N;}rBOFj0WkCZbU?o;>9#@(&EY#T>?@F8UsV4%7 z(&y$z;m`u48^5jMuaYtE@EEX-Qv#?oVt4Bz%7I<%E2D>PqId4&0nNCwcL z)``?AnlBNXagHYcfs?2PJT7btuQqQq`uYkPmd94^8l55YNpH>_iwg6?FrF|sC0f-ioxl6k#mj;ae zH6?MJIBI)ScE718$=mB>@*7py$4IUUmzJ%Gg;p(y?fO%S7@V6Yb$!$%4j1;mQgrEA zt+b9A-jnVAIWqVPp0_u0kLtUG#AZHf#6ua$0p02_-qz1DyxO*JzE@N?SdFh<223NG zZ4XIA)&!qBDl{I!j`MhtUiDp{N;K!1KIay9Mz`!8SE6j6|Fp^rwY|RRyZw0V*_|7< zWWIAUyL4VQvY4e;iFEHUWV=qf-iI`KPkUdZ23?B;*r8h^;TjFVtv_x?`R?|ORNVZb zV5f)Xe^Af>mgc{;t!V%pfD$R)i2d)+sHVIDnka&Da{v1?KX6dFz{+UJYFzrRZyNmPCU$knJ?-Cdx$pl+fBkuYfWTcoj_~~V zXVN9V0Zkm_Y8wBuKX(lu683=yg!kRLerEpK~i$;lIYY zMto=Xr1Dy@TiC)FdUbW)JT-TW>> zX=(XIN}M#l?|J%aPiUbE>)*axD@NnA1ZSs^jQ-!#nfd+a`f6rpFFEWYk{kw}m$+&N zx;`|``aU9fPK2>;G?F^-0nM*k-6XuNR=p3twQ#?;sf0?5zI7Du4cR z&_iipJtL{W1E`#v&c_py3Jm{4#ql)YQsF=Rmi_jo>yoF+s$Bn>ca1vm>R95CZh*;+ zh5?-k%v&TYy752lx+=iSgLK(BZm7npCAr569lrcW@Nd{8>qdAE_i~+p+e1=rsIo{{ zlkoFD0`p=Y7_F?KQw1xq_Vxf#X_&z~lb3I`ujez17c<71R@y7Sv+as7TGywI4&aVp)THFn6ms=8>I=6>;|Ft5IU)^;k1KXXgj~1T} z6d0qQ5%@Xv{?y1`*bqg}jZ;DHkuh&kaigGi#!vDr&WO~SLr4^DVVp5up7Zv{5k*&5 zyHM2o?o6Pl?0zIOXxtGfQYkiF&09deqTbxlc1g%p2A1j}9-{e+tkHU>nIPpE={&Rp zc5r<6o$b{`O#fH|*ar4lvEAb$UD@!5(disyLf3kcg!t*n;Eka_3NgY25)m{-QwP5bX<5@HR7Q2vXY zYjrp?c!)#SrbfP|of-S@bEuQgLELAiQ)+$RO_hW=Lg*Uo+12p<@#D-sPrTD;G-dqe zYzVxb0bp!fz#V>@8WxEV;shUlO}IOxR(ZKG@nU-kCg;TPMQzsYBmf44*jmyxrT)cL zFYc1B2|&xU7sRX!iJZ)PAE(cEZjSkVi{(;YPfw3YIu2Yno|!cJ_C@$KySWM3KH2s1 z5jYH|JvvY|<=)MF2@&}Y9#f>akVBFg7tEQp6|L{x)=)LBUTHl!KXEv3t%xS@lOwqHnz@a%^g|%(6ClhPB=#X8(iacoRne=DroA9r-ROPvX{q*<~>P>vS36 zT|*beD!UP^zrNG@=>hr`t~WG$H(l94sD*iyeo|PVOy~N~%12xRBg-GKa|7z8RHm*+ zpU%Dta6_PtDTLM>d(as!Yt!`Ow%1271w>3%L5gL{@uaWLE+a?1VdiSe_L9TVbHp$I z(MSD^H{7mkWmRuT62M41A}+C-dR5M*P~Y3n5PP~hHd`!k*#0S_Aokjazz0_ z93=Voy`rgfeRF728{RPt>0+3eN@t!+FwiW;75}3acI42~sBUhHlPBCB}RkyYp|M zFsA^7Lg7QD#Z1~cni<|N;f5(Un|9OdBoFr@EOK_ zJ-CQD?>Fe97E)zSUj;S9;qZ=m59V{(9MoX!who=zY*o9mCtFR2~jSRN6K`g7Vh> zx2(~zFJzy=4l6Q5?{nr{V~&>TW=|5IPOI$1kt9Z+nH}+2ye3PDYi@QV1^+ZmKPU`l zYn&apQUdH7Yg>{tlf_Rdt9yrhJH=8msu`J`_z+$ zc)zla{4!aKpdRN2Ly|k_B63*z6m!b(a{%g$+!M0%{Ji~xTrUrM$|5k_8^3LqQ{S_Z z@3?$-@77{?d$IzFqzLR`#;Wma)bLL3RF=JHnnbeeMxd=mXpeOLfsGH6o!Te3s{LK) zDm^N}|D9`kPi+$P<)z4Fm8q;V&D)gC93s$?=gEmF2ShEb5S()0PI;6w;TU?DLYKCF zq%^zhIJcqMu=y6s8N@zm(EvRR!_%M)T(S^fyjA!`wt;d`9G9k2>?xgOt(N5ng7u2vz+^Ch1Ym(v+7GWNX`GaF3@b~0UiV=Y+JZ}IqRo*AWV-X1wK{D{a{KclsBf*#Jl zYbjyXs2o6L9{`KY5A5SYzJT|~gGL!NXvq&M*C0Nvg_X(2u^S3CSc1 z0^7yez(*=|atrOV;{T?N=uu`=)Wd!VOv$=O{%)&$zZ*sG-WzwdDPg5F7DxhWZGg)3&A__Acr2O?bM6;|fxYjpbPoW4Ih+dqWd1I~dcWh^_OnbN z6@j|=@}X-p*tNO3fT2BxU_d@f99^twATyfSx*BW5pdSTnS8Es5{1T#4_stWVR>24{ zGtq02U}JAuji(6mOG(}IoOP%jKB&N|Ch<8tav#v-QZ0NzDC2L;ctA7Gj0pkCunH-6 z6Gu5uOQEPP&Z$#;%lBr(zi3-4Pxf1l@sq|rmf;O(V?>=1X2fMZb+5(?O!z!(3wiX+ zC}5ecgswt$Pvh<$lXjSP&8zdJsJEBv9HxnXozf&Qs`FM8NA>!*Ov>X{eTAT57@Ck-;Y@|R38>mJ-ns1 z)t_mAQ7m&nX=Vi95?G&&xAy5xN69cU8(YzYuJtob{WJrNzxO_i7OLCTjc3LTc>?Ih zaz&yW`^GuX400T9Gh}V^$gr9xZBIx3OchlG{%tR5g(t!=NbsW5=bT>(Z?tNSK`D0t zYT)H)w~xrseK1AA_|;AGrC18D336LPV%Pz;MB~#s-*&0sv`ssD{mhQ_r z>TRNkz381PrYEl7R%|FlOSEA0QXj((g6A%$$-*kKMA8}F=?Yt*S!*yhfAYBdMtq^R z6y*uJ(B)|R$PV5UhZ@?%yY#0$Ynn}8mN{TgDXTCqQPBUtlAY|f{b zCvd_R;d&bUDdm*lB!6|`${y-=^ez%o>r1(+cwE)Anq)cq>pJ?BG>=%{`vzP2kW#dt zL3`BpLP_A{Xzk6FzwRa?D7V=BPDiKr9evE=CfkmZ)xeRlE2Ph7G!FCI#33@uf&tQX zJ$G2Xcry%c%|O5H)i9)U`9bH&dm`jYU|#I#o3me}HuvEYR)Bp8@PEm_m))8c-K#D@ zxCrLKz>aeQ+jp?{=R)6`2*KNY!`!oq`M zB71s+dFE?5mAW?LDu9PNnRzIz6*Hj}K+%xDR1x($VvsA;WOAX>#djkZ3_c!z89)DF zR^m$c5Ly-=3NlG%t$1LUHUGt_*ZPEC=$*x2IH6Z^t1A8@qskr(LWAdyhDX0$vIXm^ zY%7=^fA+OQj5`4U#MOFCJz+F7&VXPNuD+9ji^OtoSWHZq!dR4fcm1x_OnWknK>I$w z3n)XBR)Yj>#ff2XYoJq|Bmxtw+ZD8AL5*PS7<03;DvFZX0hv5>45>~;o?-G=9G}46 z43Yi;wsL;2o&ezdJ4_?^iP zr%PRL?t9S~te*tqxVB7PCR{S^QW(GSZ6QWZ+$1=lZ)vvJ%0Iq=+s@8J% zK$n{B;!0()CH;4&i#+qr(3$XOgtfHpCT;K%903J#f!tI|{lUtu8}87$?xmC~uIN>> zQH*24g(p30Q-O5nTo;n>BO`@&L{B;pqI0#s1I!&?Ojoim zzJA#xnE8;4!)ckk8=48{`9#8FsIs?Q{&v^%XiHzV9f^Ll#%>d(Ngz_vM#l@{2`7-z z|7-&0*U0WEGd@kmIj*u9YInIEe?6vY;!EeA4Mz9q1lyM{&icz}2U=V_`n8&&1Zse0 zW&)TK(ra02{)zB)8 z?ahiNiGAs5X96FH5K2Gr-mVK=sIaiilq%P<>o>mje6+)+eX4<#mz@YZ-I`{eADgM0 zHxHXI80q9-Oo@dXCgVOqE8WgM8~5~Oc6oRIp%PH1Qyf{a{~pzom+cMq7n{2=>~|yQ z*?KXv_G7`eDD|^U%j~CHlN87_e#QPlZBh%Qqxwam`Vs$6ikVWgmEVC6T3IfKX)`#e z+1Wenko3^gu`WsPyW`andVVEDA1j}`33{?{z!KvKN&h9ROGMhsPwr*Zt~8Ogbzkq0 zXw}j^v&D?e+i;37${sL-R2fTl;*XaM*1& zrAxnk(A0k9zVHS+r;fX%Qc?TT@%QUMx2Ls`SvTF=M?Y}DioQbFpQCBR%4U?k>Pb~) z+`96Yhh-=Qnc6hgiZ;%~0#iz74A8ruE~stdsQ? zqS(+diDANtCcmZOlS`~|1qH0jBicFw@o|nFJiop*;M%qjwW&z#rt_)3G}<`7_smjP zMGZiZM-a~yQ%-B_fwu;cwTeRM&6w9m%z`ghAyOySHl$IO)U3yrMcI?r&O({wqH@3M zN%zZ>X?2g&u{A}#=oic(nR<2ssWOkYU$R>l1ej99WskMg-@aJmc3#vS;IB*1V+HV@)W4gGCOn6dQW}vkELsZav%BI-RGW)H;kq z5(eL~VUp86kCGvPiql5HGOtCh4BYrPFV*`yo^P0*Z_&SZM^3~Ulg zcP5|vT?>v1_m7Tf>^Haew;I2M#4qxB$B&w&y|VG`bzEdRp=+6F$iLC}EaO~0|KYj; zr|-M(0T8VrhHwedlL=%4IiBMonR~iDdtxWc6c6S4%Fw~ncu$5_kWfF$b=maiZSgIf zS+P9ODN_p2G1qxjB0*PUMDplCd3FCl{?DM#?Sa%$Zx-nOq*$C9D+OWdKh<#CH>|Z* z1&3|C@Tpngs~wQ_zxW3-c{@NK_b0;U)k?7cxqq!03pH5YtG8@5Nw~R;%DtNVgH=54 z2Vhkyu8EzMpJ63Zr?&h=0xswUah8$V*ShGqzB`(_?YCBcJiLzlN@)!?ijtWv4q(C& zL-&m~=Kfq!V<9-i&vCn2K50%S$)T5>QHd5((v_Ja^61#I-}`_OTH84c`X0Ki>cExm zFPKh29E-*>`dR265dqmvF3p&gm8FO^99FRq*{@P;SIgiay~h?@*J9oNxF<)^)aWzx z&)Aj4gGSBjD6cR1O!j^et>1p>(z&leG=OG)%#A@>YSM$PyxOqJcXo7eV!}|1oLPvp z>i8jY1A_VXMqtNShqZrpW9tv;xbdkE3 zn-xr7(HWTe7>D;P4bL>$j?dU@c@O#fR&0lC6IB0@x}71AS6wIPzJPm`S3^{&;j@?Q z7b{}Lsyv9@=CnX3$u`+9>w=vVDlrwuQCA1=yxwmgMo1rR9X6QV3>;95jBnSq*zH`a zO;2S6`Vb`Ciq~H@RosXA4cG7i8*QxX4@WKfUKD<<+@fDEDShT^w~Al9yYedgc0Rb) za3Cddw7m@{{1!xs_FfcPt_^0&UXMW+o4GbLpT?>xr@wR14- zRHHO)&GjY4q=!Ct|LBZzoxsEOQXPmfTyOoCJgm0rtuf+NAF{NM+Nq`YkZ`745b4gx zW$V$hiyEec#bY$RgnzXF*H%7@Utw>OfRObb7ps|1C&vk&8d%##KI1?I6s}=tYE4El z_Hqik=kMb$)0v*1A44mnY4e|qKk(K})~PyxDHgoYJ6HYy(?jSC?uuJjjdb{9f4j|K z<*okFTnRsgsiYbACB#BeSHhcy?Pc1g z2ShH<_oIVJs>dzn?X!5DVIG)`Pr=EDU*zOa`1}RzFRs0C`C7Al@`=GopWp{tI!eh@ zkCse^Ixim!lU6-7zYwxrTh`_pO{e-ub=#>EjFHCEm?^Vem4;;$I1dXdlt96SeyB5L z9bf=w{YzholmOjqUa)#Sj@l3e-u#T^PeOYNdX`5RQ-$H^NDCT z{|m2|%K(4U`FrN~5vWre^Q2{K{Y#8F7XU=mD=M-?fTL*52PjG=cS@IcF9QJ*@-GQi zjbb>T)O=7w{j&F^DBd6+@#bIDTInVG%u>`P!>gN}lk%0_u=|V28si4X2c6??)(>B{ za2$b0qxg&M7Mmfm^OqmvrYmh%bFbe0QEv}m8=$~-dTF`Zp`@cxw7HD1rTmbWn(V!1 zNGFIN>s%Zvr?yz}tQo!fu85Rdxv_@UB7Rr%!<(x0of_B)oab017duFR%e>kw`(^Xe z%icBt^L`d@=nG!QmPxNktCx6AcBfP$;i4sD@|q|v<72w=Uz#0tQCV{S!&p#-n@EA> z;-fH`!+dK_O>To^NF&dgFEY1$TPDyys8W1^6jslDV>?MX2fF3P)`t)W93e@e#4+gnV z@R3Hod5+~={`hqKr~bs60O>iSJIhJMasp;d=KRj#8DFs(fanKpEgWSQi$8(zt*(+X zguFU=X^nAKc-BDcYX!txtz!a&(Tkh6F8>imT9}Pbz<> zp6kHeafO{}DO&lKi18smcP>S@XXy^sD8M}?%cP#?dE4t@6gF@;au!Y0PKzBcp(h12 zm?1V0YpI3cJ)>R#`Nl_6nOQr^=rNa!@-wRDE-Aiy@Jd_s(KErFa*0)g$>ZgVy!0a7 zc&K6`()5vPnSO2}^`NeoA4CPibAapJ&D>Uo@5Qaz-lc11dW{5fLJYz%5(bGmHddTX zruO1|q|C)%%~38`&P+`@I=oY}xDQ@Rsywb1J+WVJn$%aOP_IfCK$`KKa}_O4bkr?SqBQFvZyIDGo~Rx~gxIT6`l@k{Nns^4 zTl8j>RrbvQ;d;)i5qHaU_`_-i`O;)AC(jq{Xlr*Xd2ZQ)&9|l(b@!ka5V&SoJ0J(K z=z=-0K(wpU9klJID^2*2FHd4K9a^OWpTWDXl8_6$1mGJ5I9+f}4Ls;J29}t?5xIV` zRfd(e(R)SoDDq-!iw^3SKF+gA#Pz+!iAq_rbH5{z^vgE2Fs~0p;jHd(q1@!XTk+j2 zSX&iAi3la(%B}WT3CmcL9f47tuGMHq6rc3cR1JNAF?#i9*5 zd(h&!9KVY_ElJVhb-aA`^g>DWWXR<1c9@UFh4}6V756Emi$_NZNwO_Nig-t3>bibz z_23ZCcM-HI$=e`yL$)G6<-Gknoyt+E=JfX~fNHE=sbYi9;|^SLjHSZc$5NApG}=PYC8IschL?L#!ssa z#iDP_RItKQ=#_@s@n>c(wvsT6Zt(f1O;Q9cpw5$2N_P1l|CnbJk>p(7OR_Mu+J7sB znJ`3YBk<6IflA=zy>?K7V@wX|iGbEO$FNjMWB-p!_{cs8DDV&bfl>)|%*O0}VNTd= znrCTl1r#G|FvY{CW^B>yCKNK=j$M_0`$!QBWA_)`5k@P=E!I@7E_k`8tBI-b(<*@^ zN6?tn_UM^Y&v5YgM0F;I@zx|ciHKyz0Kh*gcrG^~s2z>=A>}Z%uXa-8d@VKD3>&Jg z_MVTHCd@ZX_w?u#Cr6@=DXi!&g}52MDpFrR)vxd(X=(RW@U2?BN#eco=)pa0i`4H7 zmKx@jC)!v5y=$=RgZM5^)xR&5v(LUm5wrQ%t88!nTl}-c>waaGAm{|!I-+EaA;f5X zp99Uu{QN^-(HIjMLRxJ0JM9O4YF5CMxNFjeX!)7j$R@eq=V~N|0{g3@qx7*%$x;W7 z26;gPeQBp5gprHK z(wtk;O2^yLYV?(paVR1~iuf@iY$U>`Fn2Knd+}r_oyL)X@;YWx`pCkH{IquVi_A`y zLmm_h8cw0iN9#;kWX%0dG@;*bIXlbji!PfD`I=cnE##qq+xBlKRd|U%1*ta1Jk8zN z703XN+l4<9UV!uAsW!O!k$;N&(QLGhq~=qK%tA@!en@9TzO~kFLW##&Mk1o=JUAHV z+Eb$_xDn}2K6S!w3cMavXI>C~fDshV8OQ;zPwO+PG8B;ica@f|xi^mm4f#XwKJSyP za^FPGH=Ib+ml*A#GA}J7LWwM%p+vG*xH`weAjO(%xq7V46WyGqRg%>2Oo;1o0lK&K zNFusA9b&ge8zabrK8{l~6X(M>qiwn(FwW@($R_<_7T3L+H;lF-JT~WAt3ho!%Hf!~ zQL@C(-_weo$l_o+BRIXFog3J`jdm7r3$(bFjvjT_qiLx|3jXBH?mv4rNrIdnp3Drm zQc-qJ&DRSkeY=z01Gf+q{o@hFlq^A_*pcU69?*RAFhT2+Qxx)AWdE>2ZHZ9)IT6U6 zrO~ci+yLnD$@IP2FRch5g;%tsKy^}dL^u8)`ET`POWK{gg5~$C#S+eR3rAh@Ss;;*8uZx(F;H1ql466^+>`+VAoOC-%R8B8{@uxYrEc9+Gr zyQz?smS?)YSZErEN0|ye)MPzLCyYC-SI4^c^Ih4TbPDIk4vYg8am)DxysBA6|xO zp^B|if^E-#D?Qy3V7}22nM^!>tZZ0?Kf891FwtP8X_H=r~Av zGOdi^tg8=+bI$#}CeC>RWJ-0(?}pvdwURGwWX}k1It)sgY{sD!w^Am9oy1pFIKXDL zW1)5=*HCQv&d|4%t+9F%M2F1Wo94W?68c_C@39JbCqPx>hE}h4r=ifSitCV;!``JR z$cUY{zt<>&WV7cWSvZv}e_e=i(B5J*OdB-|yX>4J{;iOeQR|qoP#cH8Nq^d+A?M;& zPO4`Ul3e^C1&0&1IB#3Ew;O&BGC4}?&f+y`lE`x{{RWanl`%fi?V8J%Ri_5jkPc^_ zK=$wdbYVlE?=^#zD8kd7HSrmh_Vq6>Z4 zyCTSs&#Po;KCb2}K-F)|G@BzXf*C>!AKNw?uT-=fLH}wUm}$04X0?ve5>;%R?v(v= z$>AKBo|xdSsq%s*U?p+}#AZNEMB136@NZM_J{2hYcd9=q0*AwG{z{Q5e6aH`|5>+& zPJwfCT08gg$TeM%R>`M-_WodXsoxg4T2}JEb2U*#3RS$Bk`?UB*?dWkxM#%XC z;sV|&Yx%M)4Ir|mncNk2qm|&@VHmqj-@k6toC~xOlhPlMQ9uu42MCC)(ZOX+rZ)8# z8$zFk>XC_?ZH4RdZI*dy{6?$p>y;GkDA7;oAwSJrqoZYsF2i?k2!K-O48DV}VJ?4_ zBK^EgO$N8kA>^uU3%Xs(C|CxhHA$aL0uWJ3x@0itg}Jdsu7UlqyFqIY${|Piv1+hI z48!_yy5;7qZLR#Z`_(Q9YXd{%qW|*9=_Zf1?quvLTBpZ@_#jq-Qru+U+UM5`Pkcyg ztr;QkAp%=+M=F;E*Ucbc+&3wV9k#E{a}cRc z0N+p~qOmd;L$^qD0DBJ0VvYN~IUI|vf3sF00=@C}*53Ao#veOXr&y z)m@uwx2tl{HXPgrx8JUIeW5OH%yq?!>h)UPR2VYzw%4lnUdH^=8r^FAyWenj^p4W3 zBGAg*kYHHuEXG?cTM`fTr9i#ANYTCNn6*y2-qu~ zT*S$fqA14Skqn%@we=}<>WK=@bE2%4pN9%p@OWR<7rddR#^elJm|LyO27>Ik%ZkaG3)heChsWIPtmZxd@|o1j}9KblQ$%~d}!`Q(aHf2k2YYOss1<$qgY`dHqVWqv}* zjs*^%^n5BNnVq^Vc0%HOARGw(5)3I1drlz>`yA|qx0$Z zhndSUJc#nJt+5I0$qCU-35@q<1(6$0U|yC+Tk@4IqO3U4w)OL#E;2>eE-%p3hWUtg zKQ9D3#K}DyW<|$8-K;`<&EspBE=9J{vdiryXmj_t4n4Y{qBrTx#}4 zbbv=nMy2Gb6@I7lc+V|{)fH{a?9`Ax_%$&at>_;0+jV3gazN#$$D=kf;$L(wM^yGR z1zg{u@v)ZK1q1T_wt#AQDk6(E8Kr2AK#k648I^|H^+d%tor1wKEf>8?YYCM1Sfdx+ zG)f}5R%fz*4rGQVW48coSeeHebCSY4cOo33Y^1EfPWns%GGMt!igwOou|5K%(?UMbvRm4SpBVZ84)(wr-t!4OdIwhDn}t^ zV8|AFll};#>Ig??({ru2}Fp&uQn0dmpvmGapJ7GQ&F4jFB5i<@%)?g*Jmt#SM3y^$CWTe>tD?HNpSlhAQRbh# z&D-8U?9^N`r|GSF_w8;cq*uXxj2w@e7#Q%x>|#t$p?@<>C5~>+ob+a|n7{6^Qx(dt zsxW-VRklRq7$7p%oBfl;W_+R|6`45wr*7IEGr>e9c?5rz;U$)GcHzCmTIs$4hlmo= zUWs7tE;lgeH4jACphG9Hc5kM1 zf-6?bsYHCdwodq_&gWMGXDU6b;vgaeP0Ityu9KHTKat z-R67Ene6CZeV!yG=qa}P3>!Y{DYdiAwP$woDs=aCMHyJw2z~gK-nO5ZBh{{?z(bXv zi<1<_+Ou5@qLkLoZ+e{Zp|?CVF*vGF{bX+J_HrAZ+lJJu;sTbG;CX%`xrOZDcgIg5N94rVFa$<<&@5 zT`PG{&Sauv-9X+sbc;^I#Wz1o+reM2i8m`F+B}b;neee>U~s&gbjDwzN>jbR+<7-U z$F@n^?_V85dEE~9`PDHJcY^2?Mhvl(3JW{Uh5n(O+nF8>o@F^lhm3u_4*2}sUcGST zGG8@c<;4|pLO((AzWBN5L_j2a9Lj~RBuU)yPWuYy2%w2|M zncZ$CH4!$B&3orhbgXRFDNe3n@ZDbTOzXbg>+h+(KGj=Eb4tm_+WHKah)Rx&OM+Yf z+H3b|vPavzTQwDB=JDfQ=XwAd^x|^!#ep%pBQ4~@M|llf^1i@L!`x)EK0H17sr+c* z;d6jvpE*mq_6+^@on+urwW;hEbCqVgynhr*9ys!~NCXA;e*`W+88D0BD}QY18TnLH zsDB=ghZ*9GE^wU$m?jaPR(eeh1XB?gB+vHEv`v$VEdXi1G1rTNa8#R+QSrAe0QO_b z!XQ#o+1`=*IGe8)A1;CUcAv#7-LS4#q9eL`PdK$^cAw$7EBtsgX~sE!7D0>11_6Vx zj*V&-{67Ip2hj2#(*tYDKcqs2Jg{^E8#i{dpoR!&G*GaTlh#v~e~&)_`i+wOoXWqS zcSJQGGV|2`bRNJ({XdJv{{@Q$vG7H%d6D|RH~j*5!^OP(i&zx`q9VY>)*1Z)Rowp_ zqF1Q$E(e{i3ROV307DP>{RS*e%l|#DhI)Hs#`XLq!g~G^R4%^%krbA|0E>wH+(`lc zoepqV0j`#SgWTMIo)w_`{0Y2=q9%1%flm*iCikpgmu}M{PTgV+#~h+Hm)&p<*wp-Z zwC(w3|GpxDa+%x{{%uv#px}c>hwkgj!Q@y+RA<_h1y#Ijtu|v*766_);N(upXpDEwY(;k)K66NMe z5pgq1U^i^(**p9o)iBZI+Dr&L`kiC=$8sNEs+hu6Ey>C^y=(yi020~_2DcV#4G2;z=K*#6f zd0%6woYMZcVMd>mfFqzi{Zw=z#&7ZI>QWsGHicBa@TiKI^SWy{M3kjHP(RZpE7jpW zlKL|!_`mrng4u`*PEK1khCYN=YyGiWZ0Vh}?dim_x)`Z+{2k*@)ia7Wq1J*(x1xT(hUcS`=!at9N3`aW9 zi*{bi?EI-Q+Z#x`4CRIilW72CMLB@d$IUL7&s85y>}m(;Y<4xza};a}rD)e}Bq^gE zu!hZSUFC@K|gm;z9U~2;nQF zE0NXdqXZ4k_%u9Mb2nA2hNnbIoxAuCs+69>O)byukr!kIg8O4cs#Lqi+|JqTG{Z zYBYTA9TbG>4=H^*47as*UXF}dZ&KPM4vaZ0wB;C1kHFXkCJbjtw+)Shn|amjgp8z_ zfo%)8lH1_ed{QL~#Wle`l(6&(g1ez#J<1n_>*&5mFk-sdjW;$6yN!SSa_oS_pTWHk z8;#xIb@To(PYv!15E{$TP22Q6# zpW{OZmN%M0S1E)1n__jR5qm!<3CZ`)l#?oVf7-Otl9RoE6q;=(Nf=73(sdi0q7f(y z59Pg?m!t^mdxfmEv{wZQ($DOF}iv*M^8LAjtac*!mhW~ zJ-Fp>~_{p3gY$Juk^%o-^sA;1?^6}n1Q2}2E_uEjs zW!=N{r?sN>u1i7T%73KfOL6buO6Y#wgG6*^AQcp7Lmf#Y=eg2+Ns!&T0ANf262*fn z&KA+yde@}qOD9nv<|pBcoK8=BvH^%2`IyB4^16XOZ4NF90+thf`hJ{#aQcY~)Fe&&CaG%JpVM#6^1N!JRR76qmsSyb=X> z%@@Tz9}+s9gW)WrE1}snIT_cxNZozwX4RSlBOGO`ao={DS$B~{{!#7%Qa0nclUg#w zVplWR062)npIpme6!>Y0XWnbajO}sQli7n61VY<<2C`xyOsa=2b;XM5PHC=rshn&Q zue6k@GxSJ26r#5IOQ#;%i{4!YOiiDfdE(bollv{&?{0Eqbt5@ll}{3Xo~pX5H%WPXrj&7-6m)hp9a zE`2FCh#{AtGngnK^7@yPA!4)zALW_g#_*d2*xI+zE5d@o5mQ_M^SE-2{^{ZoCbyS2 zLSc=yhueH%g}Y)9vD`J!O*7KXvE8j{2&lX&Qt@yFLGtjLZ5h7YKSDMtjK1;1LHUnd zN3rqYT@np0R&mc;H_Ugk2(~&7UzQ!ngK&in7#kgiNcNqmYJVJpK2Uxen05h!OCpJX zd^HZzi>ZQZh3cTmwp?vfy`c@q8U_*Dq(dfFOh{cb(N}}@VzR`%BYh33{M{if&8PX( zJd1yP0zMed{E9!K$oMlN9eQsj@avrZL$Kuo-4iCdRTJaH%V*ORs&)O0AmPpjLVmv} z!B16ZR)2t8_uP+bVjd45CGJWNud*(wdZI{f+EjPj8xg$YI~ipjYcsTII)iV(olop9 z352D0yo$AF2!(4wQ1Q{kO;&u#*su8L@*u)ikl;Xw9|ke7e++hBsxaG)!8nhh`DaD~ zbMQonk)y~Xb=UV`nmNGVrAi3F4g$Rt%7r-F-eVHqEWoiTqD{F*XGgc)BZq}70(OL> zWJccH!QEe3Vlqk3Gh*|6$!U@zsudT9?!9kv{N2BNpp6By2*bBi(!+8$NiC4l8Gb5W z;}WptU{n1kko;Vk!2S;Ko(T7!SQc$n2))kF2~mOU{Bcs%9M}(!G9oxWA5l9dteVbC z8{rjvI!4}&xJ8`EY469C$xQ={P^*PnhW2uli;g7E4Ms{gMYM+e@L2&wA;up)OpfCh zqn!DqlWh+!hse>kKM%x}Z0>4supwVeu`f|$Qog?(Y|TNFQ#v{bcXS6B=F#lg*=UBb zW9mn5kP039g79B1Sj7u4X6h96K-NI%)*xO#y;eM->%Kf&_{A1F$fEHn3+RQ%i<~$<{HsVHvh=V3z<#z=LA65Mj`g69`LaRx?W@E=?AZ@`h+BSagUFe{s^xCt!ET zXVw^fS60Bf*q;M5g?O;)*TSAQwLJP2sWF3&d4n<4XV}+ntVw-xe6p0{OR#QPv~Ad) zR@1IW+7#JHM(V5ET>X)PzrT665^SD7$>^$9srv2>qwu)S_I67V{cfL* z%Xah^%tPud!oDH%0bR@9Ion#Oa;x<{W+NeZv?I~Q$qUq4Y(^`;v;O%QF(LR`AoJCA zcB93J_E{n}ZPD1IDG{7@ae1z%h!jsQ_?+ldDTn)c^tmUpdlpUMVRcBxbN7X+DEwBB zL8?WC{n653!d4G&Z*gdl6!KNo=w&m`#9mdVU}*SvBL(hPHlK*-9J9mW*dUT^Z}aew zk$5#;okV;4@Ssk3*aR<}N#m*ekJ*8Eh)}n0c@0xiBD6{A@cE0k^h5Z5v5=ubPrqbZ z7)U34NLgmVmg`8vj>T!Qpl)LrktHH-DC~|S-m~vkrvLq>;Hf)?V5l(XLYJhzNnhB+ zWaO7aebgHVr@9=A19~6M1LYr}Zg%rzm6O8w&O}oXOetmg!!!d!r{W;OS;Kd2of&&; zZM&p_i0HWjVQ+$(7hsiKi9dh@!e5)5#XXT9u}$x9GuE7)nwo6+iS@~pkGLG~1JU#I zUAVPkrhi(CXs}FJB}qxL_oYMCV~`g8w@MN`Ky*vZF<^ta_-7OatzZ(mM=bIBB}L1X#kcJQna!)YOheHf^VT@t#OY`` z4J@c==4O_-K;OpER#_3>fEl$ZNUAjyXC^YWET{T)m>-&&5aemRC-I(O(k>RwBSQL0 zHQ>oT>sQgYTpV$> zw%czF-++}*TM%z;vbIEe3iK8bxdTJu01}e~7i`p7HBk0gM*BEH+8DZ%^KG|jc{oR6*kbhP>j+Ei_XAIA6dQNHz9j9+Un!m% z#525sWbdRURIm8%Wen`9l_*9j!hg@aL8Le@nIez>>cI(*Y%mo}96~oqM zHif$8u;aIL4?{yZ2}n-bWx%Yu7XT5)aD};5pxy+(=ut0+qt@8BOhbxCIDX{=QRi;8 zqJ!KtUt&X<%L>^;jPCUHWO07m0U{wZ>^|LnPwQ8@lRY(SvlSDsHTWsFaD@&a2vE87lT$Yr3|rrxL^ z@Ffh!1o&RXX4g6Y@soEO{Q`WLHKK;|aKzVC-I7r&1zw2qxTUQ?sQ=N<7vK zLA%Q#pQf>R^JM&N)_I=9dER^>dsfvSR&FO%JqqRpV#l=eEQht6=|5>ytFk7sA$uQK zi7wN9+46uFld*)}1}Iwe4{j~62s7wMM7?d%0~GApzTt1=kP*hRvtz2Yvo8pk-`3RN zIen#F7R8)CkO&hd*HDqUHE4t1$5~CUm3?x_t~~Cl5-qbLR2FUX7Z=A0WOE2)hA=+H z#kj)tfng1+XxiX`TdD}drS1a(PxzpUXyP6m+wA6z_p$m=s%w`xv(RQg{Bwt^ngBCW zE94Y?C(Rc}+-{@7qG^K*-cMde7$4zZzzu3J8#vCx4PK96rPil(*)gYDL)5eldZaW@ zDFmjhgCd;Ef5E$FRB5KmbgQlUUX@`ZLHAgbEUkq47cyPaQn<=%`fa__1)z2*gnS!@ zHkO1KMnu@6rp$dek%#a3tkip5bNAQczwG>tcnMeg+u-%F)mv|QfrlqR1H7TjTqFFl zXeQsa&S04ka@F=mWT1Y$~M&r&_iuT?40>}2gEXB~C$GVg)fsgSiNl{TT zwG`w7F^92A`h-d2q+RxT2n9Cpv$I-zWa|b8#fadLr|X7mo=e=YExzAEi&ACr;k6KE zL7<}fR+AKNb41C{+<*$L<{(`QY5B_nys!J4^j z!L{n%IZb);ew>Y$I!Y|-aOk;2W|gYw=$?mL_ELFgn~cKSMIAu4P@J_xnQU25lLmmA zkrKQkO=bYpXs#7r7ipFkjo%h_6FuosP{WoU0C51DlvV=$oBuG7`~yH7jlyaZfAJ9D zxP>zC`LKY3dK6%iA&L4@WxoGEgF7lJULL&&I3o`X#m;pjbG%YF;Vyj!+^qOK>$|Xl6nalD!$rS(>sDd^6&XX_N#qw`3ale{qPQT zIjCHaBYw}HALIVJoHzcq5yFr6lL4?p3+nD5h|TtD5L)RZi9ktC6CiD4uT6Qo-Y#_n z5|EvIcQ2(I(HK)B6rQN+pP4#dvBDJ&)7x0+EZ=?%3{2zuzk1~d^C}GgCXwX7L&-H4 z%G?0OVNkGfHo?%nwSfkA%LKEJ*|k}K1g#$`PXMNNRpNfoTJG5&R1T;j+08e?KXh%Mk_3|) zHCLlVx?fy?mwUq!c^qi==b5B76tbh?IDP2L_{I6JFl;NO!KYvjXq@DeKu*Q-I!CdlxUX1i zhz)drECXDY>qNn~66+du4yy1vxDb+=6UQAD5Rn1*?kNbCnaQ)Mayh4>z!I-&tsUFw z><{RYYgUhy^*>NSVRU=1pfRYFt-lT13$+Xiz+bg_@s!VI2>yDhkJdfKYxkV>4e>M2 zZM2wsMEGfhfZ>|?7ahfYOQA-?`YkhiQg{xWgR_n!f0ZI$2;c%Xr{ri77n1W?N zGPMuq9MR-U$E%oO&!e|9+kkqjR98lDH@tot--?=5aC=m(BBCaI0#?T=R>z&&0e4B6 zlKNVL5By$Fl-zx(!tJM~$bSQrAzs%`XZ46wrQMo$T;JLrG z{9OxB=33fr%v~|Syyp80gnP9|k3abLwmnD1Tzty-3%g|jU_G$dRKrX6{w~tMs13yc z&}XiR$}`mei@*6hIfLG1{_n8@u=6V5_^_~Nr7kcLZT}f_2H%+fQh8ng!hem1?85iJ zVGbbH3Ye$Ty883~oZi0zQ0_YvhgZXyfs>;mc3QBIgJL*)&1sJM zXjq_~W<|CQNO(J%^m8!8UR7ov{B9kk)&Xq*I46HL`KU2qWD5F2nCT<}h_cVbP6{5h zw+L4i*r>WnmQ<|nDGh#VigabmrdDTZGzb~2(Wds1D4GkNEh*dCC3CuIT0jppo9PhC z1%MN44+F)~CB<1l%|qcR#;QF-YTM%UCV}kPEr9W0iZRsv9`vy1*6~W-j_yGXCW=qJ za31}e=;aTjGp#ZObVbvG6h&8tP_m&JeohC|?|q+ZQ;oUXjp;aL@gUXJts@A0a8##1x@9$HC zN-lXBBqM&%cS<`40BPhuM&F5W=r}ISopEKzoCO5pZWXR0w|!g9ZUg+&8*abC9*nr$ z)?Wf@oY-F5``UL9o9%AZjly-lJm(2iloF(TCrJzAi<1wsxBUuvfk(s;9%jQP8}*n0 zrWz?M{PR&(A^^mGZyn3DQphG{)#QCt6G}J$q{yiFoWr*w&}$En$L;9I2%81Kbzktx zc?tL~#TtucB_r-hI20nJ=ly(|4-xa!&`m+RpALG4JqtNKjmYtIcgNrkB_pU7$}nAE z>s)S3p8Sl=Dv{)p#gk_2G@AJXD3{~)6$#(%{2++w-#zMlzxYuZo%VP3!U*;#i5G~T zJ2z!AwXwl=MF{_`aUiQyl#GGdZDtNn2}8?axk-A>Fd&c7?UfLTXZuNWzWnoxe6$D< zP?I*3Gnd;{JJ!Rxdr0xPpo)p@&dFO;+Q71_b412uFg!}gJ9)M63E%jR=)N&yF2tTi z%Tcj17U2(35M0YhDm|lmi%|J#_bzPJ?vls`A*itHM9LyNqqPQwgNC%#U*SRKj=KPP z5fTIv^gT0HBLMs86on!{yooMGx z&ykk}(DXb&nKa$yGUneb77mG)83JWZGb)uyr5SOKaqBe(P2+#5>A-CrE<9rIBq9-BqLUczn z{G`*t>BkM%(U(f;@6r%ib^V7iDQfZ5vO1QNghjrKrfX8>3f{P>DxbkX^wH8- zrh;3Pf@uiFNNv=p$o`#RBEYizq&-XOD#82lbOoNxV~pQhUl%`^Lol8&%)9mjtd#sD zaY^bYEHIkCos?j zmKklobiRxrKqfs-gLk?P*98#AxGq=dwO9=1<$6BqStgtxx~^6=m-I_kuFu6cpg-xn z3orU5yuW5;vVTb#$D|!ck~q2SLa*Za=bG@qNU{&VlfdBoD8vRO&*Im(ISv(k88#$4;4^7jTZ0zJ|t2Q98UsUBV(sf>3yEP@?+~^2lX@rgiX~UzL zFgr7W8&|=AYZIS*4bN%|r)1E{Brie)AGvZTWWj4cboEetGcfj}7y z_S6p41VW(D?V8)3V?iDFE9nEl90tfqVG`6>2D**?wA+r=R?ydzDTflCgh z_G&BCDNkV1@ai0DFYSj~*Z+sR_Y8}w>DokTkf0<<0s;+!WDyX_O;C~`NLGR*8_7{} z20?;^CP~hr$vG)GNh6XoP0o@erzV}rD=Q@9U^y$58SFKvL>b_U4 zwW?R{k&-F>d0yBlg0Y1QDP5S@4duN4=*36x&MRJAakTTsbE@bKJ5L<2<3_9wy_*M; zDf0iR#f2A45_L#I!5Cc3XME5rJ=3DLIE(007?Lq0N;sO(p1ORfCVz9BE4W`ktM>3aU@vkv80T&3F6oG~5Uk0(0xO>M$=&gTya zReM-gN7qNV9A0d07>Rz+nNQky2i7a5bUT6uHcKxZI3{ids0S4pG#I}?qV#-} zs`e74}*9xSlB0)mphU;AEX(K^vDfYOj~h=c1`FWP7**qiK)8z(7VrGb%bO! zYyK#*`R2o>5l>FF18iDy7kEA1zzVBJS2YaXOArVR*@|;+xi(44{~OVQ6;T_toMm4{&9j0aS@DA;QJ0?5SsYN zLTeyxrukCD`S6Hjht{>+FV>WZ9>i4@H6UDERy{Ce*70E1U@q`|(M)rr4f52h$Lq5* zfGGF*HwUhQ2O3L1UQb#{cwYUun$xfPvWx38A8Q_KX`uXj=o(k<5{;$k&xq!^?hm)t{-5H%x?@1BO6%k; z;-=LF&r3Bizm)mPw2?wvo2W|cq^ftzEHu!mv82?RA?VGS0UZ@lPk0OU(SW)dFokJg zeW1X{D?bt-h78E`c;TY1{x7F z<^t=d!O_q-4)}8Rn_FHnDqKSF-+9GX;Nx#c)wFNl|AFRW*?)=A|3K%z{(m~1c(8Bp ztU~!I!KuXANZPmokn-%I>t}0lNVz!h^z3L(Ae$A5&M@+5j~YW)z_}gJ$9s-^5U|sw z_M*DM_a`YL9;G;FMnuF`ZoDsSbkJ~JW_LWy?UZp+@h%t5kxm-*#r_*d;zetTB4M2f zCpJJwT#Lsa-4giuH{#DTU?%hg7@o=9mM%qD{Ct28cRFSRiah@_*%`mlgl5XO zoA#f&t3?#({FCDGY>i~JVxVKBo}z>MKVmUD{8Kcx_^lP1qUylZtpBAC^@@NMj3*54 zjk=AIsnDrFC;M9bUw32@=eCq8P}mU(TyI)p{v6)8TW)vWj^7R(&uEH@D2+PNw$o62<;_JDyGHUe8VrGL)F?>m^#_D3MDznVTt)yQbNXzII|L86R zgj8@^n+koKMF*QKwc)bt3_*dyi5&%{2bR;+l%7{74FZ9$`?q>85CG3n|NdbJ8;IFV zoBH^#SO86mTc;8Lxa7|L$*CFuy)L5jK<@{)F)-EYYhPZk4G>l-r;@OQO>@tH7p;aO>ij+?SjU|IOHccp|MG$p z%TRC3PaFtA50xB`FPu3>(JTVF4vXUyS9(~HVI4=yc|h;8Q!9!U%Cg*(=qTrjFX?81 z@{5%b3C@2%GvBRr+Z!(SDxn$+c6delxevwiK{hH{7C=f&{$*1 zGn$@-iej&M!$kdNMUwX;w%b3PR);l?0I7G*8-&)=^5iIgT;JS)qSW)~5zoD`>yZh( zPlc;vYX-2ez|yfYr#(kctJBZm5<27Bzw!@`6v2C5Cb7E1qm}J3AQID{H47dv;oJ zjLgi($cRVz(65|wAU~bqieB^i(7O^Ahk4m1_)KdhvV=vU{WV_!oYcbySX;myp|vxK zkFLWhJ4C{g=G%eB*7pHEjEB2E@H)np#Un@mnK`av0?$AMhKo*^;WK-a4{wA+8Q>u% zPY^4Ve;yB;3@W%~*(gf?Uf2gJZsv$^hqDI(;X+(8uXgoop2)bB+j|DQQ?m(`6x!{W z^vvhyo-8aFxR^sseCMWK?H>Dq#?k_;;b{-zRAVW?AK$}#<8t@({r9Wq%=X;b_ zQbJs+*-Xl_|{#4Bgb~-lN{G&z8Ox41|!n)6y%k` zeeQDaK5*if_ZczMaMVD4c6$}Zzpr5YJ+qi~&-R_5faegF8G)#(=kH1v-C2flRKUTX zgnCAl6T`THbevEf43oOqAH2C_ac#>Da}s<&!U|TD0#OerOfjKgUhjrR?R02fvd#}130#~vG3mtOi0|u@5zz4AlFNGAiYSirmHdvmi$zPed)NX z?*ec6uGUiBq%)A%HV#hWsr6+k*mJWeywNi+8oPd>Vck>&01OwzTd^3-aA1!SP|L4D zA9^m3nA6CBL&s?!TJeBP)GQ1~??E2aY-I~fu1!D=L{+nX*;F=*zIg?UCSF&2T zF5HaCt9V^Gg{IQ^xTKEMYHsgU+$$7CJPE8{6y4@xU>Y}G<*+XdBji23?Q3cXrbL*j>d_B8FpYJ9 z1~HiW@ICj)bC`D)?$B7}^#if9KjaWhM^OXsnu1xA5A!@dPecUKl+Es4@1Pr z4t9T<^>cB?

Puet+)CjtN$6t#o|N(vJ4Uhn*1?3qKYyEh8@guIFMH$1P?0D%ZL4 z^PN6TKKG`iah3iG$^DtDu4MDWhm2np;|`BhJ+Kk8b?;*`qK{4B?}*aD;2%#*=%-`E z??KQh4|mz%M$%fNU}#$352AmaKO-)ib}u`_@5>JWGHes+E34G`HU>H#!(T=bEMsO9GSfxYHvM{&)uA)_DwegGHj~r zF=>G;oMn3bpz6G@_$b4_+iZwa7)WstKf@(xZU)jwdBl9%)~)-X*%hq(lvjHO;LAOX z41&#}Mr!&ppt4z4pJ8N0^&h_UDKXPi37U(rdG6B1aBp2=Fjww`b8!t}!pXR$f8o_( z4l+j)9RXc5qQ)=pH-ye=MUs%Ab7#5-j0H-zzQ#<>noslqwZa69pp4z;srF0#cV^0b z9;XiPHd`dGsBrUi$Ue6U=s>FpIeUoo_MCNKQj*0?0QrOSEni395v z*2$z(TwqUIkgvON-U6^>zL3H#(#UeOes;&34)#W=jiRWcxdQALUMWDf=9U)a`32J(|4=0g-QUBmc54ojeBanMS5kT5?(riF7eV;i*`DRU2k4Z0;v&NJ7@R+5gT)l zwTQu_;EYtuSw9^Uh&77W8z*=mQ^9GYGlur?F#(_PFlHDdWFHI!UKfxqatHyafmVrJ zfdHCTNCuI+ZYCN8K_yUAL}R5Eq9v^($v*ez4*$A1*C)24JSe~hUT&smJ4K=$nY+Rw z+k!SP)sf=oFj%#Qcv-B#yeIUX&~{TyvPGHxqpF)piR-=ct;&1F{f+G$)A_wxn$H>0 zO7u29OUl=^Eo)!? zW*{sv<1%pC-rjO)a<(mOV4*O5N`FG%emw8Nqv+-1(dv9ycP#=rKa^`HyjgC8Ba7Yz z*V}~Lcwf)l2yWLGV-{8Azr^r(F>0|!onBPj6jg}F=DotYl?+~wsi^p~;>Ps05&m#8MgLNvEk4t||izId|w8G-2s6S*$lE8u?r;7zJn9rO9T ztJk};?&>;RMvJnaf0pZgTx$!qg79IwOhU~kJ^cz8VfDcQX*ano7Ck2>_b5Q@I%22F z%FHUcO&(cqahstZ_{N-+5;-!PEJgTV1_JV;Kvzuo@5~C27jP-i<83?*PS+=tKlEHL zuQzS6eLv$ZtiSQ_nKff@mPbM zFDy6*&CQE^$Jbg6=)1zx?+0UkqP-6~w7t1VT`c_lG8=PIKfSVP4 zr#E~)on<^X*zA-Y!MotTLG{&C>x;{U_VIos7h1cTTE9A8L8b& z8H?HBtu#E#BfNyM1d_fCzJYj|z?}xdC1GQsHSq>s4hl-xPj498zqNER8sa$2H=M5D z)i-B)vEu%Y|GQ|aegz*g?Y}-O|6@6k^CGL6e)dq}gV#+; z&)$U>Njq>@kVF`3{Qx|)dL-ede6}ZFW#J1GsPnwAZQt4QPLrgWo%0@iBrh1@sraoH zc}@9kp~7qDYbp7^I{^NmPfm&MieiodUV$%i0zHo?DDalp6cBgZ!RNmMb*Ou&&s^`{ zQ3E4UEfzSKF0|lgPvbtRu(sKG*@eXGDD4dqU#k}TWy>g;)~B%YsW&A+ta7QR*oRGo zR0X|#>Ia*aT@RwpA4}4Nc|OL@m>*v&<$ARaI#yf0NkXNQ&0zj0=Da%F@X_&q-7_gG z)7Q?lvm&BSOtQQ|pPGtXT)#MDGW?{A^+9A-(9hvd zvZIU5VVMiXyh*B4;Yq36yPd1?!?W(Gnn2s8t)jx?BHI#8y$1Rs!6T9jjA{7Wl-h?o zCNi#J@MMFh?M#cj+OQAi8ou{b{9?%&An?alI6q0jF<;~`l;Uj=vA%@4H=|Qd6hT%g z%h-NGwxw=IUroOF$;Ad8VQ5Qll*{g?3>f4$+f_6q7f3T!v=PDmPn`RSUHX4%D3O7$ z;K?60cXkAohE&D<5b1(9@Yy{1ZGlA5@0ce0f*7L#S`~CrlVqu{3fv4G=t4-dtQ42A zSAIQGZOhmby4ZX@CeeJ7Wh$1JYF`^6kd+!rr_xogj==?xdj z9h`=_)VMHIE$`bnlO)&5G%gZXBxgt?f=OD@Mari|cqI>Nhbpw2s61KZ6?W|mBTIJl%{V!uyIFg-G{ug2(Hgm)JQ+3^6f%gbE>(d;78EagMidT#|eYJ0G%c48%ms_rP) zN1g+!|Fbsu$(7B%?2GQ}gYI1fg!Zefi!228+4iO?$9zT%C&@u|Sm6nn2jvke85_-V zvu5;Gtr1z3ykTOR6kFHj$?U_)G;6OkxQQSyi9x#T%151Dl7p{WNt{DuE1@NdZu~B$ z6t2&A#y<+tEM`2d0&n0Kn@dk)L?pmDj=vjvgr(_lCgTHv9#h|6RW}|sYr4nlk-g;m z9)Pchy~sQDm+8NfGqo%EWaY%A{Km=OOy7ocqFy5u6HzNcmW6y9QxCZz1x@(_GG8W| zrtY<8pTG%4Bgp%)rbz& zsfA##9>EvxL3*B6s&%cW^!c9%H#9h(X#|Z3C{F)0n(%*S)9CKF0U4gOrWD=bPoRF^ z{-yNuUV_yr3HUDTmpl3EY)oL$<>X*2@-iFovBm8r5I|&iI50>BzR2_Gd=W8D&9G)= zjF=3-F=QWk_Pa)A_;;6x>NFh-eXEnfbQG6$QOx|BxR60X__xhAHw?Ie&!Xpj z!j9^u@ex4vc8vb3)m?-Sqjt2{(_F-bIWfQVdk8F&+A2KQf4+VmLrfM-5;b4A_9|{l zb1*_!7@-CC|Ereo!l=J%n`m~A4nN5oGa3K>us9ePa~|n`G3HmUy{&y(*c5vjz;Z2y z-v2*5#sG8$D?qLtieuBo0W7Kv%zX+5NY_NU4m0}Iu>-O3*Vt5UisQI=ut$sbBWop_ zwjL?@5kifbdddr@4yfZd#V#k?*6O=E$dWfZQ~7h#KXl_gwukhf@#)6eJUFX#Lq9V8 z!A69@4LrN3@*J)sNTUPm>~#(-hyN9_*&;q(BmHdyo%T3v>o~o3R|Vm?8{O@cl)EES z2xL6v%vsoSE=KKXz2D7Um3apY$%>d1EY-d&SAYC=pj1Dre`7um-4O||a{h|BsUwA| zq?UYnu?Dz&pTT$Ocu~{w>d94B?FV5m+r$$LwWK@vfL+UBPogM(DRRj?w|<7 zX@iQM_Xc*vjevzjX_ub|PK40J2mWm$b=F1RFr9OS*RGEtYrmPymBiR30cEJW3n+sY z_}d*b!@-Na!o1Og2HTO^9I?Ftd}yX|jPBZEF=w=O5Lf_27oF2J)H5~$R%ils%5G1CE|hV7v4s!HbH?r4>Jaux2R z3Q`BGW92pQX%Lu%*YnerEFpHn*K-F}wGh82I4-tU(~F9S+c`dn=YlC6ql&(rl&td^ zC)?&@=R8-0=8cT7sx>Z+ftH!#k;Rsep=%pASgn8E_Ux~0W9zp6y3xVCz7l%q>e)?A z*DG`BLF$Y2jeiN#q>I&FwIRNNO%wOGO29uVAW)e+8^Wk*+QsUM0tJy72T^L`%gp#s|tt88D1TJO@-d|k}H#kZ# z&>@+e&SheMdP~2bcWK2v=@3+rRk;8u#+Zm;H2buqy?NsG81>4-?(e96cy6=I`5!?= zM4$iyJS(H;IQN5&QEN%G#rg8nXR?nC-aSHebd&~y)7JBF6~qd4oiKc7BF_-t^M3v0 zAoSY$RCqgZ{skq?r#{a$e7xR!l465kYl(?O{&K5*h&660^;v8+9g@4=`fX5csBOXo zPHBVBCnWQA=)v|B?$YTWvdfE^DwNrUD))92B}+XlMLdBI`ZYp-uKD|~!-s-p2C;Q@ z*69}BYxYh9!w4sXZl{2)2d8ACp;*^XtZOgeuYBabAh_Q{UU)4=-%V2z+h0-FkXmPY z7G<cfbHX0;u-E_McD!@t-)8?gNz+58IFGxlDPUjLh|d&L~;? z)Y7-6b+NFB2)ud4lyUZ`_E3II!_(*7i9$tp>;w$YWx&=KDqR%W+=Dty19-Tuo#JMX z?%R3Jy>XtM=?+s zlg0|G_NMv^sISXD37@9^G6#-K=&Os%q^}aW{`&ouHQl>euVGjF#D$rSzvj!Dt1!bA z6y+`KDqRn)ci~#)yAmUS^n~J_4YInY6qRWvKD|2aKW5{$b0=<6%=9`LRlYzyzj;dO z7BHV}AmgH_DLdusFk0i(F>lWGGtQt1HA2K=T}REG(K(?4E)^p@=sI$qJj!vniM+Ub zUHWCCSas3dW`0NI~%O@2SU_Y7wJ_+vm z=4lT_zT5t(ybH@@hT?GCR{)ke+Yb&F7Kp5`oHWt>AJ2%T2^C%ML;}?<>c!Uy60jwE z2%|3u=<>#&G!)(O@FwBNX|U<}=q|~H$e}(Q<*tL|f{woQwG2k`EHyen@^;*mtS`=f zt>@nyp0McAW>E&m8rfaU^%E=DZPmfaRv#_7Tx8)+%g{2r2R{Q5I(t`ny;!VB@e;7> znWxf%Mn=5&LF+wo(U?Keq6u6J9(KR)Gm&$8fS(-Mq#_%!g+wdf9?KPO{^58Eui;PY=vw@AQdZ z%?-D3`cZ8kd)R{(E?3v`6x72qozf4xHnvJ>A)EZefwjS5*#>*bzK>f;CrXRsJNd;; z$2I7%pen#-08qo zXn6`H(#JPQ&Jw>|@N&9=3H+IV;A2^ETtK?_#QiR<6wrN@Hxi zUhYQxWqls z>s~{CcSG0=C4*j6P8_K_ln1eqFfx#`ANkAWVC77b$Rs`pK?ychYAQoJY){tc^cMm^ zBJk!%!-3sQ@ZpUOXCgd9yNFLcZA=G73m3eKnPNP2Dw}>}?yEtmRQK@{64gboaQ1w0 za->Fo)(#MZVfOGXqn<)Vqc39StxRynX|K|wV)#+EhB+?c4tv`#K zkaH2bN+;?!geIx0UZLg#Ha|%QP|{3@iXekVqbMLr+**eCM`ESB*r?ps%&yWcNw}V* z6U-RI%^~?^)L*1E&a#Y%wyF2nL~y>yRoIW1uwrgV2hGo1+n7IejKr1FACdloz)xW> z(jR#%%1^7W<016@l-0?Rv^)rFPcUa-K3})xFyrO5%zWdED}Ss+m$^EfvZ$G(sv3)C ztdwZEh5dk-H$yF66RD z4(V+l=yXxJc8Ym=`2LXXzW+@&*FohA$2%Hs))>ah$u)T&lElqVq=bEfWP<@lsHINn z(U<*hg~ThT?NU-&H7n%zgCFWZE@^Ftm4~ov^+o5n+<5(xi}sCHL7xeI!s-3P`4baG zI2drsZf7&64rjGzr}L+aEj#4qFL|=|oc$HGwHWO1Gh6w9OXX7uz&PvAIkC7I?@v2n zqXWr4BTo-p``6`S3p)eFf+3g+0IHGWHh2tyJG2-UXh@=EyoHaJF$oqQ!Du-z4o>Z) zC${B*KuMX1yCJuE^wgqCKQ4Y4zcAfi0%xk^q$< zBk7~$omO!WSxAyTZx{8M5RG+r9VdugNYESwaVo9~=?9y}q;}AVY~W?w6$UO?CY0;F z+!al3U!aNb^)kaXq&)fNFGuhf)IDj1Ef6=&gS%>2l>|*ug5KBccrJD1 zCw-uTL$oc$c=fd z?s30k)(=YIWa`XkP5wK6#~$8$c(0;?CV!H7mAXjIMDpNnCC~xIZ+Q@n z;!(s`3|pbU+p^D^&In5d9Rfj{@#gE8yQ`)9pQ7Yqof`OdXx$g89_?Yz1XW+ZX(C+> zGD*;R-^s)Q!AWGSU*7RiBYP@RMb6yWCEzo1OvS(6KpdArJk$}`9~7TsX*pXIxjRPZ zbA&C`nmwuvpjJ|FsOx%W-@n0asLDBS#+}YDR|Hr%$qA)zH~6ql*4RG8TXCot*mxXL zi?+<` zR2!Fly^4H9Q#U!Zrhr79i+bbk{hTGh@rqD#D4$btra!U3-Rw}^Kvf^g{#u_{`-DPH zP+oUEN@g>Ugba==T*n~}&D)uf7r7*+e>ULIvhQ#8Ao&&5oQ0C~&el60ibKf5fty)m z-FI>nTpcx+lH_hUzeXV-bJk|+T(^*1@GgwK4O%(dIb4|QOIJ}8Nay}=eKFNZ`mX5d zobyEVa1zpDGDbR80K%eb68mhh34RYzV>!&plSJ+X_u0LLd@6hB zan65l9vaJD)Zo%oW<;92n4qpk;&i#^Z&2hA_`bUv`o)G7knKnVU%4@diar{igI@yT zX4z8Zf1BhPos-n}QiCX6Pcnc|-KJtnVKUg6f9JGNv>@1M#<`71(Wi^t*g?#C=2M~s z9X7CR=L3byN!8Uq25C+`mfOv7?-Nu=UT2uqG z3ZCN*;3+&Mxf0KB3jYZ?`8Q7w0|z9I51~&ijCL5|OZXIan2KVA3hImLTrJg59`zRl zi+nKE^kp*S!-HgnMPbqK2SnJ5@ADqg{5|#BT4Vr*xz#o>)#b^7ralJ$3lCJ35gTp`BEyU1$!XR*Iyn@Hf`M-@45UKnm!B=KL$b5EuZ(jiPytfsg=l^OL_}~(!q-$82QH=t6 zCW=-)isSF`93&JI|DU`8hAX^S^yqi~X&4Y|a2eoDX$~CY@B;>29JgDc&(YcqtrVC1 zM{%Eo-%|l`L`DNLhz;n=(E1I1)C_qoo) zgBP}(g|?{NT+QF;;py5oxFsbyjKsd2OmbmDOStiZZRge*WQL6g`{{J29cq73n#SdG z{juO|N8nkR!78;~0 zbNVvCHUWe281i=DLW>V@k!Uak00X}NVf6|7BCjdkO9xEg=O^4`i@cFEWA7Q!im;ZF zM3{xCks$yey$5v$cVRzw8r*AB&_Xo5Ikgl8w4;0LGg^2mct9V&{9#cBdj9VZu|iO6 zc6Sz|Ca}?8%(xFI2mX*!0Ak6RjH?b%e^RiUs-uQ)lw3Pg8UC%3Jp%skgREp=#5*iH zZ(IphvECn2DU>G3D*}BV596zP1gP0)EztF)6Yji{2X(ufQ=eqP)NcP(mt?`A(@NDT zQ3w@rVA9!sSg`P-eKCCfy@BYCPXk>Foo)#O2Ka9+nXU}Ufou{we*ZH%0`v_0Vdduh zUq?p@-naq!qvH1xP}V0lfDgC(XXSuK=Etg5(KbQsLIP;!)lDASAxN$Rm|FV=7|=*_k?C)= zez>3b0L?^QE2I6$Y}IIqIMV}-c)c5lBSYJm?HiyOrmOVZ3A$CH9r6FBL}(knHFbjq zJ}8OXsTsVLgBMz?dSbe7(88{|K{s>cb2~4Yw>ofvo|pfj1L$V{Ukktx@Vi;;;x`5uL_i7CPFL&Jpl_NbxstqM9ts#rX2}Ya=$E`LxhO#Ge- zI*lAibKkta>p$=oDlXAow=lnBt=ZJ|KGXa7Xk;@c{Y+XLE8>p_9C=9$%O7!1jm^(| z5{4F+BzCms!p-#}@#eA5Oq^Bb-FV=R$m@oOH)FQ>yI#8_EFc@Y?S9F;TA6kq~TbCanqQ!bp53B^V$^?+R+OFF; z0giw%eD1~!BGK*g0EJ_2lYulbi|)ur7VF$;Z}r3zJ*Byhaf~%Ui@Z#kmcyp;eOqGQvp> zEgcIrKpn*!z5!2q|7y@g|2F4U{qO|+;V}TP$fI>KUmjRC=i6`p|I{hoN3K@qV;-A= zH>lmQKT`h;Gy_vubwRM@%7y>BXkLZ8aqqLpc6o`>#aF^^E@0z7SgQ}D0CimF8=I4wts74OqY!~JAId8ME%>k*O z0EJnoINZk?&4Wqk)1AEA07_CU2myYwTMZZC*h{}TPv1rWpPx;r0}I=#6O52t8+5u|3cgUl1a_X}mZBvKd2NCvd*mFIojd zEoSMC4LV#f>$s*Z?(ffr1?95$)^di>6!id^59QH7)F@n|lHXgp)wx$OzL zzF+>{*{Hg50kOp8VAU1ndpo~PWKGe!aAK{3>yurP07Scij;1+ayBoIy5QX1Aj&Y(P zP0`UnQA z&)3sov4U3cxVQ)W-j`?PQ;w+8+4>?UZrg}hK?|04sK)BoR2X3Qp48%wxZfJ(2=ZVo zm|0ge^P)fx0DH97$-w>_8ovvGQAvrl82P&|_+4m1q0qkP6jcvw8g>NuZ%V&dbmk8w z)&j{q1v5Vi!hrUA!}*5q-?ldd7>KT|7o~1tdGrqP?=r?QDw7uQa)G_X?I(I^A8(vn z@uMe+0UKD_`_h1Y8-e}cPM0JvLkcT%y_zy>ge(eSPV^XpGg6SIMnS=Fh#3KFg7rGcx^L*sz+l((_w81Dm-9X@*yx^M z@1hHs%vt`yJ6XRhka1coVB}ijftrQDf93|_Zg*W$U{|J6R{3YVLGLoyFcJlU&IF#; z=={1J##inty4ztCqQU3{b^yW^#q07M`+z9Y?GDh{=LSVz-lKcXb;dglU}Ox6?k~Vb z>^ciP4Tw2tNw=8`$$W) ze$)p6(v?_yqwiOYQE9gD%2jc0;;R}XdJ4!5a{t+GW^M&5^N(Of?&T0h%Af@+()>0+ z?Ji97Gor@wZNY4VxY;@rVXA0R7g$U)z1d5BpN_y{yi_~8G(}u0o|vZISpr#5X25Y= zp>nIpO#qe+n^+D&^q}}{r-}iaU>;v?dHT2iEHel!B`w_h456Ho|4@V;oSWe62LA3* z0Uj9bp|%&sYrlVKu3pMA!e%lJ~Q#O}W7BSi=;3yiL0&eb;W znp$81?!9`H7$UUSML1x_pf^+fBR2LyPs8YO$iyn|P+_6{xq72r@z`C`M&* z$smq@*7M${#mf|idET`TdMseyVg&4wz$&bx_pF9IPbGVgft}E+W z%m~SH*h#L&msP(xLWfq80m)-6+1kCQSkS(iLB)Sq(R zlat)>ZDDJGoX4dqyKUM4D|Vy|E-)!+P0#hFfy*HM*|HIniB*m?Nmo*;zQjG;Z*4m$A$UpnqKlgT-wsS__fxJl;P_mw_*X&CX zRu88U1hl`IMr0))*Ht>37Yh&L$9MCB!!Yr(9IUjCXJccYwH*fgy#_o!Y2N$OH6C@t zd=EeVIs~iAH$cd3B1DZF8C&i`BGQHAVFrzxk@f^#>}v^_ALD6m9xsqqd=18rtib@R zi`G+(KfM76+V*9@Ow;aJ3<`c~H0mUz<41}eOA*-8s3J5rJ&QM##oKzyLKoh z_$~JyUIB*n+IBAXp{+WM%Rt9HBy1nE>)tZ!oAH6ah&b+%0S`!C6!Cy*7`<_?-?J#( z0ml%tC1yb)2Y8g&#j6F9)xIA_CJiDyrINGwYXcG(#j{Ryz$}eG@6bNGZu<^`Qn!9g zi~A{!-K_%x6aZ5Y{`moL;!gru>bg7F4!C%>pNYv_cM+2N3V2H1kWRLpVtny^<2D^k z!=K?W`?}1`Oj&clER(++RVC9QL91@C zeUJ&}l)A#~`q9$x8R*_?Fgq&&{G5UU5@beXn z)ZY_=ZayZA3%2M1Ep*x*w6@KETJCBA#g+dg1}k|eO6>~_2aM`8mQS((leVeu$F>*D zUU)VDsdwDSdfK?x{*{pw%&Cw=Hp&TEnu?(8KheKqnm#-d0(mo>Jmp#Q0L3DSpd;De1=^FiaeYB$X;4Mn z&{k_T8RT*Am(A$X8Ji+~V$3Q}KN%NMTR~LtMnS^n5-zN~Z8wr`^1%7UAo$iu(qc#Z z%7K0{zmC&*{$)=~HLKoVt`X9ug~1*DduRJ8cVW{436$V6$h7gtrHuY13pQ-EiGxrxCW4EAQMON!Lv>nG(CUeapaH>3;|{=0!Vwo zjznFQKn~rn>bw#n`a$Kg^jDke3~oQn%x*znt1=)hv-q*m(Hy3z0L02=u|6Yg$*0l) z#6Wz(7^}-^){z}1x))8!UA>>4BTot@>FXTTZpk(i{eA&5F8K`XRzEJ(hZKNR_WR(S z<9kbvlPNeulC4Rinz<#jg5Ms0*xEaF7>whBOYrcP z3i06-)Y7=1vH?CDy;IWaFC0-0lG)^8rQuI#1Fo{b_`)gz;~9OW9GY@>!a-p(ye;^mA%Z7cjIkX!S!Tq9wp zQJGsc9hRWljLObN3FZe^t!@`ukl9+2JP2adi-p(eHWQZnWYYH)v(1{&o^Pw|fgYu`XkZ zGN+Zf+Dy-@)u!(pT*me7txR!2vE1CY+s%q_RC^z^AJW~#@%mfM;fk)1(YuClEkBfI z-EYW|^N!t!TW`+k!vEM}Pk;=mkjk}J`}ng``4L~01vPCZ$0D!Ce2-Lk0D_|p3KmHh z0KgF1cUpPf2nMvNRZ8 z14v4{Fg3j%?Hs*yW#YOe{N(R}-JK-aYJ0LmsxL{?O^;Y&jHK7d!n|(GkjsRFBNFY= zJ>u_&5~AA%UquVt#y{RG0Co~8_+kLU(1HZu3Y{7n3}L{NJQibbbkME^=f=c;KA@ou zF#JZMh3YW?@d{FOqX~bU#d_XtXsE>8tJlCf$-u-0qM4}5u`L8! zKe##!R?QXxZb$m61ni5Oo>phI-PXyxPHGLr6mk`rYT)Vy01bvzQ#vg|f1OP}6L-Dr z@(_JJ_8XCCUz+J)I`5rtY|B4@WwyX{wpTUbSDS4enjFV$!GglO-db-k`Iraxa1@=* zrh4YKZFZGufZ+}x+hvS-)FjqBf>Pk`I|QAkfz70ml>VDe+}1>?f{Hj8 z#M`e)$s2tot?psHG(twnAQfsmg6z)PK5Edc&-h+%(BOG5wKFl$AD6seuVvop`2B9- z;_tDLaMUJelaNAAw8)bHpjRXRNv}BCnHKK*OVeUJ2Yvf*;CrxTdPtl=5vMZLfgV|#Se~nUEON&cit)xinL=l^lcsXu4Sbw=X^I8rh z#LW_jkIU$;rT>_u&Y#`NbkHihk6mGKiBlU|qVGP1`c`%0*FYJMG?&d?nI9ZKhI#97 zR};E9?;p1?5(i5FNts}SbFZ=_G=Q#K*v+!MQKGu?^ zUp|Naq5Mh(aF-ftwapWro_tC*8MH->Tm3opkLbA)ig101B{oD{;Ns^A>-DTEuzVn8 z03ieTa)D$VU=6A?L?xU63~~qN%Rr#>5hK*x>zQ5Gt}mwaWL&A8kxWFD^2RE`Uf$OH z49HqSYyrWb+@DFiV!J)WL=Nfy0iw^DD_fgi#e9fUOcgxPV!7zoz06@vyxC4JLcoK) zq+$@+9X%!Bpa8~s4-HH&GZ{$Cw$=ymu+8+g@F7x<%WSzmUf%}yBQ%hB#14~7H3HuY zBQ@6@Bkb9pD7@#XjZWbJRsgSEpmRChj^}<~oukNQ1d2C5PCQE7E-$@S*qW|zz{r9Z zPLg#KNG$aFl+aslc2K@rnyI~=X*e4ugLSF9?ULP2qp%a$9wC~lP+awz|h-Zf;sG3lm5Xk$?PJbL7UXKy+NBOAX>Jz4TVCBk3j7?m-d->Qq zG>7$+W?ya=T8}4yfR>AjqMIdB2ue?|JLp={y+Zq_Q+O2DdU5#`u1^r`J2&%NORt|T z#z_LDmMa~*(ZueV%5EBOfpfmv>gs&2i<58nc1H_hEUc`G-zUa=o_8a79JA!|A8aV} z+X9Kd5i*1dLN_pLdKO1~P+r-jt33+TDN)Wab5Yf~6`+XR=(dTPd0j&osrl{ITyPVJt| z%^GR4@%7t|=fGd7OD-Si1o6LO0k*JKQyL>l(#x&oL_w-7koJkimPs{>IcrESo16%L&k9dJ7fZ8RI7zOx*xJdJ-+^Gp*vgZ;zW;8QiL8JI z3E(i?wR>M_EYGlv2lF##gy6)46y!^?0h?gvN?~FrdS7M2IScm1@aBocmPXPnPwwHB z(THQHNA+gzWF(@&HClt^y79@ODo$1|H^HF`k@W& zhta@x(jnYRfMikESbcbS_$Xw-{amjPa;|3eirn>iUm|ekcOA2ru-&B*1|(q~0hieU zzPoYL2{N=rfj9gj7m_BnI^$iGf=@oG#GAyDcC-HT*%3Fd8axw=UFjazkgK<&U8Na2UBwu);&>7RGL&dge!Zf+F|nso*% zL&V@A+h<}EMUWOfWu^2=rWVo-X?+LxvWD7$)b_7fkrw*&aH87lGu={bK9P4s+kIyF z+G&J-<##8tHzZ!svmCIg8)H{mFVrw~e}KKqsS~G%4e2PM(^XcMlF)9s{|Tg^mm!v* zOJRP4u*_lHI|WhUo?dphygLdr z&(EiKdZjT&+}!D%6VDGz`1(io+l=}D!`xd(RTZuM!W)o~20^4Y2+|=)NrQBQbeD8W z=LQ5R2~m^|>F(|ZK|mTd4bmN(j=MIV^N#nNbH8ug@4I8%asP8L_HxZN=d+$UpXV1V z3m;Fsk(7^T(`B7kn}>c(ewhe_mH>^Ys)(v4O9#5i;?*OXhfJ|J*MV)Bwg%L8aW(Zj zQo@$CHHuJL+&_e#E>nkg48>~_ycPKvoGw!dZgX}-W>g>OeQ}E4737b*{~li7wh{9& z=$D!ujErJ)eYUlm*MMO@TWzr4@Jr$fIe2^z^=y>8e84s-zg2!j=yl}8tseI2t6S98 zcFCg7Z(G|H>m&LnjgmGX??ax^J}#Q`uYsx?=W!)=O_&`Ab$1G_1H+k2t>59@FRX{A zq5^US997DOUgiUQcnOa#5HS*m`?)O9xTADXo68f-i+4-RNc!%%3g;)puiqhI#;zjk z&=VmIoUw(F6S2Q`cUS99C%k0Wa&u>QrB-@Iu*&0H`*!*z>G*US!FwJg?Hq)*C>Q9y z1Gc#tda+e&TUaBzLNCtXfQ16?CDLL12zA2B=021+|J|ouKE@hRQb0rOCXzaBxxq1u z$nx8qhtcQo3I2XbX5lQ?Y_;=g0J+R;8V7a%Z!qp-!EPlZ4hYXR%O*>9^6jVvtB8KV z4gsl3+C}JfM#k+q!aSBW_Wr_S-8G&uZY$E$;2aa2(Red-f%+vU<$I^J4G?92NnJ+i zI16mqp-Rq8`XkP2GB1oY9mnvibSqIFdeZ>R=t?oWC8nnRsk3kPX7u7x;XZ6t@^a7n z!@Q7oTv*k*q|ycXS(~Ew3EjxtO>B4-YU{G_$YN9<3ar*kUJB@R?mYBQ|NRYM5676^ zxqfGD@RkBA+C=rK=dKddI~BT}zFfr6iu#=={4L^Txh^PH0fL0Hkv)-Q!#w(uYE!3Bdk) zPB4Iz(rtVa`n!CfY>=xyQ6++7kQ5GCG(b_S9Pr_xVI1(E4-E7G{=e2GB6=P^H%Gk_ zfjB~W>w`(Tim#U+!9E$@ywP`TM{X(DovD<KNl25q8%U6 zZsfnuKhRxXjr=?P%8u}sJ>Td5thWG|xR=!G@k39030}v#QvT;#4ZujzJfnZ_2WJNN z?1=oITgU&W`tn~2=7)Or#eYUK0EZt*>b!Yq{M5mF1mx2H8L0m{Q7dh${{UvyoSmJG z2+wwBGJ`RRGazR=m3+r}N+?5dQ$YZZc!s%`fk+PDm~%BBXkY(R{On)qfqxy1%0mZ# zZ?;wm-o+QZyI8f}9?#!X0~8`kua2MnGKQRAH*e<|1dccEOck<9fr*(_L)GY#h2;gu zIhC-;=Xk_fdA2OBB2`y&^fH5^n_jyZn5QEG!Fs5r04vnwfnza(2d0A$(MzHVyuYk^ zb;^4{S7C3VS=aYsIivtU?e^5PE8c~b$^vZzY;hpoo~Wt>umO?KnWxTg^?=f>v*_}9 zs7&q8t4-}o#X%eZLMBj#Ws`WH7Li8}h{^#~Y%vL+y9QE7Y8;Y{76~0NPV(z^M*rk%NA`UU+jJC}9DWDg4NHHa_P!OCt`*Osfkjo<|&6q5}LfbSN ztlrv71Jwq9T-Gjo--+T&u{XvO@37Re!vk3ntY2(0B}15t}^So*cspui4| zZxfGyu;!gv<2cgZ`{p8VE9Xgdq6UC^)3m>u2q03$`j!3lwJejvY;(EqivbYg=cR+w z%r8$0so2KF!FWCyq*qYp)kwTd$vC^0`;E_pJ;{v^es-dsjtzH~ogel$Ywr>S^_rX; zs_g)CA0&n8*laKE(TS4BjyePhw3H$3LSW0wCkS}_1;rJpxCag-ZD%!0Zk#rL@q`+{ zysH=GNT_SSQ<@f=IeX#+wPbNkAEqeDrLU0pZ!qd(fk88I$S!Jb@RLCCAz>$ zH>N?$65H~~0gDT-ALEq4H3^$?b_Loi^{B=hHUrT^TK81X9m2!!4Qs! zyY|J=ILi$HQQY(ywOFI78*Sa>IDg%B6!r}&)Cvh20(xKXM>%7UneBCSWM8%*2#)a3 zx+L8C|6-Y4ob(NXNcz$f?R7netgZ3?Ci0SLO}~@X`N;*+Uq09|@XB`SC8Xfk`M|xI zB;(?2|I)~*1lW64r`GZ~O zy7K{f>^Y<(9_;C*?N?&=c7QtCX3#r5;-k5|M3H&9mw7zCG8FAAysv5z?KdLda8!*IrL#AG^>GcT`SSrpb*C+| z+;m*oUaNu@g9ifoDyTn*JUNmrntMq*)KuQ@!h^tynd9i((}@&l%OG_p>17r2_|dU{ zjGG8i?Bn@EP>0`Hl`Ii-{o8iO;N-`sI9EX2qow>5%bkes?25`coF_;Ff(&=`u5uC4ido_swsb)@>tbZcTm6NnJ-^vK&A7pe6-glngQ zI+|YTYU1=Iv16YYMa_WR<3`qzZd?9saj?M6UO=GcpOIaTYcITe_tI|+PzT40X1m&3 zy^?au7E8lL(dCh*lKu(J;`}8~&*`23sokmu%Mq#)PrWX#=(QVd5Yjo*oaP~g!S)iH zp?!ZP`RCA$Vqe2Ik5mo%E(gK+kD}LId_-dW3wRA;t}U|5MSk~XT74CWURxu{sa?^= zQuxFB$;(WZc}c4W2#{6Y{e{`Ntzw9ZASu|4`9sAa^OqUcQHPpI^Ll?jV$!}_t(>m# z;8Ad;!6}h}V?VF+u3GUmz@^mb*Q_;ofZH4re_0};{HZHP4v@-Xr)GWDMpY0%n(kZK z8;Lja?EE>$xU)VLSTYoId5@IJ$K&f}wIqfa9NSc*ms@xX4KzM!4?y64+K@D&*!Bn- z4Y0%(mX?cY`du<#+Mi-<(4<`&9VHEIR`(1-RJW^95Ysm#c>uH8N7HXy&{_xl7aoz0 zuSwQpvo5$J3`T;INYG9_+o`vOUZWlEQ=D)wBXi?_JK2#E=RNu?aovUUXa&^f;k}Dk z!4E259@#}bNxm(UYF!fMKeiN$+kC!tQ}yb4#>dzQ=QE(S8j=yr@%@d2V{)Rz* z=j$%Rv}G#LBtf13#O?9!B^KGP5Qp!q-KxoLFi9ZzGz3$;zdbYGnb%O9PZepFD6qry z_tmzqf-;#$mwh3%WW?{Z?a#x`OB`VRMmKdVtXDSax9I_m#VDlW6VPB@M85q`^=4P# zD2wP{PHg9@ZMW?UQV5p_I`Mm}9UJt+`Gwz>Mto9bbp#whHg&Zt5dR7@$zCXzjZZJ4 z@$yItu}e$T(9eJ)r2TA=7+^qf^g)o--?wanZ0bVL{dPaW+zUZ%qz(Ksq2VV7A#63f z`ZD4@LV4*v^%JK+Pv5J2wCF9H~bEb&~7Yl*)IHsdK@brbnOy- zf54pLS(YDT=c*++L&}k29l896^HO9fe6DXV)TB&JGcB}%^BVpXm4NKP z;3iROw@1sY9ED@_@dtX()K#Hn*so~BXeZ%VEH6ijZV%-95UjHvp|elUrC_cA1=}}5 zO|QQZ)fkvQPiX%TH~k8!+vo0LM#uij9@m3F*A`2;L=dSzNUC)3^j!k(vPyoEeS-}7 zRApR)bx)BI5u^joLHjReU635B#`~b&4;|F@LKSDyOPx&Uq0Z})fV@(WUA==$+7!eT zBMMZX`9!ovv4K)VlD)B$9tmgAvAcKVn&W+$MO>UypaxaBd9F`uImIi>R*3a88laM* zw69xDuez1DUsa!Zk1;rqnvv5S$Ezy+Sw=N4bVs3{RcFn19W`d;GL zZJ8#lkP(0ZACDFjj2x-u;!<+Y*xJ>KoZl&mm`lDAQu;v03%LQr()Uu8b5FMfP^e^7 zi~pXpDh!F8Ol%{1kBx+>>g|4uougmMTD{5XP8!7s1oZT5+4M;;%T(owMxiO~b zHI3h=Q)pcwRt+TEZB=ez;uuYdc4gH4uZm{}&OgD>hIx)TDTsumXzS9&-@!z8R&Kp(i#ta9IS{` zt`(l!-^E*RvxfT(I9EPP$l0*J-Gk6}K`{pcDs%2*xGAT6le6|MoY;xXG}Q zv3+$W_f!CPFi{u!tZ$zpD@MWX7ily<%j2X8Tj9f#ySKujf?EC#XVjeCONgppe(>HQ zVg6i4z97e8n6ad#7m&S2=m16T(@O6LOP>Y28icU({CbQY{fezOaMB^kEkOrs@15%N zQmev!N=#A}Uq_?8BgpOVUdhP zG3D9VJ_zP5CbKMY2~H0asZeakIb_x2-4D`S1f#?wEVW2)mQWX;5!9B!CZK_@-EmEd18@36K&%ZcWI+?TSBom-M zJpP&TaZFim-=>%E_6a?Muqy7x z^anx}ys;O02RClpv7FPj#jJ|?pstS0u5|`?)HTpyeeM1yFOJcQ6?_Ms-W$5xEkcYs zQ+{N-p164%71k3W*?y}rVPv-Lm=@>O!Eobx5f^?KpZr~dF$_+Fi&%NFpWb@=9V*JL z71MA-rJchfx@hE?jqzpbW#ppCEj^!1YMvR2RfwG?zUS^MHjy@@$y9u+7P7;_+T@|K z`Ba@}-H_52;PgP=-P_d9!-K%cBls$`Gzqej{TRZOD~EfJUSLzd^V*VlG?kKj_NB__ z-km3`q9v_mXUGhdeO5qg!YdlsL#9ecU3XmVydtST=yi&YPJfrGFO|qgg`w0_P^T2UW%Z?hm1iC8I7?cf}EwZAy zWsi7Ti*_76DD2nU3P*VTyk(aAx4(8$D#9}F2NeJ3wVcdwp6J*i)AzqDdN={#r~!Ug z;q`yP!T%5UWlTkv@sdK8o?uT;;FEq|683Rm%|}}N+~FSB0X7#p(G4&j`04HCvjnD) z?aAfr_nm%yu$S%&G!|aKS)-|`|Jktv{>PCUJ*1YS!00{1cVGB25MvTbzb}u>9dQt->;QHlv=aB5kL{(?MrM8SRV9k1Vp@st`z1(-L&6=;DD^!+&2#ft z6rTXNqLbXxE?AeJrTV)L&Wtz2I0?39b!Mv+%8+3{bIG!P1rK2<>fZ`dr9Pylf;I?ekrX6~I^_b;HT=En0q*~jN)+Cab@xn^AgqNV@-*PR~Xl!ZDoy<}= zJZYN&0vUjv3hK^cj-8m7c*qg|sTgsY!twfsh6tQnA^ir97!&?a@OiQ}YDx@B)M?N= zpa&t@e6g;J?Xss1$9NIY9H}Xh{a;Z>g9ODdzn5qg=ax3yyS0X)_95W10EljY;}8~y z9L4)y)Omzg24ngPl!zAyKFTQl;=};C)*JCNxo41|$v{N@R~ORKWFb{Q`Gq1`@9Z$rf7xA|=!XV4*nrJ%)s2l?&W`GbKM6%R%^Z5$cPR7~Zy`lAKyPIu#B#*|q^M+*F z`;4KvD)LOl9$LT~Iq|VVh6I!?526tn5HO;?LvmaZAqL9*rK+RRx354XAkr<+CpWd> z!jwKFkYqhAT86S!>A1!03#&iwR+SiC4(??N8C8fEFwa8c!h8{5dR#(qn%6c%HBi({ zWXlm@MS%JM2ss}W>>x)FqzDi_a1WiKDu7{ZUG@rr7E^%gm@Yl!)$QaZGT`CHvNR&JTjSN9DWA`Ef=G);-o31j zQl&RnRTSI(XeMh3&+KZ(+{Un3E|m*l;C{|Q{M(3(q!2dv2miL@-9nLe<#^*kOW|aR z{*KM7Wp*tGV59ptN|7n{(g+IsCFvO0LOvy9viVf@=PE9&b6iE(qlzcLT?ECEgznf< ziQ!v*){X&mZdn!$Jv#I=6`zh3dM;LU{F_Fgy(h>uA@qx($O+pEp^cr;W32&}4g0Q@ z_Sh(nq0QVyrK(%aM4r^(d~_h&=WWSUm3rwFjW4fqY0B(lU7)KgLg10ibv@xnD|6k^sDAeof1=UdLFqjj@Ss3X4p0mH`-3{ti3DMY`@(XV zD`pvo5V%3&75Uf@B(|T}>7eJ=s^o9MM!kBPmN`u4VK_5nC}$wsn5S-Gkrk!|z6|k* z@>qWV$GO_3ti-J(fH6_7{EO1Rt03+CY5CJsxUs#HwftlE;#TK?LXm- z^+y1{kv;tvZ@6UyMAJm9dU=qmv9#^#$Zu|%)!%3YP)@iyOxaT6!_k9O0GgU)F;oWb zXEhncQ~4K4Vq^lY!*d0wxfrm9o_gmLhfcn{J*i}0NyHn zdZ?1CQ6zOnG^k%Og)cu}HMeFqV8R~!zjS@xA-(zPbrc2U;>X>X!&kD(FraE92b8b> z-enK!g&vvLJV0g2X2>fYrdlUJ1QSpLf*3eO;u&yEFdi>Rse*Iw_B=S?u@7kQDjpCG z$AtvnaU7!ghhDmYsD^!qX@*k;8)NzdHbMRW3!C^~LQ4McgOqqx(u=FrQ~Wdxt4oVn zzDT@mKK;UX`df^84eP7bVvFzgobxc&*X-DuA3rLuW_ENr$~p1?v@u1$-^sGP8 zI^B|anqs95>fI@6RNV7$4*|?PMh}LCk7LBQ?}<>$=#=V2e7zUA!eTYY-vBOyXkZHM z+gPuIsm4#+s8vaSq3wS9GP51w!oeXwxi}U%WXhz(M1q{Op%i{irLV}FuG`}>#tN%F zk)-NkziQX%9r|M#w&x&e>b`e1QufzZnH0Bq4fe-cuG5BhW*OY;#Na7A5AEg}SKW*~ zGh;Q%0>t|}zq7m$ihEQpr$5~vA4wzh;FZ6+=%#|)O3QFJNDPRBCq&{pxTOaCcBzQxtcE|zuq~CrZdLl`GFbz&|P>1WX|I4Hy9fd#|k@Bm*)Q8Mg4m_~U(i_t!1tlT|z^rKL zYd$z*>;x30z=KQ~3B3!sZ@$sJ5D=>>!}jO-zmPoYJ+8n5Q`Zx6s03i6tC3PZj+$_n zg%iE645TssIXim(5sV1!QVrbTSyjlW0$f23xNI^1y@eF|JFL&M zHFm0ox7!opNvmwfT2gVuNr_0v6)1i8SEct(ErI-E#+vH(QL6f=|2jNV^moXgLA`|~ z4YDlBJb{e`8i&s%!8W^8rp``3{6T-}kx&as9h%s=l0Z>Y`tHTh`};d-M|p*{C1kjO zzPYi5W{LPxZm{S#>OxK=9b7{Cp8*?NV478*YGLl7ECLCh~Gcr0a@_*Z5DeRJyI=4wb2_*oF#EgC*=Hl@uPw-ATIM9+a@xc$JO)hC_4XlFMFfm82^czBkMhOQIU(pqj;o_62xY8p+I zE^2D(y?ToU=A_3Lv36|Q=YvUY+~eHMGXk0BR((iUPj_AaGP~UR7qSIDc)*ouxx6Mh zwfI4S@JBr$42aS@B1CDOJ5SAR-H=IP(mfaG!F?G}6x91joLLLc7~yT(k69w)}7-Q3cGuxx?2xWq0_79d^@e-h8XN$Dr1;2Y=*nKkh-O@5eeyhN48HueO zdy+Wtgiptutsb5*eTbmW{Zf|ec9MVM3vz9q%qm)xjJxnMyOl)eH=yLq)nv(i>c4xJ zZ%XFq6T1{&IRt!d1?;^3g)`*uHg!W_3Ah^+9MzdJD5C?77gby?aX^oSYce4^x_Gza zpq8tM1*{tObs}6h{zG^4#otXk9dQP(&(Lsa&0fRyz}{lVdAn@L^@zVE}!7<1q_s!?kLct}j7RjUT1!$;uXD&yrBS~jo~5dwlp_;T8$nZjFKz<>aAao~aC3!3r?6g}i6G@i;L z;{)m#K=eG9uSNNfasQLcHL?xZT#iN7=ZQ={+)DeJZ0Eu22mWLQ!1AlDDP%i#m@-yW zC^LQrSV_QCt|)dR{!M`X=xT6dT&{^|4fkgrK1=%&+kg(D5P+HGxLkyq#6AM*+I;rT zko;~1xrw$P8{fDrkEi7T-SqAFw=s)?b(W-wKjoPdqz8MagMp{7fkqK|-48&AvOYed z33ShhU*kM^8_)zSD9~Y?;ISh5=isG*u~Prkn2o3R1*1r0c3kblO+9^CF{_<2Vg zwGI!UuB`T+LbYCN$mQoe1Aud0W!`e~M~IlDeD3?W`J8|`r!`zWyx?>g$_FUE8}!+~ zEvfXw3TF#{t-x4WN@##J3hLE4wy62|cSZ920gB=9TEu{Wkl0HTGCkz#G0Zc{$_wcgpkNf!w__MSoalbSF>^v{%T@0KQOXtojT+ zs*30ht%_t;Okb95_$rYn0b3Q%Jh4!E+LNu_66yem%?mi0YNM&KXC$~6V9iY6T05L^ zm|u7{=!rOFV+DjyHCEMq2UZjyAO1|6dHT;qPOi}rp$G+#t-=EFU6A=cYtgJMI_MA- z-{`(KIwoOOU`gXauvz(h*x&^1^|#{~R9L#Au!s1&s^aSEPEIutb-$?Yp@TT}pc_G% zoRw4LLu5|o*;H!(ef5+}0cS9+rc?mWw4|YOi{IwGFOj%9A&Y;@IHqN${|+FG@u7#_ zueRy@%saH~pfGYdo@O5!9}9kanTP6j(N3K+*x)#Gr%C~mEE?>>F30y|KL7c71;)lw zLijhNj?8KvM1(-@@P|7&2}l7p4Eqf|m)H@-q zHmarJ6z=PYsHgqsw0m16XI1Jv1$A@fCu?r}t%+-ZTf#;w?A?PImD1f%&4cz2IHdp- zPG$o-sgF|H8=;}p*c=%lu&_{BlX)s^e}Hg);Rl$LdWmzDuQId|IMT<+&#?8Ph)yGZ zmf)Kams(PpRLrpVUupZ%d5T^5I!jMR%!4`ge)20|1(V#i%HwcZVm&jtvgJJ=wO`Oc zKCi$s%SD-6+Y1vp4t{5#)-gJ7sMx>+`DM&iOvwxv8zugi1pu^8=6NLxQ zNpRj_=ywxF`Wzp`o?nCSAN3#ZN!UsTT2iHBlTP+kjXI@mgEp5dDS$MzGaS%&suoL4 zx?aa$QM1KRF3n>yo`;k+wV9hc+|XEfHnl?r;8n0(K=NrETc%v;TjqpX#aJx2M9Xg1Rfqt|0-V9Oq zBb`3aUd$C+RJz1DfePbe{ekzA0HCfIdv`<1`$?WZz<@6I0PN414bnzd zuHeao%|rap-p@ zJ2e6pqeW*0mcHN9Jx~*N%jtlIq_pTkpLe3>JNO;AOqCW44BCkSMYxuS-=vW5t_)OXSYi~4yuvZc3+2|g!awv?(&7_QQV@CqSIen|IFE9C=zfsI)WeV^pxcB(yJOpEi5t z(wO%nd1pP#dr0Qx*gN)=lltOempWM#n2?f#k*WO>5^m>mHB*u1m1q=;WzrO_$QJ`! z9K>jlZX2iV-B0Jj*=ii1%3t9rznndvD`6$(uMj#w`Nt?F;Q>$zH}>1%(9uf+#_Ws| z4Y5bV<;%R^LRVq;CI@GH4E=rS+aZ<_fhZX-d&OeWUx4-FEl);79uD3chFP3~EM{jU z3Iuj>qQR{qdc!3p5j@xD6 z4;yDUaIVs7Y5~0SN{21q`@#>J!~%&UJmOe>EqA;Y+gmB8EPmImMaadSDi!ZZlap`!10DBh23eN6)9F z2k^b|pHGPyz48S=rE}2$Pb7dw{GchPNtQQM$3!-#&GfT_L=IN;t2J)4z6^5XrSdOe zI$qVF*5#sQpufB^7+stLoMzn~{!54dHgOoBXh($vaJZi-dDZ|#xw=;--@2R6Nc6)ts7RQzuIqe=}M4#onSz~=K3EnwD>C*tRuyWEv(3JkSpaCdp zPm)1VAZgxrk!g!0k|3~~-nWCN{j{&w`6R|}&D_;(-v%mKE{#z_VnjfyDWyGlKwi(Lh~DUNdVTmiw*|~2?|(&z9#oi$56ZP z&{WO9I=|@B$oS8w(L^(p>UtputbasV-NR$K|M$oGAXS$qK4BaG6^$G+#b3d<=(i!zi_7rcc)Un0WBlx6P(st;iE1Zt2D8b0=dt?>exwTqp%c!2LjTB8M zAcJ=4=nK1YrqYy8O1JCHmBEDt?X8#Oi7w&sd2Shhx7um%Gxc2n&A>CBH9Wx`U3~*W zPAIb*2A>V1Lo}Xd%O!e2EW)(iwj3TO5Hp3rF*TO4(~@qKru_Anjoy9s6qs%;MAI)< z1=}ZM6?ltAmYpdL%&7MUYyA|kh=uazC!Rb7#}I=qi*;KH4V=@*t8Sq)npWwt)bs*W zf|Fs8#mg5`xPoYa*A~({c;Nrzqy|{M99=~`oyrArU2>c0mwi-RoB7!scLOe-$)iHC zQ6!W#@9=M^h=^<6I%{-7o1fti6nrW~*hR7XYd znp}6}p(Y0b+Z5bTQA=wiQLSIoz!*J{tWUQ1Stl@<012@LMs!i!<#df^a&4 z97@JdS%?h4i3h0MmNb~Z{NvOv0t3dZp>&kRjKa#QZ%KiXayNJ|5*>P^n_TL_nQ)J@cVRWkwS)fB>IL z@wyk<1{NT9`+43*4BhwZ$p8o1n(BR3I+(!7)*@Fb{^-6=m2lY*jw&qr_K)3fit@ykF4T%%77o%7)J?+rnY+D z_0$snO)v6(C?LoHKAnLwF`a3V=VSFEn8o-S5AwU(+dUU6B-a>!;8Yn{aa_O<52`y( zYyk`7TEcQd<^;otCyr zcM}~5Ndix_d>tP^Cn3gIrJmtY*QnRDl4qfFjsCKR7#hX#dmh_dSQg8RzvpxLl&xuV-8aJN;A@ za6pQBXL0gzA@=ARb0YzJlh>3oj`3}*b`SInOHi}r|&#Cu$}#JKVR(~ zhm9m8j+mz3s1oWRwgM0@|#z;sKUccHi$9;pJ9CfAN>ngt6_!(*A z;)(OpQ|;F0)|n>#4Rk7{VF6N@opQV8^Au?YusUO&<(^)=-7KLI{B^8Mm+@WL)83UI z7f)9wh35+$%+{7D%xkiom>XNj&uGg%%VB<}rCFRJy_xQuPv$=I>c{F6rc^ba#iMGs z8rhbi5S~pRH+@SANU!InL+4upkJAdn-Jto`(Qd#ucg~S_?~OL>Ck98RYAEb_lB5wZ zZz5eR18+!g?Ivk%9}Cw{hk`m-$?&UtTGx0k$z7XU>a}Mh@7j$&a6qdE$|r`S@puE% z^w{k_3}NV|^Fu>+O#j5=W!Fp}h6-_)vef4cy#~R~TsM#l=*3FD&Nu4u58km_wCd%S zQB-2Qpx6$eb-L|8$PjipE*Ln~y(o{ngK(hUEUDZKjjLQ?yDl}=oV58C&bbadt5ISA zIY2uv*_K>oX(R|m9IoNbH1Ihot_Vgz10}0atHVv!;wVr?zo_>&R?#1N00fV5z~dmQ zNMdwPmIS%UG+$dXJ>KFUI|wl6WsDFT`p?V(e20kDHPVyoH$t{c*>^zjH6U< ztZf+fw!B=3u!3=3UdA8=@>mxe_0~Ext4gWk$#mCK2;2x_z5Goi63q~vu||BWG_~;= zhwn8pjQ7u1%c8hjpjs;;R}KPH!4YSCEr{16t-yZtmH|H!5=i0VM7bN7LSdP(?|qS4 zaZc7aZ=O&#c*--TaWk9JFt^!eS_s{^Ays+1rR2}e`6h@YoZ@8wV!b{+<*0ZBaN4q-jPZOV2PZBFY7)L-Lw=P6z+5Ur#)sE}ZxkJyK+ zr3UYPANR;#OZZ(lSy+Hh6OrPFxrB@D2%EEnVyPiU+XqAwXCI`-4s5TLgqN9b-y+;n zPnFL#9$&O&D!?+~rIIf>5qQL;Eu?J~u=3awUojX-pPtT)d!n6GD1mVET=wHV+k|ub z&E?RiI>Q}$+Klf&o*3QwL)PE6EXjG!e@V2{%HHg>6+WSOH|rw!dd_Rz#h-op!8CI( zaY8Z3rIA%`_o!f_e~UwwJDuESs%UiY*=v`0q~bBxOG{K+$#+HNQaJPAHtahbQot`z z-3d|r8GH3uL`?@R@8_px=_Qe*sjODZnncGx45p**J5zzI^$i+QBlE~(HP~X@bRZ6# zw~bpIC|~Srd-=-F1`yPdHD2$y7{o}4ECKziEqVs*DzU4_F;Z5Iq%^yR+elANB{shA z?GGSp4xI62?m5{n{r)jDfW{MUcg}T{VRNqJdFCoJPI3p38Bh=DagU!^IPUO#8@6c+ z7yU!1N@uy$o{opaOB`#eLyod+jOz4Epyh6VfTV5LHT0R9A8cT1X8<9FpE%aUKOEuJ zu|z`n<^*?@1j=>ZK}J9(v>hKpI&PsAQmuQjmq=Q&%hpVUWFZnMFZgkN%Ez;zMtkP~ zbA{%E)$A&d9bv1fKh9yBzoEzzHk;Y#7LpZlvlp*Wt~=W@+k)f=2&98=uL9OiXKN4Y z^=oI(kXx_g>{|0xXgoM)O^~GO-NK5w1rXH`k~dMS@XSC^7quY|Q4lHK5qJCa4h`Z} z$0IsD9Dg4FqSFI=)OQHp>jS8#qz0e+1`s%)tb9;kCcB0i?N-KHro?GThz;79+j2;m zLx;3{wQobGYheD|Z>>o)stV{jh}-rfH_#u^sPI-kI6381n~rc>p|3@$n~SwR^v)wtn8@(S9|;(@MYk$= zB(u9#AmNG0r3YF?fu6LX4Iz*`sslNKs48vSNbXR?S42+7Z1&OtiX&+X&?lsVPCFVj1abYY}<$hAP553x@xd%7A}bs^Ofz#gY}k+aQ40?h>z!AzB5m|wQmj9Y_J7@$ zzZueMJO#9gdHpv!GB+)3UO@a8N74|h*B8r(LgeSawQzHNt7&WPhq)e=G#x&D0?(eC z+?d#S`p;HGX8PEPT(x%Ak+q)D*Hl;MQwW?2(!{VnVFht-e-=xI1rb@{Vj{Xd!!+2< zszpu59|3VvjUE>3?lVj5cil-PLb629ju{Nmt2Kr(CLir~Wd|arELQQiTH;am1b3#p zUW(FWR0WcUav}W00i8$1t^KhQS|S)CXhp7z*NOn^i+Pzg zKvVJj49%ZvDV=e&m-=|?BYOjI z>NZc?yvnVB$ z-KR~PufZCr;xV5kQ~DFON4Ot^5I^Sln$L3^QT2ydwZT<=V)}0LXAOWwi;k%(wJMQ6 z2{eeF8Qb})G;X~N$)DwSu)uGeJ)OBK`OZvU-x&pA39)=Dy8fqqQpB4U;v~&iBAlZaZsCsp-IgY9BFrzpYMPN*!d5Klml;`~wb%F6Z(&RRH}eP}>YT zE4(=NQn)^KV#H*|Qx_2z&#|XUY3@-``jp~q(b!&V)tXTIMdvY?9l2&svBG$1q-EdEZv}<_+rGVkAq#NE zn0PDX)vU6ll8!LKCw}utd`KwU!b&I8Du&ooyb7o7g(?vZd4`?8X!41UuvOrbbVN2J zkxoCRsp9kG8f(Q~PJ|H@T8@s7p{e5QT|zR3*kI!)ZGabM64#*-Nxq@D+HS?3qiA(& zW_wK^U>GCry*p?Nx&l6Vrm~k`1@wqHzF56U5%;kJ(w=>1rlH|=Gkw{VK!)vU`RroS ztb}`}H{{6afu&e+gr0%v_2ij_-SXgxgKe!O;IzvA?c}5rb*I|u^)CfBHn#85m?-%? zykiJSep^F7iJpnSLspSRh|r&VhXXy+y}T0smRmyO zK!P`fv$$cuO$@$a^eEaYcXP4gNOadEzGi_aQ)aQ3iX)@)`)5GgA4}3VeF-k`56D_p znWgM6d?r-&*(4c<5GN@o3~JOUBc$vz|58S^{v>VHwPOG5m#1Eu_r`9*qMEwT@UPwG zNrz(I-TR{EbK+sjman(?y3h!T%O3(NH+Cs{JV$xYehIucKYL}WkV^W#yHVaYTt?4x z+(O9yYW7;cW+&gN-{5K24a=g2ezSm|j1x4W5{me?#+P6BpkOf9rHk}BFVV0n(}DemTa!N3CsPhU*Z*B zw1&jF%?n@o-mmUkw-)%HRA2ae$iK9fq5`YiebKTmp63@V6wpu5Y_tu}K)KbRIsPUU z#-R>Y(7N3DuJ2@QP|vY!+W6&Zn3RpK>T{Y1lkykusqidsFRZHG3)g&C@hub#(-U^p z=#U_+Ra{XSnQF%GXjstP^D*}rAvlmP*v_7`C@>*DpRid|nP}HE^si0c-#KYV|~&yhv6~k<+AzKdQTP#@~=<=fntE$f3R?+_oc2!i%09q#oOJLgT4v zlNO}gd2cp_r`pDIMrN*FU27vJ?OWJEH&S+aDpzH{3)RAm7I=!CE3w3M#;)Af38k*} zrk<)F6=7l79t;K*=OAr|YFl^WDE#<+#aGDq^NxksRF^{Ml;6Kc#||pVb>zE%gVj)N z95dr!qdIsuubpy~k|8)Day<)iv*kB4A&Q8nUPqj4qM zo2$D%$zjrfiB9MJp)Wl+e0G2L{3Xpg^L@7#q00T+E}vRG^?SY>HAM=;wNC~`^g>=g z)B9KMaA-VqhhyFNYKX8?AgP^`mRA-(ZOaSFy9XUy-U;iQ6fqB*#hFuDLQC8-VCP*o ztF6U4d4pl*X2Vg%ID4_WDMPLmegd9THV`NBM^Qnbl_Tj*b?1YaP$_NZ5lVKd7;{zf zYR_<#i^NoVycb97-I?l_E-Bb{KGf{_`K4}(V+6XbKk8bWqm;&|Xf#+GSHi_?sCCb6 zIG*aFZZgPbRdahJe5swaF09s2@vH6ned8uP8GQNNTW6{UI<+|8m0A3J9EHnF*l?vg z^FXd<=b)m+i!jy*DWFpO#8MT=2_dr!FR zRH<)ixk$vfH{HJ`ADtSm2|~-d4vMt1Sx)uI12V#^wa2#f61pWwTc+i3)KSzgS)g+{ ze2Ax*2xzf*A_6&aq_^R{85ALLeahKGC`T+mxcPGM>Dj5-mkI+@AdM;;I{Y=M3&90$ zuG1Ftkn0g~o!mt%=IvfS=HpH`aJ9mF9Yl9d9g3MmHyyX>{h~Xc81naqM~m;7S0V#{ zIjFxGT%cME-`z4#g4yv8U)9M9^h~seg}Tm2%4`XKY}StOkXI96Y)Y*0`c*!5%$Nvq zI9S`L+1SYnFQ917M$!~b2S4he1{Z&+r!Ty*Y0jK{BBu;>+4B0_j)BG*2wGupetpga zzJ`_2kmURsNu`zz{85ORzpl&y`(>Ee-ltcD3paX&pl7zkr_cfjOEvBV*j^vLh zl?4&HOkwPsQy;>fM(Z@16J}KCt6W#tPwl89B+29D!h-nva|+L_-3z8>BzbBsRSF=O zh4Z1kUEQl?v`^hcL5R5ip#Ra{m4`#w_H87REU73Y$&x*fUAB@?p^_~zq6m#4+t~AD z--cvgMk#6RhOtHoBfAD;tQpH>Z>)o1zI&+WeU9h&zJI^(IKKCt|L(cw{$0QG{GHc! z4)@R_1fD|+BFUtk%qK*pfcB~rbnHLr*wc51kIWam9dIGQm!7%>Wuc|sTp>iA1_-2n5Z+HiU~CM zMv& zqO7m^Q%fHu^e;w$bz!V_cG!Ev(hD;uV_s!LgoimHyJsYoM7}P(0?8Vr@FfK}6CZ9g z5QowqqURxeGj57H9^?MzwJ>MjA0;=N^M9;5gNL@%G=_NwMqQkskLF)|9OEdeCWpE# z#(*;7J}--+;b+EnrY%BH(Ta*E6RKCcl_lP*G`I1TOfwFz?AT{1<=9`Z=^4k0hWg8^ z1aq|;o^9JAwzQ6X+s)Zw3wA)?V(}dx=W2W<`fze|K5S;^`!vCd3G%4>r>UZ!&@2Bi z59atR_zOn1P~g8ULLeixuZO4oGdGn*f@-E24GE}czlQRKzll%jVQMk$aG!$_b4bgj zNS&ZK%iVB~t&2gbizyC=2ui8=Qlo-8+sRYc_UculbUr@sIq#}wWn!heovg#*WENF2)LWZiw0(ldQ#`t4>RRbYTSf1)^&V7X*|Cd4|!gW4s z2Tlbohs=ujN${j}bs#JQi!!%n809LAwUomE3DC=Tbos1JHt={26a94rab$Q-T` zoHtc)&sV*XJrYRpYRvL;@x5VHDicKLmbCPA7=&-3*4&b3My4uDUuM@xJK17~m(LD_ zp4nWtsK?ctdhSiS4X@tltvl?7CRt0?!5KxX;ohPf zQH9rvo8|4Mc8Sqse?Xq`rm*H#JVI4Iy)XBf$tlr@OPS&vgvkE3ZfQ0cxzpCWV@Nrv z*=o}=VH#O+hETkOd|*2A%1C8u9+96+pl~J}GM|Q^*}OPsG<*FYC!#$m<^fG8bJnl+ z5Vv^Jn)Jywz|Ho_t+Y!-k-WdHidp$ctq>M^Hp7i)UTJJZ?<~K3vm?k`n8p>QGu~i7 zN0H4Z;gIi05ig35ZQHlo6cX-?^OOzS$?29r>K0?`B>fe?I^(9@47yRpsy=~h56oiE zgxQuYo3wYvY!<-dQV)0XKD(8L4M%^qRm;m_hrJNcyUdXr6poau!f2Xd9n%&^4!bqtG6E&C4LErLSeX0P8RarnZ>QpW(W zo#k!P-YjQ`k(`hWP!aL%G%S^~{cbaEV><@ll8R{ z!Q1sK(kXSY4GA=+>mx;dz=t)_OW~b`a=nx6XSe%SNs{wA$o=@z*-y!t^58m#Cy6^A-RWNuU|BR_A<)uQ0**k z*o!6FKk@3JnbBpkMF6hPL8tQY8;}u!@j3C;R}zFNq?1iGjg2%Jl#k#hs$3i`p7pHX zws+!_Z%u#%V4~Ay&#$+2aj~XvW82fvZ$#abvnV3UB20$J;wN#=0ggSVL8fb;a5TpK zRYJ@f=~3&|=0Z7753xsFFuo?(WZ#i7X7{9DU0Uff4zHarX5z}Kdr>d$NgR1C->^b| zxqPNKI6&e)d35I!= zKL7D~1gtDWdAC$3WWE0@}J_ z(tUZi(e2_XV{GTRzXW_G|B6Tak22Cp9KPAsoVB$9>h}6dBwC<0@>+v z(HHoP4<~*XA3E}0f)GjWwfCW&%>Pgd>*N)9J1-AxWCqXwwXC}yY07EBwh5WWet153 zPg|c7{XS!;+`#zWQ-lMqysvCj1xz#7?c|s_AmB*D&4yUFvoc}?)0{I*M}95@!IX0E zCX7OiH2W**2a3ErE8mwV={qIleaps)J^L80!*UVuLvuUz*z;D9^63WN{1(!uifPv| z>i*hVPQttHdKD+!q6#?Yyy;|6~1X zqw<+j-L=8KfwDH+cuOB|mq6jP$u_5A{GC$F{hRvl7Cf7j#d`0q)#aVd#I&=tgQ6bu zYOELYnh515K%*y}786~gcQ)(S1^5;(UsaYk*Ctlys2E@u`4r=^arVON5lO|}?MF_< zw^Unpy&`QT_=LVoctvL2bZWPemcl;RdnY4}inN&r_akR^XA`w5{iet+z;TV$RMn@H zfjG!4R1~DS4(wZiLtr8Ux4Uy^uB@YVv6gX5#XN)?dEIdqF4cvlL)bh{R~qzDHJXXfIWI?ia_THowHl?ma&62{ZMblVS9q8#e8L(+UX9%t60H!rEEh5`a68R# z8)Sja)3+3adQgfgJ*WGHGLat6t6iDtkd`-d-(PlHr5Pq5gDjVPP0UMK9DGvg6eaWb zKCB4JSo74i^66V(?n@g#sUSupSWv*T0#~sSFs6Cv_u{!YR(&`|_|jGbk`}==yxk!N z!xoxn?yPKvDLjgoMqM{N=Dsvq=@qir-7sW@eRl=5mE%^6bc~81Dltwa5aZ4KWYf3v z>h2~Q@rbVjkJUBx{rHI^;SeKhId&O0-h#_DX#s&z^#=2MPrvY<(~=etR4;dp!skS$ zD0GP;B$~G}iI3HtjBq@D?QtD-h>~1HEVXU6&kbjyp*!x3$ z+konQO55b1!g4Kr0{FoxW{U=e?#*I*JKv;96fQO}>rr}@uF`x@yKuXVf00;K7SaIU z`)svb7AfY8;v7(Ly6da$#5YO64RaDgHb*reuCZQe*QKR=OkPd;7=Xd~)4BCG<@86M z#_aaCD4}Q#6_10RUgc8^6*=86Jclk^e?sa4>>+7kGx{I_V3%?JIP7RFgC)md6}!jt zZ^?3MEKoVMn{@npnQEgVpWg*#g5TyS)a)(<7i!&0GzbG>?zuzEHImGTYJ2v~9U8a~ zZGSSL zho@$oaxV-9UywjBq)T&(FGqEmOSm^cNipCKcoO@F;*7{umF5<|+had^n8ODZ&gGK` zI^^-PJJJe*+o!L^bU24g_7}(rRD1ap|%{TR~ zXkBg5ct7UVaK@y!`x6xYaa4Pps}#Ja9MhoFXOa=+8ZALt*g=nf~bo2*pkL)R=QuW#8@BhJ2Cto*}2pk=SM$bfe$CuMEbNd4Gl1i)xP>@L*z zx@v4P@8%WjXTS+GOjp&w`G>`Pu8O`>=2Ktce2qn$nw8b$=|eY+eL-D_3hl&>uVrBY z)MK)ybqO%+UQ8>WDLl_7^5PGF&F`&12p$PO;Fq^B*V8=*Sz{29d6D)SnZ0tXBxdRn zxQKed(Ei&In1vJ8dCU9PdA{ZZ^*sOZKj-=XE8{|(2wiG@bIE_EV=WqOb3`uu6Vf8< zXkhiW?8MD{NQAa2L{+2qySwvgsD;M_pET+|L)v;P3*jJ6((4AncL`avtF_e~}m z`j_VcuSodb>7#)86G!!X%)XSj2p#x6;y}8V7otFb8Fdth9*#b_a*}7?(4nDI2JD}R zeQ!r)-|O+f>2&WKK{P??z);wsZ<(fEGU!qbCSGfm-jl!bv;kU0lB5f%-p`L~)Yd7c zpaT$sTEKSrR^FwPbnJQO_wA)nhnRgp{I^X305#V+8-V;z0`AChnCO(K!qo#W?HP~( z2QAez^Vm;wt_+s-D@}jE8rxusZl_)z+sCK$$^DJ!fyMTz31~Ht0NoD*`tOOLqHjGx z2apMb)eQxlu+-ZRF9Oz<);>ZO40rNA)%!!)BSsNGI?oT2fRB;y8mKqmGLoQExkh8b*op|On5)Uy@~%8sxhd+-DQRnBTt2JH7@gdJr$mh{G15xDAYUq^912zkhIVyCu?cf4b^NM8UknYt)cJVxIiRS{z^6Q-F7Evr zlN?n4R?Z~_aC7AV8J5btZn<-i#U~eFonZCyD`BN710T;zwO*+mSziRy7AA1)G%awE z{R(KB`frq>9Wg##o9?@~dX1_nX(Z~lMbq@kkYlTXmhkO$A@05S1mCa43;X}wQ30(V9 z@)#2u#C>VH0Ec8NGJ{%~p`N_8{bE{3u_OKbL^)RO#!W5O-*XT8e4^^fUY$!n-jJ<) zBCB~))AyasKgrRJ1ZJ}jE)OOCajzqwn*0fa;(rkL68LiBme_;S)Q!tuoB_Jx1}0(0 zDvbC)qPzv7Bpl^x`86H?PA`wDUGAkdU}^b#6n;@4%G<_}(tmV{09K-c(90kH5#|47 a>ST>RFd6PY0IQ(^UV7RF*NU!M|M_2mCMdfA 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 bc90b0401d755b79e27ff9200434660d02b132db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1231242 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�J&@sZ248x|( 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%0Amv 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

O~HwiqD>OS^w3gbMxY_Z7*5?D2sBgav|? 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 z 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%0A45ung`3;HQ7SH#?=@~A4JY;?HnbSs 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 z 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

P*!`&`K;|YcV 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

grC0Jv)?2rw(F0Z-L8XHbT631-M+ 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

J(wE5_J+msU(Jsj{V{$m> z>o_=kMAW7eezNz;LqD_WI`X(~$11sY1d66{;)no5yhrE? z`rwzD{(X85@VE$5Mme>f^G;Y9$++)bP06E47l7G;i~Y^|GcC-SYuWUk&jB zwS)^0rzBWcYHS_L=MwFnjCO0>t?gj2hlDSZZy6H*7XFgFL|~{UGdR>iIjawv{y>5A zRPD#mGx+DJAELjrewjt&eS?yLI-bjG(vD-+A9K_s~u@Ft6PG7>B0dgP2i#r z{Y=y-NO%!0_v8&QlKLYEUi!P#WIg(W#oC1hpK&z?DaR%Kb`tnzBtAh(XK zQVkDW8sX%Zp~bltrRo;ugumg?AMrNkWhdVMo#mAG$1IJ`=eo%xCuf;SPHxR{D3wFS ziAdcY_3C4COrzaT>9jhY)*-Ft%KMXPHGg9Cf!K^UbgZ-0YOvcVhLp6M@KoU1$lVOiw&CZ*8vJROuA;k`YKx`lM0-b07r zq{N}>xF4R(&;w;$P2)5paCJUai!eyPw&?VOykXhbAa7N#zSv>h=TF$z*!~8xC|W?B z{N+CBBZE_A*D;ya_5fi zMMnro%VNEgx7jT2*mmqjZ|wcxM>sdPOCMbqA-}G2iNg}SNYxe5sGbA2RA7VtYPe_> zAP6cpW4Vr(h;JvEK5F3A`M0c&k5K%BerFYImDcVi#^TV`kntQLe&Y9k5Hame zp^~!@KFP0?{7jYVrIJtkf$H6E)_a!gP0WJf)7{LVk8@7ahd0Cd?jkj|)9ZSVV08J_ ztojaJEvj$PKK@=|?c*SBsr-7c?xB`Si+$GP^8CiD`T5D^{JhY;!{e}eV>{3rwK{hN z+sP0SJQP7E;~&r&dLni7@@W%D(=x;_CS)b9vJ+Rii7V%6f>Zlp|6+16rfs)pdD4Wt z!LuAo($(UdPBUy#LP~D-AMOWNPoM_D41yK7DH;jF32UAjP%B8elLg$D?Pr!ubTK|c z6-Ihb&|!&oax8Eu*0rDLI7+mwh8}?v=6=B05sOI1E|KhwczTySjSj$D{rzk# z#gaph)?k!I5bmrM-^p+TBfvcV)ciU&560T2>Q`o=j7GRel2lhveSIt!=AwpOzd8#6 zf(ic4%x?k5MTLW0^@^uS+Z)YX|IJd1#kFhG^GlHz=m%G$Qqru!3z)@Ivs7jDS>v2m z_Nh&J=9RDtfE8ZzdRipjV#lc1e(l@HM3cv^#Y`vowQx~*ewrn}#b`Prn!Kfa02f`c zfN?eM#P8^;8SIl;M$fXL=Lr|s?n$#4bA=zdoQfBha&aFNUoXYyQ}LtF+k^|wLve}4 zBvGC80Ag|Dj4gE5vhcO&9U6$SKPCRZFtzvOzo)*WGiCp&;i%iG!iA{tz?VFrQiQHWuV#RPz;!G{2^v)IZPfdc1{b=Y zPN6;!Vwe-wE!Na9PMoX5_C@#d#DFF`z@skdFzSAtMtz?@p@zg6&~^_!lmN{|j}g2W zN4~JhW^s1(B-Xy?i7Y4#@WdfRrZJttKiCiA5|`aYPv&P3mynApx~*Q)v?QPvuwg$o z5$@LwftiwJ@u3qozMW2;_e1Bme!(+xEzL+X=!?ZHAjVEOPLN|v{KCfmz2h+(=oquX zWKvqJ2_gWR5iy@15WS4xC3t6=CHgD6cncTj()fq_=sY^WGZXDa_bW#6y{RJj?r!*v z#`hRa4F*o~ezj}unu!^IP+n4^o(YF^>fel!V3?6k4sA`t9JOYrZ@>=q** zDsC;Em$s9$zV=gOX3Vr6I6fI8K{J7M$ebJfr{F8#szIN3l@l!eTC!2IULhW;5;~)Y zf3zobM(ki^^1$&>$}sQmY{C-{_^RE+(pRN-I_NS*4L>Et|1oB;pk<8&$-yyZOyZKe zR+(z(D?|YynNECK#HaJPjN2HlGLHXXx5UF!p8-oJOJ}Wd=6_7lxz?&U(-h|<8U#Wg zPRdp_h=kMG0FKz_aK`OOXr!rG@PP@YHxy^%d^?RkO=!P(;P{`A=!Mwa_wC3P7#s+e zcdJ}8N4$=&m8w@5F?}dWs1jM|J=wq*`3E@71+POX9$QGwkjV}0qlkgR9%^ZCT{UF(F}|Fi!f zdDeI|knPsTXS+2TRD*{ZtwyqmoUYHrr2t_-p1)`$HHVlA`8z$tRq8hom8DHzP3#`AmgcCS z_DyxKvl35DC@FYmG=px;H&m^iCrhiSp?AhR;&52q611uMJbDnURh;7-<|l>c#zO5W z3sSYRRobr5AzSFUl@(v1k1Sf*lP&crf%FCsj3zBD^^Tw|e@`?6bSJPD>%Lp+odJg$ z+GSIv-yx^x$UtKc5N46Al7#B(d|-O4(|F{*^+izIt7owL>O3L!|@ z=*F1yJR{<>wXG#u#XFv=SYVP@pOhtGX3N1TC@bnB)fUmRPDpB5U;a&djEO|AUO{aB zphI^Mt3IWe?y~4d^sgtFeqIE6xNDOzKf45c$a$P3i{q%jXU6d|4t>goOLb@oi*3p!O;ayjOWx;8-CA1ia0n2mJsU) zmu7-Wm}TXeaFuy&w@l0;5%$a{cbda6#Mt&^v{%Nd$8hP)(2dfe`*WV{uo`T;d5hIl8Y$wIr zr-N~n>B!pIekz{u$wZrMHNke5j97VZCbpXqxJMM-m5dUDt1y+&>aF%kK29|ptYIX2 z%y^lJ+lBV%RGf3+U@fYd5QekqAt8QU5=@;RiOHdVr7=gI4I&T}fDDV%41%Njbk8c| ztK+6&LXFW@#M13r+k6)`$eCz}n3Rf-SS3t* z2L#t?Qam8PYFVwBm4yzA4F^Cxdsc&S#Nl!NTWzt*LW@!*Awb5(60tFxK-bW*J1IPp z=3x42->@jsOLiBM*GT;cA!)byhy8?Dwa9Z*@;PF@2Ncd@r+eOVk4g)sNAJPy48*AQ zSq;B-WbA`IM}@CCT6x?)FC9{&@1o->k7WmbLUeZ+3@+}Ya_qBS+>;S|OB}}Hfl*Hw z_DyUOB##f$cuSCKV6ctn3+Uw?wZaB68{Fes9UNV6nS$ ziOm{x(U094yu_`nosb5UbQh7DYS>on3lFc(VyW!buYIm)#ckBowi0g2KvN)N-;nzi zbicWqAmVdwjVqP)49`~yqD84b7yc}#I9E|4_edi_G`gNsLf$^x8y-0X<{0-r!s^83 zX1c3I8$@z+UrN0AFjv9BzYy*>;R%_DVJ?o_;jrX|W4~vgB&+s?U%DYgZncn8K1^->~nLhp$c%83LVja~*nVtFmk9@rfng$%}KB9{162pm^!=@#7~? z4wNiC?srcrRjNm@xyvi!2Y)C!mY@3qdGt&5mFhF)xge%p(X;8Aho$X_o<-MUHT_Yv zyP1^Cr)`PV)0!+ugFeOez4E|BMx*yRRQ;(uKI0E4Rl6ad(O-Zton1;k;E)OTI7&1_ zY4nB{JK+@5XY!TUdF&ysYHQeOyjQ7+7^cFI6ecqf;9Bbm-hazD5j^bkR_?WNvWsD# z5M=n3lCRmk=6!Z_+U_6rwerAT@${CqKQ(SG<#Y+lEP-4C`(?34uWNkn{O(>pw#L-6 zZh)#S-zPyf{w`B)JiQOEwc3>jMp;E1A1-*sMP&cu2E zX}lDyn9mv|9KQ?-D5MRcD;GyoQN)Q-4@=0Eof2_F6{ zPwEe*aw?3tE2mQRFCIX6cD%y_09aQPV7exqU_Y7`%=uWpE-Qxlkq1THr07*CdIv=<$AMzb z-AC6^CtV!DMLJ#l%$*m6t}rnr?XJjs$7TKH{k~YBwNzxNyID*(RmumV{AsCLB1JhU z($Q5alQVv8@ietQLQ^(rMx^TaY5XoNai15Q#PyHIgUD~-nc-+0vgWp8KG#U?CByJo;<>h@#v}QVKE4}q!rub6t zRK1~CZt#-meD~44C9ZkJi*NSM+|ltli)Frr3FnIsK{Xu94U8ss<5G8cytQy#aYd0g z9LzM0JgXmK>zfPIaMAr^?3OO-jmBa&t$~DPI6aL#B-)r#@65e=$!?p{NOX0!wqxmG zn&~B~Yu=3cvxudf7Pf5{TwqI6l}5eiZu(l+#N7D@^x%HuIeMSv+Ma_1Mb~q2#eT%Fs6G%VX^xGX4M9BK z-uFHy(Kv|2j|ZXyVM9+7^+-`tg1Yb5Nl0h0mpMNb2O%+T#xR` zsOQ&!kd3^asTLMvo`Vi&afcNLs}Gd-@oJYxHGbs4qlxq=`X}S6eHKeJoSfir(O1-> zasK=Kog-Er}_*^5u4|K<2 z=4uZ95WR@ncmkbfPQ-wUUZ87BurHNXq4du2Hh=)GMZ-22OLeI)T=dkhF`eU_>M;8y z{KfY>Vi|dOXV^;k79nRRCt;piEN=yOcTolqN0mjN<@$a}Pc?P2lP{I0PQxxCQ+Hk5 zGV5oySsF|Oypu*?tbUj0Y5>jE9}C3`L#E4EJFPty5z3ON*}Lix#{q)}>zL(p9b7UP z2|!hAz0dX8qBACjGtX09O-s7rhz>90^L}Ek1PAYr*M8-<9*)1+zr&loe6Hpt-F!6k z@HjsA2jE-(jTk8UScm5Mz^Bi3`t+i2uE8YPXI;l4k5n4#<~+!bpk9nQ`52#Sl_Xc% zR`2fbItmF{06^byFn^EtC^5rLbVR7bws^I&Ebp+rw9Lz?aj$EKPnq0Ich6BDK5Mh8 z*;k@Bmwh2UF3~GKm^a99aki$Qld8?chzjiisx$WpjD5VJ?GBo(61dEKZ+yA}{KUd@ zj5K~Fa1>RNk2kLnb_1y^V)jC6M7QVD|5%-7ABJxAjQ;p3%(#$#=BKM##@TdHXwSsx zXgwrUiobDwnr64~3s$7C)cUD~Ljr?nd?%)1s#Ge?XvQVd^2EmFs@f3Wg)_4t(CSX` zS2FA%1VjW6*Hb0q>9=hbU+PRpbRbj8_Lix9lF{Qac)a9oPLAng+pp6FIgyPMF6xEa z6W?aw8bk|L;7V*n zY_)Jw_B?xy6&dXHOCj6*WVJQW2Np8KSQOLqaoO|JXv=sBO(JyruHefM8C{I?{(Yj+ z-1-uSaZaPn;%=D0?s_z`=cZz08TVhCW>J2NbRe9prhZfs`Tn|$PmG&UQEM?Cq%UQB zxu0G!2JAAmRSDCKaM5NwNTCOjt)@sVj`3c=lS4asqSNE1w7Pw;%oc)1WptmKW@ggs zfVglre};Fj2Z{<8O}{pQ2%p%QG=0;DV6NPFMSb;E0}RvVo@RNiG;49&%(B+ z^+(mKsH&Nfth43XHB)GsFh9I*ukpIsXVSeVe-D=KK>kj@KC;O~mxcLte(gVA?H#C_ zB!)B+`es1}(*uHSTBaMb=R0bwVo9zFzWmo}Yp|QV=-2kr>iM-F{Mrek9kGnh;O#84pn{B0O-OZoD+Pq`#YD z0`)KEwRbRj`dKUqk!DmGHqNOGOQqFX8L`KGO%$j7KDsl7FlM0GgpYA&jZjkNshNp5 zwYZz98NsuY?DVMd$402Zzf-jxut)vS2rfQ>SeZ(RvaX`W-O^xHsw;(|@#52ZTH>Ca zf4iEfg`ZfG$x-!;VXN759-}e_$u$SW>MhrtNXahO97yZfi)Q$qX1?IyTgDeJwh5u_ z=z!vf40Tw zp)Gix85`92(P|Og@g9Gj8Afe~k@NSqSQJgXB~5IKf5!ZmxCuwF4;(vsOK=oC_~9k< zjXHT_OZ-8Jyy4^#ZIg#P;$OeNh94FO{zqBodBP#Io$+~{FZWsTshlPE*$hnA$xUt?puBRQ zmwzBKMkxxGkL;&iKy= zHW#ap5`}5sGy?26UDS>+9i-Ncuv<>Y(SZ_6=E>IWfBDibR?trSvM;gYJvGLM%t9XB z1dXjxw@qN82=BzU9{?7<;4N5DV?6m9 z77NB-`t&AjY&uuZfi>P_{x?r9kw18h!$Oq!JoYPjd_VWdrx17Sc$7AL9cx| zScUupUTrXJkC|`KZgfDMZC*Q}&NZ*I=sMfH&Zg^J^E#KV^UUkKUrb6U3jBn0qKgSb zJR2wAXQVG&@VXzvtH@#vQMh1m9&f1)5W7;5Gp=1{iEHFRfsW;n6T+F}L^FC#}r94)F8jna(CKa__Y@T4875G?mIBRcd@#qAZ&dDk7x_~QR=+(;* z6}}<)0#X95of!A6y;pub}LQ~EU5jkpe{p1J<*edO|40usAq`r^5iMG zp5;oef0dG3Rzti<85k13Xe8ruNFV}H(ki*qM6TJO*k591VdLHA-0Ei{oL{51dCYaV6jL$!6GbL|bRLKa#N5pxD{sWn4 zfv8zy)n*an-@(GlpQz)74@9QN61kFSy*$l|GhJ~`b}G)PFlaqU6Docj`gnRgAun#$ z;=DFn=}lF7Pi8wC_P!jC)uXkcH*)FC-lzf#n6$XXB5bL9i+Zm+Tf%hGTgv&PUt!#H zOgvipGFl?yC!ajatz=sQ{St@QKzTEpGn71wgP<2{DPMWd)KYddA~cN}#Wb86Kawtu z8zHWDe5aGyb(6?G(~`iFOFwdoxNIN6pR5?!+9Jpg~}) zPjRp-(6AqBMIyRIRmL@`sUu=jaqyI<6RtO~~SC z4D29Ss9GD;VLOaVF}Pv#oTr=jD|iIfcJ;z3PNO%!Ug)zPyKn1+PTGYL0|yl|N7nau`Fd%p&Hw2e1JNxhQQm=Vvn-vJOlu~ z;=xoQ5vu9}mnxfDjT)+>Y-+4Om{mlL{3`HFiR-h#6AzBFB9+%i`E{dHJ^fzgtX;IAza@R0 zpW^A>#`ZEa;+_E{GYI5l`OJ{r)b-Z0PR2uVe();$I^OBm4vX_o%y>2Vbgew~p3+=Y+r(AbDH^Td|Gz?0de~j3;O<9tX*a+ ztS99fOKYU?wf)PTU2Sf?X`(aFTE;Tr+gjeg=2<@o7 zzhSjCNlk}Zt^E!}Gh`G-$j%n~2g)yC_hJq!)^4QivWgvlrs;@?!bN9UEcLBJhC<3z z*BGCq{XvCCn#6F%CvTi;6}ya4YgiVPRf=}wxvpVK=q5V_7&c<?-blgQ&p5lE{)_*Uf$>Q%Yk@Z@I5FK6IYMIgl-p$VG1*3-n@F z-zVmnzTReZWFx;%vVfsIyAMNnYC{sj`$&SFt{~q3_0u{)zY~vz15j5rP=fX~J389$ zg%LP9Eg1rFC7{2Uo%j}}!!7${@K&AZez-P=zII4RILy#-zt-&6BBimQ(|wJx@g$#j z*-#L1Tsx$d5BpcKPbSDqM32$lu}VblN=!lqPr{0OOds#CeI%#vu2?3UYPoUXOw*Zs z{&r;Sw6|?fPDAfgLW&!GUpsXQ%Gq!29cJc?j&5S|;i_CYQZ4*C0=V^Uv zDh%WKDgcn(XSZ}9wP@!GG#f9;l#KO- zZ>xou0>VCu?ST>HN5SE7Q-mMrD5r1#MB8fId3ihYPnl|HlqGn9UhatYLgdC#1d{_d z_ZPACf*nBPeTuW~7G~nVFKkClve1doN)*rM*!K8byYbc--m#V~$<;Lj8gvQ((f=P^ zmUp)}S@Yt?_h#^*F{?H1o*Xp5@c5b5f-GU5eXq=RD}LN@G; zIe{9g7&Qdx%^kU5_1E0Nj???uO;@+i+09$L4%x*Nr~Rtk5GSS^o=4jx9$yfGh`3+s zbXYOkzxk8hk{?snjvS?i+Aj`vM+R`$zPaBZ7y{ z(Q9_t92N=2a4Z)ZdjvFy8Ry;3q5694pn)}bnoN9GXIPdadUrYT|KlBW^uoEbC06Rd z8Gtoutv@lOWax=5v_sr#IBk05jKa7ZW0#HbTF;Yass^6({5?jKnW$o6PuMSiI2sAq z_+T)Mi+Y`Y-s3J%%ohqNb&^B(5(ZEAY95OR;JX+4V$I*k{*Iy6wqSp(!RHyG8<%h{ zFK6)gU&!-)t~->LqH;om?_g-6`y1(8GZ6pCj7IllhB=^L4m$_WEEC3%?}IaHnfW51 z9;Xoo8;S8Ws=rIMB*F}-Gq-xJ+t@L&$4a}!%oq2=x2YC0ROOnlQ!NiVtM&x?bIdkn z?H*e1(U$Vr+O7vPow53=JwaGR8y>1>T4@zqEWt}qw(x6aKa7e0V3W!e@zj|~rR>7N z6!>Ao^$+GuuEVnlU#G^4TVLVgLJoELo$)>miL;ho$H!g4(*u)COW~;YSnWySbvw>a zEnE?!U!mdFXeyJ+G|7#SUU$waJEW)O)MLh@z3YSVjK5L#8Rn4Jy4G|T@M-lPtkD7S*fm_h^w=Qv_Oks&Vp{YLsO~gT(8W z&!bIP>k0b_IQ&_vhOiMJ#)aNC>lY^OD2_b&bhsy4ib>11$D4}j6Z)7Xf6XV!bIb?)`-vK2wl9T8Ia zv@M8A6fRgYfR@M%OStmV_RgNWU8h>Yet&V3wP5dml@26BV&{41k{(6}b ziSrQgMIOyC`nIH6qCHfJ3Gwk!t~-CH0Q3)5E@|Ey(~; z%I2||p=0fV3|Av^pcH%pW3m3qy1H4R*7OD4J5616zvR?qjr^slGe>Y2k3eQCzkp|J zX21As{WdvUzm_24*jY1Xg0I^=E|UY#WpY3V+M;wg1afj=C@DLT8gx?QV`JACPR8~_ zJH#y+yBcDO^vG?AnY*5O-6QnYM?2-M?8pQYyp(klh@9#4p*^VL(vfKvwhNU{d5+$j z9=o+Z`*d-+iq?1XoARvWv_YX`sS5_femILhxra>ImzN+d)d`HLm9h2P?3D_Oi4x88 zJSa3{!YG!wP~#_Z=a#`bA{%6x1DbpsF;LGa>(sMmg^pRpZh96nj#ndqm0tFI=y-de zr?Oeigq`-AED1{Yib$te)!kpMmtZ^J8qYj$v$Slr z27174dACt{tG%X~w){#n9BvH^7t)4UpmjA%5nb#z15MLcPy}VG*$()y?tk7`bkfY& zMMV7{IP0~&TWt~}6iP_6j$|KZFuDN;-9R>0C{W+EB>?Z4e9R&sFS^D!{uk2{RA`lN z{@NC&RkX(Sz@XD3s%fv2Ai0&z6EZu}Nz%EU`Rq_Y`pzf zn;BQgwAcY!V&QO?-DW1#rMJfc6BB+dB%D%tg(Wb8n8_;}VDR^is-Iao+G2WTw;R>H z`J7g~90MoU8#?I-ejH8pAaq9aX~f~7m_zwvojUV>s zRMw5pR5mxdb_aVC!kIt_XG{)_CGsgl%3f+Gkb_9niaXTa4zD~w{l+E}T zd65C;#7g-3o=LbiI70}xPmQO~Nkz7H^KMznNy(xVEc3Ze1Tr8rV$jHYv=#`BUDOc;%i zo=1QppxY8+TF+n_?sTDql3YNs_AfVcPczpfGQi0qF!E4*b!%#0Eo67*^0*0 z6N#`26zPqK)JCL1E?A-bKIYb!WPxsNKSA$jzk+S4-LWPqw{yy}7AFOFInN4IH^;_j ztJ-C!^T5m1{NlQa004EMq99357176km|QVVa<--mX-8gRrdNXy=&m36%q9-+M2TMU zjyn`<5AJct{T+~6hZ%-~yUYzL_2_DW#{k!a;|vm7E_qx89Z;n;)c^7 z)ENGrBL9A^t7tbb2_Y%ZbPn{F^}4mP=-0y#6lIFrB(BA*y(OOyltM_nCHY_Q3r<~` z$)w0RyuF8%xPo7>z4oUKh#wWlwIhbNb8P!gChF*yS(oXNKgQirYUTdpR=J-Zx&3(j zsxonTTHnSNUzh+A`BlnXM&3t$)e)U7* z>O|t|5AkMF`L&J5;?2l?dZL*>CSLh_;_8jW)s<~sd~-_UaVG%gC3KqMeb7uxysl5Y z%GghcB)X+H9|0y|1LmO>F~?WgEUx|Yy2a|$m0m3kc1{Jwy_2?%f4-pI4EgrU$c*Kr zaUHh(@tXJ+JE$*q8r#@CCvY_c;0Q|_xT*xYN>l$7uBhBl%zLBVxIlOzuf$EfJf8nT z8}Cq@smieNPLnk{YTSkRxaYxf)M*FuuilA6u3&>RNi=>wEa^XLuZjDQ9t@r#VoLE^ z-x*=q=8z|oq92^T;_ZCo0`_+PFY>U&Io~N*S60`vzYA_P35b`UP7n}@Rjh67X0;e| z|4ayC*tThI?OhcIgo(PYcr`)&Y400%iNQ?O7RE;#b6eVD#-Jq~0;h#HX0^cbIJlfA zm?$YQSvx=>u`-or`hHbkA(i-j)HN>RHp-{_v^Ci%qoeL}U-*^fvG&*ogcU3i;oX3X zBoXt&)s}e9G&BJpSZ#}8EapbCe8YYW?o`8TxOIIa8Z-_shA&q`e9RBiZ4~5dPbIl{ z=jFD?;woR%)$L>dktE|TfVtJuZJ4XhN5bJ=Nx1#|d}{XzqvVOxXf@nmR_VODsA@CB zCU?~+PWx{*vsvCMn1kQthf=d*m63Ogc(?^;3)_AVByLx5&2)*m!Z{?)C~Fr^$!K2$ z30QEb$l&}&owZ1ogV9nrZ^PECnsD?d;s^zI# zsY6rQretxOC`^9IVvE5hyhc2Uj~H`~6TuK)c@L37%hj1%RoDLD|3lrohc{7ef8$A; z&=guGNRgrlMT@qA+A3&60UMgo8AzZiD0&3(0^%J@0#zs!(qM;i6fYyK0r+|oHlG+Z-94(Wy^O2wRx+#oC3U9(q5Jb=$ zS?7DOgI`rVfU}!)5$oNAuFY>FF8`6so%L$myv-%wH2r!~WhW-+QId%5x~9^|@{nk* zmM~NTx_in~vvB0Ee~UnrZlMUa8ep@%(6?s;?o!IbS5Wv>H$m)oLPb}K5b6QSpWY@o z0!%i-{1`j3cxkj{P@cuh5j!njkYMndxYeT*G=xgTkC}{N-<^|s*l|Z9O#rkJi(TsN zJ8$$pCAxQFwhtIz|3I2~PdDfwLIkWm)Xu@c^DH^LWjVwd7RkBOUOJjEK~a8jgSKjA z5P(V+>(&rlTo-yGN>3M;IMtH5AEC2`{^v6yk<7#hcd5Nj2NX-h(;3;^no9G0NgM4N zc8mmFye8sjrZaony=k-i@)EFj$yARm=8#8GbOvHfQQ*Llu8~m1ao1_a&dzHV)pYS2 zyKb0ZVlBfqt>M>6PVbMLibALxr~m=APRSOeiNPG0G|VCG&` zY5z);yU|HU8TlKdhfU!Uc1*vQPDnt06;3j+D3*Q%Ersl`@{1{KBiv5+b*LCRpO%OA z-fA)^J7O`osfi37cseSNH3D6NO0X0}lCmY1;&az|>?L)c5x%0825(C7xtqOL1A*yH zL8pOV#f#b|il>wqXhGv8xp!)VRXCL)5d7mic;O?l7)=vD3 z#P$o}b1jhGU%a5FFGrL|mo!cDT0w{?WgNrgwYbFV5H;R{bZMoTK570d(YUA5!0IF$?1 z44$WmZ6F2^!SEsim@5@{l51}ZFWC_N3Sryw2~1=B43w4=@MLZ~V)s_S&MuA5!JA$6 zo6A6dEk0!Qc1Lrako_QP!aEB7#jPe##7+P~zz=!ytp;M*&mcMy_QH#y-h8STD=q9! zlcrYTyzOH_WF6dJVKX(2H)wvc-Usj$k(Uco1bJK*x{7j+b7fz=kYf# zsx*e7LF}Nt^T^_^em5GAJB%zVfBBKsdUbz?v8`iJu+oHmFt)>@#x|Lk?#sb5R}P1< z0f#X_2)5#u;=@KnAe?1{zC&LNzUEd}b{@&7opT1T%lr>JVD=Q(IG56DMT0MbL5}J| zo&je~5rX@@FPcEe?i+86*nKJT+;=Xm;1&jqtN0ix1Z3Bgbp3GK#x%_gCSU} z+iOMUrn3E4bZQBkZhv~Eqv^I7mfFN(Jtkx?>@CVwm#niHue+{d<$S`ihKrYObGt1~A zGm)yiCQ!?#n!>#P6t)_*?-AJQD?9uM_Xl20wma8f^)@$pt@qlFtY{duk{Iv>F51^)_0xUluA4KA`>Hma{RLOYooy;JR(rZ|U*#r+ zdNGuGrHY3Es>w}CGfXc}Gho%zeJyDP859{QP=xtI)CK6(W2{$l3;~t@o{ZL-RMN*QIX~iz1<`X%Kww&6zKrpr zH`W2=5g8Q)XE~C<9eDC1x>q3+J`DHqb<)^m$+-$o_`0(;*a94xaNrGS?|+7gVd(w0 zilESlMQo#GzZs~=dn9I;7K-yXv4I76M_Sw4z#R@&Q;2j@LuQ~zM7*z z#o&v`C{Ff4KcL@X<`O?>x8#+M$H6x&Y3K4IAjH#l=FtQUh`f8y*9ew}G?JP4n_s@D zUe329--YYwyU1~_mKFy_=q8>f4N>A(8EL+rQ%zwi%<8Ra1)(eu>a{)39lhr%5{-O4 z%k(7i$%4q?1lYyy=-}H4U7l%1xI)<&KV?8$a;x_`v{5+8a^xKlT}WfWxm513rymyn z1eodmHj`m(8kvs{DC&6_;(OR6)@v*l&u}mzXD%^WXFVOAbW#MJh}7^6EgE!_E~<4x z1JI(-t0zOm{@FSj5%0A|rgT~_eM;wCMvUpT1gA8>u!uoU8PBGJk^UHMzJ?(QE^DIsN)8twl~lQ2 zD+9a7h_S6v(=_QEymrxL1NvZ(h`3?n2KLLJ!~BgTQF-Ws9uxwvjCW8UpI{7F@D<^X zkx%Z{pd)6gxJv`YY7=B(JH-nyKR}}_y}(tZV0-B-*DW@(&BBb$et@Q@D6L=vtDVlN zYn){?9W~CCOfNA%(u-^$cU>@PHV`_~zstbR^hM_i+!SDRuF|4l(Sw^{FI}L;8gw5yppEbFt5-n{t$D>Zahd!$ox`L zlsl^V;dk2cs*d}YGS`2p&0aF6zw<|8Vk*q$)fb68x1NuXXZ01DL=y~>sqlM7*Xz>Q zb7?#`YHz{dOHeKfet&wY9p!TVkC4mBj~Y=g?jR&?EV-PJ$Y`0klc-VhRHXKgPZPCY z)2@`po~CLA?}!o)alg#Sp{-CoPaPencT^V*_w>+R%%sHgZ%6R2xlaDyC7q)fRuX$K zSH68&c}h>Qp{LepCtp2*NQ&ql^&Jx#c#$Gf&^r=6IF?d85%Vd}rFGFV10@)NjzJ4o+pR@n15thUP==E_RD2+4_18+2E7Nm3JG$u`cNUdbBIai9#3hfyf0R&TVE`^os%ATtwW5Q}R zfo*2-h}#moAQIxsG)&LYdnISFmZub|&{pAc<@2BQRhS-@2oK#E?|Hy*R-%SV&? zw3rO@@E%&v%vZe?UPhchNW$$UY}Cj!s8SZxnitQO_N^>!;$0~q58=}0Ip;ntX6l(m zc+xMkC>A5G@P)X-WsU7T&vc9-ALHi!K0_+b#lwOtK1NGdEcLPX2qM#SEt*G1CD7*B z=gED%OgTTCeq7oR_2bR>ql6s!zLv=1jprDu)$5O4)P&dIDFj5gf1#xii#dj=_f3LPP89d3Re}xl)j2=>fo7Ve=S5~lO5p6`mF#rGxzhoYsVGOtQgky) z8n@E~QqcDL7FwItO_6@syQAuZZqs)d&Oe!EorGf=#|-9}cuc)7i^#KRrSdP> z&w@iQArlpf?w1+DISXi#%n!X0(K9sVj5LjAcKph8Bl72Vcc)Ep_!%^I=RuDhjV;B6 z2?oy30{AinjCFNsIJr!UTgbeUkfSkW|%rsNwu+3{W^JhT-X$@#LFI~B1PpyIVGiM9DJzynmwG|E%x z{}>&a^_s1=BeK=@oQ`Zo&#E1b(zWc`!2%;N0fxcMdh{Zm{ zHjXF;3u?6>-514TLC}XybIMfgNpC^j%n(EIyKS}*K zcOue{-v47icsj=$8qe~N%0mYn2mYe~-D?xZe(x3j-FV60&svx-ZnTwe1_^D@CG$o( zZ0JKw94)%9S^4i!6o13vek!WP9}Fe#bf?}4%Ef{{YOXjk?9Gy+4SNR}&Ck#cd#}Er znIaedh7zSF*JIXhJt=7i3>Gb!crnfqX7nDfB@>^ir4XMApY`yWPw*B!@^VlJliVfJ z#FwMtO1K{PWn4b<_q3&SlKRW>h=c6>F8YdHxCvX@o)a*vSRc>Y?!I1A6q6c>d?#<8PRqn0y6c_dX3@Qq zoB+-+YzgJsxhT0+^9!r7YXx0+UvXK|MdW%y- zXt8rbHEdLCRNTcm=XcV?dVhnMTL=P?m^*K}DB-?ejsidDteh_TirKb8ADAs%HeW%z zH%x|X{yBzWUBKl>u?B`YDVy)_65fLL#)Y>aS2wl=!R4#$l84I%b~yu@hXe*#k~nu0)~m7E|5A&M>=;#m6>Epr=ar17E{4;%>WAcCVhOu+Z(-nYoZUBn zp23ULT@~BKP@DwwUdKQU#-!4TS~4X z5Y{Br4S&>c)?3j{DWttlnQ|X$ROT};MT{+d3Ge}DENXT7wpfD%L1*$@GKl%RC@==6 zmG`xzdDC^%{uUSdRw^3Q15nuu+Ns)a83=w9dXgm%Pwf8=(d-J~vq-ascbHolN;;J; zF(`-?N;Rhu>P-~7CVN*XTjRA`SHYXhHQKEp+C}B2UNjQE(h6nPy&9SRQGSptvvx>G zW=+Ywe{nR47A+?*#2mz@XAA33%e95I3xQL5#xwtqpP89~%4LuEYB55;q3*5x#fAd( zCM_U5F7y8-Ppva_R-5-Wl-0l~Q=4??Oz$&D?4~J|hNvhhFua zvv{uwG+MaT@@sG}KJY}~;N0WuNBFIyEZm|)WQO{3#d%GDmzOQ2Dw{Eg8E8n5G*t8 zbYK(aul-6QzWtK9Vi~y`6$90Nw2YW*JCuc@(l9?&K5t;05EH4pHDj|Fq~h{v zyO$z6}}&9NFV#-1t?b0VOt(IN}uyH-nT{^_~o1hF3B_ zKwhcs*2bLtCZy&N<&oiQ{M~4l4gBkCI@BlZ#P#;}NPjpE%eJ-0GMx z_qvL>*BE05*7XpBuwgJFno-lcl;9QiDmS9lQ*+G16L+rkdw7!u%Q1ZmbL9AhSg>=c zfB;}R?vaMgIra$?MdbaN$Zo_NKWiKe1@1uyDPk^UgFnU4J^30r!B-9IH8!8P*gM5hTnx{Om?v9DkUx3oz@H-u-tFgGF_&5? z$f<>Hj7Np86f?|D(CQLcax#=TcWT!;5u~TEIm4(q`bh*MBpQQ{(6`CO!Rx4`O1suR zW%vx7FE)}dF^LHDYv5N5AFN9b;}1&}4^3?0vwFH1eP$@n2{E=?;v!R1I7OS19kmqj zFkCk#v7|ugY?xj-+a`!_rY_fr3j|+}d8x7(7-$IbeS#O;*leK5_pYBJ<8$RX#K}4r z`~eL$&p#D?YMl~B;Mlelm&4?G&GKBflv$o(ww|IRcES#uJPuvtV4S%(D;NwzJ1CNr z=reGrb1qZ@%5FXS+(MlX!dE+&-UZd(8{=?C#jE&nnxv7^?oeDa7gL0gWX^2gx+}ES z$zKsOgqD3gp4^ZXUlmevET3(DcD~tw$h?T>@`A-BK5wO_U?O_a2n)ZZD=FZx1piU1 zx24E^QH@SEoz-4lY&T#Zyh;LCy~c|cyvmR?ZYI7{colouNT~jHJM-^vR{C|QKGI_# z&ebhuLzHhJqQe}H)ugqa2vhOrYVu6O!;z9YPfT=j?#@uD|i^8naCEaxD74&MN zlwQ!(ov+Y_M*Kp$ozEVcTZA%K1JV@$U_hV0L5_1hFyfZk78wNEirX0f`jRZfj6Fyn zVSR${VoX80om(9jW>Z%Kn}QqTJMyW`v|K)`Xroq)W34FD(5SUcoUoiQWse7XzD`>i zw>YF{mZFSRzL}Org0@D5^lxWPL7%Qe5mF!2)QWA!N|my)Fxv4<0O%gchyKo3;xxC+ zi{dn%7)@SEGj>1|#VF}&Uae-{FUsn(t!n54CPtOD{cpu6XXZ~p2Puy-PEW3N(wA)b zmocWmTHL6WVA8I)IEtNsxI{(zO=CsA)(p@(L^(SXBet?9hV6Xs;Q5tA`Q32zUfjfZ z{lDo++7L043%iCc%*y^Vt$NhVG;#xDDT(#A{e@@V(;uK;c`V95bYH`LePFsti)EbO z7G_!q*6kFZwdz%TKZy>wgMT7ERRg2K4&r3<+OuX2HQ#{{+^o3o5fJ7^6L}0>bda)1 z=+o?ov^4;a&pk_9`RW6@4dgbK3n~)i@CL>1PcB7<4y~iHO0V)*iG@<2$UbGn49bL4 z%BSz4!56#W55|M~(0}+S>m!~qvKG3bg(c|40Z-YhO^B&`z20d$wy}!`$?+fK6%Ryo z0{`h&HE2d+JTfghlMLmSSWSi+Uv(N8fnsO%QtVK?qh*^oBZy#mB=a5Or8nrYg;h&+ zGvWc|W8os9C_c9V54Y|VVi#C()1H%pU*iO6JaqrAbV0n&TJ5l;W2%A=ScF-fr^vyr z?&`qsQj@PSPK8dQS%5B;IzwoqmifVTLgDK_Zlt zGZjd%sQMz_j4d?lYC)~W#9@ua!;=l3BwpRZLvwAryvIZNnGH}&C?5V`I+*5tZrd?W zwqX1LjYBT+Xl9+A#zWcs9RiBD>zSbebZfZi$%}UACe-d0@9NRSIJl(M+e7#bN@WYKKw1g_p9Ge{RHx4bPtluU2Mq70jCsjBU@T zv1c)Ds@Hy2Bk?jbH_Eg`U2an0cs{f4bjfP)6)j$(we>i~CV% zJqpa3HjL3b$@wRmX6PmQ!jC zf`h8z{G-i?|NWw;w08 z`EaVeOJP#bv@LMiesyu9ex)ySjI=pcH>q8=e#tyMx;MI z2cv;>9qC_p{t1l)<_C^lqHhu4@R3UX*R-&b(KlXSI4bTX2U-Oy^W`0A0F>uJlt-i;| zZAglV-@=vBOv~;yrFW@gL7GGEd8o<5I=@}4Qtmz0N|Hb~0tFm^pnzr_3-GDgbZ8jbZDLq}KZg(o zzVovrjai2Cxqw)M)b`f^pMzy)NJq!4tvy)5r&tB z1PICZpTp>xKFp!!B`iE=KLYw8AAd1R$LZRmd~+khZ0fed#y`ORwPMUrg$6DRA|foi z7+#uHm|3TUQpri`CYL<$_TNZZ+vCD@2`^yLQc#TS&*!1=1}f}14D%NM8;;95Y&i&R zq%yGMo*Eyy4^ofj7Al+iYd*1^+ot9JGH(cx@HT&!Zim6OwC1md4ielwXkw8I3ze3B zG(fpEu|{S$a~Q(sOJ5tp=S$OL!iP$4#)OZL-e#9G1+iZ^@kS>{S43NwGOWD^+iu0oHSk0~%0gA0iaFiTM6?^1 zbwwzF`S+UtAQ4o)6J^$K^nS8c=`lCY18HFC~q-(8)ZwWfLf_K zkyXdu5nQ65Ek+RXUo1p`|323+g6V<&_Pp3l%1ObqK{S)Ls_ooD78FhnzL64@P*fR- zq4~IaM)#$ed{4Rb&ZKRt$ipMcTXZ&(vxS0Q&f$oC8>Z_doj}s@ZYP75Gq(^pOQSO6 zdqUbtV5=gOKtBTeHW`@*Wc!^ndQ&{ZV$IM0LTfm7hrWi(a1D=)=@4tq98#IB6bP>n z9x0);kw=x-oz#SR;Z^;QnDD9|92-6=9&8G)>Jn3URc|td4~6Hj6Xtxl>}d|44?o2& zr^2PJOZcdGpdp$WgyQ}%jGdWecEhdt}aMPGfRdK)wQ;_Lm zDru`K*dxgE3za1e2%~?^wxedC!VS1PtM}y4`O=;7Ccp1XTvlg z)wpRXgMp?A>nFzL6v z?Nz*MA+qrIpM5;!7O9?2||g|ImPYFUO0#$Qx>Gq z>1#ng-MkV8eFdIvNY0gXMq5TagqISZe2(kw?jD7r?0f<3x+zM_GJq zXaegvdKs$#_$xEl6> zQF1O43mGB!zD^|p&XWe_*;N^d@HjbW|?i7h+0Aq%-Q`1Zr^Ew9t90t;NN!Q z0tn>rhFt@4(0H7Pwt6S@)BMjvw4wa>TYW>p6Q?y-#xS8U>^(d=yqBbexrDO}jW_3% z{%c4rya|0=W%HeE4?+0EQL*8j#i{Kq2-^qhbtsXgvK<6(*L-O^=VfDoo%&=e)ASiS zfi@uJaRZZ1Gxx(*uxz41#{DB=16tfTocsv}c-UQnws z&kRiGh(X_k4-MNo#zn!%H8KjN#u8)U=cr zCoYE`t?&%iOrjGWBUn7Hq?P8$dyOE^v5;SuoM zY4QqvTgPGi3w5ZdnCcL{rI_wmex}T2YYa;TipP-X>I z=*7tPAM219iPw1obWlI|(Fpgvrc=c8h^6p=k_JUXJCyA48l#gIq)ZMre$}Q%zAX>5 zMdi=L+yGna$?N;4AOFCjLcY(^Y%4ki``XOhqQ8;I&`cDJ;B2?8qN8KwstvIeBT6;_ zpiY4-#x=&r@xrFU$Ff+8kdOTU& zA=rle;ITT4=N$tY>}rj}w$ED|y57Fyn7yew*3LQW9kxnO5--;C0mWpOObel|9m>jB zPq(Pe1@l!PU{dJ!jto%S%%nU^c3wikK)W;~)h;Q2!+Y|m8y|;cZqd8d$}a;Ek4vwtILxpr~zM93=}W;A(ZAOJEt@{ zd5mPL6-3gs@H>Wx)?&H}6-2qNm$B(4t6Rkr+m-ke#75!+bO;zD^xt?;#& z))8~b+jENNZmc@R-EZzW)NDA#O=6!sHyESvZFwfn_e=~^2SsPCOHTZDx7k2T%6Gxa z;?f*kZX;-~g;gLXV5Nv*d(>XuldLayWkeYeuA`bZ3xS_vK=32BhQ@MvjLBe^Znqu4 z9b(p_l)qN|0jeBW6}A&;6@m^v78;=5lR*`JOWs|hDa|dEKU>+cyk77_Rxkx#gGkVb zc{3gDBl4q&gXWg*1wK(h%QI;a@CgI1&)u{>V_7JzAP-ptMX+sxG$q9)^{sJ9302%D zTf{3};$B=Pj?BHtY#O^|);b0>iZy}bP@QMJfmOFIhL)-Sv^SmBjJ z#vh~fJ_>}#lY#a0Bq4oZ?e}K#hs@B&KB^GbqE9|6fr*DvUVr_263pG=vsSy<&n}HN z*)buws0K^b$IgY zYfCRk732kJysvtX@}kqkqz-#IM$uzftg1|do1upV@r1Bl@eIqXgNBz@m|&IJxz&9~ zVq^@^?GlsKUTRw4JHjn7^|Y5d78o&=k1x-LX zxh1oXTkYs>#C$DKkV;G#AM0y`GA2W*W4wuudd~Iq?g?X#Gnc8)uS3_uD&AL>p=Ibi zh{9ihPGUP`lEu@9oE>B(U$PM<9?P%w8knh^0*kECbreO_fqB9oGZ~ohg+OnSXds*r zJB#MxMl}iYY*opHCr4E~Zc`2XCB3%Dk71i0;$H+TdYjTC&tzauD8Y4fLmQK{@ zvYnojr>EsOtSoZUF>Xd~@w|a)UA<{;Bcm8ZHbM2lOpsahWTBO0WQ>W4B#6BvRta;x z)66AZ?u!asD=OQ-)HqdnwpG2%n=fm|U*q>;bX#(N_%Yu%!8 zs2WEx)j}F=rPJUpu+;QPz0|$6NwgqD2Yc)^_gozO>pq=3UOSz8HqQ!w?u9?c>!)*} z?U@w_L(sszsiP;u$}gvua-%9SF;T%yyv(=3Ds{;Y&gha|-Hn+IOA>kyOSsaTNjkfV z<&1MeK#QR+g4iN}L<4KjYF`p>ztuuALGd|mPCSh&p^MX-mUJnp@I2^}$3vy&Eg5D5 zx4Hu8m?d8*X($}ylJ7NE95%rc?23mFR;2!ty24xWAk(rX6zc*3kXvn6v+BKls4@;W z|MYVLqx|{*!54C?x1`sy7b=UP;^sYlw4P>GWY!fA=M3INSSr4AN#0XYjr+qN!-sP& zdBlKvVslS@tt&KWby{OLGAC(VBI&SHHdtxyYxER$-9gE)Fkxv{awuMN_08OWnHan# zraXPQ4JqVKU?~?tvRIo!OzcYX*>( zCJ^*;17$K31o+i?Xt&;YGrXJI(AUcQE~p-_z-`>j2O7;nY?qQc&tP7%Xh=fbYIIV4 z?Pfe5PqM-^*}08p(Z=_YW|}GFzDk-j9Vl@G{3$eL)`cw1`=*OYlRh`1AwaD`{9NC~ zG_T+OHBx+NkX@RR92A&4+69oaf`idTja5sT?-fC-yDt{C+kW6)z6y(|o1EhGWQTYp z*iF@v)!2RW`x>~C3(P&QbZumCR({*629LClxf8^#c5$~|^XnfEJN6taZ#!AglQ&}S zV&xSpDP`?#y zn+q`W)w_2^ybZXHt_I~JOp!A}=-1+JX=!@bw6ir_^}n?>DvcOgo(B|rh?j=f;<#@=hjByhoenY+71g5s+G)J#9Iy%0NvG{w?>|Ggz-pGp zTS12>cQmZ;u)p4$?8v^s(-S=`&|y-n=0V5wCw=be(FyAd3J^9*=$A|2p6q0NPBTsn zkZzN5+ZiTs88m2yiB0f&={AQvPIXEnoddQx(7F)gl5(xS#*22zWB~o*PBIhtf1}+P zGiZaHAWo}b`jiu;O7BYX6pYs@r+C&L_}!E%nO1@ddAsjOKe1ZetJx=}lYQb=apJek zfR+P;b`l4Tm%Qc5yDiK&(k0ogFk*RFhcxk97|2!JhkNYYs9jFuQRjfI$RTWP-evG! zahFS)hVUo#p&OV#!Uk-jb`NS@8RDY9L3P=;c?USe6U=~841K#D`vwfd$vN6=r|>U2 zJ~g|bNe<1>l7!{Z(!%Ea3Y_x{2S(cGCIc6!57~KX7WCyjeA%^u>>Ed$cj5LiV8}u> z*QDlJLjC@@2x2O^#MFA4=gWsdlJM3d-AT3&zsi+-#fVtl1~hCRa4t;42wN@|5eW-Y zj!wc!5fZLPl7pUmvsW6u*9tTjVFI=`GXlm0exUEbZ1e&8wGX(c(eJ0sp=5-3FcdEy z6eQj%C9T<@6Y^32Df-=ejWavNldS!mS>ZqB?dIS<`Bh9>V^?|8|Ag_NuhU{?tBtHv zhVOtGC)%%5r}&#a@SACrWLl9cKX{V?iLVlfk0xzg)ItriezqxTO`R5MU#Ib`bHHZ1 zTJ5xb2Nc8E#qUDbAawlip)0k839A;WRaVAIoP%=)GeIZ)4s#n{qC@`=8(98(9W$`d zXS9Lk;dTa=r>ZYwVBx=LZ(zBqvw@}er41~DZI>~yoc(XK!Gt-~UGwYah=HY|y@6$O zr}BEiw>ukH9{67ySibom3@mmj)-j+_(+9md_hHq$8f$M~7&8YG^8C3*kRC)LhjVfK#OBq!b ze%`^TauqYG%-Zxn8C9;jgi&S0rvKkYm8DBNIX|9>WNd`G4^@$n!hNm_DKol(kRmf7 zB`U`9s1`#hm!~0aK~ghwj;^6Y(shJoV9@S;!R}>s#grB(X`BkMUGvX$)^lBrFQ=Qq zz`Tg&T9v$H7P&N!Jysa6p+G9H-NGViSW1Gq7W6_Yt}{lZB)E-^@4c1mUN+tHBJkD4 zGV-$7qiia_NC{vQDNNm)go&0x^?>R@Qt+j8Lk~@^^kYN#$zA%BOD_GSLI={mG<-4! z5vAy)#BTg>xN=K=)FpBc8#x7z8`||I&&=yTespbxKh?3 z`LG-D1RJp~MZ3`zsPUeFnF0MViu&aYDlbGyO2bBtUWQ*u-qT1Yit%Rhp6(lHe~uX? z&Wb0*uaMj>DHQC~Z73UwsQ=xfA=7dGk>vH}t(7DTHc#>;J^Sr+?vX@yU##cB#EJAd4+`C13k4I+ zDfm4N9(d3luE zlGc=E;QR;`AQf5&npU}Ey&m`0nHR%~Mk<2s|LG0noK2K3C%*9sY!)+UNmbj+gW8Ud z?5V5nAc`vgzqP?tdYn>K-#Tol!Sj$tij-a@dhD-0&Boq~yO&xm_%_dAv@F=R7VHcT z16fmduJ4{l&h_tqqB+->e%(rOal=rlt_yOl?G4+S`3J8_il0 z(?5VI&XV57_JD}nz?FPpLeZkNcq35>=YPdS9>F;B*!SLoB;%AYDr{2g?b0$@Bl3up z^&m>^hW5MuWipVv<(iubD)2tg={8X#XzdJ#8tsywUdi&pB)}c98l}{x%mzVPPtzei z$ffYU3%3^Z6tdq(em$ovZ`?Lk9DW8ykxY$&8JKrxo8W7U;TF}#QY@2=qnzHT2IRku zi7mZl@U9%98*hU0x3w{_Ug$eoD*Gc`@|tdBKD*VRWu8B(Otcyd!I>CQTmw}W{S&%_ z8^@ZrO{_cA=t|muoV89##_HU7lshDr;%vAybL=%{1DBSVa1BLkW;VDG5)*UY*YWAw zUE+z%2EO?uFW-wXe^Qel@X z$hS?Jwvv*s-i!=~YU7`vydrDy4{xkri-WOl1rE)InY0s3uH|cLFqn3Xyefm@aeZww zJ$+oV_Q(an*e3Xf_e2~5@BR?xN2TOSTW&HLLVw0K{f$UqUuFfa;k7heKDBp24? ze}m^nUYuBgAOO;p(%orrBb}G#w`AX!<^{s9w(x2lru76ho0V$b%gaNyhT<|CLj8Gh z%UE$$Hip&;NKf=?A-&!u7PFYIi4|kTH?z}V6z~&qBgWR0WaFqXjI&?d;txs}=(#)n z3=Z_!!E6qzsSDm(C_OSiT>1nC`ZC;(w+1s`qb-Bc?X{@F;OUB!44Y_qD1EH-^~e>_ zCZLqXg9%?(c|a>)ir=A-T8G8`b-*x=m%|$IC(>bPQ7ziN?b4UphD#cT@?V7UuJ$7< zGD0ORyr6@L0r+OaKVVzDf^CZvzG_v0@CXew`u^~*TIn_L-Z|wAUjrMW)yiBnKI-HS z3xxq?r-7q!Jsg%jc4;xysd2X-nU~-z#1fyXpTWzn9?N;PmX}~-0+LDKrGhM8 zd_IR4$7I1n%MqjfAf{1}hkkiA;UOw-eGx-q`EAIZSoP?_;mEAZ+>c(XtFiJW6S_}r zsx*0rHdR`@$-JD@T@WX1#`I3buI^JU+H=5O9HPd0cNA<2#R0d2|Mxq@YTkBwmYsj< zn;AUXRKj%@A5JJfZ~CJeYw%&JvAKY18N)wy0czQ+)gnz8ndCcf@|ZEHUH>M>$f>M> zBO}#~jH)g`)z!>EqxpKMj`RJ9E23S)eDk^|#b90Cr~YAQqnoxVh)B5Msn{{2$bd2uT*2^pAO;0zvdK9O0+i>EN{@Iag%_~vi&{tlNppBwS=FfZLrvuDG5q2HQD zK}8ASCXAU1GU*t~6jjk=XFs{vPXhiV(A4<^&EEtwCw2whQFDEaC;tOg=99-CFnDew)GdY;m z?P6zaYd0a@+Y!G=OA7qRm~isHyfMsY94_Udy{-c-x^r@ab`Z) z{BoPh&eLIYm$d+N=Sm!k=e2jg$^_st`k1%^f0}uoM$AL5r7~fFD3jjOQh+`#EUeD& z%3P`y(~>rZK3A=rY6Lbuh5?yOWQ{8$E1t6EE3{1%4kYkOsW(XbbKeJ^O>kghAA*L6 z=cUPIK}5z9tF)LMs{h81+8A`a*hRzNDeUMi13M&+{xDd#7GA8J98@ID?^k{a+u1(5 z3FR{)pV~$Y?^sY0705l5xnE~CDBqu;8>!HSMrBgzMTV?Yt@LB!egfTpq=XQU!hz10 zh-uBxz&kPOP0N%6>YQ7g-U4L(#ph<&oVvhX1QO}aoiloFbj$NC zng@DY7ow-$C_dctXski&|0WCGZkO4x9~Kz~MFi5RQiXzfpD2si;0d6@4-_s)Bm1FegE9uRyzr`>Yr)n7Y9HK|Me{`Ozc1UN- z^*3Nx=?C!d6Yap6&JJI)gsDz?$=dZ&W*43@jJt+Jq#95LccJ0djHF6oLr{Oa8nnO zO#I&wDPgKJ0>h{`Ff-+AB#cg5ZeQX^OdZChZSXDJoDv(9`MLBT` z^4FMPRc#kWzFM{gl2!Kh_i5`D3aPg>ApURP;cnr(dAoVZzWn%fJHX(w&tQ|6qZ8wJ0^ zoYx&sK`I&l5Yq6m} zYJX1n=f14H>HL49>`gz$Gkep|@$KzR%Mv@=o8Eykv&@)R@`13?>5V9(ljd{X6t+6u zCRQogpIsgrA)gGcz3Tp~S#P%dtF>d8^raBUT%x}m)i~6)m!ZPO@&f`9n%^2l$i*iZ z3RvMNLIGh=4<_w+ z7@9}wxspl?3W0e*fBp(m#^4e240?iq{%E3I=`HZJ7F#MiVcYW86OhYq%xY6X$7v!) zEIw0C=usF_1WQT!A^|E=t3~=mdqRWqLn}*R=91EQ$xm%jL98t*RlNO}viP@n=9b5& z1BE|R>=LJ~U|@x0fX4~Q$7miw?#sE-PrIaN%Fzf^a3^o8nLUgb_hdE*&CPt^uo?Ef zG4k*mmAm3e>4o|Pbt`pHDyFJbTyow($b^+37$Wa0%tFvFHYa;LgP50L4eW9=wN}Ax zA-!T22L6^(?s;kA(%^N7!7a%&fc`q_p6F-!KnSabD;aMliF7FiZ8VzQvdavrN8cW9 zIjOe*ZFR*i!!Z?Vs>yj#dcT%U1~4;sh0Auqj*txoHh3-#lOsZ&3sc^&)VyeiUyOx9$gckw z>J@q0nZL8K#hgx^pK;ObvsDi-16GKuKKKqIdq=$~)K%k^NX$TEASxCMk|!1ViYb_u zawX*IAWcZk2Rg!iQ~9(fJIQV(qC?bS`I;HnmV2P*>rXHj&6i(;)slp{A$p=K0K(u> zMkTUY!$8vxEG?tbVvUl~8^@7$X_l+VK1qLF-*Xpq@K4;?Jy^EivwihNAD+e@U?SR$4~?Obq%$0 z=`zBTg5W@mPuwv^HVt#7pI}=g(BmD5>@ANr(hY&!gLieTB$w;K{=yyfy;tkJ-@1&) za07HPC^i>P!9FgH-omA^clH=(<$81pb&D#;tCjdNm#xLcjXL47oiEq+f%^8vMA#>N z0ShAdq#iXQ+a6?yjWUJo0xBffmv;I#brFM z+}8^|M13onwT&Jsr{fZ1jbiS_&i1j~&|W4AIJlt~c^nMmed`EB!<)#|c;x_)btni` zm1$LBX*CH=`RiC~{ZHbeMO@@JUyWGL+y2t3UOMKS1#)O!u055p%?Mmtjc&3^23%t# zOcP&|Yt`G$tZq`QD|RMA(}Y&&#y7N{8#H`!bWA+a9w{Xs#bW6pO6AnwEzdV<0Tla@ zE7_`%nn26UK`rxV*QKo?y3vdUYurCDtoJS%H5DC1pN8pNX=I<2QG_yVX{Oo{2{9nw zmfK4)s||*7;OUll$SrPC-c{N5yAq!BWyiS1Mz?qo2(8>}5o+=<36Ftc_1Kr>O-;R+ zV5CZPm=8+9Y6VI}Or{2xsBsG?u&*nKOFhJ+RnA{SU#3_Hzo?ku7nPzCy{S}#Ml}!~0-Ye+7vz)%XPd{vqWXu$q&5jU2Fae*E zb(-zn>)7^ILFu}`AvH)#{H9^{y35_7;>@g5hM&F2tQZwaAGjoQZcQvYy@a~d#3B=C znWU?(i$YjA9>dTz+Z)^jX|{#w_~(_{mo)pK5sw?skm9~`R=6)KlQl21jtcvBk#a%!p_+#wrhXw{}jz;?mJ*y!IXFr^3rQgX??rV#4i$}G+$9t0? zEy&PK;!DZ)U-*z9&B<8H?ol1eyHr8pXlU0YTxOGzY|xWf3%3hDni`er5MKP~DRfiV zjEN_pBquJ!SvAug#J_u=T!KipfJu0?00yBa(_xRjhm#E=fIKvL3GBHAMhYkc_3laN zyIcN8AyeCwHSweuqN6n;I4FnXO$<-8@B`2dmt&FN;t^mNTkOd~1C-!fkbx(eWu7Y# z0qZ?tGq4<)jbEjsiy-Ee)aIqQm82fn@R!5X=-HH^ce}e1+|oVFPV`IkTojIkZ!5!t zaa6hgWUH3P@D_btV}*q8NbU1{h;4I;r-Kiw1eNL%j|6uUIP~e@Hr!e+Cg|`HYstst z!Zzk~Vk+jRn!*u$?X$^g09du!e7yEMBa~G%x6axne3CO$Z3+NuL)Vz%I%6rH#0+Ki zSbp@gT1r^1^mT(~Q}^e`lAb-6$QVukN(|hhFuNLMn;S1N37xVPE`2Sro<6>o81JoG z0-i~#R^tmPA;eRwVENCL=HF=8u0su~m`^gI6Ovj*FHFK0+Nug(3t2EnX#&gZS+CSS zb14s=OSq6VYu4nyK0~akRx|UJ{Kf_&mfWexk-m1xXc&;6R>pFE%;%O6Q#zUeEHWFE zhxe*l9v%Pp+U_`ae5`?~-XsH}i+<*Q#4lkc%-_c0P*mfntZ`|h(yWxb*r;UVsCa=4 z>)Ci$;3({RT0hxfURAfyXl)|qxc6x^HvaU2Jv50rK_IQaDjP!dh#jXB-rbawWc1Qm zQno9WCXBMgS1NzqqqV=V4}y0<^S>TPN$(@g0tt zJbiibRB>H#sRebWz^`%Q$>Ku`P&o8Acz=Pr>6iemqtxRTYbbGTJ%d>mB&$ny?xZx; zWUg#dz8HyX?mRmk_he#@SZ=jN+zPMs9gP!j6Sw+~as(GqQdgKNhXo>pq;#=&;tWl&R7(_Dm^?4~$V&7XjN_23N+A$C9 z!rv4U(HR6cLG#F<2;inphi$cPF-=Q7wNv?L8>87nXn~Y4-*1JlvCY@gh4VKMRbrlZ zpd}f0b=h6ZP+Qz$P(hb9mOtS&J5;e>%kPA~M>1(Q$fQ;^7(E zr8Tp{O(smLR5%-BSz(8&brHRKYxQ=z#KSJ}9A@BZVL@p_+BMcYi4i=5JPW$TlN2<^ zz~@fpVEbP9G?Xk>q1KBTw&HjVnaGK$;RtpP2Q6x**_q1EE)0#?*U62|EpF3u!JTDi z8{Vs|aZ_LkerSuF6c%A*_` z{ayHw&y<>k8i^ZydH;^qJ#l1cET;8cOyu=1pUDuU3`p|iayr-As$8f-bN~9~w4x3u z`|C6}6Ux);%QAQ#qH3Yr0wUlAQCyIUR{2yT1DtnodE3agEs(_?{xb@;bDjk*Tji`j zajS>eFqS=VI8Hq6JFrJrjJ1ka6Mi^`58Wz zvX5f=$eT%7I57ifkGvf814cJs^aAE(_$T(}#jjQn3uiXn)dt+%UqC?GL%vAbf$nd# z4_ghxbz3I~uQYZ}%CyIVv$4LcnIPiZlEY+&CsuMYsi(`*n$do7BjUo-4Vh;j73^ar ze#pya!Ut1|LHed&y7IDrDLxA3#)SsePs zk??XeNVO}dZRG}12aYLse8uR-k2t>|C+bg}>S6-ARPDU@el6Vc7V)r+YZb#KHZlh; zH{u_5@F4eka*@ffCNqXiPFKBQW>J-X>K#%h0++5e&YxjNYsc®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

Fx*SiH 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�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�iY^C*8mCtx&qJ&KoMq-H`Et~2|ha!d+j%E|9 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

wTX_g$l;>BfTDq}CyEyk?cCgg0ncI)8l|J+M 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

JY_Q;_C?k%M3#E8HqxtiTGK4ISTpi~ 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ⅆ7+F;7wY|YF(9>K9cm*dhrZF(+E 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 MA4TJ)lK`wU04UGlUH||9 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.go b/components/serverless/internal/controllers/kubernetes/configmap_service.go deleted file mode 100644 index 25a03b368..000000000 --- a/components/serverless/internal/controllers/kubernetes/configmap_service.go +++ /dev/null @@ -1,98 +0,0 @@ -package kubernetes - -import ( - "context" - "fmt" - - "go.uber.org/zap" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/kyma-project/serverless/components/serverless/internal/resource" -) - -type ConfigMapService interface { - IsBase(configMap *corev1.ConfigMap) bool - ListBase(ctx context.Context) ([]corev1.ConfigMap, error) - UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ConfigMap) error -} - -var _ ConfigMapService = &configMapService{} - -type configMapService struct { - client resource.Client - config Config -} - -func NewConfigMapService(client resource.Client, config Config) ConfigMapService { - return &configMapService{ - client: client, - config: config, - } -} - -func (r *configMapService) ListBase(ctx context.Context) ([]corev1.ConfigMap, error) { - configMaps := corev1.ConfigMapList{} - if err := r.client.ListByLabel(ctx, r.config.BaseNamespace, map[string]string{ConfigLabel: RuntimeLabelValue}, &configMaps); err != nil { - return nil, err - } - - return configMaps.Items, nil -} - -func (r *configMapService) IsBase(configMap *corev1.ConfigMap) bool { - return configMap.Namespace == r.config.BaseNamespace && configMap.Labels[ConfigLabel] == RuntimeLabelValue -} - -func (r *configMapService) UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ConfigMap) error { - logger.Debug(fmt.Sprintf("Updating ConfigMap '%s/%s'", namespace, baseInstance.GetName())) - instance := &corev1.ConfigMap{} - if err := r.client.Get(ctx, client.ObjectKey{Namespace: namespace, Name: baseInstance.GetName()}, instance); err != nil { - if errors.IsNotFound(err) { - return r.createConfigMap(ctx, logger, namespace, baseInstance) - } - logger.Error(err, fmt.Sprintf("Gathering existing ConfigMap '%s/%s' failed", namespace, baseInstance.GetName())) - return err - } - - return r.updateConfigMap(ctx, logger, instance, baseInstance) -} - -func (r *configMapService) createConfigMap(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ConfigMap) error { - configMap := corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: baseInstance.GetName(), - Namespace: namespace, - Labels: baseInstance.Labels, - Annotations: baseInstance.Annotations, - }, - Data: baseInstance.Data, - BinaryData: baseInstance.BinaryData, - } - - logger.Debug(fmt.Sprintf("Creating ConfigMap '%s/%s'", configMap.GetNamespace(), configMap.GetName())) - if err := r.client.Create(ctx, &configMap); err != nil { - logger.Error(err, fmt.Sprintf("Creating ConfigMap '%s/%s' failed", configMap.GetNamespace(), configMap.GetName())) - return err - } - - return nil -} - -func (r *configMapService) updateConfigMap(ctx context.Context, logger *zap.SugaredLogger, instance, baseInstance *corev1.ConfigMap) error { - copy := instance.DeepCopy() - copy.Annotations = baseInstance.GetAnnotations() - copy.Labels = baseInstance.GetLabels() - copy.Data = baseInstance.Data - copy.BinaryData = baseInstance.BinaryData - - if err := r.client.Update(ctx, copy); err != nil { - logger.Error(err, fmt.Sprintf("Updating ConfigMap '%s/%s' failed", copy.GetNamespace(), copy.GetName())) - return err - } - - return nil -} 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.go b/components/serverless/internal/controllers/kubernetes/namespace_controller.go deleted file mode 100644 index 2a53941f3..000000000 --- a/components/serverless/internal/controllers/kubernetes/namespace_controller.go +++ /dev/null @@ -1,116 +0,0 @@ -package kubernetes - -import ( - "context" - "fmt" - - "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 NamespaceReconciler struct { - Log *zap.SugaredLogger - client client.Client - config Config - configMapSvc ConfigMapService - secretSvc SecretService - serviceAccountSvc ServiceAccountService -} - -func NewNamespace(client client.Client, log *zap.SugaredLogger, config Config, - configMapSvc ConfigMapService, secretSvc SecretService, serviceAccountSvc ServiceAccountService) *NamespaceReconciler { - return &NamespaceReconciler{ - client: client, - Log: log, - config: config, - configMapSvc: configMapSvc, - secretSvc: secretSvc, - serviceAccountSvc: serviceAccountSvc, - } -} - -func (r *NamespaceReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - Named("namespace-controller"). - For(&corev1.Namespace{}). - WithEventFilter(r.predicate()). - Complete(r) -} - -func (r *NamespaceReconciler) predicate() predicate.Predicate { - return predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { - namespace, ok := e.Object.(*corev1.Namespace) - if !ok { - return false - } - return !isExcludedNamespace(namespace.Name, r.config.BaseNamespace, r.config.ExcludedNamespaces) - }, - GenericFunc: func(genericEvent event.GenericEvent) bool { - return false - }, - UpdateFunc: func(e event.UpdateEvent) bool { - return false - }, - DeleteFunc: func(e event.DeleteEvent) bool { - return false - }, - } -} - -// Reconcile reads that state of the cluster for a Namespace object and updates other resources based on it -// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch -// +kubebuilder:rbac:groups="",resources=configmaps;secrets;serviceaccounts,verbs=get;list;watch;create;update;patch;delete - -func (r *NamespaceReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) { - instance := &corev1.Namespace{} - if err := r.client.Get(ctx, request.NamespacedName, instance); err != nil { - return ctrl.Result{}, client.IgnoreNotFound(err) - } - - logger := r.Log.With("name", instance.GetName()) - - logger.Debug(fmt.Sprintf("Updating ConfigMaps in namespace '%s'", instance.GetName())) - configMaps, err := r.configMapSvc.ListBase(ctx) - if err != nil { - logger.Error(err, "Listing base ConfigMaps failed") - return ctrl.Result{}, err - } - for _, configMap := range configMaps { - c := configMap - if err := r.configMapSvc.UpdateNamespace(ctx, logger, instance.GetName(), &c); err != nil { - return ctrl.Result{}, err - } - } - - logger.Debug(fmt.Sprintf("Updating Secret in namespace '%s'", instance.GetName())) - secret, err := r.secretSvc.GetBase(ctx) - if err != nil { - logger.Error(err, "Listing base Secrets failed") - return ctrl.Result{}, err - } - - if err := r.secretSvc.UpdateNamespace(ctx, logger, instance.GetName(), secret); err != nil { - return ctrl.Result{}, err - } - - logger.Debug(fmt.Sprintf("Updating ServiceAccounts in namespace '%s'", instance.GetName())) - serviceAccounts, err := r.serviceAccountSvc.ListBase(ctx) - if err != nil { - logger.Error(err, "Listing base ServiceAccounts failed") - return ctrl.Result{}, err - } - for _, serviceAccount := range serviceAccounts { - sa := serviceAccount - if err := r.serviceAccountSvc.UpdateNamespace(ctx, logger, instance.GetName(), &sa); err != nil { - return ctrl.Result{}, err - } - } - - return ctrl.Result{}, nil -} 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.go b/components/serverless/internal/controllers/kubernetes/secret_controller.go deleted file mode 100644 index 006eddfd5..000000000 --- a/components/serverless/internal/controllers/kubernetes/secret_controller.go +++ /dev/null @@ -1,103 +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 SecretReconciler struct { - Log *zap.SugaredLogger - client client.Client - config Config - svc SecretService -} - -func NewSecret(client client.Client, log *zap.SugaredLogger, config Config, secretSvc SecretService) *SecretReconciler { - return &SecretReconciler{ - client: client, - Log: log, - config: config, - svc: secretSvc, - } -} - -func (r *SecretReconciler) SetupWithManager(mgr ctrl.Manager) error { - return ctrl.NewControllerManagedBy(mgr). - Named("secret-controller"). - For(&corev1.Secret{}). - WithEventFilter(r.predicate()). - Complete(r) -} - -func (r *SecretReconciler) predicate() predicate.Predicate { - return predicate.Funcs{ - CreateFunc: func(e event.CreateEvent) bool { - runtime, ok := e.Object.(*corev1.Secret) - if !ok { - return false - } - return r.svc.IsBase(runtime) - }, - UpdateFunc: func(e event.UpdateEvent) bool { - runtime, ok := e.ObjectNew.(*corev1.Secret) - if !ok { - return false - } - return r.svc.IsBase(runtime) - }, - GenericFunc: func(e event.GenericEvent) bool { - runtime, ok := e.Object.(*corev1.Secret) - if !ok { - return false - } - return r.svc.IsBase(runtime) - }, - DeleteFunc: func(e event.DeleteEvent) bool { - runtime, ok := e.Object.(*corev1.Secret) - if !ok { - return false - } - return r.svc.IsBase(runtime) - }, - } -} - -// Reconcile reads that state of the cluster for a Secret object and makes changes based -// +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups="",resources=namespaces,verbs=get;list;watch - -func (r *SecretReconciler) Reconcile(ctx context.Context, request ctrl.Request) (ctrl.Result, error) { - instance := &corev1.Secret{} - 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 - } - - if err := r.svc.HandleFinalizer(ctx, logger, instance, namespaces); err != nil { - return ctrl.Result{}, err - } - if !instance.ObjectMeta.DeletionTimestamp.IsZero() { - return ctrl.Result{}, nil - } - - 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.SecretRequeueDuration}, nil -} 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.go b/components/serverless/internal/controllers/kubernetes/secret_service.go deleted file mode 100644 index 60fce07f2..000000000 --- a/components/serverless/internal/controllers/kubernetes/secret_service.go +++ /dev/null @@ -1,173 +0,0 @@ -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" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/kyma-project/serverless/components/serverless/internal/resource" -) - -const cfgSecretFinalizerName = "serverless.kyma-project.io/finalizer-registry-config" - -type SecretService interface { - IsBase(secret *corev1.Secret) bool - GetBase(ctx context.Context) (*corev1.Secret, error) - UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.Secret) error - HandleFinalizer(ctx context.Context, logger *zap.SugaredLogger, secret *corev1.Secret, namespaces []string) error -} - -var _ SecretService = &secretService{} - -type secretService struct { - client resource.Client - config Config -} - -func NewSecretService(client resource.Client, config Config) SecretService { - return &secretService{ - client: client, - config: config, - } -} - -func (r *secretService) GetBase(ctx context.Context) (*corev1.Secret, error) { - secret := &corev1.Secret{} - err := r.client.Get(ctx, types.NamespacedName{ - Namespace: r.config.BaseNamespace, - Name: r.config.BaseDefaultSecretName, - }, secret) - - return secret, err -} - -func (r *secretService) IsBase(secret *corev1.Secret) bool { - return secret.Namespace == r.config.BaseNamespace && - secret.Name == r.config.BaseDefaultSecretName && - secret.Labels[ConfigLabel] == CredentialsLabelValue -} - -func (r *secretService) UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.Secret) error { - logger.Debug(fmt.Sprintf("Updating Secret '%s/%s'", namespace, baseInstance.GetName())) - instance := &corev1.Secret{} - if err := r.client.Get(ctx, client.ObjectKey{Namespace: namespace, Name: baseInstance.GetName()}, instance); err != nil { - if errors.IsNotFound(err) { - return r.createSecret(ctx, logger, namespace, baseInstance) - } - logger.Error(err, fmt.Sprintf("Gathering existing Secret '%s/%s' failed", namespace, baseInstance.GetName())) - return err - } - if instance.Labels[v1alpha2.FunctionManagedByLabel] == v1alpha2.FunctionResourceLabelUserValue { - return nil - } - return r.updateSecret(ctx, logger, instance, baseInstance) -} - -func (r *secretService) HandleFinalizer(ctx context.Context, logger *zap.SugaredLogger, instance *corev1.Secret, namespaces []string) error { - if instance.ObjectMeta.DeletionTimestamp.IsZero() { - if containsString(instance.ObjectMeta.Finalizers, cfgSecretFinalizerName) { - return nil - } - instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, cfgSecretFinalizerName) - if err := r.client.Update(context.Background(), instance); err != nil { - return err - } - } else { - if !containsString(instance.ObjectMeta.Finalizers, cfgSecretFinalizerName) { - return nil - } - for _, namespace := range namespaces { - logger.Debug(fmt.Sprintf("Deleting Secret '%s/%s'", namespace, instance.Name)) - if err := r.deleteSecret(ctx, logger, namespace, instance.Name); err != nil { - return err - } - } - instance.ObjectMeta.Finalizers = removeString(instance.ObjectMeta.Finalizers, cfgSecretFinalizerName) - if err := r.client.Update(context.Background(), instance); err != nil { - return err - } - } - return nil -} - -func (r *secretService) createSecret(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.Secret) error { - secret := corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: baseInstance.GetName(), - Namespace: namespace, - Labels: baseInstance.Labels, - Annotations: baseInstance.Annotations, - }, - Data: baseInstance.Data, - StringData: baseInstance.StringData, - Type: baseInstance.Type, - } - - logger.Debug(fmt.Sprintf("Creating Secret '%s/%s'", secret.GetNamespace(), secret.GetName())) - if err := r.client.Create(ctx, &secret); err != nil { - logger.Error(err, fmt.Sprintf("Creating Secret '%s/%s' failed", secret.GetNamespace(), secret.GetName())) - return err - } - - return nil -} - -func (r *secretService) updateSecret(ctx context.Context, logger *zap.SugaredLogger, instance, baseInstance *corev1.Secret) error { - copy := instance.DeepCopy() - copy.Annotations = baseInstance.GetAnnotations() - copy.Labels = baseInstance.GetLabels() - copy.Data = baseInstance.Data - copy.StringData = baseInstance.StringData - copy.Type = baseInstance.Type - - if err := r.client.Update(ctx, copy); err != nil { - logger.Error(err, fmt.Sprintf("Updating Secret '%s/%s' failed", copy.GetNamespace(), copy.GetName())) - return err - } - - return nil -} - -func (r *secretService) deleteSecret(ctx context.Context, logger *zap.SugaredLogger, namespace, baseInstanceName string) error { - instance := &corev1.Secret{} - 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 { - return nil - } - if err := r.client.Delete(ctx, instance); err != nil { - logger.Error(err, fmt.Sprintf("Deleting Secret '%s/%s' failed", namespace, baseInstanceName)) - return err - } - - return nil -} - -// Helper functions to check and remove string from a slice of strings. -func containsString(slice []string, s string) bool { - for _, item := range slice { - if item == s { - return true - } - } - return false -} - -func removeString(slice []string, s string) (result []string) { - for _, item := range slice { - if item == s { - continue - } - result = append(result, item) - } - return -} 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.go b/components/serverless/internal/controllers/kubernetes/serviceaccount_service.go deleted file mode 100644 index 5bf12183d..000000000 --- a/components/serverless/internal/controllers/kubernetes/serviceaccount_service.go +++ /dev/null @@ -1,130 +0,0 @@ -package kubernetes - -import ( - "context" - "fmt" - "strings" - - "go.uber.org/zap" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - "github.com/kyma-project/serverless/components/serverless/internal/resource" -) - -type ServiceAccountService interface { - IsBase(serviceAccount *corev1.ServiceAccount) bool - ListBase(ctx context.Context) ([]corev1.ServiceAccount, error) - UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ServiceAccount) error -} - -type serviceAccountService struct { - client resource.Client - config Config -} - -func NewServiceAccountService(client resource.Client, config Config) ServiceAccountService { - return &serviceAccountService{ - client: client, - config: config, - } -} - -func (r *serviceAccountService) ListBase(ctx context.Context) ([]corev1.ServiceAccount, error) { - serviceAccounts := &corev1.ServiceAccountList{} - if err := r.client.ListByLabel(ctx, r.config.BaseNamespace, map[string]string{ConfigLabel: ServiceAccountLabelValue}, serviceAccounts); err != nil { - return nil, err - } - - return serviceAccounts.Items, nil -} - -func (r *serviceAccountService) IsBase(serviceAccount *corev1.ServiceAccount) bool { - return serviceAccount.Namespace == r.config.BaseNamespace && serviceAccount.Labels[ConfigLabel] == ServiceAccountLabelValue -} - -func (r *serviceAccountService) UpdateNamespace(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ServiceAccount) error { - logger.Debug(fmt.Sprintf("Updating ServiceAccount '%s/%s'", namespace, baseInstance.GetName())) - serviceAccount := &corev1.ServiceAccount{} - if err := r.client.Get(ctx, client.ObjectKey{Namespace: namespace, Name: baseInstance.GetName()}, serviceAccount); err != nil { - if errors.IsNotFound(err) { - return r.createServiceAccount(ctx, logger, namespace, baseInstance) - } - logger.Error(err, fmt.Sprintf("Gathering existing ServiceAccount '%s/%s' failed", namespace, baseInstance.GetName())) - return err - } - - return r.updateServiceAccount(ctx, logger, serviceAccount, baseInstance) -} - -func (r *serviceAccountService) createServiceAccount(ctx context.Context, logger *zap.SugaredLogger, namespace string, baseInstance *corev1.ServiceAccount) error { - secrets := r.shiftSecretTokens(baseInstance) - serviceAccount := corev1.ServiceAccount{ - ObjectMeta: metav1.ObjectMeta{ - Name: baseInstance.GetName(), - Namespace: namespace, - Labels: baseInstance.Labels, - Annotations: baseInstance.Annotations, - }, - Secrets: secrets, - ImagePullSecrets: baseInstance.ImagePullSecrets, - AutomountServiceAccountToken: baseInstance.AutomountServiceAccountToken, - } - - logger.Debug(fmt.Sprintf("Creating ServiceAccount '%s/%s'", serviceAccount.GetNamespace(), serviceAccount.GetName())) - if err := r.client.Create(ctx, &serviceAccount); err != nil { - logger.Error(err, fmt.Sprintf("Creating ServiceAccount '%s/%s'", serviceAccount.GetNamespace(), serviceAccount.GetName())) - return err - } - - return nil -} - -func (r *serviceAccountService) updateServiceAccount(ctx context.Context, logger *zap.SugaredLogger, instance, baseInstance *corev1.ServiceAccount) error { - tokens := r.extractSecretTokens(instance) - secrets := r.shiftSecretTokens(baseInstance) - secrets = append(secrets, tokens...) - - copy := instance.DeepCopy() - copy.Annotations = baseInstance.GetAnnotations() - copy.Labels = baseInstance.GetLabels() - copy.ImagePullSecrets = baseInstance.ImagePullSecrets - copy.AutomountServiceAccountToken = baseInstance.AutomountServiceAccountToken - copy.Secrets = secrets - - if err := r.client.Update(ctx, copy); err != nil { - logger.Error(err, fmt.Sprintf("Updating ServiceAccount '%s/%s' failed", copy.GetNamespace(), copy.GetName())) - return err - } - - return nil -} - -func (*serviceAccountService) shiftSecretTokens(baseInstance *corev1.ServiceAccount) []corev1.ObjectReference { - prefix := fmt.Sprintf("%s-token", baseInstance.Name) - - secrets := make([]corev1.ObjectReference, 0) - for _, secret := range baseInstance.Secrets { - if !strings.HasPrefix(secret.Name, prefix) { - secrets = append(secrets, secret) - } - } - - return secrets -} - -func (*serviceAccountService) extractSecretTokens(serviceAccount *corev1.ServiceAccount) []corev1.ObjectReference { - prefix := fmt.Sprintf("%s-token", serviceAccount.Name) - - secrets := make([]corev1.ObjectReference, 0) - for _, secret := range serviceAccount.Secrets { - if strings.HasPrefix(secret.Name, prefix) { - secrets = append(secrets, secret) - } - } - - return secrets -} 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.go b/components/serverless/internal/controllers/kubernetes/shared.go deleted file mode 100644 index ac1f0faad..000000000 --- a/components/serverless/internal/controllers/kubernetes/shared.go +++ /dev/null @@ -1,57 +0,0 @@ -package kubernetes - -import ( - "context" - "time" - - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" -) - -const ( - ConfigLabel = "serverless.kyma-project.io/config" - RuntimeLabel = "serverless.kyma-project.io/runtime" - RbacLabel = "serverless.kyma-project.io/rbac" - CredentialsLabelValue = "credentials" - ServiceAccountLabelValue = "service-account" - RuntimeLabelValue = "runtime" -) - -type Config struct { - BaseNamespace string `envconfig:"default=kyma-system"` - BaseDefaultSecretName string `envconfig:"default=serverless-registry-config-default"` - ExcludedNamespaces []string `envconfig:"default=kyma-system"` - ConfigMapRequeueDuration time.Duration `envconfig:"default=1m"` - SecretRequeueDuration time.Duration `envconfig:"default=1m"` - ServiceAccountRequeueDuration time.Duration `envconfig:"default=1m"` -} - -func getNamespaces(ctx context.Context, client client.Client, base string, excluded []string) ([]string, error) { - var namespaces corev1.NamespaceList - if err := client.List(ctx, &namespaces); err != nil { - return nil, err - } - - names := make([]string, 0) - for _, namespace := range namespaces.Items { - if !isExcludedNamespace(namespace.GetName(), base, excluded) && namespace.Status.Phase != corev1.NamespaceTerminating { - names = append(names, namespace.GetName()) - } - } - - return names, nil -} - -func isExcludedNamespace(name, base string, excluded []string) bool { - if name == base { - return true - } - - for _, namespace := range excluded { - if name == namespace { - return true - } - } - - return false -} 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----- -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 ------END OPENSSH PRIVATE KEY-----` - - testSSHPrivateKeyPassphrase = `-----BEGIN OPENSSH PRIVATE KEY----- -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 -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 6a1c43b8335f27b5b0be94d8bbb76b5db4674e67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 81920 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 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.go b/components/serverless/internal/resource/resource.go deleted file mode 100644 index afb88f91d..000000000 --- a/components/serverless/internal/resource/resource.go +++ /dev/null @@ -1,107 +0,0 @@ -package resource - -import ( - "context" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - apilabels "k8s.io/apimachinery/pkg/labels" - "k8s.io/apimachinery/pkg/runtime" - ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" -) - -//go:generate mockery --name=Client --output=automock --outpkg=automock --case=underscore -type Client interface { - Create(ctx context.Context, object Object) error - CreateWithReference(ctx context.Context, parent Object, object Object) error - Update(ctx context.Context, object Object) error - Get(ctx context.Context, key ctrlclient.ObjectKey, object Object) error - ListByLabel(ctx context.Context, namespace string, labels map[string]string, object ctrlclient.ObjectList) error - DeleteAllBySelector(ctx context.Context, resourceType Object, namespace string, selector apilabels.Selector) error - Delete(ctx context.Context, resourceType Object) error - Status() ctrlclient.StatusWriter -} - -//go:generate mockery --name=K8sClient --output=automock --outpkg=automock --case=underscore -type K8sClient interface { - Create(context.Context, ctrlclient.Object, ...ctrlclient.CreateOption) error - Update(ctx context.Context, obj ctrlclient.Object, opts ...ctrlclient.UpdateOption) error - Get(ctx context.Context, key ctrlclient.ObjectKey, obj ctrlclient.Object, opts ...ctrlclient.GetOption) error - List(context.Context, ctrlclient.ObjectList, ...ctrlclient.ListOption) error - DeleteAllOf(context.Context, ctrlclient.Object, ...ctrlclient.DeleteAllOfOption) error - Status() ctrlclient.StatusWriter - Delete(ctx context.Context, obj ctrlclient.Object, opts ...ctrlclient.DeleteOption) error -} - -type Object interface { - runtime.Object - metav1.Object -} - -var _ Client = &client{} - -type client struct { - k8sClient K8sClient - schema *runtime.Scheme -} - -func (c *client) Delete(ctx context.Context, obj Object) error { - propagationPolicy := metav1.DeletePropagationBackground - return c.k8sClient.Delete(ctx, obj, &ctrlclient.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }) -} - -func New(k8sClient K8sClient, schema *runtime.Scheme) Client { - return &client{ - k8sClient: k8sClient, - schema: schema, - } -} - -func (c *client) Create(ctx context.Context, object Object) error { - return c.CreateWithReference(ctx, nil, object) -} - -func (c *client) CreateWithReference(ctx context.Context, parent, object Object) error { - if parent != nil { - if err := controllerutil.SetControllerReference(parent, object, c.schema); err != nil { - return err - } - } - - return c.k8sClient.Create(ctx, object) -} - -func (c *client) Update(ctx context.Context, object Object) error { - return c.k8sClient.Update(ctx, object) -} - -func (c *client) Get(ctx context.Context, key ctrlclient.ObjectKey, object Object) error { - return c.k8sClient.Get(ctx, key, object) -} - -func (c *client) ListByLabel(ctx context.Context, namespace string, labels map[string]string, list ctrlclient.ObjectList) error { - return c.k8sClient.List(ctx, list, &ctrlclient.ListOptions{ - LabelSelector: apilabels.SelectorFromSet(labels), - Namespace: namespace, - }) -} - -func (c *client) DeleteAllBySelector(ctx context.Context, resourceType Object, namespace string, selector apilabels.Selector) error { - propagationPolicy := metav1.DeletePropagationBackground - - return c.k8sClient.DeleteAllOf(ctx, resourceType, &ctrlclient.DeleteAllOfOptions{ - ListOptions: ctrlclient.ListOptions{ - LabelSelector: selector, - Namespace: namespace, - }, - DeleteOptions: ctrlclient.DeleteOptions{ - PropagationPolicy: &propagationPolicy, - }, - }) -} - -func (c *client) Status() ctrlclient.StatusWriter { - return c.k8sClient.Status() -} 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 -}