英文:
Golang kubernetes client - patching an existing resource with a label
问题
我想要在 Kubernetes 中修补一个现有的秘密资源。该对象在 default
命名空间中被称为 centos-secretstorage
。我想要添加一个简单的标签 test: empty
。然而,当秘密对象 centos-secretstorage
存在但没有任何现有标签时,这个操作会失败。如果我事先使用 kubectl label centos-secretstorage hello=world
手动给秘密对象添加其他标签,然后重新运行我的 Golang 代码,它就能成功地添加 test: empty
标签。
然而,我希望无论现有标签是否存在,都能添加一个标签。
错误信息:the server rejected our request due to an error in our request
。
英文:
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
答案1
得分: 2
问题在于 JSON 补丁策略中的 add
操作要求路径指向一个已存在的映射,而你要修补的对象根本没有这个映射。这就是为什么只要存在 任何 标签,补丁就会成功。我们可以通过使用不同的补丁策略来解决这个问题。我认为 merge
策略应该能很好地工作。
我使用 kubectl
(在调试 Kubernetes API 时通常很有用)复现了这个问题(在一个命名空间上,但对象并不重要):
kubectl patch ns a --type='json' -p='[{"op": "merge", "path": "/metadata/labels/test", "value":"empty"}]'
-> 失败kubectl patch ns a --type='merge' -p='{"metadata": {"labels": {"test": "empty"}}}'
-> 成功
使用 Golang 的 client-go 库,代码大致如下(实际上没有编译/运行过):
payload := `{"metadata": {"labels": {"test": "empty"}}}`
emptyres, emptyerr := k8sClient.CoreV1().Secrets(p.namespace).Patch(p.name, types.MergePatchType, []byte(payload))
你可以使用结构体来更好地创建 payload
JSON,就像你使用 patchStringValue
一样。
有关补丁策略的更多信息可以在以下链接中找到:
- https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/
- https://erosb.github.io/post/json-patch-vs-merge-patch/
英文:
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"}]'
-> failskubectl 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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论