Hello!
Today I want to show how with the help of AWS Lambda and Golang you can get messages in slack when Autoscaling could not create an Ec2 server. Deploy I automate using serverless.
Let’s start with the installation of node and serverless. I use nvm to manage node versions.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
nvm install v14.15.3
npm install -g serverless
I will create a folder and initialize the go module in it.
mkdir failed-asg
cd failed-asg
go mod init
touch main.go
In the beginning, there will be a package, imports, and main function. Main function will be responsible for executing the handler function.
package main
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func main() {
lambda.Start(handleRequest)
}
The main function will be handleRequest. It will generate a message based on AutoScalingEvent
and send a message to slack.
func handleRequest(ctx context.Context, event events.AutoScalingEvent) (string, error) {
url := "https://hooks.slack.com/services/token"
var sb strings.Builder
sb.WriteString(":siren: *EC2 Instance Launch Unsuccessful* :siren:\n")
sb.WriteString("*Autoscaling Group Name*:")
sb.WriteString(event.Detail["AutoScalingGroupName"].(string))
sb.WriteString("\n")
sb.WriteString("*StatusMessage*:")
sb.WriteString(event.Detail["StatusMessage"].(string))
sb.WriteString("\n")
payload := map[string]interface{}{
"username": "ASGFailedEvents",
"channel": "#test-db-alerts",
"text": sb.String(),
}
_, err := SendSlackNotification(url, payload)
if err != nil {
log.Fatalln("Not able to send slack message", err)
}
return sb.String(), nil
}
Url needs to be replaced with the value of your Slack Webhook.
Using strings.Builder
I create a message to be sent, by adding to it the name AutoScalingGroup and an error message. Then I form payload
in which it is necessary to specify the name of the user from whom message will be sent, the channel and the text of the message and SendSlackNotification
will send the message.
Let’s move on to creating the SendSlackNotification
function.
func SendSlackNotification(url string, data interface{}) (bodyString string, err error) {
jsonString, _ := json.Marshal(data)
req, err := http.NewRequest("programming", url, bytes.NewBuffer(jsonString))
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
bodyString = string(body)
if resp.StatusCode != 200 {
fmt.Println("Response Status:", resp.Status) // 200 OK
fmt.Println("Response Headers:", resp.Header)
fmt.Println("Response Body:", bodyString)
return bodyString, errors.New("can't work with 42")
}
return bodyString, nil
}
Here json is formed from the previously created payload
and with the help of http the request made to Webhook Url. Then it is checked whether the request was successfully sent.
Let’s go back to serverless for lambda deployment.
At the root of the repository, I create a file serverless.yml
with content
service: asg-failed-events
provider:
name: aws
runtime: go1.x
package:
exclude:
- ./**
include:
- ./bin/**
functions:
lambda-time:
handler: bin/failed-asg-event-notification
events:
- cloudwatchEvent:
event:
source:
- "aws.autoscaling"
detail-type:
- "EC2 Instance Launch Unsuccessful"
This configuration describes the name of the lambda that will be created and lambda trigger, in this case, it is EC2 Instance Launch Unsuccessful
event from aws.autoscaling
passed to the lambda by cloudwatchEvent
.
Now you need to install all the dependencies, compile the code and deploy.
go mod tidy
OOS=linux GOARCH=amd64 go build -o bin/failed-asg-event-notification .
sls deploy
After that, if there is an event of the type EC2 Instance Launch Unsuccessful
from aws.autoscaling
the corresponding message will be sent to the slack.