terraform-provider-snowflake icon indicating copy to clipboard operation
terraform-provider-snowflake copied to clipboard

Unable to use snowflake_grant_privileges_to_role for functions and procedures

Open danu165 opened this issue 1 year ago • 9 comments

Provider Version

0.69.0

Terraform Version

1.0.8

Describe the bug

Terraform creates an incorrect SQL statement where data types are needed for objects like procedures and grants

Expected behavior

Terraform would create a correct SQL statement.

Code samples and commands

I've tried 2 different methods, one where I do not specify any double quotes (see resource ID functions) and one where I escape the double quotes (see resource ID procedures).

resource "snowflake_grant_privileges_to_role" "functions" {
  privileges = ["USAGE"]
  role_name  = "DEV_90467_DATA_ANALYST_FR"
  on_schema_object {
    object_type = "FUNCTION"
    object_name = "DEV_90467_DB.DT_LOCAL_PAVE_FUNCTION_PROCS.EXAMPLE(FLOAT)"
  }
}
resource "snowflake_grant_privileges_to_role" "procedures" {
  privileges = ["USAGE"]
  role_name  = "DEV_90467_DATA_ANALYST_FR"
  on_schema_object {
    object_type = "PROCEDURE"
    object_name = "\"DEV_90467_DB\".\"DT_LOCAL_PAVE_FUNCTION_PROCS\".\"EXAMPLE\"(VARCHAR)"
  }
}

The errors returned are:

╷
│ Error: error granting privileges to account role: 090208 (42601): Argument types of function 'EXAMPLE(FLOAT)' must be specified.
│
│   with snowflake_grant_privileges_to_role.functions,
│   on main.tf line 79, in resource "snowflake_grant_privileges_to_role" "functions":
│   79: resource "snowflake_grant_privileges_to_role" "functions" {
│
╵
╷
│ Error: error granting privileges to account role: 001003 (42000): SQL compilation error:
│ syntax error line 1 at position 89 unexpected '" TO ROLE "'.
│ syntax error line 1 at position 100 unexpected 'DEV_90467_DATA_ANALYST_FR'.
│
│   with snowflake_grant_privileges_to_role.procedures,
│   on main.tf line 87, in resource "snowflake_grant_privileges_to_role" "procedures":
│   87: resource "snowflake_grant_privileges_to_role" "procedures" {
│

In query history, I see the functions statement resolve to this:

GRANT USAGE ON FUNCTION "DEV_90467_DB"."DT_LOCAL_PAVE_FUNCTION_PROCS"."EXAMPLE(FLOAT)" TO ROLE "DEV_90467_DATA_ANALYST_FR"

The problem here is that (FLOAT) should not be included in the double quotes.

The procedures statement resolves to this:

GRANT USAGE ON PROCEDURE "DEV_90467_DB"."DT_LOCAL_PAVE_FUNCTION_PROCS"."EXAMPLE"(VARCHAR)" TO ROLE "DEV_90467_DATA_ANALYST_FR"

The problem here is that there is an extra quote after (VARCHAR).

The goal would be to resolve to one of these 2 statements:

GRANT USAGE ON PROCEDURE "DEV_90467_DB"."DT_LOCAL_PAVE_FUNCTION_PROCS"."EXAMPLE"(VARCHAR) TO ROLE "DEV_90467_DATA_ANALYST_FR";  -- option 1
GRANT USAGE ON PROCEDURE DEV_90467_DB.DT_LOCAL_PAVE_FUNCTION_PROCS.EXAMPLE(VARCHAR) TO ROLE "DEV_90467_DATA_ANALYST_FR";  -- option 2

Additional context

Ideally I'm looking for a syntactical solution here. Please let me know what we can do to get around these errors.

danu165 avatar Aug 07 '23 21:08 danu165

@sfc-gh-swinkler I see you merged a fix but my problem fits completely the Terraform creates an incorrect SQL statement where data types are needed for objects like procedures and grants so I'll chip in.

  • snowflake-labs/snowflake v0.70.1
  • Terraform v1.4.2

I have a procedure: STAGE.PUBLIC.REFRESH_WAREHOUSE_DETAILS() that takes no arguments and I am piping it like this to the resource (and it still has the parenthesis at that point):

  "STAGE.PUBLIC.REFRESH_WAREHOUSE_DETAILS()|TRANSFORMER|false|false" = [
    "USAGE",
  ]

It results in

  # snowflake_grant_privileges_to_role.on_this_procedure["STAGE.PUBLIC.REFRESH_WAREHOUSE_DETAILS|TRANSFORMER|false|false"] will be created
  + resource "snowflake_grant_privileges_to_role" "on_this_procedure" {
      + all_privileges    = false
      + id                = (known after apply)
      + on_account        = false
      + privileges        = [
          + "USAGE",
        ]
      + role_name         = "TRANSFORMER"
      + with_grant_option = false

      + on_schema_object {
          + object_name = "STAGE.PUBLIC.REFRESH_WAREHOUSE_DETAILS"
          + object_type = "PROCEDURE"
        }
    }

and when applying

╷
│ Error: error granting privileges to account role: 090208 (42601): Argument types of function 'REFRESH_WAREHOUSE_DETAILS' must be specified.
│ 
│   with snowflake_grant_privileges_to_role.on_this_procedure["STAGE.PUBLIC.REFRESH_WAREHOUSE_DETAILS|TRANSFORMER|false|false"],
│   on main.tf line 321, in resource "snowflake_grant_privileges_to_role" "on_this_procedure":
│  321: resource "snowflake_grant_privileges_to_role" "on_this_procedure" {
│ 
╵

All my procedures that do contain arguments have no problem for grants

PedroMartinSteenstrup avatar Sep 20 '23 13:09 PedroMartinSteenstrup

I also faced this issue. The grants for the functions/procedures with the arguments work fine as is:

resource "snowflake_grant_privileges_to_role" "test" {
  privileges = [
    "USAGE",
  ]
  role_name = "MY_ROLE"

  on_schema_object {
    object_name = "DB.MY_SCHEMA.ARGUMENT_PROCEDURE(VARCHAR, VARCHAR)"
    object_type = "PROCEDURE"
  }
}

But for the function/procedure without arguments you still have to include parentheses, just escape them like this: MY_FUNCTION(\\):

resource "snowflake_grant_privileges_to_role" "test" {
  privileges = [
    "USAGE",
  ]
  role_name = "MY_ROLE"

  on_schema_object {
    object_name = "DB.MY_SCHEMA.NO_ARGUMENTS_PROCEDURE(\\)"
    object_type = "PROCEDURE"
  }
}

abarabash-sift avatar Nov 20 '23 23:11 abarabash-sift

This method does not seem to work (anymore) with the new "snowflake_grant_privileges_to_account_role".

resource "snowflake_grant_privileges_to_account_role" "object_procedure" {
  on_schema_object {
    object_type = "PROCEDURE"
    object_name = "MYDB.MYSCHEMA.MYPROC(\\)"
  }
  account_role_name  = var.role
  privileges = var.privileges

  with_grant_option = false
}

The error I get then is:

│ Error: Failed to retrieve grants
│ 
│   with module.sf_autorisation["MYROLE"].module.single_procedure["MYROLE-MYDB-MYSCHEMA-MYPROC(\\\\)"].snowflake_grant_privileges_to_account_role.object_procedure,

It goes from \\ to \\\\ somehow. It also "corrupts" the state file because subsequent plans will fail looking for MYROLE-MYDB-MYSCHEMA-MYPROC(\\\\) which is not there.

Not putting anything between the brackets also still does not work:

Error: 090208 (42601): Argument types of function 'MYPROC'
│ must be specified.

Edit: just to confirm, I can create the exact same successful result as above comment using the old resource "snowflake_grant_privileges_to_role" so this really is something that has to to with the new "snowflake_grant_privileges_to_account_role"

maxnsdia avatar Mar 27 '24 10:03 maxnsdia

Hey @danu165 @PedroMartinSteenstrup @abarabash-sift @maxnsdia 👋 This seems like a typical issue that we would like to resolve soon with the identifiers refactor, we mentioned on our roadmap. It's connected with the way identifiers are represented and quoted internally. Right now, there's no good internal identifier to represent identifiers of functions/procedures, but we should start working on it soon. For now, I'll try to check if there's any workaround you could use instead.

sfc-gh-jcieslak avatar Mar 27 '24 16:03 sfc-gh-jcieslak

Thank you for the response @sfc-gh-jcieslak, good to know it's being worked on as part of a larger refactoring. The workaround now is using the method @abarabash-sift mentions above, which works fine as long as you use snowflake_grant_privileges_to_role and not upgrade yet to snowflake_grant_privileges_to_account_role.

A minor inconvenience with using that using the 'old' resource is that this message turns up in the pipeline.

╷
│ Warning: Deprecated Resource
│ 
│   with module.MYMODULE,
│   on MYREPO\myfile.tf line 1, in resource "snowflake_grant_privileges_to_role" "object_procedure":
│    1: resource "snowflake_grant_privileges_to_role" "object_procedure" {
│ 
│ This resource is deprecated and will be removed in a future major version
│ release. Please use snowflake_grant_privileges_to_account_role instead.
│ 
│ (and one more similar warning elsewhere)
╵

maxnsdia avatar Mar 28 '24 16:03 maxnsdia

Hi @sfc-gh-jcieslak , From 0.93 onwards the older resource (grant_privileges_to_role) is phased out and I still can't get the new resource (grant_privileges_to_account_role) to work with a single procedure that has no argument types: myproc(). If there is at least one argument type it does work. What would the fully qualified object_name have to be? The below snippet does not work.

resource "snowflake_grant_privileges_to_account_role" "object_procedure" {
  on_schema_object {
    object_type = "PROCEDURE"
    object_name = \"MYDB\".\"MYSCHEMA\".\"MYPROC\"()"
  }
  account_role_name  = var.role
  privileges = var.privileges

  with_grant_option = false
}
 Id:
│ "MYROLE"|false|false|USAGE|OnSchemaObject|OnObject|PROCEDURE|MYDB"."MYSCHEMA"."MYPROC"
│ Account role name: {MYROLE}
│ Error: 090208 (42601): Argument types of function
│ 'MYPROC' must be specified.

When there is an argument type, the fully qualified name works: \"MYDB\".\"MYSCHEMA\".\"MYPROC\"(VARCHAR)"

maxnsdia avatar Aug 16 '24 08:08 maxnsdia

Hi @maxnsdia 👋 We're now fixing this issue - it should be improved in the next release.

sfc-gh-jmichalak avatar Aug 16 '24 08:08 sfc-gh-jmichalak

Hello, we are currently facing this issue as well, any news on this ? Thank you 🙏

anaslebrigui avatar Oct 01 '24 12:10 anaslebrigui

Hi @anaslebrigui 👋 This was fixed in https://github.com/Snowflake-Labs/terraform-provider-snowflake/releases/tag/v0.95.0 - please migrate using our migration guide. For referencing a function in object_name, use

object_name = snowflake_function.function.fully_qualified_name

sfc-gh-jmichalak avatar Oct 01 '24 13:10 sfc-gh-jmichalak