go.ligato.io/vpp-agent/v3@v3.5.0/plugins/orchestrator/orchestrator.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 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 orchestrator 16 17 import ( 18 "context" 19 "os" 20 "strings" 21 "sync" 22 23 "github.com/go-errors/errors" 24 "go.ligato.io/cn-infra/v2/datasync" 25 "go.ligato.io/cn-infra/v2/datasync/resync" 26 "go.ligato.io/cn-infra/v2/infra" 27 "go.ligato.io/cn-infra/v2/logging" 28 "go.ligato.io/cn-infra/v2/rpc/grpc" 29 "google.golang.org/grpc/reflection" 30 "google.golang.org/protobuf/proto" 31 32 "go.ligato.io/vpp-agent/v3/pkg/models" 33 kvs "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api" 34 "go.ligato.io/vpp-agent/v3/plugins/orchestrator/contextdecorator" 35 "go.ligato.io/vpp-agent/v3/proto/ligato/generic" 36 "go.ligato.io/vpp-agent/v3/proto/ligato/kvscheduler" 37 ) 38 39 var ( 40 // EnableStatusPublishing enables status publishing. 41 EnableStatusPublishing = os.Getenv("ENABLE_STATUS_PUBLISHING") != "" 42 43 debugOrchestrator = os.Getenv("DEBUG_ORCHESTRATOR") != "" 44 ) 45 46 // Plugin implements sync service for GRPC. 47 type Plugin struct { 48 Deps 49 50 *dispatcher 51 manager *genericService 52 53 reflection bool 54 55 // datasync channels 56 changeChan chan datasync.ChangeEvent 57 resyncChan chan datasync.ResyncEvent 58 watchDataReg datasync.WatchRegistration 59 60 wg sync.WaitGroup 61 quit chan struct{} 62 } 63 64 // Deps represents dependencies for the plugin. 65 type Deps struct { 66 infra.PluginDeps 67 68 GRPC grpc.Server 69 KVScheduler kvs.KVScheduler 70 Watcher datasync.KeyValProtoWatcher 71 StatusPublisher datasync.KeyProtoValWriter 72 } 73 74 // Init registers the service to GRPC server. 75 func (p *Plugin) Init() (err error) { 76 p.quit = make(chan struct{}) 77 78 p.dispatcher = &dispatcher{ 79 log: logging.DefaultRegistry.NewLogger("dispatcher"), 80 db: newMemStore(), 81 kvs: p.KVScheduler, 82 } 83 84 // register grpc service 85 p.manager = &genericService{ 86 log: p.log, 87 dispatch: p.dispatcher, 88 } 89 90 if grpcServer := p.GRPC.GetServer(); grpcServer != nil { 91 p.Log.Debugf("registering generic manager and meta service") 92 generic.RegisterManagerServiceServer(grpcServer, p.manager) 93 generic.RegisterMetaServiceServer(grpcServer, p.manager) 94 95 // register grpc services for reflection 96 if p.reflection { 97 p.Log.Debugf("registering grpc reflection service") 98 reflection.Register(grpcServer) 99 } 100 } else { 101 p.log.Infof("grpc server is not available") 102 } 103 104 p.Log.Infof("Found %d registered models", len(models.RegisteredModels())) 105 for _, model := range models.RegisteredModels() { 106 p.debugf("- model: %+v", *model.Spec()) 107 } 108 109 var prefixes []string 110 if nbPrefixes := p.kvs.GetRegisteredNBKeyPrefixes(); len(nbPrefixes) > 0 { 111 p.log.Infof("Watching %d key prefixes from KVScheduler", len(nbPrefixes)) 112 for _, prefix := range nbPrefixes { 113 p.debugf("- prefix: %s", prefix) 114 prefixes = append(prefixes, prefix) 115 } 116 } else { 117 p.log.Warnf("No key prefixes found in KVScheduler (ensure that all KVDescriptors are registered before this)") 118 } 119 120 // initialize datasync channels 121 p.resyncChan = make(chan datasync.ResyncEvent) 122 p.changeChan = make(chan datasync.ChangeEvent) 123 124 p.watchDataReg, err = p.Watcher.Watch(p.PluginName.String(), 125 p.changeChan, p.resyncChan, prefixes...) 126 if err != nil { 127 return err 128 } 129 130 return nil 131 } 132 133 // AfterInit subscribes to known NB prefixes. 134 func (p *Plugin) AfterInit() (err error) { 135 // watch datasync events 136 p.wg.Add(1) 137 go p.watchEvents() 138 139 statusChan := make(chan *kvscheduler.BaseValueStatus, 100) 140 p.kvs.WatchValueStatus(statusChan, nil) 141 142 // watch KVSchedular status changes 143 p.wg.Add(1) 144 go p.watchStatus(statusChan) 145 146 return nil 147 } 148 149 func (p *Plugin) Close() (err error) { 150 close(p.quit) 151 p.wg.Wait() 152 return nil 153 } 154 155 // InitialSync will start initial synchronization. 156 func (p *Plugin) InitialSync() error { 157 // SB resync 158 p.Log.Debugf("starting initial SB sync") 159 txn := p.KVScheduler.StartNBTransaction() 160 ctx := kvs.WithResync(context.Background(), kvs.DownstreamResync, true) 161 if _, err := txn.Commit(ctx); err != nil { 162 return errors.Errorf("initial SB sync failed: %v", err) 163 } 164 p.Log.Infof("initial SB sync complete") 165 166 // NB resync 167 p.Log.Debugf("starting initial NB sync") 168 resync.DefaultPlugin.DoResync() // NB init file data is also resynced here 169 p.Log.Infof("initial NB sync complete") 170 171 return nil 172 } 173 174 func (p *Plugin) watchEvents() { 175 defer p.wg.Done() 176 177 p.Log.Debugf("watching datasync events") 178 defer p.Log.Debugf("done watching datasync events") 179 180 for { 181 select { 182 case e := <-p.changeChan: 183 p.log.Debugf("=> received CHANGE event (%v changes)", len(e.GetChanges())) 184 185 var err error 186 var kvPairs []KeyVal 187 188 for _, x := range e.GetChanges() { 189 kv := KeyVal{ 190 Key: x.GetKey(), 191 } 192 if x.GetChangeType() != datasync.Delete { 193 kv.Val, err = UnmarshalLazyValue(kv.Key, x) 194 if err != nil { 195 p.log.Errorf("decoding value for key %q failed: %v", kv.Key, err) 196 continue 197 } 198 } 199 kvPairs = append(kvPairs, kv) 200 } 201 202 if len(kvPairs) == 0 { 203 p.log.Warn("no valid kv pairs received in change event") 204 e.Done(nil) 205 continue 206 } 207 208 p.log.Debugf("Change with %d items", len(kvPairs)) 209 210 ctx := e.GetContext() 211 if ctx == nil { 212 ctx = context.Background() 213 } 214 _, withDataSrc := contextdecorator.DataSrcFromContext(ctx) 215 if !withDataSrc { 216 ctx = contextdecorator.DataSrcContext(ctx, "datasync") 217 } 218 ctx = kvs.WithRetryDefault(ctx) 219 _, err = p.PushData(ctx, kvPairs, nil) 220 e.Done(err) 221 222 case e := <-p.resyncChan: 223 p.log.Debugf("=> received RESYNC event (%v prefixes)", len(e.GetValues())) 224 225 var kvPairs []KeyVal 226 227 for prefix, iter := range e.GetValues() { 228 var keyVals []datasync.KeyVal 229 for x, done := iter.GetNext(); !done; x, done = iter.GetNext() { 230 key := x.GetKey() 231 val, err := UnmarshalLazyValue(key, x) 232 if err != nil { 233 p.log.Errorf("unmarshal value for key %q failed: %v", key, err) 234 continue 235 } 236 kvPairs = append(kvPairs, KeyVal{ 237 Key: key, 238 Val: val, 239 }) 240 p.log.Debugf(" -- key: %s", x.GetKey()) 241 keyVals = append(keyVals, x) 242 } 243 if len(keyVals) > 0 { 244 p.log.Debugf("- %q (%v items)", prefix, len(keyVals)) 245 } else { 246 p.log.Debugf("- %q (no items)", prefix) 247 } 248 for _, x := range keyVals { 249 p.log.Debugf("\t - %q: (rev: %v)", x.GetKey(), x.GetRevision()) 250 } 251 } 252 253 p.log.Debugf("Resync with %d items", len(kvPairs)) 254 255 ctx := e.GetContext() 256 if ctx == nil { 257 ctx = context.Background() 258 } 259 _, withDataSrc := contextdecorator.DataSrcFromContext(ctx) 260 if !withDataSrc { 261 ctx = contextdecorator.DataSrcContext(ctx, "datasync") 262 } 263 ctx = kvs.WithResync(ctx, kvs.FullResync, true) 264 ctx = kvs.WithRetryDefault(ctx) 265 266 _, err := p.PushData(ctx, kvPairs, nil) 267 e.Done(err) 268 269 case <-p.quit: 270 return 271 } 272 } 273 } 274 275 func (p *Plugin) watchStatus(ch <-chan *kvscheduler.BaseValueStatus) { 276 defer p.wg.Done() 277 278 p.Log.Debugf("watching status changes") 279 defer p.Log.Debugf("done watching status events") 280 281 for { 282 select { 283 case s := <-ch: 284 p.debugf("incoming status change: %15s %v ===> %v (%v) %v", 285 s.Value.State, s.Value.Details, s.Value.Key, s.Value.LastOperation, s.Value.Error) 286 for _, dv := range s.DerivedValues { 287 p.debugf(" \t%15s %v ---> %v (%v) %v", 288 dv.State, dv.Details, dv.Key, dv.LastOperation, dv.Error) 289 } 290 291 if EnableStatusPublishing { 292 p.publishStatuses([]Result{ 293 {Key: s.Value.Key, Status: s.Value}, 294 }) 295 } 296 297 case <-p.quit: 298 return 299 } 300 } 301 } 302 303 func (p *Plugin) publishStatuses(results []Result) { 304 if p.StatusPublisher == nil { 305 return 306 } 307 308 p.debugf("publishing %d statuses", len(results)) 309 for _, res := range results { 310 statusKey := strings.Replace(res.Key, "config/", "config-status/", 1) 311 if statusKey == res.Key { 312 p.debugf("replace for key %q failed", res.Key) 313 continue 314 } 315 if err := p.StatusPublisher.Put(statusKey, res.Status, datasync.WithClientLifetimeTTL()); err != nil { 316 p.debugf("publishing status for key %q failed: %v", statusKey, err) 317 } 318 } 319 } 320 321 func (p *Plugin) debugf(f string, a ...interface{}) { 322 if debugOrchestrator { 323 p.log.Debugf(f, a...) 324 } 325 } 326 327 // UnmarshalLazyValue is helper function for unmarshalling from datasync.LazyValue. 328 func UnmarshalLazyValue(key string, lazy datasync.LazyValue) (proto.Message, error) { 329 model, err := models.GetModelForKey(key) 330 if err != nil { 331 return nil, err 332 } 333 instance := model.NewInstance() 334 // try to deserialize the value into instance 335 if err := lazy.GetValue(instance); err != nil { 336 return nil, err 337 } 338 return instance, nil 339 } 340 341 func HasCorrectLabels(want map[string]string, have Labels) bool { 342 include := make(map[string]string) 343 exclude := make(map[string]string) 344 for wk, wl := range want { 345 if len(wk) > 0 && wk[0] == '!' { 346 exclude[wk[1:]] = wl 347 } else { 348 include[wk] = wl 349 } 350 } 351 for ik, iv := range include { 352 if hv, ok := have[ik]; !ok || iv != "" && iv != hv { 353 return false 354 } 355 } 356 for ek, ev := range exclude { 357 if hv, ok := have[ek]; ok && ev == hv || ok && ev == "" { 358 return false 359 } 360 } 361 return true 362 } 363 364 func ContainsItemID(want []*generic.Item_ID, have *generic.Item_ID) bool { 365 if len(want) == 0 { 366 return true 367 } 368 for _, w := range want { 369 if w.Model == have.Model && w.Name == have.Name { 370 return true 371 } 372 } 373 return false 374 }