Update DaemonSet API for rollback and history
1. Add revisionHistoryLimit (default 10), collisionCount, and validation code 2. Add daemonset-controller-hash label, and deprecate templateGeneration
This commit is contained in:
@@ -553,6 +553,11 @@ func extensionFuncs(t apitesting.TestingCommon) []interface{} {
|
||||
}
|
||||
}
|
||||
},
|
||||
func(j *extensions.DaemonSetSpec, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
rhl := int32(c.Rand.Int31())
|
||||
j.RevisionHistoryLimit = &rhl
|
||||
},
|
||||
func(j *extensions.DaemonSetUpdateStrategy, c fuzz.Continue) {
|
||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||
// Ensure that strategyType is one of valid values.
|
||||
|
@@ -386,7 +386,7 @@ type DaemonSetUpdateStrategy struct {
|
||||
// Rolling update config params. Present only if type = "RollingUpdate".
|
||||
//---
|
||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
||||
// to be. Same as DeploymentStrategy.RollingUpdate.
|
||||
// to be. Same as Deployment `strategy.rollingUpdate`.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||
// +optional
|
||||
RollingUpdate *RollingUpdateDaemonSet
|
||||
@@ -449,10 +449,17 @@ type DaemonSetSpec struct {
|
||||
// +optional
|
||||
MinReadySeconds int32
|
||||
|
||||
// DEPRECATED.
|
||||
// A sequence number representing a specific generation of the template.
|
||||
// Populated by the system. It can be set only during the creation.
|
||||
// +optional
|
||||
TemplateGeneration int64
|
||||
|
||||
// The number of old history to retain to allow rollback.
|
||||
// This is a pointer to distinguish between explicit zero and not specified.
|
||||
// Defaults to 10.
|
||||
// +optional
|
||||
RevisionHistoryLimit *int32
|
||||
}
|
||||
|
||||
// DaemonSetStatus represents the current status of a daemon set.
|
||||
@@ -492,6 +499,12 @@ type DaemonSetStatus struct {
|
||||
// (ready for at least spec.minReadySeconds)
|
||||
// +optional
|
||||
NumberUnavailable int32
|
||||
|
||||
// Count of hash collisions for the DaemonSet. The DaemonSet controller
|
||||
// uses this field as a collision avoidance mechanism when it needs to
|
||||
// create the name for the newest ControllerRevision.
|
||||
// +optional
|
||||
CollisionCount *int64
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
@@ -519,10 +532,16 @@ type DaemonSet struct {
|
||||
}
|
||||
|
||||
const (
|
||||
// DEPRECATED: DefaultDaemonSetUniqueLabelKey is used instead.
|
||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates
|
||||
// during DaemonSet template update.
|
||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
||||
|
||||
// DefaultDaemonSetUniqueLabelKey is the default label key that is added
|
||||
// to existing DaemonSet pods to distinguish between old and new
|
||||
// DaemonSet pods during DaemonSet template updates.
|
||||
DefaultDaemonSetUniqueLabelKey string = "daemonset-controller-hash"
|
||||
)
|
||||
|
||||
// DaemonSetList is a collection of daemon sets.
|
||||
|
@@ -56,6 +56,10 @@ func SetDefaults_DaemonSet(obj *DaemonSet) {
|
||||
updateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable
|
||||
}
|
||||
}
|
||||
if obj.Spec.RevisionHistoryLimit == nil {
|
||||
obj.Spec.RevisionHistoryLimit = new(int32)
|
||||
*obj.Spec.RevisionHistoryLimit = 10
|
||||
}
|
||||
}
|
||||
|
||||
func SetDefaults_Deployment(obj *Deployment) {
|
||||
|
@@ -32,7 +32,7 @@ import (
|
||||
. "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||
)
|
||||
|
||||
func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
func TestSetDefaultDaemonSetSpec(t *testing.T) {
|
||||
defaultLabels := map[string]string{"foo": "bar"}
|
||||
period := int64(v1.DefaultTerminationGracePeriodSeconds)
|
||||
defaultTemplate := v1.PodTemplateSpec{
|
||||
@@ -78,6 +78,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
RevisionHistoryLimit: newInt32(10),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -90,6 +91,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
},
|
||||
Spec: DaemonSetSpec{
|
||||
Template: defaultTemplate,
|
||||
RevisionHistoryLimit: newInt32(1),
|
||||
},
|
||||
},
|
||||
expected: &DaemonSet{
|
||||
@@ -106,6 +108,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
RevisionHistoryLimit: newInt32(1),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -117,19 +120,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ // Update strategy.
|
||||
original: &DaemonSet{
|
||||
Spec: DaemonSetSpec{},
|
||||
},
|
||||
expected: &DaemonSet{
|
||||
Spec: DaemonSetSpec{
|
||||
Template: templateNoLabel,
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
RevisionHistoryLimit: newInt32(10),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -143,6 +134,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||
Type: OnDeleteDaemonSetStrategyType,
|
||||
},
|
||||
RevisionHistoryLimit: newInt32(10),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@@ -386,7 +386,7 @@ type DaemonSetUpdateStrategy struct {
|
||||
// Rolling update config params. Present only if type = "RollingUpdate".
|
||||
//---
|
||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
||||
// to be. Same as DeploymentStrategy.RollingUpdate.
|
||||
// to be. Same as Deployment `strategy.rollingUpdate`.
|
||||
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||
// +optional
|
||||
RollingUpdate *RollingUpdateDaemonSet `json:"rollingUpdate,omitempty" protobuf:"bytes,2,opt,name=rollingUpdate"`
|
||||
@@ -449,10 +449,17 @@ type DaemonSetSpec struct {
|
||||
// +optional
|
||||
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,4,opt,name=minReadySeconds"`
|
||||
|
||||
// DEPRECATED.
|
||||
// A sequence number representing a specific generation of the template.
|
||||
// Populated by the system. It can be set only during the creation.
|
||||
// +optional
|
||||
TemplateGeneration int64 `json:"templateGeneration,omitempty" protobuf:"varint,5,opt,name=templateGeneration"`
|
||||
|
||||
// The number of old history to retain to allow rollback.
|
||||
// This is a pointer to distinguish between explicit zero and not specified.
|
||||
// Defaults to 10.
|
||||
// +optional
|
||||
RevisionHistoryLimit *int32 `json:"revisionHistoryLimit,omitempty"`
|
||||
}
|
||||
|
||||
// DaemonSetStatus represents the current status of a daemon set.
|
||||
@@ -495,6 +502,12 @@ type DaemonSetStatus struct {
|
||||
// (ready for at least spec.minReadySeconds)
|
||||
// +optional
|
||||
NumberUnavailable int32 `json:"numberUnavailable,omitempty" protobuf:"varint,8,opt,name=numberUnavailable"`
|
||||
|
||||
// Count of hash collisions for the DaemonSet. The DaemonSet controller
|
||||
// uses this field as a collision avoidance mechanism when it needs to
|
||||
// create the name for the newest ControllerRevision.
|
||||
// +optional
|
||||
CollisionCount *int64 `json:"collisionCount,omitempty" protobuf:"varint,9,opt,name=collisionCount"`
|
||||
}
|
||||
|
||||
// +genclient=true
|
||||
@@ -522,10 +535,16 @@ type DaemonSet struct {
|
||||
}
|
||||
|
||||
const (
|
||||
// DEPRECATED: DefaultDaemonSetUniqueLabelKey is used instead.
|
||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||
// to daemon set pods to distinguish between old and new pod templates
|
||||
// during DaemonSet template update.
|
||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
||||
|
||||
// DefaultDaemonSetUniqueLabelKey is the default label key that is added
|
||||
// to existing DaemonSet pods to distinguish between old and new
|
||||
// DaemonSet pods during DaemonSet template updates.
|
||||
DefaultDaemonSetUniqueLabelKey string = "daemonset-controller-hash"
|
||||
)
|
||||
|
||||
// DaemonSetList is a collection of daemon sets.
|
||||
|
@@ -21,6 +21,8 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
unsafe "unsafe"
|
||||
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -28,7 +30,6 @@ import (
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
extensions "k8s.io/kubernetes/pkg/apis/extensions"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@@ -21,12 +21,13 @@ limitations under the License.
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
v1 "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"
|
||||
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@@ -134,6 +134,9 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.UpdatedNumberScheduled), fldPath.Child("updatedNumberScheduled"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberAvailable), fldPath.Child("numberAvailable"))...)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberUnavailable), fldPath.Child("numberUnavailable"))...)
|
||||
if status.CollisionCount != nil {
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*status.CollisionCount), fldPath.Child("collisionCount"))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -141,6 +144,13 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.
|
||||
func ValidateDaemonSetStatusUpdate(ds, oldDS *extensions.DaemonSet) field.ErrorList {
|
||||
allErrs := apivalidation.ValidateObjectMetaUpdate(&ds.ObjectMeta, &oldDS.ObjectMeta, field.NewPath("metadata"))
|
||||
allErrs = append(allErrs, validateDaemonSetStatus(&ds.Status, field.NewPath("status"))...)
|
||||
if isDecremented(ds.Status.CollisionCount, oldDS.Status.CollisionCount) {
|
||||
value := int64(0)
|
||||
if ds.Status.CollisionCount != nil {
|
||||
value = *ds.Status.CollisionCount
|
||||
}
|
||||
allErrs = append(allErrs, field.Invalid(field.NewPath("status").Child("collisionCount"), value, "cannot be decremented"))
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
@@ -172,6 +182,10 @@ func ValidateDaemonSetSpec(spec *extensions.DaemonSetSpec, fldPath *field.Path)
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.TemplateGeneration), fldPath.Child("templateGeneration"))...)
|
||||
|
||||
allErrs = append(allErrs, ValidateDaemonSetUpdateStrategy(&spec.UpdateStrategy, fldPath.Child("updateStrategy"))...)
|
||||
if spec.RevisionHistoryLimit != nil {
|
||||
// zero is a valid RevisionHistoryLimit
|
||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(*spec.RevisionHistoryLimit), fldPath.Child("revisionHistoryLimit"))...)
|
||||
}
|
||||
return allErrs
|
||||
}
|
||||
|
||||
|
@@ -21,12 +21,13 @@ limitations under the License.
|
||||
package extensions
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
v1 "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"
|
||||
api "k8s.io/kubernetes/pkg/api"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
Reference in New Issue
Block a user