-
Notifications
You must be signed in to change notification settings - Fork 38.7k
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
start serving customresourcedefinition based on status #45838
Conversation
The first commit is just the renaming commit, so this isn't as enormous as it seems. |
Reviewed 66 of 66 files at r1, 12 of 12 files at r2. staging/src/k8s.io/kube-apiextensions-server/pkg/apis/apiextensions/helpers.go, line 58 at r2 (raw file):
Could you short-circuit here? I'm assuming there can only be one condition of a given type? if condition.Type == conditionType {
return condition.Status == status
} staging/src/k8s.io/kube-apiextensions-server/pkg/apiserver/customresource_discovery_controller.go, line 85 at r2 (raw file):
Is there enough plumbing now to add something here? If there is a name conflict, we don't want to list the resource in discovery, right? staging/src/k8s.io/kube-apiextensions-server/pkg/controller/status/naming_controller.go, line 84 at r2 (raw file):
Informers are not write-through, right? Even though this is single-worker, our cache may not yet reflect updates we made in a previous staging/src/k8s.io/kube-apiextensions-server/pkg/controller/status/naming_controller.go, line 228 at r2 (raw file):
It doesn't matter yet with only one worker, but I would expect the Comments from Reviewable |
Good catch. I'll upstream origin's mutation filter.
Yes. I was going to overhaul it separately, but I'll see how invasive the things I want to do are.
Sure. I don't know that I see us multithreading this in the near term though. |
|
||
// SetCustomResourceDefinitionCondition sets the status condition. It either overwrites the existing one or | ||
// creates a new one | ||
func SetCustomResourceDefinitionCondition(customResourceDefinition *CustomResourceDefinition, newCondition CustomResourceDefinitionCondition) { |
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.
can we at least use short parameter names if types and func names are that long?
// This controller is reserving names. To avoid conflicts, be sure to run only one instance of the worker at a time. | ||
// This could eventually be lifted, but starting simple. | ||
type NamingConditionController struct { | ||
customResourceDefinitionClient client.CustomResourceDefinitionsGetter |
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.
crdClient
return c | ||
} | ||
|
||
func (c *NamingConditionController) getNamesForGroup(group string) (allResources sets.String, allKinds sets.String) { |
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.
getAcceptedNamesForGroup
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.
We are using names
for two things in this file: for the Names
type and for a set of strings.
return newNames, condition | ||
} | ||
|
||
func checkName(requestedName, acceptedName string, usedNames sets.String) error { |
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.
s/checkName/equalToAcceptedOrFresh/
} else { | ||
newNames.Singular = requestedNames.Singular | ||
} | ||
if !reflect.DeepEqual(requestedNames.ShortNames, acceptedNames.ShortNames) { |
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.
where is the sorting? If there is one, please add a comment there.
|
||
// Check each name for mismatches. If there's a mismatch between spec and status, then try to deconflict. | ||
// Continue on errors so that the status is the best match possible | ||
if err := checkName(requestedNames.Plural, acceptedNames.Plural, allResources); err != nil { |
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.
Where is it checked that singular, plural and shortnames do not overlap? I haven't seen this in the validation either.
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.
Where is it checked that singular, plural and shortnames do not overlap?
Inside of a single resource, they should be able to since the parsing would still be unambiguous for intent. Think endpoints
and endpoints
. They point to the same spot.
condition.Message = "no conflicts found" | ||
} | ||
|
||
return newNames, condition |
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.
Would the semantics be much simpler if we either accept all requested names or none? Now it can happen that the plural changes, but the singular has a conflicts. Don't like that very much.
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.
Would the semantics be much simpler if we either accept all requested names or none? Now it can happen that the plural changes, but the singular has a conflicts. Don't like that very much.
Instead of reserving the names that are valid? The change ought to be straightforward, but I think we actually serve with some names conflicting.
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.
Instead of reserving the names that are valid? The change ought to be straightforward, but I think we actually serve with some names conflicting.
I guess I wouldn't want to explain this to anyone. You sure we don't want to reserve the names that were ok?
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 if you notice that there is a conflict, you do kubectl-edit and some of the names are already accepted. There is not way to unaccept them, right? I would like to be able to edit all the names as long as the CRD is not ready. If I can do that even after parts were accepted, that's 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.
What if you notice that there is a conflict, you do kubectl-edit and some of the names are already accepted. There is not way to unaccept them, right? I would like to be able to edit all the names as long as the CRD is not ready. If I can do that even after parts were accepted, that's fine.
that is possible. There's even a test for it: "merge on conflict"
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, then it's fine. I had the impression it's not possible. But I trust the test ;)
} | ||
|
||
func (c *NamingConditionController) sync(key string) error { | ||
inCustomResourceDefinition, err := c.customResourceDefinitionLister.Get(key) |
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.
inCRD
} | ||
|
||
// IsCustomResourceDefinitionEquivalent returns true if the lhs and rhs are equivalent except for times | ||
func IsCustomResourceDefinitionEquivalent(lhs, rhs *CustomResourceDefinitionCondition) bool { |
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.
s/IsCustomResourceDefinitionEquivalent/equivalentConditions/
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.
s/IsCustomResourceDefinitionEquivalent/equivalentConditions/
No guarantee that this group doesn't grow more types with other conditions.
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.
equivalentCRDConditions. The main point is that "Conditions" is missing in the name now.
} | ||
|
||
// IsCustomResourceDefinitionCondition indicates if the condition is present and equal to the arg | ||
func IsCustomResourceDefinitionCondition(customResourceDefinition *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType, status ConditionStatus) bool { |
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.
conditionPresentAndEqual
} | ||
|
||
// IsCustomResourceDefinitionConditionTrue indicates if the condition is present and strictly true | ||
func IsCustomResourceDefinitionConditionTrue(customResourceDefinition *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) bool { |
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.
conditionTrue
} | ||
|
||
// GetCustomResourceDefinitionCondition returns the condition you're looking for or nil | ||
func GetCustomResourceDefinitionCondition(customResourceDefinition *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) *CustomResourceDefinitionCondition { |
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.
findCondition
|
||
// SetCustomResourceDefinitionCondition sets the status condition. It either overwrites the existing one or | ||
// creates a new one | ||
func SetCustomResourceDefinitionCondition(customResourceDefinition *CustomResourceDefinition, newCondition CustomResourceDefinitionCondition) { |
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.
setCondition
return err | ||
} | ||
|
||
acceptedNames, namingCondition := c.calculateNames(inCustomResourceDefinition) |
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.
// nothing to do if accepted names and NameConflict condition didn't change
// if we haven't changed the condition, then our names must be good. | ||
if condition.Status == apiextensions.ConditionUnknown { | ||
condition.Status = apiextensions.ConditionFalse | ||
condition.Reason = "Passed" |
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.
s/Passed/NoConflicts/
} | ||
} | ||
|
||
_, err = c.customResourceDefinitionClient.CustomResourceDefinitions().UpdateStatus(customResourceDefinition) |
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 know that the customResourceDefinitionLister is up-to-date immediately? I.e. do we see a consistent group state for the next item in the queue?
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 know that the customResourceDefinitionLister is up-to-date immediately? I.e. do we see a consistent group state for the next item in the queue?
pulling in a mutation cache filter from openshift.
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.
👍
Rebased, added a mutation cache, addressed comments in a separate commit. |
3cb6eee
to
40eff82
Compare
changed to IsCRDConditionEquivalent
…On Tue, May 16, 2017 at 12:32 PM, Dr. Stefan Schimanski < ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In staging/src/k8s.io/kube-apiextensions-server/pkg/apis/
apiextensions/helpers.go
<#45838 (comment)>
:
> +func IsCustomResourceDefinitionConditionTrue(customResourceDefinition *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType) bool {
+ return IsCustomResourceDefinitionCondition(customResourceDefinition, conditionType, ConditionTrue)
+}
+
+// IsCustomResourceDefinitionCondition indicates if the condition is present and equal to the arg
+func IsCustomResourceDefinitionCondition(customResourceDefinition *CustomResourceDefinition, conditionType CustomResourceDefinitionConditionType, status ConditionStatus) bool {
+ for _, condition := range customResourceDefinition.Status.Conditions {
+ if condition.Type == conditionType && condition.Status == status {
+ return true
+ }
+ }
+ return false
+}
+
+// IsCustomResourceDefinitionEquivalent returns true if the lhs and rhs are equivalent except for times
+func IsCustomResourceDefinitionEquivalent(lhs, rhs *CustomResourceDefinitionCondition) bool {
equivalentCRDConditions. The main point is that "Conditions" is missing in
the name now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#45838 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AH2BSvyGkUXToFUrjMa3474XY1AcqoG_ks5r6c-1gaJpZM4Nbp3M>
.
|
LGTM overall but it's unfortunate that the mutation cache only mostly prevents name conflicts. What's the worst case scenario if we hand out a name twice? Perhaps the apiextensions-server crashloops? Is it infeasible to switch to an uncached listing of all CRDs upon each sync, until and unless it is shown to be a performance problem? Or, is there a way to do something like WaitForCache on each sync to make sure it's caught up to see any updates from the previous sync? If there's no easy win, I'm ok with a TODO to revisit this if conflicts are found to occur in the wild. |
It's an n^2 lookup without any server-side filtering (though the server side filtering could be done with more work). I'd rather bump the size of the LRU cache before I tried to go out to the server for every check. I suspect we're o(ones) to start, and then stabilize o(dozens) or maybe o(hundreds). Getting to o(thousands) and having a controller so fast it doesn't observe the update before its dropped from the cache seems unlikely. The worst case isn't a crash loop, it's serving inconsistent information (same as can already happen today). |
/lgtm |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: deads2k, enisoc
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
squashed, retagging. |
@k8s-bot kops aws e2e test this |
Automatic merge from submit-queue (batch tested with PRs 44520, 45253, 45838, 44685, 45901) |
Automatic merge from submit-queue Move the remaining controllers to shared informers Completes work done in 1.6 to move the last two hold outs to shared informers - tokens controller and scheduler. Adds a few more tools to allow informer reuse (like filtering the informer, or maintaining a mutation cache). The mutation cache is identical to #45838 and will be removed when that merges @ncdc @deads2k extracted from openshift/origin#14086
This exposes the
customresourcedefinition/status
endpoint, wires a controller to driveNameConflict
conditions, and serves discovery from status, not spec.Next steps after this include wiring the conditions into handling and reswizzling the handling chain to be cleaner now that we have a custom mux.