kubernetes / kubernetes

Production-Grade Container Scheduling and Management

Home Page:https://kubernetes.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

kubectl apply does not update ThirdPartyResource object.

ianlewis opened this issue · comments

I have a ThirdPartyResource object. The resource is as follows:

resource.yaml

metadata:
  name: cron-tab.stable.example.com
apiVersion: extensions/v1beta1
kind: ThirdPartyResource
description: "A specification of a Pod to run on a cron style schedule"
versions:
  - name: v1
  - name: v2

crontab.yaml

apiVersion: "stable.example.com/v1"
kind: "CronTab"
metadata:
  name: hello-world
cronSpec: "*/1 * * * *"
image: hello-world

I create the resource and object

$ kubectl create -f resource.yaml
$ kubectl create -f crontab.yaml

However, when I run apply I fails to update the properties.

$ cat crontab.yaml 
apiVersion: "stable.example.com/v1"
kind: "CronTab"
metadata:
  name: hello-world
cronSpec: "*/5 * * * *"
image: hello-world

$ kubectl apply -f crontab.yaml
crontab "hello-world" configured

kubectl is sending a request to the API and if I watch the object I get a modified event but it is still the old value. Getting the object also returns the old value.

$ kubectl get crontab hello-world -o json | jq '.cronSpec'
"*/1 * * * *"

I suspect that kubectl is not diffing the object properly and neglects to send the updated object JSON data.

@ianlewis what's your kubernetes version? kubectl version can give you this info.

Here ya go. Didn't realize the client wasn't 1.3.3 yet.

Client was pulled from https://storage.googleapis.com/kubernetes-release/release/v1.3.0/bin/darwin/amd64/kubectl

Client Version: version.Info{Major:"1", Minor:"3", GitVersion:"v1.3.0", GitCommit:"283137936a498aed572ee22af6774b6fb6e9fd94", GitTreeState:"clean", BuildDate:"2016-07-01T19:26:38Z", GoVersion:"go1.6.2", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"3", GitVersion:"v1.3.2", GitCommit:"9bafa3400a77c14ee50782bb05f9efc5c91b3185", GitTreeState:"clean", BuildDate:"2016-07-17T18:23:58Z", GoVersion:"go1.6.2", Compiler:"gc", Platform:"linux/amd64"}

We just met the exact same issue. It does not work for current master either.

@pwittrock Should this be considered as a bug? Why this is a p2 issue?

@xiang90 Sounds like a bug. Re: the priority, it was a rough estimate. If you think things need a higher priority and attention, ping the thread and I will give it more attention. If you need this fixed immediately let me know and I will shuffle things around.

@pwittrock Thank you!

We can workaround this by using cURL. But it is not ideal. :)

I plan to have this fixed in 1.5. Do you think that is sufficient?

sure. thanks.

@adohe Do you have time to look into this?

ok, will fix this asap.

@adohe Any updates?

@ianlewis actually in the final patch, we have include the configuration change, something like below:

map[string]interface {}{"metadata":map[string]interface {}{"creationTimestamp":interface {}(nil), "annotations":map[string]interface {}{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"extensions/v1beta1\",\"metadata\":{\"name\":\"hello-world\",\"namespace\":\"default\",\"creationTimestamp\":null},\"data\":\"eyJhcGlWZXJzaW9uIjoic3RhYmxlLmV4YW1wbGUuY29tL3YxIiwiY3JvblNwZWMiOiIqLzUgKiAqICogKiIsImltYWdlIjoiaGVsbG8td29ybGQiLCJraW5kIjoiQ3JvblRhYiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJoZWxsby13b3JsZCJ9fQ==\"}"}}, "data":"eyJhcGlWZXJzaW9uIjoic3RhYmxlLmV4YW1wbGUuY29tL3YxIiwiY3JvblNwZWMiOiIqLzUgKiAqICogKiIsImltYWdlIjoiaGVsbG8td29ybGQiLCJraW5kIjoiQ3JvblRhYiIsIm1ldGFkYXRhIjp7Im5hbWUiOiJoZWxsby13b3JsZCJ9fQ=="}

the reason why the cronSpec keeps the same is that in the server side when we apply this patch, we use strategic merge, this will just update the original configuration if the merge key exists in both maps, so it will still use the cronSpec in original document.

@brendandburns could you please explain the data field in third party resource data? how we generate it and how to use it? I am taking a deep look at third party resource now.

@adohe The data field is basically arbitrary JSON that the user can specify per object.

@adohe the data field is the arbitrary JSON representation of the third party object.

We need to store the object as a runtime.Object inside the internals of the system, but of course the third party object doesn't exist as a golang object, so we use ThirdPartyResourceData and store the contents of the third party object in the data field.

@brendandburns that's the problem, when we apply a patch, we just update the data field of ThirdPartyResourceData

@adohe are you working on this? If not I'll take it back over...

@brendandburns yes, I am working on it.

@adohe @brendandburns

when we apply a patch, we just update the data field of

This does not match users expectation I think. Kubectl apply should only apply changes without changing the unspecified fields, right? We probably can not just replace/update the data field with user given data.

There are a couple libraries in go to deal with the JSON-patch spec, here's one that can produce merge patches based on two arbitrary JSONs and also apply those patches: https://github.com/evanphx/json-patch

@ConnorDoyle thanks for reference this, actually in kubernetes, we not only support standard JSON merge patch, but also support strategic merge patch, which is a custom implementation of merge patch. I have fixed this on my local, and will open a PR this weekend after I test it.

@adohe Any updates on this one? or has this been punted to 1.6?

@foxish yes, I think we can put this on 1.6, we are going to remove ThirdPartyResourceData

@foxish @adohe

This is going to affect anyone using TPR (we develop etcd operator for example) pretty hard. This is a bug, and I feel we should fix this in 1.5.

/cc @brendandburns

@xiang90 I agree, but I don't think we have enough bandwidth to fix this properly in 1.5.
We have a similar use case, and we're going to use PATCH, which is a little more convenient than the "PUT" that the etcd-operator example uses in documentation.

@foxish I did kubectl patch but it complains like this:

the provided version "example.com/v1alpha1" has no relevant versions: group example.com has not been registered

Could you tell us how to make this work?

I use kubectl v1.5.0-beta.2

@xiang90 what's the workaround with cURL?

Note that this issue is breaking Helm for TPRs; see helm/helm#1468.

@adohe Are there any updates on the status of this issue? Would it help to have @ymqytw look into it as well?

Isn't the core issue apply requiring a go struct to use as a schema?

@liggitt Yeah, the struct is used for the tags determining how to merge list fields. Is it used for anything else? WDYT of simply choosing defaults for the values we would get from the structs for TPRs? e.g. always assume replace strategy for lists in TPRs.

WDYT of simply choosing defaults for the values we would get from the structs for TPRs? e.g. always assume replace strategy for lists in TPRs.

I wouldn't want to assume unknown types are TPRs, but having a default apply mode for types where we can't use the normal go struct logic (which could be TPRs or types from add-on API servers) makes sense to me. The same approach could work for fields of type Interface or runtime.RawExtension that currently don't support apply either

runtime.RawExtension that currently don't support apply either

c.f. #14998