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",
},
}
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
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:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With