feta/manager.go

203 lines
4.1 KiB
Go
Raw Normal View History

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 "fmt"
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
type InstanceBackend interface {
//FIXME
}
type InstanceManager struct {
2019-11-03 18:00:01 +00:00
mu sync.Mutex
2019-11-03 13:17:00 +00:00
instances map[InstanceHostname]*Instance
newInstanceNotifications chan InstanceHostname
2019-11-03 18:00:01 +00:00
startup time.Time
2019-11-05 23:32:09 +00:00
addLock sync.Mutex
2019-11-03 13:17:00 +00:00
}
func NewInstanceManager() *InstanceManager {
i := new(InstanceManager)
2019-11-03 18:00:01 +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-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-03 18:00:01 +00:00
2019-11-04 17:07:04 +00:00
func (self *InstanceManager) managerLoop() {
self.Lock()
2019-11-05 23:32:09 +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 {
if v.dueForFetch() {
go func(i *Instance) {
i.Fetch()
}(v)
}
}
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-05 23:32:09 +00:00
// we do these one at a time
self.addLock.Lock()
defer self.addLock.Unlock()
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-04 17:07:04 +00:00
i := NewInstance(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-04 17:07:04 +00:00
self.Lock()
defer self.Unlock()
self.instances[newhn] = i
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
go func() {
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
log.Info().
Uint("up", r.up).
Uint("total", r.total).
Uint("identified", r.identified).
Msg("instance report")
}
2019-11-04 17:07:04 +00:00
type InstanceSummaryReport struct {
2019-11-03 18:00:01 +00:00
up uint
identified uint
total uint
}
2019-11-04 17:07:04 +00:00
func (r *InstanceSummaryReport) String() string {
2019-11-03 18:00:01 +00:00
return fmt.Sprintf("up=%d identified=%d total=%d", r.up, r.identified, r.total)
}
func (self *InstanceManager) NumInstances() uint {
2019-11-04 17:07:04 +00:00
return self.instanceSummaryReport().total
2019-11-03 18:00:01 +00:00
}
type InstanceListReport []*InstanceDetail
type InstanceDetail struct {
hostname string
up bool
nextFetch string
}
2019-11-04 17:07:04 +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
}
func (self *InstanceManager) instanceSummaryReport() *InstanceSummaryReport {
2019-11-03 18:00:01 +00:00
self.Lock()
defer self.Unlock()
2019-11-04 17:07:04 +00:00
r := new(InstanceSummaryReport)
2019-11-03 18:00:01 +00:00
r.total = uint(len(self.instances))
for _, elem := range self.instances {
if elem.identified == true {
r.identified = r.identified + 1
}
if elem.status == InstanceStatusAlive {
r.up = r.up + 1
}
}
return r
}