Skip to content

Instantly share code, notes, and snippets.

@dwmkerr
Last active September 19, 2023 11:42
Show Gist options
  • Save dwmkerr/447692c8bba28929ef914239781c4e59 to your computer and use it in GitHub Desktop.
Save dwmkerr/447692c8bba28929ef914239781c4e59 to your computer and use it in GitHub Desktop.
Example showing how to patch Kubernetes resources in Golang. Companion to the article 'https://dwmkerr.com/patching-kubernetes-resources-in-golang/'.
// Example showing how to patch kubernetes resources.
// This is the companion to my article 'Patching Kubernetes Resources in Golang':
// https://dwmkerr.com/patching-kubernetes-resources-in-golang/
package main
import (
"encoding/json"
"fmt"
types "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/kubernetes"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/client-go/tools/clientcmd"
)
var (
// Leave blank for the default context in your kube config.
context = ""
// Name of the replication controller to scale, and the desired number of replicas.
replicationControllerName = "my-rc"
replicas = uint32(3)
)
// patchStringValue specifies a patch operation for a string.
type patchStringValue struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
// patchUint32Value specifies a patch operation for a uint32.
type patchUInt32Value struct {
Op string `json:"op"`
Path string `json:"path"`
Value uint32 `json:"value"`
}
func scaleReplicationController(clientSet *kubernetes.Clientset, replicasetName string, scale uint32) error {
payload := []patchUInt32Value{{
Op: "replace",
Path: "/spec/replicas",
Value: scale,
}}
payloadBytes, _ := json.Marshal(payload)
_, err := clientSet.
CoreV1().
ReplicationControllers("default").
Patch(replicasetName, types.JSONPatchType, payloadBytes)
return err
}
func main() {
// Get the local kube config.
fmt.Printf("Connecting to Kubernetes Context %v\n", context)
config, err := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
clientcmd.NewDefaultClientConfigLoadingRules(),
&clientcmd.ConfigOverrides{CurrentContext: context}).ClientConfig()
if err != nil {
panic(err.Error())
}
// Creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
// Scale our replication controller.
fmt.Printf("Scaling replication controller %v to %v\n", replicationControllerName, replicas)
err = scaleReplicationController(clientset, replicationControllerName, replicas)
if err != nil {
panic(err.Error())
}
}
@Adirio
Copy link

Adirio commented Feb 10, 2020

Line 32 has a typo, it should be // patchUint32Value ...

@dwmkerr
Copy link
Author

dwmkerr commented Feb 11, 2020

Well spotted! Thanks @Adirio, I've just fixed it now :)

@zulhfreelancer
Copy link

Why do we need that patchStringValue? I'm curious.

@dwmkerr
Copy link
Author

dwmkerr commented Jan 26, 2021

@zuthfreelancer - you don't for this sample, it's there in case you want to patch something else which is a string, sorry it's a bit odd!

@zulhfreelancer
Copy link

Thank you

@dyipon
Copy link

dyipon commented Sep 21, 2021

How can I escape the "statefulset.kubernetes.io/pod-name" if I use patchStringValue() func? API does not accept it. Thanks

@michaelmdresser
Copy link

If anyone is trying to patch something that is an array, like tolerations, I made a slight modification (thank you dwmkerr for the original code!):

	type tolerationValue struct {
		Key      string `json:"key"`
		Operator string `json:"operator"`
		Value    string `json:"value"`
		Effect   string `json:"effect"`
	}

	type structArrayPayload struct {
		Op    string            `json:"op"`
		Path  string            `json:"path"`
                // tolerations are an array
		Value []tolerationValue `json:"value"`
	}

	patchPayload := []structArrayPayload{
		{
			Op:   "replace",
			Path: "/spec/template/spec/tolerations",
			Value: []tolerationValue{
				{
					Key:      "toleration.key.here",
					Operator: "Equal",
					Value:    "true",
					Effect:   "NoSchedule",
				},
			},
		},
	}

@grosser
Copy link

grosser commented Jan 12, 2023

this seems to also work and avoids having to define lots of structs:

type patch struct {
	Op    string `json:"op"`
	Path  string `json:"path"`
	Value interface{} `json:"value"`
}

@mjtrangoni
Copy link

How can I escape the "statefulset.kubernetes.io/pod-name" if I use patchStringValue() func? API does not accept it. Thanks

Did you find any solutions for this?

@dyipon
Copy link

dyipon commented Sep 19, 2023

How can I escape the "statefulset.kubernetes.io/pod-name" if I use patchStringValue() func? API does not accept it. Thanks

Did you find any solutions for this?

I'm sorry, I can't remember how I solved it.

@mjtrangoni
Copy link

How can I escape the "statefulset.kubernetes.io/pod-name" if I use patchStringValue() func? API does not accept it. Thanks

For the records, the solution here is, assuming we are changing a pod label,

podLabel := `statefulset.kubernetes.io~1pod-name`

Resulting in path being,

path := fmt.Sprintf("/metadata/labels/%s", podLabel)

My 2 cents.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment