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 {
Checks []CheckConfig

View file

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

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 {
RecordValue string

View file

@ -1,4 +1,4 @@
package monitor
package core
type Status int
@ -24,4 +24,3 @@ type Transition struct {
From Status
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 (
"../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
}
}

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"
"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{}

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