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

Fix synchronization between claim and the counterpart composite #4896

Merged
merged 2 commits into from Dec 13, 2023

Conversation

pedjak
Copy link
Contributor

@pedjak pedjak commented Oct 25, 2023

Description of your changes

Removing of a claim annotation, label, field and/or array member is properly propagated to the counterpart composite by using k8s server-side apply feature. The same approach is used by propagating composite changes back to the claim.

Implementing the server-side apply requested the following changes on the claim reconciler:

  • Given that a submitted patch needs to contain all fields that a reconciler care about and wants to take the ownership, the existing configurators and binders cannot perform updates. Instead, they are only adding the requested changes to the patch, that gets applied in one shot.
  • The claim configurator requires access to actual claim and composite, but produces a claim patch, similar goes for the composite configurator. Hence, Configurator was not applicable anymore got removed.
  • Given that WithClaimConfigurator and WithCompositeConfigurator are used only for mocking in the unit tests, their visibility is reduced.
  • Field manager name follows the convention: crossplane-claim-controller/<CLAIM_GROUP_KIND_LOWERCASE>
  • Claim status subresource is still modified by sending UPDATE requests, because the controller should own it completely. That is expressed explicitly by setting the status field ownership.
  • Given that Applicator is not used anymore, Reconciler.client is redeclared to client.Client
  • Unit tests reworked/updated to verify the new implementation

Following the proposal stated in #4581, the following composite fields are propagated back to the claim:

  • spec.compositionRef
  • spec.compositionSelector
  • spec.compositionUpdatePolicy
  • spec.compositionRevisionSelector
  • status minus status.conditions

Fixes:

An e2e test added for verifying the above fixes and catching future regressions.

Part of #4047 epic.

Implements: #4581

I have:

  • Read and followed Crossplane's contribution process.
  • Run make reviewable to ensure this PR is ready for review.
  • Added or updated unit tests.
  • Added or updated e2e tests.
  • [ ] Linked a PR or a docs tracking issue to document this change.
  • [ ] Added backport release-x.y labels to auto-backport this PR.

@pedjak pedjak requested review from negz and a team as code owners October 25, 2023 15:11
@pedjak pedjak requested a review from turkenh October 25, 2023 15:11
@pedjak pedjak self-assigned this Oct 25, 2023
@@ -125,35 +126,37 @@ func ConfigureComposite(_ context.Context, cm resource.CompositeClaim, cp resour
}

claimSpecFilter := xcrd.GetPropFields(wellKnownClaimFields)
ucp.Object["spec"] = filter(spec, claimSpecFilter...)
cpPatch.(*composite.Unstructured).Object["spec"] = filter(spec, claimSpecFilter...)
Copy link
Contributor

Choose a reason for hiding this comment

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

this is ugly. Why not use that type for cpPatch directly? A type cast is always suspicious, unguarded even more so.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see why you do that. Still ugly, but I don't see a better way.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Me neither, but I see this sort of casting often in this part of the codebase. This gives me a signal that we have just one implementation of resource.Composite or resource.CompositeClaim interface and perhaps it would be better to use it directly where needed. Using casts mean that we have single data model, and hence there is no much benefit of hiding it behind some interfaces.

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 have removed type casting in this commit. Let me know what do you think. I like it.

if err := merge(ucm.Object["status"], ucp.Object["status"],
udesiredCm, ok := cmPatch.(*claim.Unstructured)
if !ok {
return nil
Copy link
Contributor

Choose a reason for hiding this comment

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

what does this mean? Similar to above: don't cast. Use the proper types directly.

@pedjak pedjak force-pushed the fix-claim-xr-sync branch 2 times, most recently from e44abc9 to 44eb7ed Compare October 30, 2023 12:57
@pedjak pedjak force-pushed the fix-claim-xr-sync branch 2 times, most recently from ab2cef4 to 53a3081 Compare November 29, 2023 18:09
@pedjak
Copy link
Contributor Author

pedjak commented Nov 29, 2023

@turkenh #5062 got merged and I have rebased this one on the top of the latest master, answered your comments as well. PTAL.

Copy link
Member

@turkenh turkenh left a comment

Choose a reason for hiding this comment

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

I tried an upgrade test and noticed that the composite keep getting updates, see below:

updates.mp4

Reproduction steps:

  1. Install Crossplane v1.14.2
  2. Follow the steps here.
  3. Upgrade Crossplane to a local build from this branch.
  4. Run kubectl get xnopresources.nop.example.org -w

Could you investigate that?


Well, actually this is true for just regular install as well without upgrading Crossplane:

Reproduction steps:

  1. Install Crossplane with a local build from this branch.
  2. Follow the steps here.
  3. Run kubectl get xnopresources.nop.example.org -w
install.mp4

It become True/True only after around 5mins:

Screenshot 2023-12-05 at 10 29 40

internal/controller/apiextensions/claim/configurator.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/configurator.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
internal/controller/apiextensions/claim/reconciler.go Outdated Show resolved Hide resolved
@pedjak
Copy link
Contributor Author

pedjak commented Dec 11, 2023

@turkenh I have addressed your comments. PTAL.

@turkenh
Copy link
Member

turkenh commented Dec 11, 2023

@turkenh I have addressed your comments. PTAL.

Did you have a chance to do some testing and see what was going on here?

Removing of a claim annotation, label, field and/or array member is properly
propagated to the counterpart composite by using
[k8s server-side apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/)
feature. The same approach is used by propagating composite changes back
to the claim.

Implementing the server-side apply requested the following changes
on the claim reconciler:

* Given that a submitted patch needs to contain all fields that a reconciler
  care about and wants to take the ownership, the existing configurators
  and binders cannot perform updates. Instead, they are only adding the requested
  changes to the patch, that gets applied in one shot.
* The claim configurator requires access to actual claim and composite, but
  produces a claim patch, similar goes for the composite configurator. Hence,
  `Configurator` was not applicable anymore got removed.
* Given that `WithClaimConfigurator` and `WithCompositeConfigurator` are used
  only for mocking in the unit tests, their visibility is reduced.
* Field manager name follows the convention: `crossplane-claim-controller/<CLAIM_GROUP_KIND_LOWERCASE>`
* Claim status subresource is still modified by sending UPDATE requests, because
  the controller should own it completely. That is expressed explicitly by setting
  the status field ownership.
* Given that `Applicator` is not used anymore, `Reconciler.client` is
  redeclared to `client.Client`
* unit tests reworked/updated to verify the new implementation

Following the proposal stated in crossplane#4581, the following composite fields
are propagated back to the claim:
* `spec.compositionRef`
* `spec.compositionSelector`
* `spec.compositionUpdatePolicy`
* `spec.compositionRevisionSelector`
*  `status` minus `status.conditions`

Signed-off-by: Predrag Knezevic <predrag.knezevic@upbound.io>
@pedjak pedjak force-pushed the fix-claim-xr-sync branch 3 times, most recently from 44d4181 to f0f7c14 Compare December 11, 2023 17:40
@pedjak
Copy link
Contributor Author

pedjak commented Dec 11, 2023

Did you have a chance to do some testing and see what was going on #4896 (review)

Yes, fixed, but please double check.

Signed-off-by: Predrag Knezevic <predrag.knezevic@upbound.io>
Copy link
Member

@turkenh turkenh left a comment

Choose a reason for hiding this comment

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

Great work @pedjak, see how many (long running issues) fixed by this single PR 💪
Thanks for bearing with me during reviews 🙌

@turkenh turkenh merged commit 841258b into crossplane:master Dec 13, 2023
16 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants