-
Notifications
You must be signed in to change notification settings - Fork 170
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add status conditions to operator MachineSet controller (#2899)
* Add status conditions to operator MachineSet controller * Use base ARO GetCluster method for retrieving cluster resource in derived controllers * Add helper functions for status * Refactor operator controller conditions tests to use shared default conditions
- Loading branch information
Showing
10 changed files
with
486 additions
and
497 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package base | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
import ( | ||
"context" | ||
|
||
operatorv1 "github.com/openshift/api/operator/v1" | ||
"github.com/openshift/library-go/pkg/operator/v1helpers" | ||
"github.com/sirupsen/logrus" | ||
"k8s.io/apimachinery/pkg/api/equality" | ||
"k8s.io/apimachinery/pkg/types" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1" | ||
) | ||
|
||
type AROController struct { | ||
Log *logrus.Entry | ||
Client client.Client | ||
Name string | ||
} | ||
|
||
func (c *AROController) SetConditions(ctx context.Context, cnds ...*operatorv1.OperatorCondition) { | ||
cluster, err := c.GetCluster(ctx) | ||
if err != nil { | ||
c.Log.Warn("Failed to retrieve ARO cluster resource") | ||
return | ||
} | ||
|
||
newConditions := cluster.Status.DeepCopy().Conditions | ||
for _, cnd := range cnds { | ||
v1helpers.SetOperatorCondition(&newConditions, *cnd) | ||
} | ||
|
||
if equality.Semantic.DeepEqual(cluster.Status.Conditions, newConditions) { | ||
return | ||
} | ||
|
||
cluster.Status.Conditions = newConditions | ||
if err := c.Client.Status().Update(ctx, cluster); err != nil { | ||
c.Log.Error("error updating controller conditions", err) | ||
} | ||
} | ||
|
||
func (c *AROController) SetProgressing(ctx context.Context, message string) { | ||
cnd := c.defaultProgressing() | ||
cnd.Status = operatorv1.ConditionTrue | ||
cnd.Message = message | ||
|
||
c.SetConditions(ctx, cnd) | ||
} | ||
|
||
func (c *AROController) ClearProgressing(ctx context.Context) { | ||
c.SetConditions(ctx, c.defaultProgressing()) | ||
} | ||
|
||
func (c *AROController) SetDegraded(ctx context.Context, err error) { | ||
cnd := c.defaultDegraded() | ||
cnd.Status = operatorv1.ConditionTrue | ||
cnd.Message = err.Error() | ||
|
||
c.SetConditions(ctx, cnd) | ||
} | ||
|
||
func (c *AROController) ClearDegraded(ctx context.Context) { | ||
c.SetConditions(ctx, c.defaultDegraded()) | ||
} | ||
|
||
func (c *AROController) ClearConditions(ctx context.Context) { | ||
c.SetConditions(ctx, c.defaultAvailable(), c.defaultProgressing(), c.defaultDegraded()) | ||
} | ||
|
||
func (c *AROController) GetCluster(ctx context.Context) (*arov1alpha1.Cluster, error) { | ||
cluster := &arov1alpha1.Cluster{} | ||
err := c.Client.Get(ctx, types.NamespacedName{Name: arov1alpha1.SingletonClusterName}, cluster) | ||
|
||
return cluster, err | ||
} | ||
|
||
func (c *AROController) defaultAvailable() *operatorv1.OperatorCondition { | ||
return &operatorv1.OperatorCondition{ | ||
Type: c.conditionName(operatorv1.OperatorStatusTypeAvailable), | ||
Status: operatorv1.ConditionTrue, | ||
} | ||
} | ||
|
||
func (c *AROController) defaultProgressing() *operatorv1.OperatorCondition { | ||
return &operatorv1.OperatorCondition{ | ||
Type: c.conditionName(operatorv1.OperatorStatusTypeProgressing), | ||
Status: operatorv1.ConditionFalse, | ||
} | ||
} | ||
|
||
func (c *AROController) defaultDegraded() *operatorv1.OperatorCondition { | ||
return &operatorv1.OperatorCondition{ | ||
Type: c.conditionName(operatorv1.OperatorStatusTypeDegraded), | ||
Status: operatorv1.ConditionFalse, | ||
} | ||
} | ||
|
||
func (c *AROController) conditionName(conditionType string) string { | ||
return c.Name + "Controller" + conditionType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package base | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"testing" | ||
"time" | ||
|
||
operatorv1 "github.com/openshift/api/operator/v1" | ||
"github.com/sirupsen/logrus" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
ctrlfake "sigs.k8s.io/controller-runtime/pkg/client/fake" | ||
|
||
arov1alpha1 "github.com/Azure/ARO-RP/pkg/operator/apis/aro.openshift.io/v1alpha1" | ||
_ "github.com/Azure/ARO-RP/pkg/util/scheme" | ||
utilconditions "github.com/Azure/ARO-RP/test/util/conditions" | ||
) | ||
|
||
func TestConditions(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
controllerName := "Fake" | ||
|
||
now := metav1.NewTime(time.Now()) | ||
past := metav1.NewTime(now.Add(-1 * time.Hour)) | ||
|
||
internetReachable := operatorv1.OperatorCondition{ | ||
Type: arov1alpha1.InternetReachableFromMaster, | ||
Status: operatorv1.ConditionFalse, | ||
LastTransitionTime: now, | ||
} | ||
|
||
defaultAvailable := utilconditions.ControllerDefaultAvailable(controllerName) | ||
defaultProgressing := utilconditions.ControllerDefaultProgressing(controllerName) | ||
defaultDegraded := utilconditions.ControllerDefaultDegraded(controllerName) | ||
|
||
defaultAvailableInPast := *defaultAvailable.DeepCopy() | ||
defaultAvailableInPast.LastTransitionTime = past | ||
|
||
unavailable := *defaultAvailable.DeepCopy() | ||
unavailable.Status = operatorv1.ConditionFalse | ||
unavailable.Message = "Something bad happened" | ||
|
||
isProgressing := *defaultProgressing.DeepCopy() | ||
isProgressing.Status = operatorv1.ConditionTrue | ||
isProgressing.Message = "Controller is performing task" | ||
|
||
isDegraded := *defaultDegraded.DeepCopy() | ||
isDegraded.Status = operatorv1.ConditionTrue | ||
isDegraded.Message = "Controller failed to perform task" | ||
|
||
for _, tt := range []struct { | ||
name string | ||
start []operatorv1.OperatorCondition | ||
action func(c AROController) | ||
want []operatorv1.OperatorCondition | ||
}{ | ||
{ | ||
name: "SetConditions - sets all provided conditions", | ||
start: []operatorv1.OperatorCondition{internetReachable}, | ||
action: func(c AROController) { | ||
c.SetConditions(ctx, &defaultAvailable, &defaultProgressing, &defaultDegraded) | ||
}, | ||
want: []operatorv1.OperatorCondition{internetReachable, defaultAvailable, defaultProgressing, defaultDegraded}, | ||
}, | ||
{ | ||
name: "SetConditions - if condition exists and status matches, does not update", | ||
start: []operatorv1.OperatorCondition{internetReachable, defaultAvailableInPast}, | ||
action: func(c AROController) { | ||
c.SetConditions(ctx, &defaultAvailable, &defaultProgressing, &defaultDegraded) | ||
}, | ||
want: []operatorv1.OperatorCondition{internetReachable, defaultAvailableInPast, defaultProgressing, defaultDegraded}, | ||
}, | ||
{ | ||
name: "SetConditions - if condition exists and status does not match, updates", | ||
start: []operatorv1.OperatorCondition{internetReachable, defaultAvailableInPast}, | ||
action: func(c AROController) { | ||
c.SetConditions(ctx, &unavailable, &defaultProgressing, &defaultDegraded) | ||
}, | ||
want: []operatorv1.OperatorCondition{internetReachable, unavailable, defaultProgressing, defaultDegraded}, | ||
}, | ||
{ | ||
name: "SetProgressing - sets Progressing to true with message", | ||
start: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, defaultDegraded}, | ||
action: func(c AROController) { | ||
c.SetProgressing(ctx, isProgressing.Message) | ||
}, | ||
want: []operatorv1.OperatorCondition{defaultAvailable, isProgressing, defaultDegraded}, | ||
}, | ||
{ | ||
name: "ClearProgressing - sets Progressing to false and clears message", | ||
start: []operatorv1.OperatorCondition{defaultAvailable, isProgressing, defaultDegraded}, | ||
action: func(c AROController) { | ||
c.ClearProgressing(ctx) | ||
}, | ||
want: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, defaultDegraded}, | ||
}, | ||
{ | ||
name: "SetDegraded - sets Degraded to true with message", | ||
start: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, defaultDegraded}, | ||
action: func(c AROController) { | ||
err := errors.New(isDegraded.Message) | ||
c.SetDegraded(ctx, err) | ||
}, | ||
want: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, isDegraded}, | ||
}, | ||
{ | ||
name: "ClearDegraded - sets Degraded to false and clears message", | ||
start: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, isDegraded}, | ||
action: func(c AROController) { | ||
c.ClearDegraded(ctx) | ||
}, | ||
want: []operatorv1.OperatorCondition{defaultAvailable, defaultProgressing, defaultDegraded}, | ||
}, | ||
} { | ||
t.Run(tt.name, func(t *testing.T) { | ||
client := ctrlfake.NewClientBuilder(). | ||
WithObjects( | ||
&arov1alpha1.Cluster{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: arov1alpha1.SingletonClusterName, | ||
}, | ||
Status: arov1alpha1.ClusterStatus{ | ||
Conditions: tt.start, | ||
OperatorVersion: "unknown", | ||
}, | ||
}, | ||
).Build() | ||
|
||
controller := AROController{ | ||
Log: logrus.NewEntry(logrus.StandardLogger()), | ||
Client: client, | ||
Name: controllerName, | ||
} | ||
|
||
tt.action(controller) | ||
utilconditions.AssertControllerConditions(t, ctx, client, tt.want) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.