@ -0,0 +1,2 @@ |
|||||
|
config.json |
||||
|
logs |
@ -0,0 +1,39 @@ |
|||||
|
# canaryBot |
||||
|
Bot to check if services are alive. |
||||
|
Current bots: |
||||
|
- Matrix (Riot) |
||||
|
|
||||
|
|
||||
|
#### Config |
||||
|
File `config.json` |
||||
|
```json |
||||
|
{ |
||||
|
"matrix": { |
||||
|
"room_id": "!zzzzz:mmmmmm.ooo", |
||||
|
"user": "aaaaa", |
||||
|
"password": "xxxxx", |
||||
|
"server": "https://sssss.ooo" |
||||
|
}, |
||||
|
"services": [{ |
||||
|
"name": "name01", |
||||
|
"url": "http://127.0.0.1:80", |
||||
|
"statusCode": 200 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "service02", |
||||
|
"url": "http://127.0.0.1:7000/api", |
||||
|
"statusCode": 200 |
||||
|
} |
||||
|
], |
||||
|
"sleepTime": 30, |
||||
|
"retry": 5 |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
- sleepTime: time between each request to the services |
||||
|
- retry: after X times failing, restart the counter |
||||
|
|
||||
|
### Run |
||||
|
``` |
||||
|
./canaryBot |
||||
|
``` |
@ -0,0 +1,54 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"log" |
||||
|
"net/http" |
||||
|
"strconv" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func checker(services []Service) { |
||||
|
log.Println("serverChecker started") |
||||
|
log.Println(services) |
||||
|
|
||||
|
ticker := time.NewTicker(time.Second * time.Duration(int64(config.SleepTime))) |
||||
|
for _ = range ticker.C { |
||||
|
for k, service := range services { |
||||
|
resp, err := checkUrl(service.Url) |
||||
|
if err != nil { |
||||
|
if service.Counter == 0 { |
||||
|
msg := "⚠️ Service " + service.Name + ", with url " + service.Url + " is not responding" |
||||
|
matrixSendMsg(msg) |
||||
|
} |
||||
|
services[k].Counter = services[k].Counter + 1 |
||||
|
} else if resp.StatusCode != service.StatusCode { |
||||
|
if service.Counter == 0 { |
||||
|
msg := "⚠️ Service " + service.Name + ", with url " + service.Url + " has returned a non expected StatusCode: " + strconv.Itoa(resp.StatusCode) + ", expected: " + strconv.Itoa(service.StatusCode) |
||||
|
matrixSendMsg(msg) |
||||
|
} |
||||
|
services[k].Counter = services[k].Counter + 1 |
||||
|
} else { |
||||
|
if services[k].Counter != 0 { |
||||
|
msg := "✔️ Service " + service.Name + ", with url " + service.Url + " is alive again" |
||||
|
matrixSendMsg(msg) |
||||
|
} |
||||
|
services[k].Counter = 0 |
||||
|
} |
||||
|
|
||||
|
if services[k].Counter > config.Retry { |
||||
|
msg := "⚠️ Service " + services[k].Name + ", with url " + services[k].Url + " is still failing" |
||||
|
matrixSendNotice(msg) |
||||
|
services[k].Counter = 1 |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func checkUrl(url string) (*http.Response, error) { |
||||
|
timeout := time.Duration(1 * time.Second) |
||||
|
client := http.Client{ |
||||
|
Timeout: timeout, |
||||
|
} |
||||
|
resp, err := client.Get(url) |
||||
|
return resp, err |
||||
|
} |
@ -0,0 +1,37 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"io/ioutil" |
||||
|
) |
||||
|
|
||||
|
//MatrixConfig stores the matrix data config
|
||||
|
type MatrixConfig struct { |
||||
|
RoomId string `json:"room_id"` |
||||
|
User string `json:"user"` |
||||
|
Password string `json:"password"` |
||||
|
Server string `json:"server"` |
||||
|
} |
||||
|
type Service struct { |
||||
|
Name string `json:"name"` |
||||
|
Url string `json:"url"` |
||||
|
StatusCode int `json:"statusCode"` |
||||
|
Counter int |
||||
|
} |
||||
|
type Config struct { |
||||
|
Matrix MatrixConfig `json:"matrix"` |
||||
|
Services []Service `json:"services"` |
||||
|
SleepTime int `json:"sleepTime"` |
||||
|
Retry int `json:"retry"` |
||||
|
} |
||||
|
|
||||
|
var config Config |
||||
|
|
||||
|
func readConfig() { |
||||
|
file, e := ioutil.ReadFile("config.json") |
||||
|
if e != nil { |
||||
|
panic(e) |
||||
|
} |
||||
|
content := string(file) |
||||
|
json.Unmarshal([]byte(content), &config) |
||||
|
} |
@ -0,0 +1,7 @@ |
|||||
|
module github.com/arnaucube/canaryBot |
||||
|
|
||||
|
require ( |
||||
|
github.com/fatih/color v1.7.0 |
||||
|
github.com/mattn/go-colorable v0.0.9 // indirect |
||||
|
github.com/mattn/go-isatty v0.0.4 // indirect |
||||
|
) |
@ -0,0 +1,6 @@ |
|||||
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= |
||||
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= |
||||
|
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= |
||||
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= |
||||
|
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= |
||||
|
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= |
@ -0,0 +1,19 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"io" |
||||
|
"log" |
||||
|
"os" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func savelog() { |
||||
|
timeS := time.Now().String() |
||||
|
_ = os.Mkdir("logs", os.ModePerm) |
||||
|
logFile, err := os.OpenFile("logs/log-"+timeS+".log", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0666) |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
mw := io.MultiWriter(os.Stdout, logFile) |
||||
|
log.SetOutput(mw) |
||||
|
} |
@ -0,0 +1,28 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"fmt" |
||||
|
|
||||
|
"github.com/fatih/color" |
||||
|
) |
||||
|
|
||||
|
const version = "0.0.1-dev" |
||||
|
|
||||
|
func main() { |
||||
|
savelog() |
||||
|
|
||||
|
color.Green("canaryBot") |
||||
|
color.Yellow("version: " + version) |
||||
|
|
||||
|
color.Magenta("------matrix------") |
||||
|
readConfig() |
||||
|
loginMatrix() |
||||
|
fmt.Print("matrix token: ") |
||||
|
color.Cyan(matrixToken.AccessToken) |
||||
|
fmt.Println("") |
||||
|
matrixSendMsg("canaryBot started") |
||||
|
|
||||
|
color.Magenta("------starting to listen------") |
||||
|
|
||||
|
checker(config.Services) |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"fmt" |
||||
|
"io/ioutil" |
||||
|
"log" |
||||
|
"math/rand" |
||||
|
"net/http" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/fatih/color" |
||||
|
) |
||||
|
|
||||
|
//MatrixToken stores the token data from matrix
|
||||
|
type MatrixToken struct { |
||||
|
AccessToken string `json:"access_token"` |
||||
|
Server string `json:"server"` |
||||
|
UserId string `json:"user_id"` |
||||
|
DeviceId string `json:"device_id"` |
||||
|
} |
||||
|
|
||||
|
var matrixToken MatrixToken |
||||
|
|
||||
|
var defaultTimeFormat = "15:04:05" |
||||
|
|
||||
|
func loginMatrix() { |
||||
|
url := config.Matrix.Server + "/_matrix/client/r0/login" |
||||
|
jsonStr := `{ |
||||
|
"type":"m.login.password", |
||||
|
"user":"` + config.Matrix.User + `", |
||||
|
"password":"` + config.Matrix.Password + `" |
||||
|
}` |
||||
|
b := strings.NewReader(jsonStr) |
||||
|
req, _ := http.NewRequest("POST", url, b) |
||||
|
req.Header.Set("Content-Type", "application/json") |
||||
|
res, err := http.DefaultClient.Do(req) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
defer res.Body.Close() |
||||
|
body, _ := ioutil.ReadAll(res.Body) |
||||
|
|
||||
|
json.Unmarshal([]byte(body), &matrixToken) |
||||
|
|
||||
|
} |
||||
|
func matrixSendMsg(msg string) { |
||||
|
txnId := strconv.Itoa(rand.Int()) |
||||
|
url := config.Matrix.Server + "/_matrix/client/r0/rooms/" + config.Matrix.RoomId + "/send/m.room.message/" + txnId + "?access_token=" + matrixToken.AccessToken |
||||
|
jsonStr := `{ |
||||
|
"body":"` + time.Now().Format(defaultTimeFormat) + `: ` + msg + `", |
||||
|
"msgtype":"m.text" |
||||
|
}` |
||||
|
b := strings.NewReader(jsonStr) |
||||
|
req, _ := http.NewRequest("PUT", url, b) |
||||
|
req.Header.Set("Content-Type", "application/json") |
||||
|
res, err := http.DefaultClient.Do(req) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
defer res.Body.Close() |
||||
|
body, _ := ioutil.ReadAll(res.Body) |
||||
|
|
||||
|
fmt.Println(string(body)) |
||||
|
fmt.Print("msg sent to Matrix: ") |
||||
|
color.Green(msg) |
||||
|
|
||||
|
} |
||||
|
|
||||
|
func matrixSendNotice(msg string) { |
||||
|
txnId := strconv.Itoa(rand.Int()) |
||||
|
url := config.Matrix.Server + "/_matrix/client/r0/rooms/" + config.Matrix.RoomId + "/send/m.room.message/" + txnId + "?access_token=" + matrixToken.AccessToken |
||||
|
jsonStr := `{ |
||||
|
"body":"` + time.Now().Format(defaultTimeFormat) + `: ` + msg + `", |
||||
|
"msgtype":"m.notice" |
||||
|
}` |
||||
|
b := strings.NewReader(jsonStr) |
||||
|
req, _ := http.NewRequest("PUT", url, b) |
||||
|
req.Header.Set("Content-Type", "application/json") |
||||
|
res, err := http.DefaultClient.Do(req) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
} |
||||
|
defer res.Body.Close() |
||||
|
body, _ := ioutil.ReadAll(res.Body) |
||||
|
|
||||
|
fmt.Println(string(body)) |
||||
|
fmt.Print("msg sent to Matrix: ") |
||||
|
color.Green(msg) |
||||
|
|
||||
|
} |