Deserializing ObjectMeta Regardless of Kind

6/26/2019

TL;DR: How can I flexibly decode a k8s API object and inspect its top-level metav1.ObjectMeta struct without knowing the object's Kind in advance?


I'm writing an admission controller endpoint that unmarshals a metav1.AdmissionReview object's Request.Object.Raw field into a concrete object based on the Request.Kind field - e.g.

if kind == "Pod" {
    var pod core.Pod
    // ...
    if _, _, err := deserializer.Decode(admissionReview.Request.Object.Raw, nil, &pod); err != nil {
        return nil, err
    }

    annotations := pod.ObjectMeta.Annotations
    // inspect/validate the annotations...

This requires knowing all possible types up front, or perhaps asking a user to supply a map[kind]corev1.Object that we can use to be more flexible.

What I'd like to instead achieve is something closer to:

var objMeta core.ObjectMeta
if _, _, err := deserializer.Decode(admissionReview.Request.Object.Raw, nil, &objMeta); err != nil {
        return nil, err
}

// if objMeta is populated, validate the fields, else
// assume it is an object that does not define an ObjectMeta
// as part of its schema.

Is this possible? The k8s API surface is fairly extensive, and I've crawled through the metav1 godoc, corev1 godoc & https://cs.k8s.io for prior art without a decent example.

The closest I've found is possibly the ObjectMetaAccessor interface, but I'd need to get from an AdmissionReview.Request.Object (type runtime.RawExtension) to a runtime.Object first.

-- elithrar
go
kubernetes

2 Answers

6/27/2019

It seems there are two possibilities:

  1. Either the field Object should already contain the correct object instance, when using Go client, check code here.
  2. Try using the converters here
-- Nepomucen
Source: StackOverflow

7/5/2019

I believe you can't find what you are looking for because, when decoding an object, Kubernetes uses GetObjectKind and compares the result to a Scheme to convert the object to a concrete type, rather than using some generic like approach and interacting with the fields of an object without knowing it's concrete type.

So you can use reflection instead, something like:

k8sObjValue := reflect.ValueOf(admissionReview.Request.Object.Raw).Elem()
k8sObjObjectMeta := k8sObjValue.FieldByName("ObjectMeta")
annotations, ok := k8sObjObjectMeta.FieldByName("Annotations").(map[string]string)
if !ok {
    panic("failed to retrieve annotations")
}

EDIT:

Or closer to your requirements, convert to an ObjectMeta object

k8sObjValue := reflect.ValueOf(admissionReview.Request.Object.Raw).Elem()
objMeta, ok := k8sObjValue.FieldByName("ObjectMeta").(core.ObjectMeta)
if !ok {
    panic("failed to retrieve object metadata")
}
-- dippynark
Source: StackOverflow