@@ -421,7 +421,8 @@ func (r *OperatorPolicyReconciler) handleResources(ctx context.Context, policy *
421421 return earlyComplianceEvents , condChanged , err
422422 }
423423
424- changed , err = r .handleInstallPlan (ctx , policy , subscription )
424+ changed , earlyConds , err = r .handleInstallPlan (ctx , policy , subscription )
425+ earlyComplianceEvents = append (earlyComplianceEvents , earlyConds ... )
425426 condChanged = condChanged || changed
426427
427428 if err != nil {
@@ -1118,7 +1119,9 @@ func (r *OperatorPolicyReconciler) musthaveOpGroup(
11181119 // Now the OperatorGroup should match, so report Compliance
11191120 updateStatus (policy , createdCond ("OperatorGroup" ), createdObj (desiredOpGroup ))
11201121 // Emit a dedicated "created" event regardless of later status aggregation
1121- earlyConds = append (earlyConds , createdCond ("OperatorGroup" ))
1122+ cond := createdCond ("OperatorGroup" )
1123+ cond .LastTransitionTime = metav1 .Now ()
1124+ earlyConds = append (earlyConds , cond )
11221125
11231126 return true , earlyConds , true , nil
11241127 case 1 :
@@ -1203,6 +1206,10 @@ func (r *OperatorPolicyReconciler) musthaveOpGroup(
12031206 desiredOpGroup .SetGroupVersionKind (operatorGroupGVK ) // Update stripped this information
12041207
12051208 updateStatus (policy , updatedCond ("OperatorGroup" ), updatedObj (desiredOpGroup ))
1209+ // Emit a dedicated "updated" event
1210+ upd := updatedCond ("OperatorGroup" )
1211+ upd .LastTransitionTime = metav1 .Now ()
1212+ earlyConds = append (earlyConds , upd )
12061213
12071214 return true , earlyConds , true , nil
12081215 default :
@@ -1363,6 +1370,10 @@ func (r *OperatorPolicyReconciler) mustnothaveOpGroup(
13631370 desiredOpGroup .SetGroupVersionKind (operatorGroupGVK ) // Delete stripped this information
13641371
13651372 updateStatus (policy , deletedCond ("OperatorGroup" ), deletedObj (desiredOpGroup ))
1373+ // Emit a dedicated "deleted" event
1374+ del := deletedCond ("OperatorGroup" )
1375+ del .LastTransitionTime = metav1 .Now ()
1376+ earlyConds = append (earlyConds , del )
13661377
13671378 return earlyConds , true , nil
13681379}
@@ -1416,7 +1427,6 @@ func (r *OperatorPolicyReconciler) musthaveSubscription(
14161427 earlyConds = append (earlyConds , calculateComplianceCondition (policy ))
14171428 }
14181429
1419- log .Info ("!!!!!!!!!!!!!! create subscription!!!!!!!!!!!" )
14201430 err := r .createWithNamespace (ctx , desiredSub )
14211431 if err != nil {
14221432 return nil , nil , changed , fmt .Errorf ("error creating the Subscription: %w" , err )
@@ -1533,6 +1543,10 @@ func (r *OperatorPolicyReconciler) musthaveSubscription(
15331543 mergedSub .SetGroupVersionKind (subscriptionGVK ) // Update stripped this information
15341544
15351545 updateStatus (policy , updatedCond ("Subscription" ), updatedObj (mergedSub ))
1546+ // Emit a dedicated "updated" event
1547+ upd := updatedCond ("Subscription" )
1548+ upd .LastTransitionTime = metav1 .Now ()
1549+ earlyConds = append (earlyConds , upd )
15361550
15371551 return mergedSub , earlyConds , true , nil
15381552}
@@ -1856,6 +1870,10 @@ func (r *OperatorPolicyReconciler) mustnothaveSubscription(
18561870 }
18571871
18581872 updateStatus (policy , deletedCond ("Subscription" ), deletedObj (desiredSub ))
1873+ // Emit a dedicated "deleted" event
1874+ del := deletedCond ("Subscription" )
1875+ del .LastTransitionTime = metav1 .Now ()
1876+ earlyConds = append (earlyConds , del )
18591877
18601878 return foundSub , earlyConds , true , nil
18611879}
@@ -1887,14 +1905,14 @@ func messageIncludesSubscription(subscription *operatorv1alpha1.Subscription, me
18871905
18881906func (r * OperatorPolicyReconciler ) handleInstallPlan (
18891907 ctx context.Context , policy * policyv1beta1.OperatorPolicy , sub * operatorv1alpha1.Subscription ,
1890- ) (bool , error ) {
1908+ ) (bool , []metav1. Condition , error ) {
18911909 if sub == nil {
18921910 // Note: existing related objects will not be removed by this status update
1893- return updateStatus (policy , invalidCausingUnknownCond ("InstallPlan" )), nil
1911+ return updateStatus (policy , invalidCausingUnknownCond ("InstallPlan" )), []metav1. Condition {}, nil
18941912 }
18951913
18961914 if sub .Status .CurrentCSV == "" && sub .Status .InstalledCSV == "" {
1897- return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), nil
1915+ return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), []metav1. Condition {}, nil
18981916 }
18991917
19001918 watcher := opPolIdentifier (policy .Namespace , policy .Name )
@@ -1907,14 +1925,14 @@ func (r *OperatorPolicyReconciler) handleInstallPlan(
19071925 // potentially vulnerable operators.
19081926 installPlans , err := r .DynamicWatcher .List (watcher , installPlanGVK , sub .Namespace , labels .Everything ())
19091927 if err != nil {
1910- return false , fmt .Errorf ("error listing InstallPlans: %w" , err )
1928+ return false , []metav1. Condition {}, fmt .Errorf ("error listing InstallPlans: %w" , err )
19111929 }
19121930
19131931 // InstallPlans are generally kept in order to provide a history of actions on the cluster, but
19141932 // they can be deleted without impacting the installed operator. So, not finding any should not
19151933 // be considered a reason for NonCompliance, regardless of musthave or mustnothave.
19161934 if len (installPlans ) == 0 {
1917- return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), nil
1935+ return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), []metav1. Condition {}, nil
19181936 }
19191937
19201938 var latestInstallPlan * unstructured.Unstructured
@@ -1982,24 +2000,26 @@ func (r *OperatorPolicyReconciler) handleInstallPlan(
19822000 "subscription" , sub .Name , "namespace" , sub .Namespace ,
19832001 )
19842002
1985- return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), nil
2003+ return updateStatus (policy , noInstallPlansCond , noInstallPlansObj (sub .Namespace )), []metav1. Condition {}, nil
19862004 }
19872005
19882006 if policy .Spec .ComplianceType .IsMustHave () {
1989- changed , err := r .musthaveInstallPlan (ctx , policy , sub , latestInstallPlan )
2007+ changed , earlyConds , err := r .musthaveInstallPlan (ctx , policy , sub , latestInstallPlan )
19902008
1991- return changed , err
2009+ return changed , earlyConds , err
19922010 }
19932011
1994- return r .mustnothaveInstallPlan (policy , latestInstallPlan )
2012+ changed , err := r .mustnothaveInstallPlan (policy , latestInstallPlan )
2013+
2014+ return changed , []metav1.Condition {}, err
19952015}
19962016
19972017func (r * OperatorPolicyReconciler ) musthaveInstallPlan (
19982018 ctx context.Context ,
19992019 policy * policyv1beta1.OperatorPolicy ,
20002020 sub * operatorv1alpha1.Subscription ,
20012021 latestInstallPlanUnstruct * unstructured.Unstructured ,
2002- ) (bool , error ) {
2022+ ) (bool , []metav1. Condition , error ) {
20032023 opLog := ctrl .LoggerFrom (ctx )
20042024 complianceConfig := policy .Spec .ComplianceConfig .UpgradesAvailable
20052025 latestInstallPlan := operatorv1alpha1.InstallPlan {}
@@ -2009,7 +2029,7 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
20092029 opLog .Error (err , "Unable to determine the CSV names of the current InstallPlan" ,
20102030 "InstallPlan.Name" , latestInstallPlanUnstruct .GetName ())
20112031
2012- return updateStatus (policy , installPlansNoApprovals ), nil
2032+ return updateStatus (policy , installPlansNoApprovals ), []metav1. Condition {}, nil
20132033 }
20142034
20152035 ipCSVs := latestInstallPlan .Spec .ClusterServiceVersionNames
@@ -2024,21 +2044,21 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
20242044 currentCSV := sub .Status .CurrentCSV
20252045
20262046 if installedCSV != "" && currentCSV != "" && installedCSV == currentCSV {
2027- return updateStatus (policy , installPlansNoApprovals ), nil
2047+ return updateStatus (policy , installPlansNoApprovals ), []metav1. Condition {}, nil
20282048 }
20292049 case operatorv1alpha1 .InstallPlanPhaseInstalling :
20302050 return updateStatus (
20312051 policy ,
20322052 installPlanInstallingCond ,
20332053 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2034- ), nil
2054+ ), []metav1. Condition {}, nil
20352055 case operatorv1alpha1 .InstallPlanFailed :
20362056 // Generally, a failed InstallPlan is not a reason for NonCompliance, because it could be from
20372057 // an old installation. But if the current InstallPlan is failed, we should alert the user.
20382058 if len (ipCSVs ) == 1 {
20392059 return updateStatus (
20402060 policy , installPlanFailed , existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2041- ), nil
2061+ ), []metav1. Condition {}, nil
20422062 }
20432063
20442064 // If there is more than one CSV in the InstallPlan, make sure this CSV failed before marking it as
@@ -2056,27 +2076,30 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
20562076 policy ,
20572077 installPlanFailed ,
20582078 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2059- ), nil
2079+ ), []metav1. Condition {}, nil
20602080 }
20612081 }
20622082
20632083 // If no step for this CSV failed in the InstallPlan, treat it the same as no install plans requiring approval
2064- return updateStatus (policy , installPlansNoApprovals ), nil
2084+ return updateStatus (policy , installPlansNoApprovals ), []metav1. Condition {}, nil
20652085 default :
20662086 return updateStatus (
20672087 policy ,
20682088 installPlansNoApprovals , existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2069- ), nil
2089+ ), []metav1. Condition {}, nil
20702090 }
20712091
20722092 // Check if it's already approved. This can happen if this OperatorPolicy or another managing the same InstallPlan
20732093 // performed the approval but it hasn't started installing yet.
20742094 if latestInstallPlan .Spec .Approved {
2095+ ipApproved := installPlanApprovedCond (sub .Status .CurrentCSV )
2096+ ipApproved .LastTransitionTime = metav1 .Now ()
2097+
20752098 return updateStatus (
20762099 policy ,
20772100 installPlanApprovedCond (sub .Status .CurrentCSV ),
20782101 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2079- ), nil
2102+ ), []metav1. Condition { ipApproved }, nil
20802103 }
20812104
20822105 initialInstall := sub .Status .InstalledCSV == ""
@@ -2085,43 +2108,54 @@ func (r *OperatorPolicyReconciler) musthaveInstallPlan(
20852108 // Only report this status when not approving an InstallPlan, because otherwise it could easily
20862109 // oscillate between this and another condition.
20872110 if policy .Spec .RemediationAction .IsInform () || (! initialInstall && ! autoUpgrade ) {
2111+ // Emit an early event to record that an upgrade is available and requires approval
2112+ ipUpgrade := installPlanUpgradeCond (complianceConfig , ipCSVs , nil )
2113+ ipUpgrade .LastTransitionTime = metav1 .Now ()
2114+
20882115 return updateStatus (
20892116 policy ,
2090- installPlanUpgradeCond ( complianceConfig , ipCSVs , nil ) ,
2117+ ipUpgrade ,
20912118 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2092- ), nil
2119+ ), []metav1. Condition { ipUpgrade }, nil
20932120 }
20942121
20952122 remainingCSVsToApprove , err := r .getRemainingCSVApprovals (ctx , policy , sub , & latestInstallPlan )
20962123 if err != nil {
2097- return false , fmt .Errorf ("error finding the InstallPlan approvals: %w" , err )
2124+ return false , []metav1. Condition {}, fmt .Errorf ("error finding the InstallPlan approvals: %w" , err )
20982125 }
20992126
21002127 if len (remainingCSVsToApprove ) != 0 {
2128+ // Emit an early event that approval is required for the listed CSVs
2129+ ipUpgrade := installPlanUpgradeCond (complianceConfig , ipCSVs , remainingCSVsToApprove )
2130+ ipUpgrade .LastTransitionTime = metav1 .Now ()
2131+
21012132 return updateStatus (
21022133 policy ,
2103- installPlanUpgradeCond ( complianceConfig , ipCSVs , remainingCSVsToApprove ) ,
2134+ ipUpgrade ,
21042135 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
2105- ), nil
2136+ ), []metav1. Condition { ipUpgrade }, nil
21062137 }
21072138
21082139 opLog .Info ("Approving InstallPlan" , "InstallPlanName" , latestInstallPlan .Name ,
21092140 "InstallPlanNamespace" , latestInstallPlan .Namespace )
21102141
21112142 if err := unstructured .SetNestedField (latestInstallPlanUnstruct .Object , true , "spec" , "approved" ); err != nil {
2112- return false , fmt .Errorf ("error approving InstallPlan: %w" , err )
2143+ return false , []metav1. Condition {}, fmt .Errorf ("error approving InstallPlan: %w" , err )
21132144 }
21142145
21152146 if err := r .TargetClient .Update (ctx , latestInstallPlanUnstruct ); err != nil {
2116- return false , fmt .Errorf ("error updating approved InstallPlan: %w" , err )
2147+ return false , []metav1. Condition {}, fmt .Errorf ("error updating approved InstallPlan: %w" , err )
21172148 }
21182149
2150+ ipApproved := installPlanApprovedCond (sub .Status .CurrentCSV )
2151+ ipApproved .LastTransitionTime = metav1 .Now ()
2152+
21192153 return updateStatus (
21202154 policy ,
21212155 installPlanApprovedCond (sub .Status .CurrentCSV ),
21222156 existingInstallPlanObj (& latestInstallPlan , string (phase ), complianceConfig ),
21232157 ),
2124- nil
2158+ []metav1. Condition { ipApproved }, nil
21252159}
21262160
21272161// getRemainingCSVApprovals will return all CSVs that can't be approved by an OperatorPolicy (currentPolicy and others).
@@ -2577,6 +2611,7 @@ func (r *OperatorPolicyReconciler) mustnothaveCSV(
25772611 }
25782612
25792613 updateStatus (policy , deletedCond ("ClusterServiceVersion" , csvNames ... ), relatedCSVs ... )
2614+ earlyConds = append (earlyConds , deletedCond ("ClusterServiceVersion" , csvNames ... ))
25802615
25812616 return earlyConds , true , nil
25822617}
@@ -2755,6 +2790,7 @@ func (r *OperatorPolicyReconciler) handleCRDs(
27552790 }
27562791
27572792 updateStatus (policy , deletedCond ("CustomResourceDefinition" ), relatedCRDs ... )
2793+ earlyConds = append (earlyConds , deletedCond ("CustomResourceDefinition" ))
27582794
27592795 return earlyConds , true , nil
27602796}
0 commit comments