mirror of https://github.com/statping/statping
AWS SNS Notifier, go:generate version and commit into API.js
parent
8b54ceb16f
commit
0eba5881be
|
@ -262,6 +262,10 @@ jobs:
|
||||||
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
||||||
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
||||||
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
||||||
|
SNS_TOKEN: ${{ secrets.SNS_TOKEN }}
|
||||||
|
SNS_SECRET: ${{ secrets.SNS_SECRET }}
|
||||||
|
SNS_REGION: ${{ secrets.SNS_REGION }}
|
||||||
|
SNS_TOPIC: ${{ secrets.SNS_TOPIC }}
|
||||||
|
|
||||||
- name: Coveralls Testing Coverage
|
- name: Coveralls Testing Coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -262,6 +262,10 @@ jobs:
|
||||||
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
TEST_EMAIL: ${{ secrets.TEST_EMAIL }}
|
||||||
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
GOTIFY_URL: ${{ secrets.GOTIFY_URL }}
|
||||||
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
GOTIFY_TOKEN: ${{ secrets.GOTIFY_TOKEN }}
|
||||||
|
SNS_TOKEN: ${{ secrets.SNS_TOKEN }}
|
||||||
|
SNS_SECRET: ${{ secrets.SNS_SECRET }}
|
||||||
|
SNS_REGION: ${{ secrets.SNS_REGION }}
|
||||||
|
SNS_TOPIC: ${{ secrets.SNS_TOPIC }}
|
||||||
|
|
||||||
- name: Coveralls Testing Coverage
|
- name: Coveralls Testing Coverage
|
||||||
run: |
|
run: |
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
- Modified Service Group failures on index page to show 90 days of failures
|
- Modified Service Group failures on index page to show 90 days of failures
|
||||||
- Modified Service view page, updated Latency and Ping charts, added failures below
|
- Modified Service view page, updated Latency and Ping charts, added failures below
|
||||||
- Modified Service chart on index page to show ping data along with latency
|
- Modified Service chart on index page to show ping data along with latency
|
||||||
|
- Added AWS SNS Notifier
|
||||||
|
|
||||||
# 0.90.63 (08-17-2020)
|
# 0.90.63 (08-17-2020)
|
||||||
- Modified build process to use xgo for all arch builds
|
- Modified build process to use xgo for all arch builds
|
||||||
|
|
|
@ -4,12 +4,17 @@ const qs = require('querystring');
|
||||||
axios.defaults.withCredentials = true
|
axios.defaults.withCredentials = true
|
||||||
|
|
||||||
const tokenKey = "statping_auth";
|
const tokenKey = "statping_auth";
|
||||||
|
const version = "0.90.64";
|
||||||
|
const commit = "8b54ceb16f0e2ca6c4f5b8f0fe3b5cc2598dc594";
|
||||||
|
|
||||||
class Api {
|
class Api {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
version = () => version
|
||||||
|
commit = () => commit
|
||||||
|
|
||||||
async oauth() {
|
async oauth() {
|
||||||
const oauth = axios.get('api/oauth').then(response => (response.data))
|
const oauth = axios.get('api/oauth').then(response => (response.data))
|
||||||
return oauth
|
return oauth
|
||||||
|
|
|
@ -2275,7 +2275,7 @@ OluFxewsEO0QNDrfFb+0gnjYlnGqOFcZjUMXbDdY5oLSPtXohynuTK1qyQ==
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="text-center small text-dim" v-pre>
|
<div class="text-center small text-dim" v-pre>
|
||||||
Automatically generated from Statping's Wiki on 2020-08-19 02:31:01.555206 +0000 UTC
|
Automatically generated from Statping's Wiki on 2020-08-20 04:46:47.972956 +0000 UTC
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -5,6 +5,7 @@ go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/GeertJohan/go.rice v1.0.0
|
github.com/GeertJohan/go.rice v1.0.0
|
||||||
|
github.com/aws/aws-sdk-go v1.30.20
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/fatih/structs v1.1.0
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/foomo/simplecert v1.7.5
|
github.com/foomo/simplecert v1.7.5
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
package notifiers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
|
"github.com/aws/aws-sdk-go/service/sns"
|
||||||
|
"github.com/statping/statping/types/null"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/statping/statping/types/failures"
|
||||||
|
"github.com/statping/statping/types/notifications"
|
||||||
|
"github.com/statping/statping/types/notifier"
|
||||||
|
"github.com/statping/statping/types/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ notifier.Notifier = (*amazonSNS)(nil)
|
||||||
|
|
||||||
|
type amazonSNS struct {
|
||||||
|
*notifications.Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *amazonSNS) Select() *notifications.Notification {
|
||||||
|
return g.Notification
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *amazonSNS) Valid(values notifications.Values) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var AmazonSNS = &amazonSNS{¬ifications.Notification{
|
||||||
|
Method: "amazon_sns",
|
||||||
|
Title: "Amazon SNS",
|
||||||
|
Description: "Use amazonSNS to receive push notifications. Add your amazonSNS URL and App Token to receive notifications.",
|
||||||
|
Author: "Hunter Long",
|
||||||
|
AuthorUrl: "https://github.com/hunterlong",
|
||||||
|
Icon: "amazon",
|
||||||
|
Delay: 5 * time.Second,
|
||||||
|
Limits: 60,
|
||||||
|
SuccessData: null.NewNullString(`{{.Service.Name}} is back online and was down for {{.Service.Downtime.Human}}`),
|
||||||
|
FailureData: null.NewNullString(`{{.Service.Name}} is offline and has been down for {{.Service.Downtime.Human}}`),
|
||||||
|
DataType: "html",
|
||||||
|
Form: []notifications.NotificationForm{{
|
||||||
|
Type: "text",
|
||||||
|
Title: "AWS Access Token",
|
||||||
|
DbField: "api_key",
|
||||||
|
Placeholder: "AKPMED5XUXSEU3O5AB6M",
|
||||||
|
Required: true,
|
||||||
|
}, {
|
||||||
|
Type: "text",
|
||||||
|
Title: "AWS Secret Key",
|
||||||
|
DbField: "api_secret",
|
||||||
|
Placeholder: "39eAZODxEosHRgzLx173ttX9sCtJVOE8rzElRE9B",
|
||||||
|
Required: true,
|
||||||
|
}, {
|
||||||
|
Type: "text",
|
||||||
|
Title: "Region",
|
||||||
|
SmallText: "Amazon Region for SNS",
|
||||||
|
DbField: "var1",
|
||||||
|
Placeholder: "us-west-2",
|
||||||
|
Required: true,
|
||||||
|
}, {
|
||||||
|
Type: "text",
|
||||||
|
Title: "SNS Topic ARN",
|
||||||
|
SmallText: "The ARN of the Topic",
|
||||||
|
DbField: "host",
|
||||||
|
Placeholder: "arn:aws:sns:us-west-2:123456789012:YourTopic",
|
||||||
|
Required: true,
|
||||||
|
}}},
|
||||||
|
}
|
||||||
|
|
||||||
|
func valToAttr(val interface{}) *sns.MessageAttributeValue {
|
||||||
|
dataType := "String"
|
||||||
|
switch val.(type) {
|
||||||
|
case string, bool:
|
||||||
|
dataType = "String"
|
||||||
|
case int, int64, uint, uint64, uint32:
|
||||||
|
dataType = "Number"
|
||||||
|
}
|
||||||
|
return &sns.MessageAttributeValue{
|
||||||
|
DataType: aws.String(dataType),
|
||||||
|
StringValue: aws.String(fmt.Sprintf("%v", val)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func messageAttributesSNS(s services.Service, f failures.Failure) map[string]*sns.MessageAttributeValue {
|
||||||
|
attr := make(map[string]*sns.MessageAttributeValue)
|
||||||
|
attr["service_id"] = valToAttr(s.Id)
|
||||||
|
attr["online"] = valToAttr(s.Online)
|
||||||
|
attr["downtime_milliseconds"] = valToAttr(s.Downtime().Milliseconds())
|
||||||
|
if f.Id != 0 {
|
||||||
|
attr["failure_issue"] = valToAttr(f.Issue)
|
||||||
|
attr["failure_reason"] = valToAttr(f.Reason)
|
||||||
|
attr["failure_status_code"] = valToAttr(f.ErrorCode)
|
||||||
|
attr["failure_ping"] = valToAttr(f.PingTime)
|
||||||
|
}
|
||||||
|
return attr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send will send a HTTP Post to the amazonSNS API. It accepts type: string
|
||||||
|
func (g *amazonSNS) sendMessage(msg string, s services.Service, f failures.Failure) (string, error) {
|
||||||
|
creds := credentials.NewStaticCredentials(g.ApiKey.String, g.ApiSecret.String, "")
|
||||||
|
c := aws.NewConfig()
|
||||||
|
c.Credentials = creds
|
||||||
|
c.Region = aws.String(g.Var1.String)
|
||||||
|
sess, err := session.NewSession(c)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := sns.New(sess)
|
||||||
|
input := &sns.PublishInput{
|
||||||
|
Message: aws.String(msg),
|
||||||
|
TopicArn: aws.String(g.Host.String),
|
||||||
|
MessageAttributes: messageAttributesSNS(s, f),
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := client.Publish(input)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnFailure will trigger failing service
|
||||||
|
func (g *amazonSNS) OnFailure(s services.Service, f failures.Failure) (string, error) {
|
||||||
|
msg := ReplaceVars(g.FailureData.String, s, f)
|
||||||
|
return g.sendMessage(msg, s, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnSuccess will trigger successful service
|
||||||
|
func (g *amazonSNS) OnSuccess(s services.Service) (string, error) {
|
||||||
|
msg := ReplaceVars(g.SuccessData.String, s, failures.Failure{})
|
||||||
|
return g.sendMessage(msg, s, failures.Failure{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnTest will test the amazonSNS notifier
|
||||||
|
func (g *amazonSNS) OnTest() (string, error) {
|
||||||
|
s := services.Example(true)
|
||||||
|
f := failures.Example()
|
||||||
|
msg := ReplaceVars(`This is a test SNS notification from Statping. Service: {{.Service.Name}} - Downtime: {{.Service.Downtime.Human}}`, s, f)
|
||||||
|
return g.sendMessage(msg, s, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OnSave will trigger when this notifier is saved
|
||||||
|
func (g *amazonSNS) OnSave() (string, error) {
|
||||||
|
return "", nil
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package notifiers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/statping/statping/database"
|
||||||
|
"github.com/statping/statping/types/core"
|
||||||
|
"github.com/statping/statping/types/failures"
|
||||||
|
"github.com/statping/statping/types/notifications"
|
||||||
|
"github.com/statping/statping/types/null"
|
||||||
|
"github.com/statping/statping/types/services"
|
||||||
|
"github.com/statping/statping/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAmazonSNSNotifier(t *testing.T) {
|
||||||
|
err := utils.InitLogs()
|
||||||
|
require.Nil(t, err)
|
||||||
|
snsToken := utils.Params.GetString("SNS_TOKEN")
|
||||||
|
snsSecret := utils.Params.GetString("SNS_SECRET")
|
||||||
|
snsRegion := utils.Params.GetString("SNS_REGION")
|
||||||
|
snsTopic := utils.Params.GetString("SNS_TOPIC")
|
||||||
|
|
||||||
|
db, err := database.OpenTester()
|
||||||
|
require.Nil(t, err)
|
||||||
|
db.AutoMigrate(¬ifications.Notification{})
|
||||||
|
notifications.SetDB(db)
|
||||||
|
core.Example()
|
||||||
|
|
||||||
|
if snsToken == "" || snsSecret == "" || snsRegion == "" || snsTopic == "" {
|
||||||
|
t.Log("SNS notifier testing skipped, missing SNS_TOKEN, SNS_SECRET, SNS_REGION, SNS_TOPIC environment variables")
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Load SNS", func(t *testing.T) {
|
||||||
|
AmazonSNS.ApiKey = null.NewNullString(snsToken)
|
||||||
|
AmazonSNS.ApiSecret = null.NewNullString(snsSecret)
|
||||||
|
AmazonSNS.Var1 = null.NewNullString(snsRegion)
|
||||||
|
AmazonSNS.Host = null.NewNullString(snsTopic)
|
||||||
|
AmazonSNS.Delay = 15 * time.Second
|
||||||
|
AmazonSNS.Enabled = null.NewNullBool(true)
|
||||||
|
|
||||||
|
Add(AmazonSNS)
|
||||||
|
|
||||||
|
assert.Equal(t, "Hunter Long", AmazonSNS.Author)
|
||||||
|
assert.Equal(t, snsToken, AmazonSNS.ApiKey.String)
|
||||||
|
assert.Equal(t, snsSecret, AmazonSNS.ApiSecret.String)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SNS Notifier Tester", func(t *testing.T) {
|
||||||
|
assert.True(t, AmazonSNS.CanSend())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SNS Notifier Tester OnSave", func(t *testing.T) {
|
||||||
|
_, err := AmazonSNS.OnSave()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SNS OnFailure", func(t *testing.T) {
|
||||||
|
_, err := AmazonSNS.OnFailure(services.Example(false), failures.Example())
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SNS OnSuccess", func(t *testing.T) {
|
||||||
|
_, err := AmazonSNS.OnSuccess(services.Example(true))
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("SNS Test", func(t *testing.T) {
|
||||||
|
_, err := AmazonSNS.OnTest()
|
||||||
|
assert.Nil(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ func TestMobileNotifier(t *testing.T) {
|
||||||
Add(Mobile)
|
Add(Mobile)
|
||||||
|
|
||||||
assert.Equal(t, "Hunter Long", Mobile.Author)
|
assert.Equal(t, "Hunter Long", Mobile.Author)
|
||||||
assert.Equal(t, mobileToken, Mobile.Var1)
|
assert.Equal(t, mobileToken, Mobile.Var1.String)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Mobile Notifier Tester", func(t *testing.T) {
|
t.Run("Mobile Notifier Tester", func(t *testing.T) {
|
||||||
|
|
|
@ -35,6 +35,7 @@ func InitNotifiers() {
|
||||||
Pushover,
|
Pushover,
|
||||||
statpingMailer,
|
statpingMailer,
|
||||||
Gotify,
|
Gotify,
|
||||||
|
AmazonSNS,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/statping/statping/types/null"
|
"github.com/statping/statping/types/null"
|
||||||
"github.com/statping/statping/types/services"
|
"github.com/statping/statping/types/services"
|
||||||
"github.com/statping/statping/utils"
|
"github.com/statping/statping/utils"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -93,5 +94,10 @@ func (s *slack) OnSave() (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *slack) Valid(values notifications.Values) error {
|
func (s *slack) Valid(values notifications.Values) error {
|
||||||
|
regex := `https\:\/\/hooks\.slack\.com/services/[A-Z0-9]{9}/[A-Z0-9]{10}/[a-zA-Z0-9]{22}`
|
||||||
|
r := regexp.MustCompile(regex)
|
||||||
|
if !r.MatchString(values.Host) {
|
||||||
|
return errors.New("slack webhook does not match with expected regex " + regex)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,7 @@ type Render struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
fmt.Println("RUNNING: ./source/generate_help.go")
|
||||||
fmt.Println("\n\nGenerating Help.vue from Statping's Wiki")
|
fmt.Println("\n\nGenerating Help.vue from Statping's Wiki")
|
||||||
fmt.Println("Cloning ", wikiUrl)
|
fmt.Println("Cloning ", wikiUrl)
|
||||||
cmd := exec.Command("git", "clone", wikiUrl)
|
cmd := exec.Command("git", "clone", wikiUrl)
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const replace = `const version = "[0-9]\.[0-9]{2}\.[0-9]{2}";`
|
||||||
|
const replaceCommit = `const commit = \"[a-z0-9]{40}\"\;`
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("RUNNING: ./source/generate_version.go")
|
||||||
|
version, _ := ioutil.ReadFile("../version.txt")
|
||||||
|
apiJsFile, _ := ioutil.ReadFile("../frontend/src/API.js")
|
||||||
|
|
||||||
|
w := bytes.NewBuffer(nil)
|
||||||
|
cmd := exec.Command("git", "rev-parse", "HEAD")
|
||||||
|
cmd.Stdout = w
|
||||||
|
cmd.Run()
|
||||||
|
gitCommit := strings.TrimSpace(w.String())
|
||||||
|
|
||||||
|
fmt.Println("git commit: ", gitCommit)
|
||||||
|
|
||||||
|
replaceWith := `const version = "` + strings.TrimSpace(string(version)) + `";`
|
||||||
|
replaceCommitWith := `const commit = "` + gitCommit + `";`
|
||||||
|
|
||||||
|
vRex := regexp.MustCompile(replace)
|
||||||
|
newApiFile := vRex.ReplaceAllString(string(apiJsFile), replaceWith)
|
||||||
|
cRex := regexp.MustCompile(replaceCommit)
|
||||||
|
newApiFile = cRex.ReplaceAllString(newApiFile, replaceCommitWith)
|
||||||
|
|
||||||
|
fmt.Printf("Setting version %s to frontend/src/API.js\n", string(version))
|
||||||
|
ioutil.WriteFile("../frontend/src/API.js", []byte(newApiFile), os.FileMode(0755))
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package source
|
package source
|
||||||
|
|
||||||
//go:generate go run generate_help.go
|
//go:generate go run generate_help.go
|
||||||
|
//go:generate go run generate_version.go
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
Loading…
Reference in New Issue