add json body, Pushbullet example

This commit is contained in:
AJ ONeal 2019-06-12 00:52:33 -06:00
parent 4b9230bd90
commit 7b84c74754
2 changed files with 71 additions and 10 deletions

View File

@ -147,6 +147,35 @@ The `from` address can be _any_ domain in your mailgun account.
`subject` is the plain-text subject and `text` must be plain-text (not html) email contents. `subject` is the plain-text subject and `text` must be plain-text (not html) email contents.
</details>
<details>
<summary>How to use with Pushbullet</summary>
Pushbullet is a push notification service that I found pretty easy to work with.
I logged in with my iPhone through facebook, as well as in a web browser,
grabbed the API token, and I was able to test the documentation all in just a few minutes.
### `my_pushbullet`
Replace `my_pushbullet` with whatever name you like, or leave it the same.
It's an arbitrary name for you to reference.
For example, you may have different Pushbullet configurations for different domains.
### `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
Replace `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` in the HTTP Access-Token header
with your API token.
You'll find this on the Pushbullet dashboard under Settings, Account, Access Tokens,
and you'll have to click to create it:
- <https://www.pushbullet.com/#settings/account>
The example was taken from the Pushbullet API documentation:
- <https://docs.pushbullet.com/#create-push>
</details> </details>
<details> <details>
<summary>How to use with Twilio</summary> <summary>How to use with Twilio</summary>
@ -188,7 +217,7 @@ All phone numbers should have the country code prefix (`+1` for USA) attached.
<details> <details>
<summary>How to use with Nexmo, Mailjet, and other webhook-enabled services</summary> <summary>How to use with Nexmo, Mailjet, and other webhook-enabled services</summary>
See the examples of Twilio and Mailgun. See the examples of Mailgun, Pushbullet, Twilio.
Look for "curl" in the documentation of the service that you're using. Look for "curl" in the documentation of the service that you're using.
It should be fairly easy to just look at the headers that are being set and repeat. It should be fairly easy to just look at the headers that are being set and repeat.
@ -199,7 +228,7 @@ It should be fairly easy to just look at the headers that are being set and repe
You can set notifications for _any_ service that supports HTTPS webhooks. You can set notifications for _any_ service that supports HTTPS webhooks.
The examples below are shown with Twilio and Mailgun, as taken from their `curl` documentation. The examples below are shown with Mailgun, Pushbullet, and Twilio, as taken from their `curl` documentation.
```json ```json
{ {
@ -208,7 +237,7 @@ The examples below are shown with Twilio and Mailgun, as taken from their `curl`
"name": "Example Site", "name": "Example Site",
"url": "https://example.com/", "url": "https://example.com/",
"keywords": "My Site", "keywords": "My Site",
"webhooks": ["my_mailgun", "my_twilio"], "webhooks": ["my_mailgun", "my_pushbullet", "my_twilio"],
"recover_script": "systemctl restart example-site" "recover_script": "systemctl restart example-site"
} }
], ],
@ -231,6 +260,20 @@ The examples below are shown with Twilio and Mailgun, as taken from their `curl`
"text": "The system is down. Check up on {{ .Name }} ASAP." "text": "The system is down. Check up on {{ .Name }} ASAP."
} }
}, },
{
"name": "my_pushbullet",
"method": "POST",
"url": "https://api.pushbullet.com/v2/pushes",
"headers": {
"Access-Token": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"User-Agent": "Watchdog/1.0"
},
"json": {
"body": "The system is down. Check up on {{ .Name }} ASAP.",
"title": "{{ .Name }} is down.",
"type": "note"
}
},
{ {
"name": "my_twilio", "name": "my_twilio",
"method": "POST", "method": "POST",

View File

@ -138,7 +138,10 @@ func (d *Dog) watch() {
err := d.check() err := d.check()
if nil != err { if nil != err {
failure = true failure = true
} else {
failure = false
} }
// We should notify if // We should notify if
// * We've had success since the last notification // * We've had success since the last notification
// * It's been at least 5 minutes since the last notification // * It's been at least 5 minutes since the last notification
@ -146,7 +149,7 @@ func (d *Dog) watch() {
if d.lastPassed.After(d.lastNotified) && d.lastNotified.Before(fiveMinutesAgo) { if d.lastPassed.After(d.lastNotified) && d.lastNotified.Before(fiveMinutesAgo) {
d.notify(failure) d.notify(failure)
} }
if d.failures >= 5 { if !failure || d.failures >= 5 {
// go back to the main 5-minute loop // go back to the main 5-minute loop
break break
} }
@ -213,7 +216,7 @@ func (d *Dog) recover() {
err = cmd.Wait() err = cmd.Wait()
cancel() cancel()
if nil != err { if nil != err {
d.logger <- fmt.Sprintf("[Recover] '%s' failed: %s", d.Recover, err) d.logger <- fmt.Sprintf("[Recover] '%s' failed for '%s': %s", d.Recover, d.Name, err)
} }
} }
@ -241,26 +244,40 @@ func (d *Dog) notify(hardFail bool) {
} }
var body *strings.Reader var body *strings.Reader
var err error
// TODO real templates
if 0 != len(h.Form) { if 0 != len(h.Form) {
form := url.Values{} form := url.Values{}
for k := range h.Form { for k := range h.Form {
v := h.Form[k] v := h.Form[k]
// TODO real templates // because `{{` gets urlencoded
//k = strings.Replace(k, "{{ .Name }}", d.Name, -1)
v = strings.Replace(v, "{{ .Name }}", d.Name, -1) v = strings.Replace(v, "{{ .Name }}", d.Name, -1)
d.logger <- fmt.Sprintf("[HEADER] %s: %s", k, v)
form.Set(k, v) form.Set(k, v)
} }
body = strings.NewReader(form.Encode()) body = strings.NewReader(form.Encode())
} else if 0 != len(h.JSON) {
bodyBuf, err := json.Marshal(h.JSON)
if nil != err {
d.logger <- fmt.Sprintf("[Notify] JSON Marshal Error for '%s': %s", h.Name, err)
continue
}
// `{{` should be left alone
body = strings.NewReader(strings.Replace(string(bodyBuf), "{{ .Name }}", d.Name, -1))
} }
client := NewHTTPClient() client := NewHTTPClient()
req, err := http.NewRequest(h.Method, h.URL, body) req, err := http.NewRequest(h.Method, h.URL, body)
if nil != err { if nil != err {
log.Println("[Notify] HTTP Client Network Error:", err) d.logger <- fmt.Sprintf("[Notify] HTTP Client Network Error for '%s': %s", h.Name, err)
continue continue
} }
if 0 != len(h.Form) { if 0 != len(h.Form) {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
} else if 0 != len(h.JSON) {
req.Header.Set("Content-Type", "application/json")
} }
if 0 != len(h.Auth) { if 0 != len(h.Auth) {
@ -282,12 +299,12 @@ func (d *Dog) notify(hardFail bool) {
resp, err := client.Do(req) resp, err := client.Do(req)
if nil != err { if nil != err {
d.logger <- fmt.Sprintf("[Notify] HTTP Client Error: %s", err) d.logger <- fmt.Sprintf("[Notify] HTTP Client Error for '%s': %s", h.Name, err)
continue continue
} }
if !(resp.StatusCode >= 200 && resp.StatusCode < 300) { if !(resp.StatusCode >= 200 && resp.StatusCode < 300) {
d.logger <- fmt.Sprintf("[Notify] Response Error: %s", resp.Status) d.logger <- fmt.Sprintf("[Notify] Response Error for '%s': %s", h.Name, resp.Status)
continue continue
} }
@ -297,7 +314,7 @@ func (d *Dog) notify(hardFail bool) {
decoder := json.NewDecoder(resp.Body) decoder := json.NewDecoder(resp.Body)
err = decoder.Decode(&data) err = decoder.Decode(&data)
if err != nil { if err != nil {
d.logger <- fmt.Sprintf("[Notify] Response Body Error: %s", resp.Status) d.logger <- fmt.Sprintf("[Notify] Response Body Error for '%s': %s", h.Name, resp.Status)
continue continue
} }
@ -326,6 +343,7 @@ type ConfigWebhook struct {
Auth map[string]string `json:"auth"` Auth map[string]string `json:"auth"`
Headers map[string]string `json:"headers"` Headers map[string]string `json:"headers"`
Form map[string]string `json:"form"` Form map[string]string `json:"form"`
JSON map[string]string `json:"json"`
Config map[string]string `json:"config"` Config map[string]string `json:"config"`
Configs []map[string]string `json:"configs"` Configs []map[string]string `json:"configs"`
} }