diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index a3aab7a..0000000 --- a/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file -# Ignore build and test binaries. -bin/ diff --git a/.github/workflows/release-binaries.yaml b/.github/workflows/release-binaries.yaml deleted file mode 100644 index 6433ac8..0000000 --- a/.github/workflows/release-binaries.yaml +++ /dev/null @@ -1,45 +0,0 @@ -name: Compile into binaries - -on: - release: - types: [created] - - workflow_dispatch: - inputs: - release: - description: 'Release tag where to create the binaries (as SemVer vX.X.X)' - required: true - default: v0.1.0 - -permissions: - contents: write - packages: write - -jobs: - releases-matrix: - name: Release Go Binary - runs-on: ubuntu-latest - strategy: - matrix: - # build and publish in parallel: - # linux/386, linux/amd64, linux/arm64, windows/386, windows/amd64, darwin/amd64, darwin/arm64 - goos: [linux, windows, darwin] - goarch: ["386", amd64, arm64] - exclude: - - goarch: "386" - goos: darwin - - goarch: arm64 - goos: windows - steps: - - uses: actions/checkout@v3 - - uses: wangyoucao577/go-release-action@v1.31 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - goos: ${{ matrix.goos }} - goarch: ${{ matrix.goarch }} - goversion: "https://dl.google.com/go/go1.21.6.linux-amd64.tar.gz" - project_path: "./cmd/" - binary_name: "notifik" - release_tag: ${{ inputs.release }} - overwrite: true - extra_files: LICENSE README.md diff --git a/.github/workflows/release-charts.yaml b/.github/workflows/release-charts.yaml deleted file mode 100644 index 93b9094..0000000 --- a/.github/workflows/release-charts.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: Release Charts - -on: - workflow_dispatch: - - # Ref: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release - release: - types: [ published ] - -jobs: - release: - # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions - # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token - permissions: - contents: write - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Configure Git - run: | - git config user.name "$GITHUB_ACTOR" - git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - - - name: Install Helm - uses: azure/setup-helm@v3 - with: - token: "${{ secrets.GITHUB_TOKEN }}" - - - name: Run chart-releaser - uses: helm/chart-releaser-action@v1.5.0 - with: - charts_dir: charts - packages_with_index: true - pages_branch: helm-registry - env: - CR_OWNER: "$GITHUB_REPOSITORY_OWNER" - CR_GIT_REPO: notifik - CR_SKIP_EXISTING: true - CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/release-docker-images.yaml b/.github/workflows/release-docker-images.yaml deleted file mode 100644 index ea176f4..0000000 --- a/.github/workflows/release-docker-images.yaml +++ /dev/null @@ -1,57 +0,0 @@ -name: Build Docker image - -on: - release: - types: [created] - - workflow_dispatch: - inputs: - release: - description: 'Release tag where to create the binaries (as SemVer vX.X.X)' - required: true - default: v0.1.0 - -permissions: - contents: write - packages: write - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: 1.21 - - - name: Set up QEMU - id: qemu - uses: docker/setup-qemu-action@v3 - with: - image: tonistiigi/binfmt:latest - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@v3 - - - name: Docker Login - uses: docker/login-action@v3 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push - run: | - if [ "${{ github.event_name }}" = "release" ]; then - export TAG="${{ github.ref_name }}" - elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - export TAG="${{ inputs.release }}" - fi - - export IMG="ghcr.io/$GITHUB_REPOSITORY:$TAG" - make docker-buildx diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 7a7feec..0000000 --- a/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ - -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib -bin/* -Dockerfile.cross - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Go workspace file -go.work - -# Kubernetes Generated files - skip generated files, except for vendored files -!vendor/**/zz_generated.* - -# editor and IDE paraphernalia -.idea -.vscode -*.swp -*.swo -*~ diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index aed8644..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,40 +0,0 @@ -run: - deadline: 5m - allow-parallel-runners: true - -issues: - # don't skip warning about doc comments - # don't exclude the default set of lint - exclude-use-default: false - # restore some of the defaults - # (fill in the rest as needed) - exclude-rules: - - path: "api/*" - linters: - - lll - - path: "internal/*" - linters: - - dupl - - lll -linters: - disable-all: true - enable: - - dupl - - errcheck - - exportloopref - - goconst - - gocyclo - - gofmt - - goimports - - gosimple - - govet - - ineffassign - - lll - - misspell - - nakedret - - prealloc - - staticcheck - - typecheck - - unconvert - - unparam - - unused diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index fa0ed5d..0000000 --- a/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -# Build the manager binary -FROM golang:1.21 AS builder -ARG TARGETOS -ARG TARGETARCH - -WORKDIR /workspace -# Copy the Go Modules manifests -COPY go.mod go.mod -COPY go.sum go.sum -# cache deps before building and copying source so that we don't need to re-download as much -# and so that source changes don't invalidate our downloaded layer -RUN go mod download - -# Copy the go source -COPY cmd/main.go cmd/main.go -COPY api/ api/ -COPY internal/ internal/ - -# Build -# the GOARCH has not a default value to allow the binary be built according to the host where the command -# was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO -# the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, -# by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go - -# Use distroless as minimal base image to package the manager binary -# Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/static:nonroot -WORKDIR / -COPY --from=builder /workspace/manager . -USER 65532:65532 - -ENTRYPOINT ["/manager"] diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. diff --git a/Makefile b/Makefile deleted file mode 100644 index 39aea44..0000000 --- a/Makefile +++ /dev/null @@ -1,203 +0,0 @@ - -# Image URL to use all building/pushing image targets -IMG ?= controller:latest -# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary. -ENVTEST_K8S_VERSION = 1.29.0 - -# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) -ifeq (,$(shell go env GOBIN)) -GOBIN=$(shell go env GOPATH)/bin -else -GOBIN=$(shell go env GOBIN) -endif - -# CONTAINER_TOOL defines the container tool to be used for building images. -# Be aware that the target commands are only tested with Docker which is -# scaffolded by default. However, you might want to replace it to use other -# tools. (i.e. podman) -CONTAINER_TOOL ?= docker - -# 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 - -.PHONY: all -all: build - -##@ General - -# The help target prints out all targets with their descriptions organized -# beneath their categories. The categories are represented by '##@' and the -# target descriptions by '##'. The awk command is responsible for reading the -# entire set of makefiles included in this invocation, looking for lines of the -# file as xyz: ## something, and then pretty-format the target and help. Then, -# if there's a line with ##@ something, that gets pretty-printed as a category. -# More info on the usage of ANSI control characters for terminal formatting: -# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters -# More info on the awk command: -# http://linuxcommand.org/lc3_adv_awk.php - -.PHONY: help -help: ## Display this help. - @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) - -##@ Development - -.PHONY: manifests -manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects. - $(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases - -.PHONY: generate -generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. - $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." - -.PHONY: fmt -fmt: ## Run go fmt against code. - go fmt ./... - -.PHONY: vet -vet: ## Run go vet against code. - go vet ./... - -.PHONY: test -test: manifests generate fmt vet envtest ## Run tests. - KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out - -# Utilize Kind or modify the e2e tests to load the image locally, enabling compatibility with other vendors. -.PHONY: test-e2e # Run the e2e tests against a Kind k8s instance that is spun up. -test-e2e: - go test ./test/e2e/ -v -ginkgo.v - -.PHONY: lint -lint: golangci-lint ## Run golangci-lint linter & yamllint - $(GOLANGCI_LINT) run - -.PHONY: lint-fix -lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes - $(GOLANGCI_LINT) run --fix - -##@ Build - -.PHONY: build -build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go - -.PHONY: run -run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go - -# If you wish to build the manager image targeting other platforms you can use the --platform flag. -# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it. -# More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -.PHONY: docker-build -docker-build: ## Build docker image with the manager. - $(CONTAINER_TOOL) build -t ${IMG} . - -.PHONY: docker-push -docker-push: ## Push docker image with the manager. - $(CONTAINER_TOOL) push ${IMG} - -# PLATFORMS defines the target platforms for the manager image be built to provide support to multiple -# architectures. (i.e. make docker-buildx IMG=myregistry/mypoperator:0.0.1). To use this option you need to: -# - be able to use docker buildx. More info: https://docs.docker.com/build/buildx/ -# - have enabled BuildKit. More info: https://docs.docker.com/develop/develop-images/build_enhancements/ -# - be able to push the image to your registry (i.e. if you do not set a valid value via IMG=> then the export will fail) -# To adequately provide solutions that are compatible with multiple platforms, you should consider using this option. -PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le -.PHONY: docker-buildx -docker-buildx: ## Build and push docker image for the manager for cross-platform support - # copy existing Dockerfile and insert --platform=${BUILDPLATFORM} into Dockerfile.cross, and preserve the original Dockerfile - sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross - - $(CONTAINER_TOOL) buildx create --name project-v3-builder - $(CONTAINER_TOOL) buildx use project-v3-builder - - $(CONTAINER_TOOL) buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross . - - $(CONTAINER_TOOL) buildx rm project-v3-builder - rm Dockerfile.cross - -.PHONY: build-installer -build-installer: manifests generate kustomize ## Generate a consolidated YAML with CRDs and deployment. - mkdir -p dist - @if [ -d "config/crd" ]; then \ - $(KUSTOMIZE) build config/crd > dist/install.yaml; \ - fi - echo "---" >> dist/install.yaml # Add a document separator before appending - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default >> dist/install.yaml - -##@ Deployment - -ifndef ignore-not-found - ignore-not-found = false -endif - -.PHONY: install -install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config. - $(KUSTOMIZE) build config/crd | $(KUBECTL) apply -f - - -.PHONY: uninstall -uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/crd | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - - -.PHONY: deploy -deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} - $(KUSTOMIZE) build config/default | $(KUBECTL) apply -f - - -.PHONY: undeploy -undeploy: kustomize ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion. - $(KUSTOMIZE) build config/default | $(KUBECTL) delete --ignore-not-found=$(ignore-not-found) -f - - -##@ Dependencies - -## Location to install dependencies to -LOCALBIN ?= $(shell pwd)/bin -$(LOCALBIN): - mkdir -p $(LOCALBIN) - -## Tool Binaries -KUBECTL ?= kubectl -KUSTOMIZE ?= $(LOCALBIN)/kustomize-$(KUSTOMIZE_VERSION) -CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen-$(CONTROLLER_TOOLS_VERSION) -ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION) -GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION) - -## Tool Versions -KUSTOMIZE_VERSION ?= v5.3.0 -CONTROLLER_TOOLS_VERSION ?= v0.14.0 -ENVTEST_VERSION ?= latest -GOLANGCI_LINT_VERSION ?= v1.54.2 - -.PHONY: kustomize -kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary. -$(KUSTOMIZE): $(LOCALBIN) - $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) - -.PHONY: controller-gen -controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary. -$(CONTROLLER_GEN): $(LOCALBIN) - $(call go-install-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen,$(CONTROLLER_TOOLS_VERSION)) - -.PHONY: envtest -envtest: $(ENVTEST) ## Download setup-envtest locally if necessary. -$(ENVTEST): $(LOCALBIN) - $(call go-install-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest,$(ENVTEST_VERSION)) - -.PHONY: golangci-lint -golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary. -$(GOLANGCI_LINT): $(LOCALBIN) - $(call go-install-tool,$(GOLANGCI_LINT),github.com/golangci/golangci-lint/cmd/golangci-lint,${GOLANGCI_LINT_VERSION}) - -# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist -# $1 - target path with name of binary (ideally with version) -# $2 - package url which can be installed -# $3 - specific version of package -define go-install-tool -@[ -f $(1) ] || { \ -set -e; \ -package=$(2)@$(3) ;\ -echo "Downloading $${package}" ;\ -GOBIN=$(LOCALBIN) go install $${package} ;\ -mv "$$(echo "$(1)" | sed "s/-$(3)$$//")" $(1) ;\ -} -endef diff --git a/PROJECT b/PROJECT deleted file mode 100644 index 86498f8..0000000 --- a/PROJECT +++ /dev/null @@ -1,20 +0,0 @@ -# Code generated by tool. DO NOT EDIT. -# This file is used to track the info used to scaffold your project -# and allow the plugins properly work. -# More info: https://book.kubebuilder.io/reference/project-config.html -domain: freepik.com -layout: -- go.kubebuilder.io/v4 -projectName: notifik -repo: freepik.com/notifik -resources: -- api: - crdVersion: v1 - namespaced: true - controller: true - domain: freepik.com - group: notifik - kind: Notification - path: freepik.com/notifik/api/v1alpha1 - version: v1alpha1 -version: "3" diff --git a/README.md b/README.md index bc7e737..af97d0c 100644 --- a/README.md +++ b/README.md @@ -1,364 +1,37 @@ -# Notifik +# Helm Charts -Notifik Logo (Main) logo. +[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +![Release Charts](https://github.com/freepik-company/notifik/workflows/Release%20Charts/badge.svg?branch=main) +[![Releases downloads](https://img.shields.io/github/downloads/freepik-company/notifik/total.svg)](https://github.com/freepik-company/notifik/releases) -![GitHub go.mod Go version (subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/freepik-company/tekton-exporter) -![GitHub](https://img.shields.io/github/license/freepik-company/tekton-exporter) +Notifik Helm Charts -![YouTube Channel Subscribers](https://img.shields.io/youtube/channel/subscribers/UCeSb3yfsPNNVr13YsYNvCAw?label=achetronic&link=http%3A%2F%2Fyoutube.com%2Fachetronic) -![GitHub followers](https://img.shields.io/github/followers/achetronic?label=achetronic&link=http%3A%2F%2Fgithub.com%2Fachetronic) -![X (formerly Twitter) Follow](https://img.shields.io/twitter/follow/achetronic?style=flat&logo=twitter&link=https%3A%2F%2Ftwitter.com%2Fachetronic) +## Usage -Kubernetes operator to watch groups of resources and send notifications if conditions are met (realtime) +[Helm](https://helm.sh) must be installed to use the charts. +Please refer to Helm's [documentation](https://helm.sh/docs/) to get started. -## Motivation - -As you probably know, on Prometheus centered monitoring systems, -the alerts are commonly managed using PrometheusRule resources as they are straightforward -to understand and configure. - -These alerts are triggered based on PromQL queries results, but PromQL is quite limited to -what it can evaluate or compare, and in some scenarios, something more advanced is needed. -For example, PromQL cannot compare labels as they were values. - -What if it is possible to watch a group of resources directly from Kubernetes and -send notifications when something happens? - -What if this 'something' could be templated with all the functionalities you already know from Helm -to craft really complex or powerful conditions? - -This is exactly our proposal - -## Prerequisites - -- kubectl version v1.11.3+. -- Access to a Kubernetes v1.11.3+ cluster. - -### Development purposes - -- go version v1.21.0+ -- docker version 17.03+. -- kubebuilder version v3.14.0 (Only for development) - -## Flags - -Some configuration parameters can be defined by flags that can be passed to the controller. -They are described in the following table: - -| Name | Description | Default Example | | -|:------------------------------|:-------------------------------------------------------------------|:---------------:|---------------------------------------| -| `--config` | The path to configuration file | `notifik.yaml` | `--config "./notifik.yaml"` | -| `--kubeconfig` | Path to kubeconfig | `-` | `--kubeconfig="~/.kube/config"` | -| `--enable-http2` | If set, HTTP/2 will be enabled for the metrics and webhook servers | `false` | `--enable-http2 true` | -| `--metrics-secure` | If set the metrics endpoint is served securely | `false` | `--metrics-secure true` | -| `--leader-elect` | Enable leader election for controller manager | `false` | `--leader-elect true` | -| `--health-probe-bind-address` | The address the probe endpoint binds to | `-` | `--health-probe-bind-address ":8091"` | -| `--metrics-bind-address` | The address the metric endpoint binds to | `:8080` | `--metrics-bind-address ":8090"` | -| `--events-per-second` | Amount of events processed per second (best effort) | `20` | `--events-per-second 50` | - -## Config - -There are some parameters that must be configured through the config file. -For instance, those related to integrations, that is how the messages are sent to your monitoring systems. - -```yaml -integrations: - - # (Optional) Configuration parameters to be able to connect with generic webhooks - webhook: - url: "https://${WEBHOOK_TEST_USERNAME}:${WEBHOOK_TEST_PASSWORD}@webhook.site/98f1c771-bfaf-4c4f-81f6-f11c76684fcf" - headers: - X-Scope-OrgID: your-company - - # (Optional) Configuration parameters to be able to connect with Alertmanager - alertmanager: - url: "https://${TEST_USERNAME}:${TEST_PASSWORD}@webhook.site/d0fd5417-8931-476c-ae6e-c41eda3682af" - headers: - X-Scope-OrgID: freepik-company -``` - -As you can see in the previous example, we expand environment variables passed to the controller for configuration file. -This way, you can manage credentials in your desired way (this applies to everything, headers included) - -## RBAC - -We designed the operator to be able to watch any kind of resource in a Kubernetes cluster, but by design, Kubernetes -permissions are always only additive. - -This means that we had to grant only some resources to be watched by default, such as Secrets and ConfigMaps. -But you can watch other kinds of resources just granting some permissions to the -ServiceAccount of the controller as follows: - -```yaml -# clusterRole-notifik-custom-resources.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: notifik-custom-resources -rules: - - apiGroups: - - "*" - resources: - - "*" - verbs: - - create - - delete - - get - - list - - patch - - update - - watch ---- -# clusterRoleBinding-notifik-custom-resources.yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: notifik-custom-resources -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: notifik-custom-resources -subjects: - - kind: ServiceAccount - name: notifik-controller-manager - namespace: default ---- -# kustomization.yaml -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization - -namespace: notifik - -resources: - - https://github.com/freepik-company/notifik//deploy/?ref=main - - # Add your custom resources - - clusterRole-notifik-custom-resources.yaml - - clusterRoleBinding-notifik-custom-resources.yaml -``` - -## Example - -To watch resources using this operator, you will need to create a CR of kind Notification. -You can find the spec samples for all the versions of the resource in the [examples directory](./config/samples) - -You may prefer to learn directly from an example, so let's explain it watching a ConfigMap: - -```yaml - apiVersion: v1 - kind: ConfigMap - metadata: - name: testing - data: - TEST_VAR: "placeholder" -``` - -Now use a Notification CR to watch ConfigMap looking for changes. When the conditions are met, we want to -send the notification to a webhook: - -```yaml -apiVersion: notifik.freepik.com/v1alpha1 -kind: Notification -metadata: - name: notification-sample-simple -spec: - - # Resource type to be watched - watch: - group: "" - version: v1 - resource: configmaps - - # Optional: It's possible to watch specific resources - # name: testing - # namespace: default - - conditions: - - name: check-configmap-name - # The 'key' field admits vitamin Golang templating (well known from Helm) - # The result of this field will be compared with 'value' for equality - key: | - {{- $source := . -}} - {{- printf "%s" $source.metadata.name -}} - value: testing - - message: - reason: "NameMatchedAlert" - data: | - {{- $source := . -}} - {{- printf "Hi, I'm on fire: %s/%s" $source.metadata.namespace $source.metadata.name -}} -``` - -## Templating engine - -### What you can use - -We recommend keeping the scope of the Notification resources as small as possible. -At the same time, we wanted to craft a powerful engine to do whatever we needed. -So we mixed several gears, from here and there, and got all the power of a wonderful toy. - -At the end of this madness you are reading about, what you will notice is that you can use everything you -already know from [Helm Template](https://helm.sh/docs/chart_template_guide/functions_and_pipelines/) - -### How to use collected data - -When a watched resource triggers an event, we pass the whole manifest to all the conditions (and even to -the alert data). - -This means the manifest (as Go object) is available in the main scope `.`. You can retrieve it as follows: - -This means that the objects can be accessed or stored in variables in the following way: -```yaml -apiVersion: notifik.freepik.com/v1alpha1 -kind: Notification -metadata: - name: notification-sample-simple -spec: - . - . - . - conditions: - - name: check-configmap-name - # The 'key' field admits vitamin Golang templating (well known from Helm) - # The result of this field will be compared with 'value' for equality - key: | - {{- $source := . -}} - {{- printf "%s" $source.metadata.name -}} - value: testing -``` - -> Remember: with a big power comes a big responsibility -> ```gotemplate -> {{- $source := . -}} -> ``` - -### How to debug - -Templating issues are thrown on controller logs. This is done this way as a watcher is intended to watch a group of -resources, so if we create a status condition into the `Notification`, we could end creating potentially hundreds -of conditions: one per object that is being watched - -To debug templates easy, we recommend using [helm-playground](https://helm-playground.com). -You can create a template on the left side, put your manifests in the middle, and the result is shown on the right side. - -[We created an example for you](https://helm-playground.com/#t=N7C0AIBIGcHsFcBOBjApuAXAXnAOgGoCGANvKtLgLaEB2AlgGbkAu4oAvuwFAgSQAOqQZhwAKfojo1mDcAAMu0ZoUTNoAQWYZwAIgBMABj0AWUAYDMoPQHYAKgYCcGAKzmM587j0AOcwC0dLlQaABMNLV1DEzNLG3snV3dPH39A2hpYZWY6WBpoDC5wcEIQkLps3JIABURYfgBGbSVJGgBzQuLS8pyaatr%2BPSbmFvaikrKK3uIaurdwZql24kIAI1RifI7eynJ%2BQjRtAFJocC3CHaPoLlbg1ERCZlhEAFUAJQAZIZHQfmW0AAtYMQQnc5FA4Eg0FRUMoQg9CLhtrt9ugYAgUKhobD4YjzqgAJRsTg8MDgBi1SgATXOxCggmEAB9wI8AFJwGhE9hAA&v=LQhQFsEMDsEsDMCmBnALgLlAAi5ADrAGqIBOysA9tOlgG4CM2WA1rNACY0DCV8sA5gFl8TcIlSR2kCZhw5okMTVQpUbfk3mKUeSAGNENAFYBXGLFQUmUmZqwAVAKIBlewH1CAQQBKNAER4ADb6iAAWFIHspH5AA) - -## How to develop - -> We recommend you to use a development tool like [Kind](https://kind.sigs.k8s.io/) -> or [Minikube](https://minikube.sigs.k8s.io/docs/start/) -> to launch a lightweight Kubernetes on your local machine for development purposes - -For learning purposes, we will suppose you are going to use Kind. -So the first step is to create a Kubernetes cluster on your local machine executing the following command: +Once Helm is set up properly, add the repo as follows: ```console -kind create cluster +helm repo add prosimcorp https://freepik-company.github.io/notifik/ ``` -Once you have launched a safe play place, execute the following command. -It will install the custom resource definitions (CRDs) in the cluster configured -in your ~/.kube/config file and run the Operator locally against the cluster: +You can then run the following command to see the charts. ```console -make install run +helm search repo notifik ``` -> Remember that your `kubectl` is pointing to your Kind cluster. -> However, you should always review the context your kubectl CLI is pointing to - -If you desire to run against your cluster using a custom configuration, run the controller this way -from the root directory of this project: - -```console - go run ./cmd/main.go --config ./your-path-to-notifik/config/samples/config/notifik.yaml -``` - -## How releases are created - -Each release of this operator is done following several steps carefully in order not to break the things for anyone. -Reliability is important to us, so we automated all the process of launching a release. - -For a better understanding of the process, the steps are described in the following recipe: - -1. Test the changes in the code: - - ```console - make test - ``` - - > A release is not done if this stage fails - +## How to contribute -2. Define the package information +For doing it you must: +* Fork the repository +* Make your changes to the code in a specific branch +* Open a PR - ```console - export VERSION="0.0.1" - export IMG="freepik-company/notifik:v$VERSION" - ``` - -3. Generate and push the Docker image (published on Docker Hub). - - ```console - make docker-build docker-push - ``` - -4. Generate the manifests for deployments using Kustomize. - - > NOTE: The makefile target mentioned above generates an 'install.yaml' - > file in the dist directory. This file contains all the resources built - > with Kustomize, which are necessary to install this project without - > its dependencies. - - ```console - make build-installer - ``` - -## How to deploy - -1. Using the installer - - The operator can be installed just running kubectl apply -f to install the project, i.e.: - - ```sh - kubectl apply -f https://raw.githubusercontent.com/freepik-company/notifik//dist/install.yaml - ``` - -2. Using Helm - - > TBD in a future release - - -## How to collaborate - -This project is done on top of [Kubebuilder](https://github.com/kubernetes-sigs/kubebuilder), so read -about that project before collaborating. - -Of course, we are open to external collaborations for this project. -For doing it, you must fork the repository, make your changes to the code and open a PR. -The code will be reviewed and tested (always) - -> We are developers and hate bad code. For that reason, we ask you the highest quality on each line of code to improve -> this project on each iteration. +> The charts will be reviewed and tested (always) ## License -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. - -## Special mention - -This project was done using IDEs from JetBrains. They helped us to develop faster, so we recommend them a lot! 🤓 - -JetBrains Logo (Main) logo. +[Apache 2.0 License](./LICENSE) diff --git a/api/v1alpha1/configuration_types.go b/api/v1alpha1/configuration_types.go deleted file mode 100644 index 35bf763..0000000 --- a/api/v1alpha1/configuration_types.go +++ /dev/null @@ -1,24 +0,0 @@ -package v1alpha1 - -// ConfigurationT TODO -type ConfigurationT struct { - Integrations IntegrationsT `yaml:"integrations"` -} - -// IntegrationsT TODO -type IntegrationsT struct { - Alertmanager AlertmanagerT `yaml:"alertmanager,omitempty"` - Webhook WebhookT `yaml:"webhook,omitempty"` -} - -// AlertmanagerT TODO -type AlertmanagerT struct { - Url string `yaml:"url"` - Headers map[string]string `yaml:"headers,omitempty"` -} - -// WebhookT TODO -type WebhookT struct { - Url string `yaml:"url"` - Headers map[string]string `yaml:"headers,omitempty"` -} diff --git a/api/v1alpha1/groupversion_info.go b/api/v1alpha1/groupversion_info.go deleted file mode 100644 index dc60d74..0000000 --- a/api/v1alpha1/groupversion_info.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2024. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package v1alpha1 contains API Schema definitions for the notifik v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=notifik.freepik.com -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -var ( - // GroupVersion is group version used to register these objects - GroupVersion = schema.GroupVersion{Group: "notifik.freepik.com", Version: "v1alpha1"} - - // 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 -) diff --git a/api/v1alpha1/notification_types.go b/api/v1alpha1/notification_types.go deleted file mode 100644 index 7498eb8..0000000 --- a/api/v1alpha1/notification_types.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2024. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v1alpha1 - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// TODO -type NotificationWatch struct { - Group string `json:"group"` - Version string `json:"version"` - Resource string `json:"resource"` - Namespace string `json:"namespace,omitempty"` - Name string `json:"name,omitempty"` -} - -// TODO -type NotificationCondition struct { - Name string `json:"name"` - Key string `json:"key"` - Value string `json:"value"` -} - -// TODO -type NotificationMessage struct { - Reason string `json:"reason"` - Data string `json:"data"` -} - -// NotificationSpec defines the desired state of Notification -type NotificationSpec struct { - Watch NotificationWatch `json:"watch"` - Conditions []NotificationCondition `json:"conditions"` - Message NotificationMessage `json:"message"` -} - -// NotificationStatus defines the observed state of Notification -type NotificationStatus struct { - - // Conditions represent the latest available observations of an object's state - Conditions []metav1.Condition `json:"conditions"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:resource:scope=Namespaced,categories={notifications} -//+kubebuilder:subresource:status -//+kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" - -// Notification is the Schema for the notifications API -type Notification struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec NotificationSpec `json:"spec,omitempty"` - Status NotificationStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// NotificationList contains a list of Notification -type NotificationList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - Items []Notification `json:"items"` -} - -func init() { - SchemeBuilder.Register(&Notification{}, &NotificationList{}) -} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index de9ee74..0000000 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,251 +0,0 @@ -//go:build !ignore_autogenerated - -/* -Copyright 2024. - -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. -*/ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - "k8s.io/apimachinery/pkg/apis/meta/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 *AlertmanagerT) DeepCopyInto(out *AlertmanagerT) { - *out = *in - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *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 AlertmanagerT. -func (in *AlertmanagerT) DeepCopy() *AlertmanagerT { - if in == nil { - return nil - } - out := new(AlertmanagerT) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ConfigurationT) DeepCopyInto(out *ConfigurationT) { - *out = *in - in.Integrations.DeepCopyInto(&out.Integrations) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationT. -func (in *ConfigurationT) DeepCopy() *ConfigurationT { - if in == nil { - return nil - } - out := new(ConfigurationT) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *IntegrationsT) DeepCopyInto(out *IntegrationsT) { - *out = *in - in.Alertmanager.DeepCopyInto(&out.Alertmanager) - in.Webhook.DeepCopyInto(&out.Webhook) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IntegrationsT. -func (in *IntegrationsT) DeepCopy() *IntegrationsT { - if in == nil { - return nil - } - out := new(IntegrationsT) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Notification) DeepCopyInto(out *Notification) { - *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 Notification. -func (in *Notification) DeepCopy() *Notification { - if in == nil { - return nil - } - out := new(Notification) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Notification) 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 *NotificationCondition) DeepCopyInto(out *NotificationCondition) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationCondition. -func (in *NotificationCondition) DeepCopy() *NotificationCondition { - if in == nil { - return nil - } - out := new(NotificationCondition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationList) DeepCopyInto(out *NotificationList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]Notification, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationList. -func (in *NotificationList) DeepCopy() *NotificationList { - if in == nil { - return nil - } - out := new(NotificationList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *NotificationList) 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 *NotificationMessage) DeepCopyInto(out *NotificationMessage) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationMessage. -func (in *NotificationMessage) DeepCopy() *NotificationMessage { - if in == nil { - return nil - } - out := new(NotificationMessage) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationSpec) DeepCopyInto(out *NotificationSpec) { - *out = *in - out.Watch = in.Watch - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]NotificationCondition, len(*in)) - copy(*out, *in) - } - out.Message = in.Message -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationSpec. -func (in *NotificationSpec) DeepCopy() *NotificationSpec { - if in == nil { - return nil - } - out := new(NotificationSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationStatus) DeepCopyInto(out *NotificationStatus) { - *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]v1.Condition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationStatus. -func (in *NotificationStatus) DeepCopy() *NotificationStatus { - if in == nil { - return nil - } - out := new(NotificationStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *NotificationWatch) DeepCopyInto(out *NotificationWatch) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotificationWatch. -func (in *NotificationWatch) DeepCopy() *NotificationWatch { - if in == nil { - return nil - } - out := new(NotificationWatch) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WebhookT) DeepCopyInto(out *WebhookT) { - *out = *in - if in.Headers != nil { - in, out := &in.Headers, &out.Headers - *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 WebhookT. -func (in *WebhookT) DeepCopy() *WebhookT { - if in == nil { - return nil - } - out := new(WebhookT) - in.DeepCopyInto(out) - return out -} diff --git a/charts/notifik/Chart.yaml b/charts/notifik/Chart.yaml deleted file mode 100644 index 40d692c..0000000 --- a/charts/notifik/Chart.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Notifik -# Ref: https://helm.sh/docs/topics/charts/#the-chartyaml-file -apiVersion: v2 -name: notifik -type: application -description: >- - A Helm chart for Notifik, a Kubernetes operator to watch groups of resources and send - notifications if conditions are met (realtime) -version: 0.1.0 # chart version -appVersion: "0.2.0" # notifik version -kubeVersion: ">=1.22.0-0" # kubernetes version -home: https://github.com/freepik-company/notifik -sources: - - https://github.com/freepik-company/notifik -keywords: - - freepik - - prosimcorp - - notifik - - gitops -maintainers: - - name: Alby Hernández - email: ahernandez@freepik.com - url: https://github.com/freepik-company/notifik - - name: prosimcorp - url: https://github.com/prosimcorp diff --git a/charts/notifik/crds/notifik.freepik.com_notifications.yaml b/charts/notifik/crds/notifik.freepik.com_notifications.yaml deleted file mode 100644 index d852f6e..0000000 --- a/charts/notifik/crds/notifik.freepik.com_notifications.yaml +++ /dev/null @@ -1,179 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.14.0 - name: notifications.notifik.freepik.com -spec: - group: notifik.freepik.com - names: - categories: - - notifications - kind: Notification - listKind: NotificationList - plural: notifications - singular: notification - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Notification is the Schema for the notifications API - 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: NotificationSpec defines the desired state of Notification - properties: - conditions: - items: - description: TODO - properties: - key: - type: string - name: - type: string - value: - type: string - required: - - key - - name - - value - type: object - type: array - message: - description: TODO - properties: - data: - type: string - reason: - type: string - required: - - data - - reason - type: object - watch: - description: TODO - properties: - group: - type: string - name: - type: string - namespace: - type: string - resource: - type: string - version: - type: string - required: - - group - - resource - - version - type: object - required: - - conditions - - message - - watch - type: object - status: - description: NotificationStatus defines the observed state of Notification - properties: - conditions: - description: Conditions represent the latest available observations - of an object's state - items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - conditions - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/charts/notifik/templates/_helpers.tpl b/charts/notifik/templates/_helpers.tpl deleted file mode 100644 index 07df176..0000000 --- a/charts/notifik/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "notifik.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "notifik.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "notifik.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "notifik.labels" -}} -helm.sh/chart: {{ include "notifik.chart" . }} -{{ include "notifik.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "notifik.selectorLabels" -}} -app.kubernetes.io/name: {{ include "notifik.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "notifik.serviceAccountName" -}} -{{- if .Values.controller.serviceAccount.create }} -{{- default (include "notifik.fullname" .) .Values.controller.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.controller.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/charts/notifik/templates/clusterrolebindings/custom.yaml b/charts/notifik/templates/clusterrolebindings/custom.yaml deleted file mode 100644 index d5da3ab..0000000 --- a/charts/notifik/templates/clusterrolebindings/custom.yaml +++ /dev/null @@ -1,22 +0,0 @@ -{{- if (.Values.customClusterRole.create) -}} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "notifik.fullname" . }}-custom - labels: - {{- include "notifik.labels" . | nindent 4 }} - {{- if .Values.customClusterRole.clusterRoleBinding.annotations }} - annotations: - {{- range $key, $value := .Values.customClusterRole.clusterRoleBinding.annotations }} - {{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }} - {{- end }} - {{- end }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "notifik.fullname" . }}-custom -subjects: - - kind: ServiceAccount - name: {{ include "notifik.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- end }} diff --git a/charts/notifik/templates/clusterrolebindings/manager.yaml b/charts/notifik/templates/clusterrolebindings/manager.yaml deleted file mode 100644 index 83e382f..0000000 --- a/charts/notifik/templates/clusterrolebindings/manager.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "notifik.fullname" . }}-manager - labels: - {{- include "notifik.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "notifik.fullname" . }}-manager -subjects: - - kind: ServiceAccount - name: {{ include "notifik.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} diff --git a/charts/notifik/templates/clusterrolebindings/proxy.yaml b/charts/notifik/templates/clusterrolebindings/proxy.yaml deleted file mode 100644 index 3e9adb9..0000000 --- a/charts/notifik/templates/clusterrolebindings/proxy.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- if and (.Values.controller.metrics.enabled) (.Values.controller.metrics.rbacProtectionEnabled) }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "notifik.fullname" . }}-proxy - labels: - {{- include "notifik.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "notifik.fullname" . }}-proxy -subjects: - - kind: ServiceAccount - name: {{ include "notifik.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} -{{- end }} diff --git a/charts/notifik/templates/clusterroles/custom.yaml b/charts/notifik/templates/clusterroles/custom.yaml deleted file mode 100644 index 0b76250..0000000 --- a/charts/notifik/templates/clusterroles/custom.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if (.Values.customClusterRole.create) -}} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "notifik.fullname" . }}-custom - labels: - {{- include "notifik.labels" . | nindent 4 }} - {{- if .Values.customClusterRole.annotations }} - annotations: - {{- range $key, $value := .Values.customClusterRole.annotations }} - {{- printf "%s: %s" $key (tpl $value $ | quote) | nindent 4 }} - {{- end }} - {{- end }} -rules: - {{- if .Values.customClusterRole.rules -}} - {{ toYaml .Values.customClusterRole.rules | nindent 2 -}} - {{- end }} -{{- end }} diff --git a/charts/notifik/templates/clusterroles/manager.yaml b/charts/notifik/templates/clusterroles/manager.yaml deleted file mode 100644 index bf280a0..0000000 --- a/charts/notifik/templates/clusterroles/manager.yaml +++ /dev/null @@ -1,34 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "notifik.fullname" . }}-manager - labels: - {{- include "notifik.labels" . | nindent 4 }} -rules: - - apiGroups: - - notifik.prosimcorp.com - resources: - - notifications - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - apiGroups: - - notifik.prosimcorp.com - resources: - - notifications/finalizers - verbs: - - update - - apiGroups: - - notifik.prosimcorp.com - resources: - - notifications/status - verbs: - - get - - patch - - update - diff --git a/charts/notifik/templates/clusterroles/metrics-reader.yaml b/charts/notifik/templates/clusterroles/metrics-reader.yaml deleted file mode 100644 index 035d162..0000000 --- a/charts/notifik/templates/clusterroles/metrics-reader.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if and (.Values.controller.metrics.enabled) (.Values.controller.metrics.rbacProtectionEnabled) }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "notifik.fullname" . }}-metrics-reader-role - labels: - {{- include "notifik.labels" . | nindent 4 }} -rules: - - nonResourceURLs: - - /metrics - verbs: - - get -{{- end }} diff --git a/charts/notifik/templates/clusterroles/proxy-role.yaml b/charts/notifik/templates/clusterroles/proxy-role.yaml deleted file mode 100644 index 93d0a62..0000000 --- a/charts/notifik/templates/clusterroles/proxy-role.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- if and (.Values.controller.metrics.enabled) (.Values.controller.metrics.rbacProtectionEnabled) }} -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "notifik.fullname" . }}-proxy-role - labels: - {{- include "notifik.labels" . | nindent 4 }} -rules: - - apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create - - apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create -{{- end }} diff --git a/charts/notifik/templates/configmap.yaml b/charts/notifik/templates/configmap.yaml deleted file mode 100644 index 6fddbb1..0000000 --- a/charts/notifik/templates/configmap.yaml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "notifik.fullname" . }}-config - labels: - {{- include "notifik.labels" . | nindent 4 }} -data: - notifik.yaml: | - {{- with .Values.configuration }} - {{ toYaml . | nindent 4 }} - {{- end }} diff --git a/charts/notifik/templates/deployment.yaml b/charts/notifik/templates/deployment.yaml deleted file mode 100644 index c2bb732..0000000 --- a/charts/notifik/templates/deployment.yaml +++ /dev/null @@ -1,136 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "notifik.fullname" . }} - labels: - {{- include "notifik.labels" . | nindent 4 }} -spec: - {{- if not .Values.controller.autoscaling.enabled }} - replicas: {{ .Values.controller.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "notifik.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.controller.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "notifik.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.controller.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "notifik.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.controller.podSecurityContext | nindent 8 }} - containers: - - {{- if and (.Values.controller.metrics.enabled) (.Values.controller.metrics.rbacProtectionEnabled) }} - - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=0 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.15.1 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: metrics - protocol: TCP - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - {{- end }} - - - args: - {{- if and (.Values.controller.metrics.enabled) }} - - --metrics-bind-address=127.0.0.1:8080 - {{- end }} - - --health-probe-bind-address=:8081 - - --leader-elect - - --config=/notifik.yaml - {{- with .Values.controller.extraArgs }} - {{ toYaml . | nindent 10 }} - {{- end }} - - {{- with .Values.controller.env }} - {{ toYaml . | nindent 10 }} - {{- end }} - - {{- with .Values.controller.envFrom }} - {{ toYaml . | nindent 10 }} - {{- end }} - - {{- if and (.Values.controller.metrics.enabled) (not .Values.controller.metrics.rbacProtectionEnabled) }} - ports: - - containerPort: 8080 - name: metrics - protocol: TCP - {{- end }} - command: - - /manager - image: "{{ .Values.controller.image.repository }}:{{ .Values.controller.image.tag | default (printf "v%s" .Chart.AppVersion) }}" - imagePullPolicy: {{ .Values.controller.image.pullPolicy }} - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - name: manager - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - {{- toYaml .Values.controller.resources | nindent 12 }} - securityContext: - {{- toYaml .Values.controller.securityContext | nindent 12 }} - - volumeMounts: - - name: config-volume - mountPath: /notifik.yaml - subPath: notifik.yaml - - {{- with .Values.controller.extraVolumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - - {{- with .Values.controller.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.controller.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.controller.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - - volumes: - - name: config-volume - configMap: - name: {{ include "notifik.fullname" . }}-config - defaultMode: 420 - - {{- with .Values.controller.extraVolumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - diff --git a/charts/notifik/templates/hpa.yaml b/charts/notifik/templates/hpa.yaml deleted file mode 100644 index 2f7bb48..0000000 --- a/charts/notifik/templates/hpa.yaml +++ /dev/null @@ -1,28 +0,0 @@ -{{- if .Values.controller.autoscaling.enabled }} -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "notifik.fullname" . }} - labels: - {{- include "notifik.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "notifik.fullname" . }} - minReplicas: {{ .Values.controller.autoscaling.minReplicas }} - maxReplicas: {{ .Values.controller.autoscaling.maxReplicas }} - metrics: - {{- if .Values.controller.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.controller.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.controller.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.controller.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/charts/notifik/templates/rolebindings/leader-election.yaml b/charts/notifik/templates/rolebindings/leader-election.yaml deleted file mode 100644 index 94e6c14..0000000 --- a/charts/notifik/templates/rolebindings/leader-election.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "notifik.fullname" . }}-leader-election - labels: - {{- include "notifik.labels" . | nindent 4 }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "notifik.fullname" . }}-leader-election -subjects: - - kind: ServiceAccount - name: {{ include "notifik.serviceAccountName" . }} - namespace: {{ .Release.Namespace }} diff --git a/charts/notifik/templates/roles/leader-election.yaml b/charts/notifik/templates/roles/leader-election.yaml deleted file mode 100644 index 2b09073..0000000 --- a/charts/notifik/templates/roles/leader-election.yaml +++ /dev/null @@ -1,39 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "notifik.fullname" . }}-leader-election - labels: - {{- include "notifik.labels" . | nindent 4 }} - namespace: {{ .Release.Namespace }} -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch diff --git a/charts/notifik/templates/service.yaml b/charts/notifik/templates/service.yaml deleted file mode 100644 index d0fdeba..0000000 --- a/charts/notifik/templates/service.yaml +++ /dev/null @@ -1,18 +0,0 @@ -{{- if and (.Values.controller.metrics.enabled) (.Values.controller.metrics.service.enabled) }} -apiVersion: v1 -kind: Service -metadata: - name: {{ include "notifik.fullname" . }}-metrics - labels: - {{- include "notifik.labels" . | nindent 4 }} -spec: - type: {{ .Values.controller.metrics.service.type }} - ports: - - port: {{ .Values.controller.metrics.service.port }} - name: metrics - protocol: TCP - targetPort: metrics - selector: - {{- include "notifik.selectorLabels" . | nindent 4 }} - -{{- end }} diff --git a/charts/notifik/templates/serviceaccount.yaml b/charts/notifik/templates/serviceaccount.yaml deleted file mode 100644 index 69feec9..0000000 --- a/charts/notifik/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.controller.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "notifik.serviceAccountName" . }} - labels: - {{- include "notifik.labels" . | nindent 4 }} - {{- with .Values.controller.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/charts/notifik/values.yaml b/charts/notifik/values.yaml deleted file mode 100644 index 1b5becc..0000000 --- a/charts/notifik/values.yaml +++ /dev/null @@ -1,141 +0,0 @@ -# Default values for notifik. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -nameOverride: "" -fullnameOverride: "" - -# Following custom ClusterRole is a place where to add the type of resources -# allowed to be replicated by Replika. By default, only Secrets and ConfigMaps are allowed, -# but it's possible to add extra resources or even get rid of some of them for improved security -customClusterRole: - # Specifies whether a custom clusterRole should be created - create: true - - # Annotations to add to the clusterRole - annotations: {} - - # A set of rules as documented here : https://kubernetes.io/docs/reference/access-authn-authz/rbac/ - rules: - - apiGroups: [''] - resources: - - configmaps - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch - - clusterRoleBinding: - # Annotations to add to the clusterRoleBinding - annotations: {} - -# Configuration for the controller. -# This is commonly used for passing credentials to integrations -# Remember Notifik supports environment variables expansion, so you can use this pattern ${SOMETHING_SECRET} -# as you were in your terminal -# Ref: https://github.com/freepik-company/notifik?tab=readme-ov-file#config -configuration: "" - -# TODO -controller: - - serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: { } - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "notifik-controller-manager" - - replicaCount: 1 - - image: - repository: ghcr.io/freepik-company/notifik - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - - imagePullSecrets: [] - - # Extra args to pass to the controller. - # Ref: https://github.com/freepik-company/notifik?tab=readme-ov-file#flags - # Example: - # - --events-per-second=100 - extraArgs: [] - - # Define a list of environment variables used inside the controller - # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#use-configmap-defined-environment-variables-in-pod-commands - # - name: SPECIAL_LEVEL_KEY - # valueFrom: - # configMapKeyRef: - # name: special-config - # key: SPECIAL_LEVEL - env: [] - - # Define a list of environment variables coming from a ConfigMap or a Secret - # - configMapRef: - # name: special-config - # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#configure-all-key-value-pairs-in-a-configmap-as-container-environment-variables - envFrom: [] - - # Define a list of extra volumes to mount into the controller - # Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#populate-a-volume-with-data-stored-in-a-configmap - extraVolumes: [] - extraVolumeMounts: [] - - podAnnotations: {} - - podSecurityContext: {} - - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - - resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - - autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - - nodeSelector: {} - - tolerations: [] - - affinity: {} - - metrics: - # Specify whether metrics should be exposed or not - enabled: false - - # Specify whether RBAC proxy should protect metrics - rbacProtectionEnabled: false - - # Specifies configuration for a Service resource to expose the metrics - service: - enabled: false - type: ClusterIP - port: 9090 diff --git a/cmd/main.go b/cmd/main.go deleted file mode 100644 index 1c1254b..0000000 --- a/cmd/main.go +++ /dev/null @@ -1,193 +0,0 @@ -/* -Copyright 2024. - -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 main - -import ( - "crypto/tls" - "flag" - "gopkg.in/yaml.v2" - "os" - // Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.) - // to ensure that exec-entrypoint and run can make use of them. - _ "k8s.io/client-go/plugin/pkg/client/auth" - - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - clientgoscheme "k8s.io/client-go/kubernetes/scheme" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/healthz" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" - "sigs.k8s.io/controller-runtime/pkg/webhook" - - // - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" - "freepik.com/notifik/internal/controller" - "freepik.com/notifik/internal/globals" - "freepik.com/notifik/internal/xyz" - //+kubebuilder:scaffold:imports -) - -var ( - scheme = runtime.NewScheme() - setupLog = ctrl.Log.WithName("setup") -) - -func init() { - utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - - utilruntime.Must(notifikv1alpha1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme -} - -func main() { - var metricsAddr string - var enableLeaderElection bool - var probeAddr string - var secureMetrics bool - var enableHTTP2 bool - var configPath string - var eventsPerSecond int - - flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.StringVar(&probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") - flag.BoolVar(&enableLeaderElection, "leader-elect", false, - "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - flag.BoolVar(&secureMetrics, "metrics-secure", false, - "If set the metrics endpoint is served securely") - flag.BoolVar(&enableHTTP2, "enable-http2", false, - "If set, HTTP/2 will be enabled for the metrics and webhook servers") - flag.StringVar(&configPath, "config", "notifik.yaml", "The path to configuration file.") - flag.IntVar(&eventsPerSecond, "events-per-second", 20, "Amount of events processed per second (best effort)") - - opts := zap.Options{ - Development: true, - } - opts.BindFlags(flag.CommandLine) - flag.Parse() - - ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) - - // Parse the config file - configBytes, err := os.ReadFile(configPath) - if err != nil { - setupLog.Error(err, "unable to find configuration YAML") - os.Exit(1) - } - - configString := os.ExpandEnv(string(configBytes)) - err = yaml.Unmarshal([]byte(configString), &globals.Application.Configuration) - if err != nil { - setupLog.Error(err, "imposible to parse configuration YAML") - os.Exit(1) - } - - // if the enable-http2 flag is false (the default), http/2 should be disabled - // due to its vulnerabilities. More specifically, disabling http/2 will - // prevent from being vulnerable to the HTTP/2 Stream Cancelation and - // Rapid Reset CVEs. For more information see: - // - https://github.com/advisories/GHSA-qppj-fm5r-hxr3 - // - https://github.com/advisories/GHSA-4374-p667-p6c8 - disableHTTP2 := func(c *tls.Config) { - setupLog.Info("disabling http/2") - c.NextProtos = []string{"http/1.1"} - } - - tlsOpts := []func(*tls.Config){} - if !enableHTTP2 { - tlsOpts = append(tlsOpts, disableHTTP2) - } - - webhookServer := webhook.NewServer(webhook.Options{ - TLSOpts: tlsOpts, - }) - - mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{ - Scheme: scheme, - Metrics: metricsserver.Options{ - BindAddress: metricsAddr, - SecureServing: secureMetrics, - TLSOpts: tlsOpts, - }, - WebhookServer: webhookServer, - HealthProbeBindAddress: probeAddr, - LeaderElection: enableLeaderElection, - LeaderElectionID: "0c074d83.freepik.com", - // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily - // when the Manager ends. This requires the binary to immediately end when the - // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly - // speeds up voluntary leader transitions as the new leader don't have to wait - // LeaseDuration time first. - // - // In the default scaffold provided, the program ends immediately after - // the manager stops, so would be fine to enable this option. However, - // if you are doing or is intended to do any operation such as perform cleanups - // after the manager stops then its usage might be unsafe. - // LeaderElectionReleaseOnCancel: true, - }) - if err != nil { - setupLog.Error(err, "unable to start manager") - os.Exit(1) - } - - if err = (&controller.NotificationReconciler{ - Client: mgr.GetClient(), - Scheme: mgr.GetScheme(), - }).SetupWithManager(mgr); err != nil { - setupLog.Error(err, "unable to create controller", "controller", "Notification") - os.Exit(1) - } - - //+kubebuilder:scaffold:builder - - if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up health check") - os.Exit(1) - } - if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil { - setupLog.Error(err, "unable to set up ready check") - os.Exit(1) - } - - // Define the context separated as it will be used by our custom controller too. - // This will synchronize goroutine death when the main controller is killed - //signalCtx := ctrl.SetupSignalHandler() - globals.Application.Context = ctrl.SetupSignalHandler() - globals.Application.KubeRawClient, err = globals.NewKubernetesClient() - if err != nil { - setupLog.Error(err, "unable to set up kubernetes client") - os.Exit(1) - } - - // Init secondary controller to process coming events - workloadController := xyz.WorkloadController{ - Client: mgr.GetClient(), - Options: xyz.WorkloadControllerOptions{ - EventsPerSecond: eventsPerSecond, - }, - } - - setupLog.Info("starting workload controller") - go workloadController.Start(globals.Application.Context) - - setupLog.Info("starting manager") - if err := mgr.Start(globals.Application.Context); err != nil { - setupLog.Error(err, "problem running manager") - os.Exit(1) - } -} diff --git a/config/crd/bases/notifik.freepik.com_notifications.yaml b/config/crd/bases/notifik.freepik.com_notifications.yaml deleted file mode 100644 index d852f6e..0000000 --- a/config/crd/bases/notifik.freepik.com_notifications.yaml +++ /dev/null @@ -1,179 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.14.0 - name: notifications.notifik.freepik.com -spec: - group: notifik.freepik.com - names: - categories: - - notifications - kind: Notification - listKind: NotificationList - plural: notifications - singular: notification - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Notification is the Schema for the notifications API - 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: NotificationSpec defines the desired state of Notification - properties: - conditions: - items: - description: TODO - properties: - key: - type: string - name: - type: string - value: - type: string - required: - - key - - name - - value - type: object - type: array - message: - description: TODO - properties: - data: - type: string - reason: - type: string - required: - - data - - reason - type: object - watch: - description: TODO - properties: - group: - type: string - name: - type: string - namespace: - type: string - resource: - type: string - version: - type: string - required: - - group - - resource - - version - type: object - required: - - conditions - - message - - watch - type: object - status: - description: NotificationStatus defines the observed state of Notification - properties: - conditions: - description: Conditions represent the latest available observations - of an object's state - items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - conditions - type: object - type: object - served: true - storage: true - subresources: - status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml deleted file mode 100644 index 57e8de7..0000000 --- a/config/crd/kustomization.yaml +++ /dev/null @@ -1,23 +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/notifik.freepik.com_notifications.yaml -#+kubebuilder:scaffold:crdkustomizeresource - -patches: -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix. -# patches here are for enabling the conversion webhook for each CRD -#- path: patches/webhook_in_notifications.yaml -#+kubebuilder:scaffold:crdkustomizewebhookpatch - -# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. -# patches here are for enabling the CA injection for each CRD -#- path: patches/cainjection_in_notifications.yaml -#+kubebuilder:scaffold:crdkustomizecainjectionpatch - -# [WEBHOOK] To enable webhook, uncomment the following section -# the following config is for teaching kustomize how to do kustomization for CRDs. - -#configurations: -#- kustomizeconfig.yaml diff --git a/config/crd/kustomizeconfig.yaml b/config/crd/kustomizeconfig.yaml deleted file mode 100644 index ec5c150..0000000 --- a/config/crd/kustomizeconfig.yaml +++ /dev/null @@ -1,19 +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 - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/name - -namespace: -- kind: CustomResourceDefinition - version: v1 - group: apiextensions.k8s.io - path: spec/conversion/webhook/clientConfig/service/namespace - create: false - -varReference: -- path: metadata/annotations diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml deleted file mode 100644 index cf0eda8..0000000 --- a/config/default/kustomization.yaml +++ /dev/null @@ -1,142 +0,0 @@ -# Adds namespace to all resources. -namespace: notifik - -# 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: notifik- - -# Labels to add to all resources and selectors. -#labels: -#- includeSelectors: true -# pairs: -# someName: someValue - -resources: -- ../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 - -patches: -# Protect the /metrics endpoint by putting it behind auth. -# If you want your controller-manager to expose the /metrics -# endpoint w/o any authn/z, please comment the following line. -- path: manager_auth_proxy_patch.yaml - -# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in -# crd/kustomization.yaml -#- path: 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 -#- path: webhookcainjection_patch.yaml - -# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix. -# Uncomment the following replacements to add the cert-manager CA injection annotations -#replacements: -# - source: # Add cert-manager annotation to ValidatingWebhookConfiguration, MutatingWebhookConfiguration and CRDs -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -# fieldPath: .metadata.namespace # namespace of the certificate CR -# targets: -# - select: -# kind: ValidatingWebhookConfiguration -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 0 -# create: true -# - select: -# kind: MutatingWebhookConfiguration -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 0 -# create: true -# - select: -# kind: CustomResourceDefinition -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 0 -# create: true -# - source: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# name: serving-cert # this name should match the one in certificate.yaml -# fieldPath: .metadata.name -# targets: -# - select: -# kind: ValidatingWebhookConfiguration -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 1 -# create: true -# - select: -# kind: MutatingWebhookConfiguration -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 1 -# create: true -# - select: -# kind: CustomResourceDefinition -# fieldPaths: -# - .metadata.annotations.[cert-manager.io/inject-ca-from] -# options: -# delimiter: '/' -# index: 1 -# create: true -# - source: # Add cert-manager annotation to the webhook Service -# kind: Service -# version: v1 -# name: webhook-service -# fieldPath: .metadata.name # namespace of the service -# targets: -# - select: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# fieldPaths: -# - .spec.dnsNames.0 -# - .spec.dnsNames.1 -# options: -# delimiter: '.' -# index: 0 -# create: true -# - source: -# kind: Service -# version: v1 -# name: webhook-service -# fieldPath: .metadata.namespace # namespace of the service -# targets: -# - select: -# kind: Certificate -# group: cert-manager.io -# version: v1 -# fieldPaths: -# - .spec.dnsNames.0 -# - .spec.dnsNames.1 -# options: -# delimiter: '.' -# index: 1 -# create: true diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml deleted file mode 100644 index 70c3437..0000000 --- a/config/default/manager_auth_proxy_patch.yaml +++ /dev/null @@ -1,39 +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 - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.15.0 - args: - - "--secure-listen-address=0.0.0.0:8443" - - "--upstream=http://127.0.0.1:8080/" - - "--logtostderr=true" - - "--v=0" - ports: - - containerPort: 8443 - protocol: TCP - name: https - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - - name: manager - args: - - "--health-probe-bind-address=:8081" - - "--metrics-bind-address=127.0.0.1:8080" - - "--leader-elect" diff --git a/config/default/manager_config_patch.yaml b/config/default/manager_config_patch.yaml deleted file mode 100644 index f6f5891..0000000 --- a/config/default/manager_config_patch.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system -spec: - template: - spec: - containers: - - name: manager diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml deleted file mode 100644 index d4c98d0..0000000 --- a/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: ghcr.io/freepik-company/notifik - newTag: v0.1.0 diff --git a/config/manager/manager.yaml b/config/manager/manager.yaml deleted file mode 100644 index 26e6ef6..0000000 --- a/config/manager/manager.yaml +++ /dev/null @@ -1,102 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: namespace - app.kubernetes.io/instance: system - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: system ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: controller-manager - namespace: system - labels: - control-plane: controller-manager - app.kubernetes.io/name: deployment - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize -spec: - selector: - matchLabels: - control-plane: controller-manager - replicas: 1 - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - control-plane: controller-manager - spec: - # TODO(user): Uncomment the following code to configure the nodeAffinity expression - # according to the platforms which are supported by your solution. - # It is considered best practice to support multiple architectures. You can - # build your manager image using the makefile target docker-buildx. - # affinity: - # nodeAffinity: - # requiredDuringSchedulingIgnoredDuringExecution: - # nodeSelectorTerms: - # - matchExpressions: - # - key: kubernetes.io/arch - # operator: In - # values: - # - amd64 - # - arm64 - # - ppc64le - # - s390x - # - key: kubernetes.io/os - # operator: In - # values: - # - linux - securityContext: - runAsNonRoot: true - # TODO(user): For common cases that do not require escalating privileges - # it is recommended to ensure that all your Pods/Containers are restrictive. - # More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted - # Please uncomment the following code if your project does NOT have to work on old Kubernetes - # versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ). - # seccompProfile: - # type: RuntimeDefault - containers: - - command: - - /manager - args: - - --leader-elect - image: controller:latest - name: manager - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - "ALL" - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - # TODO(user): Configure the resources accordingly based on the project requirements. - # More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 10m - memory: 64Mi - serviceAccountName: controller-manager - terminationGracePeriodSeconds: 10 diff --git a/config/prometheus/kustomization.yaml b/config/prometheus/kustomization.yaml deleted file mode 100644 index ed13716..0000000 --- a/config/prometheus/kustomization.yaml +++ /dev/null @@ -1,2 +0,0 @@ -resources: -- monitor.yaml diff --git a/config/prometheus/monitor.yaml b/config/prometheus/monitor.yaml deleted file mode 100644 index 61edbaa..0000000 --- a/config/prometheus/monitor.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Prometheus Monitor Service (Metrics) -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: servicemonitor - app.kubernetes.io/instance: controller-manager-metrics-monitor - app.kubernetes.io/component: metrics - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: controller-manager-metrics-monitor - namespace: system -spec: - endpoints: - - path: /metrics - port: https - scheme: https - bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token - tlsConfig: - insecureSkipVerify: true - selector: - matchLabels: - control-plane: controller-manager diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml deleted file mode 100644 index ecd756e..0000000 --- a/config/rbac/auth_proxy_client_clusterrole.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: metrics-reader - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: metrics-reader -rules: -- nonResourceURLs: - - "/metrics" - verbs: - - get diff --git a/config/rbac/auth_proxy_role.yaml b/config/rbac/auth_proxy_role.yaml deleted file mode 100644 index 2b84fc7..0000000 --- a/config/rbac/auth_proxy_role.yaml +++ /dev/null @@ -1,24 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: proxy-role - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create diff --git a/config/rbac/auth_proxy_role_binding.yaml b/config/rbac/auth_proxy_role_binding.yaml deleted file mode 100644 index 94974ed..0000000 --- a/config/rbac/auth_proxy_role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/instance: proxy-rolebinding - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: proxy-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/rbac/auth_proxy_service.yaml b/config/rbac/auth_proxy_service.yaml deleted file mode 100644 index 32dd513..0000000 --- a/config/rbac/auth_proxy_service.yaml +++ /dev/null @@ -1,21 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - labels: - control-plane: controller-manager - app.kubernetes.io/name: service - app.kubernetes.io/instance: controller-manager-metrics-service - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: controller-manager-metrics-service - namespace: system -spec: - ports: - - name: https - port: 8443 - protocol: TCP - targetPort: https - selector: - control-plane: controller-manager diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml deleted file mode 100644 index 731832a..0000000 --- a/config/rbac/kustomization.yaml +++ /dev/null @@ -1,18 +0,0 @@ -resources: -# All RBAC will be applied under this service account in -# the deployment namespace. You may comment out this resource -# if your manager will use a service account that exists at -# runtime. Be sure to update RoleBinding and ClusterRoleBinding -# subjects if changing service account names. -- service_account.yaml -- role.yaml -- role_binding.yaml -- leader_election_role.yaml -- leader_election_role_binding.yaml -# Comment the following 4 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 -- auth_proxy_client_clusterrole.yaml diff --git a/config/rbac/leader_election_role.yaml b/config/rbac/leader_election_role.yaml deleted file mode 100644 index 0b3f3e3..0000000 --- a/config/rbac/leader_election_role.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# permissions to do leader election. -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - app.kubernetes.io/name: role - app.kubernetes.io/instance: leader-election-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: leader-election-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch diff --git a/config/rbac/leader_election_role_binding.yaml b/config/rbac/leader_election_role_binding.yaml deleted file mode 100644 index 90291e7..0000000 --- a/config/rbac/leader_election_role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/name: rolebinding - app.kubernetes.io/instance: leader-election-rolebinding - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: leader-election-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: leader-election-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/rbac/notification_editor_role.yaml b/config/rbac/notification_editor_role.yaml deleted file mode 100644 index 0f651db..0000000 --- a/config/rbac/notification_editor_role.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# permissions for end users to edit notifications. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: notification-editor-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: notification-editor-role -rules: -- apiGroups: - - notifik.freepik.com - resources: - - notifications - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications/status - verbs: - - get diff --git a/config/rbac/notification_viewer_role.yaml b/config/rbac/notification_viewer_role.yaml deleted file mode 100644 index 87db3e3..0000000 --- a/config/rbac/notification_viewer_role.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# permissions for end users to view notifications. -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/name: clusterrole - app.kubernetes.io/instance: notification-viewer-role - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: notification-viewer-role -rules: -- apiGroups: - - notifik.freepik.com - resources: - - notifications - verbs: - - get - - list - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications/status - verbs: - - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml deleted file mode 100644 index 2a8f51a..0000000 --- a/config/rbac/role.yaml +++ /dev/null @@ -1,45 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: manager-role -rules: -- apiGroups: - - "" - resources: - - configmaps - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications/finalizers - verbs: - - update -- apiGroups: - - notifik.freepik.com - resources: - - notifications/status - verbs: - - get - - patch - - update diff --git a/config/rbac/role_binding.yaml b/config/rbac/role_binding.yaml deleted file mode 100644 index 2e02d19..0000000 --- a/config/rbac/role_binding.yaml +++ /dev/null @@ -1,19 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/instance: manager-rolebinding - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: manager-role -subjects: -- kind: ServiceAccount - name: controller-manager - namespace: system diff --git a/config/rbac/service_account.yaml b/config/rbac/service_account.yaml deleted file mode 100644 index b0d6f74..0000000 --- a/config/rbac/service_account.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/name: serviceaccount - app.kubernetes.io/instance: controller-manager-sa - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - name: controller-manager - namespace: system diff --git a/config/samples/config/notifik.yaml b/config/samples/config/notifik.yaml deleted file mode 100644 index 2cea03a..0000000 --- a/config/samples/config/notifik.yaml +++ /dev/null @@ -1,12 +0,0 @@ -integrations: - # (Optional) Configuration parameters to be able to connect with generic webhooks - webhook: - url: "https://${WEBHOOK_TEST_USERNAME}:${WEBHOOK_TEST_PASSWORD}@webhook.site/98f1c771-bfaf-4c4f-81f6-f11c76684fcf" - headers: - X-Scope-OrgID: your-company - - # (Optional) Configuration parameters to be able to connect with Alertmanager - alertmanager: - url: "https://${TEST_USERNAME}:${TEST_PASSWORD}@webhook.site/d0fd5417-8931-476c-ae6e-c41eda3682af" - headers: - X-Scope-OrgID: freepik-company diff --git a/config/samples/configmap-2.yaml b/config/samples/configmap-2.yaml deleted file mode 100644 index eaa1dc3..0000000 --- a/config/samples/configmap-2.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: testing-2 -data: - TEST_VAR: "placeholder" diff --git a/config/samples/configmap-3.yaml b/config/samples/configmap-3.yaml deleted file mode 100644 index 41d0df9..0000000 --- a/config/samples/configmap-3.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: testing-3 -data: - TEST_VAR: "placeholder" diff --git a/config/samples/configmap-4.yaml b/config/samples/configmap-4.yaml deleted file mode 100644 index b42b020..0000000 --- a/config/samples/configmap-4.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: testing-4 -data: - TEST_VAR: "placeholder" diff --git a/config/samples/configmap.yaml b/config/samples/configmap.yaml deleted file mode 100644 index 9ba78d3..0000000 --- a/config/samples/configmap.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: testing -data: - TEST_VAR: "placeholder" diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml deleted file mode 100644 index 6decb7f..0000000 --- a/config/samples/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -## Append samples of your project ## -resources: - - configmap.yaml - - configmap-2.yaml - - configmap-3.yaml - - configmap-4.yaml - - # - - notification/alertmanager/notifik_v1alpha1_notification_yaml.yaml - - #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/notification/alertmanager/notifik_v1alpha1_notification_json.yaml b/config/samples/notification/alertmanager/notifik_v1alpha1_notification_json.yaml deleted file mode 100644 index fa4121e..0000000 --- a/config/samples/notification/alertmanager/notifik_v1alpha1_notification_json.yaml +++ /dev/null @@ -1,50 +0,0 @@ -apiVersion: notifik.freepik.com/v1alpha1 -kind: Notification -metadata: - labels: - app.kubernetes.io/name: notification - app.kubernetes.io/instance: notification-sample-alertmanager-json - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: notifik - name: notification-sample-alertmanager-json -spec: - # Resource to be watched - watch: - group: "" - version: v1 - resource: configmaps - - # (Optional) It's possible to watch specific resources - # name: testing - # namespace: default - - conditions: - - name: check-configmap-name - # The 'key' field admits vitamin Golang templating (well known from Helm) - # The result of this field will be compared with 'value' for equality - key: | - {{- $source := . -}} - {{- printf "%s" $source.metadata.name -}} - value: testing - - message: - reason: "PipelineRunTimeout" - data: | - {{- $source := . -}} - {{- $now := (now | date "2006-01-02T15:04:05Z07:00") -}} - {{- $alertStructure := (printf ` - { - "startsAt": "%s", - "annotations": { - "additionalProp1": "string", - "additionalProp2": "string", - "additionalProp3": "string" - }, - "labels": { - "namespace": "%s", - "name": "%s", - }, - "generatorURL": "string" - }` $now $source.metadata.namespace $source.metadata.name) -}} - {{- toJson $alertStructure -}} diff --git a/config/samples/notification/alertmanager/notifik_v1alpha1_notification_yaml.yaml b/config/samples/notification/alertmanager/notifik_v1alpha1_notification_yaml.yaml deleted file mode 100644 index c2b14e0..0000000 --- a/config/samples/notification/alertmanager/notifik_v1alpha1_notification_yaml.yaml +++ /dev/null @@ -1,46 +0,0 @@ -apiVersion: notifik.freepik.com/v1alpha1 -kind: Notification -metadata: - labels: - app.kubernetes.io/name: notification - app.kubernetes.io/instance: notification-sample-alertmanager-yaml - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: notifik - name: notification-sample-alertmanager-yaml -spec: - # Resource to be watched - watch: - group: "" - version: v1 - resource: configmaps - - # (Optional) It's possible to watch specific resources - # name: testing - # namespace: default - - conditions: - - name: check-configmap-name - # The 'key' field admits vitamin Golang templating (well known from Helm) - # The result of this field will be compared with 'value' for equality - key: | - {{- $source := . -}} - {{- printf "%s" $source.metadata.name -}} - value: testing - - # TODO: Fix last line, we need it broken for testing purposes - message: - reason: "PipelineRunTimeout" - data: | - {{- $source := . -}} - {{- $now := (now | date "2006-01-02T15:04:05Z07:00") -}} - {{- $alertStructure := (printf ` - startsAt: "%s" - annotations: - additionalProp1: string - additionalProp2: string - labels: - namespace: %s - name: %s - generatorURL: string-placeholder` $now $source.metadata.namespace $source.metadata.name) -}} - {{- printf # fromYaml $alertStructure | toJson -}} diff --git a/config/samples/notification/webhook/notifik_v1alpha1_notification.yaml b/config/samples/notification/webhook/notifik_v1alpha1_notification.yaml deleted file mode 100644 index 1d5dae5..0000000 --- a/config/samples/notification/webhook/notifik_v1alpha1_notification.yaml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: notifik.freepik.com/v1alpha1 -kind: Notification -metadata: - labels: - app.kubernetes.io/name: notification - app.kubernetes.io/instance: notification-sample-simple - app.kubernetes.io/part-of: notifik - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/created-by: notifik - name: notification-sample-simple -spec: - # Resource to be watched - watch: - group: "" - version: v1 - resource: configmaps - - # (Optional) It's possible to watch specific resources - # name: testing - # namespace: default - - - conditions: - - name: check-configmap-name - # The 'key' field admits vitamin Golang templating (well known from Helm) - # The result of this field will be compared with 'value' for equality - key: | - {{- $source := . -}} - {{- printf "%s" $source.metadata.name -}} - value: testing - - message: - reason: "PipelineRunTimeout" - data: | - {{- $source := . -}} - {{- printf "Hi, I'm on fire: %s/%s" $source.metadata.namespace $source.metadata.name -}} diff --git a/dist/install.yaml b/dist/install.yaml deleted file mode 100644 index bcd384b..0000000 --- a/dist/install.yaml +++ /dev/null @@ -1,702 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.14.0 - name: notifications.notifik.freepik.com -spec: - group: notifik.freepik.com - names: - categories: - - notifications - kind: Notification - listKind: NotificationList - plural: notifications - singular: notification - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Notification is the Schema for the notifications API - 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: NotificationSpec defines the desired state of Notification - properties: - conditions: - items: - description: TODO - properties: - key: - type: string - name: - type: string - value: - type: string - required: - - key - - name - - value - type: object - type: array - message: - description: TODO - properties: - data: - type: string - reason: - type: string - required: - - data - - reason - type: object - synchronization: - description: SynchronizationSpec defines the behavior of synchronization - properties: - time: - type: string - required: - - time - type: object - watch: - description: TODO - properties: - group: - type: string - name: - type: string - namespace: - type: string - resource: - type: string - version: - type: string - required: - - group - - resource - - version - type: object - required: - - conditions - - message - - synchronization - - watch - type: object - status: - description: NotificationStatus defines the observed state of Notification - properties: - conditions: - description: Conditions represent the latest available observations - of an object's state - items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - conditions - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: Namespace -metadata: - labels: - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: system - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: namespace - app.kubernetes.io/part-of: notifik - control-plane: controller-manager - name: notifik ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.14.0 - name: notifications.notifik.freepik.com -spec: - group: notifik.freepik.com - names: - categories: - - notifications - kind: Notification - listKind: NotificationList - plural: notifications - singular: notification - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .metadata.creationTimestamp - name: Age - type: date - name: v1alpha1 - schema: - openAPIV3Schema: - description: Notification is the Schema for the notifications API - 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: NotificationSpec defines the desired state of Notification - properties: - conditions: - items: - description: TODO - properties: - key: - type: string - name: - type: string - value: - type: string - required: - - key - - name - - value - type: object - type: array - message: - description: TODO - properties: - data: - type: string - reason: - type: string - required: - - data - - reason - type: object - synchronization: - description: SynchronizationSpec defines the behavior of synchronization - properties: - time: - type: string - required: - - time - type: object - watch: - description: TODO - properties: - group: - type: string - name: - type: string - namespace: - type: string - resource: - type: string - version: - type: string - required: - - group - - resource - - version - type: object - required: - - conditions - - message - - synchronization - - watch - type: object - status: - description: NotificationStatus defines the observed state of Notification - properties: - conditions: - description: Conditions represent the latest available observations - of an object's state - items: - description: "Condition contains details for one aspect of the current - state of this API Resource.\n---\nThis struct is intended for - direct use as an array at the field path .status.conditions. For - example,\n\n\n\ttype FooStatus struct{\n\t // Represents the - observations of a foo's current state.\n\t // Known .status.conditions.type - are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // - +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t - \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" - patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t - \ // other fields\n\t}" - properties: - lastTransitionTime: - description: |- - lastTransitionTime is the last time the condition transitioned from one status to another. - This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: |- - message is a human readable message indicating details about the transition. - This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: |- - observedGeneration represents the .metadata.generation that the condition was set based upon. - For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date - with respect to the current state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: |- - reason contains a programmatic identifier indicating the reason for the condition's last transition. - Producers of specific condition types may define expected values and meanings for this field, - and whether the values are considered a guaranteed API. - The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: |- - type of condition in CamelCase or in foo.example.com/CamelCase. - --- - Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be - useful (see .node.status.conditions), the ability to deconflict is important. - The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - required: - - conditions - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: controller-manager-sa - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: serviceaccount - app.kubernetes.io/part-of: notifik - name: notifik-controller-manager - namespace: notifik ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: leader-election-role - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: role - app.kubernetes.io/part-of: notifik - name: notifik-leader-election-role - namespace: notifik -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: notifik-manager-role -rules: -- apiGroups: - - "" - resources: - - configmaps - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - notifik.freepik.com - resources: - - notifications/finalizers - verbs: - - update -- apiGroups: - - notifik.freepik.com - resources: - - notifications/status - verbs: - - get - - patch - - update ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: metrics-reader - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrole - app.kubernetes.io/part-of: notifik - name: notifik-metrics-reader -rules: -- nonResourceURLs: - - /metrics - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: proxy-role - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrole - app.kubernetes.io/part-of: notifik - name: notifik-proxy-role -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: leader-election-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: rolebinding - app.kubernetes.io/part-of: notifik - name: notifik-leader-election-rolebinding - namespace: notifik -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: notifik-leader-election-role -subjects: -- kind: ServiceAccount - name: notifik-controller-manager - namespace: notifik ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/component: rbac - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: manager-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/part-of: notifik - name: notifik-manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: notifik-manager-role -subjects: -- kind: ServiceAccount - name: notifik-controller-manager - namespace: notifik ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: proxy-rolebinding - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: clusterrolebinding - app.kubernetes.io/part-of: notifik - name: notifik-proxy-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: notifik-proxy-role -subjects: -- kind: ServiceAccount - name: notifik-controller-manager - namespace: notifik ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app.kubernetes.io/component: kube-rbac-proxy - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: controller-manager-metrics-service - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: service - app.kubernetes.io/part-of: notifik - control-plane: controller-manager - name: notifik-controller-manager-metrics-service - namespace: notifik -spec: - ports: - - name: https - port: 8443 - protocol: TCP - targetPort: https - selector: - control-plane: controller-manager ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app.kubernetes.io/component: manager - app.kubernetes.io/created-by: notifik - app.kubernetes.io/instance: controller-manager - app.kubernetes.io/managed-by: kustomize - app.kubernetes.io/name: deployment - app.kubernetes.io/part-of: notifik - control-plane: controller-manager - name: notifik-controller-manager - namespace: notifik -spec: - replicas: 1 - selector: - matchLabels: - control-plane: controller-manager - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - labels: - control-plane: controller-manager - spec: - containers: - - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=0 - image: gcr.io/kubebuilder/kube-rbac-proxy:v0.15.0 - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - protocol: TCP - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 5m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - - args: - - --health-probe-bind-address=:8081 - - --metrics-bind-address=127.0.0.1:8080 - - --leader-elect - command: - - /manager - image: ghcr.io/freepik-company/notifik:v0.1.0 - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - name: manager - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - limits: - cpu: 500m - memory: 128Mi - requests: - cpu: 10m - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - securityContext: - runAsNonRoot: true - serviceAccountName: notifik-controller-manager - terminationGracePeriodSeconds: 10 diff --git a/docs/img/logo.png b/docs/img/logo.png deleted file mode 100644 index fc3831a..0000000 Binary files a/docs/img/logo.png and /dev/null differ diff --git a/docs/img/logo.svg b/docs/img/logo.svg deleted file mode 100644 index 5475ffd..0000000 --- a/docs/img/logo.svg +++ /dev/null @@ -1,87 +0,0 @@ - - - - diff --git a/go.mod b/go.mod deleted file mode 100644 index 6ad17d3..0000000 --- a/go.mod +++ /dev/null @@ -1,81 +0,0 @@ -module freepik.com/notifik - -go 1.21 - -require ( - github.com/BurntSushi/toml v1.3.2 - github.com/Masterminds/sprig v2.22.0+incompatible - github.com/onsi/ginkgo/v2 v2.14.0 - github.com/onsi/gomega v1.30.0 - gopkg.in/yaml.v2 v2.4.0 - k8s.io/apimachinery v0.29.0 - k8s.io/client-go v0.29.0 - sigs.k8s.io/controller-runtime v0.17.0 - sigs.k8s.io/yaml v1.4.0 -) - -require ( - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver v1.5.0 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/evanphx/json-patch/v5 v5.8.0 // indirect - github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.19.6 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect - github.com/google/uuid v1.3.0 // indirect - github.com/huandu/xstrings v1.4.0 // indirect - github.com/imdario/mergo v0.3.6 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/prometheus/client_golang v1.18.0 // indirect - github.com/prometheus/client_model v0.5.0 // indirect - github.com/prometheus/common v0.45.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.16.0 // indirect - golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.12.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.16.1 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.29.0 // indirect - k8s.io/apiextensions-apiserver v0.29.0 // indirect - k8s.io/component-base v0.29.0 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect - sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect -) diff --git a/go.sum b/go.sum deleted file mode 100644 index 2c9c681..0000000 --- a/go.sum +++ /dev/null @@ -1,221 +0,0 @@ -github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= -github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= -github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= -github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= -github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= -github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.8.0 h1:lRj6N9Nci7MvzrXuX6HFzU8XjmhPiXPlsKEy1u0KQro= -github.com/evanphx/json-patch/v5 v5.8.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= -github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= -github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= -github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= -github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= -github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= -github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= -github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= -golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4= -golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.29.0 h1:NiCdQMY1QOp1H8lfRyeEf8eOwV6+0xA6XEE44ohDX2A= -k8s.io/api v0.29.0/go.mod h1:sdVmXoz2Bo/cb77Pxi71IPTSErEW32xa4aXwKH7gfBA= -k8s.io/apiextensions-apiserver v0.29.0 h1:0VuspFG7Hj+SxyF/Z/2T0uFbI5gb5LRgEyUVE3Q4lV0= -k8s.io/apiextensions-apiserver v0.29.0/go.mod h1:TKmpy3bTS0mr9pylH0nOt/QzQRrW7/h7yLdRForMZwc= -k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o= -k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis= -k8s.io/client-go v0.29.0 h1:KmlDtFcrdUzOYrBhXHgKw5ycWzc3ryPX5mQe0SkG3y8= -k8s.io/client-go v0.29.0/go.mod h1:yLkXH4HKMAywcrD82KMSmfYg2DlE8mepPR4JGSo5n38= -k8s.io/component-base v0.29.0 h1:T7rjd5wvLnPBV1vC4zWd/iWRbV8Mdxs+nGaoaFzGw3s= -k8s.io/component-base v0.29.0/go.mod h1:sADonFTQ9Zc9yFLghpDpmNXEdHyQmFIGbiuZbqAXQ1M= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= -k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.17.0 h1:fjJQf8Ukya+VjogLO6/bNX9HE6Y2xpsO5+fyS26ur/s= -sigs.k8s.io/controller-runtime v0.17.0/go.mod h1:+MngTvIQQQhfXtwfdGw/UOQ/aIaqsYywfCINOtwMO/s= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= -sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= -sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= -sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt deleted file mode 100644 index ff72ff2..0000000 --- a/hack/boilerplate.go.txt +++ /dev/null @@ -1,15 +0,0 @@ -/* -Copyright 2024. - -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. -*/ \ No newline at end of file diff --git a/internal/controller/notification_controller.go b/internal/controller/notification_controller.go deleted file mode 100644 index b3d8967..0000000 --- a/internal/controller/notification_controller.go +++ /dev/null @@ -1,161 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - "fmt" - "time" - - // - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/watch" - ctrl "sigs.k8s.io/controller-runtime" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" - "sigs.k8s.io/controller-runtime/pkg/log" - - // - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" -) - -const ( - defaultSyncTimeForExitWithError = 10 * time.Second - notificationFinalizer = "notifik.freepik.com/finalizer" - - scheduleSynchronization = "Schedule synchronization in: %s" - - notificationNotFoundError = "Notification resource not found. Ignoring since object must be deleted." - notificationRetrievalError = "Error getting the notification from the cluster" - notificationFinalizersUpdateError = "Failed to update finalizer of notification: %s" - notificationConditionUpdateError = "Failed to update the condition on notification: %s" - notificationSyncTimeRetrievalError = "Can not get synchronization time from the notification: %s" - notificationReconcileError = "Can not reconcile Notification: %s" -) - -// NotificationReconciler reconciles a Notification object -type NotificationReconciler struct { - client.Client - Scheme *runtime.Scheme -} - -//+kubebuilder:rbac:groups=notifik.freepik.com,resources=notifications,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=notifik.freepik.com,resources=notifications/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=notifik.freepik.com,resources=notifications/finalizers,verbs=update -//+kubebuilder:rbac:groups="",resources=secrets;configmaps,verbs=get;list;watch;create;update;patch;delete - -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.17.0/pkg/reconcile -func (r *NotificationReconciler) Reconcile(ctx context.Context, req ctrl.Request) (result ctrl.Result, err error) { - logger := log.FromContext(ctx) - _ = logger - - // 1. Get the content of the notification - notificationManifest := ¬ifikv1alpha1.Notification{} - err = r.Get(ctx, req.NamespacedName, notificationManifest) - - // 2. Check the existence inside the cluster - if err != nil { - - // 2.1 It does NOT exist: manage removal - if err = client.IgnoreNotFound(err); err == nil { - logger.Info(notificationNotFoundError) - return result, err - } - - // 2.2 Failed to get the resource, requeue the request - logger.Info(notificationRetrievalError) - return result, err - } - - // 3. Check if the notification instance is marked to be deleted: indicated by the deletion timestamp being set - if !notificationManifest.DeletionTimestamp.IsZero() { - if controllerutil.ContainsFinalizer(notificationManifest, notificationFinalizer) { - // Delete Notification from WatcherPool - err = r.ReconcileNotification(ctx, watch.Deleted, notificationManifest) - if err != nil { - logger.Info(fmt.Sprintf(notificationReconcileError, notificationManifest.Name)) - return result, err - } - - // Remove the finalizers on notification CR - controllerutil.RemoveFinalizer(notificationManifest, notificationFinalizer) - err = r.Update(ctx, notificationManifest) - if err != nil { - logger.Info(fmt.Sprintf(notificationFinalizersUpdateError, req.Name)) - } - } - result = ctrl.Result{} - err = nil - return result, err - } - - // 4. Add finalizer to the notification CR - if !controllerutil.ContainsFinalizer(notificationManifest, notificationFinalizer) { - controllerutil.AddFinalizer(notificationManifest, notificationFinalizer) - err = r.Update(ctx, notificationManifest) - if err != nil { - return result, err - } - } - - // 5. Update the status before the requeue - defer func() { - err = r.Status().Update(ctx, notificationManifest) - if err != nil { - logger.Info(fmt.Sprintf(notificationConditionUpdateError, req.Name)) - } - }() - - // 6. Schedule periodical request - //RequeueTime, err := r.GetSynchronizationTime(notificationManifest) - //if err != nil { - // logger.Info(fmt.Sprintf(notificationSyncTimeRetrievalError, notificationManifest.Name)) - // return result, err - //} - //result = ctrl.Result{ - // RequeueAfter: RequeueTime, - //} - - // 7. The Notification CR already exists: manage the update - err = r.ReconcileNotification(ctx, watch.Modified, notificationManifest) - if err != nil { - logger.Info(fmt.Sprintf(notificationReconcileError, notificationManifest.Name)) - return result, err - } - - // 8. Success, update the status - UpdateNotificationCondition(notificationManifest, NewNotificationCondition(ConditionTypeResourceWatched, - metav1.ConditionTrue, - ConditionReasonResourceWatched, - ConditionReasonResourceWatchedMessage, - )) - - //logger.Info(fmt.Sprintf(scheduleSynchronization, result.RequeueAfter.String())) - return result, err -} - -// SetupWithManager sets up the controller with the Manager. -func (r *NotificationReconciler) SetupWithManager(mgr ctrl.Manager) error { - - return ctrl.NewControllerManagedBy(mgr). - For(¬ifikv1alpha1.Notification{}). - Complete(r) -} diff --git a/internal/controller/notification_controller_test.go b/internal/controller/notification_controller_test.go deleted file mode 100644 index e93f976..0000000 --- a/internal/controller/notification_controller_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "context" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/reconcile" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" -) - -var _ = Describe("Notification Controller", func() { - Context("When reconciling a resource", func() { - const resourceName = "test-resource" - - ctx := context.Background() - - typeNamespacedName := types.NamespacedName{ - Name: resourceName, - Namespace: "default", // TODO(user):Modify as needed - } - notification := ¬ifikv1alpha1.Notification{} - - BeforeEach(func() { - By("creating the custom resource for the Kind Notification") - err := k8sClient.Get(ctx, typeNamespacedName, notification) - if err != nil && errors.IsNotFound(err) { - resource := ¬ifikv1alpha1.Notification{ - ObjectMeta: metav1.ObjectMeta{ - Name: resourceName, - Namespace: "default", - }, - // TODO(user): Specify other spec details if needed. - } - Expect(k8sClient.Create(ctx, resource)).To(Succeed()) - } - }) - - AfterEach(func() { - // TODO(user): Cleanup logic after each test, like removing the resource instance. - resource := ¬ifikv1alpha1.Notification{} - err := k8sClient.Get(ctx, typeNamespacedName, resource) - Expect(err).NotTo(HaveOccurred()) - - By("Cleanup the specific resource instance Notification") - Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) - }) - It("should successfully reconcile the resource", func() { - By("Reconciling the created resource") - controllerReconciler := &NotificationReconciler{ - Client: k8sClient, - Scheme: k8sClient.Scheme(), - } - - _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ - NamespacedName: typeNamespacedName, - }) - Expect(err).NotTo(HaveOccurred()) - // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. - // Example: If you expect a certain status condition after reconciliation, verify it here. - }) - }) -}) diff --git a/internal/controller/notification_status.go b/internal/controller/notification_status.go deleted file mode 100644 index 7a385c6..0000000 --- a/internal/controller/notification_status.go +++ /dev/null @@ -1,95 +0,0 @@ -package controller - -import ( - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - // - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" -) - -const ( - // ConditionTypeResourceWatched indicates that the watcher for the resource type was launched or not - ConditionTypeResourceWatched = "ResourceWatched" - - // Resource not found - ConditionReasonResourceNotFound = "ResourceNotFound" - ConditionReasonResourceNotFoundMessage = "Resource was not found" - - // Template failed - ConditionReasonInvalidTemplate = "InvalidTemplate" - ConditionReasonInvalidTemplateMessage = "Patch template is not valid. Deeper information inside the Patch status" - - // Failure - ConditionReasonInvalidPatch = "InvalidPatch" - ConditionReasonInvalidPatchMessage = "Patch is invalid" - - // Success - ConditionReasonResourceWatched = "ResourceWatched" - ConditionReasonResourceWatchedMessage = "Resource was successfully watched" - - //////////////////// - - // ConditionTypeConditionsTemplateSucceed indicates that the templating stage was performed successfully for a condition - ConditionTypeConditionsTemplateSucceed = "ConditionsTemplateSucceed" - - // Conditions template parsing failed - ConditionReasonConditionsTemplateParsingFailed = "ConditionsTemplateParsingFailed" - ConditionReasonConditionsTemplateParsingFailedMessage = "Golang returned: %s" - - // Success - ConditionReasonConditionsTemplateParsed = "ConditionsTemplateParsed" - ConditionReasonConditionsTemplateParsedMessage = "Conditions template was successfully parsed" - - //////////////////// - - // ConditionTypeMessageTemplateSucceed indicates that the templating stage was performed successfully for the message - ConditionTypeMessageTemplateSucceed = "MessageTemplateSucceed" - - // Message template parsing failed - ConditionReasonMessageTemplateParsingFailed = "MessageTemplateParsingFailed" - ConditionReasonMessageTemplateParsingFailedMessage = "Golang returned: %s" - - // Success - ConditionReasonMessageTemplateParsed = "MessageTemplateParsed" - ConditionReasonMessageTemplateParsedMessage = "Message template was successfully parsed" -) - -// NewNotificationCondition a set of default options for creating a Condition. -func NewNotificationCondition(condType string, status metav1.ConditionStatus, reason, message string) *metav1.Condition { - return &metav1.Condition{ - Type: condType, - Status: status, - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: message, - } -} - -// GetNotificationCondition returns the condition with the provided type. -func GetNotificationCondition(patch *notifikv1alpha1.Notification, condType string) *metav1.Condition { - - for i, v := range patch.Status.Conditions { - if v.Type == condType { - return &patch.Status.Conditions[i] - } - } - return nil -} - -// UpdateNotificationCondition update or create a new condition inside the status of the CR -func UpdateNotificationCondition(patch *notifikv1alpha1.Notification, condition *metav1.Condition) { - - // Get the condition - currentCondition := GetNotificationCondition(patch, condition.Type) - - if currentCondition == nil { - // Create the condition when not existent - patch.Status.Conditions = append(patch.Status.Conditions, *condition) - } else { - // Update the condition when existent. - currentCondition.Status = condition.Status - currentCondition.Reason = condition.Reason - currentCondition.Message = condition.Message - currentCondition.LastTransitionTime = metav1.Now() - } -} diff --git a/internal/controller/notification_sync.go b/internal/controller/notification_sync.go deleted file mode 100644 index 6462bcd..0000000 --- a/internal/controller/notification_sync.go +++ /dev/null @@ -1,98 +0,0 @@ -package controller - -import ( - "context" - "strings" - // - "k8s.io/apimachinery/pkg/watch" - "sigs.k8s.io/controller-runtime/pkg/log" - - // - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" - "freepik.com/notifik/internal/globals" -) - -const ( - - // parseSyncTimeError error message for invalid value on 'synchronization' parameter - parseSyncTimeError = "Can not parse the synchronization time from Notification: %s" - - // - watcherPoolAddedNotificationMessage = "A Notification will be added into the WatcherPool" - watcherPoolUpdatedNotificationMessage = "A Notification will be modified into the WatcherPool" - watcherPoolDeletedNotificationMessage = "A Notification will be deleted from WatcherPool" -) - -// ReconcileNotification call Kubernetes API to actually Notification the resource -func (r *NotificationReconciler) ReconcileNotification(ctx context.Context, eventType watch.EventType, notificationManifest *notifikv1alpha1.Notification) (err error) { - logger := log.FromContext(ctx) - - // TODO check if is the last watcher of his resource type in global map - - watchedTypeString := strings.Join([]string{ - notificationManifest.Spec.Watch.Group, - notificationManifest.Spec.Watch.Version, - notificationManifest.Spec.Watch.Resource, - notificationManifest.Spec.Watch.Namespace, - notificationManifest.Spec.Watch.Name, - }, "/") - watchedType := globals.ResourceTypeName(watchedTypeString) - - // Initialize the watcher into WatcherPool when not registered - if _, watcherFound := globals.Application.WatcherPool[watchedType]; !watcherFound { - globals.InitWatcher(watchedType) - } - - notificationList := globals.Application.WatcherPool[watchedType].NotificationList - //notificationIndex := globals.GetWatcherNotificationIndex(watchedType, notificationManifest) - - notificationIndexes := globals.GetWatcherPoolNotificationIndexes(notificationManifest) - notificationIndex, notificationIndexFound := notificationIndexes[watchedTypeString] - - // Delete Notification from WatcherPool and exit - if eventType == watch.Deleted { - logger.Info(watcherPoolDeletedNotificationMessage, - "watcher", watchedType) - - // Notification found, delete it from the pool - if notificationIndexFound { - globals.DeleteWatcherNotificationByIndex(watchedType, notificationIndex) - } - return nil - } - - // Notification isn't found, create it into the pool - if !notificationIndexFound { - logger.Info(watcherPoolAddedNotificationMessage, - "watcher", watchedType) - - globals.CreateWatcherNotification(watchedType, notificationManifest) - - // TODO: Decide if resourceType watcher restart is suitable on Notification creation events - //*(globals.Application.WatcherPool[watchedType].StopSignal) <- true - return nil - } - - // Delete Notification from other Watchers when Notification is updated - if eventType == watch.Modified { - for currentWatchedType, currentNotificationIndex := range notificationIndexes { - - if currentWatchedType != watchedTypeString { - globals.DeleteWatcherNotificationByIndex(globals.ResourceTypeName(currentWatchedType), currentNotificationIndex) - } - } - } - - // Notification found, update it into the pool - // TODO: Decide if we want to log everything related to state - //logger.Info(watcherPoolUpdatedNotificationMessage, - // "watcher", watchedType) - (*notificationList)[notificationIndex] = notificationManifest - - // TODO: Create a cleaner to delete empty watchers from WatcherPool - - // TODO: Decide if resourceType watcher restart is suitable on Notification update events - //*(globals.Application.WatcherPool[watchedType].StopSignal) <- true - return nil - -} diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go deleted file mode 100644 index 29a79a6..0000000 --- a/internal/controller/suite_test.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2024. - -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 controller - -import ( - "fmt" - "path/filepath" - "runtime" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/rest" - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/envtest" - logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" - - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" - //+kubebuilder:scaffold:imports -) - -// These tests use Ginkgo (BDD-style Go testing framework). Refer to -// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. - -var cfg *rest.Config -var k8sClient client.Client -var testEnv *envtest.Environment - -func TestControllers(t *testing.T) { - RegisterFailHandler(Fail) - - RunSpecs(t, "Controller Suite") -} - -var _ = BeforeSuite(func() { - logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) - - By("bootstrapping test environment") - testEnv = &envtest.Environment{ - CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")}, - ErrorIfCRDPathMissing: true, - - // The BinaryAssetsDirectory is only required if you want to run the tests directly - // without call the makefile target test. If not informed it will look for the - // default path defined in controller-runtime which is /usr/local/kubebuilder/. - // Note that you must have the required binaries setup under the bin directory to perform - // the tests directly. When we run make test it will be setup and used automatically. - BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s", - fmt.Sprintf("1.29.0-%s-%s", runtime.GOOS, runtime.GOARCH)), - } - - var err error - // cfg is defined in this file globally. - cfg, err = testEnv.Start() - Expect(err).NotTo(HaveOccurred()) - Expect(cfg).NotTo(BeNil()) - - err = notifikv1alpha1.AddToScheme(scheme.Scheme) - Expect(err).NotTo(HaveOccurred()) - - //+kubebuilder:scaffold:scheme - - k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme}) - Expect(err).NotTo(HaveOccurred()) - Expect(k8sClient).NotTo(BeNil()) - -}) - -var _ = AfterSuite(func() { - By("tearing down the test environment") - err := testEnv.Stop() - Expect(err).NotTo(HaveOccurred()) -}) diff --git a/internal/globals/globals.go b/internal/globals/globals.go deleted file mode 100644 index e606f90..0000000 --- a/internal/globals/globals.go +++ /dev/null @@ -1,49 +0,0 @@ -package globals - -import ( - "context" - "sync" - - "k8s.io/client-go/dynamic" - - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" -) - -var ( - Application = applicationT{ - Context: context.Background(), - - WatcherPool: make(map[ResourceTypeName]ResourceTypeWatcherT), - } -) - -// TODO -type ResourceTypeName string - -// ApplicationT TODO -type applicationT struct { - // Context TODO - Context context.Context - - // Configuration TODO - Configuration notifikv1alpha1.ConfigurationT - - // KubeRawClient TODO - KubeRawClient *dynamic.DynamicClient - - // WatcherPool TODO - WatcherPool map[ResourceTypeName]ResourceTypeWatcherT -} - -// TODO -type ResourceTypeWatcherT struct { - // Enforce concurrency safety - Mutex *sync.Mutex - - // - Started *bool - StopSignal *chan bool - - // - NotificationList *[]*notifikv1alpha1.Notification -} diff --git a/internal/globals/utils.go b/internal/globals/utils.go deleted file mode 100644 index 28c3a20..0000000 --- a/internal/globals/utils.go +++ /dev/null @@ -1,124 +0,0 @@ -package globals - -import ( - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" - "k8s.io/client-go/dynamic" - ctrl "sigs.k8s.io/controller-runtime" - "strings" - "sync" -) - -// NewKubernetesClient return a new Kubernetes Dynamic client from client-go SDK -func NewKubernetesClient() (client *dynamic.DynamicClient, err error) { - config, err := ctrl.GetConfig() - if err != nil { - return client, err - } - - // Create the clients to do requests to our friend: Kubernetes - client, err = dynamic.NewForConfig(config) - if err != nil { - return client, err - } - - return client, err -} - -// CopyMap return a map that is a real copy of the original -// Ref: https://go.dev/blog/maps -func CopyMap(src map[string]interface{}) map[string]interface{} { - m := make(map[string]interface{}, len(src)) - for k, v := range src { - m[k] = v - } - return m -} - -// SplitCommaSeparatedValues get a list of strings and return a new list -// where each element containing commas is divided in separated elements -func SplitCommaSeparatedValues(input []string) []string { - var result []string - for _, item := range input { - parts := strings.Split(item, ",") - result = append(result, parts...) - } - return result -} - -// TODO -func InitWatcher(watcherType ResourceTypeName) { - - var initialStartedState bool = false - var initialNotificationListState []*notifikv1alpha1.Notification - - initialStopSignalState := make(chan bool) - initialMutexState := sync.Mutex{} - - Application.WatcherPool[watcherType] = ResourceTypeWatcherT{ - Mutex: &initialMutexState, - Started: &initialStartedState, - StopSignal: &initialStopSignalState, - NotificationList: &initialNotificationListState, - } -} - -// TODO -func GetWatcherNotificationIndex(watcherType ResourceTypeName, notificationManifest *notifikv1alpha1.Notification) (result int) { - - notificationList := Application.WatcherPool[watcherType].NotificationList - - for notificationIndex, notification := range *notificationList { - if (notification.Name == notificationManifest.Name) && - (notification.Namespace == notificationManifest.Namespace) { - return notificationIndex - } - } - - return -1 -} - -// TODO -func GetWatcherPoolNotificationIndexes(notificationManifest *notifikv1alpha1.Notification) (result map[string]int) { - - result = make(map[string]int) - - for watcherType, _ := range Application.WatcherPool { - notificationIndex := GetWatcherNotificationIndex(watcherType, notificationManifest) - - if notificationIndex != -1 { - result[string(watcherType)] = notificationIndex - } - } - - return result -} - -// TODO -func CreateWatcherNotification(watcherType ResourceTypeName, notificationManifest *notifikv1alpha1.Notification) { - - notificationList := Application.WatcherPool[watcherType].NotificationList - - (Application.WatcherPool[watcherType].Mutex).Lock() - - temporaryManifest := (*notificationManifest).DeepCopy() - *notificationList = append(*notificationList, temporaryManifest) - - (Application.WatcherPool[watcherType].Mutex).Unlock() -} - -// TODO -func DeleteWatcherNotificationByIndex(watcherType ResourceTypeName, notificationIndex int) { - - notificationList := Application.WatcherPool[watcherType].NotificationList - - (Application.WatcherPool[watcherType].Mutex).Lock() - - // Substitute the selected notification object with the last one from the list, - // then replace the whole list with it, minus the last. - //(*notificationList)[notificationIndex] = (*notificationList)[len(*notificationList)-1] - //*notificationList = (*notificationList)[:len(*notificationList)-1] - - *notificationList = append((*notificationList)[:notificationIndex], (*notificationList)[notificationIndex+1:]...) - - (Application.WatcherPool[watcherType].Mutex).Unlock() -} diff --git a/internal/integrations/alertmanager/alertmanager.go b/internal/integrations/alertmanager/alertmanager.go deleted file mode 100644 index d0b5efa..0000000 --- a/internal/integrations/alertmanager/alertmanager.go +++ /dev/null @@ -1,94 +0,0 @@ -package alertmanager - -import ( - "bytes" - "context" - "encoding/json" - "errors" - "fmt" - "io" - "net/http" - "reflect" - "time" - // corelog "log" - - "sigs.k8s.io/controller-runtime/pkg/log" - - "freepik.com/notifik/internal/globals" -) - -const ( - HttpEventVerb = "POST" - - HttpRequestCreationErrorMessage = "error creating http request: %s" - HttpRequestSendingErrorMessage = "error sending http request: %s" -) - -// SendMessage TODO -// Ref: https://raw.githubusercontent.com/prometheus/alertmanager/main/api/v2/openapi.yaml -func SendMessage(ctx context.Context, reason string, data string) (err error) { - logger := log.FromContext(ctx) - _ = logger - - // 1. Check whether the data meets the requirements for Alertmanager - alert := Alert{} - err = json.Unmarshal([]byte(data), &alert) - if err != nil { - return errors.New(fmt.Sprintf("pepito: %s", err)) - } - - if reflect.ValueOf(alert).IsZero() { - return errors.New("notification 'data' field does not meet the syntax requirements for Alertmanager") - } - - // 2. Set the main label for the alert. - // This is required only on API v1 - alert.Labels["alertname"] = reason - - if alert.StartAt == "" { - currentMoment := time.Now().In(time.Local) - alert.StartAt = currentMoment.Format(time.RFC3339) - } - - // 3. Prepare the alert for being sent - alertList := AlertList{alert} - alertsJson, err := json.Marshal(alertList) - if err != nil { - return errors.New(fmt.Sprintf("Cannot convert back alert into JSON: %s", err)) - } - - // TODO: DEBUG - //corelog.Print(string(alertsJson)) - - // 4. Perform HTTP request against Alertmanager - httpClient := &http.Client{} - - alertmanagerConfig := globals.Application.Configuration.Integrations.Alertmanager - - // Create the request - httpRequest, err := http.NewRequest(HttpEventVerb, alertmanagerConfig.Url, nil) - if err != nil { - return errors.New(fmt.Sprintf(HttpRequestCreationErrorMessage, err)) - } - - // Add headers to the request - for headerKey, headerValue := range alertmanagerConfig.Headers { - httpRequest.Header.Set(headerKey, headerValue) - } - - httpRequest.Header.Set("X-Notification-Reason", reason) - - // Add data to the request - httpRequest.Body = io.NopCloser(bytes.NewBuffer(alertsJson)) - httpRequest.Header.Set("Content-Type", "application/json") - - // Send HTTP request - httpResponse, err := httpClient.Do(httpRequest) - if err != nil { - return errors.New(fmt.Sprintf(HttpRequestSendingErrorMessage, err)) - } - defer httpResponse.Body.Close() - - // - return err -} diff --git a/internal/integrations/alertmanager/types.go b/internal/integrations/alertmanager/types.go deleted file mode 100644 index 91f02aa..0000000 --- a/internal/integrations/alertmanager/types.go +++ /dev/null @@ -1,17 +0,0 @@ -package alertmanager - -// TODO: Review if this is needed -type AlertList []Alert - -// Alert represents the structure of an alert in Alertmanager -// Ref: https://prometheus.io/docs/alerting/latest/clients/ -// Ref: https://raw.githubusercontent.com/prometheus/alertmanager/main/api/v2/openapi.yaml -type Alert struct { - Labels map[string]string `json:"labels"` - Annotations map[string]string `json:"annotations"` - - // Optional params - StartAt string `json:"startAt,omitempty"` - EndsAt string `json:"endsAt,omitempty"` - GeneratorUrl string `json:"generatorURL,omitempty"` -} diff --git a/internal/integrations/integrations.go b/internal/integrations/integrations.go deleted file mode 100644 index f424d4e..0000000 --- a/internal/integrations/integrations.go +++ /dev/null @@ -1,33 +0,0 @@ -package integrations - -import ( - "context" - "reflect" - - // - "freepik.com/notifik/internal/globals" - "freepik.com/notifik/internal/integrations/alertmanager" - "freepik.com/notifik/internal/integrations/webhook" -) - -// SendMessage send a message to all configured integrations -func SendMessage(ctx context.Context, reason string, msg string) (err error) { - - // Send the message to Alertmanager - if !reflect.ValueOf(globals.Application.Configuration.Integrations.Alertmanager).IsZero() { - err = alertmanager.SendMessage(ctx, reason, msg) - if err != nil { - return err - } - } - - // Send the message to a webhook - if !reflect.ValueOf(globals.Application.Configuration.Integrations.Webhook).IsZero() { - err = webhook.SendMessage(ctx, reason, msg) - if err != nil { - return err - } - } - - return nil -} diff --git a/internal/integrations/webhook/webhook.go b/internal/integrations/webhook/webhook.go deleted file mode 100644 index c198e09..0000000 --- a/internal/integrations/webhook/webhook.go +++ /dev/null @@ -1,62 +0,0 @@ -package webhook - -import ( - "bytes" - "context" - "errors" - "fmt" - "io" - "net/http" - "time" - - // - "sigs.k8s.io/controller-runtime/pkg/log" - - // - "freepik.com/notifik/internal/globals" -) - -const ( - HttpEventPattern = `{"reason":"%s","data":"%s","timestamp":"%s"}` - HttpEventVerb = "POST" - - HttpRequestCreationErrorMessage = "error creating http request: %s" - HttpRequestSendingErrorMessage = "error sending http request: %s" -) - -func SendMessage(ctx context.Context, reason string, data string) (err error) { - logger := log.FromContext(ctx) - _ = logger - - httpClient := &http.Client{} - - webhookConfig := globals.Application.Configuration.Integrations.Webhook - - // Create the request - httpRequest, err := http.NewRequest(HttpEventVerb, webhookConfig.Url, nil) - if err != nil { - return errors.New(fmt.Sprintf(HttpRequestCreationErrorMessage, err)) - } - - // Add headers to the request - for headerKey, headerValue := range webhookConfig.Headers { - httpRequest.Header.Set(headerKey, headerValue) - } - - httpRequest.Header.Set("X-Notification-Reason", reason) - - // Add data to the request - payload := []byte(fmt.Sprintf(HttpEventPattern, reason, data, time.Now().In(time.Local))) - httpRequest.Body = io.NopCloser(bytes.NewBuffer(payload)) - httpRequest.Header.Set("Content-Type", "application/json") - - // Send HTTP request - httpResponse, err := httpClient.Do(httpRequest) - if err != nil { - return errors.New(fmt.Sprintf(HttpRequestSendingErrorMessage, err)) - } - defer httpResponse.Body.Close() - - // - return err -} diff --git a/internal/template/functions.go b/internal/template/functions.go deleted file mode 100644 index 8a3bbf5..0000000 --- a/internal/template/functions.go +++ /dev/null @@ -1,165 +0,0 @@ -package template - -import ( - "bytes" - "encoding/json" - "strings" - "text/template" - - "github.com/BurntSushi/toml" - "github.com/Masterminds/sprig" - "sigs.k8s.io/yaml" -) - -// FOLKS, ATTENTION HERE: -// Some parts of the magic you are going to see are replicated from Helm templating engine. -// We decided to use Golang templating and add, more or less, the same extra functionality to this operator -// for people who are already comfortable with Helm. Not all the extra functionality was added to keep this simpler. -// Ref: https://github.com/helm/helm/blob/main/pkg/engine/funcs.go - -func EvaluateTemplate(templateString string, data map[string]interface{}) (result string, err error) { - templateFunctionsMap := GetFunctionsMap() - - // Create a Template object from the given string - parsedTemplate, err := template.New("main").Funcs(templateFunctionsMap).Parse(templateString) - if err != nil { - return result, err - } - - // Create a new buffer to store the templating result - buffer := new(bytes.Buffer) - - err = parsedTemplate.Execute(buffer, data) - if err != nil { - return result, err - } - - return buffer.String(), nil -} - -// GetFunctionsMap return a map with equivalency between functions for inside templating and real Golang ones -func GetFunctionsMap() template.FuncMap { - f := sprig.TxtFuncMap() - - // Delete risky functions - // Ref: http://masterminds.github.io/sprig/os.html - delete(f, "env") - delete(f, "expandenv") - - // Add some extra functionality - extra := template.FuncMap{ - "toToml": toTOML, - "toYaml": toYAML, - "fromYaml": fromYAML, - "fromYamlArray": fromYAMLArray, - "toJson": toJSON, - "fromJson": fromJSON, - "fromJsonArray": fromJSONArray, - } - - for k, v := range extra { - f[k] = v - } - - return f -} - -// toYAML takes an interface, marshals it to yaml, and returns a string. It will -// always return a string, even on marshal error (empty string). -// -// This is designed to be called from a template. -func toYAML(v interface{}) string { - data, err := yaml.Marshal(v) - if err != nil { - // Swallow errors inside of a template. - return "" - } - return strings.TrimSuffix(string(data), "\n") -} - -// fromYAML converts a YAML document into a map[string]interface{}. -// -// This is not a general-purpose YAML parser, and will not parse all valid -// YAML documents. Additionally, because its intended use is within templates -// it tolerates errors. It will insert the returned error message string into -// m["Error"] in the returned map. -func fromYAML(str string) map[string]interface{} { - m := map[string]interface{}{} - - if err := yaml.Unmarshal([]byte(str), &m); err != nil { - m["Error"] = err.Error() - } - return m -} - -// fromYAMLArray converts a YAML array into a []interface{}. -// -// This is not a general-purpose YAML parser, and will not parse all valid -// YAML documents. Additionally, because its intended use is within templates -// it tolerates errors. It will insert the returned error message string as -// the first and only item in the returned array. -func fromYAMLArray(str string) []interface{} { - a := []interface{}{} - - if err := yaml.Unmarshal([]byte(str), &a); err != nil { - a = []interface{}{err.Error()} - } - return a -} - -// toTOML takes an interface, marshals it to toml, and returns a string. It will -// always return a string, even on marshal error (empty string). -// -// This is designed to be called from a template. -func toTOML(v interface{}) string { - b := bytes.NewBuffer(nil) - e := toml.NewEncoder(b) - err := e.Encode(v) - if err != nil { - return err.Error() - } - return b.String() -} - -// toJSON takes an interface, marshals it to json, and returns a string. It will -// always return a string, even on marshal error (empty string). -// -// This is designed to be called from a template. -func toJSON(v interface{}) string { - data, err := json.Marshal(v) - if err != nil { - // Swallow errors inside of a template. - return "" - } - return string(data) -} - -// fromJSON converts a JSON document into a map[string]interface{}. -// -// This is not a general-purpose JSON parser, and will not parse all valid -// JSON documents. Additionally, because its intended use is within templates -// it tolerates errors. It will insert the returned error message string into -// m["Error"] in the returned map. -func fromJSON(str string) map[string]interface{} { - m := make(map[string]interface{}) - - if err := json.Unmarshal([]byte(str), &m); err != nil { - m["Error"] = err.Error() - } - return m -} - -// fromJSONArray converts a JSON array into a []interface{}. -// -// This is not a general-purpose JSON parser, and will not parse all valid -// JSON documents. Additionally, because its intended use is within templates -// it tolerates errors. It will insert the returned error message string as -// the first and only item in the returned array. -func fromJSONArray(str string) []interface{} { - a := []interface{}{} - - if err := json.Unmarshal([]byte(str), &a); err != nil { - a = []interface{}{err.Error()} - } - return a -} diff --git a/internal/xyz/utils.go b/internal/xyz/utils.go deleted file mode 100644 index d2cc566..0000000 --- a/internal/xyz/utils.go +++ /dev/null @@ -1,28 +0,0 @@ -package xyz - -import ( - "errors" - "k8s.io/apimachinery/pkg/runtime" -) - -// GetObjectMapFromRuntimeObject converts the runtime.Object to map[string]interface{} -func GetObjectMapFromRuntimeObject(obj *runtime.Object) (objectData map[string]interface{}, err error) { - objectData, err = runtime.DefaultUnstructuredConverter.ToUnstructured(obj) - return objectData, err -} - -// TODO -func GetObjectBasicData(object *map[string]interface{}) (objectData map[string]interface{}, err error) { - - metadata, ok := (*object)["metadata"].(map[string]interface{}) - if !ok { - err = errors.New("metadata not found or not in expected format") - return - } - - objectData = make(map[string]interface{}) - objectData["name"] = metadata["name"] - objectData["namespace"] = metadata["namespace"] - - return objectData, nil -} diff --git a/internal/xyz/workload_controller.go b/internal/xyz/workload_controller.go deleted file mode 100644 index 116ea3d..0000000 --- a/internal/xyz/workload_controller.go +++ /dev/null @@ -1,263 +0,0 @@ -/* -Copyright 2024. - -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 xyz - -import ( - "context" - "fmt" - "freepik.com/notifik/internal/integrations" - "k8s.io/apimachinery/pkg/fields" - "k8s.io/client-go/dynamic" - "slices" - "strings" - "time" - - // - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/watch" - - "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/log" - - // - notifikv1alpha1 "freepik.com/notifik/api/v1alpha1" - "freepik.com/notifik/internal/globals" - "freepik.com/notifik/internal/template" -) - -const ( - // Default values - secondsBetweenWatchingRetries = 10 * time.Second - - // - controllerContextFinishedMessage = "xyz.WorkloadController finished by context" - controllerWatcherStartedMessage = "Watcher for '%s' has been started" - controllerWatcherKilledMessage = "Watcher for resource type '%s' killed by StopSignal" - - evengConditionsTriggerIntegrationsMessage = "Object has met conditions. Integrations will be triggered" - - kubeWatcherStartFailedError = "Impossible to watch resource type '%s'. RBAC issues?: %s" - watchedObjectParseError = "Impossible to process watched object: %s" - runtimeObjectConversionError = "Failed to parse object: %v" - resourceWatcherLaunchingError = "Impossible to start watcher for resource type: %s" - integrationsSendMessageError = "Impossible to send the message to some integration: %s" - resourceWatcherGvrParsingError = "Failed to parse GVR from resourceType. Does it look like {group}/{version}/{resource}?" - - eventConditionGoTemplateError = "Go templating reported failure for object conditions: %s" - eventMessageGoTemplateError = "Go templating reported failure for object message: %s" -) - -type WorkloadControllerOptions struct { - // Events to be processed per second (best effort policy) - EventsPerSecond int -} - -// WorkloadController represents the controller that triggers parallel threads. -// These threads process coming events against the conditions defined in Notification CRs -// Each thread is a watcher in charge of a group of resources GVRNN (Group + Version + Resource + Namespace + Name) -type WorkloadController struct { - Client client.Client - - // - Options WorkloadControllerOptions -} - -// Start launches the XYZ.WorkloadController and keeps it alive -// It kills the controller on application context death, and rerun the process when failed -func (r *WorkloadController) Start(ctx context.Context) { - logger := log.FromContext(ctx) - - for { - select { - case <-ctx.Done(): - logger.Info(controllerContextFinishedMessage) - return - default: - r.ReconcileWatchers(ctx) - } - } -} - -// ReconcileWatchers launches a parallel process that launches -// watchers for resource types defined into the WatcherPool -func (r *WorkloadController) ReconcileWatchers(ctx context.Context) { - logger := log.FromContext(ctx) - - for resourceType, resourceTypeWatcher := range globals.Application.WatcherPool { - - if !*resourceTypeWatcher.Started { - go r.watchType(ctx, resourceType) - - // Wait for the resourceType watcher to ACK itself into WatcherPool - // TODO: Improve this logic in future version - time.Sleep(secondsBetweenWatchingRetries) - if *(globals.Application.WatcherPool[resourceType].Started) == false { - logger.Info(fmt.Sprintf(resourceWatcherLaunchingError, resourceType)) - } - } - } -} - -// WatchType launches a watcher for a certain resource type, and trigger processing for each entering resource event -func (r *WorkloadController) watchType(ctx context.Context, watchedType globals.ResourceTypeName) { - - logger := log.FromContext(ctx) - - logger.Info(fmt.Sprintf(controllerWatcherStartedMessage, watchedType)) - - // Set ACK flag for watcher launching into the WatcherPool - *(globals.Application.WatcherPool[watchedType].Started) = true - defer func() { - *(globals.Application.WatcherPool[watchedType].Started) = false - }() - - notificationList := globals.Application.WatcherPool[watchedType].NotificationList - - // Extract GVR + Namespace + Name from watched type: - // {group}/{version}/{resource}/{namespace}/{name} - GVRNN := strings.Split(string(watchedType), "/") - if len(GVRNN) != 5 { - logger.Info(resourceWatcherGvrParsingError) - return - } - resourceGVR := schema.GroupVersionResource{ - Group: GVRNN[0], - Version: GVRNN[1], - Resource: GVRNN[2], - } - - namespace := GVRNN[3] - name := GVRNN[4] - - // - watchOptions := metav1.ListOptions{} - - // Include the name when defined by the user - if name != "" { - // DOCS: Alternative way to do the same - // FieldSelector: fmt.Sprintf("metadata.name=%s", name), - watchOptions.FieldSelector = fields.OneTermEqualSelector(metav1.ObjectNameField, name).String() - } - - // Include the namespace when defined by the user - var resourceSelector dynamic.ResourceInterface - resourceSelector = globals.Application.KubeRawClient.Resource(resourceGVR) - if namespace != "" { - resourceSelector = globals.Application.KubeRawClient.Resource(resourceGVR).Namespace(namespace) - } - - // Create a watcher for defined resources - resourceWatcher, err := resourceSelector.Watch(ctx, watchOptions) - if err != nil { - logger.Info(fmt.Sprintf(kubeWatcherStartFailedError, string(watchedType), err)) - return - } - defer resourceWatcher.Stop() - - // Listen to stop signal to kill this watcher just in case it's needed - go func(p watch.Interface) { - <-*(globals.Application.WatcherPool[watchedType].StopSignal) - p.Stop() - logger.Info(fmt.Sprintf(controllerWatcherKilledMessage, watchedType)) - }(resourceWatcher) - - // Calculate waiting time between loops to process N items per second - // Done this way to allow limitation of consumed resources - waitDuration := time.Second / time.Duration(r.Options.EventsPerSecond) - - // - for WatchEvent := range resourceWatcher.ResultChan() { - // Extract the unstructured object from the event - objectMap, err := GetObjectMapFromRuntimeObject(&WatchEvent.Object) - if err != nil { - logger.Error(err, fmt.Sprintf(runtimeObjectConversionError, err)) - continue - } - - // Process event for watched object apart - // TODO: Probably we need to trigger processing into goroutines not to affect waiting calculation - err = r.processEvent(ctx, notificationList, objectMap, WatchEvent.Type) - if err != nil { - logger.Error(err, fmt.Sprintf(watchedObjectParseError, err)) - continue - } - - // - time.Sleep(waitDuration) - } -} - -// processEvent process an event coming from a watched resource type. -// It computes templating, evaluates conditions and decides whether to send a message for a given manifest -func (r *WorkloadController) processEvent(ctx context.Context, notificationList *[]*notifikv1alpha1.Notification, object map[string]interface{}, eventType watch.EventType) (err error) { - logger := log.FromContext(ctx) - - // Process only certain event types - if eventType != watch.Added && eventType != watch.Modified && eventType != watch.Deleted { - return nil - } - - // Get object name and namespace for logging ease - objectBasicData, err := GetObjectBasicData(&object) - if err != nil { - return err - } - - for _, notification := range *notificationList { - - var conditionFlags []bool - for _, condition := range notification.Spec.Conditions { - parsedKey, err := template.EvaluateTemplate(condition.Key, object) - if err != nil { - logger.WithValues( - "notification", fmt.Sprintf("%s/%s", notification.Namespace, notification.Name), - "object", fmt.Sprintf("%s/%s", objectBasicData["namespace"], objectBasicData["name"]), - "error", err).Info(eventConditionGoTemplateError) - conditionFlags = append(conditionFlags, false) - continue - } - conditionFlags = append(conditionFlags, parsedKey == condition.Value) - } - - if slices.Contains(conditionFlags, false) { - continue - } - - parsedMessage, err := template.EvaluateTemplate(notification.Spec.Message.Data, object) - if err != nil { - logger.WithValues( - "notification", fmt.Sprintf("%s/%s", notification.Namespace, notification.Name), - "object", fmt.Sprintf("%s/%s", objectBasicData["namespace"], objectBasicData["name"]), - "error", err).Info(eventMessageGoTemplateError) - continue - } - - logger.WithValues( - "notification", fmt.Sprintf("%s/%s", notification.Namespace, notification.Name), - "object", fmt.Sprintf("%s/%s", objectBasicData["namespace"], objectBasicData["name"])). - Info(evengConditionsTriggerIntegrationsMessage) - - // Send the message through integrations - err = integrations.SendMessage(ctx, notification.Spec.Message.Reason, parsedMessage) - if err != nil { - logger.Info(fmt.Sprintf(integrationsSendMessageError, err)) - } - } - - return err -} diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go deleted file mode 100644 index 46685e1..0000000 --- a/test/e2e/e2e_suite_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2024. - -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 e2e - -import ( - "fmt" - "testing" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -// Run e2e tests using the Ginkgo runner. -func TestE2E(t *testing.T) { - RegisterFailHandler(Fail) - fmt.Fprintf(GinkgoWriter, "Starting notifik suite\n") - RunSpecs(t, "e2e suite") -} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go deleted file mode 100644 index d78a7b7..0000000 --- a/test/e2e/e2e_test.go +++ /dev/null @@ -1,121 +0,0 @@ -/* -Copyright 2024. - -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 e2e - -import ( - "fmt" - "os/exec" - "time" - - . "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" - - "freepik.com/notifik/test/utils" -) - -const namespace = "notifik" - -var _ = Describe("controller", Ordered, func() { - BeforeAll(func() { - By("installing prometheus operator") - Expect(utils.InstallPrometheusOperator()).To(Succeed()) - - By("installing the cert-manager") - Expect(utils.InstallCertManager()).To(Succeed()) - - By("creating manager namespace") - cmd := exec.Command("kubectl", "create", "ns", namespace) - _, _ = utils.Run(cmd) - }) - - AfterAll(func() { - By("uninstalling the Prometheus manager bundle") - utils.UninstallPrometheusOperator() - - By("uninstalling the cert-manager bundle") - utils.UninstallCertManager() - - By("removing manager namespace") - cmd := exec.Command("kubectl", "delete", "ns", namespace) - _, _ = utils.Run(cmd) - }) - - Context("Operator", func() { - It("should run successfully", func() { - var controllerPodName string - var err error - - // projectimage stores the name of the image used in the example - var projectimage = "example.com/notifik:v0.0.1" - - By("building the manager(Operator) image") - cmd := exec.Command("make", "docker-build", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("loading the the manager(Operator) image on Kind") - err = utils.LoadImageToKindClusterWithName(projectimage) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("installing CRDs") - cmd = exec.Command("make", "install") - _, err = utils.Run(cmd) - - By("deploying the controller-manager") - cmd = exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", projectimage)) - _, err = utils.Run(cmd) - ExpectWithOffset(1, err).NotTo(HaveOccurred()) - - By("validating that the controller-manager pod is running as expected") - verifyControllerUp := func() error { - // Get pod name - - cmd = exec.Command("kubectl", "get", - "pods", "-l", "control-plane=controller-manager", - "-o", "go-template={{ range .items }}"+ - "{{ if not .metadata.deletionTimestamp }}"+ - "{{ .metadata.name }}"+ - "{{ \"\\n\" }}{{ end }}{{ end }}", - "-n", namespace, - ) - - podOutput, err := utils.Run(cmd) - ExpectWithOffset(2, err).NotTo(HaveOccurred()) - podNames := utils.GetNonEmptyLines(string(podOutput)) - if len(podNames) != 1 { - return fmt.Errorf("expect 1 controller pods running, but got %d", len(podNames)) - } - controllerPodName = podNames[0] - ExpectWithOffset(2, controllerPodName).Should(ContainSubstring("controller-manager")) - - // Validate pod status - cmd = exec.Command("kubectl", "get", - "pods", controllerPodName, "-o", "jsonpath={.status.phase}", - "-n", namespace, - ) - status, err := utils.Run(cmd) - ExpectWithOffset(2, err).NotTo(HaveOccurred()) - if string(status) != "Running" { - return fmt.Errorf("controller pod in %s status", status) - } - return nil - } - EventuallyWithOffset(1, verifyControllerUp, time.Minute, time.Second).Should(Succeed()) - - }) - }) -}) diff --git a/test/utils/utils.go b/test/utils/utils.go deleted file mode 100644 index 7363aa5..0000000 --- a/test/utils/utils.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2024. - -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 utils - -import ( - "fmt" - "os" - "os/exec" - "strings" - - . "github.com/onsi/ginkgo/v2" //nolint:golint,revive -) - -const ( - prometheusOperatorVersion = "v0.68.0" - prometheusOperatorURL = "https://github.com/prometheus-operator/prometheus-operator/" + - "releases/download/%s/bundle.yaml" - - certmanagerVersion = "v1.5.3" - certmanagerURLTmpl = "https://github.com/jetstack/cert-manager/releases/download/%s/cert-manager.yaml" -) - -func warnError(err error) { - fmt.Fprintf(GinkgoWriter, "warning: %v\n", err) -} - -// InstallPrometheusOperator installs the prometheus Operator to be used to export the enabled metrics. -func InstallPrometheusOperator() error { - url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) - cmd := exec.Command("kubectl", "create", "-f", url) - _, err := Run(cmd) - return err -} - -// Run executes the provided command within this context -func Run(cmd *exec.Cmd) ([]byte, error) { - dir, _ := GetProjectDir() - cmd.Dir = dir - - if err := os.Chdir(cmd.Dir); err != nil { - fmt.Fprintf(GinkgoWriter, "chdir dir: %s\n", err) - } - - cmd.Env = append(os.Environ(), "GO111MODULE=on") - command := strings.Join(cmd.Args, " ") - fmt.Fprintf(GinkgoWriter, "running: %s\n", command) - output, err := cmd.CombinedOutput() - if err != nil { - return output, fmt.Errorf("%s failed with error: (%v) %s", command, err, string(output)) - } - - return output, nil -} - -// UninstallPrometheusOperator uninstalls the prometheus -func UninstallPrometheusOperator() { - url := fmt.Sprintf(prometheusOperatorURL, prometheusOperatorVersion) - cmd := exec.Command("kubectl", "delete", "-f", url) - if _, err := Run(cmd); err != nil { - warnError(err) - } -} - -// UninstallCertManager uninstalls the cert manager -func UninstallCertManager() { - url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) - cmd := exec.Command("kubectl", "delete", "-f", url) - if _, err := Run(cmd); err != nil { - warnError(err) - } -} - -// InstallCertManager installs the cert manager bundle. -func InstallCertManager() error { - url := fmt.Sprintf(certmanagerURLTmpl, certmanagerVersion) - cmd := exec.Command("kubectl", "apply", "-f", url) - if _, err := Run(cmd); err != nil { - return err - } - // Wait for cert-manager-webhook to be ready, which can take time if cert-manager - // was re-installed after uninstalling on a cluster. - cmd = exec.Command("kubectl", "wait", "deployment.apps/cert-manager-webhook", - "--for", "condition=Available", - "--namespace", "cert-manager", - "--timeout", "5m", - ) - - _, err := Run(cmd) - return err -} - -// LoadImageToKindCluster loads a local docker image to the kind cluster -func LoadImageToKindClusterWithName(name string) error { - cluster := "kind" - if v, ok := os.LookupEnv("KIND_CLUSTER"); ok { - cluster = v - } - kindOptions := []string{"load", "docker-image", name, "--name", cluster} - cmd := exec.Command("kind", kindOptions...) - _, err := Run(cmd) - return err -} - -// GetNonEmptyLines converts given command output string into individual objects -// according to line breakers, and ignores the empty elements in it. -func GetNonEmptyLines(output string) []string { - var res []string - elements := strings.Split(output, "\n") - for _, element := range elements { - if element != "" { - res = append(res, element) - } - } - - return res -} - -// GetProjectDir will return the directory where the project is -func GetProjectDir() (string, error) { - wd, err := os.Getwd() - if err != nil { - return wd, err - } - wd = strings.Replace(wd, "/test/e2e", "", -1) - return wd, nil -}