Skip to content

Commit 456ec4d

Browse files
author
Lars Wander
committed
provider/google: SQL user resource, documentation & tests
1 parent aa05e82 commit 456ec4d

5 files changed

Lines changed: 377 additions & 0 deletions

File tree

builtin/providers/google/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ func Provider() terraform.ResourceProvider {
7070
"google_dns_record_set": resourceDnsRecordSet(),
7171
"google_sql_database": resourceSqlDatabase(),
7272
"google_sql_database_instance": resourceSqlDatabaseInstance(),
73+
"google_sql_user": resourceSqlUser(),
7374
"google_pubsub_topic": resourcePubsubTopic(),
7475
"google_pubsub_subscription": resourcePubsubSubscription(),
7576
"google_storage_bucket": resourceStorageBucket(),
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
package google
2+
3+
import (
4+
"fmt"
5+
"log"
6+
7+
"github.com/hashicorp/terraform/helper/schema"
8+
9+
"google.golang.org/api/googleapi"
10+
"google.golang.org/api/sqladmin/v1beta4"
11+
)
12+
13+
func resourceSqlUser() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceSqlUserCreate,
16+
Read: resourceSqlUserRead,
17+
Update: resourceSqlUserUpdate,
18+
Delete: resourceSqlUserDelete,
19+
20+
Schema: map[string]*schema.Schema{
21+
"name": &schema.Schema{
22+
Type: schema.TypeString,
23+
Required: true,
24+
ForceNew: true,
25+
},
26+
27+
"password": &schema.Schema{
28+
Type: schema.TypeString,
29+
Required: true,
30+
},
31+
32+
"host": &schema.Schema{
33+
Type: schema.TypeString,
34+
Required: true,
35+
ForceNew: true,
36+
},
37+
38+
"instance": &schema.Schema{
39+
Type: schema.TypeString,
40+
Required: true,
41+
ForceNew: true,
42+
},
43+
},
44+
}
45+
}
46+
47+
func resourceSqlUserCreate(d *schema.ResourceData, meta interface{}) error {
48+
config := meta.(*Config)
49+
50+
name := d.Get("name").(string)
51+
instance := d.Get("instance").(string)
52+
password := d.Get("password").(string)
53+
host := d.Get("host").(string)
54+
project := config.Project
55+
56+
user := &sqladmin.User{
57+
Name: name,
58+
Instance: instance,
59+
Password: password,
60+
Host: host,
61+
}
62+
63+
op, err := config.clientSqlAdmin.Users.Insert(project, instance,
64+
user).Do()
65+
66+
if err != nil {
67+
return fmt.Errorf("Error, failed to insert "+
68+
"user %s into instance %s: %s", name, instance, err)
69+
}
70+
71+
err = sqladminOperationWait(config, op, "Insert User")
72+
73+
if err != nil {
74+
return fmt.Errorf("Error, failure waiting for insertion of %s "+
75+
"into %s: %s", name, instance, err)
76+
}
77+
78+
return resourceSqlUserRead(d, meta)
79+
}
80+
81+
func resourceSqlUserRead(d *schema.ResourceData, meta interface{}) error {
82+
config := meta.(*Config)
83+
84+
name := d.Get("name").(string)
85+
instance := d.Get("instance").(string)
86+
project := config.Project
87+
88+
users, err := config.clientSqlAdmin.Users.List(project, instance).Do()
89+
90+
if err != nil {
91+
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
92+
log.Printf("[WARN] Removing SQL User %q because it's gone", d.Get("name").(string))
93+
d.SetId("")
94+
95+
return nil
96+
}
97+
98+
return fmt.Errorf("Error, failed to get user %s in instance %s: %s", name, instance, err)
99+
}
100+
101+
found := false
102+
for _, user := range users.Items {
103+
if user.Name == name {
104+
found = true
105+
break
106+
}
107+
}
108+
109+
if !found {
110+
log.Printf("[WARN] Removing SQL User %q because it's gone", d.Get("name").(string))
111+
d.SetId("")
112+
113+
return nil
114+
}
115+
116+
d.SetId(name)
117+
118+
return nil
119+
}
120+
121+
func resourceSqlUserUpdate(d *schema.ResourceData, meta interface{}) error {
122+
config := meta.(*Config)
123+
124+
if d.HasChange("password") {
125+
name := d.Get("name").(string)
126+
instance := d.Get("instance").(string)
127+
host := d.Get("host").(string)
128+
password := d.Get("password").(string)
129+
project := config.Project
130+
131+
user := &sqladmin.User{
132+
Name: name,
133+
Instance: instance,
134+
Password: password,
135+
Host: host,
136+
}
137+
138+
op, err := config.clientSqlAdmin.Users.Update(project, instance, host, name,
139+
user).Do()
140+
141+
if err != nil {
142+
return fmt.Errorf("Error, failed to update"+
143+
"user %s into user %s: %s", name, instance, err)
144+
}
145+
146+
err = sqladminOperationWait(config, op, "Insert User")
147+
148+
if err != nil {
149+
return fmt.Errorf("Error, failure waiting for update of %s "+
150+
"in %s: %s", name, instance, err)
151+
}
152+
153+
return resourceSqlUserRead(d, meta)
154+
}
155+
156+
return nil
157+
}
158+
159+
func resourceSqlUserDelete(d *schema.ResourceData, meta interface{}) error {
160+
config := meta.(*Config)
161+
162+
name := d.Get("name").(string)
163+
instance := d.Get("instance").(string)
164+
host := d.Get("host").(string)
165+
project := config.Project
166+
167+
op, err := config.clientSqlAdmin.Users.Delete(project, instance, host, name).Do()
168+
169+
if err != nil {
170+
return fmt.Errorf("Error, failed to delete"+
171+
"user %s in instance %s: %s", name,
172+
instance, err)
173+
}
174+
175+
err = sqladminOperationWait(config, op, "Delete User")
176+
177+
if err != nil {
178+
return fmt.Errorf("Error, failure waiting for deletion of %s "+
179+
"in %s: %s", name, instance, err)
180+
}
181+
182+
return nil
183+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package google
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform/helper/acctest"
8+
"github.com/hashicorp/terraform/helper/resource"
9+
"github.com/hashicorp/terraform/terraform"
10+
)
11+
12+
func TestAccGoogleSqlUser_basic(t *testing.T) {
13+
user := acctest.RandString(10)
14+
instance := acctest.RandString(10)
15+
16+
resource.Test(t, resource.TestCase{
17+
PreCheck: func() { testAccPreCheck(t) },
18+
Providers: testAccProviders,
19+
CheckDestroy: testAccGoogleSqlUserDestroy,
20+
Steps: []resource.TestStep{
21+
resource.TestStep{
22+
Config: testGoogleSqlUser_basic(instance, user),
23+
Check: resource.ComposeTestCheckFunc(
24+
testAccCheckGoogleSqlUserExists("google_sql_user.user"),
25+
),
26+
},
27+
},
28+
})
29+
}
30+
31+
func TestAccGoogleSqlUser_update(t *testing.T) {
32+
user := acctest.RandString(10)
33+
instance := acctest.RandString(10)
34+
35+
resource.Test(t, resource.TestCase{
36+
PreCheck: func() { testAccPreCheck(t) },
37+
Providers: testAccProviders,
38+
CheckDestroy: testAccGoogleSqlUserDestroy,
39+
Steps: []resource.TestStep{
40+
resource.TestStep{
41+
Config: testGoogleSqlUser_basic(instance, user),
42+
Check: resource.ComposeTestCheckFunc(
43+
testAccCheckGoogleSqlUserExists("google_sql_user.user"),
44+
),
45+
},
46+
47+
resource.TestStep{
48+
Config: testGoogleSqlUser_basic2(instance, user),
49+
Check: resource.ComposeTestCheckFunc(
50+
testAccCheckGoogleSqlUserExists("google_sql_user.user"),
51+
),
52+
},
53+
},
54+
})
55+
}
56+
57+
func testAccCheckGoogleSqlUserExists(n string) resource.TestCheckFunc {
58+
return func(s *terraform.State) error {
59+
config := testAccProvider.Meta().(*Config)
60+
rs, ok := s.RootModule().Resources[n]
61+
if !ok {
62+
return fmt.Errorf("Resource not found: %s", n)
63+
}
64+
65+
name := rs.Primary.Attributes["name"]
66+
instance := rs.Primary.Attributes["instance"]
67+
host := rs.Primary.Attributes["host"]
68+
users, err := config.clientSqlAdmin.Users.List(config.Project,
69+
instance).Do()
70+
71+
for _, user := range users.Items {
72+
if user.Name == name && user.Host == host {
73+
return nil
74+
}
75+
}
76+
77+
return fmt.Errorf("Not found: %s: %s", n, err)
78+
}
79+
}
80+
81+
func testAccGoogleSqlUserDestroy(s *terraform.State) error {
82+
for _, rs := range s.RootModule().Resources {
83+
config := testAccProvider.Meta().(*Config)
84+
if rs.Type != "google_sql_database" {
85+
continue
86+
}
87+
88+
name := rs.Primary.Attributes["name"]
89+
instance := rs.Primary.Attributes["instance"]
90+
host := rs.Primary.Attributes["host"]
91+
users, err := config.clientSqlAdmin.Users.List(config.Project,
92+
instance).Do()
93+
94+
for _, user := range users.Items {
95+
if user.Name == name && user.Host == host {
96+
return fmt.Errorf("User still %s exists %s", name, err)
97+
}
98+
}
99+
100+
return nil
101+
}
102+
103+
return nil
104+
}
105+
106+
func testGoogleSqlUser_basic(instance, user string) string {
107+
return fmt.Sprintf(`
108+
resource "google_sql_database_instance" "instance" {
109+
name = "i%s"
110+
region = "us-central"
111+
settings {
112+
tier = "D0"
113+
}
114+
}
115+
116+
resource "google_sql_user" "user" {
117+
name = "user%s"
118+
instance = "${google_sql_database_instance.instance.name}"
119+
host = "google.com"
120+
password = "hunter2"
121+
}
122+
`, instance, user)
123+
}
124+
125+
func testGoogleSqlUser_basic2(instance, user string) string {
126+
return fmt.Sprintf(`
127+
resource "google_sql_database_instance" "instance" {
128+
name = "i%s"
129+
region = "us-central"
130+
settings {
131+
tier = "D0"
132+
}
133+
}
134+
135+
resource "google_sql_user" "user" {
136+
name = "user%s"
137+
instance = "${google_sql_database_instance.instance.name}"
138+
host = "google.com"
139+
password = "oops"
140+
}
141+
`, instance, user)
142+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
layout: "google"
3+
page_title: "Google: google_sql_user"
4+
sidebar_current: "docs-google-sql-user"
5+
description: |-
6+
Creates a new SQL user in Google Cloud SQL.
7+
---
8+
9+
# google\_sql\_user
10+
11+
Creates a new Google SQL User on a Google SQL User Instance. For more information, see the [official documentation](https://cloud.google.com/sql/), or the [JSON API](https://cloud.google.com/sql/docs/admin-api/v1beta4/users).
12+
13+
## Example Usage
14+
15+
Example creating a SQL User.
16+
17+
```
18+
resource "google_sql_database_instance" "master" {
19+
name = "master-instance"
20+
21+
settings {
22+
tier = "D0"
23+
}
24+
}
25+
26+
resource "google_sql_user" "users" {
27+
name = "me"
28+
instance = "${google_sql_database_instance.master.name}"
29+
host = "me.com"
30+
}
31+
32+
```
33+
34+
## Argument Reference
35+
36+
The following arguments are supported:
37+
38+
* `name` - (Required) The name of the user.
39+
Changing this forces a new resource to be created.
40+
41+
* `host` - (Required) The host the user can connect from. Can be an IP address.
42+
Changing this forces a new resource to be created.
43+
44+
* `password` - (Required) The users password. Can be updated.
45+
46+
* `instance` - (Required) The name of the Cloud SQL instance.
47+
Changing this forces a new resource to be created.

website/source/layouts/google.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,10 @@
152152
<li<%= sidebar_current("docs-google-sql-database-instance") %>>
153153
<a href="/docs/providers/google/r/sql_database_instance.html">google_sql_database_instance</a>
154154
</li>
155+
156+
<li<%= sidebar_current("docs-google-sql-user") %>>
157+
<a href="/docs/providers/google/r/sql_user.html">google_sql_user</a>
158+
</li>
155159
</ul>
156160
</li>
157161

0 commit comments

Comments
 (0)