From 357203d992bb9b0cf9685f878d8635cf3277bef9 Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Fri, 30 Aug 2019 00:05:18 -0700 Subject: [PATCH 1/2] API: maxUnavailable for StatefulSet --- api/openapi-spec/swagger.json | 6 +- .../v3/apis__apps__v1_openapi.json | 6 +- pkg/apis/apps/types.go | 15 +- pkg/apis/apps/v1/defaults.go | 16 +- pkg/apis/apps/v1/defaults_test.go | 171 ++++++++- pkg/apis/apps/v1/zz_generated.conversion.go | 3 + pkg/apis/apps/v1beta1/defaults.go | 16 +- .../apps/v1beta1/zz_generated.conversion.go | 3 + pkg/apis/apps/v1beta2/defaults.go | 22 +- pkg/apis/apps/v1beta2/defaults_test.go | 206 ++++++++++- .../apps/v1beta2/zz_generated.conversion.go | 3 + pkg/apis/apps/validation/validation.go | 26 +- pkg/apis/apps/validation/validation_test.go | 66 ++++ pkg/apis/apps/zz_generated.deepcopy.go | 8 +- pkg/features/kube_features.go | 8 + pkg/generated/openapi/zz_generated.openapi.go | 30 +- pkg/registry/apps/statefulset/strategy.go | 17 + .../apps/statefulset/strategy_test.go | 72 +++- .../src/k8s.io/api/apps/v1/generated.pb.go | 321 +++++++++------- .../src/k8s.io/api/apps/v1/generated.proto | 17 +- staging/src/k8s.io/api/apps/v1/types.go | 16 +- .../apps/v1/types_swagger_doc_generated.go | 5 +- .../api/apps/v1/zz_generated.deepcopy.go | 5 + .../k8s.io/api/apps/v1beta1/generated.pb.go | 303 +++++++++------- .../k8s.io/api/apps/v1beta1/generated.proto | 16 +- staging/src/k8s.io/api/apps/v1beta1/types.go | 15 +- .../v1beta1/types_swagger_doc_generated.go | 5 +- .../api/apps/v1beta1/zz_generated.deepcopy.go | 5 + .../k8s.io/api/apps/v1beta2/generated.pb.go | 342 ++++++++++-------- .../k8s.io/api/apps/v1beta2/generated.proto | 17 +- staging/src/k8s.io/api/apps/v1beta2/types.go | 16 +- .../v1beta2/types_swagger_doc_generated.go | 5 +- .../api/apps/v1beta2/zz_generated.deepcopy.go | 5 + .../testdata/HEAD/apps.v1.StatefulSet.json | 3 +- .../api/testdata/HEAD/apps.v1.StatefulSet.pb | Bin 10780 -> 10807 bytes .../testdata/HEAD/apps.v1.StatefulSet.yaml | 1 + .../HEAD/apps.v1beta1.StatefulSet.json | 3 +- .../testdata/HEAD/apps.v1beta1.StatefulSet.pb | Bin 10785 -> 10812 bytes .../HEAD/apps.v1beta1.StatefulSet.yaml | 1 + .../HEAD/apps.v1beta2.StatefulSet.json | 3 +- .../testdata/HEAD/apps.v1beta2.StatefulSet.pb | Bin 10785 -> 10812 bytes .../HEAD/apps.v1beta2.StatefulSet.yaml | 1 + .../v1/rollingupdatestatefulsetstrategy.go | 15 +- .../rollingupdatestatefulsetstrategy.go | 15 +- .../rollingupdatestatefulsetstrategy.go | 15 +- .../applyconfigurations/internal/internal.go | 9 + 46 files changed, 1369 insertions(+), 484 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 719c7f83ff7d..82eeea3fff06 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -1212,8 +1212,12 @@ "io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy": { "description": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", "properties": { + "maxUnavailable": { + "$ref": "#/definitions/io.k8s.apimachinery.pkg.util.intstr.IntOrString", + "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable." + }, "partition": { - "description": "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + "description": "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", "format": "int32", "type": "integer" } diff --git a/api/openapi-spec/v3/apis__apps__v1_openapi.json b/api/openapi-spec/v3/apis__apps__v1_openapi.json index 4e6f9c626194..a0457223f265 100644 --- a/api/openapi-spec/v3/apis__apps__v1_openapi.json +++ b/api/openapi-spec/v3/apis__apps__v1_openapi.json @@ -746,8 +746,12 @@ "io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy": { "description": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", "properties": { + "maxUnavailable": { + "$ref": "#/components/schemas/io.k8s.apimachinery.pkg.util.intstr.IntOrString", + "description": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable." + }, "partition": { - "description": "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + "description": "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", "format": "int32", "type": "integer" } diff --git a/pkg/apis/apps/types.go b/pkg/apis/apps/types.go index 70a841c285f4..a86fd4f7dd76 100644 --- a/pkg/apis/apps/types.go +++ b/pkg/apis/apps/types.go @@ -92,9 +92,20 @@ const ( // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. type RollingUpdateStatefulSetStrategy struct { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. Partition int32 + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + MaxUnavailable *intstr.IntOrString } // PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine diff --git a/pkg/apis/apps/v1/defaults.go b/pkg/apis/apps/v1/defaults.go index c6862ec7fc99..2a57d78950a8 100644 --- a/pkg/apis/apps/v1/defaults.go +++ b/pkg/apis/apps/v1/defaults.go @@ -113,10 +113,18 @@ func SetDefaults_StatefulSet(obj *appsv1.StatefulSet) { } if obj.Spec.UpdateStrategy.Type == appsv1.RollingUpdateStatefulSetStrategyType && - obj.Spec.UpdateStrategy.RollingUpdate != nil && - obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { - obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) - *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + obj.Spec.UpdateStrategy.RollingUpdate != nil { + + if obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { + obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) + *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + } + if utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) { + if obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable == nil { + maxUnavailable := intstr.FromInt(1) + obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable + } + } } if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetAutoDeletePVC) { diff --git a/pkg/apis/apps/v1/defaults_test.go b/pkg/apis/apps/v1/defaults_test.go index 9dec309753b8..c1f97d0590ce 100644 --- a/pkg/apis/apps/v1/defaults_test.go +++ b/pkg/apis/apps/v1/defaults_test.go @@ -175,6 +175,15 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { } } +func getMaxUnavailable(maxUnavailable int) *intstr.IntOrString { + maxUnavailableIntOrStr := intstr.FromInt(maxUnavailable) + return &maxUnavailableIntOrStr +} + +func getPartition(partition int32) *int32 { + return &partition +} + func TestSetDefaultStatefulSet(t *testing.T) { defaultLabels := map[string]string{"foo": "bar"} var defaultPartition int32 = 0 @@ -196,10 +205,11 @@ func TestSetDefaultStatefulSet(t *testing.T) { } tests := []struct { - name string - original *appsv1.StatefulSet - expected *appsv1.StatefulSet - enablePVCDeletionPolicy bool + name string + original *appsv1.StatefulSet + expected *appsv1.StatefulSet + enablePVCDeletionPolicy bool + enableMaxUnavailablePolicy bool }{ { name: "labels and default update strategy", @@ -439,12 +449,165 @@ func TestSetDefaultStatefulSet(t *testing.T) { }, enablePVCDeletionPolicy: false, }, + { + name: "MaxUnavailable disabled, with maxUnavailable not specified", + original: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: defaultTemplate, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1.OrderedReadyPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable disabled, with default maxUnavailable specified", + original: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: &defaultPartition, + MaxUnavailable: getMaxUnavailable(1), + }, + }, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1.OrderedReadyPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + MaxUnavailable: getMaxUnavailable(1), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable disabled, with non default maxUnavailable specified", + original: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: ¬TheDefaultPartition, + MaxUnavailable: getMaxUnavailable(3), + }, + }, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1.OrderedReadyPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(42), + MaxUnavailable: getMaxUnavailable(3), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable enabled, with no maxUnavailable specified", + original: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: defaultTemplate, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1.OrderedReadyPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + MaxUnavailable: getMaxUnavailable(1), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: true, + }, + { + name: "MaxUnavailable enabled, with non default maxUnavailable specified", + original: &appsv1.StatefulSet{ + Spec: appsv1.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: ¬TheDefaultPartition, + MaxUnavailable: getMaxUnavailable(3), + }, + }, + }, + }, + expected: &appsv1.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1.OrderedReadyPodManagement, + UpdateStrategy: appsv1.StatefulSetUpdateStrategy{ + Type: appsv1.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(42), + MaxUnavailable: getMaxUnavailable(3), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: true, + }, } for _, test := range tests { test := test t.Run(test.name, func(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetAutoDeletePVC, test.enablePVCDeletionPolicy)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, test.enableMaxUnavailablePolicy)() obj2 := roundTrip(t, runtime.Object(test.original)) got, ok := obj2.(*appsv1.StatefulSet) diff --git a/pkg/apis/apps/v1/zz_generated.conversion.go b/pkg/apis/apps/v1/zz_generated.conversion.go index 7789fb681084..103eeff6a371 100644 --- a/pkg/apis/apps/v1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1/zz_generated.conversion.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" apps "k8s.io/kubernetes/pkg/apis/apps" core "k8s.io/kubernetes/pkg/apis/core" apiscorev1 "k8s.io/kubernetes/pkg/apis/core/v1" @@ -1042,6 +1043,7 @@ func autoConvert_v1_RollingUpdateStatefulSetStrategy_To_apps_RollingUpdateStatef if err := metav1.Convert_Pointer_int32_To_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } @@ -1054,6 +1056,7 @@ func autoConvert_apps_RollingUpdateStatefulSetStrategy_To_v1_RollingUpdateStatef if err := metav1.Convert_int32_To_Pointer_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } diff --git a/pkg/apis/apps/v1beta1/defaults.go b/pkg/apis/apps/v1beta1/defaults.go index 799973e3fca1..1378747504e7 100644 --- a/pkg/apis/apps/v1beta1/defaults.go +++ b/pkg/apis/apps/v1beta1/defaults.go @@ -70,10 +70,18 @@ func SetDefaults_StatefulSet(obj *appsv1beta1.StatefulSet) { *obj.Spec.RevisionHistoryLimit = 10 } if obj.Spec.UpdateStrategy.Type == appsv1beta1.RollingUpdateStatefulSetStrategyType && - obj.Spec.UpdateStrategy.RollingUpdate != nil && - obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { - obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) - *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + obj.Spec.UpdateStrategy.RollingUpdate != nil { + + if obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { + obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) + *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + } + if utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) { + if obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable == nil { + maxUnavailable := intstr.FromInt(1) + obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable + } + } } } diff --git a/pkg/apis/apps/v1beta1/zz_generated.conversion.go b/pkg/apis/apps/v1beta1/zz_generated.conversion.go index e1ba487a11e0..ce30467ed1e1 100644 --- a/pkg/apis/apps/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1beta1/zz_generated.conversion.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" apps "k8s.io/kubernetes/pkg/apis/apps" autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" core "k8s.io/kubernetes/pkg/apis/core" @@ -641,6 +642,7 @@ func autoConvert_v1beta1_RollingUpdateStatefulSetStrategy_To_apps_RollingUpdateS if err := metav1.Convert_Pointer_int32_To_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } @@ -653,6 +655,7 @@ func autoConvert_apps_RollingUpdateStatefulSetStrategy_To_v1beta1_RollingUpdateS if err := metav1.Convert_int32_To_Pointer_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } diff --git a/pkg/apis/apps/v1beta2/defaults.go b/pkg/apis/apps/v1beta2/defaults.go index 78a415d64784..c2c17863cdf8 100644 --- a/pkg/apis/apps/v1beta2/defaults.go +++ b/pkg/apis/apps/v1beta2/defaults.go @@ -63,15 +63,25 @@ func SetDefaults_StatefulSet(obj *appsv1beta2.StatefulSet) { if obj.Spec.UpdateStrategy.Type == "" { obj.Spec.UpdateStrategy.Type = appsv1beta2.RollingUpdateStatefulSetStrategyType - // UpdateStrategy.RollingUpdate will take default values below. - obj.Spec.UpdateStrategy.RollingUpdate = &appsv1beta2.RollingUpdateStatefulSetStrategy{} + if obj.Spec.UpdateStrategy.RollingUpdate == nil { + // UpdateStrategy.RollingUpdate will take default values below. + obj.Spec.UpdateStrategy.RollingUpdate = &appsv1beta2.RollingUpdateStatefulSetStrategy{} + } } if obj.Spec.UpdateStrategy.Type == appsv1beta2.RollingUpdateStatefulSetStrategyType && - obj.Spec.UpdateStrategy.RollingUpdate != nil && - obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { - obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) - *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + obj.Spec.UpdateStrategy.RollingUpdate != nil { + + if obj.Spec.UpdateStrategy.RollingUpdate.Partition == nil { + obj.Spec.UpdateStrategy.RollingUpdate.Partition = new(int32) + *obj.Spec.UpdateStrategy.RollingUpdate.Partition = 0 + } + if utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) { + if obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable == nil { + maxUnavailable := intstr.FromInt(1) + obj.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable + } + } } if utilfeature.DefaultFeatureGate.Enabled(features.StatefulSetAutoDeletePVC) { diff --git a/pkg/apis/apps/v1beta2/defaults_test.go b/pkg/apis/apps/v1beta2/defaults_test.go index 8bf13b41d689..1cbcda06edaf 100644 --- a/pkg/apis/apps/v1beta2/defaults_test.go +++ b/pkg/apis/apps/v1beta2/defaults_test.go @@ -27,10 +27,13 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" + utilfeature "k8s.io/apiserver/pkg/util/feature" + featuregatetesting "k8s.io/component-base/featuregate/testing" "k8s.io/kubernetes/pkg/api/legacyscheme" _ "k8s.io/kubernetes/pkg/apis/apps/install" . "k8s.io/kubernetes/pkg/apis/apps/v1beta2" _ "k8s.io/kubernetes/pkg/apis/core/install" + "k8s.io/kubernetes/pkg/features" utilpointer "k8s.io/utils/pointer" ) @@ -172,9 +175,19 @@ func TestSetDefaultDaemonSetSpec(t *testing.T) { } } +func getMaxUnavailable(maxUnavailable int) *intstr.IntOrString { + maxUnavailableIntOrStr := intstr.FromInt(maxUnavailable) + return &maxUnavailableIntOrStr +} + +func getPartition(partition int32) *int32 { + return &partition +} + func TestSetDefaultStatefulSet(t *testing.T) { defaultLabels := map[string]string{"foo": "bar"} var defaultPartition int32 = 0 + var notTheDefaultPartition int32 = 42 var defaultReplicas int32 = 1 period := int64(v1.DefaultTerminationGracePeriodSeconds) @@ -192,10 +205,13 @@ func TestSetDefaultStatefulSet(t *testing.T) { } tests := []struct { - original *appsv1beta2.StatefulSet - expected *appsv1beta2.StatefulSet + name string + original *appsv1beta2.StatefulSet + expected *appsv1beta2.StatefulSet + enableMaxUnavailablePolicy bool }{ - { // labels and default update strategy + { + name: "labels and default update strategy", original: &appsv1beta2.StatefulSet{ Spec: appsv1beta2.StatefulSetSpec{ Template: defaultTemplate, @@ -220,7 +236,8 @@ func TestSetDefaultStatefulSet(t *testing.T) { }, }, }, - { // Alternate update strategy + { + name: "Alternate update strategy", original: &appsv1beta2.StatefulSet{ Spec: appsv1beta2.StatefulSetSpec{ Template: defaultTemplate, @@ -245,7 +262,8 @@ func TestSetDefaultStatefulSet(t *testing.T) { }, }, }, - { // Parallel pod management policy. + { + name: "Parallel pod management policy.", original: &appsv1beta2.StatefulSet{ Spec: appsv1beta2.StatefulSetSpec{ Template: defaultTemplate, @@ -271,20 +289,174 @@ func TestSetDefaultStatefulSet(t *testing.T) { }, }, }, + { + name: "MaxUnavailable disabled, with maxUnavailable not specified", + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable disabled, with default maxUnavailable specified", + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: &defaultPartition, + MaxUnavailable: getMaxUnavailable(1), + }, + }, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + MaxUnavailable: getMaxUnavailable(1), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable disabled, with non default maxUnavailable specified", + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: ¬TheDefaultPartition, + MaxUnavailable: getMaxUnavailable(3), + }, + }, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(42), + MaxUnavailable: getMaxUnavailable(3), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: false, + }, + { + name: "MaxUnavailable enabled, with no maxUnavailable specified", + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(0), + MaxUnavailable: getMaxUnavailable(1), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: true, + }, + { + name: "MaxUnavailable enabled, with non default maxUnavailable specified", + original: &appsv1beta2.StatefulSet{ + Spec: appsv1beta2.StatefulSetSpec{ + Template: defaultTemplate, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: ¬TheDefaultPartition, + MaxUnavailable: getMaxUnavailable(3), + }, + }, + }, + }, + expected: &appsv1beta2.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{ + Labels: defaultLabels, + }, + Spec: appsv1beta2.StatefulSetSpec{ + Replicas: &defaultReplicas, + Template: defaultTemplate, + PodManagementPolicy: appsv1beta2.OrderedReadyPodManagement, + UpdateStrategy: appsv1beta2.StatefulSetUpdateStrategy{ + Type: appsv1beta2.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &appsv1beta2.RollingUpdateStatefulSetStrategy{ + Partition: getPartition(42), + MaxUnavailable: getMaxUnavailable(3), + }, + }, + RevisionHistoryLimit: utilpointer.Int32Ptr(10), + }, + }, + enableMaxUnavailablePolicy: true, + }, } - for i, test := range tests { - original := test.original - expected := test.expected - obj2 := roundTrip(t, runtime.Object(original)) - got, ok := obj2.(*appsv1beta2.StatefulSet) - if !ok { - t.Errorf("(%d) unexpected object: %v", i, got) - t.FailNow() - } - if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) { - t.Errorf("(%d) got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", i, got.Spec, expected.Spec) - } + for _, test := range tests { + test := test + t.Run(test.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, test.enableMaxUnavailablePolicy)() + obj2 := roundTrip(t, runtime.Object(test.original)) + got, ok := obj2.(*appsv1beta2.StatefulSet) + if !ok { + t.Errorf("unexpected object: %v", got) + t.FailNow() + } + if !apiequality.Semantic.DeepEqual(got.Spec, test.expected.Spec) { + t.Errorf("got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", got.Spec, test.expected.Spec) + } + }) } } diff --git a/pkg/apis/apps/v1beta2/zz_generated.conversion.go b/pkg/apis/apps/v1beta2/zz_generated.conversion.go index b5deccf43630..18e6a0fe6b28 100644 --- a/pkg/apis/apps/v1beta2/zz_generated.conversion.go +++ b/pkg/apis/apps/v1beta2/zz_generated.conversion.go @@ -29,6 +29,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" conversion "k8s.io/apimachinery/pkg/conversion" runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" apps "k8s.io/kubernetes/pkg/apis/apps" autoscaling "k8s.io/kubernetes/pkg/apis/autoscaling" core "k8s.io/kubernetes/pkg/apis/core" @@ -1073,6 +1074,7 @@ func autoConvert_v1beta2_RollingUpdateStatefulSetStrategy_To_apps_RollingUpdateS if err := metav1.Convert_Pointer_int32_To_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } @@ -1085,6 +1087,7 @@ func autoConvert_apps_RollingUpdateStatefulSetStrategy_To_v1beta2_RollingUpdateS if err := metav1.Convert_int32_To_Pointer_int32(&in.Partition, &out.Partition, s); err != nil { return err } + out.MaxUnavailable = (*intstr.IntOrString)(unsafe.Pointer(in.MaxUnavailable)) return nil } diff --git a/pkg/apis/apps/validation/validation.go b/pkg/apis/apps/validation/validation.go index e2eedf45c5ad..24c2f65432f0 100644 --- a/pkg/apis/apps/validation/validation.go +++ b/pkg/apis/apps/validation/validation.go @@ -115,10 +115,8 @@ func ValidateStatefulSetSpec(spec *apps.StatefulSetSpec, fldPath *field.Path, op } case apps.RollingUpdateStatefulSetStrategyType: if spec.UpdateStrategy.RollingUpdate != nil { - allErrs = append(allErrs, - apivalidation.ValidateNonnegativeField( - int64(spec.UpdateStrategy.RollingUpdate.Partition), - fldPath.Child("updateStrategy").Child("rollingUpdate").Child("partition"))...) + allErrs = append(allErrs, validateRollingUpdateStatefulSet(spec.UpdateStrategy.RollingUpdate, fldPath.Child("updateStrategy", "rollingUpdate"))...) + } default: allErrs = append(allErrs, @@ -419,6 +417,26 @@ func ValidateRollingUpdateDaemonSet(rollingUpdate *apps.RollingUpdateDaemonSet, return allErrs } +// validateRollingUpdateStatefulSet validates a given RollingUpdateStatefulSet. +func validateRollingUpdateStatefulSet(rollingUpdate *apps.RollingUpdateStatefulSetStrategy, fldPath *field.Path) field.ErrorList { + var allErrs field.ErrorList + fldPathMaxUn := fldPath.Child("maxUnavailable") + allErrs = append(allErrs, + apivalidation.ValidateNonnegativeField( + int64(rollingUpdate.Partition), + fldPath.Child("partition"))...) + if rollingUpdate.MaxUnavailable != nil { + allErrs = append(allErrs, ValidatePositiveIntOrPercent(*rollingUpdate.MaxUnavailable, fldPathMaxUn)...) + if getIntOrPercentValue(*rollingUpdate.MaxUnavailable) == 0 { + // MaxUnavailable cannot be 0. + allErrs = append(allErrs, field.Invalid(fldPathMaxUn, *rollingUpdate.MaxUnavailable, "cannot be 0")) + } + // Validate that MaxUnavailable is not more than 100%. + allErrs = append(allErrs, IsNotMoreThan100Percent(*rollingUpdate.MaxUnavailable, fldPathMaxUn)...) + } + return allErrs +} + // ValidateDaemonSetUpdateStrategy validates a given DaemonSetUpdateStrategy. func ValidateDaemonSetUpdateStrategy(strategy *apps.DaemonSetUpdateStrategy, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go index 7d5d69cc9706..423b4220f2b1 100644 --- a/pkg/apis/apps/validation/validation_test.go +++ b/pkg/apis/apps/validation/validation_test.go @@ -34,6 +34,10 @@ import ( "k8s.io/kubernetes/pkg/features" ) +func intStrAddr(intOrStr intstr.IntOrString) *intstr.IntOrString { + return &intOrStr +} + func TestValidateStatefulSet(t *testing.T) { validLabels := map[string]string{"a": "b"} validPodTemplate := api.PodTemplate{ @@ -142,6 +146,22 @@ func TestValidateStatefulSet(t *testing.T) { }, }, }, + "maxUnavailable with parallel pod management": { + ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.ParallelPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + Replicas: 3, + UpdateStrategy: apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ + Partition: 2, + MaxUnavailable: intStrAddr(intstr.FromInt(2)), + }, + }, + }, + }, } for name, successCase := range successCases { @@ -394,6 +414,51 @@ func TestValidateStatefulSet(t *testing.T) { UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, }, }, + "zero maxUnavailable": { + ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.OrderedReadyPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + Replicas: 3, + UpdateStrategy: apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: intStrAddr(intstr.FromInt(0)), + }, + }, + }, + }, + "zero percent maxUnavailable": { + ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.ParallelPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + Replicas: 3, + UpdateStrategy: apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: intStrAddr(intstr.FromString("0%")), + }, + }, + }, + }, + "greater than 100 percent maxUnavailable": { + ObjectMeta: metav1.ObjectMeta{Name: "abc-123", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.ParallelPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: validLabels}, + Template: validPodTemplate.Template, + Replicas: 3, + UpdateStrategy: apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &apps.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: intStrAddr(intstr.FromString("101%")), + }, + }, + }, + }, } for k, v := range errorCases { @@ -426,6 +491,7 @@ func TestValidateStatefulSet(t *testing.T) { field != "spec.persistentVolumeClaimRetentionPolicy" && field != "spec.persistentVolumeClaimRetentionPolicy.whenDeleted" && field != "spec.persistentVolumeClaimRetentionPolicy.whenScaled" && + field != "spec.updateStrategy.rollingUpdate.maxUnavailable" && field != "spec.template.spec.activeDeadlineSeconds" { t.Errorf("%s: missing prefix for: %v", k, errs[i]) } diff --git a/pkg/apis/apps/zz_generated.deepcopy.go b/pkg/apis/apps/zz_generated.deepcopy.go index b496f6bff528..011086ca23a8 100644 --- a/pkg/apis/apps/zz_generated.deepcopy.go +++ b/pkg/apis/apps/zz_generated.deepcopy.go @@ -24,6 +24,7 @@ package apps import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" + intstr "k8s.io/apimachinery/pkg/util/intstr" core "k8s.io/kubernetes/pkg/apis/core" ) @@ -621,6 +622,11 @@ func (in *RollingUpdateDeployment) DeepCopy() *RollingUpdateDeployment { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateStatefulSetStrategy) { *out = *in + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } return } @@ -807,7 +813,7 @@ func (in *StatefulSetUpdateStrategy) DeepCopyInto(out *StatefulSetUpdateStrategy if in.RollingUpdate != nil { in, out := &in.RollingUpdate, &out.RollingUpdate *out = new(RollingUpdateStatefulSetStrategy) - **out = **in + (*in).DeepCopyInto(*out) } return } diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 76b1abb91737..d5485b9ff6a4 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -858,6 +858,12 @@ const ( // // Allow pods to failover to a different node in case of non graceful node shutdown NodeOutOfServiceVolumeDetach featuregate.Feature = "NodeOutOfServiceVolumeDetach" + + // owner: @krmayankk + // alpha: v1.24 + // + // Enables maxUnavailable for StatefulSet + MaxUnavailableStatefulSet featuregate.Feature = "MaxUnavailableStatefulSet" ) func init() { @@ -982,6 +988,8 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS MinDomainsInPodTopologySpread: {Default: false, PreRelease: featuregate.Alpha}, ServiceIPStaticSubrange: {Default: false, PreRelease: featuregate.Alpha}, NodeOutOfServiceVolumeDetach: {Default: false, PreRelease: featuregate.Alpha}, + MaxUnavailableStatefulSet: {Default: false, PreRelease: featuregate.Alpha}, + // inherited features from generic apiserver, relisted here to get a conflict if it is changed // unintentionally on either side: genericfeatures.AdvancedAuditing: {Default: true, PreRelease: featuregate.GA}, diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 6a09f8bbaac0..517c4306358e 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3774,14 +3774,22 @@ func schema_k8sio_api_apps_v1_RollingUpdateStatefulSetStrategy(ref common.Refere Properties: map[string]spec.Schema{ "partition": { SchemaProps: spec.SchemaProps{ - Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", Type: []string{"integer"}, Format: "int32", }, }, + "maxUnavailable": { + SchemaProps: spec.SchemaProps{ + Description: "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", + Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"), + }, + }, }, }, }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, } } @@ -4762,14 +4770,22 @@ func schema_k8sio_api_apps_v1beta1_RollingUpdateStatefulSetStrategy(ref common.R Properties: map[string]spec.Schema{ "partition": { SchemaProps: spec.SchemaProps{ - Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned.", + Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", Type: []string{"integer"}, Format: "int32", }, }, + "maxUnavailable": { + SchemaProps: spec.SchemaProps{ + Description: "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", + Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"), + }, + }, }, }, }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, } } @@ -6406,14 +6422,22 @@ func schema_k8sio_api_apps_v1beta2_RollingUpdateStatefulSetStrategy(ref common.R Properties: map[string]spec.Schema{ "partition": { SchemaProps: spec.SchemaProps{ - Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + Description: "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", Type: []string{"integer"}, Format: "int32", }, }, + "maxUnavailable": { + SchemaProps: spec.SchemaProps{ + Description: "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", + Ref: ref("k8s.io/apimachinery/pkg/util/intstr.IntOrString"), + }, + }, }, }, }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/util/intstr.IntOrString"}, } } diff --git a/pkg/registry/apps/statefulset/strategy.go b/pkg/registry/apps/statefulset/strategy.go index eec69049269b..00da328154a5 100644 --- a/pkg/registry/apps/statefulset/strategy.go +++ b/pkg/registry/apps/statefulset/strategy.go @@ -79,6 +79,18 @@ func (statefulSetStrategy) PrepareForCreate(ctx context.Context, obj runtime.Obj pod.DropDisabledTemplateFields(&statefulSet.Spec.Template, nil) } +// maxUnavailableInUse returns true if StatefulSet's maxUnavailable set(used) +func maxUnavailableInUse(statefulset *apps.StatefulSet) bool { + if statefulset == nil { + return false + } + if statefulset.Spec.UpdateStrategy.RollingUpdate == nil { + return false + } + + return statefulset.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable != nil +} + // PrepareForUpdate clears fields that are not allowed to be set by end users on update. func (statefulSetStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { newStatefulSet := obj.(*apps.StatefulSet) @@ -115,6 +127,11 @@ func dropStatefulSetDisabledFields(newSS *apps.StatefulSet, oldSS *apps.Stateful newSS.Spec.PersistentVolumeClaimRetentionPolicy = nil } } + if !utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) && !maxUnavailableInUse(oldSS) { + if newSS.Spec.UpdateStrategy.RollingUpdate != nil { + newSS.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable = nil + } + } } // minReadySecondsFieldsInUse returns true if fields related to StatefulSet minReadySeconds are set and diff --git a/pkg/registry/apps/statefulset/strategy_test.go b/pkg/registry/apps/statefulset/strategy_test.go index 757f6f59a1bb..887ec686ebe4 100644 --- a/pkg/registry/apps/statefulset/strategy_test.go +++ b/pkg/registry/apps/statefulset/strategy_test.go @@ -17,11 +17,11 @@ limitations under the License. package statefulset import ( - "reflect" "testing" + "github.com/google/go-cmp/cmp" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/intstr" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" utilfeature "k8s.io/apiserver/pkg/util/feature" featuregatetesting "k8s.io/component-base/featuregate/testing" @@ -353,11 +353,35 @@ func generateStatefulSetWithMinReadySeconds(minReadySeconds int32) *apps.Statefu } } +func makeStatefulSetWithMaxUnavailable(maxUnavailable *int) *apps.StatefulSet { + rollingUpdate := apps.RollingUpdateStatefulSetStrategy{} + if maxUnavailable != nil { + maxUnavailableIntStr := intstr.FromInt(*maxUnavailable) + rollingUpdate = apps.RollingUpdateStatefulSetStrategy{ + MaxUnavailable: &maxUnavailableIntStr, + } + } + + return &apps.StatefulSet{ + Spec: apps.StatefulSetSpec{ + UpdateStrategy: apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: &rollingUpdate, + }, + }, + } +} + +func getMaxUnavailable(maxUnavailable int) *int { + return &maxUnavailable +} + // TestDropStatefulSetDisabledFields tests if the drop functionality is working fine or not func TestDropStatefulSetDisabledFields(t *testing.T) { testCases := []struct { name string enableMinReadySeconds bool + enableMaxUnavailable bool ss *apps.StatefulSet oldSS *apps.StatefulSet expectedSS *apps.StatefulSet @@ -418,21 +442,57 @@ func TestDropStatefulSetDisabledFields(t *testing.T) { oldSS: generateStatefulSetWithMinReadySeconds(0), expectedSS: generateStatefulSetWithMinReadySeconds(10), }, + { + name: "MaxUnavailable not enabled, field not used", + enableMaxUnavailable: false, + ss: makeStatefulSetWithMaxUnavailable(nil), + oldSS: nil, + expectedSS: makeStatefulSetWithMaxUnavailable(nil), + }, + { + name: "MaxUnavailable not enabled, field used in new, not in old", + enableMaxUnavailable: false, + ss: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + oldSS: nil, + expectedSS: makeStatefulSetWithMaxUnavailable(nil), + }, + { + name: "MaxUnavailable not enabled, field used in old and new", + enableMaxUnavailable: false, + ss: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + oldSS: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + expectedSS: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + }, + { + name: "MaxUnavailable enabled, field used in new only", + enableMaxUnavailable: true, + ss: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + oldSS: nil, + expectedSS: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + }, + { + name: "MaxUnavailable enabled, field used in both old and new", + enableMaxUnavailable: true, + ss: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(1)), + oldSS: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(3)), + expectedSS: makeStatefulSetWithMaxUnavailable(getMaxUnavailable(1)), + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, tc.enableMaxUnavailable)() defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.StatefulSetMinReadySeconds, tc.enableMinReadySeconds)() old := tc.oldSS.DeepCopy() dropStatefulSetDisabledFields(tc.ss, tc.oldSS) // old obj should never be changed - if !reflect.DeepEqual(tc.oldSS, old) { - t.Fatalf("old ds changed: %v", diff.ObjectReflectDiff(tc.oldSS, old)) + if diff := cmp.Diff(tc.oldSS, old); diff != "" { + t.Fatalf("%v: old statefulSet changed: %v", tc.name, diff) } - if !reflect.DeepEqual(tc.ss, tc.expectedSS) { - t.Fatalf("unexpected ds spec: %v", diff.ObjectReflectDiff(tc.expectedSS, tc.ss)) + if diff := cmp.Diff(tc.expectedSS, tc.ss); diff != "" { + t.Fatalf("%v: unexpected statefulSet spec: %v, want %v, got %v", tc.name, diff, tc.expectedSS, tc.ss) } }) } diff --git a/staging/src/k8s.io/api/apps/v1/generated.pb.go b/staging/src/k8s.io/api/apps/v1/generated.pb.go index 019f7934bf23..ee10998d52c0 100644 --- a/staging/src/k8s.io/api/apps/v1/generated.pb.go +++ b/staging/src/k8s.io/api/apps/v1/generated.pb.go @@ -899,142 +899,142 @@ func init() { } var fileDescriptor_e1014cab6f31e43b = []byte{ - // 2151 bytes of a gzipped FileDescriptorProto + // 2160 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcd, 0x6f, 0x1c, 0xb7, 0x15, 0xd7, 0xec, 0x87, 0xb4, 0xa2, 0x2c, 0xc9, 0xa6, 0x54, 0x69, 0x63, 0x37, 0xbb, 0xee, 0xd6, - 0x75, 0x94, 0x38, 0xde, 0xad, 0x1d, 0x27, 0x08, 0xe2, 0x22, 0x81, 0x66, 0x95, 0xa6, 0x69, 0xf4, - 0x55, 0xca, 0x72, 0x00, 0x37, 0x2d, 0x4a, 0xcd, 0xd2, 0xab, 0x89, 0xe6, 0x0b, 0x33, 0x1c, 0xc5, - 0x42, 0x2f, 0x45, 0x81, 0xde, 0x7a, 0xe8, 0x7f, 0x52, 0x14, 0x45, 0x73, 0x2b, 0x82, 0xa0, 0x17, - 0x5f, 0x8a, 0x06, 0xbd, 0x34, 0xa7, 0x45, 0xbd, 0x39, 0x15, 0x45, 0x6f, 0xed, 0xc5, 0x97, 0x16, - 0xe4, 0x70, 0xbe, 0x39, 0xda, 0x95, 0x9c, 0x28, 0x4d, 0xe0, 0x9b, 0x96, 0xfc, 0xbd, 0x1f, 0x1f, - 0xc9, 0xf7, 0xf8, 0x7e, 0xe4, 0x08, 0xdc, 0x3e, 0x78, 0xd5, 0x6b, 0xeb, 0x76, 0xe7, 0xc0, 0xdf, - 0x23, 0xae, 0x45, 0x28, 0xf1, 0x3a, 0x87, 0xc4, 0xea, 0xd9, 0x6e, 0x47, 0x74, 0x60, 0x47, 0xef, - 0x60, 0xc7, 0xf1, 0x3a, 0x87, 0x37, 0x3a, 0x7d, 0x62, 0x11, 0x17, 0x53, 0xd2, 0x6b, 0x3b, 0xae, - 0x4d, 0x6d, 0x08, 0x03, 0x4c, 0x1b, 0x3b, 0x7a, 0x9b, 0x61, 0xda, 0x87, 0x37, 0x2e, 0x5e, 0xef, - 0xeb, 0x74, 0xdf, 0xdf, 0x6b, 0x6b, 0xb6, 0xd9, 0xe9, 0xdb, 0x7d, 0xbb, 0xc3, 0xa1, 0x7b, 0xfe, - 0x7d, 0xfe, 0x8b, 0xff, 0xe0, 0x7f, 0x05, 0x14, 0x17, 0x5b, 0x89, 0x61, 0x34, 0xdb, 0x25, 0x92, - 0x61, 0x2e, 0xde, 0x8a, 0x31, 0x26, 0xd6, 0xf6, 0x75, 0x8b, 0xb8, 0x47, 0x1d, 0xe7, 0xa0, 0xcf, - 0x1a, 0xbc, 0x8e, 0x49, 0x28, 0x96, 0x59, 0x75, 0x8a, 0xac, 0x5c, 0xdf, 0xa2, 0xba, 0x49, 0x72, - 0x06, 0xaf, 0x8c, 0x32, 0xf0, 0xb4, 0x7d, 0x62, 0xe2, 0x9c, 0xdd, 0x4b, 0x45, 0x76, 0x3e, 0xd5, - 0x8d, 0x8e, 0x6e, 0x51, 0x8f, 0xba, 0x59, 0xa3, 0xd6, 0x7f, 0x14, 0x00, 0xbb, 0xb6, 0x45, 0x5d, - 0xdb, 0x30, 0x88, 0x8b, 0xc8, 0xa1, 0xee, 0xe9, 0xb6, 0x05, 0x7f, 0x06, 0x6a, 0x6c, 0x3e, 0x3d, - 0x4c, 0x71, 0x5d, 0xb9, 0xac, 0xac, 0xcc, 0xdc, 0xfc, 0x6e, 0x3b, 0x5e, 0xe4, 0x88, 0xbe, 0xed, - 0x1c, 0xf4, 0x59, 0x83, 0xd7, 0x66, 0xe8, 0xf6, 0xe1, 0x8d, 0xf6, 0xd6, 0xde, 0xfb, 0x44, 0xa3, - 0x1b, 0x84, 0x62, 0x15, 0x3e, 0x1c, 0x34, 0x27, 0x86, 0x83, 0x26, 0x88, 0xdb, 0x50, 0xc4, 0x0a, - 0xb7, 0x40, 0x85, 0xb3, 0x97, 0x38, 0xfb, 0xf5, 0x42, 0x76, 0x31, 0xe9, 0x36, 0xc2, 0x1f, 0xbc, - 0xf9, 0x80, 0x12, 0x8b, 0xb9, 0xa7, 0x9e, 0x13, 0xd4, 0x95, 0x35, 0x4c, 0x31, 0xe2, 0x44, 0xf0, - 0x45, 0x50, 0x73, 0x85, 0xfb, 0xf5, 0xf2, 0x65, 0x65, 0xa5, 0xac, 0x9e, 0x17, 0xa8, 0x5a, 0x38, - 0x2d, 0x14, 0x21, 0x5a, 0x7f, 0x52, 0xc0, 0x52, 0x7e, 0xde, 0xeb, 0xba, 0x47, 0xe1, 0x7b, 0xb9, - 0xb9, 0xb7, 0xc7, 0x9b, 0x3b, 0xb3, 0xe6, 0x33, 0x8f, 0x06, 0x0e, 0x5b, 0x12, 0xf3, 0x7e, 0x07, - 0x54, 0x75, 0x4a, 0x4c, 0xaf, 0x5e, 0xba, 0x5c, 0x5e, 0x99, 0xb9, 0x79, 0xb5, 0x9d, 0x8f, 0xdd, - 0x76, 0xde, 0x31, 0x75, 0x56, 0x50, 0x56, 0xdf, 0x66, 0xc6, 0x28, 0xe0, 0x68, 0xfd, 0x57, 0x01, - 0xd3, 0x6b, 0x98, 0x98, 0xb6, 0xb5, 0x43, 0xe8, 0x19, 0x6c, 0x5a, 0x17, 0x54, 0x3c, 0x87, 0x68, - 0x62, 0xd3, 0xbe, 0x25, 0xf3, 0x3d, 0x72, 0x67, 0xc7, 0x21, 0x5a, 0xbc, 0x51, 0xec, 0x17, 0xe2, - 0xc6, 0xf0, 0x1d, 0x30, 0xe9, 0x51, 0x4c, 0x7d, 0x8f, 0x6f, 0xd3, 0xcc, 0xcd, 0x6f, 0x1f, 0x4f, - 0xc3, 0xa1, 0xea, 0x9c, 0x20, 0x9a, 0x0c, 0x7e, 0x23, 0x41, 0xd1, 0xfa, 0x47, 0x09, 0xc0, 0x08, - 0xdb, 0xb5, 0xad, 0x9e, 0x4e, 0x59, 0xfc, 0xbe, 0x06, 0x2a, 0xf4, 0xc8, 0x21, 0x7c, 0x19, 0xa6, - 0xd5, 0xab, 0xa1, 0x17, 0x77, 0x8e, 0x1c, 0xf2, 0x78, 0xd0, 0x5c, 0xca, 0x5b, 0xb0, 0x1e, 0xc4, - 0x6d, 0xe0, 0x7a, 0xe4, 0x5f, 0x89, 0x5b, 0xdf, 0x4a, 0x0f, 0xfd, 0x78, 0xd0, 0x94, 0x1c, 0x16, - 0xed, 0x88, 0x29, 0xed, 0x20, 0x3c, 0x04, 0xd0, 0xc0, 0x1e, 0xbd, 0xe3, 0x62, 0xcb, 0x0b, 0x46, - 0xd2, 0x4d, 0x22, 0x66, 0xfe, 0xc2, 0x78, 0xdb, 0xc3, 0x2c, 0xd4, 0x8b, 0xc2, 0x0b, 0xb8, 0x9e, - 0x63, 0x43, 0x92, 0x11, 0xe0, 0x55, 0x30, 0xe9, 0x12, 0xec, 0xd9, 0x56, 0xbd, 0xc2, 0x67, 0x11, - 0x2d, 0x20, 0xe2, 0xad, 0x48, 0xf4, 0xc2, 0xe7, 0xc1, 0x94, 0x49, 0x3c, 0x0f, 0xf7, 0x49, 0xbd, - 0xca, 0x81, 0xf3, 0x02, 0x38, 0xb5, 0x11, 0x34, 0xa3, 0xb0, 0xbf, 0xf5, 0x3b, 0x05, 0xcc, 0x46, - 0x2b, 0x77, 0x06, 0xa9, 0xa2, 0xa6, 0x53, 0xe5, 0xd9, 0x63, 0xe3, 0xa4, 0x20, 0x43, 0x3e, 0x2a, - 0x27, 0x7c, 0x66, 0x41, 0x08, 0x7f, 0x02, 0x6a, 0x1e, 0x31, 0x88, 0x46, 0x6d, 0x57, 0xf8, 0xfc, - 0xd2, 0x98, 0x3e, 0xe3, 0x3d, 0x62, 0xec, 0x08, 0x53, 0xf5, 0x1c, 0x73, 0x3a, 0xfc, 0x85, 0x22, - 0x4a, 0xf8, 0x23, 0x50, 0xa3, 0xc4, 0x74, 0x0c, 0x4c, 0x89, 0x48, 0x93, 0x54, 0x7c, 0xb3, 0x70, - 0x61, 0x64, 0xdb, 0x76, 0xef, 0x8e, 0x80, 0xf1, 0x44, 0x89, 0xd6, 0x21, 0x6c, 0x45, 0x11, 0x0d, - 0x3c, 0x00, 0x73, 0xbe, 0xd3, 0x63, 0x48, 0xca, 0x8e, 0xee, 0xfe, 0x91, 0x08, 0x9f, 0x6b, 0xc7, - 0x2e, 0xc8, 0x6e, 0xca, 0x44, 0x5d, 0x12, 0x03, 0xcc, 0xa5, 0xdb, 0x51, 0x86, 0x1a, 0xae, 0x82, - 0x79, 0x53, 0xb7, 0x10, 0xc1, 0xbd, 0xa3, 0x1d, 0xa2, 0xd9, 0x56, 0xcf, 0xe3, 0x01, 0x54, 0x55, - 0x97, 0x05, 0xc1, 0xfc, 0x46, 0xba, 0x1b, 0x65, 0xf1, 0x70, 0x1d, 0x2c, 0x86, 0xe7, 0xec, 0x0f, - 0x74, 0x8f, 0xda, 0xee, 0xd1, 0xba, 0x6e, 0xea, 0xb4, 0x3e, 0xc9, 0x79, 0xea, 0xc3, 0x41, 0x73, - 0x11, 0x49, 0xfa, 0x91, 0xd4, 0xaa, 0xf5, 0xeb, 0x49, 0x30, 0x9f, 0x39, 0x0d, 0xe0, 0x5d, 0xb0, - 0xa4, 0xf9, 0xae, 0x4b, 0x2c, 0xba, 0xe9, 0x9b, 0x7b, 0xc4, 0xdd, 0xd1, 0xf6, 0x49, 0xcf, 0x37, - 0x48, 0x8f, 0xef, 0x68, 0x55, 0x6d, 0x08, 0x5f, 0x97, 0xba, 0x52, 0x14, 0x2a, 0xb0, 0x86, 0x3f, - 0x04, 0xd0, 0xe2, 0x4d, 0x1b, 0xba, 0xe7, 0x45, 0x9c, 0x25, 0xce, 0x19, 0x25, 0xe0, 0x66, 0x0e, - 0x81, 0x24, 0x56, 0xcc, 0xc7, 0x1e, 0xf1, 0x74, 0x97, 0xf4, 0xb2, 0x3e, 0x96, 0xd3, 0x3e, 0xae, - 0x49, 0x51, 0xa8, 0xc0, 0x1a, 0xbe, 0x0c, 0x66, 0x82, 0xd1, 0xf8, 0x9a, 0x8b, 0xcd, 0x59, 0x10, - 0x64, 0x33, 0x9b, 0x71, 0x17, 0x4a, 0xe2, 0xd8, 0xd4, 0xec, 0x3d, 0x8f, 0xb8, 0x87, 0xa4, 0xf7, - 0x56, 0xa0, 0x01, 0x58, 0xa1, 0xac, 0xf2, 0x42, 0x19, 0x4d, 0x6d, 0x2b, 0x87, 0x40, 0x12, 0x2b, - 0x36, 0xb5, 0x20, 0x6a, 0x72, 0x53, 0x9b, 0x4c, 0x4f, 0x6d, 0x57, 0x8a, 0x42, 0x05, 0xd6, 0x2c, - 0xf6, 0x02, 0x97, 0x57, 0x0f, 0xb1, 0x6e, 0xe0, 0x3d, 0x83, 0xd4, 0xa7, 0xd2, 0xb1, 0xb7, 0x99, - 0xee, 0x46, 0x59, 0x3c, 0x7c, 0x0b, 0x5c, 0x08, 0x9a, 0x76, 0x2d, 0x1c, 0x91, 0xd4, 0x38, 0xc9, - 0x33, 0x82, 0xe4, 0xc2, 0x66, 0x16, 0x80, 0xf2, 0x36, 0xf0, 0x35, 0x30, 0xa7, 0xd9, 0x86, 0xc1, - 0xe3, 0xb1, 0x6b, 0xfb, 0x16, 0xad, 0x4f, 0x73, 0x16, 0xc8, 0x72, 0xa8, 0x9b, 0xea, 0x41, 0x19, - 0x24, 0xbc, 0x07, 0x80, 0x16, 0x96, 0x03, 0xaf, 0x0e, 0x8a, 0x0b, 0x7d, 0xbe, 0x0e, 0xc5, 0x05, - 0x38, 0x6a, 0xf2, 0x50, 0x82, 0xad, 0xf5, 0x91, 0x02, 0x96, 0x0b, 0x72, 0x1c, 0xbe, 0x91, 0xaa, - 0x7a, 0xd7, 0x32, 0x55, 0xef, 0x52, 0x81, 0x59, 0xa2, 0xf4, 0x69, 0x60, 0x96, 0xe9, 0x0e, 0xdd, - 0xea, 0x07, 0x10, 0x71, 0x82, 0xbd, 0x20, 0xf3, 0x1d, 0x25, 0x81, 0xf1, 0x31, 0x7c, 0x61, 0x38, - 0x68, 0xce, 0xa6, 0xfa, 0x50, 0x9a, 0xb3, 0xf5, 0xcb, 0x12, 0x00, 0x6b, 0xc4, 0x31, 0xec, 0x23, - 0x93, 0x58, 0x67, 0xa1, 0x5a, 0xd6, 0x52, 0xaa, 0xa5, 0x25, 0xdd, 0x88, 0xc8, 0x9f, 0x42, 0xd9, - 0xb2, 0x9e, 0x91, 0x2d, 0x57, 0x46, 0xf0, 0x1c, 0xaf, 0x5b, 0xfe, 0x56, 0x06, 0x0b, 0x31, 0x38, - 0x16, 0x2e, 0xb7, 0x53, 0x5b, 0xf8, 0x5c, 0x66, 0x0b, 0x97, 0x25, 0x26, 0x5f, 0x98, 0x72, 0x79, - 0x1f, 0xcc, 0x31, 0x5d, 0x11, 0xec, 0x1a, 0x57, 0x2d, 0x93, 0x27, 0x56, 0x2d, 0x51, 0xd5, 0x59, - 0x4f, 0x31, 0xa1, 0x0c, 0x73, 0x81, 0x4a, 0x9a, 0xfa, 0x2a, 0xaa, 0xa4, 0xdf, 0x2b, 0x60, 0x2e, - 0xde, 0xa6, 0x33, 0x90, 0x49, 0xdd, 0xb4, 0x4c, 0x6a, 0x1c, 0x1f, 0x97, 0x05, 0x3a, 0xe9, 0xaf, - 0x95, 0xa4, 0xd7, 0x5c, 0x28, 0xad, 0xb0, 0x0b, 0x95, 0x63, 0xe8, 0x1a, 0xf6, 0x44, 0x59, 0x3d, - 0x17, 0x5c, 0xa6, 0x82, 0x36, 0x14, 0xf5, 0xa6, 0x24, 0x55, 0xe9, 0x8b, 0x95, 0x54, 0xe5, 0xcf, - 0x47, 0x52, 0xdd, 0x01, 0x35, 0x2f, 0x14, 0x53, 0x15, 0x4e, 0x79, 0x75, 0x54, 0x3a, 0x0b, 0x1d, - 0x15, 0xb1, 0x46, 0x0a, 0x2a, 0x62, 0x92, 0x69, 0xa7, 0xea, 0x97, 0xa9, 0x9d, 0x58, 0x78, 0x3b, - 0xd8, 0xf7, 0x48, 0x8f, 0xa7, 0x52, 0x2d, 0x0e, 0xef, 0x6d, 0xde, 0x8a, 0x44, 0x2f, 0xdc, 0x05, - 0xcb, 0x8e, 0x6b, 0xf7, 0x5d, 0xe2, 0x79, 0x6b, 0x04, 0xf7, 0x0c, 0xdd, 0x22, 0xe1, 0x04, 0x82, - 0xaa, 0x77, 0x69, 0x38, 0x68, 0x2e, 0x6f, 0xcb, 0x21, 0xa8, 0xc8, 0xb6, 0xf5, 0xc7, 0x0a, 0x38, - 0x9f, 0x3d, 0x11, 0x0b, 0x84, 0x88, 0x72, 0x2a, 0x21, 0xf2, 0x62, 0x22, 0x44, 0x03, 0x95, 0x96, - 0xb8, 0xf3, 0xe7, 0xc2, 0x74, 0x15, 0xcc, 0x0b, 0xe1, 0x11, 0x76, 0x0a, 0x29, 0x16, 0x6d, 0xcf, - 0x6e, 0xba, 0x1b, 0x65, 0xf1, 0xf0, 0x36, 0x98, 0x75, 0xb9, 0xb6, 0x0a, 0x09, 0x02, 0x7d, 0xf2, - 0x0d, 0x41, 0x30, 0x8b, 0x92, 0x9d, 0x28, 0x8d, 0x65, 0xda, 0x24, 0x96, 0x1c, 0x21, 0x41, 0x25, - 0xad, 0x4d, 0x56, 0xb3, 0x00, 0x94, 0xb7, 0x81, 0x1b, 0x60, 0xc1, 0xb7, 0xf2, 0x54, 0x41, 0xac, - 0x5d, 0x12, 0x54, 0x0b, 0xbb, 0x79, 0x08, 0x92, 0xd9, 0xc1, 0x1f, 0xa7, 0xe4, 0xca, 0x24, 0x3f, - 0x45, 0x9e, 0x3b, 0x3e, 0x1d, 0xc6, 0xd6, 0x2b, 0x12, 0x1d, 0x55, 0x1b, 0x57, 0x47, 0xb5, 0x3e, - 0x54, 0x00, 0xcc, 0xa7, 0xe0, 0xc8, 0xcb, 0x7d, 0xce, 0x22, 0x51, 0x22, 0x7b, 0x72, 0x85, 0x73, - 0x6d, 0xb4, 0xc2, 0x89, 0x4f, 0xd0, 0xf1, 0x24, 0x8e, 0x58, 0xde, 0xb3, 0x79, 0x98, 0x19, 0x43, - 0xe2, 0xc4, 0xfe, 0x3c, 0x99, 0xc4, 0x49, 0xf0, 0x1c, 0x2f, 0x71, 0xfe, 0x59, 0x02, 0x0b, 0x31, - 0x78, 0x6c, 0x89, 0x23, 0x31, 0x79, 0xfa, 0x38, 0x33, 0x9e, 0xec, 0x88, 0x97, 0xee, 0xff, 0x44, - 0x76, 0xc4, 0x0e, 0x15, 0xc8, 0x8e, 0xdf, 0x96, 0x92, 0x5e, 0x9f, 0x50, 0x76, 0x7c, 0x0e, 0x4f, - 0x15, 0x5f, 0x39, 0xe5, 0xd2, 0xfa, 0xb8, 0x0c, 0xce, 0x67, 0x53, 0x30, 0x55, 0x07, 0x95, 0x91, - 0x75, 0x70, 0x1b, 0x2c, 0xde, 0xf7, 0x0d, 0xe3, 0x88, 0xcf, 0x21, 0x51, 0x0c, 0x83, 0x0a, 0xfa, - 0x4d, 0x61, 0xb9, 0xf8, 0x7d, 0x09, 0x06, 0x49, 0x2d, 0xf3, 0x65, 0xb1, 0xf2, 0xa4, 0x65, 0xb1, - 0x7a, 0x8a, 0xb2, 0x28, 0x57, 0x16, 0xe5, 0x53, 0x29, 0x8b, 0xb1, 0x6b, 0xa2, 0xe4, 0xb8, 0x1a, - 0x79, 0x87, 0x1f, 0x2a, 0x60, 0x49, 0x7e, 0x7d, 0x86, 0x06, 0x98, 0x33, 0xf1, 0x83, 0xe4, 0xe3, - 0xc5, 0xa8, 0x82, 0xe1, 0x53, 0xdd, 0x68, 0x07, 0x5f, 0x77, 0xda, 0x6f, 0x5b, 0x74, 0xcb, 0xdd, - 0xa1, 0xae, 0x6e, 0xf5, 0x83, 0x02, 0xbb, 0x91, 0xe2, 0x42, 0x19, 0x6e, 0x78, 0x0f, 0xd4, 0x4c, - 0xfc, 0x60, 0xc7, 0x77, 0xfb, 0x61, 0x21, 0x3c, 0xf9, 0x38, 0x3c, 0xf6, 0x37, 0x04, 0x0b, 0x8a, - 0xf8, 0x5a, 0x9f, 0x29, 0x60, 0xb9, 0xa0, 0x82, 0x7e, 0x8d, 0x66, 0xb9, 0x05, 0x2e, 0xa7, 0x26, - 0xc9, 0x12, 0x92, 0xdc, 0xf7, 0x0d, 0x9e, 0x9b, 0x42, 0xaf, 0x5c, 0x03, 0xd3, 0x0e, 0x76, 0xa9, - 0x1e, 0x09, 0xdd, 0xaa, 0x3a, 0x3b, 0x1c, 0x34, 0xa7, 0xb7, 0xc3, 0x46, 0x14, 0xf7, 0xb7, 0x7e, - 0x55, 0x02, 0x33, 0x09, 0x92, 0x33, 0xd0, 0x0e, 0x6f, 0xa6, 0xb4, 0x83, 0xf4, 0x6b, 0x4c, 0x72, - 0x56, 0x45, 0xe2, 0x61, 0x23, 0x23, 0x1e, 0xbe, 0x33, 0x8a, 0xe8, 0x78, 0xf5, 0xf0, 0xaf, 0x12, - 0x58, 0x4c, 0xa0, 0x63, 0xf9, 0xf0, 0xbd, 0x94, 0x7c, 0x58, 0xc9, 0xc8, 0x87, 0xba, 0xcc, 0xe6, - 0xa9, 0x7e, 0x18, 0xad, 0x1f, 0xfe, 0xa0, 0x80, 0xf9, 0xc4, 0xda, 0x9d, 0x81, 0x80, 0x58, 0x4b, - 0x0b, 0x88, 0xe6, 0x88, 0x78, 0x29, 0x50, 0x10, 0xff, 0x56, 0x40, 0x27, 0x81, 0xda, 0x26, 0xae, - 0xa7, 0x7b, 0x94, 0x58, 0xf4, 0xae, 0x6d, 0xf8, 0x26, 0xe9, 0x1a, 0x58, 0x37, 0x11, 0x61, 0x0d, - 0xba, 0x6d, 0x6d, 0xdb, 0x86, 0xae, 0x1d, 0x41, 0x0c, 0x66, 0x3e, 0xd8, 0x27, 0xd6, 0x1a, 0x31, - 0x08, 0x15, 0xdf, 0x0c, 0xa6, 0xd5, 0x37, 0xc2, 0x27, 0xf4, 0x77, 0xe3, 0xae, 0xc7, 0x83, 0xe6, - 0xca, 0x38, 0x8c, 0x3c, 0xc0, 0x92, 0x9c, 0xf0, 0xa7, 0x00, 0xb0, 0x9f, 0x3b, 0x1a, 0x0e, 0xbf, - 0x20, 0x4c, 0xab, 0xaf, 0x87, 0x69, 0xf8, 0x6e, 0xd4, 0x73, 0xa2, 0x01, 0x12, 0x8c, 0xad, 0xbf, - 0x4c, 0xa5, 0xb6, 0xeb, 0x6b, 0xff, 0x60, 0xf3, 0x73, 0xb0, 0x78, 0x18, 0xaf, 0x4e, 0x08, 0x60, - 0x42, 0x83, 0xc5, 0xce, 0xf3, 0x52, 0x7a, 0xd9, 0xba, 0xc6, 0xf2, 0xe6, 0xae, 0x84, 0x0e, 0x49, - 0x07, 0x81, 0x2f, 0x83, 0x19, 0x26, 0x10, 0x74, 0x8d, 0x6c, 0x62, 0x33, 0x4c, 0xa5, 0xe8, 0x93, - 0xcb, 0x4e, 0xdc, 0x85, 0x92, 0x38, 0xb8, 0x0f, 0x16, 0x1c, 0xbb, 0xb7, 0x81, 0x2d, 0xdc, 0x27, - 0xac, 0xec, 0x05, 0x5b, 0xc9, 0x9f, 0x72, 0xa6, 0xd5, 0x57, 0xc2, 0x6b, 0xfa, 0x76, 0x1e, 0xc2, - 0xae, 0x41, 0x92, 0x66, 0x1e, 0x04, 0x32, 0x4a, 0x68, 0xe6, 0xbe, 0x10, 0x4e, 0xe5, 0xfe, 0xad, - 0x42, 0x96, 0x53, 0xa7, 0xfc, 0x46, 0x58, 0xf4, 0x48, 0x55, 0x3b, 0xd5, 0x23, 0x95, 0x44, 0xc6, - 0x4f, 0x9f, 0x50, 0xc6, 0x7f, 0xac, 0x80, 0x2b, 0xce, 0x18, 0x69, 0x54, 0x07, 0x7c, 0x59, 0xba, - 0x23, 0x96, 0x65, 0x9c, 0x8c, 0x54, 0x57, 0x86, 0x83, 0xe6, 0x95, 0x71, 0x90, 0x68, 0x2c, 0xd7, - 0x5a, 0x1f, 0x56, 0xc1, 0x85, 0x5c, 0x79, 0xfc, 0x12, 0x5f, 0xcb, 0x72, 0x9a, 0xbe, 0x7c, 0x02, - 0x4d, 0xbf, 0x0a, 0xe6, 0xc5, 0x27, 0xd6, 0xcc, 0x95, 0x20, 0xda, 0xd3, 0x6e, 0xba, 0x1b, 0x65, - 0xf1, 0xb2, 0xd7, 0xba, 0xea, 0x09, 0x5f, 0xeb, 0x92, 0x5e, 0x88, 0xff, 0x0c, 0x0a, 0x92, 0x2f, - 0xef, 0x85, 0xf8, 0x07, 0xa1, 0x2c, 0x1e, 0xbe, 0x1e, 0x66, 0x56, 0xc4, 0x30, 0xc5, 0x19, 0x32, - 0xa9, 0x12, 0x11, 0x64, 0xd0, 0x4f, 0xf4, 0x19, 0xf1, 0x3d, 0xc9, 0x67, 0xc4, 0x95, 0x11, 0xa1, - 0x3b, 0xfe, 0xc3, 0x9c, 0xf4, 0xda, 0x35, 0x73, 0xf2, 0x6b, 0x57, 0xeb, 0xcf, 0x0a, 0x78, 0xa6, - 0xf0, 0x4c, 0x81, 0xab, 0x29, 0xb9, 0x76, 0x3d, 0x23, 0xd7, 0x9e, 0x2d, 0x34, 0x4c, 0x68, 0x36, - 0x53, 0xfe, 0x66, 0x77, 0x6b, 0xe4, 0x9b, 0x9d, 0x44, 0x8c, 0x8f, 0x7e, 0xbc, 0x53, 0x5f, 0x7d, - 0xf8, 0xa8, 0x31, 0xf1, 0xc9, 0xa3, 0xc6, 0xc4, 0xa7, 0x8f, 0x1a, 0x13, 0xbf, 0x18, 0x36, 0x94, - 0x87, 0xc3, 0x86, 0xf2, 0xc9, 0xb0, 0xa1, 0x7c, 0x3a, 0x6c, 0x28, 0x7f, 0x1f, 0x36, 0x94, 0xdf, - 0x7c, 0xd6, 0x98, 0xb8, 0x07, 0xf3, 0xff, 0x97, 0xf8, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x75, - 0x73, 0xb6, 0x6e, 0xc5, 0x28, 0x00, 0x00, + 0x75, 0x94, 0x38, 0xde, 0xad, 0x1d, 0x27, 0x08, 0xe2, 0x22, 0x81, 0x66, 0x95, 0xa6, 0x69, 0x24, + 0x59, 0xa5, 0x2c, 0x07, 0x70, 0xd3, 0xa2, 0xd4, 0x2c, 0xbd, 0x9a, 0x68, 0xbe, 0x30, 0xc3, 0x51, + 0x2c, 0xf4, 0x52, 0x14, 0xe8, 0xad, 0x87, 0xfe, 0x27, 0x45, 0x51, 0x34, 0xb7, 0x20, 0x08, 0x7a, + 0xf1, 0xa5, 0x68, 0xd0, 0x4b, 0x73, 0x5a, 0xd4, 0x9b, 0x53, 0x51, 0xf4, 0xd6, 0x5e, 0x7c, 0x69, + 0x41, 0x0e, 0xe7, 0x9b, 0xa3, 0x5d, 0xc9, 0xb1, 0xf2, 0x01, 0xdf, 0xb4, 0xe4, 0xef, 0xfd, 0xf8, + 0x48, 0xbe, 0xc7, 0xf7, 0x23, 0x47, 0xe0, 0xe6, 0xfe, 0xab, 0x5e, 0x5b, 0xb7, 0x3b, 0xfb, 0xfe, + 0x2e, 0x71, 0x2d, 0x42, 0x89, 0xd7, 0x39, 0x20, 0x56, 0xcf, 0x76, 0x3b, 0xa2, 0x03, 0x3b, 0x7a, + 0x07, 0x3b, 0x8e, 0xd7, 0x39, 0xb8, 0xd6, 0xe9, 0x13, 0x8b, 0xb8, 0x98, 0x92, 0x5e, 0xdb, 0x71, + 0x6d, 0x6a, 0x43, 0x18, 0x60, 0xda, 0xd8, 0xd1, 0xdb, 0x0c, 0xd3, 0x3e, 0xb8, 0x76, 0xfe, 0x6a, + 0x5f, 0xa7, 0x7b, 0xfe, 0x6e, 0x5b, 0xb3, 0xcd, 0x4e, 0xdf, 0xee, 0xdb, 0x1d, 0x0e, 0xdd, 0xf5, + 0xef, 0xf1, 0x5f, 0xfc, 0x07, 0xff, 0x2b, 0xa0, 0x38, 0xdf, 0x4a, 0x0c, 0xa3, 0xd9, 0x2e, 0x91, + 0x0c, 0x73, 0xfe, 0x46, 0x8c, 0x31, 0xb1, 0xb6, 0xa7, 0x5b, 0xc4, 0x3d, 0xec, 0x38, 0xfb, 0x7d, + 0xd6, 0xe0, 0x75, 0x4c, 0x42, 0xb1, 0xcc, 0xaa, 0x53, 0x64, 0xe5, 0xfa, 0x16, 0xd5, 0x4d, 0x92, + 0x33, 0x78, 0x65, 0x94, 0x81, 0xa7, 0xed, 0x11, 0x13, 0xe7, 0xec, 0x5e, 0x2a, 0xb2, 0xf3, 0xa9, + 0x6e, 0x74, 0x74, 0x8b, 0x7a, 0xd4, 0xcd, 0x1a, 0xb5, 0xfe, 0xab, 0x00, 0xd8, 0xb5, 0x2d, 0xea, + 0xda, 0x86, 0x41, 0x5c, 0x44, 0x0e, 0x74, 0x4f, 0xb7, 0x2d, 0xf8, 0x0b, 0x50, 0x63, 0xf3, 0xe9, + 0x61, 0x8a, 0xeb, 0xca, 0x45, 0x65, 0x65, 0xe6, 0xfa, 0xf7, 0xdb, 0xf1, 0x22, 0x47, 0xf4, 0x6d, + 0x67, 0xbf, 0xcf, 0x1a, 0xbc, 0x36, 0x43, 0xb7, 0x0f, 0xae, 0xb5, 0x6f, 0xed, 0xbe, 0x4f, 0x34, + 0xba, 0x41, 0x28, 0x56, 0xe1, 0x83, 0x41, 0x73, 0x62, 0x38, 0x68, 0x82, 0xb8, 0x0d, 0x45, 0xac, + 0xf0, 0x16, 0xa8, 0x70, 0xf6, 0x12, 0x67, 0xbf, 0x5a, 0xc8, 0x2e, 0x26, 0xdd, 0x46, 0xf8, 0x83, + 0x37, 0xef, 0x53, 0x62, 0x31, 0xf7, 0xd4, 0x33, 0x82, 0xba, 0xb2, 0x86, 0x29, 0x46, 0x9c, 0x08, + 0xbe, 0x08, 0x6a, 0xae, 0x70, 0xbf, 0x5e, 0xbe, 0xa8, 0xac, 0x94, 0xd5, 0xb3, 0x02, 0x55, 0x0b, + 0xa7, 0x85, 0x22, 0x44, 0xeb, 0xcf, 0x0a, 0x58, 0xca, 0xcf, 0x7b, 0x5d, 0xf7, 0x28, 0x7c, 0x2f, + 0x37, 0xf7, 0xf6, 0x78, 0x73, 0x67, 0xd6, 0x7c, 0xe6, 0xd1, 0xc0, 0x61, 0x4b, 0x62, 0xde, 0xef, + 0x80, 0xaa, 0x4e, 0x89, 0xe9, 0xd5, 0x4b, 0x17, 0xcb, 0x2b, 0x33, 0xd7, 0x2f, 0xb7, 0xf3, 0xb1, + 0xdb, 0xce, 0x3b, 0xa6, 0xce, 0x0a, 0xca, 0xea, 0xdb, 0xcc, 0x18, 0x05, 0x1c, 0xad, 0xff, 0x29, + 0x60, 0x7a, 0x0d, 0x13, 0xd3, 0xb6, 0xb6, 0x09, 0x3d, 0x85, 0x4d, 0xeb, 0x82, 0x8a, 0xe7, 0x10, + 0x4d, 0x6c, 0xda, 0x77, 0x64, 0xbe, 0x47, 0xee, 0x6c, 0x3b, 0x44, 0x8b, 0x37, 0x8a, 0xfd, 0x42, + 0xdc, 0x18, 0xbe, 0x03, 0x26, 0x3d, 0x8a, 0xa9, 0xef, 0xf1, 0x6d, 0x9a, 0xb9, 0xfe, 0xdd, 0xa3, + 0x69, 0x38, 0x54, 0x9d, 0x13, 0x44, 0x93, 0xc1, 0x6f, 0x24, 0x28, 0x5a, 0xff, 0x2c, 0x01, 0x18, + 0x61, 0xbb, 0xb6, 0xd5, 0xd3, 0x29, 0x8b, 0xdf, 0xd7, 0x40, 0x85, 0x1e, 0x3a, 0x84, 0x2f, 0xc3, + 0xb4, 0x7a, 0x39, 0xf4, 0xe2, 0xf6, 0xa1, 0x43, 0x1e, 0x0d, 0x9a, 0x4b, 0x79, 0x0b, 0xd6, 0x83, + 0xb8, 0x0d, 0x5c, 0x8f, 0xfc, 0x2b, 0x71, 0xeb, 0x1b, 0xe9, 0xa1, 0x1f, 0x0d, 0x9a, 0x92, 0xc3, + 0xa2, 0x1d, 0x31, 0xa5, 0x1d, 0x84, 0x07, 0x00, 0x1a, 0xd8, 0xa3, 0xb7, 0x5d, 0x6c, 0x79, 0xc1, + 0x48, 0xba, 0x49, 0xc4, 0xcc, 0x5f, 0x18, 0x6f, 0x7b, 0x98, 0x85, 0x7a, 0x5e, 0x78, 0x01, 0xd7, + 0x73, 0x6c, 0x48, 0x32, 0x02, 0xbc, 0x0c, 0x26, 0x5d, 0x82, 0x3d, 0xdb, 0xaa, 0x57, 0xf8, 0x2c, + 0xa2, 0x05, 0x44, 0xbc, 0x15, 0x89, 0x5e, 0xf8, 0x3c, 0x98, 0x32, 0x89, 0xe7, 0xe1, 0x3e, 0xa9, + 0x57, 0x39, 0x70, 0x5e, 0x00, 0xa7, 0x36, 0x82, 0x66, 0x14, 0xf6, 0xb7, 0xfe, 0xa0, 0x80, 0xd9, + 0x68, 0xe5, 0x4e, 0x21, 0x55, 0xd4, 0x74, 0xaa, 0x3c, 0x7b, 0x64, 0x9c, 0x14, 0x64, 0xc8, 0xc7, + 0xe5, 0x84, 0xcf, 0x2c, 0x08, 0xe1, 0xcf, 0x40, 0xcd, 0x23, 0x06, 0xd1, 0xa8, 0xed, 0x0a, 0x9f, + 0x5f, 0x1a, 0xd3, 0x67, 0xbc, 0x4b, 0x8c, 0x6d, 0x61, 0xaa, 0x9e, 0x61, 0x4e, 0x87, 0xbf, 0x50, + 0x44, 0x09, 0x7f, 0x02, 0x6a, 0x94, 0x98, 0x8e, 0x81, 0x29, 0x11, 0x69, 0x92, 0x8a, 0x6f, 0x16, + 0x2e, 0x8c, 0x6c, 0xcb, 0xee, 0xdd, 0x16, 0x30, 0x9e, 0x28, 0xd1, 0x3a, 0x84, 0xad, 0x28, 0xa2, + 0x81, 0xfb, 0x60, 0xce, 0x77, 0x7a, 0x0c, 0x49, 0xd9, 0xd1, 0xdd, 0x3f, 0x14, 0xe1, 0x73, 0xe5, + 0xc8, 0x05, 0xd9, 0x49, 0x99, 0xa8, 0x4b, 0x62, 0x80, 0xb9, 0x74, 0x3b, 0xca, 0x50, 0xc3, 0x55, + 0x30, 0x6f, 0xea, 0x16, 0x22, 0xb8, 0x77, 0xb8, 0x4d, 0x34, 0xdb, 0xea, 0x79, 0x3c, 0x80, 0xaa, + 0xea, 0xb2, 0x20, 0x98, 0xdf, 0x48, 0x77, 0xa3, 0x2c, 0x1e, 0xae, 0x83, 0xc5, 0xf0, 0x9c, 0xfd, + 0x91, 0xee, 0x51, 0xdb, 0x3d, 0x5c, 0xd7, 0x4d, 0x9d, 0xd6, 0x27, 0x39, 0x4f, 0x7d, 0x38, 0x68, + 0x2e, 0x22, 0x49, 0x3f, 0x92, 0x5a, 0xb5, 0x7e, 0x3b, 0x09, 0xe6, 0x33, 0xa7, 0x01, 0xbc, 0x03, + 0x96, 0x34, 0xdf, 0x75, 0x89, 0x45, 0x37, 0x7d, 0x73, 0x97, 0xb8, 0xdb, 0xda, 0x1e, 0xe9, 0xf9, + 0x06, 0xe9, 0xf1, 0x1d, 0xad, 0xaa, 0x0d, 0xe1, 0xeb, 0x52, 0x57, 0x8a, 0x42, 0x05, 0xd6, 0xf0, + 0xc7, 0x00, 0x5a, 0xbc, 0x69, 0x43, 0xf7, 0xbc, 0x88, 0xb3, 0xc4, 0x39, 0xa3, 0x04, 0xdc, 0xcc, + 0x21, 0x90, 0xc4, 0x8a, 0xf9, 0xd8, 0x23, 0x9e, 0xee, 0x92, 0x5e, 0xd6, 0xc7, 0x72, 0xda, 0xc7, + 0x35, 0x29, 0x0a, 0x15, 0x58, 0xc3, 0x97, 0xc1, 0x4c, 0x30, 0x1a, 0x5f, 0x73, 0xb1, 0x39, 0x0b, + 0x82, 0x6c, 0x66, 0x33, 0xee, 0x42, 0x49, 0x1c, 0x9b, 0x9a, 0xbd, 0xeb, 0x11, 0xf7, 0x80, 0xf4, + 0xde, 0x0a, 0x34, 0x00, 0x2b, 0x94, 0x55, 0x5e, 0x28, 0xa3, 0xa9, 0xdd, 0xca, 0x21, 0x90, 0xc4, + 0x8a, 0x4d, 0x2d, 0x88, 0x9a, 0xdc, 0xd4, 0x26, 0xd3, 0x53, 0xdb, 0x91, 0xa2, 0x50, 0x81, 0x35, + 0x8b, 0xbd, 0xc0, 0xe5, 0xd5, 0x03, 0xac, 0x1b, 0x78, 0xd7, 0x20, 0xf5, 0xa9, 0x74, 0xec, 0x6d, + 0xa6, 0xbb, 0x51, 0x16, 0x0f, 0xdf, 0x02, 0xe7, 0x82, 0xa6, 0x1d, 0x0b, 0x47, 0x24, 0x35, 0x4e, + 0xf2, 0x8c, 0x20, 0x39, 0xb7, 0x99, 0x05, 0xa0, 0xbc, 0x0d, 0x7c, 0x0d, 0xcc, 0x69, 0xb6, 0x61, + 0xf0, 0x78, 0xec, 0xda, 0xbe, 0x45, 0xeb, 0xd3, 0x9c, 0x05, 0xb2, 0x1c, 0xea, 0xa6, 0x7a, 0x50, + 0x06, 0x09, 0xef, 0x02, 0xa0, 0x85, 0xe5, 0xc0, 0xab, 0x83, 0xe2, 0x42, 0x9f, 0xaf, 0x43, 0x71, + 0x01, 0x8e, 0x9a, 0x3c, 0x94, 0x60, 0x6b, 0x7d, 0xac, 0x80, 0xe5, 0x82, 0x1c, 0x87, 0x6f, 0xa4, + 0xaa, 0xde, 0x95, 0x4c, 0xd5, 0xbb, 0x50, 0x60, 0x96, 0x28, 0x7d, 0x1a, 0x98, 0x65, 0xba, 0x43, + 0xb7, 0xfa, 0x01, 0x44, 0x9c, 0x60, 0x2f, 0xc8, 0x7c, 0x47, 0x49, 0x60, 0x7c, 0x0c, 0x9f, 0x1b, + 0x0e, 0x9a, 0xb3, 0xa9, 0x3e, 0x94, 0xe6, 0x6c, 0xfd, 0xba, 0x04, 0xc0, 0x1a, 0x71, 0x0c, 0xfb, + 0xd0, 0x24, 0xd6, 0x69, 0xa8, 0x96, 0xb5, 0x94, 0x6a, 0x69, 0x49, 0x37, 0x22, 0xf2, 0xa7, 0x50, + 0xb6, 0xac, 0x67, 0x64, 0xcb, 0xa5, 0x11, 0x3c, 0x47, 0xeb, 0x96, 0xbf, 0x97, 0xc1, 0x42, 0x0c, + 0x8e, 0x85, 0xcb, 0xcd, 0xd4, 0x16, 0x3e, 0x97, 0xd9, 0xc2, 0x65, 0x89, 0xc9, 0x13, 0x53, 0x2e, + 0xef, 0x83, 0x39, 0xa6, 0x2b, 0x82, 0x5d, 0xe3, 0xaa, 0x65, 0xf2, 0xd8, 0xaa, 0x25, 0xaa, 0x3a, + 0xeb, 0x29, 0x26, 0x94, 0x61, 0x2e, 0x50, 0x49, 0x53, 0x5f, 0x47, 0x95, 0xf4, 0x47, 0x05, 0xcc, + 0xc5, 0xdb, 0x74, 0x0a, 0x32, 0xa9, 0x9b, 0x96, 0x49, 0x8d, 0xa3, 0xe3, 0xb2, 0x40, 0x27, 0xfd, + 0xad, 0x92, 0xf4, 0x9a, 0x0b, 0xa5, 0x15, 0x76, 0xa1, 0x72, 0x0c, 0x5d, 0xc3, 0x9e, 0x28, 0xab, + 0x67, 0x82, 0xcb, 0x54, 0xd0, 0x86, 0xa2, 0xde, 0x94, 0xa4, 0x2a, 0x3d, 0x59, 0x49, 0x55, 0xfe, + 0x62, 0x24, 0xd5, 0x6d, 0x50, 0xf3, 0x42, 0x31, 0x55, 0xe1, 0x94, 0x97, 0x47, 0xa5, 0xb3, 0xd0, + 0x51, 0x11, 0x6b, 0xa4, 0xa0, 0x22, 0x26, 0x99, 0x76, 0xaa, 0x7e, 0x99, 0xda, 0x89, 0x85, 0xb7, + 0x83, 0x7d, 0x8f, 0xf4, 0x78, 0x2a, 0xd5, 0xe2, 0xf0, 0xde, 0xe2, 0xad, 0x48, 0xf4, 0xc2, 0x1d, + 0xb0, 0xec, 0xb8, 0x76, 0xdf, 0x25, 0x9e, 0xb7, 0x46, 0x70, 0xcf, 0xd0, 0x2d, 0x12, 0x4e, 0x20, + 0xa8, 0x7a, 0x17, 0x86, 0x83, 0xe6, 0xf2, 0x96, 0x1c, 0x82, 0x8a, 0x6c, 0x5b, 0x1f, 0x55, 0xc0, + 0xd9, 0xec, 0x89, 0x58, 0x20, 0x44, 0x94, 0x13, 0x09, 0x91, 0x17, 0x13, 0x21, 0x1a, 0xa8, 0xb4, + 0xc4, 0x9d, 0x3f, 0x17, 0xa6, 0xab, 0x60, 0x5e, 0x08, 0x8f, 0xb0, 0x53, 0x48, 0xb1, 0x68, 0x7b, + 0x76, 0xd2, 0xdd, 0x28, 0x8b, 0x87, 0x37, 0xc1, 0xac, 0xcb, 0xb5, 0x55, 0x48, 0x10, 0xe8, 0x93, + 0x6f, 0x09, 0x82, 0x59, 0x94, 0xec, 0x44, 0x69, 0x2c, 0xd3, 0x26, 0xb1, 0xe4, 0x08, 0x09, 0x2a, + 0x69, 0x6d, 0xb2, 0x9a, 0x05, 0xa0, 0xbc, 0x0d, 0xdc, 0x00, 0x0b, 0xbe, 0x95, 0xa7, 0x0a, 0x62, + 0xed, 0x82, 0xa0, 0x5a, 0xd8, 0xc9, 0x43, 0x90, 0xcc, 0x0e, 0xfe, 0x34, 0x25, 0x57, 0x26, 0xf9, + 0x29, 0xf2, 0xdc, 0xd1, 0xe9, 0x30, 0xb6, 0x5e, 0x91, 0xe8, 0xa8, 0xda, 0xb8, 0x3a, 0xaa, 0xf5, + 0xa1, 0x02, 0x60, 0x3e, 0x05, 0x47, 0x5e, 0xee, 0x73, 0x16, 0x89, 0x12, 0xd9, 0x93, 0x2b, 0x9c, + 0x2b, 0xa3, 0x15, 0x4e, 0x7c, 0x82, 0x8e, 0x27, 0x71, 0xc4, 0xf2, 0x9e, 0xce, 0xc3, 0xcc, 0x18, + 0x12, 0x27, 0xf6, 0xe7, 0xf1, 0x24, 0x4e, 0x82, 0xe7, 0x68, 0x89, 0xf3, 0xaf, 0x12, 0x58, 0x88, + 0xc1, 0x63, 0x4b, 0x1c, 0x89, 0xc9, 0xd3, 0xc7, 0x99, 0xf1, 0x64, 0x47, 0xbc, 0x74, 0x5f, 0x11, + 0xd9, 0x11, 0x3b, 0x54, 0x20, 0x3b, 0x7e, 0x5f, 0x4a, 0x7a, 0x7d, 0x4c, 0xd9, 0xf1, 0x05, 0x3c, + 0x55, 0x7c, 0xed, 0x94, 0x4b, 0xeb, 0x93, 0x32, 0x38, 0x9b, 0x4d, 0xc1, 0x54, 0x1d, 0x54, 0x46, + 0xd6, 0xc1, 0x2d, 0xb0, 0x78, 0xcf, 0x37, 0x8c, 0x43, 0x3e, 0x87, 0x44, 0x31, 0x0c, 0x2a, 0xe8, + 0xb7, 0x85, 0xe5, 0xe2, 0x0f, 0x25, 0x18, 0x24, 0xb5, 0xcc, 0x97, 0xc5, 0xca, 0xe3, 0x96, 0xc5, + 0xea, 0x09, 0xca, 0xa2, 0x5c, 0x59, 0x94, 0x4f, 0xa4, 0x2c, 0xc6, 0xae, 0x89, 0x92, 0xe3, 0x6a, + 0xe4, 0x1d, 0x7e, 0xa8, 0x80, 0x25, 0xf9, 0xf5, 0x19, 0x1a, 0x60, 0xce, 0xc4, 0xf7, 0x93, 0x8f, + 0x17, 0xa3, 0x0a, 0x86, 0x4f, 0x75, 0xa3, 0x1d, 0x7c, 0xdd, 0x69, 0xbf, 0x6d, 0xd1, 0x5b, 0xee, + 0x36, 0x75, 0x75, 0xab, 0x1f, 0x14, 0xd8, 0x8d, 0x14, 0x17, 0xca, 0x70, 0xc3, 0xbb, 0xa0, 0x66, + 0xe2, 0xfb, 0xdb, 0xbe, 0xdb, 0x0f, 0x0b, 0xe1, 0xf1, 0xc7, 0xe1, 0xb1, 0xbf, 0x21, 0x58, 0x50, + 0xc4, 0xd7, 0xfa, 0x5c, 0x01, 0xcb, 0x05, 0x15, 0xf4, 0x1b, 0x34, 0xcb, 0x8f, 0x14, 0x70, 0x31, + 0x35, 0x4b, 0x96, 0x91, 0xe4, 0x9e, 0x6f, 0xf0, 0xe4, 0x14, 0x82, 0xe5, 0x0a, 0x98, 0x76, 0xb0, + 0x4b, 0xf5, 0x48, 0xe9, 0x56, 0xd5, 0xd9, 0xe1, 0xa0, 0x39, 0xbd, 0x15, 0x36, 0xa2, 0xb8, 0x5f, + 0xb2, 0x36, 0xa5, 0x27, 0xb7, 0x36, 0xad, 0xdf, 0x94, 0xc0, 0x4c, 0xc2, 0xe5, 0x53, 0x90, 0x2a, + 0x6f, 0xa6, 0xa4, 0x8a, 0xf4, 0xe3, 0x4f, 0x72, 0x0d, 0x8b, 0xb4, 0xca, 0x46, 0x46, 0xab, 0x7c, + 0x6f, 0x14, 0xd1, 0xd1, 0x62, 0xe5, 0xdf, 0x25, 0xb0, 0x98, 0x40, 0xc7, 0x6a, 0xe5, 0x07, 0x29, + 0xb5, 0xb2, 0x92, 0x51, 0x2b, 0x75, 0x99, 0xcd, 0x53, 0xb9, 0x32, 0x5a, 0xae, 0xfc, 0x49, 0x01, + 0xf3, 0x89, 0xb5, 0x3b, 0x05, 0xbd, 0xb2, 0x96, 0xd6, 0x2b, 0xcd, 0x11, 0xf1, 0x52, 0x20, 0x58, + 0xfe, 0xa3, 0x80, 0x4e, 0x02, 0xb5, 0x45, 0x5c, 0x4f, 0xf7, 0x28, 0xb1, 0xe8, 0x1d, 0xdb, 0xf0, + 0x4d, 0xd2, 0x35, 0xb0, 0x6e, 0x22, 0xc2, 0x1a, 0x74, 0xdb, 0xda, 0xb2, 0x0d, 0x5d, 0x3b, 0x84, + 0x18, 0xcc, 0x7c, 0xb0, 0x47, 0xac, 0x35, 0x62, 0x10, 0x2a, 0x3e, 0x51, 0x4c, 0xab, 0x6f, 0x84, + 0x2f, 0xf6, 0xef, 0xc6, 0x5d, 0x8f, 0x06, 0xcd, 0x95, 0x71, 0x18, 0x79, 0x80, 0x25, 0x39, 0xe1, + 0xcf, 0x01, 0x60, 0x3f, 0xb7, 0x35, 0x1c, 0x7e, 0xb0, 0x98, 0x56, 0x5f, 0x0f, 0xd3, 0xf0, 0xdd, + 0xa8, 0xe7, 0x58, 0x03, 0x24, 0x18, 0x5b, 0x7f, 0x9d, 0x4a, 0x6d, 0xd7, 0x37, 0xfe, 0x7d, 0xe8, + 0x97, 0x60, 0xf1, 0x20, 0x5e, 0x9d, 0x10, 0xc0, 0x74, 0x0d, 0x8b, 0x9d, 0xe7, 0xa5, 0xf4, 0xb2, + 0x75, 0x8d, 0xd5, 0xd4, 0x1d, 0x09, 0x1d, 0x92, 0x0e, 0x02, 0x5f, 0x06, 0x33, 0x4c, 0x8f, 0xe8, + 0x1a, 0xd9, 0xc4, 0x66, 0x98, 0x4a, 0xd1, 0x17, 0x9e, 0xed, 0xb8, 0x0b, 0x25, 0x71, 0x70, 0x0f, + 0x2c, 0x38, 0x76, 0x6f, 0x03, 0x5b, 0xb8, 0x4f, 0x58, 0x95, 0x0d, 0xb6, 0x92, 0xbf, 0x1c, 0x4d, + 0xab, 0xaf, 0x84, 0xaf, 0x02, 0x5b, 0x79, 0x08, 0xbb, 0x75, 0x49, 0x9a, 0x79, 0x10, 0xc8, 0x28, + 0xa1, 0x99, 0xfb, 0x20, 0x39, 0x95, 0xfb, 0x2f, 0x0e, 0x59, 0x4e, 0x9d, 0xf0, 0x93, 0x64, 0xd1, + 0x9b, 0x58, 0xed, 0x44, 0x6f, 0x62, 0x92, 0x5b, 0xc3, 0xf4, 0x31, 0x6f, 0x0d, 0x9f, 0x28, 0xe0, + 0x92, 0x33, 0x46, 0x1a, 0xd5, 0x01, 0x5f, 0x96, 0xee, 0x88, 0x65, 0x19, 0x27, 0x23, 0xd5, 0x95, + 0xe1, 0xa0, 0x79, 0x69, 0x1c, 0x24, 0x1a, 0xcb, 0xb5, 0xd6, 0x87, 0x55, 0x70, 0x2e, 0x57, 0x1e, + 0xbf, 0xc4, 0xc7, 0xb9, 0xdc, 0x15, 0xa2, 0x7c, 0x8c, 0x2b, 0xc4, 0x2a, 0x98, 0x17, 0x5f, 0x74, + 0x33, 0x37, 0x90, 0x68, 0x4f, 0xbb, 0xe9, 0x6e, 0x94, 0xc5, 0xcb, 0x1e, 0x07, 0xab, 0xc7, 0x7c, + 0x1c, 0x4c, 0x7a, 0x21, 0xfe, 0x11, 0x29, 0x48, 0xbe, 0xbc, 0x17, 0xe2, 0xff, 0x91, 0xb2, 0x78, + 0xf8, 0x7a, 0x98, 0x59, 0x11, 0xc3, 0x14, 0x67, 0xc8, 0xa4, 0x4a, 0x44, 0x90, 0x41, 0x3f, 0xd6, + 0x57, 0xcb, 0xf7, 0x24, 0x5f, 0x2d, 0x57, 0x46, 0x84, 0xee, 0xf8, 0xef, 0x80, 0xd2, 0x5b, 0xde, + 0xcc, 0xf1, 0x6f, 0x79, 0xad, 0xbf, 0x28, 0xe0, 0x99, 0xc2, 0x33, 0x05, 0xae, 0xa6, 0xe4, 0xda, + 0xd5, 0x8c, 0x5c, 0x7b, 0xb6, 0xd0, 0x30, 0xa1, 0xd9, 0x4c, 0xf9, 0x13, 0xe1, 0x8d, 0x91, 0x4f, + 0x84, 0x12, 0xe9, 0x3f, 0xfa, 0xad, 0x50, 0x7d, 0xf5, 0xc1, 0xc3, 0xc6, 0xc4, 0xa7, 0x0f, 0x1b, + 0x13, 0x9f, 0x3d, 0x6c, 0x4c, 0xfc, 0x6a, 0xd8, 0x50, 0x1e, 0x0c, 0x1b, 0xca, 0xa7, 0xc3, 0x86, + 0xf2, 0xd9, 0xb0, 0xa1, 0xfc, 0x63, 0xd8, 0x50, 0x7e, 0xf7, 0x79, 0x63, 0xe2, 0x2e, 0xcc, 0xff, + 0x1b, 0xe4, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x92, 0xcf, 0x5d, 0xcc, 0x34, 0x29, 0x00, 0x00, } func (m *ControllerRevision) Marshal() (dAtA []byte, err error) { @@ -2168,6 +2168,18 @@ func (m *RollingUpdateStatefulSetStrategy) MarshalToSizedBuffer(dAtA []byte) (in _ = i var l int _ = l + if m.MaxUnavailable != nil { + { + size, err := m.MaxUnavailable.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if m.Partition != nil { i = encodeVarintGenerated(dAtA, i, uint64(*m.Partition)) i-- @@ -2984,6 +2996,10 @@ func (m *RollingUpdateStatefulSetStrategy) Size() (n int) { if m.Partition != nil { n += 1 + sovGenerated(uint64(*m.Partition)) } + if m.MaxUnavailable != nil { + l = m.MaxUnavailable.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -3453,6 +3469,7 @@ func (this *RollingUpdateStatefulSetStrategy) String() string { } s := strings.Join([]string{`&RollingUpdateStatefulSetStrategy{`, `Partition:` + valueToStringGenerated(this.Partition) + `,`, + `MaxUnavailable:` + strings.Replace(fmt.Sprintf("%v", this.MaxUnavailable), "IntOrString", "intstr.IntOrString", 1) + `,`, `}`, }, "") return s @@ -7075,6 +7092,42 @@ func (m *RollingUpdateStatefulSetStrategy) Unmarshal(dAtA []byte) error { } } m.Partition = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxUnavailable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MaxUnavailable == nil { + m.MaxUnavailable = &intstr.IntOrString{} + } + if err := m.MaxUnavailable.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/apps/v1/generated.proto b/staging/src/k8s.io/api/apps/v1/generated.proto index 832460dd766f..d46373d92dcf 100644 --- a/staging/src/k8s.io/api/apps/v1/generated.proto +++ b/staging/src/k8s.io/api/apps/v1/generated.proto @@ -550,11 +550,22 @@ message RollingUpdateDeployment { // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. message RollingUpdateStatefulSetStrategy { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. - // Default value is 0. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. // +optional optional int32 partition = 1; + + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 2; } // StatefulSet represents a set of pods with consistent identities. diff --git a/staging/src/k8s.io/api/apps/v1/types.go b/staging/src/k8s.io/api/apps/v1/types.go index 469b47297f64..74c0ad66d85d 100644 --- a/staging/src/k8s.io/api/apps/v1/types.go +++ b/staging/src/k8s.io/api/apps/v1/types.go @@ -111,11 +111,21 @@ const ( // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. type RollingUpdateStatefulSetStrategy struct { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. - // Default value is 0. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. // +optional Partition *int32 `json:"partition,omitempty" protobuf:"varint,1,opt,name=partition"` + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"varint,2,opt,name=maxUnavailable"` } // PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine diff --git a/staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go index f640f9cdd661..f00d10aeabc2 100644 --- a/staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/apps/v1/types_swagger_doc_generated.go @@ -281,8 +281,9 @@ func (RollingUpdateDeployment) SwaggerDoc() map[string]string { } var map_RollingUpdateStatefulSetStrategy = map[string]string{ - "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", - "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", + "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", + "maxUnavailable": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", } func (RollingUpdateStatefulSetStrategy) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/apps/v1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/apps/v1/zz_generated.deepcopy.go index 8e4d4261a290..72d76670e78c 100644 --- a/staging/src/k8s.io/api/apps/v1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/apps/v1/zz_generated.deepcopy.go @@ -597,6 +597,11 @@ func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateState *out = new(int32) **out = **in } + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } return } diff --git a/staging/src/k8s.io/api/apps/v1beta1/generated.pb.go b/staging/src/k8s.io/api/apps/v1beta1/generated.pb.go index 98a483f611f4..48ac988f4529 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/generated.pb.go +++ b/staging/src/k8s.io/api/apps/v1beta1/generated.pb.go @@ -699,131 +699,131 @@ func init() { } var fileDescriptor_2a07313e8f66e805 = []byte{ - // 1971 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcd, 0x6f, 0x1b, 0xc7, - 0x15, 0xd7, 0x4a, 0xa2, 0x44, 0x3e, 0x45, 0x54, 0x3c, 0x52, 0x2d, 0x46, 0x69, 0x49, 0x81, 0x35, - 0x12, 0xe5, 0xc3, 0xcb, 0x58, 0x49, 0x83, 0xc4, 0x6e, 0xdd, 0x8a, 0x92, 0x1b, 0x3b, 0x90, 0x22, - 0x65, 0x24, 0xc5, 0x68, 0xfa, 0x81, 0x0c, 0xc9, 0x31, 0xb5, 0xd1, 0x7e, 0x61, 0x77, 0xc8, 0x98, - 0xe8, 0xa5, 0x7f, 0x40, 0x81, 0xf4, 0xdc, 0xbf, 0xa2, 0xb7, 0x16, 0xed, 0xad, 0x87, 0xc2, 0xc7, - 0xa0, 0x97, 0xa6, 0x17, 0xa2, 0x66, 0xae, 0xed, 0xad, 0xbd, 0x18, 0x28, 0x50, 0xcc, 0xec, 0xec, - 0xf7, 0xae, 0xb4, 0x2c, 0x10, 0x01, 0xed, 0x4d, 0x3b, 0xef, 0xbd, 0xdf, 0x9b, 0x99, 0xf7, 0x31, - 0xef, 0x47, 0xc1, 0x0f, 0xce, 0xdf, 0x71, 0x55, 0xcd, 0x6a, 0x9d, 0x0f, 0x3a, 0xd4, 0x31, 0x29, - 0xa3, 0x6e, 0x6b, 0x48, 0xcd, 0x9e, 0xe5, 0xb4, 0xa4, 0x80, 0xd8, 0x5a, 0x8b, 0xd8, 0xb6, 0xdb, - 0x1a, 0xde, 0xea, 0x50, 0x46, 0x6e, 0xb5, 0xfa, 0xd4, 0xa4, 0x0e, 0x61, 0xb4, 0xa7, 0xda, 0x8e, - 0xc5, 0x2c, 0xb4, 0xee, 0x29, 0xaa, 0xc4, 0xd6, 0x54, 0xae, 0xa8, 0x4a, 0xc5, 0x8d, 0x9b, 0x7d, - 0x8d, 0x9d, 0x0d, 0x3a, 0x6a, 0xd7, 0x32, 0x5a, 0x7d, 0xab, 0x6f, 0xb5, 0x84, 0x7e, 0x67, 0xf0, - 0x48, 0x7c, 0x89, 0x0f, 0xf1, 0x97, 0x87, 0xb3, 0xd1, 0x8c, 0x38, 0xec, 0x5a, 0x0e, 0x6d, 0x0d, - 0x53, 0xbe, 0x36, 0xde, 0x0a, 0x75, 0x0c, 0xd2, 0x3d, 0xd3, 0x4c, 0xea, 0x8c, 0x5a, 0xf6, 0x79, - 0x9f, 0x2f, 0xb8, 0x2d, 0x83, 0x32, 0x92, 0x65, 0xd5, 0xca, 0xb3, 0x72, 0x06, 0x26, 0xd3, 0x0c, - 0x9a, 0x32, 0x78, 0xfb, 0x32, 0x03, 0xb7, 0x7b, 0x46, 0x0d, 0x92, 0xb2, 0x7b, 0x33, 0xcf, 0x6e, - 0xc0, 0x34, 0xbd, 0xa5, 0x99, 0xcc, 0x65, 0x4e, 0xd2, 0xa8, 0xf9, 0x2f, 0x05, 0xd0, 0xae, 0x65, - 0x32, 0xc7, 0xd2, 0x75, 0xea, 0x60, 0x3a, 0xd4, 0x5c, 0xcd, 0x32, 0xd1, 0x27, 0x50, 0xe6, 0xe7, - 0xe9, 0x11, 0x46, 0x6a, 0xca, 0xa6, 0xb2, 0xb5, 0xb4, 0xfd, 0x86, 0x1a, 0xde, 0x74, 0x00, 0xaf, - 0xda, 0xe7, 0x7d, 0xbe, 0xe0, 0xaa, 0x5c, 0x5b, 0x1d, 0xde, 0x52, 0x0f, 0x3b, 0x9f, 0xd2, 0x2e, - 0x3b, 0xa0, 0x8c, 0xb4, 0xd1, 0x93, 0x71, 0x63, 0x66, 0x32, 0x6e, 0x40, 0xb8, 0x86, 0x03, 0x54, - 0x74, 0x08, 0xf3, 0x02, 0x7d, 0x56, 0xa0, 0xdf, 0xcc, 0x45, 0x97, 0x87, 0x56, 0x31, 0xf9, 0xec, - 0xde, 0x63, 0x46, 0x4d, 0xbe, 0xbd, 0xf6, 0x73, 0x12, 0x7a, 0x7e, 0x8f, 0x30, 0x82, 0x05, 0x10, - 0x7a, 0x1d, 0xca, 0x8e, 0xdc, 0x7e, 0x6d, 0x6e, 0x53, 0xd9, 0x9a, 0x6b, 0x3f, 0x2f, 0xb5, 0xca, - 0xfe, 0xb1, 0x70, 0xa0, 0xd1, 0x7c, 0xa2, 0xc0, 0xf5, 0xf4, 0xb9, 0xf7, 0x35, 0x97, 0xa1, 0x9f, - 0xa4, 0xce, 0xae, 0x16, 0x3b, 0x3b, 0xb7, 0x16, 0x27, 0x0f, 0x1c, 0xfb, 0x2b, 0x91, 0x73, 0x1f, - 0x41, 0x49, 0x63, 0xd4, 0x70, 0x6b, 0xb3, 0x9b, 0x73, 0x5b, 0x4b, 0xdb, 0xaf, 0xa9, 0x39, 0x09, - 0xac, 0xa6, 0x77, 0xd7, 0x5e, 0x96, 0xb8, 0xa5, 0x07, 0x1c, 0x01, 0x7b, 0x40, 0xcd, 0x5f, 0xce, - 0x02, 0xec, 0x51, 0x5b, 0xb7, 0x46, 0x06, 0x35, 0xd9, 0x15, 0x84, 0xee, 0x01, 0xcc, 0xbb, 0x36, - 0xed, 0xca, 0xd0, 0xbd, 0x9c, 0x7b, 0x82, 0x70, 0x53, 0xc7, 0x36, 0xed, 0x86, 0x41, 0xe3, 0x5f, - 0x58, 0x40, 0xa0, 0x0f, 0x61, 0xc1, 0x65, 0x84, 0x0d, 0x5c, 0x11, 0xb2, 0xa5, 0xed, 0x57, 0x8a, - 0x80, 0x09, 0x83, 0x76, 0x55, 0xc2, 0x2d, 0x78, 0xdf, 0x58, 0x02, 0x35, 0xff, 0x32, 0x07, 0xab, - 0xa1, 0xf2, 0xae, 0x65, 0xf6, 0x34, 0xc6, 0x53, 0xfa, 0x0e, 0xcc, 0xb3, 0x91, 0x4d, 0xc5, 0x9d, - 0x54, 0xda, 0x2f, 0xfb, 0x9b, 0x39, 0x19, 0xd9, 0xf4, 0xd9, 0xb8, 0xb1, 0x9e, 0x61, 0xc2, 0x45, - 0x58, 0x18, 0xa1, 0xfd, 0x60, 0x9f, 0xb3, 0xc2, 0xfc, 0xad, 0xb8, 0xf3, 0x67, 0xe3, 0x46, 0x46, - 0x03, 0x51, 0x03, 0xa4, 0xf8, 0x16, 0xd1, 0xa7, 0x50, 0xd5, 0x89, 0xcb, 0x4e, 0xed, 0x1e, 0x61, - 0xf4, 0x44, 0x33, 0x68, 0x6d, 0x41, 0x9c, 0xfe, 0xd5, 0x62, 0x81, 0xe2, 0x16, 0xed, 0xeb, 0x72, - 0x07, 0xd5, 0xfd, 0x18, 0x12, 0x4e, 0x20, 0xa3, 0x21, 0x20, 0xbe, 0x72, 0xe2, 0x10, 0xd3, 0xf5, - 0x4e, 0xc5, 0xfd, 0x2d, 0x4e, 0xed, 0x6f, 0x43, 0xfa, 0x43, 0xfb, 0x29, 0x34, 0x9c, 0xe1, 0x01, - 0xbd, 0x04, 0x0b, 0x0e, 0x25, 0xae, 0x65, 0xd6, 0xe6, 0xc5, 0x8d, 0x05, 0xe1, 0xc2, 0x62, 0x15, - 0x4b, 0x29, 0x7a, 0x05, 0x16, 0x0d, 0xea, 0xba, 0xa4, 0x4f, 0x6b, 0x25, 0xa1, 0xb8, 0x22, 0x15, - 0x17, 0x0f, 0xbc, 0x65, 0xec, 0xcb, 0x9b, 0xbf, 0x53, 0xa0, 0x1a, 0x86, 0xe9, 0x0a, 0x6a, 0xf5, - 0x7e, 0xbc, 0x56, 0xbf, 0x5d, 0x20, 0x39, 0x73, 0x6a, 0xf4, 0xef, 0xb3, 0x80, 0x42, 0x25, 0x6c, - 0xe9, 0x7a, 0x87, 0x74, 0xcf, 0xd1, 0x26, 0xcc, 0x9b, 0xc4, 0xf0, 0x73, 0x32, 0x28, 0x90, 0x0f, - 0x88, 0x41, 0xb1, 0x90, 0xa0, 0xcf, 0x15, 0x40, 0x03, 0x11, 0xcd, 0xde, 0x8e, 0x69, 0x5a, 0x8c, - 0xf0, 0x0b, 0xf6, 0x37, 0xb4, 0x5b, 0x60, 0x43, 0xbe, 0x2f, 0xf5, 0x34, 0x85, 0x72, 0xcf, 0x64, - 0xce, 0x28, 0x0c, 0x6c, 0x5a, 0x01, 0x67, 0xb8, 0x46, 0x3f, 0x06, 0x70, 0x24, 0xe6, 0x89, 0x25, - 0xcb, 0x36, 0xbf, 0x07, 0xf8, 0xee, 0x77, 0x2d, 0xf3, 0x91, 0xd6, 0x0f, 0x1b, 0x0b, 0x0e, 0x20, - 0x70, 0x04, 0x6e, 0xe3, 0x1e, 0xac, 0xe7, 0xec, 0x13, 0x3d, 0x0f, 0x73, 0xe7, 0x74, 0xe4, 0x5d, - 0x15, 0xe6, 0x7f, 0xa2, 0x35, 0x28, 0x0d, 0x89, 0x3e, 0xa0, 0x5e, 0x4d, 0x62, 0xef, 0xe3, 0xf6, - 0xec, 0x3b, 0x4a, 0xf3, 0x37, 0xa5, 0x68, 0xa6, 0xf0, 0x7e, 0x83, 0xb6, 0xf8, 0xf3, 0x60, 0xeb, - 0x5a, 0x97, 0xb8, 0x02, 0xa3, 0xd4, 0x7e, 0xce, 0x7b, 0x1a, 0xbc, 0x35, 0x1c, 0x48, 0xd1, 0x4f, - 0xa1, 0xec, 0x52, 0x9d, 0x76, 0x99, 0xe5, 0xc8, 0x16, 0xf7, 0x66, 0xc1, 0x9c, 0x22, 0x1d, 0xaa, - 0x1f, 0x4b, 0x53, 0x0f, 0xde, 0xff, 0xc2, 0x01, 0x24, 0xfa, 0x10, 0xca, 0x8c, 0x1a, 0xb6, 0x4e, - 0x18, 0x95, 0xb7, 0x17, 0xcb, 0x2b, 0xde, 0x3b, 0x38, 0xd8, 0x91, 0xd5, 0x3b, 0x91, 0x6a, 0xa2, - 0x7b, 0x06, 0x79, 0xea, 0xaf, 0xe2, 0x00, 0x06, 0xfd, 0x08, 0xca, 0x2e, 0xe3, 0xaf, 0x7a, 0x7f, - 0x24, 0xaa, 0xed, 0xa2, 0x67, 0x25, 0xda, 0x47, 0x3d, 0x93, 0x10, 0xda, 0x5f, 0xc1, 0x01, 0x1c, - 0xda, 0x81, 0x15, 0x43, 0x33, 0x31, 0x25, 0xbd, 0xd1, 0x31, 0xed, 0x5a, 0x66, 0xcf, 0x15, 0x65, - 0x5a, 0x6a, 0xaf, 0x4b, 0xa3, 0x95, 0x83, 0xb8, 0x18, 0x27, 0xf5, 0xd1, 0x3e, 0xac, 0xf9, 0xcf, - 0xee, 0x7d, 0xcd, 0x65, 0x96, 0x33, 0xda, 0xd7, 0x0c, 0x8d, 0x89, 0x9e, 0x57, 0x6a, 0xd7, 0x26, - 0xe3, 0xc6, 0x1a, 0xce, 0x90, 0xe3, 0x4c, 0x2b, 0xde, 0x57, 0x6c, 0x32, 0x70, 0x69, 0x4f, 0xf4, - 0xb0, 0x72, 0xd8, 0x57, 0x8e, 0xc4, 0x2a, 0x96, 0x52, 0xf4, 0x30, 0x96, 0xa6, 0xe5, 0xe9, 0xd2, - 0xb4, 0x9a, 0x9f, 0xa2, 0xe8, 0x14, 0xd6, 0x6d, 0xc7, 0xea, 0x3b, 0xd4, 0x75, 0xf7, 0x28, 0xe9, - 0xe9, 0x9a, 0x49, 0xfd, 0x9b, 0xa9, 0x88, 0x13, 0xbd, 0x38, 0x19, 0x37, 0xd6, 0x8f, 0xb2, 0x55, - 0x70, 0x9e, 0x6d, 0xf3, 0x8f, 0xf3, 0xf0, 0x7c, 0xf2, 0x8d, 0x43, 0xef, 0x03, 0xb2, 0x3a, 0x2e, - 0x75, 0x86, 0xb4, 0xf7, 0x9e, 0x37, 0xb8, 0xf1, 0xe9, 0x46, 0x11, 0xd3, 0x4d, 0x50, 0xb7, 0x87, - 0x29, 0x0d, 0x9c, 0x61, 0xe5, 0xcd, 0x47, 0xb2, 0x00, 0x66, 0xc5, 0x46, 0x23, 0xf3, 0x51, 0xaa, - 0x08, 0x76, 0x60, 0x45, 0xd6, 0xbe, 0x2f, 0x14, 0xc9, 0x1a, 0x89, 0xfb, 0x69, 0x5c, 0x8c, 0x93, - 0xfa, 0xe8, 0x0e, 0x2c, 0x3b, 0x3c, 0x0f, 0x02, 0x80, 0x45, 0x01, 0xf0, 0x0d, 0x09, 0xb0, 0x8c, - 0xa3, 0x42, 0x1c, 0xd7, 0x45, 0xef, 0xc1, 0x35, 0x32, 0x24, 0x9a, 0x4e, 0x3a, 0x3a, 0x0d, 0x00, - 0xe6, 0x05, 0xc0, 0x0b, 0x12, 0xe0, 0xda, 0x4e, 0x52, 0x01, 0xa7, 0x6d, 0xd0, 0x01, 0xac, 0x0e, - 0xcc, 0x34, 0x94, 0x97, 0xc4, 0x2f, 0x4a, 0xa8, 0xd5, 0xd3, 0xb4, 0x0a, 0xce, 0xb2, 0x43, 0x9f, - 0x00, 0x74, 0xfd, 0x57, 0xdd, 0xad, 0x2d, 0x88, 0x36, 0xfc, 0x7a, 0x81, 0x62, 0x0b, 0x46, 0x81, - 0xb0, 0x05, 0x06, 0x4b, 0x2e, 0x8e, 0x60, 0xa2, 0xdb, 0x50, 0xed, 0x5a, 0xba, 0x2e, 0x32, 0x7f, - 0xd7, 0x1a, 0x98, 0x4c, 0x24, 0x6f, 0xa9, 0x8d, 0xf8, 0x63, 0xbf, 0x1b, 0x93, 0xe0, 0x84, 0x66, - 0xf3, 0x0f, 0x4a, 0xf4, 0x99, 0xf1, 0xcb, 0x19, 0xdd, 0x8e, 0x8d, 0x3e, 0x2f, 0x25, 0x46, 0x9f, - 0xeb, 0x69, 0x8b, 0xc8, 0xe4, 0xa3, 0xc1, 0x32, 0x4f, 0x7e, 0xcd, 0xec, 0x7b, 0x01, 0x97, 0x2d, - 0xf1, 0x8d, 0x0b, 0x4b, 0x29, 0xd0, 0x8e, 0x3c, 0x8c, 0xd7, 0x44, 0xcc, 0xa3, 0x42, 0x1c, 0x47, - 0x6e, 0xde, 0x85, 0x6a, 0xbc, 0x0e, 0x63, 0x33, 0xbd, 0x72, 0xe9, 0x4c, 0xff, 0x95, 0x02, 0xeb, - 0x39, 0xde, 0x91, 0x0e, 0x55, 0x83, 0x3c, 0x8e, 0x84, 0xf9, 0xd2, 0xd9, 0x98, 0xb3, 0x26, 0xd5, - 0x63, 0x4d, 0xea, 0x03, 0x93, 0x1d, 0x3a, 0xc7, 0xcc, 0xd1, 0xcc, 0xbe, 0x17, 0x87, 0x83, 0x18, - 0x16, 0x4e, 0x60, 0xa3, 0x8f, 0xa1, 0x6c, 0x90, 0xc7, 0xc7, 0x03, 0xa7, 0x9f, 0x75, 0x5f, 0xc5, - 0xfc, 0x88, 0xf7, 0xe3, 0x40, 0xa2, 0xe0, 0x00, 0xaf, 0x79, 0x08, 0x9b, 0xb1, 0x43, 0xf2, 0x56, - 0x41, 0x1f, 0x0d, 0xf4, 0x63, 0x1a, 0x06, 0xfc, 0x35, 0xa8, 0xd8, 0xc4, 0x61, 0x5a, 0xd0, 0x2e, - 0x4a, 0xed, 0xe5, 0xc9, 0xb8, 0x51, 0x39, 0xf2, 0x17, 0x71, 0x28, 0x6f, 0xfe, 0x5b, 0x81, 0xd2, - 0x71, 0x97, 0xe8, 0xf4, 0x0a, 0xa8, 0xc3, 0x5e, 0x8c, 0x3a, 0x34, 0x73, 0x93, 0x48, 0xec, 0x27, - 0x97, 0x35, 0xec, 0x27, 0x58, 0xc3, 0x8d, 0x4b, 0x70, 0x2e, 0x26, 0x0c, 0xef, 0x42, 0x25, 0x70, - 0x17, 0xeb, 0x92, 0xca, 0x65, 0x5d, 0xb2, 0xf9, 0xeb, 0x59, 0x58, 0x8a, 0xb8, 0x98, 0xce, 0x9a, - 0x5f, 0x77, 0x64, 0xd0, 0xe0, 0x9d, 0x64, 0xbb, 0xc8, 0x41, 0x54, 0x7f, 0xa8, 0xf0, 0xe6, 0xb7, - 0xf0, 0xf5, 0x4e, 0xcf, 0x1a, 0x77, 0xa1, 0xca, 0x88, 0xd3, 0xa7, 0xcc, 0x97, 0x89, 0x0b, 0xab, - 0x84, 0xe4, 0xe1, 0x24, 0x26, 0xc5, 0x09, 0xed, 0x8d, 0x3b, 0xb0, 0x1c, 0x73, 0x36, 0xd5, 0x10, - 0xf6, 0x39, 0xbf, 0x9c, 0x30, 0x39, 0xaf, 0x20, 0xbb, 0xde, 0x8f, 0x65, 0xd7, 0x56, 0xfe, 0x65, - 0x46, 0x4a, 0x26, 0x2f, 0xc7, 0x70, 0x22, 0xc7, 0x5e, 0x2d, 0x84, 0x76, 0x71, 0xa6, 0xfd, 0x63, - 0x16, 0xd6, 0x22, 0xda, 0x21, 0x37, 0xfd, 0x6e, 0xac, 0x41, 0x6f, 0x25, 0x1a, 0x74, 0x2d, 0xcb, - 0xe6, 0x6b, 0x23, 0xa7, 0xd9, 0x84, 0x71, 0xee, 0x7f, 0x91, 0x30, 0xfe, 0x5e, 0x81, 0x95, 0xc8, - 0xdd, 0x5d, 0x01, 0x63, 0x7c, 0x10, 0x67, 0x8c, 0x37, 0x8a, 0x24, 0x4d, 0x0e, 0x65, 0xfc, 0xa7, - 0x02, 0xad, 0x88, 0xd6, 0x11, 0x75, 0x5c, 0xcd, 0x65, 0xd4, 0x64, 0x1f, 0x59, 0xfa, 0xc0, 0xa0, - 0xbb, 0x3a, 0xd1, 0x0c, 0x4c, 0xf9, 0x82, 0x66, 0x99, 0x47, 0x96, 0xae, 0x75, 0x47, 0x88, 0xc0, - 0xd2, 0x67, 0x67, 0xd4, 0xdc, 0xa3, 0x3a, 0x65, 0xb4, 0x27, 0xd3, 0xe9, 0xfb, 0x12, 0x7e, 0xe9, - 0x61, 0x28, 0x7a, 0x36, 0x6e, 0x6c, 0x15, 0x41, 0x14, 0x59, 0x16, 0xc5, 0x44, 0x3f, 0x03, 0xe0, - 0x9f, 0xa2, 0x1f, 0xf5, 0x64, 0xc2, 0xdd, 0xf5, 0xab, 0xf2, 0x61, 0x20, 0x99, 0xca, 0x41, 0x04, - 0xb1, 0xf9, 0xd7, 0xc5, 0x58, 0xcc, 0xfe, 0xef, 0xb9, 0xdb, 0xcf, 0x61, 0x6d, 0x18, 0xde, 0x8e, - 0xaf, 0xc0, 0x67, 0xdd, 0xb9, 0xe4, 0xef, 0x61, 0x01, 0x7c, 0xd6, 0xbd, 0xb6, 0xbf, 0x29, 0x9d, - 0xac, 0x7d, 0x94, 0x01, 0x87, 0x33, 0x9d, 0xa0, 0xef, 0xc0, 0x12, 0xe7, 0x09, 0x5a, 0x97, 0x7e, - 0x40, 0x0c, 0xbf, 0x9e, 0x56, 0xfd, 0x7c, 0x39, 0x0e, 0x45, 0x38, 0xaa, 0x87, 0xce, 0x60, 0xd5, - 0xb6, 0x7a, 0x07, 0xc4, 0x24, 0x7d, 0xca, 0xa7, 0x2b, 0x2f, 0x94, 0x82, 0xd0, 0x55, 0xda, 0x6f, - 0xfb, 0x33, 0xf5, 0x51, 0x5a, 0xe5, 0x19, 0x67, 0x46, 0xe9, 0x65, 0x91, 0x04, 0x59, 0x90, 0xc8, - 0x81, 0xea, 0x40, 0x4e, 0x39, 0x92, 0xdf, 0x7a, 0xbf, 0x5c, 0x6d, 0x17, 0x29, 0xac, 0xd3, 0x98, - 0x65, 0xf8, 0xe8, 0xc5, 0xd7, 0x71, 0xc2, 0x43, 0x2e, 0x5f, 0x2d, 0xff, 0x57, 0x7c, 0x35, 0x83, - 0x40, 0x57, 0xa6, 0x24, 0xd0, 0x7f, 0x52, 0xe0, 0x86, 0x5d, 0xa0, 0x96, 0x6a, 0x20, 0xee, 0xe6, - 0x7e, 0x91, 0xbb, 0x29, 0x52, 0x9b, 0xed, 0xad, 0xc9, 0xb8, 0x71, 0xa3, 0x88, 0x26, 0x2e, 0xb4, - 0xbf, 0xe6, 0x6f, 0x4b, 0x70, 0x2d, 0xf5, 0x5a, 0xa2, 0x1f, 0x5e, 0x40, 0x72, 0xaf, 0x7f, 0x6d, - 0x04, 0x37, 0xc5, 0x4e, 0xe7, 0xa6, 0x60, 0xa7, 0x3b, 0xb0, 0xd2, 0x1d, 0x38, 0x0e, 0x35, 0x59, - 0x82, 0x9b, 0x06, 0x41, 0xdd, 0x8d, 0x8b, 0x71, 0x52, 0x3f, 0x8b, 0x60, 0x97, 0xa6, 0x24, 0xd8, - 0xd1, 0x5d, 0x48, 0x92, 0xe4, 0x95, 0x60, 0x7a, 0x17, 0x92, 0x2b, 0x25, 0xf5, 0xf9, 0x80, 0xe8, - 0xa1, 0x06, 0x08, 0x8b, 0xf1, 0x01, 0xf1, 0x34, 0x26, 0xc5, 0x09, 0xed, 0x0c, 0xb2, 0x5a, 0x29, - 0x4a, 0x56, 0x11, 0x89, 0x51, 0x69, 0x10, 0xfd, 0xee, 0x66, 0x91, 0xdc, 0x2d, 0xce, 0xa5, 0x33, - 0x7f, 0x45, 0x58, 0x9a, 0xfe, 0x57, 0x84, 0xe6, 0x9f, 0x15, 0x78, 0x21, 0xb7, 0xb3, 0xa0, 0x9d, - 0xd8, 0xf8, 0x76, 0x33, 0x31, 0xbe, 0x7d, 0x2b, 0xd7, 0x30, 0x32, 0xc3, 0x39, 0xd9, 0x34, 0xfb, - 0xdd, 0x62, 0x34, 0x3b, 0x83, 0x03, 0x5e, 0xce, 0xb7, 0xdb, 0xdf, 0x7b, 0xf2, 0xb4, 0x3e, 0xf3, - 0xc5, 0xd3, 0xfa, 0xcc, 0x97, 0x4f, 0xeb, 0x33, 0xbf, 0x98, 0xd4, 0x95, 0x27, 0x93, 0xba, 0xf2, - 0xc5, 0xa4, 0xae, 0x7c, 0x39, 0xa9, 0x2b, 0x7f, 0x9b, 0xd4, 0x95, 0x5f, 0x7d, 0x55, 0x9f, 0xf9, - 0x78, 0x3d, 0xe7, 0x5f, 0xb1, 0xff, 0x09, 0x00, 0x00, 0xff, 0xff, 0x51, 0x48, 0x04, 0x5b, 0xbd, - 0x1d, 0x00, 0x00, + // 1982 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xdc, 0x59, 0xcf, 0x6f, 0x1b, 0xc7, + 0xf5, 0xd7, 0x52, 0xa2, 0x44, 0x3d, 0x45, 0x94, 0x3d, 0xd2, 0xd7, 0x62, 0x94, 0x6f, 0x49, 0x81, + 0x35, 0x12, 0xe5, 0x87, 0x97, 0xb1, 0x92, 0x06, 0x89, 0xdd, 0xba, 0x15, 0x25, 0x37, 0x76, 0x20, + 0xc5, 0xca, 0x48, 0x8a, 0xd1, 0xf4, 0x07, 0x32, 0x24, 0xc7, 0xd4, 0x46, 0xfb, 0x0b, 0xbb, 0x43, + 0xc6, 0x44, 0x2f, 0xfd, 0x03, 0x0a, 0xa4, 0xe7, 0xfe, 0x15, 0xbd, 0xb5, 0x68, 0xd1, 0x4b, 0x0f, + 0x85, 0x8f, 0x41, 0x2f, 0x4d, 0x2f, 0x44, 0xcd, 0x5c, 0xdb, 0x5b, 0x7b, 0x31, 0x50, 0xa0, 0x98, + 0xd9, 0xd9, 0xdf, 0xbb, 0xd2, 0xb2, 0x80, 0x05, 0xb4, 0x37, 0xed, 0xbc, 0xf7, 0x3e, 0x6f, 0xe6, + 0xcd, 0x7b, 0x6f, 0xde, 0x87, 0x82, 0xef, 0x9d, 0xbd, 0xeb, 0xaa, 0x9a, 0xd5, 0x3a, 0x1b, 0x74, + 0xa8, 0x63, 0x52, 0x46, 0xdd, 0xd6, 0x90, 0x9a, 0x3d, 0xcb, 0x69, 0x49, 0x01, 0xb1, 0xb5, 0x16, + 0xb1, 0x6d, 0xb7, 0x35, 0xbc, 0xd9, 0xa1, 0x8c, 0xdc, 0x6c, 0xf5, 0xa9, 0x49, 0x1d, 0xc2, 0x68, + 0x4f, 0xb5, 0x1d, 0x8b, 0x59, 0x68, 0xdd, 0x53, 0x54, 0x89, 0xad, 0xa9, 0x5c, 0x51, 0x95, 0x8a, + 0x1b, 0x37, 0xfa, 0x1a, 0x3b, 0x1d, 0x74, 0xd4, 0xae, 0x65, 0xb4, 0xfa, 0x56, 0xdf, 0x6a, 0x09, + 0xfd, 0xce, 0xe0, 0x91, 0xf8, 0x12, 0x1f, 0xe2, 0x2f, 0x0f, 0x67, 0xa3, 0x19, 0x71, 0xd8, 0xb5, + 0x1c, 0xda, 0x1a, 0xa6, 0x7c, 0x6d, 0xbc, 0x1d, 0xea, 0x18, 0xa4, 0x7b, 0xaa, 0x99, 0xd4, 0x19, + 0xb5, 0xec, 0xb3, 0x3e, 0x5f, 0x70, 0x5b, 0x06, 0x65, 0x24, 0xcb, 0xaa, 0x95, 0x67, 0xe5, 0x0c, + 0x4c, 0xa6, 0x19, 0x34, 0x65, 0xf0, 0xce, 0x45, 0x06, 0x6e, 0xf7, 0x94, 0x1a, 0x24, 0x65, 0xf7, + 0x56, 0x9e, 0xdd, 0x80, 0x69, 0x7a, 0x4b, 0x33, 0x99, 0xcb, 0x9c, 0xa4, 0x51, 0xf3, 0x9f, 0x0a, + 0xa0, 0x5d, 0xcb, 0x64, 0x8e, 0xa5, 0xeb, 0xd4, 0xc1, 0x74, 0xa8, 0xb9, 0x9a, 0x65, 0xa2, 0x4f, + 0xa1, 0xc2, 0xcf, 0xd3, 0x23, 0x8c, 0xd4, 0x94, 0x4d, 0x65, 0x6b, 0x69, 0xfb, 0x4d, 0x35, 0x8c, + 0x74, 0x00, 0xaf, 0xda, 0x67, 0x7d, 0xbe, 0xe0, 0xaa, 0x5c, 0x5b, 0x1d, 0xde, 0x54, 0x1f, 0x74, + 0x3e, 0xa3, 0x5d, 0x76, 0x40, 0x19, 0x69, 0xa3, 0x27, 0xe3, 0xc6, 0xcc, 0x64, 0xdc, 0x80, 0x70, + 0x0d, 0x07, 0xa8, 0xe8, 0x01, 0xcc, 0x09, 0xf4, 0x92, 0x40, 0xbf, 0x91, 0x8b, 0x2e, 0x0f, 0xad, + 0x62, 0xf2, 0xf9, 0xdd, 0xc7, 0x8c, 0x9a, 0x7c, 0x7b, 0xed, 0x17, 0x24, 0xf4, 0xdc, 0x1e, 0x61, + 0x04, 0x0b, 0x20, 0xf4, 0x06, 0x54, 0x1c, 0xb9, 0xfd, 0xda, 0xec, 0xa6, 0xb2, 0x35, 0xdb, 0xbe, + 0x22, 0xb5, 0x2a, 0xfe, 0xb1, 0x70, 0xa0, 0xd1, 0x7c, 0xa2, 0xc0, 0xb5, 0xf4, 0xb9, 0xf7, 0x35, + 0x97, 0xa1, 0x1f, 0xa5, 0xce, 0xae, 0x16, 0x3b, 0x3b, 0xb7, 0x16, 0x27, 0x0f, 0x1c, 0xfb, 0x2b, + 0x91, 0x73, 0x1f, 0x42, 0x59, 0x63, 0xd4, 0x70, 0x6b, 0xa5, 0xcd, 0xd9, 0xad, 0xa5, 0xed, 0xd7, + 0xd5, 0x9c, 0x04, 0x56, 0xd3, 0xbb, 0x6b, 0x2f, 0x4b, 0xdc, 0xf2, 0x7d, 0x8e, 0x80, 0x3d, 0xa0, + 0xe6, 0xcf, 0x4b, 0x00, 0x7b, 0xd4, 0xd6, 0xad, 0x91, 0x41, 0x4d, 0x76, 0x09, 0x57, 0x77, 0x1f, + 0xe6, 0x5c, 0x9b, 0x76, 0xe5, 0xd5, 0xbd, 0x92, 0x7b, 0x82, 0x70, 0x53, 0x47, 0x36, 0xed, 0x86, + 0x97, 0xc6, 0xbf, 0xb0, 0x80, 0x40, 0x1f, 0xc1, 0xbc, 0xcb, 0x08, 0x1b, 0xb8, 0xe2, 0xca, 0x96, + 0xb6, 0x5f, 0x2d, 0x02, 0x26, 0x0c, 0xda, 0x55, 0x09, 0x37, 0xef, 0x7d, 0x63, 0x09, 0xd4, 0xfc, + 0xf3, 0x2c, 0xac, 0x86, 0xca, 0xbb, 0x96, 0xd9, 0xd3, 0x18, 0x4f, 0xe9, 0xdb, 0x30, 0xc7, 0x46, + 0x36, 0x15, 0x31, 0x59, 0x6c, 0xbf, 0xe2, 0x6f, 0xe6, 0x78, 0x64, 0xd3, 0x67, 0xe3, 0xc6, 0x7a, + 0x86, 0x09, 0x17, 0x61, 0x61, 0x84, 0xf6, 0x83, 0x7d, 0x96, 0x84, 0xf9, 0xdb, 0x71, 0xe7, 0xcf, + 0xc6, 0x8d, 0x8c, 0x06, 0xa2, 0x06, 0x48, 0xf1, 0x2d, 0xa2, 0xcf, 0xa0, 0xaa, 0x13, 0x97, 0x9d, + 0xd8, 0x3d, 0xc2, 0xe8, 0xb1, 0x66, 0xd0, 0xda, 0xbc, 0x38, 0xfd, 0x6b, 0xc5, 0x2e, 0x8a, 0x5b, + 0xb4, 0xaf, 0xc9, 0x1d, 0x54, 0xf7, 0x63, 0x48, 0x38, 0x81, 0x8c, 0x86, 0x80, 0xf8, 0xca, 0xb1, + 0x43, 0x4c, 0xd7, 0x3b, 0x15, 0xf7, 0xb7, 0x30, 0xb5, 0xbf, 0x0d, 0xe9, 0x0f, 0xed, 0xa7, 0xd0, + 0x70, 0x86, 0x07, 0xf4, 0x32, 0xcc, 0x3b, 0x94, 0xb8, 0x96, 0x59, 0x9b, 0x13, 0x11, 0x0b, 0xae, + 0x0b, 0x8b, 0x55, 0x2c, 0xa5, 0xe8, 0x55, 0x58, 0x30, 0xa8, 0xeb, 0x92, 0x3e, 0xad, 0x95, 0x85, + 0xe2, 0x8a, 0x54, 0x5c, 0x38, 0xf0, 0x96, 0xb1, 0x2f, 0x6f, 0xfe, 0x46, 0x81, 0x6a, 0x78, 0x4d, + 0x97, 0x50, 0xab, 0xf7, 0xe2, 0xb5, 0xfa, 0xcd, 0x02, 0xc9, 0x99, 0x53, 0xa3, 0x7f, 0x2b, 0x01, + 0x0a, 0x95, 0xb0, 0xa5, 0xeb, 0x1d, 0xd2, 0x3d, 0x43, 0x9b, 0x30, 0x67, 0x12, 0xc3, 0xcf, 0xc9, + 0xa0, 0x40, 0x3e, 0x24, 0x06, 0xc5, 0x42, 0x82, 0xbe, 0x50, 0x00, 0x0d, 0xc4, 0x6d, 0xf6, 0x76, + 0x4c, 0xd3, 0x62, 0x84, 0x07, 0xd8, 0xdf, 0xd0, 0x6e, 0x81, 0x0d, 0xf9, 0xbe, 0xd4, 0x93, 0x14, + 0xca, 0x5d, 0x93, 0x39, 0xa3, 0xf0, 0x62, 0xd3, 0x0a, 0x38, 0xc3, 0x35, 0xfa, 0x21, 0x80, 0x23, + 0x31, 0x8f, 0x2d, 0x59, 0xb6, 0xf9, 0x3d, 0xc0, 0x77, 0xbf, 0x6b, 0x99, 0x8f, 0xb4, 0x7e, 0xd8, + 0x58, 0x70, 0x00, 0x81, 0x23, 0x70, 0x1b, 0x77, 0x61, 0x3d, 0x67, 0x9f, 0xe8, 0x0a, 0xcc, 0x9e, + 0xd1, 0x91, 0x17, 0x2a, 0xcc, 0xff, 0x44, 0x6b, 0x50, 0x1e, 0x12, 0x7d, 0x40, 0xbd, 0x9a, 0xc4, + 0xde, 0xc7, 0xad, 0xd2, 0xbb, 0x4a, 0xf3, 0x57, 0xe5, 0x68, 0xa6, 0xf0, 0x7e, 0x83, 0xb6, 0xf8, + 0xf3, 0x60, 0xeb, 0x5a, 0x97, 0xb8, 0x02, 0xa3, 0xdc, 0x7e, 0xc1, 0x7b, 0x1a, 0xbc, 0x35, 0x1c, + 0x48, 0xd1, 0x8f, 0xa1, 0xe2, 0x52, 0x9d, 0x76, 0x99, 0xe5, 0xc8, 0x16, 0xf7, 0x56, 0xc1, 0x9c, + 0x22, 0x1d, 0xaa, 0x1f, 0x49, 0x53, 0x0f, 0xde, 0xff, 0xc2, 0x01, 0x24, 0xfa, 0x08, 0x2a, 0x8c, + 0x1a, 0xb6, 0x4e, 0x18, 0x95, 0xd1, 0x8b, 0xe5, 0x15, 0xef, 0x1d, 0x1c, 0xec, 0xd0, 0xea, 0x1d, + 0x4b, 0x35, 0xd1, 0x3d, 0x83, 0x3c, 0xf5, 0x57, 0x71, 0x00, 0x83, 0x7e, 0x00, 0x15, 0x97, 0xf1, + 0x57, 0xbd, 0x3f, 0x12, 0xd5, 0x76, 0xde, 0xb3, 0x12, 0xed, 0xa3, 0x9e, 0x49, 0x08, 0xed, 0xaf, + 0xe0, 0x00, 0x0e, 0xed, 0xc0, 0x8a, 0xa1, 0x99, 0x98, 0x92, 0xde, 0xe8, 0x88, 0x76, 0x2d, 0xb3, + 0xe7, 0x8a, 0x32, 0x2d, 0xb7, 0xd7, 0xa5, 0xd1, 0xca, 0x41, 0x5c, 0x8c, 0x93, 0xfa, 0x68, 0x1f, + 0xd6, 0xfc, 0x67, 0xf7, 0x9e, 0xe6, 0x32, 0xcb, 0x19, 0xed, 0x6b, 0x86, 0xc6, 0x44, 0xcf, 0x2b, + 0xb7, 0x6b, 0x93, 0x71, 0x63, 0x0d, 0x67, 0xc8, 0x71, 0xa6, 0x15, 0xef, 0x2b, 0x36, 0x19, 0xb8, + 0xb4, 0x27, 0x7a, 0x58, 0x25, 0xec, 0x2b, 0x87, 0x62, 0x15, 0x4b, 0x29, 0x7a, 0x18, 0x4b, 0xd3, + 0xca, 0x74, 0x69, 0x5a, 0xcd, 0x4f, 0x51, 0x74, 0x02, 0xeb, 0xb6, 0x63, 0xf5, 0x1d, 0xea, 0xba, + 0x7b, 0x94, 0xf4, 0x74, 0xcd, 0xa4, 0x7e, 0x64, 0x16, 0xc5, 0x89, 0x5e, 0x9a, 0x8c, 0x1b, 0xeb, + 0x87, 0xd9, 0x2a, 0x38, 0xcf, 0xb6, 0xf9, 0x87, 0x39, 0xb8, 0x92, 0x7c, 0xe3, 0xd0, 0x07, 0x80, + 0xac, 0x8e, 0x4b, 0x9d, 0x21, 0xed, 0xbd, 0xef, 0x0d, 0x6e, 0x7c, 0xba, 0x51, 0xc4, 0x74, 0x13, + 0xd4, 0xed, 0x83, 0x94, 0x06, 0xce, 0xb0, 0xf2, 0xe6, 0x23, 0x59, 0x00, 0x25, 0xb1, 0xd1, 0xc8, + 0x7c, 0x94, 0x2a, 0x82, 0x1d, 0x58, 0x91, 0xb5, 0xef, 0x0b, 0x45, 0xb2, 0x46, 0xee, 0xfd, 0x24, + 0x2e, 0xc6, 0x49, 0x7d, 0x74, 0x1b, 0x96, 0x1d, 0x9e, 0x07, 0x01, 0xc0, 0x82, 0x00, 0xf8, 0x3f, + 0x09, 0xb0, 0x8c, 0xa3, 0x42, 0x1c, 0xd7, 0x45, 0xef, 0xc3, 0x55, 0x32, 0x24, 0x9a, 0x4e, 0x3a, + 0x3a, 0x0d, 0x00, 0xe6, 0x04, 0xc0, 0x8b, 0x12, 0xe0, 0xea, 0x4e, 0x52, 0x01, 0xa7, 0x6d, 0xd0, + 0x01, 0xac, 0x0e, 0xcc, 0x34, 0x94, 0x97, 0xc4, 0x2f, 0x49, 0xa8, 0xd5, 0x93, 0xb4, 0x0a, 0xce, + 0xb2, 0x43, 0x9f, 0x02, 0x74, 0xfd, 0x57, 0xdd, 0xad, 0xcd, 0x8b, 0x36, 0xfc, 0x46, 0x81, 0x62, + 0x0b, 0x46, 0x81, 0xb0, 0x05, 0x06, 0x4b, 0x2e, 0x8e, 0x60, 0xa2, 0x5b, 0x50, 0xed, 0x5a, 0xba, + 0x2e, 0x32, 0x7f, 0xd7, 0x1a, 0x98, 0x4c, 0x24, 0x6f, 0xb9, 0x8d, 0xf8, 0x63, 0xbf, 0x1b, 0x93, + 0xe0, 0x84, 0x66, 0xf3, 0x77, 0x4a, 0xf4, 0x99, 0xf1, 0xcb, 0x19, 0xdd, 0x8a, 0x8d, 0x3e, 0x2f, + 0x27, 0x46, 0x9f, 0x6b, 0x69, 0x8b, 0xc8, 0xe4, 0xa3, 0xc1, 0x32, 0x4f, 0x7e, 0xcd, 0xec, 0x7b, + 0x17, 0x2e, 0x5b, 0xe2, 0x9b, 0xe7, 0x96, 0x52, 0xa0, 0x1d, 0x79, 0x18, 0xaf, 0x8a, 0x3b, 0x8f, + 0x0a, 0x71, 0x1c, 0xb9, 0x79, 0x07, 0xaa, 0xf1, 0x3a, 0x8c, 0xcd, 0xf4, 0xca, 0x85, 0x33, 0xfd, + 0xd7, 0x0a, 0xac, 0xe7, 0x78, 0x47, 0x3a, 0x54, 0x0d, 0xf2, 0x38, 0x72, 0xcd, 0x17, 0xce, 0xc6, + 0x9c, 0x35, 0xa9, 0x1e, 0x6b, 0x52, 0xef, 0x9b, 0xec, 0x81, 0x73, 0xc4, 0x1c, 0xcd, 0xec, 0x7b, + 0xf7, 0x70, 0x10, 0xc3, 0xc2, 0x09, 0x6c, 0xf4, 0x09, 0x54, 0x0c, 0xf2, 0xf8, 0x68, 0xe0, 0xf4, + 0xb3, 0xe2, 0x55, 0xcc, 0x8f, 0x78, 0x3f, 0x0e, 0x24, 0x0a, 0x0e, 0xf0, 0x9a, 0xbf, 0x57, 0x60, + 0x33, 0x76, 0x4a, 0xde, 0x2b, 0xe8, 0xa3, 0x81, 0x7e, 0x44, 0xc3, 0x1b, 0x7f, 0x1d, 0x16, 0x6d, + 0xe2, 0x30, 0x2d, 0xe8, 0x17, 0xe5, 0xf6, 0xf2, 0x64, 0xdc, 0x58, 0x3c, 0xf4, 0x17, 0x71, 0x28, + 0xcf, 0x88, 0x4d, 0xe9, 0xf9, 0xc5, 0xa6, 0xf9, 0x2f, 0x05, 0xca, 0x47, 0x5d, 0xa2, 0xd3, 0x4b, + 0x60, 0x2a, 0x7b, 0x31, 0xa6, 0xd2, 0xcc, 0xcd, 0x59, 0xb1, 0x9f, 0x5c, 0x92, 0xb2, 0x9f, 0x20, + 0x29, 0xd7, 0x2f, 0xc0, 0x39, 0x9f, 0x9f, 0xbc, 0x07, 0x8b, 0x81, 0xbb, 0x58, 0x53, 0x56, 0x2e, + 0x6a, 0xca, 0xcd, 0x5f, 0x96, 0x60, 0x29, 0xe2, 0x62, 0x3a, 0x6b, 0x1e, 0xee, 0xc8, 0x5c, 0xc3, + 0x1b, 0xd7, 0x76, 0x91, 0x83, 0xa8, 0xfe, 0x0c, 0xe3, 0x8d, 0x8b, 0xe1, 0xb0, 0x90, 0x1e, 0x6d, + 0xee, 0x40, 0x95, 0x11, 0xa7, 0x4f, 0x99, 0x2f, 0x13, 0x01, 0x5b, 0x0c, 0xb9, 0xca, 0x71, 0x4c, + 0x8a, 0x13, 0xda, 0x1b, 0xb7, 0x61, 0x39, 0xe6, 0x6c, 0xaa, 0x99, 0xef, 0x0b, 0x1e, 0x9c, 0xb0, + 0x14, 0x2e, 0x21, 0xbb, 0x3e, 0x88, 0x65, 0xd7, 0x56, 0x7e, 0x30, 0x23, 0x05, 0x9a, 0x97, 0x63, + 0x38, 0x91, 0x63, 0xaf, 0x15, 0x42, 0x3b, 0x3f, 0xd3, 0xfe, 0x5e, 0x82, 0xb5, 0x88, 0x76, 0x48, + 0x85, 0xbf, 0x1d, 0x7b, 0x0f, 0xb6, 0x12, 0xef, 0x41, 0x2d, 0xcb, 0xe6, 0xb9, 0x71, 0xe1, 0x6c, + 0x7e, 0x3a, 0xfb, 0xdf, 0xc8, 0x4f, 0x7f, 0xab, 0xc0, 0x4a, 0x24, 0x76, 0x97, 0x40, 0x50, 0xef, + 0xc7, 0x09, 0xea, 0xf5, 0x22, 0x49, 0x93, 0xc3, 0x50, 0xff, 0xa1, 0x40, 0x2b, 0xa2, 0x75, 0x48, + 0x1d, 0x57, 0x73, 0x19, 0x35, 0xd9, 0xc7, 0x96, 0x3e, 0x30, 0xe8, 0xae, 0x4e, 0x34, 0x03, 0x53, + 0xbe, 0xa0, 0x59, 0xe6, 0xa1, 0xa5, 0x6b, 0xdd, 0x11, 0x22, 0xb0, 0xf4, 0xf9, 0x29, 0x35, 0xf7, + 0xa8, 0x4e, 0x19, 0xed, 0xc9, 0x74, 0xfa, 0xae, 0x84, 0x5f, 0x7a, 0x18, 0x8a, 0x9e, 0x8d, 0x1b, + 0x5b, 0x45, 0x10, 0x45, 0x96, 0x45, 0x31, 0xd1, 0x4f, 0x00, 0xf8, 0xa7, 0xe8, 0x47, 0x3d, 0x99, + 0x70, 0x77, 0xfc, 0xaa, 0x7c, 0x18, 0x48, 0xa6, 0x72, 0x10, 0x41, 0x6c, 0xfe, 0x65, 0x21, 0x76, + 0x67, 0xff, 0xf3, 0x54, 0xf1, 0xa7, 0xb0, 0x36, 0x0c, 0xa3, 0xe3, 0x2b, 0xf0, 0xd1, 0x7a, 0x36, + 0xf9, 0xf3, 0x5b, 0x00, 0x9f, 0x15, 0xd7, 0xf6, 0xff, 0x4b, 0x27, 0x6b, 0x1f, 0x67, 0xc0, 0xe1, + 0x4c, 0x27, 0xe8, 0x5b, 0xb0, 0xc4, 0x69, 0x89, 0xd6, 0xa5, 0x1f, 0x12, 0xc3, 0xaf, 0xa7, 0x55, + 0x3f, 0x5f, 0x8e, 0x42, 0x11, 0x8e, 0xea, 0xa1, 0x53, 0x58, 0xb5, 0xad, 0xde, 0x01, 0x31, 0x49, + 0x9f, 0xf2, 0x61, 0xce, 0xbb, 0x4a, 0xc1, 0x1f, 0x17, 0xdb, 0xef, 0xf8, 0x23, 0xfc, 0x61, 0x5a, + 0xe5, 0x19, 0x27, 0x62, 0xe9, 0x65, 0x91, 0x04, 0x59, 0x90, 0xc8, 0x81, 0xea, 0x40, 0xce, 0x54, + 0x92, 0x4e, 0x7b, 0x3f, 0x94, 0x6d, 0x17, 0x29, 0xac, 0x93, 0x98, 0x65, 0xf8, 0xe8, 0xc5, 0xd7, + 0x71, 0xc2, 0x43, 0x2e, 0x3d, 0xae, 0xfc, 0x47, 0xf4, 0x38, 0x83, 0xaf, 0x2f, 0x4e, 0xc9, 0xd7, + 0xff, 0xa8, 0xc0, 0x75, 0xbb, 0x40, 0x2d, 0xd5, 0x40, 0xc4, 0xe6, 0x5e, 0x91, 0xd8, 0x14, 0xa9, + 0xcd, 0xf6, 0xd6, 0x64, 0xdc, 0xb8, 0x5e, 0x44, 0x13, 0x17, 0xda, 0x5f, 0xf3, 0xd7, 0x65, 0xb8, + 0x9a, 0x7a, 0x2d, 0xd1, 0xf7, 0xcf, 0xe1, 0xd4, 0xd7, 0x9e, 0x1b, 0x9f, 0x4e, 0x91, 0xe1, 0xd9, + 0x29, 0xc8, 0xf0, 0x0e, 0xac, 0x74, 0x07, 0x8e, 0x43, 0x4d, 0x96, 0xa0, 0xc2, 0xc1, 0xa5, 0xee, + 0xc6, 0xc5, 0x38, 0xa9, 0x9f, 0xc5, 0xe7, 0xcb, 0x53, 0xf2, 0xf9, 0xe8, 0x2e, 0x24, 0x27, 0xf3, + 0x4a, 0x30, 0xbd, 0x0b, 0x49, 0xcd, 0x92, 0xfa, 0x7c, 0x40, 0xf4, 0x50, 0x03, 0x84, 0x85, 0xf8, + 0x80, 0x78, 0x12, 0x93, 0xe2, 0x84, 0x76, 0x06, 0x37, 0x5e, 0x2c, 0xca, 0x8d, 0x11, 0x89, 0x31, + 0x77, 0x10, 0xfd, 0xee, 0x46, 0x91, 0xdc, 0x2d, 0x4e, 0xdd, 0x33, 0x7f, 0xb4, 0x58, 0x9a, 0xfe, + 0x47, 0x8b, 0xe6, 0x9f, 0x14, 0x78, 0x31, 0xb7, 0xb3, 0xa0, 0x9d, 0xd8, 0xf8, 0x76, 0x23, 0x31, + 0xbe, 0x7d, 0x23, 0xd7, 0x30, 0x32, 0xc3, 0x39, 0xd9, 0xac, 0xfe, 0xbd, 0x62, 0xac, 0x3e, 0x83, + 0x71, 0x5e, 0x4c, 0xef, 0xdb, 0xdf, 0x79, 0xf2, 0xb4, 0x3e, 0xf3, 0xe5, 0xd3, 0xfa, 0xcc, 0x57, + 0x4f, 0xeb, 0x33, 0x3f, 0x9b, 0xd4, 0x95, 0x27, 0x93, 0xba, 0xf2, 0xe5, 0xa4, 0xae, 0x7c, 0x35, + 0xa9, 0x2b, 0x7f, 0x9d, 0xd4, 0x95, 0x5f, 0x7c, 0x5d, 0x9f, 0xf9, 0x64, 0x3d, 0xe7, 0x3f, 0xbf, + 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xe7, 0x15, 0x68, 0x85, 0x2c, 0x1e, 0x00, 0x00, } func (m *ControllerRevision) Marshal() (dAtA []byte, err error) { @@ -1430,6 +1430,18 @@ func (m *RollingUpdateStatefulSetStrategy) MarshalToSizedBuffer(dAtA []byte) (in _ = i var l int _ = l + if m.MaxUnavailable != nil { + { + size, err := m.MaxUnavailable.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if m.Partition != nil { i = encodeVarintGenerated(dAtA, i, uint64(*m.Partition)) i-- @@ -2197,6 +2209,10 @@ func (m *RollingUpdateStatefulSetStrategy) Size() (n int) { if m.Partition != nil { n += 1 + sovGenerated(uint64(*m.Partition)) } + if m.MaxUnavailable != nil { + l = m.MaxUnavailable.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -2569,6 +2585,7 @@ func (this *RollingUpdateStatefulSetStrategy) String() string { } s := strings.Join([]string{`&RollingUpdateStatefulSetStrategy{`, `Partition:` + valueToStringGenerated(this.Partition) + `,`, + `MaxUnavailable:` + strings.Replace(fmt.Sprintf("%v", this.MaxUnavailable), "IntOrString", "intstr.IntOrString", 1) + `,`, `}`, }, "") return s @@ -4604,6 +4621,42 @@ func (m *RollingUpdateStatefulSetStrategy) Unmarshal(dAtA []byte) error { } } m.Partition = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxUnavailable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MaxUnavailable == nil { + m.MaxUnavailable = &intstr.IntOrString{} + } + if err := m.MaxUnavailable.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/apps/v1beta1/generated.proto b/staging/src/k8s.io/api/apps/v1beta1/generated.proto index ba204b60fa36..7f49e3eb543d 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/apps/v1beta1/generated.proto @@ -270,9 +270,21 @@ message RollingUpdateDeployment { // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. message RollingUpdateStatefulSetStrategy { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. optional int32 partition = 1; + + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 2; } // Scale represents a scaling request for a resource. diff --git a/staging/src/k8s.io/api/apps/v1beta1/types.go b/staging/src/k8s.io/api/apps/v1beta1/types.go index 832ef34f45f6..08a36f5182d4 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/types.go +++ b/staging/src/k8s.io/api/apps/v1beta1/types.go @@ -153,9 +153,20 @@ const ( // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. type RollingUpdateStatefulSetStrategy struct { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. Partition *int32 `json:"partition,omitempty" protobuf:"varint,1,opt,name=partition"` + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"varint,2,opt,name=maxUnavailable"` } // PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine diff --git a/staging/src/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go b/staging/src/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go index e92881a35da1..f57b7b2efcfd 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/apps/v1beta1/types_swagger_doc_generated.go @@ -157,8 +157,9 @@ func (RollingUpdateDeployment) SwaggerDoc() map[string]string { } var map_RollingUpdateStatefulSetStrategy = map[string]string{ - "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", - "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned.", + "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", + "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", + "maxUnavailable": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", } func (RollingUpdateStatefulSetStrategy) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/apps/v1beta1/zz_generated.deepcopy.go b/staging/src/k8s.io/api/apps/v1beta1/zz_generated.deepcopy.go index be3fcc75b62c..185f868cd683 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/apps/v1beta1/zz_generated.deepcopy.go @@ -342,6 +342,11 @@ func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateState *out = new(int32) **out = **in } + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } return } diff --git a/staging/src/k8s.io/api/apps/v1beta2/generated.pb.go b/staging/src/k8s.io/api/apps/v1beta2/generated.pb.go index 46d478fb657f..df26908fcfc3 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/generated.pb.go +++ b/staging/src/k8s.io/api/apps/v1beta2/generated.pb.go @@ -988,150 +988,151 @@ func init() { } var fileDescriptor_42fe616264472f7e = []byte{ - // 2285 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcd, 0x6f, 0x1b, 0xc7, - 0x15, 0xd7, 0xf2, 0x43, 0x22, 0x47, 0x91, 0x64, 0x8f, 0x54, 0x89, 0x91, 0x5b, 0xd2, 0xd8, 0x18, - 0x8e, 0x12, 0xdb, 0xa4, 0xad, 0x7c, 0x20, 0xb1, 0xdb, 0xa4, 0xa2, 0x94, 0xda, 0x0e, 0xf4, 0xc1, - 0x8c, 0x2c, 0x07, 0x0d, 0xfa, 0xe1, 0x11, 0x39, 0xa6, 0x36, 0x5a, 0xee, 0x2e, 0x76, 0x67, 0x19, - 0x13, 0xbd, 0xf4, 0x5a, 0xa0, 0x40, 0xdb, 0x6b, 0xff, 0x89, 0xde, 0x8a, 0xa2, 0xb9, 0x15, 0x41, - 0xe0, 0x63, 0xd0, 0x4b, 0xd2, 0x0b, 0x51, 0x33, 0xa7, 0xa2, 0xe8, 0xad, 0xbd, 0x18, 0x28, 0x50, - 0xcc, 0xec, 0xec, 0xf7, 0xae, 0xb9, 0x54, 0x1c, 0xa5, 0x09, 0x72, 0x13, 0xe7, 0xbd, 0xf7, 0x9b, - 0xf7, 0x66, 0xde, 0x9b, 0xf7, 0x9b, 0x59, 0x81, 0x1f, 0x1e, 0xbf, 0x66, 0xd5, 0x15, 0xbd, 0x71, - 0x6c, 0x1f, 0x12, 0x53, 0x23, 0x94, 0x58, 0x8d, 0x3e, 0xd1, 0x3a, 0xba, 0xd9, 0x10, 0x02, 0x6c, - 0x28, 0x0d, 0x6c, 0x18, 0x56, 0xa3, 0x7f, 0xed, 0x90, 0x50, 0xbc, 0xde, 0xe8, 0x12, 0x8d, 0x98, - 0x98, 0x92, 0x4e, 0xdd, 0x30, 0x75, 0xaa, 0xc3, 0x15, 0x47, 0xb1, 0x8e, 0x0d, 0xa5, 0xce, 0x14, - 0xeb, 0x42, 0x71, 0xf5, 0x4a, 0x57, 0xa1, 0x47, 0xf6, 0x61, 0xbd, 0xad, 0xf7, 0x1a, 0x5d, 0xbd, - 0xab, 0x37, 0xb8, 0xfe, 0xa1, 0x7d, 0x9f, 0xff, 0xe2, 0x3f, 0xf8, 0x5f, 0x0e, 0xce, 0xaa, 0x1c, - 0x98, 0xb0, 0xad, 0x9b, 0xa4, 0xd1, 0xbf, 0x16, 0x9d, 0x6b, 0xf5, 0x65, 0x5f, 0xa7, 0x87, 0xdb, - 0x47, 0x8a, 0x46, 0xcc, 0x41, 0xc3, 0x38, 0xee, 0xb2, 0x01, 0xab, 0xd1, 0x23, 0x14, 0x27, 0x59, - 0x35, 0xd2, 0xac, 0x4c, 0x5b, 0xa3, 0x4a, 0x8f, 0xc4, 0x0c, 0x5e, 0x1d, 0x67, 0x60, 0xb5, 0x8f, - 0x48, 0x0f, 0xc7, 0xec, 0x5e, 0x4a, 0xb3, 0xb3, 0xa9, 0xa2, 0x36, 0x14, 0x8d, 0x5a, 0xd4, 0x8c, - 0x1a, 0xc9, 0xff, 0x91, 0x00, 0xdc, 0xd4, 0x35, 0x6a, 0xea, 0xaa, 0x4a, 0x4c, 0x44, 0xfa, 0x8a, - 0xa5, 0xe8, 0x1a, 0xbc, 0x07, 0x4a, 0x2c, 0x9e, 0x0e, 0xa6, 0xb8, 0x22, 0x9d, 0x97, 0xd6, 0x66, - 0xd7, 0xaf, 0xd6, 0xfd, 0x95, 0xf6, 0xe0, 0xeb, 0xc6, 0x71, 0x97, 0x0d, 0x58, 0x75, 0xa6, 0x5d, - 0xef, 0x5f, 0xab, 0xef, 0x1d, 0xbe, 0x4f, 0xda, 0x74, 0x87, 0x50, 0xdc, 0x84, 0x0f, 0x87, 0xb5, - 0xa9, 0xd1, 0xb0, 0x06, 0xfc, 0x31, 0xe4, 0xa1, 0xc2, 0x3d, 0x50, 0xe0, 0xe8, 0x39, 0x8e, 0x7e, - 0x25, 0x15, 0x5d, 0x04, 0x5d, 0x47, 0xf8, 0x83, 0xb7, 0x1e, 0x50, 0xa2, 0x31, 0xf7, 0x9a, 0xcf, - 0x08, 0xe8, 0xc2, 0x16, 0xa6, 0x18, 0x71, 0x20, 0x78, 0x19, 0x94, 0x4c, 0xe1, 0x7e, 0x25, 0x7f, - 0x5e, 0x5a, 0xcb, 0x37, 0xcf, 0x08, 0xad, 0x92, 0x1b, 0x16, 0xf2, 0x34, 0xe4, 0x87, 0x12, 0x58, - 0x8e, 0xc7, 0xbd, 0xad, 0x58, 0x14, 0xfe, 0x24, 0x16, 0x7b, 0x3d, 0x5b, 0xec, 0xcc, 0x9a, 0x47, - 0xee, 0x4d, 0xec, 0x8e, 0x04, 0xe2, 0x6e, 0x81, 0xa2, 0x42, 0x49, 0xcf, 0xaa, 0xe4, 0xce, 0xe7, - 0xd7, 0x66, 0xd7, 0x2f, 0xd5, 0x53, 0x12, 0xb8, 0x1e, 0xf7, 0xae, 0x39, 0x27, 0x70, 0x8b, 0xb7, - 0x19, 0x02, 0x72, 0x80, 0xe4, 0x5f, 0xe5, 0x40, 0x79, 0x0b, 0x93, 0x9e, 0xae, 0xed, 0x13, 0x7a, - 0x0a, 0x3b, 0x77, 0x0b, 0x14, 0x2c, 0x83, 0xb4, 0xc5, 0xce, 0x5d, 0x4c, 0x0d, 0xc0, 0xf3, 0x69, - 0xdf, 0x20, 0x6d, 0x7f, 0xcb, 0xd8, 0x2f, 0xc4, 0x11, 0x60, 0x0b, 0x4c, 0x5b, 0x14, 0x53, 0xdb, - 0xe2, 0x1b, 0x36, 0xbb, 0xbe, 0x96, 0x01, 0x8b, 0xeb, 0x37, 0xe7, 0x05, 0xda, 0xb4, 0xf3, 0x1b, - 0x09, 0x1c, 0xf9, 0x1f, 0x39, 0x00, 0x3d, 0xdd, 0x4d, 0x5d, 0xeb, 0x28, 0x94, 0xa5, 0xf3, 0x75, - 0x50, 0xa0, 0x03, 0x83, 0xf0, 0x05, 0x29, 0x37, 0x2f, 0xba, 0xae, 0xdc, 0x19, 0x18, 0xe4, 0xf1, - 0xb0, 0xb6, 0x1c, 0xb7, 0x60, 0x12, 0xc4, 0x6d, 0xe0, 0xb6, 0xe7, 0x64, 0x8e, 0x5b, 0xbf, 0x1c, - 0x9e, 0xfa, 0xf1, 0xb0, 0x96, 0x70, 0x76, 0xd4, 0x3d, 0xa4, 0xb0, 0x83, 0xb0, 0x0f, 0xa0, 0x8a, - 0x2d, 0x7a, 0xc7, 0xc4, 0x9a, 0xe5, 0xcc, 0xa4, 0xf4, 0x88, 0x08, 0xff, 0xc5, 0x6c, 0x1b, 0xc5, - 0x2c, 0x9a, 0xab, 0xc2, 0x0b, 0xb8, 0x1d, 0x43, 0x43, 0x09, 0x33, 0xc0, 0x8b, 0x60, 0xda, 0x24, - 0xd8, 0xd2, 0xb5, 0x4a, 0x81, 0x47, 0xe1, 0x2d, 0x20, 0xe2, 0xa3, 0x48, 0x48, 0xe1, 0x0b, 0x60, - 0xa6, 0x47, 0x2c, 0x0b, 0x77, 0x49, 0xa5, 0xc8, 0x15, 0x17, 0x84, 0xe2, 0xcc, 0x8e, 0x33, 0x8c, - 0x5c, 0xb9, 0xfc, 0x47, 0x09, 0xcc, 0x79, 0x2b, 0x77, 0x0a, 0x95, 0x73, 0x33, 0x5c, 0x39, 0xf2, - 0xf8, 0x64, 0x49, 0x29, 0x98, 0x8f, 0xf2, 0x01, 0xc7, 0x59, 0x3a, 0xc2, 0x9f, 0x82, 0x92, 0x45, - 0x54, 0xd2, 0xa6, 0xba, 0x29, 0x1c, 0x7f, 0x29, 0xa3, 0xe3, 0xf8, 0x90, 0xa8, 0xfb, 0xc2, 0xb4, - 0xf9, 0x0c, 0xf3, 0xdc, 0xfd, 0x85, 0x3c, 0x48, 0xf8, 0x0e, 0x28, 0x51, 0xd2, 0x33, 0x54, 0x4c, - 0x89, 0xa8, 0x9a, 0xe7, 0x82, 0xce, 0xb3, 0x9c, 0x61, 0x60, 0x2d, 0xbd, 0x73, 0x47, 0xa8, 0xf1, - 0x92, 0xf1, 0x16, 0xc3, 0x1d, 0x45, 0x1e, 0x0c, 0x34, 0xc0, 0xbc, 0x6d, 0x74, 0x98, 0x26, 0x65, - 0xc7, 0x79, 0x77, 0x20, 0x72, 0xe8, 0xea, 0xf8, 0x55, 0x39, 0x08, 0xd9, 0x35, 0x97, 0xc5, 0x2c, - 0xf3, 0xe1, 0x71, 0x14, 0xc1, 0x87, 0x1b, 0x60, 0xa1, 0xa7, 0x68, 0x88, 0xe0, 0xce, 0x60, 0x9f, - 0xb4, 0x75, 0xad, 0x63, 0xf1, 0x54, 0x2a, 0x36, 0x57, 0x04, 0xc0, 0xc2, 0x4e, 0x58, 0x8c, 0xa2, - 0xfa, 0x70, 0x1b, 0x2c, 0xb9, 0x07, 0xf0, 0x2d, 0xc5, 0xa2, 0xba, 0x39, 0xd8, 0x56, 0x7a, 0x0a, - 0xad, 0x4c, 0x73, 0x9c, 0xca, 0x68, 0x58, 0x5b, 0x42, 0x09, 0x72, 0x94, 0x68, 0x25, 0xff, 0x6e, - 0x1a, 0x2c, 0x44, 0xce, 0x05, 0x78, 0x17, 0x2c, 0xb7, 0x6d, 0xd3, 0x24, 0x1a, 0xdd, 0xb5, 0x7b, - 0x87, 0xc4, 0xdc, 0x6f, 0x1f, 0x91, 0x8e, 0xad, 0x92, 0x0e, 0xdf, 0xd6, 0x62, 0xb3, 0x2a, 0x7c, - 0x5d, 0xde, 0x4c, 0xd4, 0x42, 0x29, 0xd6, 0xf0, 0x6d, 0x00, 0x35, 0x3e, 0xb4, 0xa3, 0x58, 0x96, - 0x87, 0x99, 0xe3, 0x98, 0x5e, 0x29, 0xee, 0xc6, 0x34, 0x50, 0x82, 0x15, 0xf3, 0xb1, 0x43, 0x2c, - 0xc5, 0x24, 0x9d, 0xa8, 0x8f, 0xf9, 0xb0, 0x8f, 0x5b, 0x89, 0x5a, 0x28, 0xc5, 0x1a, 0xbe, 0x02, - 0x66, 0x9d, 0xd9, 0xf8, 0x9a, 0x8b, 0xcd, 0x59, 0x14, 0x60, 0xb3, 0xbb, 0xbe, 0x08, 0x05, 0xf5, - 0x58, 0x68, 0xfa, 0xa1, 0x45, 0xcc, 0x3e, 0xe9, 0xdc, 0x74, 0xc8, 0x01, 0xeb, 0xa0, 0x45, 0xde, - 0x41, 0xbd, 0xd0, 0xf6, 0x62, 0x1a, 0x28, 0xc1, 0x8a, 0x85, 0xe6, 0x64, 0x4d, 0x2c, 0xb4, 0xe9, - 0x70, 0x68, 0x07, 0x89, 0x5a, 0x28, 0xc5, 0x9a, 0xe5, 0x9e, 0xe3, 0xf2, 0x46, 0x1f, 0x2b, 0x2a, - 0x3e, 0x54, 0x49, 0x65, 0x26, 0x9c, 0x7b, 0xbb, 0x61, 0x31, 0x8a, 0xea, 0xc3, 0x9b, 0xe0, 0xac, - 0x33, 0x74, 0xa0, 0x61, 0x0f, 0xa4, 0xc4, 0x41, 0x9e, 0x15, 0x20, 0x67, 0x77, 0xa3, 0x0a, 0x28, - 0x6e, 0x03, 0xaf, 0x83, 0xf9, 0xb6, 0xae, 0xaa, 0x3c, 0x1f, 0x37, 0x75, 0x5b, 0xa3, 0x95, 0x32, - 0x47, 0x81, 0xac, 0x86, 0x36, 0x43, 0x12, 0x14, 0xd1, 0x84, 0x3f, 0x07, 0xa0, 0xed, 0x36, 0x06, - 0xab, 0x02, 0xc6, 0x30, 0x80, 0x78, 0x5b, 0xf2, 0x3b, 0xb3, 0x37, 0x64, 0xa1, 0x00, 0xa4, 0xfc, - 0x91, 0x04, 0x56, 0x52, 0x0a, 0x1d, 0xbe, 0x19, 0x6a, 0x82, 0x97, 0x22, 0x4d, 0xf0, 0x5c, 0x8a, - 0x59, 0xa0, 0x13, 0x1e, 0x81, 0x39, 0x46, 0x48, 0x14, 0xad, 0xeb, 0xa8, 0x88, 0xb3, 0xac, 0x91, - 0x1a, 0x00, 0x0a, 0x6a, 0xfb, 0xa7, 0xf2, 0xd9, 0xd1, 0xb0, 0x36, 0x17, 0x92, 0xa1, 0x30, 0xb0, - 0xfc, 0xeb, 0x1c, 0x00, 0x5b, 0xc4, 0x50, 0xf5, 0x41, 0x8f, 0x68, 0xa7, 0xc1, 0x69, 0x6e, 0x87, - 0x38, 0xcd, 0xf3, 0xe9, 0x5b, 0xe2, 0x39, 0x95, 0x4a, 0x6a, 0xde, 0x89, 0x90, 0x9a, 0x17, 0xb2, - 0x80, 0x3d, 0x99, 0xd5, 0x7c, 0x9a, 0x07, 0x8b, 0xbe, 0xb2, 0x4f, 0x6b, 0x6e, 0x84, 0x76, 0xf4, - 0xf9, 0xc8, 0x8e, 0xae, 0x24, 0x98, 0x7c, 0x69, 0xbc, 0xe6, 0x7d, 0x30, 0xcf, 0x58, 0x87, 0xb3, - 0x7f, 0x9c, 0xd3, 0x4c, 0x4f, 0xcc, 0x69, 0xbc, 0x4e, 0xb4, 0x1d, 0x42, 0x42, 0x11, 0xe4, 0x14, - 0x0e, 0x35, 0xf3, 0x75, 0xe4, 0x50, 0x7f, 0x92, 0xc0, 0xbc, 0xbf, 0x4d, 0xa7, 0x40, 0xa2, 0x6e, - 0x85, 0x49, 0xd4, 0x73, 0x19, 0x92, 0x33, 0x85, 0x45, 0x7d, 0x5a, 0x08, 0xba, 0xce, 0x69, 0xd4, - 0x1a, 0xbb, 0x82, 0x19, 0xaa, 0xd2, 0xc6, 0x96, 0xe8, 0xb7, 0xcf, 0x38, 0xd7, 0x2f, 0x67, 0x0c, - 0x79, 0xd2, 0x10, 0xe1, 0xca, 0x7d, 0xb9, 0x84, 0x2b, 0xff, 0x74, 0x08, 0xd7, 0x8f, 0x41, 0xc9, - 0x72, 0xa9, 0x56, 0x81, 0x43, 0x5e, 0xca, 0x54, 0xd8, 0x82, 0x65, 0x79, 0xd0, 0x1e, 0xbf, 0xf2, - 0xe0, 0x92, 0x98, 0x55, 0xf1, 0xab, 0x64, 0x56, 0x2c, 0xd1, 0x0d, 0x6c, 0x5b, 0xa4, 0xc3, 0x8b, - 0xaa, 0xe4, 0x27, 0x7a, 0x8b, 0x8f, 0x22, 0x21, 0x85, 0x07, 0x60, 0xc5, 0x30, 0xf5, 0xae, 0x49, - 0x2c, 0x6b, 0x8b, 0xe0, 0x8e, 0xaa, 0x68, 0xc4, 0x0d, 0xc0, 0xe9, 0x89, 0xe7, 0x46, 0xc3, 0xda, - 0x4a, 0x2b, 0x59, 0x05, 0xa5, 0xd9, 0xca, 0x7f, 0x29, 0x80, 0x33, 0xd1, 0xb3, 0x31, 0x85, 0xa6, - 0x48, 0x27, 0xa2, 0x29, 0x97, 0x03, 0x79, 0xea, 0x70, 0xb8, 0xc0, 0x53, 0x41, 0x2c, 0x57, 0x37, - 0xc0, 0x82, 0xa0, 0x25, 0xae, 0x50, 0x10, 0x35, 0x6f, 0x7b, 0x0e, 0xc2, 0x62, 0x14, 0xd5, 0x87, - 0x37, 0xc0, 0x9c, 0xc9, 0x99, 0x97, 0x0b, 0xe0, 0xb0, 0x97, 0xef, 0x08, 0x80, 0x39, 0x14, 0x14, - 0xa2, 0xb0, 0x2e, 0x63, 0x2e, 0x3e, 0x21, 0x71, 0x01, 0x0a, 0x61, 0xe6, 0xb2, 0x11, 0x55, 0x40, - 0x71, 0x1b, 0xb8, 0x03, 0x16, 0x6d, 0x2d, 0x0e, 0xe5, 0xe4, 0xda, 0x39, 0x01, 0xb5, 0x78, 0x10, - 0x57, 0x41, 0x49, 0x76, 0xf0, 0x5e, 0x88, 0xcc, 0x4c, 0xf3, 0xf3, 0xe4, 0x72, 0x86, 0x9a, 0xc8, - 0xcc, 0x66, 0x12, 0xa8, 0x56, 0x29, 0x2b, 0xd5, 0x92, 0x3f, 0x94, 0x00, 0x8c, 0xd7, 0xe1, 0xd8, - 0x97, 0x80, 0x98, 0x45, 0xa0, 0x63, 0x2a, 0xc9, 0xfc, 0xe7, 0x6a, 0x46, 0xfe, 0xe3, 0x1f, 0xa8, - 0xd9, 0x08, 0x90, 0x58, 0xe8, 0xd3, 0x79, 0xd4, 0xc9, 0x4a, 0x80, 0x7c, 0xa7, 0x9e, 0x02, 0x01, - 0x0a, 0x80, 0x3d, 0x99, 0x00, 0xfd, 0x33, 0x07, 0x16, 0x7d, 0xe5, 0xcc, 0x04, 0x28, 0xc1, 0xe4, - 0xdb, 0x87, 0x9d, 0x6c, 0xa4, 0xc4, 0x5f, 0xba, 0xff, 0x27, 0x52, 0xe2, 0x7b, 0x95, 0x42, 0x4a, - 0xfe, 0x90, 0x0b, 0xba, 0x3e, 0x21, 0x29, 0x79, 0x0a, 0x2f, 0x1c, 0x5f, 0x3b, 0x5e, 0x23, 0x7f, - 0x9c, 0x07, 0x67, 0xa2, 0x75, 0x18, 0x6a, 0x90, 0xd2, 0xd8, 0x06, 0xd9, 0x02, 0x4b, 0xf7, 0x6d, - 0x55, 0x1d, 0xf0, 0x18, 0x02, 0x5d, 0xd2, 0x69, 0xad, 0xdf, 0x15, 0x96, 0x4b, 0x3f, 0x4a, 0xd0, - 0x41, 0x89, 0x96, 0xf1, 0x7e, 0x59, 0xf8, 0xa2, 0xfd, 0xb2, 0x78, 0x82, 0x7e, 0x99, 0x4c, 0x39, - 0xf2, 0x27, 0xa2, 0x1c, 0x93, 0x35, 0xcb, 0x84, 0x83, 0x6b, 0xec, 0xd5, 0x7f, 0x24, 0x81, 0xe5, - 0xe4, 0x0b, 0x37, 0x54, 0xc1, 0x7c, 0x0f, 0x3f, 0x08, 0x3e, 0x7c, 0x8c, 0x6b, 0x22, 0x36, 0x55, - 0xd4, 0xba, 0xf3, 0xc9, 0xa8, 0x7e, 0x5b, 0xa3, 0x7b, 0xe6, 0x3e, 0x35, 0x15, 0xad, 0xeb, 0x74, - 0xde, 0x9d, 0x10, 0x16, 0x8a, 0x60, 0xc3, 0xf7, 0x40, 0xa9, 0x87, 0x1f, 0xec, 0xdb, 0x66, 0x37, - 0xa9, 0x43, 0x66, 0x9b, 0x87, 0x17, 0xc0, 0x8e, 0x40, 0x41, 0x1e, 0x9e, 0xfc, 0xb9, 0x04, 0x56, - 0x52, 0xba, 0xea, 0x37, 0x28, 0xca, 0x3d, 0x70, 0x3e, 0x14, 0x24, 0xab, 0x4a, 0x72, 0xdf, 0x56, - 0x79, 0x81, 0x0a, 0x22, 0x73, 0x09, 0x94, 0x0d, 0x6c, 0x52, 0xc5, 0xa3, 0xc1, 0xc5, 0xe6, 0xdc, - 0x68, 0x58, 0x2b, 0xb7, 0xdc, 0x41, 0xe4, 0xcb, 0xe5, 0xff, 0x4a, 0xa0, 0xb8, 0xdf, 0xc6, 0x2a, - 0x39, 0x05, 0x26, 0xb1, 0x15, 0x62, 0x12, 0xe9, 0xaf, 0xf4, 0xdc, 0x9f, 0x54, 0x12, 0xb1, 0x1d, - 0x21, 0x11, 0x17, 0xc6, 0xe0, 0x3c, 0x99, 0x3f, 0xbc, 0x0e, 0xca, 0xde, 0x74, 0x93, 0x1d, 0x6e, - 0xf2, 0xef, 0x73, 0x60, 0x36, 0x30, 0xc5, 0x84, 0x47, 0xe3, 0xbd, 0x50, 0x3f, 0x60, 0x45, 0xbf, - 0x9e, 0x25, 0x90, 0xba, 0x7b, 0xf6, 0xbf, 0xa5, 0x51, 0x33, 0x78, 0x79, 0x8c, 0xb7, 0x84, 0x37, - 0xc0, 0x3c, 0xc5, 0x66, 0x97, 0x50, 0x57, 0xc6, 0x17, 0xac, 0xec, 0x3f, 0xa6, 0xdc, 0x09, 0x49, - 0x51, 0x44, 0x7b, 0xf5, 0x06, 0x98, 0x0b, 0x4d, 0x06, 0xcf, 0x80, 0xfc, 0x31, 0x19, 0x38, 0x94, - 0x0a, 0xb1, 0x3f, 0xe1, 0x12, 0x28, 0xf6, 0xb1, 0x6a, 0x3b, 0x79, 0x5e, 0x46, 0xce, 0x8f, 0xeb, - 0xb9, 0xd7, 0x24, 0xf9, 0x37, 0x6c, 0x71, 0xfc, 0xe4, 0x3c, 0x85, 0xec, 0x7a, 0x3b, 0x94, 0x5d, - 0xe9, 0x1f, 0x0c, 0x83, 0x25, 0x93, 0x96, 0x63, 0x28, 0x92, 0x63, 0x2f, 0x66, 0x42, 0x7b, 0x72, - 0xa6, 0xfd, 0x2b, 0x07, 0x96, 0x02, 0xda, 0x3e, 0x55, 0xfd, 0x7e, 0x88, 0xaa, 0xae, 0x45, 0xa8, - 0x6a, 0x25, 0xc9, 0xe6, 0x5b, 0xae, 0x3a, 0x9e, 0xab, 0xfe, 0x59, 0x02, 0x0b, 0x81, 0xb5, 0x3b, - 0x05, 0xb2, 0x7a, 0x3b, 0x4c, 0x56, 0x2f, 0x64, 0x49, 0x9a, 0x14, 0xb6, 0xfa, 0x6f, 0x09, 0x34, - 0x02, 0x5a, 0x2d, 0x62, 0x5a, 0x8a, 0x45, 0x89, 0x46, 0xef, 0xea, 0xaa, 0xdd, 0x23, 0x9b, 0x2a, - 0x56, 0x7a, 0x88, 0xb0, 0x01, 0x45, 0xd7, 0x5a, 0xba, 0xaa, 0xb4, 0x07, 0x10, 0x83, 0xd9, 0x0f, - 0x8e, 0x88, 0xb6, 0x45, 0x54, 0x42, 0xc5, 0x67, 0xad, 0x72, 0xf3, 0x4d, 0xf7, 0x2b, 0xcf, 0xbb, - 0xbe, 0xe8, 0xf1, 0xb0, 0xb6, 0x96, 0x05, 0x91, 0x67, 0x59, 0x10, 0x13, 0xfe, 0x0c, 0x00, 0xf6, - 0x93, 0x9f, 0x47, 0x1d, 0x91, 0x70, 0x6f, 0xb8, 0x55, 0xf9, 0xae, 0x27, 0x99, 0x68, 0x82, 0x00, - 0xa2, 0xfc, 0xb7, 0x99, 0xd0, 0x9e, 0x7d, 0xe3, 0x9f, 0x0e, 0x7f, 0x01, 0x96, 0xfa, 0xfe, 0xea, - 0xb8, 0x0a, 0x8c, 0xd4, 0xe6, 0xa3, 0xd7, 0x63, 0x0f, 0x3e, 0x69, 0x5d, 0x7d, 0x2a, 0x7d, 0x37, - 0x01, 0x0e, 0x25, 0x4e, 0x02, 0x5f, 0x01, 0xb3, 0x8c, 0x8c, 0x2a, 0x6d, 0xb2, 0x8b, 0x7b, 0x6e, - 0x3d, 0x79, 0x5f, 0x05, 0xf7, 0x7d, 0x11, 0x0a, 0xea, 0xc1, 0x23, 0xb0, 0x68, 0xe8, 0x9d, 0x1d, - 0xac, 0xe1, 0x2e, 0x61, 0xec, 0xca, 0xd9, 0x4a, 0xfe, 0x9e, 0x58, 0x6e, 0xbe, 0xea, 0xbe, 0x15, - 0xb5, 0xe2, 0x2a, 0xec, 0xde, 0x9d, 0x30, 0xcc, 0x93, 0x20, 0x09, 0x12, 0x9a, 0xb1, 0x2f, 0xd9, - 0xce, 0x4b, 0xfe, 0x7a, 0x96, 0xc2, 0x3a, 0xe1, 0xb7, 0xec, 0xb4, 0xe7, 0xd2, 0xd2, 0x89, 0x9e, - 0x4b, 0x13, 0xee, 0x8d, 0xe5, 0x09, 0xef, 0x8d, 0x1f, 0x4b, 0xe0, 0x82, 0x91, 0xa1, 0x96, 0x2a, - 0x80, 0xaf, 0xcd, 0xad, 0x2c, 0x6b, 0x93, 0xa5, 0x36, 0x9b, 0x6b, 0xa3, 0x61, 0xed, 0x42, 0x16, - 0x4d, 0x94, 0xc9, 0x3f, 0xf9, 0xc3, 0x22, 0x38, 0x1b, 0xeb, 0x96, 0x5f, 0xe1, 0xe3, 0x6d, 0xec, - 0x26, 0x99, 0x9f, 0xe0, 0x26, 0xb9, 0x01, 0x16, 0xc4, 0xff, 0x03, 0x44, 0x2e, 0xa2, 0xde, 0xc6, - 0x6e, 0x86, 0xc5, 0x28, 0xaa, 0x9f, 0xf4, 0x78, 0x5c, 0x9c, 0xf0, 0xf1, 0x38, 0xe8, 0x85, 0xf8, - 0xff, 0x36, 0xa7, 0x0c, 0xe3, 0x5e, 0x88, 0x7f, 0x73, 0x8b, 0xea, 0x33, 0x92, 0xe8, 0xa0, 0x7a, - 0x08, 0x33, 0x61, 0x92, 0x78, 0x10, 0x92, 0xa2, 0x88, 0xf6, 0x17, 0xfa, 0xe6, 0x8d, 0x13, 0xbe, - 0x79, 0x5f, 0xc9, 0x92, 0xbf, 0xd9, 0xdf, 0x89, 0x13, 0x6f, 0xfc, 0xb3, 0x93, 0xdf, 0xf8, 0xe5, - 0xbf, 0x4a, 0xe0, 0xd9, 0xd4, 0xd3, 0x05, 0x6e, 0x84, 0x28, 0xdc, 0x95, 0x08, 0x85, 0xfb, 0x5e, - 0xaa, 0x61, 0x80, 0xc7, 0x99, 0xc9, 0x4f, 0xc8, 0xaf, 0x67, 0x7b, 0x42, 0x4e, 0xb8, 0x07, 0x8e, - 0x7f, 0x4b, 0x6e, 0xfe, 0xe0, 0xe1, 0xa3, 0xea, 0xd4, 0x27, 0x8f, 0xaa, 0x53, 0x9f, 0x3d, 0xaa, - 0x4e, 0xfd, 0x72, 0x54, 0x95, 0x1e, 0x8e, 0xaa, 0xd2, 0x27, 0xa3, 0xaa, 0xf4, 0xd9, 0xa8, 0x2a, - 0xfd, 0x7d, 0x54, 0x95, 0x7e, 0xfb, 0x79, 0x75, 0xea, 0xbd, 0x95, 0x94, 0xff, 0xb8, 0xfd, 0x5f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x5c, 0xf5, 0x97, 0xcb, 0xa4, 0x2b, 0x00, 0x00, + // 2295 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcf, 0x6f, 0x1b, 0xc7, + 0xf5, 0xd7, 0xf2, 0x87, 0x44, 0x8e, 0x2c, 0xc9, 0x1e, 0xe9, 0x2b, 0x31, 0xf2, 0xb7, 0xa4, 0xb1, + 0x31, 0x1c, 0x25, 0xb6, 0x49, 0x5b, 0xf9, 0x81, 0xc4, 0x6e, 0x93, 0x8a, 0x52, 0x6a, 0x3b, 0x90, + 0x64, 0x66, 0x64, 0x39, 0x68, 0xd0, 0x1f, 0x1e, 0x91, 0x63, 0x6a, 0xa3, 0xe5, 0xee, 0x62, 0x77, + 0x96, 0x31, 0xd1, 0x4b, 0xaf, 0x05, 0x0a, 0xb4, 0xbd, 0xf6, 0x9f, 0xe8, 0xad, 0x28, 0x1a, 0xf4, + 0x52, 0x04, 0x81, 0x8f, 0x41, 0x2f, 0x49, 0x2f, 0x44, 0xcd, 0x9c, 0x8a, 0xa2, 0xb7, 0xf6, 0x62, + 0xa0, 0x40, 0x31, 0xb3, 0xb3, 0xbf, 0x77, 0xcd, 0xa5, 0x62, 0x2b, 0x4d, 0x90, 0x1b, 0x77, 0xde, + 0x7b, 0x9f, 0x79, 0x33, 0xf3, 0xde, 0xbc, 0xcf, 0xcc, 0x10, 0x7c, 0xff, 0xe8, 0x75, 0xab, 0xae, + 0xe8, 0x8d, 0x23, 0xfb, 0x80, 0x98, 0x1a, 0xa1, 0xc4, 0x6a, 0xf4, 0x89, 0xd6, 0xd1, 0xcd, 0x86, + 0x10, 0x60, 0x43, 0x69, 0x60, 0xc3, 0xb0, 0x1a, 0xfd, 0xab, 0x07, 0x84, 0xe2, 0xf5, 0x46, 0x97, + 0x68, 0xc4, 0xc4, 0x94, 0x74, 0xea, 0x86, 0xa9, 0x53, 0x1d, 0xae, 0x38, 0x8a, 0x75, 0x6c, 0x28, + 0x75, 0xa6, 0x58, 0x17, 0x8a, 0xab, 0x97, 0xbb, 0x0a, 0x3d, 0xb4, 0x0f, 0xea, 0x6d, 0xbd, 0xd7, + 0xe8, 0xea, 0x5d, 0xbd, 0xc1, 0xf5, 0x0f, 0xec, 0xfb, 0xfc, 0x8b, 0x7f, 0xf0, 0x5f, 0x0e, 0xce, + 0xaa, 0x1c, 0xe8, 0xb0, 0xad, 0x9b, 0xa4, 0xd1, 0xbf, 0x1a, 0xed, 0x6b, 0xf5, 0x15, 0x5f, 0xa7, + 0x87, 0xdb, 0x87, 0x8a, 0x46, 0xcc, 0x41, 0xc3, 0x38, 0xea, 0xb2, 0x06, 0xab, 0xd1, 0x23, 0x14, + 0x27, 0x59, 0x35, 0xd2, 0xac, 0x4c, 0x5b, 0xa3, 0x4a, 0x8f, 0xc4, 0x0c, 0x5e, 0x1b, 0x67, 0x60, + 0xb5, 0x0f, 0x49, 0x0f, 0xc7, 0xec, 0x5e, 0x4e, 0xb3, 0xb3, 0xa9, 0xa2, 0x36, 0x14, 0x8d, 0x5a, + 0xd4, 0x8c, 0x1a, 0xc9, 0xff, 0x96, 0x00, 0xdc, 0xd4, 0x35, 0x6a, 0xea, 0xaa, 0x4a, 0x4c, 0x44, + 0xfa, 0x8a, 0xa5, 0xe8, 0x1a, 0xbc, 0x07, 0x4a, 0x6c, 0x3c, 0x1d, 0x4c, 0x71, 0x45, 0x3a, 0x27, + 0xad, 0xcd, 0xae, 0x5f, 0xa9, 0xfb, 0x33, 0xed, 0xc1, 0xd7, 0x8d, 0xa3, 0x2e, 0x6b, 0xb0, 0xea, + 0x4c, 0xbb, 0xde, 0xbf, 0x5a, 0xbf, 0x7d, 0xf0, 0x01, 0x69, 0xd3, 0x1d, 0x42, 0x71, 0x13, 0x3e, + 0x1c, 0xd6, 0xa6, 0x46, 0xc3, 0x1a, 0xf0, 0xdb, 0x90, 0x87, 0x0a, 0x6f, 0x83, 0x02, 0x47, 0xcf, + 0x71, 0xf4, 0xcb, 0xa9, 0xe8, 0x62, 0xd0, 0x75, 0x84, 0x3f, 0x7c, 0xfb, 0x01, 0x25, 0x1a, 0x73, + 0xaf, 0x79, 0x4a, 0x40, 0x17, 0xb6, 0x30, 0xc5, 0x88, 0x03, 0xc1, 0x4b, 0xa0, 0x64, 0x0a, 0xf7, + 0x2b, 0xf9, 0x73, 0xd2, 0x5a, 0xbe, 0x79, 0x5a, 0x68, 0x95, 0xdc, 0x61, 0x21, 0x4f, 0x43, 0x7e, + 0x28, 0x81, 0xe5, 0xf8, 0xb8, 0xb7, 0x15, 0x8b, 0xc2, 0x1f, 0xc5, 0xc6, 0x5e, 0xcf, 0x36, 0x76, + 0x66, 0xcd, 0x47, 0xee, 0x75, 0xec, 0xb6, 0x04, 0xc6, 0xdd, 0x02, 0x45, 0x85, 0x92, 0x9e, 0x55, + 0xc9, 0x9d, 0xcb, 0xaf, 0xcd, 0xae, 0x5f, 0xac, 0xa7, 0x04, 0x70, 0x3d, 0xee, 0x5d, 0x73, 0x4e, + 0xe0, 0x16, 0x6f, 0x31, 0x04, 0xe4, 0x00, 0xc9, 0xbf, 0xc8, 0x81, 0xf2, 0x16, 0x26, 0x3d, 0x5d, + 0xdb, 0x23, 0xf4, 0x04, 0x56, 0xee, 0x26, 0x28, 0x58, 0x06, 0x69, 0x8b, 0x95, 0xbb, 0x90, 0x3a, + 0x00, 0xcf, 0xa7, 0x3d, 0x83, 0xb4, 0xfd, 0x25, 0x63, 0x5f, 0x88, 0x23, 0xc0, 0x16, 0x98, 0xb6, + 0x28, 0xa6, 0xb6, 0xc5, 0x17, 0x6c, 0x76, 0x7d, 0x2d, 0x03, 0x16, 0xd7, 0x6f, 0xce, 0x0b, 0xb4, + 0x69, 0xe7, 0x1b, 0x09, 0x1c, 0xf9, 0xef, 0x39, 0x00, 0x3d, 0xdd, 0x4d, 0x5d, 0xeb, 0x28, 0x94, + 0x85, 0xf3, 0x35, 0x50, 0xa0, 0x03, 0x83, 0xf0, 0x09, 0x29, 0x37, 0x2f, 0xb8, 0xae, 0xdc, 0x19, + 0x18, 0xe4, 0xf1, 0xb0, 0xb6, 0x1c, 0xb7, 0x60, 0x12, 0xc4, 0x6d, 0xe0, 0xb6, 0xe7, 0x64, 0x8e, + 0x5b, 0xbf, 0x12, 0xee, 0xfa, 0xf1, 0xb0, 0x96, 0xb0, 0x77, 0xd4, 0x3d, 0xa4, 0xb0, 0x83, 0xb0, + 0x0f, 0xa0, 0x8a, 0x2d, 0x7a, 0xc7, 0xc4, 0x9a, 0xe5, 0xf4, 0xa4, 0xf4, 0x88, 0x18, 0xfe, 0x4b, + 0xd9, 0x16, 0x8a, 0x59, 0x34, 0x57, 0x85, 0x17, 0x70, 0x3b, 0x86, 0x86, 0x12, 0x7a, 0x80, 0x17, + 0xc0, 0xb4, 0x49, 0xb0, 0xa5, 0x6b, 0x95, 0x02, 0x1f, 0x85, 0x37, 0x81, 0x88, 0xb7, 0x22, 0x21, + 0x85, 0x2f, 0x82, 0x99, 0x1e, 0xb1, 0x2c, 0xdc, 0x25, 0x95, 0x22, 0x57, 0x5c, 0x10, 0x8a, 0x33, + 0x3b, 0x4e, 0x33, 0x72, 0xe5, 0xf2, 0xef, 0x25, 0x30, 0xe7, 0xcd, 0xdc, 0x09, 0x64, 0xce, 0x8d, + 0x70, 0xe6, 0xc8, 0xe3, 0x83, 0x25, 0x25, 0x61, 0x3e, 0xce, 0x07, 0x1c, 0x67, 0xe1, 0x08, 0x7f, + 0x0c, 0x4a, 0x16, 0x51, 0x49, 0x9b, 0xea, 0xa6, 0x70, 0xfc, 0xe5, 0x8c, 0x8e, 0xe3, 0x03, 0xa2, + 0xee, 0x09, 0xd3, 0xe6, 0x29, 0xe6, 0xb9, 0xfb, 0x85, 0x3c, 0x48, 0xf8, 0x2e, 0x28, 0x51, 0xd2, + 0x33, 0x54, 0x4c, 0x89, 0xc8, 0x9a, 0xe7, 0x83, 0xce, 0xb3, 0x98, 0x61, 0x60, 0x2d, 0xbd, 0x73, + 0x47, 0xa8, 0xf1, 0x94, 0xf1, 0x26, 0xc3, 0x6d, 0x45, 0x1e, 0x0c, 0x34, 0xc0, 0xbc, 0x6d, 0x74, + 0x98, 0x26, 0x65, 0xdb, 0x79, 0x77, 0x20, 0x62, 0xe8, 0xca, 0xf8, 0x59, 0xd9, 0x0f, 0xd9, 0x35, + 0x97, 0x45, 0x2f, 0xf3, 0xe1, 0x76, 0x14, 0xc1, 0x87, 0x1b, 0x60, 0xa1, 0xa7, 0x68, 0x88, 0xe0, + 0xce, 0x60, 0x8f, 0xb4, 0x75, 0xad, 0x63, 0xf1, 0x50, 0x2a, 0x36, 0x57, 0x04, 0xc0, 0xc2, 0x4e, + 0x58, 0x8c, 0xa2, 0xfa, 0x70, 0x1b, 0x2c, 0xb9, 0x1b, 0xf0, 0x4d, 0xc5, 0xa2, 0xba, 0x39, 0xd8, + 0x56, 0x7a, 0x0a, 0xad, 0x4c, 0x73, 0x9c, 0xca, 0x68, 0x58, 0x5b, 0x42, 0x09, 0x72, 0x94, 0x68, + 0x25, 0xff, 0x66, 0x1a, 0x2c, 0x44, 0xf6, 0x05, 0x78, 0x17, 0x2c, 0xb7, 0x6d, 0xd3, 0x24, 0x1a, + 0xdd, 0xb5, 0x7b, 0x07, 0xc4, 0xdc, 0x6b, 0x1f, 0x92, 0x8e, 0xad, 0x92, 0x0e, 0x5f, 0xd6, 0x62, + 0xb3, 0x2a, 0x7c, 0x5d, 0xde, 0x4c, 0xd4, 0x42, 0x29, 0xd6, 0xf0, 0x1d, 0x00, 0x35, 0xde, 0xb4, + 0xa3, 0x58, 0x96, 0x87, 0x99, 0xe3, 0x98, 0x5e, 0x2a, 0xee, 0xc6, 0x34, 0x50, 0x82, 0x15, 0xf3, + 0xb1, 0x43, 0x2c, 0xc5, 0x24, 0x9d, 0xa8, 0x8f, 0xf9, 0xb0, 0x8f, 0x5b, 0x89, 0x5a, 0x28, 0xc5, + 0x1a, 0xbe, 0x0a, 0x66, 0x9d, 0xde, 0xf8, 0x9c, 0x8b, 0xc5, 0x59, 0x14, 0x60, 0xb3, 0xbb, 0xbe, + 0x08, 0x05, 0xf5, 0xd8, 0xd0, 0xf4, 0x03, 0x8b, 0x98, 0x7d, 0xd2, 0xb9, 0xe1, 0x90, 0x03, 0x56, + 0x41, 0x8b, 0xbc, 0x82, 0x7a, 0x43, 0xbb, 0x1d, 0xd3, 0x40, 0x09, 0x56, 0x6c, 0x68, 0x4e, 0xd4, + 0xc4, 0x86, 0x36, 0x1d, 0x1e, 0xda, 0x7e, 0xa2, 0x16, 0x4a, 0xb1, 0x66, 0xb1, 0xe7, 0xb8, 0xbc, + 0xd1, 0xc7, 0x8a, 0x8a, 0x0f, 0x54, 0x52, 0x99, 0x09, 0xc7, 0xde, 0x6e, 0x58, 0x8c, 0xa2, 0xfa, + 0xf0, 0x06, 0x38, 0xe3, 0x34, 0xed, 0x6b, 0xd8, 0x03, 0x29, 0x71, 0x90, 0xe7, 0x04, 0xc8, 0x99, + 0xdd, 0xa8, 0x02, 0x8a, 0xdb, 0xc0, 0x6b, 0x60, 0xbe, 0xad, 0xab, 0x2a, 0x8f, 0xc7, 0x4d, 0xdd, + 0xd6, 0x68, 0xa5, 0xcc, 0x51, 0x20, 0xcb, 0xa1, 0xcd, 0x90, 0x04, 0x45, 0x34, 0xe1, 0x4f, 0x01, + 0x68, 0xbb, 0x85, 0xc1, 0xaa, 0x80, 0x31, 0x0c, 0x20, 0x5e, 0x96, 0xfc, 0xca, 0xec, 0x35, 0x59, + 0x28, 0x00, 0x29, 0x7f, 0x2c, 0x81, 0x95, 0x94, 0x44, 0x87, 0x6f, 0x85, 0x8a, 0xe0, 0xc5, 0x48, + 0x11, 0x3c, 0x9b, 0x62, 0x16, 0xa8, 0x84, 0x87, 0x60, 0x8e, 0x11, 0x12, 0x45, 0xeb, 0x3a, 0x2a, + 0x62, 0x2f, 0x6b, 0xa4, 0x0e, 0x00, 0x05, 0xb5, 0xfd, 0x5d, 0xf9, 0xcc, 0x68, 0x58, 0x9b, 0x0b, + 0xc9, 0x50, 0x18, 0x58, 0xfe, 0x65, 0x0e, 0x80, 0x2d, 0x62, 0xa8, 0xfa, 0xa0, 0x47, 0xb4, 0x93, + 0xe0, 0x34, 0xb7, 0x42, 0x9c, 0xe6, 0x85, 0xf4, 0x25, 0xf1, 0x9c, 0x4a, 0x25, 0x35, 0xef, 0x46, + 0x48, 0xcd, 0x8b, 0x59, 0xc0, 0x9e, 0xcc, 0x6a, 0x3e, 0xcb, 0x83, 0x45, 0x5f, 0xd9, 0xa7, 0x35, + 0xd7, 0x43, 0x2b, 0xfa, 0x42, 0x64, 0x45, 0x57, 0x12, 0x4c, 0x9e, 0x19, 0xaf, 0xf9, 0x00, 0xcc, + 0x33, 0xd6, 0xe1, 0xac, 0x1f, 0xe7, 0x34, 0xd3, 0x13, 0x73, 0x1a, 0xaf, 0x12, 0x6d, 0x87, 0x90, + 0x50, 0x04, 0x39, 0x85, 0x43, 0xcd, 0x7c, 0x1d, 0x39, 0xd4, 0x1f, 0x24, 0x30, 0xef, 0x2f, 0xd3, + 0x09, 0x90, 0xa8, 0x9b, 0x61, 0x12, 0xf5, 0x7c, 0x86, 0xe0, 0x4c, 0x61, 0x51, 0x9f, 0x15, 0x82, + 0xae, 0x73, 0x1a, 0xb5, 0xc6, 0x8e, 0x60, 0x86, 0xaa, 0xb4, 0xb1, 0x25, 0xea, 0xed, 0x29, 0xe7, + 0xf8, 0xe5, 0xb4, 0x21, 0x4f, 0x1a, 0x22, 0x5c, 0xb9, 0x67, 0x4b, 0xb8, 0xf2, 0x4f, 0x87, 0x70, + 0xfd, 0x10, 0x94, 0x2c, 0x97, 0x6a, 0x15, 0x38, 0xe4, 0xc5, 0x4c, 0x89, 0x2d, 0x58, 0x96, 0x07, + 0xed, 0xf1, 0x2b, 0x0f, 0x2e, 0x89, 0x59, 0x15, 0xbf, 0x4a, 0x66, 0xc5, 0x02, 0xdd, 0xc0, 0xb6, + 0x45, 0x3a, 0x3c, 0xa9, 0x4a, 0x7e, 0xa0, 0xb7, 0x78, 0x2b, 0x12, 0x52, 0xb8, 0x0f, 0x56, 0x0c, + 0x53, 0xef, 0x9a, 0xc4, 0xb2, 0xb6, 0x08, 0xee, 0xa8, 0x8a, 0x46, 0xdc, 0x01, 0x38, 0x35, 0xf1, + 0xec, 0x68, 0x58, 0x5b, 0x69, 0x25, 0xab, 0xa0, 0x34, 0x5b, 0xf9, 0xcf, 0x05, 0x70, 0x3a, 0xba, + 0x37, 0xa6, 0xd0, 0x14, 0xe9, 0x58, 0x34, 0xe5, 0x52, 0x20, 0x4e, 0x1d, 0x0e, 0x17, 0xb8, 0x2a, + 0x88, 0xc5, 0xea, 0x06, 0x58, 0x10, 0xb4, 0xc4, 0x15, 0x0a, 0xa2, 0xe6, 0x2d, 0xcf, 0x7e, 0x58, + 0x8c, 0xa2, 0xfa, 0xf0, 0x3a, 0x98, 0x33, 0x39, 0xf3, 0x72, 0x01, 0x1c, 0xf6, 0xf2, 0x7f, 0x02, + 0x60, 0x0e, 0x05, 0x85, 0x28, 0xac, 0xcb, 0x98, 0x8b, 0x4f, 0x48, 0x5c, 0x80, 0x42, 0x98, 0xb9, + 0x6c, 0x44, 0x15, 0x50, 0xdc, 0x06, 0xee, 0x80, 0x45, 0x5b, 0x8b, 0x43, 0x39, 0xb1, 0x76, 0x56, + 0x40, 0x2d, 0xee, 0xc7, 0x55, 0x50, 0x92, 0x1d, 0xbc, 0x17, 0x22, 0x33, 0xd3, 0x7c, 0x3f, 0xb9, + 0x94, 0x21, 0x27, 0x32, 0xb3, 0x99, 0x04, 0xaa, 0x55, 0xca, 0x4a, 0xb5, 0xe4, 0x8f, 0x24, 0x00, + 0xe3, 0x79, 0x38, 0xf6, 0x26, 0x20, 0x66, 0x11, 0xa8, 0x98, 0x4a, 0x32, 0xff, 0xb9, 0x92, 0x91, + 0xff, 0xf8, 0x1b, 0x6a, 0x36, 0x02, 0x24, 0x26, 0xfa, 0x64, 0x2e, 0x75, 0xb2, 0x12, 0x20, 0xdf, + 0xa9, 0xa7, 0x40, 0x80, 0x02, 0x60, 0x4f, 0x26, 0x40, 0xff, 0xc8, 0x81, 0x45, 0x5f, 0x39, 0x33, + 0x01, 0x4a, 0x30, 0xf9, 0xf6, 0x62, 0x27, 0x1b, 0x29, 0xf1, 0xa7, 0xee, 0x7f, 0x89, 0x94, 0xf8, + 0x5e, 0xa5, 0x90, 0x92, 0xdf, 0xe5, 0x82, 0xae, 0x4f, 0x48, 0x4a, 0x9e, 0xc2, 0x0d, 0xc7, 0xd7, + 0x8e, 0xd7, 0xc8, 0x9f, 0xe4, 0xc1, 0xe9, 0x68, 0x1e, 0x86, 0x0a, 0xa4, 0x34, 0xb6, 0x40, 0xb6, + 0xc0, 0xd2, 0x7d, 0x5b, 0x55, 0x07, 0x7c, 0x0c, 0x81, 0x2a, 0xe9, 0x94, 0xd6, 0xff, 0x17, 0x96, + 0x4b, 0x3f, 0x48, 0xd0, 0x41, 0x89, 0x96, 0xf1, 0x7a, 0x59, 0xf8, 0xb2, 0xf5, 0xb2, 0x78, 0x8c, + 0x7a, 0x99, 0x4c, 0x39, 0xf2, 0xc7, 0xa2, 0x1c, 0x93, 0x15, 0xcb, 0x84, 0x8d, 0x6b, 0xec, 0xd1, + 0x7f, 0x24, 0x81, 0xe5, 0xe4, 0x03, 0x37, 0x54, 0xc1, 0x7c, 0x0f, 0x3f, 0x08, 0x5e, 0x7c, 0x8c, + 0x2b, 0x22, 0x36, 0x55, 0xd4, 0xba, 0xf3, 0x64, 0x54, 0xbf, 0xa5, 0xd1, 0xdb, 0xe6, 0x1e, 0x35, + 0x15, 0xad, 0xeb, 0x54, 0xde, 0x9d, 0x10, 0x16, 0x8a, 0x60, 0xc3, 0xf7, 0x41, 0xa9, 0x87, 0x1f, + 0xec, 0xd9, 0x66, 0x37, 0xa9, 0x42, 0x66, 0xeb, 0x87, 0x27, 0xc0, 0x8e, 0x40, 0x41, 0x1e, 0x9e, + 0xfc, 0x85, 0x04, 0x56, 0x52, 0xaa, 0xea, 0x37, 0x68, 0x94, 0x7f, 0x92, 0xc0, 0xb9, 0xd0, 0x28, + 0x59, 0x5a, 0x92, 0xfb, 0xb6, 0xca, 0x33, 0x54, 0x30, 0x99, 0x8b, 0xa0, 0x6c, 0x60, 0x93, 0x2a, + 0x1e, 0x0f, 0x2e, 0x36, 0xe7, 0x46, 0xc3, 0x5a, 0xb9, 0xe5, 0x36, 0x22, 0x5f, 0x9e, 0x30, 0x37, + 0xb9, 0x67, 0x37, 0x37, 0xf2, 0x7f, 0x24, 0x50, 0xdc, 0x6b, 0x63, 0x95, 0x9c, 0x00, 0x71, 0xd9, + 0x0a, 0x11, 0x97, 0xf4, 0x47, 0x01, 0xee, 0x4f, 0x2a, 0x67, 0xd9, 0x8e, 0x70, 0x96, 0xf3, 0x63, + 0x70, 0x9e, 0x4c, 0x57, 0xde, 0x00, 0x65, 0xaf, 0xbb, 0xc9, 0xf6, 0x52, 0xf9, 0xb7, 0x39, 0x30, + 0x1b, 0xe8, 0x62, 0xc2, 0x9d, 0xf8, 0x5e, 0xa8, 0xfc, 0xb0, 0x3d, 0x66, 0x3d, 0xcb, 0x40, 0xea, + 0x6e, 0xa9, 0x79, 0x5b, 0xa3, 0x66, 0xf0, 0xac, 0x1a, 0xaf, 0x40, 0x6f, 0x82, 0x79, 0x8a, 0xcd, + 0x2e, 0xa1, 0xae, 0x8c, 0x4f, 0x58, 0xd9, 0xbf, 0xbb, 0xb9, 0x13, 0x92, 0xa2, 0x88, 0xf6, 0xea, + 0x75, 0x30, 0x17, 0xea, 0x0c, 0x9e, 0x06, 0xf9, 0x23, 0x32, 0x70, 0x18, 0x1c, 0x62, 0x3f, 0xe1, + 0x12, 0x28, 0xf6, 0xb1, 0x6a, 0x3b, 0x21, 0x5a, 0x46, 0xce, 0xc7, 0xb5, 0xdc, 0xeb, 0x92, 0xfc, + 0x2b, 0x36, 0x39, 0x7e, 0x2a, 0x9c, 0x40, 0x74, 0xbd, 0x13, 0x8a, 0xae, 0xf4, 0xf7, 0xc9, 0x60, + 0x82, 0xa6, 0xc5, 0x18, 0x8a, 0xc4, 0xd8, 0x4b, 0x99, 0xd0, 0x9e, 0x1c, 0x69, 0xff, 0xcc, 0x81, + 0xa5, 0x80, 0xb6, 0xcf, 0x8c, 0xbf, 0x1b, 0x62, 0xc6, 0x6b, 0x11, 0x66, 0x5c, 0x49, 0xb2, 0xf9, + 0x96, 0x1a, 0x8f, 0xa7, 0xc6, 0x7f, 0x94, 0xc0, 0x42, 0x60, 0xee, 0x4e, 0x80, 0x1b, 0xdf, 0x0a, + 0x73, 0xe3, 0xf3, 0x59, 0x82, 0x26, 0x85, 0x1c, 0xff, 0x4b, 0x02, 0x8d, 0x80, 0x56, 0x8b, 0x98, + 0x96, 0x62, 0x51, 0xa2, 0xd1, 0xbb, 0xba, 0x6a, 0xf7, 0xc8, 0xa6, 0x8a, 0x95, 0x1e, 0x22, 0xac, + 0x41, 0xd1, 0xb5, 0x96, 0xae, 0x2a, 0xed, 0x01, 0xc4, 0x60, 0xf6, 0xc3, 0x43, 0xa2, 0x6d, 0x11, + 0x95, 0x50, 0xf1, 0x8a, 0x56, 0x6e, 0xbe, 0xe5, 0x3e, 0x2a, 0xbd, 0xe7, 0x8b, 0x1e, 0x0f, 0x6b, + 0x6b, 0x59, 0x10, 0x79, 0x94, 0x05, 0x31, 0xe1, 0x4f, 0x00, 0x60, 0x9f, 0x7c, 0x3f, 0xea, 0x88, + 0x80, 0x7b, 0xd3, 0xcd, 0xca, 0xf7, 0x3c, 0xc9, 0x44, 0x1d, 0x04, 0x10, 0xe5, 0xbf, 0xce, 0x84, + 0xd6, 0xec, 0x1b, 0x7f, 0x53, 0xf9, 0x33, 0xb0, 0xd4, 0xf7, 0x67, 0xc7, 0x55, 0x60, 0x1c, 0x3a, + 0x1f, 0x3d, 0x8d, 0x7b, 0xf0, 0x49, 0xf3, 0xea, 0x33, 0xf7, 0xbb, 0x09, 0x70, 0x28, 0xb1, 0x13, + 0xf8, 0x2a, 0x98, 0x65, 0xdc, 0x57, 0x69, 0x93, 0x5d, 0xdc, 0x73, 0xf3, 0xc9, 0x7b, 0x84, 0xdc, + 0xf3, 0x45, 0x28, 0xa8, 0x07, 0x0f, 0xc1, 0xa2, 0xa1, 0x77, 0x76, 0xb0, 0x86, 0xbb, 0x84, 0x91, + 0x39, 0x67, 0x29, 0xf9, 0xf5, 0x65, 0xb9, 0xf9, 0x9a, 0x7b, 0x35, 0xd5, 0x8a, 0xab, 0xb0, 0x63, + 0x7e, 0x42, 0x33, 0x0f, 0x82, 0x24, 0x48, 0x68, 0xc6, 0x1e, 0xce, 0x9d, 0x87, 0x83, 0xf5, 0x2c, + 0x89, 0x75, 0xcc, 0xa7, 0xf3, 0xb4, 0xdb, 0xd9, 0xd2, 0xb1, 0x6e, 0x67, 0x13, 0x8e, 0xa9, 0xe5, + 0x09, 0x8f, 0xa9, 0x9f, 0x48, 0xe0, 0xbc, 0x91, 0x21, 0x97, 0x2a, 0x80, 0xcf, 0xcd, 0xcd, 0x2c, + 0x73, 0x93, 0x25, 0x37, 0x9b, 0x6b, 0xa3, 0x61, 0xed, 0x7c, 0x16, 0x4d, 0x94, 0xc9, 0x3f, 0xf9, + 0xa3, 0x22, 0x38, 0x13, 0xab, 0x96, 0x5f, 0xe1, 0x5d, 0x71, 0xec, 0xe0, 0x9a, 0x9f, 0xe0, 0xe0, + 0xba, 0x01, 0x16, 0xc4, 0xdf, 0x0f, 0x22, 0xe7, 0x5e, 0x6f, 0x61, 0x37, 0xc3, 0x62, 0x14, 0xd5, + 0x4f, 0xba, 0xab, 0x2e, 0x4e, 0x78, 0x57, 0x1d, 0xf4, 0x42, 0xfc, 0x9d, 0xce, 0x49, 0xc3, 0xb8, + 0x17, 0xe2, 0x5f, 0x75, 0x51, 0x7d, 0x46, 0x12, 0x1d, 0x54, 0x0f, 0x61, 0x26, 0x4c, 0x12, 0xf7, + 0x43, 0x52, 0x14, 0xd1, 0xfe, 0x52, 0x4f, 0xec, 0x38, 0xe1, 0x89, 0xfd, 0x72, 0x96, 0xf8, 0xcd, + 0x7e, 0x2d, 0x9d, 0x78, 0xc1, 0x30, 0x3b, 0xf9, 0x05, 0x83, 0xfc, 0x17, 0x09, 0x3c, 0x97, 0xba, + 0xbb, 0xc0, 0x8d, 0x10, 0x85, 0xbb, 0x1c, 0xa1, 0x70, 0xdf, 0x49, 0x35, 0x0c, 0xf0, 0x38, 0x33, + 0xf9, 0xc6, 0xfa, 0x8d, 0x6c, 0x37, 0xd6, 0x09, 0xa7, 0xce, 0xf1, 0x57, 0xd7, 0xcd, 0xef, 0x3d, + 0x7c, 0x54, 0x9d, 0xfa, 0xf4, 0x51, 0x75, 0xea, 0xf3, 0x47, 0xd5, 0xa9, 0x9f, 0x8f, 0xaa, 0xd2, + 0xc3, 0x51, 0x55, 0xfa, 0x74, 0x54, 0x95, 0x3e, 0x1f, 0x55, 0xa5, 0xbf, 0x8d, 0xaa, 0xd2, 0xaf, + 0xbf, 0xa8, 0x4e, 0xbd, 0xbf, 0x92, 0xf2, 0x07, 0xdf, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff, 0x5c, + 0xbc, 0x64, 0x9c, 0x13, 0x2c, 0x00, 0x00, } func (m *ControllerRevision) Marshal() (dAtA []byte, err error) { @@ -2265,6 +2266,18 @@ func (m *RollingUpdateStatefulSetStrategy) MarshalToSizedBuffer(dAtA []byte) (in _ = i var l int _ = l + if m.MaxUnavailable != nil { + { + size, err := m.MaxUnavailable.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x12 + } if m.Partition != nil { i = encodeVarintGenerated(dAtA, i, uint64(*m.Partition)) i-- @@ -3215,6 +3228,10 @@ func (m *RollingUpdateStatefulSetStrategy) Size() (n int) { if m.Partition != nil { n += 1 + sovGenerated(uint64(*m.Partition)) } + if m.MaxUnavailable != nil { + l = m.MaxUnavailable.Size() + n += 1 + l + sovGenerated(uint64(l)) + } return n } @@ -3729,6 +3746,7 @@ func (this *RollingUpdateStatefulSetStrategy) String() string { } s := strings.Join([]string{`&RollingUpdateStatefulSetStrategy{`, `Partition:` + valueToStringGenerated(this.Partition) + `,`, + `MaxUnavailable:` + strings.Replace(fmt.Sprintf("%v", this.MaxUnavailable), "IntOrString", "intstr.IntOrString", 1) + `,`, `}`, }, "") return s @@ -7395,6 +7413,42 @@ func (m *RollingUpdateStatefulSetStrategy) Unmarshal(dAtA []byte) error { } } m.Partition = &v + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MaxUnavailable", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.MaxUnavailable == nil { + m.MaxUnavailable = &intstr.IntOrString{} + } + if err := m.MaxUnavailable.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/staging/src/k8s.io/api/apps/v1beta2/generated.proto b/staging/src/k8s.io/api/apps/v1beta2/generated.proto index 47bb909810bf..f9e3ef7ef512 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/generated.proto +++ b/staging/src/k8s.io/api/apps/v1beta2/generated.proto @@ -556,11 +556,22 @@ message RollingUpdateDeployment { // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. message RollingUpdateStatefulSetStrategy { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. - // Default value is 0. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. // +optional optional int32 partition = 1; + + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + optional k8s.io.apimachinery.pkg.util.intstr.IntOrString maxUnavailable = 2; } // Scale represents a scaling request for a resource. diff --git a/staging/src/k8s.io/api/apps/v1beta2/types.go b/staging/src/k8s.io/api/apps/v1beta2/types.go index 332bc7ed82bf..a93ef4f95468 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/types.go +++ b/staging/src/k8s.io/api/apps/v1beta2/types.go @@ -162,11 +162,21 @@ const ( // RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType. type RollingUpdateStatefulSetStrategy struct { - // Partition indicates the ordinal at which the StatefulSet should be - // partitioned. - // Default value is 0. + // Partition indicates the ordinal at which the StatefulSet should be partitioned + // for updates. During a rolling update, all pods from ordinal Replicas-1 to + // Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. + // This is helpful in being able to do a canary based deployment. The default value is 0. // +optional Partition *int32 `json:"partition,omitempty" protobuf:"varint,1,opt,name=partition"` + // The maximum number of pods that can be unavailable during the update. + // Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). + // Absolute number is calculated from percentage by rounding up. This can not be 0. + // Defaults to 1. This field is alpha-level and is only honored by servers that enable the + // MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to + // Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it + // will be counted towards MaxUnavailable. + // +optional + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"varint,2,opt,name=maxUnavailable"` } // PersistentVolumeClaimRetentionPolicyType is a string enumeration of the policies that will determine diff --git a/staging/src/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go b/staging/src/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go index 454c632dc257..ef1de63b2f2e 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go +++ b/staging/src/k8s.io/api/apps/v1beta2/types_swagger_doc_generated.go @@ -281,8 +281,9 @@ func (RollingUpdateDeployment) SwaggerDoc() map[string]string { } var map_RollingUpdateStatefulSetStrategy = map[string]string{ - "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", - "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned. Default value is 0.", + "": "RollingUpdateStatefulSetStrategy is used to communicate parameter for RollingUpdateStatefulSetStrategyType.", + "partition": "Partition indicates the ordinal at which the StatefulSet should be partitioned for updates. During a rolling update, all pods from ordinal Replicas-1 to Partition are updated. All pods from ordinal Partition-1 to 0 remain untouched. This is helpful in being able to do a canary based deployment. The default value is 0.", + "maxUnavailable": "The maximum number of pods that can be unavailable during the update. Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%). Absolute number is calculated from percentage by rounding up. This can not be 0. Defaults to 1. This field is alpha-level and is only honored by servers that enable the MaxUnavailableStatefulSet feature. The field applies to all pods in the range 0 to Replicas-1. That means if there is any unavailable pod in the range 0 to Replicas-1, it will be counted towards MaxUnavailable.", } func (RollingUpdateStatefulSetStrategy) SwaggerDoc() map[string]string { diff --git a/staging/src/k8s.io/api/apps/v1beta2/zz_generated.deepcopy.go b/staging/src/k8s.io/api/apps/v1beta2/zz_generated.deepcopy.go index 8293b9886b6c..118fd38093d4 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/zz_generated.deepcopy.go +++ b/staging/src/k8s.io/api/apps/v1beta2/zz_generated.deepcopy.go @@ -597,6 +597,11 @@ func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateState *out = new(int32) **out = **in } + if in.MaxUnavailable != nil { + in, out := &in.MaxUnavailable, &out.MaxUnavailable + *out = new(intstr.IntOrString) + **out = **in + } return } diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.json b/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.json index 0813338ad438..a954396e37af 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.json +++ b/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.json @@ -1742,7 +1742,8 @@ "updateStrategy": { "type": "typeValue", "rollingUpdate": { - "partition": 1 + "partition": 1, + "maxUnavailable": "maxUnavailableValue" } }, "revisionHistoryLimit": 8, diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.pb b/staging/src/k8s.io/api/testdata/HEAD/apps.v1.StatefulSet.pb index e891201dc6b9cf202439bb5d5476bd034a115865..43d5247b3465eda10ed51da4a27e58330a57c35f 100644 GIT binary patch delta 76 zcmbOevOQ#iEYp;bjq+uTtcwCT7=k@7+Dtua4-r@ZWQ<3{D!ekU0aKbv!t>hH7qfwG*w6zC?(0k cD8L{koSRq?nwMCXn3k@7+Ko`I2eT{H;Vgie#2O&F2K*lSyEY$8kU$-nkvM^!8m!U G=5heca1h!6 diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta1.StatefulSet.yaml b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta1.StatefulSet.yaml index 84a687040acd..7b32b8574a6e 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta1.StatefulSet.yaml +++ b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta1.StatefulSet.yaml @@ -1131,6 +1131,7 @@ spec: volumePath: volumePathValue updateStrategy: rollingUpdate: + maxUnavailable: maxUnavailableValue partition: 1 type: typeValue volumeClaimTemplates: diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.json b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.json index 248a71ec9327..97cf48fb460e 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.json +++ b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.json @@ -1742,7 +1742,8 @@ "updateStrategy": { "type": "typeValue", "rollingUpdate": { - "partition": 1 + "partition": 1, + "maxUnavailable": "maxUnavailableValue" } }, "revisionHistoryLimit": 8, diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.pb b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.pb index 25c2822f51b08c10121c30b100a36fbba908c899..747648dd31a81371db75ee01ef2ed01764bc02c2 100644 GIT binary patch delta 77 zcmZ1&vL|GM64R8B&F>k@7+Dtua4-r@ZWQ<3{D!ekU0aKbv!t>hH7qfwG*w6zC?(0k cD8L{koSRq?nwMCXn3k@7+Ko`I2eT{H;Vgie#2O&F2K*lSyEY$8kU$-nkvM^!8m!U G=5heca1h!6 diff --git a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.yaml b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.yaml index ae1725c873b7..10612d37dcc2 100644 --- a/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.yaml +++ b/staging/src/k8s.io/api/testdata/HEAD/apps.v1beta2.StatefulSet.yaml @@ -1131,6 +1131,7 @@ spec: volumePath: volumePathValue updateStrategy: rollingUpdate: + maxUnavailable: maxUnavailableValue partition: 1 type: typeValue volumeClaimTemplates: diff --git a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1/rollingupdatestatefulsetstrategy.go b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1/rollingupdatestatefulsetstrategy.go index 2090d88ed9d5..c1b5dea85523 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1/rollingupdatestatefulsetstrategy.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1/rollingupdatestatefulsetstrategy.go @@ -18,10 +18,15 @@ limitations under the License. package v1 +import ( + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + // RollingUpdateStatefulSetStrategyApplyConfiguration represents an declarative configuration of the RollingUpdateStatefulSetStrategy type for use // with apply. type RollingUpdateStatefulSetStrategyApplyConfiguration struct { - Partition *int32 `json:"partition,omitempty"` + Partition *int32 `json:"partition,omitempty"` + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` } // RollingUpdateStatefulSetStrategyApplyConfiguration constructs an declarative configuration of the RollingUpdateStatefulSetStrategy type for use with @@ -37,3 +42,11 @@ func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithPartition(value b.Partition = &value return b } + +// WithMaxUnavailable sets the MaxUnavailable field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MaxUnavailable field is set to the value of the last call. +func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithMaxUnavailable(value intstr.IntOrString) *RollingUpdateStatefulSetStrategyApplyConfiguration { + b.MaxUnavailable = &value + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta1/rollingupdatestatefulsetstrategy.go b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta1/rollingupdatestatefulsetstrategy.go index 64273f61834d..8989a08d2c96 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta1/rollingupdatestatefulsetstrategy.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta1/rollingupdatestatefulsetstrategy.go @@ -18,10 +18,15 @@ limitations under the License. package v1beta1 +import ( + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + // RollingUpdateStatefulSetStrategyApplyConfiguration represents an declarative configuration of the RollingUpdateStatefulSetStrategy type for use // with apply. type RollingUpdateStatefulSetStrategyApplyConfiguration struct { - Partition *int32 `json:"partition,omitempty"` + Partition *int32 `json:"partition,omitempty"` + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` } // RollingUpdateStatefulSetStrategyApplyConfiguration constructs an declarative configuration of the RollingUpdateStatefulSetStrategy type for use with @@ -37,3 +42,11 @@ func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithPartition(value b.Partition = &value return b } + +// WithMaxUnavailable sets the MaxUnavailable field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MaxUnavailable field is set to the value of the last call. +func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithMaxUnavailable(value intstr.IntOrString) *RollingUpdateStatefulSetStrategyApplyConfiguration { + b.MaxUnavailable = &value + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta2/rollingupdatestatefulsetstrategy.go b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta2/rollingupdatestatefulsetstrategy.go index f828ef70d493..4a12e51c0a2a 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta2/rollingupdatestatefulsetstrategy.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/apps/v1beta2/rollingupdatestatefulsetstrategy.go @@ -18,10 +18,15 @@ limitations under the License. package v1beta2 +import ( + intstr "k8s.io/apimachinery/pkg/util/intstr" +) + // RollingUpdateStatefulSetStrategyApplyConfiguration represents an declarative configuration of the RollingUpdateStatefulSetStrategy type for use // with apply. type RollingUpdateStatefulSetStrategyApplyConfiguration struct { - Partition *int32 `json:"partition,omitempty"` + Partition *int32 `json:"partition,omitempty"` + MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"` } // RollingUpdateStatefulSetStrategyApplyConfiguration constructs an declarative configuration of the RollingUpdateStatefulSetStrategy type for use with @@ -37,3 +42,11 @@ func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithPartition(value b.Partition = &value return b } + +// WithMaxUnavailable sets the MaxUnavailable field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MaxUnavailable field is set to the value of the last call. +func (b *RollingUpdateStatefulSetStrategyApplyConfiguration) WithMaxUnavailable(value intstr.IntOrString) *RollingUpdateStatefulSetStrategyApplyConfiguration { + b.MaxUnavailable = &value + return b +} diff --git a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go index bd7f58d02dc0..4ae62c215d20 100644 --- a/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go +++ b/staging/src/k8s.io/client-go/applyconfigurations/internal/internal.go @@ -862,6 +862,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.api.apps.v1.RollingUpdateStatefulSetStrategy map: fields: + - name: maxUnavailable + type: + namedType: io.k8s.apimachinery.pkg.util.intstr.IntOrString - name: partition type: scalar: numeric @@ -1162,6 +1165,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.api.apps.v1beta1.RollingUpdateStatefulSetStrategy map: fields: + - name: maxUnavailable + type: + namedType: io.k8s.apimachinery.pkg.util.intstr.IntOrString - name: partition type: scalar: numeric @@ -1660,6 +1666,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.api.apps.v1beta2.RollingUpdateStatefulSetStrategy map: fields: + - name: maxUnavailable + type: + namedType: io.k8s.apimachinery.pkg.util.intstr.IntOrString - name: partition type: scalar: numeric From 2733b66e80dd7631194fa2f247ee1528e507e79b Mon Sep 17 00:00:00 2001 From: Mayank Kumar Date: Tue, 9 Jun 2020 01:54:20 -0700 Subject: [PATCH 2/2] add maxUnavailable implementation and UT --- .../statefulset/stateful_set_control.go | 86 +++++ .../statefulset/stateful_set_control_test.go | 320 ++++++++++++++++++ 2 files changed, 406 insertions(+) diff --git a/pkg/controller/statefulset/stateful_set_control.go b/pkg/controller/statefulset/stateful_set_control.go index a248fd81fba0..6fb3579fce67 100644 --- a/pkg/controller/statefulset/stateful_set_control.go +++ b/pkg/controller/statefulset/stateful_set_control.go @@ -22,8 +22,10 @@ import ( apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" + intstrutil "k8s.io/apimachinery/pkg/util/intstr" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/tools/record" "k8s.io/klog/v2" @@ -546,6 +548,16 @@ func (ssc *defaultStatefulSetControl) updateStatefulSet( return &status, nil } + if utilfeature.DefaultFeatureGate.Enabled(features.MaxUnavailableStatefulSet) { + return updateStatefulSetAfterInvariantEstablished(ctx, + ssc, + set, + replicas, + updateRevision, + status, + ) + } + // we compute the minimum ordinal of the target sequence for a destructive update based on the strategy. updateMin := 0 if set.Spec.UpdateStrategy.RollingUpdate != nil { @@ -574,6 +586,80 @@ func (ssc *defaultStatefulSetControl) updateStatefulSet( return &status, nil } +func updateStatefulSetAfterInvariantEstablished( + ctx context.Context, + ssc *defaultStatefulSetControl, + set *apps.StatefulSet, + replicas []*v1.Pod, + updateRevision *apps.ControllerRevision, + status apps.StatefulSetStatus, +) (*apps.StatefulSetStatus, error) { + + replicaCount := int(*set.Spec.Replicas) + + // we compute the minimum ordinal of the target sequence for a destructive update based on the strategy. + updateMin := 0 + maxUnavailable := 1 + if set.Spec.UpdateStrategy.RollingUpdate != nil { + updateMin = int(*set.Spec.UpdateStrategy.RollingUpdate.Partition) + + // if the feature was enabled and then later disabled, MaxUnavailable may have a value + // other than 1. Ignore the passed in value and Use maxUnavailable as 1 to enforce + // expected behavior when feature gate is not enabled. + var err error + maxUnavailable, err = intstrutil.GetValueFromIntOrPercent(intstrutil.ValueOrDefault(set.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable, intstrutil.FromInt(1)), int(replicaCount), false) + if err != nil { + return &status, err + } + + } + + // Collect all targets in the range between the 0 and Spec.Replicas. Count any targets in that range + // that are unhealthy i.e. terminated or not running and ready as unavailable). Select the + // (MaxUnavailable - Unavailable) Pods, in order with respect to their ordinal for termination. Delete + // those pods and count the successful deletions. Update the status with the correct number of deletions. + unavailablePods := 0 + for target := len(replicas) - 1; target >= 0; target-- { + if !isHealthy(replicas[target]) { + unavailablePods++ + } + } + + if unavailablePods >= maxUnavailable { + klog.V(2).Infof("StatefulSet %s/%s found unavailablePods %v, more than or equal to allowed maxUnavailable %v", + set.Namespace, + set.Name, + unavailablePods, + maxUnavailable) + return &status, nil + } + + // Now we need to delete MaxUnavailable- unavailablePods + // start deleting one by one starting from the highest ordinal first + podsToDelete := maxUnavailable - unavailablePods + + deletedPods := 0 + for target := len(replicas) - 1; target >= updateMin && deletedPods < podsToDelete; target-- { + + // delete the Pod if it is healthy and the revision doesnt match the target + if getPodRevision(replicas[target]) != updateRevision.Name && !isTerminating(replicas[target]) { + // delete the Pod if it is healthy and the revision doesnt match the target + klog.V(2).Infof("StatefulSet %s/%s terminating Pod %s for update", + set.Namespace, + set.Name, + replicas[target].Name) + if err := ssc.podControl.DeleteStatefulPod(set, replicas[target]); err != nil { + if !errors.IsNotFound(err) { + return nil, err + } + } + deletedPods++ + status.CurrentReplicas-- + } + } + return &status, nil +} + // updateStatefulSetStatus updates set's Status to be equal to status. If status indicates a complete update, it is // mutated to indicate completion. If status is semantically equivalent to set's Status no update is performed. If the // returned error is nil, the update is successful. diff --git a/pkg/controller/statefulset/stateful_set_control_test.go b/pkg/controller/statefulset/stateful_set_control_test.go index 782215d5189e..cda8f435d6d4 100644 --- a/pkg/controller/statefulset/stateful_set_control_test.go +++ b/pkg/controller/statefulset/stateful_set_control_test.go @@ -36,6 +36,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apimachinery/pkg/util/intstr" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/client-go/informers" appsinformers "k8s.io/client-go/informers/apps/v1" @@ -728,6 +729,325 @@ func TestStatefulSetControl_getSetRevisions(t *testing.T) { }) } +func setupPodManagementPolicy(podManagementPolicy apps.PodManagementPolicyType, set *apps.StatefulSet) *apps.StatefulSet { + set.Spec.PodManagementPolicy = podManagementPolicy + return set +} + +func TestStatefulSetControlRollingUpdateWithMaxUnavailable(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, true)() + + simpleParallelVerificationFn := func( + set *apps.StatefulSet, + spc *fakeObjectManager, + ssc StatefulSetControlInterface, + pods []*v1.Pod, + totalPods int, + selector labels.Selector, + ) []*v1.Pod { + // in burst mode, 2 pods got deleted, so 2 new pods will be created at the same time + if len(pods) != totalPods { + t.Fatalf("Expected create pods 4/5, got pods %v", len(pods)) + } + + // if pod 4 ready, start to update pod 3, even though 5 is not ready + spc.setPodRunning(set, 4) + spc.setPodRunning(set, 5) + originalPods, _ := spc.setPodReady(set, 4) + sort.Sort(ascendingOrdinal(originalPods)) + if _, err := ssc.UpdateStatefulSet(context.TODO(), set, originalPods); err != nil { + t.Fatal(err) + } + pods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + sort.Sort(ascendingOrdinal(pods)) + // pods 0, 1,2, 4,5 should be present(note 3 is missing) + if !reflect.DeepEqual(pods, append(originalPods[:3], originalPods[4:]...)) { + t.Fatalf("Expected pods %v, got pods %v", append(originalPods[:3], originalPods[4:]...), pods) + } + + // create new pod 3 + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil { + t.Fatal(err) + } + pods, err = spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + if len(pods) != totalPods { + t.Fatalf("Expected create pods 2/3, got pods %v", pods) + } + + return pods + } + simpleOrderedVerificationFn := func( + set *apps.StatefulSet, + spc *fakeObjectManager, + ssc StatefulSetControlInterface, + pods []*v1.Pod, + totalPods int, + selector labels.Selector, + ) []*v1.Pod { + // only one pod gets created at a time due to OrderedReady + if len(pods) != 5 { + t.Fatalf("Expected create pods 5, got pods %v", len(pods)) + } + spc.setPodRunning(set, 4) + pods, _ = spc.setPodReady(set, 4) + + // create new pods 4(only one pod gets created at a time due to OrderedReady) + if _, err := ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil { + t.Fatal(err) + } + pods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + + if len(pods) != totalPods { + t.Fatalf("Expected create pods 4, got pods %v", len(pods)) + } + // if pod 4 ready, start to update pod 3 + spc.setPodRunning(set, 5) + originalPods, _ := spc.setPodReady(set, 5) + sort.Sort(ascendingOrdinal(originalPods)) + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, originalPods); err != nil { + t.Fatal(err) + } + pods, err = spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + sort.Sort(ascendingOrdinal(pods)) + + // verify the remaining pods are 0,1,2,4,5 (3 got deleted) + if !reflect.DeepEqual(pods, append(originalPods[:3], originalPods[4:]...)) { + t.Fatalf("Expected pods %v, got pods %v", append(originalPods[:3], originalPods[4:]...), pods) + } + + // create new pod 3 + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil { + t.Fatal(err) + } + pods, err = spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + if len(pods) != totalPods { + t.Fatalf("Expected create pods 2/3, got pods %v", pods) + } + + return pods + } + testCases := []struct { + policyType apps.PodManagementPolicyType + verifyFn func( + set *apps.StatefulSet, + spc *fakeObjectManager, + ssc StatefulSetControlInterface, + pods []*v1.Pod, + totalPods int, + selector labels.Selector, + ) []*v1.Pod + }{ + {apps.OrderedReadyPodManagement, simpleOrderedVerificationFn}, + {apps.ParallelPodManagement, simpleParallelVerificationFn}, + } + for _, tc := range testCases { + // Setup the statefulSet controller + totalPods := 6 + var partition int32 = 3 + var maxUnavailable = intstr.FromInt(2) + set := setupPodManagementPolicy(tc.policyType, newStatefulSet(totalPods)) + set.Spec.UpdateStrategy = apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { + return &apps.RollingUpdateStatefulSetStrategy{ + Partition: &partition, + MaxUnavailable: &maxUnavailable, + } + }(), + } + + client := fake.NewSimpleClientset() + spc, _, ssc := setupController(client) + if err := scaleUpStatefulSetControl(set, ssc, spc, assertBurstInvariants); err != nil { + t.Fatal(err) + } + set, err := spc.setsLister.StatefulSets(set.Namespace).Get(set.Name) + if err != nil { + t.Fatal(err) + } + + // Change the image to trigger an update + set.Spec.Template.Spec.Containers[0].Image = "foo" + + selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) + if err != nil { + t.Fatal(err) + } + originalPods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + sort.Sort(ascendingOrdinal(originalPods)) + + // since maxUnavailable is 2, update pods 4 and 5, this will delete the pod 4 and 5, + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, originalPods); err != nil { + t.Fatal(err) + } + pods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + + sort.Sort(ascendingOrdinal(pods)) + + // expected number of pod is 0,1,2,3 + if !reflect.DeepEqual(pods, originalPods[:4]) { + t.Fatalf("Expected pods %v, got pods %v", originalPods[:4], pods) + } + + // create new pods + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, pods); err != nil { + t.Fatal(err) + } + pods, err = spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + + tc.verifyFn(set, spc, ssc, pods, totalPods, selector) + + // pods 3/4/5 ready, should not update other pods + spc.setPodRunning(set, 3) + spc.setPodRunning(set, 5) + spc.setPodReady(set, 5) + originalPods, _ = spc.setPodReady(set, 3) + sort.Sort(ascendingOrdinal(originalPods)) + if _, err = ssc.UpdateStatefulSet(context.TODO(), set, originalPods); err != nil { + t.Fatal(err) + } + pods, err = spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + sort.Sort(ascendingOrdinal(pods)) + if !reflect.DeepEqual(pods, originalPods) { + t.Fatalf("Expected pods %v, got pods %v", originalPods, pods) + } + } + +} + +func setupForInvariant(t *testing.T) (*apps.StatefulSet, *fakeObjectManager, StatefulSetControlInterface, intstr.IntOrString, int) { + totalPods := 6 + set := newStatefulSet(totalPods) + // update all pods >=3(3,4,5) + var partition int32 = 3 + var maxUnavailable = intstr.FromInt(2) + set.Spec.UpdateStrategy = apps.StatefulSetUpdateStrategy{ + Type: apps.RollingUpdateStatefulSetStrategyType, + RollingUpdate: func() *apps.RollingUpdateStatefulSetStrategy { + return &apps.RollingUpdateStatefulSetStrategy{ + Partition: &partition, + MaxUnavailable: &maxUnavailable, + } + }(), + } + + client := fake.NewSimpleClientset() + spc, _, ssc := setupController(client) + if err := scaleUpStatefulSetControl(set, ssc, spc, assertBurstInvariants); err != nil { + t.Fatal(err) + } + set, err := spc.setsLister.StatefulSets(set.Namespace).Get(set.Name) + if err != nil { + t.Fatal(err) + } + + return set, spc, ssc, maxUnavailable, totalPods +} + +func TestStatefulSetControlRollingUpdateWithMaxUnavailableInOrderedModeVerifyInvariant(t *testing.T) { + // Make all pods in statefulset unavailable one by one + // and verify that RollingUpdate doesnt proceed with maxUnavailable set + // this could have been a simple loop, keeping it like this to be able + // to add more params here. + testCases := []struct { + ordinalOfPodToTerminate []int + }{ + + {[]int{}}, + {[]int{5}}, + {[]int{3}}, + {[]int{4}}, + {[]int{5, 4}}, + {[]int{5, 3}}, + {[]int{4, 3}}, + {[]int{5, 4, 3}}, + {[]int{2}}, // note this is an ordinal greater than partition(3) + {[]int{1}}, // note this is an ordinal greater than partition(3) + } + for _, tc := range testCases { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.MaxUnavailableStatefulSet, true)() + set, spc, ssc, maxUnavailable, totalPods := setupForInvariant(t) + t.Run(fmt.Sprintf("terminating pod at ordinal %d", tc.ordinalOfPodToTerminate), func(t *testing.T) { + status := apps.StatefulSetStatus{Replicas: int32(totalPods)} + updateRevision := &apps.ControllerRevision{} + + for i := 0; i < len(tc.ordinalOfPodToTerminate); i++ { + // Ensure at least one pod is unavailable before trying to update + _, err := spc.addTerminatingPod(set, tc.ordinalOfPodToTerminate[i]) + if err != nil { + t.Fatal(err) + } + } + + selector, err := metav1.LabelSelectorAsSelector(set.Spec.Selector) + if err != nil { + t.Fatal(err) + } + + originalPods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + + sort.Sort(ascendingOrdinal(originalPods)) + + // start to update + set.Spec.Template.Spec.Containers[0].Image = "foo" + + // try to update the statefulset + // this function is only called in main code when feature gate is enabled + if _, err = updateStatefulSetAfterInvariantEstablished(context.TODO(), ssc.(*defaultStatefulSetControl), set, originalPods, updateRevision, status); err != nil { + t.Fatal(err) + } + pods, err := spc.podsLister.Pods(set.Namespace).List(selector) + if err != nil { + t.Fatal(err) + } + + sort.Sort(ascendingOrdinal(pods)) + + expecteddPodsToBeDeleted := maxUnavailable.IntValue() - len(tc.ordinalOfPodToTerminate) + if expecteddPodsToBeDeleted < 0 { + expecteddPodsToBeDeleted = 0 + } + + expectedPodsAfterUpdate := totalPods - expecteddPodsToBeDeleted + + if len(pods) != expectedPodsAfterUpdate { + t.Errorf("Expected pods %v, got pods %v", expectedPodsAfterUpdate, len(pods)) + } + + }) + } +} + func TestStatefulSetControlRollingUpdate(t *testing.T) { type testcase struct { name string