Skip to content

Commit

Permalink
feat: added on_all grants for view, stage, schema and materialized vi…
Browse files Browse the repository at this point in the history
…ew resource (#1686)

* feat: added all view grant

* fix: fixed docs to all table grant

* feat: added all stage grant

* feat: added all schema grant

* fix: fixed copy and paste errors in with all schema and all stage grant

* feat: added materialized view all grant

* docs: fixing typos

* test: fixed test after correcting the underlying query

* docs: fixed copy & paste error

* fix: minor fixes after code review

* docs: fixes

* test: added acceptance test for view_grants

* fix: looking into importing on_future or on_all grants

* fix: added logic to distinguish on_future and on_all grants during reading

* fix: added getOnFutureOnAll function

* fix: fixed on_future import for table_grant

* fix: went back to simpler on_all/on_future read-check for view grant

* fix: updated read-logic for stage_grant and added acceptance test

* fix: updated read-logic for materialized_view_grant and schema_grant and added acceptance test

* docs: update

* style: fmt linter

* style: fmt linter

---------

Co-authored-by: Arkadius Schuchhardt <schuchhardt@auxmoney.com>
Co-authored-by: Scott Winkler <scott.winkler@snowflake.com>
  • Loading branch information
3 people authored Apr 11, 2023
1 parent 4a84eb9 commit f27a9e4
Show file tree
Hide file tree
Showing 18 changed files with 512 additions and 412 deletions.
9 changes: 5 additions & 4 deletions docs/resources/materialized_view_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ resource "snowflake_materialized_view_grant" "grant" {
### Optional

- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.
- `materialized_view_name` (String) The name of the materialized view on which to grant privileges immediately (only valid if on_future is false).
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future.
- `privilege` (String) The privilege to grant on the current or future materialized view view.
- `materialized_view_name` (String) The name of the materialized view on which to grant privileges immediately (only valid if on_future and on_all are false).
- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.
- `privilege` (String) The privilege to grant on the current or future materialized view.
- `roles` (Set of String) Grants privilege to these roles.
- `schema_name` (String) The name of the schema containing the current or future materialized views on which to grant privileges.
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is false).
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are false).
- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles.

### Read-Only
Expand Down
5 changes: 3 additions & 2 deletions docs/resources/schema_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ resource "snowflake_schema_grant" "grant" {
### Optional

- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.
- `on_future` (Boolean) When this is set to true, apply this grant on all future schemas in the given database. The schema_name and shares fields must be unset in order to use on_future.
- `on_all` (Boolean) When this is set to true, apply this grant on all schemas in the given database. The schema_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.
- `on_future` (Boolean) When this is set to true, apply this grant on all future schemas in the given database. The schema_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.
- `privilege` (String) The privilege to grant on the current or future schema. Note that if "OWNERSHIP" is specified, ensure that the role that terraform is using is granted access.
- `roles` (Set of String) Grants privilege to these roles.
- `schema_name` (String) The name of the schema on which to grant privileges.
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is unset).
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are unset).
- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles.

### Read-Only
Expand Down
5 changes: 3 additions & 2 deletions docs/resources/stage_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ resource "snowflake_stage_grant" "grant" {
### Optional

- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future stages in the given schema. When this is true and no schema_name is provided apply this grant on all future stages in the given database. The stage_name field must be unset in order to use on_future.
- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all stages in the given schema. When this is true and no schema_name is provided apply this grant on all stages in the given database. The stage_name field must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future stages in the given schema. When this is true and no schema_name is provided apply this grant on all future stages in the given database. The stage_name field must be unset in order to use on_future. Cannot be used together with on_all.
- `privilege` (String) The privilege to grant on the stage.
- `schema_name` (String) The name of the schema containing the current stage on which to grant privileges.
- `stage_name` (String) The name of the stage on which to grant privilege (only valid if on_future is false).
- `stage_name` (String) The name of the stage on which to grant privilege (only valid if on_future and on_all are false).
- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles.

### Read-Only
Expand Down
8 changes: 4 additions & 4 deletions docs/resources/table_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ resource "snowflake_table_grant" "grant" {
### Optional

- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.
- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all all tables in the given schema. When this is true and no schema_name is provided apply this grant on all all tables in the given database. The table_name and shares fields must be unset in order to use on_all.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future tables in the given schema. When this is true and no schema_name is provided apply this grant on all future tables in the given database. The table_name and shares fields must be unset in order to use on_future.
- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all tables in the given schema. When this is true and no schema_name is provided apply this grant on all tables in the given database. The table_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future tables in the given schema. When this is true and no schema_name is provided apply this grant on all future tables in the given database. The table_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.
- `privilege` (String) The privilege to grant on the current or future table.
- `roles` (Set of String) Grants privilege to these roles.
- `schema_name` (String) The name of the schema containing the current or future tables on which to grant privileges.
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future or on_all is unset).
- `table_name` (String) The name of the table on which to grant privileges immediately (only valid if on_future or on_all is unset).
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future or on_all are unset).
- `table_name` (String) The name of the table on which to grant privileges immediately (only valid if on_future or on_all are unset).
- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles.

### Read-Only
Expand Down
7 changes: 4 additions & 3 deletions docs/resources/view_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,13 @@ resource "snowflake_schema_grant" "grant" {
### Optional

- `enable_multiple_grants` (Boolean) When this is set to true, multiple grants of the same type can be created. This will cause Terraform to not revoke grants applied to roles and objects outside Terraform.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future views in the given schema. When this is true and no schema_name is provided apply this grant on all future views in the given database. The view_name and shares fields must be unset in order to use on_future.
- `on_all` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all views in the given schema. When this is true and no schema_name is provided apply this grant on all views in the given database. The view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.
- `on_future` (Boolean) When this is set to true and a schema_name is provided, apply this grant on all future views in the given schema. When this is true and no schema_name is provided apply this grant on all future views in the given database. The view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.
- `privilege` (String) The privilege to grant on the current or future view.
- `roles` (Set of String) Grants privilege to these roles.
- `schema_name` (String) The name of the schema containing the current or future views on which to grant privileges.
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future is unset).
- `view_name` (String) The name of the view on which to grant privileges immediately (only valid if on_future is unset).
- `shares` (Set of String) Grants privilege to these shares (only valid if on_future and on_all are unset).
- `view_name` (String) The name of the view on which to grant privileges immediately (only valid if on_future and on_all are unset).
- `with_grant_option` (Boolean) When this is set to true, allows the recipient role to grant the privileges to other roles.

### Read-Only
Expand Down
8 changes: 8 additions & 0 deletions pkg/resources/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ import (
"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources"
)

type grantType int

const (
normal grantType = iota
onFuture
onAll
)

func database(t *testing.T, id string, params map[string]interface{}) *schema.ResourceData {
t.Helper()
r := require.New(t)
Expand Down
87 changes: 54 additions & 33 deletions pkg/resources/materialized_view_grant.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

/*
NewPriviligeSet creates a set of privileges that are allowed
NewPrivilegeSet creates a set of privileges that are allowed
They are used for validation in the schema object below.
*/

Expand All @@ -28,7 +28,7 @@ var materializedViewGrantSchema = map[string]*schema.Schema{
"materialized_view_name": {
Type: schema.TypeString,
Optional: true,
Description: "The name of the materialized view on which to grant privileges immediately (only valid if on_future is false).",
Description: "The name of the materialized view on which to grant privileges immediately (only valid if on_future and on_all are false).",
ForceNew: true,
},
"schema_name": {
Expand All @@ -46,7 +46,7 @@ var materializedViewGrantSchema = map[string]*schema.Schema{
"privilege": {
Type: schema.TypeString,
Optional: true,
Description: "The privilege to grant on the current or future materialized view view.",
Description: "The privilege to grant on the current or future materialized view.",
Default: "SELECT",
ValidateFunc: validation.StringInSlice(validMaterializedViewPrivileges.ToList(), true),
ForceNew: true,
Expand All @@ -61,12 +61,19 @@ var materializedViewGrantSchema = map[string]*schema.Schema{
Type: schema.TypeSet,
Elem: &schema.Schema{Type: schema.TypeString},
Optional: true,
Description: "Grants privilege to these shares (only valid if on_future is false).",
Description: "Grants privilege to these shares (only valid if on_future and on_all are false).",
},
"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 materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future.",
Description: "When this is set to true and a schema_name is provided, apply this grant on all future materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all future materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_future. Cannot be used together with on_all.",
Default: false,
ForceNew: true,
},
"on_all": {
Type: schema.TypeBool,
Optional: true,
Description: "When this is set to true and a schema_name is provided, apply this grant on all materialized views in the given schema. When this is true and no schema_name is provided apply this grant on all materialized views in the given database. The materialized_view_name and shares fields must be unset in order to use on_all. Cannot be used together with on_future. Importing the resource with the on_all=true option is not supported.",
Default: false,
ForceNew: true,
},
Expand Down Expand Up @@ -140,26 +147,30 @@ func CreateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error
databaseName := d.Get("database_name").(string)
schemaName := d.Get("schema_name").(string)
privilege := d.Get("privilege").(string)
futureMaterializedViews := d.Get("on_future").(bool)
onFuture := d.Get("on_future").(bool)
onAll := d.Get("on_all").(bool)
withGrantOption := d.Get("with_grant_option").(bool)
roles := expandStringList(d.Get("roles").(*schema.Set).List())
shares := expandStringList(d.Get("shares").(*schema.Set).List())

if (schemaName == "") && !futureMaterializedViews {
return errors.New("schema_name must be set unless on_future is true")
if (schemaName == "") && !onFuture && !onAll {
return errors.New("schema_name must be set unless on_future or on_all is true")
}

if (materializedViewName == "") && !futureMaterializedViews {
return errors.New("materialized_view_name must be set unless on_future is true")
if (materializedViewName == "") && !onFuture && !onAll {
return errors.New("materialized_view_name must be set unless on_future or on_all is true")
}
if (materializedViewName != "") && futureMaterializedViews {
return errors.New("materialized_view_name must be empty if on_future is true")
if (materializedViewName != "") && onFuture && onAll {
return errors.New("materialized_view_name must be empty if on_future and on_all is true")
}

var builder snowflake.GrantBuilder
if futureMaterializedViews {
switch {
case onFuture:
builder = snowflake.FutureMaterializedViewGrant(databaseName, schemaName)
} else {
case onAll:
builder = snowflake.AllMaterializedViewGrant(databaseName, schemaName)
default:
builder = snowflake.MaterializedViewGrant(databaseName, schemaName, materializedViewName)
}

Expand All @@ -185,33 +196,35 @@ func ReadMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error {
if err := d.Set("schema_name", grantID.SchemaName); err != nil {
return err
}
futureMaterializedViewsEnabled := false
if grantID.ObjectName == "" {
futureMaterializedViewsEnabled = true
}
if err := d.Set("materialized_view_name", grantID.ObjectName); err != nil {
return err
}
if err := d.Set("on_future", futureMaterializedViewsEnabled); err != nil {
return err
}
if err := d.Set("privilege", grantID.Privilege); err != nil {
return err
}
if err := d.Set("with_grant_option", grantID.WithGrantOption); err != nil {
return err
}

onAll := d.Get("on_all").(bool) // importing on_all is not supported as there is no way to determine on_all state in snowflake
onFuture := false
if grantID.ObjectName == "" && !onAll {
onFuture = true
}
if err = d.Set("on_future", onFuture); err != nil {
return err
}
var builder snowflake.GrantBuilder
if futureMaterializedViewsEnabled {
switch {
case onFuture:
builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
} else {
case onAll:
builder = snowflake.AllMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
default:
builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName)
}
// TODO
onAll := false

return readGenericGrant(d, meta, materializedViewGrantSchema, builder, futureMaterializedViewsEnabled, onAll, validMaterializedViewPrivileges)
return readGenericGrant(d, meta, materializedViewGrantSchema, builder, onFuture, onAll, validMaterializedViewPrivileges)
}

// DeleteMaterializedViewGrant implements schema.DeleteFunc.
Expand All @@ -221,12 +234,16 @@ func DeleteMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error
return err
}

futureMaterializedViews := (grantID.ObjectName == "")
onFuture := d.Get("on_future").(bool)
onAll := d.Get("on_all").(bool)

var builder snowflake.GrantBuilder
if futureMaterializedViews {
switch {
case onFuture:
builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
} else {
case onAll:
builder = snowflake.AllMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
default:
builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName)
}
return deleteGenericGrant(d, meta, builder)
Expand All @@ -235,7 +252,7 @@ func DeleteMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error
// 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 nothing changed, nothing to update, and we're done
if !d.HasChanges("roles", "shares") {
return nil
}
Expand All @@ -255,13 +272,17 @@ func UpdateMaterializedViewGrant(d *schema.ResourceData, meta interface{}) error
return err
}

futureMaterializedViews := (grantID.ObjectName == "")
onFuture := d.Get("on_future").(bool)
onAll := d.Get("on_all").(bool)

// create the builder
var builder snowflake.GrantBuilder
if futureMaterializedViews {
switch {
case onFuture:
builder = snowflake.FutureMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
} else {
case onAll:
builder = snowflake.AllMaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName)
default:
builder = snowflake.MaterializedViewGrant(grantID.DatabaseName, grantID.SchemaName, grantID.ObjectName)
}

Expand Down
Loading

0 comments on commit f27a9e4

Please sign in to comment.