diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b6e6ef6..5d05554 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,72 +1,92 @@ # SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) # SPDX-License-Identifier: Apache-2.0 -name: Release and publish a new version +name: 🚀 Release +permissions: read-all on: - pull_request: - types: [closed] - branches: ['main', 'hotfix/*'] + release: + types: + - created env: REGISTRY: ghcr.io - OWNER: InditexTech - OPERATOR_NAME: redkey-operator + IMAGE_NAME: inditextech/redkey-operator jobs: - create-release: - name: Create release + release: + name: 🏷️ Release runs-on: ubuntu-latest - permissions: - contents: write + outputs: + version: ${{ steps.version.outputs.version }} + user_agent_version: ${{ steps.version.outputs.user_agent_version }} steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Get version from Makefile - id: makefile_version - uses: ./.github/workflows/actions/get-version-from-makefile - - name: Check version - uses: ./.github/workflows/actions/check-version + - name: 🛎️ Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: - new_version: ${{ steps.makefile_version.outputs.version }} - - name: Create release - uses: ncipollo/release-action@v1.16.0 - id: github-release - continue-on-error: true - with: - tag: v${{ steps.makefile_version.outputs.version }} - commit: main - body: | - Check out the [changelog](CHANGELOG.md) for version v${{ steps.makefile_version.outputs.version }} - publish-operator-image: - name: Publish Redkey Operator image to the registry - needs: create-release + fetch-depth: 0 + - name: Check bundle generation 🧪 + run: | + make bundle IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + git diff --ignore-matching-lines='.*createdAt:.*' --exit-code + + - name: 📝 Load Operator version + id: version + run: | + echo "version=$(make version)" >> $GITHUB_OUTPUT + echo "user_agent_version=$(cat cmd/main.go | grep 'USER_AGENT_VERSION =' | cut -d'=' -f2 | cut -d'"' -f2)" >> $GITHUB_OUTPUT + echo $GITHUB_OUTPUT + + check: + name: 🔎 Check versions + needs: release + runs-on: ubuntu-latest + steps: + - name: 🔎 Check versions + run: | + echo "version: ${{ needs.release.outputs.version }}" + echo "user_agent_version: ${{ needs.release.outputs.user_agent_version }}" + echo "tag_name: ${{ github.event.release.tag_name }}" + + if [ "${{ github.event.release.tag_name }}" != "${{ needs.release.outputs.version }}" ]; then + echo "Version in Makefile does not match release tag" + exit 1 + fi + + if [ "${{ github.event.release.tag_name }}" != "${{ needs.release.outputs.user_agent_version }}" ]; then + echo "Version in main.go/USER_AGENT_VERSION does not match release tag" + exit 1 + fi + + build: + name: 🛠️ Build Operator images + needs: check runs-on: ubuntu-latest + permissions: + contents: write + packages: write steps: - - name: Checkout code - uses: actions/checkout@v4 - - name: Get version from Makefile - id: makefile_version - uses: ./.github/workflows/actions/get-version-from-makefile - - name: Login to registry ${{ env.REGISTRY }} - uses: docker/login-action@v3 + - name: 🛎️ Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + with: + fetch-depth: 0 + + - name: 🔐 Login into ${{ env.REGISTRY }} + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Build and push - uses: docker/build-push-action@v6 - with: - context: . - push: true - tags: ${{ env.REGISTRY }}/${{ env.OWNER }}/${{ env.OPERATOR_NAME }}:${{ steps.makefile_version.outputs.version }} -# publish-operator: -# name: Publish Redkey Operator to OperatorHub.io -# needs: [create-release, publish-operator-image] -# runs-on: ubuntu-latest -# steps: -# - name: checkout code -# uses: actions/checkout@v4 + + - name: 🏗️ Build and push Operator image + run: | + make docker-build IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + make docker-push IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: 🏗️ Build and push Operator bundle + run: | + make bundle IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + make bundle-build IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + make bundle-push IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + - name: 🏗️ Build and push Operator catalog + run: | + make catalog-build IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + make catalog-push IMAGE_TAG_BASE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} diff --git a/.gitignore b/.gitignore index 0c370a8..443478e 100644 --- a/.gitignore +++ b/.gitignore @@ -46,6 +46,7 @@ config/init-test/tests.yaml # Bundle temporary files bundle +bundle_* bundle.Dockerfile # Certificates diff --git a/.tool-versions b/.tool-versions index ad00fe8..de62786 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,3 +1,3 @@ # SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) # SPDX-License-Identifier: Apache-2.0 -golang 1.25.6 +golang 1.25.7 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d21dc8..59f60e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ diff --git a/CLA.md b/CLA.md index b103962..5d0f883 100644 --- a/CLA.md +++ b/CLA.md @@ -1,5 +1,5 @@ diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md index 1b90f7c..075fa14 100644 --- a/CODE-OF-CONDUCT.md +++ b/CODE-OF-CONDUCT.md @@ -1,5 +1,5 @@ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 51daf31..1023753 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ diff --git a/Dockerfile b/Dockerfile index fc73a27..8ec5e5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ### Build stage # Define the desired Golang version -ARG GOLANG_VERSION=1.25.6 +ARG GOLANG_VERSION=1.25.7 # Use an official Golang image with a specific version based on Debian FROM golang:${GOLANG_VERSION}-trixie AS builder diff --git a/MANIFESTO.md b/MANIFESTO.md index 4113da5..1417b0d 100644 --- a/MANIFESTO.md +++ b/MANIFESTO.md @@ -1,5 +1,5 @@ diff --git a/Makefile b/Makefile index f99a435..913a511 100644 --- a/Makefile +++ b/Makefile @@ -5,16 +5,16 @@ .DEFAULT_GOAL := help SHELL := /bin/bash -name := redkey-cluster-operator -version := 1.3.0 -golang_version := 1.25.6 -delve_version := 1.25 -package := github.com/inditextech/$(name) +NAME := redkey-cluster-operator +VERSION := 0.1.0 +GOLANG_VERSION := 1.25.7 +DELVE_VERSION := 1.25 +PACKAGE := github.com/inditextech/$(NAME) ## Tool Versions KUSTOMIZE_VERSION ?= v5.8.0 -CONTROLLER_TOOLS_VERSION ?= v0.20.0 OPERATOR_SDK_VERSION ?= v1.42.0 +CONTROLLER_TOOLS_VERSION ?= v0.18.0 # ............................................................................. # DONT TOUCH THIS SECTION @@ -33,7 +33,7 @@ SRC = $(shell find . -path ./vendor -prune -o -name '*.go' -print) M = $(shell printf "\033[34;1m▶\033[0m") MODULE=$(shell go list -m) -GO_COMPILE_FLAGS='-X $(MODULE)/cmd/server.GitCommit=$(COMMIT) -X $(MODULE)/cmd/server.BuildDate=$(DATE) -X $(MODULE)/cmd/server.VersionBuild=$(version)' +GO_COMPILE_FLAGS='-X $(MODULE)/cmd/server.GitCommit=$(COMMIT) -X $(MODULE)/cmd/server.BuildDate=$(DATE) -X $(MODULE)/cmd/server.VersionBuild=$(VERSION)' # Auxiliar programs SED = sed @@ -68,6 +68,8 @@ ifeq ($(filter $(PROFILE_ROBIN),$(PROFILES_ROBIN)), ) $(error The PROFILE_ROBIN specified ($(PROFILE)) is not supported) endif +CHANNELS ?= alpha,beta,stable + # CHANNELS define the bundle channels used in the bundle. # Add a new line here if you would like to change its default config. (E.g CHANNELS = "preview,fast,stable") # To re-generate a bundle for other specific channels without changing the standard setup, you can: @@ -82,6 +84,7 @@ endif # To re-generate a bundle for any other default channel without changing the default setup, you can: # - use the DEFAULT_CHANNEL as arg of the bundle target (e.g make bundle DEFAULT_CHANNEL=stable) # - use environment variables to overwrite this value (e.g export DEFAULT_CHANNEL="stable") +DEFAULT_CHANNEL ?= stable ifneq ($(origin DEFAULT_CHANNEL), undefined) BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) endif @@ -94,15 +97,27 @@ 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 + +# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images. +# This variable is used to construct full image tags for bundle and catalog images. +# +# For example, running 'make bundle-build bundle-push catalog-build catalog-push' will build and push both +# inditex.dev/sample-bundle:$VERSION and inditex.dev/sample-catalog:$VERSION. +IMAGE_TAG_BASE ?= localhost:5001/redkey-operator +ROBIN_IMAGE_TAG_BASE ?= localhost:5001/redkey-robin + # Image URL to use for building/pushing image targets -IMG ?= localhost:5001/redkey-operator:$(PROFILE) -IMG_ROBIN ?= localhost:5001/redkey-robin:$(PROFILE_ROBIN) +IMG ?= $(IMAGE_TAG_BASE):$(VERSION) +IMG_ROBIN ?= $(ROBIN_IMAGE_TAG_BASE):$(PROFILE_ROBIN) # BUNDLE_IMG defines the image:tag used for the bundle. # You can use it as an arg. (E.g make bundle-build BUNDLE_IMG=/:) -BUNDLE_IMG ?= controller-bundle:$(version) - -CHANNELS ?= alpha,beta +BUNDLE_IMG ?= $(IMAGE_TAG_BASE)-bundle:$(VERSION) # Image REF in bundle image # Can be overwritten with make bundle IMAGE_REF=/: @@ -144,7 +159,7 @@ deps: ## Installs dependencies .PHONY: version version:: ## Print the current version of the project. - @echo "$(version)" + @echo "$(VERSION)" .PHONY: version-next version-next:: ## Bump to next development version @@ -190,12 +205,16 @@ clean: ## Clean the build artifacts and Go cache rm -f bundle.Dockerfile rm -rf ./deployment rm -rf ./certs + rm -rf .local $(GO) clean --modcache ##@ Development -manifests: controller-gen ## Generate ClusterRole and CustomResourceDefinition objects. +manifests: kustomize controller-gen ## Generate ClusterRole and CustomResourceDefinition objects. $(info $(M) generating config CRD base manifest files from code) $(CONTROLLER_GEN) rbac:roleName=redkey-operator-role crd:maxDescLen=0 paths="./..." output:crd:artifacts:config=config/crd/bases + $(info $(M) setting operator-version annotation in CRD kustomization file) + cd config/crd && \ + $(KUSTOMIZE) edit set annotation inditex.dev/operator-version:$(VERSION); generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. $(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..." @@ -229,22 +248,22 @@ run: ## Execute the program locally docker-build: test ## Build operator docker image from source or an empty image to copy the binary if default profile (uses `${IMG}` image name) $(info $(M) building operator docker image) if [ ${PROFILE} != "debug" ]; then \ - docker build -t ${IMG} --build-arg GOLANG_VERSION=${golang_version} . ; \ + $(CONTAINER_TOOL) build -t ${IMG} --build-arg GOLANG_VERSION=$(GOLANG_VERSION) . ; \ else \ - docker build -t ${IMG} -f debug.Dockerfile --build-arg GOLANG_VERSION=${golang_version} --build-arg DELVE_VERSION=${delve_version} . ; \ + $(CONTAINER_TOOL) build -t ${IMG} -f debug.Dockerfile --build-arg GOLANG_VERSION=$(GOLANG_VERSION) --build-arg DELVE_VERSION=$(DELVE_VERSION) . ; \ fi -docker-push: ## Push operator docker image (uses `${IMG}` image name). +docker-push: ## Push operator $(CONTAINER_TOOL) image (uses `${IMG}` image name). $(info $(M) pushing operator docker image) - docker push ${IMG} + $(CONTAINER_TOOL) push ${IMG} ##@ Deployment install: create-namespace process-manifests-crd ## Install CRD into the K8s cluster specified by kubectl default context (Kustomize is installed if not present). $(info $(M) applying CRD manifest file) - kubectl apply -f deployment/redis.inditex.dev_redkeyclusters.yaml + kubectl apply -f deployment/redkey.inditex.dev_redkeyclusters.yaml uninstall: process-manifests-crd ## Uninstall CRD from the K8s cluster specified by kubectl default context (Kustomize is installed if not present). $(info $(M) deleting CRD) - kubectl delete -f deployment/redis.inditex.dev_redkeyclusters.yaml + kubectl delete -f deployment/redkey.inditex.dev_redkeyclusters.yaml process-manifests: kustomize process-manifests-crd ## Generate the kustomized yamls into the `deployment` directory to deploy the manager. $(info $(M) generating Manager deploying manifest files using ${PROFILE} profile) @@ -262,7 +281,7 @@ process-manifests: kustomize process-manifests-crd ## Generate the kustomized y process-manifests-crd: kustomize manifests ## Generate the kustomized yamls into the `deployment` directory to deploy the CRD. $(info $(M) generating CRD deploying manifest files) mkdir -p deployment - $(KUSTOMIZE) build config/crd > deployment/redis.inditex.dev_redkeyclusters.yaml + $(KUSTOMIZE) build config/crd > deployment/redkey.inditex.dev_redkeyclusters.yaml @echo "CRD manifest generated successfully" deploy: deploy-manager ## Deploy the manager into the K8s cluster specified by kubectl default context. @@ -450,16 +469,58 @@ bundle: kustomize manifests ## Generate the files for bundle. rm -rf bundle/metadata/* $(OPERATOR_SDK) generate kustomize manifests -q cd config/manager && $(KUSTOMIZE) edit set image redkey-operator=$(IMAGE_REF) - $(KUSTOMIZE) build config | $(OPERATOR_SDK) generate bundle -q --overwrite --channels $(CHANNELS) --version $(version) $(BUNDLE_METADATA_OPTS) + $(KUSTOMIZE) build config | $(OPERATOR_SDK) generate bundle -q --overwrite --channels $(CHANNELS) --version $(VERSION) $(BUNDLE_METADATA_OPTS) $(OPERATOR_SDK) bundle validate ./bundle + # Remove the images section from the kustomization.yaml added when kustomizing. + cd config/manager && sed -i '/^images:$$/,/^[^ -]/{ /^images:$$/d; /^- name: redkey-operator$$/,/^ newTag:/d; }' kustomization.yaml && sed -i '/^images:$$/d' kustomization.yaml .PHONY: bundle-build bundle-build: ## Build the bundle image. - docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . + $(CONTAINER_TOOL) build -f bundle.Dockerfile -t $(BUNDLE_IMG) . bundle-push: ## Push the bundle image. - docker push $(BUNDLE_IMG) + $(CONTAINER_TOOL) push $(BUNDLE_IMG) + +.PHONY: opm +OPM = $(LOCALBIN)/opm +opm: ## Download opm locally if necessary. +ifeq (,$(wildcard $(OPM))) +ifeq (,$(shell which opm 2>/dev/null)) + @{ \ + set -e ;\ + mkdir -p $(dir $(OPM)) ;\ + OS=$(shell go env GOOS) && ARCH=$(shell go env GOARCH) && \ + curl -sSLo $(OPM) https://github.com/operator-framework/operator-registry/releases/download/v1.55.0/$${OS}-$${ARCH}-opm ;\ + chmod +x $(OPM) ;\ + } +else +OPM = $(shell which opm) +endif +endif + +# A comma-separated list of bundle images (e.g. make catalog-build BUNDLE_IMGS=example.com/operator-bundle:v0.1.0,example.com/operator-bundle:v0.2.0). +# These images MUST exist in a registry and be pull-able. +BUNDLE_IMGS ?= $(BUNDLE_IMG) + +# The image tag given to the resulting catalog image (e.g. make catalog-build CATALOG_IMG=example.com/operator-catalog:v0.2.0). +CATALOG_IMG ?= $(IMAGE_TAG_BASE)-catalog:v$(VERSION) + +# Set CATALOG_BASE_IMG to an existing catalog image tag to add $BUNDLE_IMGS to that image. +ifneq ($(origin CATALOG_BASE_IMG), undefined) +FROM_INDEX_OPT := --from-index $(CATALOG_BASE_IMG) +endif +# Build a catalog image by adding bundle images to an empty catalog using the operator package manager tool, 'opm'. +# This recipe invokes 'opm' in 'semver' bundle add mode. For more information on add modes, see: +# https://github.com/operator-framework/community-operators/blob/7f1438c/docs/packaging-operator.md#updating-your-existing-operator +.PHONY: catalog-build +catalog-build: opm ## Build a catalog image. + $(OPM) index add --container-tool $(CONTAINER_TOOL) --mode semver --tag $(CATALOG_IMG) --bundles $(BUNDLE_IMGS) $(FROM_INDEX_OPT) + +# Push the catalog image. +.PHONY: catalog-push +catalog-push: ## Push a catalog image. + $(MAKE) docker-push IMG=$(CATALOG_IMG) ##@ Test diff --git a/PROJECT b/PROJECT new file mode 100644 index 0000000..c134d4f --- /dev/null +++ b/PROJECT @@ -0,0 +1,26 @@ +# SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +# SPDX-License-Identifier: Apache-2.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: inditex.dev +layout: +- go.kubebuilder.io/v4 +plugins: + manifests.sdk.operatorframework.io/v2: {} + scorecard.sdk.operatorframework.io/v2: {} +projectName: redkeyoperator +repo: github.com/InditexTech/redkeyoperator +resources: +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: inditex.dev + group: redis + kind: RedkeyCluster + path: github.com/InditexTech/redkeyoperator/api/v1 + version: v1 +version: "3" diff --git a/README.md b/README.md index 3557b4a..d24ac35 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,39 @@ + +
+ +# Redkey Operator + +**Seamless Redkey Cluster Management on Kubernetes** + +[![GitHub License](https://img.shields.io/github/license/InditexTech/redkeyoperator)](LICENSE) +[![GitHub Release](https://img.shields.io/github/v/release/InditexTech/redkeyoperator)](https://github.com/InditexTech/redkeyoperator/releases) +[![Go Version](https://img.shields.io/github/go-mod/go-version/InditexTech/redkeyoperator)](go.mod) +[![Build Status](https://img.shields.io/github/actions/workflow/status/InditexTech/redkeyoperator/ci.yml?branch=main)](https://github.com/InditexTech/redkeyoperator/actions) + +[![Kubernetes](https://img.shields.io/badge/Kubernetes-326CE5?style=flat&logo=kubernetes&logoColor=white)](https://kubernetes.io/) +[![Operator SDK](https://img.shields.io/badge/Operator%20SDK-326CE5?style=flat&logo=kubernetes&logoColor=white)](https://sdk.operatorframework.io/) +[![Go](https://img.shields.io/badge/Go-00ADD8?style=flat&logo=go&logoColor=white)](https://golang.org/) +[![REUSE Compliance](https://img.shields.io/badge/REUSE-compliant-green)](https://reuse.software/) + +[![GitHub Issues](https://img.shields.io/github/issues/InditexTech/redkeyoperator)](https://github.com/InditexTech/redkeyoperator/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/InditexTech/redkeyoperator)](https://github.com/InditexTech/redkeyoperator/pulls) +[![GitHub Stars](https://img.shields.io/github/stars/InditexTech/redkeyoperator?style=social)](https://github.com/InditexTech/redkeyoperator/stargazers) +[![GitHub Forks](https://img.shields.io/github/forks/InditexTech/redkeyoperator?style=social)](https://github.com/InditexTech/redkeyoperator/network/members) + +[🚀 Quick Start](#quick-start) • [📖 Documentation](./docs) • [🤝 Contributing](./CONTRIBUTING.md) • [📝 License](./LICENSE) + ![Redkey Operator icon](docs/images/redkey-logo-50.png) -# Redkey Operator for Kubernetes + +
+ +--- + +## Overview A **Redkey Cluster** is a key/value cluster using either [Redis Official Image](https://hub.docker.com/_/redis) or [Valkey Official Image](https://hub.docker.com/r/valkey/valkey/) images to create its nodes (note that all cluster nodes must use the same image). @@ -14,7 +43,7 @@ This operator implements a controller that extends the Kubernetes API allowing t Redkey operator is built using [kubebuilder](https://github.com/kubernetes-sigs/kubebuilder) and [operator-sdk](https://github.com/operator-framework/operator-sdk). -## Features +## Key Features - Redkey Cluster creation - Cluster scaling up and down @@ -27,6 +56,40 @@ Redkey operator is built using [kubebuilder](https://github.com/kubernetes-sigs/ - Ephemeral cluster (pure cache-like behavior) or using persistence - RedisGraph support +## Quick Start + +Prerrequisites: +- A running Kubernetes cluster (v1.24+) +- kubectl (v1.24+) +- Make + +The operator can be installed using the provided Makefile. The following steps will guide you through the installation and deployment of a sample Redkey Cluster. Redkey Operator can be installed in any namespace, but for this quick start we will use the `redkey-operator` namespace. + +1. Clone the repository to your local machine: + +```bash +git clone https://github.com/InditexTech/redkeyoperator.git +cd redkeyoperator +``` + +2. Generate and install the CRDs: + +```bash +make install +``` + +3. Deploy the operator in the cluster (replace `${VERSION}` with the desired version, e.g., `0.1.0`; check the repo releases for available versions): + +```bash +make deploy IMG=ghcr.io/inditextech/redkey-operator:${VERSION} +``` + +4. Create a Redkey Cluster (replace `${VERSION}` with the desired version, e.g., `0.1.0`; check the [Redkey Robin](https://github.com/InditexTech/redkeyrobin) repo releases for available versions): + +```bash +make apply-rkcl IMG_ROBIN=ghcr.io/inditextech/redkey-robin:${VERSION} +``` + ## Documentation Refer to [operator guide](./docs/operator-guide/toc.md) to have an overview of the main Redis configuration and management options, and a troubleshooting guide. @@ -39,11 +102,15 @@ Discover [Redkey Robin](./docs/redkey-robin.md). The importance of the [purgeKeysOnRebalance](./docs/purge-keys-on-rebalance.md) parameter. +## Contributing + +Contributions are welcome! Please read our [contributing guidelines](./CONTRIBUTING.md) to get started. + ## Versions -- Go version (https://github.com/golang/go): v1.25.6 +- Go version (https://github.com/golang/go): v1.25.7 - Operator SDK version (https://github.com/operator-framework/operator-sdk): v1.42.0 -- Kubernetes Controller Tools version (https://github.com/kubernetes-sigs/controller-tools): v0.20.0 +- Kubernetes Controller Tools version (https://github.com/kubernetes-sigs/controller-tools): v0.18.0 ## License diff --git a/SECURITY.md b/SECURITY.md index 4227d89..d768edb 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,5 +1,5 @@ diff --git a/SUPPORT.md b/SUPPORT.md index 0dbba46..0dc0ca8 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -1,5 +1,5 @@ diff --git a/api/v1/groupversion_info.go b/api/v1/groupversion_info.go index da666ce..38bb147 100644 --- a/api/v1/groupversion_info.go +++ b/api/v1/groupversion_info.go @@ -2,9 +2,9 @@ // // SPDX-License-Identifier: Apache-2.0 -// Package v1 contains API Schema definitions for the redis v1 API group. +// Package v1 contains API Schema definitions for the redkey v1 API group. // +kubebuilder:object:generate=true -// +groupName=redis.inditex.dev +// +groupName=redkey.inditex.dev package v1 import ( @@ -14,7 +14,7 @@ import ( var ( // GroupVersion is group version used to register these objects. - GroupVersion = schema.GroupVersion{Group: "redis.inditex.dev", Version: "v1"} + GroupVersion = schema.GroupVersion{Group: "redkey.inditex.dev", Version: "v1"} // SchemeBuilder is used to add go types to the GroupVersionKind scheme. SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} diff --git a/cmd/main.go b/cmd/main.go index 69e4499..53ba6cd 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -32,7 +32,7 @@ import ( const ( USER_AGENT_NAME = "redkey-cluster-operator" - USER_AGENT_VERSION = "1.3.0" + USER_AGENT_VERSION = "0.1.0" ) var ( diff --git a/config/crd/bases/redis.inditex.dev_redkeyclusters.yaml b/config/crd/bases/redkey.inditex.dev_redkeyclusters.yaml similarity index 99% rename from config/crd/bases/redis.inditex.dev_redkeyclusters.yaml rename to config/crd/bases/redkey.inditex.dev_redkeyclusters.yaml index bfd7261..a709b2e 100644 --- a/config/crd/bases/redis.inditex.dev_redkeyclusters.yaml +++ b/config/crd/bases/redkey.inditex.dev_redkeyclusters.yaml @@ -6,10 +6,10 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.20.0 - name: redkeyclusters.redis.inditex.dev + controller-gen.kubebuilder.io/version: v0.18.0 + name: redkeyclusters.redkey.inditex.dev spec: - group: redis.inditex.dev + group: redkey.inditex.dev names: kind: RedkeyCluster listKind: RedkeyClusterList diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 10a80b0..e36cead 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -5,7 +5,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: -- bases/redis.inditex.dev_redkeyclusters.yaml - -patches: -- path: ./patches/operator-crd-patch.yaml +- bases/redkey.inditex.dev_redkeyclusters.yaml +commonAnnotations: + inditex.dev/operator-version: 0.1.0 diff --git a/config/crd/patches/operator-crd-patch.yaml b/config/crd/patches/operator-crd-patch.yaml deleted file mode 100644 index 4f97f19..0000000 --- a/config/crd/patches/operator-crd-patch.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) -# SPDX-License-Identifier: Apache-2.0 - -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: redkeyclusters.redis.inditex.dev - annotations: - inditex.dev/operator-version: 0.2.40 diff --git a/config/examples/ephemeral-robin-debug/kustomization.yml b/config/examples/ephemeral-robin-debug/kustomization.yml index fee4200..3e0bd87 100644 --- a/config/examples/ephemeral-robin-debug/kustomization.yml +++ b/config/examples/ephemeral-robin-debug/kustomization.yml @@ -11,6 +11,6 @@ patches: name: redis-cluster-ephemeral resources: - - redis_v1_redkeycluster-ephemeral.yaml + - redkey_v1_redkeycluster-ephemeral.yaml namespace: redkey-operator \ No newline at end of file diff --git a/config/examples/ephemeral-robin-debug/redis_v1_redkeycluster-ephemeral.yaml b/config/examples/ephemeral-robin-debug/redkey_v1_redkeycluster-ephemeral.yaml similarity index 99% rename from config/examples/ephemeral-robin-debug/redis_v1_redkeycluster-ephemeral.yaml rename to config/examples/ephemeral-robin-debug/redkey_v1_redkeycluster-ephemeral.yaml index e4ff76d..8de6916 100644 --- a/config/examples/ephemeral-robin-debug/redis_v1_redkeycluster-ephemeral.yaml +++ b/config/examples/ephemeral-robin-debug/redkey_v1_redkeycluster-ephemeral.yaml @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) # SPDX-License-Identifier: Apache-2.0 -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: labels: diff --git a/config/examples/ephemeral-robin-dev/kustomization.yaml b/config/examples/ephemeral-robin-dev/kustomization.yaml index af66cdd..41d4bc6 100644 --- a/config/examples/ephemeral-robin-dev/kustomization.yaml +++ b/config/examples/ephemeral-robin-dev/kustomization.yaml @@ -5,6 +5,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - - redis_v1_redkeycluster-ephemeral.yaml + - redkey_v1_redkeycluster-ephemeral.yaml namespace: redkey-operator diff --git a/config/examples/ephemeral-robin-dev/redis_v1_redkeycluster-ephemeral.yaml b/config/examples/ephemeral-robin-dev/redkey_v1_redkeycluster-ephemeral.yaml similarity index 99% rename from config/examples/ephemeral-robin-dev/redis_v1_redkeycluster-ephemeral.yaml rename to config/examples/ephemeral-robin-dev/redkey_v1_redkeycluster-ephemeral.yaml index e4ff76d..8de6916 100644 --- a/config/examples/ephemeral-robin-dev/redis_v1_redkeycluster-ephemeral.yaml +++ b/config/examples/ephemeral-robin-dev/redkey_v1_redkeycluster-ephemeral.yaml @@ -1,7 +1,7 @@ # SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) # SPDX-License-Identifier: Apache-2.0 -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: labels: diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 7967cf4..634fa18 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -16,5 +16,3 @@ configMapGenerator: apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization - - diff --git a/config/manifests/bases/redkeyoperator.clusterserviceversion.yaml b/config/manifests/bases/redkeyoperator.clusterserviceversion.yaml new file mode 100644 index 0000000..cb2af29 --- /dev/null +++ b/config/manifests/bases/redkeyoperator.clusterserviceversion.yaml @@ -0,0 +1,111 @@ +# SPDX-FileCopyrightText: 2025 INDUSTRIA DE DISEÑO TEXTIL S.A. (INDITEX S.A.) +# SPDX-License-Identifier: Apache-2.0 + +apiVersion: operators.coreos.com/v1alpha1 +kind: ClusterServiceVersion +metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "redkey.inditex.dev/v1", + "kind": "RedkeyCluster", + "metadata": { + "name": "redis-cluster-example" + }, + "spec": { + "primaries": 3, + "ephemeral": true, + "accessModes": ["ReadWriteOnce"], + "image": "redis:8-bookworm", + "purgeKeysOnRebalance": true, + "resources": { + "limits": { + "cpu": "100m", + "memory": "128Mi" + } + } + } + } + ] + capabilities: Auto Pilot + categories: Database + name: redkeyoperator.v0.0.0 + namespace: placeholder +spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - description: RedkeyCluster is the Schema for the redkeyclusters API + displayName: Redkey Cluster + kind: RedkeyCluster + name: redkeyclusters.redkey.inditex.dev + specDescriptors: + - description: ReplicasPerPrimary specifies how many replicas should be attached + to each Redis Primary node + displayName: Number of replicas per Primary Node + path: replicasPerPrimary + version: v1 + description: | + Seamless Redkey Cluster Management on Kubernetes. + + The Redkey Operator simplifies the deployment and management of Redis/Valkey clusters on Kubernetes. It automates tasks such as scaling, failover, and configuration management, allowing you to focus on your applications while ensuring high availability and performance for your Redis instances. + + ### Documentation + + [Quick Start](https://github.com/InditexTech/redkeyoperator/tree/main?tab=readme-ov-file#quick-start) + + Refer to the [operator guide](https://github.com/InditexTech/redkeyoperator/blob/main/docs/operator-guide/toc.md) to have an overview of the main Redis configuration and management options, and a troubleshooting guide. + + If you are a developer, you'll find interesting information in the [developer guide](https://github.com/InditexTech/redkeyoperator/blob/main/docs/developer-guide/toc.md). + + ### Contributing + + Contributions are welcome! Please read our [contributing guidelines](https://github.com/InditexTech/redkeyoperator/blob/main/CONTRIBUTING.md) to get started. + + ### License + + This project is licensed under the Apache License 2.0 - see the [LICENSE](https://github.com/InditexTech/redkeyoperator/blob/main/LICENSE) file for details. + displayName: Redkey Operator + icon: + - base64data: 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 + mediatype: image/png + install: + spec: + deployments: null + strategy: "" + installModes: + - supported: false + type: OwnNamespace + - supported: false + type: SingleNamespace + - supported: false + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - redis + - valkey + - cluster + - real-time-data + - kubernetes + - k8s + - ocp + links: + - name: Redkey Operator Documentation + url: https://github.com/InditexTech/redkeyoperator/tree/main/docs + - name: Redkey Operator Source Code + url: https://github.com/InditexTech/redkeyoperator + - name: Redkey Robin Documentation + url: https://github.com/InditexTech/redkeyrobin/tree/main/docs + - name: Redkey Robin Source Code + url: https://github.com/InditexTech/redkeyrobin + maintainers: + - email: lddpaas@inditex.com + name: Inditex PaaS Team + maturity: alpha + minKubeVersion: 1.24.0 + provider: + name: InditexTech + url: https://github.com/InditexTech + version: 0.0.0 diff --git a/config/rbac/bases/clusterrole.yaml b/config/rbac/bases/clusterrole.yaml index 50e28a3..3699d26 100644 --- a/config/rbac/bases/clusterrole.yaml +++ b/config/rbac/bases/clusterrole.yaml @@ -68,7 +68,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -80,13 +80,13 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/finalizers verbs: - update - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/config/rbac/bases/redkeycluster_editor_role.yaml b/config/rbac/bases/redkeycluster_editor_role.yaml index f88a210..d35bc4f 100644 --- a/config/rbac/bases/redkeycluster_editor_role.yaml +++ b/config/rbac/bases/redkeycluster_editor_role.yaml @@ -10,7 +10,7 @@ metadata: rbac.authorization.k8s.io/aggregate-to-admin: "true" rules: - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -22,7 +22,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/config/rbac/bases/redkeycluster_viewer_role.yaml b/config/rbac/bases/redkeycluster_viewer_role.yaml index 406ff6c..08d4860 100644 --- a/config/rbac/bases/redkeycluster_viewer_role.yaml +++ b/config/rbac/bases/redkeycluster_viewer_role.yaml @@ -10,7 +10,7 @@ metadata: rbac.authorization.k8s.io/aggregate-to-admin: "true" rules: - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -18,7 +18,7 @@ rules: - list - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/config/rbac/bases/role.yaml b/config/rbac/bases/role.yaml index 5098924..c4a2281 100644 --- a/config/rbac/bases/role.yaml +++ b/config/rbac/bases/role.yaml @@ -77,7 +77,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -89,13 +89,13 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/finalizers verbs: - update - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/config/rbac/rediscluster_editor_role.yaml b/config/rbac/rediscluster_editor_role.yaml index 6fa86af..51caf4f 100644 --- a/config/rbac/rediscluster_editor_role.yaml +++ b/config/rbac/rediscluster_editor_role.yaml @@ -23,7 +23,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/config/rbac/rediscluster_viewer_role.yaml b/config/rbac/rediscluster_viewer_role.yaml index 56a0ea3..428b6e9 100644 --- a/config/rbac/rediscluster_viewer_role.yaml +++ b/config/rbac/rediscluster_viewer_role.yaml @@ -11,7 +11,7 @@ metadata: name: redkeycluster-viewer-role rules: - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -19,7 +19,7 @@ rules: - list - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/controllers/redkeycluster_reconciler.go b/controllers/redkeycluster_reconciler.go index 634514f..32b3d83 100644 --- a/controllers/redkeycluster_reconciler.go +++ b/controllers/redkeycluster_reconciler.go @@ -46,9 +46,9 @@ type RedkeyClusterReconciler struct { FindExistingPodDisruptionBudgetFunc func(ctx context.Context, req ctrl.Request) (*pv1.PodDisruptionBudget, error) } -// +kubebuilder:rbac:groups=redis.inditex.dev,resources=redkeyclusters,verbs=get;list;watch;create;update;patch;delete -// +kubebuilder:rbac:groups=redis.inditex.dev,resources=redkeyclusters/status,verbs=get;update;patch -// +kubebuilder:rbac:groups=redis.inditex.dev,resources=redkeyclusters/finalizers,verbs=update +// +kubebuilder:rbac:groups=redkey.inditex.dev,resources=redkeyclusters,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=redkey.inditex.dev,resources=redkeyclusters/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=redkey.inditex.dev,resources=redkeyclusters/finalizers,verbs=update // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch // +kubebuilder:rbac:groups="",resources=secrets,verbs=get // +kubebuilder:rbac:groups=apps,resources=statefulsets;deployments,verbs=get;list;watch diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 8a5447c..9b4d1df 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -233,7 +233,7 @@ func CreateRedkeyCluster() *redkeyv1.RedkeyCluster { cluster := &redkeyv1.RedkeyCluster{ TypeMeta: metav1.TypeMeta{ Kind: "RedkeyCluster", - APIVersion: "redis.inditex.dev/redisv1", + APIVersion: "redkey.inditex.dev/redisv1", }, ObjectMeta: metav1.ObjectMeta{ Name: "redkeycluster-sample", diff --git a/debug.Dockerfile b/debug.Dockerfile index 7ccad12..3a8e1c2 100644 --- a/debug.Dockerfile +++ b/debug.Dockerfile @@ -3,7 +3,7 @@ # SPDX-License-Identifier: Apache-2.0 # Define the desired Golang version -ARG GOLANG_VERSION=1.25.6 +ARG GOLANG_VERSION=1.25.7 # Use an official Golang image with a specific version based on Debian FROM golang:${GOLANG_VERSION}-trixie diff --git a/docs/developer-guide/development-guide.md b/docs/developer-guide/development-guide.md index b8b1f63..5da7a9d 100644 --- a/docs/developer-guide/development-guide.md +++ b/docs/developer-guide/development-guide.md @@ -1,5 +1,5 @@ @@ -59,7 +59,7 @@ make install make deploy ``` -3. Deploy an example Redkey Cluster from `config/examples` folder. Just so you know, a Redkey Robin image is required; for example, see [Redkey Robin](https://github.com/InditexTech/redkeyrobin). +3. Deploy an example Redkey Cluster from `config/examples` folder. Just so you know, a Redkey Robin image is required; to know how it can be built, see [Redkey Robin](https://github.com/InditexTech/redkeyrobin). ```shell # Create a rkcl/redis-cluster-ephemeral: 3 nodes, ephemeral: true and purgeKeysOnRebalance: true. diff --git a/docs/developer-guide/profiling-guide.md b/docs/developer-guide/profiling-guide.md index db29ea3..3625677 100644 --- a/docs/developer-guide/profiling-guide.md +++ b/docs/developer-guide/profiling-guide.md @@ -1,5 +1,5 @@ diff --git a/docs/developer-guide/toc.md b/docs/developer-guide/toc.md index fd506ec..52fbfae 100644 --- a/docs/developer-guide/toc.md +++ b/docs/developer-guide/toc.md @@ -1,5 +1,5 @@ diff --git a/docs/images/redkey-logo-50.png b/docs/images/redkey-logo-50.png index a5ca28f..7ffc5ba 100644 Binary files a/docs/images/redkey-logo-50.png and b/docs/images/redkey-logo-50.png differ diff --git a/docs/operator-guide/backup-configuration.md b/docs/operator-guide/backup-configuration.md index 522c5d1..fc533a1 100644 --- a/docs/operator-guide/backup-configuration.md +++ b/docs/operator-guide/backup-configuration.md @@ -1,5 +1,5 @@ diff --git a/docs/operator-guide/delete-pvc.md b/docs/operator-guide/delete-pvc.md index 647f76d..d3c3015 100644 --- a/docs/operator-guide/delete-pvc.md +++ b/docs/operator-guide/delete-pvc.md @@ -1,5 +1,5 @@ @@ -21,7 +21,7 @@ Starting with Redkey Operator release 0.2.33, Redkey Operator supports deletion ## Example ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: diff --git a/docs/operator-guide/ephemeral-cluster.md b/docs/operator-guide/ephemeral-cluster.md index c4bd716..98c28b5 100644 --- a/docs/operator-guide/ephemeral-cluster.md +++ b/docs/operator-guide/ephemeral-cluster.md @@ -1,5 +1,5 @@ @@ -13,7 +13,7 @@ Ephemeral mode, also known as Zero Persistent Volume Claims (PVCs), disables per For a new cluster configuration, set the property `ephemeral: true` and apply the configuration. See the following snippet: ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: name: redis-cluster diff --git a/docs/operator-guide/operator-deployment.md b/docs/operator-guide/operator-deployment.md index 8d1efc0..f550f33 100644 --- a/docs/operator-guide/operator-deployment.md +++ b/docs/operator-guide/operator-deployment.md @@ -1,5 +1,5 @@ diff --git a/docs/operator-guide/primary-replica-cluster.md b/docs/operator-guide/primary-replica-cluster.md index 78afee0..f4ed706 100644 --- a/docs/operator-guide/primary-replica-cluster.md +++ b/docs/operator-guide/primary-replica-cluster.md @@ -1,5 +1,5 @@ @@ -13,7 +13,7 @@ Clusters with primary-replica architecture can be created by adding `replciasPer The minimum configuration for the correct operation of this function is: ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -27,7 +27,7 @@ The `primaries` definition is the total number of Redis primary nodes in the clu If this feature is enabled, this additional configuration should be added to `redis.conf` to improve efficiency. ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -48,7 +48,7 @@ spec: ## Examples ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -61,7 +61,7 @@ spec: Redkey Operator will create 6 pods, 3 primaries and 3 replicas (one for each primary). ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -73,7 +73,7 @@ spec: Redkey Operator will create 15 pods, 5 primaries and 10 replicas (two for each primary). ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -85,7 +85,7 @@ spec: Redkey Operator will create 5 pods, 5 primaries and no replicas. ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: diff --git a/docs/operator-guide/redis-deployment.md b/docs/operator-guide/redis-deployment.md index 6634fdc..7910950 100644 --- a/docs/operator-guide/redis-deployment.md +++ b/docs/operator-guide/redis-deployment.md @@ -1,5 +1,5 @@ @@ -13,7 +13,7 @@ Redkey operator CRD defines a new resource type `RedkeyCluster`. Below you'll find an example of manifest conforming to the resource definition that will deploy a Redkey cluster: ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: name: redkeycluster-sample diff --git a/docs/operator-guide/robin.md b/docs/operator-guide/robin.md index bf65b44..1c00ab8 100644 --- a/docs/operator-guide/robin.md +++ b/docs/operator-guide/robin.md @@ -1,5 +1,5 @@ @@ -25,7 +25,7 @@ to the Pod IP is needed for Robin to work. ### Example ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: @@ -83,7 +83,7 @@ The expected fields of the `spec.robin.config` YAML are: ### Example ```yaml -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster ... spec: diff --git a/docs/operator-guide/toc.md b/docs/operator-guide/toc.md index 14b8bc2..a796ab7 100644 --- a/docs/operator-guide/toc.md +++ b/docs/operator-guide/toc.md @@ -1,5 +1,5 @@ diff --git a/docs/operator-guide/troubleshooting.md b/docs/operator-guide/troubleshooting.md index 48a7612..871100e 100644 --- a/docs/operator-guide/troubleshooting.md +++ b/docs/operator-guide/troubleshooting.md @@ -1,5 +1,5 @@ diff --git a/docs/purge-keys-on-rebalance.md b/docs/purge-keys-on-rebalance.md index 4ac186e..71e3590 100644 --- a/docs/purge-keys-on-rebalance.md +++ b/docs/purge-keys-on-rebalance.md @@ -1,5 +1,5 @@ diff --git a/docs/redkey-cluster-status.md b/docs/redkey-cluster-status.md index d39c8da..eefcec6 100644 --- a/docs/redkey-cluster-status.md +++ b/docs/redkey-cluster-status.md @@ -1,5 +1,5 @@ diff --git a/docs/redkey-robin.md b/docs/redkey-robin.md index facc854..5dfb8f7 100644 --- a/docs/redkey-robin.md +++ b/docs/redkey-robin.md @@ -1,5 +1,5 @@ diff --git a/go.mod b/go.mod index 938f242..8546886 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 module github.com/inditextech/redkeyoperator -go 1.25.6 +go 1.25.7 require ( github.com/go-logr/logr v1.4.2 @@ -17,11 +17,12 @@ require ( k8s.io/apimachinery v0.33.0 k8s.io/client-go v0.33.0 k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e - sigs.k8s.io/controller-runtime v0.20.4 + sigs.k8s.io/controller-runtime v0.21.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect diff --git a/go.sum b/go.sum index efe1835..c966df5 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -186,8 +188,8 @@ k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUy k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro= k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= -sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= diff --git a/internal/finalizers/backup.go b/internal/finalizers/backup.go index ccf8209..b7412ca 100644 --- a/internal/finalizers/backup.go +++ b/internal/finalizers/backup.go @@ -20,5 +20,5 @@ func (ef *BackupFinalizer) DeleteMethod(ctx context.Context, redis *redkeyv1.Red } func (ef *BackupFinalizer) GetId() string { - return "redis.inditex.dev/rdb-backup" + return "redkey.inditex.dev/rdb-backup" } diff --git a/internal/finalizers/configmap.go b/internal/finalizers/configmap.go index 9a89786..1668e64 100644 --- a/internal/finalizers/configmap.go +++ b/internal/finalizers/configmap.go @@ -25,5 +25,5 @@ func (ef *ConfigMapCleanupFinalizer) DeleteMethod(ctx context.Context, redis *re } func (ef *ConfigMapCleanupFinalizer) GetId() string { - return "redis.inditex.dev/configmap-cleanup" + return "redkey.inditex.dev/configmap-cleanup" } diff --git a/internal/finalizers/delete_pvc.go b/internal/finalizers/delete_pvc.go index 852dfc0..31e4bc6 100644 --- a/internal/finalizers/delete_pvc.go +++ b/internal/finalizers/delete_pvc.go @@ -22,5 +22,5 @@ func (ef *DeletePVCFinalizer) DeleteMethod(ctx context.Context, redis *redkeyv1. } func (ef *DeletePVCFinalizer) GetId() string { - return "redis.inditex.dev/delete-pvc" + return "redkey.inditex.dev/delete-pvc" } diff --git a/test/cmd/manifests/deployment-test-local/deployment-operator-local.yaml b/test/cmd/manifests/deployment-test-local/deployment-operator-local.yaml index 5a221ac..b12ba26 100644 --- a/test/cmd/manifests/deployment-test-local/deployment-operator-local.yaml +++ b/test/cmd/manifests/deployment-test-local/deployment-operator-local.yaml @@ -109,7 +109,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -121,13 +121,13 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/finalizers verbs: - update - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: @@ -201,7 +201,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -213,13 +213,13 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/finalizers verbs: - update - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: @@ -235,7 +235,7 @@ metadata: name: redkeycluster-editor-role rules: - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters verbs: @@ -247,7 +247,7 @@ rules: - update - watch - apiGroups: - - redis.inditex.dev + - redkey.inditex.dev resources: - redkeyclusters/status verbs: diff --git a/test/cmd/manifests/rdcl-test-local.yml b/test/cmd/manifests/rdcl-test-local.yml index a3fb0ad..0798842 100644 --- a/test/cmd/manifests/rdcl-test-local.yml +++ b/test/cmd/manifests/rdcl-test-local.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: annotations: diff --git a/test/cmd/manifests/rdcl-test-loki-local.yml b/test/cmd/manifests/rdcl-test-loki-local.yml index 543e5cc..4891bd0 100644 --- a/test/cmd/manifests/rdcl-test-loki-local.yml +++ b/test/cmd/manifests/rdcl-test-loki-local.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: annotations: diff --git a/test/cmd/manifests/rdcl-test-size-local.yml b/test/cmd/manifests/rdcl-test-size-local.yml index d4bd1f4..3f65a9e 100644 --- a/test/cmd/manifests/rdcl-test-size-local.yml +++ b/test/cmd/manifests/rdcl-test-size-local.yml @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: Apache-2.0 -apiVersion: redis.inditex.dev/v1 +apiVersion: redkey.inditex.dev/v1 kind: RedkeyCluster metadata: annotations: diff --git a/test/e2e/framework/redisclient.go b/test/e2e/framework/redisclient.go index e374a74..5acfb0b 100644 --- a/test/e2e/framework/redisclient.go +++ b/test/e2e/framework/redisclient.go @@ -45,7 +45,7 @@ const ( defaultConfig = `save "" appendonly no maxmemory 70mb` - finalizerName = "redis.inditex.dev/configmap-cleanup" + finalizerName = "redkey.inditex.dev/configmap-cleanup" pollInterval = 5 * time.Second defaultTimeout = 60 * time.Minute diff --git a/test/e2e/operator_test.go b/test/e2e/operator_test.go index 9f326c3..aa728b3 100644 --- a/test/e2e/operator_test.go +++ b/test/e2e/operator_test.go @@ -207,17 +207,17 @@ func operatorPolicyRules() []rbacv1.PolicyRule { Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, }, { - APIGroups: []string{"redis.inditex.dev"}, + APIGroups: []string{"redkey.inditex.dev"}, Resources: []string{"redkeyclusters"}, Verbs: []string{"create", "delete", "get", "list", "patch", "update", "watch"}, }, { - APIGroups: []string{"redis.inditex.dev"}, + APIGroups: []string{"redkey.inditex.dev"}, Resources: []string{"redkeyclusters/finalizers"}, Verbs: []string{"update"}, }, { - APIGroups: []string{"redis.inditex.dev"}, + APIGroups: []string{"redkey.inditex.dev"}, Resources: []string{"redkeyclusters/status"}, Verbs: []string{"get", "patch", "update"}, }, diff --git a/v1client/client.go b/v1client/client.go index d93a53b..eb733f2 100644 --- a/v1client/client.go +++ b/v1client/client.go @@ -31,7 +31,7 @@ func (c *rkclClient) List(ctx context.Context, opts metav1.ListOptions) (*redkey result := redkeyv1.RedkeyClusterList{} err := c.restClient. Get(). - AbsPath("/apis/redis.inditex.dev/redisv1"). + AbsPath("/apis/redkey.inditex.dev/redisv1"). Namespace(c.ns). Resource("redkeyclusters"). VersionedParams(&opts, scheme.ParameterCodec). @@ -45,7 +45,7 @@ func (c *rkclClient) Get(ctx context.Context, name string, opts metav1.GetOption result := redkeyv1.RedkeyCluster{} err := c.restClient. Get(). - AbsPath("/apis/redis.inditex.dev/v1"). + AbsPath("/apis/redkey.inditex.dev/v1"). Namespace(c.ns). Resource("redkeyclusters"). Name(name). @@ -58,7 +58,7 @@ func (c *rkclClient) Get(ctx context.Context, name string, opts metav1.GetOption func (c *rkclClient) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { opts.Watch = true return c.restClient.Get(). - AbsPath("/apis/redis.inditex.dev/v1"). + AbsPath("/apis/redkey.inditex.dev/v1"). Namespace(c.ns). Resource("redkeyclusters"). VersionedParams(&opts, scheme.ParameterCodec).