Promote new Event API to v1

This commit is contained in:
Chelsey Chen 2020-06-01 11:03:13 -04:00
parent 1cbda2493d
commit 75612c1746
23 changed files with 1458 additions and 41 deletions

View File

@ -252,6 +252,7 @@ var apiVersionPriorities = map[schema.GroupVersion]priority{
{Group: "extensions", Version: "v1beta1"}: {group: 17900, version: 1},
// to my knowledge, nothing below here collides
{Group: "apps", Version: "v1"}: {group: 17800, version: 15},
{Group: "events.k8s.io", Version: "v1"}: {group: 17750, version: 15},
{Group: "events.k8s.io", Version: "v1beta1"}: {group: 17750, version: 5},
{Group: "authentication.k8s.io", Version: "v1"}: {group: 17700, version: 15},
{Group: "authentication.k8s.io", Version: "v1beta1"}: {group: 17700, version: 9},

View File

@ -28,6 +28,7 @@ pkg/apis/core/v1/helper/qos
pkg/apis/core/validation
pkg/apis/discovery/v1alpha1
pkg/apis/discovery/v1beta1
pkg/apis/events/v1
pkg/apis/events/v1beta1
pkg/apis/extensions/v1beta1
pkg/apis/flowcontrol/v1alpha1
@ -228,6 +229,7 @@ staging/src/k8s.io/api/certificates/v1beta1
staging/src/k8s.io/api/coordination/v1
staging/src/k8s.io/api/coordination/v1beta1
staging/src/k8s.io/api/core/v1
staging/src/k8s.io/api/events/v1
staging/src/k8s.io/api/events/v1beta1
staging/src/k8s.io/api/extensions/v1beta1
staging/src/k8s.io/api/imagepolicy/v1alpha1

View File

@ -19,6 +19,7 @@
"k8s.io/api/core/v1": "v1",
"k8s.io/api/discovery/v1alpha1": "discoveryv1alpha1",
"k8s.io/api/discovery/v1beta1": "discoveryv1beta1",
"k8s.io/api/events/v1": "eventsv1",
"k8s.io/api/events/v1beta1": "eventsv1beta1",
"k8s.io/api/extensions/v1beta1": "extensionsv1beta1",
"k8s.io/api/imagepolicy/v1alpha1": "imagepolicyv1alpha1",

View File

@ -87,6 +87,7 @@ coordination.k8s.io/v1 \
discovery.k8s.io/v1alpha1 \
discovery.k8s.io/v1beta1 \
extensions/v1beta1 \
events.k8s.io/v1 \
events.k8s.io/v1beta1 \
imagepolicy.k8s.io/v1alpha1 \
networking.k8s.io/v1 \

View File

@ -18,9 +18,14 @@ package validation
import (
"fmt"
"reflect"
"time"
"k8s.io/api/core/v1"
eventsv1beta1 "k8s.io/api/events/v1beta1"
apimachineryvalidation "k8s.io/apimachinery/pkg/api/validation"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/kubernetes/pkg/apis/core"
@ -33,8 +38,88 @@ const (
NoteLengthLimit = 1024
)
// ValidateEvent makes sure that the event makes sense.
func ValidateEvent(event *core.Event) field.ErrorList {
func ValidateEventCreate(event *core.Event, requestVersion schema.GroupVersion) field.ErrorList {
// Make sure events always pass legacy validation.
allErrs := legacyValidateEvent(event)
if requestVersion == v1.SchemeGroupVersion || requestVersion == eventsv1beta1.SchemeGroupVersion {
// No further validation for backwards compatibility.
return allErrs
}
// Strict validation applies to creation via events.k8s.io/v1 API and newer.
allErrs = append(allErrs, ValidateObjectMeta(&event.ObjectMeta, true, apimachineryvalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...)
allErrs = append(allErrs, validateV1EventSeries(event)...)
zeroTime := time.Time{}
if event.EventTime.Time == zeroTime {
allErrs = append(allErrs, field.Required(field.NewPath("eventTime"), ""))
}
if event.Type != v1.EventTypeNormal && event.Type != v1.EventTypeWarning {
allErrs = append(allErrs, field.Invalid(field.NewPath("type"), "", fmt.Sprintf("has invalid value: %v", event.Type)))
}
if event.FirstTimestamp.Time != zeroTime {
allErrs = append(allErrs, field.Invalid(field.NewPath("firstTimestamp"), "", "needs to be unset"))
}
if event.LastTimestamp.Time != zeroTime {
allErrs = append(allErrs, field.Invalid(field.NewPath("lastTimestamp"), "", "needs to be unset"))
}
if event.Count != 0 {
allErrs = append(allErrs, field.Invalid(field.NewPath("count"), "", "needs to be unset"))
}
if event.Source.Component != "" || event.Source.Host != "" {
allErrs = append(allErrs, field.Invalid(field.NewPath("source"), "", "needs to be unset"))
}
return allErrs
}
func ValidateEventUpdate(newEvent, oldEvent *core.Event, requestVersion schema.GroupVersion) field.ErrorList {
// Make sure the new event always passes legacy validation.
allErrs := legacyValidateEvent(newEvent)
if requestVersion == v1.SchemeGroupVersion || requestVersion == eventsv1beta1.SchemeGroupVersion {
// No further validation for backwards compatibility.
return allErrs
}
// Strict validation applies to update via events.k8s.io/v1 API and newer.
allErrs = append(allErrs, ValidateObjectMetaUpdate(&newEvent.ObjectMeta, &oldEvent.ObjectMeta, field.NewPath("metadata"))...)
// if the series was modified, validate the new data
if !reflect.DeepEqual(newEvent.Series, oldEvent.Series) {
allErrs = append(allErrs, validateV1EventSeries(newEvent)...)
}
allErrs = append(allErrs, ValidateImmutableField(newEvent.InvolvedObject, oldEvent.InvolvedObject, field.NewPath("involvedObject"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.Reason, oldEvent.Reason, field.NewPath("reason"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.Message, oldEvent.Message, field.NewPath("message"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.Source, oldEvent.Source, field.NewPath("source"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.FirstTimestamp, oldEvent.FirstTimestamp, field.NewPath("firstTimestamp"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.LastTimestamp, oldEvent.LastTimestamp, field.NewPath("lastTimestamp"))...)
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.Type, oldEvent.Type, field.NewPath("type"))...)
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.Related, oldEvent.Related, field.NewPath("related"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingController, oldEvent.ReportingController, field.NewPath("reportingController"))...)
allErrs = append(allErrs, ValidateImmutableField(newEvent.ReportingInstance, oldEvent.ReportingInstance, field.NewPath("reportingInstance"))...)
return allErrs
}
func validateV1EventSeries(event *core.Event) field.ErrorList {
allErrs := field.ErrorList{}
zeroTime := time.Time{}
if event.Series != nil {
if event.Series.Count < 2 {
allErrs = append(allErrs, field.Invalid(field.NewPath("series.count"), "", fmt.Sprintf("should be at least 2")))
}
if event.Series.LastObservedTime.Time == zeroTime {
allErrs = append(allErrs, field.Required(field.NewPath("series.lastObservedTime"), ""))
}
}
return allErrs
}
// legacyValidateEvent makes sure that the event makes sense.
func legacyValidateEvent(event *core.Event) field.ErrorList {
allErrs := field.ErrorList{}
// Because go
zeroTime := time.Time{}

View File

@ -20,11 +20,14 @@ import (
"testing"
"time"
"k8s.io/api/core/v1"
eventsv1 "k8s.io/api/events/v1"
eventsv1beta1 "k8s.io/api/events/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/apis/core"
)
func TestValidateEvent(t *testing.T) {
func TestValidateEventForCoreV1Events(t *testing.T) {
table := []struct {
*core.Event
valid bool
@ -214,13 +217,18 @@ func TestValidateEvent(t *testing.T) {
}
for _, item := range table {
if e, a := item.valid, len(ValidateEvent(item.Event)) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.Event.Name, e, a, ValidateEvent(item.Event))
createErrs := ValidateEventCreate(item.Event, v1.SchemeGroupVersion)
if e, a := item.valid, len(createErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.Event.Name, e, a, createErrs)
}
updateErrs := ValidateEventUpdate(item.Event, &core.Event{}, v1.SchemeGroupVersion)
if e, a := item.valid, len(updateErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.Event.Name, e, a, updateErrs)
}
}
}
func TestValidateNewEvent(t *testing.T) {
func TestValidateEventForNewV1beta1Events(t *testing.T) {
someTime := metav1.MicroTime{Time: time.Unix(1505828956, 0)}
table := []struct {
*core.Event
@ -384,8 +392,923 @@ zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz`,
}
for _, item := range table {
if e, a := item.valid, len(ValidateEvent(item.Event)) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.msg, e, a, ValidateEvent(item.Event))
createErrs := ValidateEventCreate(item.Event, eventsv1beta1.SchemeGroupVersion)
if e, a := item.valid, len(createErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.msg, e, a, createErrs)
}
updateErrs := ValidateEventUpdate(item.Event, &core.Event{}, eventsv1beta1.SchemeGroupVersion)
if e, a := item.valid, len(updateErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.msg, e, a, updateErrs)
}
}
}
func TestValidateEventCreateForNewV1Events(t *testing.T) {
someTime := metav1.MicroTime{Time: time.Unix(1505828956, 0)}
table := []struct {
*core.Event
valid bool
msg string
}{
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
},
valid: true,
msg: "valid new event",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Reason: "Because",
},
valid: false,
msg: "missing name in objectMeta",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Reason: "Because",
},
valid: false,
msg: "missing namespace in objectMeta",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceDefault,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
},
valid: false,
msg: "missing EventTime",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "my-contr@ller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
},
valid: false,
msg: "not qualified reportingController",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
Action: "Do",
Reason: "Because",
},
valid: false,
msg: "too long reporting instance",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
},
valid: false,
msg: "missing reason",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Reason: "Because",
},
valid: false,
msg: "missing action",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Message: `zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz`,
},
valid: false,
msg: "too long message",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "invalid-type",
},
valid: false,
msg: "invalid type",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
FirstTimestamp: metav1.Time{Time: time.Unix(1505828956, 0)},
},
valid: false,
msg: "non-empty firstTimestamp",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
LastTimestamp: metav1.Time{Time: time.Unix(1505828956, 0)},
},
valid: false,
msg: "non-empty lastTimestamp",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
Count: 123,
},
valid: false,
msg: "non-empty count",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
Source: core.EventSource{
Host: "host",
},
},
valid: false,
msg: "non-empty source",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
Series: &core.EventSeries{
Count: 0,
LastObservedTime: someTime,
},
},
valid: false,
msg: "non-nil series with cound < 2",
},
{
Event: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Because",
Type: "Normal",
Series: &core.EventSeries{
Count: 2,
},
},
valid: false,
msg: "non-nil series with empty lastObservedTime",
},
}
for _, item := range table {
createErrs := ValidateEventCreate(item.Event, eventsv1.SchemeGroupVersion)
if e, a := item.valid, len(createErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.msg, e, a, createErrs)
}
}
}
func TestValidateEventUpdateForNewV1Events(t *testing.T) {
someTime := metav1.MicroTime{Time: time.Unix(1505828956, 0)}
table := []struct {
newEvent *core.Event
oldEvent *core.Event
valid bool
msg string
}{
{
newEvent: &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: someTime,
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "2",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v2",
Kind: "Node",
},
Series: &core.EventSeries{
Count: 1,
LastObservedTime: someTime,
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: true,
msg: "valid new updated event",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v2",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to involvedObject",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees-new",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to reason",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
Message: "new-message",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
Message: "message",
},
valid: false,
msg: "forbidden updates to message",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
Source: core.EventSource{
Host: "host",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to source",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
FirstTimestamp: metav1.Time{Time: time.Unix(1505828956, 0)},
},
valid: false,
msg: "forbidden updates to firstTimestamp",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
LastTimestamp: metav1.Time{Time: time.Unix(1505828956, 0)},
},
valid: false,
msg: "forbidden updates to lastTimestamp",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
Count: 2,
},
valid: false,
msg: "forbidden updates to count",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Warning",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to type",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: metav1.MicroTime{Time: time.Unix(1505828999, 0)},
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to eventTime",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Undo",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to action",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
Related: &core.ObjectReference{
APIVersion: "v1",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to related",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller/new",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to reportingController",
},
{
newEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz-new",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
oldEvent: &core.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: metav1.NamespaceSystem,
ResourceVersion: "1",
},
InvolvedObject: core.ObjectReference{
APIVersion: "v1",
Kind: "Node",
},
EventTime: someTime,
ReportingController: "k8s.io/my-controller",
ReportingInstance: "node-xyz",
Action: "Do",
Reason: "Yeees",
Type: "Normal",
},
valid: false,
msg: "forbidden updates to reportingInstance",
},
}
for _, item := range table {
updateErrs := ValidateEventUpdate(item.newEvent, item.oldEvent, eventsv1.SchemeGroupVersion)
if e, a := item.valid, len(updateErrs) == 0; e != a {
t.Errorf("%v: expected %v, got %v: %v", item.msg, e, a, updateErrs)
}
}
}

View File

@ -23,6 +23,7 @@ import (
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/events"
"k8s.io/kubernetes/pkg/apis/events/v1"
"k8s.io/kubernetes/pkg/apis/events/v1beta1"
)
@ -34,5 +35,6 @@ func init() {
func Install(scheme *runtime.Scheme) {
utilruntime.Must(events.AddToScheme(scheme))
utilruntime.Must(v1beta1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1beta1.SchemeGroupVersion))
utilruntime.Must(v1.AddToScheme(scheme))
utilruntime.Must(scheme.SetVersionPriority(v1beta1.SchemeGroupVersion, v1.SchemeGroupVersion))
}

View File

@ -0,0 +1,58 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
v1 "k8s.io/api/events/v1"
conversion "k8s.io/apimachinery/pkg/conversion"
k8s_api "k8s.io/kubernetes/pkg/apis/core"
k8s_api_v1 "k8s.io/kubernetes/pkg/apis/core/v1"
)
func Convert_v1_Event_To_core_Event(in *v1.Event, out *k8s_api.Event, s conversion.Scope) error {
if err := autoConvert_v1_Event_To_core_Event(in, out, s); err != nil {
return err
}
if err := k8s_api_v1.Convert_v1_ObjectReference_To_core_ObjectReference(&in.Regarding, &out.InvolvedObject, s); err != nil {
return err
}
if err := k8s_api_v1.Convert_v1_EventSource_To_core_EventSource(&in.DeprecatedSource, &out.Source, s); err != nil {
return err
}
out.Message = in.Note
out.FirstTimestamp = in.DeprecatedFirstTimestamp
out.LastTimestamp = in.DeprecatedLastTimestamp
out.Count = in.DeprecatedCount
return nil
}
func Convert_core_Event_To_v1_Event(in *k8s_api.Event, out *v1.Event, s conversion.Scope) error {
if err := autoConvert_core_Event_To_v1_Event(in, out, s); err != nil {
return err
}
if err := k8s_api_v1.Convert_core_ObjectReference_To_v1_ObjectReference(&in.InvolvedObject, &out.Regarding, s); err != nil {
return err
}
if err := k8s_api_v1.Convert_core_EventSource_To_v1_EventSource(&in.Source, &out.DeprecatedSource, s); err != nil {
return err
}
out.Note = in.Message
out.DeprecatedFirstTimestamp = in.FirstTimestamp
out.DeprecatedLastTimestamp = in.LastTimestamp
out.DeprecatedCount = in.Count
return nil
}

24
pkg/apis/events/v1/doc.go Normal file
View File

@ -0,0 +1,24 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/events
// +k8s:conversion-gen-external-types=k8s.io/api/events/v1
// +k8s:defaulter-gen=TypeMeta
// +k8s:defaulter-gen-input=../../../../vendor/k8s.io/api/events/v1
// +groupName=events.k8s.io
package v1 // import "k8s.io/kubernetes/pkg/apis/events/v1"

View File

@ -0,0 +1,45 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
eventsv1 "k8s.io/api/events/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "events.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
localSchemeBuilder = &eventsv1.SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
func init() {
// We only register manually written functions here. The registration of the
// generated functions takes place in the generated files. The separation
// makes the code compile even when the generated files are missing.
localSchemeBuilder.Register(RegisterDefaults)
}

View File

@ -44,6 +44,7 @@ import (
coordinationapiv1beta1 "k8s.io/api/coordination/v1beta1"
apiv1 "k8s.io/api/core/v1"
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
eventsv1 "k8s.io/api/events/v1"
eventsv1beta1 "k8s.io/api/events/v1beta1"
extensionsapiv1beta1 "k8s.io/api/extensions/v1beta1"
flowcontrolv1alpha1 "k8s.io/api/flowcontrol/v1alpha1"
@ -612,6 +613,7 @@ func DefaultAPIResourceConfigSource() *serverstorage.ResourceConfig {
coordinationapiv1.SchemeGroupVersion,
coordinationapiv1beta1.SchemeGroupVersion,
discoveryv1beta1.SchemeGroupVersion,
eventsv1.SchemeGroupVersion,
eventsv1beta1.SchemeGroupVersion,
extensionsapiv1beta1.SchemeGroupVersion,
networkingapiv1.SchemeGroupVersion,

View File

@ -103,5 +103,6 @@ var GVRToStorageVersionHash = map[string]string{
"admissionregistration.k8s.io/v1beta1/validatingwebhookconfigurations": "P9NhrezfnWE=",
"admissionregistration.k8s.io/v1/mutatingwebhookconfigurations": "yxW1cpLtfp8=",
"admissionregistration.k8s.io/v1/validatingwebhookconfigurations": "P9NhrezfnWE=",
"events.k8s.io/v1/events": "r2yiGXH7wu8=",
"events.k8s.io/v1beta1/events": "r2yiGXH7wu8=",
}

View File

@ -18,6 +18,7 @@ package storage
import (
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -46,16 +47,26 @@ func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) {
}
func validNewEvent(namespace string) *api.Event {
someTime := metav1.MicroTime{Time: time.Unix(1505828956, 0)}
return &api.Event{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
Namespace: namespace,
},
Reason: "forTesting",
InvolvedObject: api.ObjectReference{
Name: "bar",
Namespace: namespace,
},
EventTime: someTime,
ReportingController: "test-controller",
ReportingInstance: "test-node",
Action: "Do",
Reason: "forTesting",
Type: "Normal",
Series: &api.EventSeries{
Count: 2,
LastObservedTime: someTime,
},
}
}
@ -85,13 +96,13 @@ func TestUpdate(t *testing.T) {
// valid updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Event)
object.Reason = "forDifferentTesting"
object.Series.Count = 100
return object
},
// invalid updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Event)
object.InvolvedObject.Namespace = "different-namespace"
object.ReportingController = ""
return object
},
)

View File

@ -23,7 +23,9 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/storage"
@ -57,8 +59,9 @@ func (eventStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Obje
}
func (eventStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
groupVersion := requestGroupVersion(ctx)
event := obj.(*api.Event)
return validation.ValidateEvent(event)
return validation.ValidateEventCreate(event, groupVersion)
}
// Canonicalize normalizes the object after validation.
@ -70,8 +73,10 @@ func (eventStrategy) AllowCreateOnUpdate() bool {
}
func (eventStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
groupVersion := requestGroupVersion(ctx)
event := obj.(*api.Event)
return validation.ValidateEvent(event)
oldEvent := obj.(*api.Event)
return validation.ValidateEventUpdate(event, oldEvent, groupVersion)
}
func (eventStrategy) AllowUnconditionalUpdate() bool {
@ -113,3 +118,11 @@ func ToSelectableFields(event *api.Event) fields.Set {
}
return generic.MergeFieldsSets(objectMetaFieldsSet, specificFieldsSet)
}
// requestGroupVersion returns the group/version associated with the given context, or a zero-value group/version.
func requestGroupVersion(ctx context.Context) schema.GroupVersion {
if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
return schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
}
return schema.GroupVersion{}
}

View File

@ -23,13 +23,15 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation/field"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/generic"
apistorage "k8s.io/apiserver/pkg/storage"
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/kubernetes/pkg/api/legacyscheme"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/core/validation"
coreapi "k8s.io/kubernetes/pkg/apis/core"
corevalidation "k8s.io/kubernetes/pkg/apis/core/validation"
)
// eventStrategy implements verification logic for Pod Presets.
@ -56,8 +58,9 @@ func (eventStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Obje
// Validate validates a new Event.
func (eventStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
event := obj.(*api.Event)
return validation.ValidateEvent(event)
groupVersion := requestGroupVersion(ctx)
event := obj.(*coreapi.Event)
return corevalidation.ValidateEventCreate(event, groupVersion)
}
// Canonicalize normalizes the object after validation.
@ -70,8 +73,10 @@ func (eventStrategy) Canonicalize(obj runtime.Object) {}
// ValidateUpdate is the default update validation for an end user.
func (eventStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList {
event := obj.(*api.Event)
return validation.ValidateEvent(event)
groupVersion := requestGroupVersion(ctx)
event := obj.(*coreapi.Event)
oldEvent := old.(*coreapi.Event)
return corevalidation.ValidateEventUpdate(event, oldEvent, groupVersion)
}
// AllowUnconditionalUpdate is the default update policy for Event objects.
@ -80,13 +85,13 @@ func (eventStrategy) AllowUnconditionalUpdate() bool {
}
// SelectableFields returns a field set that represents the object.
func SelectableFields(pip *api.Event) fields.Set {
func SelectableFields(pip *coreapi.Event) fields.Set {
return generic.ObjectMetaFieldsSet(&pip.ObjectMeta, true)
}
// GetAttrs returns labels and fields of a given object for filtering purposes.
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
pip, ok := obj.(*api.Event)
pip, ok := obj.(*coreapi.Event)
if !ok {
return nil, nil, fmt.Errorf("given object is not a Event")
}
@ -102,3 +107,11 @@ func Matcher(label labels.Selector, field fields.Selector) apistorage.SelectionP
GetAttrs: GetAttrs,
}
}
// requestGroupVersion returns the group/version associated with the given context, or a zero-value group/version.
func requestGroupVersion(ctx context.Context) schema.GroupVersion {
if requestInfo, found := genericapirequest.RequestInfoFrom(ctx); found {
return schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
}
return schema.GroupVersion{}
}

View File

@ -19,6 +19,7 @@ package rest
import (
"time"
eventsapiv1 "k8s.io/api/events/v1"
eventsapiv1beta1 "k8s.io/api/events/v1beta1"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
@ -45,6 +46,13 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorag
apiGroupInfo.VersionedResourcesStorageMap[eventsapiv1beta1.SchemeGroupVersion.Version] = storageMap
}
}
if apiResourceConfigSource.VersionEnabled(eventsapiv1.SchemeGroupVersion) {
if storageMap, err := p.v1Storage(apiResourceConfigSource, restOptionsGetter); err != nil {
return genericapiserver.APIGroupInfo{}, false, err
} else {
apiGroupInfo.VersionedResourcesStorageMap[eventsapiv1.SchemeGroupVersion.Version] = storageMap
}
}
return apiGroupInfo, true, nil
}
@ -61,6 +69,18 @@ func (p RESTStorageProvider) v1beta1Storage(apiResourceConfigSource serverstorag
return storage, err
}
func (p RESTStorageProvider) v1Storage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (map[string]rest.Storage, error) {
storage := map[string]rest.Storage{}
// events
eventsStorage, err := eventstore.NewREST(restOptionsGetter, uint64(p.TTL.Seconds()))
if err != nil {
return storage, err
}
storage["events"] = eventsStorage
return storage, err
}
func (p RESTStorageProvider) GroupName() string {
return events.GroupName
}

View File

@ -0,0 +1,23 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// +k8s:deepcopy-gen=package
// +k8s:protobuf-gen=package
// +k8s:openapi-gen=true
// +groupName=events.k8s.io
package v1 // import "k8s.io/api/events/v1"

View File

@ -0,0 +1,53 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// GroupName is the group name use in this package
const GroupName = "events.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"}
// Resource takes an unqualified resource and returns a Group qualified GroupResource
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}
var (
// TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api.
// localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes.
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
localSchemeBuilder = &SchemeBuilder
AddToScheme = localSchemeBuilder.AddToScheme
)
// Adds the list of known types to api.Scheme.
func addKnownTypes(scheme *runtime.Scheme) error {
scheme.AddKnownTypes(SchemeGroupVersion,
&Event{},
&EventList{},
)
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
return nil
}

View File

@ -0,0 +1,119 @@
/*
Copyright 2020 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// Event is a report of an event somewhere in the cluster. It generally denotes some state change in the system.
type Event struct {
metav1.TypeMeta `json:",inline"`
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// eventTime is the time when this Event was first observed. It is required.
EventTime metav1.MicroTime `json:"eventTime" protobuf:"bytes,2,opt,name=eventTime"`
// series is data about the Event series this event represents or nil if it's a singleton Event.
// +optional
Series *EventSeries `json:"series,omitempty" protobuf:"bytes,3,opt,name=series"`
// reportingController is the name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`.
// This field cannot be empty for new Events.
// +optional
ReportingController string `json:"reportingController,omitempty" protobuf:"bytes,4,opt,name=reportingController"`
// reportingInstance is the ID of the controller instance, e.g. `kubelet-xyzf`.
// This field cannot be empty for new Events and it can have at most 128 characters.
// +optional
ReportingInstance string `json:"reportingInstance,omitempty" protobuf:"bytes,5,opt,name=reportingInstance"`
// action is what action was taken/failed regarding to the regarding object. It is machine-readable.
// This field can have at most 128 characters.
// +optional
Action string `json:"action,omitempty" protobuf:"bytes,6,name=action"`
// reason is why the action was taken. It is human-readable.
// This field can have at most 128 characters.
// +optional
Reason string `json:"reason,omitempty" protobuf:"bytes,7,name=reason"`
// regarding contains the object this Event is about. In most cases it's an Object reporting controller
// implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because
// it acts on some changes in a ReplicaSet object.
// +optional
Regarding corev1.ObjectReference `json:"regarding,omitempty" protobuf:"bytes,8,opt,name=regarding"`
// related is the optional secondary object for more complex actions. E.g. when regarding object triggers
// a creation or deletion of related object.
// +optional
Related *corev1.ObjectReference `json:"related,omitempty" protobuf:"bytes,9,opt,name=related"`
// note is a human-readable description of the status of this operation.
// Maximal length of the note is 1kB, but libraries should be prepared to
// handle values up to 64kB.
// +optional
Note string `json:"note,omitempty" protobuf:"bytes,10,opt,name=note"`
// type is the type of this event (Normal, Warning), new types could be added in the future.
// It is machine-readable.
// +optional
Type string `json:"type,omitempty" protobuf:"bytes,11,opt,name=type"`
// deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedSource corev1.EventSource `json:"deprecatedSource,omitempty" protobuf:"bytes,12,opt,name=deprecatedSource"`
// deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedFirstTimestamp metav1.Time `json:"deprecatedFirstTimestamp,omitempty" protobuf:"bytes,13,opt,name=deprecatedFirstTimestamp"`
// deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedLastTimestamp metav1.Time `json:"deprecatedLastTimestamp,omitempty" protobuf:"bytes,14,opt,name=deprecatedLastTimestamp"`
// deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedCount int32 `json:"deprecatedCount,omitempty" protobuf:"varint,15,opt,name=deprecatedCount"`
}
// EventSeries contain information on series of events, i.e. thing that was/is happening
// continuously for some time. How often to update the EventSeries is up to the event reporters.
// The default event reporter in "k8s.io/client-go/tools/events/event_broadcaster.go" shows
// how this struct is updated on heartbeats and can guide customized reporter implementations.
type EventSeries struct {
// count is the number of occurrences in this series up to the last heartbeat time.
Count int32 `json:"count" protobuf:"varint,1,opt,name=count"`
// lastObservedTime is the time when last Event from the series was seen before last heartbeat.
LastObservedTime metav1.MicroTime `json:"lastObservedTime" protobuf:"bytes,2,opt,name=lastObservedTime"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// EventList is a list of Event objects.
type EventList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// items is a list of schema objects.
Items []Event `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@ -32,60 +32,65 @@ type Event struct {
// +optional
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Required. Time when this Event was first observed.
// eventTime is the time when this Event was first observed. It is required.
EventTime metav1.MicroTime `json:"eventTime" protobuf:"bytes,2,opt,name=eventTime"`
// Data about the Event series this event represents or nil if it's a singleton Event.
// series is data about the Event series this event represents or nil if it's a singleton Event.
// +optional
Series *EventSeries `json:"series,omitempty" protobuf:"bytes,3,opt,name=series"`
// Name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`.
// reportingController is the name of the controller that emitted this Event, e.g. `kubernetes.io/kubelet`.
// This field cannot be empty for new Events.
// +optional
ReportingController string `json:"reportingController,omitempty" protobuf:"bytes,4,opt,name=reportingController"`
// ID of the controller instance, e.g. `kubelet-xyzf`.
// reportingInstance is the ID of the controller instance, e.g. `kubelet-xyzf`.
// This field cannot be empty for new Events and it can have at most 128 characters.
// +optional
ReportingInstance string `json:"reportingInstance,omitempty" protobuf:"bytes,5,opt,name=reportingInstance"`
// What action was taken/failed regarding to the regarding object.
// action is what action was taken/failed regarding to the regarding object. It is machine-readable.
// This field can have at most 128 characters.
// +optional
Action string `json:"action,omitempty" protobuf:"bytes,6,name=action"`
// Why the action was taken.
// reason is why the action was taken. It is human-readable.
// This field can have at most 128 characters.
// +optional
Reason string `json:"reason,omitempty" protobuf:"bytes,7,name=reason"`
// The object this Event is about. In most cases it's an Object reporting controller implements.
// E.g. ReplicaSetController implements ReplicaSets and this event is emitted because
// regarding contains the object this Event is about. In most cases it's an Object reporting controller
// implements, e.g. ReplicaSetController implements ReplicaSets and this event is emitted because
// it acts on some changes in a ReplicaSet object.
// +optional
Regarding corev1.ObjectReference `json:"regarding,omitempty" protobuf:"bytes,8,opt,name=regarding"`
// Optional secondary object for more complex actions. E.g. when regarding object triggers
// related is the optional secondary object for more complex actions. E.g. when regarding object triggers
// a creation or deletion of related object.
// +optional
Related *corev1.ObjectReference `json:"related,omitempty" protobuf:"bytes,9,opt,name=related"`
// Optional. A human-readable description of the status of this operation.
// note is a human-readable description of the status of this operation.
// Maximal length of the note is 1kB, but libraries should be prepared to
// handle values up to 64kB.
// +optional
Note string `json:"note,omitempty" protobuf:"bytes,10,opt,name=note"`
// Type of this event (Normal, Warning), new types could be added in the
// future.
// type is the type of this event (Normal, Warning), new types could be added in the future.
// It is machine-readable.
// +optional
Type string `json:"type,omitempty" protobuf:"bytes,11,opt,name=type"`
// Deprecated field assuring backward compatibility with core.v1 Event type
// deprecatedSource is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedSource corev1.EventSource `json:"deprecatedSource,omitempty" protobuf:"bytes,12,opt,name=deprecatedSource"`
// Deprecated field assuring backward compatibility with core.v1 Event type
// deprecatedFirstTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedFirstTimestamp metav1.Time `json:"deprecatedFirstTimestamp,omitempty" protobuf:"bytes,13,opt,name=deprecatedFirstTimestamp"`
// Deprecated field assuring backward compatibility with core.v1 Event type
// deprecatedLastTimestamp is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedLastTimestamp metav1.Time `json:"deprecatedLastTimestamp,omitempty" protobuf:"bytes,14,opt,name=deprecatedLastTimestamp"`
// Deprecated field assuring backward compatibility with core.v1 Event type
// deprecatedCount is the deprecated field assuring backward compatibility with core.v1 Event type.
// +optional
DeprecatedCount int32 `json:"deprecatedCount,omitempty" protobuf:"varint,15,opt,name=deprecatedCount"`
}
@ -93,9 +98,9 @@ type Event struct {
// EventSeries contain information on series of events, i.e. thing that was/is happening
// continuously for some time.
type EventSeries struct {
// Number of occurrences in this series up to the last heartbeat time
// count is the number of occurrences in this series up to the last heartbeat time.
Count int32 `json:"count" protobuf:"varint,1,opt,name=count"`
// Time when last Event from the series was seen before last heartbeat.
// lastObservedTime is the time when last Event from the series was seen before last heartbeat.
LastObservedTime metav1.MicroTime `json:"lastObservedTime" protobuf:"bytes,2,opt,name=lastObservedTime"`
// +k8s:deprecated=state,protobuf=3
@ -113,6 +118,6 @@ type EventList struct {
// +optional
metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
// Items is a list of schema objects.
// items is a list of schema objects.
Items []Event `json:"items" protobuf:"bytes,2,rep,name=items"`
}

View File

@ -42,6 +42,7 @@ import (
coordinationv1 "k8s.io/api/coordination/v1"
coordinationv1beta1 "k8s.io/api/coordination/v1beta1"
corev1 "k8s.io/api/core/v1"
eventsv1 "k8s.io/api/events/v1"
eventsv1beta1 "k8s.io/api/events/v1beta1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
imagepolicyv1alpha1 "k8s.io/api/imagepolicy/v1alpha1"
@ -92,6 +93,7 @@ var groups = []runtime.SchemeBuilder{
coordinationv1.SchemeBuilder,
coordinationv1beta1.SchemeBuilder,
corev1.SchemeBuilder,
eventsv1.SchemeBuilder,
eventsv1beta1.SchemeBuilder,
extensionsv1beta1.SchemeBuilder,
imagepolicyv1alpha1.SchemeBuilder,

View File

@ -206,6 +206,14 @@ func GetEtcdStorageDataForNamespace(namespace string) map[schema.GroupVersionRes
},
// --
// k8s.io/kubernetes/pkg/apis/events/v1
gvr("events.k8s.io", "v1", "events"): {
Stub: `{"metadata": {"name": "event3"}, "regarding": {"namespace": "` + namespace + `"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness", "type": "Normal"}`,
ExpectedEtcdPath: "/registry/events/" + namespace + "/event3",
ExpectedGVK: gvkP("", "v1", "Event"),
},
// --
// k8s.io/kubernetes/pkg/apis/events/v1beta1
gvr("events.k8s.io", "v1beta1", "events"): {
Stub: `{"metadata": {"name": "event2"}, "regarding": {"namespace": "` + namespace + `"}, "note": "some data here", "eventTime": "2017-08-09T15:04:05.000000Z", "reportingInstance": "node-xyz", "reportingController": "k8s.io/my-controller", "action": "DidNothing", "reason": "Laziness"}`,

5
vendor/modules.txt vendored
View File

@ -1560,6 +1560,7 @@ k8s.io/api/coordination/v1beta1
k8s.io/api/core/v1
k8s.io/api/discovery/v1alpha1
k8s.io/api/discovery/v1beta1
k8s.io/api/events/v1
k8s.io/api/events/v1beta1
k8s.io/api/extensions/v1beta1
k8s.io/api/flowcontrol/v1alpha1
@ -1887,6 +1888,7 @@ k8s.io/client-go/informers/discovery
k8s.io/client-go/informers/discovery/v1alpha1
k8s.io/client-go/informers/discovery/v1beta1
k8s.io/client-go/informers/events
k8s.io/client-go/informers/events/v1
k8s.io/client-go/informers/events/v1beta1
k8s.io/client-go/informers/extensions
k8s.io/client-go/informers/extensions/v1beta1
@ -1962,6 +1964,8 @@ k8s.io/client-go/kubernetes/typed/discovery/v1alpha1
k8s.io/client-go/kubernetes/typed/discovery/v1alpha1/fake
k8s.io/client-go/kubernetes/typed/discovery/v1beta1
k8s.io/client-go/kubernetes/typed/discovery/v1beta1/fake
k8s.io/client-go/kubernetes/typed/events/v1
k8s.io/client-go/kubernetes/typed/events/v1/fake
k8s.io/client-go/kubernetes/typed/events/v1beta1
k8s.io/client-go/kubernetes/typed/events/v1beta1/fake
k8s.io/client-go/kubernetes/typed/extensions/v1beta1
@ -2016,6 +2020,7 @@ k8s.io/client-go/listers/coordination/v1beta1
k8s.io/client-go/listers/core/v1
k8s.io/client-go/listers/discovery/v1alpha1
k8s.io/client-go/listers/discovery/v1beta1
k8s.io/client-go/listers/events/v1
k8s.io/client-go/listers/events/v1beta1
k8s.io/client-go/listers/extensions/v1beta1
k8s.io/client-go/listers/flowcontrol/v1alpha1