Skip to content

Commit 545c342

Browse files
committed
api: make status substruct on operatorstatus
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.
1 parent 7964bd2 commit 545c342

File tree

13 files changed

+337
-125
lines changed

13 files changed

+337
-125
lines changed

cmd/start.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ func startControllers(ctx *controllerContext) error {
232232
componentNamespace, componentName,
233233
rootOpts.releaseImage,
234234
ctx.InformerFactory.Clusterversion().V1().CVOConfigs(),
235-
ctx.InformerFactory.Operatorstatus().V1().OperatorStatuses(),
235+
ctx.InformerFactory.Operatorstatus().V1().ClusterOperators(),
236236
ctx.APIExtInformerFactory.Apiextensions().V1beta1().CustomResourceDefinitions(),
237237
ctx.KubeInformerFactory.Apps().V1().Deployments(),
238238
ctx.ClientBuilder.RestConfig(),
@@ -245,7 +245,7 @@ func startControllers(ctx *controllerContext) error {
245245
go autoupdate.New(
246246
componentNamespace, componentName,
247247
ctx.InformerFactory.Clusterversion().V1().CVOConfigs(),
248-
ctx.InformerFactory.Operatorstatus().V1().OperatorStatuses(),
248+
ctx.InformerFactory.Operatorstatus().V1().ClusterOperators(),
249249
ctx.ClientBuilder.ClientOrDie(componentName),
250250
ctx.ClientBuilder.KubeClientOrDie(componentName),
251251
).Run(2, ctx.Stop)

install/0000_00_cluster-version-operator_01_cvoconfig.crd.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ spec:
1515
storage: true
1616
# either Namespaced or Cluster
1717
scope: Namespaced
18+
subresources:
19+
# enable spec/status
20+
status: {}
1821
names:
1922
# plural name to be used in the URL: /apis/<group>/<version>/<plural>
2023
plural: cvoconfigs

lib/resourceapply/cv.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import (
1515
"k8s.io/utils/pointer"
1616
)
1717

18-
func ApplyOperatorStatus(client osclientv1.OperatorStatusesGetter, required *osv1.OperatorStatus) (*osv1.OperatorStatus, bool, error) {
19-
if required.Extension.Raw != nil && required.Extension.Object != nil {
18+
func ApplyOperatorStatus(client osclientv1.ClusterOperatorsGetter, required *osv1.ClusterOperator) (*osv1.ClusterOperator, bool, error) {
19+
if required.Status.Extension.Raw != nil && required.Status.Extension.Object != nil {
2020
return nil, false, fmt.Errorf("both extension.Raw and extension.Object should not be set")
2121
}
22-
existing, err := client.OperatorStatuses(required.Namespace).Get(required.Name, metav1.GetOptions{})
22+
existing, err := client.ClusterOperators(required.Namespace).Get(required.Name, metav1.GetOptions{})
2323
if errors.IsNotFound(err) {
24-
actual, err := client.OperatorStatuses(required.Namespace).Create(required)
24+
actual, err := client.ClusterOperators(required.Namespace).Create(required)
2525
return actual, true, err
2626
}
2727
if err != nil {
@@ -34,17 +34,17 @@ func ApplyOperatorStatus(client osclientv1.OperatorStatusesGetter, required *osv
3434
return existing, false, nil
3535
}
3636

37-
actual, err := client.OperatorStatuses(required.Namespace).Update(existing)
37+
actual, err := client.ClusterOperators(required.Namespace).Update(existing)
3838
return actual, true, err
3939
}
4040

41-
func ApplyOperatorStatusFromCache(lister oslistersv1.OperatorStatusLister, client osclientv1.OperatorStatusesGetter, required *osv1.OperatorStatus) (*osv1.OperatorStatus, bool, error) {
42-
if required.Extension.Raw != nil && required.Extension.Object != nil {
41+
func ApplyOperatorStatusFromCache(lister oslistersv1.ClusterOperatorLister, client osclientv1.ClusterOperatorsGetter, required *osv1.ClusterOperator) (*osv1.ClusterOperator, bool, error) {
42+
if required.Status.Extension.Raw != nil && required.Status.Extension.Object != nil {
4343
return nil, false, fmt.Errorf("both extension.Raw and extension.Object should not be set")
4444
}
45-
existing, err := lister.OperatorStatuses(required.Namespace).Get(required.Name)
45+
existing, err := lister.ClusterOperators(required.Namespace).Get(required.Name)
4646
if errors.IsNotFound(err) {
47-
actual, err := client.OperatorStatuses(required.Namespace).Create(required)
47+
actual, err := client.ClusterOperators(required.Namespace).Create(required)
4848
return actual, true, err
4949
}
5050
if err != nil {
@@ -59,7 +59,7 @@ func ApplyOperatorStatusFromCache(lister oslistersv1.OperatorStatusLister, clien
5959
return existing, false, nil
6060
}
6161

62-
actual, err := client.OperatorStatuses(required.Namespace).Update(existing)
62+
actual, err := client.ClusterOperators(required.Namespace).Update(existing)
6363
return actual, true, err
6464
}
6565

lib/resourcemerge/os.go

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,28 @@
11
package resourcemerge
22

33
import (
4-
osv1 "github.com/openshift/cluster-version-operator/pkg/apis/operatorstatus.openshift.io/v1"
4+
"time"
5+
56
"k8s.io/apimachinery/pkg/api/equality"
7+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8+
9+
osv1 "github.com/openshift/cluster-version-operator/pkg/apis/operatorstatus.openshift.io/v1"
610
)
711

8-
func EnsureOperatorStatus(modified *bool, existing *osv1.OperatorStatus, required osv1.OperatorStatus) {
12+
func EnsureOperatorStatus(modified *bool, existing *osv1.ClusterOperator, required osv1.ClusterOperator) {
913
EnsureObjectMeta(modified, &existing.ObjectMeta, required.ObjectMeta)
10-
if !equality.Semantic.DeepEqual(existing.Condition, required.Condition) {
14+
ensureOperatorStatusStatus(modified, &existing.Status, required.Status)
15+
}
16+
17+
func ensureOperatorStatusStatus(modified *bool, existing *osv1.ClusterOperatorStatus, required osv1.ClusterOperatorStatus) {
18+
if !equality.Semantic.DeepEqual(existing.Conditions, required.Conditions) {
1119
*modified = true
12-
existing.Condition = required.Condition
20+
existing.Conditions = required.Conditions
1321
}
1422
if existing.Version != required.Version {
1523
*modified = true
1624
existing.Version = required.Version
1725
}
18-
if !existing.LastUpdate.Equal(&required.LastUpdate) {
19-
*modified = true
20-
existing.LastUpdate = required.LastUpdate
21-
}
2226
if !equality.Semantic.DeepEqual(existing.Extension.Raw, required.Extension.Raw) {
2327
*modified = true
2428
existing.Extension.Raw = required.Extension.Raw
@@ -28,3 +32,64 @@ func EnsureOperatorStatus(modified *bool, existing *osv1.OperatorStatus, require
2832
existing.Extension.Object = required.Extension.Object
2933
}
3034
}
35+
36+
func SetOperatorStatusCondition(conditions *[]osv1.ClusterOperatorStatusCondition, newCondition osv1.ClusterOperatorStatusCondition) {
37+
if conditions == nil {
38+
conditions = &[]osv1.ClusterOperatorStatusCondition{}
39+
}
40+
existingCondition := FindOperatorStatusCondition(*conditions, newCondition.Type)
41+
if existingCondition == nil {
42+
newCondition.LastTransitionTime = metav1.NewTime(time.Now())
43+
*conditions = append(*conditions, newCondition)
44+
return
45+
}
46+
47+
if existingCondition.Status != newCondition.Status {
48+
existingCondition.Status = newCondition.Status
49+
existingCondition.LastTransitionTime = newCondition.LastTransitionTime
50+
}
51+
52+
existingCondition.Reason = newCondition.Reason
53+
existingCondition.Message = newCondition.Message
54+
}
55+
56+
func RemoveOperatorStatusCondition(conditions *[]osv1.ClusterOperatorStatusCondition, conditionType osv1.ClusterStatusConditionType) {
57+
if conditions == nil {
58+
conditions = &[]osv1.ClusterOperatorStatusCondition{}
59+
}
60+
newConditions := []osv1.ClusterOperatorStatusCondition{}
61+
for _, condition := range *conditions {
62+
if condition.Type != conditionType {
63+
newConditions = append(newConditions, condition)
64+
}
65+
}
66+
67+
*conditions = newConditions
68+
}
69+
70+
func FindOperatorStatusCondition(conditions []osv1.ClusterOperatorStatusCondition, conditionType osv1.ClusterStatusConditionType) *osv1.ClusterOperatorStatusCondition {
71+
for i := range conditions {
72+
if conditions[i].Type == conditionType {
73+
return &conditions[i]
74+
}
75+
}
76+
77+
return nil
78+
}
79+
80+
func IsOperatorStatusConditionTrue(conditions []osv1.ClusterOperatorStatusCondition, conditionType osv1.ClusterStatusConditionType) bool {
81+
return IsOperatorStatusConditionPresentAndEqual(conditions, conditionType, osv1.ConditionTrue)
82+
}
83+
84+
func IsOperatorStatusConditionFalse(conditions []osv1.ClusterOperatorStatusCondition, conditionType osv1.ClusterStatusConditionType) bool {
85+
return IsOperatorStatusConditionPresentAndEqual(conditions, conditionType, osv1.ConditionFalse)
86+
}
87+
88+
func IsOperatorStatusConditionPresentAndEqual(conditions []osv1.ClusterOperatorStatusCondition, conditionType osv1.ClusterStatusConditionType, status osv1.ConditionStatus) bool {
89+
for _, condition := range conditions {
90+
if condition.Type == conditionType {
91+
return condition.Status == status
92+
}
93+
}
94+
return false
95+
}

pkg/apis/operatorstatus.openshift.io/v1/register.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ func init() {
3636
// Adds the list of known types to api.Scheme.
3737
func addKnownTypes(scheme *runtime.Scheme) error {
3838
scheme.AddKnownTypes(SchemeGroupVersion,
39-
&OperatorStatus{},
40-
&OperatorStatusList{},
39+
&ClusterOperator{},
40+
&ClusterOperatorList{},
4141
)
4242

4343
metav1.AddToGroupVersion(scheme, SchemeGroupVersion)

pkg/apis/operatorstatus.openshift.io/v1/types.go

Lines changed: 69 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,72 +5,102 @@ import (
55
"k8s.io/apimachinery/pkg/runtime"
66
)
77

8-
// OperatorStatusList is a list of OperatorStatus resources.
8+
// ClusterOperatorList is a list of OperatorStatus resources.
99
// +k8s:deepcopy-gen=true
1010
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
11-
type OperatorStatusList struct {
11+
type ClusterOperatorList struct {
1212
metav1.TypeMeta `json:",inline"`
1313
metav1.ListMeta `json:"metadata"`
1414

15-
Items []OperatorStatus `json:"items"`
15+
Items []ClusterOperator `json:"items"`
1616
}
1717

18-
// OperatorStatus is the Custom Resource object which holds the current state
18+
// ClusterOperator is the Custom Resource object which holds the current state
1919
// of an operator. This object is used by operators to convey their state to
2020
// the rest of the cluster.
2121
// +genclient
2222
// +k8s:deepcopy-gen=true
2323
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
24-
type OperatorStatus struct {
24+
type ClusterOperator struct {
2525
metav1.TypeMeta `json:",inline"`
2626
metav1.ObjectMeta `json:"metadata"`
2727

28-
// Condition describes the state of the operator's reconciliation
29-
// functionality.
30-
Condition OperatorStatusCondition `json:"condition"`
28+
// Spec hold the intent of how this operator should behave.
29+
Spec ClusterOperatorSpec `json:"spec"`
3130

32-
// Version indicates which version of the operator updated the current
31+
// status holds the information about the state of an operator. It is consistent with status information across
32+
// the kube ecosystem.
33+
Status ClusterOperatorStatus `json:"status"`
34+
}
35+
36+
// ClusterOperatorSpec is empty for now, but you could imagine holding information like "pause".
37+
type ClusterOperatorSpec struct {
38+
}
39+
40+
// ClusterOperatorStatus provides information about the status of the operator.
41+
// +k8s:deepcopy-gen=true
42+
type ClusterOperatorStatus struct {
43+
// conditions describes the state of the operator's reconciliation functionality.
44+
// +patchMergeKey=type
45+
// +patchStrategy=merge
46+
Conditions []ClusterOperatorStatusCondition `json:"conditions"`
47+
48+
// version indicates which version of the operator updated the current
3349
// status object.
3450
Version string `json:"version"`
3551

36-
// LasteUpdate is the time of the last update to the current status object.
37-
LastUpdate metav1.Time `json:"lastUpdate"`
38-
39-
// Extension contains any additional status information specific to the
52+
// extension contains any additional status information specific to the
4053
// operator which owns this status object.
41-
Extension runtime.RawExtension `json:"extension"`
54+
Extension runtime.RawExtension `json:"extension,omitempty"`
4255
}
4356

44-
// OperatorStatusCondition represents the state of the operator's
57+
type ConditionStatus string
58+
59+
// These are valid condition statuses. "ConditionTrue" means a resource is in the condition.
60+
// "ConditionFalse" means a resource is not in the condition. "ConditionUnknown" means kubernetes
61+
// can't decide if a resource is in the condition or not. In the future, we could add other
62+
// intermediate conditions, e.g. ConditionDegraded.
63+
const (
64+
ConditionTrue ConditionStatus = "True"
65+
ConditionFalse ConditionStatus = "False"
66+
ConditionUnknown ConditionStatus = "Unknown"
67+
)
68+
69+
// ClusterOperatorStatusCondition represents the state of the operator's
4570
// reconciliation functionality.
46-
type OperatorStatusCondition struct {
47-
// Type specifies the state of the operator's reconciliation functionality.
48-
Type OperatorStatusConditionType `json:"type"`
71+
// +k8s:deepcopy-gen=true
72+
type ClusterOperatorStatusCondition struct {
73+
// type specifies the state of the operator's reconciliation functionality.
74+
Type ClusterStatusConditionType `json:"type"`
75+
76+
// Status of the condition, one of True, False, Unknown.
77+
Status ConditionStatus `json:"status"`
4978

50-
// Message provides any additional information about the current condition.
79+
// LastTransitionTime is the time of the last update to the current status object.
80+
LastTransitionTime metav1.Time `json:"lastTransitionTime"`
81+
82+
// reason is the reason for the condition's last transition. Reasons are CamelCase
83+
Reason string `json:"reason,omitempty"`
84+
85+
// message provides additional information about the current condition.
5186
// This is only to be consumed by humans.
52-
Message string `json:"message"`
87+
Message string `json:"message,omitempty"`
5388
}
5489

55-
// OperatorStatusConditionType is the state of the operator's reconciliation
56-
// functionality.
57-
type OperatorStatusConditionType string
90+
// ClusterStatusConditionType is the state of the operator's reconciliation functionality.
91+
type ClusterStatusConditionType string
5892

5993
const (
60-
// OperatorStatusConditionTypeWaiting indicates that the operator isn't
61-
// running its reconciliation functionality. This may be because a
62-
// dependency or other prerequisite hasn't been satisfied.
63-
OperatorStatusConditionTypeWaiting OperatorStatusConditionType = "Waiting"
64-
65-
// OperatorStatusConditionTypeWorking indicates that the operator is
66-
// actively reconciling its operands.
67-
OperatorStatusConditionTypeWorking OperatorStatusConditionType = "Working"
68-
69-
// OperatorStatusConditionTypeDone indicates that the operator has finished
70-
// reconciling its operands and is waiting for changes.
71-
OperatorStatusConditionTypeDone OperatorStatusConditionType = "Done"
72-
73-
// OperatorStatusConditionTypeDegraded indicates that the operator has
74-
// encountered an error that is preventing it from working properly.
75-
OperatorStatusConditionTypeDegraded OperatorStatusConditionType = "Degraded"
94+
// OperatorAvailable indicates that the binary maintained by the operator (eg: openshift-apiserver for the
95+
// openshift-apiserver-operator), is functional and available in the cluster.
96+
OperatorAvailable ClusterStatusConditionType = "Available"
97+
98+
// OperatorProgressing indicates that the operator is actively making changes to the binary maintained by the
99+
// operator (eg: openshift-apiserver for the openshift-apiserver-operator).
100+
OperatorProgressing ClusterStatusConditionType = "Progressing"
101+
102+
// OperatorFailing indicates that the operator has encountered an error that is preventing it from working properly.
103+
// The binary maintained by the operator (eg: openshift-apiserver for the openshift-apiserver-operator) may still be
104+
// available, but the user intent cannot be fulfilled.
105+
OperatorFailing ClusterStatusConditionType = "Failing"
76106
)

0 commit comments

Comments
 (0)