commit - f21c51c745099616c3451e39569df1b46feae6af
commit + 43c71de36cec7d072d2436925b93cf2e94b71606
blob - c24b1c8b4b98bd3a7e656f48e9f62c5cc40912a7
blob + 493802b3395fcdbcea77e51d9182872d21248345
--- checker.go
+++ checker.go
}
return fmt.Errorf("%s", resp.Status)
}
+
+func nextCheck(objects []checker) time.Time {
+ soonest := time.Time{}
+ for _, obj := range objects {
+ next := time.Time{}
+ switch obj.(type); obj {
+ case Host, Service:
+ next = obj.NextCheck
+ }
+ if soonest.IsZero() {
+ soonest = next
+ }
+ if next.Before(soonest) {
+ soonest = next
+ }
+ }
+ return soonest
+}
blob - /dev/null
blob + d619bf13ce259580676700dc4f34061acc56a17d (mode 644)
--- /dev/null
+++ cmd/i2cache/i2cache.go
+package main
+
+type Cache struct {
+ client *icinga.Client
+ hosts map[string]*hostEntry
+ services map[string]*serviceEntry
+}
+
+func NewCache(client *icinga.Client) *Cache {
+ return &Cache{
+ client: client,
+ hosts: make(map[string]*hostEntry),
+ services: make(map[string]*serviceEntry),
+ }
+}
+
+type serviceEntry struct {
+ accessTime time.Time
+ watcher *ServiceWatcher
+ services []Service
+}
+
+func (c *Cache) GetServices(expr string) []icinga.Service {
+ entry, ok := c.services[expr]
+ if !ok {
+ return nil
+ }
+ entry.accessTime = time.Now()
+ if entry.wacher == nil {
+ entry := entry
+ entry.watcher = WatchServices(c.client, expr)
+ go func() {
+ for msg := range entry.watcher.Updates {
+ if msg.Err != nil {
+ // TODO(otl) ??
+ }
+ entry.services = msg.Services
+ }
+ }()
+ }
+ return entry.services
+}
+
+type hostEntry struct {
+ accessTime time.Time
+ hosts []Host
+}
+
+func (c *Cache) GetHosts(expr string) *hostEntry {}
+
+func (c *Cache) evictOlderThan(d time.Duration) {
+ t := time.Now().Sub(d)
+ for _, entry := range c.services {
+ if entry.accessTime.Before(t) {
+ entry.kill <- true
+ delete(c.services[expr])
+ }
+ }
+ for _, entry := range c.Hosts {
+ if entry.accessTime.Before(t) {
+ entry.kill <- true
+ delete(c.hosts[expr])
+ }
+ }
+}
blob - /dev/null
blob + 053c8422dbb89f47a6db1921ef5d82dcc969e749 (mode 644)
--- /dev/null
+++ watch.go
+package icinga
+
+// A ServiceWatcher continuously queries Icinga about a set of Services.
+// A ServiceWatcher uses the next check time of Services to determine when to query Icinga again.
+// If it cannot determine the next check time, the Watcher waits 1 minute before trying again.
+type ServiceWatcher struct {
+ kill chan bool
+ Updates chan ServiceMsg
+}
+
+type HostWatcher struct {
+ Kill chan bool
+ Updates chan HostMsg
+}
+
+type ServiceMsg struct {
+ Services []Service
+ Err error
+}
+
+type HostMsg struct {
+ Hosts []Host
+ Err error
+}
+
+// Kill stops the Watcher irrevocably.
+// A new Watcher must be created with WatchServices.
+func (w *ServiceWatcher) Kill() {
+ w.kill <- true
+}
+
+// WatchServices returns a new Watcher which uses client to
+// continuously query Icinga for Services matching the given filter
+// expression.
+func WatchServices(client *Client, expr string) *Watcher {
+ timer := time.NewTimer(0)
+ kill := make(chan bool)
+ ch := make(chan ServiceMsg)
+ go func() {
+ select {
+ case <-kill:
+ close(ch)
+ return
+ case <-timer.C:
+ services, err := client.Services(expr)
+ ch <- ServiceMsg{services, err}
+ if err != nil {
+ timer.Reset(1*time.Minute)
+ } else {
+ timer.Reset(time.Until(nextCheck(services)))
+ }
+ }
+ }
+ return &Watcher{
+ kill: kill
+ Updates: ch
+ }
+}
+
+func WatchHosts(expr string, ch chan HostMsg, stop chan bool) {
+ timer := time.NewTimer(0)
+ select {
+ case <-stop:
+ close(ch)
+ return
+ case <-timer.C:
+ hosts, err := client.Hosts(expr)
+ ch <- HostMsg{hosts, err}
+ timer.Reset(time.Until(NextCheck(hosts)))
+ }
+}