From 555490c790a222d08a928d9621f885d445b856d5 Mon Sep 17 00:00:00 2001 From: ChrisIsidora Date: Wed, 21 Sep 2022 16:33:44 +0200 Subject: [PATCH 1/2] feat: Add Missing Grant Updates + Removed ForceNew --- pkg/resources/database_grant.go | 3 +- pkg/resources/external_table_grant.go | 56 ++++++++++++++++++++- pkg/resources/file_format_grant.go | 52 +++++++++++++++++++- pkg/resources/function_grant.go | 62 +++++++++++++++++++++++- pkg/resources/integration_grant.go | 44 ++++++++++++++++- pkg/resources/masking_policy_grant.go | 46 +++++++++++++++++- pkg/resources/materialized_view_grant.go | 56 ++++++++++++++++++++- pkg/resources/pipe_grant.go | 53 +++++++++++++++++++- pkg/resources/procedure_grant.go | 62 +++++++++++++++++++++++- pkg/resources/resource_monitor_grant.go | 44 ++++++++++++++++- pkg/resources/row_access_policy_grant.go | 45 ++++++++++++++++- pkg/resources/sequence_grant.go | 46 +++++++++++++++++- pkg/resources/stage_grant.go | 46 +++++++++++++++++- pkg/resources/stream_grant.go | 46 +++++++++++++++++- pkg/resources/task_grant.go | 46 +++++++++++++++++- 15 files changed, 686 insertions(+), 21 deletions(-) diff --git a/pkg/resources/database_grant.go b/pkg/resources/database_grant.go index 71896d59fa..00b4928b5d 100644 --- a/pkg/resources/database_grant.go +++ b/pkg/resources/database_grant.go @@ -3,8 +3,8 @@ package resources import ( "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/snowflake" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/pkg/errors" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/pkg/errors" ) var validDatabasePrivileges = NewPrivilegeSet( @@ -36,7 +36,6 @@ var databaseGrantSchema = map[string]*schema.Schema{ Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, - ForceNew: true, Description: "Grants privilege to these roles.", }, "shares": { diff --git a/pkg/resources/external_table_grant.go b/pkg/resources/external_table_grant.go index a0e4d89ce4..11acb9a23a 100644 --- a/pkg/resources/external_table_grant.go +++ b/pkg/resources/external_table_grant.go @@ -45,14 +45,12 @@ var externalTableGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "shares": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these shares (only valid if on_future is false).", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -84,6 +82,7 @@ func ExternalTableGrant() *TerraformGrantResource { Create: CreateExternalTableGrant, Read: ReadExternalTableGrant, Delete: DeleteExternalTableGrant, + Update: UpdateExternalTableGrant, Schema: externalTableGrantSchema, Importer: &schema.ResourceImporter{ @@ -216,3 +215,56 @@ func DeleteExternalTableGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateExternalTableGrant implements schema.UpdateFunc +func UpdateExternalTableGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles", "shares") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + sharesToAdd := []string{} + sharesToRevoke := []string{} + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + if d.HasChange("shares") { + sharesToAdd, sharesToRevoke = changeDiff(d, "shares") + } + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + externalTableName := grantID.ObjectName + futureExternalTables := (externalTableName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futureExternalTables { + builder = snowflake.FutureExternalTableGrant(dbName, schemaName) + } else { + builder = snowflake.ExternalTableGrant(dbName, schemaName, externalTableName) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, sharesToRevoke) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd) + if err != nil { + return err + } + + // Done, refresh state + return ReadExternalTableGrant(d, meta) +} diff --git a/pkg/resources/file_format_grant.go b/pkg/resources/file_format_grant.go index 7675d0ed0d..e95024c602 100644 --- a/pkg/resources/file_format_grant.go +++ b/pkg/resources/file_format_grant.go @@ -44,7 +44,6 @@ var fileFormatGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -76,6 +75,7 @@ func FileFormatGrant() *TerraformGrantResource { Create: CreateFileFormatGrant, Read: ReadFileFormatGrant, Delete: DeleteFileFormatGrant, + Update: UpdateFileFormat, Schema: fileFormatGrantSchema, Importer: &schema.ResourceImporter{ @@ -205,3 +205,53 @@ func DeleteFileFormatGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateFileFormatGrant implements schema.UpdateFunc +func UpdateFileFormatGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + fileFormatName := grantID.ObjectName + futureFileFormats := (fileFormatName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futureFileFormats { + builder = snowflake.FutureFileFormatGrant(dbName, schemaName) + } else { + builder = snowflake.FileFormatGrant(dbName, schemaName, fileFormatName) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadFileFormatGrant(d, meta) +} diff --git a/pkg/resources/function_grant.go b/pkg/resources/function_grant.go index 2ef6f15a66..0d9c48be45 100644 --- a/pkg/resources/function_grant.go +++ b/pkg/resources/function_grant.go @@ -72,14 +72,12 @@ var functionGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "shares": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these shares (only valid if on_future is false).", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -111,6 +109,7 @@ func FunctionGrant() *TerraformGrantResource { Create: CreateFunctionGrant, Read: ReadFunctionGrant, Delete: DeleteFunctionGrant, + Update: UpdateFunctionGrant, Schema: functionGrantSchema, Importer: &schema.ResourceImporter{ @@ -286,3 +285,62 @@ func DeleteFunctionGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateFunctionGrant implements schema.UpdateFunc +func UpdateFunctionGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles", "shares") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + sharesToAdd := []string{} + sharesToRevoke := []string{} + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + if d.HasChange("shares") { + sharesToAdd, sharesToRevoke = changeDiff(d, "shares") + } + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + functionName := grantID.ObjectName + futureFunctions := (functionName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futureFunctions { + builder = snowflake.FutureFunctionGrant(dbName, schemaName) + } else { + functionSignatureMap, err := parseCallableObjectName(grantID.ObjectName) + if err != nil { + return err + } + functionName := functionSignatureMap["callableName"].(string) + argumentTypes := functionSignatureMap["argumentTypes"].([]string) + builder = snowflake.FunctionGrant(dbName, schemaName, functionName, argumentTypes) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, sharesToRevoke) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd) + if err != nil { + return err + } + + // Done, refresh state + return ReadFunctionGrant(d, meta) +} diff --git a/pkg/resources/integration_grant.go b/pkg/resources/integration_grant.go index 7c6701ec11..38bd47432e 100644 --- a/pkg/resources/integration_grant.go +++ b/pkg/resources/integration_grant.go @@ -30,7 +30,6 @@ var integrationGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "with_grant_option": { Type: schema.TypeBool, @@ -55,6 +54,7 @@ func IntegrationGrant() *TerraformGrantResource { Create: CreateIntegrationGrant, Read: ReadIntegrationGrant, Delete: DeleteIntegrationGrant, + Update: UpdateIntegrationGrant, Schema: integrationGrantSchema, Importer: &schema.ResourceImporter{ @@ -133,3 +133,45 @@ func DeleteIntegrationGrant(d *schema.ResourceData, meta interface{}) error { return deleteGenericGrant(d, meta, builder) } + +// UpdateIntegrationGrant implements schema.UpdateFunc +func UpdateIntegrationGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + w := grantID.ResourceName + + // create the builder + builder := snowflake.IntegrationGrant(w) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadIntegrationGrant(d, meta) +} diff --git a/pkg/resources/masking_policy_grant.go b/pkg/resources/masking_policy_grant.go index ae2a9002b8..35ff13e91a 100644 --- a/pkg/resources/masking_policy_grant.go +++ b/pkg/resources/masking_policy_grant.go @@ -37,7 +37,6 @@ var maskingPolicyGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "schema_name": { Type: schema.TypeString, @@ -68,6 +67,7 @@ func MaskingPolicyGrant() *TerraformGrantResource { Create: CreateMaskingPolicyGrant, Read: ReadMaskingPolicyGrant, Delete: DeleteMaskingPolicyGrant, + Update: UpdateMaskingPolicyGrant, Schema: maskingPolicyGrantSchema, Importer: &schema.ResourceImporter{ @@ -165,3 +165,47 @@ func DeleteMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { return deleteGenericGrant(d, meta, builder) } + +// UpdateMaskingPolicyGrant implements schema.UpdateFunc +func UpdateMaskingPolicyGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + maskingPolicyName := grantID.ObjectName + + // create the builder + builder := snowflake.MaskingPolicyGrant(dbName, schemaName, maskingPolicyName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadMaskingPolicyGrant(d, meta) +} diff --git a/pkg/resources/materialized_view_grant.go b/pkg/resources/materialized_view_grant.go index 850ae69cdc..86458f84e6 100644 --- a/pkg/resources/materialized_view_grant.go +++ b/pkg/resources/materialized_view_grant.go @@ -51,14 +51,12 @@ var materializedViewGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "shares": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these shares (only valid if on_future is false).", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -90,6 +88,7 @@ func MaterializedViewGrant() *TerraformGrantResource { Create: CreateMaterializedViewGrant, Read: ReadMaterializedViewGrant, Delete: DeleteMaterializedViewGrant, + Update: UpdateMaterializedViewGrant, Schema: materializedViewGrantSchema, Importer: &schema.ResourceImporter{ @@ -223,3 +222,56 @@ func DeleteMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error } return deleteGenericGrant(d, meta, builder) } + +// UpdateMaterializedViewGrant implements schema.UpdateFunc +func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles", "shares") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + sharesToAdd := []string{} + sharesToRevoke := []string{} + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + if d.HasChange("shares") { + sharesToAdd, sharesToRevoke = changeDiff(d, "shares") + } + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + materializedViewName := grantID.ObjectName + futureMaterializedViews := (materializedViewName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futureMaterializedViews { + builder = snowflake.FutureMaterializedViewGrant(dbName, schemaName) + } else { + builder = snowflake.MaterializedViewGrant(dbName, schemaName, materializedViewName) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, sharesToRevoke) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd) + if err != nil { + return err + } + + // Done, refresh state + return ReadMaterializedViewGrant(d, meta) +} diff --git a/pkg/resources/pipe_grant.go b/pkg/resources/pipe_grant.go index 4dcc8bbdbb..98bc7e8c1e 100644 --- a/pkg/resources/pipe_grant.go +++ b/pkg/resources/pipe_grant.go @@ -45,14 +45,12 @@ var pipeGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, Optional: true, Description: "When this is set to true and a schema_name is provided, apply this grant on all future pipes in the given schema. When this is true and no schema_name is provided apply this grant on all future pipes in the given database. The pipe_name field must be unset in order to use on_future.", Default: false, - ForceNew: true, }, "with_grant_option": { Type: schema.TypeBool, @@ -77,6 +75,7 @@ func PipeGrant() *TerraformGrantResource { Create: CreatePipeGrant, Read: ReadPipeGrant, Delete: DeletePipeGrant, + Update: UpdatePipeGrant, Schema: pipeGrantSchema, Importer: &schema.ResourceImporter{ @@ -206,3 +205,53 @@ func DeletePipeGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdatePipeGrant implements schema.UpdateFunc +func UpdatePipeGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + pipeName := grantID.ObjectName + futurePipes := (pipeName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futurePipes { + builder = snowflake.FuturePipeGrant(dbName, schemaName) + } else { + builder = snowflake.PipeGrant(dbName, schemaName, pipeName) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadPipeGrant(d, meta) +} diff --git a/pkg/resources/procedure_grant.go b/pkg/resources/procedure_grant.go index 50e3ccd699..f8073b676f 100644 --- a/pkg/resources/procedure_grant.go +++ b/pkg/resources/procedure_grant.go @@ -72,14 +72,12 @@ var procedureGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "shares": { Type: schema.TypeSet, Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these shares (only valid if on_future is false).", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -111,6 +109,7 @@ func ProcedureGrant() *TerraformGrantResource { Create: CreateProcedureGrant, Read: ReadProcedureGrant, Delete: DeleteProcedureGrant, + Update: UpdateProcedureGrant, Schema: procedureGrantSchema, Importer: &schema.ResourceImporter{ @@ -286,3 +285,62 @@ func DeleteProcedureGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateProcedureGrant implements schema.UpdateFunc +func UpdateProcedureGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles", "shares") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + sharesToAdd := []string{} + sharesToRevoke := []string{} + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + if d.HasChange("shares") { + sharesToAdd, sharesToRevoke = changeDiff(d, "shares") + } + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + procedureName := grantID.ObjectName + futureProcedures := (procedureName == "") + + // create the builder + var builder snowflake.GrantBuilder + if futureProcedures { + builder = snowflake.FutureProcedureGrant(dbName, schemaName) + } else { + procedureSignatureMap, err := parseCallableObjectName(grantID.ObjectName) + if err != nil { + return err + } + procedureName := procedureSignatureMap["callableName"].(string) + argumentTypes := procedureSignatureMap["argumentTypes"].([]string) + builder = snowflake.ProcedureGrant(dbName, schemaName, procedureName, argumentTypes) + } + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, sharesToRevoke) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, sharesToAdd) + if err != nil { + return err + } + + // Done, refresh state + return ReadProcedureGrant(d, meta) +} diff --git a/pkg/resources/resource_monitor_grant.go b/pkg/resources/resource_monitor_grant.go index 12a6e64973..7d6b149b45 100644 --- a/pkg/resources/resource_monitor_grant.go +++ b/pkg/resources/resource_monitor_grant.go @@ -31,7 +31,6 @@ var resourceMonitorGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "with_grant_option": { Type: schema.TypeBool, @@ -56,6 +55,7 @@ func ResourceMonitorGrant() *TerraformGrantResource { Create: CreateResourceMonitorGrant, Read: ReadResourceMonitorGrant, Delete: DeleteResourceMonitorGrant, + Update: UpdateResourceMonitorGrant, Schema: resourceMonitorGrantSchema, }, @@ -129,3 +129,45 @@ func DeleteResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error return deleteGenericGrant(d, meta, builder) } + +// UpdateResourceMonitorGrant implements schema.UpdateFunc +func UpdateResourceMonitorGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + w := grantID.ResourceName + + // create the builder + builder := snowflake.ResourceMonitorGrant(w) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadResourceMonitorGrant(d, meta) +} diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index 8b56a7b7b0..bfa561c464 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -37,7 +37,6 @@ var rowAccessPolicyGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "schema_name": { Type: schema.TypeString, @@ -165,3 +164,47 @@ func DeleteRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error return deleteGenericGrant(d, meta, builder) } + +// UpdateRowAccessPolicyGrant implements schema.UpdateFunc +func UpdateRowAccessPolicyGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + rowAccessPolicyName := grantID.ObjectName + + // create the builder + builder := snowflake.RowAccessPolicyGrant(dbName, schemaName, rowAccessPolicyName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadRowAccessPolicyGrant(d, meta) +} diff --git a/pkg/resources/sequence_grant.go b/pkg/resources/sequence_grant.go index 0eda749a47..c04181ac73 100644 --- a/pkg/resources/sequence_grant.go +++ b/pkg/resources/sequence_grant.go @@ -44,7 +44,6 @@ var sequenceGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -76,6 +75,7 @@ func SequenceGrant() *TerraformGrantResource { Create: CreateSequenceGrant, Read: ReadSequenceGrant, Delete: DeleteSequenceGrant, + Update: UpdateSequenceGrant, Schema: sequenceGrantSchema, Importer: &schema.ResourceImporter{ @@ -205,3 +205,47 @@ func DeleteSequenceGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateSequenceGrant implements schema.UpdateFunc +func UpdateSequenceGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + sequenceName := grantID.ObjectName + + // create the builder + builder := snowflake.SequenceGrant(dbName, schemaName, sequenceName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadSequenceGrant(d, meta) +} diff --git a/pkg/resources/stage_grant.go b/pkg/resources/stage_grant.go index 82397b9e35..5a86dd13d5 100644 --- a/pkg/resources/stage_grant.go +++ b/pkg/resources/stage_grant.go @@ -47,7 +47,6 @@ var stageGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -80,6 +79,7 @@ func StageGrant() *TerraformGrantResource { Create: CreateStageGrant, Read: ReadStageGrant, Delete: DeleteStageGrant, + Update: UpdateStageGrant, Schema: stageGrantSchema, Importer: &schema.ResourceImporter{ @@ -201,3 +201,47 @@ func DeleteStageGrant(d *schema.ResourceData, meta interface{}) error { return deleteGenericGrant(d, meta, builder) } + +// UpdateStageGrant implements schema.UpdateFunc +func UpdateStageGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + stageName := grantID.ObjectName + + // create the builder + builder := snowflake.StageGrant(dbName, schemaName, stageName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadStageGrant(d, meta) +} diff --git a/pkg/resources/stream_grant.go b/pkg/resources/stream_grant.go index a05e28e1ab..1fdc9a7b8a 100644 --- a/pkg/resources/stream_grant.go +++ b/pkg/resources/stream_grant.go @@ -44,7 +44,6 @@ var streamGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -76,6 +75,7 @@ func StreamGrant() *TerraformGrantResource { Create: CreateStreamGrant, Read: ReadStreamGrant, Delete: DeleteStreamGrant, + Update: UpdateStreamGrant, Schema: streamGrantSchema, Importer: &schema.ResourceImporter{ @@ -205,3 +205,47 @@ func DeleteStreamGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateStreamGrant implements schema.UpdateFunc +func UpdateStreamGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + streamName := grantID.ObjectName + + // create the builder + builder := snowflake.StreamGrant(dbName, schemaName, streamName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadStreamGrant(d, meta) +} diff --git a/pkg/resources/task_grant.go b/pkg/resources/task_grant.go index f881535744..0e372a1b9f 100644 --- a/pkg/resources/task_grant.go +++ b/pkg/resources/task_grant.go @@ -45,7 +45,6 @@ var taskGrantSchema = map[string]*schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, Description: "Grants privilege to these roles.", - ForceNew: true, }, "on_future": { Type: schema.TypeBool, @@ -77,6 +76,7 @@ func TaskGrant() *TerraformGrantResource { Create: CreateTaskGrant, Read: ReadTaskGrant, Delete: DeleteTaskGrant, + Update: UpdateTaskGrant, Schema: taskGrantSchema, Importer: &schema.ResourceImporter{ @@ -206,3 +206,47 @@ func DeleteTaskGrant(d *schema.ResourceData, meta interface{}) error { } return deleteGenericGrant(d, meta, builder) } + +// UpdateTaskGrant implements schema.UpdateFunc +func UpdateTaskGrant(d *schema.ResourceData, meta interface{}) error { + // for now the only thing we can update are roles or shares + // if nothing changed, nothing to update and we're done + if !d.HasChanges("roles") { + return nil + } + + rolesToAdd := []string{} + rolesToRevoke := []string{} + + if d.HasChange("roles") { + rolesToAdd, rolesToRevoke = changeDiff(d, "roles") + } + + grantID, err := grantIDFromString(d.Id()) + if err != nil { + return err + } + + dbName := grantID.ResourceName + schemaName := grantID.SchemaName + taskName := grantID.ObjectName + + // create the builder + builder := snowflake.TaskGrant(dbName, schemaName, taskName) + + // first revoke + err = deleteGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, rolesToRevoke, []string{}) + if err != nil { + return err + } + // then add + err = createGenericGrantRolesAndShares( + meta, builder, grantID.Privilege, grantID.GrantOption, rolesToAdd, []string{}) + if err != nil { + return err + } + + // Done, refresh state + return ReadTaskGrant(d, meta) +} From 7807218757d2d7499796c4fef3a205cf484ea470 Mon Sep 17 00:00:00 2001 From: ChrisIsidora Date: Tue, 27 Sep 2022 06:38:58 +0200 Subject: [PATCH 2/2] Added Missing Update Function --- pkg/resources/row_access_policy_grant.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/resources/row_access_policy_grant.go b/pkg/resources/row_access_policy_grant.go index bfa561c464..c4f1e9e5c4 100644 --- a/pkg/resources/row_access_policy_grant.go +++ b/pkg/resources/row_access_policy_grant.go @@ -67,6 +67,7 @@ func RowAccessPolicyGrant() *TerraformGrantResource { Create: CreateRowAccessPolicyGrant, Read: ReadRowAccessPolicyGrant, Delete: DeleteRowAccessPolicyGrant, + Update: UpdateRowAccessPolicyGrant, Schema: rowAccessPolicyGrantSchema, Importer: &schema.ResourceImporter{