/
main.go
129 lines (110 loc) · 3 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package main
import (
"io/ioutil"
"net/http"
"strings"
log "github.com/Sirupsen/logrus"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/gin-gonic/gin"
"github.com/prometheus/client_golang/prometheus"
"gopkg.in/alecthomas/kingpin.v2"
)
var (
region string
topicARN = kingpin.Arg("topic", "SNS Topic ARN").Required().String()
debug = kingpin.Flag("debug", "Enable debug mode").Short('d').Bool()
messagesReceived = prometheus.NewCounter(prometheus.CounterOpts{
Name: "hermes_received_messages_total",
Help: "Number of messages processd by Hermes",
})
messagesErrored = prometheus.NewCounter(prometheus.CounterOpts{
Name: "hermes_error_messages_total",
Help: "Number of messages received by Hermes that ended in an error",
})
)
func init() {
kingpin.Parse()
if *debug {
log.SetLevel(log.DebugLevel)
} else {
gin.SetMode(gin.ReleaseMode)
}
inflectRegionFromARN(*topicARN)
log.WithFields(log.Fields{
"region": region,
"topicARN": *topicARN,
"debug": *debug,
}).Info("starting webhook service")
prometheus.MustRegister(messagesReceived)
prometheus.MustRegister(messagesErrored)
}
func main() {
r := gin.Default()
r.POST("/event", func(c *gin.Context) {
messagesReceived.Inc()
defer c.Request.Body.Close()
body, err := ioutil.ReadAll(c.Request.Body)
if err != nil {
log.WithFields(log.Fields{
"origErr": err.Error(),
}).Error("could not read request body")
messagesErrored.Inc()
return
}
if *debug {
log.WithFields(log.Fields{
"client": c.ClientIP(),
"body": string(body),
}).Debug("received request")
}
err = forwardToSNS(body)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok {
log.WithFields(log.Fields{
"code": awsErr.Code(),
"origErr": awsErr.OrigErr(),
}).Error(awsErr.Message())
if reqErr, ok := err.(awserr.RequestFailure); ok {
log.WithFields(log.Fields{
"code": reqErr.Code(),
"statusCode": reqErr.StatusCode(),
"requestId": reqErr.RequestID(),
}).Error(reqErr.Message())
c.String(http.StatusInternalServerError, "ERR")
messagesErrored.Inc()
return
}
c.String(http.StatusBadGateway, "ERR")
} else {
log.Error(err.Error())
c.String(http.StatusInternalServerError, "ERR")
}
messagesErrored.Inc()
return
}
log.WithFields(log.Fields{
"body": string(body),
}).Info("successfully forwarded message")
c.String(http.StatusNoContent, "")
})
r.GET("/metrics", gin.WrapH(prometheus.Handler()))
r.Run(":8080")
}
func inflectRegionFromARN(arn string) {
parts := strings.Split(arn, ":")
if len(parts) != 6 {
log.Fatal("Could not inflect AWS region from ARN: ARN does not look valid")
}
region = string(parts[3])
}
func forwardToSNS(data []byte) error {
svc := sns.New(&aws.Config{Region: region})
params := &sns.PublishInput{
Message: aws.String(string(data)),
TopicARN: aws.String(*topicARN),
}
_, err := svc.Publish(params)
return err
}