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