Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions manifests/02-rbac-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ rules:
resources:
- consoles
- consoles/status
- clusteroperators
- clusteroperators/status
verbs:
- get
- list
Expand All @@ -138,6 +140,7 @@ rules:
- operator.openshift.io
resources:
- consoles
- consoles/status
verbs:
- get
- list
Expand Down
5 changes: 5 additions & 0 deletions manifests/05-clusteroperator.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
apiVersion: config.openshift.io/v1
kind: ClusterOperator
metadata:
name: console
spec: {}
27 changes: 11 additions & 16 deletions pkg/console/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"fmt"
"time"

// 3rd party
"github.com/sirupsen/logrus"

// kube

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
Expand Down Expand Up @@ -47,7 +47,8 @@ import (
)

const (
controllerName = "Console"
controllerName = "Console"
workloadFailingCondition = "WorkloadFailing"
)

var CreateDefaultConsoleFlag bool
Expand Down Expand Up @@ -148,43 +149,37 @@ func (c *consoleOperator) Sync(obj metav1.Object) error {
}

if err := c.handleSync(operatorConfig, consoleConfig); err != nil {
c.SyncStatus(c.ConditionFailing(operatorConfig, "SyncLoopError", "Operator sync loop failed to completele."))
return err
}
c.SyncStatus(c.ConditionNotFailing(operatorConfig))
return nil
}

func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consoleConfig *configv1.Console) error {
func (c *consoleOperator) handleSync(originalOperatorConfig *operatorsv1.Console, consoleConfig *configv1.Console) error {

operatorConfig := originalOperatorConfig.DeepCopy()
switch operatorConfig.Spec.ManagementState {
case operatorsv1.Managed:
logrus.Println("console is in a managed state.")
// handled below
case operatorsv1.Unmanaged:
logrus.Println("console is in an unmanaged state.")
c.SyncStatus(c.ConditionsManagementStateUnmanaged(operatorConfig))
return nil
case operatorsv1.Removed:
logrus.Println("console has been removed.")
c.SyncStatus(c.ConditionsManagementStateRemoved(operatorConfig))
return c.deleteAllResources(operatorConfig)
default:
// TODO should update status
return fmt.Errorf("unknown state: %v", operatorConfig.Spec.ManagementState)
}

// do we need the if(configChanged) update bits?
operatorConfigOut, consoleConfigOut, configChanged, err := sync_v400(c, operatorConfig, consoleConfig)
_, _, _, err := sync_v400(c, operatorConfig, consoleConfig)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't notice this change, I need to look into it a bit.

if err != nil {
return err
}
// TODO: these should probably be handled separately
if configChanged {
// TODO: this should do better apply logic or similar, maybe use SetStatusFromAvailability
if _, err = c.operatorConfigClient.Update(operatorConfigOut); err != nil {
return err
}

if _, err = c.consoleConfigClient.Update(consoleConfigOut); err != nil {
return err
}
}
return nil
}

Expand Down
257 changes: 257 additions & 0 deletions pkg/console/operator/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package operator
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are pretty verbose / repetitive.


import (
"fmt"

"github.com/sirupsen/logrus"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

operatorsv1 "github.com/openshift/api/operator/v1"
"github.com/openshift/library-go/pkg/operator/v1helpers"
)

// Operator status is set on the Operator Config, which is:
// group: console.operator.openshift.io
// kind: Console
// name: console
// And is replicated out onto the the clusteroperator by a separate sync loop:
// group: config.openshift.io
// kind: ClusterOperator
// name: console
//
// Status Condition Types
// Status conditions should not be set to a "default" state when the operator starts up.
// Instead, set a status explicitly only when the state is known. This is because
// the various status conditions may have been set on previous runs of the sync loop, or
// possibly even by a previous operator container.
//
// Available = the operand (not the operator) is available
// example: the console resources are stabilized.
// example: the console is not yet in a functional state, one or
// more resources may be missing.
// Progressing = the operator is trying to transition operand state
// example: during the initial deployment, the operator needs to create a number
// of resources. the console (operand) is likely in flux.
// example: the assigned route .spec.host changes for the console. the oauthclient
// must be updated, as must the configmap, etc. numerous resources are in flux,
// the operator reports progressing until the resources stabilize
// Failing = the operator (not the operand) is failing
// example: The console operator is unable to update the console config with
// a new logoutRedirect URL. The operator is failing to do its job, however the
// console (operand) may or may not be functional (see Available above).
//
//
// Status Condition Reason & Message
// Reason: OperatorSyncLoopError
// Message: "The operator sync loop was not completed successfully"
//
//

// Lets transition to using this, and get the repetition out of all of the above.
func (c *consoleOperator) SyncStatus(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) {
updatedConfig, err := c.operatorConfigClient.UpdateStatus(operatorConfig)
if err != nil {
return nil, fmt.Errorf("status update error: %v \n", err)
}
return updatedConfig, nil
}

// setStatusCondition
// A generic helper for setting a status condition
// examples:
// setStatusCondition(operatorConfig, Failing, True, "SyncLoopError", "Sync loop failed to complete successfully")
func (c *consoleOperator) SetStatusCondition(operatorConfig *operatorsv1.Console, conditionType string, conditionStatus operatorsv1.ConditionStatus, conditionReason string, conditionMessage string) *operatorsv1.Console {
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: conditionType,
Status: conditionStatus,
Reason: conditionReason,
Message: conditionMessage,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

// examples:
// conditionFailing(operatorConfig, "SyncLoopError", "Sync loop failed to complete successfully")
func (c *consoleOperator) ConditionFailing(operatorConfig *operatorsv1.Console, conditionReason string, conditionMessage string) *operatorsv1.Console {
fmt.Printf(
"Status: %s %s %s %s %s",
operatorsv1.OperatorStatusTypeFailing,
operatorsv1.ConditionTrue,
conditionReason,
conditionMessage,
metav1.Now())
// conditionReason string, conditionMessage string
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionTrue,
Reason: conditionReason,
Message: conditionMessage,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionNotFailing(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionFalse,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionProgressing() {
// TODO: if progressing, we are saying something is moving and we need to report why.
}
func (c *consoleOperator) ConditionNotProgressing(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeProgressing,
Status: operatorsv1.ConditionFalse,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionAvailable(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeAvailable,
Status: operatorsv1.ConditionTrue,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionNotAvailable(operatorConfig *operatorsv1.Console) {
// TODO: if not available, something with the operand is wrong asd we need to report why
}

// A sync failure has happened.
// We dont necessarily know the condition of the operand (console),
// but we do know that the operator is failing to update the operand.
func (c *consoleOperator) ConditionResourceSyncFailure(operatorConfig *operatorsv1.Console, message string) *operatorsv1.Console {
logrus.Printf("Status: Workload sync failure: %v \n", message)
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionTrue,
Message: message,
Reason: "SyncError",
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionResourceSyncSuccess(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
logrus.Printf("Status: Workload sync success: \n")
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionFalse,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionDeploymentAvailable(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
logrus.Printf("Status: Available: console pods available \n")
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeAvailable,
Status: operatorsv1.ConditionTrue,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionDeploymentNotAvailable(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
reason := "NoPodsAvailable"
message := "No pods available for Console deployment."
logrus.Printf("Status: Not Available: %v \n", message)
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeAvailable,
Status: operatorsv1.ConditionFalse,
Reason: reason,
Message: message,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionResourceSyncProgressing(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
reason := "SyncLoopProgressing"
message := "Changes made during sync updates, additional sync expected."
logrus.Printf("Status: Progressing: %v \n", message)
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeProgressing,
Status: operatorsv1.ConditionTrue,
Reason: reason,
Message: message,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

func (c *consoleOperator) ConditionResourceSyncNotProgressing(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
logrus.Printf("Status: Not Progressing: Sync success \n")
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeProgressing,
Status: operatorsv1.ConditionFalse,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

// sets multiple conditions
func (c *consoleOperator) ConditionsManagementStateUnmanaged(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
logrus.Printf("Status: ManagementState: Removed. Conditions unknown.")
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeAvailable,
Status: operatorsv1.ConditionUnknown,
Reason: "ManagementStateUnmanaged",
Message: "the operator is in an unmanaged state, therefore its availability is unknown.",
LastTransitionTime: metav1.Now(),
})
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeProgressing,
Status: operatorsv1.ConditionFalse,
Reason: "ManagementStateUnmanaged",
Message: "the operator is in an unmanaged state, therefore no changes are being applied.",
LastTransitionTime: metav1.Now(),
})
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionFalse,
Reason: "ManagementStateUnmanaged",
Message: "the operator is in an unmanaged state, therefore no operator actions are failing.",
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}

// sets multiple conditions
func (c *consoleOperator) ConditionsManagementStateRemoved(operatorConfig *operatorsv1.Console) *operatorsv1.Console {
logrus.Printf("Status: ManagementState: Removed")
reason := "ManagementStateRemoved"
message := "The console has been removed."
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeAvailable,
Status: operatorsv1.ConditionFalse,
Reason: reason,
Message: message,
LastTransitionTime: metav1.Now(),
})
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeProgressing,
Status: operatorsv1.ConditionFalse,
Reason: reason,
Message: message,
LastTransitionTime: metav1.Now(),
})
v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{
Type: operatorsv1.OperatorStatusTypeFailing,
Status: operatorsv1.ConditionFalse,
Reason: reason,
Message: message,
LastTransitionTime: metav1.Now(),
})
return operatorConfig
}
Loading