2021-07-28 14:15:56 +02:00
package teams
import (
2021-12-03 03:05:17 +01:00
"bytes"
2022-10-20 21:31:29 +02:00
"encoding/json"
2021-07-28 14:15:56 +02:00
"fmt"
2021-12-03 07:44:17 +01:00
"io"
2021-07-28 14:15:56 +02:00
"net/http"
2022-12-06 07:41:09 +01:00
"github.com/TwiN/gatus/v5/alerting/alert"
"github.com/TwiN/gatus/v5/client"
"github.com/TwiN/gatus/v5/core"
2021-07-28 14:15:56 +02:00
)
// AlertProvider is the configuration necessary for sending an alert using Teams
type AlertProvider struct {
WebhookURL string ` yaml:"webhook-url" `
2021-10-23 22:47:12 +02:00
// DefaultAlert is the default alert configuration to use for endpoints with an alert of the appropriate type
2022-01-12 02:13:37 +01:00
DefaultAlert * alert . Alert ` yaml:"default-alert,omitempty" `
2022-03-24 01:31:10 +01:00
// Overrides is a list of Override that may be prioritized over the default configuration
Overrides [ ] Override ` yaml:"overrides,omitempty" `
}
// Override is a case under which the default integration is overridden
type Override struct {
Group string ` yaml:"group" `
WebhookURL string ` yaml:"webhook-url" `
2021-07-28 14:15:56 +02:00
}
// IsValid returns whether the provider's configuration is valid
func ( provider * AlertProvider ) IsValid ( ) bool {
2022-03-24 01:31:10 +01:00
registeredGroups := make ( map [ string ] bool )
if provider . Overrides != nil {
for _ , override := range provider . Overrides {
if isAlreadyRegistered := registeredGroups [ override . Group ] ; isAlreadyRegistered || override . Group == "" || len ( override . WebhookURL ) == 0 {
return false
}
registeredGroups [ override . Group ] = true
}
}
2021-07-28 14:15:56 +02:00
return len ( provider . WebhookURL ) > 0
}
2021-12-03 03:05:17 +01:00
// Send an alert using the provider
func ( provider * AlertProvider ) Send ( endpoint * core . Endpoint , alert * alert . Alert , result * core . Result , resolved bool ) error {
2022-10-20 21:31:29 +02:00
buffer := bytes . NewBuffer ( provider . buildRequestBody ( endpoint , alert , result , resolved ) )
2022-03-24 01:31:10 +01:00
request , err := http . NewRequest ( http . MethodPost , provider . getWebhookURLForGroup ( endpoint . Group ) , buffer )
2021-12-03 03:05:17 +01:00
if err != nil {
return err
}
request . Header . Set ( "Content-Type" , "application/json" )
response , err := client . GetHTTPClient ( nil ) . Do ( request )
if err != nil {
return err
}
2022-10-20 21:16:27 +02:00
defer response . Body . Close ( )
2021-12-03 03:05:17 +01:00
if response . StatusCode > 399 {
2021-12-03 07:44:17 +01:00
body , _ := io . ReadAll ( response . Body )
2021-12-03 03:05:17 +01:00
return fmt . Errorf ( "call to provider alert returned status code %d: %s" , response . StatusCode , string ( body ) )
}
return err
}
2022-10-20 21:31:29 +02:00
type Body struct {
Type string ` json:"@type" `
Context string ` json:"@context" `
ThemeColor string ` json:"themeColor" `
Title string ` json:"title" `
Text string ` json:"text" `
2024-04-11 02:46:17 +02:00
Sections [ ] Section ` json:"sections,omitempty" `
2022-10-20 21:31:29 +02:00
}
type Section struct {
ActivityTitle string ` json:"activityTitle" `
Text string ` json:"text" `
}
2021-12-03 03:05:17 +01:00
// buildRequestBody builds the request body for the provider
2022-10-20 21:31:29 +02:00
func ( provider * AlertProvider ) buildRequestBody ( endpoint * core . Endpoint , alert * alert . Alert , result * core . Result , resolved bool ) [ ] byte {
2021-12-03 03:05:17 +01:00
var message , color string
2021-07-28 14:15:56 +02:00
if resolved {
2021-12-12 22:33:16 +01:00
message = fmt . Sprintf ( "An alert for *%s* has been resolved after passing successfully %d time(s) in a row" , endpoint . DisplayName ( ) , alert . SuccessThreshold )
2021-07-28 14:15:56 +02:00
color = "#36A64F"
} else {
2021-12-12 22:33:16 +01:00
message = fmt . Sprintf ( "An alert for *%s* has been triggered due to having failed %d time(s) in a row" , endpoint . DisplayName ( ) , alert . FailureThreshold )
2021-07-28 14:15:56 +02:00
color = "#DD0000"
}
2024-04-11 02:46:17 +02:00
var formattedConditionResults string
2021-07-28 14:15:56 +02:00
for _ , conditionResult := range result . ConditionResults {
var prefix string
if conditionResult . Success {
2021-07-30 01:54:40 +02:00
prefix = "✅"
2021-07-28 14:15:56 +02:00
} else {
prefix = "❌"
}
2024-04-11 02:46:17 +02:00
formattedConditionResults += fmt . Sprintf ( "%s - `%s`<br/>" , prefix , conditionResult . Condition )
2021-07-28 14:15:56 +02:00
}
2021-07-30 01:54:40 +02:00
var description string
if alertDescription := alert . GetDescription ( ) ; len ( alertDescription ) > 0 {
2022-10-20 21:31:29 +02:00
description = ": " + alertDescription
2021-07-30 01:54:40 +02:00
}
2024-04-11 02:46:17 +02:00
body := Body {
2022-10-20 21:31:29 +02:00
Type : "MessageCard" ,
Context : "http://schema.org/extensions" ,
ThemeColor : color ,
Title : "🚨 Gatus" ,
Text : message + description ,
2024-04-11 02:46:17 +02:00
}
if len ( formattedConditionResults ) > 0 {
body . Sections = append ( body . Sections , Section {
ActivityTitle : "Condition results" ,
Text : formattedConditionResults ,
} )
}
bodyAsJSON , _ := json . Marshal ( body )
return bodyAsJSON
2021-07-28 14:15:56 +02:00
}
2022-03-24 01:31:10 +01:00
// getWebhookURLForGroup returns the appropriate Webhook URL integration to for a given group
func ( provider * AlertProvider ) getWebhookURLForGroup ( group string ) string {
if provider . Overrides != nil {
for _ , override := range provider . Overrides {
if group == override . Group {
return override . WebhookURL
}
}
}
return provider . WebhookURL
}
2021-07-28 14:15:56 +02:00
// GetDefaultAlert returns the provider's default alert configuration
2024-02-08 02:09:45 +01:00
func ( provider * AlertProvider ) GetDefaultAlert ( ) * alert . Alert {
2021-07-28 14:15:56 +02:00
return provider . DefaultAlert
}