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.
It seems there are two possibilities:
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")
}