github.com/kubewharf/katalyst-core@v0.5.3/pkg/controller/overcommit/node/matcher/matcher.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 matcher 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 24 v1 "k8s.io/api/core/v1" 25 "k8s.io/apimachinery/pkg/api/errors" 26 "k8s.io/apimachinery/pkg/labels" 27 "k8s.io/apimachinery/pkg/selection" 28 "k8s.io/apimachinery/pkg/util/sets" 29 corelisters "k8s.io/client-go/listers/core/v1" 30 "k8s.io/client-go/tools/cache" 31 "k8s.io/klog/v2" 32 33 "github.com/kubewharf/katalyst-api/pkg/apis/overcommit/v1alpha1" 34 overcommitlisters "github.com/kubewharf/katalyst-api/pkg/client/listers/overcommit/v1alpha1" 35 "github.com/kubewharf/katalyst-api/pkg/consts" 36 ) 37 38 const LabelSelectorValIndex = "spec.nodeOvercommitSelectorVal" 39 40 type ( 41 ConfigToNodes map[string]sets.String 42 NodeToConfig map[string]*v1alpha1.NodeOvercommitConfig 43 ) 44 45 type Matcher interface { 46 // Reconcile rematch all configs and nodes 47 Reconcile() error 48 49 // MatchConfig matches nodes for config, return nodeNames whose matched config maybe updated. 50 MatchConfig(configName string) ([]string, error) 51 // MatchNode matches and sorts configs for node. 52 MatchNode(nodeName string) (*v1alpha1.NodeOvercommitConfig, error) 53 // ListNodeToConfig list nodes with matched configName 54 ListNodeToConfig() map[string]string 55 // GetConfig get matched config by nodeName 56 GetConfig(nodeName string) *v1alpha1.NodeOvercommitConfig 57 // GetNodes get matched nodes by configName 58 GetNodes(configName string) []string 59 // DelNode delete node in matcher cache 60 DelNode(nodeName string) 61 } 62 63 type NodeMatchEvent struct { 64 NodeName string 65 NodeUpdate bool 66 } 67 68 type DummyMatcher struct{} 69 70 func (dm *DummyMatcher) Reconcile() error { 71 return nil 72 } 73 74 func (dm *DummyMatcher) MatchConfig(_ string) ([]string, error) { 75 return []string{}, nil 76 } 77 78 func (dm *DummyMatcher) MatchNode(_ string) (*v1alpha1.NodeOvercommitConfig, error) { 79 return nil, nil 80 } 81 82 func (dm *DummyMatcher) GetConfig(_ string) *v1alpha1.NodeOvercommitConfig { 83 return nil 84 } 85 86 func (dm *DummyMatcher) DelNode(_ string) {} 87 88 func (dm *DummyMatcher) GetNodeToConfig(_ string) *v1alpha1.NodeOvercommitConfig { 89 return nil 90 } 91 92 func (dm *DummyMatcher) ListNodeToConfig() map[string]string { 93 return nil 94 } 95 96 func (dm *DummyMatcher) GetNodes(_ string) []string { 97 return nil 98 } 99 100 func NewMatcher(nodelister corelisters.NodeLister, noclister overcommitlisters.NodeOvercommitConfigLister, indexer cache.Indexer) *MatcherImpl { 101 return &MatcherImpl{ 102 RWMutex: sync.RWMutex{}, 103 nodeLister: nodelister, 104 nocLister: noclister, 105 nocIndexer: indexer, 106 configToNodes: make(map[string]sets.String), 107 nodeToConfig: make(map[string]*v1alpha1.NodeOvercommitConfig), 108 } 109 } 110 111 type MatcherImpl struct { 112 ctx context.Context 113 sync.RWMutex 114 115 nodeLister corelisters.NodeLister 116 nocLister overcommitlisters.NodeOvercommitConfigLister 117 118 nocIndexer cache.Indexer 119 configToNodes ConfigToNodes 120 nodeToConfig NodeToConfig 121 } 122 123 func (i *MatcherImpl) Reconcile() error { 124 err := i.reconcileConfig() 125 if err != nil { 126 return err 127 } 128 129 return i.reconcileNode() 130 } 131 132 func (i *MatcherImpl) reconcileConfig() error { 133 nodeOvercommitConfigs, err := i.nocLister.List(labels.Everything()) 134 if err != nil { 135 klog.Errorf("list nodeOvercommitConfig fail: %v", err) 136 return err 137 } 138 139 i.Lock() 140 defer i.Unlock() 141 i.configToNodes = make(map[string]sets.String) 142 for _, config := range nodeOvercommitConfigs { 143 nodeNames, err := i.matchConfigToNodes(config) 144 if err != nil { 145 return err 146 } 147 148 i.configToNodes[config.Name] = sets.NewString(nodeNames...) 149 } 150 return nil 151 } 152 153 func (i *MatcherImpl) reconcileNode() error { 154 nodeList, err := i.nodeLister.List(labels.Everything()) 155 if err != nil { 156 klog.Errorf("list node fail: %v", err) 157 return err 158 } 159 160 i.Lock() 161 defer i.Unlock() 162 163 for _, node := range nodeList { 164 _, err := i.matchNode(node) 165 if err != nil { 166 klog.Errorf("matchNode %v fail: %v", node.Name, err) 167 } 168 } 169 return nil 170 } 171 172 func (i *MatcherImpl) MatchConfig(configName string) ([]string, error) { 173 var nodeUnionSets sets.String 174 nodeNames, err := i.matchConfigNameToNodes(configName) 175 if err != nil && errors.IsNotFound(err) { 176 i.Lock() 177 nodeUnionSets = i.configToNodes[configName] 178 delete(i.configToNodes, configName) 179 i.Unlock() 180 return nodeUnionSets.UnsortedList(), nil 181 } 182 if err != nil { 183 return nil, err 184 } 185 i.Lock() 186 nodeUnionSets = i.configNodeUnion(configName, nodeNames) 187 i.configToNodes[configName] = sets.NewString(nodeNames...) 188 i.Unlock() 189 return nodeUnionSets.UnsortedList(), nil 190 } 191 192 func (i *MatcherImpl) MatchNode(nodeName string) (*v1alpha1.NodeOvercommitConfig, error) { 193 node, err := i.nodeLister.Get(nodeName) 194 if err != nil { 195 if errors.IsNotFound(err) { 196 klog.Errorf("node %v has been deleted", nodeName) 197 i.Lock() 198 delete(i.nodeToConfig, nodeName) 199 i.Unlock() 200 return nil, nil 201 } 202 klog.Errorf("getnode %v fail, err: %v", nodeName, err) 203 return nil, err 204 } 205 206 i.Lock() 207 defer i.Unlock() 208 return i.matchNode(node) 209 } 210 211 func (i *MatcherImpl) matchNode(node *v1.Node) (*v1alpha1.NodeOvercommitConfig, error) { 212 nodeName := node.Name 213 if len(node.Labels) == 0 { 214 delete(i.nodeToConfig, nodeName) 215 return nil, nil 216 } 217 val, ok := node.Labels[consts.NodeOvercommitSelectorKey] 218 if !ok { 219 klog.Warningf("node %s has no label %s", nodeName, consts.NodeOvercommitSelectorKey) 220 delete(i.nodeToConfig, nodeName) 221 return nil, nil 222 } 223 config, err := GetValidNodeOvercommitConfig(i.nocIndexer, val) 224 if err != nil { 225 return nil, err 226 } 227 if config == nil { 228 delete(i.nodeToConfig, nodeName) 229 return nil, nil 230 } 231 i.nodeToConfig[nodeName] = config 232 return config, nil 233 } 234 235 func (i *MatcherImpl) DelNode(nodeName string) { 236 i.Lock() 237 defer i.Unlock() 238 239 delete(i.nodeToConfig, nodeName) 240 for key := range i.configToNodes { 241 i.configToNodes[key].Delete(nodeName) 242 } 243 } 244 245 func (i *MatcherImpl) GetConfig(nodeName string) *v1alpha1.NodeOvercommitConfig { 246 i.RLock() 247 defer i.RUnlock() 248 return i.nodeToConfig[nodeName] 249 } 250 251 func (i *MatcherImpl) ListNodeToConfig() map[string]string { 252 ret := make(map[string]string) 253 i.RLock() 254 defer i.RUnlock() 255 256 for nodeName, config := range i.nodeToConfig { 257 ret[nodeName] = config.Name 258 } 259 return ret 260 } 261 262 func (i *MatcherImpl) GetNodes(configName string) []string { 263 i.RLock() 264 defer i.RUnlock() 265 return i.configToNodes[configName].UnsortedList() 266 } 267 268 func (i *MatcherImpl) matchConfigNameToNodes(configName string) ([]string, error) { 269 overcommitConfig, err := i.nocLister.Get(configName) 270 if err != nil { 271 return nil, err 272 } 273 274 if overcommitConfig == nil { 275 return nil, fmt.Errorf("config %s is nil", configName) 276 } 277 278 return i.matchConfigToNodes(overcommitConfig) 279 } 280 281 func (i *MatcherImpl) matchConfigToNodes(overcommitConfig *v1alpha1.NodeOvercommitConfig) ([]string, error) { 282 nodeNames := make([]string, 0) 283 284 val := overcommitConfig.Spec.NodeOvercommitSelectorVal 285 if val == "" { 286 return []string{}, nil 287 } 288 289 requirement, err := labels.NewRequirement(consts.NodeOvercommitSelectorKey, selection.Equals, []string{val}) 290 if err != nil { 291 return nil, err 292 } 293 selector := labels.NewSelector().Add(*requirement) 294 295 nodeList, err := i.nodeLister.List(selector) 296 if err != nil { 297 return nil, err 298 } 299 for _, node := range nodeList { 300 nodeNames = append(nodeNames, node.Name) 301 } 302 return nodeNames, nil 303 } 304 305 func (i *MatcherImpl) configNodeUnion(configName string, nodeNames []string) sets.String { 306 newNodes := sets.NewString(nodeNames...) 307 308 originalNodes, ok := i.configToNodes[configName] 309 if !ok { 310 return newNodes 311 } 312 313 return originalNodes.Union(newNodes) 314 }