Skip to content

Commit 0a08c26

Browse files
Add Grafana Cloud stack resource and DataSource (#354)
* Add Grafana stacks resource and data source * Fixed CI issues about string templating * Created a new CI pipeline for Cloud Stacks * Revert go.mod change to resolve conflicts * Replace gapi with experimental version * Revert "Created a new CI pipeline for Cloud Stacks" This reverts commit 0d2d9b7. * Use the gcloudapi client for stacks * Add a precheck for stack tests * Fixed a typo in stack tests * Applied suggestions for schema validation from PR review * Updated stack slug to match the validation rules * Added a valid stack name for grafana stack * Generate a random stack name * Fixed stack data source tests * Use the new gcloudapi * Use the latest version of the client api * Slug name must start with a letter * Switched to released version of client api v0.2.6 * Add cleanup and fix client in datasource * Removed broken link for http api as it doesn't exist yet Co-authored-by: Julien Duchesne <[email protected]>
1 parent 524ee0d commit 0a08c26

File tree

12 files changed

+759
-6
lines changed

12 files changed

+759
-6
lines changed

docs/data-sources/cloud_stack.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "grafana_cloud_stack Data Source - terraform-provider-grafana"
4+
subcategory: ""
5+
description: |-
6+
Data source for Grafana Stack
7+
---
8+
9+
# grafana_cloud_stack (Data Source)
10+
11+
Data source for Grafana Stack
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "grafana_cloud_stack" "test" {
17+
name = "gcloudstacktest"
18+
slug = "gcloudstacktest"
19+
region_slug = "eu"
20+
description = "Test Grafana Cloud Stack"
21+
}
22+
23+
data "grafana_cloud_stack" "test" {
24+
slug = grafana_cloud_stack.test.slug
25+
}
26+
```
27+
28+
<!-- schema generated by tfplugindocs -->
29+
## Schema
30+
31+
### Required
32+
33+
- **slug** (String) Subdomain that the Grafana instance will be available at (i.e. setting slug to “<stack_slug>” will make the instance
34+
available at “https://<stack_slug>.grafana.net".
35+
36+
### Read-Only
37+
38+
- **alertmanager_name** (String) Name of the Alertmanager instance configured for this stack.
39+
- **alertmanager_status** (String) Status of the Alertmanager instance configured for this stack.
40+
- **alertmanager_url** (String) Base URL of the Alertmanager instance configured for this stack.
41+
- **alertmanager_user_id** (Number) User ID of the Alertmanager instance configured for this stack.
42+
- **description** (String) Description of stack.
43+
- **id** (String) The stack id assigned to this stack by Grafana.
44+
- **name** (String) Name of stack. Conventionally matches the url of the instance (e.g. “<stack_slug>.grafana.net”).
45+
- **org_id** (Number) Organization id to assign to this stack.
46+
- **org_name** (String) Organization name to assign to this stack.
47+
- **org_slug** (String) Organization slug to assign to this stack.
48+
- **prometheus_name** (String) Prometheus name for this instance.
49+
- **prometheus_remote_endpoint** (String) Use this URL to query hosted metrics data e.g. Prometheus data source in Grafana
50+
- **prometheus_remote_write_endpoint** (String) Use this URL to send prometheus metrics to Grafana cloud
51+
- **prometheus_status** (String) Prometheus status for this instance.
52+
- **prometheus_url** (String) Prometheus url for this instance.
53+
- **prometheus_user_id** (Number) Promehteus user ID. Used for e.g. remote_write.
54+
- **region_slug** (String) The region this stack is deployed to.
55+
- **status** (String) Status of the stack.
56+
- **url** (String) Custom URL for the Grafana instance. Must have a CNAME setup to point to `.grafana.net` before creating the stack
57+
58+

docs/resources/cloud_stack.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "grafana_cloud_stack Resource - terraform-provider-grafana"
4+
subcategory: ""
5+
description: |-
6+
Official documentation https://grafana.com/docs/grafana-cloud/reference/cloud-api/#stacks/
7+
---
8+
9+
# grafana_cloud_stack (Resource)
10+
11+
* [Official documentation](https://grafana.com/docs/grafana-cloud/reference/cloud-api/#stacks/)
12+
13+
## Example Usage
14+
15+
```terraform
16+
resource "grafana_cloud_stack" "test" {
17+
name = "gcloudstacktest"
18+
slug = "gcloudstacktest"
19+
region_slug = "eu"
20+
description = "Test Grafana Cloud Stack"
21+
}
22+
```
23+
24+
<!-- schema generated by tfplugindocs -->
25+
## Schema
26+
27+
### Required
28+
29+
- **name** (String) Name of stack. Conventionally matches the url of the instance (e.g. “<stack_slug>.grafana.net”).
30+
- **slug** (String) Subdomain that the Grafana instance will be available at (i.e. setting slug to “<stack_slug>” will make the instance
31+
available at “https://<stack_slug>.grafana.net".
32+
33+
### Optional
34+
35+
- **description** (String) Description of stack.
36+
- **region_slug** (String) Region slug to assign to this stack.
37+
Changing region will destroy the existing stack and create a new one in the desired region
38+
- **url** (String) Custom URL for the Grafana instance. Must have a CNAME setup to point to `.grafana.net` before creating the stack
39+
40+
### Read-Only
41+
42+
- **alertmanager_name** (String) Name of the Alertmanager instance configured for this stack.
43+
- **alertmanager_status** (String) Status of the Alertmanager instance configured for this stack.
44+
- **alertmanager_url** (String) Base URL of the Alertmanager instance configured for this stack.
45+
- **alertmanager_user_id** (Number) User ID of the Alertmanager instance configured for this stack.
46+
- **id** (String) The stack id assigned to this stack by Grafana.
47+
- **org_id** (Number) Organization id to assign to this stack.
48+
- **org_name** (String) Organization name to assign to this stack.
49+
- **org_slug** (String) Organization slug to assign to this stack.
50+
- **prometheus_name** (String) Prometheus name for this instance.
51+
- **prometheus_remote_endpoint** (String) Use this URL to query hosted metrics data e.g. Prometheus data source in Grafana
52+
- **prometheus_remote_write_endpoint** (String) Use this URL to send prometheus metrics to Grafana cloud
53+
- **prometheus_status** (String) Prometheus status for this instance.
54+
- **prometheus_url** (String) Prometheus url for this instance.
55+
- **prometheus_user_id** (Number) Promehteus user ID. Used for e.g. remote_write.
56+
- **status** (String) Status of the stack.
57+
58+
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
resource "grafana_cloud_stack" "test" {
2+
name = "gcloudstacktest"
3+
slug = "gcloudstacktest"
4+
region_slug = "eu"
5+
description = "Test Grafana Cloud Stack"
6+
}
7+
8+
data "grafana_cloud_stack" "test" {
9+
slug = grafana_cloud_stack.test.slug
10+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
resource "grafana_cloud_stack" "test" {
2+
name = "gcloudstacktest"
3+
slug = "gcloudstacktest"
4+
region_slug = "eu"
5+
description = "Test Grafana Cloud Stack"
6+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.16
44

55
require (
66
github.com/Masterminds/semver/v3 v3.1.1
7-
github.com/grafana/grafana-api-golang-client v0.2.5
7+
github.com/grafana/grafana-api-golang-client v0.2.6
88
github.com/grafana/machine-learning-go-client v0.1.1
99
github.com/grafana/synthetic-monitoring-agent v0.6.2
1010
github.com/grafana/synthetic-monitoring-api-go-client v0.5.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,8 +455,8 @@ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51
455455
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
456456
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
457457
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
458-
github.com/grafana/grafana-api-golang-client v0.2.5 h1:rZhy+0r/B/zV9gZ6BHAHY73JOi1DgVUegghF54yLn/M=
459-
github.com/grafana/grafana-api-golang-client v0.2.5/go.mod h1:24W29gPe9yl0/3A9X624TPkAOR8DpHno490cPwnkv8E=
458+
github.com/grafana/grafana-api-golang-client v0.2.6 h1:/S9vz8gwwxURnQwU/SDgFl4JaX0PTGNrszBKKeOunF4=
459+
github.com/grafana/grafana-api-golang-client v0.2.6/go.mod h1:24W29gPe9yl0/3A9X624TPkAOR8DpHno490cPwnkv8E=
460460
github.com/grafana/machine-learning-go-client v0.1.1 h1:Gw6cX8xAd6IVF2LApkXOIdBK8Gzz07B3jQPukecw7fc=
461461
github.com/grafana/machine-learning-go-client v0.1.1/go.mod h1:QFfZz8NkqVF8++skjkKQXJEZfpCYd8S0yTWJUpsLLTA=
462462
github.com/grafana/synthetic-monitoring-agent v0.5.0/go.mod h1:oC2+OFrK7WHqrDmilaa8eNNjyB2fMRk7DCj3Z/b/TrA=

grafana/data_source_stack.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
package grafana
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
)
9+
10+
func DataSourceStack() *schema.Resource {
11+
return &schema.Resource{
12+
Description: "Data source for Grafana Stack",
13+
ReadContext: datasourceStackRead,
14+
Schema: map[string]*schema.Schema{
15+
"id": {
16+
Type: schema.TypeString,
17+
Computed: true,
18+
Description: "The stack id assigned to this stack by Grafana.",
19+
},
20+
"slug": {
21+
Type: schema.TypeString,
22+
Required: true,
23+
Description: `
24+
Subdomain that the Grafana instance will be available at (i.e. setting slug to “<stack_slug>” will make the instance
25+
available at “https://<stack_slug>.grafana.net".`,
26+
},
27+
"name": {
28+
Type: schema.TypeString,
29+
Computed: true,
30+
Description: "Name of stack. Conventionally matches the url of the instance (e.g. “<stack_slug>.grafana.net”).",
31+
},
32+
"description": {
33+
Type: schema.TypeString,
34+
Computed: true,
35+
Description: "Description of stack.",
36+
},
37+
"region_slug": {
38+
Type: schema.TypeString,
39+
Computed: true,
40+
Description: "The region this stack is deployed to.",
41+
},
42+
"url": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
Description: "Custom URL for the Grafana instance. Must have a CNAME setup to point to `.grafana.net` before creating the stack",
46+
},
47+
"org_id": {
48+
Type: schema.TypeInt,
49+
Computed: true,
50+
Description: "Organization id to assign to this stack.",
51+
},
52+
"org_slug": {
53+
Type: schema.TypeString,
54+
Computed: true,
55+
Description: "Organization slug to assign to this stack.",
56+
},
57+
"org_name": {
58+
Type: schema.TypeString,
59+
Computed: true,
60+
Description: "Organization name to assign to this stack.",
61+
},
62+
"status": {
63+
Type: schema.TypeString,
64+
Computed: true,
65+
Description: "Status of the stack.",
66+
},
67+
"prometheus_user_id": {
68+
Type: schema.TypeInt,
69+
Computed: true,
70+
Description: "Promehteus user ID. Used for e.g. remote_write.",
71+
},
72+
"prometheus_url": {
73+
Type: schema.TypeString,
74+
Computed: true,
75+
Description: "Prometheus url for this instance.",
76+
},
77+
"prometheus_name": {
78+
Type: schema.TypeString,
79+
Computed: true,
80+
Description: "Prometheus name for this instance.",
81+
},
82+
"prometheus_remote_endpoint": {
83+
Type: schema.TypeString,
84+
Computed: true,
85+
Description: "Use this URL to query hosted metrics data e.g. Prometheus data source in Grafana",
86+
},
87+
"prometheus_remote_write_endpoint": {
88+
Type: schema.TypeString,
89+
Computed: true,
90+
Description: "Use this URL to send prometheus metrics to Grafana cloud",
91+
},
92+
"prometheus_status": {
93+
Type: schema.TypeString,
94+
Computed: true,
95+
Description: "Prometheus status for this instance.",
96+
},
97+
"alertmanager_user_id": {
98+
Type: schema.TypeInt,
99+
Computed: true,
100+
Description: "User ID of the Alertmanager instance configured for this stack.",
101+
},
102+
"alertmanager_name": {
103+
Type: schema.TypeString,
104+
Computed: true,
105+
Description: "Name of the Alertmanager instance configured for this stack.",
106+
},
107+
"alertmanager_url": {
108+
Type: schema.TypeString,
109+
Computed: true,
110+
Description: "Base URL of the Alertmanager instance configured for this stack.",
111+
},
112+
"alertmanager_status": {
113+
Type: schema.TypeString,
114+
Computed: true,
115+
Description: "Status of the Alertmanager instance configured for this stack.",
116+
},
117+
},
118+
}
119+
}
120+
121+
func datasourceStackRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
122+
client := meta.(*client).gcloudapi
123+
124+
var diags diag.Diagnostics
125+
126+
slug := d.Get("slug").(string)
127+
128+
stack, err := client.StackBySlug(slug)
129+
if err != nil {
130+
return diag.FromErr(err)
131+
}
132+
133+
FlattenStack(d, stack)
134+
135+
return diags
136+
}

grafana/data_source_stack_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package grafana
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
"time"
7+
8+
gapi "github.com/grafana/grafana-api-golang-client"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
11+
)
12+
13+
func TestAccDataSourceStack_Basic(t *testing.T) {
14+
CheckCloudTestsEnabled(t)
15+
16+
prefix := "tfdatatest"
17+
18+
resourceName := GetRandomStackName(prefix)
19+
var stack gapi.Stack
20+
resource.Test(t, resource.TestCase{
21+
PreCheck: func() {
22+
testAccPreCheckCloudStack(t)
23+
testAccDeleteExistingStacks(t, prefix)
24+
},
25+
ProviderFactories: testAccProviderFactories,
26+
CheckDestroy: testAccStackCheckDestroy(&stack),
27+
Steps: []resource.TestStep{
28+
{
29+
Config: testAccDataSourceStackConfig(resourceName),
30+
Check: resource.ComposeTestCheckFunc(
31+
testAccStackCheckExists("grafana_cloud_stack.test", &stack),
32+
resource.TestCheckResourceAttrSet("data.grafana_cloud_stack.test", "id"),
33+
resource.TestCheckResourceAttr("data.grafana_cloud_stack.test", "name", resourceName),
34+
resource.TestCheckResourceAttr("data.grafana_cloud_stack.test", "slug", resourceName),
35+
resource.TestCheckResourceAttrSet("data.grafana_cloud_stack.test", "prometheus_url"),
36+
resource.TestCheckResourceAttrSet("data.grafana_cloud_stack.test", "prometheus_user_id"),
37+
resource.TestCheckResourceAttrSet("data.grafana_cloud_stack.test", "alertmanager_user_id"),
38+
39+
// TODO: Check how we can remove this sleep
40+
// Sometimes the stack is not ready to be deleted at the end of the test
41+
func(s *terraform.State) error {
42+
time.Sleep(time.Second * 15)
43+
return nil
44+
},
45+
),
46+
},
47+
},
48+
})
49+
}
50+
51+
func testAccDataSourceStackConfig(resourceName string) string {
52+
return fmt.Sprintf(`
53+
resource "grafana_cloud_stack" "test" {
54+
name = "%s"
55+
slug = "%s"
56+
region_slug = "eu"
57+
}
58+
data "grafana_cloud_stack" "test" {
59+
slug = grafana_cloud_stack.test.slug
60+
depends_on = [grafana_cloud_stack.test]
61+
}
62+
`, resourceName, resourceName)
63+
}

grafana/provider.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ func Provider(version string) func() *schema.Provider {
142142
"grafana_team_preferences": ResourceTeamPreferences(),
143143
"grafana_team_external_group": ResourceTeamExternalGroup(),
144144
"grafana_user": ResourceUser(),
145+
"grafana_cloud_stack": ResourceStack(),
145146

146147
// Synthetic Monitoring
147148
"grafana_synthetic_monitoring_check": resourceSyntheticMonitoringCheck(),
@@ -153,9 +154,10 @@ func Provider(version string) func() *schema.Provider {
153154

154155
DataSourcesMap: map[string]*schema.Resource{
155156
// Grafana
156-
"grafana_dashboard": DatasourceDashboard(),
157-
"grafana_folder": DatasourceFolder(),
158-
"grafana_user": DatasourceUser(),
157+
"grafana_dashboard": DatasourceDashboard(),
158+
"grafana_folder": DatasourceFolder(),
159+
"grafana_user": DatasourceUser(),
160+
"grafana_cloud_stack": DataSourceStack(),
159161

160162
// Synthetic Monitoring
161163
"grafana_synthetic_monitoring_probe": dataSourceSyntheticMonitoringProbe(),

grafana/provider_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ func testAccPreCheckCloud(t *testing.T) {
8686
testAccPreCheck(t)
8787
}
8888

89+
// testAccPreCheckCloudStack should be called by cloud stack acceptance tests
90+
func testAccPreCheckCloudStack(t *testing.T) {
91+
testAccPreCheckEnv = append(testAccPreCheckEnv, "GRAFANA_CLOUD_API_KEY")
92+
testAccPreCheck(t)
93+
}
94+
8995
// testAccExample returns an example config from the examples directory.
9096
// Examples are used for both documentation and acceptance tests.
9197
func testAccExample(t *testing.T, path string) string {

0 commit comments

Comments
 (0)