mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 10:51:29 +00:00
Tolerate sub-microsecond eventTime changes on update
This commit is contained in:
parent
c870f1ddc7
commit
42bb7bb458
@ -95,7 +95,18 @@ func ValidateEventUpdate(newEvent, oldEvent *core.Event, requestVersion schema.G
|
|||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.Count, oldEvent.Count, field.NewPath("count"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.Count, oldEvent.Count, field.NewPath("count"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.Reason, oldEvent.Reason, field.NewPath("reason"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.Reason, oldEvent.Reason, field.NewPath("reason"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.Type, oldEvent.Type, field.NewPath("type"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.Type, oldEvent.Type, field.NewPath("type"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.EventTime, oldEvent.EventTime, field.NewPath("eventTime"))...)
|
|
||||||
|
// Disallow changes to eventTime greater than microsecond-level precision.
|
||||||
|
// Tolerating sub-microsecond changes is required to tolerate updates
|
||||||
|
// from clients that correctly truncate to microsecond-precision when serializing,
|
||||||
|
// or from clients built with incorrect nanosecond-precision protobuf serialization.
|
||||||
|
// See https://github.com/kubernetes/kubernetes/issues/111928
|
||||||
|
newTruncated := newEvent.EventTime.Truncate(time.Microsecond).UTC()
|
||||||
|
oldTruncated := oldEvent.EventTime.Truncate(time.Microsecond).UTC()
|
||||||
|
if newTruncated != oldTruncated {
|
||||||
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.EventTime, oldEvent.EventTime, field.NewPath("eventTime"))...)
|
||||||
|
}
|
||||||
|
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.Action, oldEvent.Action, field.NewPath("action"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.Action, oldEvent.Action, field.NewPath("action"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.Related, oldEvent.Related, field.NewPath("related"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.Related, oldEvent.Related, field.NewPath("related"))...)
|
||||||
allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingController, oldEvent.ReportingController, field.NewPath("reportingController"))...)
|
allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingController, oldEvent.ReportingController, field.NewPath("reportingController"))...)
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
eventsv1 "k8s.io/api/events/v1"
|
eventsv1 "k8s.io/api/events/v1"
|
||||||
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
eventsv1beta1 "k8s.io/api/events/v1beta1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@ -1312,3 +1312,67 @@ func TestValidateEventUpdateForNewV1Events(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEventV1EventTimeImmutability(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
Name string
|
||||||
|
Old metav1.MicroTime
|
||||||
|
New metav1.MicroTime
|
||||||
|
Valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "noop microsecond precision",
|
||||||
|
Old: metav1.NewMicroTime(time.Unix(100, int64(5*time.Microsecond))),
|
||||||
|
New: metav1.NewMicroTime(time.Unix(100, int64(5*time.Microsecond))),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "noop nanosecond precision",
|
||||||
|
Old: metav1.NewMicroTime(time.Unix(100, int64(5*time.Nanosecond))),
|
||||||
|
New: metav1.NewMicroTime(time.Unix(100, int64(5*time.Nanosecond))),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "modify nanoseconds within the same microsecond",
|
||||||
|
Old: metav1.NewMicroTime(time.Unix(100, int64(5*time.Nanosecond))),
|
||||||
|
New: metav1.NewMicroTime(time.Unix(100, int64(6*time.Nanosecond))),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "modify microseconds",
|
||||||
|
Old: metav1.NewMicroTime(time.Unix(100, int64(5*time.Microsecond))),
|
||||||
|
New: metav1.NewMicroTime(time.Unix(100, int64(5*time.Microsecond-time.Nanosecond))),
|
||||||
|
Valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "modify seconds",
|
||||||
|
Old: metav1.NewMicroTime(time.Unix(100, 0)),
|
||||||
|
New: metav1.NewMicroTime(time.Unix(101, 0)),
|
||||||
|
Valid: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testcases {
|
||||||
|
t.Run(tc.Name, func(t *testing.T) {
|
||||||
|
oldEvent := &core.Event{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: metav1.NamespaceSystem, ResourceVersion: "2"},
|
||||||
|
InvolvedObject: core.ObjectReference{APIVersion: "v2", Kind: "Node"},
|
||||||
|
Series: &core.EventSeries{Count: 2, LastObservedTime: tc.Old},
|
||||||
|
EventTime: tc.Old,
|
||||||
|
ReportingController: "k8s.io/my-controller",
|
||||||
|
ReportingInstance: "node-xyz",
|
||||||
|
Action: "Do",
|
||||||
|
Reason: "Yeees",
|
||||||
|
Type: "Normal",
|
||||||
|
}
|
||||||
|
|
||||||
|
newEvent := oldEvent.DeepCopy()
|
||||||
|
newEvent.EventTime = tc.New
|
||||||
|
|
||||||
|
updateErrs := ValidateEventUpdate(newEvent, oldEvent, eventsv1.SchemeGroupVersion)
|
||||||
|
if e, a := tc.Valid, len(updateErrs) == 0; e != a {
|
||||||
|
t.Errorf("%v: expected valid=%v, got %v: %v", tc.Valid, e, a, updateErrs)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user