Skip to content

Conversation

@jpbetz
Copy link
Contributor

@jpbetz jpbetz commented Aug 12, 2020

xref: Design proposal

WARNING: All merge type changes are backward incompatible! The functionality this PR provides is intended to reduce the pain caused should a merge type change need to be made (in a alpha API for example, or in a CRD where the author has control of all clients and is able to ensure the change is safe). This should be used with caution.

Enables developers to add/remove these tags to Kubernetes types, by reconciling existing managed field data with the schema change:

  • atomic tags: +listType=atomic, +structType=atomic, +mapType=atomic
  • granular tags: +listType=map with +listMapKey, +listType=set, +mapType=granular

The corresponding x-kubernetes OpenAPI annotations for CRDs are also supported.

Need to do more careful benchmarking in k8s, but a simple benchmark in SMD suggests a 3.8% bump in CPU utilization and less than a 0.5% bump in allocations. The low allocation number is expected because the traversal is read-only unless there is an actual reconciliation change to apply afterward.

Before:

BenchmarkMultipleApplierRecursiveRealConversion 	   11803	   1547320 ns/op	  708431 B/op	    7441 allocs/op

After:

BenchmarkMultipleApplierRecursiveRealConversion 	   10000	   1606807 ns/op	  711170 B/op	    7471 allocs/op

Unblocks kubernetes/kubernetes#92913 and kubernetes/kubernetes#91256.

xref kubernetes/kubernetes#93901 which enables structType=atomic usage in k8s

@k8s-ci-robot k8s-ci-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels Aug 12, 2020
@k8s-ci-robot k8s-ci-robot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Aug 12, 2020
@jpbetz
Copy link
Contributor Author

jpbetz commented Aug 12, 2020

@apelisse I'll look into if what is required to have an atomic clear nested managed fields from other field managers when applied.

@apelisse
Copy link
Contributor

Also, the second apply does not require a force, but probably should when it clears the ownership of the fields owned by the first applier

Correct. If we look at both cases (going from atomic to non-atomic and vice versa), both should probably generate a conflict:

  • changing an atomic list that already had items MUST be a conflict
  • adding an item to a list that used to be atomic should maybe generate a conflict. Note that we also need to somehow transfer ownership of existing items to the owner of the former atomic list.

Trying to see what happens on HA clusters that have multiple versions ... I don't think it has additional consequences beside the typical "things are blurry during transition".

@jpbetz jpbetz force-pushed the test-atomic-introduction branch from 382e16c to 82b7e0f Compare August 14, 2020 21:33
@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels Aug 14, 2020
@apelisse
Copy link
Contributor

Let me know when I should take a look, thanks :-)

@jpbetz jpbetz force-pushed the test-atomic-introduction branch from 82b7e0f to e965b91 Compare August 25, 2020 22:02
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. labels Aug 25, 2020
@jpbetz jpbetz force-pushed the test-atomic-introduction branch 5 times, most recently from 411eaee to eb03fad Compare September 19, 2020 04:51
@k8s-ci-robot k8s-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Sep 19, 2020
@jpbetz jpbetz changed the title [WIP] Add test for changing struct from granular to atomic [WIP] Support granular<->atomic schema changes Sep 21, 2020
@jpbetz jpbetz force-pushed the test-atomic-introduction branch 5 times, most recently from 5157704 to 9664c45 Compare September 23, 2020 02:20
@jpbetz jpbetz force-pushed the test-atomic-introduction branch 2 times, most recently from 1042d0a to b4bff7c Compare September 23, 2020 02:29
@jpbetz
Copy link
Contributor Author

jpbetz commented Sep 23, 2020

@apelisse This is ready for review.

@jpbetz
Copy link
Contributor Author

jpbetz commented Sep 23, 2020

@apelisse to close the loop on the case of handling atomic->granular schema changes. I was concerned that it might be possible to mis-interpret a field set that is already granular as atomic if the fieldset only owned the root of a map/list but not any of it's children (i.e.{ .: {}}). I added a test case for this and it does what you had hoped-- it drops ownership of the entire map once no children are owned. So it appears the case I was concerned with cannot happen. It looks like lists are handled the same way. This is great because it means if we ever see {} we know for sure the field was atomically owned when the fieldset was written.

@jpbetz jpbetz force-pushed the test-atomic-introduction branch from b4bff7c to c4315fe Compare September 23, 2020 03:04
@jpbetz jpbetz force-pushed the test-atomic-introduction branch from c4315fe to 90b911a Compare September 23, 2020 03:08
@jpbetz
Copy link
Contributor Author

jpbetz commented Sep 23, 2020

@jennybuckley if you have any extra review bandwidth, this one could use some extra eyes

Copy link
Contributor

@apelisse apelisse left a comment

Choose a reason for hiding this comment

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

Looks good, a couple of minor questions

merge/update.go Outdated
return newObject, managers, nil
}

// reconcileManagedFieldsWithSchemaChanges reconciles the managed fields with any changes to the
Copy link
Contributor

Choose a reason for hiding this comment

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

Super nit: can you move that below "update/apply" methods.

merge/update.go Outdated
if err != nil {
return nil, err
}
reconciled, err := typed.ReconcileFieldSetWithSchema(versionedSet.Set(), tv)
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious if we really need the live object for that? Can't we fix each manager set by merely looking at the current type information?

Copy link
Contributor

Choose a reason for hiding this comment

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

Not asking you to change anything, just curious if we considered that and if that's any better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason we need the live type is that when we go from atomic to granular, we need to add to the fieldset all the fields that exist in the live object under the field that was previously atomic. We don't know exactly what they are just from the schema, because we don't know which fields are absent, or which map keys or list items are present.

return result, nil
}

func prefixWithPath(prefix fieldpath.Path, set *fieldpath.Set) *fieldpath.Set {
Copy link
Contributor

Choose a reason for hiding this comment

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

That makes me a little sad, there's probably a better way to do that :-)

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've switched to constructing the new field path in a more direct way that doesn't require the prefixing.

string: "b"
`,
APIVersion: "v1",
Managed: fieldpath.ManagedFields{
Copy link
Contributor

Choose a reason for hiding this comment

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

Very nice!

@jpbetz
Copy link
Contributor Author

jpbetz commented Sep 29, 2020

Thanks for the review @apelisse! Feedback applied.

@jpbetz jpbetz force-pushed the test-atomic-introduction branch from f1d2e49 to 9a22ec6 Compare September 29, 2020 19:17
@apelisse
Copy link
Contributor

/lgtm
/approve

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Sep 29, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: apelisse, jpbetz

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Sep 29, 2020
@k8s-ci-robot k8s-ci-robot merged commit 0bcdf88 into kubernetes-sigs:master Sep 29, 2020
return node, ok
}

func descendToPath(node *fieldpath.Set, path fieldpath.Path) *fieldpath.Set {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit for next time we look at it, this code should probably live in fieldpath rather than here.

@apelisse
Copy link
Contributor

We also probably need to cherry-pick this in as many versions as we can :-(

@jpbetz
Copy link
Contributor Author

jpbetz commented Sep 30, 2020

We also probably need to cherry-pick this in as many versions as we can :-(

Roger that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants