How to Submit generic "runtime.Object" to Kubernetes API using client-go

11/16/2018

I'm using AWS' EKS which is Kubernetes v1.10 and I'm using client-go v7.0.0.

What I'm trying to do is parse a .yml file with multiple Kubernetes resource definitions in a file and submit those resources to the Kubernetes API. I can successfully parse the files using this code scheme.Codecs.UniversalDeserializer().Decode, and I get back an array of runtime.Object.

I know that all the Kubernetes resources conform to the runtime.Object interface, but I can't find a way to submit the generic interface to the API. Most methods I've seen use the methods on the concrete types like Deployment, Pod, etc.

I've seen some code around a generic RESTClient like this clientset.RESTClient().Put().Body(obj).Do(), but that doesn't work and I can't figure it out.

I know my clientset is configured correctly because I can successfully list all Pods.

-- aloisbarreras
client-go
kubernetes
kubernetes-apiserver

2 Answers

11/18/2018

If you have a "generic" runtime.Object, you can use the dynamic client in client-go for this. The dynamic client deals with unstructured.Unstructured objects and all runtime.Objects can be converted to it. Here is an example:

// create the dynamic client from kubeconfig
dynamicClient, err := dynamic.NewForConfig(kubeconfig)
if err != nil {
    return err
}

// convert the runtime.Object to unstructured.Unstructured
unstructuredObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
if err != nil {
    return err
}

// create the object using the dynamic client
nodeResource := schema.GroupVersionResource{Version: "v1", Resource: "Node"}
createdUnstructuredObj, err := dynamicClient.Resource(nodeResource).Namespace(ns).Create(unstructuredObj)
if err != nil {
    return err
}

// convert unstructured.Unstructured to a Node
var node *corev1.Node
if err = runtime.DefaultUnstructuredConverter.FromUnstructured(createdUnstructuredObj, node); err != nil {
    return err
}
-- Nikhita Raghunath
Source: StackOverflow

3/21/2019

It's correct that you need the dynamic client for that but to keep things generic working with runtime.Object you need to use the DiscoveryRESTMapper which needs to use the typed client for discovery of available api versions:

dynClient, err := dynamic.NewForConfig(config)
...
clientset, err := kubernetes.NewForConfig(config)
...
gvk := obj.GroupVersionKind()
gk := schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}
groupResources, err := restmapper.GetAPIGroupResources(clientset.Discovery())
...
rm := restmapper.NewDiscoveryRESTMapper(groupResources)
mapping, err := rm.RESTMapping(gk, gvk.Version)
...
dynClient.Resource(mapping.Resource).Namespace("default").Create(obj, metav1.CreateOptions{})
-- Johannes 'fish' Ziemke
Source: StackOverflow