knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/webhook/psbinding/index.go (about)

     1  /*
     2  Copyright 2019 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package psbinding
    18  
    19  import (
    20  	"sync"
    21  
    22  	"k8s.io/apimachinery/pkg/labels"
    23  )
    24  
    25  // exactKey is the type for keys that match exactly.
    26  type exactKey struct {
    27  	Group     string
    28  	Kind      string
    29  	Namespace string
    30  	Name      string
    31  }
    32  
    33  // exactMatcher is our reverse index from subjects to the Bindings that apply to
    34  // them.
    35  type exactMatcher map[exactKey][]Bindable
    36  
    37  // add associates a Binding with a key in the reverse index.
    38  func (em exactMatcher) add(key exactKey, b Bindable) {
    39  	em[key] = append(em[key], b)
    40  }
    41  
    42  // get fetches the key from the reverse index, if present.
    43  func (em exactMatcher) get(key exactKey) []Bindable {
    44  	return em[key]
    45  }
    46  
    47  // inexactKey is the type for keys that match inexactly (via selector)
    48  type inexactKey struct {
    49  	Group     string
    50  	Kind      string
    51  	Namespace string
    52  }
    53  
    54  // pair holds selectors and bindables for a particular inexactKey.
    55  type pair struct {
    56  	selector labels.Selector
    57  	sb       Bindable
    58  }
    59  
    60  // inexactMatcher is our reverse index from subjects to the Bindings that apply to
    61  // them.
    62  type inexactMatcher map[inexactKey][]pair
    63  
    64  // add writes a key into the reverse index.
    65  func (im inexactMatcher) add(key inexactKey, selector labels.Selector, b Bindable) {
    66  	pl := im[key]
    67  	pl = append(pl, pair{
    68  		selector: selector,
    69  		sb:       b,
    70  	})
    71  	im[key] = pl
    72  }
    73  
    74  // get fetches the key from the reverse index, if present.
    75  func (im inexactMatcher) get(key inexactKey, ls labels.Set) []Bindable {
    76  	found := []Bindable{}
    77  	// Iterate over the list of pairs matched for this GK + namespace and collect the
    78  	// Bindables that matches our selector.
    79  	for _, p := range im[key] {
    80  		if p.selector.Matches(ls) {
    81  			found = append(found, p.sb)
    82  		}
    83  	}
    84  	return found
    85  }
    86  
    87  // index is a collection of Bindables indexed by their subject resources.
    88  type index struct {
    89  	// lock protects access to exact and inexact
    90  	lock    sync.RWMutex
    91  	exact   exactMatcher
    92  	inexact inexactMatcher
    93  }
    94  
    95  // indexBuilder allows an index to be built atomically
    96  type indexBuilder struct {
    97  	exact   exactMatcher
    98  	inexact inexactMatcher
    99  }
   100  
   101  // newIndexBuilder constructs a new IndexBuilder.
   102  func newIndexBuilder() *indexBuilder {
   103  	return &indexBuilder{
   104  		exact:   make(exactMatcher),
   105  		inexact: make(inexactMatcher),
   106  	}
   107  }
   108  
   109  // associate associates a resource with a given exact key with a given Bindable.
   110  func (ib *indexBuilder) associate(key exactKey, fb Bindable) *indexBuilder {
   111  	ib.exact.add(key, fb)
   112  	return ib
   113  }
   114  
   115  // associateSelection associates resources with the given inexact key and labels matching the given selector with a given Bindable.
   116  func (ib *indexBuilder) associateSelection(inexactKey inexactKey, selector labels.Selector, fb Bindable) *indexBuilder {
   117  	ib.inexact.add(inexactKey, selector, fb)
   118  	return ib
   119  }
   120  
   121  // build sets the given index to the built value.
   122  func (ib *indexBuilder) build(index *index) {
   123  	index.setIndex(ib.exact, ib.inexact)
   124  }
   125  
   126  // setIndex replaces the index atomically with the given matchers.
   127  func (idx *index) setIndex(exact exactMatcher, inexact inexactMatcher) {
   128  	idx.lock.Lock()
   129  	defer idx.lock.Unlock()
   130  	idx.exact = exact
   131  	idx.inexact = inexact
   132  }
   133  
   134  // lookUp returns the Bindables associated with a resource with the given group, kind, namespace, name, and labels.
   135  func (idx *index) lookUp(key exactKey, labels labels.Set) []Bindable {
   136  	idx.lock.RLock()
   137  	defer idx.lock.RUnlock()
   138  
   139  	exactMatches := idx.exact.get(key)
   140  
   141  	inexactMatches := idx.inexact.get(inexactKey{
   142  		Group:     key.Group,
   143  		Kind:      key.Kind,
   144  		Namespace: key.Namespace,
   145  	}, labels)
   146  
   147  	return append(exactMatches, inexactMatches...)
   148  }