将 Kubernetes unstructured 类型转为对象
2021-03-14 tech go kubernetes 8 mins 2852 字
使用代码和k8s交互,主要用到 client-go 这个库中的两个主要 APIs: kubernetes.Interface
API 和非结构化的 dynamic.Interface
API。
在使用 dynamic.Interface
时,我们经常需要在 string,unstructured ,对象, map[string] interface{} 转来转去,本文介绍将非结构化的类型 (unstructured) 与对象互转的两个方法。
方法一:json
使用 json 包将 unstructured 序列化为 []byte ,再反序列化为对象,这是 golang 里最通用的做法了。不过这个做法有点局限性,如果内容存在一些特殊字符容易在 json.Unmarshal 的时候报错,这时候还是使用方法二,官方的比较靠谱。
unstructured -> []byte -> object
import "encoding/json"
...
// 从k8s返回值里构造一个 unstructured
var utd *unstructured.Unstructured
utd, err = dynamicClient.Resource(gvr).Create(xxxUnstructured, metav1.CreateOptions{})
if err != nil {
logrus.Error(err)
return nil, err
}
// unstructured -> []byte
result, err := utd.MarshalJSON()
if err != nil {
logrus.Error(err)
return nil, err
}
// []byte -> obj
var obj XxxObject
if err := json.Unmarshal(result, &obj); err != nil {
logrus.Error(err)
return nil, err
}
object -> []byte -> unstructured
ps: 对象转为[]byte时需要注意的一点是,object里不能存在 map[interface{}] interface{} 类型,如果存在此种类型,一定要在源头将其转换为 map[string]interface 类型,否则无法使用json包。
json: unsupported type: map[interface {}]interface {}
相关 issue参考:map[interface{}]interface{} on a map[string]interface{}
import "gopkg.in/yaml.v3"
...
//// 从k8s返回值里构造一个 object
var obj XxxObj
err := yaml.Unmarshal([]byte(yamlData), &obj)
if err != nil {
logrus.Error(err)
return nil, err
}
// obj -> []byte
data, err := json.Marshal(&obj)
if err != nil {
logrus.Error(err)
return nil, err
}
// []byte -> Unstructured
utd := &unstructured.Unstructured{}
err := json.Unmarshal(data, &utd.Object)
if err != nil {
logrus.Error(err)
return nil, err
}
方法二:runtime.UnstructuredConverter
runtime.DefaultUnstructuredConverter
基本上满足了我们大部分场景。
unstructured -> obj
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
"sigs.k8s.io/cluster-api/api/v1alpha2"
)
...
// 从k8s返回值里构造一个 unstructured
var utd *unstructured.Unstructured
utd, err = dynamicClient.Resource(gvr).Create(xxxUnstructured, metav1.CreateOptions{})
if err != nil {
logrus.Error(err)
return nil, err
}
// unstructured -> obj
var obj XxxObject
runtime.DefaultUnstructuredConverter.FromUnstructured(utd.UnstructuredContent(), &cpol)
obj -> unstructured
utd, err := runtime.UnstructuredConverter.ToUnstructured(obj)
objOther -> objK8sVx
假定c是一个第三方封装的object,内容包含了v1node的数据。
node := c.(interface{})
utd, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&node)
if err != nil {
logrus.Error(err)
}
v1node := &v1.Node{}
err = runtime.DefaultUnstructuredConverter.FromUnstructured(utd, v1node)
if err != nil {
logrus.Error(err)
}