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 }