mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
use existing validation code and decoding in fieldManager admission
This commit is contained in:
parent
da610d6667
commit
fc1841d72f
@ -21,7 +21,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apiserver/pkg/admission"
|
"k8s.io/apiserver/pkg/admission"
|
||||||
"k8s.io/apiserver/pkg/warning"
|
"k8s.io/apiserver/pkg/warning"
|
||||||
)
|
)
|
||||||
@ -65,7 +64,7 @@ func (admit *managedFieldsValidatingAdmissionController) Admit(ctx context.Conte
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
managedFieldsAfterAdmission := objectMeta.GetManagedFields()
|
managedFieldsAfterAdmission := objectMeta.GetManagedFields()
|
||||||
if err := validateManagedFields(managedFieldsAfterAdmission); err != nil {
|
if err := ValidateManagedFields(managedFieldsAfterAdmission); err != nil {
|
||||||
objectMeta.SetManagedFields(managedFieldsBeforeAdmission)
|
objectMeta.SetManagedFields(managedFieldsBeforeAdmission)
|
||||||
warning.AddWarning(ctx, "",
|
warning.AddWarning(ctx, "",
|
||||||
fmt.Sprintf(InvalidManagedFieldsAfterMutatingAdmissionWarningFormat,
|
fmt.Sprintf(InvalidManagedFieldsAfterMutatingAdmissionWarningFormat,
|
||||||
@ -82,21 +81,3 @@ func (admit *managedFieldsValidatingAdmissionController) Validate(ctx context.Co
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateManagedFields(managedFields []metav1.ManagedFieldsEntry) error {
|
|
||||||
for i, managed := range managedFields {
|
|
||||||
if len(managed.APIVersion) < 1 {
|
|
||||||
return fmt.Errorf(".metadata.managedFields[%d]: missing apiVersion", i)
|
|
||||||
}
|
|
||||||
if len(managed.FieldsType) < 1 {
|
|
||||||
return fmt.Errorf(".metadata.managedFields[%d]: missing fieldsType", i)
|
|
||||||
}
|
|
||||||
if len(managed.Manager) < 1 {
|
|
||||||
return fmt.Errorf(".metadata.managedFields[%d]: missing manager", i)
|
|
||||||
}
|
|
||||||
if managed.FieldsV1 == nil {
|
|
||||||
return fmt.Errorf(".metadata.managedFields[%d]: missing fieldsV1", i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,115 @@
|
|||||||
|
package fieldmanager_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||||
|
"k8s.io/apiserver/pkg/admission"
|
||||||
|
"k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager"
|
||||||
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAdmission(t *testing.T) {
|
||||||
|
wrap := &mockAdmissionController{}
|
||||||
|
ac := fieldmanager.NewManagedFieldsValidatingAdmissionController(wrap)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
beforeAdmission []metav1.ManagedFieldsEntry
|
||||||
|
afterAdmission []metav1.ManagedFieldsEntry
|
||||||
|
expected []metav1.ManagedFieldsEntry
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
beforeAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
Manager: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
afterAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
Manager: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
Manager: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
beforeAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
APIVersion: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
afterAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
APIVersion: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
APIVersion: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
beforeAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
FieldsType: "FieldsV1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
afterAdmission: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
FieldsType: "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: []metav1.ManagedFieldsEntry{
|
||||||
|
{
|
||||||
|
FieldsType: "FieldsV1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
obj := &unstructured.Unstructured{}
|
||||||
|
obj.SetManagedFields(test.beforeAdmission)
|
||||||
|
wrap.admit = replaceManagedFields(test.afterAdmission)
|
||||||
|
|
||||||
|
attrs := admission.NewAttributesRecord(obj, obj, api.Kind("ConfigMap").WithVersion("version"), "default", "", api.Resource("configmaps").WithVersion("version"), "", admission.Update, nil, false, nil)
|
||||||
|
if err := ac.(admission.MutationInterface).Admit(context.TODO(), attrs, nil); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(obj.GetManagedFields(), test.expected) {
|
||||||
|
t.Fatalf("expected: \n%v\ngot:\n%v", test.expected, obj.GetManagedFields())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceManagedFields(with []metav1.ManagedFieldsEntry) func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
objectMeta, err := meta.Accessor(a.GetObject())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
objectMeta.SetManagedFields(with)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockAdmissionController struct {
|
||||||
|
admit func(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockAdmissionController) Handles(operation admission.Operation) bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *mockAdmissionController) Admit(ctx context.Context, a admission.Attributes, o admission.ObjectInterfaces) error {
|
||||||
|
return c.admit(ctx, a, o)
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package fieldmanager
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
v1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ValidateManagedFields by checking the integrity of every entry and trying to decode
|
||||||
|
// them to the internal format
|
||||||
|
func ValidateManagedFields(managedFields []metav1.ManagedFieldsEntry) error {
|
||||||
|
validationErrs := v1validation.ValidateManagedFields(managedFields, field.NewPath("metadata").Child("managedFields"))
|
||||||
|
if len(validationErrs) > 0 {
|
||||||
|
return validationErrs.ToAggregate()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := DecodeManagedFields(managedFields); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user