Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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
Add Conditions to status #91
Add Conditions to status #91
Changes from 5 commits
39b3c2e
29631dc
f3d0987
1a3d231
407cd2f
4e05d47
9f797cc
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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 haven't seen (and I haven't looked very hard) patchStrategy and patchMergeKey on conditions before. Is this something suggested in official k8s docs somewhere?
I'm wondering what the implications are? It seems like this would permit two writers to server-side apply two different types concurrently? Do we want that?
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.
Yes, these are the recommended attributes:
https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Condition
What it should mean is that you can only have a single instance of each type.
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.
Do we also need the other tags for
Conditions
that are listed in the exampleFooStatus
on that page? I'm not actually sure, but it's definitely worth adding them and runningmake generate manifests
to see what they do to the generated code and/or CRD file.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.
It does add something (
x-kubernetes-list
) values. So I might as well.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.
Another follow-up/TODO/ground rule/invariant:
For every
condition.Type
that we define, that type has a condition set no matter what code path is taken through the reconciler. Every single time reconcile is called, we make sure to evaluate what the value of eachcondition.Type
should be and we make sure it is set that way.TL;DR:
Where input is defined as: "Operator CR (minus its status) + existing cluster state"
And output is defined as: "Operator CR status + new desired cluster state"
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
Could you explain when the controller would modify something other than the Operator CR's status? I can't imagine a scenario where we'd want to modify the resource's spec, is this to update something in the metadata (annotations, labels, etc..)? If the point of this update call is to modify something outside the spec, does it make sense to exclude it?
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.
This was suggested by @joelanford; it's copied from the rukpak reconciler. My assumption is to make this a complete wrapper around the reconcile helper function My presumption would be to fill in default values if they were not included in the original resource (if we wanted to do that).
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.
(And possibly metadata)
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.
Finalizers are the only thing that comes to mind. Defaulting should be handled for us by the apiserver during admission. Not reconciliation.
This is a good question though. Perhaps we should have the code panic if it detects a change we made to non-status, non-finalizers, as that would indicate a programming mistake.
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.
Should rukpak be updated as well?
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.
@joelanford: something like?
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.
This would strip finalizers from the object, which we may not want to. Something like this may work.
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.
Are you sure? We aren't doing an
r.Update()
in this case, although that might still be necessary due to updated finalizers. We can't just compare theSpecs
, as that ignores othermetadata
.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.
OK, weirdness!
r.Status().Update()
actually makes additional modifications to the structure. So, do all the comparisons first, then update the status,panic()
if required, then update the spec (should just be the finalizers).The
reconciledOp
existingOp
andcompareOp
are all local variables, and k8s is unmodified until anUpdate()
call is made.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.
Ah sorry, I didn't notice that you changed the code between the time that I initially reviewed the PR and made that comment.
Controllers are allowed to edit metadata and remove finalizers, if we're saying that this controller specifically isn't allowed to make meatadata changes, this is fine.
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.
Oh this reminds me of another way to test for making sure we update all conditions. Unit tests of the
Reconcile
method should make sure that all condition types have condition objects AND all of those objects have observedGeneration that matches the metadata.generation of the Operator that was reconciled.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.
Should we also test for the specific Status and Reason we expect?
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 decided to not bother with that. As I wanted to minimize changes (vs. additions) to the tests as code is added.
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.
Nit, but perhaps some good future proofing to do while things aren't already baked. Could we declare a slice of all of our condition types in the same place the we define them, and then in this test iterate that slice to make sure that all of them exist and have the generation of the
opName
operator?