<p>I have a YAML file defining multiple Kubernetes resources of various types (separated with <code>---</code> according to the YAML spec):</p>
<pre class="lang-yaml prettyprint-override"><code>apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # ...
spec:
  # ...
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  # ...
rules:
  # ...
---
# etc
</code></pre>
<p>Now, I want to parse this list into a slice of <code>client.Object</code> instances, so I can apply some filtering and transforms, and eventually send them to the cluster using</p>
<pre class="lang-golang prettyprint-override"><code>myClient.Patch( # myClient is a client.Client instance
  ctx,
  object,       # object needs to be a client.Object
  client.Apply,
  client.ForceOwnership,
  client.FieldOwner(&quot;my.operator.acme.inc&quot;),
)
</code></pre>
<p>However, I can't for the life of me figure out how to get from the YAML doc to <code>[]client.Object</code>. The following gets me <em>almost</em> there:</p>
<pre class="lang-golang prettyprint-override"><code>results := make([]client.Object, 0)

scheme := runtime.NewScheme()
clientgoscheme.AddToScheme(scheme)
apiextensionsv1beta1.AddToScheme(scheme)
apiextensionsv1.AddToScheme(scheme)

decode := serializer.NewCodecFactory(scheme).UniversalDeserializer().Decode
data, err := ioutil.ReadAll(reader)
if err != nil {
    return nil, err
}
for _, doc := range strings.Split(string(data), &quot;---&quot;) {
    object, gvk, err := decode([]byte(doc), nil, nil)
    if err != nil {
        return nil, err
    }

    // object is now a runtime.Object, and gvk is a schema.GroupVersionKind
    // taken together, they have all the information I need to expose a
    // client.Object (I think) but I have no idea how to actually construct a
    // type that implements that interface

    result = append(result, ?????)

}

return result, nil
</code></pre>
<p>I am totally open to other parser implementations, of course, but I haven't found anything that gets me any further. But this seems like it <em>must</em> be a solved problem in the Kubernetes world... so how do I do it?</p>

<p>I was finally able to make it work! Here's how:</p>
<pre class="lang-golang prettyprint-override"><code>import (
    &quot;k8s.io/client-go/kubernetes/scheme&quot;
    &quot;sigs.k8s.io/controller-runtime/pkg/client&quot;

    apiextensionsv1 &quot;k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1&quot;
    apiextensionsv1beta1 &quot;k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1&quot;
)

func deserialize(data []byte) (*client.Object, error) {
    apiextensionsv1.AddToScheme(scheme.Scheme)
    apiextensionsv1beta1.AddToScheme(scheme.Scheme)
    decoder := scheme.Codecs.UniversalDeserializer()

    runtimeObject, groupVersionKind, err := decoder.Decode(data, nil, nil)
    if err != nil {
        return nil, err
    }

    return runtime
}
</code></pre>
<p>A couple of things that seem key (but I'm not sure my understanding is 100% correct here):</p>
<ul>
<li>while the declared return type of <code>decoder.Decode</code> is <code>(runtime.Object, *scheme.GroupVersionKind, error)</code>, the returned first item of that tuple is actually a <code>client.Object</code> and can be cast as such without problems.</li>
<li>By using <code>scheme.Scheme</code> as the baseline before adding the <code>apiextensions.k8s.io</code> groups, I get all the &quot;standard&quot; resources registered for free.</li>
<li>If I use <code>scheme.Codecs.UniversalDecoder()</code>, I get errors about <code> no kind &quot;CustomResourceDefinition&quot; is registered for the internal version of group &quot;apiextensions.k8s.io&quot; in scheme &quot;pkg/runtime/scheme.go:100&quot;</code>, and the returned <code>groupVersionKind</code> instance shows <code>__internal</code> for version. No idea why this happens, or why it <em>doesn't</em> happen when I use the <code>UniversalDeserializer()</code> instead.</li>
</ul>
