diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d9310a65d1..0882eefb59 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -72,7 +72,7 @@ role = "" host="" ``` -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. diff --git a/Makefile b/Makefile index c47bd5a031..46d53e635f 100644 --- a/Makefile +++ b/Makefile @@ -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 ./... diff --git a/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/config.yaml b/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/config.yaml new file mode 100644 index 0000000000..fc735db0fd --- /dev/null +++ b/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/config.yaml @@ -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: \ No newline at end of file diff --git a/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/main.tf b/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/main.tf new file mode 100644 index 0000000000..bf19044eba --- /dev/null +++ b/pkg/resources/manual_tests/granting_role_to_multiple_users_or_roles/main.tf @@ -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 +} diff --git a/pkg/sdk/testint/setup_test.go b/pkg/sdk/testint/setup_test.go index d09be1d489..9cfa0abc7b 100644 --- a/pkg/sdk/testint/setup_test.go +++ b/pkg/sdk/testint/setup_test.go @@ -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 @@ -154,6 +154,10 @@ 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 @@ -161,21 +165,21 @@ func (itc *integrationTestContext) initialize() error { 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 @@ -206,12 +210,12 @@ 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 } @@ -219,12 +223,12 @@ func createDb(client *sdk.Client, ctx context.Context) (*sdk.Database, func(), e 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 } @@ -232,12 +236,12 @@ func createSc(client *sdk.Client, ctx context.Context, db *sdk.Database) (*sdk.S 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 }