Skip to content

Commit a35a285

Browse files
committed
add postgresql_script resource
1 parent 9864481 commit a35a285

File tree

4 files changed

+310
-0
lines changed

4 files changed

+310
-0
lines changed

postgresql/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ func Provider() *schema.Provider {
201201
"postgresql_server": resourcePostgreSQLServer(),
202202
"postgresql_user_mapping": resourcePostgreSQLUserMapping(),
203203
"postgresql_alter_role": resourcePostgreSQLAlterRole(),
204+
"postgresql_script": resourcePostgreSQLScript(),
204205
},
205206

206207
DataSourcesMap: map[string]*schema.Resource{
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package postgresql
2+
3+
import (
4+
"crypto/sha1"
5+
"encoding/hex"
6+
"time"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
9+
)
10+
11+
const (
12+
scriptCommandsAttr = "commands"
13+
scriptTriesAttr = "tries"
14+
scriptTimeoutAttr = "timeout"
15+
scriptShasumAttr = "shasum"
16+
)
17+
18+
func resourcePostgreSQLScript() *schema.Resource {
19+
return &schema.Resource{
20+
Create: PGResourceFunc(resourcePostgreSQLScriptCreateOrUpdate),
21+
Read: PGResourceFunc(resourcePostgreSQLScriptRead),
22+
Update: PGResourceFunc(resourcePostgreSQLScriptCreateOrUpdate),
23+
Delete: PGResourceFunc(resourcePostgreSQLScriptDelete),
24+
25+
Schema: map[string]*schema.Schema{
26+
scriptCommandsAttr: {
27+
Type: schema.TypeList,
28+
Required: true,
29+
Description: "List of SQL commands to execute",
30+
Elem: &schema.Schema{
31+
Type: schema.TypeString,
32+
},
33+
},
34+
scriptTriesAttr: {
35+
Type: schema.TypeInt,
36+
Optional: true,
37+
Default: 1,
38+
Description: "Number of tries for a failing command",
39+
},
40+
scriptTimeoutAttr: {
41+
Type: schema.TypeInt,
42+
Optional: true,
43+
Default: 1,
44+
Description: "Number of seconds between two tries for a command",
45+
},
46+
scriptShasumAttr: {
47+
Type: schema.TypeString,
48+
Computed: true,
49+
Description: "Shasum of commands",
50+
},
51+
},
52+
}
53+
}
54+
55+
func resourcePostgreSQLScriptCreateOrUpdate(db *DBConnection, d *schema.ResourceData) error {
56+
commands := d.Get(scriptCommandsAttr).([]any)
57+
tries := d.Get(scriptTriesAttr).(int)
58+
timeout := d.Get(scriptTimeoutAttr).(int)
59+
60+
sum := shasumCommands(commands)
61+
62+
if err := executeCommands(db, commands, tries, timeout); err != nil {
63+
return err
64+
}
65+
66+
d.Set(scriptShasumAttr, sum)
67+
d.SetId(sum)
68+
return nil
69+
}
70+
71+
func resourcePostgreSQLScriptRead(db *DBConnection, d *schema.ResourceData) error {
72+
commands := d.Get(scriptCommandsAttr).([]any)
73+
newSum := shasumCommands(commands)
74+
d.Set(scriptShasumAttr, newSum)
75+
76+
return nil
77+
}
78+
79+
func resourcePostgreSQLScriptDelete(db *DBConnection, d *schema.ResourceData) error {
80+
return nil
81+
}
82+
83+
func executeCommands(db *DBConnection, commands []any, tries int, timeout int) error {
84+
for _, command := range commands {
85+
for i := 1; ; i++ {
86+
_, err := db.Query(command.(string))
87+
if err != nil {
88+
if i >= tries {
89+
return err
90+
}
91+
time.Sleep(time.Duration(timeout) * time.Second)
92+
continue
93+
}
94+
break
95+
}
96+
}
97+
return nil
98+
}
99+
100+
func shasumCommands(commands []any) string {
101+
sha := sha1.New()
102+
for _, command := range commands {
103+
sha.Write([]byte(command.(string)))
104+
}
105+
return hex.EncodeToString(sha.Sum(nil))
106+
}
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package postgresql
2+
3+
import (
4+
"regexp"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
)
9+
10+
func TestAccPostgresqlScript_basic(t *testing.T) {
11+
config := `
12+
resource "postgresql_script" "test" {
13+
commands = [
14+
"SELECT 1;"
15+
]
16+
tries = 2
17+
timeout = 4
18+
}
19+
`
20+
21+
resource.Test(t, resource.TestCase{
22+
PreCheck: func() { testAccPreCheck(t) },
23+
Providers: testAccProviders,
24+
Steps: []resource.TestStep{
25+
{
26+
Config: config,
27+
Check: resource.ComposeTestCheckFunc(
28+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 1;"),
29+
resource.TestCheckResourceAttr("postgresql_script.test", "tries", "2"),
30+
resource.TestCheckResourceAttr("postgresql_script.test", "timeout", "4"),
31+
),
32+
},
33+
},
34+
})
35+
}
36+
37+
func TestAccPostgresqlScript_multiple(t *testing.T) {
38+
config := `
39+
resource "postgresql_script" "test" {
40+
commands = [
41+
"SELECT 1;",
42+
"SELECT 2;",
43+
"SELECT 3;"
44+
]
45+
tries = 2
46+
timeout = 4
47+
}
48+
`
49+
50+
resource.Test(t, resource.TestCase{
51+
PreCheck: func() { testAccPreCheck(t) },
52+
Providers: testAccProviders,
53+
Steps: []resource.TestStep{
54+
{
55+
Config: config,
56+
Check: resource.ComposeTestCheckFunc(
57+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 1;"),
58+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.1", "SELECT 2;"),
59+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.2", "SELECT 3;"),
60+
resource.TestCheckResourceAttr("postgresql_script.test", "tries", "2"),
61+
resource.TestCheckResourceAttr("postgresql_script.test", "timeout", "4"),
62+
),
63+
},
64+
},
65+
})
66+
}
67+
68+
func TestAccPostgresqlScript_default(t *testing.T) {
69+
config := `
70+
resource "postgresql_script" "test" {
71+
commands = [
72+
"SELECT 1;"
73+
]
74+
}
75+
`
76+
77+
resource.Test(t, resource.TestCase{
78+
PreCheck: func() { testAccPreCheck(t) },
79+
Providers: testAccProviders,
80+
Steps: []resource.TestStep{
81+
{
82+
Config: config,
83+
Check: resource.ComposeTestCheckFunc(
84+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 1;"),
85+
resource.TestCheckResourceAttr("postgresql_script.test", "tries", "1"),
86+
resource.TestCheckResourceAttr("postgresql_script.test", "timeout", "1"),
87+
),
88+
},
89+
},
90+
})
91+
}
92+
93+
func TestAccPostgresqlScript_reapply(t *testing.T) {
94+
config := `
95+
resource "postgresql_script" "test" {
96+
commands = [
97+
"SELECT 1;"
98+
]
99+
}
100+
`
101+
102+
configChange := `
103+
resource "postgresql_script" "test" {
104+
commands = [
105+
"SELECT 2;"
106+
]
107+
}
108+
`
109+
110+
resource.Test(t, resource.TestCase{
111+
PreCheck: func() { testAccPreCheck(t) },
112+
Providers: testAccProviders,
113+
Steps: []resource.TestStep{
114+
{
115+
Config: config,
116+
Check: resource.ComposeTestCheckFunc(
117+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 1;"),
118+
),
119+
},
120+
{
121+
Config: config,
122+
Check: resource.ComposeTestCheckFunc(
123+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 1;"),
124+
),
125+
},
126+
{
127+
Config: configChange,
128+
Check: resource.ComposeTestCheckFunc(
129+
resource.TestCheckResourceAttr("postgresql_script.test", "commands.0", "SELECT 2;"),
130+
),
131+
},
132+
},
133+
})
134+
}
135+
136+
func TestAccPostgresqlScript_fail(t *testing.T) {
137+
config := `
138+
resource "postgresql_script" "invalid" {
139+
commands = [
140+
"SLC FROM nowhere;"
141+
]
142+
tries = 2
143+
timeout = 2
144+
}
145+
`
146+
147+
resource.Test(t, resource.TestCase{
148+
PreCheck: func() { testAccPreCheck(t) },
149+
Providers: testAccProviders,
150+
Steps: []resource.TestStep{
151+
{
152+
Config: config,
153+
ExpectError: regexp.MustCompile("syntax error"),
154+
},
155+
},
156+
})
157+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
layout: "postgresql"
3+
page_title: "PostgreSQL: postgresql_script"
4+
sidebar_current: "docs-postgresql-resource-postgresql_script"
5+
description: |-
6+
Execute a SQL scipt
7+
---
8+
9+
# postgresql\_script
10+
11+
The ``postgresql_script`` execute a script given as parameter.
12+
13+
## Usage
14+
15+
```hcl
16+
resource "postgresql_script" "foo" {
17+
commands = [
18+
"command 1",
19+
"command 2"
20+
]
21+
tries = 1
22+
timeout = 1
23+
}
24+
```
25+
26+
## Argument Reference
27+
28+
* `commands` - (Required) An array of commands to execute, one by one.
29+
* `tries` - (Optional) Number of tries of a command before raising an error.
30+
* `timeout` - (Optional) Time in second between two failing commands.
31+
32+
## Examples
33+
34+
Revoke default accesses for public schema:
35+
36+
```hcl
37+
resource "postgresql_script" "foo" {
38+
commands = [
39+
"BEBIN",
40+
"SELECT * FROM table",
41+
"COMMIT"
42+
]
43+
tries = 3
44+
timeout = 1
45+
}
46+
```

0 commit comments

Comments
 (0)