mirror of https://github.com/k3s-io/k3s
Add TypeAccessor to api/meta for objects without Object/ListMeta
Adding objects that have TypeMeta (use runtime.Scheme) but do not expose ObjectMeta/ListMeta (because they are not Kube API objects) and wanted to get the simpler access path for in memory objects.pull/6/head
parent
eeb712d163
commit
5f6caaba2e
|
@ -32,17 +32,16 @@ type VersionInterfaces struct {
|
|||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field (Name, UID, Namespace on lists) will be a no-op and return
|
||||
// a default value.
|
||||
// TODO: rename to ObjectInterface when we clear up these interfaces.
|
||||
type Interface interface {
|
||||
TypeInterface
|
||||
|
||||
Namespace() string
|
||||
SetNamespace(namespace string)
|
||||
Name() string
|
||||
SetName(name string)
|
||||
UID() types.UID
|
||||
SetUID(uid types.UID)
|
||||
APIVersion() string
|
||||
SetAPIVersion(version string)
|
||||
Kind() string
|
||||
SetKind(kind string)
|
||||
ResourceVersion() string
|
||||
SetResourceVersion(version string)
|
||||
SelfLink() string
|
||||
|
@ -53,6 +52,14 @@ type Interface interface {
|
|||
SetAnnotations(annotations map[string]string)
|
||||
}
|
||||
|
||||
// TypeInterface exposes the type and APIVersion of versioned or internal API objects.
|
||||
type TypeInterface interface {
|
||||
APIVersion() string
|
||||
SetAPIVersion(version string)
|
||||
Kind() string
|
||||
SetKind(kind string)
|
||||
}
|
||||
|
||||
// MetadataAccessor lets you work with object and list metadata from any of the versioned or
|
||||
// internal API objects. Attempting to set or retrieve a field on an object that does
|
||||
// not support that field (Name, UID, Namespace on lists) will be a no-op and return
|
||||
|
|
|
@ -74,6 +74,32 @@ func Accessor(obj interface{}) (Interface, error) {
|
|||
return a, nil
|
||||
}
|
||||
|
||||
// TypeAccessor returns an interface that allows retrieving and modifying the APIVersion
|
||||
// and Kind of an in-memory internal object.
|
||||
// TODO: this interface is used to test code that does not have ObjectMeta or ListMeta
|
||||
// in round tripping (objects which can use apiVersion/kind, but do not fit the Kube
|
||||
// api conventions).
|
||||
func TypeAccessor(obj interface{}) (TypeInterface, error) {
|
||||
v, err := conversion.EnforcePtr(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
t := v.Type()
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("expected struct, but got %v: %v (%#v)", v.Kind(), t, v.Interface())
|
||||
}
|
||||
|
||||
typeMeta := v.FieldByName("TypeMeta")
|
||||
if !typeMeta.IsValid() {
|
||||
return nil, fmt.Errorf("struct %v lacks embedded TypeMeta type", t)
|
||||
}
|
||||
a := &genericAccessor{}
|
||||
if err := extractFromTypeMeta(typeMeta, a); err != nil {
|
||||
return nil, fmt.Errorf("unable to find type fields on %#v: %v", typeMeta, err)
|
||||
}
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// NewAccessor returns a MetadataAccessor that can retrieve
|
||||
// or manipulate resource version on objects derived from core API
|
||||
// metadata concepts.
|
||||
|
|
|
@ -79,6 +79,17 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
typeAccessor, err := TypeAccessor(&j)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if e, a := "a", accessor.APIVersion(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "b", accessor.Kind(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
accessor.SetNamespace("baz")
|
||||
accessor.SetName("bar")
|
||||
accessor.SetUID("other")
|
||||
|
@ -109,6 +120,15 @@ func TestGenericTypeMeta(t *testing.T) {
|
|||
if e, a := "google.com", j.SelfLink; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
|
||||
typeAccessor.SetAPIVersion("d")
|
||||
typeAccessor.SetKind("e")
|
||||
if e, a := "d", j.APIVersion; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
if e, a := "e", j.Kind; e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
}
|
||||
}
|
||||
|
||||
type InternalTypeMeta struct {
|
||||
|
|
|
@ -163,7 +163,7 @@ func fuzzerFor(t *testing.T, version string, src rand.Source) *fuzz.Fuzzer {
|
|||
func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, seed int64) runtime.Object {
|
||||
fuzzerFor(t, forVersion, rand.NewSource(seed)).Fuzz(item)
|
||||
|
||||
j, err := meta.Accessor(item)
|
||||
j, err := meta.TypeAccessor(item)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error %v for %#v", err, item)
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func TestRoundTripTypes(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Couldn't make a %v? %v", kind, err)
|
||||
}
|
||||
if _, err := meta.Accessor(item); err != nil {
|
||||
if _, err := meta.TypeAccessor(item); err != nil {
|
||||
t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err)
|
||||
}
|
||||
roundTripSame(t, item)
|
||||
|
|
|
@ -360,6 +360,9 @@ func (s *Scheme) Decode(data []byte) (Object, error) {
|
|||
// pointer to an api type.
|
||||
// If obj's APIVersion doesn't match that in data, an attempt will be made to convert
|
||||
// data into obj's version.
|
||||
// TODO: allow Decode/DecodeInto to take a default apiVersion and a default kind, to
|
||||
// be applied if the provided object does not have either field (integrate external
|
||||
// apis into the decoding scheme).
|
||||
func (s *Scheme) DecodeInto(data []byte, obj Object) error {
|
||||
return s.raw.DecodeInto(data, obj)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue