Compare commits
17 Commits
65668934a8
...
aa83379dd3
Author | SHA1 | Date |
---|---|---|
|
aa83379dd3 | |
|
adbef3c3fd | |
|
e4faaeb5b7 | |
|
809d48e57e | |
|
e1004c0352 | |
|
afd663611c | |
|
a2f7243c7f | |
|
6d294f5cbe | |
|
ed95c2c660 | |
|
fefd300cb9 | |
|
cc0c9b0f92 | |
|
6d2ec60c8e | |
|
aa8d2d9cf1 | |
|
a8ab85d4fa | |
|
d17ea8b4bf | |
|
4a41f558dc | |
|
321cc1d498 |
|
@ -29,10 +29,15 @@ jobs:
|
||||||
go-version: ${{ env.GOLANG_VERSION }}
|
go-version: ${{ env.GOLANG_VERSION }}
|
||||||
cache: false
|
cache: false
|
||||||
|
|
||||||
|
- name: Get golangci-lint version from Makefile
|
||||||
|
run: |
|
||||||
|
GOLANGCI_VERSION=$(grep '^GOLANGCI_LINT_VERSION' Makefile | cut -d'=' -f2 | tr -d ' ?')
|
||||||
|
echo "GOLANGCI_LINT_VERSION=$GOLANGCI_VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Run GolangCI-Lint
|
- name: Run GolangCI-Lint
|
||||||
uses: golangci/golangci-lint-action@v6
|
uses: golangci/golangci-lint-action@v8
|
||||||
with:
|
with:
|
||||||
version: v1.62.2
|
version: ${{ env.GOLANGCI_LINT_VERSION }}
|
||||||
|
|
||||||
gotest:
|
gotest:
|
||||||
needs:
|
needs:
|
||||||
|
@ -212,7 +217,7 @@ jobs:
|
||||||
- name: Build Dockerfile
|
- name: Build Dockerfile
|
||||||
run: docker build . --file Dockerfile --tag redis-operator:e2e
|
run: docker build . --file Dockerfile --tag redis-operator:e2e
|
||||||
- name: Install Cosign
|
- name: Install Cosign
|
||||||
uses: sigstore/cosign-installer@v3.9.1
|
uses: sigstore/cosign-installer@v3.9.2
|
||||||
- name: Install chainsaw
|
- name: Install chainsaw
|
||||||
uses: kyverno/action-install-chainsaw@v0.2.12
|
uses: kyverno/action-install-chainsaw@v0.2.12
|
||||||
with:
|
with:
|
||||||
|
@ -233,11 +238,14 @@ jobs:
|
||||||
|
|
||||||
# NOTE: This is a workaround for the issue where the default storage class does not support volume expansion.
|
# NOTE: This is a workaround for the issue where the default storage class does not support volume expansion.
|
||||||
# Since we don't require PVC resizing (unlike physical disks), we can simply ensure that the requested PVC size is met.
|
# Since we don't require PVC resizing (unlike physical disks), we can simply ensure that the requested PVC size is met.
|
||||||
- name: Set allowVolumeExpansion to true
|
- name: Setup k8s Kind Cluster
|
||||||
run: |
|
run: |
|
||||||
DEFAULT_SC=$(kubectl get storageclass -o=jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}')
|
DEFAULT_SC=$(kubectl get storageclass -o=jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}')
|
||||||
kubectl patch storageclass $DEFAULT_SC -p '{"allowVolumeExpansion": true}'
|
kubectl patch storageclass $DEFAULT_SC -p '{"allowVolumeExpansion": true}'
|
||||||
|
|
||||||
|
# install cert-manager
|
||||||
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml
|
||||||
|
|
||||||
- name: Load Docker image into Kind
|
- name: Load Docker image into Kind
|
||||||
run: |
|
run: |
|
||||||
kubectl cluster-info --context kind-kind
|
kubectl cluster-info --context kind-kind
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
linters-settings:
|
version: "2"
|
||||||
gofmt:
|
run:
|
||||||
simplify: true
|
go: 1.23.4
|
||||||
|
tests: true
|
||||||
linters:
|
linters:
|
||||||
enable:
|
enable:
|
||||||
- asasalint
|
- asasalint
|
||||||
|
@ -12,38 +12,43 @@ linters:
|
||||||
- decorder
|
- decorder
|
||||||
- dogsled
|
- dogsled
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- errcheck
|
|
||||||
- errname
|
- errname
|
||||||
- gci
|
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- gofmt
|
|
||||||
- gofumpt
|
|
||||||
- goprintffuncname
|
- goprintffuncname
|
||||||
- gosimple
|
|
||||||
- govet
|
|
||||||
- grouper
|
- grouper
|
||||||
- importas
|
- importas
|
||||||
- ineffassign
|
|
||||||
- makezero
|
- makezero
|
||||||
- misspell
|
- misspell
|
||||||
- noctx
|
- noctx
|
||||||
- nolintlint
|
- nolintlint
|
||||||
- nosprintfhostport
|
- nosprintfhostport
|
||||||
- staticcheck
|
|
||||||
- tenv
|
|
||||||
- thelper
|
- thelper
|
||||||
- tparallel
|
- tparallel
|
||||||
- unconvert
|
- unconvert
|
||||||
- unused
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
- whitespace
|
||||||
|
exclusions:
|
||||||
run:
|
generated: lax
|
||||||
timeout: 15m
|
presets:
|
||||||
go: "1.23.4"
|
- comments
|
||||||
tests: true
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
output:
|
- std-error-handling
|
||||||
sort-results: true
|
paths:
|
||||||
print-linter-name: true
|
- third_party$
|
||||||
print-issued-lines: true
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
enable:
|
||||||
|
- gci
|
||||||
|
- gofmt
|
||||||
|
- gofumpt
|
||||||
|
settings:
|
||||||
|
gofmt:
|
||||||
|
simplify: true
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
|
|
@ -2,7 +2,7 @@ extends: default
|
||||||
|
|
||||||
rules:
|
rules:
|
||||||
line-length:
|
line-length:
|
||||||
max: 200
|
max: 300
|
||||||
level: warning
|
level: warning
|
||||||
allow-non-breakable-words: true
|
allow-non-breakable-words: true
|
||||||
allow-non-breakable-inline-mappings: true
|
allow-non-breakable-inline-mappings: true
|
||||||
|
|
226
CHANGELOG.md
226
CHANGELOG.md
|
@ -1,5 +1,229 @@
|
||||||
|
### v0.21.0
|
||||||
|
##### June 2025 Latest
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Round robin where to transfer cluster shards when scaling in a Redis Cluster #1412
|
||||||
|
- Add auto max memory configuration for Redis instances #1411
|
||||||
|
- Add bus port configuration for Redis cluster services #1406
|
||||||
|
- Add automatic Redis pod role label synchronization for rediscluster #1404
|
||||||
|
- RedisCluster observability #1392
|
||||||
|
- Add liveness/readiness probes to values.yaml and templates #1378
|
||||||
|
- Reduce unnecessary requeue when skip reconcile annotation exists #1374
|
||||||
|
- RedisReplication observability, skip reconcile or not #1369
|
||||||
|
- Add Redis Sentinel validation webhook for clusterSize #1361
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Resolve StatefulSet selector immutability issues #1382
|
||||||
|
- Avoid sentinel restart after replication failover #1381
|
||||||
|
- Define named probe port outside webhook block #1354
|
||||||
|
|
||||||
|
#### :tada: Refactors
|
||||||
|
|
||||||
|
- Reorganize manager agent cmd package #1383
|
||||||
|
- Reorganize API structure and update paths #1363
|
||||||
|
- Remove useless structure and refactor package #1362
|
||||||
|
- Reorganize command structure for Redis operator #1351
|
||||||
|
|
||||||
|
### v0.20.2
|
||||||
|
##### May 12, 2024
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Handle panic when retrieving StatefulSet in GetRedisNodesByRole #1330
|
||||||
|
- VCT resize detection logic; add support for scaling out with new VCT size #1342
|
||||||
|
- Service updated before Statefulset during Reconciliation #1348
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Add data assertion generation and enhance Redis configuration commands #1331
|
||||||
|
- Add feature gates support for Redis Operator #1333
|
||||||
|
- Migrate kubebuilder go.kubebuilder.io/v3 to go.kubebuilder.io/v4 #1340
|
||||||
|
|
||||||
|
#### :tada: Refactors
|
||||||
|
|
||||||
|
- Define container port for http probes in operator chart #1326
|
||||||
|
- Enhance environment variable management and CI workflow #1315
|
||||||
|
|
||||||
|
### v0.20.1
|
||||||
|
##### April 27, 2024
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Move VCT logic before diff calculation for stateful set #1322
|
||||||
|
|
||||||
|
### v0.20.0
|
||||||
|
##### April 1, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Sentinel - support hostname resolve and announce #1247
|
||||||
|
- Add redis agent with bootstrap configuration generation #1254
|
||||||
|
- Implement comprehensive Redis configuration generation for agent bootstrap #1260
|
||||||
|
- Added support for hostport to allow direct connection to the pod #1263
|
||||||
|
- Add preStop hook for Redis Cluster failover #1264
|
||||||
|
- Sentinel - announce-ip when resolve & announce are set #1271
|
||||||
|
- Fix PVC resizing issue and refactor PVC resizing logic #1268
|
||||||
|
- Add redisreplication observability #1274
|
||||||
|
- Add recreate-stateful-strategy, orphan, background, foreground(default) #1286
|
||||||
|
- Update Dockerfile and Makefile for unified operator binary #1294
|
||||||
|
- Add support for anti affinity configuration in helm charts #1296
|
||||||
|
- Guarantee to avoid bad master ip on Sentinel #1289
|
||||||
|
- Add feature gates for sentinel configuration generation in init container #1300
|
||||||
|
- Support redis configuration generation in init container #1303
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Replace hardcoded Redis port 6379 with configurable port from cr.Spec.Port #1261
|
||||||
|
- Update references from master to main in docs and workflow files #1288
|
||||||
|
- Svc finalizer removed #1297
|
||||||
|
- Race condition resulting in permanently broken Redis cluster #1298
|
||||||
|
|
||||||
|
### v0.19.1
|
||||||
|
##### February 19, 2024
|
||||||
|
|
||||||
|
#### :warning: Deprecation Notice
|
||||||
|
|
||||||
|
The v1beta1 API version will be removed in next release. Users are strongly encouraged to migrate to v1beta2, which offers enhanced features and improved stability.
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Add data-assert tool for Redis data management #1204
|
||||||
|
- Check data consistent by external tool #1205
|
||||||
|
- Added actions to publish charts to github container registry #1201
|
||||||
|
- Add headless service configuration support #1219
|
||||||
|
- Update redis-operator cert manager configuration #1220
|
||||||
|
- Add additional service configuration with optional enable flag #1228
|
||||||
|
- Enhance Redis HA and node scheduling strategy #1237
|
||||||
|
- Add securityContext config in chart for redis-exporter #1238
|
||||||
|
- Add dynamic Redis configuration support for Redis Cluster #1241
|
||||||
|
- Configurable operator maxConcurrentReconciles #1242
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Skip-reconcile annotation still skipping reconcile even the value is false #1202
|
||||||
|
- Make recreate statefulset only trigger when value true #1240
|
||||||
|
- Improve pod label patching with error handling and retry mechanism #1231
|
||||||
|
- Changed certificate serverName to pod+namespace #1221
|
||||||
|
- Add missing topologySpreadConstraint on RedisCluster follower #1218
|
||||||
|
|
||||||
|
### v0.19.0
|
||||||
|
##### January 12, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Add PDB and probes, drop unspecified acl in sentinel helm #1123
|
||||||
|
- Add master/replica service to redis replication #1124
|
||||||
|
- Add recreateStatefulSetOnUpdateInvalid helm chart value #1127
|
||||||
|
- Enhance RedisReplication controller and CRD with additional status #1154
|
||||||
|
- Support PDB in redisreplication #1166
|
||||||
|
- Enhance RedisSentinel reconciliation logic and update workflow #1176
|
||||||
|
- Support redis-cluster topologySpreadConstraints #1177
|
||||||
|
- Add event recording functionality for RedisCluster controller #1182
|
||||||
|
- Support topologySpreadConstraints in replication & sentinel #1184
|
||||||
|
- Redis-cluster add podAntiAffinity #1180
|
||||||
|
- Separate resources section for leader and follower #1188
|
||||||
|
- Enhance RedisCluster resource management by introducing separate resource handling for leader and follower #1199
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- PDB value mapping in redis-sentinel #1136
|
||||||
|
- Chart render error when enable initcontainer #1146
|
||||||
|
- InitContainer enabled properties not define in template #1152
|
||||||
|
- Redis-cluster unexpected downscaling #1173
|
||||||
|
- Reduce the impact of Redis cluster intermediate states #1178
|
||||||
|
- Label selector mapping on redisreplication pdb #1191
|
||||||
|
|
||||||
|
### v0.18.1
|
||||||
|
##### November 7, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Support setting minReadySeconds on the stateful sets #1023
|
||||||
|
- Add tolerations to operator chart #1051
|
||||||
|
- Add image pull secret for redis operator #1053
|
||||||
|
- Add service monitor to redis sentinel chart #1071
|
||||||
|
- Add readiness/liveness probe to redis operator chart #1072
|
||||||
|
- Upgrade redis/sentinel image to 7.0.15 #1099
|
||||||
|
- Reconcile redissentinel only on master changed #1122
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Fix indentation error when enable additional config #1031
|
||||||
|
- Fix field validate error when enable additional config for sentinel #1033
|
||||||
|
- Fix unknown field error when upgrade chart #1034
|
||||||
|
- Fix bad indentation on redis standalone additional configs #1040
|
||||||
|
- Fix attempt to repair disconnected/failed master nodes before failing over #1105
|
||||||
|
- Fix set controller probe endpoint handler #1121
|
||||||
|
|
||||||
|
### v0.18.0
|
||||||
|
##### July 11, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Added redisReplicationPassword values to connect secured replication #1021
|
||||||
|
- Added redis/redisreplication/redissentinel/rediscluster chart #1007
|
||||||
|
- Added support for extra volume mounts for redis sentinel #994
|
||||||
|
- Added automountServiceAccountToken values for deployment and serviceaccount #991
|
||||||
|
- Added securityContext for exporter, initcontainers and sidecars #987
|
||||||
|
- Added security context values in operator chart #973
|
||||||
|
- Added rolling update sequence from leader to follower #966
|
||||||
|
- Added support for configurable probe handlers #934
|
||||||
|
- Added redis operator helm chart and release workflow #941
|
||||||
|
- Added support for other container engines #947
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Added default port to enable `SENTINEL_PORT` environment #999
|
||||||
|
- ReadyReplicas need to be checked in `IsStatefulSetReady` #993
|
||||||
|
- watchNamespace value does not take effect in chart #990
|
||||||
|
- Sentinel should not reconcile until replication cluster ready #964
|
||||||
|
- Return ASAP after handling finalizer #940
|
||||||
|
- Check redis replication after handling finalizer #936
|
||||||
|
|
||||||
|
### v0.17.0
|
||||||
|
##### May 14, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- WATCH_NAMESPACE support multi namespace #919
|
||||||
|
- Add workflow to publish image to ghcr #914
|
||||||
|
- Probe use built-in, discarded healthcheck.sh #907
|
||||||
|
- Implement redis cluster ready state #867
|
||||||
|
- Add redisreplication status masterNode #849
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Runtime panic when delete rediscluster which disable persistent #922
|
||||||
|
- Runtime panic when storage param is empty #887
|
||||||
|
- Exporter can not connect to redis when enable tls #902
|
||||||
|
- Update status if not equal #900
|
||||||
|
- Should get the really leader count when scale in #885
|
||||||
|
- ClusterSlaves result should be cut #884
|
||||||
|
- Redis cluster update as scale out #882
|
||||||
|
- Add common AddFinalizer for all api #858
|
||||||
|
|
||||||
|
### v0.16.0
|
||||||
|
##### March 27, 2024
|
||||||
|
|
||||||
|
#### :tada: Features
|
||||||
|
|
||||||
|
- Added support for multiple CRDs and enhanced functionality
|
||||||
|
- Improved test coverage and CI/CD pipeline
|
||||||
|
- Enhanced Redis cluster management and scaling capabilities
|
||||||
|
- Added support for custom Redis configurations
|
||||||
|
- Implemented advanced security features
|
||||||
|
|
||||||
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
- Fixed various StatefulSet and service management issues
|
||||||
|
- Resolved Redis cluster scaling problems
|
||||||
|
- Fixed authentication and TLS connectivity issues
|
||||||
|
- Improved error handling and logging
|
||||||
|
|
||||||
### v0.15.0
|
### v0.15.0
|
||||||
##### July 17, 2023 Latest
|
##### July 17, 2023
|
||||||
|
|
||||||
#### :beetle: Bug Fixes
|
#### :beetle: Bug Fixes
|
||||||
|
|
||||||
|
|
11
Makefile
11
Makefile
|
@ -41,14 +41,16 @@ ENVTEST ?= $(LOCALBIN)/setup-envtest-$(ENVTEST_VERSION)
|
||||||
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)
|
GOLANGCI_LINT = $(LOCALBIN)/golangci-lint-$(GOLANGCI_LINT_VERSION)
|
||||||
KUTTL = $(LOCALBIN)/kuttl-$(KUTTL_VERSION)
|
KUTTL = $(LOCALBIN)/kuttl-$(KUTTL_VERSION)
|
||||||
KIND = $(LOCALBIN)/kind-$(KIND_VERSION)
|
KIND = $(LOCALBIN)/kind-$(KIND_VERSION)
|
||||||
|
CRD_REF_DOCS = $(LOCALBIN)/crd-ref-docs-$(CRD_REF_DOCS_VERSION)
|
||||||
|
|
||||||
# Tool Versions
|
# Tool Versions
|
||||||
KUSTOMIZE_VERSION ?= v5.6.0
|
KUSTOMIZE_VERSION ?= v5.6.0
|
||||||
CONTROLLER_TOOLS_VERSION ?= v0.17.2
|
CONTROLLER_TOOLS_VERSION ?= v0.17.2
|
||||||
ENVTEST_VERSION ?= release-0.17
|
ENVTEST_VERSION ?= release-0.17
|
||||||
GOLANGCI_LINT_VERSION ?= v1.57.2
|
GOLANGCI_LINT_VERSION ?= v2.2.2
|
||||||
KUTTL_VERSION ?= 0.15.0
|
KUTTL_VERSION ?= 0.15.0
|
||||||
KIND_VERSION ?= v0.24.0
|
KIND_VERSION ?= v0.24.0
|
||||||
|
CRD_REF_DOCS_VERSION ?= v0.0.12
|
||||||
|
|
||||||
# Options for 'bundle-build'
|
# Options for 'bundle-build'
|
||||||
ifneq ($(origin CHANNELS), undefined)
|
ifneq ($(origin CHANNELS), undefined)
|
||||||
|
@ -134,6 +136,11 @@ vet:
|
||||||
generate: controller-gen
|
generate: controller-gen
|
||||||
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
|
||||||
|
|
||||||
|
# Generate API documentation
|
||||||
|
.PHONY: generate-api-docs
|
||||||
|
generate-api-docs:
|
||||||
|
@hack/api-docs/build.sh
|
||||||
|
|
||||||
# Create a new builder instance for Docker Buildx with the specified platforms and set it as the current builder
|
# Create a new builder instance for Docker Buildx with the specified platforms and set it as the current builder
|
||||||
.PHONY: docker-create
|
.PHONY: docker-create
|
||||||
docker-create:
|
docker-create:
|
||||||
|
@ -169,7 +176,7 @@ bundle-build:
|
||||||
|
|
||||||
# Rebuild all generated code
|
# Rebuild all generated code
|
||||||
.PHONY: codegen
|
.PHONY: codegen
|
||||||
codegen: generate manifests sync-crds generate-dataAssert generate-metricsdocs
|
codegen: generate manifests sync-crds generate-dataAssert generate-metricsdocs generate-api-docs
|
||||||
|
|
||||||
# Verify that codegen is up to date.
|
# Verify that codegen is up to date.
|
||||||
.PHONY: verify-codegen
|
.PHONY: verify-codegen
|
||||||
|
|
12
README.md
12
README.md
|
@ -3,8 +3,8 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://dev.azure.com/opstreedevops/DevOps/_apis/build/status/redis-operator/redis-operator?repoName=OT-CONTAINER-KIT%2Fredis-operator&branchName=main">
|
<a href="https://github.com/OT-CONTAINER-KIT/redis-operator/actions/workflows/ci.yaml">
|
||||||
<img src="https://dev.azure.com/opstreedevops/DevOps/_apis/build/status/redis-operator/redis-operator?repoName=OT-CONTAINER-KIT%2Fredis-operator&branchName=main" alt="Azure Pipelines">
|
<img src="https://github.com/OT-CONTAINER-KIT/redis-operator/actions/workflows/ci.yaml/badge.svg" alt="CI Pipeline">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://goreportcard.com/report/github.com/OT-CONTAINER-KIT/redis-operator">
|
<a href="https://goreportcard.com/report/github.com/OT-CONTAINER-KIT/redis-operator">
|
||||||
<img src="https://goreportcard.com/badge/github.com/OT-CONTAINER-KIT/redis-operator" alt="GoReportCard">
|
<img src="https://goreportcard.com/badge/github.com/OT-CONTAINER-KIT/redis-operator" alt="GoReportCard">
|
||||||
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
A Golang based redis operator that will make/oversee Redis standalone and cluster mode setup on top of the Kubernetes. It can create a redis cluster setup with best practices on Cloud as well as the Bare metal environment. Also, it provides an in-built monitoring capability using redis-exporter.
|
A Golang based redis operator that will make/oversee Redis standalone and cluster mode setup on top of the Kubernetes. It can create a redis cluster setup with best practices on Cloud as well as the Bare metal environment. Also, it provides an in-built monitoring capability using redis-exporter.
|
||||||
|
|
||||||
For documentation, please refer to <https://ot-redis-operator.netlify.app/>
|
For documentation, please refer to <https://redis-operator.opstree.dev/>
|
||||||
|
|
||||||
Organizations that are using Redis Operator to manage their redis workload can be found [here](./USED_BY_ORGANIZATIONS.md). If your organization is also using Redis Operator, please free to add by creating a [pull request](https://github.com/OT-CONTAINER-KIT/redis-operator/pulls)
|
Organizations that are using Redis Operator to manage their redis workload can be found [here](./USED_BY_ORGANIZATIONS.md). If your organization is also using Redis Operator, please free to add by creating a [pull request](https://github.com/OT-CONTAINER-KIT/redis-operator/pulls)
|
||||||
|
|
||||||
|
@ -53,12 +53,6 @@ Here the features which are supported by this operator:-
|
||||||
- Ipv4 and Ipv6 support for redis setup
|
- Ipv4 and Ipv6 support for redis setup
|
||||||
- Detailed monitoring grafana dashboard
|
- Detailed monitoring grafana dashboard
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
If you want to deploy redis-operator from scratch to a local Minikube cluster, begin with the [Getting started](https://ot-container-kit.github.io/redis-operator/#/quickstart/quickstart) document. It will guide your through the setup step-by-step.
|
|
||||||
|
|
||||||
The configuration of Redis setup should be described in [CRD definitions](config/crd/bases). All the examples related to redis standalone and cluster setup can be found inside [example](./example) folder.
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
Redis operator requires a Kubernetes cluster of version `>=1.18.0`. If you have just started with Operators, it's highly recommended using the latest version of Kubernetes.
|
Redis operator requires a Kubernetes cluster of version `>=1.18.0`. If you have just started with Operators, it's highly recommended using the latest version of Kubernetes.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
|
@ -8,15 +8,16 @@ import (
|
||||||
// KubernetesConfig will be the JSON struct for Basic Redis Config
|
// KubernetesConfig will be the JSON struct for Basic Redis Config
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
type KubernetesConfig struct {
|
type KubernetesConfig struct {
|
||||||
Image string `json:"image"`
|
Image string `json:"image"`
|
||||||
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
|
||||||
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
|
Resources *corev1.ResourceRequirements `json:"resources,omitempty"`
|
||||||
ExistingPasswordSecret *ExistingPasswordSecret `json:"redisSecret,omitempty"`
|
ExistingPasswordSecret *ExistingPasswordSecret `json:"redisSecret,omitempty"`
|
||||||
ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
|
||||||
UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"`
|
UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"`
|
||||||
Service *ServiceConfig `json:"service,omitempty"`
|
PersistentVolumeClaimRetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy `json:"persistentVolumeClaimRetentionPolicy,omitempty"`
|
||||||
IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"`
|
Service *ServiceConfig `json:"service,omitempty"`
|
||||||
MinReadySeconds *int32 `json:"minReadySeconds,omitempty"`
|
IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"`
|
||||||
|
MinReadySeconds *int32 `json:"minReadySeconds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (in *KubernetesConfig) GetServiceType() string {
|
func (in *KubernetesConfig) GetServiceType() string {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package api
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
Copyright 2020 Opstree Solutions.
|
||||||
|
|
||||||
|
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 v1beta2 contains common types used by Redis Operator APIs.
|
||||||
|
// These types are shared across different Redis resource types.
|
||||||
|
//
|
||||||
|
// +groupName=redis.redis.opstreelabs.in
|
||||||
|
package v1beta2
|
|
@ -18,9 +18,10 @@ limitations under the License.
|
||||||
|
|
||||||
// Code generated by controller-gen. DO NOT EDIT.
|
// Code generated by controller-gen. DO NOT EDIT.
|
||||||
|
|
||||||
package api
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -172,6 +173,11 @@ func (in *KubernetesConfig) DeepCopyInto(out *KubernetesConfig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy)
|
in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy)
|
||||||
|
if in.PersistentVolumeClaimRetentionPolicy != nil {
|
||||||
|
in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy
|
||||||
|
*out = new(appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy)
|
||||||
|
**out = **in
|
||||||
|
}
|
||||||
if in.Service != nil {
|
if in.Service != nil {
|
||||||
in, out := &in.Service, &out.Service
|
in, out := &in.Service, &out.Service
|
||||||
*out = new(ServiceConfig)
|
*out = new(ServiceConfig)
|
||||||
|
|
|
@ -17,15 +17,84 @@ limitations under the License.
|
||||||
package v1beta2
|
package v1beta2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||||
)
|
)
|
||||||
|
|
||||||
//+kubebuilder:webhook:path=/mutate-core-v1-pod,mutating=true,failurePolicy=fail,sideEffects=None,groups=core,resources=pods,verbs=create,versions=v1,name=ot-mutate-pod.opstree.com,admissionReviewVersions=v1
|
const (
|
||||||
|
webhookPath = "/validate-redis-redis-opstreelabs-in-v1beta2-rediscluster"
|
||||||
|
)
|
||||||
|
|
||||||
|
// log is for logging in this package.
|
||||||
|
var redisclusterlog = logf.Log.WithName("rediscluster-v1beta2-validation")
|
||||||
|
|
||||||
|
// +kubebuilder:webhook:path=/validate-redis-redis-opstreelabs-in-v1beta2-rediscluster,mutating=false,failurePolicy=fail,sideEffects=None,groups=redis.redis.opstreelabs.in,resources=redisclusters,verbs=create;update,versions=v1beta2,name=validate-rediscluster.redis.opstreelabs.in,admissionReviewVersions=v1
|
||||||
|
|
||||||
|
// SetupWebhookWithManager will setup the manager
|
||||||
func (r *RedisCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
func (r *RedisCluster) SetupWebhookWithManager(mgr ctrl.Manager) error {
|
||||||
return ctrl.NewWebhookManagedBy(mgr).
|
return ctrl.NewWebhookManagedBy(mgr).
|
||||||
For(r).
|
For(r).
|
||||||
Complete()
|
Complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(user): EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
|
var _ webhook.Validator = &RedisCluster{}
|
||||||
|
|
||||||
|
// ValidateCreate implements webhook.Validator so a webhook will be registered for the type
|
||||||
|
func (r *RedisCluster) ValidateCreate() (admission.Warnings, error) {
|
||||||
|
redisclusterlog.Info("validate create", "name", r.Name)
|
||||||
|
|
||||||
|
return r.validate(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
|
||||||
|
func (r *RedisCluster) ValidateUpdate(old runtime.Object) (admission.Warnings, error) {
|
||||||
|
redisclusterlog.Info("validate update", "name", r.Name)
|
||||||
|
|
||||||
|
return r.validate(old.(*RedisCluster))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateDelete implements webhook.Validator so a webhook will be registered for the type
|
||||||
|
func (r *RedisCluster) ValidateDelete() (admission.Warnings, error) {
|
||||||
|
redisclusterlog.Info("validate delete", "name", r.Name)
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate validates the Redis Cluster CR
|
||||||
|
func (r *RedisCluster) validate(_ *RedisCluster) (admission.Warnings, error) {
|
||||||
|
var errors field.ErrorList
|
||||||
|
var warnings admission.Warnings
|
||||||
|
|
||||||
|
if r.Spec.Size == nil {
|
||||||
|
return warnings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the Size is at least 3 for proper cluster operation
|
||||||
|
if *r.Spec.Size < 3 {
|
||||||
|
errors = append(errors, field.Invalid(
|
||||||
|
field.NewPath("spec").Child("clusterSize"),
|
||||||
|
*r.Spec.Size,
|
||||||
|
"Redis cluster must have at least 3 shards",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errors) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, apierrors.NewInvalid(
|
||||||
|
schema.GroupKind{Group: "redis.redis.opstreelabs.in", Kind: "RedisCluster"},
|
||||||
|
r.Name,
|
||||||
|
errors,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RedisCluster) WebhookPath() string {
|
||||||
|
return webhookPath
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package v1beta2_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
v1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/rediscluster/v1beta2"
|
||||||
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/testutil/webhook"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
admissionv1beta1 "k8s.io/api/admission/v1beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRedisClusterWebhook(t *testing.T) {
|
||||||
|
cases := []webhook.ValidationWebhookTestCase{
|
||||||
|
{
|
||||||
|
Name: "success-create-v1beta2-rediscluster-validate-clusterSize-3",
|
||||||
|
Operation: admissionv1beta1.Create,
|
||||||
|
Object: func(t *testing.T, uid string) []byte {
|
||||||
|
t.Helper()
|
||||||
|
cluster := mkRedisCluster(uid)
|
||||||
|
cluster.Spec.Size = ptr.To(int32(3))
|
||||||
|
return marshal(t, cluster)
|
||||||
|
},
|
||||||
|
Check: webhook.ValidationWebhookSucceeded,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "failed-create-v1beta2-rediscluster-validate-clusterSize-2",
|
||||||
|
Operation: admissionv1beta1.Create,
|
||||||
|
Object: func(t *testing.T, uid string) []byte {
|
||||||
|
t.Helper()
|
||||||
|
cluster := mkRedisCluster(uid)
|
||||||
|
cluster.Spec.Size = ptr.To(int32(2))
|
||||||
|
return marshal(t, cluster)
|
||||||
|
},
|
||||||
|
Check: webhook.ValidationWebhookFailed("Redis cluster must have at least 3 shards"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
gvk := metav1.GroupVersionKind{
|
||||||
|
Group: "redis.redis.opstreelabs.in",
|
||||||
|
Version: "v1beta2",
|
||||||
|
Kind: "RedisCluster",
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster := &v1beta2.RedisCluster{}
|
||||||
|
webhook.RunValidationWebhookTests(t, gvk, cluster, cases...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mkRedisCluster(uid string) *v1beta2.RedisCluster {
|
||||||
|
return &v1beta2.RedisCluster{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: fmt.Sprintf("test-%s", uid),
|
||||||
|
UID: types.UID(fmt.Sprintf("test-%s", uid)),
|
||||||
|
},
|
||||||
|
Spec: v1beta2.RedisClusterSpec{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func marshal(t *testing.T, obj interface{}) []byte {
|
||||||
|
t.Helper()
|
||||||
|
bytes, err := json.Marshal(obj)
|
||||||
|
require.NoError(t, err)
|
||||||
|
return bytes
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ package v1beta2
|
||||||
import (
|
import (
|
||||||
commonv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/common/v1beta2"
|
commonv1beta2 "github.com/OT-CONTAINER-KIT/redis-operator/api/common/v1beta2"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
|
|
@ -102,6 +102,8 @@ kubectl create secret tls <webhook-server-cert> --key tls.key --cert tls.crt -n
|
||||||
| issuer.solver.enabled | bool | `true` | |
|
| issuer.solver.enabled | bool | `true` | |
|
||||||
| issuer.solver.ingressClass | string | `"nginx"` | |
|
| issuer.solver.ingressClass | string | `"nginx"` | |
|
||||||
| issuer.type | string | `"selfSigned"` | |
|
| issuer.type | string | `"selfSigned"` | |
|
||||||
|
| manager.config.kubeClientQPS | int | `0` | If value > 0, it will override the default value in the operator |
|
||||||
|
| manager.config.kubeClientTimeout | string | `"60s"` | |
|
||||||
| nodeSelector | object | `{}` | |
|
| nodeSelector | object | `{}` | |
|
||||||
| podSecurityContext | object | `{}` | |
|
| podSecurityContext | object | `{}` | |
|
||||||
| priorityClassName | string | `""` | |
|
| priorityClassName | string | `""` | |
|
||||||
|
|
|
@ -1564,6 +1564,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
@ -6085,6 +6106,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
@ -14779,6 +14821,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
@ -20277,6 +20340,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
|
|
@ -53,6 +53,12 @@ spec:
|
||||||
{{- if .Values.redisOperator.metrics.enabled }}
|
{{- if .Values.redisOperator.metrics.enabled }}
|
||||||
- --metrics-bind-address={{ .Values.redisOperator.metrics.bindAddress }}
|
- --metrics-bind-address={{ .Values.redisOperator.metrics.bindAddress }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.manager.config.kubeClientTimeout }}
|
||||||
|
- --kube-client-timeout={{ .Values.manager.config.kubeClientTimeout }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .Values.manager.config.kubeClientQPS (gt (.Values.manager.config.kubeClientQPS | float64) 0) }}
|
||||||
|
- --kube-client-qps={{ .Values.manager.config.kubeClientQPS }}
|
||||||
|
{{- end }}
|
||||||
{{- range $arg := .Values.redisOperator.extraArgs }}
|
{{- range $arg := .Values.redisOperator.extraArgs }}
|
||||||
- {{ $arg }}
|
- {{ $arg }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
@ -108,3 +108,10 @@ securityContext: {}
|
||||||
featureGates:
|
featureGates:
|
||||||
# Enable generating Redis configuration using an init container instead of a regular container
|
# Enable generating Redis configuration using an init container instead of a regular container
|
||||||
GenerateConfigInInitContainer: false
|
GenerateConfigInInitContainer: false
|
||||||
|
|
||||||
|
manager:
|
||||||
|
# config values for the operator manager
|
||||||
|
config:
|
||||||
|
kubeClientTimeout: 60s
|
||||||
|
# -- If value > 0, it will override the default value in the operator
|
||||||
|
kubeClientQPS: 0
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
apiVersion: v2
|
apiVersion: v2
|
||||||
name: redis-replication
|
name: redis-replication
|
||||||
description: Provides easy redis setup definitions for Kubernetes services, and deployment.
|
description: Provides easy redis setup definitions for Kubernetes services, and deployment.
|
||||||
version: 0.16.7
|
version: 0.16.8
|
||||||
appVersion: "0.16.7"
|
appVersion: "0.16.8"
|
||||||
type: application
|
type: application
|
||||||
engine: gotpl
|
engine: gotpl
|
||||||
maintainers:
|
maintainers:
|
||||||
|
|
|
@ -65,6 +65,9 @@ helm delete <my-release> --namespace <namespace>
|
||||||
| initContainer.resources | object | `{}` | |
|
| initContainer.resources | object | `{}` | |
|
||||||
| labels | object | `{}` | |
|
| labels | object | `{}` | |
|
||||||
| nodeSelector | object | `{}` | |
|
| nodeSelector | object | `{}` | |
|
||||||
|
| pdb.enabled | bool | `false` | |
|
||||||
|
| pdb.maxUnavailable | string | `nil` | |
|
||||||
|
| pdb.minAvailable | int | `1` | |
|
||||||
| podSecurityContext.fsGroup | int | `1000` | |
|
| podSecurityContext.fsGroup | int | `1000` | |
|
||||||
| podSecurityContext.runAsUser | int | `1000` | |
|
| podSecurityContext.runAsUser | int | `1000` | |
|
||||||
| priorityClassName | string | `""` | |
|
| priorityClassName | string | `""` | |
|
||||||
|
|
|
@ -95,4 +95,10 @@ spec:
|
||||||
{{- if .Values.env }}
|
{{- if .Values.env }}
|
||||||
env: {{ toYaml .Values.env | nindent 4 }}
|
env: {{ toYaml .Values.env | nindent 4 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- if .Values.pdb.enabled }}
|
||||||
|
pdb:
|
||||||
|
enabled: {{ .Values.pdb.enabled }}
|
||||||
|
minAvailable: {{ .Values.pdb.minAvailable }}
|
||||||
|
maxUnavailable: {{ .Values.pdb.maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
|
|
@ -156,3 +156,8 @@ acl:
|
||||||
env: []
|
env: []
|
||||||
# - name: VAR_NAME
|
# - name: VAR_NAME
|
||||||
# value: "value1"
|
# value: "value1"
|
||||||
|
|
||||||
|
pdb:
|
||||||
|
enabled: false
|
||||||
|
minAvailable: 1
|
||||||
|
maxUnavailable: null
|
|
@ -1565,6 +1565,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
|
|
@ -715,6 +715,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
|
|
@ -1574,6 +1574,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
|
|
@ -1500,6 +1500,27 @@ spec:
|
||||||
minReadySeconds:
|
minReadySeconds:
|
||||||
format: int32
|
format: int32
|
||||||
type: integer
|
type: integer
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
description: |-
|
||||||
|
StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs
|
||||||
|
created from the StatefulSet VolumeClaimTemplates.
|
||||||
|
properties:
|
||||||
|
whenDeleted:
|
||||||
|
description: |-
|
||||||
|
WhenDeleted specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is deleted. The default policy
|
||||||
|
of `Retain` causes PVCs to not be affected by StatefulSet deletion. The
|
||||||
|
`Delete` policy causes those PVCs to be deleted.
|
||||||
|
type: string
|
||||||
|
whenScaled:
|
||||||
|
description: |-
|
||||||
|
WhenScaled specifies what happens to PVCs created from StatefulSet
|
||||||
|
VolumeClaimTemplates when the StatefulSet is scaled down. The default
|
||||||
|
policy of `Retain` causes PVCs to not be affected by a scaledown. The
|
||||||
|
`Delete` policy causes the associated PVCs for any excess pods above
|
||||||
|
the replica count to be deleted.
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
redisSecret:
|
redisSecret:
|
||||||
description: ExistingPasswordSecret is the struct to access the
|
description: ExistingPasswordSecret is the struct to access the
|
||||||
existing secret
|
existing secret
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
---
|
---
|
||||||
apiVersion: admissionregistration.k8s.io/v1
|
apiVersion: admissionregistration.k8s.io/v1
|
||||||
kind: MutatingWebhookConfiguration
|
kind: ValidatingWebhookConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
name: mutating-webhook-configuration
|
name: validating-webhook-configuration
|
||||||
webhooks:
|
webhooks:
|
||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1
|
- v1
|
||||||
|
@ -10,25 +10,20 @@ webhooks:
|
||||||
service:
|
service:
|
||||||
name: webhook-service
|
name: webhook-service
|
||||||
namespace: system
|
namespace: system
|
||||||
path: /mutate-core-v1-pod
|
path: /validate-redis-redis-opstreelabs-in-v1beta2-rediscluster
|
||||||
failurePolicy: Fail
|
failurePolicy: Fail
|
||||||
name: ot-mutate-pod.opstree.com
|
name: validate-rediscluster.redis.opstreelabs.in
|
||||||
rules:
|
rules:
|
||||||
- apiGroups:
|
- apiGroups:
|
||||||
- ""
|
- redis.redis.opstreelabs.in
|
||||||
apiVersions:
|
apiVersions:
|
||||||
- v1
|
- v1beta2
|
||||||
operations:
|
operations:
|
||||||
- CREATE
|
- CREATE
|
||||||
|
- UPDATE
|
||||||
resources:
|
resources:
|
||||||
- pods
|
- redisclusters
|
||||||
sideEffects: None
|
sideEffects: None
|
||||||
---
|
|
||||||
apiVersion: admissionregistration.k8s.io/v1
|
|
||||||
kind: ValidatingWebhookConfiguration
|
|
||||||
metadata:
|
|
||||||
name: validating-webhook-configuration
|
|
||||||
webhooks:
|
|
||||||
- admissionReviewVersions:
|
- admissionReviewVersions:
|
||||||
- v1
|
- v1
|
||||||
clientConfig:
|
clientConfig:
|
||||||
|
|
|
@ -0,0 +1,637 @@
|
||||||
|
---
|
||||||
|
title: "API Reference Documentation"
|
||||||
|
linkTitle: "API Docs"
|
||||||
|
weight: 10
|
||||||
|
date: 2025-01-27
|
||||||
|
description: >
|
||||||
|
Complete API reference documentation for Redis Operator CRDs
|
||||||
|
---
|
||||||
|
|
||||||
|
# API Reference
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
- [redis.redis.opstreelabs.in/v1beta2](#redisredisopstreelabsinv1beta2)
|
||||||
|
|
||||||
|
|
||||||
|
## redis.redis.opstreelabs.in/v1beta2
|
||||||
|
|
||||||
|
Package v1beta2 contains common types used by Redis Operator APIs.
|
||||||
|
These types are shared across different Redis resource types.
|
||||||
|
|
||||||
|
|
||||||
|
### Resource Types
|
||||||
|
- [Redis](#redis)
|
||||||
|
- [RedisCluster](#rediscluster)
|
||||||
|
- [RedisReplication](#redisreplication)
|
||||||
|
- [RedisSentinel](#redissentinel)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### ACLConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `secret` _[SecretVolumeSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#secretvolumesource-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### AdditionalVolume
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Additional Volume is provided by user that is mounted on the pods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [ClusterStorage](#clusterstorage)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [Storage](#storage)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `volume` _[Volume](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volume-v1-core) array_ | | | |
|
||||||
|
| `mountPath` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core) array_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### ClusterStorage
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Node-conf needs to be added only in redis cluster
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `nodeConfVolume` _boolean_ | | false | |
|
||||||
|
| `nodeConfVolumeClaimTemplate` _[PersistentVolumeClaim](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#persistentvolumeclaim-v1-core)_ | | | |
|
||||||
|
| `keepAfterDelete` _boolean_ | | | |
|
||||||
|
| `volumeClaimTemplate` _[PersistentVolumeClaim](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#persistentvolumeclaim-v1-core)_ | | | |
|
||||||
|
| `volumeMount` _[AdditionalVolume](#additionalvolume)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### ExistingPasswordSecret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ExistingPasswordSecret is the struct to access the existing secret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [KubernetesConfig](#kubernetesconfig)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `name` _string_ | | | |
|
||||||
|
| `key` _string_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### InitContainer
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
InitContainer for each Redis pods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` _boolean_ | | | |
|
||||||
|
| `image` _string_ | | | |
|
||||||
|
| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `command` _string array_ | | | |
|
||||||
|
| `args` _string array_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### KubernetesConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
KubernetesConfig will be the JSON struct for Basic Redis Config
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `image` _string_ | | | |
|
||||||
|
| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
| `redisSecret` _[ExistingPasswordSecret](#existingpasswordsecret)_ | | | |
|
||||||
|
| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#localobjectreference-v1-core)_ | | | |
|
||||||
|
| `updateStrategy` _[StatefulSetUpdateStrategy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#statefulsetupdatestrategy-v1-apps)_ | | | |
|
||||||
|
| `persistentVolumeClaimRetentionPolicy` _[StatefulSetPersistentVolumeClaimRetentionPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#statefulsetpersistentvolumeclaimretentionpolicy-v1-apps)_ | | | |
|
||||||
|
| `service` _[ServiceConfig](#serviceconfig)_ | | | |
|
||||||
|
| `ignoreAnnotations` _string array_ | | | |
|
||||||
|
| `minReadySeconds` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### Redis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Redis is the Schema for the redis API
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2` | | |
|
||||||
|
| `kind` _string_ | `Redis` | | |
|
||||||
|
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
|
||||||
|
| `spec` _[RedisSpec](#redisspec)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisCluster
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisCluster is the Schema for the redisclusters API
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2` | | |
|
||||||
|
| `kind` _string_ | `RedisCluster` | | |
|
||||||
|
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
|
||||||
|
| `spec` _[RedisClusterSpec](#redisclusterspec)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisClusterSpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisClusterSpec defines the desired state of RedisCluster
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisCluster](#rediscluster)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `clusterSize` _integer_ | | | |
|
||||||
|
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | | | |
|
||||||
|
| `hostNetwork` _boolean_ | | | |
|
||||||
|
| `port` _integer_ | | 6379 | |
|
||||||
|
| `clusterVersion` _string_ | | v7 | |
|
||||||
|
| `redisConfig` _[RedisConfig](#redisconfig)_ | | | |
|
||||||
|
| `redisLeader` _[RedisLeader](#redisleader)_ | | | |
|
||||||
|
| `redisFollower` _[RedisFollower](#redisfollower)_ | | | |
|
||||||
|
| `redisExporter` _[RedisExporter](#redisexporter)_ | | | |
|
||||||
|
| `storage` _[ClusterStorage](#clusterstorage)_ | | | |
|
||||||
|
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | |
|
||||||
|
| `priorityClassName` _string_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
| `TLS` _[TLSConfig](#tlsconfig)_ | | | |
|
||||||
|
| `acl` _[ACLConfig](#aclconfig)_ | | | |
|
||||||
|
| `initContainer` _[InitContainer](#initcontainer)_ | | | |
|
||||||
|
| `sidecars` _[Sidecar](#sidecar)_ | | | |
|
||||||
|
| `serviceAccountName` _string_ | | | |
|
||||||
|
| `persistenceEnabled` _boolean_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `hostPort` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisConfig defines the external configuration of Redis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisFollower](#redisfollower)
|
||||||
|
- [RedisFollower](#redisfollower)
|
||||||
|
- [RedisLeader](#redisleader)
|
||||||
|
- [RedisLeader](#redisleader)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `maxMemoryPercentOfLimit` _integer_ | MaxMemoryPercentOfLimit is the percentage of redis container memory limit to be used as maxmemory. | | Maximum: 100 <br />Minimum: 1 <br /> |
|
||||||
|
| `dynamicConfig` _string array_ | | | |
|
||||||
|
| `additionalRedisConfig` _string_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisExporter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisExporter interface will have the information for redis exporter related stuff
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` _boolean_ | | | |
|
||||||
|
| `port` _integer_ | | 9121 | |
|
||||||
|
| `image` _string_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisFollower
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisFollower interface will have the redis follower configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `replicas` _integer_ | | | |
|
||||||
|
| `redisConfig` _[RedisConfig](#redisconfig)_ | | | |
|
||||||
|
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | |
|
||||||
|
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | | | |
|
||||||
|
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core)_ | | | |
|
||||||
|
| `nodeSelector` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#topologyspreadconstraint-v1-core) array_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
| `terminationGracePeriodSeconds` _integer_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisLeader
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisLeader interface will have the redis leader configuration
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `replicas` _integer_ | | | |
|
||||||
|
| `redisConfig` _[RedisConfig](#redisconfig)_ | | | |
|
||||||
|
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | |
|
||||||
|
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | | | |
|
||||||
|
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core)_ | | | |
|
||||||
|
| `nodeSelector` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#topologyspreadconstraint-v1-core) array_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
| `terminationGracePeriodSeconds` _integer_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisPodDisruptionBudget
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisPodDisruptionBudget configure a PodDisruptionBudget on the resource (leader/follower)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisFollower](#redisfollower)
|
||||||
|
- [RedisFollower](#redisfollower)
|
||||||
|
- [RedisLeader](#redisleader)
|
||||||
|
- [RedisLeader](#redisleader)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `enabled` _boolean_ | | | |
|
||||||
|
| `minAvailable` _integer_ | | | |
|
||||||
|
| `maxUnavailable` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisReplication
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Redis is the Schema for the redis API
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2` | | |
|
||||||
|
| `kind` _string_ | `RedisReplication` | | |
|
||||||
|
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
|
||||||
|
| `spec` _[RedisReplicationSpec](#redisreplicationspec)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisReplicationSpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisReplication](#redisreplication)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `clusterSize` _integer_ | | | |
|
||||||
|
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | | | |
|
||||||
|
| `redisExporter` _[RedisExporter](#redisexporter)_ | | | |
|
||||||
|
| `redisConfig` _[RedisConfig](#redisconfig)_ | | | |
|
||||||
|
| `storage` _[Storage](#storage)_ | | | |
|
||||||
|
| `nodeSelector` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
| `priorityClassName` _string_ | | | |
|
||||||
|
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | |
|
||||||
|
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core)_ | | | |
|
||||||
|
| `TLS` _[TLSConfig](#tlsconfig)_ | | | |
|
||||||
|
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | | | |
|
||||||
|
| `acl` _[ACLConfig](#aclconfig)_ | | | |
|
||||||
|
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `initContainer` _[InitContainer](#initcontainer)_ | | | |
|
||||||
|
| `sidecars` _[Sidecar](#sidecar)_ | | | |
|
||||||
|
| `serviceAccountName` _string_ | | | |
|
||||||
|
| `terminationGracePeriodSeconds` _integer_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#topologyspreadconstraint-v1-core) array_ | | | |
|
||||||
|
| `hostPort` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisSentinel
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Redis is the Schema for the redis API
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2` | | |
|
||||||
|
| `kind` _string_ | `RedisSentinel` | | |
|
||||||
|
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
|
||||||
|
| `spec` _[RedisSentinelSpec](#redissentinelspec)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisSentinelConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `additionalSentinelConfig` _string_ | | | |
|
||||||
|
| `redisReplicationName` _string_ | | | |
|
||||||
|
| `redisReplicationPassword` _[EnvVarSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvarsource-v1-core)_ | | | |
|
||||||
|
| `masterGroupName` _string_ | | myMaster | |
|
||||||
|
| `redisPort` _string_ | | 6379 | |
|
||||||
|
| `quorum` _string_ | | 2 | |
|
||||||
|
| `parallelSyncs` _string_ | | 1 | |
|
||||||
|
| `failoverTimeout` _string_ | | 180000 | |
|
||||||
|
| `downAfterMilliseconds` _string_ | | 30000 | |
|
||||||
|
| `resolveHostnames` _string_ | | no | |
|
||||||
|
| `announceHostnames` _string_ | | no | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisSentinelSpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisSentinel](#redissentinel)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `clusterSize` _integer_ | | 3 | Minimum: 1 <br /> |
|
||||||
|
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | | | |
|
||||||
|
| `redisExporter` _[RedisExporter](#redisexporter)_ | | | |
|
||||||
|
| `redisSentinelConfig` _[RedisSentinelConfig](#redissentinelconfig)_ | | | |
|
||||||
|
| `nodeSelector` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
| `priorityClassName` _string_ | | | |
|
||||||
|
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | |
|
||||||
|
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core)_ | | | |
|
||||||
|
| `TLS` _[TLSConfig](#tlsconfig)_ | | | |
|
||||||
|
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | | | |
|
||||||
|
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `initContainer` _[InitContainer](#initcontainer)_ | | | |
|
||||||
|
| `sidecars` _[Sidecar](#sidecar)_ | | | |
|
||||||
|
| `serviceAccountName` _string_ | | | |
|
||||||
|
| `terminationGracePeriodSeconds` _integer_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `volumeMount` _[AdditionalVolume](#additionalvolume)_ | | | |
|
||||||
|
| `topologySpreadConstraints` _[TopologySpreadConstraint](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#topologyspreadconstraint-v1-core) array_ | | | |
|
||||||
|
| `hostPort` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### RedisSpec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RedisSpec defines the desired state of Redis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [Redis](#redis)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | | | |
|
||||||
|
| `redisExporter` _[RedisExporter](#redisexporter)_ | | | |
|
||||||
|
| `redisConfig` _[RedisConfig](#redisconfig)_ | | | |
|
||||||
|
| `storage` _[Storage](#storage)_ | | | |
|
||||||
|
| `nodeSelector` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podsecuritycontext-v1-core)_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
| `priorityClassName` _string_ | | | |
|
||||||
|
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#affinity-v1-core)_ | | | |
|
||||||
|
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#toleration-v1-core)_ | | | |
|
||||||
|
| `TLS` _[TLSConfig](#tlsconfig)_ | | | |
|
||||||
|
| `acl` _[ACLConfig](#aclconfig)_ | | | |
|
||||||
|
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#probe-v1-core)_ | | | |
|
||||||
|
| `initContainer` _[InitContainer](#initcontainer)_ | | | |
|
||||||
|
| `sidecars` _[Sidecar](#sidecar)_ | | | |
|
||||||
|
| `serviceAccountName` _string_ | | | |
|
||||||
|
| `terminationGracePeriodSeconds` _integer_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `hostPort` _integer_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### Service
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Service is the struct to define the service type and its annotations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [ServiceConfig](#serviceconfig)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `type` _string_ | | ClusterIP | Enum: [LoadBalancer NodePort ClusterIP] <br /> |
|
||||||
|
| `additionalAnnotations` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `includeBusPort` _boolean_ | IncludeBusPort when set to true, it will add bus port to the service, such as 16379.<br />This field is only used for Redis cluster mode. | | |
|
||||||
|
| `enabled` _boolean_ | | true | |
|
||||||
|
|
||||||
|
|
||||||
|
#### ServiceConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
ServiceConfig define the type of service to be created and its annotations
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [KubernetesConfig](#kubernetesconfig)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `serviceType` _string_ | | | Enum: [LoadBalancer NodePort ClusterIP] <br /> |
|
||||||
|
| `annotations` _object (keys:string, values:string)_ | | | |
|
||||||
|
| `includeBusPort` _boolean_ | IncludeBusPort when set to true, it will add bus port to the service, such as 16379.<br />This field is only used for Redis cluster mode. | | |
|
||||||
|
| `headless` _[Service](#service)_ | Headless config for which suffix is -headless service | | |
|
||||||
|
| `additional` _[Service](#service)_ | Additional config for which suffix is -additional service | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### Sidecar
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Sidecar for each Redis pods
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `name` _string_ | | | |
|
||||||
|
| `image` _string_ | | | |
|
||||||
|
| `imagePullPolicy` _[PullPolicy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pullpolicy-v1-core)_ | | | |
|
||||||
|
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#resourcerequirements-v1-core)_ | | | |
|
||||||
|
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#envvar-v1-core)_ | | | |
|
||||||
|
| `mountPath` _[VolumeMount](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#volumemount-v1-core)_ | | | |
|
||||||
|
| `command` _string array_ | | | |
|
||||||
|
| `ports` _[ContainerPort](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#containerport-v1-core)_ | | | |
|
||||||
|
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#securitycontext-v1-core)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### Storage
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Storage is the inteface to add pvc and pv support in redis
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [ClusterStorage](#clusterstorage)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `keepAfterDelete` _boolean_ | | | |
|
||||||
|
| `volumeClaimTemplate` _[PersistentVolumeClaim](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#persistentvolumeclaim-v1-core)_ | | | |
|
||||||
|
| `volumeMount` _[AdditionalVolume](#additionalvolume)_ | | | |
|
||||||
|
|
||||||
|
|
||||||
|
#### TLSConfig
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TLS Configuration for redis instances
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_Appears in:_
|
||||||
|
- [RedisClusterSpec](#redisclusterspec)
|
||||||
|
- [RedisReplicationSpec](#redisreplicationspec)
|
||||||
|
- [RedisSentinelSpec](#redissentinelspec)
|
||||||
|
- [RedisSpec](#redisspec)
|
||||||
|
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `ca` _string_ | | | |
|
||||||
|
| `cert` _string_ | | | |
|
||||||
|
| `key` _string_ | | | |
|
||||||
|
| `secret` _[SecretVolumeSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#secretvolumesource-v1-core)_ | Reference to secret which contains the certificates | | |
|
||||||
|
|
||||||
|
|
|
@ -1,399 +0,0 @@
|
||||||
---
|
|
||||||
title: "Custom Resource Object API"
|
|
||||||
linkTitle: "Custom Resource Object API"
|
|
||||||
weight: 10
|
|
||||||
date: 2022-11-02T00:19:19Z
|
|
||||||
description: >
|
|
||||||
CRD Schema details for Redis and Redis Cluster Reference API
|
|
||||||
---
|
|
||||||
|
|
||||||
# Redis API Reference
|
|
||||||
|
|
||||||
This page documents the Redis API Schema definitions for the redis API group.
|
|
||||||
|
|
||||||
## Packages
|
|
||||||
|
|
||||||
- [redis.redis.opstreelabs.in/v1beta2](#redisredisopstreelabsinv1beta2)
|
|
||||||
|
|
||||||
## redis.redis.opstreelabs.in/v1beta2
|
|
||||||
|
|
||||||
Package v1beta2 contains API Schema definitions for the redis v1beta2 API group
|
|
||||||
|
|
||||||
### Annotations
|
|
||||||
|
|
||||||
Redis Operator supports the following annotations that can be added to Redis, RedisCluster, RedisReplication, and RedisSentinel resources:
|
|
||||||
|
|
||||||
| Annotation | Description | Default | Values |
|
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `redis.opstreelabs.in/recreate-statefulset` | Controls whether the StatefulSet should be recreated when changed | `false` | `"true"`, `"false"` |
|
|
||||||
| `redis.opstreelabs.in/recreate-statefulset-strategy` | Controls how dependent resources are handled when the StatefulSet is recreated | `foreground` | `"foreground"`, `"background"`, `"orphan"` |
|
|
||||||
|
|
||||||
#### Deletion Propagation Strategies
|
|
||||||
|
|
||||||
When `redis.opstreelabs.in/recreate-statefulset` is set to `"true"`, you can control the deletion behavior using the `redis.opstreelabs.in/recreate-statefulset-strategy` annotation:
|
|
||||||
|
|
||||||
- **foreground**: The StatefulSet and its dependent objects (like Pods) are deleted synchronously
|
|
||||||
- **background**: The StatefulSet is deleted immediately, and dependent objects are deleted asynchronously
|
|
||||||
- **orphan**: The StatefulSet is deleted but its dependent objects (Pods) are kept running
|
|
||||||
|
|
||||||
### Resource Types
|
|
||||||
|
|
||||||
- [Redis](#redis)
|
|
||||||
- [RedisCluster](#rediscluster)
|
|
||||||
- [RedisReplication](#redisreplication)
|
|
||||||
- [RedisSentinel](#redissentinel)
|
|
||||||
|
|
||||||
#### ExistingPasswordSecret
|
|
||||||
|
|
||||||
ExistingPasswordSecret is the struct to access the existing secret
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [KubernetesConfig](#kubernetesconfig)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `name` _string_ | |
|
|
||||||
| `key` _string_ | |
|
|
||||||
|
|
||||||
#### KubernetesConfig
|
|
||||||
|
|
||||||
KubernetesConfig will be the JSON struct for Basic Redis Config
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
- [RedisSentinel](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `image` _string_ | |
|
|
||||||
| `imagePullPolicy` _[ImagePullPolicy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy)_ | |
|
|
||||||
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#resourcerequirements-v1-core)_ | |
|
|
||||||
| `redisSecret` _[ExistingPasswordSecret](#existingpasswordsecret)_ | |
|
|
||||||
| `imagePullSecrets` _[LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#localobjectreference-v1-core)_ | |
|
|
||||||
| `updateStrategy` _[StatefulSetUpdateStrategy](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#statefulsetupdatestrategy-v1-apps)_ | |
|
|
||||||
|
|
||||||
#### VolumeMount
|
|
||||||
|
|
||||||
Mount External Volumes
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisSentinel](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `volume` _[Volume Array](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volume-v1-core)_ | |
|
|
||||||
| `mountPath` _[VolumeMount Array](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#volumemount-v1-core)_ | |
|
|
||||||
|
|
||||||
#### Redis
|
|
||||||
|
|
||||||
Redis is the Schema for the redis API
|
|
||||||
|
|
||||||
| Field | Description | Scheme | Required |
|
|
||||||
| ----- | ----------- | ------ | -------- |
|
|
||||||
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2` | | |
|
|
||||||
| `kind` _string_ | `Redis`
|
|
||||||
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. |
|
|
||||||
| `spec` _[RedisSpec](#redisspec)_ | |
|
|
||||||
|
|
||||||
#### RedisCluster
|
|
||||||
|
|
||||||
RedisCluster is the Schema for the redisclusters API
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2`
|
|
||||||
| `kind` _string_ | `RedisCluster`
|
|
||||||
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. |
|
|
||||||
| `spec` _[RedisClusterSpec](#redisclusterspec)_ | |
|
|
||||||
|
|
||||||
#### RedisReplication
|
|
||||||
|
|
||||||
RedisReplication is the Schema for the redisreplication API
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2`
|
|
||||||
| `kind` _string_ | `RedisReplication`
|
|
||||||
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. |
|
|
||||||
| `spec` _[RedisReplicationSpec](#redisreplicationspec)_ | |
|
|
||||||
|
|
||||||
#### RedisSentinel
|
|
||||||
|
|
||||||
RedisSentinel is the Schema for the redissentinel API
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `apiVersion` _string_ | `redis.redis.opstreelabs.in/v1beta2`
|
|
||||||
| `kind` _string_ | `RedisSentinel`
|
|
||||||
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. |
|
|
||||||
| `spec` _[RedisSentinelSpec](#redissentinelspec)_ | |
|
|
||||||
|
|
||||||
#### RedisClusterSpec
|
|
||||||
|
|
||||||
RedisClusterSpec defines the desired state of RedisCluster
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisCluster](#rediscluster)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `clusterSize` _integer_ | |
|
|
||||||
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | |
|
|
||||||
| `clusterVersion` _string_ | |
|
|
||||||
| `redisLeader` _[RedisLeader](#redisleader)_ | |
|
|
||||||
| `redisFollower` _[RedisFollower](#redisfollower)_ | |
|
|
||||||
| `redisExporter` _[RedisExporter](#redisexporter)_ | |
|
|
||||||
| `storage` _[Storage](#storage)_ | |
|
|
||||||
| `nodeSelector` _object (keys:string, values:string)_ | |
|
|
||||||
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ | |
|
|
||||||
| `priorityClassName` _string_ | |
|
|
||||||
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#toleration-v1-core)_ | |
|
|
||||||
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#resourcerequirements-v1-core)_ | |
|
|
||||||
| `TLS` _[TLSConfig](#tlsconfig)_ | |
|
|
||||||
| `sidecars` _[Sidecar](#sidecar)_ | |
|
|
||||||
| `serviceAccountName` _string_ | |
|
|
||||||
| `persistenceEnabled` _boolean_ | |
|
|
||||||
|
|
||||||
#### RedisSpec
|
|
||||||
|
|
||||||
RedisSpec defines the desired state of Redis
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [Redis](#redis)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | |
|
|
||||||
| `redisExporter` _[RedisExporter](#redisexporter)_ | |
|
|
||||||
| `redisConfig` _[RedisConfig](#redisconfig)_ | |
|
|
||||||
| `storage` _[Storage](#storage)_ | |
|
|
||||||
| `nodeSelector` _object (keys:string, values:string)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ | |
|
|
||||||
| `priorityClassName` _string_ | |
|
|
||||||
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | |
|
|
||||||
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#toleration-v1-core)_ | |
|
|
||||||
| `TLS` _[TLSConfig](#tlsconfig)_ | |
|
|
||||||
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `sidecars` _[Sidecar](#sidecar)_ | |
|
|
||||||
| `serviceAccountName` _string_ | |
|
|
||||||
|
|
||||||
#### RedisReplicationSpec
|
|
||||||
|
|
||||||
RedisReplicationSpec defines the desired state of RedisReplication
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisReplication](#redisreplication)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `clusterSize` _integer_ | |
|
|
||||||
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | |
|
|
||||||
| `redisExporter` _[RedisExporter](#redisexporter)_ | |
|
|
||||||
| `redisConfig` _[RedisConfig](#redisconfig)_ | |
|
|
||||||
| `storage` _[Storage](#storage)_ | |
|
|
||||||
| `nodeSelector` _object (keys:string, values:string)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ | |
|
|
||||||
| `priorityClassName` _string_ | |
|
|
||||||
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | |
|
|
||||||
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#toleration-v1-core)_ | |
|
|
||||||
| `TLS` _[TLSConfig](#tlsconfig)_ | |
|
|
||||||
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `sidecars` _[Sidecar](#sidecar)_ | |
|
|
||||||
| `serviceAccountName` _string_ | |
|
|
||||||
|
|
||||||
#### RedisSentinelSpec
|
|
||||||
|
|
||||||
RedisSentinelSpec defines the desired state of RedisSentinel
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisSentinel](#redissentinel)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `clusterSize` _integer_ | |
|
|
||||||
| `kubernetesConfig` _[KubernetesConfig](#kubernetesconfig)_ | |
|
|
||||||
| `redisSentinelConfig` _[RedisSentinelConfig](#redissentinelconfig)_ | |
|
|
||||||
| `nodeSelector` _object (keys:string, values:string)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
| `podSecurityContext` _[PodSecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#podsecuritycontext-v1-core)_ | |
|
|
||||||
| `priorityClassName` _string_ | |
|
|
||||||
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | |
|
|
||||||
| `tolerations` _[Toleration](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#toleration-v1-core)_ | |
|
|
||||||
| `TLS` _[TLSConfig](#tlsconfig)_ | |
|
|
||||||
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `sidecars` _[Sidecar](#sidecar)_ | |
|
|
||||||
| `serviceAccountName` _string_ | |
|
|
||||||
| `volumeMount` _[VolumeMount](#volumemount)_ | |
|
|
||||||
|
|
||||||
#### RedisConfig
|
|
||||||
|
|
||||||
RedisConfig defines the external configuration of Redis
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisFollower](#redisfollower)
|
|
||||||
- [RedisLeader](#redisleader)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `additionalRedisConfig` _string_ | |
|
|
||||||
|
|
||||||
#### RedisSentinelConfig
|
|
||||||
|
|
||||||
RedisSentinelConfig defines the external configuration of RedisSentinel
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisSentinelSpec](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `additionalRedisConfig` _string_ | |
|
|
||||||
| `masterGroupName` _string_ | |
|
|
||||||
| `redisPort` _string_ | |
|
|
||||||
| `quorum` _string_ | |
|
|
||||||
| `parallelSyncs` _string_ | |
|
|
||||||
| `failoverTimeout` _string_ | |
|
|
||||||
| `downAfterMilliseconds` _string_ | |
|
|
||||||
| `resolveHostnames` _string_ | |
|
|
||||||
| `announceHostnames` _string_ | |
|
|
||||||
|
|
||||||
#### RedisExporter
|
|
||||||
|
|
||||||
RedisExporter interface will have the information for redis exporter related stuff
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `enabled` _boolean_ | |
|
|
||||||
| `image` _string_ | |
|
|
||||||
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#resourcerequirements-v1-core)_ | |
|
|
||||||
| `imagePullPolicy` _[ImagePullPolicy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy)_ | |
|
|
||||||
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#envvar-v1-core)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
|
|
||||||
#### RedisFollower
|
|
||||||
|
|
||||||
RedisFollower interface will have the redis follower configuration
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `replicas` _integer_ | |
|
|
||||||
| `redisConfig` _[RedisConfig](#redisconfig)_ | |
|
|
||||||
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | |
|
|
||||||
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
|
|
||||||
#### RedisLeader
|
|
||||||
|
|
||||||
RedisLeader interface will have the redis leader configuration
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `replicas` _integer_ | |
|
|
||||||
| `redisConfig` _[RedisConfig](#redisconfig)_ | |
|
|
||||||
| `affinity` _[Affinity](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#affinity-v1-core)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
| `pdb` _[RedisPodDisruptionBudget](#redispoddisruptionbudget)_ | |
|
|
||||||
| `readinessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
| `livenessProbe` _[Probe](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#probe-v1-core)_ | |
|
|
||||||
|
|
||||||
#### RedisPodDisruptionBudget
|
|
||||||
|
|
||||||
RedisPodDisruptionBudget configure a PodDisruptionBudget on the resource (leader/follower)
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisFollower](#redisfollower)
|
|
||||||
- [RedisLeader](#redisleader)
|
|
||||||
- [RedisReplication](#redisreplicationspec)
|
|
||||||
- [RedisSentinel](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `enabled` _boolean_ | |
|
|
||||||
| `minAvailable` _integer_ | |
|
|
||||||
| `maxUnavailable` _integer_ | |
|
|
||||||
|
|
||||||
#### Sidecar
|
|
||||||
|
|
||||||
Sidecar for each Redis pods
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
- [RedisSentinel](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `name` _string_ | |
|
|
||||||
| `image` _string_ | |
|
|
||||||
| `imagePullPolicy` _[ImagePullPolicy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy)_ | |
|
|
||||||
| `resources` _[ResourceRequirements](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#resourcerequirements-v1-core)_ | |
|
|
||||||
| `env` _[EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#envvar-v1-core)_ | |
|
|
||||||
| `securityContext` _[SecurityContext](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#securitycontext-v1-core)_ | |
|
|
||||||
|
|
||||||
#### Storage
|
|
||||||
|
|
||||||
Storage is the inteface to add pvc and pv support in redis
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `volumeClaimTemplate` _[PersistentVolumeClaim](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#persistentvolumeclaim-v1-core)_ | |
|
|
||||||
|
|
||||||
#### TLSConfig
|
|
||||||
|
|
||||||
TLS Configuration for redis instances
|
|
||||||
|
|
||||||
_Appears in:_
|
|
||||||
|
|
||||||
- [RedisClusterSpec](#redisclusterspec)
|
|
||||||
- [RedisSpec](#redisspec)
|
|
||||||
- [RedisReplicationSpec](#redisreplicationspec)
|
|
||||||
- [RedisSentinel](#redissentinelspec)
|
|
||||||
|
|
||||||
| Field | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| `ca` _string_ | |
|
|
||||||
| `cert` _string_ | |
|
|
||||||
| `key` _string_ | |
|
|
||||||
| `secret` _[SecretVolumeSource](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.30/#secretvolumesource-v1-core)_ | Reference to secret which contains the certificates |
|
|
|
@ -7,6 +7,8 @@ description: >
|
||||||
Instructions for setting up Redis Replication
|
Instructions for setting up Redis Replication
|
||||||
---
|
---
|
||||||
|
|
||||||
|
> **Note:** It is recommended to use [Sentinel](../Sentinel) to monitor the Replication cluster for enhanced high availability and reliability. By implementing Redis Sentinel, you can ensure that your Redis Replication remains operational even if one or more nodes fail, thereby improving the resilience and reliability of your application.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
Redis is an in-memory key-value store that can be used as a database, cache, and message broker. Redis replication is the process of synchronizing data from a Redis leader node to one or more Redis follower nodes.
|
Redis is an in-memory key-value store that can be used as a database, cache, and message broker. Redis replication is the process of synchronizing data from a Redis leader node to one or more Redis follower nodes.
|
||||||
|
@ -21,8 +23,6 @@ Redis replication is a powerful feature that enhances the durability and scalabi
|
||||||
<img src="../../../images/replication-redis.png">
|
<img src="../../../images/replication-redis.png">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
> **Note:** By using Redis Sentinel, you can ensure that your Redis Replication remains available even if one or more nodes go down, improving the resilience and reliability of your application.
|
|
||||||
|
|
||||||
## Helm Installation
|
## Helm Installation
|
||||||
|
|
||||||
For redis replication setup we can use `helm` command with the reference of replication helm chart and additional properties:
|
For redis replication setup we can use `helm` command with the reference of replication helm chart and additional properties:
|
||||||
|
@ -78,7 +78,7 @@ metadata:
|
||||||
name: redis-replication
|
name: redis-replication
|
||||||
spec:
|
spec:
|
||||||
clusterSize: 3
|
clusterSize: 3
|
||||||
securityContext:
|
podSecurityContext:
|
||||||
runAsUser: 1000
|
runAsUser: 1000
|
||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
kubernetesConfig:
|
kubernetesConfig:
|
||||||
|
|
|
@ -78,7 +78,7 @@ spec:
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: 1Gi
|
storage: 1Gi
|
||||||
securityContext:
|
podSecurityContext:
|
||||||
runAsUser: 1000
|
runAsUser: 1000
|
||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
```
|
```
|
||||||
|
|
|
@ -41,9 +41,21 @@ Total number of rediscluster rebalance operations. Type: Counter.
|
||||||
### rediscluster_remove_follower_attempt
|
### rediscluster_remove_follower_attempt
|
||||||
Number of times to remove follower attempts. Type: Counter.
|
Number of times to remove follower attempts. Type: Counter.
|
||||||
|
|
||||||
|
### rediscluster_repair_disconnected_attempt
|
||||||
|
Number of times to repair a Redis cluster disconnected from the cluster. Type: Counter.
|
||||||
|
|
||||||
|
### rediscluster_repair_failed
|
||||||
|
Number of times to repair a Redis cluster failed. Type: Counter.
|
||||||
|
|
||||||
### rediscluster_replicas_size_desired
|
### rediscluster_replicas_size_desired
|
||||||
Total desired number of rediscluster replicas. Type: Gauge.
|
Total desired number of rediscluster replicas. Type: Gauge.
|
||||||
|
|
||||||
|
### rediscluster_reset_attempt
|
||||||
|
Number of times to reset a Redis cluster. Type: Counter.
|
||||||
|
|
||||||
|
### rediscluster_reset_failed
|
||||||
|
Number of times to reset a Redis cluster failed. Type: Counter.
|
||||||
|
|
||||||
### rediscluster_reshard_total
|
### rediscluster_reshard_total
|
||||||
Total number of rediscluster reshard operations. Type: Counter.
|
Total number of rediscluster reshard operations. Type: Counter.
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
title: "Overview"
|
title: "Overview"
|
||||||
linkTitle: "Overview"
|
linkTitle: "Overview"
|
||||||
weight: 1
|
weight: 1
|
||||||
date: 2022-11-02T00:19:19Z
|
date: 2025-07-25T00:00:00Z
|
||||||
description: >
|
description: >
|
||||||
Redis Operator is a software to set up and manage Redis on [Kubernetes](https://kubernetes.io).
|
Redis Operator is a software to set up and manage Redis on [Kubernetes](https://kubernetes.io).
|
||||||
---
|
---
|
||||||
|
|
||||||
A Golang based redis operator that will make/oversee Redis standalone/cluster/replication/sentinel mode setup on top of the Kubernetes. It can create a redis cluster setup with best practices on Cloud as well as the Bare-metal environment. Also, it provides an in-built monitoring capability using redis-exporter.
|
A Golang based redis operator that will make/oversee Redis standalone/cluster/replication/sentinel mode setup on top of the Kubernetes. It can create a redis cluster setup with best practices on Cloud as well as the Bare-metal environment. Also, it provides an in-built monitoring capability using redis-exporter.
|
||||||
|
|
||||||
Documentation is available here:- https://ot-container-kit.github.io/redis-operator/
|
Documentation is available here:- https://redis-operator.opstree.dev/docs/
|
||||||
|
|
||||||
The type of Redis setup which is currently supported:-
|
The type of Redis setup which is currently supported:-
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,325 @@
|
||||||
title: "Release History"
|
title: "Release History"
|
||||||
linkTitle: "Release History"
|
linkTitle: "Release History"
|
||||||
weight: 10
|
weight: 10
|
||||||
date: 2022-11-02T00:19:19Z
|
date: 2025-07-25T00:00:00Z
|
||||||
description: >
|
description: >
|
||||||
Release versions and their description about Redis Operator
|
Release versions and their description about Redis Operator
|
||||||
---
|
---
|
||||||
|
The most up to date release notes can be found on [GitHub](https://github.com/OT-CONTAINER-KIT/redis-operator/releases)
|
||||||
|
|
||||||
|
### v0.21.0
|
||||||
|
#### June 2025
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Round robin where to transfer cluster shards when scaling in a Redis Cluster [#1412](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1412)
|
||||||
|
- Add auto max memory configuration for Redis instances [#1411](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1411)
|
||||||
|
- Add bus port configuration for Redis cluster services [#1406](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1406)
|
||||||
|
- Add automatic Redis pod role label synchronization for rediscluster [#1404](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1404)
|
||||||
|
- RedisCluster observability [#1392](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1392)
|
||||||
|
- Add liveness/readiness probes to values.yaml and templates [#1378](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1378)
|
||||||
|
- Reduce unnecessary requeue when skip reconcile annotation exists [#1374](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1374)
|
||||||
|
- RedisReplication observability, skip reconcile or not [#1369](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1369)
|
||||||
|
- Add Redis Sentinel validation webhook for clusterSize [#1361](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1361)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Resolve StatefulSet selector immutability issues [#1382](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1382)
|
||||||
|
- Avoid sentinel restart after replication failover [#1381](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1381)
|
||||||
|
- Define named probe port outside webhook block [#1354](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1354)
|
||||||
|
|
||||||
|
**🎉 Refactors**
|
||||||
|
|
||||||
|
- Reorganize manager agent cmd package [#1383](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1383)
|
||||||
|
- Reorganize API structure and update paths [#1363](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1363)
|
||||||
|
- Remove useless structure and refactor package [#1362](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1362)
|
||||||
|
- Reorganize command structure for Redis operator [#1351](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1351)
|
||||||
|
|
||||||
|
### v0.20.2
|
||||||
|
#### May 12, 2024
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Handle panic when retrieving StatefulSet in GetRedisNodesByRole [#1330](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1330)
|
||||||
|
- VCT resize detection logic; add support for scaling out with new VCT size [#1342](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1342)
|
||||||
|
- Service updated before Statefulset during Reconciliation [#1348](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1348)
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Add data assertion generation and enhance Redis configuration commands [#1331](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1331)
|
||||||
|
- Add feature gates support for Redis Operator [#1333](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1333)
|
||||||
|
- Migrate kubebuilder go.kubebuilder.io/v3 to go.kubebuilder.io/v4 [#1340](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1340)
|
||||||
|
|
||||||
|
**🎉 Refactors**
|
||||||
|
|
||||||
|
- Define container port for http probes in operator chart [#1326](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1326)
|
||||||
|
- Enhance environment variable management and CI workflow [#1315](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1315)
|
||||||
|
|
||||||
|
### v0.20.1
|
||||||
|
#### April 27, 2024
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Move VCT logic before diff calculation for stateful set [#1322](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1322)
|
||||||
|
|
||||||
|
### v0.20.0
|
||||||
|
#### April 1, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Sentinel - support hostname resolve and announce [#1247](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1247)
|
||||||
|
- Add redis agent with bootstrap configuration generation [#1254](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1254)
|
||||||
|
- Implement comprehensive Redis configuration generation for agent bootstrap [#1260](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1260)
|
||||||
|
- Added support for hostport to allow direct connection to the pod [#1263](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1263)
|
||||||
|
- Add preStop hook for Redis Cluster failover [#1264](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1264)
|
||||||
|
- Sentinel - announce-ip when resolve & announce are set [#1271](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1271)
|
||||||
|
- Fix PVC resizing issue and refactor PVC resizing logic [#1268](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1268)
|
||||||
|
- Add redisreplication observability [#1274](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1274)
|
||||||
|
- Add recreate-stateful-strategy, orphan, background, foreground(default) [#1286](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1286)
|
||||||
|
- Update Dockerfile and Makefile for unified operator binary [#1294](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1294)
|
||||||
|
- Add support for anti affinity configuration in helm charts [#1296](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1296)
|
||||||
|
- Guarantee to avoid bad master ip on Sentinel [#1289](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1289)
|
||||||
|
- Add feature gates for sentinel configuration generation in init container [#1300](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1300)
|
||||||
|
- Support redis configuration generation in init container [#1303](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1303)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Replace hardcoded Redis port 6379 with configurable port from cr.Spec.Port [#1261](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1261)
|
||||||
|
- Update references from master to main in docs and workflow files [#1288](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1288)
|
||||||
|
- Svc finalizer removed [#1297](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1297)
|
||||||
|
- Race condition resulting in permanently broken Redis cluster [#1298](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1298)
|
||||||
|
|
||||||
|
### v0.19.1
|
||||||
|
#### February 19, 2024
|
||||||
|
|
||||||
|
**⚠️ Deprecation Notice**
|
||||||
|
|
||||||
|
The v1beta1 API version will be removed in next release. Users are strongly encouraged to migrate to v1beta2, which offers enhanced features and improved stability.
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Add data-assert tool for Redis data management [#1204](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1204)
|
||||||
|
- Check data consistent by external tool [#1205](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1205)
|
||||||
|
- Added actions to publish charts to github container registry [#1201](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1201)
|
||||||
|
- Add headless service configuration support [#1219](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1219)
|
||||||
|
- Update redis-operator cert manager configuration [#1220](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1220)
|
||||||
|
- Add additional service configuration with optional enable flag [#1228](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1228)
|
||||||
|
- Enhance Redis HA and node scheduling strategy [#1237](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1237)
|
||||||
|
- Add securityContext config in chart for redis-exporter [#1238](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1238)
|
||||||
|
- Add dynamic Redis configuration support for Redis Cluster [#1241](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1241)
|
||||||
|
- Configurable operator maxConcurrentReconciles [#1242](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1242)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Skip-reconcile annotation still skipping reconcile even the value is false [#1202](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1202)
|
||||||
|
- Make recreate statefulset only trigger when value true [#1240](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1240)
|
||||||
|
- Improve pod label patching with error handling and retry mechanism [#1231](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1231)
|
||||||
|
- Changed certificate serverName to pod+namespace [#1221](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1221)
|
||||||
|
- Add missing topologySpreadConstraint on RedisCluster follower [#1218](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1218)
|
||||||
|
|
||||||
|
### v0.19.0
|
||||||
|
#### January 12, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Add PDB and probes, drop unspecified acl in sentinel helm [#1123](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1123)
|
||||||
|
- Add master/replica service to redis replication [#1124](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1124)
|
||||||
|
- Add recreateStatefulSetOnUpdateInvalid helm chart value [#1127](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1127)
|
||||||
|
- Enhance RedisReplication controller and CRD with additional status [#1154](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1154)
|
||||||
|
- Support PDB in redisreplication [#1166](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1166)
|
||||||
|
- Enhance RedisSentinel reconciliation logic and update workflow [#1176](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1176)
|
||||||
|
- Support redis-cluster topologySpreadConstraints [#1177](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1177)
|
||||||
|
- Add event recording functionality for RedisCluster controller [#1182](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1182)
|
||||||
|
- Support topologySpreadConstraints in replication & sentinel [#1184](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1184)
|
||||||
|
- Redis-cluster add podAntiAffinity [#1180](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1180)
|
||||||
|
- Separate resources section for leader and follower [#1188](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1188)
|
||||||
|
- Enhance RedisCluster resource management by introducing separate resource handling for leader and follower [#1199](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1199)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- PDB value mapping in redis-sentinel [#1136](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1136)
|
||||||
|
- Chart render error when enable initcontainer [#1146](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1146)
|
||||||
|
- InitContainer enabled properties not define in template [#1152](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1152)
|
||||||
|
- Redis-cluster unexpected downscaling [#1173](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1173)
|
||||||
|
- Reduce the impact of Redis cluster intermediate states [#1178](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1178)
|
||||||
|
- Label selector mapping on redisreplication pdb [#1191](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1191)
|
||||||
|
|
||||||
|
### v0.18.1
|
||||||
|
#### November 7, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Support setting minReadySeconds on the stateful sets [#1023](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1023)
|
||||||
|
- Add tolerations to operator chart [#1051](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1051)
|
||||||
|
- Add image pull secret for redis operator [#1053](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1053)
|
||||||
|
- Add service monitor to redis sentinel chart [#1071](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1071)
|
||||||
|
- Add readiness/liveness probe to redis operator chart [#1072](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1072)
|
||||||
|
- Upgrade redis/sentinel image to 7.0.15 [#1099](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1099)
|
||||||
|
- Reconcile redissentinel only on master changed [#1122](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1122)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Fix indentation error when enable additional config [#1031](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1031)
|
||||||
|
- Fix field validate error when enable additional config for sentinel [#1033](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1033)
|
||||||
|
- Fix unknown field error when upgrade chart [#1034](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1034)
|
||||||
|
- Fix bad indentation on redis standalone additional configs [#1040](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1040)
|
||||||
|
- Fix attempt to repair disconnected/failed master nodes before failing over [#1105](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1105)
|
||||||
|
- Fix set controller probe endpoint handler [#1121](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1121)
|
||||||
|
|
||||||
|
### v0.18.0
|
||||||
|
#### July 11, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Added redisReplicationPassword values to connect secured replication [#1021](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1021)
|
||||||
|
- Added redis/redisreplication/redissentinel/rediscluster chart [#1007](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/1007)
|
||||||
|
- Added support for extra volume mounts for redis sentinel [#994](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/994)
|
||||||
|
- Added automountServiceAccountToken values for deployment and serviceaccount [#991](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/991)
|
||||||
|
- Added securityContext for exporter, initcontainers and sidecars [#987](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/987)
|
||||||
|
- Added security context values in operator chart [#973](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/973)
|
||||||
|
- Added rolling update sequence from leader to follower [#966](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/966)
|
||||||
|
- Added support for configurable probe handlers [#934](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/934)
|
||||||
|
- Added redis operator helm chart and release workflow [#941](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/941)
|
||||||
|
- Added support for other container engines [#947](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/947)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Added default port to enable `SENTINEL_PORT` environment [#999](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/999)
|
||||||
|
- ReadyReplicas need to be checked in `IsStatefulSetReady` [#993](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/993)
|
||||||
|
- watchNamespace value does not take effect in chart [#990](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/990)
|
||||||
|
- Sentinel should not reconcile until replication cluster ready [#964](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/964)
|
||||||
|
- Return ASAP after handling finalizer [#940](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/940)
|
||||||
|
- Check redis replication after handling finalizer [#936](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/936)
|
||||||
|
|
||||||
|
### v0.17.0
|
||||||
|
#### May 14, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- WATCH_NAMESPACE support multi namespace [#919](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/919)
|
||||||
|
- Add workflow to publish image to ghcr [#914](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/914)
|
||||||
|
- Probe use built-in, discarded healthcheck.sh [#907](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/907)
|
||||||
|
- Implement redis cluster ready state [#867](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/867)
|
||||||
|
- Add redisreplication status masterNode [#849](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/849)
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Runtime panic when delete rediscluster which disable persistent [#922](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/922)
|
||||||
|
- Runtime panic when storage param is empty [#887](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/887)
|
||||||
|
- Exporter can not connect to redis when enable tls [#902](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/902)
|
||||||
|
- Update status if not equal [#900](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/900)
|
||||||
|
- Should get the really leader count when scale in [#885](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/885)
|
||||||
|
- ClusterSlaves result should be cut [#884](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/884)
|
||||||
|
- Redis cluster update as scale out [#882](https://github.com/OT-CONTAINER-KIT/redis-operator/issues/882)
|
||||||
|
- Add common AddFinalizer for all api [#858](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/858)
|
||||||
|
|
||||||
|
### v0.16.0
|
||||||
|
#### March 27, 2024
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Added support for multiple CRDs and enhanced functionality
|
||||||
|
- Improved test coverage and CI/CD pipeline
|
||||||
|
- Enhanced Redis cluster management and scaling capabilities
|
||||||
|
- Added support for custom Redis configurations
|
||||||
|
- Implemented advanced security features
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Fixed various StatefulSet and service management issues
|
||||||
|
- Resolved Redis cluster scaling problems
|
||||||
|
- Fixed authentication and TLS connectivity issues
|
||||||
|
- Improved error handling and logging
|
||||||
|
|
||||||
|
### v0.15.1
|
||||||
|
#### September 24, 2023
|
||||||
|
|
||||||
|
**🪲 Bug Fixes**
|
||||||
|
|
||||||
|
- Added Custom EnvVars support [#631](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/631)
|
||||||
|
- Fix the backup and restore script and manifest [#624](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/624)
|
||||||
|
- e2e test for Redis Cluster [#623](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/623)
|
||||||
|
- Nil pointer de-reference in conversion webhook [#615](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/615)
|
||||||
|
- Fixes Restore script [#609](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/609)
|
||||||
|
- Close redis client to avoid resource leak [#572](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/572)
|
||||||
|
- fix:resize cluster’s pvc with wrong label [#562](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/562)
|
||||||
|
- Hardcoded 1Mi size of node-conf PVC in RedisCluster [#552](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/552)
|
||||||
|
- Cluster leader failover loop if there is only a single leader [#542](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/542)
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- e2e test for Redis Cluster [#623](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/623)
|
||||||
|
- Support ENABLE_WEBHOOKS env which cloud disable webhook server locally [#617](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/617)
|
||||||
|
- Status Field to Redis Cluster [#612](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/612)
|
||||||
|
- Support recreate statefulset of redissentinel [#607](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/607)
|
||||||
|
- Add support for multiple versions [#592](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/592)
|
||||||
|
|
||||||
|
**🎉 Refactors**
|
||||||
|
|
||||||
|
- Track examples/docs refactoring v1beta2 [#633](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/633)
|
||||||
|
- Refactor the backup and restore script and manifest [#624](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/624)
|
||||||
|
- Optional Volume split [#603](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/603) ( Breaking Change )
|
||||||
|
- kustomize install not working [#602](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/602)
|
||||||
|
- Support apply crds by kubectl apply --server-side [#601](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/601)
|
||||||
|
- Fix image path [#591](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/591)
|
||||||
|
- Add RBAC for redisreplications and redissentinels. [#590](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/590)
|
||||||
|
- Write the docs for the restore and backup [#588](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/588)
|
||||||
|
- Support redis sentinel pdb [#589](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/589)
|
||||||
|
- Migrate the Pipeline from Azure to Github actions [#571](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/571)
|
||||||
|
- Fix log pollution [#585](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/585)
|
||||||
|
|
||||||
|
### v0.15.0
|
||||||
|
##### July 17, 2023
|
||||||
|
|
||||||
|
**🐞 Bug Fixes**
|
||||||
|
|
||||||
|
- Fix Linter Issue #479
|
||||||
|
- Fix exporter ports enabled even when exporters disabled [#484](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/484)
|
||||||
|
- Corrected scenario "go-get-tool" in makefile [#499](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/499)
|
||||||
|
- Operator Crash when persistence is false/Disabled [#519](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/519) -- Breaking Change
|
||||||
|
- call of func checkAttachedSlave for 1 Master Replication [#523](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/523)
|
||||||
|
- Only created /node-conf VolumeMount for clusters [#532](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/532)
|
||||||
|
- Redis Sentinel Exporter ports in Env Vars [#533](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/533)
|
||||||
|
- Init Container tried to mount invalid volume name [#538](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/538)
|
||||||
|
- Cluster leader failover loop if there is only a single leader [#542](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/542)
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Add RedisExporter for sentinel [#440](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/440)
|
||||||
|
- Add InitContainer Field [#458](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/458)
|
||||||
|
- ACL redis via secret [#486](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/486)
|
||||||
|
- Adding Custom TerminationGracePeriodSeconds and additional fields for Sidecar [#487](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/487)
|
||||||
|
- Enable Support for Backup and Restore via script [#489](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/489)
|
||||||
|
- Support Scaling for Redis Cluster [#531](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/531) -- Breaking Change
|
||||||
|
|
||||||
|
**🎉 Refactors**
|
||||||
|
|
||||||
|
- Fixed StatefulSet(sentinel) Label for Service(Selector) [#442](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/442)
|
||||||
|
- Declare Module Correctly On sentinel [#478](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/478)
|
||||||
|
- Manage (Pod and Container) security Context explicitly [#518](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/518)
|
||||||
|
- Add watchnamespace function as per operator hub [#520](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/520)
|
||||||
|
- Remove sentinel default validation not effect [#535](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/535)
|
||||||
|
- Remove sentinel cluster size validation no effect [#536](https://github.com/OT-CONTAINER-KIT/redis-operator/pull/536)
|
||||||
|
|
||||||
|
### v0.14.0
|
||||||
|
##### Feburary 13, 2023
|
||||||
|
|
||||||
|
**🐞 Bug Fixes**
|
||||||
|
|
||||||
|
- Added check for persistent volume nil condition
|
||||||
|
- Fix crash with go panic
|
||||||
|
- Fix memory address bug and nil pointer
|
||||||
|
- CR annotations fixes w.r.t. to stateful set
|
||||||
|
- Fix issues with ARM64 support
|
||||||
|
|
||||||
|
**🎉 Features**
|
||||||
|
|
||||||
|
- Added serviceType functionality for redis standalone and cluster
|
||||||
|
- Added feature for additional volume mounts
|
||||||
|
- Added nodeSelectory and tolerations for redis cluster
|
||||||
|
- Added recreation logic for redis stateful sets
|
||||||
|
- Added replication mode support for the redis cluster
|
||||||
|
- Added sentinel support for replication failover
|
||||||
|
|
||||||
### v0.13.0
|
### v0.13.0
|
||||||
##### November 10, 2022
|
##### November 10, 2022
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||||||
|
kind: RedisCluster
|
||||||
|
metadata:
|
||||||
|
name: redis-cluster
|
||||||
|
spec:
|
||||||
|
clusterSize: 3
|
||||||
|
clusterVersion: v7
|
||||||
|
podSecurityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
persistenceEnabled: true
|
||||||
|
kubernetesConfig:
|
||||||
|
image: quay.io/opstree/redis:v7.0.12
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenScaled: Delete
|
||||||
|
whenDeleted: Delete
|
||||||
|
redisExporter:
|
||||||
|
enabled: false
|
||||||
|
image: quay.io/opstree/redis-exporter:v1.44.0
|
||||||
|
storage:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
# storageClassName: standard
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
nodeConfVolumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||||||
|
kind: RedisReplication
|
||||||
|
metadata:
|
||||||
|
name: redis-replication
|
||||||
|
spec:
|
||||||
|
clusterSize: 3
|
||||||
|
kubernetesConfig:
|
||||||
|
image: quay.io/opstree/redis:v7.0.12
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenScaled: Delete
|
||||||
|
whenDeleted: Delete
|
||||||
|
podSecurityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
storage:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
# storageClassName: standard
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
redisExporter:
|
||||||
|
enabled: false
|
||||||
|
image: quay.io/opstree/redis-exporter:v1.44.0
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||||||
|
kind: Redis
|
||||||
|
metadata:
|
||||||
|
name: redis-standalone
|
||||||
|
spec:
|
||||||
|
kubernetesConfig:
|
||||||
|
image: quay.io/opstree/redis:v7.0.12
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenScaled: Delete
|
||||||
|
whenDeleted: Delete
|
||||||
|
podSecurityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
storage:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
# storageClassName: standard
|
||||||
|
accessModes: ["ReadWriteOnce"]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
redisExporter:
|
||||||
|
enabled: false
|
||||||
|
image: quay.io/opstree/redis-exporter:v1.44.0
|
18
go.mod
18
go.mod
|
@ -13,6 +13,7 @@ require (
|
||||||
github.com/prometheus/client_golang v1.22.0
|
github.com/prometheus/client_golang v1.22.0
|
||||||
github.com/redis/go-redis/v9 v9.11.0
|
github.com/redis/go-redis/v9 v9.11.0
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
|
github.com/spf13/viper v1.19.0
|
||||||
github.com/stretchr/testify v1.10.0
|
github.com/stretchr/testify v1.10.0
|
||||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||||
k8s.io/api v0.29.4
|
k8s.io/api v0.29.4
|
||||||
|
@ -28,7 +29,7 @@ require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
|
@ -48,27 +49,37 @@ require (
|
||||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.16 // indirect
|
github.com/imdario/mergo v0.3.16 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/moby/spdystream v0.2.0 // indirect
|
github.com/moby/spdystream v0.2.0 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // indirect
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
github.com/prometheus/common v0.62.0 // indirect
|
github.com/prometheus/common v0.62.0 // indirect
|
||||||
github.com/prometheus/procfs v0.15.1 // indirect
|
github.com/prometheus/procfs v0.15.1 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.11.0 // indirect
|
||||||
|
github.com/spf13/cast v1.6.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.6 // indirect
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.26.0 // indirect
|
go.uber.org/zap v1.26.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||||
golang.org/x/net v0.38.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/oauth2 v0.24.0 // indirect
|
golang.org/x/oauth2 v0.27.0 // indirect
|
||||||
golang.org/x/sys v0.32.0 // indirect
|
golang.org/x/sys v0.32.0 // indirect
|
||||||
golang.org/x/term v0.30.0 // indirect
|
golang.org/x/term v0.30.0 // indirect
|
||||||
golang.org/x/text v0.23.0 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
|
@ -76,6 +87,7 @@ require (
|
||||||
golang.org/x/tools v0.31.0 // indirect
|
golang.org/x/tools v0.31.0 // indirect
|
||||||
google.golang.org/protobuf v1.36.5 // indirect
|
google.golang.org/protobuf v1.36.5 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
k8s.io/apiextensions-apiserver v0.29.3 // indirect
|
k8s.io/apiextensions-apiserver v0.29.3 // indirect
|
||||||
|
|
44
go.sum
44
go.sum
|
@ -25,8 +25,9 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||||
|
@ -42,6 +43,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
|
||||||
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
@ -110,6 +113,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
|
@ -135,9 +140,13 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
@ -165,10 +174,13 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||||
|
@ -185,17 +197,38 @@ github.com/redis/go-redis/v9 v9.11.0/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6
|
||||||
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
|
||||||
|
github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
|
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
@ -233,8 +266,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
|
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||||
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -302,6 +335,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
@ -309,6 +344,7 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
|
||||||
|
CRD_REF_DOCS_VERSION="v0.0.12"
|
||||||
|
|
||||||
|
echo "Starting API documentation generation..."
|
||||||
|
|
||||||
|
# Install crd-ref-docs if not present
|
||||||
|
echo "Installing crd-ref-docs ${CRD_REF_DOCS_VERSION}..."
|
||||||
|
go install github.com/elastic/crd-ref-docs@${CRD_REF_DOCS_VERSION}
|
||||||
|
|
||||||
|
# Use full path to crd-ref-docs
|
||||||
|
GOPATH=$(go env GOPATH)
|
||||||
|
if [ -z "$GOPATH" ]; then
|
||||||
|
GOPATH="$HOME/go"
|
||||||
|
fi
|
||||||
|
CRD_REF_DOCS="${GOPATH}/bin/crd-ref-docs"
|
||||||
|
|
||||||
|
if [ ! -f "${CRD_REF_DOCS}" ]; then
|
||||||
|
echo "Error: crd-ref-docs not found at ${CRD_REF_DOCS}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create output directory
|
||||||
|
OUTPUT_DIR="${REPO_ROOT}/docs/content/en/docs/CRD Reference/API Reference"
|
||||||
|
mkdir -p "${OUTPUT_DIR}"
|
||||||
|
|
||||||
|
echo "Generating API documentation..."
|
||||||
|
echo "Source path: ${REPO_ROOT}/api"
|
||||||
|
echo "Config file: ${SCRIPT_DIR}/config.yaml"
|
||||||
|
echo "Templates: ${SCRIPT_DIR}/templates"
|
||||||
|
echo "Output: ${OUTPUT_DIR}/_index.md"
|
||||||
|
|
||||||
|
# Generate the documentation using custom templates
|
||||||
|
"${CRD_REF_DOCS}" \
|
||||||
|
--source-path="${REPO_ROOT}/api" \
|
||||||
|
--config="${SCRIPT_DIR}/config.yaml" \
|
||||||
|
--templates-dir="${SCRIPT_DIR}/templates/markdown" \
|
||||||
|
--renderer=markdown \
|
||||||
|
--output-path="${OUTPUT_DIR}/_index.md"
|
||||||
|
|
||||||
|
echo "API documentation generated successfully at: ${OUTPUT_DIR}/_index.md"
|
|
@ -0,0 +1,10 @@
|
||||||
|
processor:
|
||||||
|
ignoreTypes:
|
||||||
|
- ".*List$"
|
||||||
|
- ".*Status$"
|
||||||
|
ignoreFields:
|
||||||
|
- "TypeMeta"
|
||||||
|
- "ObjectMeta"
|
||||||
|
render:
|
||||||
|
kubernetesVersion: "1.31"
|
||||||
|
renderer: "markdown"
|
|
@ -0,0 +1,19 @@
|
||||||
|
{{- define "gvDetails" -}}
|
||||||
|
{{- $gv := . -}}
|
||||||
|
|
||||||
|
## {{ $gv.GroupVersionString }}
|
||||||
|
|
||||||
|
{{ $gv.Doc }}
|
||||||
|
|
||||||
|
{{- if $gv.Kinds }}
|
||||||
|
### Resource Types
|
||||||
|
{{- range $gv.SortedKinds }}
|
||||||
|
- {{ $gv.TypeForKind . | markdownRenderTypeLink }}
|
||||||
|
{{- end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ range $gv.SortedTypes }}
|
||||||
|
{{ template "type" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{{- define "gvList" -}}
|
||||||
|
{{- $groupVersions := . -}}
|
||||||
|
---
|
||||||
|
title: "API Reference Documentation"
|
||||||
|
linkTitle: "API Docs"
|
||||||
|
weight: 10
|
||||||
|
date: 2025-01-27
|
||||||
|
description: >
|
||||||
|
Complete API reference documentation for Redis Operator CRDs
|
||||||
|
---
|
||||||
|
|
||||||
|
# API Reference
|
||||||
|
|
||||||
|
## Packages
|
||||||
|
{{- range $groupVersions }}
|
||||||
|
- {{ markdownRenderGVLink . }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ range $groupVersions }}
|
||||||
|
{{ template "gvDetails" . }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,43 @@
|
||||||
|
{{- define "type" -}}
|
||||||
|
{{- $type := . -}}
|
||||||
|
{{- if markdownShouldRenderType $type -}}
|
||||||
|
|
||||||
|
#### {{ $type.Name }}
|
||||||
|
|
||||||
|
{{ if $type.IsAlias }}_Underlying type:_ _{{ markdownRenderTypeLink $type.UnderlyingType }}_{{ end }}
|
||||||
|
|
||||||
|
{{ $type.Doc }}
|
||||||
|
|
||||||
|
{{ if $type.Validation -}}
|
||||||
|
_Validation:_
|
||||||
|
{{- range $type.Validation }}
|
||||||
|
- {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ if $type.References -}}
|
||||||
|
_Appears in:_
|
||||||
|
{{- range $type.SortedReferences }}
|
||||||
|
- {{ markdownRenderTypeLink . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{ if $type.Members -}}
|
||||||
|
| Field | Description | Default | Validation |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
{{ if $type.GVK -}}
|
||||||
|
| `apiVersion` _string_ | `{{ $type.GVK.Group }}/{{ $type.GVK.Version }}` | | |
|
||||||
|
| `kind` _string_ | `{{ $type.GVK.Kind }}` | | |
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ range $type.Members -}}
|
||||||
|
| `{{ .Name }}` _{{ markdownRenderType .Type }}_ | {{ template "type_members" . }} | {{ markdownRenderDefault .Default }} | {{ range .Validation -}} {{ markdownRenderFieldDoc . }} <br />{{ end }} |
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{ end -}}
|
||||||
|
|
||||||
|
{{/* EnumValues feature removed for compatibility */}}
|
||||||
|
|
||||||
|
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{{- define "type_members" -}}
|
||||||
|
{{- $field := . -}}
|
||||||
|
{{- if eq $field.Name "metadata" -}}
|
||||||
|
Refer to Kubernetes API documentation for fields of `metadata`.
|
||||||
|
{{- else -}}
|
||||||
|
{{ markdownRenderFieldDoc $field.Doc }}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
|
@ -108,6 +108,8 @@ func GenerateConfig() error {
|
||||||
cfg.Append("tls-key-file", redisTLSCertKey)
|
cfg.Append("tls-key-file", redisTLSCertKey)
|
||||||
cfg.Append("tls-ca-cert-file", redisTLSCAKey)
|
cfg.Append("tls-ca-cert-file", redisTLSCAKey)
|
||||||
cfg.Append("tls-auth-clients", "optional")
|
cfg.Append("tls-auth-clients", "optional")
|
||||||
|
// Sentinel should use tls for replication connection.
|
||||||
|
cfg.Append("tls-replication", "yes")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("Running sentinel without TLS mode")
|
fmt.Println("Running sentinel without TLS mode")
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,13 @@ package manager
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"time"
|
||||||
|
|
||||||
rvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redis/v1beta2"
|
rvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redis/v1beta2"
|
||||||
rcvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/rediscluster/v1beta2"
|
rcvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/rediscluster/v1beta2"
|
||||||
rrvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redisreplication/v1beta2"
|
rrvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redisreplication/v1beta2"
|
||||||
rsvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redissentinel/v1beta2"
|
rsvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redissentinel/v1beta2"
|
||||||
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common/operator"
|
||||||
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common/redis"
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common/redis"
|
||||||
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common/scheme"
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common/scheme"
|
||||||
rediscontroller "github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/redis"
|
rediscontroller "github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/redis"
|
||||||
|
@ -36,6 +38,7 @@ import (
|
||||||
"github.com/OT-CONTAINER-KIT/redis-operator/internal/monitoring"
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/monitoring"
|
||||||
coreWebhook "github.com/OT-CONTAINER-KIT/redis-operator/internal/webhook"
|
coreWebhook "github.com/OT-CONTAINER-KIT/redis-operator/internal/webhook"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
ctrl "sigs.k8s.io/controller-runtime"
|
ctrl "sigs.k8s.io/controller-runtime"
|
||||||
"sigs.k8s.io/controller-runtime/pkg/cache"
|
"sigs.k8s.io/controller-runtime/pkg/cache"
|
||||||
|
@ -72,6 +75,10 @@ func CMD() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "manager",
|
Use: "manager",
|
||||||
Short: "Start the Redis operator manager",
|
Short: "Start the Redis operator manager",
|
||||||
|
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// Bind all flags to viper
|
||||||
|
return viper.BindPFlags(cmd.Flags())
|
||||||
|
},
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
return runManager(opts)
|
return runManager(opts)
|
||||||
},
|
},
|
||||||
|
@ -92,7 +99,16 @@ func addFlags(cmd *cobra.Command, opts *managerOptions) {
|
||||||
cmd.Flags().IntVar(&opts.maxConcurrentReconciles, "max-concurrent-reconciles", 1, "Max concurrent reconciles")
|
cmd.Flags().IntVar(&opts.maxConcurrentReconciles, "max-concurrent-reconciles", 1, "Max concurrent reconciles")
|
||||||
cmd.Flags().StringVar(&opts.featureGatesString, "feature-gates", internalenv.GetFeatureGates(), "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
|
cmd.Flags().StringVar(&opts.featureGatesString, "feature-gates", internalenv.GetFeatureGates(), "A set of key=value pairs that describe feature gates for alpha/experimental features. "+
|
||||||
"Options are:\n GenerateConfigInInitContainer=true|false: enables using init container for config generation")
|
"Options are:\n GenerateConfigInInitContainer=true|false: enables using init container for config generation")
|
||||||
|
cmd.Flags().Duration(
|
||||||
|
operator.KubeClientTimeoutMGRFlag,
|
||||||
|
60*time.Second,
|
||||||
|
"Timeout for requests made by the Kubernetes API client.",
|
||||||
|
)
|
||||||
|
cmd.Flags().Float32(
|
||||||
|
operator.KubeClientQPSMGRFlag,
|
||||||
|
0,
|
||||||
|
"Maximum number of queries per second to the Kubernetes API.",
|
||||||
|
)
|
||||||
zapFlagSet := flag.NewFlagSet("zap", flag.ExitOnError)
|
zapFlagSet := flag.NewFlagSet("zap", flag.ExitOnError)
|
||||||
opts.zapOptions.BindFlags(zapFlagSet)
|
opts.zapOptions.BindFlags(zapFlagSet)
|
||||||
zapFlagSet.VisitAll(func(f *flag.Flag) {
|
zapFlagSet.VisitAll(func(f *flag.Flag) {
|
||||||
|
@ -114,8 +130,18 @@ func runManager(opts *managerOptions) error {
|
||||||
if err := setupFeatureGates(opts.featureGatesString); err != nil {
|
if err := setupFeatureGates(opts.featureGatesString); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Config to talk to k8s api server
|
||||||
|
cfg := ctrl.GetConfigOrDie()
|
||||||
|
|
||||||
|
if qps := float32(viper.GetFloat64(operator.KubeClientQPSMGRFlag)); qps > 0 {
|
||||||
|
cfg.QPS = qps
|
||||||
|
cfg.Burst = int(qps * 2)
|
||||||
|
}
|
||||||
|
cfg.Timeout = viper.GetDuration(operator.KubeClientTimeoutMGRFlag)
|
||||||
|
|
||||||
ctrlOptions := createControllerOptions(opts)
|
ctrlOptions := createControllerOptions(opts)
|
||||||
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrlOptions)
|
mgr, err := ctrl.NewManager(cfg, ctrlOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
setupLog.Error(err, "unable to start manager")
|
setupLog.Error(err, "unable to start manager")
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package operator
|
||||||
|
|
||||||
|
const (
|
||||||
|
KubeClientTimeoutMGRFlag = "kube-client-timeout"
|
||||||
|
KubeClientQPSMGRFlag = "kube-client-qps"
|
||||||
|
)
|
|
@ -71,11 +71,7 @@ func (c *checker) GetMasterFromReplication(ctx context.Context, rr *rr.RedisRepl
|
||||||
|
|
||||||
var masterPods []corev1.Pod
|
var masterPods []corev1.Pod
|
||||||
for _, pod := range pods.Items {
|
for _, pod := range pods.Items {
|
||||||
connInfo := &redis.ConnectionInfo{
|
connInfo := createConnectionInfo(ctx, pod, password, rr.Spec.TLS, c.k8s, rr.Namespace, "6379")
|
||||||
IP: pod.Status.PodIP,
|
|
||||||
Port: "6379",
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
isMaster, err := c.redis.Connect(connInfo).IsMaster(ctx)
|
isMaster, err := c.redis.Connect(connInfo).IsMaster(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return corev1.Pod{}, err
|
return corev1.Pod{}, err
|
||||||
|
@ -87,11 +83,7 @@ func (c *checker) GetMasterFromReplication(ctx context.Context, rr *rr.RedisRepl
|
||||||
|
|
||||||
var realMasterPod corev1.Pod
|
var realMasterPod corev1.Pod
|
||||||
for _, pod := range masterPods {
|
for _, pod := range masterPods {
|
||||||
connInfo := &redis.ConnectionInfo{
|
connInfo := createConnectionInfo(ctx, pod, password, rr.Spec.TLS, c.k8s, rr.Namespace, "6379")
|
||||||
IP: pod.Status.PodIP,
|
|
||||||
Port: "6379",
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
count, err := c.redis.Connect(connInfo).GetAttachedReplicaCount(ctx)
|
count, err := c.redis.Connect(connInfo).GetAttachedReplicaCount(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -2,6 +2,8 @@ package redis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -9,6 +11,7 @@ import (
|
||||||
rsvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redissentinel/v1beta2"
|
rsvb2 "github.com/OT-CONTAINER-KIT/redis-operator/api/redissentinel/v1beta2"
|
||||||
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common"
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/controller/common"
|
||||||
"github.com/OT-CONTAINER-KIT/redis-operator/internal/service/redis"
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/service/redis"
|
||||||
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/util/cryptutil"
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
@ -22,7 +25,7 @@ type Healer interface {
|
||||||
SentinelReset(ctx context.Context, rs *rsvb2.RedisSentinel) error
|
SentinelReset(ctx context.Context, rs *rsvb2.RedisSentinel) error
|
||||||
|
|
||||||
// UpdatePodRoleLabel connect to all redis pods and update pod role label `redis-role` to `master` or `slave` according to their role.
|
// UpdatePodRoleLabel connect to all redis pods and update pod role label `redis-role` to `master` or `slave` according to their role.
|
||||||
UpdateRedisRoleLabel(ctx context.Context, ns string, labels map[string]string, secret *commonapi.ExistingPasswordSecret) error
|
UpdateRedisRoleLabel(ctx context.Context, ns string, labels map[string]string, secret *commonapi.ExistingPasswordSecret, tlsConfig *commonapi.TLSConfig) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type healer struct {
|
type healer struct {
|
||||||
|
@ -37,7 +40,7 @@ func NewHealer(clientset kubernetes.Interface) Healer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *healer) UpdateRedisRoleLabel(ctx context.Context, ns string, labels map[string]string, secret *commonapi.ExistingPasswordSecret) error {
|
func (h *healer) UpdateRedisRoleLabel(ctx context.Context, ns string, labels map[string]string, secret *commonapi.ExistingPasswordSecret, tlsConfig *commonapi.TLSConfig) error {
|
||||||
selector := make([]string, 0, len(labels))
|
selector := make([]string, 0, len(labels))
|
||||||
for key, value := range labels {
|
for key, value := range labels {
|
||||||
selector = append(selector, fmt.Sprintf("%s=%s", key, value))
|
selector = append(selector, fmt.Sprintf("%s=%s", key, value))
|
||||||
|
@ -53,11 +56,7 @@ func (h *healer) UpdateRedisRoleLabel(ctx context.Context, ns string, labels map
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, pod := range pods.Items {
|
for _, pod := range pods.Items {
|
||||||
connInfo := &redis.ConnectionInfo{
|
connInfo := createConnectionInfo(ctx, pod, password, tlsConfig, h.k8s, ns, "6379")
|
||||||
IP: pod.Status.PodIP,
|
|
||||||
Port: "6379",
|
|
||||||
Password: password,
|
|
||||||
}
|
|
||||||
isMaster, err := h.redis.Connect(connInfo).IsMaster(ctx)
|
isMaster, err := h.redis.Connect(connInfo).IsMaster(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -98,11 +97,8 @@ func (h *healer) SentinelReset(ctx context.Context, rs *rsvb2.RedisSentinel) err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pod := range pods.Items {
|
for _, pod := range pods.Items {
|
||||||
connInfo := &redis.ConnectionInfo{
|
connInfo := createConnectionInfo(ctx, pod, sentinelPass, rs.Spec.TLS, h.k8s, rs.Namespace, "26379")
|
||||||
IP: pod.Status.PodIP,
|
|
||||||
Port: "26379",
|
|
||||||
Password: sentinelPass,
|
|
||||||
}
|
|
||||||
err = h.redis.Connect(connInfo).SentinelReset(ctx, rs.Spec.RedisSentinelConfig.MasterGroupName)
|
err = h.redis.Connect(connInfo).SentinelReset(ctx, rs.Spec.RedisSentinelConfig.MasterGroupName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -135,13 +131,10 @@ func (h *healer) SentinelMonitor(ctx context.Context, rs *rsvb2.RedisSentinel, m
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pod := range pods.Items {
|
for _, pod := range pods.Items {
|
||||||
connInfo := &redis.ConnectionInfo{
|
connInfo := createConnectionInfo(ctx, pod, sentinelPass, rs.Spec.TLS, h.k8s, rs.Namespace, "26379")
|
||||||
IP: pod.Status.PodIP,
|
|
||||||
Port: "26379",
|
|
||||||
Password: sentinelPass,
|
|
||||||
}
|
|
||||||
masterConnInfo := &redis.ConnectionInfo{
|
masterConnInfo := &redis.ConnectionInfo{
|
||||||
IP: master,
|
Host: master,
|
||||||
Port: "6379",
|
Port: "6379",
|
||||||
Password: masterPass,
|
Password: masterPass,
|
||||||
}
|
}
|
||||||
|
@ -177,3 +170,63 @@ func (h *healer) getSentinelPods(ctx context.Context, rs *rsvb2.RedisSentinel) (
|
||||||
}
|
}
|
||||||
return pods, nil
|
return pods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getRedisTLSConfig creates a TLS configuration for Redis connections
|
||||||
|
func getRedisTLSConfig(ctx context.Context, client kubernetes.Interface, namespace, tlsSecretName string) *tls.Config {
|
||||||
|
// This is a wrapper to access the k8sutils internal function
|
||||||
|
// We'll implement a simplified version here for now
|
||||||
|
secret, err := client.CoreV1().Secrets(namespace).Get(ctx, tlsSecretName, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
log.FromContext(ctx).Error(err, "Failed in getting TLS secret", "secretName", tlsSecretName, "namespace", namespace)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsClientCert, certExists := secret.Data["tls.crt"]
|
||||||
|
tlsClientKey, keyExists := secret.Data["tls.key"]
|
||||||
|
tlsCACert, caExists := secret.Data["ca.crt"]
|
||||||
|
|
||||||
|
if !certExists || !keyExists || !caExists {
|
||||||
|
log.FromContext(ctx).Error(fmt.Errorf("TLS secret missing required keys"), "TLS secret is missing required keys", "secretName", tlsSecretName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := tls.X509KeyPair(tlsClientCert, tlsClientKey)
|
||||||
|
if err != nil {
|
||||||
|
log.FromContext(ctx).Error(err, "Failed to load TLS key pair", "secretName", tlsSecretName)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertPool := x509.NewCertPool()
|
||||||
|
caCertPool.AppendCertsFromPEM(tlsCACert)
|
||||||
|
|
||||||
|
return &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
RootCAs: caCertPool,
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
_, _, err := cryptutil.VerifyCertificateExceptServerName(rawCerts, &tls.Config{RootCAs: caCertPool})
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// createConnectionInfo creates a Redis connection info with TLS support
|
||||||
|
func createConnectionInfo(ctx context.Context, pod v1.Pod, password string, tlsConfig *commonapi.TLSConfig, k8sClient kubernetes.Interface, namespace, port string) *redis.ConnectionInfo {
|
||||||
|
connInfo := &redis.ConnectionInfo{
|
||||||
|
Host: pod.Status.PodIP,
|
||||||
|
Port: port,
|
||||||
|
Password: password,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure TLS if enabled
|
||||||
|
if tlsConfig != nil && tlsConfig.Secret.SecretName != "" {
|
||||||
|
serviceName := common.GetHeadlessServiceNameFromPodName(pod.Name)
|
||||||
|
connInfo.Host = fmt.Sprintf("%s.%s.%s.svc.cluster.local", pod.Name, serviceName, namespace)
|
||||||
|
// Get TLS configuration
|
||||||
|
tlsCfg := getRedisTLSConfig(ctx, k8sClient, namespace, tlsConfig.Secret.SecretName)
|
||||||
|
connInfo.TLSConfig = tlsCfg
|
||||||
|
}
|
||||||
|
|
||||||
|
return connInfo
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetHeadlessServiceNameFromPodName trims the trailing ordinal (e.g. "-0", "-1") from a pod name to
|
||||||
|
// derive the headless service name. If the pod name does not contain a trailing
|
||||||
|
// ordinal segment the original name is returned unchanged.
|
||||||
|
//
|
||||||
|
// Examples for different Redis modes:
|
||||||
|
// - RedisReplication: "redis-replication-0" -> "redis-replication-headless"
|
||||||
|
// - RedisCluster Leader: "redis-cluster-leader-0" -> "redis-cluster-leader-headless"
|
||||||
|
// - RedisCluster Follower: "redis-cluster-follower-1" -> "redis-cluster-follower-headless"
|
||||||
|
// - RedisSentinel: "redis-sentinel-sentinel-0" -> "redis-sentinel-sentinel-headless"
|
||||||
|
func GetHeadlessServiceNameFromPodName(podName string) string {
|
||||||
|
// Find the last dash in the pod name. If there is none, return the whole name.
|
||||||
|
idx := strings.LastIndex(podName, "-")
|
||||||
|
if idx == -1 {
|
||||||
|
return podName
|
||||||
|
}
|
||||||
|
// Check whether the suffix after the last dash is a number (the StatefulSet
|
||||||
|
// ordinal). If it is, trim it to get the service name; otherwise return the
|
||||||
|
// original pod name.
|
||||||
|
if _, err := strconv.Atoi(podName[idx+1:]); err == nil {
|
||||||
|
return podName[:idx] + "-headless"
|
||||||
|
}
|
||||||
|
return podName
|
||||||
|
}
|
|
@ -43,11 +43,11 @@ type Reconciler struct {
|
||||||
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
instance := &rvb2.Redis{}
|
instance := &rvb2.Redis{}
|
||||||
|
|
||||||
err := r.Client.Get(context.TODO(), req.NamespacedName, instance)
|
err := r.Get(context.TODO(), req.NamespacedName, instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return intctrlutil.RequeueECheck(ctx, err, "failed to get redis instance")
|
return intctrlutil.RequeueECheck(ctx, err, "failed to get redis instance")
|
||||||
}
|
}
|
||||||
if instance.ObjectMeta.GetDeletionTimestamp() != nil {
|
if instance.GetDeletionTimestamp() != nil {
|
||||||
if err = k8sutils.HandleRedisFinalizer(ctx, r.Client, instance, RedisFinalizer); err != nil {
|
if err = k8sutils.HandleRedisFinalizer(ctx, r.Client, instance, RedisFinalizer); err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "failed to handle redis finalizer")
|
return intctrlutil.RequeueE(ctx, err, "failed to handle redis finalizer")
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,17 +56,17 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
logger := log.FromContext(ctx)
|
logger := log.FromContext(ctx)
|
||||||
instance := &rcvb2.RedisCluster{}
|
instance := &rcvb2.RedisCluster{}
|
||||||
|
|
||||||
err := r.Client.Get(context.TODO(), req.NamespacedName, instance)
|
err := r.Get(context.TODO(), req.NamespacedName, instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return intctrlutil.RequeueECheck(ctx, err, "failed to get redis cluster instance")
|
return intctrlutil.RequeueECheck(ctx, err, "failed to get redis cluster instance")
|
||||||
}
|
}
|
||||||
if instance.ObjectMeta.GetDeletionTimestamp() != nil {
|
if instance.GetDeletionTimestamp() != nil {
|
||||||
if err = k8sutils.HandleRedisClusterFinalizer(ctx, r.Client, instance, RedisClusterFinalizer); err != nil {
|
if err = k8sutils.HandleRedisClusterFinalizer(ctx, r.Client, instance, RedisClusterFinalizer); err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "failed to handle redis cluster finalizer")
|
return intctrlutil.RequeueE(ctx, err, "failed to handle redis cluster finalizer")
|
||||||
}
|
}
|
||||||
return intctrlutil.Reconciled()
|
return intctrlutil.Reconciled()
|
||||||
}
|
}
|
||||||
monitoring.RedisReplicationSkipReconcile.WithLabelValues(instance.Namespace, instance.Name).Set(0)
|
monitoring.RedisClusterSkipReconcile.WithLabelValues(instance.Namespace, instance.Name).Set(0)
|
||||||
if common.IsSkipReconcile(ctx, instance) {
|
if common.IsSkipReconcile(ctx, instance) {
|
||||||
monitoring.RedisClusterSkipReconcile.WithLabelValues(instance.Namespace, instance.Name).Set(1)
|
monitoring.RedisClusterSkipReconcile.WithLabelValues(instance.Namespace, instance.Name).Set(1)
|
||||||
return intctrlutil.Reconciled()
|
return intctrlutil.Reconciled()
|
||||||
|
@ -83,7 +83,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
|
|
||||||
// Check if the cluster is downscaled
|
// Check if the cluster is downscaled
|
||||||
if leaderCount := r.GetStatefulSetReplicas(ctx, instance.Namespace, instance.Name+"-leader"); leaderReplicas < leaderCount {
|
if leaderCount := r.GetStatefulSetReplicas(ctx, instance.Namespace, instance.Name+"-leader"); leaderReplicas < leaderCount {
|
||||||
if !(r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") && r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-follower")) {
|
if !r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") || !r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-follower") {
|
||||||
return intctrlutil.Reconciled()
|
return intctrlutil.Reconciled()
|
||||||
}
|
}
|
||||||
if masterCount := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, instance, "leader"); masterCount == leaderCount {
|
if masterCount := k8sutils.CheckRedisNodeCount(ctx, r.K8sClient, instance, "leader"); masterCount == leaderCount {
|
||||||
|
@ -178,12 +178,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !(r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") && r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-follower")) {
|
if !r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-leader") || !r.IsStatefulSetReady(ctx, instance.Namespace, instance.Name+"-follower") {
|
||||||
return intctrlutil.Reconciled()
|
return intctrlutil.Reconciled()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark the cluster status as bootstrapping if all the leader and follower nodes are ready
|
// Mark the cluster status as bootstrapping if all the leader and follower nodes are ready
|
||||||
if !(instance.Status.ReadyLeaderReplicas == leaderReplicas && instance.Status.ReadyFollowerReplicas == followerReplicas) {
|
if instance.Status.ReadyLeaderReplicas != leaderReplicas || instance.Status.ReadyFollowerReplicas != followerReplicas {
|
||||||
err = k8sutils.UpdateRedisClusterStatus(ctx, instance, rcvb2.RedisClusterBootstrap, rcvb2.BootstrapClusterReason, leaderReplicas, followerReplicas, r.Client)
|
err = k8sutils.UpdateRedisClusterStatus(ctx, instance, rcvb2.RedisClusterBootstrap, rcvb2.BootstrapClusterReason, leaderReplicas, followerReplicas, r.Client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
|
@ -230,7 +230,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("healthy leader count does not match desired; attempting to repair disconnected masters")
|
logger.Info("healthy leader count does not match desired; attempting to repair disconnected masters")
|
||||||
|
monitoring.RedisClusterRepairDisconnectedAttempt.WithLabelValues(instance.Namespace, instance.Name).Inc()
|
||||||
if err = k8sutils.RepairDisconnectedMasters(ctx, r.K8sClient, instance); err != nil {
|
if err = k8sutils.RepairDisconnectedMasters(ctx, r.K8sClient, instance); err != nil {
|
||||||
|
monitoring.RedisClusterRepairDisconnectedFailed.WithLabelValues(instance.Namespace, instance.Name).Inc()
|
||||||
logger.Error(err, "failed to repair disconnected masters")
|
logger.Error(err, "failed to repair disconnected masters")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +258,9 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
}
|
}
|
||||||
if int(totalReplicas) > 1 && unhealthyNodeCount >= int(totalReplicas)-1 {
|
if int(totalReplicas) > 1 && unhealthyNodeCount >= int(totalReplicas)-1 {
|
||||||
logger.Info("unhealthy nodes exist after attempting to repair disconnected masters; starting failover")
|
logger.Info("unhealthy nodes exist after attempting to repair disconnected masters; starting failover")
|
||||||
|
monitoring.RedisClusterResetAttempt.WithLabelValues(instance.Namespace, instance.Name).Inc()
|
||||||
if err = k8sutils.ExecuteFailoverOperation(ctx, r.K8sClient, instance); err != nil {
|
if err = k8sutils.ExecuteFailoverOperation(ctx, r.K8sClient, instance); err != nil {
|
||||||
|
monitoring.RedisClusterResetFailed.WithLabelValues(instance.Namespace, instance.Name).Inc()
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +291,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
|
||||||
|
|
||||||
for _, fakeRole := range []string{"leader", "follower"} {
|
for _, fakeRole := range []string{"leader", "follower"} {
|
||||||
labels := common.GetRedisLabels(instance.GetName()+"-"+fakeRole, common.SetupTypeCluster, fakeRole, instance.GetLabels())
|
labels := common.GetRedisLabels(instance.GetName()+"-"+fakeRole, common.SetupTypeCluster, fakeRole, instance.GetLabels())
|
||||||
if err = r.Healer.UpdateRedisRoleLabel(ctx, instance.GetNamespace(), labels, instance.Spec.KubernetesConfig.ExistingPasswordSecret); err != nil {
|
if err = r.Healer.UpdateRedisRoleLabel(ctx, instance.GetNamespace(), labels, instance.Spec.KubernetesConfig.ExistingPasswordSecret, instance.Spec.TLS); err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ type Reconciler struct {
|
||||||
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
instance := &rrvb2.RedisReplication{}
|
instance := &rrvb2.RedisReplication{}
|
||||||
|
|
||||||
err := r.Client.Get(ctx, req.NamespacedName, instance)
|
err := r.Get(ctx, req.NamespacedName, instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return intctrlutil.RequeueECheck(ctx, err, "failed to get RedisReplication instance")
|
return intctrlutil.RequeueECheck(ctx, err, "failed to get RedisReplication instance")
|
||||||
}
|
}
|
||||||
|
@ -137,12 +137,15 @@ func (r *Reconciler) reconcileService(ctx context.Context, instance *rrvb2.Redis
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Reconciler) reconcileRedis(ctx context.Context, instance *rrvb2.RedisReplication) (ctrl.Result, error) {
|
func (r *Reconciler) reconcileRedis(ctx context.Context, instance *rrvb2.RedisReplication) (ctrl.Result, error) {
|
||||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
var realMaster string
|
var realMaster string
|
||||||
masterNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "master")
|
masterNodes, err := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "master")
|
||||||
slaveNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "slave")
|
if err != nil {
|
||||||
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
|
}
|
||||||
|
slaveNodes, err := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "slave")
|
||||||
|
if err != nil {
|
||||||
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
|
}
|
||||||
if len(masterNodes) > 1 {
|
if len(masterNodes) > 1 {
|
||||||
log.FromContext(ctx).Info("Creating redis replication by executing replication creation commands")
|
log.FromContext(ctx).Info("Creating redis replication by executing replication creation commands")
|
||||||
|
|
||||||
|
@ -153,6 +156,22 @@ func (r *Reconciler) reconcileRedis(ctx context.Context, instance *rrvb2.RedisRe
|
||||||
if err := k8sutils.CreateMasterSlaveReplication(ctx, r.K8sClient, instance, masterNodes, realMaster); err != nil {
|
if err := k8sutils.CreateMasterSlaveReplication(ctx, r.K8sClient, instance, masterNodes, realMaster); err != nil {
|
||||||
return intctrlutil.RequeueAfter(ctx, time.Second*60, "")
|
return intctrlutil.RequeueAfter(ctx, time.Second*60, "")
|
||||||
}
|
}
|
||||||
|
} else if len(masterNodes) == 1 && len(slaveNodes) > 0 {
|
||||||
|
realMaster = masterNodes[0]
|
||||||
|
currentRealMaster := k8sutils.GetRedisReplicationRealMaster(ctx, r.K8sClient, instance, masterNodes)
|
||||||
|
|
||||||
|
if currentRealMaster == "" {
|
||||||
|
log.FromContext(ctx).Info("Detected disconnected slaves, reconfiguring replication",
|
||||||
|
"master", realMaster, "slaves", slaveNodes)
|
||||||
|
|
||||||
|
allPods := append(masterNodes, slaveNodes...)
|
||||||
|
if err := k8sutils.CreateMasterSlaveReplication(ctx, r.K8sClient, instance, allPods, realMaster); err != nil {
|
||||||
|
log.FromContext(ctx).Error(err, "Failed to reconfigure master-slave replication",
|
||||||
|
"master", realMaster, "slaves", slaveNodes)
|
||||||
|
return intctrlutil.RequeueAfter(ctx, time.Second*60, "")
|
||||||
|
}
|
||||||
|
log.FromContext(ctx).Info("Successfully reconfigured slave replication")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monitoring.RedisReplicationReplicasSizeMismatch.WithLabelValues(instance.Namespace, instance.Name).Set(0)
|
monitoring.RedisReplicationReplicasSizeMismatch.WithLabelValues(instance.Namespace, instance.Name).Set(0)
|
||||||
|
@ -171,17 +190,23 @@ func (r *Reconciler) reconcileStatus(ctx context.Context, instance *rrvb2.RedisR
|
||||||
var err error
|
var err error
|
||||||
var realMaster string
|
var realMaster string
|
||||||
|
|
||||||
masterNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "master")
|
masterNodes, err := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "master")
|
||||||
|
if err != nil {
|
||||||
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
|
}
|
||||||
realMaster = k8sutils.GetRedisReplicationRealMaster(ctx, r.K8sClient, instance, masterNodes)
|
realMaster = k8sutils.GetRedisReplicationRealMaster(ctx, r.K8sClient, instance, masterNodes)
|
||||||
if err = r.UpdateRedisReplicationMaster(ctx, instance, realMaster); err != nil {
|
if err = r.UpdateRedisReplicationMaster(ctx, instance, realMaster); err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
}
|
}
|
||||||
labels := common.GetRedisLabels(instance.GetName(), common.SetupTypeReplication, "replication", instance.GetLabels())
|
labels := common.GetRedisLabels(instance.GetName(), common.SetupTypeReplication, "replication", instance.GetLabels())
|
||||||
if err = r.Healer.UpdateRedisRoleLabel(ctx, instance.GetNamespace(), labels, instance.Spec.KubernetesConfig.ExistingPasswordSecret); err != nil {
|
if err = r.Healer.UpdateRedisRoleLabel(ctx, instance.GetNamespace(), labels, instance.Spec.KubernetesConfig.ExistingPasswordSecret, instance.Spec.TLS); err != nil {
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
slaveNodes := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "slave")
|
slaveNodes, err := k8sutils.GetRedisNodesByRole(ctx, r.K8sClient, instance, "slave")
|
||||||
|
if err != nil {
|
||||||
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
|
}
|
||||||
if realMaster != "" {
|
if realMaster != "" {
|
||||||
monitoring.RedisReplicationConnectedSlavesTotal.WithLabelValues(instance.Namespace, instance.Name).Set(float64(len(slaveNodes)))
|
monitoring.RedisReplicationConnectedSlavesTotal.WithLabelValues(instance.Namespace, instance.Name).Set(float64(len(slaveNodes)))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,7 +35,7 @@ type RedisSentinelReconciler struct {
|
||||||
func (r *RedisSentinelReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
func (r *RedisSentinelReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
||||||
instance := &rsvb2.RedisSentinel{}
|
instance := &rsvb2.RedisSentinel{}
|
||||||
|
|
||||||
err := r.Client.Get(ctx, req.NamespacedName, instance)
|
err := r.Get(ctx, req.NamespacedName, instance)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return intctrlutil.RequeueECheck(ctx, err, "failed to get RedisSentinel instance")
|
return intctrlutil.RequeueECheck(ctx, err, "failed to get RedisSentinel instance")
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,9 @@ func (r *RedisSentinelReconciler) Reconcile(ctx context.Context, req ctrl.Reques
|
||||||
reconcilers := []reconciler{
|
reconcilers := []reconciler{
|
||||||
{typ: "finalizer", rec: r.reconcileFinalizer},
|
{typ: "finalizer", rec: r.reconcileFinalizer},
|
||||||
{typ: "replication", rec: r.reconcileReplication},
|
{typ: "replication", rec: r.reconcileReplication},
|
||||||
{typ: "sentinel", rec: r.reconcileSentinel},
|
|
||||||
{typ: "pdb", rec: r.reconcilePDB},
|
{typ: "pdb", rec: r.reconcilePDB},
|
||||||
{typ: "service", rec: r.reconcileService},
|
{typ: "service", rec: r.reconcileService},
|
||||||
|
{typ: "sentinel", rec: r.reconcileSentinel},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, reconciler := range reconcilers {
|
for _, reconciler := range reconcilers {
|
||||||
|
@ -133,7 +133,7 @@ func (r *RedisSentinelReconciler) reconcileSentinel(ctx context.Context, instanc
|
||||||
return intctrlutil.RequeueE(ctx, err, "")
|
return intctrlutil.RequeueE(ctx, err, "")
|
||||||
} else {
|
} else {
|
||||||
if instance.Spec.RedisSentinelConfig.ResolveHostnames == "yes" {
|
if instance.Spec.RedisSentinelConfig.ResolveHostnames == "yes" {
|
||||||
monitorAddr = fmt.Sprintf("%s.%s-headless.%s.svc", master.Name, rr.Name, rr.Namespace)
|
monitorAddr = fmt.Sprintf("%s.%s.%s.svc.cluster.local", master.Name, common.GetHeadlessServiceNameFromPodName(master.Name), rr.Namespace)
|
||||||
} else {
|
} else {
|
||||||
monitorAddr = master.Status.PodIP
|
monitorAddr = master.Status.PodIP
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
ginkgo "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
gomega "github.com/onsi/gomega"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
@ -38,27 +38,27 @@ func RunSkipReconcileTest(k8sClient client.Client, config SkipReconcileTestConfi
|
||||||
annotations[config.SkipAnnotationKey] = "true"
|
annotations[config.SkipAnnotationKey] = "true"
|
||||||
config.Object.SetAnnotations(annotations)
|
config.Object.SetAnnotations(annotations)
|
||||||
|
|
||||||
Expect(k8sClient.Create(context.Background(), config.Object)).Should(Succeed())
|
gomega.Expect(k8sClient.Create(context.Background(), config.Object)).Should(gomega.Succeed())
|
||||||
defer func() {
|
defer func() {
|
||||||
Expect(k8sClient.Delete(context.Background(), config.Object)).Should(Succeed())
|
gomega.Expect(k8sClient.Delete(context.Background(), config.Object)).Should(gomega.Succeed())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
By("verifying that no StatefulSet is created when skip-reconcile is true")
|
ginkgo.By("verifying that no StatefulSet is created when skip-reconcile is true")
|
||||||
sts := &appsv1.StatefulSet{}
|
sts := &appsv1.StatefulSet{}
|
||||||
Consistently(func() error {
|
gomega.Consistently(func() error {
|
||||||
return k8sClient.Get(context.Background(), types.NamespacedName{
|
return k8sClient.Get(context.Background(), types.NamespacedName{
|
||||||
Name: config.StatefulSetName,
|
Name: config.StatefulSetName,
|
||||||
Namespace: config.Namespace,
|
Namespace: config.Namespace,
|
||||||
}, sts)
|
}, sts)
|
||||||
}, time.Second*3, time.Millisecond*500).ShouldNot(Succeed())
|
}, time.Second*3, time.Millisecond*500).ShouldNot(gomega.Succeed())
|
||||||
|
|
||||||
By("updating skip-reconcile annotation to false")
|
ginkgo.By("updating skip-reconcile annotation to false")
|
||||||
// Get the updated object from cluster
|
// Get the updated object from cluster
|
||||||
updatedObj := config.Object.DeepCopyObject().(client.Object)
|
updatedObj := config.Object.DeepCopyObject().(client.Object)
|
||||||
Expect(k8sClient.Get(context.Background(), types.NamespacedName{
|
gomega.Expect(k8sClient.Get(context.Background(), types.NamespacedName{
|
||||||
Name: config.Object.GetName(),
|
Name: config.Object.GetName(),
|
||||||
Namespace: config.Namespace,
|
Namespace: config.Namespace,
|
||||||
}, updatedObj)).Should(Succeed())
|
}, updatedObj)).Should(gomega.Succeed())
|
||||||
|
|
||||||
// Update the annotation
|
// Update the annotation
|
||||||
annotations = updatedObj.GetAnnotations()
|
annotations = updatedObj.GetAnnotations()
|
||||||
|
@ -67,15 +67,15 @@ func RunSkipReconcileTest(k8sClient client.Client, config SkipReconcileTestConfi
|
||||||
}
|
}
|
||||||
annotations[config.SkipAnnotationKey] = "false"
|
annotations[config.SkipAnnotationKey] = "false"
|
||||||
updatedObj.SetAnnotations(annotations)
|
updatedObj.SetAnnotations(annotations)
|
||||||
Expect(k8sClient.Update(context.Background(), updatedObj)).Should(Succeed())
|
gomega.Expect(k8sClient.Update(context.Background(), updatedObj)).Should(gomega.Succeed())
|
||||||
|
|
||||||
By("verifying that StatefulSet is created after skip-reconcile is set to false")
|
ginkgo.By("verifying that StatefulSet is created after skip-reconcile is set to false")
|
||||||
Eventually(func() error {
|
gomega.Eventually(func() error {
|
||||||
return k8sClient.Get(context.Background(), types.NamespacedName{
|
return k8sClient.Get(context.Background(), types.NamespacedName{
|
||||||
Name: config.StatefulSetName,
|
Name: config.StatefulSetName,
|
||||||
Namespace: config.Namespace,
|
Namespace: config.Namespace,
|
||||||
}, sts)
|
}, sts)
|
||||||
}, config.Timeout, config.Interval).Should(Succeed())
|
}, config.Timeout, config.Interval).Should(gomega.Succeed())
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTestObject creates a test object with the given name, namespace and annotations
|
// CreateTestObject creates a test object with the given name, namespace and annotations
|
||||||
|
|
|
@ -16,7 +16,7 @@ import (
|
||||||
//
|
//
|
||||||
// NOTE: when all slot been transferred, the node become slave of the transfer node.
|
// NOTE: when all slot been transferred, the node become slave of the transfer node.
|
||||||
func ReshardRedisCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, shardIdx int32, transferNodeIdx int32, remove bool) {
|
func ReshardRedisCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, shardIdx int32, transferNodeIdx int32, remove bool) {
|
||||||
transferNodeName := fmt.Sprintf("%s-leader-%d", cr.ObjectMeta.Name, transferNodeIdx)
|
transferNodeName := fmt.Sprintf("%s-leader-%d", cr.Name, transferNodeIdx)
|
||||||
redisClient := configureRedisClient(ctx, client, cr, transferNodeName)
|
redisClient := configureRedisClient(ctx, client, cr, transferNodeName)
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func RebalanceRedisClusterEmptyMasters(ctx context.Context, client kubernetes.In
|
||||||
// cmd = redis-cli --cluster rebalance <redis>:<port> --cluster-use-empty-masters -a <pass>
|
// cmd = redis-cli --cluster rebalance <redis>:<port> --cluster-use-empty-masters -a <pass>
|
||||||
var cmd []string
|
var cmd []string
|
||||||
pod := RedisDetails{
|
pod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-1",
|
PodName: cr.Name + "-leader-1",
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
cmd = []string{"redis-cli", "--cluster", "rebalance"}
|
cmd = []string{"redis-cli", "--cluster", "rebalance"}
|
||||||
|
@ -160,20 +160,20 @@ func RebalanceRedisClusterEmptyMasters(ctx context.Context, client kubernetes.In
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
|
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster rebalance command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster rebalance command is", "Command", cmd)
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-1")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-1")
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckIfEmptyMasters(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) {
|
func CheckIfEmptyMasters(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) {
|
||||||
totalRedisLeaderNodes := CheckRedisNodeCount(ctx, client, cr, "leader")
|
totalRedisLeaderNodes := CheckRedisNodeCount(ctx, client, cr, "leader")
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
for i := 0; i < int(totalRedisLeaderNodes); i++ {
|
for i := 0; i < int(totalRedisLeaderNodes); i++ {
|
||||||
pod := RedisDetails{
|
pod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(i),
|
PodName: cr.Name + "-leader-" + strconv.Itoa(i),
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
podNodeID := getRedisNodeID(ctx, client, cr, pod)
|
podNodeID := getRedisNodeID(ctx, client, cr, pod)
|
||||||
|
@ -192,7 +192,7 @@ func RebalanceRedisCluster(ctx context.Context, client kubernetes.Interface, cr
|
||||||
// cmd = redis-cli --cluster rebalance <redis>:<port> -a <pass>
|
// cmd = redis-cli --cluster rebalance <redis>:<port> -a <pass>
|
||||||
var cmd []string
|
var cmd []string
|
||||||
pod := RedisDetails{
|
pod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-1",
|
PodName: cr.Name + "-leader-1",
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
cmd = []string{"redis-cli", "--cluster", "rebalance"}
|
cmd = []string{"redis-cli", "--cluster", "rebalance"}
|
||||||
|
@ -212,10 +212,10 @@ func RebalanceRedisCluster(ctx context.Context, client kubernetes.Interface, cr
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
|
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster rebalance command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster rebalance command is", "Command", cmd)
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-1")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add redis cluster node would add a node to the existing redis cluster using redis-cli
|
// Add redis cluster node would add a node to the existing redis cluster using redis-cli
|
||||||
|
@ -224,11 +224,11 @@ func AddRedisNodeToCluster(ctx context.Context, client kubernetes.Interface, cr
|
||||||
activeRedisNode := CheckRedisNodeCount(ctx, client, cr, "leader")
|
activeRedisNode := CheckRedisNodeCount(ctx, client, cr, "leader")
|
||||||
|
|
||||||
newPod := RedisDetails{
|
newPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(int(activeRedisNode)),
|
PodName: cr.Name + "-leader-" + strconv.Itoa(int(activeRedisNode)),
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
existingPod := RedisDetails{
|
existingPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-0",
|
PodName: cr.Name + "-leader-0",
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,10 +251,10 @@ func AddRedisNodeToCluster(ctx context.Context, client kubernetes.Interface, cr
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
|
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster add-node command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster add-node command is", "Command", cmd)
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
}
|
}
|
||||||
|
|
||||||
// getAttachedFollowerNodeIDs would return a slice of redis followers attached to a redis leader
|
// getAttachedFollowerNodeIDs would return a slice of redis followers attached to a redis leader
|
||||||
|
@ -277,15 +277,15 @@ func getAttachedFollowerNodeIDs(ctx context.Context, redisClient *redis.Client,
|
||||||
// Remove redis follower node would remove all follower nodes of last leader node using redis-cli
|
// Remove redis follower node would remove all follower nodes of last leader node using redis-cli
|
||||||
func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, shardIdx int32) {
|
func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, shardIdx int32) {
|
||||||
var cmd []string
|
var cmd []string
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
existingPod := RedisDetails{
|
existingPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-0",
|
PodName: cr.Name + "-leader-0",
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
lastLeaderPod := RedisDetails{
|
lastLeaderPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(int(shardIdx)),
|
PodName: cr.Name + "-leader-" + strconv.Itoa(int(shardIdx)),
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +299,7 @@ func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes.
|
||||||
cmd = append(cmd, "-a")
|
cmd = append(cmd, "-a")
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
|
|
||||||
lastLeaderPodNodeID := getRedisNodeID(ctx, client, cr, lastLeaderPod)
|
lastLeaderPodNodeID := getRedisNodeID(ctx, client, cr, lastLeaderPod)
|
||||||
followerNodeIDs := getAttachedFollowerNodeIDs(ctx, redisClient, lastLeaderPodNodeID)
|
followerNodeIDs := getAttachedFollowerNodeIDs(ctx, redisClient, lastLeaderPodNodeID)
|
||||||
|
@ -314,7 +314,7 @@ func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes.
|
||||||
for _, followerNodeID := range followerNodeIDs {
|
for _, followerNodeID := range followerNodeIDs {
|
||||||
cmd = append(cmd, followerNodeID)
|
cmd = append(cmd, followerNodeID)
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster follower remove command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster follower remove command is", "Command", cmd)
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
cmd = cmd[:len(cmd)-1]
|
cmd = cmd[:len(cmd)-1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,16 +322,16 @@ func RemoveRedisFollowerNodesFromCluster(ctx context.Context, client kubernetes.
|
||||||
// Remove redis cluster node would remove last node to the existing redis cluster using redis-cli
|
// Remove redis cluster node would remove last node to the existing redis cluster using redis-cli
|
||||||
func RemoveRedisNodeFromCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, removePod RedisDetails) {
|
func RemoveRedisNodeFromCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, removePod RedisDetails) {
|
||||||
var cmd []string
|
var cmd []string
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
// currentRedisCount := CheckRedisNodeCount(ctx, client, cr, "leader")
|
// currentRedisCount := CheckRedisNodeCount(ctx, client, cr, "leader")
|
||||||
|
|
||||||
existingPod := RedisDetails{
|
existingPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-0",
|
PodName: cr.Name + "-leader-0",
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
//removePod := RedisDetails{
|
//removePod := RedisDetails{
|
||||||
// PodName: cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(int(currentRedisCount)-1),
|
// PodName: cr.Name + "-leader-" + strconv.Itoa(int(currentRedisCount)-1),
|
||||||
// Namespace: cr.Namespace,
|
// Namespace: cr.Namespace,
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
@ -355,13 +355,13 @@ func RemoveRedisNodeFromCluster(ctx context.Context, client kubernetes.Interface
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
|
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster leader remove command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster leader remove command is", "Command", cmd)
|
||||||
if getRedisClusterSlots(ctx, redisClient, removePodNodeID) != "0" {
|
if getRedisClusterSlots(ctx, redisClient, removePodNodeID) != "0" {
|
||||||
log.FromContext(ctx).V(1).Info("Skipping execution remove leader not empty", "cmd", cmd)
|
log.FromContext(ctx).V(1).Info("Skipping execution remove leader not empty", "cmd", cmd)
|
||||||
}
|
}
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyLeaderPod return true if the pod is leader/master
|
// verifyLeaderPod return true if the pod is leader/master
|
||||||
|
|
|
@ -19,9 +19,9 @@ import (
|
||||||
|
|
||||||
// CreateRedisLeaderPodDisruptionBudget check and create a PodDisruptionBudget for Leaders
|
// CreateRedisLeaderPodDisruptionBudget check and create a PodDisruptionBudget for Leaders
|
||||||
func ReconcileRedisPodDisruptionBudget(ctx context.Context, cr *rcvb2.RedisCluster, role string, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
func ReconcileRedisPodDisruptionBudget(ctx context.Context, cr *rcvb2.RedisCluster, role string, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
||||||
pdbName := cr.ObjectMeta.Name + "-" + role
|
pdbName := cr.Name + "-" + role
|
||||||
if pdbParams != nil && pdbParams.Enabled {
|
if pdbParams != nil && pdbParams.Enabled {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, cluster, role, cr.ObjectMeta.GetLabels())
|
labels := getRedisLabels(cr.Name, cluster, role, cr.GetLabels())
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
||||||
pdbDef := generatePodDisruptionBudgetDef(ctx, cr, role, pdbMeta, cr.Spec.RedisLeader.PodDisruptionBudget)
|
pdbDef := generatePodDisruptionBudgetDef(ctx, cr, role, pdbMeta, cr.Spec.RedisLeader.PodDisruptionBudget)
|
||||||
|
@ -41,9 +41,9 @@ func ReconcileRedisPodDisruptionBudget(ctx context.Context, cr *rcvb2.RedisClust
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReconcileSentinelPodDisruptionBudget(ctx context.Context, cr *rsvb2.RedisSentinel, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
func ReconcileSentinelPodDisruptionBudget(ctx context.Context, cr *rsvb2.RedisSentinel, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
||||||
pdbName := cr.ObjectMeta.Name + "-sentinel"
|
pdbName := cr.Name + "-sentinel"
|
||||||
if pdbParams != nil && pdbParams.Enabled {
|
if pdbParams != nil && pdbParams.Enabled {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, sentinel, "sentinel", cr.ObjectMeta.GetLabels())
|
labels := getRedisLabels(cr.Name, sentinel, "sentinel", cr.GetLabels())
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
||||||
pdbDef := generateSentinelPodDisruptionBudgetDef(ctx, cr, "sentinel", pdbMeta, pdbParams)
|
pdbDef := generateSentinelPodDisruptionBudgetDef(ctx, cr, "sentinel", pdbMeta, pdbParams)
|
||||||
|
@ -63,9 +63,9 @@ func ReconcileSentinelPodDisruptionBudget(ctx context.Context, cr *rsvb2.RedisSe
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReconcileReplicationPodDisruptionBudget(ctx context.Context, cr *rrvb2.RedisReplication, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
func ReconcileReplicationPodDisruptionBudget(ctx context.Context, cr *rrvb2.RedisReplication, pdbParams *common.RedisPodDisruptionBudget, cl kubernetes.Interface) error {
|
||||||
pdbName := cr.ObjectMeta.Name + "-replication"
|
pdbName := cr.Name + "-replication"
|
||||||
if pdbParams != nil && pdbParams.Enabled {
|
if pdbParams != nil && pdbParams.Enabled {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, replication, "replication", cr.GetObjectMeta().GetLabels())
|
labels := getRedisLabels(cr.Name, replication, "replication", cr.GetObjectMeta().GetLabels())
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
pdbMeta := generateObjectMetaInformation(pdbName, cr.Namespace, labels, annotations)
|
||||||
pdbDef := generateReplicationPodDisruptionBudgetDef(ctx, cr, "replication", pdbMeta, pdbParams)
|
pdbDef := generateReplicationPodDisruptionBudgetDef(ctx, cr, "replication", pdbMeta, pdbParams)
|
||||||
|
@ -87,7 +87,7 @@ func ReconcileReplicationPodDisruptionBudget(ctx context.Context, cr *rrvb2.Redi
|
||||||
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
||||||
func generatePodDisruptionBudgetDef(ctx context.Context, cr *rcvb2.RedisCluster, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
func generatePodDisruptionBudgetDef(ctx context.Context, cr *rcvb2.RedisCluster, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
||||||
lblSelector := LabelSelectors(map[string]string{
|
lblSelector := LabelSelectors(map[string]string{
|
||||||
"app": fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, role),
|
"app": fmt.Sprintf("%s-%s", cr.Name, role),
|
||||||
"role": role,
|
"role": role,
|
||||||
})
|
})
|
||||||
pdbTemplate := &policyv1.PodDisruptionBudget{
|
pdbTemplate := &policyv1.PodDisruptionBudget{
|
||||||
|
@ -114,7 +114,7 @@ func generatePodDisruptionBudgetDef(ctx context.Context, cr *rcvb2.RedisCluster,
|
||||||
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
||||||
func generateReplicationPodDisruptionBudgetDef(ctx context.Context, cr *rrvb2.RedisReplication, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
func generateReplicationPodDisruptionBudgetDef(ctx context.Context, cr *rrvb2.RedisReplication, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
||||||
lblSelector := LabelSelectors(map[string]string{
|
lblSelector := LabelSelectors(map[string]string{
|
||||||
"app": cr.ObjectMeta.Name,
|
"app": cr.Name,
|
||||||
"role": role,
|
"role": role,
|
||||||
})
|
})
|
||||||
pdbTemplate := &policyv1.PodDisruptionBudget{
|
pdbTemplate := &policyv1.PodDisruptionBudget{
|
||||||
|
@ -141,7 +141,7 @@ func generateReplicationPodDisruptionBudgetDef(ctx context.Context, cr *rrvb2.Re
|
||||||
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
// generatePodDisruptionBudgetDef will create a PodDisruptionBudget definition
|
||||||
func generateSentinelPodDisruptionBudgetDef(ctx context.Context, cr *rsvb2.RedisSentinel, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
func generateSentinelPodDisruptionBudgetDef(ctx context.Context, cr *rsvb2.RedisSentinel, role string, pdbMeta metav1.ObjectMeta, pdbParams *common.RedisPodDisruptionBudget) *policyv1.PodDisruptionBudget {
|
||||||
lblSelector := LabelSelectors(map[string]string{
|
lblSelector := LabelSelectors(map[string]string{
|
||||||
"app": fmt.Sprintf("%s-%s", cr.ObjectMeta.Name, role),
|
"app": fmt.Sprintf("%s-%s", cr.Name, role),
|
||||||
"role": role,
|
"role": role,
|
||||||
})
|
})
|
||||||
pdbTemplate := &policyv1.PodDisruptionBudget{
|
pdbTemplate := &policyv1.PodDisruptionBudget{
|
||||||
|
|
|
@ -69,7 +69,7 @@ func TestHandlePVCResizing_NoUpdateNeeded(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure no PVC update action occurred.
|
// Ensure no PVC update action occurred.
|
||||||
actions := cl.Fake.Actions()
|
actions := cl.Actions()
|
||||||
for _, action := range actions {
|
for _, action := range actions {
|
||||||
if action.GetVerb() == "update" {
|
if action.GetVerb() == "update" {
|
||||||
t.Errorf("Unexpected PVC update action: %#v", action)
|
t.Errorf("Unexpected PVC update action: %#v", action)
|
||||||
|
|
|
@ -42,21 +42,22 @@ func generateRedisClusterParams(ctx context.Context, cr *rcvb2.RedisCluster, rep
|
||||||
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
||||||
}
|
}
|
||||||
res := statefulSetParameters{
|
res := statefulSetParameters{
|
||||||
Replicas: &replicas,
|
Replicas: &replicas,
|
||||||
ClusterMode: true,
|
ClusterMode: true,
|
||||||
ClusterVersion: cr.Spec.ClusterVersion,
|
ClusterVersion: cr.Spec.ClusterVersion,
|
||||||
NodeSelector: params.NodeSelector,
|
NodeSelector: params.NodeSelector,
|
||||||
TopologySpreadConstraints: params.TopologySpreadConstraints,
|
TopologySpreadConstraints: params.TopologySpreadConstraints,
|
||||||
PodSecurityContext: cr.Spec.PodSecurityContext,
|
PodSecurityContext: cr.Spec.PodSecurityContext,
|
||||||
PriorityClassName: cr.Spec.PriorityClassName,
|
PriorityClassName: cr.Spec.PriorityClassName,
|
||||||
Affinity: params.Affinity,
|
Affinity: params.Affinity,
|
||||||
TerminationGracePeriodSeconds: params.TerminationGracePeriodSeconds,
|
TerminationGracePeriodSeconds: params.TerminationGracePeriodSeconds,
|
||||||
Tolerations: params.Tolerations,
|
Tolerations: params.Tolerations,
|
||||||
ServiceAccountName: cr.Spec.ServiceAccountName,
|
ServiceAccountName: cr.Spec.ServiceAccountName,
|
||||||
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
||||||
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
PersistentVolumeClaimRetentionPolicy: cr.Spec.KubernetesConfig.PersistentVolumeClaimRetentionPolicy,
|
||||||
HostNetwork: cr.Spec.HostNetwork,
|
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
||||||
MinReadySeconds: minreadyseconds,
|
HostNetwork: cr.Spec.HostNetwork,
|
||||||
|
MinReadySeconds: minreadyseconds,
|
||||||
}
|
}
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
res.EnableMetrics = cr.Spec.RedisExporter.Enabled
|
res.EnableMetrics = cr.Spec.RedisExporter.Enabled
|
||||||
|
@ -72,9 +73,9 @@ func generateRedisClusterParams(ctx context.Context, cr *rcvb2.RedisCluster, rep
|
||||||
if externalConfig != nil {
|
if externalConfig != nil {
|
||||||
res.ExternalConfig = externalConfig
|
res.ExternalConfig = externalConfig
|
||||||
}
|
}
|
||||||
if value, found := cr.ObjectMeta.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
if value, found := cr.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
||||||
res.RecreateStatefulSet = true
|
res.RecreateStatefulSet = true
|
||||||
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.ObjectMeta.GetAnnotations())
|
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.GetAnnotations())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -151,7 +152,7 @@ func generateRedisClusterContainerParams(ctx context.Context, cl kubernetes.Inte
|
||||||
nps := map[string]ports{} // pod name to ports
|
nps := map[string]ports{} // pod name to ports
|
||||||
replicas := cr.Spec.GetReplicaCounts(role)
|
replicas := cr.Spec.GetReplicaCounts(role)
|
||||||
for i := 0; i < int(replicas); i++ {
|
for i := 0; i < int(replicas); i++ {
|
||||||
svc, err := getService(ctx, cl, cr.Namespace, cr.ObjectMeta.Name+"-"+role+"-"+strconv.Itoa(i))
|
svc, err := getService(ctx, cl, cr.Namespace, cr.Name+"-"+role+"-"+strconv.Itoa(i))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err, "Cannot get service for Redis", "Setup.Type", role)
|
log.FromContext(ctx).Error(err, "Cannot get service for Redis", "Setup.Type", role)
|
||||||
} else {
|
} else {
|
||||||
|
@ -283,10 +284,10 @@ func (service RedisClusterSTS) getReplicaCount(cr *rcvb2.RedisCluster) int32 {
|
||||||
|
|
||||||
// CreateRedisClusterSetup will create Redis Setup for leader and follower
|
// CreateRedisClusterSetup will create Redis Setup for leader and follower
|
||||||
func (service RedisClusterSTS) CreateRedisClusterSetup(ctx context.Context, cr *rcvb2.RedisCluster, cl kubernetes.Interface) error {
|
func (service RedisClusterSTS) CreateRedisClusterSetup(ctx context.Context, cr *rcvb2.RedisCluster, cl kubernetes.Interface) error {
|
||||||
stateFulName := cr.ObjectMeta.Name + "-" + service.RedisStateFulType
|
stateFulName := cr.Name + "-" + service.RedisStateFulType
|
||||||
labels := getRedisLabels(stateFulName, cluster, service.RedisStateFulType, cr.ObjectMeta.Labels)
|
labels := getRedisLabels(stateFulName, cluster, service.RedisStateFulType, cr.Labels)
|
||||||
// add an common label for all pods in the cluster
|
// add an common label for all pods in the cluster
|
||||||
labels["cluster"] = cr.ObjectMeta.Name
|
labels["cluster"] = cr.Name
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
||||||
err := CreateOrUpdateStateFul(
|
err := CreateOrUpdateStateFul(
|
||||||
|
@ -309,8 +310,8 @@ func (service RedisClusterSTS) CreateRedisClusterSetup(ctx context.Context, cr *
|
||||||
|
|
||||||
// CreateRedisClusterService method will create service for Redis
|
// CreateRedisClusterService method will create service for Redis
|
||||||
func (service RedisClusterService) CreateRedisClusterService(ctx context.Context, cr *rcvb2.RedisCluster, cl kubernetes.Interface) error {
|
func (service RedisClusterService) CreateRedisClusterService(ctx context.Context, cr *rcvb2.RedisCluster, cl kubernetes.Interface) error {
|
||||||
serviceName := cr.ObjectMeta.Name + "-" + service.RedisServiceRole
|
serviceName := cr.Name + "-" + service.RedisServiceRole
|
||||||
labels := getRedisLabels(serviceName, cluster, service.RedisServiceRole, cr.ObjectMeta.Labels)
|
labels := getRedisLabels(serviceName, cluster, service.RedisServiceRole, cr.Labels)
|
||||||
var epp exporterPortProvider
|
var epp exporterPortProvider
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
epp = func() (port int, enable bool) {
|
epp = func() (port int, enable bool) {
|
||||||
|
@ -390,10 +391,10 @@ func (service RedisClusterService) CreateRedisClusterService(ctx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
masterObjectMetaInfo := generateObjectMetaInformation(
|
masterObjectMetaInfo := generateObjectMetaInformation(
|
||||||
cr.ObjectMeta.Name+"-master",
|
cr.Name+"-master",
|
||||||
cr.Namespace,
|
cr.Namespace,
|
||||||
map[string]string{
|
map[string]string{
|
||||||
"cluster": cr.ObjectMeta.Name,
|
"cluster": cr.Name,
|
||||||
common.RedisRoleLabelKey: common.RedisRoleLabelMaster,
|
common.RedisRoleLabelKey: common.RedisRoleLabelMaster,
|
||||||
"redis_setup_type": "cluster",
|
"redis_setup_type": "cluster",
|
||||||
},
|
},
|
||||||
|
@ -411,8 +412,8 @@ func (service RedisClusterService) createOrUpdateClusterNodePortService(ctx cont
|
||||||
replicas := cr.Spec.GetReplicaCounts(service.RedisServiceRole)
|
replicas := cr.Spec.GetReplicaCounts(service.RedisServiceRole)
|
||||||
|
|
||||||
for i := 0; i < int(replicas); i++ {
|
for i := 0; i < int(replicas); i++ {
|
||||||
serviceName := cr.ObjectMeta.Name + "-" + service.RedisServiceRole + "-" + strconv.Itoa(i)
|
serviceName := cr.Name + "-" + service.RedisServiceRole + "-" + strconv.Itoa(i)
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name+"-"+service.RedisServiceRole, cluster, service.RedisServiceRole, map[string]string{
|
labels := getRedisLabels(cr.Name+"-"+service.RedisServiceRole, cluster, service.RedisServiceRole, map[string]string{
|
||||||
"statefulset.kubernetes.io/pod-name": serviceName,
|
"statefulset.kubernetes.io/pod-name": serviceName,
|
||||||
})
|
})
|
||||||
annotations := generateServiceAnots(cr.ObjectMeta, nil, disableMetrics)
|
annotations := generateServiceAnots(cr.ObjectMeta, nil, disableMetrics)
|
||||||
|
|
|
@ -15,7 +15,7 @@ import (
|
||||||
|
|
||||||
// CreateReplicationService method will create replication service for Redis
|
// CreateReplicationService method will create replication service for Redis
|
||||||
func CreateReplicationService(ctx context.Context, cr *rrvb2.RedisReplication, cl kubernetes.Interface) error {
|
func CreateReplicationService(ctx context.Context, cr *rrvb2.RedisReplication, cl kubernetes.Interface) error {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, replication, "replication", cr.ObjectMeta.Labels)
|
labels := getRedisLabels(cr.Name, replication, "replication", cr.Labels)
|
||||||
|
|
||||||
epp := disableMetrics
|
epp := disableMetrics
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
|
@ -26,17 +26,17 @@ func CreateReplicationService(ctx context.Context, cr *rrvb2.RedisReplication, c
|
||||||
}
|
}
|
||||||
|
|
||||||
annotations := generateServiceAnots(cr.ObjectMeta, nil, epp)
|
annotations := generateServiceAnots(cr.ObjectMeta, nil, epp)
|
||||||
objectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name, cr.Namespace, labels, annotations)
|
objectMetaInfo := generateObjectMetaInformation(cr.Name, cr.Namespace, labels, annotations)
|
||||||
headlessObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-headless", cr.Namespace, labels, annotations)
|
headlessObjectMetaInfo := generateObjectMetaInformation(cr.Name+"-headless", cr.Namespace, labels, annotations)
|
||||||
additionalObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp))
|
additionalObjectMetaInfo := generateObjectMetaInformation(cr.Name+"-additional", cr.Namespace, labels, generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp))
|
||||||
masterLabels := util.MergeMap(
|
masterLabels := util.MergeMap(
|
||||||
labels, map[string]string{common.RedisRoleLabelKey: common.RedisRoleLabelMaster},
|
labels, map[string]string{common.RedisRoleLabelKey: common.RedisRoleLabelMaster},
|
||||||
)
|
)
|
||||||
replicaLabels := util.MergeMap(
|
replicaLabels := util.MergeMap(
|
||||||
labels, map[string]string{common.RedisRoleLabelKey: common.RedisRoleLabelSlave},
|
labels, map[string]string{common.RedisRoleLabelKey: common.RedisRoleLabelSlave},
|
||||||
)
|
)
|
||||||
masterObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-master", cr.Namespace, masterLabels, annotations)
|
masterObjectMetaInfo := generateObjectMetaInformation(cr.Name+"-master", cr.Namespace, masterLabels, annotations)
|
||||||
replicaObjectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name+"-replica", cr.Namespace, replicaLabels, annotations)
|
replicaObjectMetaInfo := generateObjectMetaInformation(cr.Name+"-replica", cr.Namespace, replicaLabels, annotations)
|
||||||
|
|
||||||
if err := CreateOrUpdateService(ctx, cr.Namespace, headlessObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, true, "ClusterIP", common.RedisPort, cl); err != nil {
|
if err := CreateOrUpdateService(ctx, cr.Namespace, headlessObjectMetaInfo, redisReplicationAsOwner(cr), disableMetrics, true, "ClusterIP", common.RedisPort, cl); err != nil {
|
||||||
log.FromContext(ctx).Error(err, "Cannot create replication headless service for Redis")
|
log.FromContext(ctx).Error(err, "Cannot create replication headless service for Redis")
|
||||||
|
@ -64,8 +64,8 @@ func CreateReplicationService(ctx context.Context, cr *rrvb2.RedisReplication, c
|
||||||
|
|
||||||
// CreateReplicationRedis will create a replication redis setup
|
// CreateReplicationRedis will create a replication redis setup
|
||||||
func CreateReplicationRedis(ctx context.Context, cr *rrvb2.RedisReplication, cl kubernetes.Interface) error {
|
func CreateReplicationRedis(ctx context.Context, cr *rrvb2.RedisReplication, cl kubernetes.Interface) error {
|
||||||
stateFulName := cr.ObjectMeta.Name
|
stateFulName := cr.Name
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, replication, "replication", cr.ObjectMeta.Labels)
|
labels := getRedisLabels(cr.Name, replication, "replication", cr.Labels)
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
||||||
|
|
||||||
|
@ -94,19 +94,20 @@ func generateRedisReplicationParams(cr *rrvb2.RedisReplication) statefulSetParam
|
||||||
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
||||||
}
|
}
|
||||||
res := statefulSetParameters{
|
res := statefulSetParameters{
|
||||||
Replicas: &replicas,
|
Replicas: &replicas,
|
||||||
ClusterMode: false,
|
ClusterMode: false,
|
||||||
NodeConfVolume: false,
|
NodeConfVolume: false,
|
||||||
NodeSelector: cr.Spec.NodeSelector,
|
NodeSelector: cr.Spec.NodeSelector,
|
||||||
PodSecurityContext: cr.Spec.PodSecurityContext,
|
PodSecurityContext: cr.Spec.PodSecurityContext,
|
||||||
PriorityClassName: cr.Spec.PriorityClassName,
|
PriorityClassName: cr.Spec.PriorityClassName,
|
||||||
Affinity: cr.Spec.Affinity,
|
Affinity: cr.Spec.Affinity,
|
||||||
Tolerations: cr.Spec.Tolerations,
|
Tolerations: cr.Spec.Tolerations,
|
||||||
TopologySpreadConstraints: cr.Spec.TopologySpreadConstrains,
|
TopologySpreadConstraints: cr.Spec.TopologySpreadConstrains,
|
||||||
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
||||||
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
||||||
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
PersistentVolumeClaimRetentionPolicy: cr.Spec.KubernetesConfig.PersistentVolumeClaimRetentionPolicy,
|
||||||
MinReadySeconds: minreadyseconds,
|
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
||||||
|
MinReadySeconds: minreadyseconds,
|
||||||
}
|
}
|
||||||
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
||||||
res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets
|
res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets
|
||||||
|
@ -123,9 +124,9 @@ func generateRedisReplicationParams(cr *rrvb2.RedisReplication) statefulSetParam
|
||||||
if cr.Spec.ServiceAccountName != nil {
|
if cr.Spec.ServiceAccountName != nil {
|
||||||
res.ServiceAccountName = cr.Spec.ServiceAccountName
|
res.ServiceAccountName = cr.Spec.ServiceAccountName
|
||||||
}
|
}
|
||||||
if value, found := cr.ObjectMeta.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
if value, found := cr.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
||||||
res.RecreateStatefulSet = true
|
res.RecreateStatefulSet = true
|
||||||
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.ObjectMeta.GetAnnotations())
|
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.GetAnnotations())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,8 +58,8 @@ func CreateRedisSentinelService(ctx context.Context, cr *rsvb2.RedisSentinel, cl
|
||||||
|
|
||||||
// Create Redis Sentinel Cluster Setup
|
// Create Redis Sentinel Cluster Setup
|
||||||
func (service RedisSentinelSTS) CreateRedisSentinelSetup(ctx context.Context, client kubernetes.Interface, cr *rsvb2.RedisSentinel, cl kubernetes.Interface, ctrlClient client.Client) error {
|
func (service RedisSentinelSTS) CreateRedisSentinelSetup(ctx context.Context, client kubernetes.Interface, cr *rsvb2.RedisSentinel, cl kubernetes.Interface, ctrlClient client.Client) error {
|
||||||
stateFulName := cr.ObjectMeta.Name + "-" + service.RedisStateFulType
|
stateFulName := cr.Name + "-" + service.RedisStateFulType
|
||||||
labels := getRedisLabels(stateFulName, sentinel, service.RedisStateFulType, cr.ObjectMeta.Labels)
|
labels := getRedisLabels(stateFulName, sentinel, service.RedisStateFulType, cr.Labels)
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations)
|
||||||
containerParams, err := generateRedisSentinelContainerParams(ctx, client, cr, service.ReadinessProbe, service.LivenessProbe, ctrlClient)
|
containerParams, err := generateRedisSentinelContainerParams(ctx, client, cr, service.ReadinessProbe, service.LivenessProbe, ctrlClient)
|
||||||
|
@ -92,20 +92,21 @@ func generateRedisSentinelParams(ctx context.Context, cr *rsvb2.RedisSentinel, r
|
||||||
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
||||||
}
|
}
|
||||||
res := statefulSetParameters{
|
res := statefulSetParameters{
|
||||||
Replicas: &replicas,
|
Replicas: &replicas,
|
||||||
ClusterMode: false,
|
ClusterMode: false,
|
||||||
NodeConfVolume: false,
|
NodeConfVolume: false,
|
||||||
NodeSelector: cr.Spec.NodeSelector,
|
NodeSelector: cr.Spec.NodeSelector,
|
||||||
PodSecurityContext: cr.Spec.PodSecurityContext,
|
PodSecurityContext: cr.Spec.PodSecurityContext,
|
||||||
PriorityClassName: cr.Spec.PriorityClassName,
|
PriorityClassName: cr.Spec.PriorityClassName,
|
||||||
Affinity: affinity,
|
Affinity: affinity,
|
||||||
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
||||||
Tolerations: cr.Spec.Tolerations,
|
Tolerations: cr.Spec.Tolerations,
|
||||||
TopologySpreadConstraints: cr.Spec.TopologySpreadConstrains,
|
TopologySpreadConstraints: cr.Spec.TopologySpreadConstrains,
|
||||||
ServiceAccountName: cr.Spec.ServiceAccountName,
|
ServiceAccountName: cr.Spec.ServiceAccountName,
|
||||||
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
||||||
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
PersistentVolumeClaimRetentionPolicy: cr.Spec.KubernetesConfig.PersistentVolumeClaimRetentionPolicy,
|
||||||
MinReadySeconds: minreadyseconds,
|
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
||||||
|
MinReadySeconds: minreadyseconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
||||||
|
@ -117,9 +118,9 @@ func generateRedisSentinelParams(ctx context.Context, cr *rsvb2.RedisSentinel, r
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
res.EnableMetrics = cr.Spec.RedisExporter.Enabled
|
res.EnableMetrics = cr.Spec.RedisExporter.Enabled
|
||||||
}
|
}
|
||||||
if value, found := cr.ObjectMeta.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
if value, found := cr.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
||||||
res.RecreateStatefulSet = true
|
res.RecreateStatefulSet = true
|
||||||
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.ObjectMeta.GetAnnotations())
|
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.GetAnnotations())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
@ -211,8 +212,8 @@ func (service RedisSentinelSTS) getSentinelCount(cr *rsvb2.RedisSentinel) int32
|
||||||
|
|
||||||
// Create the Service for redis sentinel
|
// Create the Service for redis sentinel
|
||||||
func (service RedisSentinelService) CreateRedisSentinelService(ctx context.Context, cr *rsvb2.RedisSentinel, cl kubernetes.Interface) error {
|
func (service RedisSentinelService) CreateRedisSentinelService(ctx context.Context, cr *rsvb2.RedisSentinel, cl kubernetes.Interface) error {
|
||||||
serviceName := cr.ObjectMeta.Name + "-" + service.RedisServiceRole
|
serviceName := cr.Name + "-" + service.RedisServiceRole
|
||||||
labels := getRedisLabels(serviceName, sentinel, service.RedisServiceRole, cr.ObjectMeta.Labels)
|
labels := getRedisLabels(serviceName, sentinel, service.RedisServiceRole, cr.Labels)
|
||||||
var epp exporterPortProvider
|
var epp exporterPortProvider
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
epp = func() (port int, enable bool) {
|
epp = func() (port int, enable bool) {
|
||||||
|
@ -330,7 +331,11 @@ func getRedisReplicationMasterPod(ctx context.Context, client kubernetes.Interfa
|
||||||
log.FromContext(ctx).V(1).Info("Successfully got RedisReplication", "replication name", replicationName, "namespace", replicationNamespace)
|
log.FromContext(ctx).V(1).Info("Successfully got RedisReplication", "replication name", replicationName, "namespace", replicationNamespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
masterPods := GetRedisNodesByRole(ctx, client, &replicationInstance, "master")
|
masterPods, err := GetRedisNodesByRole(ctx, client, &replicationInstance, "master")
|
||||||
|
if err != nil {
|
||||||
|
log.FromContext(ctx).Error(err, "Failed to get RedisReplication master pods", "replication name", replicationName, "namespace", replicationNamespace)
|
||||||
|
return emptyRedisInfo
|
||||||
|
}
|
||||||
if len(masterPods) == 0 {
|
if len(masterPods) == 0 {
|
||||||
log.FromContext(ctx).Error(errors.New("no master pods found"), "")
|
log.FromContext(ctx).Error(errors.New("no master pods found"), "")
|
||||||
return emptyRedisInfo
|
return emptyRedisInfo
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
|
|
||||||
// CreateStandaloneService method will create standalone service for Redis
|
// CreateStandaloneService method will create standalone service for Redis
|
||||||
func CreateStandaloneService(ctx context.Context, cr *rvb2.Redis, cl kubernetes.Interface) error {
|
func CreateStandaloneService(ctx context.Context, cr *rvb2.Redis, cl kubernetes.Interface) error {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, standalone, "standalone", cr.ObjectMeta.Labels)
|
labels := getRedisLabels(cr.Name, standalone, "standalone", cr.Labels)
|
||||||
var epp exporterPortProvider
|
var epp exporterPortProvider
|
||||||
if cr.Spec.RedisExporter != nil {
|
if cr.Spec.RedisExporter != nil {
|
||||||
epp = func() (port int, enable bool) {
|
epp = func() (port int, enable bool) {
|
||||||
|
@ -24,19 +24,19 @@ func CreateStandaloneService(ctx context.Context, cr *rvb2.Redis, cl kubernetes.
|
||||||
epp = disableMetrics
|
epp = disableMetrics
|
||||||
}
|
}
|
||||||
objectMetaInfo := generateObjectMetaInformation(
|
objectMetaInfo := generateObjectMetaInformation(
|
||||||
cr.ObjectMeta.Name,
|
cr.Name,
|
||||||
cr.Namespace,
|
cr.Namespace,
|
||||||
labels,
|
labels,
|
||||||
generateServiceAnots(cr.ObjectMeta, nil, epp),
|
generateServiceAnots(cr.ObjectMeta, nil, epp),
|
||||||
)
|
)
|
||||||
headlessObjectMetaInfo := generateObjectMetaInformation(
|
headlessObjectMetaInfo := generateObjectMetaInformation(
|
||||||
cr.ObjectMeta.Name+"-headless",
|
cr.Name+"-headless",
|
||||||
cr.Namespace,
|
cr.Namespace,
|
||||||
labels,
|
labels,
|
||||||
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetHeadlessServiceAnnotations(), epp),
|
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetHeadlessServiceAnnotations(), epp),
|
||||||
)
|
)
|
||||||
additionalObjectMetaInfo := generateObjectMetaInformation(
|
additionalObjectMetaInfo := generateObjectMetaInformation(
|
||||||
cr.ObjectMeta.Name+"-additional",
|
cr.Name+"-additional",
|
||||||
cr.Namespace,
|
cr.Namespace,
|
||||||
labels,
|
labels,
|
||||||
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp),
|
generateServiceAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.GetServiceAnnotations(), epp),
|
||||||
|
@ -73,9 +73,9 @@ func CreateStandaloneService(ctx context.Context, cr *rvb2.Redis, cl kubernetes.
|
||||||
|
|
||||||
// CreateStandaloneRedis will create a standalone redis setup
|
// CreateStandaloneRedis will create a standalone redis setup
|
||||||
func CreateStandaloneRedis(ctx context.Context, cr *rvb2.Redis, cl kubernetes.Interface) error {
|
func CreateStandaloneRedis(ctx context.Context, cr *rvb2.Redis, cl kubernetes.Interface) error {
|
||||||
labels := getRedisLabels(cr.ObjectMeta.Name, standalone, "standalone", cr.ObjectMeta.Labels)
|
labels := getRedisLabels(cr.Name, standalone, "standalone", cr.Labels)
|
||||||
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations)
|
||||||
objectMetaInfo := generateObjectMetaInformation(cr.ObjectMeta.Name, cr.Namespace, labels, annotations)
|
objectMetaInfo := generateObjectMetaInformation(cr.Name, cr.Namespace, labels, annotations)
|
||||||
err := CreateOrUpdateStateFul(
|
err := CreateOrUpdateStateFul(
|
||||||
ctx,
|
ctx,
|
||||||
cl,
|
cl,
|
||||||
|
@ -102,18 +102,19 @@ func generateRedisStandaloneParams(cr *rvb2.Redis) statefulSetParameters {
|
||||||
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds
|
||||||
}
|
}
|
||||||
res := statefulSetParameters{
|
res := statefulSetParameters{
|
||||||
Replicas: &replicas,
|
Replicas: &replicas,
|
||||||
ClusterMode: false,
|
ClusterMode: false,
|
||||||
NodeConfVolume: false,
|
NodeConfVolume: false,
|
||||||
NodeSelector: cr.Spec.NodeSelector,
|
NodeSelector: cr.Spec.NodeSelector,
|
||||||
PodSecurityContext: cr.Spec.PodSecurityContext,
|
PodSecurityContext: cr.Spec.PodSecurityContext,
|
||||||
PriorityClassName: cr.Spec.PriorityClassName,
|
PriorityClassName: cr.Spec.PriorityClassName,
|
||||||
Affinity: cr.Spec.Affinity,
|
Affinity: cr.Spec.Affinity,
|
||||||
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds,
|
||||||
Tolerations: cr.Spec.Tolerations,
|
Tolerations: cr.Spec.Tolerations,
|
||||||
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy,
|
||||||
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
PersistentVolumeClaimRetentionPolicy: cr.Spec.KubernetesConfig.PersistentVolumeClaimRetentionPolicy,
|
||||||
MinReadySeconds: minreadyseconds,
|
IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations,
|
||||||
|
MinReadySeconds: minreadyseconds,
|
||||||
}
|
}
|
||||||
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
if cr.Spec.KubernetesConfig.ImagePullSecrets != nil {
|
||||||
res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets
|
res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets
|
||||||
|
@ -130,9 +131,9 @@ func generateRedisStandaloneParams(cr *rvb2.Redis) statefulSetParameters {
|
||||||
if cr.Spec.ServiceAccountName != nil {
|
if cr.Spec.ServiceAccountName != nil {
|
||||||
res.ServiceAccountName = cr.Spec.ServiceAccountName
|
res.ServiceAccountName = cr.Spec.ServiceAccountName
|
||||||
}
|
}
|
||||||
if value, found := cr.ObjectMeta.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
if value, found := cr.GetAnnotations()[common.AnnotationKeyRecreateStatefulset]; found && value == "true" {
|
||||||
res.RecreateStatefulSet = true
|
res.RecreateStatefulSet = true
|
||||||
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.ObjectMeta.GetAnnotations())
|
res.RecreateStatefulsetStrategy = getDeletionPropagationStrategy(cr.GetAnnotations())
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ func getRedisServerAddress(ctx context.Context, client kubernetes.Interface, rd
|
||||||
|
|
||||||
// getRedisHostname will return the complete FQDN for redis
|
// getRedisHostname will return the complete FQDN for redis
|
||||||
func getRedisHostname(redisInfo RedisDetails, cr *rcvb2.RedisCluster, role string) string {
|
func getRedisHostname(redisInfo RedisDetails, cr *rcvb2.RedisCluster, role string) string {
|
||||||
fqdn := fmt.Sprintf("%s.%s-%s-headless.%s.svc", redisInfo.PodName, cr.ObjectMeta.Name, role, cr.Namespace)
|
fqdn := fmt.Sprintf("%s.%s-%s-headless.%s.svc", redisInfo.PodName, cr.Name, role, cr.Namespace)
|
||||||
return fqdn
|
return fqdn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ func CreateSingleLeaderRedisCommand(ctx context.Context, cr *rcvb2.RedisCluster)
|
||||||
// RepairDisconnectedMasters attempts to repair disconnected/failed masters by issuing
|
// RepairDisconnectedMasters attempts to repair disconnected/failed masters by issuing
|
||||||
// a CLUSTER MEET with the updated address of the host
|
// a CLUSTER MEET with the updated address of the host
|
||||||
func RepairDisconnectedMasters(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) error {
|
func RepairDisconnectedMasters(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) error {
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
return repairDisconnectedMasters(ctx, client, cr, redisClient)
|
return repairDisconnectedMasters(ctx, client, cr, redisClient)
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ func CreateMultipleLeaderRedisCommand(ctx context.Context, client kubernetes.Int
|
||||||
replicas := cr.Spec.GetReplicaCounts("leader")
|
replicas := cr.Spec.GetReplicaCounts("leader")
|
||||||
|
|
||||||
for podCount := 0; podCount < int(replicas); podCount++ {
|
for podCount := 0; podCount < int(replicas); podCount++ {
|
||||||
podName := cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(podCount)
|
podName := cr.Name + "-leader-" + strconv.Itoa(podCount)
|
||||||
var address string
|
var address string
|
||||||
if cr.Spec.ClusterVersion != nil && *cr.Spec.ClusterVersion == "v7" {
|
if cr.Spec.ClusterVersion != nil && *cr.Spec.ClusterVersion == "v7" {
|
||||||
address = getRedisHostname(RedisDetails{PodName: podName, Namespace: cr.Namespace}, cr, "leader") + fmt.Sprintf(":%d", *cr.Spec.Port)
|
address = getRedisHostname(RedisDetails{PodName: podName, Namespace: cr.Namespace}, cr, "leader") + fmt.Sprintf(":%d", *cr.Spec.Port)
|
||||||
|
@ -183,9 +183,9 @@ func ExecuteRedisClusterCommand(ctx context.Context, client kubernetes.Interface
|
||||||
cmd = append(cmd, "-a")
|
cmd = append(cmd, "-a")
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
log.FromContext(ctx).V(1).Info("Redis cluster creation command is", "Command", cmd)
|
log.FromContext(ctx).V(1).Info("Redis cluster creation command is", "Command", cmd)
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRedisTLSArgs(tlsConfig *common.TLSConfig, clientHost string) []string {
|
func getRedisTLSArgs(tlsConfig *common.TLSConfig, clientHost string) []string {
|
||||||
|
@ -240,7 +240,7 @@ func ExecuteRedisReplicationCommand(ctx context.Context, client kubernetes.Inter
|
||||||
leaderCounts := cr.Spec.GetReplicaCounts("leader")
|
leaderCounts := cr.Spec.GetReplicaCounts("leader")
|
||||||
followerPerLeader := followerCounts / leaderCounts
|
followerPerLeader := followerCounts / leaderCounts
|
||||||
|
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
nodes, err := clusterNodes(ctx, redisClient)
|
nodes, err := clusterNodes(ctx, redisClient)
|
||||||
|
@ -250,11 +250,11 @@ func ExecuteRedisReplicationCommand(ctx context.Context, client kubernetes.Inter
|
||||||
for followerIdx := 0; followerIdx <= int(followerCounts)-1; {
|
for followerIdx := 0; followerIdx <= int(followerCounts)-1; {
|
||||||
for i := 0; i < int(followerPerLeader) && followerIdx <= int(followerCounts)-1; i++ {
|
for i := 0; i < int(followerPerLeader) && followerIdx <= int(followerCounts)-1; i++ {
|
||||||
followerPod := RedisDetails{
|
followerPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-follower-" + strconv.Itoa(followerIdx),
|
PodName: cr.Name + "-follower-" + strconv.Itoa(followerIdx),
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
leaderPod := RedisDetails{
|
leaderPod := RedisDetails{
|
||||||
PodName: cr.ObjectMeta.Name + "-leader-" + strconv.Itoa((followerIdx)%int(leaderCounts)),
|
PodName: cr.Name + "-leader-" + strconv.Itoa((followerIdx)%int(leaderCounts)),
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
podIP = getRedisServerIP(ctx, client, followerPod)
|
podIP = getRedisServerIP(ctx, client, followerPod)
|
||||||
|
@ -269,7 +269,7 @@ func ExecuteRedisReplicationCommand(ctx context.Context, client kubernetes.Inter
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if pong == "PONG" {
|
if pong == "PONG" {
|
||||||
executeCommand(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
executeCommand(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
} else {
|
} else {
|
||||||
log.FromContext(ctx).V(1).Info("Skipping execution of command due to failed Redis ping", "Follower.Pod", followerPod)
|
log.FromContext(ctx).V(1).Info("Skipping execution of command due to failed Redis ping", "Follower.Pod", followerPod)
|
||||||
}
|
}
|
||||||
|
@ -321,7 +321,7 @@ func ExecuteFailoverOperation(ctx context.Context, client kubernetes.Interface,
|
||||||
// executeFailoverCommand will execute failover command
|
// executeFailoverCommand will execute failover command
|
||||||
func executeFailoverCommand(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, role string) error {
|
func executeFailoverCommand(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, role string) error {
|
||||||
replicas := cr.Spec.GetReplicaCounts(role)
|
replicas := cr.Spec.GetReplicaCounts(role)
|
||||||
podName := fmt.Sprintf("%s-%s-", cr.ObjectMeta.Name, role)
|
podName := fmt.Sprintf("%s-%s-", cr.Name, role)
|
||||||
for podCount := 0; podCount <= int(replicas)-1; podCount++ {
|
for podCount := 0; podCount <= int(replicas)-1; podCount++ {
|
||||||
log.FromContext(ctx).V(1).Info("Executing redis failover operations", "Redis Node", podName+strconv.Itoa(podCount))
|
log.FromContext(ctx).V(1).Info("Executing redis failover operations", "Redis Node", podName+strconv.Itoa(podCount))
|
||||||
client := configureRedisClient(ctx, client, cr, podName+strconv.Itoa(podCount))
|
client := configureRedisClient(ctx, client, cr, podName+strconv.Itoa(podCount))
|
||||||
|
@ -354,7 +354,7 @@ func executeFailoverCommand(ctx context.Context, client kubernetes.Interface, cr
|
||||||
|
|
||||||
// CheckRedisNodeCount will check the count of redis nodes
|
// CheckRedisNodeCount will check the count of redis nodes
|
||||||
func CheckRedisNodeCount(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, nodeType string) int32 {
|
func CheckRedisNodeCount(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster, nodeType string) int32 {
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
var redisNodeType string
|
var redisNodeType string
|
||||||
clusterNodes, err := clusterNodes(ctx, redisClient)
|
clusterNodes, err := clusterNodes(ctx, redisClient)
|
||||||
|
@ -387,7 +387,7 @@ func CheckRedisNodeCount(ctx context.Context, client kubernetes.Interface, cr *r
|
||||||
|
|
||||||
// RedisClusterStatusHealth use `redis-cli --cluster check 127.0.0.1:6379`
|
// RedisClusterStatusHealth use `redis-cli --cluster check 127.0.0.1:6379`
|
||||||
func RedisClusterStatusHealth(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) bool {
|
func RedisClusterStatusHealth(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) bool {
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
|
|
||||||
cmd := []string{"redis-cli", "--cluster", "check", fmt.Sprintf("127.0.0.1:%d", *cr.Spec.Port)}
|
cmd := []string{"redis-cli", "--cluster", "check", fmt.Sprintf("127.0.0.1:%d", *cr.Spec.Port)}
|
||||||
|
@ -399,8 +399,8 @@ func RedisClusterStatusHealth(ctx context.Context, client kubernetes.Interface,
|
||||||
cmd = append(cmd, "-a")
|
cmd = append(cmd, "-a")
|
||||||
cmd = append(cmd, pass)
|
cmd = append(cmd, pass)
|
||||||
}
|
}
|
||||||
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.ObjectMeta.Name+"-leader-0")...)
|
cmd = append(cmd, getRedisTLSArgs(cr.Spec.TLS, cr.Name+"-leader-0")...)
|
||||||
out, err := executeCommand1(ctx, client, cr, cmd, cr.ObjectMeta.Name+"-leader-0")
|
out, err := executeCommand1(ctx, client, cr, cmd, cr.Name+"-leader-0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -415,7 +415,7 @@ func RedisClusterStatusHealth(ctx context.Context, client kubernetes.Interface,
|
||||||
|
|
||||||
// UnhealthyNodesInCluster returns the number of unhealthy nodes in the cluster cr
|
// UnhealthyNodesInCluster returns the number of unhealthy nodes in the cluster cr
|
||||||
func UnhealthyNodesInCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) (int, error) {
|
func UnhealthyNodesInCluster(ctx context.Context, client kubernetes.Interface, cr *rcvb2.RedisCluster) (int, error) {
|
||||||
redisClient := configureRedisClient(ctx, client, cr, cr.ObjectMeta.Name+"-leader-0")
|
redisClient := configureRedisClient(ctx, client, cr, cr.Name+"-leader-0")
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
clusterNodes, err := clusterNodes(ctx, redisClient)
|
clusterNodes, err := clusterNodes(ctx, redisClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -527,7 +527,7 @@ func getContainerID(ctx context.Context, client kubernetes.Interface, cr *rcvb2.
|
||||||
targetContainer := -1
|
targetContainer := -1
|
||||||
for containerID, tr := range pod.Spec.Containers {
|
for containerID, tr := range pod.Spec.Containers {
|
||||||
log.FromContext(ctx).V(1).Info("Inspecting container", "Pod Name", podName, "Container ID", containerID, "Container Name", tr.Name)
|
log.FromContext(ctx).V(1).Info("Inspecting container", "Pod Name", podName, "Container ID", containerID, "Container Name", tr.Name)
|
||||||
if tr.Name == cr.ObjectMeta.Name+"-leader" {
|
if tr.Name == cr.Name+"-leader" {
|
||||||
targetContainer = containerID
|
targetContainer = containerID
|
||||||
log.FromContext(ctx).V(1).Info("Leader container found", "Container ID", containerID, "Container Name", tr.Name)
|
log.FromContext(ctx).V(1).Info("Leader container found", "Container ID", containerID, "Container Name", tr.Name)
|
||||||
break
|
break
|
||||||
|
@ -568,8 +568,16 @@ func configureRedisReplicationClient(ctx context.Context, client kubernetes.Inte
|
||||||
log.FromContext(ctx).Error(err, "Error in getting redis password")
|
log.FromContext(ctx).Error(err, "Error in getting redis password")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var addr string
|
||||||
|
if cr.Spec.TLS != nil {
|
||||||
|
// Use DNS name for TLS connections
|
||||||
|
addr = fmt.Sprintf("%s:%d", getRedisReplicationHostname(redisInfo, cr), 6379)
|
||||||
|
} else {
|
||||||
|
// Use IP address for non-TLS connections
|
||||||
|
addr = getRedisServerAddress(ctx, client, redisInfo, 6379)
|
||||||
|
}
|
||||||
opts := &redis.Options{
|
opts := &redis.Options{
|
||||||
Addr: getRedisServerAddress(ctx, client, redisInfo, 6379),
|
Addr: addr,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
DB: 0,
|
DB: 0,
|
||||||
}
|
}
|
||||||
|
@ -579,12 +587,16 @@ func configureRedisReplicationClient(ctx context.Context, client kubernetes.Inte
|
||||||
return redis.NewClient(opts)
|
return redis.NewClient(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getRedisReplicationHostname(redisInfo RedisDetails, cr *rrvb2.RedisReplication) string {
|
||||||
|
return fmt.Sprintf("%s.%s-headless.%s.svc.cluster.local", redisInfo.PodName, cr.Name, cr.Namespace)
|
||||||
|
}
|
||||||
|
|
||||||
// Get Redis nodes by it's role i.e. master, slave and sentinel
|
// Get Redis nodes by it's role i.e. master, slave and sentinel
|
||||||
func GetRedisNodesByRole(ctx context.Context, cl kubernetes.Interface, cr *rrvb2.RedisReplication, redisRole string) []string {
|
func GetRedisNodesByRole(ctx context.Context, cl kubernetes.Interface, cr *rrvb2.RedisReplication, redisRole string) ([]string, error) {
|
||||||
statefulset, err := GetStatefulSet(ctx, cl, cr.GetNamespace(), cr.GetName())
|
statefulset, err := GetStatefulSet(ctx, cl, cr.GetNamespace(), cr.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err, "Failed to Get the Statefulset of the", "custom resource", cr.Name, "in namespace", cr.Namespace)
|
log.FromContext(ctx).Error(err, "Failed to Get the Statefulset of the", "custom resource", cr.Name, "in namespace", cr.Namespace)
|
||||||
return nil
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pods []string
|
var pods []string
|
||||||
|
@ -594,32 +606,35 @@ func GetRedisNodesByRole(ctx context.Context, cl kubernetes.Interface, cr *rrvb2
|
||||||
podName := statefulset.Name + "-" + strconv.Itoa(i)
|
podName := statefulset.Name + "-" + strconv.Itoa(i)
|
||||||
redisClient := configureRedisReplicationClient(ctx, cl, cr, podName)
|
redisClient := configureRedisReplicationClient(ctx, cl, cr, podName)
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
podRole := checkRedisServerRole(ctx, redisClient, podName)
|
podRole, err := checkRedisServerRole(ctx, redisClient, podName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if podRole == redisRole {
|
if podRole == redisRole {
|
||||||
pods = append(pods, podName)
|
pods = append(pods, podName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pods
|
return pods, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the Redis Server Role i.e. master, slave and sentinel
|
// Check the Redis Server Role i.e. master, slave and sentinel
|
||||||
func checkRedisServerRole(ctx context.Context, redisClient *redis.Client, podName string) string {
|
func checkRedisServerRole(ctx context.Context, redisClient *redis.Client, podName string) (string, error) {
|
||||||
info, err := redisClient.Info(ctx, "Replication").Result()
|
info, err := redisClient.Info(ctx, "Replication").Result()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err, "Failed to Get the role Info of the", "redis pod", podName)
|
log.FromContext(ctx).Error(err, "Failed to Get the role Info of the", "redis pod", podName)
|
||||||
return ""
|
return "", err
|
||||||
}
|
}
|
||||||
lines := strings.Split(info, "\r\n")
|
lines := strings.Split(info, "\r\n")
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if strings.HasPrefix(line, "role:") {
|
if strings.HasPrefix(line, "role:") {
|
||||||
role := strings.TrimPrefix(line, "role:")
|
role := strings.TrimPrefix(line, "role:")
|
||||||
log.FromContext(ctx).V(1).Info("Role of the Redis Pod", "pod", podName, "role", role)
|
log.FromContext(ctx).V(1).Info("Role of the Redis Pod", "pod", podName, "role", role)
|
||||||
return role
|
return role, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.FromContext(ctx).Error(err, "Failed to find role from Info # Replication in", "redis pod", podName)
|
log.FromContext(ctx).Error(err, "Failed to find role from Info # Replication in", "redis pod", podName)
|
||||||
return ""
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkAttachedSlave would return redis pod name which has slave
|
// checkAttachedSlave would return redis pod name which has slave
|
||||||
|
@ -655,20 +670,29 @@ func CreateMasterSlaveReplication(ctx context.Context, client kubernetes.Interfa
|
||||||
Namespace: cr.Namespace,
|
Namespace: cr.Namespace,
|
||||||
}
|
}
|
||||||
|
|
||||||
realMasterPodIP := getRedisServerIP(ctx, client, realMasterInfo)
|
var realMasterAddr string
|
||||||
|
if cr.Spec.TLS != nil {
|
||||||
if realMasterPodIP == "" {
|
// Use DNS name for TLS connections to match certificate validation
|
||||||
return errors.New("CreateMasterSlaveReplication got empty master IP, refusing")
|
realMasterAddr = getRedisReplicationHostname(realMasterInfo, cr)
|
||||||
|
log.FromContext(ctx).V(1).Info("Using DNS address for TLS master replication", "masterAddr", realMasterAddr)
|
||||||
|
} else {
|
||||||
|
// Use IP address for non-TLS connections
|
||||||
|
realMasterPodIP := getRedisServerIP(ctx, client, realMasterInfo)
|
||||||
|
if realMasterPodIP == "" {
|
||||||
|
return errors.New("CreateMasterSlaveReplication got empty master IP, refusing")
|
||||||
|
}
|
||||||
|
realMasterAddr = realMasterPodIP
|
||||||
|
log.FromContext(ctx).V(1).Info("Using IP address for non-TLS master replication", "masterAddr", realMasterAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < len(masterPods); i++ {
|
for i := 0; i < len(masterPods); i++ {
|
||||||
if masterPods[i] != realMasterPod {
|
if masterPods[i] != realMasterPod {
|
||||||
redisClient := configureRedisReplicationClient(ctx, client, cr, masterPods[i])
|
redisClient := configureRedisReplicationClient(ctx, client, cr, masterPods[i])
|
||||||
defer redisClient.Close()
|
defer redisClient.Close()
|
||||||
log.FromContext(ctx).V(1).Info("Setting the", "pod", masterPods[i], "to slave of", realMasterPod)
|
log.FromContext(ctx).V(1).Info("Setting the", "pod", masterPods[i], "to slave of", realMasterPod, "masterAddr", realMasterAddr)
|
||||||
err := redisClient.SlaveOf(ctx, realMasterPodIP, "6379").Err()
|
err := redisClient.SlaveOf(ctx, realMasterAddr, "6379").Err()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FromContext(ctx).Error(err, "Failed to set", "pod", masterPods[i], "to slave of", realMasterPod)
|
log.FromContext(ctx).Error(err, "Failed to set", "pod", masterPods[i], "to slave of", realMasterPod, "masterAddr", realMasterAddr)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,9 +729,9 @@ func SetRedisClusterDynamicConfig(ctx context.Context, client kubernetes.Interfa
|
||||||
for i := 0; i < int(leaderReplicas+followerReplicas); i++ {
|
for i := 0; i < int(leaderReplicas+followerReplicas); i++ {
|
||||||
var podName string
|
var podName string
|
||||||
if i < int(leaderReplicas) {
|
if i < int(leaderReplicas) {
|
||||||
podName = cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(i)
|
podName = cr.Name + "-leader-" + strconv.Itoa(i)
|
||||||
} else {
|
} else {
|
||||||
podName = cr.ObjectMeta.Name + "-follower-" + strconv.Itoa(i-int(leaderReplicas))
|
podName = cr.Name + "-follower-" + strconv.Itoa(i-int(leaderReplicas))
|
||||||
}
|
}
|
||||||
|
|
||||||
redisClient := configureRedisClient(ctx, client, cr, podName)
|
redisClient := configureRedisClient(ctx, client, cr, podName)
|
||||||
|
|
|
@ -17,7 +17,6 @@ import (
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
|
||||||
k8sClientFake "k8s.io/client-go/kubernetes/fake"
|
k8sClientFake "k8s.io/client-go/kubernetes/fake"
|
||||||
"k8s.io/utils/ptr"
|
"k8s.io/utils/ptr"
|
||||||
)
|
)
|
||||||
|
@ -567,14 +566,14 @@ func TestCreateRedisReplicationCommand(t *testing.T) {
|
||||||
pods := mock_utils.CreateFakeObjectWithPodIPs(tt.redisCluster)
|
pods := mock_utils.CreateFakeObjectWithPodIPs(tt.redisCluster)
|
||||||
var secret []runtime.Object
|
var secret []runtime.Object
|
||||||
if tt.redisCluster.Spec.KubernetesConfig.ExistingPasswordSecret != nil {
|
if tt.redisCluster.Spec.KubernetesConfig.ExistingPasswordSecret != nil {
|
||||||
secret = mock_utils.CreateFakeObjectWithSecret(tt.secret.name, tt.secret.namespace, tt.secret.key)
|
secret = mock_utils.CreateFakeObjectWithSecret(tt.secret.name, tt.secret.namespace, tt.secret.key) //nolint
|
||||||
}
|
}
|
||||||
|
|
||||||
var objects []runtime.Object
|
var objects []runtime.Object
|
||||||
objects = append(objects, pods...)
|
objects = append(objects, pods...)
|
||||||
objects = append(objects, secret...)
|
objects = append(objects, secret...)
|
||||||
|
|
||||||
client := fake.NewSimpleClientset(objects...)
|
client := k8sClientFake.NewSimpleClientset(objects...)
|
||||||
cmd := createRedisReplicationCommand(context.TODO(), client, tt.redisCluster, tt.leaderPod, tt.followerPod)
|
cmd := createRedisReplicationCommand(context.TODO(), client, tt.redisCluster, tt.leaderPod, tt.followerPod)
|
||||||
|
|
||||||
// Assert the command is as expected using testify
|
// Assert the command is as expected using testify
|
||||||
|
@ -838,7 +837,10 @@ func Test_checkRedisServerRole(t *testing.T) {
|
||||||
mock.ExpectInfo("Replication").SetVal(tt.infoReturn)
|
mock.ExpectInfo("Replication").SetVal(tt.infoReturn)
|
||||||
}
|
}
|
||||||
|
|
||||||
role := checkRedisServerRole(ctx, client, tt.podName)
|
role, err := checkRedisServerRole(ctx, client, tt.podName)
|
||||||
|
if err != nil {
|
||||||
|
assert.Error(t, err)
|
||||||
|
}
|
||||||
if tt.shouldFail {
|
if tt.shouldFail {
|
||||||
assert.Empty(t, role, "Test case: "+tt.name)
|
assert.Empty(t, role, "Test case: "+tt.name)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/OT-CONTAINER-KIT/redis-operator/internal/util/cryptutil"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
@ -59,10 +60,14 @@ func getRedisTLSConfig(ctx context.Context, client kubernetes.Interface, namespa
|
||||||
}
|
}
|
||||||
|
|
||||||
return &tls.Config{
|
return &tls.Config{
|
||||||
Certificates: []tls.Certificate{cert},
|
Certificates: []tls.Certificate{cert},
|
||||||
ServerName: podName + "." + namespace,
|
RootCAs: tlsCaCertificates,
|
||||||
RootCAs: tlsCaCertificates,
|
MinVersion: tls.VersionTLS12,
|
||||||
MinVersion: tls.VersionTLS12,
|
ClientAuth: tls.NoClientCert,
|
||||||
ClientAuth: tls.NoClientCert,
|
InsecureSkipVerify: true,
|
||||||
|
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||||
|
_, _, err := cryptutil.VerifyCertificateExceptServerName(rawCerts, &tls.Config{RootCAs: tlsCaCertificates})
|
||||||
|
return err
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,8 @@ func (s *StatefulSetService) IsStatefulSetReady(ctx context.Context, namespace,
|
||||||
log.FromContext(ctx).V(1).Info("StatefulSet is not ready", "Status.CurrentRevision", sts.Status.CurrentRevision, "Status.UpdateRevision", sts.Status.UpdateRevision)
|
log.FromContext(ctx).V(1).Info("StatefulSet is not ready", "Status.CurrentRevision", sts.Status.CurrentRevision, "Status.UpdateRevision", sts.Status.UpdateRevision)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if sts.Status.ObservedGeneration != sts.ObjectMeta.Generation {
|
if sts.Status.ObservedGeneration != sts.Generation {
|
||||||
log.FromContext(ctx).V(1).Info("StatefulSet is not ready", "Status.ObservedGeneration", sts.Status.ObservedGeneration, "ObjectMeta.Generation", sts.ObjectMeta.Generation)
|
log.FromContext(ctx).V(1).Info("StatefulSet is not ready", "Status.ObservedGeneration", sts.Status.ObservedGeneration, "Generation", sts.Generation)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if int(sts.Status.ReadyReplicas) != replicas {
|
if int(sts.Status.ReadyReplicas) != replicas {
|
||||||
|
@ -97,29 +97,30 @@ const (
|
||||||
|
|
||||||
// statefulSetParameters will define statefulsets input params
|
// statefulSetParameters will define statefulsets input params
|
||||||
type statefulSetParameters struct {
|
type statefulSetParameters struct {
|
||||||
Replicas *int32
|
Replicas *int32
|
||||||
ClusterMode bool
|
ClusterMode bool
|
||||||
ClusterVersion *string
|
ClusterVersion *string
|
||||||
NodeConfVolume bool
|
NodeConfVolume bool
|
||||||
NodeSelector map[string]string
|
NodeSelector map[string]string
|
||||||
TopologySpreadConstraints []corev1.TopologySpreadConstraint
|
TopologySpreadConstraints []corev1.TopologySpreadConstraint
|
||||||
PodSecurityContext *corev1.PodSecurityContext
|
PodSecurityContext *corev1.PodSecurityContext
|
||||||
PriorityClassName string
|
PriorityClassName string
|
||||||
Affinity *corev1.Affinity
|
Affinity *corev1.Affinity
|
||||||
Tolerations *[]corev1.Toleration
|
Tolerations *[]corev1.Toleration
|
||||||
EnableMetrics bool
|
EnableMetrics bool
|
||||||
PersistentVolumeClaim corev1.PersistentVolumeClaim
|
PersistentVolumeClaim corev1.PersistentVolumeClaim
|
||||||
NodeConfPersistentVolumeClaim corev1.PersistentVolumeClaim
|
NodeConfPersistentVolumeClaim corev1.PersistentVolumeClaim
|
||||||
ImagePullSecrets *[]corev1.LocalObjectReference
|
ImagePullSecrets *[]corev1.LocalObjectReference
|
||||||
ExternalConfig *string
|
ExternalConfig *string
|
||||||
ServiceAccountName *string
|
ServiceAccountName *string
|
||||||
UpdateStrategy appsv1.StatefulSetUpdateStrategy
|
UpdateStrategy appsv1.StatefulSetUpdateStrategy
|
||||||
RecreateStatefulSet bool
|
PersistentVolumeClaimRetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy
|
||||||
RecreateStatefulsetStrategy *metav1.DeletionPropagation
|
RecreateStatefulSet bool
|
||||||
TerminationGracePeriodSeconds *int64
|
RecreateStatefulsetStrategy *metav1.DeletionPropagation
|
||||||
IgnoreAnnotations []string
|
TerminationGracePeriodSeconds *int64
|
||||||
HostNetwork bool
|
IgnoreAnnotations []string
|
||||||
MinReadySeconds int32
|
HostNetwork bool
|
||||||
|
MinReadySeconds int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// containerParameters will define container input params
|
// containerParameters will define container input params
|
||||||
|
@ -277,11 +278,12 @@ func generateStatefulSetsDef(stsMeta metav1.ObjectMeta, params statefulSetParame
|
||||||
TypeMeta: generateMetaInformation("StatefulSet", "apps/v1"),
|
TypeMeta: generateMetaInformation("StatefulSet", "apps/v1"),
|
||||||
ObjectMeta: stsMeta,
|
ObjectMeta: stsMeta,
|
||||||
Spec: appsv1.StatefulSetSpec{
|
Spec: appsv1.StatefulSetSpec{
|
||||||
Selector: LabelSelectors(selectorLabels),
|
Selector: LabelSelectors(selectorLabels),
|
||||||
ServiceName: fmt.Sprintf("%s-headless", stsMeta.Name),
|
ServiceName: fmt.Sprintf("%s-headless", stsMeta.Name),
|
||||||
Replicas: params.Replicas,
|
Replicas: params.Replicas,
|
||||||
UpdateStrategy: params.UpdateStrategy,
|
UpdateStrategy: params.UpdateStrategy,
|
||||||
MinReadySeconds: params.MinReadySeconds,
|
PersistentVolumeClaimRetentionPolicy: params.PersistentVolumeClaimRetentionPolicy,
|
||||||
|
MinReadySeconds: params.MinReadySeconds,
|
||||||
Template: corev1.PodTemplateSpec{
|
Template: corev1.PodTemplateSpec{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Labels: stsMeta.GetLabels(),
|
Labels: stsMeta.GetLabels(),
|
||||||
|
@ -807,7 +809,7 @@ func getProbeInfo(probe *corev1.Probe, sentinel, enableTLS, enableAuth bool) *co
|
||||||
if probe == nil {
|
if probe == nil {
|
||||||
probe = &corev1.Probe{}
|
probe = &corev1.Probe{}
|
||||||
}
|
}
|
||||||
if probe.ProbeHandler.Exec == nil && probe.ProbeHandler.HTTPGet == nil && probe.ProbeHandler.TCPSocket == nil && probe.ProbeHandler.GRPC == nil {
|
if probe.Exec == nil && probe.HTTPGet == nil && probe.TCPSocket == nil && probe.GRPC == nil {
|
||||||
healthChecker := []string{
|
healthChecker := []string{
|
||||||
"redis-cli",
|
"redis-cli",
|
||||||
"-h", "$(hostname)",
|
"-h", "$(hostname)",
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
appsv1 "k8s.io/api/apps/v1"
|
appsv1 "k8s.io/api/apps/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -1036,7 +1035,7 @@ func TestGenerateContainerDef(t *testing.T) {
|
||||||
test := tests[i]
|
test := tests[i]
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
containerDef := generateContainerDef(test.containerName, test.containerDef, test.redisClusterMode, test.containerNodeConfVolume, test.containerEnableMetrics, test.containerExternalConfig, test.redisClusterVersion, test.containerMountPaths, test.sideCareContainer)
|
containerDef := generateContainerDef(test.containerName, test.containerDef, test.redisClusterMode, test.containerNodeConfVolume, test.containerEnableMetrics, test.containerExternalConfig, test.redisClusterVersion, test.containerMountPaths, test.sideCareContainer)
|
||||||
assert.Equal(t, containerDef, test.expectedContainerDef, "Container Configration")
|
assert.Equal(t, containerDef, test.expectedContainerDef, "Container Configuration")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1059,16 +1058,16 @@ func TestGenerateInitContainerDef(t *testing.T) {
|
||||||
Command: []string{"/bin/bash", "-c", "/app/restore.bash"},
|
Command: []string{"/bin/bash", "-c", "/app/restore.bash"},
|
||||||
PersistenceEnabled: ptr.To(false),
|
PersistenceEnabled: ptr.To(false),
|
||||||
Resources: &corev1.ResourceRequirements{
|
Resources: &corev1.ResourceRequirements{
|
||||||
Requests: v1.ResourceList{
|
Requests: corev1.ResourceList{
|
||||||
v1.ResourceCPU: resource.MustParse("220m"),
|
corev1.ResourceCPU: resource.MustParse("220m"),
|
||||||
v1.ResourceMemory: resource.MustParse("500Mi"),
|
corev1.ResourceMemory: resource.MustParse("500Mi"),
|
||||||
},
|
},
|
||||||
Limits: v1.ResourceList{
|
Limits: corev1.ResourceList{
|
||||||
v1.ResourceCPU: resource.MustParse("250m"),
|
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||||
v1.ResourceMemory: resource.MustParse("500Mi"),
|
corev1.ResourceMemory: resource.MustParse("500Mi"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
AdditionalEnvVariable: &[]v1.EnvVar{
|
AdditionalEnvVariable: &[]corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: "TLS_MODE",
|
Name: "TLS_MODE",
|
||||||
Value: "true",
|
Value: "true",
|
||||||
|
@ -1083,16 +1082,16 @@ func TestGenerateInitContainerDef(t *testing.T) {
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
ImagePullPolicy: corev1.PullAlways,
|
||||||
VolumeMounts: getVolumeMount("redisVolume", ptr.To(false), false, false, nil, []corev1.VolumeMount{}, nil, nil),
|
VolumeMounts: getVolumeMount("redisVolume", ptr.To(false), false, false, nil, []corev1.VolumeMount{}, nil, nil),
|
||||||
Resources: corev1.ResourceRequirements{
|
Resources: corev1.ResourceRequirements{
|
||||||
Requests: v1.ResourceList{
|
Requests: corev1.ResourceList{
|
||||||
v1.ResourceCPU: resource.MustParse("220m"),
|
corev1.ResourceCPU: resource.MustParse("220m"),
|
||||||
v1.ResourceMemory: resource.MustParse("500Mi"),
|
corev1.ResourceMemory: resource.MustParse("500Mi"),
|
||||||
},
|
},
|
||||||
Limits: v1.ResourceList{
|
Limits: corev1.ResourceList{
|
||||||
v1.ResourceCPU: resource.MustParse("250m"),
|
corev1.ResourceCPU: resource.MustParse("250m"),
|
||||||
v1.ResourceMemory: resource.MustParse("500Mi"),
|
corev1.ResourceMemory: resource.MustParse("500Mi"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Env: []v1.EnvVar{
|
Env: []corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: "TLS_MODE",
|
Name: "TLS_MODE",
|
||||||
Value: "true",
|
Value: "true",
|
||||||
|
@ -1124,7 +1123,7 @@ func TestGenerateInitContainerDef(t *testing.T) {
|
||||||
MountPath: "/data",
|
MountPath: "/data",
|
||||||
},
|
},
|
||||||
}, nil, nil),
|
}, nil, nil),
|
||||||
Env: []v1.EnvVar{},
|
Env: []corev1.EnvVar{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mountPaths: []corev1.VolumeMount{
|
mountPaths: []corev1.VolumeMount{
|
||||||
|
@ -1401,7 +1400,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
ClusterMode: true,
|
ClusterMode: true,
|
||||||
NodeConfVolume: true,
|
NodeConfVolume: true,
|
||||||
ExternalConfig: ptr.To(""),
|
ExternalConfig: ptr.To(""),
|
||||||
Tolerations: &[]v1.Toleration{
|
Tolerations: &[]corev1.Toleration{
|
||||||
{
|
{
|
||||||
Key: "node.kubernetes.io/unreachable",
|
Key: "node.kubernetes.io/unreachable",
|
||||||
Operator: corev1.TolerationOpExists,
|
Operator: corev1.TolerationOpExists,
|
||||||
|
@ -1436,15 +1435,15 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
MatchLabels: map[string]string{},
|
MatchLabels: map[string]string{},
|
||||||
},
|
},
|
||||||
Replicas: ptr.To(int32(3)),
|
Replicas: ptr.To(int32(3)),
|
||||||
Template: v1.PodTemplateSpec{
|
Template: corev1.PodTemplateSpec{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"redis.opstreelabs.in": "true",
|
"redis.opstreelabs.in": "true",
|
||||||
"redis.opstreelabs.instance": "test-sts",
|
"redis.opstreelabs.instance": "test-sts",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.PodSpec{
|
Spec: corev1.PodSpec{
|
||||||
Tolerations: []v1.Toleration{
|
Tolerations: []corev1.Toleration{
|
||||||
{
|
{
|
||||||
Key: "node.kubernetes.io/unreachable",
|
Key: "node.kubernetes.io/unreachable",
|
||||||
Operator: corev1.TolerationOpExists,
|
Operator: corev1.TolerationOpExists,
|
||||||
|
@ -1509,7 +1508,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
VolumeMounts: []v1.VolumeMount{
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "tls-certs",
|
Name: "tls-certs",
|
||||||
MountPath: "/tls",
|
MountPath: "/tls",
|
||||||
|
@ -1527,25 +1526,25 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Volumes: []v1.Volume{
|
Volumes: []corev1.Volume{
|
||||||
{
|
{
|
||||||
Name: "external-config",
|
Name: "external-config",
|
||||||
VolumeSource: v1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
ConfigMap: &v1.ConfigMapVolumeSource{},
|
ConfigMap: &corev1.ConfigMapVolumeSource{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "tls-certs",
|
Name: "tls-certs",
|
||||||
VolumeSource: v1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
Secret: &v1.SecretVolumeSource{
|
Secret: &corev1.SecretVolumeSource{
|
||||||
SecretName: "sts-secret",
|
SecretName: "sts-secret",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "acl-secret",
|
Name: "acl-secret",
|
||||||
VolumeSource: v1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
Secret: &v1.SecretVolumeSource{
|
Secret: &corev1.SecretVolumeSource{
|
||||||
SecretName: "sts-acl",
|
SecretName: "sts-acl",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1558,19 +1557,19 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
initContainerParams: initContainerParameters{},
|
initContainerParams: initContainerParameters{},
|
||||||
containerParams: containerParameters{
|
containerParams: containerParameters{
|
||||||
Image: "redis:latest",
|
Image: "redis:latest",
|
||||||
EnvVars: &[]v1.EnvVar{
|
EnvVars: &[]corev1.EnvVar{
|
||||||
{
|
{
|
||||||
Name: "REDIS_MAJOR_VERSION",
|
Name: "REDIS_MAJOR_VERSION",
|
||||||
Value: "1.0",
|
Value: "1.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
TLSConfig: &common.TLSConfig{
|
TLSConfig: &common.TLSConfig{
|
||||||
Secret: v1.SecretVolumeSource{
|
Secret: corev1.SecretVolumeSource{
|
||||||
SecretName: "sts-secret",
|
SecretName: "sts-secret",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ACLConfig: &common.ACLConfig{
|
ACLConfig: &common.ACLConfig{
|
||||||
Secret: &v1.SecretVolumeSource{
|
Secret: &corev1.SecretVolumeSource{
|
||||||
SecretName: "sts-acl",
|
SecretName: "sts-acl",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1597,7 +1596,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
EnableMetrics: true,
|
EnableMetrics: true,
|
||||||
ClusterMode: true,
|
ClusterMode: true,
|
||||||
NodeConfVolume: true,
|
NodeConfVolume: true,
|
||||||
ImagePullSecrets: &[]v1.LocalObjectReference{
|
ImagePullSecrets: &[]corev1.LocalObjectReference{
|
||||||
{
|
{
|
||||||
Name: "redis-secret",
|
Name: "redis-secret",
|
||||||
},
|
},
|
||||||
|
@ -1629,17 +1628,17 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
MatchLabels: map[string]string{},
|
MatchLabels: map[string]string{},
|
||||||
},
|
},
|
||||||
Replicas: ptr.To(int32(3)),
|
Replicas: ptr.To(int32(3)),
|
||||||
Template: v1.PodTemplateSpec{
|
Template: corev1.PodTemplateSpec{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Annotations: map[string]string{
|
Annotations: map[string]string{
|
||||||
"redis.opstreelabs.in": "true",
|
"redis.opstreelabs.in": "true",
|
||||||
"redis.opstreelabs.instance": "test-sts",
|
"redis.opstreelabs.instance": "test-sts",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.PodSpec{
|
Spec: corev1.PodSpec{
|
||||||
InitContainers: []corev1.Container{
|
InitContainers: []corev1.Container{
|
||||||
{
|
{
|
||||||
Env: []v1.EnvVar{},
|
Env: []corev1.EnvVar{},
|
||||||
Name: "inittest-sts",
|
Name: "inittest-sts",
|
||||||
Image: "redis-init:latest",
|
Image: "redis-init:latest",
|
||||||
},
|
},
|
||||||
|
@ -1680,7 +1679,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
VolumeMounts: []v1.VolumeMount{
|
VolumeMounts: []corev1.VolumeMount{
|
||||||
{
|
{
|
||||||
Name: "node-conf",
|
Name: "node-conf",
|
||||||
MountPath: "/node-conf",
|
MountPath: "/node-conf",
|
||||||
|
@ -1709,25 +1708,25 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
ImagePullPolicy: corev1.PullAlways,
|
ImagePullPolicy: corev1.PullAlways,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Volumes: []v1.Volume{
|
Volumes: []corev1.Volume{
|
||||||
{
|
{
|
||||||
Name: "config",
|
Name: "config",
|
||||||
VolumeSource: v1.VolumeSource{
|
VolumeSource: corev1.VolumeSource{
|
||||||
EmptyDir: &v1.EmptyDirVolumeSource{},
|
EmptyDir: &corev1.EmptyDirVolumeSource{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "additional-vol",
|
Name: "additional-vol",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ImagePullSecrets: []v1.LocalObjectReference{
|
ImagePullSecrets: []corev1.LocalObjectReference{
|
||||||
{
|
{
|
||||||
Name: "redis-secret",
|
Name: "redis-secret",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
VolumeClaimTemplates: []v1.PersistentVolumeClaim{
|
VolumeClaimTemplates: []corev1.PersistentVolumeClaim{
|
||||||
{
|
{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: "node-conf",
|
Name: "node-conf",
|
||||||
|
@ -1736,11 +1735,11 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
"redis.opstreelabs.instance": "test-sts",
|
"redis.opstreelabs.instance": "test-sts",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.PersistentVolumeClaimSpec{
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
AccessModes: []v1.PersistentVolumeAccessMode{
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
||||||
v1.ReadWriteOnce,
|
corev1.ReadWriteOnce,
|
||||||
},
|
},
|
||||||
VolumeMode: ptr.To(v1.PersistentVolumeFilesystem),
|
VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1751,11 +1750,11 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
"redis.opstreelabs.instance": "test-sts",
|
"redis.opstreelabs.instance": "test-sts",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: v1.PersistentVolumeClaimSpec{
|
Spec: corev1.PersistentVolumeClaimSpec{
|
||||||
AccessModes: []v1.PersistentVolumeAccessMode{
|
AccessModes: []corev1.PersistentVolumeAccessMode{
|
||||||
v1.ReadWriteOnce,
|
corev1.ReadWriteOnce,
|
||||||
},
|
},
|
||||||
VolumeMode: ptr.To(v1.PersistentVolumeFilesystem),
|
VolumeMode: ptr.To(corev1.PersistentVolumeFilesystem),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1768,7 +1767,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
containerParams: containerParameters{
|
containerParams: containerParameters{
|
||||||
Image: "redis:latest",
|
Image: "redis:latest",
|
||||||
PersistenceEnabled: ptr.To(true),
|
PersistenceEnabled: ptr.To(true),
|
||||||
AdditionalVolume: []v1.Volume{
|
AdditionalVolume: []corev1.Volume{
|
||||||
{
|
{
|
||||||
Name: "additional-vol",
|
Name: "additional-vol",
|
||||||
},
|
},
|
||||||
|
@ -1788,7 +1787,7 @@ func TestGenerateStatefulSetsDef(t *testing.T) {
|
||||||
test := tests[i]
|
test := tests[i]
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
stsDef := generateStatefulSetsDef(test.statefulSetMeta, test.stsParams, test.stsOwnerDef, test.initContainerParams, test.containerParams, test.sideCareContainer)
|
stsDef := generateStatefulSetsDef(test.statefulSetMeta, test.stsParams, test.stsOwnerDef, test.initContainerParams, test.containerParams, test.sideCareContainer)
|
||||||
assert.Equal(t, stsDef, test.expectedStsDef, "StatefulSet Configration")
|
assert.Equal(t, stsDef, test.expectedStsDef, "StatefulSet Configuration")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,5 +32,9 @@ func RegisterRedisClusterMetrics() {
|
||||||
RedisClusterRebalanceTotal,
|
RedisClusterRebalanceTotal,
|
||||||
RedisClusterRemoveFollowerAttempt,
|
RedisClusterRemoveFollowerAttempt,
|
||||||
RedisClusterReshardTotal,
|
RedisClusterReshardTotal,
|
||||||
|
RedisClusterRepairDisconnectedAttempt,
|
||||||
|
RedisClusterRepairDisconnectedFailed,
|
||||||
|
RedisClusterResetAttempt,
|
||||||
|
RedisClusterResetFailed,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,30 @@ var RedisClusterDescription = map[string]MetricDescription{
|
||||||
Type: "Counter",
|
Type: "Counter",
|
||||||
labels: []string{"namespace", "instance"},
|
labels: []string{"namespace", "instance"},
|
||||||
},
|
},
|
||||||
|
"RedisClusterRepairDisconnectedAttempt": {
|
||||||
|
Name: "rediscluster_repair_disconnected_attempt",
|
||||||
|
Help: "Number of times to repair a Redis cluster disconnected from the cluster.",
|
||||||
|
Type: "Counter",
|
||||||
|
labels: []string{"namespace", "instance"},
|
||||||
|
},
|
||||||
|
"RedisClusterRepairFailed": {
|
||||||
|
Name: "rediscluster_repair_failed",
|
||||||
|
Help: "Number of times to repair a Redis cluster failed.",
|
||||||
|
Type: "Counter",
|
||||||
|
labels: []string{"namespace", "instance"},
|
||||||
|
},
|
||||||
|
"RedisClusterResetAttempt": {
|
||||||
|
Name: "rediscluster_reset_attempt",
|
||||||
|
Help: "Number of times to reset a Redis cluster.",
|
||||||
|
Type: "Counter",
|
||||||
|
labels: []string{"namespace", "instance"},
|
||||||
|
},
|
||||||
|
"RedisClusterResetFailed": {
|
||||||
|
Name: "rediscluster_reset_failed",
|
||||||
|
Help: "Number of times to reset a Redis cluster failed.",
|
||||||
|
Type: "Counter",
|
||||||
|
labels: []string{"namespace", "instance"},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -114,6 +138,38 @@ var (
|
||||||
},
|
},
|
||||||
RedisClusterDescription["RedisClusterAddingNodeAttempt"].labels,
|
RedisClusterDescription["RedisClusterAddingNodeAttempt"].labels,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
RedisClusterRepairDisconnectedAttempt = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: RedisClusterDescription["RedisClusterRepairDisconnectedAttempt"].Name,
|
||||||
|
Help: RedisClusterDescription["RedisClusterRepairDisconnectedAttempt"].Help,
|
||||||
|
},
|
||||||
|
RedisClusterDescription["RedisClusterRepairDisconnectedAttempt"].labels,
|
||||||
|
)
|
||||||
|
|
||||||
|
RedisClusterRepairDisconnectedFailed = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: RedisClusterDescription["RedisClusterRepairDisconnectedFailed"].Name,
|
||||||
|
Help: RedisClusterDescription["RedisClusterRepairDisconnectedFailed"].Help,
|
||||||
|
},
|
||||||
|
RedisClusterDescription["RedisClusterRepairDisconnectedFailed"].labels,
|
||||||
|
)
|
||||||
|
|
||||||
|
RedisClusterResetAttempt = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: RedisClusterDescription["RedisClusterResetAttempt"].Name,
|
||||||
|
Help: RedisClusterDescription["RedisClusterResetAttempt"].Help,
|
||||||
|
},
|
||||||
|
RedisClusterDescription["RedisClusterResetAttempt"].labels,
|
||||||
|
)
|
||||||
|
|
||||||
|
RedisClusterResetFailed = prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: RedisClusterDescription["RedisClusterResetFailed"].Name,
|
||||||
|
Help: RedisClusterDescription["RedisClusterResetFailed"].Help,
|
||||||
|
},
|
||||||
|
RedisClusterDescription["RedisClusterResetFailed"].labels,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ListMetrics will create a slice with the metrics available in metricDescription
|
// ListMetrics will create a slice with the metrics available in metricDescription
|
||||||
|
|
|
@ -2,6 +2,7 @@ package redis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -14,9 +15,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConnectionInfo struct {
|
type ConnectionInfo struct {
|
||||||
IP string
|
// Host is the IP address or hostname for connection
|
||||||
|
Host string
|
||||||
|
// Port is the port for redis or sentinel
|
||||||
Port string
|
Port string
|
||||||
Password string
|
Password string
|
||||||
|
// TLSConfig configuration, nil means TLS is disabled
|
||||||
|
TLSConfig *tls.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAddress returns the connection address
|
||||||
|
func (c *ConnectionInfo) GetAddress() string {
|
||||||
|
return net.JoinHostPort(c.Host, c.Port)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
|
@ -55,10 +65,13 @@ func (s *service) createClient() *rediscli.Client {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
opts := &rediscli.Options{
|
opts := &rediscli.Options{
|
||||||
Addr: net.JoinHostPort(s.connectionInfo.IP, s.connectionInfo.Port),
|
Addr: s.connectionInfo.GetAddress(),
|
||||||
Password: s.connectionInfo.Password,
|
Password: s.connectionInfo.Password,
|
||||||
DB: 0,
|
DB: 0,
|
||||||
}
|
}
|
||||||
|
if s.connectionInfo.TLSConfig != nil {
|
||||||
|
opts.TLSConfig = s.connectionInfo.TLSConfig
|
||||||
|
}
|
||||||
return rediscli.NewClient(opts)
|
return rediscli.NewClient(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +114,7 @@ func (c *service) SentinelMonitor(ctx context.Context, master *ConnectionInfo, m
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = rediscli.NewBoolCmd(ctx, "SENTINEL", "MONITOR", masterGroupName, master.IP, master.Port, quorum)
|
cmd = rediscli.NewBoolCmd(ctx, "SENTINEL", "MONITOR", masterGroupName, master.Host, master.Port, quorum)
|
||||||
err = client.Process(ctx, cmd)
|
err = client.Process(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -9,7 +9,7 @@ type customFieldOption func(*v1beta2.Redis)
|
||||||
|
|
||||||
func WithAnnotations(annotations map[string]string) customFieldOption {
|
func WithAnnotations(annotations map[string]string) customFieldOption {
|
||||||
return func(rc *v1beta2.Redis) {
|
return func(rc *v1beta2.Redis) {
|
||||||
rc.ObjectMeta.Annotations = annotations
|
rc.Annotations = annotations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ func DisablePersistence() customFieldOption {
|
||||||
|
|
||||||
func WithAnnotations(annotations map[string]string) customFieldOption {
|
func WithAnnotations(annotations map[string]string) customFieldOption {
|
||||||
return func(rc *v1beta2.RedisCluster) {
|
return func(rc *v1beta2.RedisCluster) {
|
||||||
rc.ObjectMeta.Annotations = annotations
|
rc.Annotations = annotations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ type customFieldOption func(replication *v1beta2.RedisReplication)
|
||||||
|
|
||||||
func WithAnnotations(annotations map[string]string) customFieldOption {
|
func WithAnnotations(annotations map[string]string) customFieldOption {
|
||||||
return func(rc *v1beta2.RedisReplication) {
|
return func(rc *v1beta2.RedisReplication) {
|
||||||
rc.ObjectMeta.Annotations = annotations
|
rc.Annotations = annotations
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
package cryptutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VerifyCertificateExceptServerName verifies a certificate chain without hostname verification.
|
||||||
|
// This function performs the same validation as the standard TLS verification process,
|
||||||
|
// but deliberately omits DNS name checking to support scenarios where certificates
|
||||||
|
// may not match the internal Kubernetes service names.
|
||||||
|
func VerifyCertificateExceptServerName(rawCerts [][]byte, config *tls.Config) ([]*x509.Certificate, [][]*x509.Certificate, error) {
|
||||||
|
if len(rawCerts) == 0 {
|
||||||
|
return nil, nil, errors.New("tls: no certificates provided by peer")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config == nil {
|
||||||
|
return nil, nil, errors.New("tls: config cannot be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.RootCAs == nil {
|
||||||
|
return nil, nil, errors.New("tls: no root CAs configured for verification")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse all certificates in the chain
|
||||||
|
certs := make([]*x509.Certificate, len(rawCerts))
|
||||||
|
for i, asn1Data := range rawCerts {
|
||||||
|
cert, err := x509.ParseCertificate(asn1Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("tls: failed to parse certificate at index %d: %w", i, err)
|
||||||
|
}
|
||||||
|
certs[i] = cert
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the verification time
|
||||||
|
var verifyTime time.Time
|
||||||
|
if config.Time != nil {
|
||||||
|
verifyTime = config.Time()
|
||||||
|
} else {
|
||||||
|
verifyTime = time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the intermediate certificate pool from the certificate chain
|
||||||
|
intermediates := x509.NewCertPool()
|
||||||
|
for i := 1; i < len(certs); i++ {
|
||||||
|
intermediates.AddCert(certs[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up verification options without DNS name validation
|
||||||
|
// This is the key difference from standard TLS verification
|
||||||
|
opts := x509.VerifyOptions{
|
||||||
|
Roots: config.RootCAs,
|
||||||
|
Intermediates: intermediates,
|
||||||
|
CurrentTime: verifyTime,
|
||||||
|
// Deliberately omit DNSName to skip hostname verification
|
||||||
|
// This allows certificates that don't match the server hostname
|
||||||
|
// but are still valid and signed by a trusted CA
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the leaf certificate (first in the chain)
|
||||||
|
leafCert := certs[0]
|
||||||
|
chains, err := leafCert.Verify(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("tls: certificate verification failed: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return certs, chains, nil
|
||||||
|
}
|
|
@ -107,7 +107,7 @@ func (m *PodAntiAffiniytMutate) InjectLogger(l logr.Logger) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *PodAntiAffiniytMutate) AddPodAntiAffinity(pod *corev1.Pod) {
|
func (v *PodAntiAffiniytMutate) AddPodAntiAffinity(pod *corev1.Pod) {
|
||||||
podName := pod.ObjectMeta.Name
|
podName := pod.Name
|
||||||
antiLabelValue := v.getAntiAffinityValue(podName)
|
antiLabelValue := v.getAntiAffinityValue(podName)
|
||||||
|
|
||||||
if pod.Spec.Affinity == nil {
|
if pod.Spec.Affinity == nil {
|
||||||
|
@ -158,10 +158,10 @@ func (v *PodAntiAffiniytMutate) isRedisClusterPod(pod *corev1.Pod) bool {
|
||||||
|
|
||||||
func (v *PodAntiAffiniytMutate) getAntiAffinityValue(podName string) string {
|
func (v *PodAntiAffiniytMutate) getAntiAffinityValue(podName string) string {
|
||||||
if strings.Contains(podName, "follower") {
|
if strings.Contains(podName, "follower") {
|
||||||
return strings.Replace(podName, "follower", "leader", -1)
|
return strings.ReplaceAll(podName, "follower", "leader")
|
||||||
}
|
}
|
||||||
if strings.Contains(podName, "leader") {
|
if strings.Contains(podName, "leader") {
|
||||||
return strings.Replace(podName, "leader", "follower", -1)
|
return strings.ReplaceAll(podName, "leader", "follower")
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func CreateFakeClientWithPodIPs_LeaderPods(cr *rcvb2.RedisCluster) *fake.Clients
|
||||||
pods := make([]runtime.Object, replicas)
|
pods := make([]runtime.Object, replicas)
|
||||||
|
|
||||||
for i := 0; i < int(replicas); i++ {
|
for i := 0; i < int(replicas); i++ {
|
||||||
podName := cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(i)
|
podName := cr.Name + "-leader-" + strconv.Itoa(i)
|
||||||
pods[i] = &corev1.Pod{
|
pods[i] = &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
@ -37,7 +37,7 @@ func CreateFakeObjectWithPodIPs(cr *rcvb2.RedisCluster) []runtime.Object {
|
||||||
pods := make([]runtime.Object, leaderReplicas+followerReplicas)
|
pods := make([]runtime.Object, leaderReplicas+followerReplicas)
|
||||||
|
|
||||||
for i := 0; i < int(leaderReplicas); i++ {
|
for i := 0; i < int(leaderReplicas); i++ {
|
||||||
podName := cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(i)
|
podName := cr.Name + "-leader-" + strconv.Itoa(i)
|
||||||
pods[i] = &corev1.Pod{
|
pods[i] = &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
@ -49,7 +49,7 @@ func CreateFakeObjectWithPodIPs(cr *rcvb2.RedisCluster) []runtime.Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < int(followerReplicas); i++ {
|
for i := 0; i < int(followerReplicas); i++ {
|
||||||
podName := cr.ObjectMeta.Name + "-follower-" + strconv.Itoa(i)
|
podName := cr.Name + "-follower-" + strconv.Itoa(i)
|
||||||
pods[i+int(leaderReplicas)] = &corev1.Pod{
|
pods[i+int(leaderReplicas)] = &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
@ -83,7 +83,7 @@ func CreateFakeClientWithSecrets(ctx context.Context, cr *rcvb2.RedisCluster, se
|
||||||
pods := make([]runtime.Object, 0)
|
pods := make([]runtime.Object, 0)
|
||||||
|
|
||||||
for i := 0; i < int(leaderReplicas); i++ {
|
for i := 0; i < int(leaderReplicas); i++ {
|
||||||
podName := cr.ObjectMeta.Name + "-leader-" + strconv.Itoa(i)
|
podName := cr.Name + "-leader-" + strconv.Itoa(i)
|
||||||
pods[i] = &corev1.Pod{
|
pods[i] = &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
@ -95,7 +95,7 @@ func CreateFakeClientWithSecrets(ctx context.Context, cr *rcvb2.RedisCluster, se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := 0; i < int(followerReplicas); i++ {
|
for i := 0; i < int(followerReplicas); i++ {
|
||||||
podName := cr.ObjectMeta.Name + "-follower-" + strconv.Itoa(i)
|
podName := cr.Name + "-follower-" + strconv.Itoa(i)
|
||||||
pods[i+int(leaderReplicas)] = &corev1.Pod{
|
pods[i+int(leaderReplicas)] = &corev1.Pod{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: podName,
|
Name: podName,
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -24,9 +25,10 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
host string
|
host string
|
||||||
pass string
|
pass string
|
||||||
mode string
|
mode string
|
||||||
|
tlsFlag bool
|
||||||
|
|
||||||
sentinelPass string
|
sentinelPass string
|
||||||
)
|
)
|
||||||
|
@ -52,6 +54,7 @@ func main() {
|
||||||
rootCmd.PersistentFlags().StringVarP(&host, hostFlag, "H", "", "redis host")
|
rootCmd.PersistentFlags().StringVarP(&host, hostFlag, "H", "", "redis host")
|
||||||
rootCmd.PersistentFlags().StringVarP(&pass, passFlag, "P", "", "redis password")
|
rootCmd.PersistentFlags().StringVarP(&pass, passFlag, "P", "", "redis password")
|
||||||
rootCmd.PersistentFlags().StringVarP(&mode, modeFlag, "M", "", "redis mode")
|
rootCmd.PersistentFlags().StringVarP(&mode, modeFlag, "M", "", "redis mode")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&tlsFlag, "tls", "T", false, "enable tls")
|
||||||
rootCmd.PersistentFlags().StringVarP(&sentinelPass, sentinelPassFlag, "S", "", "redis sentinel password")
|
rootCmd.PersistentFlags().StringVarP(&sentinelPass, sentinelPassFlag, "S", "", "redis sentinel password")
|
||||||
rootCmd.Execute()
|
rootCmd.Execute()
|
||||||
}
|
}
|
||||||
|
@ -74,7 +77,7 @@ func genRedisDataCmd(cmd *cobra.Command, args []string) {
|
||||||
hosts[i] = strings.TrimSpace(hosts[i])
|
hosts[i] = strings.TrimSpace(hosts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass)
|
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass, tlsFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create redis client: %v\n", err)
|
fmt.Printf("failed to create redis client: %v\n", err)
|
||||||
return
|
return
|
||||||
|
@ -125,7 +128,7 @@ func checkRedisData() error {
|
||||||
hosts[i] = strings.TrimSpace(hosts[i])
|
hosts[i] = strings.TrimSpace(hosts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass)
|
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass, tlsFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create redis client: %w", err)
|
return fmt.Errorf("failed to create redis client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -153,20 +156,28 @@ func checkRedisData() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRedisClient(mode string, hosts []string, pass string, sentinelPass string) (redis.UniversalClient, error) {
|
func createRedisClient(mode string, hosts []string, pass string, sentinelPass string, tlsFlag bool) (redis.UniversalClient, error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case "cluster":
|
case "cluster":
|
||||||
return redis.NewClusterClient(&redis.ClusterOptions{
|
opts := &redis.ClusterOptions{
|
||||||
Addrs: hosts,
|
Addrs: hosts,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
}), nil
|
}
|
||||||
|
if tlsFlag {
|
||||||
|
opts.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
}
|
||||||
|
return redis.NewClusterClient(opts), nil
|
||||||
case "sentinel":
|
case "sentinel":
|
||||||
return redis.NewFailoverClient(&redis.FailoverOptions{
|
opts := &redis.FailoverOptions{
|
||||||
MasterName: "myMaster",
|
MasterName: "myMaster",
|
||||||
SentinelAddrs: hosts,
|
SentinelAddrs: hosts,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
SentinelPassword: sentinelPass,
|
SentinelPassword: sentinelPass,
|
||||||
}), nil
|
}
|
||||||
|
if tlsFlag {
|
||||||
|
opts.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
}
|
||||||
|
return redis.NewFailoverClient(opts), nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported redis mode: %s", mode)
|
return nil, fmt.Errorf("unsupported redis mode: %s", mode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ data:
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -31,9 +32,10 @@ data:
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
host string
|
host string
|
||||||
pass string
|
pass string
|
||||||
mode string
|
mode string
|
||||||
|
tlsFlag bool
|
||||||
|
|
||||||
sentinelPass string
|
sentinelPass string
|
||||||
)
|
)
|
||||||
|
@ -59,6 +61,7 @@ data:
|
||||||
rootCmd.PersistentFlags().StringVarP(&host, hostFlag, "H", "", "redis host")
|
rootCmd.PersistentFlags().StringVarP(&host, hostFlag, "H", "", "redis host")
|
||||||
rootCmd.PersistentFlags().StringVarP(&pass, passFlag, "P", "", "redis password")
|
rootCmd.PersistentFlags().StringVarP(&pass, passFlag, "P", "", "redis password")
|
||||||
rootCmd.PersistentFlags().StringVarP(&mode, modeFlag, "M", "", "redis mode")
|
rootCmd.PersistentFlags().StringVarP(&mode, modeFlag, "M", "", "redis mode")
|
||||||
|
rootCmd.PersistentFlags().BoolVarP(&tlsFlag, "tls", "T", false, "enable tls")
|
||||||
rootCmd.PersistentFlags().StringVarP(&sentinelPass, sentinelPassFlag, "S", "", "redis sentinel password")
|
rootCmd.PersistentFlags().StringVarP(&sentinelPass, sentinelPassFlag, "S", "", "redis sentinel password")
|
||||||
rootCmd.Execute()
|
rootCmd.Execute()
|
||||||
}
|
}
|
||||||
|
@ -81,7 +84,7 @@ data:
|
||||||
hosts[i] = strings.TrimSpace(hosts[i])
|
hosts[i] = strings.TrimSpace(hosts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass)
|
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass, tlsFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to create redis client: %v\n", err)
|
fmt.Printf("failed to create redis client: %v\n", err)
|
||||||
return
|
return
|
||||||
|
@ -132,7 +135,7 @@ data:
|
||||||
hosts[i] = strings.TrimSpace(hosts[i])
|
hosts[i] = strings.TrimSpace(hosts[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass)
|
rdb, err := createRedisClient(mode, hosts, pass, sentinelPass, tlsFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to create redis client: %w", err)
|
return fmt.Errorf("failed to create redis client: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -160,20 +163,28 @@ data:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRedisClient(mode string, hosts []string, pass string, sentinelPass string) (redis.UniversalClient, error) {
|
func createRedisClient(mode string, hosts []string, pass string, sentinelPass string, tlsFlag bool) (redis.UniversalClient, error) {
|
||||||
switch mode {
|
switch mode {
|
||||||
case "cluster":
|
case "cluster":
|
||||||
return redis.NewClusterClient(&redis.ClusterOptions{
|
opts := &redis.ClusterOptions{
|
||||||
Addrs: hosts,
|
Addrs: hosts,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
}), nil
|
}
|
||||||
|
if tlsFlag {
|
||||||
|
opts.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
}
|
||||||
|
return redis.NewClusterClient(opts), nil
|
||||||
case "sentinel":
|
case "sentinel":
|
||||||
return redis.NewFailoverClient(&redis.FailoverOptions{
|
opts := &redis.FailoverOptions{
|
||||||
MasterName: "myMaster",
|
MasterName: "myMaster",
|
||||||
SentinelAddrs: hosts,
|
SentinelAddrs: hosts,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
SentinelPassword: sentinelPass,
|
SentinelPassword: sentinelPass,
|
||||||
}), nil
|
}
|
||||||
|
if tlsFlag {
|
||||||
|
opts.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
}
|
||||||
|
return redis.NewFailoverClient(opts), nil
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unsupported redis mode: %s", mode)
|
return nil, fmt.Errorf("unsupported redis mode: %s", mode)
|
||||||
}
|
}
|
||||||
|
@ -263,7 +274,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: data-assert
|
- name: data-assert
|
||||||
image: docker.io/library/golang:1.23.4
|
image: docker.m.daocloud.io/library/golang:1.23.4
|
||||||
command: ["/bin/sh", "-c"]
|
command: ["/bin/sh", "-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
|
|
|
@ -18,7 +18,7 @@ metadata:
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: data-assert
|
- name: data-assert
|
||||||
image: docker.io/library/golang:1.23.4
|
image: docker.m.daocloud.io/library/golang:1.23.4
|
||||||
command: ["/bin/sh", "-c"]
|
command: ["/bin/sh", "-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
|
|
|
@ -17,6 +17,35 @@ spec:
|
||||||
file: ha.yaml
|
file: ha.yaml
|
||||||
- apply:
|
- apply:
|
||||||
file: ../../../../data-assert/resources.yaml
|
file: ../../../../data-assert/resources.yaml
|
||||||
|
# create certificate secret use script, because the namespace name is unknown in the yaml file
|
||||||
|
- script:
|
||||||
|
timeout: 10s
|
||||||
|
content: |
|
||||||
|
cat <<EOF | kubectl apply -f -
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Issuer
|
||||||
|
metadata:
|
||||||
|
name: selfsigned-issuer
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
spec:
|
||||||
|
selfSigned: {}
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Certificate
|
||||||
|
metadata:
|
||||||
|
name: redis-tls
|
||||||
|
namespace: ${NAMESPACE}
|
||||||
|
spec:
|
||||||
|
commonName: redis-replication
|
||||||
|
dnsNames:
|
||||||
|
- "*.redis-replication-headless.${NAMESPACE}.svc.cluster.local"
|
||||||
|
- "*.redis-sentinel-sentinel-headless.${NAMESPACE}.svc.cluster.local"
|
||||||
|
issuerRef:
|
||||||
|
name: selfsigned-issuer
|
||||||
|
kind: Issuer
|
||||||
|
secretName: redis-tls-cert
|
||||||
|
EOF
|
||||||
|
|
||||||
- name: Test Master IP consistency
|
- name: Test Master IP consistency
|
||||||
try:
|
try:
|
||||||
|
@ -26,10 +55,9 @@ spec:
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
content: |
|
content: |
|
||||||
export MASTER_POD_FROM_STATUS=$(kubectl -n ${NAMESPACE} get redisreplication redis-replication -o jsonpath='{.status.masterNode}');
|
export MASTER_POD_FROM_STATUS=$(kubectl -n ${NAMESPACE} get redisreplication redis-replication -o jsonpath='{.status.masterNode}');
|
||||||
export MASTER_IP_FROM_STATUS=$(kubectl -n ${NAMESPACE} get pod ${MASTER_POD_FROM_STATUS} -o jsonpath='{.status.podIP}');
|
export FROM_SENTINEL=$(kubectl -n ${NAMESPACE} exec redis-sentinel-sentinel-0 -c redis-sentinel-sentinel -- redis-cli --no-auth-warning --tls --cacert /tls/ca.crt -a Opstree@1234sentinel -p 26379 sentinel get-master-addr-by-name myMaster | head -n 1 | cut -d'.' -f1);
|
||||||
export FROM_SENTINEL=$(kubectl -n ${NAMESPACE} exec redis-sentinel-sentinel-0 -- redis-cli -a Opstree@1234sentinel -p 26379 sentinel get-master-addr-by-name myMaster | head -n 1);
|
export MASTER_POD_FROM_LABEL=$(kubectl -n ${NAMESPACE} get pod -l app=redis-replication,redis-role=master,redis_setup_type=replication -o jsonpath='{.items[0].metadata.name}');
|
||||||
export MASTER_IP_FROM_LABEL=$(kubectl -n ${NAMESPACE} get pod -l app=redis-replication,redis-role=master,redis_setup_type=replication -o jsonpath='{.items[0].status.podIP}');
|
if [ "$FROM_SENTINEL" = "$MASTER_POD_FROM_LABEL" ] && [ "$FROM_SENTINEL" = "$MASTER_POD_FROM_STATUS" ]; then echo "OK"; else echo "FAIL"; fi
|
||||||
if [ "$FROM_SENTINEL" = "$MASTER_IP_FROM_LABEL" ] && [ "$FROM_SENTINEL" = "$MASTER_IP_FROM_STATUS" ]; then echo "OK"; else echo "FAIL"; fi
|
|
||||||
check:
|
check:
|
||||||
(contains($stdout, 'OK')): true
|
(contains($stdout, 'OK')): true
|
||||||
|
|
||||||
|
@ -42,6 +70,7 @@ spec:
|
||||||
bash -c "cd /go/src/data-assert && go run main.go gen-redis-data \
|
bash -c "cd /go/src/data-assert && go run main.go gen-redis-data \
|
||||||
--host redis-sentinel-sentinel.${NAMESPACE}.svc.cluster.local:26379 \
|
--host redis-sentinel-sentinel.${NAMESPACE}.svc.cluster.local:26379 \
|
||||||
--mode sentinel \
|
--mode sentinel \
|
||||||
|
--tls \
|
||||||
--password-sentinel Opstree@1234sentinel \
|
--password-sentinel Opstree@1234sentinel \
|
||||||
--password Opstree@1234replication"
|
--password Opstree@1234replication"
|
||||||
check:
|
check:
|
||||||
|
@ -62,10 +91,9 @@ spec:
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
content: |
|
content: |
|
||||||
export MASTER_POD_FROM_STATUS=$(kubectl -n ${NAMESPACE} get redisreplication redis-replication -o jsonpath='{.status.masterNode}');
|
export MASTER_POD_FROM_STATUS=$(kubectl -n ${NAMESPACE} get redisreplication redis-replication -o jsonpath='{.status.masterNode}');
|
||||||
export MASTER_IP_FROM_STATUS=$(kubectl -n ${NAMESPACE} get pod ${MASTER_POD_FROM_STATUS} -o jsonpath='{.status.podIP}');
|
export FROM_SENTINEL=$(kubectl -n ${NAMESPACE} exec redis-sentinel-sentinel-0 -c redis-sentinel-sentinel -- redis-cli --no-auth-warning --tls --cacert /tls/ca.crt -a Opstree@1234sentinel -p 26379 sentinel get-master-addr-by-name myMaster | head -n 1 | cut -d'.' -f1);
|
||||||
export FROM_SENTINEL=$(kubectl -n ${NAMESPACE} exec redis-sentinel-sentinel-0 -- redis-cli -a Opstree@1234sentinel -p 26379 sentinel get-master-addr-by-name myMaster | head -n 1);
|
export MASTER_POD_FROM_LABEL=$(kubectl -n ${NAMESPACE} get pod -l app=redis-replication,redis-role=master,redis_setup_type=replication -o jsonpath='{.items[0].metadata.name}');
|
||||||
export MASTER_IP_FROM_LABEL=$(kubectl -n ${NAMESPACE} get pod -l app=redis-replication,redis-role=master,redis_setup_type=replication -o jsonpath='{.items[0].status.podIP}');
|
if [ "$FROM_SENTINEL" = "$MASTER_POD_FROM_LABEL" ] && [ "$FROM_SENTINEL" = "$MASTER_POD_FROM_STATUS" ]; then echo "OK"; else echo "FAIL"; fi
|
||||||
if [ "$FROM_SENTINEL" = "$MASTER_IP_FROM_LABEL" ] && [ "$FROM_SENTINEL" = "$MASTER_IP_FROM_STATUS" ]; then echo "OK"; else echo "FAIL"; fi
|
|
||||||
check:
|
check:
|
||||||
(contains($stdout, 'OK')): true
|
(contains($stdout, 'OK')): true
|
||||||
|
|
||||||
|
@ -78,6 +106,7 @@ spec:
|
||||||
bash -c "cd /go/src/data-assert && go run main.go chk-redis-data \
|
bash -c "cd /go/src/data-assert && go run main.go chk-redis-data \
|
||||||
--host redis-sentinel-sentinel.${NAMESPACE}.svc.cluster.local:26379 \
|
--host redis-sentinel-sentinel.${NAMESPACE}.svc.cluster.local:26379 \
|
||||||
--mode sentinel \
|
--mode sentinel \
|
||||||
|
--tls \
|
||||||
--password-sentinel Opstree@1234sentinel \
|
--password-sentinel Opstree@1234sentinel \
|
||||||
--password Opstree@1234replication"
|
--password Opstree@1234replication"
|
||||||
check:
|
check:
|
||||||
|
|
|
@ -14,6 +14,12 @@ kind: RedisReplication
|
||||||
metadata:
|
metadata:
|
||||||
name: redis-replication
|
name: redis-replication
|
||||||
spec:
|
spec:
|
||||||
|
TLS:
|
||||||
|
ca: ca.crt
|
||||||
|
cert: tls.crt
|
||||||
|
key: tls.key
|
||||||
|
secret:
|
||||||
|
secretName: redis-tls-cert
|
||||||
clusterSize: 3
|
clusterSize: 3
|
||||||
podSecurityContext:
|
podSecurityContext:
|
||||||
runAsUser: 1000
|
runAsUser: 1000
|
||||||
|
@ -53,13 +59,22 @@ kind: RedisSentinel
|
||||||
metadata:
|
metadata:
|
||||||
name: redis-sentinel
|
name: redis-sentinel
|
||||||
spec:
|
spec:
|
||||||
|
TLS:
|
||||||
|
ca: ca.crt
|
||||||
|
cert: tls.crt
|
||||||
|
key: tls.key
|
||||||
|
secret:
|
||||||
|
secretName: redis-tls-cert
|
||||||
clusterSize: 1
|
clusterSize: 1
|
||||||
podSecurityContext:
|
podSecurityContext:
|
||||||
runAsUser: 1000
|
runAsUser: 1000
|
||||||
fsGroup: 1000
|
fsGroup: 1000
|
||||||
redisSentinelConfig:
|
redisSentinelConfig:
|
||||||
|
resolveHostnames: "yes"
|
||||||
|
announceHostnames: "yes"
|
||||||
redisReplicationName: redis-replication
|
redisReplicationName: redis-replication
|
||||||
quorum: '1'
|
quorum: '1'
|
||||||
|
failoverTimeout: '10000'
|
||||||
redisReplicationPassword:
|
redisReplicationPassword:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
name: redis-replication-password
|
name: redis-replication-password
|
||||||
|
|
Loading…
Reference in New Issue