diff --git a/.gitignore b/.gitignore index 1a8a47f44..692042ff4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /bin .bash_history +.vscode diff --git a/CHANGELOG.md b/CHANGELOG.md index 093248fc5..a2a218b32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,14 @@ # Changelog +## [v1.1.0-rc.2] - X + + +Update notes: + +Ensure you update the CRD definition since CRD is no longer managed by the operator: +``` +kubectl create -f https://raw.githubusercontent.com/spotahome/redis-operator/master/example/redisfailover/basic.yaml +``` + ## [v1.1.0-rc.1] - 2022-01-12 ### Major Changes diff --git a/Makefile b/Makefile index 6500f3072..3b6ae8ea0 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -VERSION := v1.1.0-rc.1 +VERSION := v1.1.0-rc.2 # Name of this service/application SERVICE_NAME := redis-operator diff --git a/README.md b/README.md index a606a1987..e3c85663c 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,32 @@ Redis Operator creates/configures/manages redis-failovers atop Kubernetes. Redis Operator is meant to be run on Kubernetes 1.19+. All dependencies have been vendored, so there's no need to any additional download. -### Versions deployed +## Operator deployment on kubernetes -The image versions deployed by the operator can be found on the [defaults file](api/redisfailover/v1/defaults.go). +In order to create Redis failovers inside a Kubernetes cluster, the operator has to be deployed. It can be done with [deployment](example/operator) or with the provided [Helm chart](charts/redisoperator). -## Images +### Using the Helm chart -### Redis Operator +From the root folder of the project, execute the following: -[![Redis Operator Image](https://quay.io/repository/spotahome/redis-operator/status "Redis Operator Image")](https://quay.io/repository/spotahome/redis-operator) +``` +helm repo add redis-operator https://spotahome.github.io/redis-operator +helm repo update +helm install redis-operator redis-operator/redis-operator +``` -## Operator deployment on kubernetes +#### Update helm chart -In order to create Redis failovers inside a Kubernetes cluster, the operator has to be deployed. It can be done with [deployment](example/operator) or with the provided [Helm chart](charts/redisoperator). +Helm chart only manage the creation of CRD in the first install. In order to update the CRD you will need to apply directly. -### Using a Deployment +``` +kubectl apply -f https://raw.githubusercontent.com/spotahome/redis-operator/master/manifests/databases.spotahome.com_redisfailovers.yaml +``` + +``` +helm upgrade redis-operator redis-operator/redis-operator +``` +### Using kubectl To create the operator, you can directly create it with kubectl: @@ -34,16 +45,6 @@ kubectl create -f https://raw.githubusercontent.com/spotahome/redis-operator/mas This will create a deployment named `redisoperator`. -### Using the Helm chart - -From the root folder of the project, execute the following: - -``` -helm repo add redis-operator https://spotahome.github.io/redis-operator -helm repo update -helm install redis-operator redis-operator/redis-operator -``` - ## Usage Once the operator is deployed inside a Kubernetes cluster, a new API will be accesible, so you'll be able to create, update and delete redisfailovers. @@ -211,13 +212,16 @@ This allows for ease of bootstrapping from an existing `RedisFailover` instance When `allowSentinels` is provided, the Operator will also create the defined Sentinel resources. These sentinels will be configured to point to the provided `bootstrapNode` as their monitored master. +### Default versions + +The image versions deployed by the operator can be found on the [defaults file](api/redisfailover/v1/defaults.go). ## Cleanup ### Operator and CRD If you want to delete the operator from your Kubernetes cluster, the operator deployment should be deleted. -Also, the CRD has to be deleted too: +Also, the CRD has to be deleted. Deleting CRD automatically wil delete all redis failover custom resources and their managed resources: ``` kubectl delete crd redisfailovers.databases.spotahome.com @@ -231,6 +235,11 @@ Thanks to Kubernetes' `OwnerReference`, all the objects created from a redis-fai kubectl delete redisfailover ``` +## Docker Images + +### Redis Operator + +[![Redis Operator Image](https://quay.io/repository/spotahome/redis-operator/status "Redis Operator Image")](https://quay.io/repository/spotahome/redis-operator) ## Documentation For the code documentation, you can lookup on the [GoDoc](https://godoc.org/github.com/spotahome/redis-operator). diff --git a/api/redisfailover/v1/types.go b/api/redisfailover/v1/types.go index 024fa9342..650e682d7 100644 --- a/api/redisfailover/v1/types.go +++ b/api/redisfailover/v1/types.go @@ -115,9 +115,56 @@ type SentinelExporter struct { // RedisStorage defines the structure used to store the Redis Data type RedisStorage struct { - KeepAfterDeletion bool `json:"keepAfterDeletion,omitempty"` - EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"` - PersistentVolumeClaim *corev1.PersistentVolumeClaim `json:"persistentVolumeClaim,omitempty"` + KeepAfterDeletion bool `json:"keepAfterDeletion,omitempty"` + EmptyDir *corev1.EmptyDirVolumeSource `json:"emptyDir,omitempty"` + PersistentVolumeClaim *EmbeddedPersistentVolumeClaim `json:"persistentVolumeClaim,omitempty"` +} + +// EmbeddedPersistentVolumeClaim is an embedded version of k8s.io/api/core/v1.PersistentVolumeClaim. +// It contains TypeMeta and a reduced ObjectMeta. +type EmbeddedPersistentVolumeClaim struct { + metav1.TypeMeta `json:",inline"` + + // EmbeddedMetadata contains metadata relevant to an EmbeddedResource. + EmbeddedObjectMetadata `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Spec defines the desired characteristics of a volume requested by a pod author. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + Spec corev1.PersistentVolumeClaimSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` + + // Status represents the current information/status of a persistent volume claim. + // Read-only. + // More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + // +optional + Status corev1.PersistentVolumeClaimStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"` +} + +// EmbeddedObjectMetadata contains a subset of the fields included in k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta +// Only fields which are relevant to embedded resources are included. +type EmbeddedObjectMetadata struct { + // Name must be unique within a namespace. Is required when creating resources, although + // some resources may allow a client to request the generation of an appropriate name + // automatically. Name is primarily intended for creation idempotence and configuration + // definition. + // Cannot be updated. + // More info: http://kubernetes.io/docs/user-guide/identifiers#names + // +optional + Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` + + // Map of string keys and values that can be used to organize and categorize + // (scope and select) objects. May match selectors of replication controllers + // and services. + // More info: http://kubernetes.io/docs/user-guide/labels + // +optional + Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,11,rep,name=labels"` + + // Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + // More info: http://kubernetes.io/docs/user-guide/annotations + // +optional + Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/api/redisfailover/v1/zz_generated.deepcopy.go b/api/redisfailover/v1/zz_generated.deepcopy.go index f52f3119e..9e388d0d7 100644 --- a/api/redisfailover/v1/zz_generated.deepcopy.go +++ b/api/redisfailover/v1/zz_generated.deepcopy.go @@ -57,6 +57,56 @@ func (in *BootstrapSettings) DeepCopy() *BootstrapSettings { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmbeddedObjectMetadata) DeepCopyInto(out *EmbeddedObjectMetadata) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedObjectMetadata. +func (in *EmbeddedObjectMetadata) DeepCopy() *EmbeddedObjectMetadata { + if in == nil { + return nil + } + out := new(EmbeddedObjectMetadata) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *EmbeddedPersistentVolumeClaim) DeepCopyInto(out *EmbeddedPersistentVolumeClaim) { + *out = *in + out.TypeMeta = in.TypeMeta + in.EmbeddedObjectMetadata.DeepCopyInto(&out.EmbeddedObjectMetadata) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EmbeddedPersistentVolumeClaim. +func (in *EmbeddedPersistentVolumeClaim) DeepCopy() *EmbeddedPersistentVolumeClaim { + if in == nil { + return nil + } + out := new(EmbeddedPersistentVolumeClaim) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RedisCommandRename) DeepCopyInto(out *RedisCommandRename) { *out = *in @@ -277,7 +327,7 @@ func (in *RedisStorage) DeepCopyInto(out *RedisStorage) { } if in.PersistentVolumeClaim != nil { in, out := &in.PersistentVolumeClaim, &out.PersistentVolumeClaim - *out = new(corev1.PersistentVolumeClaim) + *out = new(EmbeddedPersistentVolumeClaim) (*in).DeepCopyInto(*out) } return diff --git a/charts/redisoperator/Chart.yaml b/charts/redisoperator/Chart.yaml index 733690d7f..3ffa44a2d 100644 --- a/charts/redisoperator/Chart.yaml +++ b/charts/redisoperator/Chart.yaml @@ -4,7 +4,7 @@ appVersion: 1.1.0-rc.1 apiVersion: v1 description: A Helm chart for the Spotahome Redis Operator name: redis-operator -version: 3.1.3 +version: 3.1.4 home: https://github.com/spotahome/redis-operator keywords: - "golang" diff --git a/charts/redisoperator/crds/databases.spotahome.com_redisfailovers.yaml b/charts/redisoperator/crds/databases.spotahome.com_redisfailovers.yaml index d46d6924d..a2e138b76 100644 --- a/charts/redisoperator/crds/databases.spotahome.com_redisfailovers.yaml +++ b/charts/redisoperator/crds/databases.spotahome.com_redisfailovers.yaml @@ -1354,8 +1354,9 @@ spec: keepAfterDeletion: type: boolean persistentVolumeClaim: - description: PersistentVolumeClaim is a user's request for - and claim to a persistent volume + description: EmbeddedPersistentVolumeClaim is an embedded + version of k8s.io/api/core/v1.PersistentVolumeClaim. It + contains TypeMeta and a reduced ObjectMeta. properties: apiVersion: description: 'APIVersion defines the versioned schema @@ -1370,8 +1371,34 @@ spec: Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: - description: 'Standard object''s metadata. More info: - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + description: EmbeddedMetadata contains metadata relevant + to an EmbeddedResource. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. + They are not queryable and should be preserved when + modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can + be used to organize and categorize (scope and select) + objects. May match selectors of replication controllers + and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + name: + description: 'Name must be unique within a namespace. + Is required when creating resources, although some + resources may allow a client to request the generation + of an appropriate name automatically. Name is primarily + intended for creation idempotence and configuration + definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string type: object spec: description: 'Spec defines the desired characteristics diff --git a/manifests/databases.spotahome.com_redisfailovers.yaml b/manifests/databases.spotahome.com_redisfailovers.yaml index d46d6924d..a2e138b76 100644 --- a/manifests/databases.spotahome.com_redisfailovers.yaml +++ b/manifests/databases.spotahome.com_redisfailovers.yaml @@ -1354,8 +1354,9 @@ spec: keepAfterDeletion: type: boolean persistentVolumeClaim: - description: PersistentVolumeClaim is a user's request for - and claim to a persistent volume + description: EmbeddedPersistentVolumeClaim is an embedded + version of k8s.io/api/core/v1.PersistentVolumeClaim. It + contains TypeMeta and a reduced ObjectMeta. properties: apiVersion: description: 'APIVersion defines the versioned schema @@ -1370,8 +1371,34 @@ spec: Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' type: string metadata: - description: 'Standard object''s metadata. More info: - https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + description: EmbeddedMetadata contains metadata relevant + to an EmbeddedResource. + properties: + annotations: + additionalProperties: + type: string + description: 'Annotations is an unstructured key value + map stored with a resource that may be set by external + tools to store and retrieve arbitrary metadata. + They are not queryable and should be preserved when + modifying objects. More info: http://kubernetes.io/docs/user-guide/annotations' + type: object + labels: + additionalProperties: + type: string + description: 'Map of string keys and values that can + be used to organize and categorize (scope and select) + objects. May match selectors of replication controllers + and services. More info: http://kubernetes.io/docs/user-guide/labels' + type: object + name: + description: 'Name must be unique within a namespace. + Is required when creating resources, although some + resources may allow a client to request the generation + of an appropriate name automatically. Name is primarily + intended for creation idempotence and configuration + definition. Cannot be updated. More info: http://kubernetes.io/docs/user-guide/identifiers#names' + type: string type: object spec: description: 'Spec defines the desired characteristics diff --git a/operator/redisfailover/service/generator.go b/operator/redisfailover/service/generator.go index b5493410f..24b8a6145 100644 --- a/operator/redisfailover/service/generator.go +++ b/operator/redisfailover/service/generator.go @@ -6,7 +6,6 @@ import ( "bytes" appsv1 "k8s.io/api/apps/v1" - v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -263,9 +262,9 @@ func generateRedisStatefulSet(rf *redisfailoverv1.RedisFailover, labels map[stri ServiceName: name, Replicas: &rf.Spec.Redis.Replicas, UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ - Type: v1.OnDeleteStatefulSetStrategyType, + Type: appsv1.OnDeleteStatefulSetStrategyType, }, - PodManagementPolicy: v1.ParallelPodManagement, + PodManagementPolicy: appsv1.ParallelPodManagement, Selector: &metav1.LabelSelector{ MatchLabels: selectorLabels, }, @@ -340,12 +339,26 @@ func generateRedisStatefulSet(rf *redisfailoverv1.RedisFailover, labels map[stri } if rf.Spec.Redis.Storage.PersistentVolumeClaim != nil { + pvc := corev1.PersistentVolumeClaim{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "PersistentVolumeClaim", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: rf.Spec.Redis.Storage.PersistentVolumeClaim.EmbeddedObjectMetadata.Name, + Labels: rf.Spec.Redis.Storage.PersistentVolumeClaim.EmbeddedObjectMetadata.Labels, + Annotations: rf.Spec.Redis.Storage.PersistentVolumeClaim.EmbeddedObjectMetadata.Annotations, + CreationTimestamp: metav1.Time{}, + }, + Spec: rf.Spec.Redis.Storage.PersistentVolumeClaim.Spec, + Status: rf.Spec.Redis.Storage.PersistentVolumeClaim.Status, + } if !rf.Spec.Redis.Storage.KeepAfterDeletion { // Set an owner reference so the persistent volumes are deleted when the RF is - rf.Spec.Redis.Storage.PersistentVolumeClaim.OwnerReferences = ownerRefs + pvc.OwnerReferences = ownerRefs } ss.Spec.VolumeClaimTemplates = []corev1.PersistentVolumeClaim{ - *rf.Spec.Redis.Storage.PersistentVolumeClaim, + pvc, } } diff --git a/operator/redisfailover/service/generator_test.go b/operator/redisfailover/service/generator_test.go index e5d51c884..eada6f7af 100644 --- a/operator/redisfailover/service/generator_test.go +++ b/operator/redisfailover/service/generator_test.go @@ -248,6 +248,10 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ { + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "pvc-data", }, @@ -266,8 +270,8 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, }, rfRedisStorage: redisfailoverv1.RedisStorage{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ + PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{ + EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{ Name: "pvc-data", }, Spec: corev1.PersistentVolumeClaimSpec{ @@ -354,6 +358,10 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ { + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "pvc-data", OwnerReferences: []metav1.OwnerReference{ @@ -377,8 +385,8 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, }, rfRedisStorage: redisfailoverv1.RedisStorage{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ + PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{ + EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{ Name: "pvc-data", }, Spec: corev1.PersistentVolumeClaimSpec{ @@ -465,6 +473,10 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, VolumeClaimTemplates: []corev1.PersistentVolumeClaim{ { + TypeMeta: metav1.TypeMeta{ + Kind: "PersistentVolumeClaim", + APIVersion: "v1", + }, ObjectMeta: metav1.ObjectMeta{ Name: "pvc-data", }, @@ -484,8 +496,8 @@ func TestRedisStatefulSetStorageGeneration(t *testing.T) { }, rfRedisStorage: redisfailoverv1.RedisStorage{ KeepAfterDeletion: true, - PersistentVolumeClaim: &corev1.PersistentVolumeClaim{ - ObjectMeta: metav1.ObjectMeta{ + PersistentVolumeClaim: &redisfailoverv1.EmbeddedPersistentVolumeClaim{ + EmbeddedObjectMetadata: redisfailoverv1.EmbeddedObjectMetadata{ Name: "pvc-data", }, Spec: corev1.PersistentVolumeClaimSpec{