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 {
|
type Config struct {
|
||||||
Checks []CheckConfig
|
Checks []CheckConfig
|
|
@ -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
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 {
|
type Result struct {
|
||||||
RecordValue string
|
RecordValue string
|
|
@ -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
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 (
|
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
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()))
|
||||||
|
}
|
24
main.go
24
main.go
|
@ -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{}
|
||||||
|
|
|
@ -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