github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/operatorstatus/csv_reporter.go (about) 1 package operatorstatus 2 3 import ( 4 "fmt" 5 6 configv1 "github.com/openshift/api/config/v1" 7 "github.com/operator-framework/api/pkg/operators/v1alpha1" 8 "k8s.io/utils/clock" 9 ) 10 11 const ( 12 // versionName reflects the name of the version CVO expects in Status. 13 versionName = "operator" 14 15 reasonCSVSucceeded = "ClusterServiceVersionSucceeded" 16 17 reasonCSVNotSucceeded = "ClusterServiceVersionNotSucceeded" 18 19 reasonCSVDeleted = "ClusterServiceVersionDeleted" 20 ) 21 22 // newCSVStatusReporter returns a new instance of CSVStatusReporter 23 func newCSVStatusReporter(releaseVersion string) *csvStatusReporter { 24 return &csvStatusReporter{ 25 clock: &clock.RealClock{}, 26 releaseVersion: releaseVersion, 27 } 28 } 29 30 // csvStatusReporter provides the logic for initializing ClusterOperator and 31 // ClusterOperatorStatus types. 32 type csvStatusReporter struct { 33 clock clock.Clock 34 releaseVersion string 35 } 36 37 // NewNotification prepares a new notification event to be sent to the monitor. 38 func (r *csvStatusReporter) NewNotification(context *csvEventContext) NotificationFunc { 39 return func() (name string, mutator MutatorFunc) { 40 name = context.Name 41 mutator = func(existing *configv1.ClusterOperatorStatus) (new *configv1.ClusterOperatorStatus) { 42 new = r.GetNewStatus(existing, context) 43 return 44 } 45 46 return 47 } 48 } 49 50 // GetNewStatus returns the expected new status based on the notification context. 51 // We cover the following scenarios: 52 // a. Fresh install of an operator (v1), no previous version is installed. 53 // 1. Working toward v1 54 // 2. v1 successfully installed 55 // 3. v1 deploy failed 56 // 4. v1 has been removed, post successful install. 57 // 58 // b. Newer version of the operator (v2) is being installed (v1 is already installed) 59 // 1. Working toward v2. (v1 is being replaced, it waits until v2 successfully 60 // is successfully installed) Is v1 available while v2 is being installed? 61 // 2. When v1 is uninstalled, we remove the old version from status. 62 // 3. When v3 is installed successfully, we add the new version (v2) to status. 63 func (r *csvStatusReporter) GetNewStatus(existing *configv1.ClusterOperatorStatus, context *csvEventContext) (status *configv1.ClusterOperatorStatus) { 64 builder := &Builder{ 65 clock: r.clock, 66 status: existing, 67 } 68 69 defer func() { 70 status = builder.GetStatus() 71 }() 72 73 // We don't monitor whether the CSV backed operator is in degraded status. 74 builder.WithDegraded(configv1.ConditionFalse) 75 76 // CSV status won't block cluster upgrades 77 builder.WithUpgradeable(configv1.ConditionTrue, "Safe to upgrade") 78 79 // A CSV has been deleted. 80 if context.CurrentDeleted { 81 csv := context.Current 82 gvk := csv.GetObjectKind().GroupVersionKind() 83 84 builder.WithoutVersion(csv.GetName(), csv.Spec.Version.String()). 85 WithoutRelatedObject(gvk.Group, clusterServiceVersionResource, csv.GetNamespace(), csv.GetName()) 86 87 if context.WorkingToward == nil { 88 builder.WithProgressing(configv1.ConditionFalse, fmt.Sprintf("Uninstalled version %s", csv.Spec.Version)). 89 WithAvailable(configv1.ConditionFalse, fmt.Sprintf("Uninstalled version %s", csv.Spec.Version), reasonCSVDeleted) 90 91 return 92 } 93 } 94 95 // It's either a fresh install or an upgrade. 96 csv := context.GetActiveCSV() 97 name := csv.GetName() 98 version := csv.Spec.Version 99 phase := csv.Status.Phase 100 101 gvk := csv.GetObjectKind().GroupVersionKind() 102 builder.WithRelatedObject("", "namespaces", "", csv.GetNamespace()). 103 WithRelatedObject(gvk.Group, clusterServiceVersionResource, csv.GetNamespace(), csv.GetName()) 104 105 switch phase { 106 case v1alpha1.CSVPhaseSucceeded: 107 builder.WithAvailable(configv1.ConditionTrue, fmt.Sprintf("ClusterServiceVersion %v/%v observed in phase %v", csv.Namespace, csv.Name, csv.Status.Phase), reasonCSVSucceeded) 108 case v1alpha1.CSVPhaseFailed: 109 builder.WithAvailable(configv1.ConditionFalse, fmt.Sprintf("ClusterServiceVersion %v/%v observed in phase %v with reason: %v, message: %v", csv.Namespace, csv.Name, csv.Status.Phase, csv.Status.Reason, csv.Status.Message), reasonCSVNotSucceeded) 110 } 111 112 switch phase { 113 case v1alpha1.CSVPhaseSucceeded: 114 builder.WithProgressing(configv1.ConditionFalse, fmt.Sprintf("Deployed version %s", version)) 115 case v1alpha1.CSVPhaseFailed: 116 builder.WithProgressing(configv1.ConditionFalse, fmt.Sprintf("Failed to deploy %s", version)) 117 default: 118 builder.WithProgressing(configv1.ConditionTrue, fmt.Sprintf("Working toward %s", version)) 119 } 120 121 if phase == v1alpha1.CSVPhaseSucceeded { 122 builder.WithVersion(versionName, r.releaseVersion) 123 builder.WithVersion(name, version.String()) 124 } 125 126 return 127 }