@@ -38,8 +38,8 @@ import (
38
38
39
39
var (
40
40
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 " )
43
43
)
44
44
45
45
var timeNow = func () metav1.Time { return metav1 .NewTime (time .Now ().UTC ()) }
@@ -849,16 +849,18 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
849
849
}
850
850
851
851
// 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
+ }
856
856
return
857
857
}
858
858
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
+ }
862
864
return
863
865
}
864
866
@@ -897,6 +899,11 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
897
899
898
900
if installErr := a .updateInstallStatus (out , installer , strategy , v1alpha1 .CSVPhaseInstalling , v1alpha1 .CSVReasonWaiting ); installErr == nil {
899
901
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
+ }
900
907
}
901
908
902
909
case v1alpha1 .CSVPhaseSucceeded :
@@ -981,9 +988,11 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
981
988
}
982
989
983
990
// 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
+ }
987
996
return
988
997
}
989
998
@@ -1009,20 +1018,20 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
1009
1018
return
1010
1019
}
1011
1020
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
1013
1022
for _ , csv := range a .findIntermediatesForDeletion (out ) {
1014
1023
// we only mark them in this step, in case some get deleted but others fail and break the replacement chain
1015
1024
csv .SetPhaseWithEvent (v1alpha1 .CSVPhaseDeleting , v1alpha1 .CSVReasonReplaced , "has been replaced by a newer ClusterServiceVersion that has successfully installed." , now , a .recorder )
1016
1025
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
1018
1027
_ , _ = a .client .OperatorsV1alpha1 ().ClusterServiceVersions (csv .GetNamespace ()).UpdateStatus (csv )
1019
1028
err := a .csvQueueSet .Requeue (csv .GetName (), csv .GetNamespace ())
1020
1029
if err != nil {
1021
1030
a .Log .Warn (err .Error ())
1022
1031
}
1023
1032
}
1024
1033
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)
1026
1035
err := a .csvQueueSet .Requeue (out .GetName (), out .GetNamespace ())
1027
1036
if err != nil {
1028
1037
a .Log .Warn (err .Error ())
@@ -1136,6 +1145,10 @@ func (a *Operator) updateInstallStatus(csv *v1alpha1.ClusterServiceVersion, inst
1136
1145
1137
1146
if strategyErr != nil {
1138
1147
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
+
1139
1152
return strategyErr
1140
1153
}
1141
1154
@@ -1169,16 +1182,10 @@ func (a *Operator) parseStrategiesAndUpdateStatus(csv *v1alpha1.ClusterServiceVe
1169
1182
return installer , strategy , previousStrategy
1170
1183
}
1171
1184
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 {
1173
1186
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 ) {
1182
1189
return ErrCRDOwnerConflict
1183
1190
}
1184
1191
}
@@ -1187,25 +1194,34 @@ func (a *Operator) crdOwnerConflicts(in *v1alpha1.ClusterServiceVersion, csvsInN
1187
1194
return nil
1188
1195
}
1189
1196
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 )
1205
1207
}
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
+ }
1208
1223
}
1224
+
1209
1225
return nil
1210
1226
}
1211
1227
0 commit comments