Terraform plan fails because of "Data block"

HI Team,

I’m working on the AWS EFS file systems. Previously our approach was very simple create File systems and access points in a single file and folder level.

we want to move the access point creation to separate folder (I mean it queries AWS that EFS FS exist or not, if exists it captures the details and creates access points in that file system) Unfortunately this approach only works if file system actually exists on AWS else it fails. I want this to be conditionalised if file system not exists should say no FS instead of erroring out.

any input most welcome.

data "aws_efs_file_system" "fs_id" {
  for_each = local.restructured_access_points_map
  tags = {
    Name = each.value.file_system
  }
}

resource "aws_efs_access_point" "map" {
  for_each       = local.restructured_access_points_map
  file_system_id = data.aws_efs_file_system.fs_id[each.key].file_system_id
  posix_user {
    uid            = each.value.uid
    gid            = each.value.gid
    secondary_gids = each.value.secondary_gids
  }
  root_directory {
    path = each.value.path
    creation_info {
      owner_uid   = each.value.owner_uid
      owner_gid   = each.value.owner_gid
      permissions = each.value.permissions
    }
  }
  tags = merge(var.tags, { Name = "${each.value.name}" }) # overwrite default Name tag with Access Point Name tag
}
│ Error: Search returned 0 results, please revise so only one is returned 
│
│   with data.aws_efs_file_system.fs_id["env-storage"],
│   on main.tf line 30, in data "aws_efs_file_system" "fs_id":
│   30: data "aws_efs_file_system" "fs_id" {

Thanks

Hi @skkc2,

A data block in Terraform is intended to represent that your configuration depends on an object managed elsewhere, and so that object should be created first to satisfy the dependency.

Since Terraform is a desired state system, it works best when you tell it how the system should be configured, rather than trying to react dynamically to whatever mess happens to already be in the remote system.

If you need to write a module that supports both this object pre-existing or it not existing then the typical way to model that would be to expose an input variable that allows your module user to specify whether they intend to use this existing object. You can then set the count argument in the data block to either zero or one depending on the value of that variable. If the count is zero then Terraform won’t have any instances of that data resource and so it won’t try to fetch it.

There are some other more complex variations but they all have the same idea that your configuration should be the authority on what is supposed to exist, rather than the remote system. Terraform is designed to make the remote system match the desired state, and not to make the desired state match the remote system.

Hi apparentlymart,

Thanks for getting back to us, we’ve already the tried the approach of using a input variable and considering the value from there, this method works absolutely fine when managing terraform and deploying infra from local machine.

But we deploy aws infrastructure using the jenkins, all our terraform code is pushed to gitlab and our pipeline pulls the terraform code and execute, we cannot change value of input variable every time and commit it to scm and do plan and apply on jenkins. any other work arounds for this please.

Thanks

If you are trying to use the same configuration to describe multiple environments that each have different settings, the most typical approach would be:

Change your Jenkins workflow to provide a different .tfvars file depending on which environment it is working with. Each environment can then have a separate set of input variable values, allowing you to create differences.

If your environments are so different from one another that input variables alone are insufficient to describe the differences, the more complex but more powerful option is to write a separate root module for each environment and then factor out all of what they have in common to a shared module that all environments call. This would then allow you to more clearly separate the parts that are the same from the parts that differ, but at the expense of a little more code and some more complex automation in Jenkins.

There is some additional context and other ideas about ways to structure Terraform configurations for different kinds of reuse in module composition.

Thank you for the response.

I’ve something in my brain it sounds stupid may if i ask, is there a way in terrform to skip terrform plan and only run terraform apply -auto-approve command or modules gets skipped with plan action.

sorry in advance.

Hi @skkc2,

There is no way to apply without planning first. The “apply” operation means to take the actions previously decided during planning.

However, terraform apply without a saved plan file automatically creates a new plan and asks you to approve it, so it can give the “illusion” of planning without applying. Really Terraform is just planning and applying together inside the same command.

If you use terraform apply -auto-approve then Terraform will decide the plan, pretend that you typed yes to confirm it, and so then immediately apply it. You can use Terraform this way if you wish, but you won’t get any opportunity to review the proposed changes before starting to apply them, and the proposed changes might be disruptive to your infrastructure.