func (ap *availablePlugins) findLatestPool(pType, name string) (strategy.Pool, serror.SnapError) { // see if there exists a pool at all which matches name version. var latest strategy.Pool for key, pool := range ap.table { tnv := strings.Split(key, ":") if tnv[0] == pType && tnv[1] == name { latest = pool break } } if latest != nil { for key, pool := range ap.table { tnv := strings.Split(key, ":") if tnv[0] == pType && tnv[1] == name && pool.Version() > latest.Version() { latest = pool } } return latest, nil } return nil, nil }
// Empty handler acting as placeholder until implementation. This helps tests // pass to ensure registration works. func (r *runner) HandleGomitEvent(e gomit.Event) { switch v := e.Body.(type) { case *control_event.DeadAvailablePluginEvent: runnerLog.WithFields(log.Fields{ "_block": "handle-events", "event": v.Namespace(), "aplugin": v.String, }).Warning("handling dead available plugin event") pool, err := r.availablePlugins.getPool(v.Key) if err != nil { runnerLog.WithFields(log.Fields{ "_block": "handle-events", "aplugin": v.String, }).Error(err.Error()) return } if pool != nil { pool.Kill(v.Id, "plugin dead") } case *control_event.PluginUnsubscriptionEvent: runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.PluginName, "plugin-version": v.PluginVersion, "plugin-type": core.PluginType(v.PluginType).String(), }).Debug("handling plugin unsubscription event") err := r.handleUnsubscription(core.PluginType(v.PluginType).String(), v.PluginName, v.PluginVersion, v.TaskId) if err != nil { return } case *control_event.LoadPluginEvent: var pool strategy.Pool r.availablePlugins.RLock() for key, p := range r.availablePlugins.pools() { // tuple of type name and version // type @ index 0, name @ index 1, version @ index 2 tnv := strings.Split(key, ":") // make sure we don't panic and crash the service if a junk key is retrieved if len(tnv) != 3 { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), "plugin-signed": v.Signed, }).Info("pool has bad key ", key) continue } // attempt to find a pool whose type and name are the same, and whose version is // less than newly loaded plugin. If we find it, break out of loop. if core.PluginType(v.Type).String() == tnv[0] && v.Name == tnv[1] && v.Version > p.Version() { pool = p break } } r.availablePlugins.RUnlock() // now check to see if anything was put where pool points. // if not, there are no older pools whose subscriptions need to be // moved. if pool == nil { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), }).Info("No previous pool found for loaded plugin") return } plugin, err := r.pluginManager.get(fmt.Sprintf("%s:%s:%d", core.PluginType(v.Type).String(), v.Name, v.Version)) if err != nil { return } newPool, err := r.availablePlugins.getOrCreatePool(plugin.Key()) if err != nil { return } subs := pool.MoveSubscriptions(newPool) if len(subs) != 0 { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), }).Info("pool with subscriptions to move found") for _, sub := range subs { r.emitter.Emit(&control_event.PluginSubscriptionEvent{ PluginName: v.Name, PluginVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, SubscriptionType: int(strategy.UnboundSubscriptionType), }) r.emitter.Emit(&control_event.PluginUnsubscriptionEvent{ PluginName: v.Name, PluginVersion: pool.Version(), TaskId: sub.TaskID, PluginType: v.Type, }) r.emitter.Emit(&control_event.MovePluginSubscriptionEvent{ PluginName: v.Name, PreviousVersion: pool.Version(), NewVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, }) } } default: runnerLog.WithFields(log.Fields{ "_block": "handle-events", "event": v.Namespace(), }).Info("Nothing to do for this event") } }
// Empty handler acting as placeholder until implementation. This helps tests // pass to ensure registration works. func (r *runner) HandleGomitEvent(e gomit.Event) { switch v := e.Body.(type) { case *control_event.DeadAvailablePluginEvent: runnerLog.WithFields(log.Fields{ "_block": "handle-events", "event": v.Namespace(), "aplugin": v.String, }).Warning("handling dead available plugin event") pool, err := r.availablePlugins.getPool(v.Key) if err != nil { runnerLog.WithFields(log.Fields{ "_block": "handle-events", "aplugin": v.String, }).Error(err.Error()) return } if pool != nil { pool.Kill(v.Id, "plugin dead") } if pool.Eligible() { if pool.RestartCount() < MaxPluginRestartCount { e := r.restartPlugin(v.Key) if e != nil { runnerLog.WithFields(log.Fields{ "_block": "handle-events", "aplugin": v.String, }).Error(e.Error()) return } pool.IncRestartCount() runnerLog.WithFields(log.Fields{ "_block": "handle-events", "event": v.Name, "aplugin": v.Version, "restart_count": pool.RestartCount(), }).Warning("plugin restarted") r.emitter.Emit(&control_event.RestartedAvailablePluginEvent{ Id: v.Id, Name: v.Name, Version: v.Version, Key: v.Key, Type: v.Type, }) } else { r.emitter.Emit(&control_event.MaxPluginRestartsExceededEvent{ Id: v.Id, Name: v.Name, Version: v.Version, Key: v.Key, Type: v.Type, }) } } case *control_event.PluginUnsubscriptionEvent: runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.PluginName, "plugin-version": v.PluginVersion, "plugin-type": core.PluginType(v.PluginType).String(), }).Debug("handling plugin unsubscription event") err := r.handleUnsubscription(core.PluginType(v.PluginType).String(), v.PluginName, v.PluginVersion, v.TaskId) if err != nil { return } case *control_event.UnloadPluginEvent: // On plugin unload, find the key and pool info for the plugin being unloaded. r.availablePlugins.RLock() var pool strategy.Pool var k string for key, p := range r.availablePlugins.table { tnv := strings.Split(key, ":") if core.PluginType(v.Type).String() == tnv[0] && v.Name == tnv[1] && v.Version == p.Version() { pool = p k = key break } } r.availablePlugins.RUnlock() if pool == nil { return } // Check for the highest lower version plugin and move subscriptions that // are not bound to a plugin version to this pool. plugin, err := r.pluginManager.get(fmt.Sprintf("%s:%s:%d", core.PluginType(v.Type).String(), v.Name, -1)) if err != nil { return } newPool, err := r.availablePlugins.getOrCreatePool(plugin.Key()) if err != nil { return } subs := pool.MoveSubscriptions(newPool) // Start new plugins in newPool if needed if newPool.Eligible() { e := r.restartPlugin(plugin.Key()) if e != nil { runnerLog.WithFields(log.Fields{ "_block": "handle-events", }).Error(e.Error()) return } } // Remove the unloaded plugin from available plugins r.availablePlugins.Lock() delete(r.availablePlugins.table, k) r.availablePlugins.Unlock() pool.RLock() defer pool.RUnlock() if len(subs) != 0 { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), }).Info("pool with subscriptions to move found") for _, sub := range subs { r.emitter.Emit(&control_event.PluginSubscriptionEvent{ PluginName: v.Name, PluginVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, SubscriptionType: int(strategy.UnboundSubscriptionType), }) r.emitter.Emit(&control_event.PluginUnsubscriptionEvent{ PluginName: v.Name, PluginVersion: pool.Version(), TaskId: sub.TaskID, PluginType: v.Type, }) r.emitter.Emit(&control_event.MovePluginSubscriptionEvent{ PluginName: v.Name, PreviousVersion: pool.Version(), NewVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, }) } } case *control_event.LoadPluginEvent: // On loaded plugin event all subscriptions that are not bound to a specific version // need to moved to the loaded version if it's version is greater than the currently // available plugin. var pool strategy.Pool //k := fmt.Sprintf("%v:%v:%v", core.PluginType(v.Type).String(), v.Name, -1) //pool, _ = r.availablePlugins.getPool(k) r.availablePlugins.RLock() currentHighestVersion := -1 for key, p := range r.availablePlugins.pools() { // tuple of type name and version // type @ index 0, name @ index 1, version @ index 2 tnv := strings.Split(key, ":") // make sure we don't panic and crash the service if a junk key is retrieved if len(tnv) != 3 { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), "plugin-signed": v.Signed, }).Info("pool has bad key ", key) continue } // attempt to find a pool whose type and name are the same, and whose version is // less than newly loaded plugin. if core.PluginType(v.Type).String() == tnv[0] && v.Name == tnv[1] && v.Version > p.Version() { // See if the pool version is higher than the current highest. // We only want to move subscriptions from the currentHighest // because that is where subscriptions that are bound to the // latest version will be. if p.Version() > currentHighestVersion { pool = p currentHighestVersion = p.Version() } } } r.availablePlugins.RUnlock() // now check to see if anything was put where pool points. // if not, there are no older pools whose subscriptions need to be // moved. if pool == nil { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), }).Info("No previous pool found for loaded plugin") return } plugin, err := r.pluginManager.get(fmt.Sprintf("%s:%s:%d", core.PluginType(v.Type).String(), v.Name, v.Version)) if err != nil { return } newPool, err := r.availablePlugins.getOrCreatePool(plugin.Key()) if err != nil { return } // Move subscriptions to the new, higher versioned pool subs := pool.MoveSubscriptions(newPool) if newPool.Eligible() { e := r.restartPlugin(plugin.Key()) if e != nil { runnerLog.WithFields(log.Fields{ "_block": "handle-events", }).Error(e.Error()) return } runnerLog.WithFields(log.Fields{ "_block": "pool eligible", }).Info("starting plugin") } pool.RLock() defer pool.RUnlock() if len(subs) != 0 { runnerLog.WithFields(log.Fields{ "_block": "subscribe-pool", "event": v.Namespace(), "plugin-name": v.Name, "plugin-version": v.Version, "plugin-type": core.PluginType(v.Type).String(), }).Info("pool with subscriptions to move found") for _, sub := range subs { r.emitter.Emit(&control_event.PluginSubscriptionEvent{ PluginName: v.Name, PluginVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, SubscriptionType: int(strategy.UnboundSubscriptionType), }) r.emitter.Emit(&control_event.PluginUnsubscriptionEvent{ PluginName: v.Name, PluginVersion: pool.Version(), TaskId: sub.TaskID, PluginType: v.Type, }) r.emitter.Emit(&control_event.MovePluginSubscriptionEvent{ PluginName: v.Name, PreviousVersion: pool.Version(), NewVersion: v.Version, TaskId: sub.TaskID, PluginType: v.Type, }) } } default: runnerLog.WithFields(log.Fields{ "_block": "handle-events", "event": v.Namespace(), }).Info("Nothing to do for this event") } }