github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/kcc/kcct.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 kcc 18 19 import ( 20 "context" 21 "fmt" 22 "time" 23 24 v1 "k8s.io/api/core/v1" 25 apiequality "k8s.io/apimachinery/pkg/api/equality" 26 apierrors "k8s.io/apimachinery/pkg/api/errors" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 29 "k8s.io/apimachinery/pkg/labels" 30 "k8s.io/apimachinery/pkg/selection" 31 utilruntime "k8s.io/apimachinery/pkg/util/runtime" 32 "k8s.io/apimachinery/pkg/util/sets" 33 "k8s.io/apimachinery/pkg/util/wait" 34 "k8s.io/client-go/tools/cache" 35 "k8s.io/klog/v2" 36 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 37 38 configapis "github.com/kubewharf/katalyst-api/pkg/apis/config/v1alpha1" 39 configinformers "github.com/kubewharf/katalyst-api/pkg/client/informers/externalversions/config/v1alpha1" 40 "github.com/kubewharf/katalyst-api/pkg/client/listers/config/v1alpha1" 41 kcclient "github.com/kubewharf/katalyst-core/pkg/client" 42 "github.com/kubewharf/katalyst-core/pkg/client/control" 43 "github.com/kubewharf/katalyst-core/pkg/config/controller" 44 "github.com/kubewharf/katalyst-core/pkg/config/generic" 45 "github.com/kubewharf/katalyst-core/pkg/consts" 46 kcctarget "github.com/kubewharf/katalyst-core/pkg/controller/kcc/target" 47 kccutil "github.com/kubewharf/katalyst-core/pkg/controller/kcc/util" 48 "github.com/kubewharf/katalyst-core/pkg/metrics" 49 "github.com/kubewharf/katalyst-core/pkg/util" 50 "github.com/kubewharf/katalyst-core/pkg/util/native" 51 ) 52 53 const ( 54 kccTargetControllerName = "kcct" 55 ) 56 57 const ( 58 kccTargetConditionReasonNormal = "Normal" 59 kccTargetConditionReasonHashFailed = "HashFailed" 60 kccTargetConditionReasonMatchMoreOrLessThanOneKCC = "MatchMoreOrLessThanOneKCC" 61 kccTargetConditionReasonValidateFailed = "ValidateFailed" 62 ) 63 64 type KatalystCustomConfigTargetController struct { 65 ctx context.Context 66 dryRun bool 67 kccConfig *controller.KCCConfig 68 69 client *kcclient.GenericClientSet 70 kccControl control.KCCControl 71 unstructuredControl control.UnstructuredControl 72 73 // katalystCustomConfigLister can list/get KatalystCustomConfig from the shared informer's store 74 katalystCustomConfigLister v1alpha1.KatalystCustomConfigLister 75 76 syncedFunc []cache.InformerSynced 77 78 // targetHandler store gvr kcc and gvr 79 targetHandler *kcctarget.KatalystCustomConfigTargetHandler 80 81 // metricsEmitter for emit metrics 82 metricsEmitter metrics.MetricEmitter 83 } 84 85 func NewKatalystCustomConfigTargetController( 86 ctx context.Context, 87 genericConf *generic.GenericConfiguration, 88 _ *controller.GenericControllerConfiguration, 89 kccConfig *controller.KCCConfig, 90 client *kcclient.GenericClientSet, 91 katalystCustomConfigInformer configinformers.KatalystCustomConfigInformer, 92 metricsEmitter metrics.MetricEmitter, 93 targetHandler *kcctarget.KatalystCustomConfigTargetHandler, 94 ) (*KatalystCustomConfigTargetController, error) { 95 k := &KatalystCustomConfigTargetController{ 96 ctx: ctx, 97 client: client, 98 dryRun: genericConf.DryRun, 99 kccConfig: kccConfig, 100 katalystCustomConfigLister: katalystCustomConfigInformer.Lister(), 101 targetHandler: targetHandler, 102 syncedFunc: []cache.InformerSynced{ 103 katalystCustomConfigInformer.Informer().HasSynced, 104 targetHandler.HasSynced, 105 }, 106 } 107 108 if metricsEmitter == nil { 109 k.metricsEmitter = metrics.DummyMetrics{} 110 } else { 111 k.metricsEmitter = metricsEmitter.WithTags(kccTargetControllerName) 112 } 113 114 k.kccControl = control.DummyKCCControl{} 115 k.unstructuredControl = control.DummyUnstructuredControl{} 116 if !k.dryRun { 117 k.kccControl = control.NewRealKCCControl(client.InternalClient) 118 k.unstructuredControl = control.NewRealUnstructuredControl(client.DynamicClient) 119 } 120 121 // register kcc-target informer handler 122 targetHandler.RegisterTargetHandler(kccTargetControllerName, k.katalystCustomConfigTargetHandler) 123 return k, nil 124 } 125 126 // Run don't need to trigger reconcile logic. 127 func (k *KatalystCustomConfigTargetController) Run() { 128 defer utilruntime.HandleCrash() 129 130 defer klog.Infof("shutting down %s controller", kccTargetControllerName) 131 132 if !cache.WaitForCacheSync(k.ctx.Done(), k.syncedFunc...) { 133 utilruntime.HandleError(fmt.Errorf("unable to sync caches for %s controller", kccTargetControllerName)) 134 return 135 } 136 klog.Infof("caches are synced for %s controller", kccTargetControllerName) 137 138 go wait.Until(k.clearExpiredKCCTarget, 30*time.Second, k.ctx.Done()) 139 140 <-k.ctx.Done() 141 } 142 143 // katalystCustomConfigTargetHandler process object of kcc target type from targetAccessor, and 144 // KatalystCustomConfigTargetAccessor will call this handler when some update event on target is added. 145 func (k *KatalystCustomConfigTargetController) katalystCustomConfigTargetHandler(gvr metav1.GroupVersionResource, target *unstructured.Unstructured) error { 146 for _, syncFunc := range k.syncedFunc { 147 if !syncFunc() { 148 return fmt.Errorf("[kcct] informer has not synced") 149 } 150 } 151 152 klog.V(4).Infof("gvr: %s, target: %s updated", gvr.String(), native.GenerateUniqObjectNameKey(target)) 153 154 if target.GetDeletionTimestamp() != nil { 155 err := k.handleKCCTargetFinalizer(gvr, target) 156 if err != nil { 157 return err 158 } 159 return nil 160 } 161 162 target, err := kccutil.EnsureKCCTargetFinalizer(k.ctx, k.unstructuredControl, 163 consts.KatalystCustomConfigTargetFinalizerKCCT, gvr, target) 164 if err != nil { 165 return err 166 } 167 168 // add kcc target config process logic: 169 // 1. clear expired valid target config 170 // 2. generate hash of current target config and update it to annotation 171 // 3. todo: control revision history if needed 172 // 4. update target config annotation and status if needed 173 174 targetResource := util.ToKCCTargetResource(target) 175 if isExpired := targetResource.CheckExpired(time.Now()); isExpired { 176 // delete expired kcc target 177 err := k.unstructuredControl.DeleteUnstructured(k.ctx, gvr, target, metav1.DeleteOptions{}) 178 if err != nil { 179 return err 180 } 181 return nil 182 } 183 184 var ( 185 isValid bool 186 message, hash, reason string 187 overlapTargets []util.KCCTargetResource 188 ) 189 190 reason = kccTargetConditionReasonNormal 191 kccKeys := k.targetHandler.GetKCCKeyListByGVR(gvr) 192 if len(kccKeys) != 1 { 193 isValid = false 194 reason = kccTargetConditionReasonMatchMoreOrLessThanOneKCC 195 message = fmt.Sprintf("more or less than one kcc %v match same gvr %s", kccKeys, gvr.String()) 196 } else { 197 key := kccKeys[0] 198 namespace, name, err := cache.SplitMetaNamespaceKey(key) 199 if err != nil { 200 klog.Errorf("failed to split namespace and name from key %s", key) 201 return err 202 } 203 204 kcc, err := k.katalystCustomConfigLister.KatalystCustomConfigs(namespace).Get(name) 205 if apierrors.IsNotFound(err) { 206 klog.Warningf("kcc %s is not found", key) 207 return nil 208 } else if err != nil { 209 klog.Errorf("kcc %s get error: %v", key, err) 210 return err 211 } 212 213 isValid, message, overlapTargets, err = k.validateTargetResourceGenericSpec(kcc, targetResource) 214 if err != nil { 215 return err 216 } 217 218 if !isValid { 219 reason = kccTargetConditionReasonValidateFailed 220 } 221 } 222 223 if isValid { 224 // update target resource hash only when config is valid 225 hash, err = targetResource.GenerateConfigHash() 226 if err != nil { 227 // if generate config hash failed set target resource invalid 228 isValid = false 229 message = fmt.Sprintf("generate config hash failed: %s", err) 230 reason = kccTargetConditionReasonHashFailed 231 } 232 233 // set kcc target hash 234 if targetResource.GetHash() != hash { 235 targetResource.SetHash(hash) 236 target, err = k.unstructuredControl.UpdateUnstructured(k.ctx, gvr, target, metav1.UpdateOptions{}) 237 if err != nil { 238 return err 239 } 240 241 targetResource = util.ToKCCTargetResource(target) 242 } 243 } 244 245 // update kcc target status 246 oldKCCTargetResource := targetResource.DeepCopy() 247 updateTargetResourceStatus(targetResource, isValid, message, reason) 248 if !apiequality.Semantic.DeepEqual(oldKCCTargetResource, targetResource) { 249 klog.V(4).Infof("gvr: %s, target: %s need update status", gvr.String(), native.GenerateUniqObjectNameKey(target)) 250 _, err = k.unstructuredControl.UpdateUnstructuredStatus(k.ctx, gvr, target, metav1.UpdateOptions{}) 251 if err != nil { 252 return err 253 } 254 255 if len(overlapTargets) > 0 { 256 // if kcc target status changed, it needs trigger overlap kcc targets to reconcile 257 err := k.enqueueTargets(gvr, overlapTargets) 258 if err != nil { 259 return err 260 } 261 } else if !oldKCCTargetResource.CheckValid() && targetResource.CheckValid() { 262 // if old kcc is overlap and change to valid now, it needs trigger all other invalid kcc targets to reconcile 263 targets, err := k.listAllKCCTargetResource(gvr) 264 if err != nil { 265 return err 266 } 267 268 var invalidTargets []util.KCCTargetResource 269 for _, target := range targets { 270 if targetResource.GetName() == target.GetName() && targetResource.GetNamespace() == target.GetNamespace() { 271 continue 272 } 273 274 if !target.CheckValid() { 275 invalidTargets = append(invalidTargets, target) 276 } 277 } 278 279 err = k.enqueueTargets(gvr, invalidTargets) 280 if err != nil { 281 return err 282 } 283 } 284 } 285 286 return nil 287 } 288 289 func (k *KatalystCustomConfigTargetController) clearExpiredKCCTarget() { 290 k.targetHandler.RangeGVRTargetAccessor(func(gvr metav1.GroupVersionResource, accessor kcctarget.KatalystCustomConfigTargetAccessor) bool { 291 configTargets, err := accessor.List(labels.Everything()) 292 if err != nil { 293 return false 294 } 295 296 for _, target := range configTargets { 297 // expired target config will be re-enqueue periodically to make sure it is cleared 298 if util.ToKCCTargetResource(target).CheckExpired(time.Now()) { 299 accessor.Enqueue(kccTargetControllerName, target) 300 } 301 } 302 return true 303 }) 304 } 305 306 func (k *KatalystCustomConfigTargetController) enqueueTargets(gvr metav1.GroupVersionResource, targets []util.KCCTargetResource) error { 307 accessor, ok := k.targetHandler.GetTargetAccessorByGVR(gvr) 308 if !ok { 309 return fmt.Errorf("target accessor %s not found", gvr) 310 } 311 312 for _, t := range targets { 313 if t.GetDeletionTimestamp() != nil { 314 continue 315 } 316 317 accessor.Enqueue(kccTargetControllerName, t.Unstructured) 318 } 319 320 return nil 321 } 322 323 // handleKCCTargetFinalizer enqueue all kcc target to reconcile when a target was deleted 324 func (k *KatalystCustomConfigTargetController) handleKCCTargetFinalizer(gvr metav1.GroupVersionResource, target *unstructured.Unstructured) error { 325 if !controllerutil.ContainsFinalizer(target, consts.KatalystCustomConfigTargetFinalizerKCCT) { 326 return nil 327 } 328 329 klog.Infof("handling gvr: %s kcc target %s finalizer", gvr.String(), native.GenerateUniqObjectNameKey(target)) 330 targets, err := k.listAllKCCTargetResource(gvr) 331 if err != nil { 332 return err 333 } 334 335 // if kcc target deleted, it needs trigger other target to reconcile 336 err = k.enqueueTargets(gvr, targets) 337 if err != nil { 338 return err 339 } 340 341 err = kccutil.RemoveKCCTargetFinalizer(k.ctx, k.unstructuredControl, consts.KatalystCustomConfigTargetFinalizerKCCT, gvr, target) 342 if err != nil { 343 return err 344 } 345 346 klog.Infof("success remove gvr: %s kcc target %s finalizer", gvr.String(), native.GenerateUniqObjectNameKey(target)) 347 return nil 348 } 349 350 // validateTargetResourceGenericSpec validate target resource generic spec as follows rule: 351 // 1. can not set both labelSelector and nodeNames config at the same time 352 // 2. if nodeNames is not set, lastDuration must not be set either 353 // 3. labelSelector config must only contain kcc' labelSelectorKey in priority allowed key list 354 // 4. labelSelector config cannot overlap with other labelSelector config in same priority 355 // 5. nodeNames config must set lastDuration to make sure it will be auto cleared 356 // 6. nodeNames config cannot overlap with other nodeNames config 357 // 7. it is not allowed two global config (without either labelSelector or nodeNames) overlap 358 func (k *KatalystCustomConfigTargetController) validateTargetResourceGenericSpec(kcc *configapis.KatalystCustomConfig, targetResource util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 359 labelSelector := targetResource.GetLabelSelector() 360 nodeNames := targetResource.GetNodeNames() 361 if len(labelSelector) != 0 && len(nodeNames) != 0 { 362 return false, "both labelSelector and nodeNames has been set", nil, nil 363 } else if len(labelSelector) != 0 { 364 return k.validateTargetResourceLabelSelector(kcc, targetResource) 365 } else if len(nodeNames) != 0 { 366 return k.validateTargetResourceNodeNames(kcc, targetResource) 367 } else { 368 return k.validateTargetResourceGlobal(kcc, targetResource) 369 } 370 } 371 372 func (k *KatalystCustomConfigTargetController) validateTargetResourceLabelSelector(kcc *configapis.KatalystCustomConfig, targetResource util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 373 priorityAllowedKeyListMap := getPriorityAllowedKeyListMap(kcc) 374 if len(priorityAllowedKeyListMap) == 0 { 375 return false, fmt.Sprintf("kcc %s no support label selector", native.GenerateUniqObjectNameKey(kcc)), nil, nil 376 } 377 378 valid, msg, err := validateLabelSelectorMatchWithKCCDefinition(priorityAllowedKeyListMap, targetResource) 379 if err != nil { 380 return false, "", nil, nil 381 } else if !valid { 382 return false, msg, nil, nil 383 } 384 385 kccTargetResources, err := k.listAllKCCTargetResource(kcc.Spec.TargetType) 386 if err != nil { 387 return false, "", nil, err 388 } 389 390 return validateLabelSelectorOverlapped(priorityAllowedKeyListMap, targetResource, kccTargetResources) 391 } 392 393 func getPriorityAllowedKeyListMap(kcc *configapis.KatalystCustomConfig) map[int32]sets.String { 394 priorityAllowedKeyListMap := make(map[int32]sets.String) 395 for _, allowedKey := range kcc.Spec.NodeLabelSelectorAllowedKeyList { 396 priorityAllowedKeyListMap[allowedKey.Priority] = sets.NewString(allowedKey.KeyList...) 397 } 398 return priorityAllowedKeyListMap 399 } 400 401 // validateLabelSelectorMatchWithKCCDefinition make sures that labelSelector config must only contain key in kcc' allowed key list 402 func validateLabelSelectorMatchWithKCCDefinition(priorityAllowedKeyListMap map[int32]sets.String, targetResource util.KCCTargetResource) (bool, string, error) { 403 if targetResource.GetLastDuration() != nil { 404 return false, "both labelSelector and lastDuration has been set", nil 405 } 406 407 labelSelector := targetResource.GetLabelSelector() 408 selector, err := labels.Parse(labelSelector) 409 if err != nil { 410 return false, fmt.Sprintf("labelSelector parse failed: %s", err), nil 411 } 412 413 priority := targetResource.GetPriority() 414 allowedKeyList, ok := priorityAllowedKeyListMap[priority] 415 if !ok { 416 return false, fmt.Sprintf("priority %d not supported", priority), nil 417 } 418 419 reqs, selectable := selector.Requirements() 420 if !selectable { 421 return false, fmt.Sprintf("labelSelector cannot selectable"), nil 422 } 423 424 inValidLabelKeys := sets.String{} 425 for _, r := range reqs { 426 key := r.Key() 427 if !allowedKeyList.Has(key) { 428 inValidLabelKeys.Insert(key) 429 } 430 } 431 432 if len(inValidLabelKeys) > 0 { 433 return false, fmt.Sprintf("labelSelector with invalid key %v (%s)", inValidLabelKeys.List(), allowedKeyList.List()), nil 434 } 435 436 return true, "", nil 437 } 438 439 // validateLabelSelectorOverlapped make sures that labelSelector config cannot overlap with other labelSelector config 440 func validateLabelSelectorOverlapped(priorityAllowedKeyListMap map[int32]sets.String, targetResource util.KCCTargetResource, 441 otherResources []util.KCCTargetResource, 442 ) (bool, string, []util.KCCTargetResource, error) { 443 labelSelector := targetResource.GetLabelSelector() 444 selector, err := labels.Parse(labelSelector) 445 if err != nil { 446 return false, fmt.Sprintf("labelSelector parse failed: %s", err), nil, nil 447 } 448 449 priority := targetResource.GetPriority() 450 allowedKeyList, ok := priorityAllowedKeyListMap[priority] 451 if !ok { 452 return false, fmt.Sprintf("priority %d not supported", priority), nil, nil 453 } 454 455 var overlapTargets []util.KCCTargetResource 456 overlapResources := sets.String{} 457 for _, res := range otherResources { 458 if (res.GetNamespace() == targetResource.GetNamespace() && res.GetName() == targetResource.GetName()) || 459 len(res.GetLabelSelector()) == 0 { 460 continue 461 } 462 463 otherSelector, err := labels.Parse(res.GetLabelSelector()) 464 if err != nil { 465 continue 466 } 467 468 otherPriority := res.GetPriority() 469 if otherPriority != priority { 470 continue 471 } 472 473 overlap := checkLabelSelectorOverlap(selector, otherSelector, allowedKeyList.List()) 474 if overlap { 475 overlapTargets = append(overlapTargets, res) 476 overlapResources.Insert(native.GenerateUniqObjectNameKey(res)) 477 } 478 } 479 480 if len(overlapResources) > 0 { 481 return false, fmt.Sprintf("labelSelector overlay with others: %v", overlapResources.List()), overlapTargets, nil 482 } 483 484 return true, "", nil, nil 485 } 486 487 func (k *KatalystCustomConfigTargetController) validateTargetResourceNodeNames(kcc *configapis.KatalystCustomConfig, targetResource util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 488 if targetResource.GetLastDuration() == nil { 489 return false, "nodeNames has been set but lastDuration no set", nil, nil 490 } 491 492 kccTargetResources, err := k.listAllKCCTargetResource(kcc.Spec.TargetType) 493 if err != nil { 494 return false, "", nil, err 495 } 496 497 return validateTargetResourceNodeNamesOverlapped(targetResource, kccTargetResources) 498 } 499 500 // validateLabelSelectorOverlapped make sures that nodeNames config cannot overlap with other labelSelector config 501 func validateTargetResourceNodeNamesOverlapped(targetResource util.KCCTargetResource, otherResources []util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 502 nodeNames := sets.NewString(targetResource.GetNodeNames()...) 503 504 var overlapTargets []util.KCCTargetResource 505 overlapResources := sets.String{} 506 for _, res := range otherResources { 507 if (res.GetNamespace() == targetResource.GetNamespace() && res.GetName() == targetResource.GetName()) || 508 len(res.GetNodeNames()) == 0 { 509 continue 510 } 511 512 otherNodeNames := sets.NewString(res.GetNodeNames()...) 513 if nodeNames.Intersection(otherNodeNames).Len() > 0 { 514 overlapResources.Insert(native.GenerateUniqObjectNameKey(res)) 515 overlapTargets = append(overlapTargets, res) 516 } 517 } 518 519 if len(overlapResources) > 0 { 520 return false, fmt.Sprintf("nodeNames overlay with others: %v", overlapResources.List()), overlapTargets, nil 521 } 522 523 return true, "", nil, nil 524 } 525 526 func (k *KatalystCustomConfigTargetController) validateTargetResourceGlobal(kcc *configapis.KatalystCustomConfig, targetResource util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 527 if targetResource.GetLastDuration() != nil { 528 return false, "lastDuration has been set for global config", nil, nil 529 } 530 531 kccTargetResources, err := k.listAllKCCTargetResource(kcc.Spec.TargetType) 532 if err != nil { 533 return false, "", nil, err 534 } 535 536 return validateTargetResourceGlobalOverlapped(targetResource, kccTargetResources) 537 } 538 539 // validateLabelSelectorOverlapped make sures that only one global configurations is created. 540 func validateTargetResourceGlobalOverlapped(targetResource util.KCCTargetResource, otherResources []util.KCCTargetResource) (bool, string, []util.KCCTargetResource, error) { 541 var overlapTargets []util.KCCTargetResource 542 overlapTargetNames := sets.String{} 543 for _, res := range otherResources { 544 if (res.GetNamespace() == targetResource.GetNamespace() && res.GetName() == targetResource.GetName()) || 545 (len(res.GetNodeNames()) > 0 || len(res.GetLabelSelector()) > 0) { 546 continue 547 } 548 549 overlapTargetNames.Insert(native.GenerateUniqObjectNameKey(res)) 550 overlapTargets = append(overlapTargets, res) 551 } 552 553 if len(overlapTargetNames) > 0 { 554 return false, fmt.Sprintf("global config %s overlay with others: %v", 555 native.GenerateUniqObjectNameKey(targetResource), overlapTargetNames.List()), overlapTargets, nil 556 } 557 558 return true, "", nil, nil 559 } 560 561 func (k *KatalystCustomConfigTargetController) listAllKCCTargetResource(gvr metav1.GroupVersionResource) ([]util.KCCTargetResource, error) { 562 accessor, ok := k.targetHandler.GetTargetAccessorByGVR(gvr) 563 if !ok { 564 return nil, fmt.Errorf("target accessor %s not found", gvr) 565 } 566 567 list, err := accessor.List(labels.Everything()) 568 if err != nil { 569 return nil, err 570 } 571 572 resources := make([]util.KCCTargetResource, 0, len(list)) 573 for _, obj := range list { 574 if obj.GetDeletionTimestamp() != nil { 575 continue 576 } 577 resources = append(resources, util.ToKCCTargetResource(obj)) 578 } 579 580 return resources, nil 581 } 582 583 func updateTargetResourceStatus(targetResource util.KCCTargetResource, isValid bool, msg, reason string) { 584 status := targetResource.GetGenericStatus() 585 status.ObservedGeneration = targetResource.GetGeneration() 586 if !isValid { 587 kccutil.UpdateKCCTGenericConditions(&status, configapis.ConfigConditionTypeValid, v1.ConditionFalse, reason, msg) 588 } else { 589 kccutil.UpdateKCCTGenericConditions(&status, configapis.ConfigConditionTypeValid, v1.ConditionTrue, reason, "") 590 } 591 592 targetResource.SetGenericStatus(status) 593 } 594 595 // checkLabelSelectorOverlap checks whether the labelSelector overlap with other labelSelector by the keyList 596 func checkLabelSelectorOverlap(selector labels.Selector, otherSelector labels.Selector, 597 keyList []string, 598 ) bool { 599 for _, key := range keyList { 600 equalLabelSet, inEqualLabelSet, _ := getMatchLabelSet(selector, key) 601 otherEqualLabelSet, otherInEqualLabelSet, _ := getMatchLabelSet(otherSelector, key) 602 if (equalLabelSet.Len() > 0 && otherEqualLabelSet.Len() > 0 && equalLabelSet.Intersection(otherEqualLabelSet).Len() > 0) || 603 (equalLabelSet.Len() == 0 && otherEqualLabelSet.Len() == 0 && (inEqualLabelSet.Len() > 0 || otherInEqualLabelSet.Len() > 0)) || 604 (inEqualLabelSet.Len() > 0 && !inEqualLabelSet.Intersection(otherEqualLabelSet).Equal(otherEqualLabelSet)) || 605 (otherInEqualLabelSet.Len() > 0 && !otherInEqualLabelSet.Intersection(equalLabelSet).Equal(equalLabelSet)) || 606 (equalLabelSet.Len() > 0 && otherEqualLabelSet.Len() == 0 && otherInEqualLabelSet.Len() == 0) || 607 (otherEqualLabelSet.Len() > 0 && equalLabelSet.Len() == 0 && inEqualLabelSet.Len() == 0) { 608 continue 609 } else { 610 return false 611 } 612 } 613 614 return true 615 } 616 617 func getMatchLabelSet(selector labels.Selector, key string) (sets.String, sets.String, error) { 618 reqs, selectable := selector.Requirements() 619 if !selectable { 620 return nil, nil, fmt.Errorf("labelSelector cannot selectable") 621 } 622 623 equalLabelSet := sets.String{} 624 inEqualLabelSet := sets.String{} 625 for _, r := range reqs { 626 if r.Key() != key { 627 continue 628 } 629 switch r.Operator() { 630 case selection.Equals, selection.DoubleEquals, selection.In: 631 equalLabelSet = equalLabelSet.Union(r.Values()) 632 case selection.NotEquals, selection.NotIn: 633 inEqualLabelSet = inEqualLabelSet.Union(r.Values()) 634 default: 635 return nil, nil, fmt.Errorf("labelSelector operator %s not supported", r.Operator()) 636 } 637 } 638 return equalLabelSet, inEqualLabelSet, nil 639 }