Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get schema.GroupVersionResource for given k8s resource's json

  • client-go v0.19.2
  • golang 1.13

I'm building a tool to create k8s resources from json(just like kubectl create -f).

I found that dynamic client can do such things,but when i use it with code bellow,i found it is hard to find schema.GroupVersionResource for given resource's json.Am i missing something or the only way to get resource is through restmapper?

container := &unstructured.Unstructured{}
if err := container.UnmarshalJSON([]byte(jsonstring); err != nil {
    return err
}

_, err := k8sclient.Dynamic.Resource(?).Create(ctx, container, metav1.CreateOptions{})
if err != nil {
    return err
}

I know a work around is to write some code like bellow, but i'm sure it's not the best practice and there are too many of them besides crds.

var kindResourceMap = map[string]schema.GroupVersionResource{
    "Deployment": {
        Group:    "apps",
        Version:  "v1",
        Resource: "deployments",
    },
    "ConfigMap": {
        Group:    "apps",
        Version:  "v1",
        Resource: "configmaps",
    },
    "Job": {
        Group:    "batch",
        Version:  "v1",
        Resource: "jobs",
    },
    "Secret": {
        Group:    "api",
        Version:  "v1",
        Resource: "secrets",
    },
    "Service": {
        Group:    "api",
        Version:  "v1",
        Resource: "services",
    },
    "StatefulSet": {
        Group:    "apps",
        Version:  "v1",
        Resource: "statefulsets",
    },
    "PersistentVolume": {
        Group:    "api",
        Version:  "v1",
        Resource: "persistentvolumes",
    },
    "CustomResourceDefinition": {
        Group:    "apiextensions.k8s.io",
        Version:  "v1beta1",
        Resource: "customresourcedefinitions",
    },
}
like image 947
Jonyhy96 Avatar asked Dec 13 '25 12:12

Jonyhy96


1 Answers

You can use restmapper that directly queries the definitions from metav1 using the discovery client.

import (
    "k8s.io/client-go/rest"
    "k8s.io/client-go/discovery"
    "k8s.io/client-go/restmapper"
    "k8s.io/apimachinery/pkg/runtime/schema"
)

 ...

c := discovery.NewDiscoveryClientForConfigOrDie(&rest.Config{})

groupResources, err := restmapper.GetAPIGroupResources(c)
mapper := restmapper.NewDiscoveryRESTMapper(groupResources)

mapping, err := mapper.RESTMapping(schema.ParseGroupKind("apps.Deployment"))
fmt.Println(mapping.Resource)

This is cooked in sigs.k8s.io/controller-runtime/pkg/client

mapping, err := c.RESTMapper().RESTMapping(schema.ParseGroupKind("apps.Deployment"))
fmt.Println(mapping.Resource)

Look here for how it's done: https://github.com/kubernetes-sigs/controller-runtime/blob/561fa39c550f458eb6fb81bf70b9c02a190ec7bc/pkg/client/apiutil/restmapper.go#L36

Why doesn't client-go just know the apis?

The Group / Version infromation is hardcoded in kubernetes in each api package, and the Kind is derived from the actual struct names.
e.g. for apps api: https://github.com/kubernetes/kubernetes/blob/905e7510c84676fe5c6428f1038996e099a30f68/pkg/apis/apps/register.go#L36

client-go is, by design, only the generic api client implementation. It doesn't hardcode any specifics regarding any api. Except for some fundementals that provide basic structure like namespacing and such.

So there are 2 options:

  1. Static - Directly reference the api package and load the schema from there Or get the CRD yaml manifests and parse them.
  2. Dynamic - Query the live kubernetes api server for the definitions which is what the above restmapper does.

When developing a dynamic client, it must use the discovery api to identify pluggable apis.

Or you could mix both approaches. kubectl for that matter is in fact a hybrid, it references core apis statically, but supports any api dynamically.

like image 88
Tamir Daniely Avatar answered Dec 15 '25 18:12

Tamir Daniely