By leveraging the official Kubernetes client libraries for C#, we can easily interact with any Kubernetes cluster. We can also update (or patch) existing objects by invoking the corresponding Patch* methods (like PatchNamespacedPod, PatchNamespacedConfigMap, and many more) provided by the client library.

Although we can construct patches from different formats (JsonPatch, ApplyPatch, MergePatch, or StrategicMergePatch), we’ll focus on JsonPatch for the sake of this article, and we will update the following ConfigMap:

#configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
 name: sample
 namespace: default
data:
 firstName: Bob

You can quickly create the ConfigMap shown above using either kubectl create configmap sample -n default --from-literal firstName=Bob or by saving the yaml to a local file and use kubectl apply -f configmap.yml.

Patching a Config Map - The regular way

Let’s first take a look at how we can patch the ConfigMap by leveraging the default Kubernetes client libraries for C#:

using k8s;
using k8s.Models;

var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);

var configMap = "sample";
var @namespace = "default";

var jsonPatch = @"
[
 { 
  ""path"": ""/data/name"", 
  ""op"": ""replace"", 
  ""value"": ""John"" 
 } 
]";

var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);

As you can see, the patch instructions resist as simple string here. Obviously, storing the instructions about what to modify as a magical string is a smell and may have a negative impact on the overall maintainability of the code.

Patching a Config Map - Using Microsoft.AspNetCore.JsonPatch

Alternatively, we can use Microsoft.AspNetCore.JsonPatch (available on NuGet), to get rid of the magic string (jsonPatch). However, this requires some plumbing which blows up the entire sample:

using System.Text.Json;
using k8s;
using k8s.Models;
using Microsoft.AspNetCore.JsonPatch;
using Newtonsoft.Json.Serialization;

var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);

var configMap = "sample";
var @namespace = "default";

var doc = new JsonPatchDocument<V1ConfigMap>();
doc.ContractResolver = new DefaultContractResolver {
  NamingStrategy = new CamelCaseNamingStrategy()
};

doc.Replace(c => c.Data["name"], "John");

var jsonPatch = JsonSerializer.Serialize(
  doc.Operations.Select(o=> new {
    o.path,
    o.op,
    o.value
  })
);

var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);

By using Microsoft.AspNetCore.JsonPatch, we could remove the magic string 🙌🏼. However, creating a RFC compliant JSON Patch expression requires a bunch of plumbing. We’ve to configure the ContractResolver for our instance of JsonPatchDocument and we’ve to ensure that spec compliant JSON patch is being generated.

Patching a ConfigMap - The simple way

I’ve published a small NuGet package (ThorstenHans.JsonPatch.Contrib), which will take care of all the plumbing. You can add the NuGet package to the .NET project using dotnet add package ThorstenHans.JsonPatch.Contrib. Once the NuGet package is installed, we’ve access to JsonPatchDocumentBuilder.BuildFor<T> and we can use the ToJsonPatch() method on JsonPatchDocument<T>.

JsonPatchDocumentBuilder.BuildFor<T> constructs a new instance of JsonPatchDocument<T> and configures the ContractResolver correctly. We can use ToJsonPatch() to receive a valid Json patch expression as string.
Using those methods makes the entire sample easier to read and requires less code:

using k8s;
using k8s.Models;
using ThorstenHans.JsonPatch.Contrib;

var cfg = KubernetesClientConfiguration.BuildDefaultConfig();
var client = new Kubernetes(cfg);

var configMap = "sample";
var @namespace = "default";

var doc = JsonPatchDocumentBuilder.BuildFor<V1ConfigMap>();
doc.Replace(c => c.Data["name"], "John");

var jsonPatch = doc.ToJsonPatch();

var patch = new V1Patch(jsonPatch, V1Patch.PatchType.JsonPatch);
client.PatchNamespacedConfigMap(patch, configMap, @namespace);

Conclusion

Kubernetes client SDK for C# offers different ways for updating existing objects in a Kubernetes cluster. When relying on JsonPatch, the small NuGet package demonstrated here can simplify your codebase, and you could get rid of some plumbing.