diff --git a/api/v1alpha1/etcdcluster_types.go b/api/v1alpha1/etcdcluster_types.go index 3b195335..368eff2b 100644 --- a/api/v1alpha1/etcdcluster_types.go +++ b/api/v1alpha1/etcdcluster_types.go @@ -130,6 +130,82 @@ type ProviderCertManagerConfig struct { type EtcdClusterStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file + + // ObservedGeneration is the most recent generation observed for this EtcdCluster by the controller. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // CurrentReplicas is the number of etcd pods managed by the StatefulSet for this cluster. + // This reflects the .spec.replicas of the underlying StatefulSet. + // +optional + CurrentReplicas int32 `json:"currentReplicas,omitempty"` + + // ReadyReplicas is the number of etcd pods managed by the StatefulSet that are currently ready. + // This reflects the .status.readyReplicas of the underlying StatefulSet. + // +optional + ReadyReplicas int32 `json:"readyReplicas,omitempty"` + + // MemberCount is the number of members currently registered in the etcd cluster, + // as reported by the etcd 'member list' API. This may differ from CurrentReplicas + // during scaling operations or if members are added/removed outside the operator's direct control. + // +optional + MemberCount int32 `json:"memberCount,omitempty"` + + // CurrentVersion is the observed etcd version of the cluster. + // This is typically derived from the version of the healthy leader or a consensus among healthy members. + // +optional + CurrentVersion string `json:"currentVersion,omitempty"` + + // LeaderID is the hex-encoded ID of the current etcd cluster leader, if one exists and is known. + // +optional + LeaderID string `json:"leaderID,omitempty"` + + // TODO: expose LastDefragTime once the controller owns automated defragmentation. + + // Members provides the status of each individual etcd member. + // +optional + // +listType=map + // +listMapKey=id + // Alternative listMapKey could be 'name' if 'id' is not always immediately available or stable during init. + // However, 'id' is more canonical once a member is part of the cluster. + Members []MemberStatus `json:"members,omitempty"` + + // Conditions represent the latest available observations of the EtcdCluster's state. + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` +} + +// MemberStatus defines the observed state of a single etcd member. +type MemberStatus struct { + // Name of the etcd member, typically the pod name (e.g., "etcd-cluster-example-0"). + // This can also be the name reported by etcd itself if set. + // +optional + Name string `json:"name,omitempty"` + + // ID is the hex-encoded member ID as reported by etcd. + // This is the canonical identifier for an etcd member. + ID string `json:"id"` // Made non-optional as it's key for identification + + // Version of etcd running on this member. + // +optional + Version string `json:"version,omitempty"` + + // IsHealthy indicates if the member is considered healthy. + // A member is healthy if its etcd /health endpoint is reachable and reports OK, + // and its Status endpoint does not report any 'Errors'. + IsHealthy bool `json:"isHealthy"` // No omitempty, always show health + + // IsLearner indicates if the member is currently a learner in the etcd cluster. + // +optional + IsLearner bool `json:"isLearner,omitempty"` + + // IsLeader indicates if this member is currently the cluster leader. + // +optional + IsLeader bool `json:"isLeader,omitempty"` } // +kubebuilder:object:root=true diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index e1088bd2..7150dc9b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" netx "net" ) @@ -83,7 +84,7 @@ func (in *EtcdCluster) DeepCopyInto(out *EtcdCluster) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - out.Status = in.Status + in.Status.DeepCopyInto(&out.Status) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdCluster. @@ -174,6 +175,18 @@ func (in *EtcdClusterSpec) DeepCopy() *EtcdClusterSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EtcdClusterStatus) DeepCopyInto(out *EtcdClusterStatus) { *out = *in + if in.Members != nil { + in, out := &in.Members, &out.Members + *out = make([]MemberStatus, len(*in)) + copy(*out, *in) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EtcdClusterStatus. @@ -186,6 +199,21 @@ func (in *EtcdClusterStatus) DeepCopy() *EtcdClusterStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *MemberStatus) DeepCopyInto(out *MemberStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MemberStatus. +func (in *MemberStatus) DeepCopy() *MemberStatus { + if in == nil { + return nil + } + out := new(MemberStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodMetadata) DeepCopyInto(out *PodMetadata) { *out = *in diff --git a/config/crd/bases/operator.etcd.io_etcdclusters.yaml b/config/crd/bases/operator.etcd.io_etcdclusters.yaml index aa67be64..1402ece5 100644 --- a/config/crd/bases/operator.etcd.io_etcdclusters.yaml +++ b/config/crd/bases/operator.etcd.io_etcdclusters.yaml @@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.18.0 + controller-gen.kubebuilder.io/version: v0.19.0 name: etcdclusters.operator.etcd.io spec: group: operator.etcd.io @@ -221,6 +221,145 @@ spec: type: object status: description: EtcdClusterStatus defines the observed state of EtcdCluster. + properties: + conditions: + description: Conditions represent the latest available observations + of the EtcdCluster's state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + currentReplicas: + description: |- + CurrentReplicas is the number of etcd pods managed by the StatefulSet for this cluster. + This reflects the .spec.replicas of the underlying StatefulSet. + format: int32 + type: integer + currentVersion: + description: |- + CurrentVersion is the observed etcd version of the cluster. + This is typically derived from the version of the healthy leader or a consensus among healthy members. + type: string + leaderId: + description: LeaderId is the hex-encoded ID of the current etcd cluster + leader, if one exists and is known. + type: string + memberCount: + description: |- + MemberCount is the number of members currently registered in the etcd cluster, + as reported by the etcd 'member list' API. This may differ from CurrentReplicas + during scaling operations or if members are added/removed outside the operator's direct control. + format: int32 + type: integer + members: + description: |- + Members provides the status of each individual etcd member. + Alternative listMapKey could be 'name' if 'id' is not always immediately available or stable during init. + However, 'id' is more canonical once a member is part of the cluster. + items: + description: MemberStatus defines the observed state of a single + etcd member. + properties: + id: + description: |- + ID is the hex-encoded member ID as reported by etcd. + This is the canonical identifier for an etcd member. + type: string + isHealthy: + description: |- + IsHealthy indicates if the member is considered healthy. + A member is healthy if its etcd /health endpoint is reachable and reports OK, + and its Status endpoint does not report any 'Errors'. + type: boolean + isLeader: + description: IsLeader indicates if this member is currently + the cluster leader. + type: boolean + isLearner: + description: IsLearner indicates if the member is currently + a learner in the etcd cluster. + type: boolean + name: + description: |- + Name of the etcd member, typically the pod name (e.g., "etcd-cluster-example-0"). + This can also be the name reported by etcd itself if set. + type: string + version: + description: Version of etcd running on this member. + type: string + required: + - id + - isHealthy + type: object + type: array + x-kubernetes-list-map-keys: + - id + x-kubernetes-list-type: map + observedGeneration: + description: ObservedGeneration is the most recent generation observed + for this EtcdCluster by the controller. + format: int64 + type: integer + readyReplicas: + description: |- + ReadyReplicas is the number of etcd pods managed by the StatefulSet that are currently ready. + This reflects the .status.readyReplicas of the underlying StatefulSet. + format: int32 + type: integer type: object type: object served: true