From 9ac6dec2919322432a4ca2e07ac86d728f83ef37 Mon Sep 17 00:00:00 2001 From: Kegan Myers Date: Sat, 22 Aug 2015 22:20:58 -0500 Subject: [PATCH] make modules make much more sense --- checks/http.go | 54 ++++++++++++++++++++++ core/check.go | 11 +++++ {monitor => core}/config.go | 2 +- {monitor => core}/engine.go | 38 ++++++++++------ core/handler.go | 39 ++++++++++++++++ {monitor => core}/result.go | 2 +- {monitor => core}/transition.go | 3 +- engine/check.go | 19 ++++++++ engine/engine.go | 17 +++++++ engine/handler.go | 16 +++++++ {monitor => handlers}/cloudflare.go | 17 +++---- handlers/log.go | 20 +++++++++ main.go | 24 ++++------ monitor/createCheck.go | 70 ----------------------------- monitor/handler.go | 30 ------------- monitor/log.go | 19 -------- 16 files changed, 222 insertions(+), 159 deletions(-) create mode 100644 checks/http.go create mode 100644 core/check.go rename {monitor => core}/config.go (95%) rename {monitor => core}/engine.go (51%) create mode 100644 core/handler.go rename {monitor => core}/result.go (79%) rename {monitor => core}/transition.go (95%) create mode 100644 engine/check.go create mode 100644 engine/engine.go create mode 100644 engine/handler.go rename {monitor => handlers}/cloudflare.go (81%) create mode 100644 handlers/log.go delete mode 100644 monitor/createCheck.go delete mode 100644 monitor/handler.go delete mode 100644 monitor/log.go diff --git a/checks/http.go b/checks/http.go new file mode 100644 index 0000000..696d7f5 --- /dev/null +++ b/checks/http.go @@ -0,0 +1,54 @@ +package checks + +import ( + "net/http" + "../core" + "time" + "log" + "fmt" +) + +func NewHttpChecker(config core.CheckCreateConfig) *HttpChecker { + checker := HttpChecker{ + &http.Client{}, + config, + config.Host.Type + "://" + config.Host.Host + "/", + } + go checker.run() + return &checker +} + +type HttpChecker struct { + client *http.Client + config core.CheckCreateConfig + endpoint string +} + +func (this *HttpChecker) run() { + interval := time.Duration(this.config.Interval) * time.Second + log.Print(fmt.Sprintf("Starting: %v\n", this.config.Host)) + for true { + this.config.Engine.Input<- core.Result{ + this.config.Host.Host, + this.check(), + } + time.Sleep(interval) + } +} + +func (this *HttpChecker) check() core.Status { + req, err := http.NewRequest("GET", this.endpoint, nil) + if err != nil { + log.Print(fmt.Sprintf("Stopping: %v due to http NewRequest error\n", this.config)) + return core.Unknown + } + req.Header.Set("Host", this.config.Host.Options["hostname"]) + return this.determineHttpCheckStatus(this.client.Do(req)) +} + +func (this *HttpChecker) determineHttpCheckStatus(res *http.Response, err error) core.Status { + if err != nil || res.StatusCode != 200 { + return core.Down + } + return core.Up +} diff --git a/core/check.go b/core/check.go new file mode 100644 index 0000000..de01a0f --- /dev/null +++ b/core/check.go @@ -0,0 +1,11 @@ +package core + +import ( + "time" +) + +type CheckCreateConfig struct { + Engine *Engine + Interval time.Duration + Host TargetConfig +} diff --git a/monitor/config.go b/core/config.go similarity index 95% rename from monitor/config.go rename to core/config.go index efc4b12..0c002de 100644 --- a/monitor/config.go +++ b/core/config.go @@ -1,4 +1,4 @@ -package monitor +package core type Config struct { Checks []CheckConfig diff --git a/monitor/engine.go b/core/engine.go similarity index 51% rename from monitor/engine.go rename to core/engine.go index a7e3484..5d6c42a 100644 --- a/monitor/engine.go +++ b/core/engine.go @@ -1,23 +1,35 @@ -package monitor +package core + +import ( + "log" + "fmt" +) type Engine struct { Input chan Result - output []*GenericHandler + handlers []*GenericHandler + killswitch chan bool } -func CreateEngine(handlers []*GenericHandler) *Engine { - input := make(chan Result) +func NewEngine() *Engine { + return &Engine{ + make(chan Result), + make([]*GenericHandler, 0), + make(chan bool, 1), + } +} - engine := Engine{ - input, - handlers, +func (this *Engine) AddHandler(handler *GenericHandler) { + if handler == nil { + return } - e := &engine + this.handlers = append(this.handlers, handler) + log.Print(fmt.Sprintf("%v", this.handlers)) +} - go e.startProcessor() - - return e +func (this *Engine) Run() { + go this.startProcessor() } func (this *Engine) startProcessor() { @@ -38,8 +50,8 @@ func (this *Engine) startProcessor() { } //Send the record to everyone who cares - for _, relay := range this.output { - relay.channel<- change + for _, relay := range this.handlers { + relay.Channel<- change } //And set our new status diff --git a/core/handler.go b/core/handler.go new file mode 100644 index 0000000..b887b5a --- /dev/null +++ b/core/handler.go @@ -0,0 +1,39 @@ +package core + +import ( +) + +type Handler interface{ + Handle(transition Transition) +} + +type GenericHandler struct { + Channel chan Transition + killswitch chan bool +} + +func (this *GenericHandler) Stop() { + this.killswitch <- true +} + +func (this *GenericHandler) run(proxy Handler) { + for true { + var transition Transition + select { + case <-this.killswitch: + return + case transition = <-this.Channel: + proxy.Handle(transition) + } + + } +} + +func NewGenericHandler(input chan Transition, proxy Handler) *GenericHandler { + handler := &GenericHandler{ + input, + make(chan bool, 1), + } + go handler.run(proxy) + return handler +} diff --git a/monitor/result.go b/core/result.go similarity index 79% rename from monitor/result.go rename to core/result.go index 530bcfd..c724a54 100644 --- a/monitor/result.go +++ b/core/result.go @@ -1,4 +1,4 @@ -package monitor +package core type Result struct { RecordValue string diff --git a/monitor/transition.go b/core/transition.go similarity index 95% rename from monitor/transition.go rename to core/transition.go index 4afcb1a..39dea7e 100644 --- a/monitor/transition.go +++ b/core/transition.go @@ -1,4 +1,4 @@ -package monitor +package core type Status int @@ -24,4 +24,3 @@ type Transition struct { From Status RecordValue string } - diff --git a/engine/check.go b/engine/check.go new file mode 100644 index 0000000..8cd4c9a --- /dev/null +++ b/engine/check.go @@ -0,0 +1,19 @@ +package engine + +import ( + "time" + "../core" + "../checks" +) + +func createCheck(interval uint16, engine *core.Engine, host core.TargetConfig) { + config := core.CheckCreateConfig{ + engine, + time.Duration(int64(interval)) * time.Second, + host, + } + switch host.Type { + case "http", "https": + checks.NewHttpChecker(config) + } +} diff --git a/engine/engine.go b/engine/engine.go new file mode 100644 index 0000000..582b318 --- /dev/null +++ b/engine/engine.go @@ -0,0 +1,17 @@ +package engine + +import ( + "../core" +) + +func EngineFromConfig(config core.CheckConfig) *core.Engine { + engine := core.NewEngine() + + for _, reaction := range config.Reactions { + engine.AddHandler(createHandler(reaction)) + } + + createCheck(config.Interval, engine, config.Target) + + return engine +} diff --git a/engine/handler.go b/engine/handler.go new file mode 100644 index 0000000..f70f2b2 --- /dev/null +++ b/engine/handler.go @@ -0,0 +1,16 @@ +package engine + +import ( + "../core" + "../handlers" +) + +func createHandler(handler core.ReactionConfig) *core.GenericHandler { + switch handler.Type { + case "cloudflare": + return handlers.NewCloudflareHandler(handler) + case "log": + return handlers.NewLogHandler(handler) + } + return nil +} diff --git a/monitor/cloudflare.go b/handlers/cloudflare.go similarity index 81% rename from monitor/cloudflare.go rename to handlers/cloudflare.go index fd964b2..a6de925 100644 --- a/monitor/cloudflare.go +++ b/handlers/cloudflare.go @@ -1,17 +1,18 @@ -package monitor +package handlers import ( "../cloudflare" + "../core" "log" "fmt" ) -func newCloudflareHandler(config ReactionConfig) *GenericHandler { +func NewCloudflareHandler(config core.ReactionConfig) *core.GenericHandler { if config.Options["email"] == "" || config.Options["apiKey"] == "" || config.Options["domain"] == "" || config.Options["name"] == "" || config.Options["ttl"] == "" { log.Fatal(fmt.Sprintf("Misconfigured cloudflare handler: %#v", config)) } - return runHandler(make(chan Transition, 5), &cloudflareHandler{ + return core.NewGenericHandler(make(chan core.Transition, 5), &cloudflareHandler{ config, cloudflare.NewClient(config.Options["email"], config.Options["apiKey"]), make(map[string]bool), @@ -19,26 +20,26 @@ func newCloudflareHandler(config ReactionConfig) *GenericHandler { } type cloudflareHandler struct{ - config ReactionConfig + config core.ReactionConfig client *cloudflare.Client actuallyDownHosts map[string]bool } -func (this *cloudflareHandler) handle(transition Transition) { +func (this *cloudflareHandler) Handle(transition core.Transition) { switch transition.To { - case Down: + case core.Down: log.Print(fmt.Sprintf( "Removed cloudflare record for `%s`: `%v`\n", transition.RecordValue, this.removeCloudflareRecord(transition.RecordValue))) - case Up: + case core.Up: log.Print(fmt.Sprintf( "Added cloudflare record for `%s`: `%v`\n", transition.RecordValue, this.addCloudflareRecord(transition.RecordValue))) - case Unknown: //just leave it how it was, going up/down is idempotent anyways + case core.Unknown: //just leave it how it was, going up/down is idempotent anyways } } diff --git a/handlers/log.go b/handlers/log.go new file mode 100644 index 0000000..39d43de --- /dev/null +++ b/handlers/log.go @@ -0,0 +1,20 @@ +package handlers + +import ( + "fmt" + "log" + "../core" +) + +func NewLogHandler(config core.ReactionConfig) *core.GenericHandler { + return core.NewGenericHandler(make(chan core.Transition), &logHandler{}) +} + +type logHandler struct{} + +func (this *logHandler) Handle(transition core.Transition) { + log.Print(fmt.Sprintf( + "`%s` has become `%d` - `%s`", + transition.RecordValue, transition.To, + transition.To.String())) +} diff --git a/main.go b/main.go index 5675f13..0ab9124 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,8 @@ import ( "fmt" "io/ioutil" "encoding/json" - "./monitor" + "./core" + "./engine" ) func main() { @@ -14,24 +15,17 @@ func main() { log.Fatal(fmt.Sprintf("%v\n", err)) } - c := monitor.Config{} + c := core.Config{} json.Unmarshal(file, &c) + engines := make([]*core.Engine, 0) + for _, check := range c.Checks { - handlers := make([]*monitor.GenericHandler, 0) + engines = append(engines, engine.EngineFromConfig(check)) + } - for _, reaction := range check.Reactions { - handler := monitor.CreateHandler(reaction) - - if handler == nil { - continue - } - - handlers = append(handlers, handler) - } - - engine := monitor.CreateEngine(handlers) - monitor.CreateCheck(check.Interval, engine, check.Target) + for _, engine := range engines { + engine.Run() } select{} diff --git a/monitor/createCheck.go b/monitor/createCheck.go deleted file mode 100644 index ea5bfd0..0000000 --- a/monitor/createCheck.go +++ /dev/null @@ -1,70 +0,0 @@ -package monitor - -import ( - "net/http" - "time" - "log" - "fmt" -) - -type checkConfig struct { - engine *Engine - interval time.Duration - host TargetConfig -} - -type httpChecker struct { - client *http.Client - config checkConfig - endpoint string -} - -func (this *httpChecker) run() { - log.Print(fmt.Sprintf("Starting: %v\n", this.config.host)) - for true { - this.config.engine.Input<- Result{ - this.config.host.Host, - this.check(), - } - time.Sleep(this.config.interval) - } -} - -func (this *httpChecker) check() Status { - req, err := http.NewRequest("GET", this.endpoint, nil) - if err != nil { - log.Print(fmt.Sprintf("Stopping: %v due to http NewRequest error\n", this.config.host)) - return Unknown - } - req.Header.Set("Host", this.config.host.Options["hostname"]) - return this.determineHttpCheckStatus(this.client.Do(req)) -} - -func (this *httpChecker) determineHttpCheckStatus(res *http.Response, err error) Status { - if err != nil || res.StatusCode != 200 { - return Down - } - return Up -} - -func newHttpChecker(config checkConfig) *httpChecker { - checker := httpChecker{ - &http.Client{}, - config, - config.host.Type + "://" + config.host.Host + "/", - } - go checker.run() - return &checker -} - -func CreateCheck(interval uint16, engine *Engine, host TargetConfig) { - config := checkConfig{ - engine, - time.Duration(int64(interval)) * time.Second, - host, - } - switch host.Type { - case "http", "https": - newHttpChecker(config) - } -} diff --git a/monitor/handler.go b/monitor/handler.go deleted file mode 100644 index 149973c..0000000 --- a/monitor/handler.go +++ /dev/null @@ -1,30 +0,0 @@ -package monitor - -type handler interface{ - handle(transition Transition) -} - -type GenericHandler struct { - channel chan Transition -} - -func runHandler(input chan Transition, handler handler) *GenericHandler { - go func() { - for true { - handler.handle(<-input) - } - }() - return &GenericHandler{ - input, - } -} - -func CreateHandler(handler ReactionConfig) *GenericHandler { - switch handler.Type { - case "cloudflare": - return newCloudflareHandler(handler) - case "log": - return newLogHandler(handler) - } - return nil -} diff --git a/monitor/log.go b/monitor/log.go deleted file mode 100644 index 8d2feac..0000000 --- a/monitor/log.go +++ /dev/null @@ -1,19 +0,0 @@ -package monitor - -import ( - "fmt" - "log" -) - -func newLogHandler(config ReactionConfig) *GenericHandler { - return runHandler(make(chan Transition), &logHandler{}) -} - -type logHandler struct{} - -func (this *logHandler) handle(transition Transition) { - log.Print(fmt.Sprintf( - "`%s` has become `%d` - `%s`", - transition.RecordValue, transition.To, - transition.To.String())) -}