Snowflake-Labs / terraform-provider-snowflake

Terraform provider for managing Snowflake accounts
https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest
MIT License
552 stars 420 forks source link

[Bug]: invalid OnSchemaObjectGrantKind: PROCEDURE during import #3132

Closed jrobison-sb closed 1 month ago

jrobison-sb commented 1 month ago

Terraform CLI Version

v1.9.1

Terraform Provider Version

v0.96.0

Terraform Configuration

Old HCL from version 0.92 of the provider:

resource "snowflake_procedure_grant" "create_database_and_change_ownership" {
  database_name       = snowflake_procedure.create_database_and_change_ownership.database
  schema_name         = snowflake_procedure.create_database_and_change_ownership.schema
  procedure_name      = snowflake_procedure.create_database_and_change_ownership.name
  privilege           = "USAGE"
  argument_data_types = ["string"]
  roles = [
    snowflake_role.ci.name,
    ...
  ]
}

New resource in 0.96 of the provider:

resource "snowflake_grant_privileges_to_account_role" "create_database_and_change_ownership_procedure_grants" {
  for_each = toset([
    snowflake_role.ci.name,
    ...
  ])
  privileges        = ["USAGE", ]
  account_role_name = each.key
  on_schema_object {
    object_type = "PROCEDURE"
    object_name = "${snowflake_procedure.create_database_and_change_ownership.database}.${snowflake_procedure.create_database_and_change_ownership.schema}.${snowflake_procedure.create_database_and_change_ownership.name}"
  }
}

Category

category:resource

Object type(s)

resource:grant_privileges_to_account_role

Expected Behavior

I should be able to migrate this grant from version 0.92 to version 0.96 by way of terraform state rm ... && terraform state import ... as generally described here.

Actual Behavior

$ terraform import module.snowflake_ci.snowflake_grant_privileges_to_account_role.create_database_and_change_ownership_procedure_grants[\"CI_ROLE\"] "CI_ROLE|false|false|USAGE|OnSchemaObject|PROCEDURE|CREATE_DATABASE_AND_CHANGE_OWNERSHIP.CREATE_DATABASE_AND_CHANGE_OWNERSHIP.CREATE_DB_AND_CHANGE_OWNERSHIP" 

Error: [grant_privileges_to_account_role_identifier.go:196] invalid OnSchemaObjectGrantKind: PROCEDURE

I have also tried the import using slashy escape quotes around the role name and the object names, but with the same error:

$ terraform import module.snowflake_ci.snowflake_grant_privileges_to_account_role.create_database_and_change_ownership_procedure_grants[\"CI_ROLE\"] "\"CI_ROLE\"|false|false|USAGE|OnSchemaObject|PROCEDURE|\"CREATE_DATABASE_AND_CHANGE_OWNERSHIP\".\"CREATE_DATABASE_AND_CHANGE_OWNERSHIP\".\"CREATE_DB_AND_CHANGE_OWNERSHIP\"" 

Steps to Reproduce

Try to replace an old snowflake_procedure_grant resource with a new snowflake_grant_privileges_to_account_role resource by way of terraform state rm ... && terraform import ....

How much impact is this issue causing?

Medium

Logs

No response

Additional Information

Here is the old resource as seen in the terraform state:

$ terraform state show module.snowflake_ci.snowflake_procedure_grant.create_database_and_change_ownership
# module.snowflake_ci.snowflake_procedure_grant.create_database_and_change_ownership:
resource "snowflake_procedure_grant" "create_database_and_change_ownership" {
    argument_data_types    = [
        "string",
    ]
    database_name          = "CREATE_DATABASE_AND_CHANGE_OWNERSHIP"
    enable_multiple_grants = false
    id                     = "CREATE_DATABASE_AND_CHANGE_OWNERSHIP|CREATE_DATABASE_AND_CHANGE_OWNERSHIP|CREATE_DB_AND_CHANGE_OWNERSHIP|string|USAGE|false|false|false|STAFF_SPRINGBOOT,CI_ROLE|"
    on_all                 = false
    on_future              = false
    privilege              = "USAGE"
    procedure_name         = "CREATE_DB_AND_CHANGE_OWNERSHIP"
    roles                  = [
        "CI_ROLE",
        "STAFF_SPRINGBOOT",
    ]
    schema_name            = "CREATE_DATABASE_AND_CHANGE_OWNERSHIP"
    shares                 = []
    with_grant_option      = false
}

And as seen in Snowflake:

image

Would you like to implement a fix?

jrobison-sb commented 1 month ago

Here is how to reproduce this on-demand with minimal moving parts.

  1. Take this HCL and apply it using provider version 0.92.0. This will apply cleanly.
terraform {
  required_providers {
    snowflake = {
      source  = "Snowflake-Labs/snowflake"
      version = "0.92.0"
    }
  }
}

resource "snowflake_role" "foo" {
  name = "ROLE_ISSUE_3132"
}

resource "snowflake_database" "foo" {
  name = "DATABASE_ISSUE_3132"
}

resource "snowflake_schema" "foo" {
  database = snowflake_database.foo.name
  name     = "SCHEMA_ISSUE_3132"
}

resource "snowflake_procedure" "foo" {
  name     = "PROCEDURE_ISSUE_3132"
  database = snowflake_database.foo.name
  schema   = snowflake_schema.foo.name
  language = "JAVASCRIPT"
  arguments {
    name = "arg1"
    type = "varchar"
  }
  comment     = "Procedure with 1 argument"
  return_type = "VARCHAR"
  execute_as  = "OWNER"
  statement   = <<EOT
var X=1
return X
EOT
}

# terraform state rm snowflake_procedure_grant.foo
resource "snowflake_procedure_grant" "foo" {
  database_name       = snowflake_procedure.foo.database
  schema_name         = snowflake_procedure.foo.schema
  procedure_name      = snowflake_procedure.foo.name
  privilege           = "USAGE"
  argument_data_types = ["string"]
  roles = [
    snowflake_role.foo.name,
  ]
}

# terraform import snowflake_grant_privileges_to_account_role.foo[\"ROLE_ISSUE_3132\"] "\"ROLE_ISSUE_3132\"|false|false|USAGE|OnSchemaObject|PROCEDURE|\"DATABASE_ISSUE_3132\".\"SCHEMA_ISSUE_3132\".\"PROCEDURE_ISSUE_3132\""
# resource "snowflake_grant_privileges_to_account_role" "foo" {
#   for_each = toset([
#     snowflake_role.foo.name,
#   ])
#   privileges        = ["USAGE", ]
#   account_role_name = each.key
#   on_schema_object {
#     object_type = "PROCEDURE"
#     object_name = "${snowflake_procedure.foo.database}.${snowflake_procedure.foo.schema}.${snowflake_procedure.foo.name}"
#   }
# }
  1. Upgrade the provider version pin to 0.96.0 and terraform init.
  2. Comment out snowflake_procedure_grant.foo
  3. Uncomment snowflake_grant_privileges_to_account_role.foo
  4. terraform state rm snowflake_procedure_grant.foo
  5. terraform import snowflake_grant_privileges_to_account_role.foo[\"ROLE_ISSUE_3132\"] "\"ROLE_ISSUE_3132\"|false|false|USAGE|OnSchemaObject|PROCEDURE|\"DATABASE_ISSUE_3132\".\"SCHEMA_ISSUE_3132\".\"PROCEDURE_ISSUE_3132\"" (you can try this one with or without slashy escape quotes, it's the same both ways).
  6. See error:
    snowflake_grant_privileges_to_account_role.foo["ROLE_ISSUE_3132"]: Importing from ID "\"ROLE_ISSUE_3132\"|false|false|USAGE|OnSchemaObject|PROCEDURE|\"DATABASE_ISSUE_3132\".\"SCHEMA_ISSUE_3132\".\"PROCEDURE_ISSUE_3132\""...
    ╷
    │ Error: [grant_privileges_to_account_role_identifier.go:196] invalid OnSchemaObjectGrantKind: PROCEDURE
    │ 
    │ 
    ╵
sfc-gh-jmichalak commented 1 month ago

Hi @jrobison-sb 👋

Thanks for the detailed description. There are two problems here:

  1. In order to grant privileges on functions and procedures, you must provide the fully qualified name of the resource, which in this case also includes argument types. In v0.96, we introduced a computed fully_qualified_name field, which is suited for referencing in other resources. Please try something like
     object_name = snowflake_procedure.foo.fully_qualified_name
  2. The import ID is incorrect. The format should be
    "<account_role_name>|<with_grant_option>|<always_apply>|<privileges>|OnSchemaObject|OnObject|<object_type>|<object_name>"

    (see docs). You are missing OnObject part in your import statements.

jrobison-sb commented 1 month ago

@sfc-gh-jmichalak thanks.

I was able to get this to import using:

terraform import snowflake_grant_privileges_to_account_role.foo[\"ROLE_ISSUE_3132\"] "\"ROLE_ISSUE_3132\"|false|false|USAGE|OnSchemaObject|OnObject|PROCEDURE|\"DATABASE_ISSUE_3132\".\"SCHEMA_ISSUE_3132\".\"PROCEDURE_ISSUE_3132\"(VARCHAR)"

In case anyone stumbles upon this from google, the name of the procedure needed to include the argument type ((VARCHAR)), otherwise the import crashed the provider.