-
Notifications
You must be signed in to change notification settings - Fork 42
feat(controller): Refactor reconcile loop and add unit tests #180
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
base: main
Are you sure you want to change the base?
Conversation
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: ballista01 The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
Hi @ballista01. Thanks for your PR. I'm waiting for a etcd-io member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. |
baf8e00
to
59d969f
Compare
/ok-to-test |
dffb919
to
fa7f810
Compare
fa7f810
to
9250067
Compare
- split the monolithic Reconcile into fetch/sync/health/cluster phases backed by a shared reconcileState - ensure TLS setup, STS ownership checks, and primitive bootstrapping are driven through dedicated helpers - refresh controller unit tests to exercise the new helpers and drop obsolete scaffolding Signed-off-by: Wenxue Zhao <[email protected]>
9250067
to
b43d579
Compare
I was reading the code. But the changes look a little bit lengthy. Do you think that it would be possible to break down this pull request? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The refactoring makes sense to me. Just raised several minor comments.
Thanks.
cc @ivanvc @ArkaSaha30 @abdurrehman107 @hakman @frederiko PTAL when you get free cycle, thx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the pull request, @ballista01. I left a couple of comments.
I also noticed that you removed some comments from lengthy functions. I think it makes sense to comment these functions, as it is easy to get lost with all the conditions they have. Thanks again :)
cluster *ecv1alpha1.EtcdCluster // cluster custom resource currently being reconciled | ||
sts *appsv1.StatefulSet // associated StatefulSet for the cluster | ||
memberListResp *clientv3.MemberListResponse // member list fetched from the etcd cluster | ||
healthInfos []etcdutils.EpHealth // health information for each etcd member |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading this property name out loud makes me wonder if we could rename it to: memberHealth
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also recovered and updated some comments (mainly in reconcileClusterState
). Let me know if we need more!
}, | ||
req: ctrl.Request{NamespacedName: types.NamespacedName{Name: "etcd", Namespace: "default"}}, | ||
assert: func(t *testing.T, state *reconcileState, res ctrl.Result, err error, ec *ecv1alpha1.EtcdCluster, _ *appsv1.StatefulSet) { | ||
if assert.NotNil(t, state) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the value of this if statement? If it fails, either way the test will fail in the end. So, I'm trying to understand why we would want this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the question! testify
’s assert
helpers only record the failure and carry on, so the original if assert.NotNil(...)
blocks were just there to stop us from dereferencing state/state.sts
and panicing. That might seem to be confusing, so I’ve switched those checks to require.NotNil(...)
. Now the tests fail fast when the state is missing, and the following assert.Equal
calls simply verify the expected fields.
if assert.NotNil(t, state) { | ||
assert.Equal(t, ec.Name, state.cluster.Name) | ||
if assert.NotNil(t, state.sts) { | ||
assert.Equal(t, sts.Name, state.sts.Name) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the usage to require.NotNil(...)
…n tests Signed-off-by: Wenxue Zhao <[email protected]>
The change for internal/controller/etcdcluster_controller.go looks clean and better. Thanks. (But do not get much time to look into the test case.) Let's target to merge this PR before our next WG meeting. |
@ivanvc any further comments on this PR? |
Summary
EtcdClusterReconciler.Reconcile
into focused phases to reduce cyclomatic complexity and make behavior easier to reason about.reconcileState
container so data gathered in earlier phases can be reused without repeated lookups.Controller changes (
internal/controller/etcdcluster_controller.go
)Split the main reconcile loop into:
fetchAndValidateState
bootstrapStatefulSet
performHealthChecks
reconcileClusterState
Each returns early with a
ctrl.Result
when it needs a requeue or encounters an error.Introduced
reconcileState
(cluster, StatefulSet, member list, member health) to pass context between phases.fetchAndValidateState
:bootstrapStatefulSet
:ctrl.Result.IsZero()
to decide whether to continue.performHealthChecks
andreconcileClusterState
:memberHealth
.Tests (
internal/controller/etcdcluster_controller_test.go
)Replaced the previous integration-style test with table-driven unit tests using controller-runtime’s fake client.
Added
TestFetchAndValidateState
andTestBootstrapStatefulSet
, switching to require for hard preconditions and asserting on StatefulSet/Service/ConfigMap outcomes.Expanded coverage for bootstrap scenarios:
Verified cluster state remains untouched when nothing changes.