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 }