From 62e39cf19765c8ee5089e2ee891a2120d45a5a2f Mon Sep 17 00:00:00 2001 From: Samir Faci Date: Thu, 12 Sep 2024 10:18:30 -0400 Subject: [PATCH] Add Contact Points --- cli/backup/alerting.go | 34 +++ cli/backup/alerting_contacts.go | 148 ++++++++++++ cli/backup/backup.go | 1 + go.mod | 4 +- go.sum | 4 + internal/config/resource_type.go | 2 + internal/service/alerting.go | 133 +++++++++++ internal/service/contracts.go | 8 + internal/service/mocks/GrafanaService.go | 216 ++++++++++++++++++ internal/service/mocks/Storage.go | 45 ++++ test/data/org_main-org/alerting/contacts.json | 35 +++ 11 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 cli/backup/alerting.go create mode 100644 cli/backup/alerting_contacts.go create mode 100644 internal/service/alerting.go create mode 100644 test/data/org_main-org/alerting/contacts.json diff --git a/cli/backup/alerting.go b/cli/backup/alerting.go new file mode 100644 index 00000000..1f4b54fd --- /dev/null +++ b/cli/backup/alerting.go @@ -0,0 +1,34 @@ +package backup + +import ( + "context" + + "github.com/bep/simplecobra" + "github.com/esnet/gdg/cli/support" + "github.com/spf13/cobra" +) + +func newAlertingCommand() simplecobra.Commander { + description := "Manage Alerting resources" + return &support.SimpleCommand{ + NameP: "alerting", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"alert"} + // connections := cmd + // connections.PersistentFlags().StringP("connection", "", "", "filter by connection slug") + }, + CommandsList: []simplecobra.Commander{ + newAlertingContactCommand(), + // newClearConnectionsCmd(), + // newUploadConnectionsCmd(), + // newDownloadConnectionsCmd(), + // newListConnectionsCmd(), + // newConnectionsPermissionCmd(), + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + return cd.CobraCommand.Help() + }, + } +} diff --git a/cli/backup/alerting_contacts.go b/cli/backup/alerting_contacts.go new file mode 100644 index 00000000..aba9c93f --- /dev/null +++ b/cli/backup/alerting_contacts.go @@ -0,0 +1,148 @@ +package backup + +import ( + "context" + "encoding/json" + "log/slog" + + "github.com/bep/simplecobra" + "github.com/esnet/gdg/cli/support" + "github.com/esnet/gdg/internal/service" + "github.com/jedib0t/go-pretty/v6/table" + "github.com/spf13/cobra" +) + +func newAlertingContactCommand() simplecobra.Commander { + description := "Manage Alerting ContactPoints " + return &support.SimpleCommand{ + NameP: "contactpoint", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"contact", "contacts", "contactpoints"} + }, + CommandsList: []simplecobra.Commander{ + newListContactPointsCmd(), + newClearContactPointsCmd(), + newUploadContactPointsCmd(), + newDownloadContactPointsCmd(), + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + return cd.CobraCommand.Help() + }, + } +} + +func newListContactPointsCmd() simplecobra.Commander { + description := "List all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "list", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"l"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + rootCmd.TableObj.AppendHeader(table.Row{"uid", "name", "slug", "type", "provenance", "settings"}) + contactPoints := rootCmd.GrafanaSvc().ListContactPoints() + slog.Info("Listing contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + if len(contactPoints) == 0 { + slog.Info("No contact points found") + } else { + for _, link := range contactPoints { + rawBytes, err := json.Marshal(link.Settings) + if err != nil { + slog.Warn("unable to marshall settings to valid JSON") + } + rootCmd.TableObj.AppendRow(table.Row{link.UID, link.Name, service.GetSlug(link.Name), link.Type, link.Provenance, string(rawBytes)}) + } + rootCmd.Render(cd.CobraCommand, contactPoints) + } + return nil + }, + } +} + +func newDownloadContactPointsCmd() simplecobra.Commander { + description := "Download all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "download", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"d"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + file, err := rootCmd.GrafanaSvc().DownloadContactPoints() + slog.Info("Download contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + if err != nil { + slog.Error("unable to contact point") + } else { + slog.Info("contact points successfully downloaded", slog.Any("file", file)) + } + return nil + }, + } +} + +func newUploadContactPointsCmd() simplecobra.Commander { + description := "Upload all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "upload", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"u"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + removedItems, err := rootCmd.GrafanaSvc().UploadContactPoints() + slog.Info("Upload contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + if err != nil { + slog.Error("unable to upload contact points", slog.Any("err", err)) + } else { + slog.Info("contact points successfully uploaded") + rootCmd.TableObj.AppendHeader(table.Row{"name"}) + for _, item := range removedItems { + rootCmd.TableObj.AppendRow(table.Row{item}) + } + + rootCmd.Render(cd.CobraCommand, removedItems) + } + return nil + }, + } +} + +func newClearContactPointsCmd() simplecobra.Commander { + description := "Clear all contact points for the given Organization" + return &support.SimpleCommand{ + NameP: "clear", + Short: description, + Long: description, + WithCFunc: func(cmd *cobra.Command, r *support.RootCommand) { + cmd.Aliases = []string{"l"} + }, + RunFunc: func(ctx context.Context, cd *simplecobra.Commandeer, rootCmd *support.RootCommand, args []string) error { + removedItems, err := rootCmd.GrafanaSvc().ClearContactPoints() + slog.Info("Clear contact points for context", + slog.String("Organization", GetOrganizationName()), + slog.String("context", GetContext())) + if err != nil { + slog.Error("unable to contact point") + } else { + slog.Info("contact points successfully removed") + rootCmd.TableObj.AppendHeader(table.Row{"name"}) + for _, item := range removedItems { + rootCmd.TableObj.AppendRow(table.Row{item}) + } + } + return nil + }, + } +} diff --git a/cli/backup/backup.go b/cli/backup/backup.go index 8d1caf3d..bb5c7332 100644 --- a/cli/backup/backup.go +++ b/cli/backup/backup.go @@ -35,6 +35,7 @@ limited to clear/delete, list, download and upload. Any other functionality wil newOrganizationsCommand(), newTeamsCommand(), newUsersCommand(), + newAlertingCommand(), }, } } diff --git a/go.mod b/go.mod index 73d13f19..b9be3f8a 100644 --- a/go.mod +++ b/go.mod @@ -173,8 +173,8 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.16.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect go.opentelemetry.io/otel v1.30.0 // indirect go.opentelemetry.io/otel/metric v1.30.0 // indirect go.opentelemetry.io/otel/trace v1.30.0 // indirect diff --git a/go.sum b/go.sum index 0ca61cea..dc9e2d65 100644 --- a/go.sum +++ b/go.sum @@ -475,8 +475,12 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0 h1:r6I7RJCN86bpD/FQwedZ0vSixDpwuWREjW9oRMsmqDc= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.54.0/go.mod h1:B9yO6b04uB80CzjedvewuqDhxJxi11s7/GtiGa8bAjI= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0 h1:hCq2hNMwsegUvPzI7sPOvtO9cqyy5GbWt/Ybp2xrx8Q= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.55.0/go.mod h1:LqaApwGx/oUmzsbqxkzuBvyoPpkxk3JQWnqfVrJ3wCA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel v1.30.0 h1:F2t8sK4qf1fAmY9ua4ohFS/K+FUuOPemHUIXHtktrts= diff --git a/internal/config/resource_type.go b/internal/config/resource_type.go index 1489721c..b8a90e54 100644 --- a/internal/config/resource_type.go +++ b/internal/config/resource_type.go @@ -22,6 +22,7 @@ const ( UserResource ResourceType = "users" TemplatesResource ResourceType = "templates" SecureSecretsResource ResourceType = "secure" + AlertingResource ResourceType = "alerting" ) var orgNamespacedResource = map[ResourceType]bool{ @@ -32,6 +33,7 @@ var orgNamespacedResource = map[ResourceType]bool{ FolderResource: true, LibraryElementResource: true, TeamResource: true, + AlertingResource: true, } // isNamespaced returns true if the resource type is namespaced diff --git a/internal/service/alerting.go b/internal/service/alerting.go new file mode 100644 index 00000000..b7d19aa4 --- /dev/null +++ b/internal/service/alerting.go @@ -0,0 +1,133 @@ +package service + +import ( + "encoding/json" + "fmt" + "log" + "log/slog" + + "github.com/esnet/gdg/internal/config" + "github.com/esnet/gdg/internal/tools" + "github.com/grafana/grafana-openapi-client-go/client/provisioning" + "github.com/grafana/grafana-openapi-client-go/models" +) + +func (s *DashNGoImpl) ListContactPoints() []*models.EmbeddedContactPoint { + p := provisioning.NewGetContactpointsParams() + result, err := s.GetClient().Provisioning.GetContactpoints(p) + if err != nil { + log.Fatalf("unable to retrieve contact points, err:%s", err.Error()) + } + return result.GetPayload() +} + +func (s *DashNGoImpl) DownloadContactPoints() (string, error) { + var ( + dsPacked []byte + err error + ) + p := provisioning.NewGetContactpointsExportParams() + p.Download = tools.PtrOf(true) + p.Decrypt = tools.PtrOf(true) + p.Format = tools.PtrOf("json") + data, err := s.GetClient().Provisioning.GetContactpointsExport(p) + if err != nil { + log.Fatalf("unable to retrieve Contact Points, err: %s", err.Error()) + } + + dsPath := buildResourcePath("contacts", config.AlertingResource) + if dsPacked, err = json.MarshalIndent(data.GetPayload(), "", " "); err != nil { + return "", fmt.Errorf("unable to serialize data to JSON. %w", err) + } + if err = s.storage.WriteFile(dsPath, dsPacked); err != nil { + return "", fmt.Errorf("unable to write file. %w", err) + } + + return dsPath, nil +} + +func (s *DashNGoImpl) UploadContactPoints() ([]string, error) { + var ( + err error + rawDS []byte + result []string + ) + data := new(models.AlertingFileExport) + currentContacts := s.ListContactPoints() + m := make(map[string]*models.EmbeddedContactPoint) + for ndx, i := range currentContacts { + m[i.UID] = currentContacts[ndx] + } + + fileLocation := buildResourcePath("contacts", config.AlertingResource) + if rawDS, err = s.storage.ReadFile(fileLocation); err != nil { + return nil, fmt.Errorf("failed to read file. file: %s, err: %w", fileLocation, err) + } + if err = json.Unmarshal(rawDS, data); err != nil { + return nil, fmt.Errorf("failed to unmarshall file, file:%s, err: %w", fileLocation, err) + } + for _, i := range data.ContactPoints { + for _, r := range i.Receivers { + if _, ok := m[r.UID]; ok { + // do update + p := provisioning.NewPutContactpointParams() + p.UID = r.UID + p.Body = &models.EmbeddedContactPoint{ + DisableResolveMessage: false, + Name: i.Name, + Provenance: "", + Settings: r.Settings, + Type: tools.PtrOf(r.Type), + UID: r.UID, + } + _, err := s.GetClient().Provisioning.PutContactpoint(p) + if err != nil { + slog.Error("failed to update contact point", slog.Any("uid", r.UID)) + continue + } + result = append(result, i.Name) + + } else { + p := provisioning.NewPostContactpointsParams() + p.Body = &models.EmbeddedContactPoint{ + DisableResolveMessage: false, + Name: i.Name, + UID: r.UID, + Provenance: "", + Settings: r.Settings, + Type: tools.PtrOf(r.Type), + } + _, err := s.GetClient().Provisioning.PostContactpoints(p) + if err != nil { + slog.Error("failed to create contact point", slog.Any("uid", r.UID)) + continue + } + + result = append(result, i.Name) + } + } + } + + return result, nil +} + +func (s *DashNGoImpl) ClearContactPoints() ([]string, error) { + var ( + err error + results []string + ) + contacts := s.ListContactPoints() + for _, contact := range contacts { + _, err = s.GetClient().Provisioning.DeleteContactpoints(contact.UID) + if err != nil { + slog.Error("unable to delete contact point", + slog.Any("name", contact.Name), + slog.Any("uid", contact.UID), + ) + continue + } + results = append(results, contact.Name) + } + + return results, nil +} diff --git a/internal/service/contracts.go b/internal/service/contracts.go index 86dc79b8..8590103b 100644 --- a/internal/service/contracts.go +++ b/internal/service/contracts.go @@ -20,6 +20,7 @@ type GrafanaService interface { FoldersApi LibraryElementsApi TeamsApi + AlertingApi AuthenticationApi // MetaData @@ -57,6 +58,13 @@ type DashboardsApi interface { LintDashboards(req types.LintRequest) []string } +type AlertingApi interface { + ListContactPoints() []*models.EmbeddedContactPoint + DownloadContactPoints() (string, error) + ClearContactPoints() ([]string, error) + UploadContactPoints() ([]string, error) +} + // FoldersApi Contract definition type FoldersApi interface { ListFolders(filter filters.Filter) []*customModels.FolderDetails diff --git a/internal/service/mocks/GrafanaService.go b/internal/service/mocks/GrafanaService.go index f88154bd..d778cd57 100644 --- a/internal/service/mocks/GrafanaService.go +++ b/internal/service/mocks/GrafanaService.go @@ -74,6 +74,63 @@ func (_c *GrafanaService_AddUserToOrg_Call) RunAndReturn(run func(string, string return _c } +// ClearContactPoints provides a mock function with given fields: +func (_m *GrafanaService) ClearContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ClearContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_ClearContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ClearContactPoints' +type GrafanaService_ClearContactPoints_Call struct { + *mock.Call +} + +// ClearContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) ClearContactPoints() *GrafanaService_ClearContactPoints_Call { + return &GrafanaService_ClearContactPoints_Call{Call: _e.mock.On("ClearContactPoints")} +} + +func (_c *GrafanaService_ClearContactPoints_Call) Run(run func()) *GrafanaService_ClearContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_ClearContactPoints_Call) Return(_a0 []string, _a1 error) *GrafanaService_ClearContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_ClearContactPoints_Call) RunAndReturn(run func() ([]string, error)) *GrafanaService_ClearContactPoints_Call { + _c.Call.Return(run) + return _c +} + // CreateAPIKey provides a mock function with given fields: name, role, expiration func (_m *GrafanaService) CreateAPIKey(name string, role string, expiration int64) (*models.NewAPIKeyResult, error) { ret := _m.Called(name, role, expiration) @@ -885,6 +942,61 @@ func (_c *GrafanaService_DownloadConnections_Call) RunAndReturn(run func(filters return _c } +// DownloadContactPoints provides a mock function with given fields: +func (_m *GrafanaService) DownloadContactPoints() (string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for DownloadContactPoints") + } + + var r0 string + var r1 error + if rf, ok := ret.Get(0).(func() (string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_DownloadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'DownloadContactPoints' +type GrafanaService_DownloadContactPoints_Call struct { + *mock.Call +} + +// DownloadContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) DownloadContactPoints() *GrafanaService_DownloadContactPoints_Call { + return &GrafanaService_DownloadContactPoints_Call{Call: _e.mock.On("DownloadContactPoints")} +} + +func (_c *GrafanaService_DownloadContactPoints_Call) Run(run func()) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_DownloadContactPoints_Call) Return(_a0 string, _a1 error) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_DownloadContactPoints_Call) RunAndReturn(run func() (string, error)) *GrafanaService_DownloadContactPoints_Call { + _c.Call.Return(run) + return _c +} + // DownloadDashboards provides a mock function with given fields: filter func (_m *GrafanaService) DownloadDashboards(filter filters.Filter) []string { ret := _m.Called(filter) @@ -1745,6 +1857,53 @@ func (_c *GrafanaService_ListConnections_Call) RunAndReturn(run func(filters.Fil return _c } +// ListContactPoints provides a mock function with given fields: +func (_m *GrafanaService) ListContactPoints() []*models.EmbeddedContactPoint { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for ListContactPoints") + } + + var r0 []*models.EmbeddedContactPoint + if rf, ok := ret.Get(0).(func() []*models.EmbeddedContactPoint); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.EmbeddedContactPoint) + } + } + + return r0 +} + +// GrafanaService_ListContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'ListContactPoints' +type GrafanaService_ListContactPoints_Call struct { + *mock.Call +} + +// ListContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) ListContactPoints() *GrafanaService_ListContactPoints_Call { + return &GrafanaService_ListContactPoints_Call{Call: _e.mock.On("ListContactPoints")} +} + +func (_c *GrafanaService_ListContactPoints_Call) Run(run func()) *GrafanaService_ListContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_ListContactPoints_Call) Return(_a0 []*models.EmbeddedContactPoint) *GrafanaService_ListContactPoints_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *GrafanaService_ListContactPoints_Call) RunAndReturn(run func() []*models.EmbeddedContactPoint) *GrafanaService_ListContactPoints_Call { + _c.Call.Return(run) + return _c +} + // ListDashboards provides a mock function with given fields: filter func (_m *GrafanaService) ListDashboards(filter filters.Filter) []*models.Hit { ret := _m.Called(filter) @@ -2666,6 +2825,63 @@ func (_c *GrafanaService_UploadConnections_Call) RunAndReturn(run func(filters.F return _c } +// UploadContactPoints provides a mock function with given fields: +func (_m *GrafanaService) UploadContactPoints() ([]string, error) { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for UploadContactPoints") + } + + var r0 []string + var r1 error + if rf, ok := ret.Get(0).(func() ([]string, error)); ok { + return rf() + } + if rf, ok := ret.Get(0).(func() []string); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]string) + } + } + + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// GrafanaService_UploadContactPoints_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'UploadContactPoints' +type GrafanaService_UploadContactPoints_Call struct { + *mock.Call +} + +// UploadContactPoints is a helper method to define mock.On call +func (_e *GrafanaService_Expecter) UploadContactPoints() *GrafanaService_UploadContactPoints_Call { + return &GrafanaService_UploadContactPoints_Call{Call: _e.mock.On("UploadContactPoints")} +} + +func (_c *GrafanaService_UploadContactPoints_Call) Run(run func()) *GrafanaService_UploadContactPoints_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *GrafanaService_UploadContactPoints_Call) Return(_a0 []string, _a1 error) *GrafanaService_UploadContactPoints_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *GrafanaService_UploadContactPoints_Call) RunAndReturn(run func() ([]string, error)) *GrafanaService_UploadContactPoints_Call { + _c.Call.Return(run) + return _c +} + // UploadDashboards provides a mock function with given fields: filter func (_m *GrafanaService) UploadDashboards(filter filters.Filter) { _m.Called(filter) diff --git a/internal/service/mocks/Storage.go b/internal/service/mocks/Storage.go index 920d189c..ee524f0b 100644 --- a/internal/service/mocks/Storage.go +++ b/internal/service/mocks/Storage.go @@ -76,6 +76,51 @@ func (_c *Storage_FindAllFiles_Call) RunAndReturn(run func(string, bool) ([]stri return _c } +// GetPrefix provides a mock function with given fields: +func (_m *Storage) GetPrefix() string { + ret := _m.Called() + + if len(ret) == 0 { + panic("no return value specified for GetPrefix") + } + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// Storage_GetPrefix_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetPrefix' +type Storage_GetPrefix_Call struct { + *mock.Call +} + +// GetPrefix is a helper method to define mock.On call +func (_e *Storage_Expecter) GetPrefix() *Storage_GetPrefix_Call { + return &Storage_GetPrefix_Call{Call: _e.mock.On("GetPrefix")} +} + +func (_c *Storage_GetPrefix_Call) Run(run func()) *Storage_GetPrefix_Call { + _c.Call.Run(func(args mock.Arguments) { + run() + }) + return _c +} + +func (_c *Storage_GetPrefix_Call) Return(_a0 string) *Storage_GetPrefix_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *Storage_GetPrefix_Call) RunAndReturn(run func() string) *Storage_GetPrefix_Call { + _c.Call.Return(run) + return _c +} + // Name provides a mock function with given fields: func (_m *Storage) Name() string { ret := _m.Called() diff --git a/test/data/org_main-org/alerting/contacts.json b/test/data/org_main-org/alerting/contacts.json new file mode 100644 index 00000000..b550af41 --- /dev/null +++ b/test/data/org_main-org/alerting/contacts.json @@ -0,0 +1,35 @@ +{ + "apiVersion": 1, + "contactPoints": [ + { + "name": "discord", + "orgId": 4, + "receivers": [ + { + "settings": { + "url": "https://www.discord.com?q=woot", + "use_discord_username": false + }, + "type": "discord", + "uid": "fdxmqkyb5gl4xb" + } + ] + }, + { + "name": "email receiver", + "orgId": 4, + "receivers": [ + { + "settings": { + "addresses": "\u003cexample@email.com\u003e" + }, + "type": "email", + "uid": "edxmyx0pdyo74a" + } + ] + } + ], + "groups": null, + "muteTimes": null, + "policies": null +}