Skip to content

Commit eec307e

Browse files
committed
fix(transitionCSV): reorder apiservice resource check
- Move APIService resource check before installation check to prevent transitions from FAILED to PENDING when a CSV has conflicting owners - Add SetPhaseWithEventIfChanged CSV method - Use Aggregate error type for APIService resource checks
1 parent 840d806 commit eec307e

File tree

5 files changed

+116
-73
lines changed

5 files changed

+116
-73
lines changed

go.sum

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
112112
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
113113
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM=
114114
github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
115-
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:Iju5GlWwrvL6UBg4zJJt3btmonfrMlCDdsejg4CZE7c=
115+
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0 h1:BWIsLfhgKhV5g/oF34aRjniBHLTZe5DNekSjbAjIS6c=
116116
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
117117
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
118118
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
@@ -132,7 +132,6 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
132132
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
133133
github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo=
134134
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
135-
github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE=
136135
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
137136
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
138137
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -322,5 +321,5 @@ k8s.io/kube-openapi v0.0.0-20181031203759-72693cb1fadd h1:ggv/Vfza0i5xuhUZyYyxcc
322321
k8s.io/kube-openapi v0.0.0-20181031203759-72693cb1fadd/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
323322
k8s.io/kubernetes v1.11.7-beta.0.0.20181219023948-b875d52ea96d/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
324323
k8s.io/kubernetes v1.11.8-beta.0.0.20190124204751-3a10094374f2/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
325-
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298 h1:CMsSK4yqJD0IfftutHd0XjYoJTsrtx983MpdKFd8c74=
324+
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298 h1:vVWtHOzTn3+uHbF0nZUlTrwFfbxPn2ZM3chxhAIUzg0=
326325
k8s.io/kubernetes v1.11.9-beta.0.0.20190311041124-ede55fd57298/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=

pkg/api/apis/operators/v1alpha1/clusterserviceversion.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ var uncopiableReasons = map[ConditionReason]struct{}{
3030
CSVReasonCannotModifyStaticOperatorGroupProvidedAPIs: {},
3131
}
3232

33+
// SetPhaseWithEventIfChanged emits a Kubernetes event with details of a phase change and sets the current phase if phase, reason, or message would changed
34+
func (c *ClusterServiceVersion) SetPhaseWithEventIfChanged(phase ClusterServiceVersionPhase, reason ConditionReason, message string, now metav1.Time, recorder record.EventRecorder) {
35+
if c.Status.Phase == phase && c.Status.Reason == reason && c.Status.Message == message {
36+
return
37+
}
38+
39+
c.SetPhaseWithEvent(phase, reason, message, now, recorder)
40+
}
41+
42+
// SetPhaseWithEvent generates a Kubernetes event with details about the phase change and sets the current phase
3343
func (c *ClusterServiceVersion) SetPhaseWithEvent(phase ClusterServiceVersionPhase, reason ConditionReason, message string, now metav1.Time, recorder record.EventRecorder) {
3444
var eventtype string
3545
if phase == CSVPhaseFailed {

pkg/controller/operators/olm/apiservices.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
rbacv1 "k8s.io/api/rbac/v1"
1212
k8serrors "k8s.io/apimachinery/pkg/api/errors"
1313
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1415
"k8s.io/apimachinery/pkg/util/intstr"
1516
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
1617

@@ -41,35 +42,34 @@ func (a *Operator) shouldRotateCerts(csv *v1alpha1.ClusterServiceVersion) bool {
4142
return false
4243
}
4344

44-
// apiServiceResourceErrorsActionable returns true if OLM can do something about any one
45+
// apiServiceResourceErrorActionable returns true if OLM can do something about any one
4546
// of the apiService errors in errs; otherwise returns false
4647
//
4748
// This method can be used to determine if a CSV in a failed state due to APIService
4849
// issues can resolve them by reinstalling
49-
func (a *Operator) apiServiceResourceErrorsActionable(errs []error) bool {
50-
for _, err := range errs {
51-
switch err.(type) {
52-
case olmerrors.UnadoptableError:
53-
return false
54-
}
55-
}
50+
func (a *Operator) apiServiceResourceErrorActionable(err error) bool {
51+
filtered := utilerrors.FilterOut(err, func(e error) bool {
52+
_, unadoptable := e.(olmerrors.UnadoptableError)
53+
return !unadoptable
54+
})
55+
actionable := filtered == nil
5656

57-
return true
57+
return actionable
5858
}
5959

6060
// checkAPIServiceResources checks if all expected generated resources for the given APIService exist
61-
func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, hashFunc certs.PEMHash) []error {
61+
func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion, hashFunc certs.PEMHash) error {
6262
errs := []error{}
6363
owners := []ownerutil.Owner{csv}
6464
// Get replacing CSV if exists
65-
replacement, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
65+
replacing, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
6666
if err != nil && k8serrors.IsNotFound(err) == false {
6767
a.Log.Debugf("Replacement error regarding CSV (%v): %v", csv.GetName(), err)
6868
errs = append(errs, err)
69-
return errs
69+
return utilerrors.NewAggregate(errs)
7070
}
71-
if replacement != nil {
72-
owners = append(owners, replacement)
71+
if replacing != nil {
72+
owners = append(owners, replacing)
7373
}
7474
ruleChecker := install.NewCSVRuleChecker(a.lister.RbacV1().RoleLister(), a.lister.RbacV1().RoleBindingLister(), a.lister.RbacV1().ClusterRoleLister(), a.lister.RbacV1().ClusterRoleBindingLister(), csv)
7575
for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
@@ -92,7 +92,7 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
9292
err := olmerrors.NewUnadoptableError("", apiServiceName)
9393
logger.WithError(err).Warn("found unadoptable apiservice")
9494
errs = append(errs, err)
95-
return errs
95+
return utilerrors.NewAggregate(errs)
9696
}
9797

9898
serviceName := APIServiceNameToServiceName(apiServiceName)
@@ -239,7 +239,7 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
239239
}
240240
}
241241

242-
return errs
242+
return utilerrors.NewAggregate(errs)
243243
}
244244

245245
func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIService) bool {
@@ -251,8 +251,8 @@ func (a *Operator) isAPIServiceAvailable(apiService *apiregistrationv1.APIServic
251251
return false
252252
}
253253

254-
func (a *Operator) areAPIServicesAvailable(descs []v1alpha1.APIServiceDescription) (bool, error) {
255-
for _, desc := range descs {
254+
func (a *Operator) areAPIServicesAvailable(csv *v1alpha1.ClusterServiceVersion) (bool, error) {
255+
for _, desc := range csv.Spec.APIServiceDefinitions.Owned {
256256
apiServiceName := fmt.Sprintf("%s.%s", desc.Version, desc.Group)
257257
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(apiServiceName)
258258
if k8serrors.IsNotFound(err) {

pkg/controller/operators/olm/operator.go

Lines changed: 41 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -741,9 +741,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
741741
if err != nil {
742742
syncError = err
743743
logger.WithError(err).Warn("csv has invalid installmodes")
744-
if out.Status.Reason != v1alpha1.CSVReasonInvalidInstallModes {
745-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidInstallModes, syncError.Error(), now, a.recorder)
746-
}
744+
out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidInstallModes, syncError.Error(), now, a.recorder)
747745
return
748746
}
749747

@@ -754,16 +752,12 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
754752

755753
if err := modeSet.Supports(out.GetNamespace(), namespaces); err != nil {
756754
logger.WithField("reason", err.Error()).Info("installmodeset does not support operatorgroups namespace selection")
757-
if out.Status.Reason != v1alpha1.CSVReasonUnsupportedOperatorGroup {
758-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonUnsupportedOperatorGroup, err.Error(), now, a.recorder)
759-
}
755+
out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonUnsupportedOperatorGroup, err.Error(), now, a.recorder)
760756
return
761757
}
762758
} else {
763759
logger.Info("csv missing olm.targetNamespaces annotation")
764-
if out.Status.Reason != v1alpha1.CSVReasonNoTargetNamespaces {
765-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, "csv missing olm.targetNamespaces annotation", now, a.recorder)
766-
}
760+
out.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, "csv missing olm.targetNamespaces annotation", now, a.recorder)
767761
return
768762
}
769763

@@ -855,6 +849,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
855849
}
856850

857851
// Check for CRD ownership conflicts
852+
// TODO: find CSVs that provide any of those that out does across all namespaces
858853
csvSet := a.csvSet(out.GetNamespace(), v1alpha1.CSVPhaseAny)
859854
if syncError = a.crdOwnerConflicts(out, csvSet); syncError != nil {
860855
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonOwnerConflict, fmt.Sprintf("crd owner conflict: %s", syncError), now, a.recorder)
@@ -893,6 +888,7 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
893888
a.Log.Warn(err.Error())
894889
}
895890
return
891+
896892
case v1alpha1.CSVPhaseInstalling:
897893
installer, strategy, _ := a.parseStrategiesAndUpdateStatus(out)
898894
if strategy == nil {
@@ -902,15 +898,22 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
902898
if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseInstalling, v1alpha1.CSVReasonWaiting); installErr == nil {
903899
logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Infof("install strategy successful")
904900
}
901+
905902
case v1alpha1.CSVPhaseSucceeded:
906903
installer, strategy, _ := a.parseStrategiesAndUpdateStatus(out)
907904
if strategy == nil {
908905
return
909906
}
910907

911-
// Check install status
912-
if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentUnhealthy); installErr != nil {
913-
logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("unhealthy component: %s", installErr)
908+
// Check if any generated resources are missing
909+
if err := a.checkAPIServiceResources(out, certs.PEMSHA256); err != nil {
910+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceResourceIssue, err.Error(), now, a.recorder)
911+
return
912+
}
913+
914+
// Check if it's time to refresh owned APIService certs
915+
if a.shouldRotateCerts(out) {
916+
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsCertRotation, "owned APIServices need cert refresh", now, a.recorder)
914917
return
915918
}
916919

@@ -926,15 +929,9 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
926929
return
927930
}
928931

929-
// Check if any generated resources are missing
930-
if resErr := a.checkAPIServiceResources(out, certs.PEMSHA256); len(resErr) > 0 {
931-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceResourceIssue, resErr[0].Error(), now, a.recorder)
932-
return
933-
}
934-
935-
// Check if it's time to refresh owned APIService certs
936-
if a.shouldRotateCerts(out) {
937-
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsCertRotation, "owned APIServices need cert refresh", now, a.recorder)
932+
// Check install status
933+
if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonComponentUnhealthy); installErr != nil {
934+
logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("unhealthy component: %s", installErr)
938935
return
939936
}
940937

@@ -971,15 +968,9 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
971968
return
972969
}
973970

974-
// Check install status
975-
if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall); installErr != nil {
976-
logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("needs reinstall: %s", installErr)
977-
return
978-
}
979-
980971
// Check if requirements exist
981972
met, statuses, err := a.requirementAndPermissionStatus(out)
982-
if err != nil {
973+
if err != nil && out.Status.Reason != v1alpha1.CSVReasonInvalidStrategy {
983974
logger.Warn("invalid install strategy")
984975
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidStrategy, fmt.Sprintf("install strategy invalid: %s", err.Error()), now, a.recorder)
985976
return
@@ -989,20 +980,24 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
989980
return
990981
}
991982

992-
// Check if any generated resources are missing
993-
if resErr := a.checkAPIServiceResources(out, certs.PEMSHA256); len(resErr) > 0 {
983+
// 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) {
994985
// Check if API services are adoptable. If not, keep CSV as Failed state
995-
if a.apiServiceResourceErrorsActionable(resErr) {
996-
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonAPIServiceResourcesNeedReinstall, resErr[0].Error(), now, a.recorder)
997-
return
998-
}
986+
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonAPIServiceResourcesNeedReinstall, err.Error(), now, a.recorder)
987+
return
999988
}
1000989

1001990
// Check if it's time to refresh owned APIService certs
1002991
if a.shouldRotateCerts(out) {
1003992
out.SetPhaseWithEvent(v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsCertRotation, "owned APIServices need cert refresh", now, a.recorder)
1004993
return
1005994
}
995+
996+
// Check install status
997+
if installErr := a.updateInstallStatus(out, installer, strategy, v1alpha1.CSVPhasePending, v1alpha1.CSVReasonNeedsReinstall); installErr != nil {
998+
logger.WithField("strategy", out.Spec.InstallStrategy.StrategyName).Warnf("needs reinstall: %s", installErr)
999+
}
1000+
10061001
case v1alpha1.CSVPhaseReplacing:
10071002
// determine CSVs that are safe to delete by finding a replacement chain to a CSV that's running
10081003
// since we don't know what order we'll process replacements, we have to guard against breaking that chain
@@ -1109,41 +1104,38 @@ func (a *Operator) checkReplacementsAndUpdateStatus(csv *v1alpha1.ClusterService
11091104
}
11101105

11111106
func (a *Operator) updateInstallStatus(csv *v1alpha1.ClusterServiceVersion, installer install.StrategyInstaller, strategy install.Strategy, requeuePhase v1alpha1.ClusterServiceVersionPhase, requeueConditionReason v1alpha1.ConditionReason) error {
1112-
apiServicesInstalled, apiServiceErr := a.areAPIServicesAvailable(csv.Spec.APIServiceDefinitions.Owned)
1107+
apiServicesInstalled, apiServiceErr := a.areAPIServicesAvailable(csv)
11131108
strategyInstalled, strategyErr := installer.CheckInstalled(strategy)
11141109
now := timeNow()
11151110

11161111
if strategyInstalled && apiServicesInstalled {
11171112
// if there's no error, we're successfully running
1118-
if csv.Status.Phase != v1alpha1.CSVPhaseSucceeded {
1119-
csv.SetPhaseWithEvent(v1alpha1.CSVPhaseSucceeded, v1alpha1.CSVReasonInstallSuccessful, "install strategy completed with no errors", now, a.recorder)
1120-
}
1113+
csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseSucceeded, v1alpha1.CSVReasonInstallSuccessful, "install strategy completed with no errors", now, a.recorder)
11211114
return nil
11221115
}
11231116

11241117
// installcheck determined we can't progress (e.g. deployment failed to come up in time)
11251118
if install.IsErrorUnrecoverable(strategyErr) {
1126-
csv.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInstallCheckFailed, fmt.Sprintf("install failed: %s", strategyErr), now, a.recorder)
1119+
csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInstallCheckFailed, fmt.Sprintf("install failed: %s", strategyErr), now, a.recorder)
11271120
return strategyErr
11281121
}
11291122

11301123
if apiServiceErr != nil {
1131-
csv.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceInstallFailed, fmt.Sprintf("APIService install failed: %s", apiServiceErr), now, a.recorder)
1124+
csv.SetPhaseWithEventIfChanged(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonAPIServiceInstallFailed, fmt.Sprintf("APIService install failed: %s", apiServiceErr), now, a.recorder)
11321125
return apiServiceErr
11331126
}
11341127

11351128
if !apiServicesInstalled {
1136-
csv.SetPhaseWithEvent(requeuePhase, requeueConditionReason, fmt.Sprintf("APIServices not installed"), now, a.recorder)
1137-
err := a.csvQueueSet.Requeue(csv.GetName(), csv.GetNamespace())
1138-
if err != nil {
1129+
csv.SetPhaseWithEventIfChanged(requeuePhase, requeueConditionReason, fmt.Sprintf("APIServices not installed"), now, a.recorder)
1130+
if err := a.csvQueueSet.Requeue(csv.GetName(), csv.GetNamespace()); err != nil {
11391131
a.Log.Warn(err.Error())
11401132
}
11411133

11421134
return fmt.Errorf("APIServices not installed")
11431135
}
11441136

11451137
if strategyErr != nil {
1146-
csv.SetPhaseWithEvent(requeuePhase, requeueConditionReason, fmt.Sprintf("installing: %s", strategyErr), now, a.recorder)
1138+
csv.SetPhaseWithEventIfChanged(requeuePhase, requeueConditionReason, fmt.Sprintf("installing: %s", strategyErr), now, a.recorder)
11471139
return strategyErr
11481140
}
11491141

@@ -1178,23 +1170,20 @@ func (a *Operator) parseStrategiesAndUpdateStatus(csv *v1alpha1.ClusterServiceVe
11781170
}
11791171

11801172
func (a *Operator) crdOwnerConflicts(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) error {
1181-
owned := false
11821173
for _, crd := range in.Spec.CustomResourceDefinitions.Owned {
11831174
for csvName, csv := range csvsInNamespace {
11841175
if csvName == in.GetName() {
11851176
continue
11861177
}
11871178
if csv.OwnsCRD(crd.Name) {
1188-
owned = true
1189-
}
1190-
if owned && in.Spec.Replaces == csvName {
1191-
return nil
1179+
if in.Spec.Replaces == csvName {
1180+
return nil
1181+
}
1182+
return ErrCRDOwnerConflict
11921183
}
11931184
}
11941185
}
1195-
if owned {
1196-
return ErrCRDOwnerConflict
1197-
}
1186+
11981187
return nil
11991188
}
12001189

0 commit comments

Comments
 (0)