mirror of
https://github.com/TwiN/gatus.git
synced 2025-06-20 17:57:44 +02:00
feat(alerting): Add HomeAssistant support (#1125)
* Base homeassistant alerting setup * Update homeassistant alert documenation * sort alert.TypeHomeAssistant to comply alphabetic policy * Validate homeassistant as a provider interfaces implementation on compile --------- Co-authored-by: TwiN <twin@linux.com>
This commit is contained in:
parent
5b666f924c
commit
2f12088823
71
README.md
71
README.md
@ -59,6 +59,7 @@ Have any feedback or questions? [Create a discussion](https://github.com/TwiN/ga
|
|||||||
- [Configuring GitLab alerts](#configuring-gitlab-alerts)
|
- [Configuring GitLab alerts](#configuring-gitlab-alerts)
|
||||||
- [Configuring Google Chat alerts](#configuring-google-chat-alerts)
|
- [Configuring Google Chat alerts](#configuring-google-chat-alerts)
|
||||||
- [Configuring Gotify alerts](#configuring-gotify-alerts)
|
- [Configuring Gotify alerts](#configuring-gotify-alerts)
|
||||||
|
- [Configuring HomeAssistant alerts](#configuring-homeassistant-alerts)
|
||||||
- [Configuring Incident.io alerts](#configuring-incidentio-alerts)
|
- [Configuring Incident.io alerts](#configuring-incidentio-alerts)
|
||||||
- [Configuring JetBrains Space alerts](#configuring-jetbrains-space-alerts)
|
- [Configuring JetBrains Space alerts](#configuring-jetbrains-space-alerts)
|
||||||
- [Configuring Matrix alerts](#configuring-matrix-alerts)
|
- [Configuring Matrix alerts](#configuring-matrix-alerts)
|
||||||
@ -604,6 +605,7 @@ endpoints:
|
|||||||
| `alerting.telegram` | Configuration for alerts of type `telegram`. <br />See [Configuring Telegram alerts](#configuring-telegram-alerts). | `{}` |
|
| `alerting.telegram` | Configuration for alerts of type `telegram`. <br />See [Configuring Telegram alerts](#configuring-telegram-alerts). | `{}` |
|
||||||
| `alerting.twilio` | Settings for alerts of type `twilio`. <br />See [Configuring Twilio alerts](#configuring-twilio-alerts). | `{}` |
|
| `alerting.twilio` | Settings for alerts of type `twilio`. <br />See [Configuring Twilio alerts](#configuring-twilio-alerts). | `{}` |
|
||||||
| `alerting.zulip` | Configuration for alerts of type `zulip`. <br />See [Configuring Zulip alerts](#configuring-zulip-alerts). | `{}` |
|
| `alerting.zulip` | Configuration for alerts of type `zulip`. <br />See [Configuring Zulip alerts](#configuring-zulip-alerts). | `{}` |
|
||||||
|
| `alerting.homeassistant` | Configuration for alerts of type `homeassistant`. <br />See [Configuring HomeAssistant alerts](#configuring-homeassistant-alerts). | `{}` |
|
||||||
|
|
||||||
|
|
||||||
#### Configuring AWS SES alerts
|
#### Configuring AWS SES alerts
|
||||||
@ -920,6 +922,75 @@ Here's an example of what the notifications look like:
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
#### Configuring HomeAssistant alerts
|
||||||
|
To configure HomeAssistant alerts, you'll need to add the following to your configuration file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
alerting:
|
||||||
|
homeassistant:
|
||||||
|
url: "http://homeassistant:8123" # URL of your HomeAssistant instance
|
||||||
|
token: "YOUR_LONG_LIVED_ACCESS_TOKEN" # Long-lived access token from HomeAssistant
|
||||||
|
|
||||||
|
endpoints:
|
||||||
|
- name: my-service
|
||||||
|
url: "https://my-service.com"
|
||||||
|
interval: 5m
|
||||||
|
conditions:
|
||||||
|
- "[STATUS] == 200"
|
||||||
|
alerts:
|
||||||
|
- type: homeassistant
|
||||||
|
enabled: true
|
||||||
|
send-on-resolved: true
|
||||||
|
description: "My service health check"
|
||||||
|
failure-threshold: 3
|
||||||
|
success-threshold: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
The alerts will be sent as events to HomeAssistant with the event type `gatus_alert`. The event data includes:
|
||||||
|
- `status`: "triggered" or "resolved"
|
||||||
|
- `endpoint`: The name of the monitored endpoint
|
||||||
|
- `description`: The alert description if provided
|
||||||
|
- `conditions`: List of conditions and their results
|
||||||
|
- `failure_count`: Number of consecutive failures (when triggered)
|
||||||
|
- `success_count`: Number of consecutive successes (when resolved)
|
||||||
|
|
||||||
|
You can use these events in HomeAssistant automations to:
|
||||||
|
- Send notifications
|
||||||
|
- Control devices
|
||||||
|
- Trigger scenes
|
||||||
|
- Log to history
|
||||||
|
- And more
|
||||||
|
|
||||||
|
Example HomeAssistant automation:
|
||||||
|
```yaml
|
||||||
|
automation:
|
||||||
|
- alias: "Gatus Alert Handler"
|
||||||
|
trigger:
|
||||||
|
platform: event
|
||||||
|
event_type: gatus_alert
|
||||||
|
action:
|
||||||
|
- service: notify.notify
|
||||||
|
data_template:
|
||||||
|
title: "Gatus Alert: {{ trigger.event.data.endpoint }}"
|
||||||
|
message: >
|
||||||
|
Status: {{ trigger.event.data.status }}
|
||||||
|
{% if trigger.event.data.description %}
|
||||||
|
Description: {{ trigger.event.data.description }}
|
||||||
|
{% endif %}
|
||||||
|
{% for condition in trigger.event.data.conditions %}
|
||||||
|
{{ '✅' if condition.success else '❌' }} {{ condition.condition }}
|
||||||
|
{% endfor %}
|
||||||
|
```
|
||||||
|
|
||||||
|
To get your HomeAssistant long-lived access token:
|
||||||
|
1. Open HomeAssistant
|
||||||
|
2. Click on your profile name (bottom left)
|
||||||
|
3. Scroll down to "Long-Lived Access Tokens"
|
||||||
|
4. Click "Create Token"
|
||||||
|
5. Give it a name (e.g., "Gatus")
|
||||||
|
6. Copy the token - you'll only see it once!
|
||||||
|
|
||||||
|
|
||||||
#### Configuring Incident.io alerts
|
#### Configuring Incident.io alerts
|
||||||
| Parameter | Description | Default |
|
| Parameter | Description | Default |
|
||||||
|:-----------------------------------------|:-------------------------------------------------------------------------------------------|:--------------|
|
|:-----------------------------------------|:-------------------------------------------------------------------------------------------|:--------------|
|
||||||
|
@ -32,6 +32,9 @@ const (
|
|||||||
// TypeGotify is the Type for the gotify alerting provider
|
// TypeGotify is the Type for the gotify alerting provider
|
||||||
TypeGotify Type = "gotify"
|
TypeGotify Type = "gotify"
|
||||||
|
|
||||||
|
// TypeHomeAssistant is the Type for the homeassistant alerting provider
|
||||||
|
TypeHomeAssistant Type = "homeassistant"
|
||||||
|
|
||||||
// TypeIncidentIO is the Type for the incident-io alerting provider
|
// TypeIncidentIO is the Type for the incident-io alerting provider
|
||||||
TypeIncidentIO Type = "incident-io"
|
TypeIncidentIO Type = "incident-io"
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
|
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
|
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/gotify"
|
"github.com/TwiN/gatus/v5/alerting/provider/gotify"
|
||||||
|
"github.com/TwiN/gatus/v5/alerting/provider/homeassistant"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/incidentio"
|
"github.com/TwiN/gatus/v5/alerting/provider/incidentio"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/jetbrainsspace"
|
"github.com/TwiN/gatus/v5/alerting/provider/jetbrainsspace"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/matrix"
|
"github.com/TwiN/gatus/v5/alerting/provider/matrix"
|
||||||
@ -62,6 +63,9 @@ type Config struct {
|
|||||||
// Gotify is the configuration for the gotify alerting provider
|
// Gotify is the configuration for the gotify alerting provider
|
||||||
Gotify *gotify.AlertProvider `yaml:"gotify,omitempty"`
|
Gotify *gotify.AlertProvider `yaml:"gotify,omitempty"`
|
||||||
|
|
||||||
|
// HomeAssistant is the configuration for the homeassistant alerting provider
|
||||||
|
HomeAssistant *homeassistant.AlertProvider `yaml:"homeassistant,omitempty"`
|
||||||
|
|
||||||
// IncidentIO is the configuration for the incident-io alerting provider
|
// IncidentIO is the configuration for the incident-io alerting provider
|
||||||
IncidentIO *incidentio.AlertProvider `yaml:"incident-io,omitempty"`
|
IncidentIO *incidentio.AlertProvider `yaml:"incident-io,omitempty"`
|
||||||
|
|
||||||
|
196
alerting/provider/homeassistant/homeassistant.go
Normal file
196
alerting/provider/homeassistant/homeassistant.go
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package homeassistant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/TwiN/gatus/v5/alerting/alert"
|
||||||
|
"github.com/TwiN/gatus/v5/client"
|
||||||
|
"github.com/TwiN/gatus/v5/config/endpoint"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrURLNotSet = errors.New("url not set")
|
||||||
|
ErrTokenNotSet = errors.New("token not set")
|
||||||
|
ErrDuplicateGroupOverride = errors.New("duplicate group override")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
URL string `yaml:"url"`
|
||||||
|
Token string `yaml:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) Validate() error {
|
||||||
|
if len(cfg.URL) == 0 {
|
||||||
|
return ErrURLNotSet
|
||||||
|
}
|
||||||
|
if len(cfg.Token) == 0 {
|
||||||
|
return ErrTokenNotSet
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) Merge(override *Config) {
|
||||||
|
if len(override.URL) > 0 {
|
||||||
|
cfg.URL = override.URL
|
||||||
|
}
|
||||||
|
if len(override.Token) > 0 {
|
||||||
|
cfg.Token = override.Token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AlertProvider is the configuration necessary for sending an alert using HomeAssistant
|
||||||
|
type AlertProvider struct {
|
||||||
|
DefaultConfig Config `yaml:",inline"`
|
||||||
|
|
||||||
|
// DefaultAlert is the default alert configuration to use for endpoints with an alert of the appropriate type
|
||||||
|
DefaultAlert *alert.Alert `yaml:"default-alert,omitempty"`
|
||||||
|
|
||||||
|
// 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"`
|
||||||
|
Config `yaml:",inline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the provider's configuration
|
||||||
|
func (provider *AlertProvider) Validate() error {
|
||||||
|
registeredGroups := make(map[string]bool)
|
||||||
|
if provider.Overrides != nil {
|
||||||
|
for _, override := range provider.Overrides {
|
||||||
|
if isAlreadyRegistered := registeredGroups[override.Group]; isAlreadyRegistered || override.Group == "" {
|
||||||
|
return ErrDuplicateGroupOverride
|
||||||
|
}
|
||||||
|
registeredGroups[override.Group] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return provider.DefaultConfig.Validate()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send an alert using the provider
|
||||||
|
func (provider *AlertProvider) Send(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) error {
|
||||||
|
cfg, err := provider.GetConfig(ep.Group, alert)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buffer := bytes.NewBuffer(provider.buildRequestBody(ep, alert, result, resolved))
|
||||||
|
request, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/events/gatus_alert", cfg.URL), buffer)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
request.Header.Set("Content-Type", "application/json")
|
||||||
|
request.Header.Set("Authorization", "Bearer "+cfg.Token)
|
||||||
|
response, err := client.GetHTTPClient(nil).Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer response.Body.Close()
|
||||||
|
if response.StatusCode > 399 {
|
||||||
|
body, _ := io.ReadAll(response.Body)
|
||||||
|
return fmt.Errorf("call to provider alert returned status code %d: %s", response.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type Body struct {
|
||||||
|
EventType string `json:"event_type"`
|
||||||
|
EventData struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Conditions []struct {
|
||||||
|
Condition string `json:"condition"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
} `json:"conditions,omitempty"`
|
||||||
|
FailureCount int `json:"failure_count,omitempty"`
|
||||||
|
SuccessCount int `json:"success_count,omitempty"`
|
||||||
|
} `json:"event_data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildRequestBody builds the request body for the provider
|
||||||
|
func (provider *AlertProvider) buildRequestBody(ep *endpoint.Endpoint, alert *alert.Alert, result *endpoint.Result, resolved bool) []byte {
|
||||||
|
body := Body{
|
||||||
|
EventType: "gatus_alert",
|
||||||
|
EventData: struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
Endpoint string `json:"endpoint"`
|
||||||
|
Description string `json:"description,omitempty"`
|
||||||
|
Conditions []struct {
|
||||||
|
Condition string `json:"condition"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
} `json:"conditions,omitempty"`
|
||||||
|
FailureCount int `json:"failure_count,omitempty"`
|
||||||
|
SuccessCount int `json:"success_count,omitempty"`
|
||||||
|
}{
|
||||||
|
Status: "resolved",
|
||||||
|
Endpoint: ep.DisplayName(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !resolved {
|
||||||
|
body.EventData.Status = "triggered"
|
||||||
|
body.EventData.FailureCount = alert.FailureThreshold
|
||||||
|
} else {
|
||||||
|
body.EventData.SuccessCount = alert.SuccessThreshold
|
||||||
|
}
|
||||||
|
|
||||||
|
if alertDescription := alert.GetDescription(); len(alertDescription) > 0 {
|
||||||
|
body.EventData.Description = alertDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(result.ConditionResults) > 0 {
|
||||||
|
for _, conditionResult := range result.ConditionResults {
|
||||||
|
body.EventData.Conditions = append(body.EventData.Conditions, struct {
|
||||||
|
Condition string `json:"condition"`
|
||||||
|
Success bool `json:"success"`
|
||||||
|
}{
|
||||||
|
Condition: conditionResult.Condition,
|
||||||
|
Success: conditionResult.Success,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyAsJSON, _ := json.Marshal(body)
|
||||||
|
return bodyAsJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDefaultAlert returns the provider's default alert configuration
|
||||||
|
func (provider *AlertProvider) GetDefaultAlert() *alert.Alert {
|
||||||
|
return provider.DefaultAlert
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetConfig returns the configuration for the provider with the overrides applied
|
||||||
|
func (provider *AlertProvider) GetConfig(group string, alert *alert.Alert) (*Config, error) {
|
||||||
|
cfg := provider.DefaultConfig
|
||||||
|
if provider.Overrides != nil {
|
||||||
|
for _, override := range provider.Overrides {
|
||||||
|
if group == override.Group {
|
||||||
|
cfg.Merge(&override.Config)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(alert.ProviderOverride) != 0 {
|
||||||
|
overrideConfig := Config{}
|
||||||
|
if err := yaml.Unmarshal(alert.ProviderOverrideAsBytes(), &overrideConfig); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cfg.Merge(&overrideConfig)
|
||||||
|
}
|
||||||
|
err := cfg.Validate()
|
||||||
|
return &cfg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateOverrides validates the alert's provider override and, if present, the group override
|
||||||
|
func (provider *AlertProvider) ValidateOverrides(group string, alert *alert.Alert) error {
|
||||||
|
_, err := provider.GetConfig(group, alert)
|
||||||
|
return err
|
||||||
|
}
|
158
alerting/provider/homeassistant/homeassistant_test.go
Normal file
158
alerting/provider/homeassistant/homeassistant_test.go
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package homeassistant
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/TwiN/gatus/v5/alerting/alert"
|
||||||
|
"github.com/TwiN/gatus/v5/client"
|
||||||
|
"github.com/TwiN/gatus/v5/config/endpoint"
|
||||||
|
"github.com/TwiN/gatus/v5/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAlertProvider_Validate(t *testing.T) {
|
||||||
|
invalidProvider := AlertProvider{DefaultConfig: Config{URL: "", Token: ""}}
|
||||||
|
if err := invalidProvider.Validate(); err == nil {
|
||||||
|
t.Error("provider shouldn't have been valid")
|
||||||
|
}
|
||||||
|
invalidProviderNoToken := AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: ""}}
|
||||||
|
if err := invalidProviderNoToken.Validate(); err == nil {
|
||||||
|
t.Error("provider shouldn't have been valid")
|
||||||
|
}
|
||||||
|
validProvider := AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"}}
|
||||||
|
if err := validProvider.Validate(); err != nil {
|
||||||
|
t.Error("provider should've been valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertProvider_ValidateWithOverride(t *testing.T) {
|
||||||
|
providerWithInvalidOverrideGroup := AlertProvider{
|
||||||
|
Overrides: []Override{
|
||||||
|
{
|
||||||
|
Config: Config{URL: "http://homeassistant:8123", Token: "token"},
|
||||||
|
Group: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := providerWithInvalidOverrideGroup.Validate(); err == nil {
|
||||||
|
t.Error("provider Group shouldn't have been valid")
|
||||||
|
}
|
||||||
|
providerWithValidOverride := AlertProvider{
|
||||||
|
DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"},
|
||||||
|
Overrides: []Override{
|
||||||
|
{
|
||||||
|
Config: Config{URL: "http://homeassistant:8123", Token: "token"},
|
||||||
|
Group: "group",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
if err := providerWithValidOverride.Validate(); err != nil {
|
||||||
|
t.Error("provider should've been valid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertProvider_Send(t *testing.T) {
|
||||||
|
defer client.InjectHTTPClient(nil)
|
||||||
|
firstDescription := "description-1"
|
||||||
|
secondDescription := "description-2"
|
||||||
|
scenarios := []struct {
|
||||||
|
Name string
|
||||||
|
Provider AlertProvider
|
||||||
|
Alert alert.Alert
|
||||||
|
Resolved bool
|
||||||
|
MockRoundTripper test.MockRoundTripper
|
||||||
|
ExpectedError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "triggered",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"}},
|
||||||
|
Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: false,
|
||||||
|
MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
|
||||||
|
return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}
|
||||||
|
}),
|
||||||
|
ExpectedError: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "triggered-error",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"}},
|
||||||
|
Alert: alert.Alert{Description: &firstDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: false,
|
||||||
|
MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
|
||||||
|
return &http.Response{StatusCode: http.StatusInternalServerError, Body: http.NoBody}
|
||||||
|
}),
|
||||||
|
ExpectedError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "resolved",
|
||||||
|
Provider: AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"}},
|
||||||
|
Alert: alert.Alert{Description: &secondDescription, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
Resolved: true,
|
||||||
|
MockRoundTripper: test.MockRoundTripper(func(r *http.Request) *http.Response {
|
||||||
|
return &http.Response{StatusCode: http.StatusOK, Body: http.NoBody}
|
||||||
|
}),
|
||||||
|
ExpectedError: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, scenario := range scenarios {
|
||||||
|
t.Run(scenario.Name, func(t *testing.T) {
|
||||||
|
client.InjectHTTPClient(&http.Client{Transport: scenario.MockRoundTripper})
|
||||||
|
err := scenario.Provider.Send(
|
||||||
|
&endpoint.Endpoint{Name: "endpoint-name"},
|
||||||
|
&scenario.Alert,
|
||||||
|
&endpoint.Result{
|
||||||
|
ConditionResults: []*endpoint.ConditionResult{
|
||||||
|
{Condition: "SUCCESSFUL_CONDITION", Success: true},
|
||||||
|
{Condition: "FAILING_CONDITION", Success: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scenario.Resolved,
|
||||||
|
)
|
||||||
|
if scenario.ExpectedError && err == nil {
|
||||||
|
t.Error("expected error, got none")
|
||||||
|
}
|
||||||
|
if !scenario.ExpectedError && err != nil {
|
||||||
|
t.Error("expected no error, got", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertProvider_buildRequestBody(t *testing.T) {
|
||||||
|
description := "test-description"
|
||||||
|
provider := AlertProvider{DefaultConfig: Config{URL: "http://homeassistant:8123", Token: "token"}}
|
||||||
|
body := provider.buildRequestBody(
|
||||||
|
&endpoint.Endpoint{Name: "endpoint-name"},
|
||||||
|
&alert.Alert{Description: &description, SuccessThreshold: 5, FailureThreshold: 3},
|
||||||
|
&endpoint.Result{
|
||||||
|
ConditionResults: []*endpoint.ConditionResult{
|
||||||
|
{Condition: "SUCCESSFUL_CONDITION", Success: true},
|
||||||
|
{Condition: "FAILING_CONDITION", Success: false},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
var decodedBody Body
|
||||||
|
if err := json.Unmarshal(body, &decodedBody); err != nil {
|
||||||
|
t.Error("expected body to be valid JSON, got error:", err.Error())
|
||||||
|
}
|
||||||
|
if decodedBody.EventType != "gatus_alert" {
|
||||||
|
t.Errorf("expected event_type to be gatus_alert, got %s", decodedBody.EventType)
|
||||||
|
}
|
||||||
|
if decodedBody.EventData.Status != "triggered" {
|
||||||
|
t.Errorf("expected status to be triggered, got %s", decodedBody.EventData.Status)
|
||||||
|
}
|
||||||
|
if decodedBody.EventData.Description != description {
|
||||||
|
t.Errorf("expected description to be %s, got %s", description, decodedBody.EventData.Description)
|
||||||
|
}
|
||||||
|
if len(decodedBody.EventData.Conditions) != 2 {
|
||||||
|
t.Errorf("expected 2 conditions, got %d", len(decodedBody.EventData.Conditions))
|
||||||
|
}
|
||||||
|
if !decodedBody.EventData.Conditions[0].Success {
|
||||||
|
t.Error("expected first condition to be successful")
|
||||||
|
}
|
||||||
|
if decodedBody.EventData.Conditions[1].Success {
|
||||||
|
t.Error("expected second condition to be unsuccessful")
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/TwiN/gatus/v5/alerting/provider/github"
|
"github.com/TwiN/gatus/v5/alerting/provider/github"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
|
"github.com/TwiN/gatus/v5/alerting/provider/gitlab"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
|
"github.com/TwiN/gatus/v5/alerting/provider/googlechat"
|
||||||
|
"github.com/TwiN/gatus/v5/alerting/provider/homeassistant"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/incidentio"
|
"github.com/TwiN/gatus/v5/alerting/provider/incidentio"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/jetbrainsspace"
|
"github.com/TwiN/gatus/v5/alerting/provider/jetbrainsspace"
|
||||||
"github.com/TwiN/gatus/v5/alerting/provider/matrix"
|
"github.com/TwiN/gatus/v5/alerting/provider/matrix"
|
||||||
@ -80,6 +81,7 @@ var (
|
|||||||
_ AlertProvider = (*github.AlertProvider)(nil)
|
_ AlertProvider = (*github.AlertProvider)(nil)
|
||||||
_ AlertProvider = (*gitlab.AlertProvider)(nil)
|
_ AlertProvider = (*gitlab.AlertProvider)(nil)
|
||||||
_ AlertProvider = (*googlechat.AlertProvider)(nil)
|
_ AlertProvider = (*googlechat.AlertProvider)(nil)
|
||||||
|
_ AlertProvider = (*homeassistant.AlertProvider)(nil)
|
||||||
_ AlertProvider = (*jetbrainsspace.AlertProvider)(nil)
|
_ AlertProvider = (*jetbrainsspace.AlertProvider)(nil)
|
||||||
_ AlertProvider = (*matrix.AlertProvider)(nil)
|
_ AlertProvider = (*matrix.AlertProvider)(nil)
|
||||||
_ AlertProvider = (*mattermost.AlertProvider)(nil)
|
_ AlertProvider = (*mattermost.AlertProvider)(nil)
|
||||||
@ -105,6 +107,7 @@ var (
|
|||||||
_ Config[github.Config] = (*github.Config)(nil)
|
_ Config[github.Config] = (*github.Config)(nil)
|
||||||
_ Config[gitlab.Config] = (*gitlab.Config)(nil)
|
_ Config[gitlab.Config] = (*gitlab.Config)(nil)
|
||||||
_ Config[googlechat.Config] = (*googlechat.Config)(nil)
|
_ Config[googlechat.Config] = (*googlechat.Config)(nil)
|
||||||
|
_ Config[homeassistant.Config] = (*homeassistant.Config)(nil)
|
||||||
_ Config[incidentio.Config] = (*incidentio.Config)(nil)
|
_ Config[incidentio.Config] = (*incidentio.Config)(nil)
|
||||||
_ Config[jetbrainsspace.Config] = (*jetbrainsspace.Config)(nil)
|
_ Config[jetbrainsspace.Config] = (*jetbrainsspace.Config)(nil)
|
||||||
_ Config[matrix.Config] = (*matrix.Config)(nil)
|
_ Config[matrix.Config] = (*matrix.Config)(nil)
|
||||||
|
@ -411,6 +411,7 @@ func validateAlertingConfig(alertingConfig *alerting.Config, endpoints []*endpoi
|
|||||||
alert.TypeGitea,
|
alert.TypeGitea,
|
||||||
alert.TypeGoogleChat,
|
alert.TypeGoogleChat,
|
||||||
alert.TypeGotify,
|
alert.TypeGotify,
|
||||||
|
alert.TypeHomeAssistant,
|
||||||
alert.TypeJetBrainsSpace,
|
alert.TypeJetBrainsSpace,
|
||||||
alert.TypeMatrix,
|
alert.TypeMatrix,
|
||||||
alert.TypeMattermost,
|
alert.TypeMattermost,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user