Posts Unstructured Kubernetes Components with client-go's Dynamic Client
Post
Cancel

Unstructured Kubernetes Components with client-go's Dynamic Client

Recently I’ve written about how to access Kubernetes resources from Go, which works with structured objects. There may be times when you want to work with unstructured components though. Recently I needed to do this because I didn’t know at compile time the types of objects I would be working with.

Kubernetes provides a dynamic client from client-go to give you this functionality. You can import the dynamic package from k8s.io/client-go/dynamic.

Creating the dynamic client can be done like the following:

1
dynamicClient, err := dynamic.NewForConfig(kubeConfig)

We need to create a GroupVersionResource from k8s.io/apimachinery/pkg/runtime/schema:

1
2
3
4
5
gvr := schema.GroupVersionResource{
    Group:    "",
    Version:  "v1",
    Resource: "pods",
}

In my sample application I want to list out pods, so the group is the core group which is an empty string. The version is v1 and the resource is set to pods. Now we can list them out:

1
2
3
4
5
6
7
8
9
10
11
12
pods, err := dynamicClient.Resource(gvr).Namespace("kube-system").List(context.Background(), v1.ListOptions{})
if err != nil {
    fmt.Printf("error getting pods: %v\n", err)
    os.Exit(1)
}

for _, pod := range pods.Items {
    fmt.Printf(
        "Name: %s\n",
        pod.Object["metadata"].(map[string]interface{})["name"],
    )
}

The unstructured items have a type of map[string]interface{}, so as you crawl through the resources and their fields you have to use type assertion.

The full code for this example is below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package main

import (
        "context"
        "fmt"
        "os"
        "path/filepath"

        v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        "k8s.io/apimachinery/pkg/runtime/schema"
        "k8s.io/client-go/dynamic"
        "k8s.io/client-go/tools/clientcmd"
)

func main() {
        fmt.Println("Get pod names with the dynamic client")

        userHomeDir, err := os.UserHomeDir()
        if err != nil {
                fmt.Printf("error getting user home dir: %v\n", err)
                os.Exit(1)
        }
        kubeConfigPath := filepath.Join(userHomeDir, ".kube", "config")
        fmt.Printf("Using kubeconfig: %s\n", kubeConfigPath)

        kubeConfig, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath)
        if err != nil {
                fmt.Printf("error getting Kubernetes config: %v\n", err)
                os.Exit(1)
        }

        dynamicClient, err := dynamic.NewForConfig(kubeConfig)
        if err != nil {
                fmt.Printf("error creating dynamic client: %v\n", err)
                os.Exit(1)
        }

        gvr := schema.GroupVersionResource{
                Group:    "",
                Version:  "v1",
                Resource: "pods",
        }

        pods, err := dynamicClient.Resource(gvr).Namespace("kube-system").List(context.Background(), v1.ListOptions{})
        if err != nil {
                fmt.Printf("error getting pods: %v\n", err)
                os.Exit(1)
        }

        for _, pod := range pods.Items {
                fmt.Printf(
                        "Name: %s\n",
                        pod.Object["metadata"].(map[string]interface{})["name"],
                )
        }
}

And the output of running this against a cluster:

1
2
3
4
5
6
7
8
9
10
11
$ go run .
Get pod names with the dynamic client
Using kubeconfig: /home/trstringer/.kube/config
Name: coredns-558bd4d5db-fwrmj
Name: coredns-558bd4d5db-l2k52
Name: etcd-kind-control-plane
Name: kindnet-46gtb
Name: kube-apiserver-kind-control-plane
Name: kube-controller-manager-kind-control-plane
Name: kube-proxy-5t7c9
Name: kube-scheduler-kind-control-plane

Hopefully this blog post has shown how to use the dynamic client to work with unstructured Kubernetes resources!

This post is licensed under CC BY 4.0 by the author.