hashicorp/terraform

Error in Terraform 0.12.0: This object has no argument, nested block, or exported attribute

ameyaptk opened this issue · 7 comments

Terraform Version

0.12.0

Issue

Hi, when I run terraform plan on one of the config files, I get the following error

Error: Unsupported attribute

  on main.tf line 16, in module "project_01":
  16:   folder_id = "${data.terraform_remote_state.folders.folder_shared_id}"

This object has no argument, nested block, or exported attribute named
"folder_shared_id".

make: *** [plan] Error 1

Here is the main.tf file

data "terraform_remote_state" "folders" {
  backend = "local"
  config = {
    path = "../../folders/terraform.tfstate"
  }
}
...
<extraneous-code>
...
module "project_01" {
  source = "<path-to-module>"

  project_name = "network"
  folder_id = "${data.terraform_remote_state.folders.folder_shared_id}"
}

However, that attribute is present in the terraform.tfstate file


$ cat terraform.tfstate
{
  "version": 4,
  "terraform_version": "0.12.0",
  "serial": 9,
  "lineage": "76c68f13-3a49-4db0-2a95-84ef9610cefa",
  "outputs": {
    "folder_test1_id": {
      "value": "folders/***",
      "type": "string"
    },
    "folder_test2_id": {
      "value": "folders/****",
      "type": "string"
    },
    "folder_shared_id": {
      "value": "folders/****",
      "type": "string"
    }

This used to work in Terraform 0.11.13 but broke in Terraform 0.12.0. Any ideas why this is happening?

terraform 0.12upgrade fixed the config file by fixing the first class expressions and the error disappeared. First class expressions- https://www.hashicorp.com/blog/terraform-0-12-preview-first-class-expressions

Hi @ameyaptk!

I'm glad the upgrade tool fixed it. I just wanted to note what it changed that made this work:

In Terraform 0.12, the outputs from terraform_remote_state are collected together in an attribute called outputs, rather than being exposed directly on the terraform_remote_state object, as described in the upgrade guide section Remote state references.

Specifically, the upgrade tool would rewrite the following line:

   folder_id = "${data.terraform_remote_state.folders.folder_shared_id}"

As well as using the first-class expression syntax, it also added .outputs into this reference, to create the following:

   folder_id = data.terraform_remote_state.folders.outputs.folder_shared_id

The purpose of grouping them all together into one attribute like this is so that you can, where appropriate, use the entire collection together as a value.

Thank you very much @apparentlymart
I had the same problem and your explanation helped me fixing a big chunk of it.
It seems tho that the documentation is lacking the new configuration of TF 0.12.

Currently I have a problem created by the terraform_remote_state.

I have one folder where I create my GCP VPC

resource "google_compute_network" "default" {
  provider                = google-beta
  project                 = var.project
  name                    = "${var.name}-net"
  auto_create_subnetworks = "false"
}

resource "google_compute_subnetwork" "subnet_vpc" {
  provider                 = google-beta
  project                  = var.project
  name                     = "${var.name}-subnet-vpc"
  network                  = google_compute_network.default.self_link
  region                   = var.project_region
  ip_cidr_range            = var.cidr
  private_ip_google_access = true

  secondary_ip_range {
    range_name    = "${var.name}-secondary-cidr"
    ip_cidr_range = var.subnet["secondary_cidr"]
  }
}

with the output

output "link" {
  value = "${google_compute_network.default.self_link}"
}

and a folder for my cloudsql with following code:

data "terraform_remote_state" "vpc" {
    backend = "gcs"
    config = {
        bucket  = "tfstate-test-eu"
        prefix  = "test/vpc"
  }
}

resource "google_compute_global_address" "cloudsql_ip_address" {
  provider      = google-beta
  project       = var.project
  name          = "${var.name}-sql-iip"
  purpose       = "VPC_PEERING"
  address_type  = "INTERNAL"
  prefix_length = 16
  network       = "${data.terraform_remote_state.vpc.outputs.link}"
}

resource "google_service_networking_connection" "cloudsql_vpc_connection" {
  provider                = google-beta
  network                 = "${data.terraform_remote_state.vpc.outputs.link}"
  service                 = "servicenetworking.googleapis.com"
  reserved_peering_ranges = [google_compute_global_address.cloudsql_ip_address.name]
}

both folders save the tfstate in the same bucket but with a different prefix:

vpc:

terraform {
  backend "gcs" {
    bucket  = "tfstate-test-eu"
    prefix  = "test/vpc"
  }
}

cloudsql:

terraform {
  backend "gcs" {
    bucket  = "tfstate-test-eu"
    prefix  = "test/sql"
  }
}

now everytime I want to apply my terraform plan for the cloudsql, to add that ip-address to my vpc, my terraform wants to destroy the vpc but add the ip-address

  # google_compute_global_address.cloudsql_ip_address will be created
  + resource "google_compute_global_address" "cloudsql_ip_address" {
      + address            = (known after apply)
      + address_type       = "INTERNAL"
      + creation_timestamp = (known after apply)
      + id                 = (known after apply)
      + label_fingerprint  = (known after apply)
      + name               = "tf-test-sql-iip"
      + network            = "https://www.googleapis.com/compute/v1/projects/example/global/networks/tf-test-net"
      + prefix_length      = 16
      + project            = "example"
      + purpose            = "VPC_PEERING"
      + self_link          = (known after apply)
    }

  # google_compute_network.default will be destroyed
  - resource "google_compute_network" "default" {
      - auto_create_subnetworks         = false -> null
      - delete_default_routes_on_create = false -> null
      - id                              = "tf-test-net" -> null
      - name                            = "tf-test-net" -> null
      - project                         = "example" -> null
      - routing_mode                    = "REGIONAL" -> null
      - self_link                       = "https://www.googleapis.com/compute/v1/projects/example/global/networks/tf-test-net" -> null
    }

is this a problem with my terraform plan / design or something related to a bug ?
My expected behavior would be, that Terraform checks the remote backend and finds my vpc_self_link, which he uses to add the cloudsql ip-address into that vpc.

Plan: 1 to add, 0 to change, 1 to destroy.

Hi @relgisri,

That problem doesn't seem related to this issue. It looks like somehow those two configurations are being applied against the same state, and so the second operation is planning to destroy the objects created by the first.

Please note that we use GitHub issues for tracking bugs and enhancements rather than for questions. While we may be able to help with certain simple problems here it's better to use the community forum, where there are more people ready to help. The GitHub issues here are generally monitored only by our few core maintainers.

Thanks @apparentlymart. This ".outputs" hint fixed everything. I really wish error messages from terraform could suggest something like, "Did you forget to reference the .outputs. array?" or some other intelligent error messages. I wasted 2 hours trying to understand what's wrong with it.

Thanks @basilmusa , got same issue, I can confirm this fix as well.

With terraform 0.12+, we have to add extra outputs to reference variables, for example:

data.terraform_remote_state.vpc.outputs.link

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.