make modules make much more sense

This commit is contained in:
Kegan Myers 2015-08-22 22:20:58 -05:00
parent b7609e24da
commit 9ac6dec291
16 changed files with 222 additions and 159 deletions

54
checks/http.go Normal file
View file

@ -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
}

11
core/check.go Normal file
View file

@ -0,0 +1,11 @@
package core
import (
"time"
)
type CheckCreateConfig struct {
Engine *Engine
Interval time.Duration
Host TargetConfig
}

View file

@ -1,4 +1,4 @@
package monitor package core
type Config struct { type Config struct {
Checks []CheckConfig Checks []CheckConfig

View file

@ -1,23 +1,35 @@
package monitor package core
import (
"log"
"fmt"
)
type Engine struct { type Engine struct {
Input chan Result Input chan Result
output []*GenericHandler handlers []*GenericHandler
killswitch chan bool
} }
func CreateEngine(handlers []*GenericHandler) *Engine { func NewEngine() *Engine {
input := make(chan Result) return &Engine{
make(chan Result),
make([]*GenericHandler, 0),
make(chan bool, 1),
}
}
engine := Engine{ func (this *Engine) AddHandler(handler *GenericHandler) {
input, if handler == nil {
handlers, return
} }
e := &engine this.handlers = append(this.handlers, handler)
log.Print(fmt.Sprintf("%v", this.handlers))
}
go e.startProcessor() func (this *Engine) Run() {
go this.startProcessor()
return e
} }
func (this *Engine) startProcessor() { func (this *Engine) startProcessor() {
@ -38,8 +50,8 @@ func (this *Engine) startProcessor() {
} }
//Send the record to everyone who cares //Send the record to everyone who cares
for _, relay := range this.output { for _, relay := range this.handlers {
relay.channel<- change relay.Channel<- change
} }
//And set our new status //And set our new status

39
core/handler.go Normal file
View file

@ -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
}

View file

@ -1,4 +1,4 @@
package monitor package core
type Result struct { type Result struct {
RecordValue string RecordValue string

View file

@ -1,4 +1,4 @@
package monitor package core
type Status int type Status int
@ -24,4 +24,3 @@ type Transition struct {
From Status From Status
RecordValue string RecordValue string
} }

19
engine/check.go Normal file
View file

@ -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)
}
}

17
engine/engine.go Normal file
View file

@ -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
}

16
engine/handler.go Normal file
View file

@ -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
}

View file

@ -1,17 +1,18 @@
package monitor package handlers
import ( import (
"../cloudflare" "../cloudflare"
"../core"
"log" "log"
"fmt" "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"] == "" { 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)) 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, config,
cloudflare.NewClient(config.Options["email"], config.Options["apiKey"]), cloudflare.NewClient(config.Options["email"], config.Options["apiKey"]),
make(map[string]bool), make(map[string]bool),
@ -19,26 +20,26 @@ func newCloudflareHandler(config ReactionConfig) *GenericHandler {
} }
type cloudflareHandler struct{ type cloudflareHandler struct{
config ReactionConfig config core.ReactionConfig
client *cloudflare.Client client *cloudflare.Client
actuallyDownHosts map[string]bool actuallyDownHosts map[string]bool
} }
func (this *cloudflareHandler) handle(transition Transition) { func (this *cloudflareHandler) Handle(transition core.Transition) {
switch transition.To { switch transition.To {
case Down: case core.Down:
log.Print(fmt.Sprintf( log.Print(fmt.Sprintf(
"Removed cloudflare record for `%s`: `%v`\n", "Removed cloudflare record for `%s`: `%v`\n",
transition.RecordValue, transition.RecordValue,
this.removeCloudflareRecord(transition.RecordValue))) this.removeCloudflareRecord(transition.RecordValue)))
case Up: case core.Up:
log.Print(fmt.Sprintf( log.Print(fmt.Sprintf(
"Added cloudflare record for `%s`: `%v`\n", "Added cloudflare record for `%s`: `%v`\n",
transition.RecordValue, transition.RecordValue,
this.addCloudflareRecord(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
} }
} }

20
handlers/log.go Normal file
View file

@ -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()))
}

24
main.go
View file

@ -5,7 +5,8 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"encoding/json" "encoding/json"
"./monitor" "./core"
"./engine"
) )
func main() { func main() {
@ -14,24 +15,17 @@ func main() {
log.Fatal(fmt.Sprintf("%v\n", err)) log.Fatal(fmt.Sprintf("%v\n", err))
} }
c := monitor.Config{} c := core.Config{}
json.Unmarshal(file, &c) json.Unmarshal(file, &c)
engines := make([]*core.Engine, 0)
for _, check := range c.Checks { for _, check := range c.Checks {
handlers := make([]*monitor.GenericHandler, 0) engines = append(engines, engine.EngineFromConfig(check))
}
for _, reaction := range check.Reactions { for _, engine := range engines {
handler := monitor.CreateHandler(reaction) engine.Run()
if handler == nil {
continue
}
handlers = append(handlers, handler)
}
engine := monitor.CreateEngine(handlers)
monitor.CreateCheck(check.Interval, engine, check.Target)
} }
select{} select{}

View file

@ -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)
}
}

View file

@ -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
}

View file

@ -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()))
}