github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/lib/csv/replace_finder.go (about)

     1  package csv
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/sirupsen/logrus"
     7  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     8  
     9  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    10  	"github.com/operator-framework/operator-lifecycle-manager/pkg/api/client/clientset/versioned"
    11  )
    12  
    13  // NewReplaceFinder returns an instance of ReplaceFinder
    14  func NewReplaceFinder(logger *logrus.Logger, client versioned.Interface) ReplaceFinder {
    15  	return &replace{
    16  		logger: logger,
    17  		client: client,
    18  	}
    19  }
    20  
    21  // ReplaceFinder is an interface that finds the next or previous
    22  // ClusterServiceVersion object in the upgrade path for a given CSV.
    23  type ReplaceFinder interface {
    24  	IsBeingReplaced(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) (replacedBy *v1alpha1.ClusterServiceVersion)
    25  	IsReplacing(in *v1alpha1.ClusterServiceVersion) *v1alpha1.ClusterServiceVersion
    26  	GetFinalCSVInReplacing(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) (replacedBy *v1alpha1.ClusterServiceVersion)
    27  }
    28  
    29  type replace struct {
    30  	logger *logrus.Logger
    31  	client versioned.Interface
    32  }
    33  
    34  // IsBeingReplaced returns the corresponding ClusterServiceVersion object that
    35  // is replacing the given CSV specified.
    36  //
    37  // If the corresponding ClusterServiceVersion is not found nil is returned.
    38  func (r *replace) IsBeingReplaced(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) (replacedBy *v1alpha1.ClusterServiceVersion) {
    39  	for _, csv := range csvsInNamespace {
    40  		if csv.IsCopied() {
    41  			continue
    42  		}
    43  
    44  		r.logger.Debugf("checking %s", csv.GetName())
    45  
    46  		if csv.Spec.Replaces == in.GetName() {
    47  			r.logger.Infof("%s replaced by %s", in.GetName(), csv.GetName())
    48  			replacedBy = csv
    49  			return
    50  		}
    51  	}
    52  
    53  	return
    54  }
    55  
    56  // IsReplacing returns the corresponding ClusterServiceVersion object that the
    57  // given CSV specified replaces.
    58  //
    59  // If the corresponding ClusterServiceVersion is not found nil is returned.
    60  func (r *replace) IsReplacing(in *v1alpha1.ClusterServiceVersion) *v1alpha1.ClusterServiceVersion {
    61  	r.logger.Debugf("checking if csv is replacing an older version")
    62  	if in.Spec.Replaces == "" {
    63  		return nil
    64  	}
    65  
    66  	// using the client instead of a lister; missing an object because of a cache sync can cause upgrades to fail
    67  	previous, err := r.client.OperatorsV1alpha1().ClusterServiceVersions(in.GetNamespace()).Get(context.TODO(), in.Spec.Replaces, metav1.GetOptions{})
    68  	if err != nil {
    69  		r.logger.WithField("replacing", in.Spec.Replaces).WithError(err).Debugf("unable to get previous csv")
    70  		return nil
    71  	}
    72  
    73  	return previous
    74  }
    75  
    76  // GetFinalCSVInReplacing returns the most recent ClustererviceVersion that is
    77  // in the replace chain.
    78  //
    79  // If the corresponding ClusterServiceVersion is not found nil is returned.
    80  func (r *replace) GetFinalCSVInReplacing(in *v1alpha1.ClusterServiceVersion, csvsInNamespace map[string]*v1alpha1.ClusterServiceVersion) (replacedBy *v1alpha1.ClusterServiceVersion) {
    81  	current := in
    82  	for {
    83  		next := r.IsBeingReplaced(current, csvsInNamespace)
    84  		if next == nil {
    85  			break
    86  		}
    87  
    88  		replacedBy = next
    89  		current = next
    90  	}
    91  
    92  	return
    93  }