github.com/gocrane/crane@v0.11.0/pkg/recommendation/manager.go (about) 1 package recommendation 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/fsnotify/fsnotify" 8 "k8s.io/klog/v2" 9 10 analysisv1alph1 "github.com/gocrane/api/analysis/v1alpha1" 11 "github.com/gocrane/crane/pkg/recommendation/config" 12 "github.com/gocrane/crane/pkg/recommendation/framework" 13 "github.com/gocrane/crane/pkg/recommendation/recommender" 14 "github.com/gocrane/crane/pkg/recommendation/recommender/apis" 15 _ "github.com/gocrane/crane/pkg/recommendation/recommender/hpa" 16 _ "github.com/gocrane/crane/pkg/recommendation/recommender/idlenode" 17 _ "github.com/gocrane/crane/pkg/recommendation/recommender/replicas" 18 _ "github.com/gocrane/crane/pkg/recommendation/recommender/resource" 19 _ "github.com/gocrane/crane/pkg/recommendation/recommender/service" 20 _ "github.com/gocrane/crane/pkg/recommendation/recommender/volume" 21 ) 22 23 type RecommenderManager interface { 24 // GetRecommender return a registered recommender 25 GetRecommender(recommenderName string) (recommender.Recommender, error) 26 // GetRecommenderWithRule return a registered recommender, its config merged with recommendationRule 27 GetRecommenderWithRule(recommenderName string, recommendationRule analysisv1alph1.RecommendationRule) (recommender.Recommender, error) 28 } 29 30 func NewRecommenderManager(recommendationConfiguration string) RecommenderManager { 31 m := &manager{ 32 recommendationConfiguration: recommendationConfiguration, 33 } 34 35 m.loadConfigFile() // nolint:errcheck 36 37 go m.watchConfigFile() 38 39 return m 40 } 41 42 type ResourceSpec struct { 43 CPU string 44 Memory string 45 } 46 47 type ResourceSpecs []ResourceSpec 48 49 type manager struct { 50 recommendationConfiguration string 51 52 lock sync.Mutex 53 recommenderConfigs map[string]apis.Recommender 54 } 55 56 func (m *manager) GetRecommender(recommenderName string) (recommender.Recommender, error) { 57 return m.GetRecommenderWithRule(recommenderName, analysisv1alph1.RecommendationRule{}) 58 } 59 60 func (m *manager) GetRecommenderWithRule(recommenderName string, recommendationRule analysisv1alph1.RecommendationRule) (recommender.Recommender, error) { 61 m.lock.Lock() 62 defer m.lock.Unlock() 63 64 if recommenderConfig, ok := m.recommenderConfigs[recommenderName]; ok { 65 return recommender.GetRecommenderProvider(recommenderName, recommenderConfig, recommendationRule) 66 } 67 68 return nil, fmt.Errorf("unknown recommender name: %s", recommenderName) 69 } 70 71 func (m *manager) watchConfigFile() { 72 watcher, err := fsnotify.NewWatcher() 73 if err != nil { 74 klog.Error(err) 75 return 76 } 77 defer watcher.Close() 78 79 err = watcher.Add(m.recommendationConfiguration) 80 if err != nil { 81 klog.ErrorS(err, "Failed to watch", "file", m.recommendationConfiguration) 82 return 83 } 84 klog.Infof("Start watching %s for update.", m.recommendationConfiguration) 85 86 for { 87 select { 88 case event, ok := <-watcher.Events: 89 klog.Infof("Watched an event: %v", event) 90 if !ok { 91 return 92 } 93 if event.Op&fsnotify.Remove == fsnotify.Remove { 94 err = watcher.Add(m.recommendationConfiguration) 95 if err != nil { 96 klog.ErrorS(err, "Failed to watch.", "file", m.recommendationConfiguration) 97 continue 98 } 99 klog.Infof("Config file %s removed. Reload it.", event.Name) 100 if err = m.loadConfigFile(); err != nil { 101 klog.ErrorS(err, "Failed to load config set file.") 102 } 103 } else if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { 104 klog.Infof("Config file %s modified. Reload it.", event.Name) 105 if err = m.loadConfigFile(); err != nil { 106 klog.ErrorS(err, "Failed to load config set file.") 107 } 108 } 109 case err, ok := <-watcher.Errors: 110 if !ok { 111 return 112 } 113 klog.Error(err) 114 } 115 } 116 } 117 118 func (m *manager) loadConfigFile() error { 119 m.lock.Lock() 120 defer m.lock.Unlock() 121 122 recommenderConfigs, err := config.GetRecommendersFromConfiguration(m.recommendationConfiguration) 123 if err != nil { 124 klog.ErrorS(err, "Failed to load recommendation config file", "file", m.recommendationConfiguration) 125 return err 126 } 127 m.recommenderConfigs = recommenderConfigs 128 klog.Info("Recommendation Config updated.") 129 return nil 130 } 131 132 func Run(ctx *framework.RecommendationContext, recommender recommender.Recommender) error { 133 klog.Infof("%s: start to run recommender %q.", ctx.String(), recommender.Name()) 134 135 // 1. Filter phase 136 err := recommender.Filter(ctx) 137 if err != nil { 138 klog.Errorf("%s: recommender %q failed at filter phase: %v", ctx.String(), recommender.Name(), err) 139 return err 140 } 141 142 // 2. PrePrepare phase 143 err = recommender.CheckDataProviders(ctx) 144 if err != nil { 145 klog.Errorf("%s: recommender %q failed at prepare check data provider phase: %v", ctx.String(), recommender.Name(), err) 146 return err 147 } 148 149 // 3. Prepare phase 150 err = recommender.CollectData(ctx) 151 if err != nil { 152 klog.Errorf("%s: recommender %q failed at prepare collect data phase: %v", ctx.String(), recommender.Name(), err) 153 return err 154 } 155 156 // 4. PostPrepare phase 157 err = recommender.PostProcessing(ctx) 158 if err != nil { 159 klog.Errorf("%s: recommender %q failed at prepare data post processing phase: %v", ctx.String(), recommender.Name(), err) 160 return err 161 } 162 163 // 5. PreRecommend phase 164 err = recommender.PreRecommend(ctx) 165 if err != nil { 166 klog.Errorf("%s: recommender %q failed at pre commend phase: %v", ctx.String(), recommender.Name(), err) 167 return err 168 } 169 170 // 6. Recommend phase 171 err = recommender.Recommend(ctx) 172 if err != nil { 173 klog.Errorf("%s: recommender %q failed at recommend phase: %v", ctx.String(), recommender.Name(), err) 174 return err 175 } 176 177 // 7. PostRecommend phase, add policy 178 err = recommender.Policy(ctx) 179 if err != nil { 180 klog.Errorf("%s: recommender %q failed at recommend policy phase: %v", ctx.String(), recommender.Name(), err) 181 return err 182 } 183 184 // 8. Observe phase 185 err = recommender.Observe(ctx) 186 if err != nil { 187 klog.Errorf("%s: recommender %q failed at observe phase: %v", ctx.String(), recommender.Name(), err) 188 return err 189 } 190 191 klog.Infof("%s: finish to run recommender %q.", ctx.String(), recommender.Name()) 192 return nil 193 }