popopanda
popopanda

Reputation: 381

Golang kubernetes client - patching an existing resource with a label

I want to patch an existing secret resource within Kubernetes. The object is called centos-secretstorage within the default namespace. I want to add a simple label of test: empty. However, this fails when the secret object centos-secretstorage exists, but it doesn't have any existing labels. If I manually label the secret with something else beforehand via kubectl label centos-secretstorage hello=world, and rerun my golang code. It is able to add the test: empty label successfully.

However, I want to have this be able to add a label regardless if existing labels exist or not.

type secret struct {
    namespace string
    name      string
}

func main() {
    k8sClient := k8CientInit()

    vaultSecret := secret{
        namespace: "default",
        name:      "centos-secretstorage",
    }

    vaultSecret.patchSecret(k8sClient)
}

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

func (p *secret) patchSecret(k8sClient *kubernetes.Clientset) {

    emptyPayload := []patchStringValue{{
        Op:    "add",
        Path:  "/metadata/labels/test",
        Value: "empty",
    }}

    emptyPayloadBytes, _ := json.Marshal(emptyPayload)

    fmt.Println(string(emptyPayloadBytes))
    emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.JSONPatchType, emptyPayloadBytes)

    if emptyerr != nil {
        log.Fatal(emptyerr.Error())
    }

    fmt.Println(emptyres.Labels)

}

Error: the server rejected our request due to an error in our request

Upvotes: 2

Views: 4632

Answers (1)

saraf.gahl
saraf.gahl

Reputation: 1578

The problem is that the add operation in the JSON patch strategy requires the path to point to an existing map, while the object you are patching does not have this map at all. This is why when any label exists, the patch succeeds. We can work around this by using a different patch strategy. I think the merge strategy should work well.

I was able to reproduce this (on a namespace, but the object doesn't matter) using kubectl (which is generally useful when debugging the Kubernetes API):

  • kubectl patch ns a --type='json' -p='[{"op": "merge", "path": "/metadata/labels/test", "value":"empty"}]' -> fails
  • kubectl patch ns a --type='merge' -p='{"metadata": {"labels": {"test": "empty"}}}' -> succeeds

Using Golang client-go it would look something like this (didn't actually compile / run this):

    payload := `{"metadata": {"labels": {"test": "empty"}}}`
    emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.MergePatchType, []byte(payload))

You can make the creation of the payload JSON nicer using structs, as you did with patchStringValue.

More info on patch strategies can be found here:

Upvotes: 2

Related Questions