Skip to content

Conversation

@jaypipes
Copy link
Collaborator

The way that we were handling patching spec/metadata and status in the
main reconciler loop was starting to get awkward and messy. We were
calling patchResource, patchResourceStatus or
patchResourceMetadataAndSpec in quite a few places, the main
resourceReconciler.Sync() code path was getting messy and hard to
read, and we were in danger of having more subtle bugs creep into the
reconciler logic because of the duplicative patch calls and non-obvious
nature of the calls.

This patch simplifies and cleans up the logic around the core
resourceReconciler.Sync() code paths in the following ways:

  • Breaks out the create and update code paths into their own separate
    createResource and updateResource methods.
  • Renames the cleanup method to deleteResource in order to match the
    create and update methods
  • Removes ALL calls to patchResourceStatus in favor of always ensuring
    Status patching is done in the
    resourceReconciler.HandleReconcileError wrapper method
  • Removes the resourceReconciler.patchResource method entirely (which
    patched both Metadata/Spec as well as Status) and ensures that the
    createResource, updateResource and deleteResource methods on
    resourceReconciler only ever call patchResourceMetadataAndSpec
    (since patchResourceStatus is now always called by the
    HandleReconcileError wrapper)

These changes should make the late initialize work easier to fit into
the core reconciler logic and provide a more explicit contract about
what is responsible for patching status (only the
HandleReconcileError wrapper) and what is responsible for patching
metadata and spec (the createResource, updateResource and
deleteResource methods).

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license.

The way that we were handling patching spec/metadata and status in the
main reconciler loop was starting to get awkward and messy. We were
calling `patchResource`, `patchResourceStatus` or
`patchResourceMetadataAndSpec` in quite a few places, the main
`resourceReconciler.Sync()` code path was getting messy and hard to
read, and we were in danger of having more subtle bugs creep into the
reconciler logic because of the duplicative patch calls and non-obvious
nature of the calls.

This patch simplifies and cleans up the logic around the core
`resourceReconciler.Sync()` code paths in the following ways:

* Breaks out the create and update code paths into their own separate
  `createResource` and `updateResource` methods.
* Renames the `cleanup` method to `deleteResource` in order to match the
  create and update methods
* Removes ALL calls to `patchResourceStatus` in favor of always ensuring
  Status patching is done in the
  `resourceReconciler.HandleReconcileError` wrapper method
* Removes the `resourceReconciler.patchResource` method entirely (which
  patched both Metadata/Spec as well as Status) and ensures that the
  `createResource`, `updateResource` and `deleteResource` methods on
  `resourceReconciler` only ever call `patchResourceMetadataAndSpec`
  (since `patchResourceStatus` is now always called by the
  `HandleReconcileError` wrapper)

These changes should make the late initialize work easier to fit into
the core reconciler logic and provide a more explicit contract about
what is responsible for patching status (**only** the
`HandleReconcileError` wrapper) and what is responsible for patching
metadata and spec (the `createResource`, `updateResource` and
`deleteResource` methods).
Copy link
Contributor

@vijtrip2 vijtrip2 left a comment

Choose a reason for hiding this comment

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

Excellent Refactoring 🙌

// No changes to metadata or spec so Patch on the object shouldn't be done
kc.AssertNotCalled(t, "Patch", ctx, latestRTObj, client.MergeFrom(desiredRTObj))
statusWriter.AssertCalled(t, "Patch", ctx, latestRTObj, client.MergeFrom(desiredRTObj))
// Only the HandleReconcilerError wrapper function ever calls patchResourceStatus
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: should the test be renamed to TestSync_Update() , which is correct representation of the test.

Copy link
Member

@a-hilaly a-hilaly left a comment

Choose a reason for hiding this comment

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

Nice! LGTM

Comment on lines +57 to +58
// NOTE(jaypipes): This is really only here for dependency injection
// purposes in unit testing in order to simplify test setups.
Copy link
Member

Choose a reason for hiding this comment

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

👍

@a-hilaly
Copy link
Member

/lgtm

@ack-bot ack-bot added the lgtm Indicates that a PR is ready to be merged. label Jul 30, 2021
@ack-bot
Copy link
Collaborator

ack-bot commented Jul 30, 2021

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: A-Hilaly, jaypipes, vijtrip2

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:
  • OWNERS [A-Hilaly,jaypipes,vijtrip2]

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

@ack-bot ack-bot merged commit 1b10a42 into aws-controllers-k8s:main Jul 30, 2021
RedbackThomson pushed a commit to RedbackThomson/ack-runtime that referenced this pull request Aug 2, 2021
The way that we were handling patching spec/metadata and status in the
main reconciler loop was starting to get awkward and messy. We were
calling `patchResource`, `patchResourceStatus` or
`patchResourceMetadataAndSpec` in quite a few places, the main
`resourceReconciler.Sync()` code path was getting messy and hard to
read, and we were in danger of having more subtle bugs creep into the
reconciler logic because of the duplicative patch calls and non-obvious
nature of the calls.

This patch simplifies and cleans up the logic around the core
`resourceReconciler.Sync()` code paths in the following ways:

* Breaks out the create and update code paths into their own separate
  `createResource` and `updateResource` methods.
* Renames the `cleanup` method to `deleteResource` in order to match the
  create and update methods
* Removes ALL calls to `patchResourceStatus` in favor of always ensuring
  Status patching is done in the
  `resourceReconciler.HandleReconcileError` wrapper method
* Removes the `resourceReconciler.patchResource` method entirely (which
  patched both Metadata/Spec as well as Status) and ensures that the
  `createResource`, `updateResource` and `deleteResource` methods on
  `resourceReconciler` only ever call `patchResourceMetadataAndSpec`
  (since `patchResourceStatus` is now always called by the
  `HandleReconcileError` wrapper)

These changes should make the late initialize work easier to fit into
the core reconciler logic and provide a more explicit contract about
what is responsible for patching status (**only** the
`HandleReconcileError` wrapper) and what is responsible for patching
metadata and spec (the `createResource`, `updateResource` and
`deleteResource` methods).

By submitting this pull request, I confirm that my contribution is made under
the terms of the Apache 2.0 license.
ack-bot pushed a commit that referenced this pull request Aug 4, 2021
Fixes: aws-controllers-k8s/community#886

The reconciler will indefinitely requeue even when there have been no changes made to the `spec` or `status`. This is happening in both the adoption and resource reconciler types.

The root cause comes from `controller-runtime` requeue-ing the resource when we patch the `status` subresource - see [this issue](kubernetes-sigs/kubebuilder#618) for details. This bug was introduced for the resource reconciler as part of #39 , since we now call `patchResourceStatus` on every reconcile loop.

This fix adds an event filter to each manager, with a predicate that the resource must have changed generation. The generation is not changed unless there has been a modification to the `spec`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm Indicates that a PR is ready to be merged.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants