github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/cache/predicates.go (about) 1 package cache 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 8 "github.com/blang/semver/v4" 9 10 "github.com/operator-framework/api/pkg/constraints" 11 opregistry "github.com/operator-framework/operator-registry/pkg/registry" 12 ) 13 14 type Predicate interface { 15 Test(*Entry) bool 16 String() string 17 } 18 19 type csvNamePredicate string 20 21 func CSVNamePredicate(name string) Predicate { 22 return csvNamePredicate(name) 23 } 24 25 func (c csvNamePredicate) Test(o *Entry) bool { 26 return o.Name == string(c) 27 } 28 29 func (c csvNamePredicate) String() string { 30 return fmt.Sprintf("with name: %s", string(c)) 31 } 32 33 type channelPredicate string 34 35 func ChannelPredicate(channel string) Predicate { 36 return channelPredicate(channel) 37 } 38 39 func (ch channelPredicate) Test(o *Entry) bool { 40 // all operators match the empty channel 41 if string(ch) == "" { 42 return true 43 } 44 if si := o.SourceInfo; si != nil { 45 return si.Channel == string(ch) 46 } 47 return false 48 } 49 50 func (ch channelPredicate) String() string { 51 return fmt.Sprintf("with channel: %s", string(ch)) 52 } 53 54 type pkgPredicate string 55 56 func PkgPredicate(pkg string) Predicate { 57 return pkgPredicate(pkg) 58 } 59 60 func (pkg pkgPredicate) Test(o *Entry) bool { 61 for _, p := range o.Properties { 62 if p.Type != opregistry.PackageType { 63 continue 64 } 65 var prop opregistry.PackageProperty 66 err := json.Unmarshal([]byte(p.Value), &prop) 67 if err != nil { 68 continue 69 } 70 if prop.PackageName == string(pkg) { 71 return true 72 } 73 } 74 return o.Package() == string(pkg) 75 } 76 77 func (pkg pkgPredicate) String() string { 78 return fmt.Sprintf("with package: %s", string(pkg)) 79 } 80 81 type versionInRangePredicate struct { 82 r semver.Range 83 str string 84 } 85 86 func VersionInRangePredicate(r semver.Range, version string) Predicate { 87 return versionInRangePredicate{r: r, str: version} 88 } 89 90 func (v versionInRangePredicate) Test(o *Entry) bool { 91 for _, p := range o.Properties { 92 if p.Type != opregistry.PackageType { 93 continue 94 } 95 var prop opregistry.PackageProperty 96 err := json.Unmarshal([]byte(p.Value), &prop) 97 if err != nil { 98 continue 99 } 100 ver, err := semver.Parse(prop.Version) 101 if err != nil { 102 continue 103 } 104 if v.r(ver) { 105 return true 106 } 107 } 108 return o.Version != nil && v.r(*o.Version) 109 } 110 111 func (v versionInRangePredicate) String() string { 112 return fmt.Sprintf("with version in range: %v", v.str) 113 } 114 115 type labelPredicate string 116 117 func LabelPredicate(label string) Predicate { 118 return labelPredicate(label) 119 } 120 func (l labelPredicate) Test(o *Entry) bool { 121 for _, p := range o.Properties { 122 if p.Type != opregistry.LabelType { 123 continue 124 } 125 var prop opregistry.LabelProperty 126 err := json.Unmarshal([]byte(p.Value), &prop) 127 if err != nil { 128 continue 129 } 130 if prop.Label == string(l) { 131 return true 132 } 133 } 134 return false 135 } 136 137 func (l labelPredicate) String() string { 138 return fmt.Sprintf("with label: %v", string(l)) 139 } 140 141 type catalogPredicate struct { 142 key SourceKey 143 } 144 145 func CatalogPredicate(key SourceKey) Predicate { 146 return catalogPredicate{key: key} 147 } 148 149 func (c catalogPredicate) Test(o *Entry) bool { 150 return c.key.Equal(o.SourceInfo.Catalog) 151 } 152 153 func (c catalogPredicate) String() string { 154 return fmt.Sprintf("from catalog: %v/%v", c.key.Namespace, c.key.Name) 155 } 156 157 type gvkPredicate struct { 158 api opregistry.APIKey 159 } 160 161 func ProvidingAPIPredicate(api opregistry.APIKey) Predicate { 162 return gvkPredicate{ 163 api: api, 164 } 165 } 166 167 func (g gvkPredicate) Test(o *Entry) bool { 168 for _, p := range o.Properties { 169 if p.Type != opregistry.GVKType { 170 continue 171 } 172 var prop opregistry.GVKProperty 173 err := json.Unmarshal([]byte(p.Value), &prop) 174 if err != nil { 175 continue 176 } 177 if prop.Kind == g.api.Kind && prop.Version == g.api.Version && prop.Group == g.api.Group { 178 return true 179 } 180 } 181 return false 182 } 183 184 func (g gvkPredicate) String() string { 185 return fmt.Sprintf("providing an API with group: %s, version: %s, kind: %s", g.api.Group, g.api.Version, g.api.Kind) 186 } 187 188 type skipRangeIncludesPredication struct { 189 version semver.Version 190 } 191 192 func SkipRangeIncludesPredicate(version semver.Version) Predicate { 193 return skipRangeIncludesPredication{version: version} 194 } 195 196 func (s skipRangeIncludesPredication) Test(o *Entry) bool { 197 return o.SkipRange != nil && o.SkipRange(s.version) 198 } 199 200 func (s skipRangeIncludesPredication) String() string { 201 return fmt.Sprintf("skip range includes: %v", s.version.String()) 202 } 203 204 type replacesPredicate string 205 206 func ReplacesPredicate(replaces string) Predicate { 207 return replacesPredicate(replaces) 208 } 209 210 func (r replacesPredicate) Test(o *Entry) bool { 211 if o.Replaces == string(r) { 212 return true 213 } 214 for _, s := range o.Skips { 215 if s == string(r) { 216 return true 217 } 218 } 219 return false 220 } 221 222 func (r replacesPredicate) String() string { 223 return fmt.Sprintf("replaces: %v", string(r)) 224 } 225 226 type andPredicate struct { 227 predicates []Predicate 228 } 229 230 func And(p ...Predicate) Predicate { 231 return andPredicate{ 232 predicates: p, 233 } 234 } 235 236 func (p andPredicate) Test(o *Entry) bool { 237 for _, predicate := range p.predicates { 238 if !predicate.Test(o) { 239 return false 240 } 241 } 242 return true 243 } 244 245 func (p andPredicate) String() string { 246 var b bytes.Buffer 247 for i, predicate := range p.predicates { 248 b.WriteString(predicate.String()) 249 if i != len(p.predicates)-1 { 250 b.WriteString(" and ") 251 } 252 } 253 return b.String() 254 } 255 256 func Or(p ...Predicate) Predicate { 257 return orPredicate{ 258 predicates: p, 259 } 260 } 261 262 type orPredicate struct { 263 predicates []Predicate 264 } 265 266 func (p orPredicate) Test(o *Entry) bool { 267 for _, predicate := range p.predicates { 268 if predicate.Test(o) { 269 return true 270 } 271 } 272 return false 273 } 274 275 func (p orPredicate) String() string { 276 var b bytes.Buffer 277 for i, predicate := range p.predicates { 278 b.WriteString(predicate.String()) 279 if i != len(p.predicates)-1 { 280 b.WriteString(" or ") 281 } 282 } 283 return b.String() 284 } 285 286 func Not(p ...Predicate) Predicate { 287 return notPredicate{ 288 predicates: p, 289 } 290 } 291 292 type notPredicate struct { 293 predicates []Predicate 294 } 295 296 func (p notPredicate) Test(o *Entry) bool { 297 // !pred && !pred is equivalent to !(pred || pred). 298 return !orPredicate(p).Test(o) 299 } 300 301 func (p notPredicate) String() string { 302 var b bytes.Buffer 303 for i, predicate := range p.predicates { 304 b.WriteString(predicate.String()) 305 if i != len(p.predicates)-1 { 306 b.WriteString(" and not ") 307 } 308 } 309 return b.String() 310 } 311 312 type booleanPredicate struct { 313 result bool 314 } 315 316 func BooleanPredicate(result bool) Predicate { 317 return booleanPredicate{result: result} 318 } 319 320 func (b booleanPredicate) Test(o *Entry) bool { 321 return b.result 322 } 323 324 func (b booleanPredicate) String() string { 325 if b.result { 326 return "predicate is true" 327 } 328 return "predicate is false" 329 } 330 331 func True() Predicate { 332 return BooleanPredicate(true) 333 } 334 335 func False() Predicate { 336 return BooleanPredicate(false) 337 } 338 339 type countingPredicate struct { 340 p Predicate 341 n *int 342 } 343 344 func (c countingPredicate) Test(o *Entry) bool { 345 if c.p.Test(o) { 346 *c.n++ 347 return true 348 } 349 return false 350 } 351 352 func (c countingPredicate) String() string { 353 return c.p.String() 354 } 355 356 func CountingPredicate(p Predicate, n *int) Predicate { 357 return countingPredicate{p: p, n: n} 358 } 359 360 type celPredicate struct { 361 program constraints.CelProgram 362 rule string 363 failureMessage string 364 } 365 366 func (cp *celPredicate) Test(entry *Entry) bool { 367 props := make([]map[string]interface{}, len(entry.Properties)) 368 for i, p := range entry.Properties { 369 var v interface{} 370 if err := json.Unmarshal([]byte(p.Value), &v); err != nil { 371 continue 372 } 373 props[i] = map[string]interface{}{ 374 "type": p.Type, 375 "value": v, 376 } 377 } 378 379 ok, err := cp.program.Evaluate(map[string]interface{}{"properties": props}) 380 if err != nil { 381 return false 382 } 383 return ok 384 } 385 386 func CreateCelPredicate(env *constraints.CelEnvironment, rule string, failureMessage string) (Predicate, error) { 387 prog, err := env.Validate(rule) 388 if err != nil { 389 return nil, err 390 } 391 return &celPredicate{program: prog, rule: rule, failureMessage: failureMessage}, nil 392 } 393 394 func (cp *celPredicate) String() string { 395 return fmt.Sprintf("with constraint: %q and message: %q", cp.rule, cp.failureMessage) 396 }