-
Notifications
You must be signed in to change notification settings - Fork 213
make operator status more kube-like #31
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
Conversation
|
I think we have have previous discussions that there should not be a cc @crawford OperatorStatus is designed to be write only for operators and read only for CVO and users. Also operatorstatus is separate type because we don;t want operators to vendor any CVO releasted code only the operator status related api and clients. |
I'm not pitching that we fill that in at the moment. An empty spec (as I have it here) will do fine.
It seems fairly likely that this ends up in openshift/api, but with a dynamic client, nothing requires them to. |
|
@crawford @smarterclayton comments? Milestone 2 requires operators to set this, so we should try to get the API consistent early. |
crawford
left a comment
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.
These commit messages provide zero information for people to review in the future. The PR comments have a decent amount of background though. Can you distill that into commit descriptions?
| metav1.ObjectMeta `json:"metadata"` | ||
|
|
||
| // Spec hold the intent of how this operator should behave. | ||
| Spec OperatorSpec `json:"spec""` |
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 cannot combine the Status and the Spec into the same object. This was the original design and we pivoted away from it. I don't think there is any need for this parent 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.
We cannot combine the Status and the Spec into the same object. This was the original design and we pivoted away from it. I don't think there is any need for this parent type.
Responded in the main thread with more detail below. The tl;dr is that spec/status is so ingrained in kubernetes, the burden is on this API to provide a reason why it cannot be structured like a "normal" resource. Not the other way around.
| type OperatorSpec struct { | ||
| } | ||
|
|
||
| type OperatorStatus struct { |
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.
Why is this being moved back into this API (and leaving the other copy in the other API)?
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.
Why is this being moved back into this API (and leaving the other copy in the other API)?
The copy only exists while we talk about this API. Before it moves out of WIP, we can remove the other.
The OperatorStatus is designed to be the common API between all of the operators. Right now, CVO is the only one who cares, but in the future, operators almost certainly will have dependencies between one another. I'd like to keep this in a separate API. |
@crawford I think the burden is on this type to explain why an empty |
I'm not aware of plans to try to have a secondary status object be a means to express and discover dependency relationships. It seems like we'd want the dependencies to be directly "owned" by producer with consumers being responsible for conforming. You can see an example of using a common status object not working is the relationship between etcd and all apiservers. Etcd takes care of creating and rotating client cert/keys pairs which are secrets. They must be consumed by the apiserver operators to keep their etcd connections alive. If you tried to include that here, you would create a confidential resource that you cannot grant read access to. If you do not include them here, you have to create the alternative to depending on this resource. I think we have to go with the latter. |
I wasn't clear. The operator status is designed to allow two operators who have a dependency on one another to communicate; not to declare the dependency. CVO currently enforces ordering in order to work around dependencies, but the eventual goal is to allow operators to coordinate between one another by watching relevant operator statuses. |
If a consumer knows that it has a dependency on a producer, there is no reason to depend on an intermediate object like this. It could simply go directly to the thing it depends upon. |
So these two statements are pretty close in intent. Let's work an example:
David, what object were you expecting kube-scheduler operator to look at in a dependency case? Alex, I assume you are implying that kube-scheduler operator would look at the kube apiserver operator object in the status field and look for a generic "version output"? So |
I wired up the kube and openshift control planes so that the kube-apiserver-operator publishes version information about itself and the openshift-apiserver-operator reads version information from that location. It avoids having an intermediate API and the same pattern can be used to collect secret information via secrets. |
Yep. I'm trying to reduce coupling between the operators. If you know how to read the generic status of one operator, you can read it for all of them. The escape hatch for this scheme is the Extension member of the type. |
The thing is, if I'm trying to discover that version, I'm already coupled. This doesn't reduce the coupling, it just makes another object that both operators have to go through. Ultimately, I'll move the object to a different group to fix the internal schema of said object. But I think the idea of a "universal operator information sharing space" is going to be poorly used internally and never used externally. |
|
So certain collaboration between operators is going to be confusing if we try to make it generic here - the status of certain config flags or whatever belongs in a different object (which it all seems we're on board with). Re versions - it might be good for us to talk about that in a design doc, but a few thoughts below: will agree with Alex here that the whole point of the CVO is to take a top level version and ensure specific, known versions are showing up in other places. It's reasonable that a human will want to look at operator status and at a glance know whether operator X is at the "right" level (whatever that is). I don't know that means that the operators have to report that, but who better than the kube operators to know what version of kube exists and report that back to an admin? The counter argument to that is that most or almost all of the individual versions really need to parrot the top level version (i.e. Openshift 4.2.1) while the versions we're talking about here might be kube (v1.13.1) or prometheus (2.4.0) or etcd (3.2.29). I haven't seen a design for this yet, but I am worried about components outside of the master team family having to look at an object geared for the kube-apiserver. Within master team - sure, since technically the master team has a "cluster-kube-operator" that just happens to be split into 5 processes - but outside the master team I would have expected an operator to ask "is the control plane at v1.13", not "hey kube-apiserver, what version do you think you're at". |
|
Re operator spec: I think the operator spec here isn't the config of the operator - it's the control point that the SLO respects for specific, limited generic operator behavior. I.e. it's a generic spec that all operators are expected to follow for things like Re spec and status: Given the kube conventions, I argued for this which is the primary goal of the object is to be a generic interface for operator level actions, which includes generic status (human focused) and possibly an abstract version thing (which obviously we have disagreement on). The status is single writer from the operator. The spec would only be things that were necessary for consistent operational behavior across all SLOs, like pausing the operator. Re: status being namespace vs cluster scoped Just from a purely mechanical level, I'd rather run |
|
I'll open a different pull for the status structure change the name change. I'll rebase this on that so we can merge the easier bits and revisit some of the harder ones. |
|
@crawford updated per our conversation on Friday.
After this merges, I plan to open more pulls to push further (name of resource, possibly scoping, possibly group), but I think we agree this far and it will help make integration from other teams easier and reduce overall change. |
| // OperatorAvailable indicates that the binary supported by the operator is functional and available in the cluster. | ||
| OperatorAvailable OperatorStatusConditionType = "Available" | ||
|
|
||
| // OperatorProgressing indicates that the operator is actively binary supported by the operator is functional and available in the cluster. |
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.
Looks like the wrong godoc.
Is progressing supposed to be "I'm reconciling towards the desired state"? Or reflect the operator status itself?
I think it's acceptable to have different condition types when the definition is not the same. For instance, Deployment uses Progressing False to represent "failing" because deployment has no perm fail state.
The removal of "Done" means that a consumer doesn't have an unambiguous signal about when all possible changes have been applied. I think we should have a positive, affirmative condition on "up to date".
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 removal of "Done" means that a consumer doesn't have an unambiguous signal about when all possible changes have been applied. I think we should have a positive, affirmative condition on "up to date".
as opposed to that being done := available && !progressing && !failed each of which have clear individual signals for different conditions?
| // OperatorStatusConditionTypeDegraded indicates that the operator has | ||
| // encountered an error that is preventing it from working properly. | ||
| OperatorStatusConditionTypeDegraded OperatorStatusConditionType = "Degraded" | ||
| // OperatorAvailable indicates that the binary supported by the operator is functional and available in the cluster. |
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 explain binary supported by the operator ?
|
Initial comments addressed. Typo, type name, doc. |
|
@deads2k #31 (comment) these functions don't seem to belong to Where would be rather recommend we keep them. Some Kubernetes api packages do have versioned helper functions in the apis. |
I think that in the next month we will move this to openshift/api. Once we do that, then they will have a home inside of library-go near https://github.com/openshift/library-go/tree/master/pkg/operator/v1alpha1helpers . We can simulate that structure now if you like. I didn't think that it mattered either way. |
|
I am fine if we move these helper functions anywhere out of |
The spec/status split is a kuberentes standard that is respected in a generic way by kubectl and CRDs. Making OperatorStatus conform will make it match expectations.
|
/approve |
|
@crawford / @smarterclayton can you take another look and |
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: abhinavdahiya, crawford, deads2k The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
cvo/internal: catch up the operator status handler to PR #31
We have blocking on this condition since 545c342 (api: make status substruct on operatorstatus, 2018-10-15, openshift#31) when it was Failing. We'd softened our install-time handling to act this way back in b0b4902 (clusteroperator: Don't block on failing during initialization, 2019-03-11, openshift#136), motivated by install speed [1]. And a degraded operator may slow dependent components in their own transitions. But as long as the operator/operand are available at all, it should not block depndent components from transitioning, so this commit removes the Degraded=True block from the remaining modes. We still have the critical ClusterOperatorDegraded waking admins up when an operator goes Degraded=True for a while, we will just no longer block updates at that point. We won't block ReconcilingMode manifest application either, but since that's already flattened and permuted, and ClusterOperator tend to be towards the end of their TaskNode, the impact on ReconcilingMode is minimal (except that we will no longer go Failing=True in ClusterVersion when the only issue is some Degraded=True ClusterOperator). [1]: openshift#136 (comment)
We have blocking on this condition since 545c342 (api: make status substruct on operatorstatus, 2018-10-15, openshift#31) when it was Failing. We'd softened our install-time handling to act this way back in b0b4902 (clusteroperator: Don't block on failing during initialization, 2019-03-11, openshift#136), motivated by install speed [1]. And a degraded operator may slow dependent components in their own transitions. But as long as the operator/operand are available at all, it should not block depndent components from transitioning, so this commit removes the Degraded=True block from the remaining modes. We still have the warning ClusterOperatorDegraded alerting admins when an operator goes Degraded=True for a while, we will just no longer block updates at that point. We won't block ReconcilingMode manifest application either, but since that's already flattened and permuted, and ClusterOperator tend to be towards the end of their TaskNode, the impact on ReconcilingMode is minimal (except that we will no longer go Failing=True in ClusterVersion when the only issue is some Degraded=True ClusterOperator). [1]: openshift#136 (comment)
We have blocking on this condition since 545c342 (api: make status substruct on operatorstatus, 2018-10-15, openshift#31) when it was Failing. We'd softened our install-time handling to act this way back in b0b4902 (clusteroperator: Don't block on failing during initialization, 2019-03-11, openshift#136), motivated by install speed [1]. And a degraded operator may slow dependent components in their own transitions. But as long as the operator/operand are available at all, it should not block depndent components from transitioning, so this commit removes the Degraded=True block from the remaining modes. We still have the warning ClusterOperatorDegraded alerting admins when an operator goes Degraded=True for a while, we will just no longer block updates at that point. We won't block ReconcilingMode manifest application either, but since that's already flattened and permuted, and ClusterOperator tend to be towards the end of their TaskNode, the impact on ReconcilingMode is minimal (except that we will no longer go Failing=True in ClusterVersion when the only issue is some Degraded=True ClusterOperator). [1]: openshift#136 (comment)
We have blocking on this condition since 545c342 (api: make status substruct on operatorstatus, 2018-10-15, openshift#31) when it was Failing. We'd softened our install-time handling to act this way back in b0b4902 (clusteroperator: Don't block on failing during initialization, 2019-03-11, openshift#136), motivated by install speed [1]. And a degraded operator may slow dependent components in their own transitions. But as long as the operator/operand are available at all, it should not block depndent components from transitioning, so this commit removes the Degraded=True block from the remaining modes. We still have the warning ClusterOperatorDegraded alerting admins when an operator goes Degraded=True for a while, we will just no longer block updates at that point. We won't block ReconcilingMode manifest application either, but since that's already flattened and permuted, and ClusterOperator tend to be towards the end of their TaskNode, the impact on ReconcilingMode is minimal (except that we will no longer go Failing=True in ClusterVersion when the only issue is some Degraded=True ClusterOperator). [1]: openshift#136 (comment)
@crawford @smarterclayton @abhinavdahiya @derekwaynecarr @openshift/api-review
Let's figure out the shape of the status reporting API. This is WIP where we can work out fine details. The story so far.....
Kube and OpenShift workload and core resources have a dedicate slice of conditions under
.status.conditionsthat individually trackTrue,False,Unknownstates. This avoids multiplying states in a state machine and various ecosystem features have built around them likekubectl waitand the CRD spec/status permissions split. Along with the concept of status being a thing that is completely re-derivable from cluster state.Since the operatorstatus described here is closely related to the CVO (only consumer), this pull moves the
OperatorStatustype intoclusterversion.openshift.io. Also, the spec/status split for customresources provides a kube-like experience, so I've renamed it toOperatorwith filled in.statusand an empty.spec.One key question I had is why the
OperatorStatusis namespace scoped. It's fairly easy to keep it there, but in looking at the operators we manage by the CVO, it seems that they are largely cluster-scoped, not largely namespace scoped.Given that, naming at a cluster scope seems to make more sense since they do not scale with the number of namespaces available.