From 62e1e494fe341a7cc718125bd980017c2d8c35a4 Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 7 Feb 2019 13:38:35 -0500 Subject: [PATCH 01/11] Operator status --- manifests/02-rbac-role.yaml | 3 + manifests/05-clusteroperator.yaml | 5 + pkg/console/operator/operator.go | 50 +++++++- pkg/console/operator/sync_v400.go | 128 ++++++++++++++----- pkg/console/operatorclient/operatorclient.go | 61 +++++++++ pkg/console/starter/starter.go | 59 ++++----- 6 files changed, 241 insertions(+), 65 deletions(-) create mode 100644 manifests/05-clusteroperator.yaml create mode 100644 pkg/console/operatorclient/operatorclient.go diff --git a/manifests/02-rbac-role.yaml b/manifests/02-rbac-role.yaml index b7141eb93..1495364a5 100644 --- a/manifests/02-rbac-role.yaml +++ b/manifests/02-rbac-role.yaml @@ -127,6 +127,8 @@ rules: resources: - consoles - consoles/status + - clusteroperators + - clusteroperators/status verbs: - get - list @@ -138,6 +140,7 @@ rules: - operator.openshift.io resources: - consoles + - consoles/status verbs: - get - list diff --git a/manifests/05-clusteroperator.yaml b/manifests/05-clusteroperator.yaml new file mode 100644 index 000000000..64ffae057 --- /dev/null +++ b/manifests/05-clusteroperator.yaml @@ -0,0 +1,5 @@ +apiVersion: config.openshift.io/v1 +kind: ClusterOperator +metadata: + name: console +spec: {} diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 68d72f633..0862eef5a 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -6,9 +6,11 @@ import ( "time" // 3rd party + "github.com/golang/glog" "github.com/sirupsen/logrus" // kube + "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -25,6 +27,7 @@ import ( "github.com/openshift/console-operator/pkg/api" "github.com/openshift/console-operator/pkg/boilerplate/operator" "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/v1helpers" // informers configinformerv1 "github.com/openshift/client-go/config/informers/externalversions/config/v1" @@ -47,7 +50,8 @@ import ( ) const ( - controllerName = "Console" + controllerName = "Console" + workloadFailingCondition = "WorkloadFailing" ) var CreateDefaultConsoleFlag bool @@ -148,18 +152,62 @@ func (c *consoleOperator) Sync(obj metav1.Object) error { } if err := c.handleSync(operatorConfig, consoleConfig); err != nil { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeFailing, + Status: operatorsv1.ConditionTrue, + Reason: "OperatorSyncLoopError", + Message: err.Error(), + LastTransitionTime: metav1.Now(), + }) + if _, updateErr := c.operatorConfigClient.UpdateStatus(operatorConfig); updateErr != nil { + glog.Errorf("error updating status: %s", err) + } return err } + + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeAvailable, + Status: operatorsv1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) return nil } func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consoleConfig *configv1.Console) error { + + originalOperatorConfig := operatorConfig.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.") + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeAvailable, + Status: operatorsv1.ConditionUnknown, + Reason: "Unmanaged", + Message: "the controller manager 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: "Unmanaged", + Message: "the controller manager 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: "Unmanaged", + Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", + LastTransitionTime: metav1.Now(), + }) + if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return err + } + } return nil case operatorsv1.Removed: logrus.Println("console has been removed.") diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 833c6e425..70c377305 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -15,6 +15,7 @@ import ( routev1 "github.com/openshift/api/route/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -25,6 +26,7 @@ import ( "github.com/openshift/library-go/pkg/operator/events" "github.com/openshift/library-go/pkg/operator/resource/resourceapply" "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" + "github.com/openshift/library-go/pkg/operator/v1helpers" // operator configmapsub "github.com/openshift/console-operator/pkg/console/subresource/configmap" @@ -41,58 +43,121 @@ import ( // This ensures the logic is simpler as we do not have to handle coordination between objects within // the loop. func sync_v400(co *consoleOperator, operatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (*operatorv1.Console, *configv1.Console, bool, error) { + errors := []error{} + originalOperatorConfig := operatorConfig.DeepCopy() logrus.Println("running sync loop 4.0.0") recorder := co.recorder // track changes, may trigger ripples & update operator config or console config status toUpdate := false - rt, rtChanged, rtErr := SyncRoute(co, operatorConfig) - if rtErr != nil { - return operatorConfig, consoleConfig, toUpdate, rtErr + rt, rtChanged, err := SyncRoute(co, operatorConfig) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "route", err)) } toUpdate = toUpdate || rtChanged - _, svcChanged, svcErr := SyncService(co, recorder, operatorConfig) - if svcErr != nil { - return operatorConfig, consoleConfig, toUpdate, svcErr + _, svcChanged, err := SyncService(co, recorder, operatorConfig) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "service", err)) } toUpdate = toUpdate || svcChanged - cm, cmChanged, cmErr := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) - if cmErr != nil { - return operatorConfig, consoleConfig, toUpdate, cmErr + cm, cmChanged, err := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "configmap", err)) } toUpdate = toUpdate || cmChanged - serviceCAConfigMap, serviceCAConfigMapChanged, serviceCAConfigMapErr := SyncServiceCAConfigMap(co, operatorConfig) - if serviceCAConfigMapErr != nil { - return operatorConfig, consoleConfig, toUpdate, serviceCAConfigMapErr + serviceCAConfigMap, serviceCAConfigMapChanged, err := SyncServiceCAConfigMap(co, operatorConfig) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "serviceCAconfigmap", err)) } toUpdate = toUpdate || serviceCAConfigMapChanged - sec, secChanged, secErr := SyncSecret(co, recorder, operatorConfig) - if secErr != nil { - return operatorConfig, consoleConfig, toUpdate, secErr + sec, secChanged, err := SyncSecret(co, recorder, operatorConfig) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "secret", err)) } toUpdate = toUpdate || secChanged - _, oauthChanged, oauthErr := SyncOAuthClient(co, operatorConfig, sec, rt) - if oauthErr != nil { - return operatorConfig, consoleConfig, toUpdate, oauthErr + _, oauthChanged, err := SyncOAuthClient(co, operatorConfig, sec, rt) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "oauth", err)) } toUpdate = toUpdate || oauthChanged - _, depChanged, depErr := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) - if depErr != nil { - return operatorConfig, consoleConfig, toUpdate, depErr + actualDeployment, depChanged, err := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "deployment", err)) } toUpdate = toUpdate || depChanged + if actualDeployment.Status.ReadyReplicas > 0 { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeAvailable, + Status: operatorv1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) + } else { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeAvailable, + Status: operatorv1.ConditionFalse, + Reason: "NoPodsAvailable", + Message: "NoDeploymentPodsAvailableOnAnyNode.", + LastTransitionTime: metav1.Now(), + }) + } + + if len(errors) > 0 { + message := "" + for _, err := range errors { + message = message + err.Error() + "\n" + } + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionTrue, + Message: message, + Reason: "SyncError", + LastTransitionTime: metav1.Now(), + }) + } else { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionFalse, + }) + } + logrus.Println("sync_v400: updating console status") - if updatedConfig, err := SyncConsoleConfig(co, consoleConfig, rt); err != nil { - logrus.Errorf("Could not update console config status: %v \n", err) - return operatorConfig, updatedConfig, toUpdate, err + _, consoleConfigChanged, err := SyncConsoleConfig(co, consoleConfig, rt) + if err != nil { + errors = append(errors, fmt.Errorf("%q: %v", "consoleConfig", err)) + // logrus.Errorf("Could not update console config status: %v \n", err) + // return operatorConfig, updatedConfig, toUpdate, err + } + toUpdate = toUpdate || consoleConfigChanged + + if toUpdate { + logrus.Infof("sync_v400: to update spec: %v", toUpdate) + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionTrue, + Reason: "DesiredStateNotYetAchieved", + LastTransitionTime: metav1.Now(), + }) + } else { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionFalse, + }) + } + + if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { + if _, err := co.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + // we should be returning error only if status update fails, since sync errors + // should be reported as part of the status update. + return operatorConfig, consoleConfig, toUpdate, err + } } defer func() { @@ -105,16 +170,17 @@ func sync_v400(co *consoleOperator, operatorConfig *operatorv1.Console, consoleC logrus.Printf("\t deployment changed: %v", depChanged) }() - // at this point there should be no existing errors, we survived the sync loop - // pass back config (updated), and bool indicating change happened so we can update - // the cluster operator status return operatorConfig, consoleConfig, toUpdate, nil } -func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, error) { - logrus.Printf("Updating console.config.openshift.io with hostname: %v \n", route.Spec.Host) - consoleConfig.Status.PublicHostname = util.HTTPS(route.Spec.Host) - return co.consoleConfigClient.UpdateStatus(consoleConfig) +func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, bool, error) { + if consoleConfig.Status.PublicHostname != route.Spec.Host { + logrus.Printf("Updating console.config.openshift.io with hostname: %v \n", route.Spec.Host) + consoleConfig.Status.PublicHostname = util.HTTPS(route.Spec.Host) + updatedConsoleConfig, err := co.consoleConfigClient.UpdateStatus(consoleConfig) + return updatedConsoleConfig, true, err + } + return consoleConfig, false, nil } func SyncDeployment(co *consoleOperator, recorder events.Recorder, operatorConfig *operatorv1.Console, cm *corev1.ConfigMap, serviceCAConfigMap *corev1.ConfigMap, sec *corev1.Secret) (*appsv1.Deployment, bool, error) { diff --git a/pkg/console/operatorclient/operatorclient.go b/pkg/console/operatorclient/operatorclient.go new file mode 100644 index 000000000..79fb1865a --- /dev/null +++ b/pkg/console/operatorclient/operatorclient.go @@ -0,0 +1,61 @@ +package operatorclient + +import ( + "k8s.io/client-go/tools/cache" + + operatorv1 "github.com/openshift/api/operator/v1" + operatorv1client "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1" + operatorv1informers "github.com/openshift/client-go/operator/informers/externalversions" + "github.com/openshift/console-operator/pkg/api" +) + +type OperatorClient struct { + Informers operatorv1informers.SharedInformerFactory + Client operatorv1client.ConsolesGetter +} + +func (c *OperatorClient) Informer() cache.SharedIndexInformer { + return c.Informers.Operator().V1().Consoles().Informer() +} + +func (c *OperatorClient) GetOperatorState() (*operatorv1.OperatorSpec, *operatorv1.OperatorStatus, string, error) { + instance, err := c.Informers.Operator().V1().Consoles().Lister().Get(api.ConfigResourceName) + if err != nil { + return nil, nil, "", err + } + + return &instance.Spec.OperatorSpec, &instance.Status.OperatorStatus, instance.ResourceVersion, nil +} + +func (c *OperatorClient) UpdateOperatorSpec(resourceVersion string, spec *operatorv1.OperatorSpec) (*operatorv1.OperatorSpec, string, error) { + original, err := c.Informers.Operator().V1().Consoles().Lister().Get(api.ConfigResourceName) + if err != nil { + return nil, "", err + } + copy := original.DeepCopy() + copy.ResourceVersion = resourceVersion + copy.Spec.OperatorSpec = *spec + + ret, err := c.Client.Consoles().Update(copy) + if err != nil { + return nil, "", err + } + + return &ret.Spec.OperatorSpec, ret.ResourceVersion, nil +} +func (c *OperatorClient) UpdateOperatorStatus(resourceVersion string, status *operatorv1.OperatorStatus) (*operatorv1.OperatorStatus, error) { + original, err := c.Informers.Operator().V1().Consoles().Lister().Get(api.ConfigResourceName) + if err != nil { + return nil, err + } + copy := original.DeepCopy() + copy.ResourceVersion = resourceVersion + copy.Status.OperatorStatus = *status + + ret, err := c.Client.Consoles().UpdateStatus(copy) + if err != nil { + return nil, err + } + + return &ret.Status.OperatorStatus, nil +} diff --git a/pkg/console/starter/starter.go b/pkg/console/starter/starter.go index 4260b3742..5b7f4c3d5 100644 --- a/pkg/console/starter/starter.go +++ b/pkg/console/starter/starter.go @@ -13,8 +13,11 @@ import ( "k8s.io/client-go/kubernetes" // openshift + configv1 "github.com/openshift/api/config/v1" "github.com/openshift/console-operator/pkg/api" + operatorclient "github.com/openshift/console-operator/pkg/console/operatorclient" "github.com/openshift/library-go/pkg/controller/controllercmd" + "github.com/openshift/library-go/pkg/operator/status" // clients configclient "github.com/openshift/client-go/config/clientset/versioned" @@ -23,7 +26,7 @@ import ( authclient "github.com/openshift/client-go/oauth/clientset/versioned" oauthinformers "github.com/openshift/client-go/oauth/informers/externalversions" - operatorclient "github.com/openshift/client-go/operator/clientset/versioned" + operatorversionedclient "github.com/openshift/client-go/operator/clientset/versioned" operatorinformers "github.com/openshift/client-go/operator/informers/externalversions" routesclient "github.com/openshift/client-go/route/clientset/versioned" @@ -50,7 +53,7 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { return err } - consoleOperatorConfigClient, err := operatorclient.NewForConfig(ctx.KubeConfig) + consoleOperatorConfigClient, err := operatorversionedclient.NewForConfig(ctx.KubeConfig) if err != nil { return err } @@ -115,6 +118,11 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { // TODO: Replace this with real event recorder (use ControllerContext). recorder := ctx.EventRecorder + operatorClient := &operatorclient.OperatorClient{ + Informers: consoleOperatorConfigInformers, + Client: consoleOperatorConfigClient.OperatorV1(), + } + // TODO: rearrange these into informer,client pairs, NOT separated. consoleOperator := operator.NewConsoleOperator( // informers @@ -136,6 +144,21 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { recorder, ) + clusterOperatorStatus := status.NewClusterOperatorStatusController( + "console", + []configv1.ObjectReference{ + {Group: "operator.openshift.io", Resource: "consoles", Name: api.OpenShiftConsoleName}, + {Group: "config.openshift.io", Resource: "consoles", Name: api.OpenShiftConsoleName}, + {Group: "oauth.openshift.io", Resource: "oauthclients", Name: api.OAuthClientName}, + {Resource: "namespaces", Name: api.OpenShiftConsoleOperatorNamespace}, + {Resource: "namespaces", Name: api.OpenShiftConsoleNamespace}, + }, + consoleConfigClient.ConfigV1(), + operatorClient, + status.NewVersionGetter(), + ctx.EventRecorder, + ) + kubeInformersNamespaced.Start(ctx.Context.Done()) consoleOperatorConfigInformers.Start(ctx.Context.Done()) consoleConfigInformers.Start(ctx.Context.Done()) @@ -143,39 +166,9 @@ func RunOperator(ctx *controllercmd.ControllerContext) error { oauthInformers.Start(ctx.Context.Done()) go consoleOperator.Run(ctx.Context.Done()) - - // TODO: turn this back on! - // for now its just creating noise.... as we need to update library-go for it to work correctly - // our version of library-go has the old group - //clusterOperatorStatus := status.NewClusterOperatorStatusController( - // controller.TargetNamespace, - // controller.ConfigResourceName, - // // no idea why this is dynamic & not a strongly typed client. - // dynamicClient, - // &operatorStatusProvider{informers: consoleOperatorInformers}, - //) - //// TODO: will have a series of Run() funcs here - //go clusterOperatorStatus.Run(1, stopCh) + go clusterOperatorStatus.Run(1, ctx.Context.Done()) <-ctx.Context.Done() return fmt.Errorf("stopped") } - -// I'd prefer this in a /console/status/ package, but other operators keep it here. -//type operatorStatusProvider struct { -// informers externalversions.SharedInformerFactory -//} -// -//func (p *operatorStatusProvider) Informer() cache.SharedIndexInformer { -// return p.informers.Console().V1().Consoles().Informer() -//} -// -//func (p *operatorStatusProvider) CurrentStatus() (operatorv1.OperatorStatus, error) { -// instance, err := p.informers.Console().V1().Consoles().Lister().Consoles(api.TargetNamespace).Get(api.ConfigResourceName) -// if err != nil { -// return operatorv1.OperatorStatus{}, err -// } -// -// return instance.Status.OperatorStatus, nil -//} From 59396924e4f78d0de36ad24ff104ec630311b437 Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 14 Feb 2019 01:34:07 +0100 Subject: [PATCH 02/11] remove race --- pkg/console/operator/operator.go | 14 +------------- pkg/console/operator/sync_v400.go | 8 ++++---- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 0862eef5a..03fe854ee 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -217,22 +217,10 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol 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) 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 } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 70c377305..6625daee3 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -42,9 +42,9 @@ import ( // The next loop will pick up where they previous left off and move the process forward one step. // This ensures the logic is simpler as we do not have to handle coordination between objects within // the loop. -func sync_v400(co *consoleOperator, operatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (*operatorv1.Console, *configv1.Console, bool, error) { +func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (bool, error) { errors := []error{} - originalOperatorConfig := operatorConfig.DeepCopy() + operatorConfig := originalOperatorConfig.DeepCopy() logrus.Println("running sync loop 4.0.0") recorder := co.recorder @@ -156,7 +156,7 @@ func sync_v400(co *consoleOperator, operatorConfig *operatorv1.Console, consoleC if _, err := co.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { // we should be returning error only if status update fails, since sync errors // should be reported as part of the status update. - return operatorConfig, consoleConfig, toUpdate, err + return toUpdate, err } } @@ -170,7 +170,7 @@ func sync_v400(co *consoleOperator, operatorConfig *operatorv1.Console, consoleC logrus.Printf("\t deployment changed: %v", depChanged) }() - return operatorConfig, consoleConfig, toUpdate, nil + return toUpdate, nil } func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, bool, error) { From 29d48f51d298627724229f48ed2ec0619c072573 Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 14 Feb 2019 16:46:29 +0100 Subject: [PATCH 03/11] remove aggregation --- pkg/console/operator/operator.go | 14 ++++- pkg/console/operator/sync_v400.go | 88 ++++++++++++++++--------------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 03fe854ee..2a57b7a6e 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -217,10 +217,22 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol return fmt.Errorf("unknown state: %v", operatorConfig.Spec.ManagementState) } - _, err := sync_v400(c, operatorConfig, consoleConfig) + operatorConfigOut, consoleConfigOut, configChanged, err := sync_v400(c, operatorConfig, consoleConfig) 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 } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 6625daee3..4a7442c1f 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -42,7 +42,7 @@ import ( // The next loop will pick up where they previous left off and move the process forward one step. // This ensures the logic is simpler as we do not have to handle coordination between objects within // the loop. -func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (bool, error) { +func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (*operatorv1.Console, *configv1.Console, bool, error) { errors := []error{} operatorConfig := originalOperatorConfig.DeepCopy() logrus.Println("running sync loop 4.0.0") @@ -51,46 +51,54 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, // track changes, may trigger ripples & update operator config or console config status toUpdate := false - rt, rtChanged, err := SyncRoute(co, operatorConfig) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "route", err)) + rt, rtChanged, rtErr := SyncRoute(co, operatorConfig) + if rtErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%v: %s\n", "route", rtErr)) + return operatorConfig, consoleConfig, toUpdate, rtErr } toUpdate = toUpdate || rtChanged - _, svcChanged, err := SyncService(co, recorder, operatorConfig) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "service", err)) + _, svcChanged, svcErr := SyncService(co, recorder, operatorConfig) + if svcErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "service", svcErr)) + return operatorConfig, consoleConfig, toUpdate, svcErr } toUpdate = toUpdate || svcChanged - cm, cmChanged, err := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "configmap", err)) + cm, cmChanged, cmErr := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) + if cmErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "configmap", cmErr)) + return operatorConfig, consoleConfig, toUpdate, cmErr } toUpdate = toUpdate || cmChanged - serviceCAConfigMap, serviceCAConfigMapChanged, err := SyncServiceCAConfigMap(co, operatorConfig) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "serviceCAconfigmap", err)) + serviceCAConfigMap, serviceCAConfigMapChanged, serviceCAConfigMapErr := SyncServiceCAConfigMap(co, operatorConfig) + if serviceCAConfigMapErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "serviceCAconfigmap", serviceCAConfigMapErr)) + return operatorConfig, consoleConfig, toUpdate, serviceCAConfigMapErr } toUpdate = toUpdate || serviceCAConfigMapChanged - sec, secChanged, err := SyncSecret(co, recorder, operatorConfig) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "secret", err)) + sec, secChanged, secErr := SyncSecret(co, recorder, operatorConfig) + if secErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "secret", secErr)) + return operatorConfig, consoleConfig, toUpdate, secErr } toUpdate = toUpdate || secChanged - _, oauthChanged, err := SyncOAuthClient(co, operatorConfig, sec, rt) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "oauth", err)) + _, oauthChanged, oauthErr := SyncOAuthClient(co, operatorConfig, sec, rt) + if oauthErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "oauth", oauthErr)) + return operatorConfig, consoleConfig, toUpdate, oauthErr } toUpdate = toUpdate || oauthChanged - actualDeployment, depChanged, err := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "deployment", err)) + actualDeployment, depChanged, depErr := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) + if depErr != nil { + handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "route", depErr)) + return operatorConfig, consoleConfig, toUpdate, depErr } + toUpdate = toUpdate || depChanged if actualDeployment.Status.ReadyReplicas > 0 { @@ -109,24 +117,10 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, }) } - if len(errors) > 0 { - message := "" - for _, err := range errors { - message = message + err.Error() + "\n" - } - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionTrue, - Message: message, - Reason: "SyncError", - LastTransitionTime: metav1.Now(), - }) - } else { - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionFalse, - }) - } + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionFalse, + }) logrus.Println("sync_v400: updating console status") _, consoleConfigChanged, err := SyncConsoleConfig(co, consoleConfig, rt) @@ -156,7 +150,7 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, if _, err := co.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { // we should be returning error only if status update fails, since sync errors // should be reported as part of the status update. - return toUpdate, err + return nil, nil, toUpdate, err } } @@ -170,7 +164,17 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, logrus.Printf("\t deployment changed: %v", depChanged) }() - return toUpdate, nil + return nil, nil, toUpdate, nil +} + +func handleSyncErrorCondition(operatorConfig *operatorv1.Console, message string) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionTrue, + Message: message, + Reason: "SyncError", + LastTransitionTime: metav1.Now(), + }) } func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, bool, error) { From c98bd0a726cd0f18d16aad70964f304116324a5e Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 14 Feb 2019 17:10:42 +0100 Subject: [PATCH 04/11] 1 --- pkg/console/operator/operator.go | 22 +++++++++++----------- pkg/console/operator/sync_v400.go | 6 ++++++ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 2a57b7a6e..5ae898ec9 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -217,22 +217,22 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol return fmt.Errorf("unknown state: %v", operatorConfig.Spec.ManagementState) } - operatorConfigOut, consoleConfigOut, configChanged, err := sync_v400(c, operatorConfig, consoleConfig) + _, _, _, err := sync_v400(c, operatorConfig, consoleConfig) 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 - } - } + // 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 } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 4a7442c1f..c41ead571 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -154,6 +154,12 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, } } + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionFalse, + LastTransitionTime: metav1.Now(), + }) + defer func() { logrus.Printf("sync loop 4.0.0 complete:") logrus.Printf("\t service changed: %v", svcChanged) From 5e1f54892ed92a60c3c71291624b7af4cf66e7be Mon Sep 17 00:00:00 2001 From: Jakub Hadvig Date: Thu, 14 Feb 2019 19:10:02 +0100 Subject: [PATCH 05/11] debug --- pkg/console/operator/operator.go | 2 ++ pkg/console/operator/sync_v400.go | 28 +++++++++++++++------------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 5ae898ec9..764351bbb 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -152,6 +152,7 @@ func (c *consoleOperator) Sync(obj metav1.Object) error { } if err := c.handleSync(operatorConfig, consoleConfig); err != nil { + logrus.Println("~~~~~~~~~~~~ SYNC() - FAILING CONDITION - TRUE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeFailing, Status: operatorsv1.ConditionTrue, @@ -165,6 +166,7 @@ func (c *consoleOperator) Sync(obj metav1.Object) error { return err } + logrus.Println("~~~~~~~~~~~~ SYNC() - AVAILABLE CONDITION - TRUE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeAvailable, Status: operatorsv1.ConditionTrue, diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index c41ead571..6eca6b251 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -102,12 +102,14 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, toUpdate = toUpdate || depChanged if actualDeployment.Status.ReadyReplicas > 0 { + logrus.Println("~~~~~~~~~~~~ 400() - AVAILABLE CONDITION - TRUE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeAvailable, Status: operatorv1.ConditionTrue, LastTransitionTime: metav1.Now(), }) } else { + logrus.Println("~~~~~~~~~~~~ 400() - AVAILABLE CONDITION - FALSE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeAvailable, Status: operatorv1.ConditionFalse, @@ -117,11 +119,6 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, }) } - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionFalse, - }) - logrus.Println("sync_v400: updating console status") _, consoleConfigChanged, err := SyncConsoleConfig(co, consoleConfig, rt) if err != nil { @@ -131,8 +128,16 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, } toUpdate = toUpdate || consoleConfigChanged + logrus.Println("~~~~~~~~~~~~ 400() - FAILING CONDITION - FALSE ~~~~~~~~~~~~~") + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionFalse, + LastTransitionTime: metav1.Now(), + }) + if toUpdate { logrus.Infof("sync_v400: to update spec: %v", toUpdate) + logrus.Println("~~~~~~~~~~~~ 400() - PROGGRESSING CONDITION - TRUE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeProgressing, Status: operatorv1.ConditionTrue, @@ -140,6 +145,8 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, LastTransitionTime: metav1.Now(), }) } else { + logrus.Println("~~~~~~~~~~~~ 400() - PROGGRESSING CONDITION - FALSE ~~~~~~~~~~~~~") + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeProgressing, Status: operatorv1.ConditionFalse, @@ -150,16 +157,10 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, if _, err := co.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { // we should be returning error only if status update fails, since sync errors // should be reported as part of the status update. - return nil, nil, toUpdate, err + return operatorConfig, consoleConfig, toUpdate, err } } - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionFalse, - LastTransitionTime: metav1.Now(), - }) - defer func() { logrus.Printf("sync loop 4.0.0 complete:") logrus.Printf("\t service changed: %v", svcChanged) @@ -170,10 +171,11 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, logrus.Printf("\t deployment changed: %v", depChanged) }() - return nil, nil, toUpdate, nil + return operatorConfig, consoleConfig, toUpdate, nil } func handleSyncErrorCondition(operatorConfig *operatorv1.Console, message string) { + logrus.Println("~~~~~~~~~~~~ handleSyncErrorCondition() - FAILING CONDITION - TRUE ~~~~~~~~~~~~~") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: workloadFailingCondition, Status: operatorv1.ConditionTrue, From b8e4e185f8af10f2a51db395c5814e7fe2ee00c4 Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Thu, 14 Feb 2019 14:18:50 -0500 Subject: [PATCH 06/11] Extract setUnmanagedConditions() into separate file/func --- pkg/console/operator/operator.go | 23 ++--------------------- pkg/console/operator/status.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 pkg/console/operator/status.go diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 764351bbb..08b52af4e 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -184,27 +184,7 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol // handled below case operatorsv1.Unmanaged: logrus.Println("console is in an unmanaged state.") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ - Type: operatorsv1.OperatorStatusTypeAvailable, - Status: operatorsv1.ConditionUnknown, - Reason: "Unmanaged", - Message: "the controller manager 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: "Unmanaged", - Message: "the controller manager 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: "Unmanaged", - Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", - LastTransitionTime: metav1.Now(), - }) + setUnmanagedConditions(operatorConfig) if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { return err @@ -238,6 +218,7 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol return nil } + // this may need to move to sync_v400 if versions ever have custom delete logic func (c *consoleOperator) deleteAllResources(cr *operatorsv1.Console) error { logrus.Info("deleting console resources") diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go new file mode 100644 index 000000000..ee2f21aed --- /dev/null +++ b/pkg/console/operator/status.go @@ -0,0 +1,31 @@ +package operator + +import ( + operatorsv1 "github.com/openshift/api/operator/v1" + "github.com/openshift/library-go/pkg/operator/v1helpers" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func setUnmanagedConditions(operatorConfig *operatorsv1.Console) *operatorsv1.Console { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeAvailable, + Status: operatorsv1.ConditionUnknown, + Reason: "Unmanaged", + Message: "the controller manager 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: "Unmanaged", + Message: "the controller manager 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: "Unmanaged", + Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", + LastTransitionTime: metav1.Now(), + }) +} From b3a496e5db12081366b6ef3015233a174ba332bf Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Thu, 14 Feb 2019 14:42:12 -0500 Subject: [PATCH 07/11] f --- pkg/console/operator/status.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go index ee2f21aed..6f21483f5 100644 --- a/pkg/console/operator/status.go +++ b/pkg/console/operator/status.go @@ -28,4 +28,5 @@ func setUnmanagedConditions(operatorConfig *operatorsv1.Console) *operatorsv1.Co Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", LastTransitionTime: metav1.Now(), }) + return operatorConfig } From 9988728fc82b3141a3316f4080230675449a91c2 Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Thu, 14 Feb 2019 15:35:43 -0500 Subject: [PATCH 08/11] Extract operator status updates into separate functions --- pkg/console/operator/operator.go | 25 +----- pkg/console/operator/status.go | 139 +++++++++++++++++++++++++++++- pkg/console/operator/sync_v400.go | 119 ++++++++----------------- 3 files changed, 178 insertions(+), 105 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 08b52af4e..8588a85f9 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -5,8 +5,6 @@ import ( "fmt" "time" - // 3rd party - "github.com/golang/glog" "github.com/sirupsen/logrus" // kube @@ -27,7 +25,6 @@ import ( "github.com/openshift/console-operator/pkg/api" "github.com/openshift/console-operator/pkg/boilerplate/operator" "github.com/openshift/library-go/pkg/operator/events" - "github.com/openshift/library-go/pkg/operator/v1helpers" // informers configinformerv1 "github.com/openshift/client-go/config/informers/externalversions/config/v1" @@ -152,26 +149,11 @@ func (c *consoleOperator) Sync(obj metav1.Object) error { } if err := c.handleSync(operatorConfig, consoleConfig); err != nil { - logrus.Println("~~~~~~~~~~~~ SYNC() - FAILING CONDITION - TRUE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ - Type: operatorsv1.OperatorStatusTypeFailing, - Status: operatorsv1.ConditionTrue, - Reason: "OperatorSyncLoopError", - Message: err.Error(), - LastTransitionTime: metav1.Now(), - }) - if _, updateErr := c.operatorConfigClient.UpdateStatus(operatorConfig); updateErr != nil { - glog.Errorf("error updating status: %s", err) - } + c.operatorStatusFailingSyncLoopError(operatorConfig, err) return err } - logrus.Println("~~~~~~~~~~~~ SYNC() - AVAILABLE CONDITION - TRUE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ - Type: operatorsv1.OperatorStatusTypeAvailable, - Status: operatorsv1.ConditionTrue, - LastTransitionTime: metav1.Now(), - }) + c.operatorStatusAvailable(operatorConfig) return nil } @@ -184,7 +166,7 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol // handled below case operatorsv1.Unmanaged: logrus.Println("console is in an unmanaged state.") - setUnmanagedConditions(operatorConfig) + c.operatorStatusUnknownUnmanaged(operatorConfig) if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { return err @@ -218,7 +200,6 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol return nil } - // this may need to move to sync_v400 if versions ever have custom delete logic func (c *consoleOperator) deleteAllResources(cr *operatorsv1.Console) error { logrus.Info("deleting console resources") diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go index 6f21483f5..e3e1f21a5 100644 --- a/pkg/console/operator/status.go +++ b/pkg/console/operator/status.go @@ -1,12 +1,104 @@ package operator import ( + "fmt" + operatorsv1 "github.com/openshift/api/operator/v1" + operatorv1 "github.com/openshift/api/operator/v1" "github.com/openshift/library-go/pkg/operator/v1helpers" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -func setUnmanagedConditions(operatorConfig *operatorsv1.Console) *operatorsv1.Console { +// Condition +// Type: Available +// Status: True +// - +func (c *consoleOperator) operatorStatusAvailable(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeAvailable, + Status: operatorsv1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionTrue, + Reason: "DesiredStateNotYetAchieved", + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusNotProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeProgressing, + Status: operatorv1.ConditionFalse, + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusFailing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusNotFailing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionFalse, + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +// Condition +// Type: Failing +// Status: True +// OperatorSyncLoopError +func (c *consoleOperator) operatorStatusFailingSyncLoopError(operatorConfig *operatorsv1.Console, err error) (*operatorsv1.Console, error) { + fmt.Println("%s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ + Type: operatorsv1.OperatorStatusTypeFailing, + Status: operatorsv1.ConditionTrue, + Reason: "OperatorSyncLoopError", + Message: err.Error(), + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +// Conditions +// Type: Available +// Type: Progressing +// Type: Failing +// Status: Unknown +// - in an unmanaged state, we don't know the status of anything, the operator is effectively off +func (c *consoleOperator) operatorStatusUnknownUnmanaged(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeAvailable, Status: operatorsv1.ConditionUnknown, @@ -28,5 +120,48 @@ func setUnmanagedConditions(operatorConfig *operatorsv1.Console) *operatorsv1.Co Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", LastTransitionTime: metav1.Now(), }) - return operatorConfig + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusResourceSyncFailure(operatorConfig *operatorv1.Console, message string) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: workloadFailingCondition, + Status: operatorv1.ConditionTrue, + Message: message, + Reason: "SyncError", + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusDeploymentAvailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeAvailable, + Status: operatorv1.ConditionTrue, + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + +func (c *consoleOperator) operatorStatusDeploymentUnavailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + Type: operatorv1.OperatorStatusTypeAvailable, + Status: operatorv1.ConditionFalse, + Reason: "NoPodsAvailable", + Message: "NoDeploymentPodsAvailableOnAnyNode.", + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 6eca6b251..e141d60ec 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -15,7 +15,6 @@ import ( routev1 "github.com/openshift/api/route/v1" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/equality" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -26,7 +25,6 @@ import ( "github.com/openshift/library-go/pkg/operator/events" "github.com/openshift/library-go/pkg/operator/resource/resourceapply" "github.com/openshift/library-go/pkg/operator/resource/resourcemerge" - "github.com/openshift/library-go/pkg/operator/v1helpers" // operator configmapsub "github.com/openshift/console-operator/pkg/console/subresource/configmap" @@ -43,7 +41,6 @@ import ( // This ensures the logic is simpler as we do not have to handle coordination between objects within // the loop. func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, consoleConfig *configv1.Console) (*operatorv1.Console, *configv1.Console, bool, error) { - errors := []error{} operatorConfig := originalOperatorConfig.DeepCopy() logrus.Println("running sync loop 4.0.0") recorder := co.recorder @@ -53,112 +50,76 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, rt, rtChanged, rtErr := SyncRoute(co, operatorConfig) if rtErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%v: %s\n", "route", rtErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%v: %s\n", "route", rtErr)) return operatorConfig, consoleConfig, toUpdate, rtErr } toUpdate = toUpdate || rtChanged _, svcChanged, svcErr := SyncService(co, recorder, operatorConfig) if svcErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "service", svcErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "service", svcErr)) return operatorConfig, consoleConfig, toUpdate, svcErr } toUpdate = toUpdate || svcChanged cm, cmChanged, cmErr := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) if cmErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "configmap", cmErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "configmap", cmErr)) return operatorConfig, consoleConfig, toUpdate, cmErr } toUpdate = toUpdate || cmChanged serviceCAConfigMap, serviceCAConfigMapChanged, serviceCAConfigMapErr := SyncServiceCAConfigMap(co, operatorConfig) if serviceCAConfigMapErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "serviceCAconfigmap", serviceCAConfigMapErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "serviceCAconfigmap", serviceCAConfigMapErr)) return operatorConfig, consoleConfig, toUpdate, serviceCAConfigMapErr } toUpdate = toUpdate || serviceCAConfigMapChanged sec, secChanged, secErr := SyncSecret(co, recorder, operatorConfig) if secErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "secret", secErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "secret", secErr)) return operatorConfig, consoleConfig, toUpdate, secErr } toUpdate = toUpdate || secChanged _, oauthChanged, oauthErr := SyncOAuthClient(co, operatorConfig, sec, rt) if oauthErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "oauth", oauthErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "oauth", oauthErr)) return operatorConfig, consoleConfig, toUpdate, oauthErr } toUpdate = toUpdate || oauthChanged actualDeployment, depChanged, depErr := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) if depErr != nil { - handleSyncErrorCondition(operatorConfig, fmt.Sprintf("%q: %v\n", "route", depErr)) + co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "route", depErr)) return operatorConfig, consoleConfig, toUpdate, depErr } toUpdate = toUpdate || depChanged - if actualDeployment.Status.ReadyReplicas > 0 { - logrus.Println("~~~~~~~~~~~~ 400() - AVAILABLE CONDITION - TRUE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeAvailable, - Status: operatorv1.ConditionTrue, - LastTransitionTime: metav1.Now(), - }) - } else { - logrus.Println("~~~~~~~~~~~~ 400() - AVAILABLE CONDITION - FALSE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeAvailable, - Status: operatorv1.ConditionFalse, - Reason: "NoPodsAvailable", - Message: "NoDeploymentPodsAvailableOnAnyNode.", - LastTransitionTime: metav1.Now(), - }) - } - - logrus.Println("sync_v400: updating console status") - _, consoleConfigChanged, err := SyncConsoleConfig(co, consoleConfig, rt) - if err != nil { - errors = append(errors, fmt.Errorf("%q: %v", "consoleConfig", err)) - // logrus.Errorf("Could not update console config status: %v \n", err) - // return operatorConfig, updatedConfig, toUpdate, err - } - toUpdate = toUpdate || consoleConfigChanged - - logrus.Println("~~~~~~~~~~~~ 400() - FAILING CONDITION - FALSE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionFalse, - LastTransitionTime: metav1.Now(), - }) + // at this point, we should not be failing anymore + co.operatorStatusNotFailing(operatorConfig) + // but we may be in a transitional state, if any of the above resources changed if toUpdate { - logrus.Infof("sync_v400: to update spec: %v", toUpdate) - logrus.Println("~~~~~~~~~~~~ 400() - PROGGRESSING CONDITION - TRUE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeProgressing, - Status: operatorv1.ConditionTrue, - Reason: "DesiredStateNotYetAchieved", - LastTransitionTime: metav1.Now(), - }) + co.operatorStatusProgressing(operatorConfig) } else { - logrus.Println("~~~~~~~~~~~~ 400() - PROGGRESSING CONDITION - FALSE ~~~~~~~~~~~~~") - - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeProgressing, - Status: operatorv1.ConditionFalse, - }) + co.operatorStatusNotProgressing(operatorConfig) + } + // final availability is dependent upon the deployment + if actualDeployment.Status.ReadyReplicas > 0 { + co.operatorStatusDeploymentAvailable(operatorConfig) + } else { + co.operatorStatusDeploymentUnavailable(operatorConfig) } - if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { - if _, err := co.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - // we should be returning error only if status update fails, since sync errors - // should be reported as part of the status update. - return operatorConfig, consoleConfig, toUpdate, err - } + // if we survive the gauntlet, we need to update the console config with the + // public hostname so that the world can know the console is ready to roll + logrus.Println("sync_v400: updating console status") + if updatedConfig, err := SyncConsoleConfig(co, consoleConfig, rt); err != nil { + logrus.Errorf("Could not update console config status: %v \n", err) + return operatorConfig, updatedConfig, toUpdate, err } defer func() { @@ -174,26 +135,22 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, return operatorConfig, consoleConfig, toUpdate, nil } -func handleSyncErrorCondition(operatorConfig *operatorv1.Console, message string) { - logrus.Println("~~~~~~~~~~~~ handleSyncErrorCondition() - FAILING CONDITION - TRUE ~~~~~~~~~~~~~") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionTrue, - Message: message, - Reason: "SyncError", - LastTransitionTime: metav1.Now(), - }) +func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, error) { + logrus.Printf("Updating console.config.openshift.io with hostname: %v \n", route.Spec.Host) + consoleConfig.Status.PublicHostname = util.HTTPS(route.Spec.Host) + return co.consoleConfigClient.UpdateStatus(consoleConfig) } -func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, bool, error) { - if consoleConfig.Status.PublicHostname != route.Spec.Host { - logrus.Printf("Updating console.config.openshift.io with hostname: %v \n", route.Spec.Host) - consoleConfig.Status.PublicHostname = util.HTTPS(route.Spec.Host) - updatedConsoleConfig, err := co.consoleConfigClient.UpdateStatus(consoleConfig) - return updatedConsoleConfig, true, err - } - return consoleConfig, false, nil -} +// TODO: decide if this is necessary +//func SyncConsoleConfig(co *consoleOperator, consoleConfig *configv1.Console, route *routev1.Route) (*configv1.Console, bool, error) { +// if consoleConfig.Status.PublicHostname != route.Spec.Host { +// logrus.Printf("Updating console.config.openshift.io with hostname: %v \n", route.Spec.Host) +// consoleConfig.Status.PublicHostname = util.HTTPS(route.Spec.Host) +// updatedConsoleConfig, err := co.consoleConfigClient.UpdateStatus(consoleConfig) +// return updatedConsoleConfig, true, err +// } +// return consoleConfig, false, nil +//} func SyncDeployment(co *consoleOperator, recorder events.Recorder, operatorConfig *operatorv1.Console, cm *corev1.ConfigMap, serviceCAConfigMap *corev1.ConfigMap, sec *corev1.Secret) (*appsv1.Deployment, bool, error) { logrus.Printf("validating console deployment...") From 657ac0fe54b1db40fab55c3a4956492ed43d617b Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Thu, 14 Feb 2019 15:45:37 -0500 Subject: [PATCH 09/11] f --- pkg/console/operator/status.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go index e3e1f21a5..454fcf4bb 100644 --- a/pkg/console/operator/status.go +++ b/pkg/console/operator/status.go @@ -78,7 +78,7 @@ func (c *consoleOperator) operatorStatusNotFailing(operatorConfig *operatorsv1.C // Status: True // OperatorSyncLoopError func (c *consoleOperator) operatorStatusFailingSyncLoopError(operatorConfig *operatorsv1.Console, err error) (*operatorsv1.Console, error) { - fmt.Println("%s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) + fmt.Printf("%s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeFailing, Status: operatorsv1.ConditionTrue, From 817efcc51be96127eaf07e78d476c48379040d8b Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Fri, 15 Feb 2019 00:08:16 -0500 Subject: [PATCH 10/11] Add log messages to operator status funcs --- pkg/console/operator/status.go | 41 ++++++++++++++++++++----------- pkg/console/operator/sync_v400.go | 2 +- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go index 454fcf4bb..f7fc12073 100644 --- a/pkg/console/operator/status.go +++ b/pkg/console/operator/status.go @@ -3,6 +3,8 @@ package operator import ( "fmt" + "github.com/sirupsen/logrus" + operatorsv1 "github.com/openshift/api/operator/v1" operatorv1 "github.com/openshift/api/operator/v1" "github.com/openshift/library-go/pkg/operator/v1helpers" @@ -14,6 +16,7 @@ import ( // Status: True // - func (c *consoleOperator) operatorStatusAvailable(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: Available. \n") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeAvailable, Status: operatorsv1.ConditionTrue, @@ -26,6 +29,7 @@ func (c *consoleOperator) operatorStatusAvailable(operatorConfig *operatorsv1.Co } func (c *consoleOperator) operatorStatusProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: Progressing...") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeProgressing, Status: operatorv1.ConditionTrue, @@ -39,6 +43,7 @@ func (c *consoleOperator) operatorStatusProgressing(operatorConfig *operatorsv1. } func (c *consoleOperator) operatorStatusNotProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: Not progressing. \n") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeProgressing, Status: operatorv1.ConditionFalse, @@ -50,6 +55,7 @@ func (c *consoleOperator) operatorStatusNotProgressing(operatorConfig *operators } func (c *consoleOperator) operatorStatusFailing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: failing... \n") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: workloadFailingCondition, Status: operatorv1.ConditionTrue, @@ -61,24 +67,12 @@ func (c *consoleOperator) operatorStatusFailing(operatorConfig *operatorsv1.Cons return operatorConfig, nil } -func (c *consoleOperator) operatorStatusNotFailing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionFalse, - LastTransitionTime: metav1.Now(), - }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil -} - // Condition // Type: Failing // Status: True // OperatorSyncLoopError func (c *consoleOperator) operatorStatusFailingSyncLoopError(operatorConfig *operatorsv1.Console, err error) (*operatorsv1.Console, error) { - fmt.Printf("%s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) + fmt.Printf("Status: %s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeFailing, Status: operatorsv1.ConditionTrue, @@ -99,6 +93,7 @@ func (c *consoleOperator) operatorStatusFailingSyncLoopError(operatorConfig *ope // Status: Unknown // - in an unmanaged state, we don't know the status of anything, the operator is effectively off func (c *consoleOperator) operatorStatusUnknownUnmanaged(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: unmanaged state. Conditions unknown.") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorsv1.OperatorCondition{ Type: operatorsv1.OperatorStatusTypeAvailable, Status: operatorsv1.ConditionUnknown, @@ -127,8 +122,10 @@ func (c *consoleOperator) operatorStatusUnknownUnmanaged(operatorConfig *operato } func (c *consoleOperator) operatorStatusResourceSyncFailure(operatorConfig *operatorv1.Console, message string) (*operatorsv1.Console, error) { + logrus.Printf("Status: Workload sync failure: %v \n", message) v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, + // Type: workloadFailingCondition, + Type: operatorv1.OperatorStatusTypeFailing, Status: operatorv1.ConditionTrue, Message: message, Reason: "SyncError", @@ -140,7 +137,22 @@ func (c *consoleOperator) operatorStatusResourceSyncFailure(operatorConfig *oper return operatorConfig, nil } +func (c *consoleOperator) operatorStatusResourceSyncSuccess(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: Workload sync success! \n") + v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ + // Type: workloadFailingCondition, + Type: operatorv1.OperatorStatusTypeFailing, + Status: operatorv1.ConditionFalse, + LastTransitionTime: metav1.Now(), + }) + if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { + return nil, fmt.Errorf("status update error: %v \n", err) + } + return operatorConfig, nil +} + func (c *consoleOperator) operatorStatusDeploymentAvailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: deployment available. \n") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeAvailable, Status: operatorv1.ConditionTrue, @@ -153,6 +165,7 @@ func (c *consoleOperator) operatorStatusDeploymentAvailable(operatorConfig *oper } func (c *consoleOperator) operatorStatusDeploymentUnavailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { + logrus.Printf("Status: deployment unavailable.") v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ Type: operatorv1.OperatorStatusTypeAvailable, Status: operatorv1.ConditionFalse, diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index e141d60ec..27a32638b 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -99,7 +99,7 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, toUpdate = toUpdate || depChanged // at this point, we should not be failing anymore - co.operatorStatusNotFailing(operatorConfig) + co.operatorStatusResourceSyncSuccess(operatorConfig) // but we may be in a transitional state, if any of the above resources changed if toUpdate { From a7cca40ef64c21706f4843855b4de29276f67d1a Mon Sep 17 00:00:00 2001 From: "Benjamin A. Petersen" Date: Fri, 15 Feb 2019 15:55:31 -0500 Subject: [PATCH 11/11] Revise all status.condition funcs to ensure symmetry --- pkg/console/operator/operator.go | 31 +-- pkg/console/operator/status.go | 311 +++++++++++++++++++----------- pkg/console/operator/sync_v400.go | 37 ++-- 3 files changed, 226 insertions(+), 153 deletions(-) diff --git a/pkg/console/operator/operator.go b/pkg/console/operator/operator.go index 8588a85f9..5e5b73472 100644 --- a/pkg/console/operator/operator.go +++ b/pkg/console/operator/operator.go @@ -8,7 +8,7 @@ import ( "github.com/sirupsen/logrus" // kube - "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -149,32 +149,27 @@ func (c *consoleOperator) Sync(obj metav1.Object) error { } if err := c.handleSync(operatorConfig, consoleConfig); err != nil { - c.operatorStatusFailingSyncLoopError(operatorConfig, err) + c.SyncStatus(c.ConditionFailing(operatorConfig, "SyncLoopError", "Operator sync loop failed to completele.")) return err } - - c.operatorStatusAvailable(operatorConfig) + 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 { - originalOperatorConfig := operatorConfig.DeepCopy() + 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.operatorStatusUnknownUnmanaged(operatorConfig) - if !equality.Semantic.DeepEqual(operatorConfig.Status, originalOperatorConfig.Status) { - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return err - } - } + 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 @@ -185,18 +180,6 @@ func (c *consoleOperator) handleSync(operatorConfig *operatorsv1.Console, consol 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 } diff --git a/pkg/console/operator/status.go b/pkg/console/operator/status.go index f7fc12073..6494ebcde 100644 --- a/pkg/console/operator/status.go +++ b/pkg/console/operator/status.go @@ -5,176 +5,253 @@ import ( "github.com/sirupsen/logrus" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + operatorsv1 "github.com/openshift/api/operator/v1" - operatorv1 "github.com/openshift/api/operator/v1" "github.com/openshift/library-go/pkg/operator/v1helpers" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// Condition -// Type: Available -// Status: True -// - -func (c *consoleOperator) operatorStatusAvailable(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: Available. \n") +// 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: operatorsv1.OperatorStatusTypeAvailable, + 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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: Progressing...") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeProgressing, - Status: operatorv1.ConditionTrue, - Reason: "DesiredStateNotYetAchieved", +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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusNotProgressing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: Not progressing. \n") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeProgressing, - Status: operatorv1.ConditionFalse, +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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusFailing(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: failing... \n") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: workloadFailingCondition, - Status: operatorv1.ConditionTrue, +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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + 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 } -// Condition -// Type: Failing -// Status: True -// OperatorSyncLoopError -func (c *consoleOperator) operatorStatusFailingSyncLoopError(operatorConfig *operatorsv1.Console, err error) (*operatorsv1.Console, error) { - fmt.Printf("Status: %s %s %s %s %s", operatorsv1.OperatorStatusTypeFailing, operatorsv1.ConditionTrue, "OperatorSyncLoopError", err.Error(), metav1.Now()) +// 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, - Reason: "OperatorSyncLoopError", - Message: err.Error(), + Message: message, + Reason: "SyncError", LastTransitionTime: metav1.Now(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -// Conditions -// Type: Available -// Type: Progressing -// Type: Failing -// Status: Unknown -// - in an unmanaged state, we don't know the status of anything, the operator is effectively off -func (c *consoleOperator) operatorStatusUnknownUnmanaged(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: unmanaged state. Conditions unknown.") +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.OperatorStatusTypeAvailable, - Status: operatorsv1.ConditionUnknown, - Reason: "Unmanaged", - Message: "the controller manager is in an unmanaged state, therefore its availability is unknown.", + 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.OperatorStatusTypeProgressing, - Status: operatorsv1.ConditionFalse, - Reason: "Unmanaged", - Message: "the controller manager is in an unmanaged state, therefore no changes are being applied.", + 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.OperatorStatusTypeFailing, + Type: operatorsv1.OperatorStatusTypeAvailable, Status: operatorsv1.ConditionFalse, - Reason: "Unmanaged", - Message: "the controller manager is in an unmanaged state, therefore no operator actions are failing.", + Reason: reason, + Message: message, LastTransitionTime: metav1.Now(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusResourceSyncFailure(operatorConfig *operatorv1.Console, message string) (*operatorsv1.Console, error) { - logrus.Printf("Status: Workload sync failure: %v \n", message) - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - // Type: workloadFailingCondition, - Type: operatorv1.OperatorStatusTypeFailing, - Status: operatorv1.ConditionTrue, +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, - Reason: "SyncError", LastTransitionTime: metav1.Now(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusResourceSyncSuccess(operatorConfig *operatorsv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: Workload sync success! \n") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - // Type: workloadFailingCondition, - Type: operatorv1.OperatorStatusTypeFailing, - Status: operatorv1.ConditionFalse, +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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + return operatorConfig } -func (c *consoleOperator) operatorStatusDeploymentAvailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: deployment available. \n") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeAvailable, - Status: operatorv1.ConditionTrue, +// 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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + 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 } -func (c *consoleOperator) operatorStatusDeploymentUnavailable(operatorConfig *operatorv1.Console) (*operatorsv1.Console, error) { - logrus.Printf("Status: deployment unavailable.") - v1helpers.SetOperatorCondition(&operatorConfig.Status.Conditions, operatorv1.OperatorCondition{ - Type: operatorv1.OperatorStatusTypeAvailable, - Status: operatorv1.ConditionFalse, - Reason: "NoPodsAvailable", - Message: "NoDeploymentPodsAvailableOnAnyNode.", +// 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(), }) - if _, err := c.operatorConfigClient.UpdateStatus(operatorConfig); err != nil { - return nil, fmt.Errorf("status update error: %v \n", err) - } - return operatorConfig, nil + 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 } diff --git a/pkg/console/operator/sync_v400.go b/pkg/console/operator/sync_v400.go index 27a32638b..25f530528 100644 --- a/pkg/console/operator/sync_v400.go +++ b/pkg/console/operator/sync_v400.go @@ -48,72 +48,85 @@ func sync_v400(co *consoleOperator, originalOperatorConfig *operatorv1.Console, // track changes, may trigger ripples & update operator config or console config status toUpdate := false + // TODO: if the sync_loop starts, should we set condition progressing:true? + // - this may be prematurely assuming that something has to happen, when + // perhaps it does not (that said, we should not be notified unless + // a resource we care about changes... + // TODO: when it ends, should we set progressing:false? + rt, rtChanged, rtErr := SyncRoute(co, operatorConfig) if rtErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%v: %s\n", "route", rtErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%v: %s\n", "route", rtErr))) return operatorConfig, consoleConfig, toUpdate, rtErr } toUpdate = toUpdate || rtChanged _, svcChanged, svcErr := SyncService(co, recorder, operatorConfig) if svcErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "service", svcErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "service", svcErr))) return operatorConfig, consoleConfig, toUpdate, svcErr } toUpdate = toUpdate || svcChanged cm, cmChanged, cmErr := SyncConfigMap(co, recorder, operatorConfig, consoleConfig, rt) if cmErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "configmap", cmErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "configmap", cmErr))) return operatorConfig, consoleConfig, toUpdate, cmErr } toUpdate = toUpdate || cmChanged serviceCAConfigMap, serviceCAConfigMapChanged, serviceCAConfigMapErr := SyncServiceCAConfigMap(co, operatorConfig) if serviceCAConfigMapErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "serviceCAconfigmap", serviceCAConfigMapErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "serviceCAconfigmap", serviceCAConfigMapErr))) return operatorConfig, consoleConfig, toUpdate, serviceCAConfigMapErr } toUpdate = toUpdate || serviceCAConfigMapChanged sec, secChanged, secErr := SyncSecret(co, recorder, operatorConfig) if secErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "secret", secErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "secret", secErr))) return operatorConfig, consoleConfig, toUpdate, secErr } toUpdate = toUpdate || secChanged _, oauthChanged, oauthErr := SyncOAuthClient(co, operatorConfig, sec, rt) if oauthErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "oauth", oauthErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "oauth", oauthErr))) return operatorConfig, consoleConfig, toUpdate, oauthErr } toUpdate = toUpdate || oauthChanged actualDeployment, depChanged, depErr := SyncDeployment(co, recorder, operatorConfig, cm, serviceCAConfigMap, sec) if depErr != nil { - co.operatorStatusResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "route", depErr)) + co.SyncStatus(co.ConditionResourceSyncFailure(operatorConfig, fmt.Sprintf("%q: %v\n", "route", depErr))) return operatorConfig, consoleConfig, toUpdate, depErr } toUpdate = toUpdate || depChanged + logrus.Println("-----------------------") + logrus.Printf("sync loop 4.0.0 resources updated: %v \n", toUpdate) + logrus.Println("-----------------------") + // at this point, we should not be failing anymore - co.operatorStatusResourceSyncSuccess(operatorConfig) + co.ConditionResourceSyncSuccess(operatorConfig) // but we may be in a transitional state, if any of the above resources changed if toUpdate { - co.operatorStatusProgressing(operatorConfig) + co.ConditionResourceSyncProgressing(operatorConfig) } else { - co.operatorStatusNotProgressing(operatorConfig) + co.ConditionResourceSyncNotProgressing(operatorConfig) } // final availability is dependent upon the deployment if actualDeployment.Status.ReadyReplicas > 0 { - co.operatorStatusDeploymentAvailable(operatorConfig) + co.ConditionDeploymentAvailable(operatorConfig) } else { - co.operatorStatusDeploymentUnavailable(operatorConfig) + co.ConditionDeploymentNotAvailable(operatorConfig) } + // finally write out the set of conditions currently set + co.SyncStatus(operatorConfig) + // if we survive the gauntlet, we need to update the console config with the // public hostname so that the world can know the console is ready to roll logrus.Println("sync_v400: updating console status")