<p>I was following @ymmt2005 excellent <a href="https://ymmt2005.hatenablog.com/entry/2020/04/14/An_example_of_using_dynamic_client_of_k8s.io/client-go" rel="nofollow noreferrer">dynamic client guide</a>. All is good until the final step when I make the actual PATCH call, and I get a <code>the server could not find the requested resource</code> error. Just about everything seems right, except I'm unsure about the 'FieldManager' field in the PathOptions struct. I'm not sure what <em>&quot;the actor or entity that is making these changes&quot;</em> refers to. Does this need to match something in my code or system? Any other ideas?</p>
<pre><code>package main

import (
...
)

const resourceYAML = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mike-nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: 'nginx:latest'
          ports:
            - containerPort: 80
`

func main() {
    ctx := context.Background()

    // Create dynamic discovery client from local kubeconfig file
    kubePath := filepath.Join(homedir.HomeDir(), &quot;.kube&quot;, &quot;config&quot;)
    cfg, err := clientcmd.BuildConfigFromFlags(&quot;&quot;, kubePath)
    if err != nil {
        log.Fatalf(&quot;error building config, %v\n&quot;, err)
    }
    dynClient, err := dynamic.NewForConfig(cfg)
    if err != nil {
        log.Fatalf(&quot;error creating client, %v\n&quot;, err)
    }
    disClient, err := discovery.NewDiscoveryClientForConfig(cfg)
    if err != nil {
        log.Fatalf(&quot;error creating discovery client, %v\n&quot;, err)
    }

    // Decode YAML manifest &amp; get GVK
    decodeUnstr := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
    obj := &amp;unstructured.Unstructured{}
    _, gvk, err := decodeUnstr.Decode([]byte(resourceYAML), nil, obj)
    if err != nil {
        log.Fatalf(&quot;error decoding manifest, %v\n&quot;, err)
    }
    jsonObj, err := json.Marshal(obj)
    if err != nil {
        log.Fatalf(&quot;error marshaling object, %v\n&quot;, err)
    }

    // Find GVR using GVK
    mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(disClient))
    mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
    if err != nil {
        log.Fatalf(&quot;error finding GVR, %v\n&quot;, err)
    }

    // Get REST interface for the GVR, checking for namespace or cluster-wide
    var dr dynamic.ResourceInterface
    if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
        // Namespaced resource
        dr = dynClient.Resource(mapping.Resource).Namespace(obj.GetNamespace())
    } else {
        // Cluster-wide resource
        dr = dynClient.Resource(mapping.Resource)
    }

    // Create or Update the object with SSA
    options := metav1.PatchOptions{FieldManager: &quot;sample-controller&quot;}
    _, err = dr.Patch(ctx, obj.GetName(), types.ApplyPatchType, jsonObj, options)
    if err != nil {
        log.Fatalf(&quot;error patching, %v\n&quot;, err)
    }
}
</code></pre>
<p>[edit] I confirmed that I was only able to use 'Patch' on a resource that already existed. I tweaked the code to use 'Create' to create the resource, then I was able to successfully do a 'Patch' against it to change. To overcome the FieldManager inconsistencies I added Force=true to the PatchOptions which is recommended in the docs anyway. I'd still like to know how I can create if resource doesn't exist and update if it does--maybe just test for exist?</p>

<p>The answer is really trivial. The original code assumes that <code>namespace</code> is provided in the manifest. The deployment endpoint does not automatically set namespace to <code>default</code> if the provided namespace is &quot;&quot;, and errors out because &quot;&quot; is not a valid namespace. Therefore, I added logic to set namespace to <code>default</code> if not provided and presto, the server side apply will create the resource if it doesn't exist and update if it does exist. Thanks again @ymmt2005 .</p>
<pre><code>package main

import (
...
)

const resourceYAML = `
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mike-nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: 'nginx:latest'
          ports:
            - containerPort: 80
`

func main() {
    ctx := context.Background()

    // Create dynamic discovery client from local kubeconfig file
    kubePath := filepath.Join(homedir.HomeDir(), &quot;.kube&quot;, &quot;config&quot;)
    cfg, err := clientcmd.BuildConfigFromFlags(&quot;&quot;, kubePath)
    if err != nil {
        log.Fatalf(&quot;error building config, %v\n&quot;, err)
    }
    dynClient, err := dynamic.NewForConfig(cfg)
    if err != nil {
        log.Fatalf(&quot;error creating client, %v\n&quot;, err)
    }
    disClient, err := discovery.NewDiscoveryClientForConfig(cfg)
    if err != nil {
        log.Fatalf(&quot;error creating discovery client, %v\n&quot;, err)
    }

    // Decode YAML manifest &amp; get GVK
    decodeUnstr := yaml.NewDecodingSerializer(unstructured.UnstructuredJSONScheme)
    obj := &amp;unstructured.Unstructured{}
    _, gvk, err := decodeUnstr.Decode([]byte(resourceYAML), nil, obj)
    if err != nil {
        log.Fatalf(&quot;error decoding manifest, %v\n&quot;, err)
    }
    jsonObj, err := json.Marshal(obj)
    if err != nil {
        log.Fatalf(&quot;error marshaling object, %v\n&quot;, err)
    }

    // Find GVR using GVK
    mapper := restmapper.NewDeferredDiscoveryRESTMapper(memory.NewMemCacheClient(disClient))
    mapping, err := mapper.RESTMapping(gvk.GroupKind(), gvk.Version)
    if err != nil {
        log.Fatalf(&quot;error finding GVR, %v\n&quot;, err)
    }

    // Set Namespace to default if not provided in manifest
    var ns string
    if ns = obj.GetNamespace(); ns == &quot;&quot; {
        ns = &quot;default&quot;
    }

    // Get REST interface for the GVR, checking for namespace or cluster-wide
    var dr dynamic.ResourceInterface
    if mapping.Scope.Name() == meta.RESTScopeNameNamespace {
        // Namespaced resource
        dr = dynClient.Resource(mapping.Resource).Namespace(ns)
    } else {
        // Cluster-wide resource
        dr = dynClient.Resource(mapping.Resource)
    }

    // Create or Update the object with SSA
    options := metav1.PatchOptions{FieldManager: &quot;sample-controller&quot;}
    _, err = dr.Patch(ctx, obj.GetName(), types.ApplyPatchType, jsonObj, options)
    if err != nil {
        log.Fatalf(&quot;error patching, %v\n&quot;, err)
    }
}
</code></pre>
