Skip to content

Commit d3c2b32

Browse files
committed
(bug) CSV name change causes upgrade to fail
If a head CSV has a different name than the CSV it replaces, upgrade fails because olm fails to transfer ownership of the APIService from the previous CSV to the head CSV. BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1723818
1 parent 6bf64d0 commit d3c2b32

File tree

2 files changed

+72
-35
lines changed

2 files changed

+72
-35
lines changed

pkg/controller/operators/olm/apiservices.go

Lines changed: 65 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package olm
22

33
import (
4+
"errors"
45
"fmt"
56
"strings"
67
"time"
@@ -65,18 +66,6 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
6566
})
6667

6768
errs := []error{}
68-
owners := []ownerutil.Owner{csv}
69-
70-
// Get replacing CSV if exists
71-
replacing, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
72-
if err != nil && !k8serrors.IsNotFound(err) {
73-
logger.WithError(err).Warn("could not get replacement csv")
74-
return err
75-
}
76-
if replacing != nil {
77-
owners = append(owners, replacing)
78-
}
79-
8069
ruleChecker := install.NewCSVRuleChecker(a.lister.RbacV1().RoleLister(), a.lister.RbacV1().RoleBindingLister(), a.lister.RbacV1().ClusterRoleLister(), a.lister.RbacV1().ClusterRoleBindingLister(), csv)
8170
for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
8271
apiServiceName := desc.GetName()
@@ -92,8 +81,15 @@ func (a *Operator) checkAPIServiceResources(csv *v1alpha1.ClusterServiceVersion,
9281
}
9382

9483
// Check if the APIService is adoptable
95-
if !ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...) {
96-
logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Debug("adoption failed")
84+
adoptable, err := a.isAPIServiceAdoptable(csv, apiService)
85+
if err != nil {
86+
logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Errorf("adoption check failed - %v", err)
87+
errs = append(errs, err)
88+
return utilerrors.NewAggregate(errs)
89+
}
90+
91+
if !adoptable {
92+
logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Errorf("adoption failed")
9793
err := olmerrors.NewUnadoptableError("", apiServiceName)
9894
logger.WithError(err).Warn("found unadoptable apiservice")
9995
errs = append(errs, err)
@@ -707,17 +703,12 @@ func (a *Operator) installAPIServiceRequirements(desc v1alpha1.APIServiceDescrip
707703
}
708704
apiService.SetName(apiServiceName)
709705
} else {
710-
owners := []ownerutil.Owner{csv}
711-
712-
// Get replacing CSV
713-
replaces, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
714-
if err == nil {
715-
owners = append(owners, replaces)
706+
adoptable, err := a.isAPIServiceAdoptable(csv, apiService)
707+
if err != nil {
708+
logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Errorf("adoption check failed - %v", err)
716709
}
717710

718-
// check if the APIService is adoptable
719-
if !ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...) {
720-
logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Debug("adoption failed")
711+
if !adoptable{
721712
return nil, fmt.Errorf("pre-existing APIService %s is not adoptable", apiServiceName)
722713
}
723714
}
@@ -759,3 +750,54 @@ func APIServiceNameToServiceName(apiServiceName string) string {
759750
// Replace all '.'s with "-"s to convert to a DNS-1035 label
760751
return strings.Replace(apiServiceName, ".", "-", -1)
761752
}
753+
754+
func (a *Operator) isAPIServiceAdoptable(target *v1alpha1.ClusterServiceVersion, apiService *apiregistrationv1.APIService) (adoptable bool, err error) {
755+
if apiService == nil || target == nil {
756+
err = errors.New("invalid input")
757+
return
758+
}
759+
760+
labels := apiService.GetLabels()
761+
ownerKind := labels[ownerutil.OwnerKind]
762+
ownerName := labels[ownerutil.OwnerKey]
763+
ownerNamespace := labels[ownerutil.OwnerNamespaceKey]
764+
765+
if ownerKind == "" || ownerNamespace == "" || ownerName == "" {
766+
return
767+
}
768+
769+
if err := ownerutil.InferGroupVersionKind(target); err != nil {
770+
a.logger.Warn(err.Error())
771+
}
772+
773+
targetKind := target.GetObjectKind().GroupVersionKind().Kind
774+
if ownerKind != targetKind {
775+
return
776+
}
777+
778+
// Get the CSV that target replaces
779+
replacing, replaceGetErr := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(target.GetNamespace()).Get(target.Spec.Replaces)
780+
if replaceGetErr != nil && !k8serrors.IsNotFound(replaceGetErr) && !k8serrors.IsGone(replaceGetErr) {
781+
err = replaceGetErr
782+
return
783+
}
784+
785+
// Get the current owner CSV of the APIService
786+
currentOwnerCSV, ownerGetErr := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(ownerNamespace).Get(ownerName)
787+
if ownerGetErr != nil && !k8serrors.IsNotFound(ownerGetErr) && !k8serrors.IsGone(ownerGetErr) {
788+
err = ownerGetErr
789+
return
790+
}
791+
792+
owners := []ownerutil.Owner{target}
793+
if replacing != nil {
794+
owners = append(owners, replacing)
795+
}
796+
if currentOwnerCSV != nil && (
797+
currentOwnerCSV.Status.Phase == v1alpha1.CSVPhaseReplacing || currentOwnerCSV.Status.Phase == v1alpha1.CSVPhaseDeleting) {
798+
owners = append(owners, currentOwnerCSV)
799+
}
800+
801+
adoptable = ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...)
802+
return
803+
}

pkg/controller/operators/olm/operator.go

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strings"
88
"time"
99

10+
log "github.com/sirupsen/logrus"
1011
v1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1"
1112
"github.com/sirupsen/logrus"
1213
corev1 "k8s.io/api/core/v1"
@@ -1386,17 +1387,6 @@ func (a *Operator) getReplacementChain(in *v1alpha1.ClusterServiceVersion, csvsI
13861387
}
13871388

13881389
func (a *Operator) apiServiceOwnerConflicts(csv *v1alpha1.ClusterServiceVersion) error {
1389-
// Get replacing CSV if exists
1390-
replacing, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(csv.GetNamespace()).Get(csv.Spec.Replaces)
1391-
if err != nil && !k8serrors.IsNotFound(err) && !k8serrors.IsGone(err) {
1392-
return err
1393-
}
1394-
1395-
owners := []ownerutil.Owner{csv}
1396-
if replacing != nil {
1397-
owners = append(owners, replacing)
1398-
}
1399-
14001390
for _, desc := range csv.GetOwnedAPIServiceDescriptions() {
14011391
// Check if the APIService exists
14021392
apiService, err := a.lister.APIRegistrationV1().APIServiceLister().Get(desc.GetName())
@@ -1408,7 +1398,12 @@ func (a *Operator) apiServiceOwnerConflicts(csv *v1alpha1.ClusterServiceVersion)
14081398
continue
14091399
}
14101400

1411-
if !ownerutil.AdoptableLabels(apiService.GetLabels(), true, owners...) {
1401+
adoptable, err := a.isAPIServiceAdoptable(csv, apiService)
1402+
if err != nil {
1403+
a.logger.WithFields(log.Fields{"obj": "apiService", "labels": apiService.GetLabels()}).Errorf("adoption check failed - %v", err)
1404+
}
1405+
1406+
if !adoptable {
14121407
return ErrAPIServiceOwnerConflict
14131408
}
14141409
}

0 commit comments

Comments
 (0)