mongodb / terraform-provider-mongodbatlas

Terraform MongoDB Atlas Provider: Deploy, update, and manage MongoDB Atlas infrastructure as code through HashiCorp Terraform
https://registry.terraform.io/providers/mongodb/mongodbatlas
Mozilla Public License 2.0
243 stars 170 forks source link

Provider version 1.12.0 is breaking the resource mongodbatlas_database_user (1.11.1 works correctly) #1485

Closed joaquin386 closed 1 year ago

joaquin386 commented 1 year ago

Hello!

Version 1.12.0 is breaking the resource "mongodbatlas_database_user" "createdbusers". Can you please remove the 1.12.0 version? We have in many project to pick any 1.X.X version. If hardcoding to 1.11.1 then everything is fine.

1.12.0 Logs: Plan Change:

  ~ resource "mongodbatlas_database_user" "createdbusers" {
        id                 = "IDHERE-arn:aws:iam::XXXXXXXXXXX:role/service-irsa-apifactory-uaa-service-non-prod-$external"
        # (7 unchanged attributes hidden)

      - roles {
          - database_name = "caching" -> null
          - role_name     = "readWrite" -> null
        }
      + roles {
          + database_name = "caching"
          + role_name     = "readWrite"
        }

        # (2 unchanged blocks hidden)
    }

Apply Change:

  ~ resource "mongodbatlas_database_user" "createdbusers" {
        id                 = "IDHERE-arn:aws:iam::XXXXXXXXX:role/service-irsa-apifactory-uaa-service-non-prod-$external"
        # (7 unchanged attributes hidden)

      - roles {
          - database_name = "caching" -> null
          - role_name     = "readWrite" -> null
        }
      + roles {
          + database_name = "caching"
          + role_name     = "readWrite"
        }

        # (2 unchanged blocks hidden)
    }

Error when tf apply:

│ Error: Provider produced inconsistent result after apply
│ 
│ When applying changes to
│ module.db_users.mongodbatlas_database_user.createdbusers[0], provider
│ "provider[\"registry.terraform.io/mongodb/mongodbatlas\"]" produced an
│ unexpected new value: .roles: planned set element
│ cty.ObjectVal(map[string]cty.Value{"collection_name":cty.StringVal(""),
│ "database_name":cty.StringVal("caching"),
│ "role_name":cty.StringVal("readWrite")}) does not correlate with any
│ element in actual.
│ 
│ This is a bug in the provider, which should be reported in the provider's
│ own issue tracker.

It does create a DB Access but then it give the above error

github-actions[bot] commented 1 year ago

Thanks for opening this issue. The ticket INTMDB-1130 was created for internal tracking.

maastha commented 1 year ago

@joaquin386 Please also share your Terraform config for this issue.

joaquin386 commented 1 year ago

I did open a ticket internally with Mongo 01193655. FYI. All of that is shared there.

Here the service tf:

module "db_users" {
  source = "git::https://XXXXXXX/terraform-mongodb-atlas//modules/dbuser?ref=v2.1.2"
  mongodb_atlas_db_users = [
    {
      aws_iam_role       = module.irsa_role.role_arn
      aws_iam_role_type  = "ROLE"
      project_id         = data.aws_ssm_parameter.mongodbatlas_project_id.value
      auth_database_name = "$external"
      roles = [
        {
          role_name       = "readWrite"
          database_name   = local.database_name
          collection_name = ""
        },
      ]
      label_key   = "category"
      label_value = "specific_user_privileges"
      scopes = [
        {
          name = local.cluster_name
          type = "CLUSTER"
        }
      ]
    }
  ]
}

And here the module:

resource "mongodbatlas_database_user" "createdbusers" {
  count              = length(var.mongodb_atlas_db_users)
  username           = var.mongodb_atlas_db_users[count.index].aws_iam_role
  project_id         = var.mongodb_atlas_db_users[count.index].project_id
  auth_database_name = var.mongodb_atlas_db_users[count.index].auth_database_name
  aws_iam_type       = var.mongodb_atlas_db_users[count.index].aws_iam_role_type
  dynamic "roles" {
    for_each = var.mongodb_atlas_db_users[count.index].roles
    iterator = item
    content {
      role_name       = item.value.role_name
      database_name   = item.value.database_name
      collection_name = item.value.collection_name
    }
  }
  labels {
    key   = var.mongodb_atlas_db_users[count.index].label_key
    value = var.mongodb_atlas_db_users[count.index].label_value
  }

  dynamic "scopes" {
    for_each = var.mongodb_atlas_db_users[count.index].scopes
    iterator = scope
    content {
      name = scope.value.name
      type = scope.value.type
    }
  }
}

Module var file

variable "mongodb_atlas_db_users" {
  description = "list of objects where each object defines the inputs for single user"
  type = list(object({
    aws_iam_role       = string
    aws_iam_role_type  = string
    project_id         = string
    auth_database_name = string
    roles              = list(map(string))
    label_key          = string
    label_value        = string
    scopes             = list(map(string))
  }))
}
maastha commented 1 year ago

Update: I was able to reproduce this issue. The issue is caused by changes from https://github.com/mongodb/terraform-provider-mongodbatlas/pull/1471 due to collection_name = ""

@joaquin386 Could you try removing collection_name = ""? If I don't provide that, my plan is empty.

joaquin386 commented 1 year ago

Removing the collection_name = "" did the trick. Anyway this change is a breaking change because it work in 1.11.1 but didn't work in 1.12.0.

Zuhairahmed commented 1 year ago

@joaquin386 apologies for any friction this may have cause on your side. we are are working to update our guidance, documentation, and ideally a longer term fix to prevent similar issue from occurring again and can share back with you shortly. in the interim, just curious can you help us understand why your team included an empty variable in terraform script before (collection_name = "") given this parameter is optional to begin with?

joaquin386 commented 1 year ago

When a developer wants to create a service they create it from a template. Developers do not read the hashicorp provider documentation and check the options they have. We present all the options on their service (which is created from the template) on their terraform file with empty values when possible. If they see colleciton_name = "" on their file they will see it is a possibility to configure collection_name and will use it or leave it as "", if not present few will really realize it is an option.

So at the end is to show the configuration possibilities to the developers. The problem is that in 1.11.1 you could put collection_name as "" but now in 1.12.0 you can not do that.

Zuhairahmed commented 1 year ago

very helpful @joaquin386, thanks for sharing. we plan to issue v1.12.1 (new minor release) to highlight this issue, update Changelog, and add a new migration upgrade Guide as well to advise users to remove collection_name=" from their configs before upgrading.

collection_name=" behavior is not something we recommend going forward now that https://github.com/mongodb/terraform-provider-mongodbatlas/pull/1471 bug has been corrected as @maastha pointed out earlier. alternatively if users are not ready for making this change to their terraform scripts they can elect to stay on on v1.11.1. appreciate you testing out this new version of our terraform provider so quickly after release and alerting us of this issue!

joaquin386 commented 1 year ago

Thanks for the quick effort. I did release an announcement from our side to let our developers know about this change and how to fix the issue, and also for the future change.

Zuhairahmed commented 1 year ago

SGTM @joaquin386. Resolving this one as v1.12.1 is now released. Thanks again! cc: @maastha