CJW
CJW

Reputation: 1000

Pass Cloudwatch data through a Lambda - Golang

I am trying to achieve the following:

  1. Lambda is triggered by a Cloudwatch alarm
  2. Lambda looks at the data received by Cloudwatch and makes a decision on what to do based on NewStateValue
  3. If needed, the Lambda will trigger another SNS that sends all the Cloudwatch data to OpsGenie

I am getting stuck at the third step. I can pass some data by manually specifying it, however, is there a function that will just pass all JSON received by the Lambda onto the next SNS?

I have got the JSON for SNS, CloudWatch Alarms and the Message section of the CloudWatch Alarm.

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.Subject) 
        var event CloudWatchAlarmMessage

        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.Sns.Message.NewStateValue == "ALARM") {
        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: aws.String(event.OldStateValue),
        Subject: aws.String(event.NewStateValue),
        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)
}

I have attempted to use MessageStructure: aws.String("json"), but it seems to just result in cannot use snsRecord (type events.SNSEntity) as type *string in field value.

With my current set-up it successfully sends the NewStateValue and OldStateValue.

JSON Structures I currently have access to:

package main

type SNS struct {
    Type              string    `json:"Type"`
    MessageID         string    `json:"MessageId"`
    TopicArn          string    `json:"TopicArn"`
    Subject           string    `json:"Subject"`
    Message           string    `json:"Message"`
    Timestamp         string `json:"Timestamp"`
    SignatureVersion  string    `json:"SignatureVersion"`
    Signature         string    `json:"Signature"`
    SigningCertURL    string    `json:"SigningCertURL"`
    UnsubscribeURL    string    `json:"UnsubscribeURL"`
    MessageAttributes struct {
        Alias struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"alias"`
        Entity struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"entity"`
        Tags struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"tags"`
        EventType struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"eventType"`
        Recipients struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"recipients"`
        Teams struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"teams"`
        Actions struct {
            Type  string `json:"Type"`
            Value string `json:"Value"`
        } `json:"actions"`
    } `json:"MessageAttributes"`
}

package main

type CloudWatchAlarms struct {
        Records []struct {
                EventVersion         string `json:"EventVersion"`
                EventSubscriptionArn string `json:"EventSubscriptionArn"`
                EventSource          string `json:"EventSource"`
                Sns                  struct {
                        Signature         string `json:"Signature"`
                        MessageID         string `json:"MessageId"`
                        Type              string `json:"Type"`
                        TopicArn          string `json:"TopicArn"`
                        MessageAttributes struct {
                        } `json:"MessageAttributes"`
                        SignatureVersion string    `json:"SignatureVersion"`
                        Timestamp        string `json:"Timestamp"`
                        SigningCertURL   string    `json:"SigningCertUrl"`
                        Message          string    `json:"Message"`
                        UnsubscribeURL   string    `json:"UnsubscribeUrl"`
                        Subject          string    `json:"Subject"`
                } `json:"Sns"`
        } `json:"Records"`
}

package main

type CloudWatchAlarmMessage struct {
    AlarmName        string `json:"AlarmName"`
    AlarmDescription string `json:"AlarmDescription"`
    AWSAccountID     string `json:"AWSAccountId"`
    NewStateValue    string `json:"NewStateValue"`
    NewStateReason   string `json:"NewStateReason"`
    StateChangeTime  string `json:"StateChangeTime"`
    Region           string `json:"Region"`
    OldStateValue    string `json:"OldStateValue"`
    Trigger          struct {
        MetricName    string      `json:"MetricName"`
        Namespace     string      `json:"Namespace"`
        StatisticType string      `json:"StatisticType"`
        Statistic     string      `json:"Statistic"`
        Unit          interface{} `json:"Unit"`
        Dimensions    []struct {
            Name  string `json:"name"`
            Value string `json:"value"`
        } `json:"Dimensions"`
        Period                           int    `json:"Period"`
        EvaluationPeriods                int    `json:"EvaluationPeriods"`
        ComparisonOperator               string `json:"ComparisonOperator"`
        Threshold                        float64    `json:"Threshold"`
        TreatMissingData                 string `json:"TreatMissingData"`
        EvaluateLowSampleCountPercentile string `json:"EvaluateLowSampleCountPercentile"`
    } `json:"Trigger"`
}

If anyone has any insight it would be greatly appreciated.

Thanks.

Upvotes: 3

Views: 2678

Answers (1)

Pablo Flores
Pablo Flores

Reputation: 1400

If I understood correctly your question, you're trying to catch a cloudwatch event and, if certain conditions are met, you want to send a message to a SNS. I belive the code below might be helpful, it's a lambda that's fired on a cloudwatch event that sends a message to sns when conditions met

import(
  "context"
  "github.com/aws/aws-sdk-go/aws"
  "github.com/aws/aws-lambda-go/events"
  "github.com/aws/aws-lambda-go/lambda"
  "github.com/aws/aws-sdk-go/aws/session"
  "github.com/aws/aws-sdk-go/service/sns"
)
//React to cloudwatch events
func handler(ctx context.Context, cloudWatchEvent events.CloudWatchEvent) error {
  //In case event met your conditions
  if string(cloudWatchEvent.Detail) == "Detail you expect to trigger sns" {
    //create session for sns service
    sess := session.New()
    //init sns service
    snsService := sns.New(sess)
    //publish message to sns
    snsService.Publish(&sns.PublishInput{
        Message:  aws.String("Your message"), //you can marshall the cloudwatch event here
        TopicArn: aws.String("your sns topic"),
    })
    //handle error/success here
    if err != nil {
        log.Print(err)
    } else {
        log.Printf("Message %s sent", output.MessageId)
    }
  }
  return nil
}

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

Hope this gives you some help :)

Upvotes: 3

Related Questions