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) {
|
func(j *extensions.DaemonSetUpdateStrategy, c fuzz.Continue) {
|
||||||
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
c.FuzzNoCustom(j) // fuzz self without calling this function again
|
||||||
// Ensure that strategyType is one of valid values.
|
// Ensure that strategyType is one of valid values.
|
||||||
|
@@ -386,7 +386,7 @@ type DaemonSetUpdateStrategy struct {
|
|||||||
// Rolling update config params. Present only if type = "RollingUpdate".
|
// Rolling update config params. Present only if type = "RollingUpdate".
|
||||||
//---
|
//---
|
||||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
// 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
|
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||||
// +optional
|
// +optional
|
||||||
RollingUpdate *RollingUpdateDaemonSet
|
RollingUpdate *RollingUpdateDaemonSet
|
||||||
@@ -449,10 +449,17 @@ type DaemonSetSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
MinReadySeconds int32
|
MinReadySeconds int32
|
||||||
|
|
||||||
|
// DEPRECATED.
|
||||||
// A sequence number representing a specific generation of the template.
|
// A sequence number representing a specific generation of the template.
|
||||||
// Populated by the system. It can be set only during the creation.
|
// Populated by the system. It can be set only during the creation.
|
||||||
// +optional
|
// +optional
|
||||||
TemplateGeneration int64
|
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.
|
// DaemonSetStatus represents the current status of a daemon set.
|
||||||
@@ -492,6 +499,12 @@ type DaemonSetStatus struct {
|
|||||||
// (ready for at least spec.minReadySeconds)
|
// (ready for at least spec.minReadySeconds)
|
||||||
// +optional
|
// +optional
|
||||||
NumberUnavailable int32
|
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
|
// +genclient=true
|
||||||
@@ -519,10 +532,16 @@ type DaemonSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// DEPRECATED: DefaultDaemonSetUniqueLabelKey is used instead.
|
||||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||||
// to daemon set pods to distinguish between old and new pod templates
|
// to daemon set pods to distinguish between old and new pod templates
|
||||||
// during DaemonSet template update.
|
// during DaemonSet template update.
|
||||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
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.
|
// DaemonSetList is a collection of daemon sets.
|
||||||
|
@@ -56,6 +56,10 @@ func SetDefaults_DaemonSet(obj *DaemonSet) {
|
|||||||
updateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable
|
updateStrategy.RollingUpdate.MaxUnavailable = &maxUnavailable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if obj.Spec.RevisionHistoryLimit == nil {
|
||||||
|
obj.Spec.RevisionHistoryLimit = new(int32)
|
||||||
|
*obj.Spec.RevisionHistoryLimit = 10
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetDefaults_Deployment(obj *Deployment) {
|
func SetDefaults_Deployment(obj *Deployment) {
|
||||||
|
@@ -32,7 +32,7 @@ import (
|
|||||||
. "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
. "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetDefaultDaemonSet(t *testing.T) {
|
func TestSetDefaultDaemonSetSpec(t *testing.T) {
|
||||||
defaultLabels := map[string]string{"foo": "bar"}
|
defaultLabels := map[string]string{"foo": "bar"}
|
||||||
period := int64(v1.DefaultTerminationGracePeriodSeconds)
|
period := int64(v1.DefaultTerminationGracePeriodSeconds)
|
||||||
defaultTemplate := v1.PodTemplateSpec{
|
defaultTemplate := v1.PodTemplateSpec{
|
||||||
@@ -78,6 +78,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||||
Type: OnDeleteDaemonSetStrategyType,
|
Type: OnDeleteDaemonSetStrategyType,
|
||||||
},
|
},
|
||||||
|
RevisionHistoryLimit: newInt32(10),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -89,7 +90,8 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
Spec: DaemonSetSpec{
|
Spec: DaemonSetSpec{
|
||||||
Template: defaultTemplate,
|
Template: defaultTemplate,
|
||||||
|
RevisionHistoryLimit: newInt32(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: &DaemonSet{
|
expected: &DaemonSet{
|
||||||
@@ -106,6 +108,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||||
Type: OnDeleteDaemonSetStrategyType,
|
Type: OnDeleteDaemonSetStrategyType,
|
||||||
},
|
},
|
||||||
|
RevisionHistoryLimit: newInt32(1),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -117,19 +120,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||||
Type: OnDeleteDaemonSetStrategyType,
|
Type: OnDeleteDaemonSetStrategyType,
|
||||||
},
|
},
|
||||||
},
|
RevisionHistoryLimit: newInt32(10),
|
||||||
},
|
|
||||||
},
|
|
||||||
{ // Update strategy.
|
|
||||||
original: &DaemonSet{
|
|
||||||
Spec: DaemonSetSpec{},
|
|
||||||
},
|
|
||||||
expected: &DaemonSet{
|
|
||||||
Spec: DaemonSetSpec{
|
|
||||||
Template: templateNoLabel,
|
|
||||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
|
||||||
Type: OnDeleteDaemonSetStrategyType,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -143,6 +134,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
|
|||||||
UpdateStrategy: DaemonSetUpdateStrategy{
|
UpdateStrategy: DaemonSetUpdateStrategy{
|
||||||
Type: OnDeleteDaemonSetStrategyType,
|
Type: OnDeleteDaemonSetStrategyType,
|
||||||
},
|
},
|
||||||
|
RevisionHistoryLimit: newInt32(10),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -386,7 +386,7 @@ type DaemonSetUpdateStrategy struct {
|
|||||||
// Rolling update config params. Present only if type = "RollingUpdate".
|
// Rolling update config params. Present only if type = "RollingUpdate".
|
||||||
//---
|
//---
|
||||||
// TODO: Update this to follow our convention for oneOf, whatever we decide it
|
// 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
|
// See https://github.com/kubernetes/kubernetes/issues/35345
|
||||||
// +optional
|
// +optional
|
||||||
RollingUpdate *RollingUpdateDaemonSet `json:"rollingUpdate,omitempty" protobuf:"bytes,2,opt,name=rollingUpdate"`
|
RollingUpdate *RollingUpdateDaemonSet `json:"rollingUpdate,omitempty" protobuf:"bytes,2,opt,name=rollingUpdate"`
|
||||||
@@ -449,10 +449,17 @@ type DaemonSetSpec struct {
|
|||||||
// +optional
|
// +optional
|
||||||
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,4,opt,name=minReadySeconds"`
|
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,4,opt,name=minReadySeconds"`
|
||||||
|
|
||||||
|
// DEPRECATED.
|
||||||
// A sequence number representing a specific generation of the template.
|
// A sequence number representing a specific generation of the template.
|
||||||
// Populated by the system. It can be set only during the creation.
|
// Populated by the system. It can be set only during the creation.
|
||||||
// +optional
|
// +optional
|
||||||
TemplateGeneration int64 `json:"templateGeneration,omitempty" protobuf:"varint,5,opt,name=templateGeneration"`
|
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.
|
// DaemonSetStatus represents the current status of a daemon set.
|
||||||
@@ -495,6 +502,12 @@ type DaemonSetStatus struct {
|
|||||||
// (ready for at least spec.minReadySeconds)
|
// (ready for at least spec.minReadySeconds)
|
||||||
// +optional
|
// +optional
|
||||||
NumberUnavailable int32 `json:"numberUnavailable,omitempty" protobuf:"varint,8,opt,name=numberUnavailable"`
|
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
|
// +genclient=true
|
||||||
@@ -522,10 +535,16 @@ type DaemonSet struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// DEPRECATED: DefaultDaemonSetUniqueLabelKey is used instead.
|
||||||
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
// DaemonSetTemplateGenerationKey is the key of the labels that is added
|
||||||
// to daemon set pods to distinguish between old and new pod templates
|
// to daemon set pods to distinguish between old and new pod templates
|
||||||
// during DaemonSet template update.
|
// during DaemonSet template update.
|
||||||
DaemonSetTemplateGenerationKey string = "pod-template-generation"
|
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.
|
// DaemonSetList is a collection of daemon sets.
|
||||||
|
@@ -21,6 +21,8 @@ limitations under the License.
|
|||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
unsafe "unsafe"
|
||||||
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
@@ -28,7 +30,6 @@ import (
|
|||||||
api "k8s.io/kubernetes/pkg/api"
|
api "k8s.io/kubernetes/pkg/api"
|
||||||
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
extensions "k8s.io/kubernetes/pkg/apis/extensions"
|
extensions "k8s.io/kubernetes/pkg/apis/extensions"
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@@ -21,12 +21,13 @@ limitations under the License.
|
|||||||
package v1beta1
|
package v1beta1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||||
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
api_v1 "k8s.io/kubernetes/pkg/api/v1"
|
||||||
reflect "reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
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.UpdatedNumberScheduled), fldPath.Child("updatedNumberScheduled"))...)
|
||||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberAvailable), fldPath.Child("numberAvailable"))...)
|
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberAvailable), fldPath.Child("numberAvailable"))...)
|
||||||
allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.NumberUnavailable), fldPath.Child("numberUnavailable"))...)
|
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
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,6 +144,13 @@ func validateDaemonSetStatus(status *extensions.DaemonSetStatus, fldPath *field.
|
|||||||
func ValidateDaemonSetStatusUpdate(ds, oldDS *extensions.DaemonSet) field.ErrorList {
|
func ValidateDaemonSetStatusUpdate(ds, oldDS *extensions.DaemonSet) field.ErrorList {
|
||||||
allErrs := apivalidation.ValidateObjectMetaUpdate(&ds.ObjectMeta, &oldDS.ObjectMeta, field.NewPath("metadata"))
|
allErrs := apivalidation.ValidateObjectMetaUpdate(&ds.ObjectMeta, &oldDS.ObjectMeta, field.NewPath("metadata"))
|
||||||
allErrs = append(allErrs, validateDaemonSetStatus(&ds.Status, field.NewPath("status"))...)
|
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
|
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, apivalidation.ValidateNonnegativeField(int64(spec.TemplateGeneration), fldPath.Child("templateGeneration"))...)
|
||||||
|
|
||||||
allErrs = append(allErrs, ValidateDaemonSetUpdateStrategy(&spec.UpdateStrategy, fldPath.Child("updateStrategy"))...)
|
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
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,12 +21,13 @@ limitations under the License.
|
|||||||
package extensions
|
package extensions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
conversion "k8s.io/apimachinery/pkg/conversion"
|
conversion "k8s.io/apimachinery/pkg/conversion"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
intstr "k8s.io/apimachinery/pkg/util/intstr"
|
||||||
api "k8s.io/kubernetes/pkg/api"
|
api "k8s.io/kubernetes/pkg/api"
|
||||||
reflect "reflect"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
Reference in New Issue
Block a user