Skip to content
This repository was archived by the owner on Jan 17, 2025. It is now read-only.

Commit 643389a

Browse files
committed
Grant/revoke for tables
1 parent 0220024 commit 643389a

3 files changed

Lines changed: 179 additions & 33 deletions

File tree

redshift/helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ func validatePrivileges(privileges []string, objectType string) bool {
172172
}
173173
case "DATABASE":
174174
switch strings.ToUpper(p) {
175-
case "CREATE", "TEMPORARY", "TEMP":
175+
case "CREATE", "TEMPORARY":
176176
continue
177177
default:
178178
return false

redshift/resource_redshift_grant.go

Lines changed: 85 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ func resourceRedshiftGrantReadImpl(db *DBConnection, d *schema.ResourceData) err
169169
switch objectType {
170170
case "database":
171171
return readGroupDatabaseGrants(db, d)
172+
case "schema":
173+
return readGroupSchemaGrants(db, d)
174+
case "table":
175+
return readGroupTableGrants(db, d)
172176
default:
173177
return fmt.Errorf("Unsupported %s %s", grantObjectTypeAttr, objectType)
174178
}
@@ -203,48 +207,99 @@ func readGroupDatabaseGrants(db *DBConnection, d *schema.ResourceData) error {
203207
return nil
204208
}
205209

206-
func readGroupGrantsForTables(tx *sql.Tx, groupName, schemaName string, tablesNames []string) ([]string, error) {
207-
var tables, tableSelect, tableUpdate, tableInsert, tableDelete, tableReferences int
210+
func readGroupSchemaGrants(db *DBConnection, d *schema.ResourceData) error {
211+
groupName := d.Get(grantGroupAttr).(string)
212+
schemaName := d.Get(grantSchemaAttr).(string)
213+
214+
var schemaCreate, schemaUsage bool
215+
208216
query := `
209217
SELECT
210-
nvl(count(cl.relname), 0) tables,
211-
nvl(sum(decode(charindex('r',split_part(split_part(array_to_string(relacl, '|'),pu.groname,2 ) ,'/',1)), 0,0,1)), 0) as select,
212-
nvl(sum(decode(charindex('w',split_part(split_part(array_to_string(relacl, '|'),pu.groname,2 ) ,'/',1)), 0,0,1)), 0) as update,
213-
nvl(sum(decode(charindex('a',split_part(split_part(array_to_string(relacl, '|'),pu.groname,2 ) ,'/',1)), 0,0,1)), 0) as insert,
214-
nvl(sum(decode(charindex('d',split_part(split_part(array_to_string(relacl, '|'),pu.groname,2 ) ,'/',1)), 0,0,1)), 0) as delete,
215-
nvl(sum(decode(charindex('x',split_part(split_part(array_to_string(relacl, '|'),pu.groname,2 ) ,'/',1)), 0,0,1)), 0) as references
216-
FROM pg_class cl
217-
JOIN pg_group gr ON array_to_string(cl.relacl, '|') LIKE '%group '||gr.groname||'=%'
218-
JOIN pg_namespace nsp ON nsp.oid = cl.relnamespace
218+
decode(charindex('C',split_part(split_part(array_to_string(ns.nspacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as create,
219+
decode(charindex('U',split_part(split_part(array_to_string(ns.nspacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as usage
220+
FROM pg_namespace ns, pg_group gr
219221
WHERE
220-
cl.relkind = 'r'
221-
AND gr.groname=$1
222-
AND nsp.nspname=$2
222+
ns.nspname=$1
223+
AND gr.groname=$2
223224
`
224225

225-
var err error = nil
226-
if len(tablesNames) > 0 {
227-
query = fmt.Sprintf("%s AND cl.relname = ANY($3)", query)
228-
err = tx.QueryRow(query, groupName, schemaName, pq.Array(tablesNames)).Scan(tables, tableSelect, tableUpdate, tableInsert, tableDelete, tableReferences)
229-
} else {
230-
err = tx.QueryRow(query, groupName, schemaName).Scan(tableSelect, tableUpdate, tableInsert, tableDelete, tableReferences)
226+
if err := db.QueryRow(query, schemaName, groupName).Scan(&schemaCreate, &schemaUsage); err != nil {
227+
return err
231228
}
232229

230+
privileges := []string{}
231+
appendIfTrue(schemaCreate, "create", &privileges)
232+
appendIfTrue(schemaUsage, "usage", &privileges)
233+
234+
log.Printf("[DEBUG] Collected schema '%s' privileges for group %s: %v", schemaName, groupName, privileges)
235+
236+
d.Set(grantPrivilegesAttr, privileges)
237+
238+
return nil
239+
}
240+
241+
func readGroupTableGrants(db *DBConnection, d *schema.ResourceData) error {
242+
query := `
243+
SELECT
244+
relname,
245+
decode(charindex('r',split_part(split_part(array_to_string(relacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as select,
246+
decode(charindex('w',split_part(split_part(array_to_string(relacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as update,
247+
decode(charindex('a',split_part(split_part(array_to_string(relacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as insert,
248+
decode(charindex('d',split_part(split_part(array_to_string(relacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as delete,
249+
decode(charindex('x',split_part(split_part(array_to_string(relacl, '|'),gr.groname,2 ) ,'/',1)), 0,0,1) as references
250+
FROM pg_group gr, pg_class cl
251+
JOIN pg_namespace nsp ON nsp.oid = cl.relnamespace
252+
WHERE
253+
cl.relkind = $1
254+
AND gr.groname=$2
255+
AND nsp.nspname=$3
256+
`
257+
258+
groupName := d.Get(grantGroupAttr).(string)
259+
schemaName := d.Get(grantSchemaAttr).(string)
260+
objects := d.Get(grantObjectsAttr).(*schema.Set)
261+
262+
rows, err := db.Query(query, grantObjectTypesCodes["table"], groupName, schemaName)
233263
if err != nil {
234-
return []string{}, fmt.Errorf("failed to collect group privileges: %w", err)
264+
return err
235265
}
236266

237-
privileges := []string{}
238-
expectedPrivileges := len(tablesNames)
239-
appendIfTrue(tableSelect == expectedPrivileges, "select", &privileges)
240-
appendIfTrue(tableUpdate == expectedPrivileges, "update", &privileges)
241-
appendIfTrue(tableInsert == expectedPrivileges, "insert", &privileges)
242-
appendIfTrue(tableDelete == expectedPrivileges, "delete", &privileges)
243-
appendIfTrue(tableReferences == expectedPrivileges, "references", &privileges)
267+
for rows.Next() {
268+
var objName string
269+
var tableSelect, tableUpdate, tableInsert, tableDelete, tableReferences bool
270+
271+
if err := rows.Scan(&objName, &tableSelect, &tableUpdate, &tableInsert, &tableDelete, &tableReferences); err != nil {
272+
return err
273+
}
274+
275+
if objects.Len() > 0 && !objects.Contains(objName) {
276+
continue
277+
}
278+
279+
privilegesSet := schema.NewSet(schema.HashString, nil)
280+
if tableSelect {
281+
privilegesSet.Add("select")
282+
}
283+
if tableUpdate {
284+
privilegesSet.Add("update")
285+
}
286+
if tableInsert {
287+
privilegesSet.Add("insert")
288+
}
289+
if tableDelete {
290+
privilegesSet.Add("delete")
291+
}
292+
if tableReferences {
293+
privilegesSet.Add("references")
294+
}
244295

245-
log.Printf("[DEBUG] Collected privileges for group %s: %v\n", groupName, privileges)
296+
if !privilegesSet.Equal(d.Get(grantPrivilegesAttr).(*schema.Set)) {
297+
d.Set(grantPrivilegesAttr, privilegesSet)
298+
break
299+
}
300+
}
246301

247-
return privileges, nil
302+
return nil
248303
}
249304

250305
func revokeGroupGrants(tx *sql.Tx, databaseName string, d *schema.ResourceData) error {

redshift/resource_redshift_grant_test.go

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import (
1212

1313
func TestAccRedshiftGrant_BasicDatabase(t *testing.T) {
1414
groupName := strings.ReplaceAll(acctest.RandomWithPrefix("tf_acc_group_basic"), "-", "_")
15-
//dbName := os.Getenv("REDSHIFT_DATABASE")
16-
1715
resource.Test(t, resource.TestCase{
1816
PreCheck: func() { testAccPreCheck(t) },
1917
Providers: testAccProviders,
@@ -46,3 +44,96 @@ resource "redshift_grant" "grant" {
4644
privileges = ["create", "temporary"]
4745
}`, groupName)
4846
}
47+
48+
func TestAccRedshiftGrant_BasicSchema(t *testing.T) {
49+
userName := strings.ReplaceAll(acctest.RandomWithPrefix("tf_acc_user_basic"), "-", "_")
50+
groupName := strings.ReplaceAll(acctest.RandomWithPrefix("tf_acc_group_basic"), "-", "_")
51+
schemaName := strings.ReplaceAll(acctest.RandomWithPrefix("tf_acc_schema_basic"), "-", "_")
52+
53+
resource.Test(t, resource.TestCase{
54+
PreCheck: func() { testAccPreCheck(t) },
55+
Providers: testAccProviders,
56+
CheckDestroy: func(s *terraform.State) error { return nil },
57+
Steps: []resource.TestStep{
58+
{
59+
Config: testAccRedshiftGrantConfig_BasicSchema(userName, groupName, schemaName),
60+
Check: resource.ComposeTestCheckFunc(
61+
resource.TestCheckResourceAttr("redshift_grant.grant", "id", fmt.Sprintf("%s_schema_%s", groupName, schemaName)),
62+
resource.TestCheckResourceAttr("redshift_grant.grant", "group", groupName),
63+
resource.TestCheckResourceAttr("redshift_grant.grant", "object_type", "schema"),
64+
resource.TestCheckResourceAttr("redshift_grant.grant", "privileges.#", "2"),
65+
resource.TestCheckTypeSetElemAttr("redshift_grant.grant", "privileges.*", "create"),
66+
resource.TestCheckTypeSetElemAttr("redshift_grant.grant", "privileges.*", "usage"),
67+
),
68+
},
69+
},
70+
})
71+
}
72+
73+
func testAccRedshiftGrantConfig_BasicSchema(userName, groupName, schemaName string) string {
74+
return fmt.Sprintf(`
75+
resource "redshift_user" "user" {
76+
name = %[1]q
77+
}
78+
79+
resource "redshift_group" "group" {
80+
name = %[2]q
81+
}
82+
83+
resource "redshift_schema" "schema" {
84+
name = %[3]q
85+
86+
owner = redshift_user.user.name
87+
}
88+
89+
resource "redshift_grant" "grant" {
90+
group = redshift_group.group.name
91+
schema = redshift_schema.schema.name
92+
93+
object_type = "schema"
94+
privileges = ["create", "usage"]
95+
}
96+
`, userName, groupName, schemaName)
97+
}
98+
99+
func TestAccRedshiftGrant_BasicTable(t *testing.T) {
100+
groupName := strings.ReplaceAll(acctest.RandomWithPrefix("tf_acc_group_basic"), "-", "_")
101+
102+
resource.Test(t, resource.TestCase{
103+
PreCheck: func() { testAccPreCheck(t) },
104+
Providers: testAccProviders,
105+
CheckDestroy: func(s *terraform.State) error { return nil },
106+
Steps: []resource.TestStep{
107+
{
108+
Config: testAccRedshiftGrantConfig_BasicTable(groupName),
109+
Check: resource.ComposeTestCheckFunc(
110+
resource.TestCheckResourceAttr("redshift_grant.grant", "id", fmt.Sprintf("%s_table_pg_catalog_pg_user_info", groupName)),
111+
resource.TestCheckResourceAttr("redshift_grant.grant", "group", groupName),
112+
resource.TestCheckResourceAttr("redshift_grant.grant", "schema", "pg_catalog"),
113+
resource.TestCheckResourceAttr("redshift_grant.grant", "object_type", "table"),
114+
resource.TestCheckResourceAttr("redshift_grant.grant", "objects.#", "1"),
115+
resource.TestCheckTypeSetElemAttr("redshift_grant.grant", "objects.*", "pg_user_info"),
116+
resource.TestCheckResourceAttr("redshift_grant.grant", "privileges.#", "1"),
117+
resource.TestCheckTypeSetElemAttr("redshift_grant.grant", "privileges.*", "select"),
118+
),
119+
},
120+
},
121+
})
122+
}
123+
124+
func testAccRedshiftGrantConfig_BasicTable(groupName string) string {
125+
return fmt.Sprintf(`
126+
resource "redshift_group" "group" {
127+
name = %[1]q
128+
}
129+
130+
resource "redshift_grant" "grant" {
131+
group = redshift_group.group.name
132+
schema = "pg_catalog"
133+
134+
object_type = "table"
135+
objects = ["pg_user_info"]
136+
privileges = ["select"]
137+
}
138+
`, groupName)
139+
}

0 commit comments

Comments
 (0)