How to convert Health Watch notification to JSON format for Mattermost in Tanzu Application Service for VMs
search cancel

How to convert Health Watch notification to JSON format for Mattermost in Tanzu Application Service for VMs

book

Article ID: 293402

calendar_today

Updated On:

Products

Operations Manager

Issue/Introduction

This article covers how to use a conversion app to send Health Watch notifications to Mattermost in Tanzu Application Service for VMs (TAS for VMs).

Mattermost (MM) is an open-source, self-hosted Slack alternative (www.mattermost.org). MM accepts webhook inputs from TAS for VMs notifications, such as those which can generate alerts from Health Watch. However, MM does not understand the default webhook JSON format which TAS for VMs produces.

Resolution

To integrate TAS for VMs with MM, direct the webhook to a conversion program. This reformats the JSON and sends the JSON to MM.

Create a manifest file. For example: 

---
applications:
  - name: hwalert
    buildpacks:
      - go_buildpack
    env:
      GOPACKAGENAME: main
      URL: 'http://example.com'

 

Save the following code as convert_mm.go:

package main
 
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)
 
//https://docs.pivotal.io/event-alerts/1-2/using.html#webhook_targets
type IncomingWebhookMessage struct {
    Publisher string            `json:"publisher"`
    Topic     string            `json:"topic"`
    Timestamp string            `json:"timestamp"`
    Metadata  map[string]string `json:"metadata"`
    Subject   string            `json:"subject"`
    Body      string            `json:"body"`
}
 
type OutgoingWebhookMessage struct {
    Text string `json:"text"`
}

func main() {
    url := os.Getenv("URL")
    http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
        bodyBytes, err := ioutil.ReadAll(r.Body)
        if err != nil {
            fmt.Println("ERROR reading: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        defer r.Body.Close()
 
        fmt.Println("body: ", string(bodyBytes))
 
        // What event alerts sends
        var incomingWebhookMessage IncomingWebhookMessage
        err = json.Unmarshal(bodyBytes, &incomingWebhookMessage)
        if err != nil {
            fmt.Println("ERROR unmarshalling: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        // Conversion
        outgoingMessage := &OutgoingWebhookMessage{
            Text: "Converted: " + incomingWebhookMessage.Body + " " + incomingWebhookMessage.Subject,
        }
 
        // Marshal into required style
        messageBytes, marshalErr := json.Marshal(outgoingMessage)
        if marshalErr != nil {
            fmt.Println("ERROR marshalling: ", marshalErr)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        fmt.Println("sending: ", string(messageBytes))
 
        // Send to final destination
        _, err = http.DefaultClient.Post(url, "application/json", bytes.NewBuffer(messageBytes))
        if err != nil {
            fmt.Println("ERROR sending: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        w.WriteHeader(200)
    })
 
    log.Fatal(http.ListenAndServe(":8080", nil))
}

 
1. Push the sample Go app, convert_mm.go:

a. Run this command:
mkdir convert_mm; cd convert_mm

b. Paste the app code into the file, convert_mm.go.

c. Create the manifest file. In this example, create the file, manifest.yml, in the convert_mm directory. 

d. Login to cf CLI

e. Set the org and the space targets.

f. Run this command:
cf push

For more information, on pushing apps, refer to Pushing an App | Cloud Foundry Docs

2. Use cf apps to get the URL for the pushed sample app. Run this command: 
cf eva-create-target <name> webhook https://<url-of-the-app>/webhook


Note: Use HTTPS form of the webhook target URL in the argument of the cf eva-create-target command.

3. Run this command:

cf restage <the-sample-app-name>

 

4. Subscribe to the topic and publish the app with these commands:

cf eva-subscribe <target-name> healthwatch --all

cf eva-sample-publish healthwatch rep.unhealthycell


Additional Information

Save code below as "convert_mm.go"

package main
 
import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"
)
 
//https://docs.pivotal.io/event-alerts/1-2/using.html#webhook_targets
type IncomingWebhookMessage struct {
    Publisher string            `json:"publisher"`
    Topic     string            `json:"topic"`
    Timestamp string            `json:"timestamp"`
    Metadata  map[string]string `json:"metadata"`
    Subject   string            `json:"subject"`
    Body      string            `json:"body"`
}
 
type OutgoingWebhookMessage struct {
    Text string `json:"text"`
}

func main() {
    url := os.Getenv("URL")
    http.HandleFunc("/webhook", func(w http.ResponseWriter, r *http.Request) {
        bodyBytes, err := ioutil.ReadAll(r.Body)
        if err != nil {
            fmt.Println("ERROR reading: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
        defer r.Body.Close()
 
        fmt.Println("body: ", string(bodyBytes))
 
        // What event alerts sends
        var incomingWebhookMessage IncomingWebhookMessage
        err = json.Unmarshal(bodyBytes, &incomingWebhookMessage)
        if err != nil {
            fmt.Println("ERROR unmarshalling: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        // Conversion
        outgoingMessage := &OutgoingWebhookMessage{
            Text: "Converted: " + incomingWebhookMessage.Body + " " + incomingWebhookMessage.Subject,
        }
 
        // Marshal into required style
        messageBytes, marshalErr := json.Marshal(outgoingMessage)
        if marshalErr != nil {
            fmt.Println("ERROR marshalling: ", marshalErr)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        fmt.Println("sending: ", string(messageBytes))
 
        // Send to final destination
        _, err = http.DefaultClient.Post(url, "application/json", bytes.NewBuffer(messageBytes))
        if err != nil {
            fmt.Println("ERROR sending: ", err)
            w.WriteHeader(http.StatusInternalServerError)
            return
        }
 
        w.WriteHeader(200)
    })
 
    log.Fatal(http.ListenAndServe(":8080", nil))
}