2021-08-13 07:14:36 -05:00
|
|
|
package alerting
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2022-11-29 02:59:03 -06:00
|
|
|
"context"
|
2021-08-13 07:14:36 -05:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2022-08-10 08:37:51 -05:00
|
|
|
"io"
|
2021-08-13 07:14:36 -05:00
|
|
|
"net/http"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2024-02-01 08:53:15 -06:00
|
|
|
"github.com/prometheus/alertmanager/config"
|
|
|
|
"github.com/prometheus/alertmanager/pkg/labels"
|
2022-02-15 16:24:39 -06:00
|
|
|
"github.com/prometheus/common/model"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
2022-11-10 09:34:13 -06:00
|
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
2024-02-01 08:53:15 -06:00
|
|
|
"github.com/grafana/grafana/pkg/expr"
|
2022-11-10 09:34:13 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/datasources"
|
2021-08-25 08:11:22 -05:00
|
|
|
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
2021-08-13 07:14:36 -05:00
|
|
|
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
|
2022-07-19 08:32:54 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/ngalert/sender"
|
2022-08-10 04:56:48 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/org"
|
2022-11-29 02:59:03 -06:00
|
|
|
"github.com/grafana/grafana/pkg/services/org/orgimpl"
|
|
|
|
"github.com/grafana/grafana/pkg/services/quota/quotatest"
|
2022-06-28 07:32:25 -05:00
|
|
|
"github.com/grafana/grafana/pkg/services/user"
|
2021-08-13 07:14:36 -05:00
|
|
|
"github.com/grafana/grafana/pkg/tests/testinfra"
|
|
|
|
)
|
|
|
|
|
2022-12-09 01:11:56 -06:00
|
|
|
func TestIntegrationAdminConfiguration_SendingToExternalAlertmanagers(t *testing.T) {
|
|
|
|
testinfra.SQLiteIntegrationTest(t)
|
|
|
|
|
2021-09-29 09:16:40 -05:00
|
|
|
const disableOrgID int64 = 3
|
2021-08-13 07:14:36 -05:00
|
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
2021-09-29 09:16:40 -05:00
|
|
|
DisableLegacyAlerting: true,
|
|
|
|
EnableUnifiedAlerting: true,
|
2021-09-16 09:33:51 -05:00
|
|
|
DisableAnonymous: true,
|
|
|
|
NGAlertAdminConfigPollInterval: 2 * time.Second,
|
2021-09-29 09:16:40 -05:00
|
|
|
UnifiedAlertingDisabledOrgs: []int64{disableOrgID}, // disable unified alerting for organisation 3
|
2022-02-09 03:26:06 -06:00
|
|
|
AppModeProduction: true,
|
2021-08-13 07:14:36 -05:00
|
|
|
})
|
|
|
|
|
2024-04-04 08:04:47 -05:00
|
|
|
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path)
|
2021-08-13 07:14:36 -05:00
|
|
|
|
2024-04-04 08:04:47 -05:00
|
|
|
orgService, err := orgimpl.ProvideService(env.SQLStore, env.Cfg, quotatest.New(false, nil))
|
2022-11-29 02:59:03 -06:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
2021-08-13 07:14:36 -05:00
|
|
|
// Create a user to make authenticated requests
|
2024-04-04 08:04:47 -05:00
|
|
|
userID := createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
2022-08-10 04:56:48 -05:00
|
|
|
DefaultOrgRole: string(org.RoleAdmin),
|
2021-08-13 07:14:36 -05:00
|
|
|
Login: "grafana",
|
|
|
|
Password: "password",
|
|
|
|
})
|
2022-06-21 10:39:22 -05:00
|
|
|
apiClient := newAlertingApiClient(grafanaListedAddr, "grafana", "password")
|
2022-11-29 02:59:03 -06:00
|
|
|
|
2021-09-29 09:16:40 -05:00
|
|
|
// create another organisation
|
2022-11-29 02:59:03 -06:00
|
|
|
newOrg, err := orgService.CreateWithMember(context.Background(), &org.CreateOrgCommand{Name: "another org", UserID: userID})
|
|
|
|
require.NoError(t, err)
|
|
|
|
orgID := newOrg.ID
|
|
|
|
|
2021-09-29 09:16:40 -05:00
|
|
|
// ensure that the orgID is 3 (the disabled org)
|
|
|
|
require.Equal(t, disableOrgID, orgID)
|
|
|
|
|
|
|
|
// create user under different organisation
|
2024-04-04 08:04:47 -05:00
|
|
|
createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
2022-08-10 04:56:48 -05:00
|
|
|
DefaultOrgRole: string(org.RoleAdmin),
|
2021-09-29 09:16:40 -05:00
|
|
|
Password: "admin-42",
|
|
|
|
Login: "admin-42",
|
2022-06-28 07:32:25 -05:00
|
|
|
OrgID: orgID,
|
2021-09-29 09:16:40 -05:00
|
|
|
})
|
|
|
|
|
2021-08-13 07:14:36 -05:00
|
|
|
// Create a couple of "fake" Alertmanagers
|
2022-07-19 08:32:54 -05:00
|
|
|
fakeAM1 := sender.NewFakeExternalAlertmanager(t)
|
|
|
|
fakeAM2 := sender.NewFakeExternalAlertmanager(t)
|
|
|
|
fakeAM3 := sender.NewFakeExternalAlertmanager(t)
|
2021-08-13 07:14:36 -05:00
|
|
|
|
|
|
|
// Now, let's test the configuration API.
|
|
|
|
{
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := getRequest(t, alertsURL, http.StatusNotFound) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-08-13 07:14:36 -05:00
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-04-14 10:54:49 -05:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "no admin configuration available", res["message"])
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
|
|
|
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
// An invalid alertmanager choice should return an error.
|
2021-08-13 07:14:36 -05:00
|
|
|
{
|
|
|
|
ac := apimodels.PostableNGalertConfig{
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
AlertmanagersChoice: apimodels.AlertmanagersChoice("invalid"),
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&ac)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, alertsURL, buf.String(), http.StatusBadRequest) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-07-20 09:50:49 -05:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "Invalid alertmanager choice specified", res["message"])
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Let's try to send all the alerts to an external Alertmanager
|
|
|
|
// but never specify any. This should return an error.
|
|
|
|
{
|
|
|
|
ac := apimodels.PostableNGalertConfig{
|
|
|
|
AlertmanagersChoice: apimodels.AlertmanagersChoice(ngmodels.ExternalAlertmanagers.String()),
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&ac)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, alertsURL, buf.String(), http.StatusBadRequest) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-07-20 09:50:49 -05:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "At least one Alertmanager must be provided or configured as a datasource that handles alerts to choose this option", res["message"])
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
}
|
|
|
|
|
2022-11-10 09:34:13 -06:00
|
|
|
// Add an alertmanager datasource
|
|
|
|
{
|
|
|
|
cmd := datasources.AddDataSourceCommand{
|
2023-02-02 10:22:43 -06:00
|
|
|
OrgID: 1,
|
2022-11-10 09:34:13 -06:00
|
|
|
Name: "AM1",
|
|
|
|
Type: datasources.DS_ALERTMANAGER,
|
|
|
|
Access: "proxy",
|
2023-02-02 10:22:43 -06:00
|
|
|
URL: fakeAM1.URL(),
|
2023-08-30 10:46:47 -05:00
|
|
|
JsonData: simplejson.NewFromAny(map[string]any{
|
2022-11-10 09:34:13 -06:00
|
|
|
"handleGrafanaManagedAlerts": true,
|
|
|
|
"implementation": "prometheus",
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&cmd)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dataSourcesUrl := fmt.Sprintf("http://grafana:password@%s/api/datasources", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, dataSourcesUrl, buf.String(), http.StatusOK) // nolint
|
|
|
|
b, err := io.ReadAll(resp.Body)
|
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-11-10 09:34:13 -06:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "Datasource added", res["message"])
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add another alertmanager datasource
|
|
|
|
{
|
|
|
|
cmd := datasources.AddDataSourceCommand{
|
2023-02-02 10:22:43 -06:00
|
|
|
OrgID: 1,
|
2022-11-10 09:34:13 -06:00
|
|
|
Name: "AM2",
|
|
|
|
Type: datasources.DS_ALERTMANAGER,
|
|
|
|
Access: "proxy",
|
2023-02-02 10:22:43 -06:00
|
|
|
URL: fakeAM2.URL(),
|
2023-08-30 10:46:47 -05:00
|
|
|
JsonData: simplejson.NewFromAny(map[string]any{
|
2022-11-10 09:34:13 -06:00
|
|
|
"handleGrafanaManagedAlerts": true,
|
|
|
|
"implementation": "prometheus",
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&cmd)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dataSourcesUrl := fmt.Sprintf("http://grafana:password@%s/api/datasources", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, dataSourcesUrl, buf.String(), http.StatusOK) // nolint
|
|
|
|
b, err := io.ReadAll(resp.Body)
|
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-11-10 09:34:13 -06:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "Datasource added", res["message"])
|
|
|
|
}
|
|
|
|
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
// Now, lets re-set external Alertmanagers for main organisation
|
|
|
|
// and make it so that only the external Alertmanagers handle the alerts.
|
|
|
|
{
|
|
|
|
ac := apimodels.PostableNGalertConfig{
|
|
|
|
AlertmanagersChoice: apimodels.AlertmanagersChoice(ngmodels.ExternalAlertmanagers.String()),
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&ac)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, alertsURL, buf.String(), http.StatusCreated) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-08-13 07:14:36 -05:00
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-07-20 09:50:49 -05:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "admin configuration updated", res["message"])
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we get the configuration again, it shows us what we've set.
|
|
|
|
{
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-08-13 07:14:36 -05:00
|
|
|
require.NoError(t, err)
|
2022-11-10 09:34:13 -06:00
|
|
|
require.JSONEq(t, fmt.Sprintf("{\"alertmanagersChoice\": %q}\n", ngmodels.ExternalAlertmanagers), string(b))
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
|
|
|
|
2021-09-29 09:16:40 -05:00
|
|
|
// With the configuration set, we should eventually discover those Alertmanagers.
|
2021-08-13 07:14:36 -05:00
|
|
|
{
|
|
|
|
alertsURL := fmt.Sprintf("http://grafana:password@%s/api/v1/ngalert/alertmanagers", grafanaListedAddr)
|
|
|
|
require.Eventually(t, func() bool {
|
|
|
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-08-13 07:14:36 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var alertmanagers apimodels.GettableAlertmanagers
|
|
|
|
require.NoError(t, json.Unmarshal(b, &alertmanagers))
|
|
|
|
|
|
|
|
return len(alertmanagers.Data.Active) == 2
|
2021-09-29 09:16:40 -05:00
|
|
|
}, 16*time.Second, 8*time.Second) // the sync interval is 2s so after 8s all alertmanagers most probably are started
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Now, let's set an alert that should fire as quickly as possible.
|
|
|
|
{
|
2022-05-16 05:45:41 -05:00
|
|
|
// Create the namespace we'll save our alerts to
|
2022-06-21 10:39:22 -05:00
|
|
|
apiClient.CreateFolder(t, "default", "default")
|
2021-08-13 07:14:36 -05:00
|
|
|
interval, err := model.ParseDuration("10s")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
rules := apimodels.PostableRuleGroupConfig{
|
|
|
|
Name: "arulegroup",
|
|
|
|
Interval: interval,
|
|
|
|
Rules: []apimodels.PostableExtendedRuleNode{
|
|
|
|
{
|
|
|
|
ApiRuleNode: &apimodels.ApiRuleNode{
|
2022-06-30 10:46:26 -05:00
|
|
|
For: &interval,
|
2021-08-13 07:14:36 -05:00
|
|
|
Labels: map[string]string{"label1": "val1"},
|
|
|
|
Annotations: map[string]string{"annotation1": "val1"},
|
|
|
|
},
|
|
|
|
// this rule does not explicitly set no data and error states
|
|
|
|
// therefore it should get the default values
|
|
|
|
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
|
|
|
|
Title: "AlwaysFiring",
|
|
|
|
Condition: "A",
|
2023-03-27 10:55:13 -05:00
|
|
|
Data: []apimodels.AlertQuery{
|
2021-08-13 07:14:36 -05:00
|
|
|
{
|
|
|
|
RefID: "A",
|
2023-03-27 10:55:13 -05:00
|
|
|
RelativeTimeRange: apimodels.RelativeTimeRange{
|
|
|
|
From: apimodels.Duration(time.Duration(5) * time.Hour),
|
|
|
|
To: apimodels.Duration(time.Duration(3) * time.Hour),
|
2021-08-13 07:14:36 -05:00
|
|
|
},
|
2023-01-31 11:50:10 -06:00
|
|
|
DatasourceUID: expr.DatasourceUID,
|
2021-08-13 07:14:36 -05:00
|
|
|
Model: json.RawMessage(`{
|
|
|
|
"type": "math",
|
|
|
|
"expression": "2 + 3 > 1"
|
|
|
|
}`),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err = enc.Encode(&rules)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ruleURL := fmt.Sprintf("http://grafana:password@%s/api/ruler/grafana/api/v1/rules/default", grafanaListedAddr)
|
|
|
|
// nolint
|
|
|
|
_ = postRequest(t, ruleURL, buf.String(), http.StatusAccepted)
|
|
|
|
}
|
|
|
|
|
2023-01-31 11:50:10 -06:00
|
|
|
// Eventually, our Alertmanagers should receiver the alert.
|
2021-08-13 07:14:36 -05:00
|
|
|
{
|
|
|
|
require.Eventually(t, func() bool {
|
|
|
|
return fakeAM1.AlertsCount() == 1 && fakeAM2.AlertsCount() == 1
|
2022-11-22 01:09:15 -06:00
|
|
|
}, time.Minute, 5*time.Second)
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
2021-09-29 09:16:40 -05:00
|
|
|
|
2022-11-10 09:34:13 -06:00
|
|
|
// Add an alertmanager datasource fot the other organisation
|
|
|
|
{
|
|
|
|
cmd := datasources.AddDataSourceCommand{
|
2023-02-02 10:22:43 -06:00
|
|
|
OrgID: 2,
|
2022-11-10 09:34:13 -06:00
|
|
|
Name: "AM3",
|
|
|
|
Type: datasources.DS_ALERTMANAGER,
|
|
|
|
Access: "proxy",
|
2023-02-02 10:22:43 -06:00
|
|
|
URL: fakeAM3.URL(),
|
2023-08-30 10:46:47 -05:00
|
|
|
JsonData: simplejson.NewFromAny(map[string]any{
|
2022-11-10 09:34:13 -06:00
|
|
|
"handleGrafanaManagedAlerts": true,
|
|
|
|
"implementation": "prometheus",
|
|
|
|
}),
|
|
|
|
}
|
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&cmd)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dataSourcesUrl := fmt.Sprintf("http://admin-42:admin-42@%s/api/datasources", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, dataSourcesUrl, buf.String(), http.StatusOK) // nolint
|
|
|
|
b, err := io.ReadAll(resp.Body)
|
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-11-10 09:34:13 -06:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "Datasource added", res["message"])
|
|
|
|
}
|
|
|
|
|
2021-09-29 09:16:40 -05:00
|
|
|
// Now, lets re-set external Alertmanagers for the other organisation.
|
Alerting: send alerts to external, internal, or both alertmanagers (#40341)
* (WIP) send alerts to external, internal, or both alertmanagers
* Modify admin configuration endpoint, update swagger docs
* Integration test for admin config updated
* Code review changes
* Fix alertmanagers choice not changing bug, add unit test
* Add AlertmanagersChoice as enum in swagger, code review changes
* Fix API and tests errors
* Change enum from int to string, use 'SendAlertsTo' instead of 'AlertmanagerChoice' where necessary
* Fix tests to reflect last changes
* Keep senders running when alerts are handled just internally
* Check if any external AM has been discovered before sending alerts, update tests
* remove duplicate data from logs
* update comment
* represent alertmanagers choice as an int instead of a string
* default alertmanagers choice to all alertmanagers, test cases
* update definitions and generate spec
2022-02-01 17:36:55 -06:00
|
|
|
// Sending an empty value for AlertmanagersChoice should default to AllAlertmanagers.
|
2021-09-29 09:16:40 -05:00
|
|
|
{
|
2022-11-10 09:34:13 -06:00
|
|
|
ac := apimodels.PostableNGalertConfig{}
|
2021-09-29 09:16:40 -05:00
|
|
|
buf := bytes.Buffer{}
|
|
|
|
enc := json.NewEncoder(&buf)
|
|
|
|
err := enc.Encode(&ac)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
alertsURL := fmt.Sprintf("http://admin-42:admin-42@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := postRequest(t, alertsURL, buf.String(), http.StatusCreated) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-09-29 09:16:40 -05:00
|
|
|
require.NoError(t, err)
|
2023-08-30 10:46:47 -05:00
|
|
|
var res map[string]any
|
2022-07-20 09:50:49 -05:00
|
|
|
err = json.Unmarshal(b, &res)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, "admin configuration updated", res["message"])
|
2021-09-29 09:16:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we get the configuration again, it shows us what we've set.
|
|
|
|
{
|
|
|
|
alertsURL := fmt.Sprintf("http://admin-42:admin-42@%s/api/v1/ngalert/admin_config", grafanaListedAddr)
|
|
|
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-09-29 09:16:40 -05:00
|
|
|
require.NoError(t, err)
|
2022-11-10 09:34:13 -06:00
|
|
|
require.JSONEq(t, fmt.Sprintf("{\"alertmanagersChoice\": %q}\n", ngmodels.AllAlertmanagers), string(b))
|
2021-09-29 09:16:40 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// With the configuration set, we should eventually not discover Alertmanagers.
|
|
|
|
{
|
|
|
|
alertsURL := fmt.Sprintf("http://admin-42:admin-42@%s/api/v1/ngalert/alertmanagers", grafanaListedAddr)
|
|
|
|
require.Eventually(t, func() bool {
|
|
|
|
resp := getRequest(t, alertsURL, http.StatusOK) // nolint
|
2022-08-10 08:37:51 -05:00
|
|
|
b, err := io.ReadAll(resp.Body)
|
2021-09-29 09:16:40 -05:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
var alertmanagers apimodels.GettableAlertmanagers
|
|
|
|
require.NoError(t, json.Unmarshal(b, &alertmanagers))
|
|
|
|
|
|
|
|
return len(alertmanagers.Data.Active) == 0
|
|
|
|
}, 16*time.Second, 8*time.Second) // the sync interval is 2s so after 8s all alertmanagers (if any) most probably are started
|
|
|
|
}
|
2021-08-13 07:14:36 -05:00
|
|
|
}
|
2024-02-01 08:53:15 -06:00
|
|
|
|
|
|
|
func TestIntegrationAdminConfiguration_CannotCreateInhibitionRules(t *testing.T) {
|
|
|
|
testinfra.SQLiteIntegrationTest(t)
|
|
|
|
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
|
|
|
|
DisableLegacyAlerting: true,
|
|
|
|
EnableUnifiedAlerting: true,
|
|
|
|
AppModeProduction: true,
|
|
|
|
})
|
2024-04-04 08:04:47 -05:00
|
|
|
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, path)
|
|
|
|
createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
|
2024-02-01 08:53:15 -06:00
|
|
|
DefaultOrgRole: string(org.RoleAdmin),
|
|
|
|
Password: "admin",
|
|
|
|
Login: "admin",
|
|
|
|
})
|
|
|
|
client := newAlertingApiClient(grafanaListedAddr, "admin", "admin")
|
|
|
|
|
|
|
|
cfg := apimodels.PostableUserConfig{
|
|
|
|
AlertmanagerConfig: apimodels.PostableApiAlertingConfig{
|
|
|
|
Config: apimodels.Config{
|
|
|
|
Route: &apimodels.Route{
|
|
|
|
Receiver: "test",
|
|
|
|
},
|
|
|
|
InhibitRules: []config.InhibitRule{{
|
|
|
|
SourceMatchers: config.Matchers{{
|
|
|
|
Type: labels.MatchEqual,
|
|
|
|
Name: "foo",
|
|
|
|
Value: "bar",
|
|
|
|
}},
|
|
|
|
TargetMatchers: config.Matchers{{
|
|
|
|
Type: labels.MatchEqual,
|
|
|
|
Name: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
}},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
Receivers: []*apimodels.PostableApiReceiver{{
|
|
|
|
Receiver: config.Receiver{
|
|
|
|
Name: "test",
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
ok, err := client.PostConfiguration(t, cfg)
|
|
|
|
require.False(t, ok)
|
|
|
|
require.EqualError(t, err, "inhibition rules are not supported")
|
|
|
|
}
|