diff --git a/pkg/provider/provider.go b/pkg/provider/provider.go index ac77870a3c7..92a0e0dc496 100644 --- a/pkg/provider/provider.go +++ b/pkg/provider/provider.go @@ -448,6 +448,7 @@ func getResources() map[string]*schema.Resource { "snowflake_grant_privileges_to_role": resources.GrantPrivilegesToRole(), "snowflake_grant_privileges_to_account_role": resources.GrantPrivilegesToAccountRole(), "snowflake_grant_privileges_to_database_role": resources.GrantPrivilegesToDatabaseRole(), + "snowflake_grant_privileges_to_share": resources.GrantPrivilegesToShare(), "snowflake_managed_account": resources.ManagedAccount(), "snowflake_masking_policy": resources.MaskingPolicy(), "snowflake_materialized_view": resources.MaterializedView(), diff --git a/pkg/resources/grant_privileges_to_account_role.go b/pkg/resources/grant_privileges_to_account_role.go index 01b42e18c39..77a464a01b1 100644 --- a/pkg/resources/grant_privileges_to_account_role.go +++ b/pkg/resources/grant_privileges_to_account_role.go @@ -656,7 +656,7 @@ func DeleteGrantPrivilegesToAccountRole(ctx context.Context, d *schema.ResourceD diag.Diagnostic{ Severity: diag.Error, Summary: "An error occurred when revoking privileges from account role", - Detail: fmt.Sprintf("Id: %s\nAccount role name: %s\nError: %s", d.Id(), id.RoleName, err.Error()), + Detail: fmt.Sprintf("Id: %s\nAccount role name: %s\nError: %s", d.Id(), id.RoleName.FullyQualifiedName(), err.Error()), }, } } diff --git a/pkg/resources/grant_privileges_to_database_role_acceptance_test.go b/pkg/resources/grant_privileges_to_database_role_acceptance_test.go index 2a704dd7c3f..55ad93a035c 100644 --- a/pkg/resources/grant_privileges_to_database_role_acceptance_test.go +++ b/pkg/resources/grant_privileges_to_database_role_acceptance_test.go @@ -46,7 +46,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase(t *testing.T) { Steps: []resource.TestStep{ { PreConfig: func() { createDatabaseRoleOutsideTerraform(t, name) }, - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabase"), + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabaseShareGrantKind"), ConfigVariables: configVariables, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "database_role_name", databaseRoleName), @@ -56,11 +56,11 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "privileges.2", string(sdk.AccountObjectPrivilegeUsage)), resource.TestCheckResourceAttr(resourceName, "on_database", databaseName), resource.TestCheckResourceAttr(resourceName, "with_grant_option", "true"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE SCHEMA,MODIFY,USAGE|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE SCHEMA,MODIFY,USAGE|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabase"), + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabaseShareGrantKind"), ConfigVariables: configVariables, ResourceName: resourceName, ImportState: true, @@ -97,7 +97,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase_PrivilegesReversed(t *test Steps: []resource.TestStep{ { PreConfig: func() { createDatabaseRoleOutsideTerraform(t, name) }, - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabase"), + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabaseShareGrantKind"), ConfigVariables: configVariables, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "database_role_name", databaseRoleName), @@ -107,11 +107,11 @@ func TestAcc_GrantPrivilegesToDatabaseRole_OnDatabase_PrivilegesReversed(t *test resource.TestCheckResourceAttr(resourceName, "privileges.2", string(sdk.AccountObjectPrivilegeUsage)), resource.TestCheckResourceAttr(resourceName, "on_database", databaseName), resource.TestCheckResourceAttr(resourceName, "with_grant_option", "true"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE SCHEMA,MODIFY,USAGE|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|true|false|CREATE SCHEMA,MODIFY,USAGE|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { - ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabase"), + ConfigDirectory: acc.ConfigurationDirectory("TestAcc_GrantPrivilegesToDatabaseRole/OnDatabaseShareGrantKind"), ConfigVariables: configVariables, ResourceName: resourceName, ImportState: true, @@ -524,7 +524,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"), resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeCreateSchema)), resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeModify)), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,MODIFY|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,MODIFY|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { @@ -540,7 +540,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeCreateSchema)), resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeMonitor)), resource.TestCheckResourceAttr(resourceName, "privileges.2", string(sdk.AccountObjectPrivilegeUsage)), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { @@ -549,7 +549,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) { Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "all_privileges", "true"), resource.TestCheckResourceAttr(resourceName, "privileges.#", "0"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { @@ -563,7 +563,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_UpdatePrivileges(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "privileges.#", "2"), resource.TestCheckResourceAttr(resourceName, "privileges.0", string(sdk.AccountObjectPrivilegeModify)), resource.TestCheckResourceAttr(resourceName, "privileges.1", string(sdk.AccountObjectPrivilegeMonitor)), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|MODIFY,MONITOR|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|MODIFY,MONITOR|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, }, @@ -691,7 +691,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "always_apply", "false"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, { @@ -699,7 +699,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) { ConfigVariables: configVariables(true), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "always_apply", "true"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), ExpectNonEmptyPlan: true, }, @@ -713,7 +713,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "always_apply", "true"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), ExpectNonEmptyPlan: true, }, @@ -727,7 +727,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "always_apply", "true"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|true|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), ExpectNonEmptyPlan: true, }, @@ -741,7 +741,7 @@ func TestAcc_GrantPrivilegesToDatabaseRole_AlwaysApply(t *testing.T) { }, Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "always_apply", "false"), - resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabase|%s", databaseRoleName, databaseName)), + resource.TestCheckResourceAttr(resourceName, "id", fmt.Sprintf("%s|false|false|ALL|OnDatabaseShareGrantKind|%s", databaseRoleName, databaseName)), ), }, }, diff --git a/pkg/resources/grant_privileges_to_database_role_identifier.go b/pkg/resources/grant_privileges_to_database_role_identifier.go index 56e4ec2044c..f42f0a260e7 100644 --- a/pkg/resources/grant_privileges_to_database_role_identifier.go +++ b/pkg/resources/grant_privileges_to_database_role_identifier.go @@ -12,7 +12,7 @@ import ( type DatabaseRoleGrantKind string const ( - OnDatabaseDatabaseRoleGrantKind DatabaseRoleGrantKind = "OnDatabase" + OnDatabaseDatabaseRoleGrantKind DatabaseRoleGrantKind = "OnDatabaseShareGrantKind" OnSchemaDatabaseRoleGrantKind DatabaseRoleGrantKind = "OnSchema" OnSchemaObjectDatabaseRoleGrantKind DatabaseRoleGrantKind = "OnSchemaObject" ) diff --git a/pkg/resources/grant_privileges_to_database_role_identifier_test.go b/pkg/resources/grant_privileges_to_database_role_identifier_test.go index ea8cd4404b5..d80a25d63ce 100644 --- a/pkg/resources/grant_privileges_to_database_role_identifier_test.go +++ b/pkg/resources/grant_privileges_to_database_role_identifier_test.go @@ -16,7 +16,7 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) { }{ { Name: "grant database role on database", - Identifier: `"database-name"."database-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabaseShareGrantKind|"on-database-name"`, Expected: GrantPrivilegesToDatabaseRoleId{ DatabaseRoleName: sdk.NewDatabaseObjectIdentifier("database-name", "database-role"), WithGrantOption: false, @@ -29,7 +29,7 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) { }, { Name: "grant database role on database - always apply with grant option", - Identifier: `"database-name"."database-role"|true|true|CREATE SCHEMA,USAGE,MONITOR|OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"|true|true|CREATE SCHEMA,USAGE,MONITOR|OnDatabaseShareGrantKind|"on-database-name"`, Expected: GrantPrivilegesToDatabaseRoleId{ DatabaseRoleName: sdk.NewDatabaseObjectIdentifier("database-name", "database-role"), WithGrantOption: true, @@ -43,7 +43,7 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) { }, { Name: "grant database role on database - all privileges", - Identifier: `"database-name"."database-role"|false|false|ALL|OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"|false|false|ALL|OnDatabaseShareGrantKind|"on-database-name"`, Expected: GrantPrivilegesToDatabaseRoleId{ DatabaseRoleName: sdk.NewDatabaseObjectIdentifier("database-name", "database-role"), WithGrantOption: false, @@ -224,8 +224,8 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) { Error: "database role identifier should hold at least 6 parts", }, { - Name: "validation: grant database role not enough parts for OnDatabase kind", - Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabase`, + Name: "validation: grant database role not enough parts for OnDatabaseShareGrantKind kind", + Identifier: `"database-name"."role-name"|false|false|CREATE SCHEMA,USAGE,MONITOR|OnDatabaseShareGrantKind`, Error: "database role identifier should hold at least 6 parts", }, { @@ -265,22 +265,22 @@ func TestParseGrantPrivilegesToDatabaseRoleId(t *testing.T) { }, { Name: "validation: grant database role empty privileges", - Identifier: `"database-name"."database-role"|false|false||OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"|false|false||OnDatabaseShareGrantKind|"on-database-name"`, Error: `invalid Privileges value: , should be either a comma separated list of privileges or "ALL" / "ALL PRIVILEGES" for all privileges`, }, { Name: "validation: grant database role empty with grant option", - Identifier: `"database-name"."database-role"||false|ALL PRIVILEGES|OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"||false|ALL PRIVILEGES|OnDatabaseShareGrantKind|"on-database-name"`, Error: `invalid WithGrantOption value: , should be either "true" or "false"`, }, { Name: "validation: grant database role empty always apply", - Identifier: `"database-name"."database-role"|false||ALL PRIVILEGES|OnDatabase|"on-database-name"`, + Identifier: `"database-name"."database-role"|false||ALL PRIVILEGES|OnDatabaseShareGrantKind|"on-database-name"`, Error: `invalid AlwaysApply value: , should be either "true" or "false"`, }, { Name: "validation: grant database role empty database role name", - Identifier: `|false|false|ALL PRIVILEGES|OnDatabase|"on-database-name"`, + Identifier: `|false|false|ALL PRIVILEGES|OnDatabaseShareGrantKind|"on-database-name"`, Error: "invalid DatabaseRoleName value: , should be a fully qualified name of database object .", }, { @@ -323,7 +323,7 @@ func TestGrantPrivilegesToDatabaseRoleIdString(t *testing.T) { DatabaseName: sdk.NewAccountObjectIdentifier("database-name"), }, }, - Expected: `"database-name"."role-name"|true|true|ALL|OnDatabase|"database-name"`, + Expected: `"database-name"."role-name"|true|true|ALL|OnDatabaseShareGrantKind|"database-name"`, }, { Name: "grant database role on schema on schema", diff --git a/pkg/resources/grant_privileges_to_share.go b/pkg/resources/grant_privileges_to_share.go new file mode 100644 index 00000000000..0867f69eb38 --- /dev/null +++ b/pkg/resources/grant_privileges_to_share.go @@ -0,0 +1,391 @@ +package resources + +import ( + "context" + "database/sql" + "fmt" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/logging" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "log" + "slices" +) + +var grantPrivilegesToShareGrantExactlyOneOfValidation = []string{ + "database_name", + "schema_name", + //"function_name", + "table_name", + "all_tables_in_schema", + "tag_name", + "view_name", +} + +var grantPrivilegesToShareSchema = map[string]*schema.Schema{ + "share_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: "The fully qualified name of the share on which privileges will be granted.", + ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), + }, + "privileges": { + Type: schema.TypeSet, + Required: true, + Description: "The privileges to grant on the share.", + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "database_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, + "schema_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, + // TODO(SNOW-1021686): Because function identifier contains arguments which are not supported right now + //"function_name": { + // Type: schema.TypeString, + // Optional: true, + // ForceNew: true, + // Description: "TODO", + // ValidateDiagFunc: IsValidIdentifier[sdk.FunctionIdentifier](), + // ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + //}, + "table_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, + "all_tables_in_schema": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.DatabaseObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, + "tag_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.AccountObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, + "view_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "TODO", + ValidateDiagFunc: IsValidIdentifier[sdk.SchemaObjectIdentifier](), + ExactlyOneOf: grantPrivilegesToShareGrantExactlyOneOfValidation, + }, +} + +func GrantPrivilegesToShare() *schema.Resource { + return &schema.Resource{ + CreateContext: CreateGrantPrivilegesToShare, + UpdateContext: UpdateGrantPrivilegesToShare, + DeleteContext: DeleteGrantPrivilegesToShare, + ReadContext: ReadGrantPrivilegesToShare, + + Schema: grantPrivilegesToShareSchema, + Importer: &schema.ResourceImporter{ + StateContext: ImportGrantPrivilegesToShare(), + }, + } +} + +func ImportGrantPrivilegesToShare() func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + return func(ctx context.Context, d *schema.ResourceData, m interface{}) ([]*schema.ResourceData, error) { + id, err := ParseGrantPrivilegesToShareId(d.Id()) + if err != nil { + return nil, err + } + if err := d.Set("share_name", id.ShareName.FullyQualifiedName()); err != nil { + return nil, err + } + if err := d.Set("privileges", id.Privileges); err != nil { + return nil, err + } + + switch id.Kind { + case OnDatabaseShareGrantKind: + if err := d.Set("database_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnSchemaShareGrantKind: + if err := d.Set("schema_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnFunctionShareGrantKind: + if err := d.Set("function_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnTableShareGrantKind: + if err := d.Set("table_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnAllTablesInSchemaShareGrantKind: + if err := d.Set("all_tables_in_schema", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnTagShareGrantKind: + if err := d.Set("tag_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + case OnViewShareGrantKind: + if err := d.Set("view_name", id.Identifier.FullyQualifiedName()); err != nil { + return nil, err + } + } + + return []*schema.ResourceData{d}, nil + } +} + +func CreateGrantPrivilegesToShare(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + id := createGrantPrivilegesToShareIdFromSchema(d) + log.Printf("[DEBUG] created identifier from schema: %s", id.String()) + + err := client.Grants.GrantPrivilegeToShare(ctx, getObjectPrivilegesFromSchema(d), getShareGrantOn(d), id.ShareName) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "An error occurred when granting privileges to share", + Detail: fmt.Sprintf("Id: %s\nShare name: %s\nError: %s", id.String(), id.ShareName, err.Error()), + }, + } + } + + d.SetId(id.String()) + + return ReadGrantPrivilegesToShare(ctx, d, meta) +} + +func UpdateGrantPrivilegesToShare(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + return ReadGrantPrivilegesToShare(ctx, d, meta) +} + +func DeleteGrantPrivilegesToShare(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + + id, err := ParseGrantPrivilegesToShareId(d.Id()) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to parse internal identifier", + Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()), + }, + } + } + + err = client.Grants.RevokePrivilegeFromShare(ctx, getObjectPrivilegesFromSchema(d), getShareGrantOn(d), id.ShareName) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "An error occurred when revoking privileges from share", + Detail: fmt.Sprintf("Id: %s\nShare name: %s\nError: %s", d.Id(), id.ShareName.FullyQualifiedName(), err.Error()), + }, + } + } + + d.SetId("") + + return nil +} + +func ReadGrantPrivilegesToShare(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + id, err := ParseGrantPrivilegesToShareId(d.Id()) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to parse internal identifier", + Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()), + }, + } + } + + opts, grantedOn, diags := prepareShowGrantsRequestForShare(id) + if len(diags) != 0 { + return diags + } + + db := meta.(*sql.DB) + client := sdk.NewClientFromDB(db) + grants, err := client.Grants.Show(ctx, opts) + if err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Failed to retrieve grants", + Detail: fmt.Sprintf("Id: %s\nError: %s", d.Id(), err.Error()), + }, + } + } + + // TODO: Read for + var privileges []string + + logging.DebugLogger.Printf("[DEBUG] Filtering grants to be set on account: count = %d", len(grants)) + for _, grant := range grants { + if grant.GrantedTo != sdk.ObjectTypeShare { + continue + } + // Only consider privileges that are already present in the ID, so we + // don't delete privileges managed by other resources. + if !slices.Contains(id.Privileges, grant.Privilege) { + continue + } + if grant.GranteeName.Name() == id.ShareName.Name() { // TODO: id.ShareName should be outside resource identifier (forgot the name) + if grantedOn == grant.GrantedOn { + privileges = append(privileges, grant.Privilege) + } + } + } + + logging.DebugLogger.Printf("[DEBUG] Setting privileges: %v", privileges) + if err := d.Set("privileges", privileges); err != nil { + return diag.Diagnostics{ + diag.Diagnostic{ + Severity: diag.Error, + Summary: "Error setting privileges for account role", + Detail: fmt.Sprintf("Id: %s\nPrivileges: %v\nError: %s", d.Id(), privileges, err.Error()), + }, + } + } + + return nil +} + +func createGrantPrivilegesToShareIdFromSchema(d *schema.ResourceData) *GrantPrivilegesToShareId { + id := new(GrantPrivilegesToShareId) + id.ShareName = sdk.NewAccountObjectIdentifier(d.Get("share_name").(string)) + id.Privileges = expandStringList(d.Get("privileges").(*schema.Set).List()) + + databaseName, databaseNameOk := d.GetOk("database_name") + schemaName, schemaNameOk := d.GetOk("schema_name") + tableName, tableNameOk := d.GetOk("table_name") + allTablesInSchema, allTablesInSchemaOk := d.GetOk("all_tables_in_schema") + tagName, tagNameOk := d.GetOk("tag_name") + viewName, viewNameOk := d.GetOk("view_name") + + switch { + case databaseNameOk: + id.Kind = OnDatabaseShareGrantKind + id.Identifier = sdk.NewAccountObjectIdentifierFromFullyQualifiedName(databaseName.(string)) + case schemaNameOk: + id.Kind = OnSchemaShareGrantKind + id.Identifier = sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(schemaName.(string)) + case tableNameOk: + id.Kind = OnTableShareGrantKind + id.Identifier = sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(tableName.(string)) + case allTablesInSchemaOk: + id.Kind = OnAllTablesInSchemaShareGrantKind + id.Identifier = sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(allTablesInSchema.(string)) + case tagNameOk: + id.Kind = OnTagShareGrantKind + id.Identifier = sdk.NewAccountObjectIdentifierFromFullyQualifiedName(tagName.(string)) + case viewNameOk: + id.Kind = OnViewShareGrantKind + id.Identifier = sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(viewName.(string)) + } + + return id +} + +func getObjectPrivilegesFromSchema(d *schema.ResourceData) []sdk.ObjectPrivilege { + privileges := expandStringList(d.Get("privileges").(*schema.Set).List()) + objectPrivileges := make([]sdk.ObjectPrivilege, len(privileges)) + for i, privilege := range privileges { + objectPrivileges[i] = sdk.ObjectPrivilege(privilege) + } + return objectPrivileges +} + +func getShareGrantOn(d *schema.ResourceData) *sdk.ShareGrantOn { + grantOn := new(sdk.ShareGrantOn) + + databaseName, databaseNameOk := d.GetOk("database_name") + schemaName, schemaNameOk := d.GetOk("schema_name") + tableName, tableNameOk := d.GetOk("table_name") + allTablesInSchema, allTablesInSchemaOk := d.GetOk("all_tables_in_schema") + tagName, tagNameOk := d.GetOk("tag_name") + viewName, viewNameOk := d.GetOk("view_name") + + switch { + case len(databaseName.(string)) > 0 && databaseNameOk: + grantOn.Database = sdk.NewAccountObjectIdentifierFromFullyQualifiedName(databaseName.(string)) + case len(schemaName.(string)) > 0 && schemaNameOk: + grantOn.Schema = sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(schemaName.(string)) + case len(tableName.(string)) > 0 && tableNameOk: + grantOn.Table = &sdk.OnTable{ + Name: sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(tableName.(string)), + } + case len(allTablesInSchema.(string)) > 0 && allTablesInSchemaOk: + grantOn.Table = &sdk.OnTable{ + AllInSchema: sdk.NewDatabaseObjectIdentifierFromFullyQualifiedName(allTablesInSchema.(string)), + } + case len(tagName.(string)) > 0 && tagNameOk: + grantOn.Tag = sdk.NewAccountObjectIdentifierFromFullyQualifiedName(tagName.(string)) + case len(viewName.(string)) > 0 && viewNameOk: + grantOn.View = sdk.NewSchemaObjectIdentifierFromFullyQualifiedName(viewName.(string)) + } + + return grantOn +} + +func prepareShowGrantsRequestForShare(id GrantPrivilegesToShareId) (*sdk.ShowGrantOptions, sdk.ObjectType, diag.Diagnostics) { + opts := new(sdk.ShowGrantOptions) + var objectType sdk.ObjectType + + switch id.Kind { + case OnDatabaseShareGrantKind: + objectType = sdk.ObjectTypeDatabase + case OnSchemaShareGrantKind: + objectType = sdk.ObjectTypeSchema + case OnTableShareGrantKind: + objectType = sdk.ObjectTypeTable + case OnAllTablesInSchemaShareGrantKind: + return nil, "", diag.Diagnostics{ + diag.Diagnostic{ + // TODO: link to the design decisions doc (SNOW-990811) + Severity: diag.Warning, + Summary: "Show with OnAll option is skipped.", + Detail: "See our document on design decisions for grants: ", + }, + } + case OnTagShareGrantKind: + objectType = sdk.ObjectTypeTag + case OnViewShareGrantKind: + objectType = sdk.ObjectTypeView + } + + opts.On = &sdk.ShowGrantsOn{ + Object: &sdk.Object{ + ObjectType: objectType, + Name: id.Identifier, + }, + } + return opts, "", nil +} diff --git a/pkg/resources/grant_privileges_to_share_identifier.go b/pkg/resources/grant_privileges_to_share_identifier.go new file mode 100644 index 00000000000..cc56e33c38a --- /dev/null +++ b/pkg/resources/grant_privileges_to_share_identifier.go @@ -0,0 +1,97 @@ +package resources + +import ( + "fmt" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "strings" +) + +type ShareGrantKind string + +const ( + OnDatabaseShareGrantKind ShareGrantKind = "OnDatabase" + OnSchemaShareGrantKind ShareGrantKind = "OnSchema" + OnFunctionShareGrantKind ShareGrantKind = "OnFunction" + OnTableShareGrantKind ShareGrantKind = "OnTable" + OnAllTablesInSchemaShareGrantKind ShareGrantKind = "OnAllTablesInSchema" + OnTagShareGrantKind ShareGrantKind = "OnTag" + OnViewShareGrantKind ShareGrantKind = "OnView" +) + +type GrantPrivilegesToShareId struct { + ShareName sdk.AccountObjectIdentifier + Privileges []string + Kind ShareGrantKind + Identifier sdk.ObjectIdentifier +} + +func (id *GrantPrivilegesToShareId) String() string { + return strings.Join([]string{ + id.ShareName.FullyQualifiedName(), + strings.Join(id.Privileges, ","), + string(id.Kind), + id.Identifier.FullyQualifiedName(), + }, helpers.IDDelimiter) +} + +func ParseGrantPrivilegesToShareId(idString string) (GrantPrivilegesToShareId, error) { + var grantPrivilegesToShareId GrantPrivilegesToShareId + + parts := strings.Split(idString, helpers.IDDelimiter) + if len(parts) != 4 { + return grantPrivilegesToShareId, sdk.NewError(fmt.Sprintf(`snowflake_grant_privileges_to_share id is composed out of 4 parts "|||", but got %d parts: %v`, len(parts), parts)) + } + + grantPrivilegesToShareId.ShareName = sdk.NewAccountObjectIdentifier(parts[0]) + privileges := strings.Split(parts[1], ",") + if len(privileges) == 0 || (len(privileges) == 1 && privileges[0] == "") { + return grantPrivilegesToShareId, sdk.NewError(fmt.Sprintf(`invalid Privileges value: %s, should be comma separated list of privileges`, privileges)) + } + grantPrivilegesToShareId.Privileges = privileges + grantPrivilegesToShareId.Kind = ShareGrantKind(parts[2]) + + id, err := helpers.DecodeSnowflakeParameterID(parts[3]) + if err != nil { + return grantPrivilegesToShareId, err + } + + switch grantPrivilegesToShareId.Kind { + case OnDatabaseShareGrantKind, OnTagShareGrantKind: + if typedIdentifier, ok := id.(sdk.AccountObjectIdentifier); ok { + grantPrivilegesToShareId.Identifier = typedIdentifier + } else { + return grantPrivilegesToShareId, fmt.Errorf( + "invalid identifier, expected fully qualified name of account object: %s, but instead got: %s", + getExpectedIdentifierRepresentationFromGeneric[sdk.AccountObjectIdentifier](), + getExpectedIdentifierRepresentationFromParam(id), + ) + } + case OnSchemaShareGrantKind, OnAllTablesInSchemaShareGrantKind: + if typedIdentifier, ok := id.(sdk.DatabaseObjectIdentifier); ok { + grantPrivilegesToShareId.Identifier = typedIdentifier + } else { + return grantPrivilegesToShareId, fmt.Errorf( + "invalid identifier, expected fully qualified name of database object: %s, but instead got: %s", + getExpectedIdentifierRepresentationFromGeneric[sdk.DatabaseObjectIdentifier](), + getExpectedIdentifierRepresentationFromParam(id), + ) + } + case OnTableShareGrantKind, OnViewShareGrantKind: + if typedIdentifier, ok := id.(sdk.SchemaObjectIdentifier); ok { + grantPrivilegesToShareId.Identifier = typedIdentifier + } else { + return grantPrivilegesToShareId, fmt.Errorf( + "invalid identifier, expected fully qualified name of schema object: %s, but instead got: %s", + getExpectedIdentifierRepresentationFromGeneric[sdk.SchemaObjectIdentifier](), + getExpectedIdentifierRepresentationFromParam(id), + ) + } + case OnFunctionShareGrantKind: + // TODO(SNOW-1021686): Because function identifier contains arguments which are not supported right now + default: + return grantPrivilegesToShareId, fmt.Errorf("unexpected share grant kind: %v", grantPrivilegesToShareId.Kind) + } + + return grantPrivilegesToShareId, nil +} diff --git a/pkg/resources/grant_privileges_to_share_identifier_test.go b/pkg/resources/grant_privileges_to_share_identifier_test.go new file mode 100644 index 00000000000..c56136833ff --- /dev/null +++ b/pkg/resources/grant_privileges_to_share_identifier_test.go @@ -0,0 +1,204 @@ +package resources + +import ( + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/stretchr/testify/assert" + "testing" +) + +// TODO(SNOW-1021686): Add tests for function identifier +func TestParseGrantPrivilegesToShareId(t *testing.T) { + testCases := []struct { + Name string + Identifier string + Expected GrantPrivilegesToShareId + Error string + }{ + { + Name: "grant privileges on database to share", + Identifier: `"share-name"|REFERENCE_USAGE|OnDatabase|"on-database-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"REFERENCE_USAGE"}, + Kind: OnDatabaseShareGrantKind, + Identifier: sdk.NewAccountObjectIdentifier("on-database-name"), + }, + }, + { + Name: "grant privileges on schema to share", + Identifier: `"share-name"|USAGE|OnSchema|"on-database-name"."on-schema-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"USAGE"}, + Kind: OnSchemaShareGrantKind, + Identifier: sdk.NewDatabaseObjectIdentifier("on-database-name", "on-schema-name"), + }, + }, + { + Name: "grant privileges on table to share", + Identifier: `"share-name"|EVOLVE SCHEMA|OnTable|"on-database-name"."on-schema-name"."on-table-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"EVOLVE SCHEMA"}, + Kind: OnTableShareGrantKind, + Identifier: sdk.NewSchemaObjectIdentifier("on-database-name", "on-schema-name", "on-table-name"), + }, + }, + { + Name: "grant privileges on all tables in schema to share", + Identifier: `"share-name"|EVOLVE SCHEMA,SELECT|OnAllTablesInSchema|"on-database-name"."on-schema-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"EVOLVE SCHEMA", "SELECT"}, + Kind: OnAllTablesInSchemaShareGrantKind, + Identifier: sdk.NewDatabaseObjectIdentifier("on-database-name", "on-schema-name"), + }, + }, + { + Name: "grant privileges on tag to share", + Identifier: `"share-name"|READ|OnTag|"on-tag-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"READ"}, + Kind: OnTagShareGrantKind, + Identifier: sdk.NewAccountObjectIdentifier("on-tag-name"), + }, + }, + { + Name: "grant privileges on view to share", + Identifier: `"share-name"|READ|OnView|"on-database-name"."on-schema-name"."on-view-name"`, + Expected: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"READ"}, + Kind: OnViewShareGrantKind, + Identifier: sdk.NewSchemaObjectIdentifier("on-database-name", "on-schema-name", "on-view-name"), + }, + }, + { + Name: "validation: not enough parts", + Identifier: `"share-name"|SELECT|OnDatabase`, + Error: `snowflake_grant_privileges_to_share id is composed out of 4 parts "|||", but got 3 parts: ["share-name" SELECT OnDatabase]`, + }, + { + Name: "validation: empty privileges", + Identifier: `"share-name"||OnDatabase|"database-name"`, + Error: `invalid Privileges value: [], should be comma separated list of privileges`, + }, + { + Name: "validation: unsupported kind", + Identifier: `"share-name"|SELECT|OnSomething|"object-name"`, + Error: `unexpected share grant kind: OnSomething`, + }, + { + Name: "validation: invalid identifier", + Identifier: `"share-name"|SELECT|OnDatabase|one.two.three.four.five.six.seven.eight.nine.ten`, + Error: `unable to classify identifier: one.two.three.four.five.six.seven.eight.nine.ten`, + }, + { + Name: "validation: invalid account object identifier", + Identifier: `"share-name"|SELECT|OnDatabase|one.two`, + Error: `invalid identifier, expected fully qualified name of account object: , but instead got: .`, + }, + { + Name: "validation: invalid database object identifier", + Identifier: `"share-name"|SELECT|OnSchema|one.two.three`, + Error: `invalid identifier, expected fully qualified name of database object: ., but instead got: ..`, + }, + { + Name: "validation: invalid schema object identifier", + Identifier: `"share-name"|SELECT|OnTable|one`, + Error: `invalid identifier, expected fully qualified name of schema object: .., but instead got: `, + }, + } + + for _, tt := range testCases { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + id, err := ParseGrantPrivilegesToShareId(tt.Identifier) + if tt.Error == "" { + assert.NoError(t, err) + assert.Equal(t, tt.Expected, id) + } else { + assert.ErrorContains(t, err, tt.Error) + } + }) + } +} + +// TODO(SNOW-1021686): Add tests for function identifier +func TestGrantPrivilegesToShareIdString(t *testing.T) { + testCases := []struct { + Name string + Identifier GrantPrivilegesToShareId + Expected string + Error string + }{ + { + Name: "grant privileges on database to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"REFERENCE_USAGE"}, + Kind: OnDatabaseShareGrantKind, + Identifier: sdk.NewAccountObjectIdentifier("database-name"), + }, + Expected: `"share-name"|REFERENCE_USAGE|OnDatabase|"database-name"`, + }, + { + Name: "grant privileges on schema to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"USAGE"}, + Kind: OnSchemaShareGrantKind, + Identifier: sdk.NewDatabaseObjectIdentifier("database-name", "schema-name"), + }, + Expected: `"share-name"|USAGE|OnSchema|"database-name"."schema-name"`, + }, + { + Name: "grant privileges on table to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"EVOLVE SCHEMA", "SELECT"}, + Kind: OnTableShareGrantKind, + Identifier: sdk.NewSchemaObjectIdentifier("database-name", "schema-name", "table-name"), + }, + Expected: `"share-name"|EVOLVE SCHEMA,SELECT|OnTable|"database-name"."schema-name"."table-name"`, + }, + { + Name: "grant privileges on all tables in schema to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"EVOLVE SCHEMA", "SELECT"}, + Kind: OnAllTablesInSchemaShareGrantKind, + Identifier: sdk.NewDatabaseObjectIdentifier("database-name", "schema-name"), + }, + Expected: `"share-name"|EVOLVE SCHEMA,SELECT|OnAllTablesInSchema|"database-name"."schema-name"`, + }, + { + Name: "grant privileges on tag to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"READ"}, + Kind: OnTagShareGrantKind, + Identifier: sdk.NewAccountObjectIdentifier("tag-name"), + }, + Expected: `"share-name"|READ|OnTag|"tag-name"`, + }, + { + Name: "grant privileges on view to share", + Identifier: GrantPrivilegesToShareId{ + ShareName: sdk.NewAccountObjectIdentifier("share-name"), + Privileges: []string{"SELECT"}, + Kind: OnViewShareGrantKind, + Identifier: sdk.NewSchemaObjectIdentifier("database-name", "schema-name", "view-name"), + }, + Expected: `"share-name"|SELECT|OnView|"database-name"."schema-name"."view-name"`, + }, + } + + for _, tt := range testCases { + tt := tt + t.Run(tt.Name, func(t *testing.T) { + assert.Equal(t, tt.Expected, tt.Identifier.String()) + }) + } +} diff --git a/pkg/resources/share.go b/pkg/resources/share.go index f7d0d8cb63c..240bf24d4f2 100644 --- a/pkg/resources/share.go +++ b/pkg/resources/share.go @@ -123,7 +123,7 @@ func setShareAccounts(ctx context.Context, client *sdk.Client, shareID sdk.Accou // case where the main db doesn't already exist, so it will need to be revoked // before deleting the temp db. Where USAGE hasn't been already granted it is not // an error to revoke it, so it's ok to just do the revoke every time. - err = client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeReferenceUsage, &sdk.GrantPrivilegeToShareOn{ + err = client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeReferenceUsage, &sdk.ShareGrantOn{ Database: tempDatabaseID, }, shareID) if err != nil { diff --git a/pkg/sdk/grants.go b/pkg/sdk/grants.go index 2eb79f73721..7d2b318ed78 100644 --- a/pkg/sdk/grants.go +++ b/pkg/sdk/grants.go @@ -13,8 +13,8 @@ type Grants interface { RevokePrivilegesFromAccountRole(ctx context.Context, privileges *AccountRoleGrantPrivileges, on *AccountRoleGrantOn, role AccountObjectIdentifier, opts *RevokePrivilegesFromAccountRoleOptions) error GrantPrivilegesToDatabaseRole(ctx context.Context, privileges *DatabaseRoleGrantPrivileges, on *DatabaseRoleGrantOn, role DatabaseObjectIdentifier, opts *GrantPrivilegesToDatabaseRoleOptions) error RevokePrivilegesFromDatabaseRole(ctx context.Context, privileges *DatabaseRoleGrantPrivileges, on *DatabaseRoleGrantOn, role DatabaseObjectIdentifier, opts *RevokePrivilegesFromDatabaseRoleOptions) error - GrantPrivilegeToShare(ctx context.Context, privilege ObjectPrivilege, on *GrantPrivilegeToShareOn, to AccountObjectIdentifier) error - RevokePrivilegeFromShare(ctx context.Context, privilege ObjectPrivilege, on *RevokePrivilegeFromShareOn, from AccountObjectIdentifier) error + GrantPrivilegeToShare(ctx context.Context, privileges []ObjectPrivilege, on *ShareGrantOn, to AccountObjectIdentifier) error + RevokePrivilegeFromShare(ctx context.Context, privileges []ObjectPrivilege, on *ShareGrantOn, from AccountObjectIdentifier) error GrantOwnership(ctx context.Context, on OwnershipGrantOn, to OwnershipGrantTo, opts *GrantOwnershipOptions) error Show(ctx context.Context, opts *ShowGrantOptions) ([]Grant, error) @@ -120,17 +120,18 @@ type RevokePrivilegesFromDatabaseRoleOptions struct { // grantPrivilegeToShareOptions is based on https://docs.snowflake.com/en/sql-reference/sql/grant-privilege-share. type grantPrivilegeToShareOptions struct { - grant bool `ddl:"static" sql:"GRANT"` - privilege ObjectPrivilege `ddl:"keyword"` - On *GrantPrivilegeToShareOn `ddl:"keyword" sql:"ON"` - to AccountObjectIdentifier `ddl:"identifier" sql:"TO SHARE"` + grant bool `ddl:"static" sql:"GRANT"` + privileges []ObjectPrivilege `ddl:"-"` + On *ShareGrantOn `ddl:"keyword" sql:"ON"` + to AccountObjectIdentifier `ddl:"identifier" sql:"TO SHARE"` } -type GrantPrivilegeToShareOn struct { +type ShareGrantOn struct { Database AccountObjectIdentifier `ddl:"identifier" sql:"DATABASE"` Schema DatabaseObjectIdentifier `ddl:"identifier" sql:"SCHEMA"` Function SchemaObjectIdentifier `ddl:"identifier" sql:"FUNCTION"` Table *OnTable `ddl:"-"` + Tag AccountObjectIdentifier `ddl:"identifier" sql:"TAG"` View SchemaObjectIdentifier `ddl:"identifier" sql:"VIEW"` } @@ -141,17 +142,10 @@ type OnTable struct { // revokePrivilegeFromShareOptions is based on https://docs.snowflake.com/en/sql-reference/sql/revoke-privilege-share. type revokePrivilegeFromShareOptions struct { - revoke bool `ddl:"static" sql:"REVOKE"` - privilege ObjectPrivilege `ddl:"keyword"` - On *RevokePrivilegeFromShareOn `ddl:"keyword" sql:"ON"` - from AccountObjectIdentifier `ddl:"identifier" sql:"FROM SHARE"` -} - -type RevokePrivilegeFromShareOn struct { - Database AccountObjectIdentifier `ddl:"identifier" sql:"DATABASE"` - Schema DatabaseObjectIdentifier `ddl:"identifier" sql:"SCHEMA"` - Table *OnTable `ddl:"-"` - View *OnView `ddl:"-"` + revoke bool `ddl:"static" sql:"REVOKE"` + privileges []ObjectPrivilege `ddl:"-"` + On *ShareGrantOn `ddl:"keyword" sql:"ON"` + from AccountObjectIdentifier `ddl:"identifier" sql:"FROM SHARE"` } type OnView struct { diff --git a/pkg/sdk/grants_impl.go b/pkg/sdk/grants_impl.go index 31f978dd645..5df299e8775 100644 --- a/pkg/sdk/grants_impl.go +++ b/pkg/sdk/grants_impl.go @@ -56,20 +56,20 @@ func (v *grants) RevokePrivilegesFromDatabaseRole(ctx context.Context, privilege return validateAndExec(v.client, ctx, opts) } -func (v *grants) GrantPrivilegeToShare(ctx context.Context, privilege ObjectPrivilege, on *GrantPrivilegeToShareOn, to AccountObjectIdentifier) error { +func (v *grants) GrantPrivilegeToShare(ctx context.Context, privileges []ObjectPrivilege, on *ShareGrantOn, to AccountObjectIdentifier) error { opts := &grantPrivilegeToShareOptions{ - privilege: privilege, - On: on, - to: to, + privileges: privileges, + On: on, + to: to, } return validateAndExec(v.client, ctx, opts) } -func (v *grants) RevokePrivilegeFromShare(ctx context.Context, privilege ObjectPrivilege, on *RevokePrivilegeFromShareOn, id AccountObjectIdentifier) error { +func (v *grants) RevokePrivilegeFromShare(ctx context.Context, privileges []ObjectPrivilege, on *ShareGrantOn, id AccountObjectIdentifier) error { opts := &revokePrivilegeFromShareOptions{ - privilege: privilege, - On: on, - from: id, + privileges: privileges, + On: on, + from: id, } return validateAndExec(v.client, ctx, opts) } diff --git a/pkg/sdk/grants_test.go b/pkg/sdk/grants_test.go index 9bda91c4d10..797f96e7591 100644 --- a/pkg/sdk/grants_test.go +++ b/pkg/sdk/grants_test.go @@ -728,8 +728,8 @@ func TestGrantPrivilegeToShare(t *testing.T) { t.Run("on database", func(t *testing.T) { otherID := RandomAccountObjectIdentifier() opts := &grantPrivilegeToShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &GrantPrivilegeToShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Database: otherID, }, to: id, @@ -740,8 +740,8 @@ func TestGrantPrivilegeToShare(t *testing.T) { t.Run("on schema", func(t *testing.T) { otherID := RandomDatabaseObjectIdentifier() opts := &grantPrivilegeToShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &GrantPrivilegeToShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Schema: otherID, }, to: id, @@ -752,8 +752,8 @@ func TestGrantPrivilegeToShare(t *testing.T) { t.Run("on table", func(t *testing.T) { otherID := RandomSchemaObjectIdentifier() opts := &grantPrivilegeToShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &GrantPrivilegeToShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Table: &OnTable{ Name: otherID, }, @@ -766,8 +766,8 @@ func TestGrantPrivilegeToShare(t *testing.T) { t.Run("on all tables", func(t *testing.T) { otherID := RandomDatabaseObjectIdentifier() opts := &grantPrivilegeToShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &GrantPrivilegeToShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Table: &OnTable{ AllInSchema: otherID, }, @@ -780,8 +780,8 @@ func TestGrantPrivilegeToShare(t *testing.T) { t.Run("on view", func(t *testing.T) { otherID := RandomSchemaObjectIdentifier() opts := &grantPrivilegeToShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &GrantPrivilegeToShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ View: otherID, }, to: id, @@ -795,8 +795,8 @@ func TestRevokePrivilegeFromShare(t *testing.T) { t.Run("on database", func(t *testing.T) { otherID := RandomAccountObjectIdentifier() opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Database: otherID, }, from: id, @@ -807,8 +807,8 @@ func TestRevokePrivilegeFromShare(t *testing.T) { t.Run("on schema", func(t *testing.T) { otherID := RandomDatabaseObjectIdentifier() opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Schema: otherID, }, from: id, @@ -819,8 +819,8 @@ func TestRevokePrivilegeFromShare(t *testing.T) { t.Run("on table", func(t *testing.T) { otherID := RandomSchemaObjectIdentifier() opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Table: &OnTable{ Name: otherID, }, @@ -833,8 +833,8 @@ func TestRevokePrivilegeFromShare(t *testing.T) { t.Run("on all tables", func(t *testing.T) { otherID := RandomDatabaseObjectIdentifier() opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ Table: &OnTable{ AllInSchema: otherID, }, @@ -847,30 +847,40 @@ func TestRevokePrivilegeFromShare(t *testing.T) { t.Run("on view", func(t *testing.T) { otherID := RandomSchemaObjectIdentifier() opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ - View: &OnView{ - Name: otherID, - }, + privileges: []ObjectPrivilege{ObjectPrivilegeUsage}, + On: &ShareGrantOn{ + View: otherID, }, from: id, } assertOptsValidAndSQLEquals(t, opts, "REVOKE USAGE ON VIEW %s FROM SHARE %s", otherID.FullyQualifiedName(), id.FullyQualifiedName()) }) - t.Run("on all views", func(t *testing.T) { - otherID := RandomDatabaseObjectIdentifier() + t.Run("on tag", func(t *testing.T) { opts := &revokePrivilegeFromShareOptions{ - privilege: ObjectPrivilegeUsage, - On: &RevokePrivilegeFromShareOn{ - View: &OnView{ - AllInSchema: otherID, - }, + privileges: []ObjectPrivilege{ObjectPrivilegeRead}, + On: &ShareGrantOn{ + Tag: NewAccountObjectIdentifier("tag-name"), }, from: id, } - assertOptsValidAndSQLEquals(t, opts, "REVOKE USAGE ON ALL VIEWS IN SCHEMA %s FROM SHARE %s", otherID.FullyQualifiedName(), id.FullyQualifiedName()) - }) + assertOptsValidAndSQLEquals(t, opts, "REVOKE READ ON TAG \"tag-name\" FROM SHARE %s", id.FullyQualifiedName()) + }) + + // TODO: This one throws an error + //t.Run("on all views", func(t *testing.T) { + // otherID := RandomDatabaseObjectIdentifier() + // opts := &revokePrivilegeFromShareOptions{ + // privilege: ObjectPrivilegeUsage, + // On: &RevokePrivilegeFromShareOn{ + // View: &OnView{ + // AllInSchema: otherID, + // }, + // }, + // from: id, + // } + // assertOptsValidAndSQLEquals(t, opts, "REVOKE USAGE ON ALL VIEWS IN SCHEMA %s FROM SHARE %s", otherID.FullyQualifiedName(), id.FullyQualifiedName()) + //}) } func TestGrants_GrantOwnership(t *testing.T) { diff --git a/pkg/sdk/grants_validations.go b/pkg/sdk/grants_validations.go index 3f7317afbfb..844580cc876 100644 --- a/pkg/sdk/grants_validations.go +++ b/pkg/sdk/grants_validations.go @@ -233,7 +233,7 @@ func (opts *grantPrivilegeToShareOptions) validate() error { if !ValidObjectIdentifier(opts.to) { errs = append(errs, ErrInvalidObjectIdentifier) } - if !valueSet(opts.On) || opts.privilege == "" { + if !valueSet(opts.On) || len(opts.privileges) == 0 { errs = append(errs, fmt.Errorf("on and privilege are required")) } if valueSet(opts.On) { @@ -244,10 +244,10 @@ func (opts *grantPrivilegeToShareOptions) validate() error { return errors.Join(errs...) } -func (v *GrantPrivilegeToShareOn) validate() error { +func (v *ShareGrantOn) validate() error { var errs []error - if !exactlyOneValueSet(v.Database, v.Schema, v.Function, v.Table, v.View) { - errs = append(errs, errExactlyOneOf("GrantPrivilegeToShareOn", "Database", "Schema", "Function", "Table", "View")) + if !exactlyOneValueSet(v.Database, v.Schema, v.Function, v.Table, v.Tag, v.View) { + errs = append(errs, errExactlyOneOf("ShareGrantOn", "Database", "Schema", "Function", "Table", "Tag", "View")) } if valueSet(v.Table) { if err := v.Table.validate(); err != nil { @@ -272,13 +272,10 @@ func (opts *revokePrivilegeFromShareOptions) validate() error { if !ValidObjectIdentifier(opts.from) { errs = append(errs, ErrInvalidObjectIdentifier) } - if !valueSet(opts.On) || opts.privilege == "" { - errs = append(errs, errNotSet("revokePrivilegeFromShareOptions", "On", "privilege")) + if !valueSet(opts.On) || len(opts.privileges) == 0 { + errs = append(errs, errNotSet("revokePrivilegeFromShareOptions", "On", "privileges")) } if valueSet(opts.On) { - if !exactlyOneValueSet(opts.On.Database, opts.On.Schema, opts.On.Table, opts.On.View) { - errs = append(errs, errExactlyOneOf("revokePrivilegeFromShareOptions", "On.Database", "On.Schema", "On.Table", "On.View")) - } if err := opts.On.validate(); err != nil { errs = append(errs, err) } @@ -286,24 +283,6 @@ func (opts *revokePrivilegeFromShareOptions) validate() error { return errors.Join(errs...) } -func (v *RevokePrivilegeFromShareOn) validate() error { - var errs []error - if !exactlyOneValueSet(v.Database, v.Schema, v.Table, v.View) { - errs = append(errs, errExactlyOneOf("RevokePrivilegeFromShareOn", "Database", "Schema", "Table", "View")) - } - if valueSet(v.Table) { - if err := v.Table.validate(); err != nil { - errs = append(errs, err) - } - } - if valueSet(v.View) { - if err := v.View.validate(); err != nil { - errs = append(errs, err) - } - } - return errors.Join(errs...) -} - func (v *OnView) validate() error { if !exactlyOneValueSet(v.Name, v.AllInSchema) { return errExactlyOneOf("OnView", "Name", "AllInSchema") diff --git a/pkg/sdk/privileges.go b/pkg/sdk/privileges.go index f07c190b908..f1e91790519 100644 --- a/pkg/sdk/privileges.go +++ b/pkg/sdk/privileges.go @@ -243,9 +243,11 @@ func (p SchemaObjectPrivilege) String() string { type ObjectPrivilege string const ( + ObjectPrivilegeReferenceUsage ObjectPrivilege = "REFERENCE_USAGE" ObjectPrivilegeUsage ObjectPrivilege = "USAGE" + ObjectPrivilegeEvolveSchema ObjectPrivilege = "EVOLVE SCHEMA" ObjectPrivilegeSelect ObjectPrivilege = "SELECT" - ObjectPrivilegeReferenceUsage ObjectPrivilege = "REFERENCE_USAGE" + ObjectPrivilegeRead ObjectPrivilege = "READ" ) func (p ObjectPrivilege) String() string { diff --git a/pkg/sdk/testint/database_role_integration_test.go b/pkg/sdk/testint/database_role_integration_test.go index c4c9a76e426..b6b883c10e7 100644 --- a/pkg/sdk/testint/database_role_integration_test.go +++ b/pkg/sdk/testint/database_role_integration_test.go @@ -262,7 +262,7 @@ func TestInt_DatabaseRoles(t *testing.T) { share, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{Database: testDb(t).ID()}, share.ID()) + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{Database: testDb(t).ID()}, share.ID()) require.NoError(t, err) grantRequest := sdk.NewGrantDatabaseRoleToShareRequest(roleId, share.ID()) diff --git a/pkg/sdk/testint/databases_integration_test.go b/pkg/sdk/testint/databases_integration_test.go index 7441ff70409..b577b7ffd4b 100644 --- a/pkg/sdk/testint/databases_integration_test.go +++ b/pkg/sdk/testint/databases_integration_test.go @@ -119,12 +119,12 @@ func TestInt_CreateShared(t *testing.T) { shareTest, shareCleanup := createShare(t, secondaryClient) t.Cleanup(shareCleanup) - err := secondaryClient.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := secondaryClient.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: databaseTest.ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err := secondaryClient.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err := secondaryClient.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: databaseTest.ID(), }, shareTest.ID()) require.NoError(t, err) diff --git a/pkg/sdk/testint/grants_integration_test.go b/pkg/sdk/testint/grants_integration_test.go index a4c6cb70631..fff2098d049 100644 --- a/pkg/sdk/testint/grants_integration_test.go +++ b/pkg/sdk/testint/grants_integration_test.go @@ -1,12 +1,11 @@ package testint import ( - "testing" - "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/internal/collections" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "testing" ) func TestInt_GrantAndRevokePrivilegesToAccountRole(t *testing.T) { @@ -409,39 +408,60 @@ func TestInt_GrantPrivilegeToShare(t *testing.T) { ctx := testContext(t) shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - t.Run("without options", func(t *testing.T) { - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, nil, shareTest.ID()) - require.Error(t, err) - }) - t.Run("with options", func(t *testing.T) { - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + + assertGrant := func(t *testing.T, grants []sdk.Grant, onId sdk.ObjectIdentifier, privilege sdk.ObjectPrivilege) { + t.Helper() + var shareGrant *sdk.Grant + for i, grant := range grants { + if grant.GranteeName.Name() == shareTest.ID().Name() && grant.Privilege == string(privilege) { + shareGrant = &grants[i] + break + } + } + assert.NotNil(t, shareGrant) + assert.Equal(t, sdk.ObjectTypeTable, shareGrant.GrantedOn) + assert.Equal(t, sdk.ObjectTypeShare, shareGrant.GrantedTo) + assert.Equal(t, onId.FullyQualifiedName(), shareGrant.Name.FullyQualifiedName()) + } + + t.Run("with options - multiple privileges", func(t *testing.T) { + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) + + t.Cleanup(func() { + err := client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ + Database: testDb(t).ID(), + }, shareTest.ID()) + assert.NoError(t, err) + }) + + table, tableCleanup := createTable(t, client, testDb(t), testSchema(t)) + t.Cleanup(tableCleanup) + + err = client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeEvolveSchema, sdk.ObjectPrivilegeSelect}, &sdk.ShareGrantOn{ + Table: &sdk.OnTable{ + AllInSchema: testSchema(t).ID(), + }, + }, shareTest.ID()) + require.NoError(t, err) + grants, err := client.Grants.Show(ctx, &sdk.ShowGrantOptions{ On: &sdk.ShowGrantsOn{ Object: &sdk.Object{ - ObjectType: sdk.ObjectTypeDatabase, - Name: testDb(t).ID(), + ObjectType: sdk.ObjectTypeTable, + Name: table.ID(), }, }, }) require.NoError(t, err) - assert.LessOrEqual(t, 2, len(grants)) - var shareGrant *sdk.Grant - for i, grant := range grants { - if grant.GranteeName.Name() == shareTest.ID().Name() { - shareGrant = &grants[i] - break - } - } - assert.NotNil(t, shareGrant) - assert.Equal(t, string(sdk.ObjectPrivilegeUsage), shareGrant.Privilege) - assert.Equal(t, sdk.ObjectTypeDatabase, shareGrant.GrantedOn) - assert.Equal(t, sdk.ObjectTypeShare, shareGrant.GrantedTo) - assert.Equal(t, testDb(t).ID().Name(), shareGrant.Name.Name()) - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ - Database: testDb(t).ID(), + assertGrant(t, grants, table.ID(), sdk.ObjectPrivilegeSelect) + + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeEvolveSchema, sdk.ObjectPrivilegeSelect}, &sdk.ShareGrantOn{ + Table: &sdk.OnTable{ + AllInSchema: testSchema(t).ID(), + }, }, shareTest.ID()) require.NoError(t, err) }) @@ -452,16 +472,16 @@ func TestInt_RevokePrivilegeToShare(t *testing.T) { ctx := testContext(t) shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Run("without options", func(t *testing.T) { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, nil, shareTest.ID()) + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, nil, shareTest.ID()) require.Error(t, err) }) t.Run("with options", func(t *testing.T) { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) @@ -587,12 +607,12 @@ func TestInt_ShowGrants(t *testing.T) { ctx := testContext(t) shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) diff --git a/pkg/sdk/testint/shares_integration_test.go b/pkg/sdk/testint/shares_integration_test.go index 0050a1e43c9..8b643e6467d 100644 --- a/pkg/sdk/testint/shares_integration_test.go +++ b/pkg/sdk/testint/shares_integration_test.go @@ -131,12 +131,12 @@ func TestInt_SharesAlter(t *testing.T) { t.Run("add and remove accounts", func(t *testing.T) { shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) }) @@ -189,12 +189,12 @@ func TestInt_SharesAlter(t *testing.T) { shareTest, shareCleanup := createShare(t, secondaryClient) t.Cleanup(shareCleanup) - err := secondaryClient.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := secondaryClient.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: db.ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err := secondaryClient.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err := secondaryClient.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: db.ID(), }, shareTest.ID()) require.NoError(t, err) @@ -229,12 +229,12 @@ func TestInt_SharesAlter(t *testing.T) { shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) @@ -284,12 +284,12 @@ func TestInt_SharesAlter(t *testing.T) { t.Run("set and unset tags", func(t *testing.T) { shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) @@ -345,12 +345,12 @@ func TestInt_ShareDescribeProvider(t *testing.T) { shareTest, shareCleanup := createShare(t, client) t.Cleanup(shareCleanup) - err := client.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := client.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = client.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = client.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: testDb(t).ID(), }, shareTest.ID()) require.NoError(t, err) @@ -378,12 +378,12 @@ func TestInt_ShareDescribeConsumer(t *testing.T) { shareTest, shareCleanup := createShare(t, providerClient) t.Cleanup(shareCleanup) - err := providerClient.Grants.GrantPrivilegeToShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.GrantPrivilegeToShareOn{ + err := providerClient.Grants.GrantPrivilegeToShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: db.ID(), }, shareTest.ID()) require.NoError(t, err) t.Cleanup(func() { - err = providerClient.Grants.RevokePrivilegeFromShare(ctx, sdk.ObjectPrivilegeUsage, &sdk.RevokePrivilegeFromShareOn{ + err = providerClient.Grants.RevokePrivilegeFromShare(ctx, []sdk.ObjectPrivilege{sdk.ObjectPrivilegeUsage}, &sdk.ShareGrantOn{ Database: db.ID(), }, shareTest.ID()) require.NoError(t, err)