Skip to content

Commit

Permalink
Merge pull request #100842 from ravisantoshgudimetla/add-minReadySeco…
Browse files Browse the repository at this point in the history
…nds-ss

api: Add min ready seconds & availablereplicas for statefulsets
  • Loading branch information
k8s-ci-robot committed May 26, 2021
2 parents cb49f5c + 4c95bc8 commit a98d3d0
Show file tree
Hide file tree
Showing 47 changed files with 1,191 additions and 450 deletions.
10 changes: 10 additions & 0 deletions api/openapi-spec/swagger.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions pkg/apis/apps/types.go
Expand Up @@ -157,6 +157,13 @@ type StatefulSetSpec struct {
// consists of all revisions not represented by a currently applied
// StatefulSetSpec version. The default value is 10.
RevisionHistoryLimit *int32

// Minimum number of seconds for which a newly created pod should be ready
// without any of its container crashing for it to be considered available.
// Defaults to 0 (pod will be considered available as soon as it is ready)
// This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate.
// +optional
MinReadySeconds int32
}

// StatefulSetStatus represents the current state of a StatefulSet.
Expand Down Expand Up @@ -196,6 +203,12 @@ type StatefulSetStatus struct {

// Represents the latest available observations of a statefulset's current state.
Conditions []StatefulSetCondition

// Total number of available pods (ready for at least minReadySeconds) targeted by this statefulset.
// This is an alpha field and requires enabling StatefulSetMinReadySeconds feature gate.
// Remove omitempty when graduating to beta
// +optional
AvailableReplicas int32
}

// StatefulSetConditionType describes the condition types of StatefulSets.
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/apps/v1/defaults_test.go
Expand Up @@ -208,6 +208,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Expand Down Expand Up @@ -235,6 +236,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Expand All @@ -257,6 +259,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1.ParallelPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Expand Down Expand Up @@ -286,6 +289,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1.OrderedReadyPodManagement,
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/apps/v1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion pkg/apis/apps/v1beta1/defaults.go
Expand Up @@ -60,7 +60,6 @@ func SetDefaults_StatefulSet(obj *appsv1beta1.StatefulSet) {
obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32)
*obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0
}

}

// SetDefaults_Deployment sets additional defaults compared to its counterpart
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/apps/v1beta1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pkg/apis/apps/v1beta2/defaults_test.go
Expand Up @@ -207,6 +207,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1beta2.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
Expand Down Expand Up @@ -234,6 +235,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1beta2.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement,
UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
Expand All @@ -256,6 +258,7 @@ func TestSetDefaultStatefulSet(t *testing.T) {
},
Spec: appsv1beta2.StatefulSetSpec{
Replicas: &defaultReplicas,
MinReadySeconds: int32(0),
Template: defaultTemplate,
PodManagementPolicy: appsv1beta2.ParallelPodManagement,
UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/apps/v1beta2/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

26 changes: 25 additions & 1 deletion pkg/apis/apps/validation/validation.go
Expand Up @@ -109,6 +109,9 @@ func ValidateStatefulSetSpec(spec *apps.StatefulSetSpec, fldPath *field.Path, op
}

allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...)
}
if spec.Selector == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("selector"), ""))
} else {
Expand Down Expand Up @@ -152,11 +155,21 @@ func ValidateStatefulSetUpdate(statefulSet, oldStatefulSet *apps.StatefulSet) fi
newStatefulSetClone.Spec.Replicas = oldStatefulSet.Spec.Replicas // +k8s:verify-mutation:reason=clone
newStatefulSetClone.Spec.Template = oldStatefulSet.Spec.Template // +k8s:verify-mutation:reason=clone
newStatefulSetClone.Spec.UpdateStrategy = oldStatefulSet.Spec.UpdateStrategy // +k8s:verify-mutation:reason=clone
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
newStatefulSetClone.Spec.MinReadySeconds = oldStatefulSet.Spec.MinReadySeconds // +k8s:verify-mutation:reason=clone
}
if !apiequality.Semantic.DeepEqual(newStatefulSetClone.Spec, oldStatefulSet.Spec) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden"))
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to statefulset spec for fields other than 'replicas', 'template', 'minReadySeconds' and 'updateStrategy' are forbidden"))
} else {
allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to statefulset spec for fields other than 'replicas', 'template' and 'updateStrategy' are forbidden"))
}
}

allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(statefulSet.Spec.Replicas), field.NewPath("spec", "replicas"))...)
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(statefulSet.Spec.MinReadySeconds), field.NewPath("spec", "minReadySeconds"))...)
}
return allErrs
}

Expand All @@ -168,6 +181,9 @@ func ValidateStatefulSetStatus(status *apps.StatefulSetStatus, fieldPath *field.
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.ReadyReplicas), fieldPath.Child("readyReplicas"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.CurrentReplicas), fieldPath.Child("currentReplicas"))...)
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.UpdatedReplicas), fieldPath.Child("updatedReplicas"))...)
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.AvailableReplicas), fieldPath.Child("availableReplicas"))...)
}
if status.ObservedGeneration != nil {
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*status.ObservedGeneration), fieldPath.Child("observedGeneration"))...)
}
Expand All @@ -185,6 +201,14 @@ func ValidateStatefulSetStatus(status *apps.StatefulSetStatus, fieldPath *field.
if status.UpdatedReplicas > status.Replicas {
allErrs = append(allErrs, field.Invalid(fieldPath.Child("updatedReplicas"), status.UpdatedReplicas, msg))
}
if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetMinReadySeconds) {
if status.AvailableReplicas > status.Replicas {
allErrs = append(allErrs, field.Invalid(fieldPath.Child("availableReplicas"), status.AvailableReplicas, msg))
}
if status.AvailableReplicas > status.ReadyReplicas {
allErrs = append(allErrs, field.Invalid(fieldPath.Child("availableReplicas"), status.AvailableReplicas, "cannot be greater than readyReplicas"))
}
}

return allErrs
}
Expand Down

0 comments on commit a98d3d0

Please sign in to comment.