Graceful exit, and slight restructuring
This commit is contained in:
parent
9ac6dec291
commit
0291404261
28
README.md
28
README.md
|
@ -12,32 +12,8 @@ and placed in whatever directory you will run CFHA from.
|
|||
|
||||
Example configuration file:
|
||||
|
||||
```js
|
||||
{
|
||||
"hosts": [ //an array of hosts to check
|
||||
{
|
||||
"host": "192.168.1.1", //the IP address of the host
|
||||
"type": "http", //the type of check to run, can be either http or https
|
||||
"options": {} //optional additional parameters to the check module
|
||||
},
|
||||
{
|
||||
"host": "192.168.1.2",
|
||||
"type": "https",
|
||||
"options": {
|
||||
"hostname": "lb-check-hostname" //this is the only currently supported parameter, and will be sent as the "host" header of an http(s) request
|
||||
}
|
||||
}
|
||||
],
|
||||
"cloudflare": { //cloudflare configuration
|
||||
"email": "cfemail@example.com",
|
||||
"apiKey": "CF_API_KEY", //get this from your cloudflare profile
|
||||
"domain": "example.com", //the domain in cloudflare you will be operating on
|
||||
"name": "lb.example.com", //the full dns record you wish to edit
|
||||
"ttl": "1" //1 is automatic, otherwise see the cloudflare documentation on TTL
|
||||
},
|
||||
"interval": 1 //how often (in seconds) to ping the server, note that this is a number, not a string
|
||||
}
|
||||
```
|
||||
(the configuration format is currently in flux, the example will be updated when it is stable. for now just look at `core/config` and build a json object to match `Config`)
|
||||
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
|
|
@ -8,14 +8,12 @@ import (
|
|||
"fmt"
|
||||
)
|
||||
|
||||
func NewHttpChecker(config core.CheckCreateConfig) *HttpChecker {
|
||||
checker := HttpChecker{
|
||||
func NewHttpChecker(config core.CheckCreateConfig) *core.GenericCheck {
|
||||
return core.NewGenericCheck(&HttpChecker{
|
||||
&http.Client{},
|
||||
config,
|
||||
config.Host.Type + "://" + config.Host.Host + "/",
|
||||
}
|
||||
go checker.run()
|
||||
return &checker
|
||||
})
|
||||
}
|
||||
|
||||
type HttpChecker struct {
|
||||
|
@ -24,16 +22,16 @@ type HttpChecker struct {
|
|||
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() time.Duration {
|
||||
this.config.Engine.Input<- core.Result{
|
||||
this.config.Host.Host,
|
||||
this.check(),
|
||||
}
|
||||
return this.config.Interval
|
||||
}
|
||||
|
||||
func (this *HttpChecker) Stop() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *HttpChecker) check() core.Status {
|
||||
|
|
|
@ -9,3 +9,42 @@ type CheckCreateConfig struct {
|
|||
Interval time.Duration
|
||||
Host TargetConfig
|
||||
}
|
||||
|
||||
type Check interface{
|
||||
Check() time.Duration
|
||||
Stop() bool
|
||||
}
|
||||
|
||||
func NewGenericCheck(proxy Check) *GenericCheck {
|
||||
check := &GenericCheck{
|
||||
make(chan bool, 0),
|
||||
make(chan bool, 0),
|
||||
proxy,
|
||||
}
|
||||
go check.run()
|
||||
return check
|
||||
}
|
||||
|
||||
type GenericCheck struct {
|
||||
killswitch chan bool
|
||||
killresponse chan bool
|
||||
proxy Check
|
||||
}
|
||||
|
||||
func (this *GenericCheck) Stop() bool {
|
||||
this.killswitch<- true
|
||||
return <-this.killresponse
|
||||
}
|
||||
|
||||
func (this *GenericCheck) run() {
|
||||
timeout := time.NewTimer(0)
|
||||
for true {
|
||||
select {
|
||||
case <-this.killswitch:
|
||||
this.killresponse<- this.proxy.Stop()
|
||||
return
|
||||
case <-timeout.C:
|
||||
timeout = time.NewTimer(this.proxy.Check())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ type Config struct {
|
|||
}
|
||||
|
||||
type CheckConfig struct {
|
||||
Interval uint16
|
||||
Target TargetConfig
|
||||
Targets []TargetConfig
|
||||
Reactions []ReactionConfig
|
||||
}
|
||||
|
||||
type TargetConfig struct {
|
||||
Interval uint16
|
||||
Type string
|
||||
Host string
|
||||
Options map[string]string
|
||||
|
|
|
@ -8,15 +8,32 @@ import (
|
|||
type Engine struct {
|
||||
Input chan Result
|
||||
handlers []*GenericHandler
|
||||
checks []*GenericCheck
|
||||
killswitch chan bool
|
||||
killresponse chan bool
|
||||
}
|
||||
|
||||
func NewEngine() *Engine {
|
||||
return &Engine{
|
||||
engine := &Engine{
|
||||
make(chan Result),
|
||||
make([]*GenericHandler, 0),
|
||||
make(chan bool, 1),
|
||||
make([]*GenericCheck, 0),
|
||||
make(chan bool, 0),
|
||||
make(chan bool, 0),
|
||||
}
|
||||
|
||||
go engine.startProcessor()
|
||||
|
||||
return engine
|
||||
}
|
||||
|
||||
func (this *Engine) AddCheck(check *GenericCheck) {
|
||||
if check == nil {
|
||||
return
|
||||
}
|
||||
|
||||
this.checks = append(this.checks, check)
|
||||
log.Print(fmt.Sprintf("%v", this.checks))
|
||||
}
|
||||
|
||||
func (this *Engine) AddHandler(handler *GenericHandler) {
|
||||
|
@ -28,33 +45,50 @@ func (this *Engine) AddHandler(handler *GenericHandler) {
|
|||
log.Print(fmt.Sprintf("%v", this.handlers))
|
||||
}
|
||||
|
||||
func (this *Engine) Run() {
|
||||
go this.startProcessor()
|
||||
func (this *Engine) Stop() bool {
|
||||
this.killswitch<- true
|
||||
return <-this.killresponse
|
||||
}
|
||||
|
||||
func (this *Engine) startProcessor() {
|
||||
statuses := make(map[string]Status)
|
||||
for true {
|
||||
result := <-this.Input
|
||||
select {
|
||||
case result := <-this.Input:
|
||||
//No transition if we don't exist
|
||||
if result.Status == statuses[result.RecordValue] {
|
||||
continue
|
||||
}
|
||||
|
||||
//No transition if we don't exist
|
||||
if result.Status == statuses[result.RecordValue] {
|
||||
continue
|
||||
//Create a record with to, from
|
||||
change := Transition{
|
||||
result.Status,
|
||||
statuses[result.RecordValue],
|
||||
result.RecordValue,
|
||||
}
|
||||
|
||||
//Send the record to everyone who cares
|
||||
for _, relay := range this.handlers {
|
||||
relay.Channel<- change
|
||||
}
|
||||
|
||||
//And set our new status
|
||||
statuses[result.RecordValue] = result.Status
|
||||
case <-this.killswitch:
|
||||
this.killresponse<- this.stop()
|
||||
return
|
||||
}
|
||||
|
||||
//Create a record with to, from
|
||||
change := Transition{
|
||||
result.Status,
|
||||
statuses[result.RecordValue],
|
||||
result.RecordValue,
|
||||
}
|
||||
|
||||
//Send the record to everyone who cares
|
||||
for _, relay := range this.handlers {
|
||||
relay.Channel<- change
|
||||
}
|
||||
|
||||
//And set our new status
|
||||
statuses[result.RecordValue] = result.Status
|
||||
}
|
||||
}
|
||||
|
||||
func (this *Engine) stop() bool {
|
||||
exitStatus := true
|
||||
for _, handler := range this.handlers {
|
||||
exitStatus = exitStatus && handler.Stop()
|
||||
}
|
||||
for _, check := range this.checks {
|
||||
exitStatus = exitStatus && check.Stop()
|
||||
}
|
||||
return exitStatus
|
||||
}
|
||||
|
||||
|
|
|
@ -5,35 +5,42 @@ 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)
|
||||
}
|
||||
|
||||
}
|
||||
Stop() bool
|
||||
}
|
||||
|
||||
func NewGenericHandler(input chan Transition, proxy Handler) *GenericHandler {
|
||||
handler := &GenericHandler{
|
||||
input,
|
||||
make(chan bool, 1),
|
||||
make(chan bool, 0),
|
||||
make(chan bool, 0),
|
||||
proxy,
|
||||
}
|
||||
go handler.run(proxy)
|
||||
go handler.run()
|
||||
return handler
|
||||
}
|
||||
|
||||
type GenericHandler struct {
|
||||
Channel chan Transition
|
||||
killswitch chan bool
|
||||
killresponse chan bool
|
||||
proxy Handler
|
||||
}
|
||||
|
||||
func (this *GenericHandler) Stop() bool {
|
||||
this.killswitch<- true
|
||||
return <-this.killresponse
|
||||
}
|
||||
|
||||
func (this *GenericHandler) run() {
|
||||
for true {
|
||||
var transition Transition
|
||||
select {
|
||||
case <-this.killswitch:
|
||||
this.killresponse<- this.proxy.Stop()
|
||||
return
|
||||
case transition = <-this.Channel:
|
||||
this.proxy.Handle(transition)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"time"
|
||||
"../core"
|
||||
"../checks"
|
||||
)
|
||||
|
||||
func createCheck(interval uint16, engine *core.Engine, host core.TargetConfig) {
|
||||
func createCheck(engine *core.Engine, host core.TargetConfig) *core.GenericCheck {
|
||||
log.Print("createCheck called")
|
||||
log.Print(fmt.Sprintf("creating a `%s`", host.Type))
|
||||
config := core.CheckCreateConfig{
|
||||
engine,
|
||||
time.Duration(int64(interval)) * time.Second,
|
||||
time.Duration(int64(host.Interval)) * time.Second,
|
||||
host,
|
||||
}
|
||||
switch host.Type {
|
||||
case "http", "https":
|
||||
checks.NewHttpChecker(config)
|
||||
return checks.NewHttpChecker(config)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ func EngineFromConfig(config core.CheckConfig) *core.Engine {
|
|||
engine.AddHandler(createHandler(reaction))
|
||||
}
|
||||
|
||||
createCheck(config.Interval, engine, config.Target)
|
||||
for _, target := range config.Targets {
|
||||
engine.AddCheck(createCheck(engine, target))
|
||||
}
|
||||
|
||||
return engine
|
||||
}
|
||||
|
|
|
@ -43,6 +43,10 @@ func (this *cloudflareHandler) Handle(transition core.Transition) {
|
|||
}
|
||||
}
|
||||
|
||||
func (this *cloudflareHandler) Stop() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (this *cloudflareHandler) removeCloudflareRecord(recordValue string) bool {
|
||||
records, err := this.client.RetrieveRecordsByName(this.config.Options["Domain"], this.config.Options["Name"])
|
||||
|
||||
|
|
|
@ -18,3 +18,7 @@ func (this *logHandler) Handle(transition core.Transition) {
|
|||
transition.RecordValue, transition.To,
|
||||
transition.To.String()))
|
||||
}
|
||||
|
||||
func (this *logHandler) Stop() bool {
|
||||
return true
|
||||
}
|
||||
|
|
15
main.go
15
main.go
|
@ -3,7 +3,10 @@ package main
|
|||
import (
|
||||
"log"
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
"io/ioutil"
|
||||
"os/signal"
|
||||
"encoding/json"
|
||||
"./core"
|
||||
"./engine"
|
||||
|
@ -24,9 +27,13 @@ func main() {
|
|||
engines = append(engines, engine.EngineFromConfig(check))
|
||||
}
|
||||
|
||||
for _, engine := range engines {
|
||||
engine.Run()
|
||||
}
|
||||
sigs := make(chan os.Signal, 1)
|
||||
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-sigs
|
||||
|
||||
select{}
|
||||
log.Print(fmt.Sprintf("Stopping."))
|
||||
for _, engine := range engines {
|
||||
engine.Stop()
|
||||
}
|
||||
log.Print("Exiting.")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue