Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Force using versioned objects in apply's patch #35688

Closed
wants to merge 1 commit into from

Conversation

soltysh
Copy link
Contributor

@soltysh soltysh commented Oct 27, 2016

Fixes #35149 and #34413.

Until now kubectl apply was working with internal version and manually invoking encoding, which resulted in problems converting object to versioned counterpart. It worked until now mostly because each group had only single version, but with multiple versions usually the first/preferred is chosen, which in case of ScheduledJobs isn't true. (ScheduledJobs exists in batch/v2alpha1, but preferred version is batch/v1). Resource helper has all the necessary information to perform necessary conversion so I've added conversion before actually calling the patch method and passing it as versioned to that method.

@janetkuo or anyone from @kubernetes/kubectl ptal


This change is Reviewable

@soltysh soltysh added area/kubectl release-note-none Denotes a PR that doesn't merit a release note. labels Oct 27, 2016
@soltysh
Copy link
Contributor Author

soltysh commented Oct 27, 2016

/fyi @zreigz @bes @vreon

@k8s-github-robot k8s-github-robot added the size/S Denotes a PR that changes 10-29 lines, ignoring generated files. label Oct 27, 2016
@zreigz
Copy link
Contributor

zreigz commented Oct 27, 2016

Great! It works.

@smarterclayton
Copy link
Contributor

Ha! Fixes #25106 (i was right)

@@ -220,7 +230,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
helper := resource.NewHelper(info.Client, info.Mapping)
patcher := NewPatcher(encoder, decoder, info.Mapping, helper, overwrite)

patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
infos := []*resource.Info{info}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually... you should have info.VersionedObject set here. Can you verify that you do (it should be the external version)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... I'll check, but from what I see kubectl edit is using the same approach.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually that's where I copied it from 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info.VersionedObject to my surprise is of type interface {} and might be nil as well, so I'd have to cast it to runtime.Object and if that fails fall back to resource.AsVersionedObject. Or stay with current solution? Which one you prefer?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Apply has VersionedObject as nil, other things will fail. VersionedObject was added in order to solve the Apply use case, so it's expected to work in general.

@brendandburns brendandburns added lgtm "Looks good to me", indicates that a PR is ready to be merged. and removed lgtm "Looks good to me", indicates that a PR is ready to be merged. labels Oct 28, 2016
@brendandburns
Copy link
Contributor

This LGTM, but I defer to @smarterclayton for the final call.

@soltysh
Copy link
Contributor Author

soltysh commented Oct 28, 2016

Grrrr.... after using info.VersionedObject the test fail badly :/ looking into it...

@soltysh
Copy link
Contributor Author

soltysh commented Nov 1, 2016

.VersionedObject doesn't work with lists, it looks like the code does not support that case, yet. @smarterclayton are you ok with a temporary fix I've provided initially (iow. encoding in place) for now with a TODO to fix the list case? I'm not sure I have enough time to debug this now and people are sort of blocked by this. If I find time I'll fix it this or next week.

@smarterclayton
Copy link
Contributor

Please open a follow up issue for it. If versioned object doesn't work, we
shouldn't be supporting it elsewhere (it's a massive time sink).

On Nov 1, 2016, at 4:08 AM, Maciej Szulik notifications@github.com wrote:

.VersionedObject doesn't work with lists, it looks like the code does not
support that case, yet. @smarterclayton https://github.com/smarterclayton
are you ok with a temporary fix I've provided initially (iow. encoding in
place) for now with a TODO to fix the list case? I'm not sure I have enough
time to debug this now and people are sort of blocked by this. If I find
time I'll fix it this or next week.


You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
#35688 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABG_p882C_Hs-uqaMIbGOz7MZDpzGlQSks5q5vNLgaJpZM4KiPSZ
.

@soltysh
Copy link
Contributor Author

soltysh commented Nov 1, 2016

it's a massive time sink

Tell me about it 😉

I've created #35999 and assigned it to myself. Can we merge this as is in that case?

@@ -220,7 +230,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
helper := resource.NewHelper(info.Client, info.Mapping)
patcher := NewPatcher(encoder, decoder, info.Mapping, helper, overwrite)

patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
infos := []*resource.Info{info}
originalObj, err := resource.AsVersionedObject(infos, false, defaultVersion, encoder)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail if you try to apply two objects in different API versions, it looks like. Is there a test that proves it doesn't?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll verify that and add a proper test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, the reason this doesn't have VersionedObject is because you are calling Get() up above. Why are you calling Get() up above?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defending I didn't write that part won't probably help 😜 . I'll test proposed approaches.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dropped Get, but that still suffers from list not having VersionedObject set :/ I think I'll leave that for later in that case. Hopefully when we enter codefreeze I'll find some time to dig into this.

@soltysh soltysh added the do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. label Nov 3, 2016
@smarterclayton
Copy link
Contributor

This is a bug so it can be worked post feature freeze.

@k8s-github-robot k8s-github-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. and removed size/S Denotes a PR that changes 10-29 lines, ignoring generated files. labels Nov 3, 2016
@smarterclayton smarterclayton added the priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. label Nov 3, 2016
@k8s-ci-robot
Copy link
Contributor

Jenkins unit/integration failed for commit 9cafc7e. Full PR test history.

The magic incantation to run this job again is @k8s-bot unit test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-ci-robot
Copy link
Contributor

Jenkins GCE etcd3 e2e failed for commit 9cafc7e. Full PR test history.

The magic incantation to run this job again is @k8s-bot gce etcd3 e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-ci-robot
Copy link
Contributor

Jenkins GCI GCE e2e failed for commit 9cafc7e. Full PR test history.

The magic incantation to run this job again is @k8s-bot gci gce e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@k8s-ci-robot
Copy link
Contributor

Jenkins GCE e2e failed for commit 9cafc7e. Full PR test history.

The magic incantation to run this job again is @k8s-bot cvm gce e2e test this. Please help us cut down flakes by linking to an open flake issue when you hit one in your PR.

@jlutzhbo
Copy link

jlutzhbo commented Nov 9, 2016

Do we have an ETA for this? Also, what version will this be fixed in? Thanks!

@soltysh
Copy link
Contributor Author

soltysh commented Nov 9, 2016

No strict ETA, rather wishful thinking of mine to have it in for 1.5

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 11, 2016
@adohe-zz
Copy link

@soltysh please rebase this, I think this has blocked users using HPA.

@k8s-github-robot k8s-github-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 19, 2016
@soltysh
Copy link
Contributor Author

soltysh commented Nov 19, 2016

@adohe rebase is one thing, most importantly this needs final solution :/

@adohe-zz
Copy link

@soltysh Ok, I will take a look.

if !dryRun {
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
helper := resource.NewHelper(info.Client, info.Mapping)
patcher := NewPatcher(encoder, decoder, info.Mapping, helper, overwrite)

patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is right... VersionedObject is what the client provided, Object came from the server

Copy link
Member

@liggitt liggitt Dec 8, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

against master, I'm seeing an error inside patchSimple, where this line is returning an internal object:

versionedObject, _, err := p.decoder.Decode(current, nil, nil)

using the info from the mapping instead let the apply unit tests pass for me:

versionedObject, err := api.Scheme.New(p.mapping.GroupVersionKind)

edit: I take it back... that may only work for types registered into the scheme

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liggitt thx for the feedback, it's on my list for this week, hopefully.

@@ -182,45 +182,17 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *App
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%v\nfor:", info), info.Source, err)
}

if err := info.Get(); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not remove all of this. Otherwise, we can't use kubectl apply to create non-existing resource.

if !dryRun {
overwrite := cmdutil.GetFlagBool(cmd, "overwrite")
helper := resource.NewHelper(info.Client, info.Mapping)
patcher := NewPatcher(encoder, decoder, info.Mapping, helper, overwrite)

patchBytes, err := patcher.patch(info.Object, modified, info.Source, info.Namespace, info.Name)
originalObj, ok := info.VersionedObject.(runtime.Object)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info.VersionedObject is no longer a interface. Don't need to cast.

@k8s-github-robot
Copy link

@soltysh PR needs rebase

@k8s-github-robot k8s-github-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 3, 2017
@liggitt
Copy link
Member

liggitt commented Jan 3, 2017

I'm not sure this is needed anymore. Can you double check with the tests you added and see if this is already fixed in master?

@soltysh
Copy link
Contributor Author

soltysh commented Jan 4, 2017

The problem still persists. I just checked on lastest master and I'm getting following error:

$ kubectl apply -f cronjob.yaml 
Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply
error: error when applying patch:

to:
&{0xc42061afc0 0xc420139500 default pi cronjob.yaml &CronJob{ObjectMeta:k8s_io_kubernetes_pkg_api_v1.ObjectMeta{Name:pi,GenerateName:,Namespace:,SelfLink:,UID:,ResourceVersion:,Generation:0,CreationTimestamp:0001-01-01 00:00:00 +0000 UTC,DeletionTimestamp:<nil>,DeletionGracePeriodSeconds:nil,Labels:map[string]string{},Annotations:map[string]string{kubectl.kubernetes.io/last-applied-configuration: ,},OwnerReferences:[],Finalizers:[],ClusterName:,},Spec:CronJobSpec{Schedule:*/25 * * * ?,StartingDeadlineSeconds:nil,ConcurrencyPolicy:,Suspend:nil,JobTemplate:JobTemplateSpec{ObjectMeta:k8s_io_kubernetes_pkg_api_v1.ObjectMeta{Name:,GenerateName:,Namespace:,SelfLink:,UID:,ResourceVersion:,Generation:0,CreationTimestamp:0001-01-01 00:00:00 +0000 UTC,DeletionTimestamp:<nil>,DeletionGracePeriodSeconds:nil,Labels:map[string]string{},Annotations:map[string]string{},OwnerReferences:[],Finalizers:[],ClusterName:,},Spec:JobSpec{Parallelism:nil,Completions:nil,ActiveDeadlineSeconds:nil,Selector:nil,ManualSelector:nil,Template:k8s_io_kubernetes_pkg_api_v1.PodTemplateSpec{ObjectMeta:ObjectMeta{Name:pi,GenerateName:,Namespace:,SelfLink:,UID:,ResourceVersion:,Generation:0,CreationTimestamp:0001-01-01 00:00:00 +0000 UTC,DeletionTimestamp:<nil>,DeletionGracePeriodSeconds:nil,Labels:map[string]string{},Annotations:map[string]string{},OwnerReferences:[],Finalizers:[],ClusterName:,},Spec:PodSpec{Volumes:[],Containers:[{pi perl [perl -Mbignum=bpi -wle print bpi(2000)] []  [] [] [] {map[] map[]} [] nil nil nil   nil false false false}],RestartPolicy:Never,TerminationGracePeriodSeconds:nil,ActiveDeadlineSeconds:nil,DNSPolicy:,NodeSelector:map[string]string{},ServiceAccountName:,DeprecatedServiceAccount:,NodeName:,HostNetwork:false,HostPID:false,HostIPC:false,SecurityContext:nil,ImagePullSecrets:[],Hostname:,Subdomain:,Affinity:nil,},},},},},Status:CronJobStatus{Active:[],LastScheduleTime:<nil>,},} &TypeMeta{Kind:,APIVersion:,} 211 false}
for: "cronjob.yaml": error when serializing current configuration from:
&TypeMeta{Kind:,APIVersion:,}
for: "cronjob.yaml": no kind "CronJob" is registered for version "batch/v1"

I'll try to fix it this week.

@soltysh
Copy link
Contributor Author

soltysh commented Jan 9, 2017

Here's the current state. I can't use info.VersionedObject since it's user-provided versioned object, so my initial approach was wrong and I have to stick with info.Object in that case.
I started digging more into this and it's failing apply.patchSimple, which is going all the way down to scheme.convertToVersion, which fails getting batch/v2alpha1.CronJob when an input is __internal.CronJob. KindForGroupVersionKinds is getting both possible batch versions in the for loop, and since there's no direct match against actual Kind, it picks the first one, which in this case is wrong.

@deads2k @liggitt @caesarxuchao @kubernetes/sig-api-machinery-misc any ideas how this could be fixed? I'm thinking about two possible approaches:

  1. extend GroupVersions with actual Kinds` in here, but that's quite tedious, imho.
  2. create additional runtime.Encode method which would accept GVK, because here info.Mapping is holding the right GVK I'd expect.

Are there other options I'm missing here?

@soltysh
Copy link
Contributor Author

soltysh commented Jan 9, 2017

I can't use info.VersionedObject since it's user-provided versioned object,

Btw, am I the only one who finds this confusing. I've always thought info.VersionedObject is the same as info.Object but just versioned. Shouldn't that have a different name based on its description?

@huggsboson
Copy link
Contributor

huggsboson commented Jan 13, 2017

At Box we're hitting an issue like this trying to apply (update an already created one, first time apply works just fine) instances of a thirdpartyresource after upgrading to 1.4.8. I can't tell if this or #38982 will fix this problem for instances of a ThirdPartyResource.

Our error message looks like:

&{0xc820016d80 0xc82013bea0 user-dev pki-95c36eb44c4a9132082142f7d5e47bf0 /box/deployment-config/release/dsv31/dev/user/app.json &TypeMeta{Kind:,APIVersion:extensions/v1beta1,} &TypeMeta{Kind:,APIVersion:extensions/v1beta1,} 178335915 false}
for: "/box/deployment-config/release/dsv31/dev/user/app.json": error when getting instance of versioned object for box-pki.com/v1, Kind=Pki: "/box/deployment-config/release/dsv31/dev/user/app.json": no kind "Pki" is registered for version "box-pki.com/v1"

@mengqiy
Copy link
Member

mengqiy commented Jan 13, 2017

@huggsboson This is the PR #39396 merged in 1.4 branch. But the patch is not for fixing TPR.

@liggitt
Copy link
Member

liggitt commented Jan 23, 2017

I think #40260 is more likely to be what we want, switching apply to use unstructured and not do any conversion or defaulting from the input the user gives

@soltysh
Copy link
Contributor Author

soltysh commented Jan 23, 2017

I'll check, thx for the pointer.

@k8s-github-robot
Copy link

[APPROVALNOTIFIER] Needs approval from an approver in each of these OWNERS Files:

We suggest the following people:
cc @sig-cli-maintainers
You can indicate your approval by writing /approve in a comment
You can cancel your approval by writing /approve cancel in a comment

@soltysh
Copy link
Contributor Author

soltysh commented Jan 24, 2017

@liggitt confirmed, just verified this works as expected with #40260. Closing in favor of the other one in that case.

@soltysh soltysh closed this Jan 24, 2017
@soltysh soltysh deleted the issue35149 branch January 24, 2017 10:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/kubectl do-not-merge DEPRECATED. Indicates that a PR should not merge. Label can only be manually applied/removed. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. priority/important-soon Must be staffed and worked on either currently, or very soon, ideally in time for the next release. release-note-none Denotes a PR that doesn't merit a release note. size/M Denotes a PR that changes 30-99 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet