Why is my Terraform output not working in module? - terraform

I have the following simple setup:
~$ tree
.
├── main.tf
└── modules
└── world
└── main.tf
~$ cat main.tf
output "root_module_says" {
value = "hello from root module"
}
module "world" {
source = "modules/world"
}
~$ cat modules/world/main.tf
output "world_module_says" {
value = "hello from world module"
}
I then run:
~$ terraform get
~$ terraform apply
I expect to see world_module_says in the outputs, but I do not, I only see root_module_says.
This is really confusing as to why?
If it helps:
~$ terraform --version
v0.10.8

Terraform only shows the output from root (by default pre v0.12)
https://www.terraform.io/docs/commands/output.html
Prior to Terraform 0.12 you can get the output from the world module with:
terraform output -module=world
I think the logic here is that the output from the module would be consumed by root and if you actually needed the output then you'd output it in root too so main.tf might contain this:
output "root_module_says" {
value = "hello from root module"
}
output "world_module_says" {
value = "${module.world.world_module_says}"
}
module "world" {
source = "modules/world"
}
Beginning with Terraform 0.12 this is the only way to get the output from within a module.

Before Terraform 0.12
The below command shows the output for a specific module
terraform output -module=example_module
After Terraform 0.12
The below command fails in Terraform 0.12 and above with an error:
terraform output -module=example_module
Error: Unsupported option
The -module option is no longer supported since Terraform 0.12, because now
only root outputs are persisted in the state.
To get outputs from a module in Terraform 0.12 and above, you must export them from the root (e.g example_module) module using an output block in the caller module. This can be now done simply by adding one line in the caller module like below:
output "example_module_outputs" {
value = module.example_module
}
Now you can see the output running the following command:
terraform output

Expansion to the answers above when using multiple output varialbes:
When accessing a module output group (using the 'terraform output' command from a console or a script) then Terraform will printout all output variables within this group in a formatted way, or in json format using '-json' flag.
When extracting output values, we can use the '-raw' flag only if there is a single variable which has a string format.
If we have more than 1 outout in the output group within the module:
Lets say we declared in the 'root' module the following outout group in a module:
output "world_world_module_says" {
value = module.world.world_module_says
}
and in the module main.tf we have 2 vars:
output "world_module_says" {
value = "hello from world module"
}
output "world_module_says_again" {
value = "hi again from world module"
}
Two ways to extract a single output variable from the group:
using -json flag and manipulating the output using the jq command:
terraform output -json world_world_module_says |jq '.'"world_module_says"
The other way is to declare each output individually in the 'root' module to allow easy access using '-raw':
output "world_world_module_says" {
value = module.world.world_module_says
}
output "world_world_module_says_again" {
value = module.world.world_module_says_again
}

Related

Load variable values from the given .tfvars file got an error to many arguments

I run terraform plan commnad with apllo.tfvars file
terraform plan -var-file=apllo.tfvars
│ Error: Too many command line arguments
│ To specify a working directory for the plan, use the global -chdir flag.
my variable.tf
variable "user" {
type = string
}
# number variable
variable "age" {
type = number
}
apllo.tfvars
user = "AWSUSER"
age = 222
output.tf
output "name" {
value = "hello ${var.user}"
}
output "age" {
value = "age ${var.age}"
}
If you are using Powershell for running Terraform, try specifying the .tfvar file using single or double quotes, such as:
terraform plan -var-file="apollo.tfvar"

Assign terraform output to environment variable

How can I assign terraform output to environment variable?
Let's say I have following output defined in my main.tf
output "gce_public_ip" {
value = element(concat(google_compute_instance.vm_instance.*.network_interface.0.access_config.0.nat_ip, list("")), 0)
}
I would like to export gce_public_ip, so it will be available as environment variable GCE_PUBLIC_IP
You can use the terraform output command.
Not tested with your value, but it should be something like:
export GCE_PUBLIC_IP=$(terraform output -raw gce_public_ip)

Terraform not showing output despite being declared

I am declaring the following output in a TF module in the output.tf file:
output "jenkins_username" {
value = "${local.jenkins_username}"
description = "Jenkins admin username"
#sensitive = true
}
output "jenkins_password" {
value = "${local.jenkins_password}"
description = "Jenkins admin password"
#sensitive = true
}
The corresponding locals have been declared in main.tf as follows:
locals {
jenkins_username = "${var.jenkins_username == "" ? random_string.j_username.result : var.jenkins_username}"
jenkins_password = "${var.jenkins_password == "" ? random_string.j_password.result : var.jenkins_password}"
}
However, after the apply has finished, I see no relevant output, and what is more, it is not displayed even when I call the explicit output command:
$ terraform output jenkins_password
The output variable requested could not be found in the state
file. If you recently added this to your configuration, be
sure to run `terraform apply`, since the state won't be updated
with new output variables until that command is run.
I was having the exact same problem. What worked for me was to comment out the output variables in the first deployment, and uncomment them once that would succeed.

Terraform External Provider resource does not have attribute for variable during plan phase

When running terraform plan with the below scripts I Gert the following error message:
Error: Error running plan: 1 error(s) occurred:
* output.foobaz: Resource 'data.external.example' does not have attribute 'result.foobaz' for variable 'data.external.example.result.foobaz'
It doesn't appear from testing that the external script is actually executed during the plan phase, however, it does appear that the plan phase is trying to interpolate the expected response, which seem s incorrect to me. Is there something I'm missing?
provider "scaleway" {
region = "ams1"
}
resource "scaleway_ip" "swarm_manager_ip" {
count = 1
}
data "external" "example" {
program = ["./scripts/test.sh"]
query = {
# arbitrary map from strings to strings, passed
# to the external program as the data query.
foo = "${scaleway_ip.swarm_manager_ip.0.ip}"
baz = "i-am-baz"
}
}
output "foobaz" {
value = "${data.external.example.result.foobaz}"
}
output "scaleway_ip_address" {
value = "${scaleway_ip.swarm_manager_ip.0.ip}"
}
Here is the external script:
#!/bin/bash
# Exit if any of the intermediate steps fail
set -e
# Extract "foo" and "baz" arguments from the input into
# FOO and BAZ shell variables.
# jq will ensure that the values are properly quoted
# and escaped for consumption by the shell.
eval "$(jq -r '#sh "FOO=\(.foo) BAZ=\(.baz)"')"
# Placeholder for whatever data-fetching logic your script implements
FOOBAZ="$FOO BAZ"
# Safely produce a JSON object containing the result value.
# jq will ensure that the value is properly quoted
# and escaped to produce a valid JSON string.
jq -n --arg foobaz "$FOOBAZ" '{"foobaz":$foobaz}'
Your Terraform syntax is incorrect. data.external.example.result is a map. To access its entry foobaz you need to code
"${data.external.example.result["foobaz"]}"
See https://www.terraform.io/docs/configuration/interpolation.html

How do I pass a list as an argument?

This solution here did not work for me.
// my tf file:
variable "myvar" {type = "list"}
module "my-module" {
blah = "${var.myvar}"
source = "path/to/module"
}
Various command line attempts:
terraform plan -var myvar="zzzz"
should be type list, got string
terraform plan -var myvar=["zzzz"]
invalid value "myvar=[zzzz]" for flag -var: Cannot parse value for variable ("[zzzz]") as valid HCL: At 1:6: unexpected token while parsing list: IDENT
terraform plan -var 'myvar=["zzzz"]'
invalid value "myvar=[zzzz]" for flag -var: Cannot parse value for variable ("[zzzz]") as valid HCL: At 1:6: unexpected token while parsing list: IDENT
Strange.
I used the following main.tf
variable "test" {
type = "list"
}
and running:
$ terraform version
Terraform v0.11.1
$ terraform plan -var 'test=["vvv"]'
completed successfully.
It could be that there is an incorrect IDENT somewhere else in your file/module. Please try running the following command to validate everything except unset variables:
$ terraform validate -check-variables=false

Resources