client-go: анализ файлов json kubernetes для структур k8s
Я хотел бы проанализировать файл манифеста kubernetes (json/yaml) и иметь возможность конвертировать их в структуры k8s (чтобы позже манипулировать ими)
Я знаю, что есть функция NewYAMLOrJSONDecoder().Decode() ( https://github.com/kubernetes/apimachinery/blob/master/pkg/util/yaml/decoder.go) для чтения файла json / yaml, но Следующий шаг: как преобразовать их в структуру / тип k8s?
т.е. если я читаю файл yaml с объектом Namespace, как, например, преобразовать его в интерфейс core/v1/namespace
С Уважением,
2 ответа
import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/kubernetes/scheme"
)
func decode(data []byte) (*v1.Namespace, error) {
decoder := serializer.NewCodecFactory(scheme.Scheme).UniversalDecoder()
object := &v1.Namespace{}
err := runtime.DecodeInto(decoder, data, object)
if err != nil {
return nil, err
}
return object, nil
}
Проходить SchemeGroupVersion
сгенерированы для ваших CRD на UniversalDecoder
звоните, если нужно.
Использовать runtime.Decode
вместо того runtime.DecodeInto
для декодирования неопределенного типа объекта.
Спасибо svenwltr, я не знал, что мы можем сделать это.
В то же время мне удается найти не лучший подход, а другой:
package main
import (
"flag"
"fmt"
"os"
"io"
"path/filepath"
"log"
"encoding/json"
//"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func main() {
var kubeconfig *string
if home := homeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
f,err := os.Open("namespace.yaml")
if err!=nil {
log.Fatal(err)
}
d := yaml.NewYAMLOrJSONDecoder(f,4096)
dd := clientset.Discovery()
apigroups,err := discovery.GetAPIGroupResources(dd)
if err != nil {
log.Fatal(err)
}
restmapper := discovery.NewRESTMapper(apigroups,meta.InterfacesForUnstructured)
for {
// https://github.com/kubernetes/apimachinery/blob/master/pkg/runtime/types.go
ext := runtime.RawExtension{}
if err := d.Decode(&ext); err!=nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
fmt.Println("raw: ",string(ext.Raw))
versions := &runtime.VersionedObjects{}
//_, gvk, err := objectdecoder.Decode(ext.Raw,nil,versions)
obj, gvk, err := unstructured.UnstructuredJSONScheme.Decode(ext.Raw,nil,versions)
fmt.Println("obj: ",obj)
// https://github.com/kubernetes/apimachinery/blob/master/pkg/api/meta/interfaces.go
mapping, err := restmapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil {
log.Fatal(err)
}
restconfig := config
restconfig.GroupVersion = &schema.GroupVersion {
Group: mapping.GroupVersionKind.Group,
Version: mapping.GroupVersionKind.Version,
}
dclient,err := dynamic.NewClient(restconfig)
if err != nil {
log.Fatal(err)
}
// https://github.com/kubernetes/client-go/blob/master/discovery/discovery_client.go
apiresourcelist, err := dd.ServerResources()
if err != nil {
log.Fatal(err)
}
var myapiresource metav1.APIResource
for _,apiresourcegroup := range(apiresourcelist) {
if apiresourcegroup.GroupVersion == mapping.GroupVersionKind.Version {
for _,apiresource := range(apiresourcegroup.APIResources) {
//fmt.Println(apiresource)
if apiresource.Name == mapping.Resource && apiresource.Kind == mapping.GroupVersionKind.Kind {
myapiresource = apiresource
}
}
}
}
fmt.Println(myapiresource)
// https://github.com/kubernetes/client-go/blob/master/dynamic/client.go
var unstruct unstructured.Unstructured
unstruct.Object = make(map[string]interface{})
var blob interface{}
if err := json.Unmarshal(ext.Raw,&blob); err != nil {
log.Fatal(err)
}
unstruct.Object = blob.(map[string]interface{})
fmt.Println("unstruct:",unstruct)
ns := "default"
if md,ok := unstruct.Object["metadata"]; ok {
metadata := md.(map[string]interface{})
if internalns,ok := metadata["namespace"]; ok {
ns = internalns.(string)
}
}
res := dclient.Resource(&myapiresource,ns)
fmt.Println(res)
us,err := res.Create(&unstruct)
if err != nil {
log.Fatal(err)
}
fmt.Println("unstruct response:",us)
}
}
func homeDir() string {
if h := os.Getenv("HOME"); h != "" {
return h
}
return os.Getenv("USERPROFILE") // windows
}
Этот вопрос очень похож на Как десериализовать файл YAML Kubernetes, но этот вопрос немного устарел, так как имена пакетов изменились.
Кроме того, он напрямую не использует клиент go, что означает, что для этого может быть другое решение.
Вот пример:
package main
import (
"fmt"
"k8s.io/kubernetes/pkg/api"
_ "k8s.io/kubernetes/pkg/api/install"
_ "k8s.io/kubernetes/pkg/apis/extensions/install"
"k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
)
var json = `
{
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
"metadata": null,
"name": "my-nginx",
"replicas": 2,
"spec": null,
"template": {
"metadata": {
"labels": {
"run": "my-nginx"
}
},
"spec": {
"containers": [
{
"image": "nginx",
"name": "my-nginx",
"ports": [
{
"containerPort": 80
}
]
}
]
}
}
}
`
func main() {
// decode := api.Codecs.UniversalDecoder().Decode
decode := api.Codecs.UniversalDeserializer().Decode
obj, _, err := decode([]byte(json), nil, nil)
if err != nil {
fmt.Printf("%#v", err)
}
deployment := obj.(*v1beta1.Deployment)
fmt.Printf("%#v\n", deployment)
}
Заметки
.../install
пакеты важны, так как они определяют, какие типы могут быть декодированы- он может декодировать JSON, YAML и, возможно, также все другие поддерживаемые типы файлов
- не уверен, где разница между
UniversalDecoder
а такжеUniversalDeserializer
является