@@ -38,8 +38,8 @@ import (
3838
3939var (
4040 ErrRequirementsNotMet = errors .New ("requirements were not met" )
41- ErrCRDOwnerConflict = errors .New ("CRD owned by another ClusterServiceVersion " )
42- ErrAPIServiceOwnerConflict = errors .New ("APIService owned by another ClusterServiceVersion " )
41+ ErrCRDOwnerConflict = errors .New ("conflicting CRD owner in namespace " )
42+ ErrAPIServiceOwnerConflict = errors .New ("unable to adopt APIService " )
4343)
4444
4545var timeNow = func () metav1.Time { return metav1 .NewTime (time .Now ().UTC ()) }
@@ -849,16 +849,18 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
849849 }
850850
851851 // Check for CRD ownership conflicts
852- // TODO: find CSVs that provide any of those that out does across all namespaces
853- csvSet := a . csvSet ( out . GetNamespace (), v1alpha1 . CSVPhaseAny )
854- if syncError = a . crdOwnerConflicts ( out , csvSet ); syncError != nil {
855- out . SetPhaseWithEvent ( v1alpha1 . CSVPhaseFailed , v1alpha1 . CSVReasonOwnerConflict , fmt . Sprintf ( "crd owner conflict: %s" , syncError ), now , a . recorder )
852+ if syncError = a . crdOwnerConflicts ( out , a . csvSet ( out . GetNamespace (), v1alpha1 . CSVPhaseAny )); syncError != nil {
853+ if syncError == ErrCRDOwnerConflict {
854+ out . SetPhaseWithEventIfChanged ( v1alpha1 . CSVPhaseFailed , v1alpha1 . CSVReasonOwnerConflict , syncError . Error (), now , a . recorder )
855+ }
856856 return
857857 }
858858
859- // check for APIServices ownership conflicts
860- if syncError = a .apiServiceOwnerConflicts (out , csvSet ); syncError != nil {
861- out .SetPhaseWithEvent (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonOwnerConflict , fmt .Sprintf ("apiService owner conflict: %s" , syncError ), now , a .recorder )
859+ // Check for APIServices ownership conflicts
860+ if syncError = a .apiServiceOwnerConflicts (out ); syncError != nil {
861+ if syncError == ErrAPIServiceOwnerConflict {
862+ out .SetPhaseWithEventIfChanged (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonOwnerConflict , syncError .Error (), now , a .recorder )
863+ }
862864 return
863865 }
864866
@@ -897,6 +899,11 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
897899
898900 if installErr := a .updateInstallStatus (out , installer , strategy , v1alpha1 .CSVPhaseInstalling , v1alpha1 .CSVReasonWaiting ); installErr == nil {
899901 logger .WithField ("strategy" , out .Spec .InstallStrategy .StrategyName ).Infof ("install strategy successful" )
902+ } else {
903+ // Set phase to failed if it's been a long time since the last transition (5 minutes)
904+ if metav1 .Now ().Sub (out .Status .LastTransitionTime .Time ) >= 5 * time .Minute {
905+ out .SetPhaseWithEventIfChanged (v1alpha1 .CSVPhaseFailed , v1alpha1 .CSVReasonInstallCheckFailed , fmt .Sprintf ("install timeout" ), now , a .recorder )
906+ }
900907 }
901908
902909 case v1alpha1 .CSVPhaseSucceeded :
@@ -981,9 +988,11 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
981988 }
982989
983990 // Check if any generated resources are missing and that OLM can action on them
984- if err := a .checkAPIServiceResources (out , certs .PEMSHA256 ); err != nil && a .apiServiceResourceErrorActionable (err ) {
985- // Check if API services are adoptable. If not, keep CSV as Failed state
986- out .SetPhaseWithEvent (v1alpha1 .CSVPhasePending , v1alpha1 .CSVReasonAPIServiceResourcesNeedReinstall , err .Error (), now , a .recorder )
991+ if err := a .checkAPIServiceResources (out , certs .PEMSHA256 ); err != nil {
992+ if a .apiServiceResourceErrorActionable (err ) {
993+ // Check if API services are adoptable. If not, keep CSV as Failed state
994+ out .SetPhaseWithEvent (v1alpha1 .CSVPhasePending , v1alpha1 .CSVReasonAPIServiceResourcesNeedReinstall , err .Error (), now , a .recorder )
995+ }
987996 return
988997 }
989998
@@ -1009,20 +1018,20 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
10091018 return
10101019 }
10111020
1012- // if we can find a newer version that's successfully installed, we're safe to mark all intermediates
1021+ // If we can find a newer version that's successfully installed, we're safe to mark all intermediates
10131022 for _ , csv := range a .findIntermediatesForDeletion (out ) {
10141023 // we only mark them in this step, in case some get deleted but others fail and break the replacement chain
10151024 csv .SetPhaseWithEvent (v1alpha1 .CSVPhaseDeleting , v1alpha1 .CSVReasonReplaced , "has been replaced by a newer ClusterServiceVersion that has successfully installed." , now , a .recorder )
10161025
1017- // ignore errors and success here; this step is just an optimization to speed up GC
1026+ // Ignore errors and success here; this step is just an optimization to speed up GC
10181027 _ , _ = a .client .OperatorsV1alpha1 ().ClusterServiceVersions (csv .GetNamespace ()).UpdateStatus (csv )
10191028 err := a .csvQueueSet .Requeue (csv .GetName (), csv .GetNamespace ())
10201029 if err != nil {
10211030 a .Log .Warn (err .Error ())
10221031 }
10231032 }
10241033
1025- // if there's no newer version, requeue for processing (likely will be GCable before resync)
1034+ // If there's no newer version, requeue for processing (likely will be GCable before resync)
10261035 err := a .csvQueueSet .Requeue (out .GetName (), out .GetNamespace ())
10271036 if err != nil {
10281037 a .Log .Warn (err .Error ())
@@ -1136,6 +1145,10 @@ func (a *Operator) updateInstallStatus(csv *v1alpha1.ClusterServiceVersion, inst
11361145
11371146 if strategyErr != nil {
11381147 csv .SetPhaseWithEventIfChanged (requeuePhase , requeueConditionReason , fmt .Sprintf ("installing: %s" , strategyErr ), now , a .recorder )
1148+ if err := a .csvQueueSet .Requeue (csv .GetName (), csv .GetNamespace ()); err != nil {
1149+ a .Log .Warn (err .Error ())
1150+ }
1151+
11391152 return strategyErr
11401153 }
11411154
@@ -1169,16 +1182,10 @@ func (a *Operator) parseStrategiesAndUpdateStatus(csv *v1alpha1.ClusterServiceVe
11691182 return installer , strategy , previousStrategy
11701183}
11711184
1172- func (a * Operator ) crdOwnerConflicts (in * v1alpha1.ClusterServiceVersion , csvsInNamespace map [string ]* v1alpha1.ClusterServiceVersion ) error {
1185+ func (a * Operator ) crdOwnerConflicts (in * v1alpha1.ClusterServiceVersion , csvs map [string ]* v1alpha1.ClusterServiceVersion ) error {
11731186 for _ , crd := range in .Spec .CustomResourceDefinitions .Owned {
1174- for csvName , csv := range csvsInNamespace {
1175- if csvName == in .GetName () {
1176- continue
1177- }
1178- if csv .OwnsCRD (crd .Name ) {
1179- if in .Spec .Replaces == csvName {
1180- return nil
1181- }
1187+ for name , csv := range csvs {
1188+ if name != in .GetName () && in .Spec .Replaces != name && csv .OwnsCRD (crd .Name ) {
11821189 return ErrCRDOwnerConflict
11831190 }
11841191 }
@@ -1187,25 +1194,34 @@ func (a *Operator) crdOwnerConflicts(in *v1alpha1.ClusterServiceVersion, csvsInN
11871194 return nil
11881195}
11891196
1190- func (a * Operator ) apiServiceOwnerConflicts (in * v1alpha1.ClusterServiceVersion , csvsInNamespace map [string ]* v1alpha1.ClusterServiceVersion ) error {
1191- owned := false
1192- for _ , api := range in .Spec .APIServiceDefinitions .Owned {
1193- name := fmt .Sprintf ("%s.%s" , api .Version , api .Group )
1194- for csvName , csv := range csvsInNamespace {
1195- if csvName == in .GetName () {
1196- continue
1197- }
1198- if csv .OwnsAPIService (name ) {
1199- owned = true
1200- }
1201- if owned && in .Spec .Replaces == csvName {
1202- return nil
1203- }
1204- }
1197+ func (a * Operator ) apiServiceOwnerConflicts (csv * v1alpha1.ClusterServiceVersion ) error {
1198+ // Get replacing CSV if exists
1199+ replacing , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
1200+ if err != nil && ! k8serrors .IsNotFound (err ) && ! k8serrors .IsGone (err ) {
1201+ return err
1202+ }
1203+
1204+ owners := []ownerutil.Owner {csv }
1205+ if replacing != nil {
1206+ owners = append (owners , replacing )
12051207 }
1206- if owned {
1207- return ErrAPIServiceOwnerConflict
1208+
1209+ for _ , desc := range csv .GetOwnedAPIServiceDescriptions () {
1210+ // Check if the APIService exists
1211+ apiService , err := a .lister .APIRegistrationV1 ().APIServiceLister ().Get (desc .GetName ())
1212+ if err != nil && ! k8serrors .IsNotFound (err ) && ! k8serrors .IsGone (err ) {
1213+ return err
1214+ }
1215+
1216+ if apiService == nil {
1217+ continue
1218+ }
1219+
1220+ if ! ownerutil .AdoptableLabels (apiService .GetLabels (), true , owners ... ) {
1221+ return ErrAPIServiceOwnerConflict
1222+ }
12081223 }
1224+
12091225 return nil
12101226}
12111227
0 commit comments