mirror of https://github.com/grafana/grafana
Alerting: Provisioning GET routes for mute timings (#49044)
* Define GET routes and run codegen * Wire up forked and non-generated API * Implement and wire * Tests, authorization * Fix linter errorpull/49116/head
parent
7bdf76a694
commit
9af30f6570
@ -0,0 +1,23 @@ |
||||
package definitions |
||||
|
||||
import prometheus "github.com/prometheus/alertmanager/config" |
||||
|
||||
// swagger:route GET /api/provisioning/mute-timings provisioning RouteGetMuteTimings
|
||||
//
|
||||
// Get all the mute timings.
|
||||
//
|
||||
// Responses:
|
||||
// 200: []MuteTiming
|
||||
// 400: ValidationError
|
||||
|
||||
// swagger:route GET /api/provisioning/mute-timings/{name} provisioning RouteGetMuteTiming
|
||||
//
|
||||
// Get a mute timing.
|
||||
//
|
||||
// Responses:
|
||||
// 200: MuteTiming
|
||||
// 400: ValidationError
|
||||
|
||||
type MuteTiming struct { |
||||
prometheus.MuteTimeInterval |
||||
} |
||||
@ -0,0 +1,51 @@ |
||||
package provisioning |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/models" |
||||
) |
||||
|
||||
type MuteTimingService struct { |
||||
config AMConfigStore |
||||
prov ProvisioningStore |
||||
xact TransactionManager |
||||
log log.Logger |
||||
} |
||||
|
||||
func NewMuteTimingService(config AMConfigStore, prov ProvisioningStore, xact TransactionManager, log log.Logger) *MuteTimingService { |
||||
return &MuteTimingService{ |
||||
config: config, |
||||
prov: prov, |
||||
xact: xact, |
||||
log: log, |
||||
} |
||||
} |
||||
|
||||
func (m *MuteTimingService) GetMuteTimings(ctx context.Context, orgID int64) ([]definitions.MuteTiming, error) { |
||||
q := models.GetLatestAlertmanagerConfigurationQuery{ |
||||
OrgID: orgID, |
||||
} |
||||
err := m.config.GetLatestAlertmanagerConfiguration(ctx, &q) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if q.Result == nil { |
||||
return nil, fmt.Errorf("no alertmanager configuration present in this org") |
||||
} |
||||
|
||||
cfg, err := DeserializeAlertmanagerConfig([]byte(q.Result.AlertmanagerConfiguration)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
result := make([]definitions.MuteTiming, 0, len(cfg.AlertmanagerConfig.MuteTimeIntervals)) |
||||
for _, interval := range cfg.AlertmanagerConfig.MuteTimeIntervals { |
||||
result = append(result, definitions.MuteTiming{MuteTimeInterval: interval}) |
||||
} |
||||
return result, nil |
||||
} |
||||
@ -0,0 +1,118 @@ |
||||
package provisioning |
||||
|
||||
import ( |
||||
"context" |
||||
"fmt" |
||||
"testing" |
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
"github.com/grafana/grafana/pkg/services/ngalert/models" |
||||
mock "github.com/stretchr/testify/mock" |
||||
"github.com/stretchr/testify/require" |
||||
) |
||||
|
||||
func TestMuteTimingService(t *testing.T) { |
||||
t.Run("service returns timings from config file", func(t *testing.T) { |
||||
sut := createMuteTimingSvcSut() |
||||
sut.config.(*MockAMConfigStore).EXPECT(). |
||||
getsConfig(models.AlertConfiguration{ |
||||
AlertmanagerConfiguration: configWithMuteTimings, |
||||
}) |
||||
|
||||
result, err := sut.GetMuteTimings(context.Background(), 1) |
||||
|
||||
require.NoError(t, err) |
||||
require.Len(t, result, 1) |
||||
require.Equal(t, "asdf", result[0].Name) |
||||
}) |
||||
|
||||
t.Run("service returns empty map when config file contains no templates", func(t *testing.T) { |
||||
sut := createMuteTimingSvcSut() |
||||
sut.config.(*MockAMConfigStore).EXPECT(). |
||||
getsConfig(models.AlertConfiguration{ |
||||
AlertmanagerConfiguration: defaultConfig, |
||||
}) |
||||
|
||||
result, err := sut.GetMuteTimings(context.Background(), 1) |
||||
|
||||
require.NoError(t, err) |
||||
require.Empty(t, result) |
||||
}) |
||||
|
||||
t.Run("service propagates errors", func(t *testing.T) { |
||||
t.Run("when unable to read config", func(t *testing.T) { |
||||
sut := createMuteTimingSvcSut() |
||||
sut.config.(*MockAMConfigStore).EXPECT(). |
||||
GetLatestAlertmanagerConfiguration(mock.Anything, mock.Anything). |
||||
Return(fmt.Errorf("failed")) |
||||
|
||||
_, err := sut.GetMuteTimings(context.Background(), 1) |
||||
|
||||
require.Error(t, err) |
||||
}) |
||||
|
||||
t.Run("when config is invalid", func(t *testing.T) { |
||||
sut := createMuteTimingSvcSut() |
||||
sut.config.(*MockAMConfigStore).EXPECT(). |
||||
getsConfig(models.AlertConfiguration{ |
||||
AlertmanagerConfiguration: brokenConfig, |
||||
}) |
||||
|
||||
_, err := sut.GetMuteTimings(context.Background(), 1) |
||||
|
||||
require.ErrorContains(t, err, "failed to deserialize") |
||||
}) |
||||
|
||||
t.Run("when no AM config in current org", func(t *testing.T) { |
||||
sut := createMuteTimingSvcSut() |
||||
sut.config.(*MockAMConfigStore).EXPECT(). |
||||
GetLatestAlertmanagerConfiguration(mock.Anything, mock.Anything). |
||||
Return(nil) |
||||
|
||||
_, err := sut.GetMuteTimings(context.Background(), 1) |
||||
|
||||
require.ErrorContains(t, err, "no alertmanager configuration") |
||||
}) |
||||
}) |
||||
} |
||||
|
||||
func createMuteTimingSvcSut() *MuteTimingService { |
||||
return &MuteTimingService{ |
||||
config: &MockAMConfigStore{}, |
||||
prov: &MockProvisioningStore{}, |
||||
xact: newNopTransactionManager(), |
||||
log: log.NewNopLogger(), |
||||
} |
||||
} |
||||
|
||||
var configWithMuteTimings = ` |
||||
{ |
||||
"template_files": { |
||||
"a": "template" |
||||
}, |
||||
"alertmanager_config": { |
||||
"route": { |
||||
"receiver": "grafana-default-email" |
||||
}, |
||||
"mute_time_intervals": [{ |
||||
"name": "asdf", |
||||
"time_intervals": [{ |
||||
"times": [], |
||||
"weekdays": ["monday"] |
||||
}] |
||||
}], |
||||
"receivers": [{ |
||||
"name": "grafana-default-email", |
||||
"grafana_managed_receiver_configs": [{ |
||||
"uid": "", |
||||
"name": "email receiver", |
||||
"type": "email", |
||||
"isDefault": true, |
||||
"settings": { |
||||
"addresses": "<example@email.com>" |
||||
} |
||||
}] |
||||
}] |
||||
} |
||||
} |
||||
` |
||||
Loading…
Reference in new issue