Skip to content

Commit

Permalink
chore: Example of granting role to multiple objects (#3047)
Browse files Browse the repository at this point in the history
- Add example of granting role to multiple objects
- Fix setup for the integration tests when using just a single account
  • Loading branch information
sfc-gh-asawicki committed Sep 6, 2024
1 parent 5802dca commit 86a7902
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 14 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ role = "<any role, e.g. ACCOUNTADMIN>"
host="<host of your account, e.g. organisation-account_name.snowflakecomputing.com>"
```

We are aware that not everyone has access two multiple accounts, so the majority of tests can be run using just one account. The tests setup however, requires both profiles (`default` and `secondary_test_account`) to be present. You can use the same details for `secondary_test_account` as in the `default` one, if you don't plan to run tests requiring multiple accounts.
We are aware that not everyone has access two multiple accounts, so the majority of tests can be run using just one account. The tests setup however, requires both profiles (`default` and `secondary_test_account`) to be present. You can use the same details for `secondary_test_account` as in the `default` one, if you don't plan to run tests requiring multiple accounts. The warning will be logged when setting up tests with just a single account.

**⚠️ Important ⚠️** Some of the tests require the privileged role (like `ACCOUNTADMIN`). Otherwise, the managed objects may not be created. If you want to use lower role, you have to make sure it has all the necessary privileges added.

Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ test: test-client ## run unit and integration tests
go test -v -cover -timeout=45m ./...

test-acceptance: ## run acceptance tests
TF_ACC=1 SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 go test -run "^TestAcc_" -v -cover -timeout=60m ./...
TF_ACC=1 SF_TF_ACC_TEST_CONFIGURE_CLIENT_ONCE=true TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 go test -run "^TestAcc_" -v -cover -timeout=90m ./...

test-integration: ## run SDK integration tests
TEST_SF_TF_REQUIRE_TEST_OBJECT_SUFFIX=1 go test -run "^TestInt_" -v -cover -timeout=45m ./...
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
roles:
"example_role1":
grant_to:
user:
- "example_user1"
role:
"example_role2":
grant_to:
user:
role:
- "example_role3"
"example_role3":
grant_to:
user:
- "example_user1"
- "example_user2"
- "example_user3"
role:
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
terraform {
required_version = ">= 1.3.6"
required_providers {
snowflake = {
source = "snowflake-labs/snowflake"
version = "0.94.1"
}
}
}

resource "snowflake_user" "user1" {
name = "example_user1"
}

resource "snowflake_user" "user2" {
name = "example_user2"
}

resource "snowflake_user" "user3" {
name = "example_user3"
}

resource "snowflake_account_role" "role1" {
name = "example_role1"
}

resource "snowflake_account_role" "role2" {
name = "example_role2"
}

resource "snowflake_account_role" "role3" {
name = "example_role3"
}

locals {
yaml_roles = yamldecode(file("${path.module}/config.yaml"))
grant_to_user = distinct(flatten([
for k, v in local.yaml_roles.roles : v.grant_to.user == null ? [] : [
for u in v.grant_to.user : {
role = k
to_user = u
}
]]))
grant_to_role = distinct(flatten([
for k, v in local.yaml_roles.roles : v.grant_to.role == null ? [] : [
for r in v.grant_to.role : {
role = k
to_role = r
}
]]))
}

output "grant_to_user_output" {
value = local.grant_to_user
}

output "grant_to_role_output" {
value = local.grant_to_role
}

resource "snowflake_grant_account_role" "user_grants" {
depends_on = [
snowflake_user.user1, snowflake_user.user2, snowflake_user.user3, snowflake_account_role.role1,
snowflake_account_role.role2, snowflake_account_role.role3
]
for_each = {for entry in local.grant_to_user : "${entry.role}.${entry.to_user}" => entry}
role_name = each.value.role
user_name = each.value.to_user
}

resource "snowflake_grant_account_role" "role_grants" {
depends_on = [
snowflake_user.user1, snowflake_user.user2, snowflake_user.user3, snowflake_account_role.role1,
snowflake_account_role.role2, snowflake_account_role.role3
]
for_each = {for entry in local.grant_to_role : "${entry.role}.${entry.to_role}" => entry}
role_name = each.value.role
parent_role_name = each.value.to_role
}
28 changes: 16 additions & 12 deletions pkg/sdk/testint/setup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,21 @@ func (itc *integrationTestContext) initialize() error {
itc.client = c
itc.ctx = context.Background()

db, dbCleanup, err := createDb(itc.client, itc.ctx)
db, dbCleanup, err := createDb(itc.client, itc.ctx, false)
itc.databaseCleanup = dbCleanup
if err != nil {
return err
}
itc.database = db

sc, scCleanup, err := createSc(itc.client, itc.ctx, itc.database)
sc, scCleanup, err := createSc(itc.client, itc.ctx, itc.database, false)
itc.schemaCleanup = scCleanup
if err != nil {
return err
}
itc.schema = sc

wh, whCleanup, err := createWh(itc.client, itc.ctx)
wh, whCleanup, err := createWh(itc.client, itc.ctx, false)
itc.warehouseCleanup = whCleanup
if err != nil {
return err
Expand All @@ -154,28 +154,32 @@ func (itc *integrationTestContext) initialize() error {
return err
}

if config.Account == defaultConfig.Account {
log.Println("[WARN] default and secondary configs are set to the same account; it may cause problems in tests requiring multiple accounts")
}

secondaryClient, err := sdk.NewClient(config)
if err != nil {
return err
}
itc.secondaryClient = secondaryClient
itc.secondaryCtx = context.Background()

secondaryDb, secondaryDbCleanup, err := createDb(itc.secondaryClient, itc.secondaryCtx)
secondaryDb, secondaryDbCleanup, err := createDb(itc.secondaryClient, itc.secondaryCtx, true)
itc.secondaryDatabaseCleanup = secondaryDbCleanup
if err != nil {
return err
}
itc.secondaryDatabase = secondaryDb

secondarySchema, secondarySchemaCleanup, err := createSc(itc.secondaryClient, itc.secondaryCtx, itc.database)
secondarySchema, secondarySchemaCleanup, err := createSc(itc.secondaryClient, itc.secondaryCtx, itc.database, true)
itc.secondarySchemaCleanup = secondarySchemaCleanup
if err != nil {
return err
}
itc.secondarySchema = secondarySchema

secondaryWarehouse, secondaryWarehouseCleanup, err := createWh(itc.secondaryClient, itc.secondaryCtx)
secondaryWarehouse, secondaryWarehouseCleanup, err := createWh(itc.secondaryClient, itc.secondaryCtx, true)
itc.secondaryWarehouseCleanup = secondaryWarehouseCleanup
if err != nil {
return err
Expand Down Expand Up @@ -206,38 +210,38 @@ func (itc *integrationTestContext) initialize() error {
return nil
}

func createDb(client *sdk.Client, ctx context.Context) (*sdk.Database, func(), error) {
func createDb(client *sdk.Client, ctx context.Context, ifNotExists bool) (*sdk.Database, func(), error) {
id := sdk.NewAccountObjectIdentifier(TestDatabaseName)
cleanup := func() {
_ = client.Databases.Drop(ctx, id, &sdk.DropDatabaseOptions{IfExists: sdk.Bool(true)})
}
err := client.Databases.Create(ctx, id, nil)
err := client.Databases.Create(ctx, id, &sdk.CreateDatabaseOptions{IfNotExists: sdk.Bool(ifNotExists)})
if err != nil {
return nil, cleanup, err
}
database, err := client.Databases.ShowByID(ctx, id)
return database, cleanup, err
}

func createSc(client *sdk.Client, ctx context.Context, db *sdk.Database) (*sdk.Schema, func(), error) {
func createSc(client *sdk.Client, ctx context.Context, db *sdk.Database, ifNotExists bool) (*sdk.Schema, func(), error) {
id := sdk.NewDatabaseObjectIdentifier(db.Name, TestSchemaName)
cleanup := func() {
_ = client.Schemas.Drop(ctx, id, &sdk.DropSchemaOptions{IfExists: sdk.Bool(true)})
}
err := client.Schemas.Create(ctx, id, nil)
err := client.Schemas.Create(ctx, id, &sdk.CreateSchemaOptions{IfNotExists: sdk.Bool(ifNotExists)})
if err != nil {
return nil, cleanup, err
}
schema, err := client.Schemas.ShowByID(ctx, sdk.NewDatabaseObjectIdentifier(db.Name, TestSchemaName))
return schema, cleanup, err
}

func createWh(client *sdk.Client, ctx context.Context) (*sdk.Warehouse, func(), error) {
func createWh(client *sdk.Client, ctx context.Context, ifNotExists bool) (*sdk.Warehouse, func(), error) {
id := sdk.NewAccountObjectIdentifier(TestWarehouseName)
cleanup := func() {
_ = client.Warehouses.Drop(ctx, id, &sdk.DropWarehouseOptions{IfExists: sdk.Bool(true)})
}
err := client.Warehouses.Create(ctx, id, nil)
err := client.Warehouses.Create(ctx, id, &sdk.CreateWarehouseOptions{IfNotExists: sdk.Bool(ifNotExists)})
if err != nil {
return nil, cleanup, err
}
Expand Down

0 comments on commit 86a7902

Please sign in to comment.