Skip to content

Commit 7746885

Browse files
Add resource to install cloud plugin (#424)
* Add resource to install cloud plugin * Generate docs * Ensure stack is provisioned before applying plugin * Update prefix * Set installation values on create * Check resource deleted * Check resource deleted following resource removal * Fix PR comments * Remove ID check. We don't use the installation ID Co-authored-by: Julien Duchesne <[email protected]>
1 parent 6d9205f commit 7746885

File tree

6 files changed

+235
-2
lines changed

6 files changed

+235
-2
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "grafana_cloud_plugin_installation Resource - terraform-provider-grafana"
4+
subcategory: ""
5+
description: |-
6+
Manages Grafana Cloud Plugin Installations.
7+
Plugin Catalog https://grafana.com/grafana/plugins/
8+
---
9+
10+
# grafana_cloud_plugin_installation (Resource)
11+
12+
Manages Grafana Cloud Plugin Installations.
13+
14+
* [Plugin Catalog](https://grafana.com/grafana/plugins/)
15+
16+
## Example Usage
17+
18+
```terraform
19+
resource "grafana_cloud_plugin_installation" "test" {
20+
stack_slug = "stackname"
21+
slug = "some-plugin"
22+
version = "1.2.3"
23+
}
24+
```
25+
26+
<!-- schema generated by tfplugindocs -->
27+
## Schema
28+
29+
### Required
30+
31+
- `slug` (String) Slug of the plugin to be installed.
32+
- `stack_slug` (String) The stack id to which the plugin should be installed.
33+
- `version` (String) Version of the plugin to be installed.
34+
35+
### Optional
36+
37+
- `id` (String) The ID of this resource.
38+
39+
## Import
40+
41+
Import is supported using the following syntax:
42+
43+
```shell
44+
terraform import grafana_cloud_plugin_installation.plugin_name {{stack_slug}}_{{plugin_slug}}
45+
```
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform import grafana_cloud_plugin_installation.plugin_name {{stack_slug}}_{{plugin_slug}}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resource "grafana_cloud_plugin_installation" "test" {
2+
stack_slug = "stackname"
3+
slug = "some-plugin"
4+
version = "1.2.3"
5+
}

grafana/provider.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,9 @@ func Provider(version string) func() *schema.Provider {
164164
"grafana_user": ResourceUser(),
165165

166166
// Cloud
167-
"grafana_cloud_api_key": ResourceCloudAPIKey(),
168-
"grafana_cloud_stack": ResourceCloudStack(),
167+
"grafana_cloud_api_key": ResourceCloudAPIKey(),
168+
"grafana_cloud_plugin_installation": ResourceCloudPluginInstallation(),
169+
"grafana_cloud_stack": ResourceCloudStack(),
169170

170171
// Synthetic Monitoring
171172
"grafana_synthetic_monitoring_check": ResourceSyntheticMonitoringCheck(),

grafana/resource_cloud_plugin.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package grafana
2+
3+
import (
4+
"context"
5+
"log"
6+
"strings"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
9+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
10+
)
11+
12+
func ResourceCloudPluginInstallation() *schema.Resource {
13+
return &schema.Resource{
14+
Description: `
15+
Manages Grafana Cloud Plugin Installations.
16+
17+
* [Plugin Catalog](https://grafana.com/grafana/plugins/)
18+
`,
19+
Schema: map[string]*schema.Schema{
20+
"stack_slug": {
21+
Description: "The stack id to which the plugin should be installed.",
22+
Type: schema.TypeString,
23+
Required: true,
24+
ForceNew: true,
25+
},
26+
"slug": {
27+
Description: "Slug of the plugin to be installed.",
28+
Type: schema.TypeString,
29+
Required: true,
30+
ForceNew: true,
31+
},
32+
"version": {
33+
Description: "Version of the plugin to be installed.",
34+
Type: schema.TypeString,
35+
Required: true,
36+
ForceNew: true,
37+
},
38+
},
39+
CreateContext: resourceCloudPluginInstallationCreate,
40+
ReadContext: resourceCloudPluginInstallationRead,
41+
UpdateContext: nil,
42+
DeleteContext: resourceCloudPluginInstallationDelete,
43+
Importer: &schema.ResourceImporter{
44+
StateContext: schema.ImportStatePassthroughContext,
45+
},
46+
}
47+
}
48+
49+
func resourceCloudPluginInstallationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
50+
client := meta.(*client).gcloudapi
51+
52+
stackSlug := d.Get("stack_slug").(string)
53+
pluginSlug := d.Get("slug").(string)
54+
pluginVersion := d.Get("version").(string)
55+
56+
_, err := client.InstallCloudPlugin(stackSlug, pluginSlug, pluginVersion)
57+
if err != nil {
58+
return diag.FromErr(err)
59+
}
60+
61+
d.SetId(stackSlug + "_" + pluginSlug)
62+
63+
return nil
64+
}
65+
66+
func resourceCloudPluginInstallationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
67+
client := meta.(*client).gcloudapi
68+
69+
splitID := strings.SplitN(d.Id(), "_", 2)
70+
stackSlug, pluginSlug := splitID[0], splitID[1]
71+
72+
installation, err := client.GetCloudPluginInstallation(stackSlug, pluginSlug)
73+
if err != nil {
74+
if strings.HasPrefix(err.Error(), "status: 404") {
75+
log.Printf("[WARN] removing plugin %s from state because it no longer exists in stack %s", pluginSlug, stackSlug)
76+
d.SetId("")
77+
return nil
78+
}
79+
80+
return diag.FromErr(err)
81+
}
82+
83+
d.Set("stack_slug", installation.InstanceSlug)
84+
d.Set("slug", installation.PluginSlug)
85+
d.Set("version", installation.Version)
86+
87+
return nil
88+
}
89+
90+
func resourceCloudPluginInstallationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
91+
client := meta.(*client).gcloudapi
92+
93+
splitID := strings.SplitN(d.Id(), "_", 2)
94+
stackSlug, pluginSlug := splitID[0], splitID[1]
95+
96+
err := client.UninstallCloudPlugin(stackSlug, pluginSlug)
97+
98+
return diag.FromErr(err)
99+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package grafana
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
9+
)
10+
11+
func TestAccResourceCloudPluginInstallation(t *testing.T) {
12+
CheckCloudAPITestsEnabled(t)
13+
14+
slug := "terraformprovidergrafana"
15+
pluginSlug := "aws-datasource-provisioner-app"
16+
pluginVersion := "1.7.0"
17+
18+
resource.Test(t, resource.TestCase{
19+
ProviderFactories: testAccProviderFactories,
20+
Steps: []resource.TestStep{
21+
{
22+
Config: testAccGrafanaCloudPluginInstallation(slug, pluginSlug, pluginVersion),
23+
Check: resource.ComposeTestCheckFunc(
24+
testAccCloudPluginInstallationCheckExists("grafana_cloud_plugin_installation.test-installation", slug, pluginSlug),
25+
resource.TestCheckResourceAttrSet("grafana_cloud_plugin_installation.test-installation", "id"),
26+
resource.TestCheckResourceAttr("grafana_cloud_plugin_installation.test-installation", "stack_slug", slug),
27+
resource.TestCheckResourceAttr("grafana_cloud_plugin_installation.test-installation", "slug", "aws-datasource-provisioner-app"),
28+
resource.TestCheckResourceAttr("grafana_cloud_plugin_installation.test-installation", "version", "1.7.0")),
29+
},
30+
{
31+
ResourceName: "grafana_cloud_plugin_installation.test-installation",
32+
ImportState: true,
33+
ImportStateVerify: true,
34+
},
35+
},
36+
CheckDestroy: testAccCloudPluginInstallationDestroy(pluginSlug, pluginVersion),
37+
})
38+
}
39+
40+
func testAccCloudPluginInstallationCheckExists(rn string, stackSlug string, pluginSlug string) resource.TestCheckFunc {
41+
return func(s *terraform.State) error {
42+
rs, ok := s.RootModule().Resources[rn]
43+
if !ok {
44+
return fmt.Errorf("resource not found: %s\n %#v", rn, s.RootModule().Resources)
45+
}
46+
47+
if rs.Primary.ID == "" {
48+
return fmt.Errorf("resource id not set")
49+
}
50+
51+
client := testAccProvider.Meta().(*client).gcloudapi
52+
_, err := client.GetCloudPluginInstallation(stackSlug, pluginSlug)
53+
if err != nil {
54+
return fmt.Errorf("error getting installation: %s", err)
55+
}
56+
57+
return nil
58+
}
59+
}
60+
61+
func testAccCloudPluginInstallationDestroy(stackSlug string, pluginSlug string) resource.TestCheckFunc {
62+
return func(s *terraform.State) error {
63+
client := testAccProvider.Meta().(*client).gcloudapi
64+
65+
installation, err := client.GetCloudPluginInstallation(stackSlug, pluginSlug)
66+
if err == nil {
67+
return fmt.Errorf("installation `%s` with ID `%d` still exists after destroy", installation.PluginSlug, installation.ID)
68+
}
69+
70+
return nil
71+
}
72+
}
73+
74+
func testAccGrafanaCloudPluginInstallation(stackSlug, name, version string) string {
75+
return fmt.Sprintf(`
76+
resource "grafana_cloud_plugin_installation" "test-installation" {
77+
stack_slug = "%s"
78+
slug = "%s"
79+
version = "%s"
80+
}
81+
`, stackSlug, name, version)
82+
}

0 commit comments

Comments
 (0)