github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/cache/operators.go (about)

     1  package cache
     2  
     3  import (
     4  	"fmt"
     5  	"hash/fnv"
     6  	"sort"
     7  	"strings"
     8  
     9  	"github.com/blang/semver/v4"
    10  	"k8s.io/apimachinery/pkg/runtime/schema"
    11  
    12  	"github.com/operator-framework/api/pkg/operators/v1alpha1"
    13  	"github.com/operator-framework/operator-registry/pkg/api"
    14  	opregistry "github.com/operator-framework/operator-registry/pkg/registry"
    15  )
    16  
    17  // todo: drop fields from cache.Entry and move to pkg/controller/operators/olm
    18  type APISet map[opregistry.APIKey]struct{}
    19  
    20  func EmptyAPISet() APISet {
    21  	return map[opregistry.APIKey]struct{}{}
    22  }
    23  
    24  func (s APISet) PopAPIKey() *opregistry.APIKey {
    25  	for a := range s {
    26  		api := &opregistry.APIKey{
    27  			Group:   a.Group,
    28  			Version: a.Version,
    29  			Kind:    a.Kind,
    30  			Plural:  a.Plural,
    31  		}
    32  		delete(s, a)
    33  		return api
    34  	}
    35  	return nil
    36  }
    37  
    38  func GVKStringToProvidedAPISet(gvksStr string) APISet {
    39  	set := make(APISet)
    40  	// TODO: Should we make gvk strings lowercase to avoid issues with user set gvks?
    41  	gvks := strings.Split(strings.Replace(gvksStr, " ", "", -1), ",")
    42  	for _, gvkStr := range gvks {
    43  		gvk, _ := schema.ParseKindArg(gvkStr)
    44  		if gvk != nil {
    45  			set[opregistry.APIKey{Group: gvk.Group, Version: gvk.Version, Kind: gvk.Kind}] = struct{}{}
    46  		}
    47  	}
    48  
    49  	return set
    50  }
    51  
    52  func APIKeyToGVKString(key opregistry.APIKey) string {
    53  	// TODO: Add better validation of GVK
    54  	return strings.Join([]string{key.Kind, key.Version, key.Group}, ".")
    55  }
    56  
    57  func APIKeyToGVKHash(key opregistry.APIKey) (string, error) {
    58  	hash := fnv.New64a()
    59  	if _, err := hash.Write([]byte(APIKeyToGVKString(key))); err != nil {
    60  		return "", err
    61  	}
    62  	return fmt.Sprintf("%x", hash.Sum64()), nil
    63  }
    64  
    65  func (s APISet) String() string {
    66  	gvkStrs := make([]string, len(s))
    67  	i := 0
    68  	for api := range s {
    69  		// TODO: Only add valid GVK strings
    70  		gvkStrs[i] = APIKeyToGVKString(api)
    71  		i++
    72  	}
    73  	sort.Strings(gvkStrs)
    74  
    75  	return strings.Join(gvkStrs, ",")
    76  }
    77  
    78  // Union returns the union of the APISet and the given list of APISets
    79  func (s APISet) Union(sets ...APISet) APISet {
    80  	union := make(APISet)
    81  	for api := range s {
    82  		union[api] = struct{}{}
    83  	}
    84  	for _, set := range sets {
    85  		for api := range set {
    86  			union[api] = struct{}{}
    87  		}
    88  	}
    89  
    90  	return union
    91  }
    92  
    93  // Intersection returns the intersection of the APISet and the given list of APISets
    94  func (s APISet) Intersection(sets ...APISet) APISet {
    95  	intersection := make(APISet)
    96  	for _, set := range sets {
    97  		for api := range set {
    98  			if _, ok := s[api]; ok {
    99  				intersection[api] = struct{}{}
   100  			}
   101  		}
   102  	}
   103  
   104  	return intersection
   105  }
   106  
   107  func (s APISet) Difference(set APISet) APISet {
   108  	difference := make(APISet).Union(s)
   109  	for api := range set {
   110  		delete(difference, api)
   111  	}
   112  
   113  	return difference
   114  }
   115  
   116  // IsSubset returns true if the APISet is a subset of the given one
   117  func (s APISet) IsSubset(set APISet) bool {
   118  	for api := range s {
   119  		if _, ok := set[api]; !ok {
   120  			return false
   121  		}
   122  	}
   123  
   124  	return true
   125  }
   126  
   127  // StripPlural returns the APISet with the Plural field of all APIKeys removed
   128  func (s APISet) StripPlural() APISet {
   129  	set := make(APISet)
   130  	for api := range s {
   131  		set[opregistry.APIKey{Group: api.Group, Version: api.Version, Kind: api.Kind}] = struct{}{}
   132  	}
   133  
   134  	return set
   135  }
   136  
   137  type OperatorSourceInfo struct {
   138  	Package        string
   139  	Channel        string
   140  	StartingCSV    string
   141  	Catalog        SourceKey
   142  	DefaultChannel bool
   143  	Deprecations   *Deprecations
   144  	Subscription   *v1alpha1.Subscription
   145  }
   146  
   147  func (i *OperatorSourceInfo) String() string {
   148  	return fmt.Sprintf("%s/%s in %s/%s", i.Package, i.Channel, i.Catalog.Name, i.Catalog.Namespace)
   149  }
   150  
   151  type Deprecations struct {
   152  	Package *api.Deprecation
   153  	Channel *api.Deprecation
   154  	Bundle  *api.Deprecation
   155  }
   156  
   157  type Entry struct {
   158  	Name         string
   159  	Replaces     string
   160  	Skips        []string
   161  	SkipRange    semver.Range
   162  	ProvidedAPIs APISet
   163  	RequiredAPIs APISet
   164  	Version      *semver.Version
   165  	SourceInfo   *OperatorSourceInfo
   166  	Properties   []*api.Property
   167  	BundlePath   string
   168  
   169  	// Present exclusively to pipe inlined bundle
   170  	// content. Resolver components shouldn't need to read this,
   171  	// and it should eventually be possible to remove the field
   172  	// altogether.
   173  	Bundle *api.Bundle
   174  }
   175  
   176  func (o *Entry) Package() string {
   177  	if si := o.SourceInfo; si != nil {
   178  		return si.Package
   179  	}
   180  	return ""
   181  }
   182  
   183  func (o *Entry) Channel() string {
   184  	if si := o.SourceInfo; si != nil {
   185  		return si.Channel
   186  	}
   187  	return ""
   188  }