2019-11-05 02:53:11 +00:00
|
|
|
package feta
|
2019-11-03 13:17:00 +00:00
|
|
|
|
|
|
|
import "sync"
|
|
|
|
import "time"
|
2019-11-03 18:00:01 +00:00
|
|
|
import "runtime"
|
2019-11-03 13:17:00 +00:00
|
|
|
|
2019-11-05 23:32:09 +00:00
|
|
|
//import "github.com/gin-gonic/gin"
|
2019-11-03 18:00:01 +00:00
|
|
|
import "github.com/rs/zerolog/log"
|
2019-11-03 13:17:00 +00:00
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
const HOST_DISCOVERY_PARALLELISM = 1
|
2019-11-06 00:46:52 +00:00
|
|
|
|
2019-11-03 13:17:00 +00:00
|
|
|
type InstanceBackend interface {
|
|
|
|
//FIXME
|
|
|
|
}
|
|
|
|
|
|
|
|
type InstanceManager struct {
|
2019-11-03 18:00:01 +00:00
|
|
|
mu sync.Mutex
|
2019-11-06 07:03:42 +00:00
|
|
|
instances map[InstanceHostname]*instance
|
2019-11-03 13:17:00 +00:00
|
|
|
newInstanceNotifications chan InstanceHostname
|
2019-11-03 18:00:01 +00:00
|
|
|
startup time.Time
|
2019-11-06 00:46:52 +00:00
|
|
|
hostAdderSemaphore chan bool
|
2019-11-03 13:17:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewInstanceManager() *InstanceManager {
|
|
|
|
i := new(InstanceManager)
|
2019-11-06 00:46:52 +00:00
|
|
|
i.hostAdderSemaphore = make(chan bool, HOST_DISCOVERY_PARALLELISM)
|
2019-11-06 07:03:42 +00:00
|
|
|
i.instances = make(map[InstanceHostname]*instance)
|
2019-11-03 13:17:00 +00:00
|
|
|
return i
|
|
|
|
}
|
|
|
|
|
2019-11-03 18:00:01 +00:00
|
|
|
func (self *InstanceManager) logCaller(msg string) {
|
|
|
|
fpcs := make([]uintptr, 1)
|
|
|
|
// Skip 2 levels to get the caller
|
|
|
|
n := runtime.Callers(3, fpcs)
|
|
|
|
if n == 0 {
|
|
|
|
log.Debug().Msg("MSG: NO CALLER")
|
|
|
|
}
|
|
|
|
|
|
|
|
caller := runtime.FuncForPC(fpcs[0] - 1)
|
|
|
|
if caller == nil {
|
|
|
|
log.Debug().Msg("MSG CALLER WAS NIL")
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print the file name and line number
|
|
|
|
filename, line := caller.FileLine(fpcs[0] - 1)
|
|
|
|
function := caller.Name()
|
|
|
|
|
|
|
|
log.Debug().
|
|
|
|
Str("filename", filename).
|
|
|
|
Int("linenum", line).
|
|
|
|
Str("function", function).
|
|
|
|
Msg(msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) Lock() {
|
2019-11-05 23:32:09 +00:00
|
|
|
//self.logCaller("instancemanager attempting to lock")
|
2019-11-03 18:00:01 +00:00
|
|
|
self.mu.Lock()
|
2019-11-05 23:32:09 +00:00
|
|
|
//self.logCaller("instancemanager locked")
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) Unlock() {
|
|
|
|
self.mu.Unlock()
|
2019-11-05 23:32:09 +00:00
|
|
|
//self.logCaller("instancemanager unlocked")
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
|
2019-11-03 13:17:00 +00:00
|
|
|
func (self *InstanceManager) AddInstanceNotificationChannel(via chan InstanceHostname) {
|
|
|
|
self.Lock()
|
|
|
|
defer self.Unlock()
|
|
|
|
self.newInstanceNotifications = via
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) Manage() {
|
2019-11-03 18:00:01 +00:00
|
|
|
log.Info().Msg("InstanceManager starting")
|
2019-11-05 23:32:09 +00:00
|
|
|
go func() {
|
|
|
|
self.receiveNewInstanceHostnames()
|
|
|
|
}()
|
2019-11-03 18:00:01 +00:00
|
|
|
self.startup = time.Now()
|
2019-11-06 07:03:42 +00:00
|
|
|
x := self.startup
|
2019-11-03 13:17:00 +00:00
|
|
|
for {
|
2019-11-03 18:00:01 +00:00
|
|
|
log.Info().Msg("InstanceManager tick")
|
2019-11-04 17:07:04 +00:00
|
|
|
self.managerLoop()
|
2019-11-03 13:17:00 +00:00
|
|
|
time.Sleep(1 * time.Second)
|
2019-11-06 07:03:42 +00:00
|
|
|
if time.Now().After(x.Add(LOG_REPORT_INTERVAL)) {
|
|
|
|
x = time.Now()
|
|
|
|
self.logInstanceReport()
|
|
|
|
}
|
2019-11-03 13:17:00 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-03 18:00:01 +00:00
|
|
|
|
2019-11-04 17:07:04 +00:00
|
|
|
func (self *InstanceManager) managerLoop() {
|
|
|
|
self.Lock()
|
2019-11-06 07:03:42 +00:00
|
|
|
il := make([]*instance, 0)
|
2019-11-04 17:07:04 +00:00
|
|
|
for _, v := range self.instances {
|
2019-11-05 23:32:09 +00:00
|
|
|
il = append(il, v)
|
2019-11-04 17:07:04 +00:00
|
|
|
}
|
2019-11-05 23:32:09 +00:00
|
|
|
self.Unlock()
|
|
|
|
|
|
|
|
for _, v := range il {
|
2019-11-06 07:03:42 +00:00
|
|
|
go func(i *instance) {
|
|
|
|
i.Tick()
|
|
|
|
}(v)
|
2019-11-05 23:32:09 +00:00
|
|
|
}
|
2019-11-04 17:07:04 +00:00
|
|
|
}
|
|
|
|
|
2019-11-03 18:00:01 +00:00
|
|
|
func (self *InstanceManager) hostnameExists(newhn InstanceHostname) bool {
|
|
|
|
self.Lock()
|
2019-11-04 17:07:04 +00:00
|
|
|
defer self.Unlock()
|
2019-11-03 18:00:01 +00:00
|
|
|
for k, _ := range self.instances {
|
|
|
|
if newhn == k {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) addInstanceByHostname(newhn InstanceHostname) {
|
2019-11-04 17:07:04 +00:00
|
|
|
if self.hostnameExists(newhn) {
|
|
|
|
return
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
2019-11-05 23:32:09 +00:00
|
|
|
|
2019-11-06 00:46:52 +00:00
|
|
|
// this blocks on the channel size, limiting concurrency
|
|
|
|
self.hostAdderSemaphore <- true
|
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
i := NewInstance(func(x *instance) {
|
|
|
|
x.hostname = string(newhn)
|
|
|
|
})
|
2019-11-05 23:32:09 +00:00
|
|
|
// we do node detection under the addLock to avoid thundering
|
|
|
|
// on startup
|
|
|
|
i.detectNodeTypeIfNecessary()
|
|
|
|
|
2019-11-06 00:46:52 +00:00
|
|
|
// pop an item from the buffered channel
|
|
|
|
<-self.hostAdderSemaphore
|
|
|
|
|
|
|
|
// lock the map to insert
|
2019-11-04 17:07:04 +00:00
|
|
|
self.Lock()
|
|
|
|
self.instances[newhn] = i
|
2019-11-06 00:46:52 +00:00
|
|
|
self.Unlock()
|
|
|
|
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) receiveNewInstanceHostnames() {
|
|
|
|
var newhn InstanceHostname
|
|
|
|
for {
|
|
|
|
newhn = <-self.newInstanceNotifications
|
2019-11-05 23:32:09 +00:00
|
|
|
// receive them fast out of the channel, let the adding function lock to add
|
|
|
|
// them one at a time
|
2019-11-06 00:46:52 +00:00
|
|
|
go self.addInstanceByHostname(newhn)
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (self *InstanceManager) logInstanceReport() {
|
2019-11-04 17:07:04 +00:00
|
|
|
r := self.instanceSummaryReport()
|
2019-11-03 18:00:01 +00:00
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
sublogger := log.With().Logger()
|
2019-11-03 18:00:01 +00:00
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
for k, v := range r {
|
|
|
|
sublogger = sublogger.With().Uint(k, v).Logger()
|
|
|
|
}
|
2019-11-03 18:00:01 +00:00
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
sublogger.Info().
|
|
|
|
Msg("instance report")
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
func (self *InstanceManager) listInstances() []*instance {
|
|
|
|
var out []*instance
|
2019-11-03 18:00:01 +00:00
|
|
|
self.Lock()
|
|
|
|
defer self.Unlock()
|
|
|
|
for _, v := range self.instances {
|
2019-11-04 17:07:04 +00:00
|
|
|
out = append(out, v)
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2019-11-06 07:03:42 +00:00
|
|
|
func (im *InstanceManager) instanceSummaryReport() map[string]uint {
|
|
|
|
r := make(map[string]uint)
|
|
|
|
for _, v := range im.listInstances() {
|
|
|
|
v.Lock()
|
|
|
|
r[v.Status()]++
|
|
|
|
v.Unlock()
|
2019-11-03 18:00:01 +00:00
|
|
|
}
|
|
|
|
return r
|
|
|
|
}
|