Skip to content

Commit 7809a12

Browse files
Config Generation: Support for OnCall and Synthetic Monitoring (#1639)
* Config Generation: Add entrypoints for SM and OnCall (without cloud) This allows generation of the config of a single instance without going through the Cloud stuff Also, OnCall has no way to generate a token as of today, so it's required that we have a manual config for it * Simpler lister * oops. page++ * gen oncall and sm * Simpler lister
1 parent c8371ab commit 7809a12

13 files changed

+179
-19
lines changed

Diff for: cmd/generate/main.go

+31-3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,30 @@ This supports a glob format. Examples:
8282
Category: "Grafana",
8383
EnvVars: []string{"TFGEN_GRAFANA_AUTH"},
8484
},
85+
&cli.StringFlag{
86+
Name: "synthetic-monitoring-url",
87+
Usage: "URL of the Synthetic Monitoring instance to generate resources from",
88+
Category: "Grafana",
89+
EnvVars: []string{"TFGEN_SYNTHETIC_MONITORING_URL"},
90+
},
91+
&cli.StringFlag{
92+
Name: "synthetic-monitoring-access-token",
93+
Usage: "API token for the Synthetic Monitoring instance",
94+
Category: "Grafana",
95+
EnvVars: []string{"TFGEN_SYNTHETIC_MONITORING_ACCESS_TOKEN"},
96+
},
97+
&cli.StringFlag{
98+
Name: "oncall-url",
99+
Usage: "URL of the OnCall instance to generate resources from",
100+
Category: "Grafana",
101+
EnvVars: []string{"TFGEN_ONCALL_URL"},
102+
},
103+
&cli.StringFlag{
104+
Name: "oncall-access-token",
105+
Usage: "API token for the OnCall instance",
106+
Category: "Grafana",
107+
EnvVars: []string{"TFGEN_ONCALL_ACCESS_TOKEN"},
108+
},
85109

86110
// Grafana Cloud flags
87111
&cli.StringFlag{
@@ -132,8 +156,12 @@ func parseFlags(ctx *cli.Context) (*generate.Config, error) {
132156
Format: generate.OutputFormat(ctx.String("output-format")),
133157
ProviderVersion: ctx.String("terraform-provider-version"),
134158
Grafana: &generate.GrafanaConfig{
135-
URL: ctx.String("grafana-url"),
136-
Auth: ctx.String("grafana-auth"),
159+
URL: ctx.String("grafana-url"),
160+
Auth: ctx.String("grafana-auth"),
161+
SMURL: ctx.String("synthetic-monitoring-url"),
162+
SMAccessToken: ctx.String("synthetic-monitoring-access-token"),
163+
OnCallURL: ctx.String("oncall-url"),
164+
OnCallAccessToken: ctx.String("oncall-access-token"),
137165
},
138166
Cloud: &generate.CloudConfig{
139167
AccessPolicyToken: ctx.String("cloud-access-policy-token"),
@@ -152,7 +180,7 @@ func parseFlags(ctx *cli.Context) (*generate.Config, error) {
152180
err := newFlagValidations().
153181
atLeastOne("grafana-url", "cloud-access-policy-token").
154182
conflicting(
155-
[]string{"grafana-url", "grafana-auth"},
183+
[]string{"grafana-url", "grafana-auth", "synthetic-monitoring-url", "synthetic-monitoring-access-token", "oncall-url", "oncall-access-token"},
156184
[]string{"cloud-access-policy-token", "cloud-org", "cloud-create-stack-service-account", "cloud-stack-service-account-name"},
157185
).
158186
requiredWhenSet("grafana-url", "grafana-auth").

Diff for: internal/resources/oncall/common_lister.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package oncall
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
onCallAPI "github.com/grafana/amixr-api-go-client"
8+
"github.com/grafana/terraform-provider-grafana/v3/internal/common"
9+
)
10+
11+
type listerFunc func(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error)
12+
13+
// oncallListerFunction is a helper function that wraps a lister function be used more easily in oncall resources.
14+
func oncallListerFunction(listerFunc listerFunc) common.ResourceListIDsFunc {
15+
return func(ctx context.Context, client *common.Client, data any) ([]string, error) {
16+
if client.OnCallClient == nil {
17+
return nil, fmt.Errorf("client not configured for Grafana OnCall API")
18+
}
19+
ids := []string{}
20+
page := 1
21+
for {
22+
newIDs, nextPage, err := listerFunc(client.OnCallClient, onCallAPI.ListOptions{Page: page})
23+
if err != nil {
24+
return nil, err
25+
}
26+
ids = append(ids, newIDs...)
27+
if nextPage == nil {
28+
break
29+
}
30+
page++
31+
}
32+
return ids, nil
33+
}
34+
}

Diff for: internal/resources/oncall/resource_escalation.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,18 @@ func resourceEscalation() *common.Resource {
225225
"grafana_oncall_escalation",
226226
resourceID,
227227
schema,
228-
)
228+
).WithLister(oncallListerFunction(listEscalations))
229+
}
230+
231+
func listEscalations(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
232+
resp, _, err := client.Escalations.ListEscalations(&onCallAPI.ListEscalationOptions{ListOptions: listOptions})
233+
if err != nil {
234+
return nil, nil, err
235+
}
236+
for _, i := range resp.Escalations {
237+
ids = append(ids, i.ID)
238+
}
239+
return ids, resp.Next, nil
229240
}
230241

231242
func resourceEscalationCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: internal/resources/oncall/resource_escalation_chain.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,18 @@ func resourceEscalationChain() *common.Resource {
4343
"grafana_oncall_escalation_chain",
4444
resourceID,
4545
schema,
46-
)
46+
).WithLister(oncallListerFunction(listEscalationChains))
47+
}
48+
49+
func listEscalationChains(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
50+
resp, _, err := client.EscalationChains.ListEscalationChains(&onCallAPI.ListEscalationChainOptions{ListOptions: listOptions})
51+
if err != nil {
52+
return nil, nil, err
53+
}
54+
for _, i := range resp.EscalationChains {
55+
ids = append(ids, i.ID)
56+
}
57+
return ids, resp.Next, nil
4758
}
4859

4960
func resourceEscalationChainCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: internal/resources/oncall/resource_integration.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,18 @@ func resourceIntegration() *common.Resource {
240240
"grafana_oncall_integration",
241241
resourceID,
242242
schema,
243-
)
243+
).WithLister(oncallListerFunction(listIntegrations))
244+
}
245+
246+
func listIntegrations(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
247+
resp, _, err := client.Integrations.ListIntegrations(&onCallAPI.ListIntegrationOptions{ListOptions: listOptions})
248+
if err != nil {
249+
return nil, nil, err
250+
}
251+
for _, i := range resp.Integrations {
252+
ids = append(ids, i.ID)
253+
}
254+
return ids, resp.Next, nil
244255
}
245256

246257
func onCallTemplate(description string, hasMessage, hasImage bool) *schema.Schema {

Diff for: internal/resources/oncall/resource_outgoing_webhook.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,18 @@ func resourceOutgoingWebhook() *common.Resource {
108108
"grafana_oncall_outgoing_webhook",
109109
resourceID,
110110
schema,
111-
)
111+
).WithLister(oncallListerFunction(listWebhooks))
112+
}
113+
114+
func listWebhooks(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
115+
resp, _, err := client.Webhooks.ListWebhooks(&onCallAPI.ListWebhookOptions{ListOptions: listOptions})
116+
if err != nil {
117+
return nil, nil, err
118+
}
119+
for _, i := range resp.Webhooks {
120+
ids = append(ids, i.ID)
121+
}
122+
return ids, resp.Next, nil
112123
}
113124

114125
func resourceOutgoingWebhookCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: internal/resources/oncall/resource_route.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,18 @@ func resourceRoute() *common.Resource {
135135
"grafana_oncall_route",
136136
resourceID,
137137
schema,
138-
)
138+
).WithLister(oncallListerFunction(listRoutes))
139+
}
140+
141+
func listRoutes(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
142+
resp, _, err := client.Routes.ListRoutes(&onCallAPI.ListRouteOptions{ListOptions: listOptions})
143+
if err != nil {
144+
return nil, nil, err
145+
}
146+
for _, i := range resp.Routes {
147+
ids = append(ids, i.ID)
148+
}
149+
return ids, resp.Next, nil
139150
}
140151

141152
func resourceRouteCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: internal/resources/oncall/resource_schedule.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,18 @@ func resourceSchedule() *common.Resource {
106106
"grafana_oncall_schedule",
107107
resourceID,
108108
schema,
109-
)
109+
).WithLister(oncallListerFunction(listSchedules))
110+
}
111+
112+
func listSchedules(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
113+
resp, _, err := client.Schedules.ListSchedules(&onCallAPI.ListScheduleOptions{ListOptions: listOptions})
114+
if err != nil {
115+
return nil, nil, err
116+
}
117+
for _, i := range resp.Schedules {
118+
ids = append(ids, i.ID)
119+
}
120+
return ids, resp.Next, nil
110121
}
111122

112123
func resourceScheduleCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: internal/resources/oncall/resource_shift.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,18 @@ func resourceOnCallShift() *common.Resource {
187187
"grafana_oncall_on_call_shift",
188188
resourceID,
189189
schema,
190-
)
190+
).WithLister(oncallListerFunction(listShifts))
191+
}
192+
193+
func listShifts(client *onCallAPI.Client, listOptions onCallAPI.ListOptions) (ids []string, nextPage *string, err error) {
194+
resp, _, err := client.OnCallShifts.ListOnCallShifts(&onCallAPI.ListOnCallShiftOptions{ListOptions: listOptions})
195+
if err != nil {
196+
return nil, nil, err
197+
}
198+
for _, i := range resp.OnCallShifts {
199+
ids = append(ids, i.ID)
200+
}
201+
return ids, resp.Next, nil
191202
}
192203

193204
func resourceOnCallShiftCreate(ctx context.Context, d *schema.ResourceData, client *onCallAPI.Client) diag.Diagnostics {

Diff for: pkg/generate/cloud.go

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ type stack struct {
2626
managementKey string
2727
smURL string
2828
smToken string
29+
30+
onCallURL string
31+
onCallToken string
2932
}
3033

3134
func generateCloudResources(ctx context.Context, cfg *Config) ([]stack, error) {

Diff for: pkg/generate/config.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ const (
1313
var OutputFormats = []OutputFormat{OutputFormatJSON, OutputFormatHCL, OutputFormatCrossplane}
1414

1515
type GrafanaConfig struct {
16-
URL string
17-
Auth string
16+
URL string
17+
Auth string
18+
SMURL string
19+
SMAccessToken string
20+
OnCallURL string
21+
OnCallAccessToken string
1822
}
1923

2024
type CloudConfig struct {

Diff for: pkg/generate/generate.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,10 @@ func Generate(ctx context.Context, cfg *Config) error {
8080
stack := stack{
8181
managementKey: cfg.Grafana.Auth,
8282
url: cfg.Grafana.URL,
83-
smToken: "",
84-
smURL: "",
83+
smToken: cfg.Grafana.SMAccessToken,
84+
smURL: cfg.Grafana.SMURL,
85+
onCallToken: cfg.Grafana.OnCallAccessToken,
86+
onCallURL: cfg.Grafana.OnCallURL,
8587
}
8688
if err := generateGrafanaResources(ctx, cfg, stack, true); err != nil {
8789
return err

Diff for: pkg/generate/grafana.go

+17-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/grafana/terraform-provider-grafana/v3/internal/resources/grafana"
99
"github.com/grafana/terraform-provider-grafana/v3/internal/resources/machinelearning"
10+
"github.com/grafana/terraform-provider-grafana/v3/internal/resources/oncall"
1011
"github.com/grafana/terraform-provider-grafana/v3/internal/resources/slo"
1112
"github.com/grafana/terraform-provider-grafana/v3/internal/resources/syntheticmonitoring"
1213
"github.com/grafana/terraform-provider-grafana/v3/pkg/provider"
@@ -28,6 +29,14 @@ func generateGrafanaResources(ctx context.Context, cfg *Config, stack stack, gen
2829
providerBlock := hclwrite.NewBlock("provider", []string{"grafana"})
2930
providerBlock.Body().SetAttributeValue("url", cty.StringVal(stack.url))
3031
providerBlock.Body().SetAttributeValue("auth", cty.StringVal(stack.managementKey))
32+
if stack.smToken != "" && stack.smURL != "" {
33+
providerBlock.Body().SetAttributeValue("sm_url", cty.StringVal(stack.smURL))
34+
providerBlock.Body().SetAttributeValue("sm_access_token", cty.StringVal(stack.smToken))
35+
}
36+
if stack.onCallToken != "" && stack.onCallURL != "" {
37+
providerBlock.Body().SetAttributeValue("oncall_url", cty.StringVal(stack.onCallURL))
38+
providerBlock.Body().SetAttributeValue("oncall_access_token", cty.StringVal(stack.onCallToken))
39+
}
3140
if stack.name != "" {
3241
providerBlock.Body().SetAttributeValue("alias", cty.StringVal(stack.name))
3342
}
@@ -44,11 +53,16 @@ func generateGrafanaResources(ctx context.Context, cfg *Config, stack stack, gen
4453
URL: types.StringValue(stack.url),
4554
Auth: types.StringValue(stack.managementKey),
4655
}
47-
if stack.smToken != "" {
56+
resources := grafana.Resources
57+
if stack.smToken != "" && stack.smURL != "" {
58+
resources = append(resources, syntheticmonitoring.Resources...)
59+
config.SMURL = types.StringValue(stack.smURL)
4860
config.SMAccessToken = types.StringValue(stack.smToken)
4961
}
50-
if stack.smURL != "" {
51-
config.SMURL = types.StringValue(stack.smURL)
62+
if stack.onCallToken != "" && stack.onCallURL != "" {
63+
resources = append(resources, oncall.Resources...)
64+
config.OncallAccessToken = types.StringValue(stack.onCallToken)
65+
config.OncallURL = types.StringValue(stack.onCallURL)
5266
}
5367
if err := config.SetDefaults(); err != nil {
5468
return err
@@ -59,11 +73,9 @@ func generateGrafanaResources(ctx context.Context, cfg *Config, stack stack, gen
5973
return err
6074
}
6175

62-
resources := grafana.Resources
6376
if strings.HasPrefix(stack.name, "stack-") { // TODO: is cloud. Find a better way to detect this
6477
resources = append(resources, slo.Resources...)
6578
resources = append(resources, machinelearning.Resources...)
66-
resources = append(resources, syntheticmonitoring.Resources...)
6779
}
6880
if err := generateImportBlocks(ctx, client, listerData, resources, cfg, stack.name); err != nil {
6981
return err

0 commit comments

Comments
 (0)