Skip to content

Commit b5f8898

Browse files
Merge pull request #2 from grafana/user-resource
Basic implementation of a user resource. Implements what is supported in the admin user create API - email, name, login, password.
2 parents b7854e3 + 7f65d00 commit b5f8898

File tree

4 files changed

+261
-0
lines changed

4 files changed

+261
-0
lines changed

grafana/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func Provider() terraform.ResourceProvider {
3232
"grafana_data_source": ResourceDataSource(),
3333
"grafana_folder": ResourceFolder(),
3434
"grafana_organization": ResourceOrganization(),
35+
"grafana_user": ResourceUser(),
3536
},
3637

3738
ConfigureFunc: providerConfigure,

grafana/resource_user.go

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package grafana
2+
3+
import (
4+
"strconv"
5+
6+
"github.com/hashicorp/terraform/helper/schema"
7+
8+
gapi "github.com/grafana/grafana-api-golang-client"
9+
)
10+
11+
func ResourceUser() *schema.Resource {
12+
return &schema.Resource{
13+
Create: CreateUser,
14+
Read: ReadUser,
15+
Update: UpdateUser,
16+
Delete: DeleteUser,
17+
Schema: map[string]*schema.Schema{
18+
"email": {
19+
Type: schema.TypeString,
20+
Required: true,
21+
},
22+
"name": {
23+
Type: schema.TypeString,
24+
Optional: true,
25+
},
26+
"login": {
27+
Type: schema.TypeString,
28+
Optional: true,
29+
},
30+
"password": {
31+
Type: schema.TypeString,
32+
Required: true,
33+
Sensitive: true,
34+
},
35+
},
36+
}
37+
}
38+
39+
func CreateUser(d *schema.ResourceData, meta interface{}) error {
40+
client := meta.(*gapi.Client)
41+
user := gapi.User{
42+
Email: d.Get("email").(string),
43+
Name: d.Get("name").(string),
44+
Login: d.Get("login").(string),
45+
Password: d.Get("password").(string),
46+
}
47+
id, err := client.CreateUser(user)
48+
if err != nil {
49+
return err
50+
}
51+
d.SetId(strconv.FormatInt(id, 10))
52+
return ReadUser(d, meta)
53+
}
54+
55+
func ReadUser(d *schema.ResourceData, meta interface{}) error {
56+
client := meta.(*gapi.Client)
57+
id, err := strconv.ParseInt(d.Id(), 10, 64)
58+
if err != nil {
59+
return err
60+
}
61+
user, err := client.User(id)
62+
if err != nil {
63+
return err
64+
}
65+
d.Set("email", user.Email)
66+
d.Set("name", user.Name)
67+
d.Set("login", user.Login)
68+
return nil
69+
}
70+
71+
func UpdateUser(d *schema.ResourceData, meta interface{}) error {
72+
client := meta.(*gapi.Client)
73+
id, err := strconv.ParseInt(d.Id(), 10, 64)
74+
if err != nil {
75+
return err
76+
}
77+
u := gapi.User{
78+
Id: id,
79+
Email: d.Get("email").(string),
80+
Name: d.Get("name").(string),
81+
Login: d.Get("login").(string),
82+
}
83+
err = client.UserUpdate(u)
84+
if err != nil {
85+
return err
86+
}
87+
if d.HasChange("password") {
88+
err = client.UpdateUserPassword(id, d.Get("password").(string))
89+
if err != nil {
90+
return err
91+
}
92+
}
93+
return ReadUser(d, meta)
94+
}
95+
96+
func DeleteUser(d *schema.ResourceData, meta interface{}) error {
97+
client := meta.(*gapi.Client)
98+
id, err := strconv.ParseInt(d.Id(), 10, 64)
99+
if err != nil {
100+
return err
101+
}
102+
return client.DeleteUser(id)
103+
}

grafana/resource_user_test.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package grafana
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strconv"
7+
"testing"
8+
9+
"github.com/hashicorp/terraform/helper/resource"
10+
"github.com/hashicorp/terraform/terraform"
11+
12+
gapi "github.com/grafana/grafana-api-golang-client"
13+
)
14+
15+
func TestAccUser_basic(t *testing.T) {
16+
var user gapi.User
17+
resource.Test(t, resource.TestCase{
18+
PreCheck: func() { testAccPreCheck(t) },
19+
Providers: testAccProviders,
20+
CheckDestroy: testAccUserCheckDestroy(&user),
21+
Steps: []resource.TestStep{
22+
{
23+
Config: testAccUserConfig_basic,
24+
Check: resource.ComposeTestCheckFunc(
25+
testAccUserCheckExists("grafana_user.test", &user),
26+
resource.TestCheckResourceAttr(
27+
"grafana_user.test", "email", "terraform-test@localhost",
28+
),
29+
resource.TestCheckResourceAttr(
30+
"grafana_user.test", "name", "Terraform Test",
31+
),
32+
resource.TestCheckResourceAttr(
33+
"grafana_user.test", "login", "tt",
34+
),
35+
resource.TestCheckResourceAttr(
36+
"grafana_user.test", "password", "abc123",
37+
),
38+
resource.TestMatchResourceAttr(
39+
"grafana_user.test", "id", regexp.MustCompile(`\d+`),
40+
),
41+
),
42+
},
43+
{
44+
Config: testAccUserConfig_update,
45+
Check: resource.ComposeTestCheckFunc(
46+
testAccUserCheckExists("grafana_user.test", &user),
47+
resource.TestCheckResourceAttr(
48+
"grafana_user.test", "email", "terraform-test-update@localhost",
49+
),
50+
resource.TestCheckResourceAttr(
51+
"grafana_user.test", "name", "Terraform Test Update",
52+
),
53+
resource.TestCheckResourceAttr(
54+
"grafana_user.test", "login", "ttu",
55+
),
56+
resource.TestCheckResourceAttr(
57+
"grafana_user.test", "password", "zyx987",
58+
),
59+
),
60+
},
61+
},
62+
})
63+
}
64+
65+
func testAccUserCheckExists(rn string, a *gapi.User) resource.TestCheckFunc {
66+
return func(s *terraform.State) error {
67+
rs, ok := s.RootModule().Resources[rn]
68+
if !ok {
69+
return fmt.Errorf("resource not found: %s", rn)
70+
}
71+
if rs.Primary.ID == "" {
72+
return fmt.Errorf("resource id not set")
73+
}
74+
tmp, err := strconv.ParseInt(rs.Primary.ID, 10, 64)
75+
id := int64(tmp)
76+
if err != nil {
77+
return fmt.Errorf("resource id is malformed")
78+
}
79+
client := testAccProvider.Meta().(*gapi.Client)
80+
user, err := client.User(id)
81+
if err != nil {
82+
return fmt.Errorf("error getting data source: %s", err)
83+
}
84+
*a = user
85+
return nil
86+
}
87+
}
88+
89+
func testAccUserCheckDestroy(a *gapi.User) resource.TestCheckFunc {
90+
return func(s *terraform.State) error {
91+
client := testAccProvider.Meta().(*gapi.Client)
92+
user, err := client.User(a.Id)
93+
if err == nil && user.Email != "" {
94+
return fmt.Errorf("user still exists")
95+
}
96+
return nil
97+
}
98+
}
99+
100+
const testAccUserConfig_basic = `
101+
resource "grafana_user" "test" {
102+
email = "terraform-test@localhost"
103+
name = "Terraform Test"
104+
login = "tt"
105+
password = "abc123"
106+
}
107+
`
108+
109+
const testAccUserConfig_update = `
110+
resource "grafana_user" "test" {
111+
email = "terraform-test-update@localhost"
112+
name = "Terraform Test Update"
113+
login = "ttu"
114+
password = "zyx987"
115+
}
116+
`

website/docs/r/user.html.md

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
---
2+
layout: "grafana"
3+
page_title: "Grafana: grafana_user"
4+
sidebar_current: "docs-grafana-user"
5+
description: |-
6+
The grafana_user resource allows a Grafana user to be created.
7+
---
8+
9+
# grafana\_user
10+
11+
The user resource allows Grafana user management.
12+
13+
~> **NOTE on `grafana_user`:** - this resource uses Grafana's admin APIs for
14+
creating and updating users. This API does not currently work with API Tokens.
15+
You must use Basic Authentication (username and password).
16+
17+
## Example Usage
18+
19+
```hcl
20+
resource "grafana_user" "staff" {
21+
22+
name = "Staff Name"
23+
login = "staff"
24+
password = "my-password"
25+
}
26+
```
27+
28+
## Argument Reference
29+
30+
The following arguments are supported:
31+
32+
* `email` - (Required) The email address of the Grafana user.
33+
* `name` - (Optional) The display name for the Grafana user.
34+
* `login` - (Optional) The username for the Grafana user.
35+
* `password` - (Optional) The password for the Grafana user.
36+
37+
## Attributes Reference
38+
39+
The following attributes are exported:
40+
41+
* `id` - The ID of the resource

0 commit comments

Comments
 (0)