apiextensions: set 'metadata.generation: 1' during read from etcd if not set

This commit is contained in:
Dr. Stefan Schimanski 2019-08-27 08:07:57 +02:00
parent 533daf6624
commit 84d29fc8fa
3 changed files with 35 additions and 1 deletions

View File

@ -1020,6 +1020,7 @@ func (t crdConversionRESTOptionsGetter) GetRESTOptions(resource schema.GroupReso
d := schemaCoercingDecoder{delegate: ret.StorageConfig.Codec, validator: unstructuredSchemaCoercer{
// drop invalid fields while decoding old CRs (before we haven't had any ObjectMeta validation)
dropInvalidMetadata: true,
repairGeneration: true,
structuralSchemas: t.structuralSchemas,
structuralSchemaGK: t.structuralSchemaGK,
preserveUnknownFields: t.preserveUnknownFields,
@ -1120,6 +1121,7 @@ func (v schemaCoercingConverter) ConvertFieldLabel(gvk schema.GroupVersionKind,
// - generic pruning of unknown fields following a structural schema.
type unstructuredSchemaCoercer struct {
dropInvalidMetadata bool
repairGeneration bool
structuralSchemas map[string]*structuralschema.Structural
structuralSchemaGK schema.GroupKind
@ -1154,6 +1156,10 @@ func (v *unstructuredSchemaCoercer) apply(u *unstructured.Unstructured) error {
if err := schemaobjectmeta.Coerce(nil, u.Object, v.structuralSchemas[gv.Version], false, v.dropInvalidMetadata); err != nil {
return err
}
// fixup missing generation in very old CRs
if v.repairGeneration && objectMeta.Generation == 0 {
objectMeta.Generation = 1
}
}
// restore meta fields, starting clean

View File

@ -167,6 +167,7 @@ func TestGetObjectMetaNils(t *testing.T) {
"apiVersion": "v1",
"metadata": map[string]interface{}{
"generateName": nil,
"generation": nil,
"labels": map[string]interface{}{
"foo": nil,
},
@ -179,7 +180,10 @@ func TestGetObjectMetaNils(t *testing.T) {
t.Fatal(err)
}
if o.GenerateName != "" {
t.Errorf("expected null json value to be read as \"\" string, but got: %q", o.GenerateName)
t.Errorf("expected null json generateName value to be read as \"\" string, but got: %q", o.GenerateName)
}
if o.Generation != 0 {
t.Errorf("expected null json generation value to be read as zero, but got: %q", o.Generation)
}
if got, expected := o.Labels, map[string]string{"foo": ""}; !reflect.DeepEqual(got, expected) {
t.Errorf("unexpected labels, expected=%#v, got=%#v", expected, got)
@ -198,6 +202,9 @@ func TestGetObjectMetaNils(t *testing.T) {
if got, expected := o.GenerateName, pod.ObjectMeta.GenerateName; got != expected {
t.Errorf("expected generatedName to be %q, got %q", expected, got)
}
if got, expected := o.Generation, pod.ObjectMeta.Generation; got != expected {
t.Errorf("expected generation to be %q, got %q", expected, got)
}
if got, expected := o.Labels, pod.ObjectMeta.Labels; !reflect.DeepEqual(got, expected) {
t.Errorf("expected labels to be %v, got %v", expected, got)
}

View File

@ -62,6 +62,7 @@ func TestPostInvalidObjectMeta(t *testing.T) {
obj := fixtures.NewNoxuInstance("default", "foo")
unstructured.SetNestedField(obj.UnstructuredContent(), int64(42), "metadata", "unknown")
unstructured.SetNestedField(obj.UnstructuredContent(), nil, "metadata", "generation")
unstructured.SetNestedField(obj.UnstructuredContent(), map[string]interface{}{"foo": int64(42), "bar": "abc"}, "metadata", "labels")
_, err = instantiateCustomResource(t, obj, noxuResourceClient, noxuDefinition)
if err == nil {
@ -86,6 +87,14 @@ func TestPostInvalidObjectMeta(t *testing.T) {
} else if found {
t.Errorf("unexpected metadata.unknown=%#v: expected this to be pruned", unknown)
}
if generation, found, err := unstructured.NestedInt64(obj.UnstructuredContent(), "metadata", "generation"); err != nil {
t.Errorf("unexpected error getting metadata.generation: %v", err)
} else if !found {
t.Errorf("expected metadata.generation=1: got: %d", generation)
} else if generation != 1 {
t.Errorf("unexpected metadata.generation=%d: expected this to be set to 1", generation)
}
}
func TestInvalidObjectMetaInStorage(t *testing.T) {
@ -150,6 +159,8 @@ func TestInvalidObjectMetaInStorage(t *testing.T) {
original := fixtures.NewNoxuInstance("default", "foo")
unstructured.SetNestedField(original.UnstructuredContent(), int64(42), "metadata", "unknown")
unstructured.SetNestedField(original.UnstructuredContent(), nil, "metadata", "generation")
unstructured.SetNestedField(original.UnstructuredContent(), map[string]interface{}{"foo": int64(42), "bar": "abc"}, "metadata", "annotations")
unstructured.SetNestedField(original.UnstructuredContent(), map[string]interface{}{"invalid": "x y"}, "metadata", "labels")
unstructured.SetNestedField(original.UnstructuredContent(), int64(42), "embedded", "metadata", "unknown")
@ -193,6 +204,16 @@ func TestInvalidObjectMetaInStorage(t *testing.T) {
t.Errorf("Unexpected to find embedded.metadata.unknown=%#v", unknown)
}
t.Logf("Checking that metadata.generation=1")
if generation, found, err := unstructured.NestedInt64(obj.UnstructuredContent(), "metadata", "generation"); err != nil {
t.Errorf("unexpected error getting metadata.generation: %v", err)
} else if !found {
t.Errorf("expected metadata.generation=1: got: %d", generation)
} else if generation != 1 {
t.Errorf("unexpected metadata.generation=%d: expected this to be set to 1", generation)
}
t.Logf("Checking that ObjectMeta is pruned from wrongly-typed annotations")
if annotations, found, err := unstructured.NestedStringMap(obj.UnstructuredContent(), "metadata", "annotations"); err != nil {