diff --git a/apis/workloads/v1alpha1/instanceset_types.go b/apis/workloads/v1alpha1/instanceset_types.go index 80c37f02d3a..965b7d98aa8 100644 --- a/apis/workloads/v1alpha1/instanceset_types.go +++ b/apis/workloads/v1alpha1/instanceset_types.go @@ -274,27 +274,72 @@ type InstanceSetSpec struct { // InstanceSetStatus defines the observed state of InstanceSet type InstanceSetStatus struct { - appsv1.StatefulSetStatus `json:",inline"` + // observedGeneration is the most recent generation observed for this InstanceSet. It corresponds to the + // InstanceSet's generation, which is updated on mutation by the API Server. + // + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // replicas is the number of instances created by the InstanceSet controller. + Replicas int32 `json:"replicas"` + + // readyReplicas is the number of instances created for this InstanceSet with a Ready Condition. + ReadyReplicas int32 `json:"readyReplicas,omitempty"` + + // currentReplicas is the number of instances created by the InstanceSet controller from the InstanceSet version + // indicated by CurrentRevisions. + CurrentReplicas int32 `json:"currentReplicas,omitempty"` + + // updatedReplicas is the number of instances created by the InstanceSet controller from the InstanceSet version + // indicated by UpdateRevisions. + UpdatedReplicas int32 `json:"updatedReplicas,omitempty"` + + // currentRevision, if not empty, indicates the version of the InstanceSet used to generate instances in the + // sequence [0,currentReplicas). + CurrentRevision string `json:"currentRevision,omitempty"` + + // updateRevision, if not empty, indicates the version of the InstanceSet used to generate instances in the sequence + // [replicas-updatedReplicas,replicas) + UpdateRevision string `json:"updateRevision,omitempty"` + + // Represents the latest available observations of an instanceset's current state. + // Known .status.conditions.type are: "InstanceFailure", "InstanceReady" + // + // +optional + // +patchMergeKey=type + // +patchStrategy=merge + // +listType=map + // +listMapKey=type + Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"` - // Defines the initial number of pods (members) when the cluster is first initialized. + // Total number of available instances (ready for at least minReadySeconds) targeted by this InstanceSet. + // + // +optional + AvailableReplicas int32 `json:"availableReplicas"` + + // Defines the initial number of instances when the cluster is first initialized. // This value is set to spec.Replicas at the time of object creation and remains constant thereafter. + // Used only when spec.roles set. + // + // +optional InitReplicas int32 `json:"initReplicas"` - // Represents the number of pods (members) that have already reached the MembersStatus during the cluster initialization stage. + // Represents the number of instances that have already reached the MembersStatus during the cluster initialization stage. // This value remains constant once it equals InitReplicas. + // Used only when spec.roles set. // // +optional ReadyInitReplicas int32 `json:"readyInitReplicas,omitempty"` - // When not empty, indicates the version of the InstanceSet used to generate the underlying workload. + // Provides the status of each member in the cluster. // // +optional - CurrentGeneration int64 `json:"currentGeneration,omitempty"` + MembersStatus []MemberStatus `json:"membersStatus,omitempty"` - // Provides the status of each member in the cluster. + // Indicates whether it is required for the InstanceSet to have at least one primary instance ready. // // +optional - MembersStatus []MemberStatus `json:"membersStatus,omitempty"` + ReadyWithoutPrimary bool `json:"readyWithoutPrimary,omitempty"` // currentRevisions, if not empty, indicates the old version of the InstanceSet used to generate the underlying workload. // key is the pod name, value is the revision. @@ -564,16 +609,30 @@ type MemberStatus struct { // // +optional ReplicaRole *ReplicaRole `json:"role,omitempty"` +} - // Whether the corresponding Pod is in ready condition. - // +optional - Ready bool `json:"ready,omitempty"` +type ConditionType string - // Indicates whether it is required for the InstanceSet to have at least one primary instance ready. - // - // +optional - ReadyWithoutPrimary bool `json:"readyWithoutPrimary"` -} +const ( + // InstanceReady is added in an instance set when at least one of its instances(pods) is in a Ready condition. + // ConditionStatus will be True if all its instances(pods) are in a Ready condition. + // Or, a NotReady reason with not ready instances encoded in the Message filed will be set. + InstanceReady ConditionType = "InstanceReady" + + // InstanceFailure is added in an instance set when at least one of its instances(pods) is in a `Failed` phase. + InstanceFailure ConditionType = "InstanceFailure" +) + +const ( + // ReasonNotReady is a reason for condition InstanceReady. + ReasonNotReady = "NotReady" + + // ReasonReady is a reason for condition InstanceReady. + ReasonReady = "Ready" + + // ReasonInstanceFailure is a reason for condition InstanceFailure. + ReasonInstanceFailure = "InstanceFailure" +) func (t *InstanceTemplate) GetName() string { return t.Name diff --git a/apis/workloads/v1alpha1/zz_generated.deepcopy.go b/apis/workloads/v1alpha1/zz_generated.deepcopy.go index 5548e896c8b..3e537460189 100644 --- a/apis/workloads/v1alpha1/zz_generated.deepcopy.go +++ b/apis/workloads/v1alpha1/zz_generated.deepcopy.go @@ -237,7 +237,13 @@ func (in *InstanceSetSpec) DeepCopy() *InstanceSetSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InstanceSetStatus) DeepCopyInto(out *InstanceSetStatus) { *out = *in - in.StatefulSetStatus.DeepCopyInto(&out.StatefulSetStatus) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } if in.MembersStatus != nil { in, out := &in.MembersStatus, &out.MembersStatus *out = make([]MemberStatus, len(*in)) diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml index 434711e5d04..29b78555762 100644 --- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml +++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml @@ -7498,14 +7498,6 @@ spec: default: Unknown description: Represents the name of the pod. type: string - ready: - description: Whether the corresponding Pod is in ready - condition. - type: boolean - readyWithoutPrimary: - description: Indicates whether it is required for the - InstanceSet to have at least one primary instance ready. - type: boolean role: description: Defines the role of the replica in the cluster. properties: diff --git a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml index b936792ab7b..7952b194ab0 100644 --- a/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml +++ b/config/crd/bases/workloads.kubeblocks.io_instancesets.yaml @@ -12163,61 +12163,93 @@ spec: This data may be out of date. properties: availableReplicas: - description: Total number of available pods (ready for at least minReadySeconds) - targeted by this statefulset. - format: int32 - type: integer - collisionCount: - description: collisionCount is the count of hash collisions for the - StatefulSet. The StatefulSet controller uses this field as a collision - avoidance mechanism when it needs to create the name for the newest - ControllerRevision. + description: Total number of available instances (ready for at least + minReadySeconds) targeted by this InstanceSet. format: int32 type: integer conditions: - description: Represents the latest available observations of a statefulset's - current state. + description: 'Represents the latest available observations of an instanceset''s + current state. Known .status.conditions.type are: "InstanceFailure", + "InstanceReady"' items: - description: StatefulSetCondition describes the state of a statefulset - at a certain point. + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. + 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: A human readable message indicating details about - the transition. + 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: The reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: - description: Type of statefulset condition. + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 - currentGeneration: - description: When not empty, indicates the version of the InstanceSet - used to generate the underlying workload. - format: int64 - type: integer + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map currentReplicas: - description: currentReplicas is the number of Pods created by the - StatefulSet controller from the StatefulSet version indicated by - currentRevision. + description: currentReplicas is the number of instances created by + the InstanceSet controller from the InstanceSet version indicated + by CurrentRevisions. format: int32 type: integer currentRevision: description: currentRevision, if not empty, indicates the version - of the StatefulSet used to generate Pods in the sequence [0,currentReplicas). + of the InstanceSet used to generate instances in the sequence [0,currentReplicas). type: string currentRevisions: additionalProperties: @@ -12227,9 +12259,10 @@ spec: is the pod name, value is the revision. type: object initReplicas: - description: Defines the initial number of pods (members) when the - cluster is first initialized. This value is set to spec.Replicas - at the time of object creation and remains constant thereafter. + description: Defines the initial number of instances when the cluster + is first initialized. This value is set to spec.Replicas at the + time of object creation and remains constant thereafter. Used only + when spec.roles set. format: int32 type: integer membersStatus: @@ -12240,13 +12273,6 @@ spec: default: Unknown description: Represents the name of the pod. type: string - ready: - description: Whether the corresponding Pod is in ready condition. - type: boolean - readyWithoutPrimary: - description: Indicates whether it is required for the InstanceSet - to have at least one primary instance ready. - type: boolean role: description: Defines the role of the replica in the cluster. properties: @@ -12281,29 +12307,34 @@ spec: type: array observedGeneration: description: observedGeneration is the most recent generation observed - for this StatefulSet. It corresponds to the StatefulSet's generation, + for this InstanceSet. It corresponds to the InstanceSet's generation, which is updated on mutation by the API Server. format: int64 type: integer readyInitReplicas: - description: Represents the number of pods (members) that have already + description: Represents the number of instances that have already reached the MembersStatus during the cluster initialization stage. - This value remains constant once it equals InitReplicas. + This value remains constant once it equals InitReplicas. Used only + when spec.roles set. format: int32 type: integer readyReplicas: - description: readyReplicas is the number of pods created for this - StatefulSet with a Ready Condition. + description: readyReplicas is the number of instances created for + this InstanceSet with a Ready Condition. format: int32 type: integer + readyWithoutPrimary: + description: Indicates whether it is required for the InstanceSet + to have at least one primary instance ready. + type: boolean replicas: - description: replicas is the number of Pods created by the StatefulSet + description: replicas is the number of instances created by the InstanceSet controller. format: int32 type: integer updateRevision: description: updateRevision, if not empty, indicates the version of - the StatefulSet used to generate Pods in the sequence [replicas-updatedReplicas,replicas) + the InstanceSet used to generate instances in the sequence [replicas-updatedReplicas,replicas) type: string updateRevisions: additionalProperties: @@ -12313,13 +12344,12 @@ spec: is the pod name, value is the revision. type: object updatedReplicas: - description: updatedReplicas is the number of Pods created by the - StatefulSet controller from the StatefulSet version indicated by - updateRevision. + description: updatedReplicas is the number of instances created by + the InstanceSet controller from the InstanceSet version indicated + by UpdateRevisions. format: int32 type: integer required: - - initReplicas - replicas type: object type: object diff --git a/controllers/apps/transformer_component_status.go b/controllers/apps/transformer_component_status.go index dfaeea67c69..d5bdc8c71b4 100644 --- a/controllers/apps/transformer_component_status.go +++ b/controllers/apps/transformer_component_status.go @@ -21,14 +21,15 @@ package apps import ( "fmt" + "strconv" "strings" "time" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/kubectl/pkg/util/podutils" "sigs.k8s.io/controller-runtime/pkg/client" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" @@ -134,21 +135,12 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { return (r.runningITS.Spec.Replicas == nil || *r.runningITS.Spec.Replicas == 0) && r.synthesizeComp.Replicas == 0 }() - // get the component's underlying pods - pods, err := component.ListPodOwnedByComponent(r.reqCtx.Ctx, r.cli, r.cluster.Namespace, - constant.GetComponentWellKnownLabels(r.cluster.Name, r.synthesizeComp.Name), inDataContext4C()) - if err != nil { - return err - } hasComponentPod := func() bool { - return len(pods) > 0 + return r.runningITS.Status.Replicas > 0 }() // check if the ITS is running - isITSRunning, err := r.isInstanceSetRunning() - if err != nil { - return err - } + isITSUpdatedNRunning := r.isInstanceSetRunning() // check if all configTemplates are synced isAllConfigSynced, err := r.isAllConfigSynced() @@ -157,10 +149,7 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { } // check if the component has failed pod - hasFailedPod, messages, err := r.hasFailedPod(pods) - if err != nil { - return err - } + hasFailedPod, messages := r.hasFailedPod() // check if the component scale out failed isScaleOutFailed, err := r.isScaleOutFailed() @@ -180,10 +169,7 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { }() // check if the component is available - isComponentAvailable, err := r.isComponentAvailable(pods) - if err != nil { - return err - } + isComponentAvailable := r.isComponentAvailable() // check if the component is in creating phase isInCreatingPhase := func() bool { @@ -193,7 +179,7 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { r.reqCtx.Log.Info( fmt.Sprintf("component status conditions, isInstanceSetRunning: %v, isAllConfigSynced: %v, hasRunningVolumeExpansion: %v, hasFailure: %v, isInCreatingPhase: %v, isComponentAvailable: %v", - isITSRunning, isAllConfigSynced, hasRunningVolumeExpansion, hasFailure, isInCreatingPhase, isComponentAvailable)) + isITSUpdatedNRunning, isAllConfigSynced, hasRunningVolumeExpansion, hasFailure, isInCreatingPhase, isComponentAvailable)) r.podsReady = false switch { @@ -205,7 +191,7 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { case isZeroReplica: r.setComponentStatusPhase(appsv1alpha1.StoppedClusterCompPhase, nil, "component is Stopped") r.podsReady = true - case isITSRunning && isAllConfigSynced && !hasRunningVolumeExpansion: + case isITSUpdatedNRunning && isAllConfigSynced && !hasRunningVolumeExpansion: r.setComponentStatusPhase(appsv1alpha1.RunningClusterCompPhase, nil, "component is Running") r.podsReady = true case !hasFailure && isInCreatingPhase: @@ -221,61 +207,49 @@ func (r *componentStatusHandler) reconcileComponentStatus() error { return nil } +func (r *componentStatusHandler) isWorkloadUpdated() bool { + if r.cluster == nil || r.runningITS == nil { + return false + } + // check whether component spec has been sent to the underlying workload + itsComponentGeneration := r.runningITS.GetAnnotations()[constant.KubeBlocksGenerationKey] + return itsComponentGeneration == strconv.FormatInt(r.cluster.Generation, 10) +} + // isComponentAvailable tells whether the component is basically available, ether working well or in a fragile state: // 1. at least one pod is available // 2. with latest revision // 3. and with leader role label set -func (r *componentStatusHandler) isComponentAvailable(pods []*corev1.Pod) (bool, error) { - if isLatestRevision, err := component.IsComponentPodsWithLatestRevision(r.reqCtx.Ctx, r.cli, r.cluster, r.runningITS); err != nil { - return false, err - } else if !isLatestRevision { - return false, nil +func (r *componentStatusHandler) isComponentAvailable() bool { + if !r.isWorkloadUpdated() { + return false } - - shouldCheckRole := len(r.synthesizeComp.Roles) > 0 - - hasLeaderRoleLabel := func(pod *corev1.Pod) bool { - roleName, ok := pod.Labels[constant.RoleLabelKey] - if !ok { - return false - } - for _, replicaRole := range r.runningITS.Spec.Roles { - if roleName == replicaRole.Name && replicaRole.IsLeader { - return true - } - } + if r.runningITS.Status.CurrentRevision != r.runningITS.Status.UpdateRevision { return false } - - hasPodAvailable := false - for _, pod := range pods { - if !podutils.IsPodAvailable(pod, r.runningITS.Spec.MinReadySeconds, metav1.Time{Time: time.Now()}) { - continue - } - if shouldCheckRole && hasLeaderRoleLabel(pod) { - return true, nil - } - if !hasPodAvailable { - hasPodAvailable = !shouldCheckRole + if r.runningITS.Status.AvailableReplicas <= 0 { + return false + } + if len(r.synthesizeComp.Roles) == 0 { + return true + } + for _, status := range r.runningITS.Status.MembersStatus { + if status.ReplicaRole.IsLeader { + return true } } - return hasPodAvailable, nil + return false } // isRunning checks if the component underlying workload is running. -func (r *componentStatusHandler) isInstanceSetRunning() (bool, error) { +func (r *componentStatusHandler) isInstanceSetRunning() bool { if r.runningITS == nil { - return false, nil + return false } - if isLatestRevision, err := component.IsComponentPodsWithLatestRevision(r.reqCtx.Ctx, r.cli, r.cluster, r.runningITS); err != nil { - return false, err - } else if !isLatestRevision { - r.reqCtx.Log.Info("underlying workload is not the latest revision") - return false, nil + if !r.isWorkloadUpdated() { + return false } - - // whether the ITS is ready - return instanceset.IsInstanceSetReady(r.runningITS), nil + return instanceset.IsInstanceSetReady(r.runningITS) } // isAllConfigSynced checks if all configTemplates are synced. @@ -397,46 +371,44 @@ func (r *componentStatusHandler) getRunningVolumes(reqCtx intctrlutil.RequestCtx return matchedPVCs, nil } -// hasFailedPod checks if the component has failed pod. -// TODO(xingran): remove the dependency of the component's workload type. -func (r *componentStatusHandler) hasFailedPod(pods []*corev1.Pod) (bool, appsv1alpha1.ComponentMessageMap, error) { - if isLatestRevision, err := component.IsComponentPodsWithLatestRevision(r.reqCtx.Ctx, r.cli, r.cluster, r.runningITS); err != nil { - return false, nil, err - } else if !isLatestRevision { - return false, nil, nil - } - - var messages appsv1alpha1.ComponentMessageMap - // check pod readiness - hasFailedPod, msg, _ := hasFailedAndTimedOutPod(pods) +// hasFailedPod checks if the instance set has failed pod. +func (r *componentStatusHandler) hasFailedPod() (bool, appsv1alpha1.ComponentMessageMap) { + messages := appsv1alpha1.ComponentMessageMap{} + // check InstanceFailure condition + hasFailedPod := meta.IsStatusConditionTrue(r.runningITS.Status.Conditions, string(workloads.InstanceFailure)) if hasFailedPod { - messages = msg - return true, messages, nil + failureCondition := meta.FindStatusCondition(r.runningITS.Status.Conditions, string(workloads.InstanceFailure)) + messages.SetObjectMessage(workloads.Kind, r.runningITS.Name, failureCondition.Message) + return true, messages } - // check role probe - if r.synthesizeComp.WorkloadType != appsv1alpha1.Consensus && r.synthesizeComp.WorkloadType != appsv1alpha1.Replication { - return false, messages, nil + + // check InstanceReady condition + condition := meta.FindStatusCondition(r.runningITS.Status.Conditions, string(workloads.InstanceReady)) + if condition == nil { + return false, nil } - hasProbeTimeout := false - for _, pod := range pods { - if _, ok := pod.Labels[constant.RoleLabelKey]; ok { - continue - } - for _, condition := range pod.Status.Conditions { - if condition.Type != corev1.PodReady || condition.Status != corev1.ConditionTrue { - continue - } - podsReadyTime := &condition.LastTransitionTime - if IsProbeTimeout(r.synthesizeComp.Probes, podsReadyTime) { - hasProbeTimeout = true - if messages == nil { - messages = appsv1alpha1.ComponentMessageMap{} - } - messages.SetObjectMessage(pod.Kind, pod.Name, "Role probe timeout, check whether the application is available") - } + if condition.Status == metav1.ConditionFalse { + if time.Now().After(condition.LastTransitionTime.Add(intctrlutil.PodScheduledFailedTimeout)) { + messages.SetObjectMessage(workloads.Kind, r.runningITS.Name, condition.Message) + return true, messages } + return false, nil } - return hasProbeTimeout, messages, nil + + // all instances are in Ready condition, check role probe + if len(r.runningITS.Spec.Roles) == 0 { + return false, nil + } + if len(r.runningITS.Status.MembersStatus) == int(r.runningITS.Status.Replicas) { + return false, nil + } + probeTimeoutDuration := time.Duration(appsv1alpha1.DefaultRoleProbeTimeoutAfterPodsReady) * time.Second + if time.Now().After(condition.LastTransitionTime.Add(probeTimeoutDuration)) { + messages.SetObjectMessage(workloads.Kind, r.runningITS.Name, "Role probe timeout, check whether the application is available") + return true, messages + } + + return false, nil } // setComponentStatusPhase sets the component phase and messages conditionally. @@ -478,32 +450,6 @@ func (r *componentStatusHandler) updateComponentStatus(phaseTransitionMsg string return nil } -// hasFailedAndTimedOutPod returns whether the pods of components are still failed after a PodFailedTimeout period. -func hasFailedAndTimedOutPod(pods []*corev1.Pod) (bool, appsv1alpha1.ComponentMessageMap, time.Duration) { - var ( - hasTimedOutPod bool - messages = appsv1alpha1.ComponentMessageMap{} - hasFailedPod bool - requeueAfter time.Duration - ) - for _, pod := range pods { - isFailed, isTimedOut, messageStr := intctrlutil.IsPodFailedAndTimedOut(pod) - if !isFailed { - continue - } - if isTimedOut { - hasTimedOutPod = true - messages.SetObjectMessage(pod.Kind, pod.Name, messageStr) - } else { - hasFailedPod = true - } - } - if hasFailedPod && !hasTimedOutPod { - requeueAfter = intctrlutil.PodContainerFailedTimeout - } - return hasTimedOutPod, messages, requeueAfter -} - // newComponentStatusHandler creates a new componentStatusHandler func newComponentStatusHandler(reqCtx intctrlutil.RequestCtx, cli client.Client, diff --git a/controllers/workloads/instanceset_controller.go b/controllers/workloads/instanceset_controller.go index 6797ed40ab3..85124ccfcfb 100644 --- a/controllers/workloads/instanceset_controller.go +++ b/controllers/workloads/instanceset_controller.go @@ -42,7 +42,7 @@ import ( viper "github.com/apecloud/kubeblocks/pkg/viperx" ) -// InstanceSetReconciler reconciles a InstanceSet object +// InstanceSetReconciler reconciles an InstanceSet object type InstanceSetReconciler struct { client.Client Scheme *runtime.Scheme diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml index 434711e5d04..29b78555762 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml @@ -7498,14 +7498,6 @@ spec: default: Unknown description: Represents the name of the pod. type: string - ready: - description: Whether the corresponding Pod is in ready - condition. - type: boolean - readyWithoutPrimary: - description: Indicates whether it is required for the - InstanceSet to have at least one primary instance ready. - type: boolean role: description: Defines the role of the replica in the cluster. properties: diff --git a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml index b936792ab7b..7952b194ab0 100644 --- a/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml +++ b/deploy/helm/crds/workloads.kubeblocks.io_instancesets.yaml @@ -12163,61 +12163,93 @@ spec: This data may be out of date. properties: availableReplicas: - description: Total number of available pods (ready for at least minReadySeconds) - targeted by this statefulset. - format: int32 - type: integer - collisionCount: - description: collisionCount is the count of hash collisions for the - StatefulSet. The StatefulSet controller uses this field as a collision - avoidance mechanism when it needs to create the name for the newest - ControllerRevision. + description: Total number of available instances (ready for at least + minReadySeconds) targeted by this InstanceSet. format: int32 type: integer conditions: - description: Represents the latest available observations of a statefulset's - current state. + description: 'Represents the latest available observations of an instanceset''s + current state. Known .status.conditions.type are: "InstanceFailure", + "InstanceReady"' items: - description: StatefulSetCondition describes the state of a statefulset - at a certain point. + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" properties: lastTransitionTime: - description: Last time the condition transitioned from one status - to another. + 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: A human readable message indicating details about - the transition. + 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: The reason for the condition's last transition. + 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. + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown type: string type: - description: Type of statefulset condition. + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + 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 - currentGeneration: - description: When not empty, indicates the version of the InstanceSet - used to generate the underlying workload. - format: int64 - type: integer + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map currentReplicas: - description: currentReplicas is the number of Pods created by the - StatefulSet controller from the StatefulSet version indicated by - currentRevision. + description: currentReplicas is the number of instances created by + the InstanceSet controller from the InstanceSet version indicated + by CurrentRevisions. format: int32 type: integer currentRevision: description: currentRevision, if not empty, indicates the version - of the StatefulSet used to generate Pods in the sequence [0,currentReplicas). + of the InstanceSet used to generate instances in the sequence [0,currentReplicas). type: string currentRevisions: additionalProperties: @@ -12227,9 +12259,10 @@ spec: is the pod name, value is the revision. type: object initReplicas: - description: Defines the initial number of pods (members) when the - cluster is first initialized. This value is set to spec.Replicas - at the time of object creation and remains constant thereafter. + description: Defines the initial number of instances when the cluster + is first initialized. This value is set to spec.Replicas at the + time of object creation and remains constant thereafter. Used only + when spec.roles set. format: int32 type: integer membersStatus: @@ -12240,13 +12273,6 @@ spec: default: Unknown description: Represents the name of the pod. type: string - ready: - description: Whether the corresponding Pod is in ready condition. - type: boolean - readyWithoutPrimary: - description: Indicates whether it is required for the InstanceSet - to have at least one primary instance ready. - type: boolean role: description: Defines the role of the replica in the cluster. properties: @@ -12281,29 +12307,34 @@ spec: type: array observedGeneration: description: observedGeneration is the most recent generation observed - for this StatefulSet. It corresponds to the StatefulSet's generation, + for this InstanceSet. It corresponds to the InstanceSet's generation, which is updated on mutation by the API Server. format: int64 type: integer readyInitReplicas: - description: Represents the number of pods (members) that have already + description: Represents the number of instances that have already reached the MembersStatus during the cluster initialization stage. - This value remains constant once it equals InitReplicas. + This value remains constant once it equals InitReplicas. Used only + when spec.roles set. format: int32 type: integer readyReplicas: - description: readyReplicas is the number of pods created for this - StatefulSet with a Ready Condition. + description: readyReplicas is the number of instances created for + this InstanceSet with a Ready Condition. format: int32 type: integer + readyWithoutPrimary: + description: Indicates whether it is required for the InstanceSet + to have at least one primary instance ready. + type: boolean replicas: - description: replicas is the number of Pods created by the StatefulSet + description: replicas is the number of instances created by the InstanceSet controller. format: int32 type: integer updateRevision: description: updateRevision, if not empty, indicates the version of - the StatefulSet used to generate Pods in the sequence [replicas-updatedReplicas,replicas) + the InstanceSet used to generate instances in the sequence [replicas-updatedReplicas,replicas) type: string updateRevisions: additionalProperties: @@ -12313,13 +12344,12 @@ spec: is the pod name, value is the revision. type: object updatedReplicas: - description: updatedReplicas is the number of Pods created by the - StatefulSet controller from the StatefulSet version indicated by - updateRevision. + description: updatedReplicas is the number of instances created by + the InstanceSet controller from the InstanceSet version indicated + by UpdateRevisions. format: int32 type: integer required: - - initReplicas - replicas type: object type: object diff --git a/docs/developer_docs/api-reference/cluster.md b/docs/developer_docs/api-reference/cluster.md index 9c0995baf13..49f054521fe 100644 --- a/docs/developer_docs/api-reference/cluster.md +++ b/docs/developer_docs/api-reference/cluster.md @@ -23589,6 +23589,27 @@ string +
string
alias)Value | +Description | +
---|---|
"InstanceFailure" |
+InstanceFailure is added in an instance set when at least one of its instances(pods) is in a |
+
"InstanceReady" |
+InstanceReady is added in an instance set when at least one of its instances(pods) is in a Ready condition. +ConditionStatus will be True if all its instances(pods) are in a Ready condition. +Or, a NotReady reason with not ready instances encoded in the Message filed will be set. + |
+
@@ -24010,54 +24031,140 @@ Credential
StatefulSetStatus
observedGeneration
observedGeneration is the most recent generation observed for this InstanceSet. It corresponds to the +InstanceSet’s generation, which is updated on mutation by the API Server.
+replicas
replicas is the number of instances created by the InstanceSet controller.
+readyReplicas
readyReplicas is the number of instances created for this InstanceSet with a Ready Condition.
+currentReplicas
currentReplicas is the number of instances created by the InstanceSet controller from the InstanceSet version +indicated by CurrentRevisions.
+updatedReplicas
updatedReplicas is the number of instances created by the InstanceSet controller from the InstanceSet version +indicated by UpdateRevisions.
+currentRevision
currentRevision, if not empty, indicates the version of the InstanceSet used to generate instances in the +sequence [0,currentReplicas).
+updateRevision
updateRevision, if not empty, indicates the version of the InstanceSet used to generate instances in the sequence +[replicas-updatedReplicas,replicas)
+conditions
-(Members of StatefulSetStatus
are embedded into this type.)
-
Represents the latest available observations of an instanceset’s current state. +Known .status.conditions.type are: “InstanceFailure”, “InstanceReady”
initReplicas
availableReplicas
Defines the initial number of pods (members) when the cluster is first initialized. -This value is set to spec.Replicas at the time of object creation and remains constant thereafter.
+(Optional) +Total number of available instances (ready for at least minReadySeconds) targeted by this InstanceSet.
readyInitReplicas
initReplicas
Represents the number of pods (members) that have already reached the MembersStatus during the cluster initialization stage. -This value remains constant once it equals InitReplicas.
+Defines the initial number of instances when the cluster is first initialized. +This value is set to spec.Replicas at the time of object creation and remains constant thereafter. +Used only when spec.roles set.
currentGeneration
readyInitReplicas
When not empty, indicates the version of the InstanceSet used to generate the underlying workload.
+Represents the number of instances that have already reached the MembersStatus during the cluster initialization stage. +This value remains constant once it equals InitReplicas. +Used only when spec.roles set.
readyWithoutPrimary
Indicates whether it is required for the InstanceSet to have at least one primary instance ready.
+currentRevisions
Defines the role of the replica in the cluster.
ready
Whether the corresponding Pod is in ready condition.
-readyWithoutPrimary
Indicates whether it is required for the InstanceSet to have at least one primary instance ready.
-