k8s.io/apiserver@v0.29.3/pkg/storage/selection_predicate.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes 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 storage
    18  
    19  import (
    20  	"k8s.io/apimachinery/pkg/api/meta"
    21  	"k8s.io/apimachinery/pkg/fields"
    22  	"k8s.io/apimachinery/pkg/labels"
    23  	"k8s.io/apimachinery/pkg/runtime"
    24  )
    25  
    26  // AttrFunc returns label and field sets and the uninitialized flag for List or Watch to match.
    27  // In any failure to parse given object, it returns error.
    28  type AttrFunc func(obj runtime.Object) (labels.Set, fields.Set, error)
    29  
    30  // FieldMutationFunc allows the mutation of the field selection fields.  It is mutating to
    31  // avoid the extra allocation on this common path
    32  type FieldMutationFunc func(obj runtime.Object, fieldSet fields.Set) error
    33  
    34  func DefaultClusterScopedAttr(obj runtime.Object) (labels.Set, fields.Set, error) {
    35  	metadata, err := meta.Accessor(obj)
    36  	if err != nil {
    37  		return nil, nil, err
    38  	}
    39  	fieldSet := fields.Set{
    40  		"metadata.name": metadata.GetName(),
    41  	}
    42  
    43  	return labels.Set(metadata.GetLabels()), fieldSet, nil
    44  }
    45  
    46  func DefaultNamespaceScopedAttr(obj runtime.Object) (labels.Set, fields.Set, error) {
    47  	metadata, err := meta.Accessor(obj)
    48  	if err != nil {
    49  		return nil, nil, err
    50  	}
    51  	fieldSet := fields.Set{
    52  		"metadata.name":      metadata.GetName(),
    53  		"metadata.namespace": metadata.GetNamespace(),
    54  	}
    55  
    56  	return labels.Set(metadata.GetLabels()), fieldSet, nil
    57  }
    58  
    59  func (f AttrFunc) WithFieldMutation(fieldMutator FieldMutationFunc) AttrFunc {
    60  	return func(obj runtime.Object) (labels.Set, fields.Set, error) {
    61  		labelSet, fieldSet, err := f(obj)
    62  		if err != nil {
    63  			return nil, nil, err
    64  		}
    65  		if err := fieldMutator(obj, fieldSet); err != nil {
    66  			return nil, nil, err
    67  		}
    68  		return labelSet, fieldSet, nil
    69  	}
    70  }
    71  
    72  // SelectionPredicate is used to represent the way to select objects from api storage.
    73  type SelectionPredicate struct {
    74  	Label               labels.Selector
    75  	Field               fields.Selector
    76  	GetAttrs            AttrFunc
    77  	IndexLabels         []string
    78  	IndexFields         []string
    79  	Limit               int64
    80  	Continue            string
    81  	AllowWatchBookmarks bool
    82  }
    83  
    84  // Matches returns true if the given object's labels and fields (as
    85  // returned by s.GetAttrs) match s.Label and s.Field. An error is
    86  // returned if s.GetAttrs fails.
    87  func (s *SelectionPredicate) Matches(obj runtime.Object) (bool, error) {
    88  	if s.Empty() {
    89  		return true, nil
    90  	}
    91  	labels, fields, err := s.GetAttrs(obj)
    92  	if err != nil {
    93  		return false, err
    94  	}
    95  	matched := s.Label.Matches(labels)
    96  	if matched && s.Field != nil {
    97  		matched = matched && s.Field.Matches(fields)
    98  	}
    99  	return matched, nil
   100  }
   101  
   102  // MatchesObjectAttributes returns true if the given labels and fields
   103  // match s.Label and s.Field.
   104  func (s *SelectionPredicate) MatchesObjectAttributes(l labels.Set, f fields.Set) bool {
   105  	if s.Label.Empty() && s.Field.Empty() {
   106  		return true
   107  	}
   108  	matched := s.Label.Matches(l)
   109  	if matched && s.Field != nil {
   110  		matched = (matched && s.Field.Matches(f))
   111  	}
   112  	return matched
   113  }
   114  
   115  // MatchesSingleNamespace will return (namespace, true) if and only if s.Field matches on the object's
   116  // namespace.
   117  func (s *SelectionPredicate) MatchesSingleNamespace() (string, bool) {
   118  	if len(s.Continue) > 0 {
   119  		return "", false
   120  	}
   121  	if namespace, ok := s.Field.RequiresExactMatch("metadata.namespace"); ok {
   122  		return namespace, true
   123  	}
   124  	return "", false
   125  }
   126  
   127  // MatchesSingle will return (name, true) if and only if s.Field matches on the object's
   128  // name.
   129  func (s *SelectionPredicate) MatchesSingle() (string, bool) {
   130  	if len(s.Continue) > 0 {
   131  		return "", false
   132  	}
   133  	// TODO: should be namespace.name
   134  	if name, ok := s.Field.RequiresExactMatch("metadata.name"); ok {
   135  		return name, true
   136  	}
   137  	return "", false
   138  }
   139  
   140  // Empty returns true if the predicate performs no filtering.
   141  func (s *SelectionPredicate) Empty() bool {
   142  	return s.Label.Empty() && s.Field.Empty()
   143  }
   144  
   145  // For any index defined by IndexFields, if a matcher can match only (a subset)
   146  // of objects that return <value> for a given index, a pair (<index name>, <value>)
   147  // wil be returned.
   148  func (s *SelectionPredicate) MatcherIndex() []MatchValue {
   149  	var result []MatchValue
   150  	for _, field := range s.IndexFields {
   151  		if value, ok := s.Field.RequiresExactMatch(field); ok {
   152  			result = append(result, MatchValue{IndexName: FieldIndex(field), Value: value})
   153  		}
   154  	}
   155  	for _, label := range s.IndexLabels {
   156  		if value, ok := s.Label.RequiresExactMatch(label); ok {
   157  			result = append(result, MatchValue{IndexName: LabelIndex(label), Value: value})
   158  		}
   159  	}
   160  	return result
   161  }
   162  
   163  // LabelIndex add prefix for label index.
   164  func LabelIndex(label string) string {
   165  	return "l:" + label
   166  }
   167  
   168  // FiledIndex add prefix for field index.
   169  func FieldIndex(field string) string {
   170  	return "f:" + field
   171  }