diff --git a/api/common_types.go b/api/common_types.go index 42af4be25..c0212cf31 100644 --- a/api/common_types.go +++ b/api/common_types.go @@ -16,6 +16,7 @@ type KubernetesConfig struct { UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` Service *ServiceConfig `json:"service,omitempty"` IgnoreAnnotations []string `json:"ignoreAnnotations,omitempty"` + MinReadySeconds *int32 `json:"minReadySeconds,omitempty"` } // ServiceConfig define the type of service to be created and its annotations diff --git a/api/zz_generated.deepcopy.go b/api/zz_generated.deepcopy.go index df94626ef..306be262b 100644 --- a/api/zz_generated.deepcopy.go +++ b/api/zz_generated.deepcopy.go @@ -112,6 +112,11 @@ func (in *KubernetesConfig) DeepCopyInto(out *KubernetesConfig) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.MinReadySeconds != nil { + in, out := &in.MinReadySeconds, &out.MinReadySeconds + *out = new(int32) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubernetesConfig. diff --git a/charts/redis-cluster/templates/redis-cluster.yaml b/charts/redis-cluster/templates/redis-cluster.yaml index 84a0a1ad1..c224b2ad6 100644 --- a/charts/redis-cluster/templates/redis-cluster.yaml +++ b/charts/redis-cluster/templates/redis-cluster.yaml @@ -48,6 +48,7 @@ spec: name: {{ .Values.redisCluster.redisSecret.secretName | quote }} key: {{ .Values.redisCluster.redisSecret.secretKey | quote }} {{- end }} + minReadySeconds: {{ .Values.redisCluster.minReadySeconds | default 0 }} {{- if .Values.storageSpec }} storage: {{ toYaml .Values.storageSpec | nindent 4 }} diff --git a/charts/redis-cluster/values.yaml b/charts/redis-cluster/values.yaml index 4e77a20df..04302fde3 100644 --- a/charts/redis-cluster/values.yaml +++ b/charts/redis-cluster/values.yaml @@ -43,7 +43,8 @@ redisCluster: enabled: false maxUnavailable: 1 minAvailable: 1 - + # minReadySeconds: 0 + follower: replicas: 3 serviceType: ClusterIP diff --git a/charts/redis-operator/crds/redis-cluster.yaml b/charts/redis-operator/crds/redis-cluster.yaml index d6b10f5c5..a5a596988 100644 --- a/charts/redis-operator/crds/redis-cluster.yaml +++ b/charts/redis-operator/crds/redis-cluster.yaml @@ -159,6 +159,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6749,6 +6752,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/charts/redis-operator/crds/redis-replication.yaml b/charts/redis-operator/crds/redis-replication.yaml index e14a87912..8cf6c32eb 100644 --- a/charts/redis-operator/crds/redis-replication.yaml +++ b/charts/redis-operator/crds/redis-replication.yaml @@ -1109,6 +1109,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6141,6 +6144,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/charts/redis-operator/crds/redis-sentinel.yaml b/charts/redis-operator/crds/redis-sentinel.yaml index 42305a4ed..4599c070b 100644 --- a/charts/redis-operator/crds/redis-sentinel.yaml +++ b/charts/redis-operator/crds/redis-sentinel.yaml @@ -1110,6 +1110,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -3595,6 +3598,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/charts/redis-operator/crds/redis.yaml b/charts/redis-operator/crds/redis.yaml index 3506cf20d..3ad451862 100644 --- a/charts/redis-operator/crds/redis.yaml +++ b/charts/redis-operator/crds/redis.yaml @@ -1107,6 +1107,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6133,6 +6136,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/charts/redis-replication/templates/redis-replication.yaml b/charts/redis-replication/templates/redis-replication.yaml index ea89f23b0..962c9bb51 100644 --- a/charts/redis-replication/templates/redis-replication.yaml +++ b/charts/redis-replication/templates/redis-replication.yaml @@ -23,6 +23,7 @@ spec: {{- if .Values.redisReplication.ignoreAnnotations}} ignoreAnnotations: {{ toYaml .Values.redisReplication.ignoreAnnotations | nindent 6 }} {{- end }} + minReadySeconds: {{ .Values.redisReplication.minReadySeconds | default 0 }} redisExporter: enabled: {{ .Values.redisExporter.enabled }} diff --git a/charts/redis-replication/values.yaml b/charts/redis-replication/values.yaml index b2afb5ca2..ea0882658 100644 --- a/charts/redis-replication/values.yaml +++ b/charts/redis-replication/values.yaml @@ -20,7 +20,8 @@ redisReplication: # memory: 128Mi ignoreAnnotations: [] # - "redis.opstreelabs.in/ignore" - + # minReadySeconds: 0 + # Overwite name for resources # name: "" diff --git a/charts/redis-sentinel/templates/redis-sentinel.yaml b/charts/redis-sentinel/templates/redis-sentinel.yaml index 491b8ecf0..6f0aca370 100644 --- a/charts/redis-sentinel/templates/redis-sentinel.yaml +++ b/charts/redis-sentinel/templates/redis-sentinel.yaml @@ -42,6 +42,7 @@ spec: {{- if .Values.redisSentinel.ignoreAnnotations}} ignoreAnnotations: {{ toYaml .Values.redisSentinel.ignoreAnnotations | nindent 6 }} {{- end }} + minReadySeconds: {{ .Values.redisSentinel.minReadySeconds | default 0 }} redisExporter: enabled: {{ .Values.redisExporter.enabled }} diff --git a/charts/redis-sentinel/values.yaml b/charts/redis-sentinel/values.yaml index 13041b2d7..2c1073b9f 100644 --- a/charts/redis-sentinel/values.yaml +++ b/charts/redis-sentinel/values.yaml @@ -20,7 +20,8 @@ redisSentinel: # memory: 128Mi ignoreAnnotations: [] # - "redis.opstreelabs.in/ignore" - + # minReadySeconds: 0 + # Overwite name for resources # name: "" diff --git a/charts/redis/templates/redis-standalone.yaml b/charts/redis/templates/redis-standalone.yaml index c48775035..6656ea26c 100644 --- a/charts/redis/templates/redis-standalone.yaml +++ b/charts/redis/templates/redis-standalone.yaml @@ -22,7 +22,8 @@ spec: {{- if .Values.redisStandalone.ignoreAnnotations}} ignoreAnnotations: {{ toYaml .Values.redisStandalone.ignoreAnnotations | nindent 6 }} {{- end }} - + minReadySeconds: {{ .Values.redisStandalone.minReadySeconds | default 0 }} + redisExporter: enabled: {{ .Values.redisExporter.enabled }} image: "{{ .Values.redisExporter.image }}:{{ .Values.redisExporter.tag }}" diff --git a/charts/redis/values.yaml b/charts/redis/values.yaml index e929a2ebe..a916553c5 100644 --- a/charts/redis/values.yaml +++ b/charts/redis/values.yaml @@ -19,6 +19,7 @@ redisStandalone: # memory: 128Mi ignoreAnnotations: [] # - "redis.opstreelabs.in/ignore" + # minReadySeconds: 0 labels: {} # foo: bar diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml index 3506cf20d..3ad451862 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml @@ -1107,6 +1107,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6133,6 +6136,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml index d6b10f5c5..a5a596988 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml @@ -159,6 +159,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6749,6 +6752,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml index e14a87912..8cf6c32eb 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redisreplications.yaml @@ -1109,6 +1109,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -6141,6 +6144,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml index 42305a4ed..4599c070b 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redissentinels.yaml @@ -1110,6 +1110,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret @@ -3595,6 +3598,9 @@ spec: type: string type: object type: array + minReadySeconds: + format: int32 + type: integer redisSecret: description: ExistingPasswordSecret is the struct to access the existing secret diff --git a/k8sutils/redis-cluster.go b/k8sutils/redis-cluster.go index bfecb9ab2..9cc63ecd3 100644 --- a/k8sutils/redis-cluster.go +++ b/k8sutils/redis-cluster.go @@ -33,6 +33,10 @@ type RedisClusterService struct { // generateRedisClusterParams generates Redis cluster information func generateRedisClusterParams(cr *redisv1beta2.RedisCluster, replicas int32, externalConfig *string, params RedisClusterSTS) statefulSetParameters { + var minreadyseconds int32 = 0 + if cr.Spec.KubernetesConfig.MinReadySeconds != nil { + minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds + } res := statefulSetParameters{ Replicas: &replicas, ClusterMode: true, @@ -47,6 +51,7 @@ func generateRedisClusterParams(cr *redisv1beta2.RedisCluster, replicas int32, e UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy, IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations, HostNetwork: cr.Spec.HostNetwork, + MinReadySeconds: minreadyseconds, } if cr.Spec.RedisExporter != nil { res.EnableMetrics = cr.Spec.RedisExporter.Enabled diff --git a/k8sutils/redis-cluster_test.go b/k8sutils/redis-cluster_test.go index 1d6ad8a9b..857fbe825 100644 --- a/k8sutils/redis-cluster_test.go +++ b/k8sutils/redis-cluster_test.go @@ -28,6 +28,7 @@ func Test_generateRedisClusterParams(t *testing.T) { FSGroup: ptr.To(int64(1000)), }, PriorityClassName: "high-priority", + MinReadySeconds: 5, Affinity: &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ @@ -94,6 +95,7 @@ func Test_generateRedisClusterParams(t *testing.T) { FSGroup: ptr.To(int64(1000)), }, PriorityClassName: "high-priority", + MinReadySeconds: 5, Affinity: &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ diff --git a/k8sutils/redis-replication.go b/k8sutils/redis-replication.go index 545d9b079..66c066492 100644 --- a/k8sutils/redis-replication.go +++ b/k8sutils/redis-replication.go @@ -61,6 +61,7 @@ func CreateReplicationRedis(cr *redisv1beta2.RedisReplication, cl kubernetes.Int labels := getRedisLabels(cr.ObjectMeta.Name, replication, "replication", cr.ObjectMeta.Labels) annotations := generateStatefulSetsAnots(cr.ObjectMeta, cr.Spec.KubernetesConfig.IgnoreAnnotations) objectMetaInfo := generateObjectMetaInformation(stateFulName, cr.Namespace, labels, annotations) + err := CreateOrUpdateStateFul( cl, logger, @@ -81,6 +82,10 @@ func CreateReplicationRedis(cr *redisv1beta2.RedisReplication, cl kubernetes.Int func generateRedisReplicationParams(cr *redisv1beta2.RedisReplication) statefulSetParameters { replicas := cr.Spec.GetReplicationCounts("Replication") + var minreadyseconds int32 = 0 + if cr.Spec.KubernetesConfig.MinReadySeconds != nil { + minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds + } res := statefulSetParameters{ Replicas: &replicas, ClusterMode: false, @@ -93,6 +98,7 @@ func generateRedisReplicationParams(cr *redisv1beta2.RedisReplication) statefulS TerminationGracePeriodSeconds: cr.Spec.TerminationGracePeriodSeconds, UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy, IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations, + MinReadySeconds: minreadyseconds, } if cr.Spec.KubernetesConfig.ImagePullSecrets != nil { res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets diff --git a/k8sutils/redis-replication_test.go b/k8sutils/redis-replication_test.go index acde9df5c..1a88b07c5 100644 --- a/k8sutils/redis-replication_test.go +++ b/k8sutils/redis-replication_test.go @@ -28,6 +28,7 @@ func Test_generateRedisReplicationParams(t *testing.T) { FSGroup: ptr.To(int64(1000)), }, PriorityClassName: "high-priority", + MinReadySeconds: 5, Affinity: &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ @@ -86,7 +87,6 @@ func Test_generateRedisReplicationParams(t *testing.T) { if err != nil { t.Fatalf("Failed to unmarshal file %s: %v", path, err) } - actual := generateRedisReplicationParams(input) assert.EqualValues(t, expected, actual, "Expected %+v, got %+v", expected, actual) } diff --git a/k8sutils/redis-sentinel.go b/k8sutils/redis-sentinel.go index 1a985b1eb..873b05e1c 100644 --- a/k8sutils/redis-sentinel.go +++ b/k8sutils/redis-sentinel.go @@ -86,6 +86,10 @@ func (service RedisSentinelSTS) CreateRedisSentinelSetup(ctx context.Context, cl // Create Redis Sentile Params for the statefulset func generateRedisSentinelParams(cr *redisv1beta2.RedisSentinel, replicas int32, externalConfig *string, affinity *corev1.Affinity) statefulSetParameters { + var minreadyseconds int32 = 0 + if cr.Spec.KubernetesConfig.MinReadySeconds != nil { + minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds + } res := statefulSetParameters{ Replicas: &replicas, ClusterMode: false, @@ -99,6 +103,7 @@ func generateRedisSentinelParams(cr *redisv1beta2.RedisSentinel, replicas int32, ServiceAccountName: cr.Spec.ServiceAccountName, UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy, IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations, + MinReadySeconds: minreadyseconds, } if cr.Spec.KubernetesConfig.ImagePullSecrets != nil { diff --git a/k8sutils/redis-sentinel_test.go b/k8sutils/redis-sentinel_test.go index 1eae1a4a1..e01cb6529 100644 --- a/k8sutils/redis-sentinel_test.go +++ b/k8sutils/redis-sentinel_test.go @@ -35,6 +35,7 @@ func Test_generateRedisSentinelParams(t *testing.T) { FSGroup: ptr.To(int64(1000)), }, PriorityClassName: "high-priority", + MinReadySeconds: 5, Affinity: &corev1.Affinity{ NodeAffinity: &corev1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{ diff --git a/k8sutils/redis-standalone.go b/k8sutils/redis-standalone.go index b53cff6ff..4fed7d135 100644 --- a/k8sutils/redis-standalone.go +++ b/k8sutils/redis-standalone.go @@ -77,6 +77,10 @@ func CreateStandaloneRedis(cr *redisv1beta2.Redis, cl kubernetes.Interface) erro // generateRedisStandalone generates Redis standalone information func generateRedisStandaloneParams(cr *redisv1beta2.Redis) statefulSetParameters { replicas := int32(1) + var minreadyseconds int32 = 0 + if cr.Spec.KubernetesConfig.MinReadySeconds != nil { + minreadyseconds = *cr.Spec.KubernetesConfig.MinReadySeconds + } res := statefulSetParameters{ Replicas: &replicas, ClusterMode: false, @@ -89,6 +93,7 @@ func generateRedisStandaloneParams(cr *redisv1beta2.Redis) statefulSetParameters Tolerations: cr.Spec.Tolerations, UpdateStrategy: cr.Spec.KubernetesConfig.UpdateStrategy, IgnoreAnnotations: cr.Spec.KubernetesConfig.IgnoreAnnotations, + MinReadySeconds: minreadyseconds, } if cr.Spec.KubernetesConfig.ImagePullSecrets != nil { res.ImagePullSecrets = cr.Spec.KubernetesConfig.ImagePullSecrets diff --git a/k8sutils/redis-standalone_test.go b/k8sutils/redis-standalone_test.go index 2637df54f..9b2351822 100644 --- a/k8sutils/redis-standalone_test.go +++ b/k8sutils/redis-standalone_test.go @@ -17,9 +17,10 @@ import ( func Test_generateRedisStandaloneParams(t *testing.T) { path := filepath.Join("..", "tests", "testdata", "redis-standalone.yaml") expected := statefulSetParameters{ - Replicas: ptr.To(int32(1)), - ClusterMode: false, - NodeConfVolume: false, + Replicas: ptr.To(int32(1)), + ClusterMode: false, + NodeConfVolume: false, + MinReadySeconds: 5, // Metadata: metav1.ObjectMeta{ // Name: "redis-standalone", // Namespace: "redis", diff --git a/k8sutils/statefulset.go b/k8sutils/statefulset.go index 10d5f0288..bc31d4975 100644 --- a/k8sutils/statefulset.go +++ b/k8sutils/statefulset.go @@ -107,6 +107,7 @@ type statefulSetParameters struct { TerminationGracePeriodSeconds *int64 IgnoreAnnotations []string HostNetwork bool + MinReadySeconds int32 } // containerParameters will define container input params @@ -279,10 +280,11 @@ func generateStatefulSetsDef(stsMeta metav1.ObjectMeta, params statefulSetParame TypeMeta: generateMetaInformation("StatefulSet", "apps/v1"), ObjectMeta: stsMeta, Spec: appsv1.StatefulSetSpec{ - Selector: LabelSelectors(stsMeta.GetLabels()), - ServiceName: fmt.Sprintf("%s-headless", stsMeta.Name), - Replicas: params.Replicas, - UpdateStrategy: params.UpdateStrategy, + Selector: LabelSelectors(stsMeta.GetLabels()), + ServiceName: fmt.Sprintf("%s-headless", stsMeta.Name), + Replicas: params.Replicas, + UpdateStrategy: params.UpdateStrategy, + MinReadySeconds: params.MinReadySeconds, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: stsMeta.GetLabels(), diff --git a/tests/testdata/redis-cluster.yaml b/tests/testdata/redis-cluster.yaml index 26eee377e..575073d2c 100644 --- a/tests/testdata/redis-cluster.yaml +++ b/tests/testdata/redis-cluster.yaml @@ -26,6 +26,7 @@ spec: name: redis-secret key: password ignoreAnnotations: [opstreelabs.in/ignore] + minReadySeconds: 5 podSecurityContext: runAsUser: 1000 fsGroup: 1000 diff --git a/tests/testdata/redis-replication.yaml b/tests/testdata/redis-replication.yaml index 4214e2f3c..0c40a1c20 100644 --- a/tests/testdata/redis-replication.yaml +++ b/tests/testdata/redis-replication.yaml @@ -39,6 +39,7 @@ spec: name: redis-secret key: password ignoreAnnotations: [opstreelabs.in/ignore] + minReadySeconds: 5 redisExporter: enabled: true image: quay.io/opstree/redis-exporter:v1.44.0 diff --git a/tests/testdata/redis-sentinel.yaml b/tests/testdata/redis-sentinel.yaml index a183960c5..517b626e1 100644 --- a/tests/testdata/redis-sentinel.yaml +++ b/tests/testdata/redis-sentinel.yaml @@ -37,6 +37,7 @@ spec: name: redis-secret key: password ignoreAnnotations: [opstreelabs.in/ignore] + minReadySeconds: 5 redisExporter: enabled: true image: quay.io/opstree/redis-exporter:v1.44.0 diff --git a/tests/testdata/redis-standalone.yaml b/tests/testdata/redis-standalone.yaml index 305d9b9b6..ca06e5be2 100644 --- a/tests/testdata/redis-standalone.yaml +++ b/tests/testdata/redis-standalone.yaml @@ -38,6 +38,7 @@ spec: name: redis-secret key: password ignoreAnnotations: [opstreelabs.in/ignore] + minReadySeconds: 5 redisExporter: enabled: true image: quay.io/opstree/redis-exporter:v1.44.0