2

I am trying to achieve the following: Cloudwatch alarm details are received as JSON to a Lambda The Lambda looks at the JSON to determine if the 'NewStateValue' == "ALARM" If it does == "ALARM" forward the whole JSON received from the SNS out via another SNS.

I am most of the way towards achieving this and I have the following code:

package main

import (
    "context"
    "fmt"
    "encoding/json"

    "github.com/aws/aws-lambda-go/events"
    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sns"
)

func handler(ctx context.Context, snsEvent events.SNSEvent) {
    for _, record := range snsEvent.Records {
        snsRecord := record.SNS

//To add in additional fields to publish to the logs add "snsRecord.'fieldname'"
        fmt.Printf("Message = %s \n", snsRecord.Message) 
        var event CloudWatchAlarm
        err := json.Unmarshal([]byte(snsRecord.Message), &event)
        if err != nil {
            fmt.Println("There is an error: " + err.Error())
        }
        fmt.Printf("Test Message = %s \n", event.NewStateValue)
        if ( event.NewStateValue == "ALARM") {
            svc := sns.New(session.New())
  // params will be sent to the publish call included here is the bare minimum params to send a message.
    params := &sns.PublishInput{
        Message: Message: aws.String("message"), // This is the message itself (can be XML / JSON / Text - anything you want)
        TopicArn: aws.String("my arn"),  //Get this from the Topic in the AWS console.
    }

    resp, err := svc.Publish(params)   //Call to puclish the message

    if err != nil {                    //Check for errors
        // Print the error, cast err to awserr.Error to get the Code and
        // Message from an error.
        fmt.Println(err.Error())
        return
    }

    // Pretty-print the response data.
    fmt.Println(resp)
}
        }
    }


func main() {
    lambda.Start(handler)
}

Currently this sends an email to the address set-up in the SNS linked to the ARN above. However I would like the email to include the full, ideally formatted, JSON received by the first SNS. I have the Cloudwatch JSON structure defined in another file, this is being called by var event CloudWatchAlarm

Muhammad Dyas Yaskur
  • 6,914
  • 10
  • 48
  • 73
CJW
  • 710
  • 9
  • 26
  • Possible duplicate of [Sending html content in AWS SNS(Simple Notification Service) emails notifications](https://stackoverflow.com/questions/32241928/sending-html-content-in-aws-snssimple-notification-service-emails-notification) – titogeo Sep 19 '18 at 11:31
  • See here - https://stackoverflow.com/questions/32241928/sending-html-content-in-aws-snssimple-notification-service-emails-notification. SNS can only send email in plain text. Use SES for formatted/HTML email. – titogeo Sep 19 '18 at 11:32
  • Thanks for the comments. While I appreciate that SNS might not be the best tool for sending an email, the question was more geared around how to push the JSON data anywhere. Moving to SES would still result in the same problem, that I am unaware on how to publish the JSON data received by the Lambda. Truth be told I am probably going to end up sending the SNS to OpsGenie which can handle receiving the JSON blob. – CJW Sep 19 '18 at 12:25
  • If OpsGenie exposes an HTTP endpoint like webhooks then you can directly use that instead of email. – titogeo Sep 19 '18 at 12:38
  • That would be ideal. Do you have any idea how to push the data received from the SNS to the Lambda out to the SNS that is hooked up to Ops Genie, the SNS configuration part is not an issue, it is just how the code needs to handle the sending of the JSON? – CJW Sep 19 '18 at 13:50
  • I have not worked with OpsGenie. Like you created an email subscription create an HTTP subscription in SNS. Whenever the notification comes SNS will invoke the HTTP (POST) endpoint with the message. Configuring HTTP subscription involves confirming subscription just like email. So if OpsGeinie does not support that then it won't work. – titogeo Sep 19 '18 at 15:03

1 Answers1

0

From AWS SDK for Go docs:

type PublishInput struct {
// The message you want to send.
//
// If you are publishing to a topic and you want to send the same message to
// all transport protocols, include the text of the message as a String value.
// If you want to send different messages for each transport protocol, set the
// value of the MessageStructure parameter to json and use a JSON object for
// the Message parameter.

So, params would be:

params := &sns.PublishInput{
        Message: myjson, // json data you want to send
        TopicArn: aws.String("my arn"),
        MessageStructure: aws.String("json")
    }

WARNING

Notice the help paragraph says "use a JSON object for the parameter message", such JSON object must have a keys that correspond to supported transport protocol That means

{
  'default': json_message,
  'email': json_message
}

It will send json_message using both the default and email transports.

yorodm
  • 4,359
  • 24
  • 32
  • Thank you for the reply! I have attempted to implement the above and I have hit a problem I was hoping you could help with when entering "myjson", in my case I am attempting to use "snsRecord" or "snsRecord.Message" I am getting the error `cannot use snsRecord (type events.SNSEntity) as type *string in field value` and `cannot use snsRecord.Message (type string) as type *string in field value` respectively, when building. Any idea what is causing this? – CJW Sep 20 '18 at 09:56