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  }