github.com/imran-kn/cilium-fork@v1.6.9/pkg/policy/api/selector.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package api
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/cilium/cilium/pkg/labels"
    23  	"github.com/cilium/cilium/pkg/logging"
    24  	"github.com/cilium/cilium/pkg/logging/logfields"
    25  	"github.com/cilium/cilium/pkg/metrics"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/apis/meta/v1/validation"
    28  	k8sLbls "k8s.io/apimachinery/pkg/labels"
    29  )
    30  
    31  var log = logging.DefaultLogger.WithField(logfields.LogSubsys, "policy-api")
    32  
    33  // EndpointSelector is a wrapper for k8s LabelSelector.
    34  type EndpointSelector struct {
    35  	*metav1.LabelSelector
    36  
    37  	// requirements provides a cache for a k8s-friendly format of the
    38  	// LabelSelector, which allows more efficient matching in Matches().
    39  	//
    40  	// Kept as a pointer to allow EndpointSelector to be used as a map key.
    41  	requirements *k8sLbls.Requirements
    42  
    43  	// cachedString is the cached representation of the LabelSelector for this
    44  	// EndpointSelector. It is populated when EndpointSelectors are created
    45  	// via `NewESFromMatchRequirements`. It is immutable after its creation.
    46  	cachedLabelSelectorString string
    47  }
    48  
    49  // LabelSelectorString returns a user-friendly string representation of
    50  // EndpointSelector.
    51  func (n *EndpointSelector) LabelSelectorString() string {
    52  	if n != nil && n.LabelSelector == nil {
    53  		return "<all>"
    54  	}
    55  	return metav1.FormatLabelSelector(n.LabelSelector)
    56  }
    57  
    58  // String returns a string representation of EndpointSelector.
    59  func (n EndpointSelector) String() string {
    60  	j, _ := n.MarshalJSON()
    61  	return string(j)
    62  }
    63  
    64  // CachedString returns the cached string representation of the LabelSelector
    65  // for this EndpointSelector.
    66  func (n EndpointSelector) CachedString() string {
    67  	return n.cachedLabelSelectorString
    68  }
    69  
    70  // UnmarshalJSON unmarshals the endpoint selector from the byte array.
    71  func (n *EndpointSelector) UnmarshalJSON(b []byte) error {
    72  	n.LabelSelector = &metav1.LabelSelector{}
    73  	err := json.Unmarshal(b, n.LabelSelector)
    74  	if err != nil {
    75  		return err
    76  	}
    77  	if n.MatchLabels != nil {
    78  		ml := map[string]string{}
    79  		for k, v := range n.MatchLabels {
    80  			ml[labels.GetExtendedKeyFrom(k)] = v
    81  		}
    82  		n.MatchLabels = ml
    83  	}
    84  	if n.MatchExpressions != nil {
    85  		newMatchExpr := make([]metav1.LabelSelectorRequirement, len(n.MatchExpressions))
    86  		for i, v := range n.MatchExpressions {
    87  			v.Key = labels.GetExtendedKeyFrom(v.Key)
    88  			newMatchExpr[i] = v
    89  		}
    90  		n.MatchExpressions = newMatchExpr
    91  	}
    92  	n.requirements = labelSelectorToRequirements(n.LabelSelector)
    93  	n.cachedLabelSelectorString = n.LabelSelector.String()
    94  	return nil
    95  }
    96  
    97  // MarshalJSON returns a JSON representation of the byte array.
    98  func (n EndpointSelector) MarshalJSON() ([]byte, error) {
    99  	ls := metav1.LabelSelector{}
   100  
   101  	if n.LabelSelector == nil {
   102  		return json.Marshal(ls)
   103  	}
   104  
   105  	if n.MatchLabels != nil {
   106  		newLabels := map[string]string{}
   107  		for k, v := range n.MatchLabels {
   108  			newLabels[labels.GetCiliumKeyFrom(k)] = v
   109  		}
   110  		ls.MatchLabels = newLabels
   111  	}
   112  	if n.MatchExpressions != nil {
   113  		newMatchExpr := make([]metav1.LabelSelectorRequirement, len(n.MatchExpressions))
   114  		for i, v := range n.MatchExpressions {
   115  			v.Key = labels.GetCiliumKeyFrom(v.Key)
   116  			newMatchExpr[i] = v
   117  		}
   118  		ls.MatchExpressions = newMatchExpr
   119  	}
   120  	return json.Marshal(ls)
   121  }
   122  
   123  // HasKeyPrefix checks if the endpoint selector contains the given key prefix in
   124  // its MatchLabels map and MatchExpressions slice.
   125  func (n EndpointSelector) HasKeyPrefix(prefix string) bool {
   126  	for k := range n.MatchLabels {
   127  		if strings.HasPrefix(k, prefix) {
   128  			return true
   129  		}
   130  	}
   131  	for _, v := range n.MatchExpressions {
   132  		if strings.HasPrefix(v.Key, prefix) {
   133  			return true
   134  		}
   135  	}
   136  	return false
   137  }
   138  
   139  // HasKey checks if the endpoint selector contains the given key in
   140  // its MatchLabels map or in its MatchExpressions slice.
   141  func (n EndpointSelector) HasKey(key string) bool {
   142  	if _, ok := n.MatchLabels[key]; ok {
   143  		return true
   144  	}
   145  	for _, v := range n.MatchExpressions {
   146  		if v.Key == key {
   147  			return true
   148  		}
   149  	}
   150  	return false
   151  }
   152  
   153  // GetMatch checks for a match on the specified key, and returns the value that
   154  // the key must match, and true. If a match cannot be found, returns nil, false.
   155  func (n EndpointSelector) GetMatch(key string) ([]string, bool) {
   156  	if value, ok := n.MatchLabels[key]; ok {
   157  		return []string{value}, true
   158  	}
   159  	for _, v := range n.MatchExpressions {
   160  		if v.Key == key && v.Operator == metav1.LabelSelectorOpIn {
   161  			return v.Values, true
   162  		}
   163  	}
   164  	return nil, false
   165  }
   166  
   167  // labelSelectorToRequirements turns a kubernetes Selector into a slice of
   168  // requirements equivalent to the selector. These are cached internally in the
   169  // EndpointSelector to speed up Matches().
   170  //
   171  // This validates the labels, which can be expensive (and may fail..)
   172  // If there's an error, the selector will be nil and the Matches()
   173  // implementation will refuse to match any labels.
   174  func labelSelectorToRequirements(labelSelector *metav1.LabelSelector) *k8sLbls.Requirements {
   175  	selector, err := metav1.LabelSelectorAsSelector(labelSelector)
   176  	if err != nil {
   177  		metrics.PolicyImportErrors.Inc()
   178  		log.WithError(err).WithField(logfields.EndpointLabelSelector,
   179  			logfields.Repr(labelSelector)).Error("unable to construct selector in label selector")
   180  		return nil
   181  	}
   182  
   183  	requirements, selectable := selector.Requirements()
   184  	if !selectable {
   185  		return nil
   186  	}
   187  	return &requirements
   188  }
   189  
   190  // NewESFromLabels creates a new endpoint selector from the given labels.
   191  func NewESFromLabels(lbls ...labels.Label) EndpointSelector {
   192  	ml := map[string]string{}
   193  	for _, lbl := range lbls {
   194  		ml[lbl.GetExtendedKey()] = lbl.Value
   195  	}
   196  
   197  	return NewESFromMatchRequirements(ml, nil)
   198  }
   199  
   200  // NewESFromMatchRequirements creates a new endpoint selector from the given
   201  // match specifications: An optional set of labels that must match, and
   202  // an optional slice of LabelSelectorRequirements.
   203  //
   204  // If the caller intends to reuse 'matchLabels' or 'reqs' after creating the
   205  // EndpointSelector, they must make a copy of the parameter.
   206  func NewESFromMatchRequirements(matchLabels map[string]string, reqs []metav1.LabelSelectorRequirement) EndpointSelector {
   207  	labelSelector := &metav1.LabelSelector{
   208  		MatchLabels:      matchLabels,
   209  		MatchExpressions: reqs,
   210  	}
   211  	return EndpointSelector{
   212  		LabelSelector:             labelSelector,
   213  		requirements:              labelSelectorToRequirements(labelSelector),
   214  		cachedLabelSelectorString: labelSelector.String(),
   215  	}
   216  }
   217  
   218  // SyncRequirementsWithLabelSelector ensures that the requirements within the
   219  // specified EndpointSelector are in sync with the LabelSelector. This is
   220  // because the LabelSelector has publicly accessible fields, which can be
   221  // updated without concurrently updating the requirements, so the two fields can
   222  // become out of sync.
   223  func (n *EndpointSelector) SyncRequirementsWithLabelSelector() {
   224  	n.requirements = labelSelectorToRequirements(n.LabelSelector)
   225  }
   226  
   227  // newReservedEndpointSelector returns a selector that matches on all
   228  // endpoints with the specified reserved label.
   229  func newReservedEndpointSelector(ID string) EndpointSelector {
   230  	reservedLabels := labels.NewLabel(ID, "", labels.LabelSourceReserved)
   231  	return NewESFromLabels(reservedLabels)
   232  }
   233  
   234  var (
   235  	// WildcardEndpointSelector is a wildcard endpoint selector matching
   236  	// all endpoints that can be described with labels.
   237  	WildcardEndpointSelector = NewESFromLabels()
   238  
   239  	// ReservedEndpointSelectors map reserved labels to EndpointSelectors
   240  	// that will match those endpoints.
   241  	ReservedEndpointSelectors = map[string]EndpointSelector{
   242  		labels.IDNameHost:  newReservedEndpointSelector(labels.IDNameHost),
   243  		labels.IDNameWorld: newReservedEndpointSelector(labels.IDNameWorld),
   244  	}
   245  )
   246  
   247  // NewESFromK8sLabelSelector returns a new endpoint selector from the label
   248  // where it the given srcPrefix will be encoded in the label's keys.
   249  func NewESFromK8sLabelSelector(srcPrefix string, lss ...*metav1.LabelSelector) EndpointSelector {
   250  	var (
   251  		matchLabels      map[string]string
   252  		matchExpressions []metav1.LabelSelectorRequirement
   253  	)
   254  	for _, ls := range lss {
   255  		if ls == nil {
   256  			continue
   257  		}
   258  		if ls.MatchLabels != nil {
   259  			if matchLabels == nil {
   260  				matchLabels = map[string]string{}
   261  			}
   262  			for k, v := range ls.MatchLabels {
   263  				matchLabels[srcPrefix+k] = v
   264  			}
   265  		}
   266  		if ls.MatchExpressions != nil {
   267  			if matchExpressions == nil {
   268  				matchExpressions = make([]metav1.LabelSelectorRequirement, 0, len(ls.MatchExpressions))
   269  			}
   270  			for _, v := range ls.MatchExpressions {
   271  				v.Key = srcPrefix + v.Key
   272  				matchExpressions = append(matchExpressions, v)
   273  			}
   274  		}
   275  	}
   276  	return NewESFromMatchRequirements(matchLabels, matchExpressions)
   277  }
   278  
   279  // AddMatch adds a match for 'key' == 'value' to the endpoint selector.
   280  func (n *EndpointSelector) AddMatch(key, value string) {
   281  	if n.MatchLabels == nil {
   282  		n.MatchLabels = map[string]string{}
   283  	}
   284  	n.MatchLabels[key] = value
   285  	n.requirements = labelSelectorToRequirements(n.LabelSelector)
   286  	n.cachedLabelSelectorString = n.LabelSelector.String()
   287  }
   288  
   289  // Matches returns true if the endpoint selector Matches the `lblsToMatch`.
   290  // Returns always true if the endpoint selector contains the reserved label for
   291  // "all".
   292  func (n *EndpointSelector) Matches(lblsToMatch k8sLbls.Labels) bool {
   293  	// Try to update cached requirements for this EndpointSelector if possible.
   294  	if n.requirements == nil {
   295  		n.requirements = labelSelectorToRequirements(n.LabelSelector)
   296  		// Nil indicates that requirements failed validation in some way,
   297  		// so we cannot parse the labels for matching purposes; thus, we cannot
   298  		// match if labels cannot be parsed, so return false.
   299  		if n.requirements == nil {
   300  			return false
   301  		}
   302  	}
   303  	for _, req := range *n.requirements {
   304  		if !req.Matches(lblsToMatch) {
   305  			return false
   306  		}
   307  	}
   308  	return true
   309  }
   310  
   311  // IsWildcard returns true if the endpoint selector selects all endpoints.
   312  func (n *EndpointSelector) IsWildcard() bool {
   313  	return n.LabelSelector != nil &&
   314  		len(n.LabelSelector.MatchLabels)+len(n.LabelSelector.MatchExpressions) == 0
   315  }
   316  
   317  // ConvertToLabelSelectorRequirementSlice converts the MatchLabels and
   318  // MatchExpressions within the specified EndpointSelector into a list of
   319  // LabelSelectorRequirements.
   320  func (n *EndpointSelector) ConvertToLabelSelectorRequirementSlice() []metav1.LabelSelectorRequirement {
   321  	requirements := make([]metav1.LabelSelectorRequirement, 0, len(n.MatchExpressions)+len(n.MatchLabels))
   322  	// Append already existing match expressions.
   323  	requirements = append(requirements, n.MatchExpressions...)
   324  	// Convert each MatchLables to LabelSelectorRequirement.
   325  	for key, value := range n.MatchLabels {
   326  		requirementFromMatchLabels := metav1.LabelSelectorRequirement{
   327  			Key:      key,
   328  			Operator: metav1.LabelSelectorOpIn,
   329  			Values:   []string{value},
   330  		}
   331  		requirements = append(requirements, requirementFromMatchLabels)
   332  	}
   333  	return requirements
   334  }
   335  
   336  // sanitize returns an error if the EndpointSelector's LabelSelector is invalid.
   337  func (n *EndpointSelector) sanitize() error {
   338  	errList := validation.ValidateLabelSelector(n.LabelSelector, nil)
   339  	if len(errList) > 0 {
   340  		return fmt.Errorf("invalid label selector: %s", errList.ToAggregate().Error())
   341  	}
   342  	return nil
   343  }
   344  
   345  // EndpointSelectorSlice is a slice of EndpointSelectors that can be sorted.
   346  type EndpointSelectorSlice []EndpointSelector
   347  
   348  func (s EndpointSelectorSlice) Len() int      { return len(s) }
   349  func (s EndpointSelectorSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
   350  
   351  func (s EndpointSelectorSlice) Less(i, j int) bool {
   352  	strI := s[i].LabelSelectorString()
   353  	strJ := s[j].LabelSelectorString()
   354  
   355  	return strings.Compare(strI, strJ) < 0
   356  }
   357  
   358  // Matches returns true if any of the EndpointSelectors in the slice match the
   359  // provided labels
   360  func (s EndpointSelectorSlice) Matches(ctx labels.LabelArray) bool {
   361  	for _, selector := range s {
   362  		if selector.Matches(ctx) {
   363  			return true
   364  		}
   365  	}
   366  
   367  	return false
   368  }
   369  
   370  // SelectsAllEndpoints returns whether the EndpointSelectorSlice selects all
   371  // endpoints, which is true if the wildcard endpoint selector is present in the
   372  // slice.
   373  func (s EndpointSelectorSlice) SelectsAllEndpoints() bool {
   374  	for _, selector := range s {
   375  		if selector.IsWildcard() {
   376  			return true
   377  		}
   378  	}
   379  	return false
   380  }