client-go:将kubernetes json文件解析为k8s结构

时间:2017-11-04 23:48:00

标签: api go client kubernetes kubernetes-go-client

我想解析kubernetes清单文件(json / yaml)并能够将它们转换为k8s结构(以后再操作它们)

我知道有NewYAMLOrJSONDecoder()。Decode()函数(https://github.com/kubernetes/apimachinery/blob/master/pkg/util/yaml/decoder.go)来读取json / yaml文件,但下一步是:如何将它们转换为k8s结构/类型?

即。如果我使用Namespace对象读取yaml文件,如何将其转换为core / v1 / namespace接口,例如

此致

3 个答案:

答案 0 :(得分:2)

谢谢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
}

答案 1 :(得分:1)

这个问题与How to deserialize Kubernetes YAML file非常相似,但这个问题有点过时,因为包名更改了。

此外,它不直接使用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以及所有其他支持的文件类型
  • 不确定UniversalDecoderUniversalDeserializer之间的差异在哪里

答案 2 :(得分:1)

   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
    }

根据需要将为CRD生成的SchemeGroupVersion传递给UniversalDecoder呼叫。

使用runtime.Decode而不是runtime.DecodeInto来解码未指定的对象类型。