15

Internal error occurred: jsonpatch add operation does not apply: doc is missing...

 3 years ago
source link: https://zhangguanzhang.github.io/2021/03/22/jsonpatch-doc-is-missing-path/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Internal error occurred: jsonpatch add operation does not apply: doc is missi...



k8s
字数统计: 751阅读时长: 3 min
 2021/03/22  18  Share

今天在折腾 admission webhook 注入一些属性的时候遇到了 Error from server (InternalError): error when creating "xxx.yml": Internal error occurred: jsonpatch add operation does not apply: doc is missing path: "/spec/template/spec/dnsConfig/options"。折腾半天才发现在代码里使用 jsonPatch 的话不能直接绕过结构体实例去 patch。

WebHook 接收和响应都是一个 AdmissionReview 对象,请求是里面的 AdmissionRequest,响应是里面的 AdmissionResponse。
比如说我们创建了个 MutatingWebhookConfiguration 指定让 apps/v1deploy 传到我们的 webhook, 我们要修改 deploy 的一些属性,我个人是增加 dns 的 single-request-reopen的属性的,得在 AdmissionResponse 里传一个 jsonPatch的切片。
代码里这块是:

type patchOperation struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value,omitempty"`
}
...
patch := []patchOperation{
{
Op: "add",
Path: "/spec/template/spec/dnsConfig/options",
Value: []map[string]string{
{"name": "single-request-reopen"},
},
},

后面发现创建 deploy 就报开头的错误。然后日志里打印了下:

apiVersion:apps/v1 resource: default/nginx-deployment, AdmissionResponse: patch=[{"op":"replace","path":"/spec/template/spec/dnsConfig/options","value":[{"name":"single-request-reopen"}]}]

然后把这个 patch 在 kubectl 上测试了下是可以的:

$ kubectl -n kube-system patch deployments tiller-deploy --type=json -p='[{"op":"add","path":"/spec/template/spec/dnsConfig/options","value":[{"name":"single-request-reopen"}]}]'

deployment.extensions/tiller-deploy patched

刚开始把 kube-apiserver 开 -v=8 发现 panic的信息,然后升了下版本还是没用。然后在源码里找了下这个报错:

$ find -type f -name '*.go' -exec grep -l 'replace operation does not apply: doc is missing path' {} \;
./vendor/github.com/evanphx/json-patch/patch.go

发现这个错误是引入的库抛出来的,和 k8s 无关,想了下后换个 key 试试看。

			{
Op: "add",
Path: "/spec/template/spec/securityContext/runAsNonRoot",
Value: true,
},
...
for i := range deployment.Spec.Template.Spec.Containers {
patch = append(patch, patchOperation{
Op: "add",
Path: fmt.Sprintf("/spec/template/spec/containers/%d/lifecycle/postStart/exec/command", i),
Value: []string{
"/bin/sh",
"-c",
"/bin/echo 'options single-request-reopen' >> /etc/resolv.conf",
},
},
})
}

发现后面 command 这个也不行,explain 看了下,试试上层的看看:

for i := range deployment.Spec.Template.Spec.Containers {
patch = append(patch, patchOperation{
Op: "add",
Path: fmt.Sprintf("/spec/template/spec/containers/%d/lifecycle", i),
Value: corev1.Lifecycle{
PostStart: &corev1.Handler{
Exec: &corev1.ExecAction{
Command: []string{
"/bin/sh",
"-c",
"/bin/echo 'options single-request-reopen' >> /etc/resolv.conf",
},
},
},
},
})
}

发现可以,应该是得给一个嵌套的结构体实例,而不是直接绕过这个结构体,去 patch 里面属性的 value,换下前面的 dnsConfig 试试:

{
Op: "add",
Path: "/spec/template/spec/dnsConfig",
Value: corev1.PodDNSConfig{
Options: []corev1.PodDNSConfigOption{
{
Name: "single-request-reopen",
Value: nil,
},
},
},
},

发现也可以了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK