Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions apps/checker/cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,18 @@ func main() {
router := gin.New()
router.Use(gin.Recovery())
router.Use(Logger())
router.POST("/checker", h.HTTPCheckerHandler)
router.POST("/checker/http", h.HTTPCheckerHandler)
router.POST("/checker/tcp", h.TCPHandler)
router.POST("/checker/dns", h.DNSHandler)
router.POST("/ping/:region", h.PingRegionHandler)
router.POST("/tcp/:region", h.TCPHandlerRegion)
router.POST("/dns/:region", h.DNSHandlerRegion)

authed := router.Group("/")
authed.Use(handlers.AuthMiddleware(cronSecret))
authed.Use(handlers.FlyRegionMiddleware(cloudProvider, region))

authed.POST("/checker", h.HTTPCheckerHandler)
authed.POST("/checker/http", h.HTTPCheckerHandler)
authed.POST("/checker/tcp", h.TCPHandler)
authed.POST("/checker/dns", h.DNSHandler)
authed.POST("/ping/:region", h.PingRegionHandler)
authed.POST("/tcp/:region", h.TCPHandlerRegion)
authed.POST("/dns/:region", h.DNSHandlerRegion)

router.GET("/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "pong", "region": region, "provider": cloudProvider})
Expand Down
114 changes: 16 additions & 98 deletions apps/checker/handlers/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,6 @@ import (
"github.com/openstatushq/openstatus/apps/checker/request"
)

type statusCode int

func (s statusCode) IsSuccessful() bool {
return s >= 200 && s < 300
}

type PingData struct {
ID string `json:"id"`
WorkspaceID string `json:"workspaceId"`
Expand All @@ -49,23 +43,6 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {
const defaultRetry = 3
dataSourceName := "ping_response__v8"

if c.GetHeader("Authorization") != fmt.Sprintf("Basic %s", h.Secret) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})

return
}

if h.CloudProvider == "fly" {
// if the request has been routed to a wrong region, we forward it to the correct one.
region := c.GetHeader("fly-prefer-region")
if region != "" && region != h.Region {
c.Header("fly-replay", fmt.Sprintf("region=%s", region))
c.String(http.StatusAccepted, "Forwarding request to %s", region)

return
}
}

var req request.HttpCheckerRequest
if err := c.ShouldBindJSON(&req); err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to decode checker request")
Expand Down Expand Up @@ -94,13 +71,12 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {
}
defer requestClient.CloseIdleConnections()

// Might be a more efficient way to do it
var i interface{} = req.RawAssertions
jsonBytes, _ := json.Marshal(i)
assertionAsString := string(jsonBytes)

if assertionAsString == "null" {
assertionAsString = ""
var assertionAsString string
if req.RawAssertions != nil {
jsonBytes, _ := json.Marshal(req.RawAssertions)
if s := string(jsonBytes); s != "null" {
assertionAsString = s
}
}

trigger := "cron"
Expand Down Expand Up @@ -141,15 +117,7 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {
return fmt.Errorf("error while generating uuid %w", err)
}

var requestStatus = ""
switch req.Status {
case "active":
requestStatus = "success"
case "error":
requestStatus = "error"
case "degraded":
requestStatus = "degraded"
}
requestStatus := mapMonitorStatus(req.Status)

data := PingData{
ID: id.String(),
Expand Down Expand Up @@ -189,10 +157,8 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {
data.Error = 0
if req.DegradedAfter != 0 && res.Latency > req.DegradedAfter {
data.Body = res.Body

} else {
data.Body = ""

}
// Small trick to avoid sending the body at the moment to TB
} else {
Expand All @@ -202,70 +168,24 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {

data.Assertions = assertionAsString

if !isSuccessfull && req.Status != "error" {
// Q: Why here we do not check if the status was previously active?
checker.UpdateStatus(ctx, checker.UpdateData{
MonitorId: req.MonitorID,
Status: "error",
StatusCode: res.Status,
Region: h.Region,
Message: res.Error,
CronTimestamp: req.CronTimestamp,
Latency: res.Latency,
})
data.RequestStatus = "error"
}
// it's degraded
if isSuccessfull && req.DegradedAfter > 0 && res.Latency > req.DegradedAfter && req.Status != "degraded" {
checker.UpdateStatus(ctx, checker.UpdateData{
MonitorId: req.MonitorID,
Status: "degraded",
Region: h.Region,
StatusCode: res.Status,
CronTimestamp: req.CronTimestamp,
Latency: res.Latency,
})
data.RequestStatus = "degraded"
}
// it's active
if isSuccessfull && req.DegradedAfter == 0 && req.Status != "active" {
checker.UpdateStatus(ctx, checker.UpdateData{
MonitorId: req.MonitorID,
Status: "active",
Region: h.Region,
StatusCode: res.Status,
CronTimestamp: req.CronTimestamp,
Latency: res.Latency,
})
data.RequestStatus = "success"
}
// it's active
if isSuccessfull && res.Latency < req.DegradedAfter && req.DegradedAfter != 0 && req.Status != "active" {
checker.UpdateStatus(ctx, checker.UpdateData{
MonitorId: req.MonitorID,
Status: "active",
Region: h.Region,
StatusCode: res.Status,
CronTimestamp: req.CronTimestamp,
Latency: res.Latency,
})
data.RequestStatus = "success"
if newStatus := updateMonitorStatus(ctx, isSuccessfull, res.Latency, req.DegradedAfter, req.CronTimestamp,
req.Status, req.MonitorID, h.Region, res.Status, res.Error); newStatus != "" {
data.RequestStatus = newStatus
}

if err := h.TbClient.SendEvent(ctx, data, dataSourceName); err != nil {
log.Ctx(ctx).Error().Err(err).Msg("failed to send event to tinybird")
}


e, f := c.Get("event")
if f {
t := e.(map[string]any)
t["checker"] = map[string]string{
"uri": req.URL,
"uri": req.URL,
"workspace_id": req.WorkspaceID,
"monitor_id":req.MonitorID,
"trigger": trigger,
"type": "http",
"monitor_id": req.MonitorID,
"trigger": trigger,
"type": "http",
}
c.Set("event", t)
}
Expand Down Expand Up @@ -332,9 +252,8 @@ func (h Handler) HTTPCheckerHandler(c *gin.Context) {
}

func EvaluateHTTPAssertions(raw []json.RawMessage, data PingData, res checker.Response) (bool, error) {
statusCode := statusCode(res.Status)
if len(raw) == 0 {
return statusCode.IsSuccessful(), nil
return res.Status >= 200 && res.Status < 300, nil
}
isSuccessful := true
for _, a := range raw {
Expand Down Expand Up @@ -364,8 +283,7 @@ func EvaluateHTTPAssertions(raw []json.RawMessage, data PingData, res checker.Re
case request.AssertionJsonBody:
// TODO: Implement JSON body assertion
default:
fmt.Println("unknown assertion type: ", assert.AssertionType)
// TODO: Handle unknown assertion type
log.Warn().Str("type", string(assert.AssertionType)).Msg("unknown assertion type")
}
}
return isSuccessful, nil
Expand Down
15 changes: 12 additions & 3 deletions apps/checker/handlers/checker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ func TestHandler_HTTPCheckerHandler(t *testing.T) {
Region: region,
}
router := gin.New()
router.POST("/checker/:region", h.HTTPCheckerHandler)
authed := router.Group("/")
authed.Use(handlers.AuthMiddleware(h.Secret))
authed.Use(handlers.FlyRegionMiddleware(h.CloudProvider, h.Region))
authed.POST("/checker/:region", h.HTTPCheckerHandler)

w := httptest.NewRecorder()

Expand All @@ -61,7 +64,10 @@ func TestHandler_HTTPCheckerHandler(t *testing.T) {
Region: region,
}
router := gin.New()
router.POST("/checker/:region", h.HTTPCheckerHandler)
authed := router.Group("/")
authed.Use(handlers.AuthMiddleware(h.Secret))
authed.Use(handlers.FlyRegionMiddleware(h.CloudProvider, h.Region))
authed.POST("/checker/:region", h.HTTPCheckerHandler)

w := httptest.NewRecorder()

Expand Down Expand Up @@ -90,7 +96,10 @@ func TestHandler_HTTPCheckerHandler(t *testing.T) {
Region: region,
}
router := gin.New()
router.POST("/checker/:region", h.HTTPCheckerHandler)
authed := router.Group("/")
authed.Use(handlers.AuthMiddleware(h.Secret))
authed.Use(handlers.FlyRegionMiddleware(h.CloudProvider, h.Region))
authed.POST("/checker/:region", h.HTTPCheckerHandler)

w := httptest.NewRecorder()

Expand Down
99 changes: 19 additions & 80 deletions apps/checker/handlers/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,6 @@ func (h Handler) DNSHandler(c *gin.Context) {
const defaultRetry = 3
dataSourceName := "dns_response__v0"

// Authorization check
if c.GetHeader("Authorization") != fmt.Sprintf("Basic %s", h.Secret) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}

// Fly region forwarding
if h.CloudProvider == "fly" {
region := c.GetHeader("fly-prefer-region")
if region != "" && region != h.Region {
c.Header("fly-replay", fmt.Sprintf("region=%s", region))
c.String(http.StatusAccepted, "Forwarding request to %s", region)
return
}
}

// Parse request
var req request.DNSCheckerRequest
if err := c.ShouldBindJSON(&req); err != nil {
Expand Down Expand Up @@ -95,12 +79,7 @@ func (h Handler) DNSHandler(c *gin.Context) {
return
}

statusMap := map[string]string{
"active": "success",
"error": "error",
"degraded": "degraded",
}
requestStatus := statusMap[req.Status]
requestStatus := mapMonitorStatus(req.Status)

data := DNSResponse{
ID: id.String(),
Expand Down Expand Up @@ -207,11 +186,11 @@ func (h Handler) DNSHandler(c *gin.Context) {
if f {
t := event.(map[string]any)
t["checker"] = map[string]string{
"uri": req.URI,
"uri": req.URI,
"workspace_id": req.WorkspaceID,
"monitor_id":req.MonitorID,
"trigger": trigger,
"type": "dns",
"monitor_id": req.MonitorID,
"trigger": trigger,
"type": "dns",
}
c.Set("event", t)
}
Expand All @@ -224,22 +203,6 @@ func (h Handler) DNSHandlerRegion(c *gin.Context) {
dataSourceName := "check_dns_response__v0"
const defaultRetry = 3

// Authorization check
if c.GetHeader("Authorization") != fmt.Sprintf("Basic %s", h.Secret) {
c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"})
return
}

// Fly region forwarding
if h.CloudProvider == "fly" {
region := c.GetHeader("fly-prefer-region")
if region != "" && region != h.Region {
c.Header("fly-replay", fmt.Sprintf("region=%s", region))
c.String(http.StatusAccepted, "Forwarding request to %s", region)
return
}
}

// Parse request
var req request.DNSCheckerRequest
if err := c.ShouldBindJSON(&req); err != nil {
Expand All @@ -259,20 +222,19 @@ func (h Handler) DNSHandlerRegion(c *gin.Context) {
return
}

workspaceId, _ := strconv.Atoi(req.WorkspaceID)

statusMap := map[string]string{
"active": "success",
"error": "error",
"degraded": "degraded",
workspaceId, err := strconv.ParseInt(req.WorkspaceID, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid workspace id"})
return
}
requestStatus := statusMap[req.Status]

requestStatus := mapMonitorStatus(req.Status)

data := DNSResponse{
ID: id.String(),
Region: h.Region,
URI: req.URI,
WorkspaceID: int64(workspaceId),
WorkspaceID: workspaceId,
CronTimestamp: req.CronTimestamp,
RequestStatus: requestStatus,
Timestamp: time.Now().UTC().UnixMilli(),
Expand Down Expand Up @@ -340,37 +302,14 @@ func (h Handler) DNSHandlerRegion(c *gin.Context) {
}

func FormatDNSResult(result *checker.DnsResponse) map[string][]string {
r := make(map[string][]string)
a := make([]string, 0)
aaaa := make([]string, 0)
mx := make([]string, 0)
ns := make([]string, 0)
txt := make([]string, 0)

for _, v := range result.A {
a = append(a, v)
}
r["A"] = a

for _, v := range result.AAAA {
aaaa = append(aaaa, v)
}
r["AAAA"] = aaaa

r["CNAME"] = []string{result.CNAME}
for _, v := range result.MX {
mx = append(mx, v)
}
r["MX"] = mx
for _, v := range result.NS {
ns = append(ns, v)
}
r["NS"] = ns
for _, v := range result.TXT {
txt = append(txt, v)
return map[string][]string{
"A": result.A,
"AAAA": result.AAAA,
"CNAME": {result.CNAME},
"MX": result.MX,
"NS": result.NS,
"TXT": result.TXT,
}
r["TXT"] = txt
return r
}

func EvaluateDNSAssertions(rawAssertions []json.RawMessage, response *checker.DnsResponse) (bool, error) {
Expand Down
Loading
Loading