diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 1ba457741..416f38935 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -23,13 +23,19 @@ import ( // KubernetesConfig will be the JSON struct for Basic Redis Config type KubernetesConfig struct { - Image string `json:"image"` - ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` - Resources *corev1.ResourceRequirements `json:"resources,omitempty"` - ExistingPasswordSecret *ExistingPasswordSecret `json:"redisSecret,omitempty"` - ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` - UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` - Service *ServiceConfig `json:"service,omitempty"` + Image string `json:"image"` + ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"` + Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + ExistOrGenerateSecret *ExistOrGenerateSecrets `json:"redisSecret,omitempty"` + ImagePullSecrets *[]corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` + UpdateStrategy appsv1.StatefulSetUpdateStrategy `json:"updateStrategy,omitempty"` + Service *ServiceConfig `json:"service,omitempty"` +} + +// +kubebuilder:validation:MaxProperties=1 +type ExistOrGenerateSecrets struct { + ExistingPasswordSecret *ExistingPasswordSecret `json:"existRedisSecret,omitempty"` + GeneratePasswordSecret *GeneratePassword `json:"generatePasswordSecret,omitempty"` } // ServiceConfig define the type of service to be created and its annotations @@ -50,6 +56,13 @@ type ExistingPasswordSecret struct { Key *string `json:"key,omitempty"` } +type GeneratePassword struct { + Name *string `json:"name"` + // +kubebuilder:default=key + Key *string `json:"key,omitempty"` + NameSpace []string `json:"namespace,omitempty"` +} + // Storage is the inteface to add pvc and pv support in redis type Storage struct { VolumeClaimTemplate corev1.PersistentVolumeClaim `json:"volumeClaimTemplate,omitempty"` diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 461c03e35..a6aaf6e47 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -55,6 +55,31 @@ func (in *AdditionalVolume) DeepCopy() *AdditionalVolume { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ExistOrGenerateSecrets) DeepCopyInto(out *ExistOrGenerateSecrets) { + *out = *in + if in.ExistingPasswordSecret != nil { + in, out := &in.ExistingPasswordSecret, &out.ExistingPasswordSecret + *out = new(ExistingPasswordSecret) + (*in).DeepCopyInto(*out) + } + if in.GeneratePasswordSecret != nil { + in, out := &in.GeneratePasswordSecret, &out.GeneratePasswordSecret + *out = new(GeneratePassword) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExistOrGenerateSecrets. +func (in *ExistOrGenerateSecrets) DeepCopy() *ExistOrGenerateSecrets { + if in == nil { + return nil + } + out := new(ExistOrGenerateSecrets) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ExistingPasswordSecret) DeepCopyInto(out *ExistingPasswordSecret) { *out = *in @@ -80,6 +105,36 @@ func (in *ExistingPasswordSecret) DeepCopy() *ExistingPasswordSecret { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GeneratePassword) DeepCopyInto(out *GeneratePassword) { + *out = *in + if in.Name != nil { + in, out := &in.Name, &out.Name + *out = new(string) + **out = **in + } + if in.Key != nil { + in, out := &in.Key, &out.Key + *out = new(string) + **out = **in + } + if in.NameSpace != nil { + in, out := &in.NameSpace, &out.NameSpace + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeneratePassword. +func (in *GeneratePassword) DeepCopy() *GeneratePassword { + if in == nil { + return nil + } + out := new(GeneratePassword) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KubernetesConfig) DeepCopyInto(out *KubernetesConfig) { *out = *in @@ -88,9 +143,9 @@ func (in *KubernetesConfig) DeepCopyInto(out *KubernetesConfig) { *out = new(v1.ResourceRequirements) (*in).DeepCopyInto(*out) } - if in.ExistingPasswordSecret != nil { - in, out := &in.ExistingPasswordSecret, &out.ExistingPasswordSecret - *out = new(ExistingPasswordSecret) + if in.ExistOrGenerateSecret != nil { + in, out := &in.ExistOrGenerateSecret, &out.ExistOrGenerateSecret + *out = new(ExistOrGenerateSecrets) (*in).DeepCopyInto(*out) } if in.ImagePullSecrets != nil { diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml index 3238e69aa..1a224d77b 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redis.yaml @@ -957,13 +957,31 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + maxProperties: 1 properties: - key: - type: string - name: - type: string + existRedisSecret: + description: ExistingPasswordSecret is the struct to access + the existing secret + properties: + key: + type: string + name: + type: string + type: object + generatePasswordSecret: + properties: + key: + default: key + type: string + name: + type: string + namespace: + items: + type: string + type: array + required: + - name + type: object type: object resources: description: ResourceRequirements describes the compute resource diff --git a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml index bb3a74454..d62e0af7a 100644 --- a/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml +++ b/config/crd/bases/redis.redis.opstreelabs.in_redisclusters.yaml @@ -155,13 +155,31 @@ spec: type: object type: array redisSecret: - description: ExistingPasswordSecret is the struct to access the - existing secret + maxProperties: 1 properties: - key: - type: string - name: - type: string + existRedisSecret: + description: ExistingPasswordSecret is the struct to access + the existing secret + properties: + key: + type: string + name: + type: string + type: object + generatePasswordSecret: + properties: + key: + default: key + type: string + name: + type: string + namespace: + items: + type: string + type: array + required: + - name + type: object type: object resources: description: ResourceRequirements describes the compute resource diff --git a/controllers/redis_controller.go b/controllers/redis_controller.go index 6b993bcd5..36b5483cb 100644 --- a/controllers/redis_controller.go +++ b/controllers/redis_controller.go @@ -63,6 +63,14 @@ func (r *RedisReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl return ctrl.Result{}, err } + if instance.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil { + err = k8sutils.CreateRedisSecrets(instance) + if err != nil { + reqLogger.Error(err, "Failed to create the Secrets") + return ctrl.Result{RequeueAfter: time.Second * 10}, err + } + } + err = k8sutils.CreateStandaloneRedis(instance) if err != nil { return ctrl.Result{}, err diff --git a/controllers/rediscluster_controller.go b/controllers/rediscluster_controller.go index c14306abf..3ef2274dc 100644 --- a/controllers/rediscluster_controller.go +++ b/controllers/rediscluster_controller.go @@ -70,6 +70,14 @@ func (r *RedisClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request return ctrl.Result{RequeueAfter: time.Second * 60}, err } + if instance.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil { + err = k8sutils.CreateRedisClusterSecrets(instance) + if err != nil { + reqLogger.Error(err, "Failed to create the Secrets") + return ctrl.Result{RequeueAfter: time.Second * 10}, err + } + } + err = k8sutils.CreateRedisLeader(instance) if err != nil { return ctrl.Result{RequeueAfter: time.Second * 60}, err diff --git a/example/generated_secrets/redis-cluster.yaml b/example/generated_secrets/redis-cluster.yaml new file mode 100644 index 000000000..7627fbf7e --- /dev/null +++ b/example/generated_secrets/redis-cluster.yaml @@ -0,0 +1,78 @@ +--- +apiVersion: redis.redis.opstreelabs.in/v1beta1 +kind: RedisCluster +metadata: + name: redis-cluster + namespace: redis-operator +spec: + clusterSize: 3 + clusterVersion: v7 + persistenceEnabled: true + securityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.5 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 101m + memory: 128Mi + limits: + cpu: 101m + memory: 128Mi + redisSecret: + generatePasswordSecret: + name: redis-secret-cluster + namespace : + - redis-operator + key : operator-key # Default is set to 'key' + # existRedisSecret: + # name: redis-secret + # key: password + # imagePullSecrets: + # - name: regcred + # redisExporter: + # enabled: false + # image: quay.io/opstree/redis-exporter:v1.44.0 + # imagePullPolicy: Always + # resources: + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi +# Environment Variables for Redis Exporter + # env: + # - name: REDIS_EXPORTER_INCL_SYSTEM_METRICS + # value: "true" + # - name: UI_PROPERTIES_FILE_NAME + # valueFrom: + # configMapKeyRef: + # name: game-demo + # key: ui_properties_file_name + # - name: SECRET_USERNAME + # valueFrom: + # secretKeyRef: + # name: mysecret + # key: username +# redisLeader: +# redisConfig: +# additionalRedisConfig: redis-external-config +# redisFollower: +# redisConfig: +# additionalRedisConfig: redis-external-config + storage: + volumeClaimTemplate: + spec: + # storageClassName: standard + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + # nodeSelector: + # kubernetes.io/hostname: minikube + # priorityClassName: + # Affinity: + # Tolerations: [] diff --git a/example/generated_secrets/redis-standalone.yaml b/example/generated_secrets/redis-standalone.yaml new file mode 100644 index 000000000..3268d5c38 --- /dev/null +++ b/example/generated_secrets/redis-standalone.yaml @@ -0,0 +1,72 @@ +--- +apiVersion: redis.redis.opstreelabs.in/v1beta1 +kind: Redis +metadata: + name: redis-standalone + namespace: redis-operator +spec: + # redisConfig: + # additionalRedisConfig: redis-external-config\ + securityContext: + runAsUser: 1000 + fsGroup: 1000 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.5 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 101m + memory: 128Mi + limits: + cpu: 101m + memory: 128Mi + redisSecret: + generatePasswordSecret: + name: redis-secret-standalone + namespace : + - redis-operator + key : operator-key # Default is set to 'key' + # existRedisSecret: + # name: redis-secret + # key: password + # imagePullSecrets: + # - name: regcred + # redisExporter: + # enabled: false + # image: quay.io/opstree/redis-exporter:v1.44.0 + # imagePullPolicy: Always + # resources: + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # cpu: 100m + # memory: 128Mi +# Environment Variables for Redis Exporter + # env: + # - name: REDIS_EXPORTER_INCL_SYSTEM_METRICS + # value: "true" + # - name: UI_PROPERTIES_FILE_NAME + # valueFrom: + # configMapKeyRef: + # name: game-demo + # key: ui_properties_file_name + # - name: SECRET_USERNAME + # valueFrom: + # secretKeyRef: + # name: mysecret + # key: username + storage: + volumeClaimTemplate: + spec: + # storageClassName: standard + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + # nodeSelector: + # kubernetes.io/hostname: minikube + # securityContext: {} + # priorityClassName: + # affinity: + # Tolerations: [] diff --git a/go.mod b/go.mod index 2931eb770..ce65b3552 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/banzaicloud/k8s-objectmatcher v1.7.0 github.com/go-logr/logr v1.2.2 github.com/go-redis/redis v6.15.9+incompatible + github.com/google/uuid v1.3.0 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.17.0 k8s.io/api v0.23.0 @@ -35,7 +36,6 @@ require ( github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.5 // indirect github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.2 // indirect github.com/googleapis/gnostic v0.5.5 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/go.sum b/go.sum index 62a6ce859..5275d4f0c 100644 --- a/go.sum +++ b/go.sum @@ -260,8 +260,9 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= diff --git a/k8sutils/labels.go b/k8sutils/labels.go index 2edf8f7fa..e23e91a97 100644 --- a/k8sutils/labels.go +++ b/k8sutils/labels.go @@ -107,3 +107,12 @@ func getRedisLabels(name, setupType, role string, labels map[string]string) map[ } return lbls } + +func getSecretLabels(name, setupType string) map[string]string { + lbls := map[string]string{ + "app": name, + "redis_setup_type": setupType, + } + + return lbls +} diff --git a/k8sutils/redis-cluster.go b/k8sutils/redis-cluster.go index 2a5047525..55b553771 100644 --- a/k8sutils/redis-cluster.go +++ b/k8sutils/redis-cluster.go @@ -3,6 +3,7 @@ package k8sutils import ( redisv1beta1 "redis-operator/api/v1beta1" + "github.com/google/uuid" corev1 "k8s.io/api/core/v1" ) @@ -67,11 +68,18 @@ func generateRedisClusterContainerParams(cr *redisv1beta1.RedisCluster, readines containerProp.AdditionalVolume = cr.Spec.Storage.VolumeMount.Volume containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { + switch true { + case cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret != nil: containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key - } else { + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Name + containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Key + + case cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil: + containerProp.EnabledPassword = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name + containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key + + default: containerProp.EnabledPassword = &falseProperty } if cr.Spec.RedisExporter != nil { @@ -216,3 +224,51 @@ func (service RedisClusterService) CreateRedisClusterService(cr *redisv1beta1.Re } return nil } + +func CreateRedisClusterSecrets(cr *redisv1beta1.RedisCluster) error { + + // Create Logger + genLogger := log.WithValues() + + var namespacelist = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.NameSpace + var key = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key + + // If key is empty add the default value + if key == nil { + *key = "key" + } + genLogger.Info("The key is set to ", "key", *key) + + // If no namespacelist is defined default would be added automatically + if namespacelist == nil { + namespacelist = append(namespacelist, cr.Namespace) + } + genLogger.Info("Namespaces passed to generate secrets are", "namespaces", namespacelist) + // Create a random UUID which is used as redis password + rndID, err := uuid.NewRandom() + if err != nil { + genLogger.Error(err, "Unable to generate the UUID") + } + + genLogger.Info("Secrets would be generated in ", "namespaces", namespacelist) + + secretParams := RedisSecretParams{ + name: *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name, + key: *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key, + ownerRef: redisClusterAsOwner(cr), + ownerNS: cr.Namespace, + value: []byte(rndID.String()), + labels: getSecretLabels(cr.Name, "Redis-Cluster"), + } + + for _, namespace := range namespacelist { + secretParams.namespace = namespace + err := createSecretIfNotExist(secretParams) + if err != nil { + return err + } + } + + return nil + +} diff --git a/k8sutils/redis-standalone.go b/k8sutils/redis-standalone.go index 9b9c02336..09be05e8f 100644 --- a/k8sutils/redis-standalone.go +++ b/k8sutils/redis-standalone.go @@ -2,6 +2,8 @@ package k8sutils import ( redisv1beta1 "redis-operator/api/v1beta1" + + "github.com/google/uuid" ) var ( @@ -114,12 +116,18 @@ func generateRedisStandaloneContainerParams(cr *redisv1beta1.Redis) containerPar containerProp.AdditionalVolume = cr.Spec.Storage.VolumeMount.Volume containerProp.AdditionalMountPath = cr.Spec.Storage.VolumeMount.MountPath } + switch true { + case cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret != nil: + containerProp.EnabledPassword = &trueProperty + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Name + containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Key - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { + case cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil: containerProp.EnabledPassword = &trueProperty - containerProp.SecretName = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name - containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key - } else { + containerProp.SecretName = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name + containerProp.SecretKey = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key + + default: containerProp.EnabledPassword = &falseProperty } if cr.Spec.RedisExporter != nil { @@ -149,3 +157,50 @@ func generateRedisStandaloneContainerParams(cr *redisv1beta1.Redis) containerPar } return containerProp } + +func CreateRedisSecrets(cr *redisv1beta1.Redis) error { + + // Create logger + genLogger := log.WithValues() + + var namespacelist = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.NameSpace + var key = cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key + + // If key is empty add the default value + if key == nil { + *key = "key" + } + genLogger.Info("The key is set to ", "key", *key) + + // If no namespacelist is defined default would be added automatically + if namespacelist == nil { + namespacelist = append(namespacelist, cr.Namespace) + } + genLogger.Info("Namespaces passed to generate secrets are", "namespaces", namespacelist) + // Create a random UUID which is used as redis password + rndID, err := uuid.NewRandom() + if err != nil { + genLogger.Error(err, "Unable to generate the UUID") + } + + genLogger.Info("Secrets would be generated in ", "namespaces", namespacelist) + + secretParams := RedisSecretParams{ + name: *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name, + key: *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key, + ownerRef: redisAsOwner(cr), + ownerNS: cr.Namespace, + value: []byte(rndID.String()), + labels: getSecretLabels(cr.Name, "Redis-Standalone"), + } + + for _, namespace := range namespacelist { + secretParams.namespace = namespace + err := createSecretIfNotExist(secretParams) + if err != nil { + return err + } + } + + return nil +} diff --git a/k8sutils/redis.go b/k8sutils/redis.go index 8235b6bc8..72a42a783 100644 --- a/k8sutils/redis.go +++ b/k8sutils/redis.go @@ -103,8 +103,17 @@ func ExecuteRedisClusterCommand(cr *redisv1beta1.RedisCluster) { cmd = CreateMultipleLeaderRedisCommand(cr) } - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret != nil { + pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Key) + if err != nil { + logger.Error(err, "Error in getting redis password") + } + cmd = append(cmd, "-a") + cmd = append(cmd, pass) + } + + if cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil { + pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -141,8 +150,17 @@ func createRedisReplicationCommand(cr *redisv1beta1.RedisCluster, leaderPod Redi } cmd = append(cmd, "--cluster-slave") - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret != nil { + pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Key) + if err != nil { + logger.Error(err, "Error in getting redis password") + } + cmd = append(cmd, "-a") + cmd = append(cmd, pass) + } + + if cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret != nil { + pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.GeneratePasswordSecret.Key) if err != nil { logger.Error(err, "Error in getting redis password") } @@ -313,8 +331,8 @@ func configureRedisClient(cr *redisv1beta1.RedisCluster, podName string) *redis. } var client *redis.Client - if cr.Spec.KubernetesConfig.ExistingPasswordSecret != nil { - pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistingPasswordSecret.Key) + if cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret != nil { + pass, err := getRedisPassword(cr.Namespace, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Name, *cr.Spec.KubernetesConfig.ExistOrGenerateSecret.ExistingPasswordSecret.Key) if err != nil { logger.Error(err, "Error in getting redis password") } diff --git a/k8sutils/secrets.go b/k8sutils/secrets.go index 840d157a2..45fa4fd0a 100644 --- a/k8sutils/secrets.go +++ b/k8sutils/secrets.go @@ -8,10 +8,23 @@ import ( "strings" "github.com/go-logr/logr" + corev1 "k8s.io/api/core/v1" + kerror "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" logf "sigs.k8s.io/controller-runtime/pkg/log" ) +type RedisSecretParams struct { + name string + namespace string + key string + value []byte + ownerRef metav1.OwnerReference + ownerNS string + labels map[string]string + annotation map[string]string +} + var log = logf.Log.WithName("controller_redis") // getRedisPassword method will return the redis password @@ -82,3 +95,73 @@ func getRedisTLSConfig(cr *redisv1beta1.RedisCluster, redisInfo RedisDetails) *t } return nil } + +func createSecretIfNotExist(secretParams RedisSecretParams) error { + //Create a secret template and adding name, namespace, key and value + secret := generateSecretTemplate(secretParams) + + genLogger := secretLogger(secretParams.namespace, secretParams.name) + + _, err := getSecret(secretParams.namespace, secretParams.name) + if err != nil { + if kerror.IsNotFound(err) { + _, err := generateK8sClient().CoreV1().Secrets(secretParams.namespace).Create(context.TODO(), secret, metav1.CreateOptions{}) + if err != nil { + genLogger.Error(err, "Failed to create the Secrets by the operator in ", "namespaces", secretParams.namespace) + return err + } else { + genLogger.Info("Secret Created Successfully in ", "namespace", secretParams.namespace) + } + + } else { + genLogger.Error(err, "Miscellaneous error found in while getting the secret") + return err + } + } + return nil +} + +func generateSecretTemplate(secretParams RedisSecretParams) *corev1.Secret { + + secret := &corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + Kind: "Secret", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: secretParams.name, + Namespace: secretParams.namespace, + Labels: secretParams.labels, + Annotations: secretParams.annotation, + }, + + Data: map[string][]byte{ + secretParams.key: secretParams.value, + }, + + Type: "Opaque", + } + + // Add owner reference to secret if exist in same namespace + if secretParams.namespace == secretParams.ownerNS { + AddOwnerRefToObject(secret, secretParams.ownerRef) + } + + return secret +} + +// GetStateFulSet is a method to get statefulset in Kubernetes +func getSecret(namespace string, name string) (*corev1.Secret, error) { + logger := secretLogger(namespace, name) + getOpts := metav1.GetOptions{ + TypeMeta: generateMetaInformation("Secret", "v1"), + } + secretInfo, err := generateK8sClient().CoreV1().Secrets(namespace).Get(context.TODO(), name, getOpts) + + if err != nil { + logger.Info("Redis secret get action failed") + return nil, err + } + logger.Info("Redis secret get action was successful") + return secretInfo, nil +}