Skip to content

Commit 076c76f

Browse files
Merge pull request #72 from IvanOfThings/feat/add-function-priviledges
feat: Add CREATE FUNCTION and DROP FUNCTION privileges support
2 parents 127c635 + c7fc4c0 commit 076c76f

File tree

3 files changed

+147
-2
lines changed

3 files changed

+147
-2
lines changed

pkg/resources/role/resource_role_acceptance_test.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ func generateTestSteps(testStepsData []TestStepData) []resource.TestStep {
173173
return testSteps
174174
}
175175

176+
func getTestableGlobalPrivileges() []string {
177+
var testable []string
178+
excludePrivileges := map[string]bool{
179+
"REMOTE": true,
180+
"S3": true,
181+
}
182+
for _, priv := range resourcerole.AllowedGlobalPrivileges {
183+
if !excludePrivileges[priv] {
184+
testable = append(testable, priv)
185+
}
186+
}
187+
return testable
188+
}
189+
176190
func TestAccResourceRole(t *testing.T) {
177191
// Feature tests, user database
178192
resource.Test(t, resource.TestCase{
@@ -187,7 +201,7 @@ func TestAccResourceRole(t *testing.T) {
187201
CheckDestroy: testAccCheckRoleResourceDestroy([]string{roleName1, roleName2}),
188202
Steps: generateTestSteps(test2StepsData),
189203
})
190-
// Feature tests, global privileges
204+
// Feature tests, global privileges (excluding REMOTE and S3 which get expanded by ClickHouse)
191205
resource.Test(t, resource.TestCase{
192206
Providers: testutils.Provider(),
193207
CheckDestroy: testAccCheckRoleResourceDestroy([]string{roleName1, roleName2}),
@@ -196,7 +210,7 @@ func TestAccResourceRole(t *testing.T) {
196210
// Create role
197211
roleName: roleName1,
198212
database: "*",
199-
privileges: resourcerole.AllowedGlobalPrivileges,
213+
privileges: getTestableGlobalPrivileges(),
200214
}}),
201215
})
202216
// Validate privileges on create
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package resourcerole_test
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"regexp"
7+
"testing"
8+
9+
"github.com/IvanOfThings/terraform-provider-clickhouse/pkg/common"
10+
resourcerole "github.com/IvanOfThings/terraform-provider-clickhouse/pkg/resources/role"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
13+
14+
"github.com/IvanOfThings/terraform-provider-clickhouse/pkg/testutils"
15+
)
16+
17+
const functionRoleName = "test_function_role"
18+
const functionRoleResource = "clickhouse_role.test_function_role"
19+
20+
func TestAccResourceRole_FunctionPrivileges(t *testing.T) {
21+
resource.Test(t, resource.TestCase{
22+
Providers: testutils.Provider(),
23+
CheckDestroy: testAccCheckRoleResourceDestroy([]string{functionRoleName}),
24+
Steps: []resource.TestStep{
25+
{
26+
Config: `
27+
resource "clickhouse_role" "test_function_role" {
28+
name = "test_function_role"
29+
database = "*"
30+
privileges = ["CREATE FUNCTION", "DROP FUNCTION"]
31+
}
32+
`,
33+
Check: resource.ComposeTestCheckFunc(
34+
resource.TestMatchResourceAttr(
35+
functionRoleResource,
36+
"name",
37+
regexp.MustCompile(functionRoleName),
38+
),
39+
resource.TestMatchResourceAttr(
40+
functionRoleResource,
41+
"database",
42+
regexp.MustCompile("\\*"),
43+
),
44+
testutils.CheckStateSetAttr("privileges", functionRoleResource, []string{"CREATE FUNCTION", "DROP FUNCTION"}),
45+
testAccCheckFunctionPrivilegesExist(functionRoleName, []string{"CREATE FUNCTION", "DROP FUNCTION"}),
46+
),
47+
},
48+
},
49+
})
50+
}
51+
52+
func TestAccResourceRole_ValidationCreateFunction(t *testing.T) {
53+
resource.Test(t, resource.TestCase{
54+
Providers: testutils.Provider(),
55+
Steps: []resource.TestStep{
56+
{
57+
Config: `
58+
resource "clickhouse_db" "test_validation_db" {
59+
name = "test_validation_db"
60+
comment = "test db"
61+
}
62+
63+
resource "clickhouse_role" "test_role" {
64+
name = "test_role"
65+
database = clickhouse_db.test_validation_db.name
66+
privileges = ["CREATE FUNCTION"]
67+
}
68+
`,
69+
ExpectError: regexp.MustCompile("Global privilege CREATE FUNCTION is only allowed for database '\\*'"),
70+
},
71+
},
72+
})
73+
}
74+
75+
func TestAccResourceRole_ValidationDropFunction(t *testing.T) {
76+
resource.Test(t, resource.TestCase{
77+
Providers: testutils.Provider(),
78+
Steps: []resource.TestStep{
79+
{
80+
Config: `
81+
resource "clickhouse_db" "test_validation_db" {
82+
name = "test_validation_db"
83+
comment = "test db"
84+
}
85+
86+
resource "clickhouse_role" "test_role" {
87+
name = "test_role"
88+
database = clickhouse_db.test_validation_db.name
89+
privileges = ["DROP FUNCTION"]
90+
}
91+
`,
92+
ExpectError: regexp.MustCompile("Global privilege DROP FUNCTION is only allowed for database '\\*'"),
93+
},
94+
},
95+
})
96+
}
97+
98+
func testAccCheckFunctionPrivilegesExist(roleName string, expectedPrivileges []string) resource.TestCheckFunc {
99+
return func(state *terraform.State) error {
100+
client := testutils.TestAccProvider.Meta().(*common.ApiClient)
101+
conn := client.ClickhouseConnection
102+
chRoleService := resourcerole.CHRoleService{CHConnection: conn}
103+
104+
dbRole, err := chRoleService.GetRole(context.Background(), roleName)
105+
if err != nil {
106+
return fmt.Errorf("get role: %v", err)
107+
}
108+
if dbRole == nil {
109+
return fmt.Errorf("role %s not found", roleName)
110+
}
111+
112+
if len(expectedPrivileges) != len(dbRole.Privileges) {
113+
return fmt.Errorf("expected %d privileges, got %d", len(expectedPrivileges), len(dbRole.Privileges))
114+
}
115+
116+
privilegeMap := make(map[string]bool)
117+
for _, priv := range dbRole.Privileges {
118+
privilegeMap[priv.AccessType] = true
119+
}
120+
121+
for _, expected := range expectedPrivileges {
122+
if !privilegeMap[expected] {
123+
return fmt.Errorf("privilege %s not found in role", expected)
124+
}
125+
}
126+
127+
return nil
128+
}
129+
}

pkg/resources/role/validators.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ var AllowedGlobalPrivileges = []string{
3131
"SYSTEM RELOAD DICTIONARY",
3232
"S3",
3333
"CREATE TEMPORARY TABLE",
34+
"CREATE FUNCTION",
35+
"DROP FUNCTION",
3436
}
3537

3638
var AllowedPrivileges = append(AllowedDbLevelPrivileges, AllowedGlobalPrivileges...)

0 commit comments

Comments
 (0)