make modules make much more sense
This commit is contained in:
parent
b7609e24da
commit
9ac6dec291
54
checks/http.go
Normal file
54
checks/http.go
Normal 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
11
core/check.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type CheckCreateConfig struct {
|
||||
Engine *Engine
|
||||
Interval time.Duration
|
||||
Host TargetConfig
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package monitor
|
||||
package core
|
||||
|
||||
type Config struct {
|
||||
Checks []CheckConfig
|
|
@ -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)
|
||||
|
||||
engine := Engine{
|
||||
input,
|
||||
handlers,
|
||||
func NewEngine() *Engine {
|
||||
return &Engine{
|
||||
make(chan Result),
|
||||
make([]*GenericHandler, 0),
|
||||
make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
e := &engine
|
||||
func (this *Engine) AddHandler(handler *GenericHandler) {
|
||||
if handler == nil {
|
||||
return
|
||||
}
|
||||
|
||||
go e.startProcessor()
|
||||
this.handlers = append(this.handlers, handler)
|
||||
log.Print(fmt.Sprintf("%v", this.handlers))
|
||||
}
|
||||
|
||||
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
39
core/handler.go
Normal 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
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package monitor
|
||||
package core
|
||||
|
||||
type Result struct {
|
||||
RecordValue string
|
|
@ -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
19
engine/check.go
Normal 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
17
engine/engine.go
Normal 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
16
engine/handler.go
Normal 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
|
||||
}
|
|
@ -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
20
handlers/log.go
Normal 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()))
|
||||
}
|
22
main.go
22
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)
|
||||
|
||||
for _, reaction := range check.Reactions {
|
||||
handler := monitor.CreateHandler(reaction)
|
||||
|
||||
if handler == nil {
|
||||
continue
|
||||
engines = append(engines, engine.EngineFromConfig(check))
|
||||
}
|
||||
|
||||
handlers = append(handlers, handler)
|
||||
}
|
||||
|
||||
engine := monitor.CreateEngine(handlers)
|
||||
monitor.CreateCheck(check.Interval, engine, check.Target)
|
||||
for _, engine := range engines {
|
||||
engine.Run()
|
||||
}
|
||||
|
||||
select{}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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()))
|
||||
}
|
Loading…
Reference in a new issue