Usage of resource and data resource in different modules

Hello!
I have some misunderstanding about the following issue and I would appreciate if you can help to resolve it. I simplified my example to reproduce it.

Module users (file ./users.tf) will read a list of users from a file (now it is hardcoded to a list with 1 entry), creates these users using aws_iam_user, and return to the upper module:

locals {
  users = [
    "john",
  ]
}

resource "aws_iam_user" "users" {
  for_each      = toset(local.users)
  name          = each.key
  force_destroy = true
}

output "users" {
  depends_on = [
    aws_iam_user.users
  ]
  description = "List of users"
  value       = local.users
}

The main module calls users module and wants to use created users via data resource:

terraform {
  required_version = ">= 1.0.0"

  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = ">= 3.60"
    }
  }
}

provider "aws" {
  region  = "eu-central-1"
}

module "users" {
  source = "./users"
}

data "aws_iam_user" "users" {
  for_each  = toset(module.users.users)
  user_name = each.key
}

When I run terraform plan I get the following error:

│ Error: error getting user: NoSuchEntity: The user with name john cannot be found.
│       status code: 404, request id: 0f2cae2d-157c-4fbc-82c8-efdb4199d850
│
│   with data.aws_iam_user.users["john"],
│   on main.tf line 21, in data "aws_iam_user" "users":
│   21: data "aws_iam_user" "users" {

It looks like that data.aws_iam_user.users doesn’t wait for aws_iam_user.users resource creation in the module users (output depends from it).

I have multi-module projects:

  • first module creates users using aws_iam_user
  • second module gets the list of users and tries to use them via data.aws_iam_user.users

I don’t want to pass aws_iam_user as is because it may contain a lot of attributes that I don’t need. Also, it could be that one (3rd party) module may create them somewhere inside and I just want to use it.

I don’t want to use depends_on in data.aws_iam_user because:

  • in my real project, the second module has provider block and it is not possible to combine it with depends_on.
  • I have a feeling that it should work, there is a dependency from data.aws_iam_user to aws_iam_user:
$ terraform graph -type=plan > debug_graph.txt
$ dot -Tsvg debug_graph.txt > debug_graph.svg

Do you have any idea why it is so and how to resolve the issue with Error: error getting user: NoSuchEntity?

Best regards,
Maxim.

Hi @maxx27,

The problem here stems from the fact that you are trying to use a managed resource and a data source to represent the same logical resource within the same configuration. Because the users keys are known statically in the configuration, the data source is going to fetch that data during the plan, however the managed resource has yet to create the corresponding user.

You should not have a managed resource and a data source representing the same logical resource within the same configuration. The recommended structure is to pass the actual resource objects from one module to the next. In the simplified example here you would simply have the user objects available as the module output, and have no need for the data source. If that needed to be used within another module, that module should expect the user object values as an input, rather than static names to lookup the users values in a data source. Only when you do not have the managed resource under the control of the configuration would you use the corresponding data source to fetch the user values in place of the users module. The resource objects do not need to contain all possible attributes, the object can be converted to an object type containing any subset of the available attributes.

Though it is not the recommended path, the only alternative is to use depends_on to force reading of the data source to be deferred until apply (either directly, or indirectly). There should be no providers declared within your module, however I would highly recommend not using depends_on on the module itself, and rather create a specific dependency through an input variable to prevent depends_on from effecting all objects within the entire module.

1 Like

Hello @jbardin ,

Thank you for the detailed explanation, it helps!