不论种类如何,反序列化ObjectMeta

时间:2019-06-26 05:01:07

标签: go kubernetes

TL; DR::如何在不事先知道对象的metav1.ObjectMeta的情况下灵活地解码k8s API对象并检查其顶级Kind结构?


我正在编写一个准入控制器端点,该端点根据metav1.AdmissionReview字段将Request.Object.Raw对象的Request.Kind字段解组为一个具体对象-例如

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...

这需要预先知道所有可能的类型,或者要求用户提供map[kind]corev1.Object,我们可以使用它来提高灵活性。

我想实现的目标更接近:

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.

这可能吗? k8s API涉及面非常广泛,在没有适当示例的情况下,我已经遍历了metav1 godoc,corev1 godoc和https://cs.k8s.io的现有技术。

我找到的最接近的可能是ObjectMetaAccessor界面,但是我需要首先从AdmissionReview.Request.Object(类型runtime.RawExtension)到runtime.Object

3 个答案:

答案 0 :(得分:1)

我相信您找不到想要的东西,因为在解码对象时,Kubernetes使用GetObjectKind并将结果与​​Scheme进行比较以将对象转换为具体类型,而不是而不是使用某些类似generic的方法并与对象的字段进行交互而不知道其具体类型。

因此,您可以改用反射,例如:

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")
}

编辑:

或更接近您的要求,转换为ObjectMeta对象

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

答案 1 :(得分:1)

最近发现了一种执行此操作的方法,让我在这里进行描述:

快速免责声明:我使用了mission / v1,但从未使用admission / v1beta1进行过测试,该测试应该完全相同。

admissionReview.Request.Object的数据类型为runtime.RawExtensionk8s.io/apimachinery/pkg/runtime提供了一种可以将runtime.RawExtension转换为runtime.Object的方法。该方法称为runtime.Convert_runtime_RawExtension_To_runtime_Object(...)。从那里,您可以轻松地转换为unstructured.Unstructured数据类型,该数据类型具有MetaV1对象的所有字段,可以通过简单的getter方法进行访问。

下面是一个代码片段,可让您完成此任务:

import (
    // ...
    "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    "k8s.io/apimachinery/pkg/runtime"
    // ...
)

// ...

func dummyFunc(ar *v1.AdmissionReview) {
    // ...
    var obj runtime.Object
    var scope conversion.Scope // While not actually used within the function, need to pass in
    err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&ar.Request.Object, &obj, scope)
    if err != nil {
        // ...
    }

    innerObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
    if err != nil {
        // ...
    }
    u := unstructured.Unstructured{Object: innerObj}
    // Now the `u` variable has all the meta info available with simple getters.
    // Sample:
    labels := u.GetLabels()
    kind := u.GetKind()
    // etc.
    // ...
}

参考:

  1. https://godoc.org/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured
  2. https://godoc.org/k8s.io/apimachinery/pkg/runtime#Convert_runtime_RawExtension_To_runtime_Object
  3. https://godoc.org/k8s.io/api/admission/v1#AdmissionRequest

答案 2 :(得分:0)

似乎有两种可能性:

  1. 在使用Go client时,字段Object应该已经包含正确的对象实例,请检查代码here
  2. 尝试使用转换器here