Terraform Version
Terraform v1.1.2
on windows_amd64
Terraform Configuration Files
child_module1.tf(C1):
# Create Resource Group
resource "aws_resourcegroups_group" "resourcegroups_group" {
name = "test"
resource_query {
query = <<JSON
{
"ResourceTypeFilters": [
"AWS::EC2::Instance"
],
"TagFilters": [
{
"Key": "project",
"Values": ["${var.ProjectName}"]
}
]
}
JSON
}
}
child_module1_variables.tf:
########
variable "ProjectName" {
type = string
description = "This name would be prefixed with the cluster names."
}
Now call this child module in another child module**(C2)**:
child_module2.tf:
module "prepare_aws_cloud" {
source = "./modules/aws/prepare_cloud_copy"
ProjectName = "${var.test.ProjectName}"
}
child_module2_variables.tf:
variable "test" {
type = object({
ProjectName = string
})
}
Now I create a root module(R1)** which calls the child_module2.tf:**
terraform {
backend "local" {
}
}
module "test_deploy" {
source = "D:\\REPO\\installer_v2.2.22.1\\installer\\aws"
test = {
#ProjectName = ""
}
}
So the dependency is as follows:
R1 calls >> C2 calls >> C1
ERROR
PS D:\tkgTest> terraform apply -input=true
╷
│ Error: Invalid value for module argument
│
│ on testing.tf line 21, in module "test_deploy":
│ 21: test= {
│ 22: #ProjectName = ""
│ 23: }
│
│ The given value is not suitable for child module variable "test" defined at .terraform\modules\test_deploy\variables.tf:108,1-15: attribute "ProjectName" is required.
Expected Behavior
I would have expected that the user input would be taken interactively by the console as I am passing the -input=true flag but it doesn't seem to work.
The interactive prompts for input variables are intended only to help with getting started with Terraform (e.g. following a simple tutorial) and so they are limited in the scope of what they support. The typical way to set root module input variables for routine use is to either create a .tfvars file and pass it to Terraform with -var-file or to set a variable directly using -var.
Note also that only root module input variables can be set directly as part of the planning options. Any child module variables are defined exclusively by the expressions written in the module block, and so if you want to be able to set a child module's input variable on a per-run basis you'll need to also declare it as a root module variable and then pass it through to the child module.
For example, in the root module:
variable "test" {
type = object({
ProjectName = string
})
}
module "test_deploy" {
source = "./installer/aws"
test = var.test
}
You can then create an example.tfvars file with the following to set a value for the variable:
test = {
ProjectName = "example"
}
Specify that file when you run Terraform:
terraform apply -var-file=example.tfvars
If you will always set the same values then you can avoid the need for the extra option by naming your file example.auto.tfvars and placing it in the same directory where you will run Terraform. Terraform will load .auto.tfvars files automatically without any explicit -var-file option.
Related
I have a main.tf file with the following code block:
module "login_service" {
source = "/path/to/module"
name = var.name
image = "python:${var.image_version}"
port = var.port
command = var.command
}
# Other stuff below
I've defined a variables.tf file as follows:
variable "name" {
type = string
default = "login-service"
description = "Name of the login service module"
}
variable "command" {
type = list(string)
default = ["python", "-m", "LoginService"]
description = "Command to run the LoginService module"
}
variable "port" {
type = number
default = 8000
description = "Port number used by the LoginService module"
}
variable "image" {
type = string
default = "python:3.10-alpine"
description = "Image used to run the LoginService module"
}
Unfortunately, I keep getting this error when running terraform plan.
Error: Unsupported argument
│
│ on main.tf line 4, in module "login_service":
│ 4: name = var.name
│
│ An argument named "name" is not expected here.
This error repeats for the other variables. I've done a bit of research and read the terraform documentation on variables, and read other stack overflow answers but I haven't really found a good answer to the problem.
Any help appreciated.
A Terraform module block is only for referring to a Terraform module. It doesn't support any other kind of module. Terraform modules are a means for reusing Terraform declarations across many configurations, but th
Therefore in order for this to be valid you must have at least one .tf file in /path/to/module that declares the variables that you are trying to pass into the module.
From what you've said it seems like there's a missing step in your design: you are trying to declare something in Kubernetes using Terraform, but the configuration you've shown here doesn't include anything which would tell Terraform to interact with Kubernetes.
A typical way to manage Kubernetes objects with Terraform is using the hashicorp/kubernetes provider. A Terraform configuration using that provider would include a declaration of the dependency on that provider, the configuration for that provider, and at least one resource block declaring something that should exist in your Kubernetes cluster:
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
}
}
}
provider "kubernetes" {
host = "https://example.com/" # URL of your Kubernetes API
# ...
}
# For example only, a kubernetes_deployment resource
# that declares one Kubernetes deployment.
# In practice you can use any resource type from this
# provider, depending on what you want to declare.
resource "kubernetes_deployment" "example" {
metadata {
name = "terraform-example"
labels = {
test = "MyExampleApp"
}
}
spec {
replicas = 3
selector {
match_labels = {
test = "MyExampleApp"
}
}
template {
metadata {
labels = {
test = "MyExampleApp"
}
}
spec {
container {
image = "nginx:1.21.6"
name = "example"
resources {
limits = {
cpu = "0.5"
memory = "512Mi"
}
requests = {
cpu = "250m"
memory = "50Mi"
}
}
liveness_probe {
http_get {
path = "/"
port = 80
http_header {
name = "X-Custom-Header"
value = "Awesome"
}
}
initial_delay_seconds = 3
period_seconds = 3
}
}
}
}
}
}
Although you can arrange resources into separate modules in Terraform if you wish, I would suggest focusing on learning to directly describe resources in Terraform first and then once you are confident with that you can learn about techniques for code reuse using Terraform modules.
I don't know if it is possible but I would like to take outputs from different modules as needed:
locals {
node_proyect =
[
["node_1", "project_A"],
["node_2", "project_B"],
...
["node_N", "project_N"],
]
}
Working modules:
module "node_1" {
...
}
[...]
module "node_N" {
...
}
trying to do:
module "outputs_sample" {
for_each = {for i,v in local.node_proyect: i=>v}
...
node_name = module.node_[each.value[0]].node_name
proyect_name = each.value[1]
...
}
What I want:
node_name --> module.node_node_1.node_name --> "string with the name with which the node has been created"
project_name --> "project_A"
Next for_each:
node_name --> module.node_node_2.node_name --> "string with the name with which the node has been created"
project_name --> "project_B"
But I get:
Error: Reference to undeclared module
│
│ on ....tf line ..., in module "outputs_sample":
│ 1073: node_name = module.node_[each.value[0]].node_name
│
│ No module call named "module.node_" is declared in module.....
The output of the modules exists and works perfectly, so if I do: module.node_node_1.node_name works.
I don't know how to make Terraform to interpret it like this, instead of literally as the error says: module.node_[each.value[0]].node_name
Given that you stated the modules are declared in the same config directory despite being absent from the config provided in the question, we can first fix the type and structure of the local variable:
locals {
node_proyect = {
"1" = "proyect_A",
"2" = "proyect_B"
}
}
Now we can use this for module iteration and fix the value accessors and string interpolation, and remove the unnecessary list constructor also causing issues:
module "outputs_sample" {
source = "./module"
for_each = local.node_proyect
...
node_name = "module.node_${each.key}.node_name"
proyect_name = each.value
...
}
But this will still causes issues due to a violation of the Terraform DSL. You need to restructure your module declarations (still absent from question so need to be hypothetical here):
module "node" {
...
for_each = local.node_proyect
...
}
and then the outputs can be accessed normally from the resulting map of objects:
module "outputs_sample" {
source = "./module"
for_each = local.node_proyect
...
node_name = module.node[each.key].node_name
proyect_name = each.value
...
}
After all of these fixes to your config you will achieve your goal.
I'm trying to pass a variable from an environment dir to a module, but having some issues. My directory structure looks like this
repository
-> prod
-> test
main.tf
terraform.tf
vars.tfvars
-> modules
infra
main.tf
terraform.tf
In test/main.tf I have
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}
module "launch" {
source = "../../modules/infra"
range = var.range
}
test/terraform.tf looks like this
variable "range" {}
test/vars.tfvars
range="10.0.0.0/16"
modules/infra/main.tf
resource "aws_vpc" "testvpc" {
cidr_block = var.range
}
When I run this I get the prompt
var.range
Enter a value:
I'm expecting it to pick up the value from the variable automatically, but even when I do enter the value I get the error
│ Error: Unsupported argument
on main.tf line 20, in module "launch":
range = var.range
An argument named "range" is not expected here
Is it possible to pass a variable from a file for a given environment to a module?
Make sure the file modules/infra/terraform.tf contains the variable:
variable "range" {}
I have a module cluster that spins up a GKE cluster and associated GCS buckets.
The backend for this is a GCS bucket called cluster_tf_state_bucket
I have defined an output in this module
output "vault_storage_bucket_name" {
value = "${google_storage_bucket.vault_storage.name}"
}
Once I run the code, I get the output
✗ terraform output
vault_storage_bucket_name = vault-storage
Now I have a another module vault and in that module I need to invoke the value of vault_storage_bucket_name from the other module that is using a different GCS backend bucket.
So in the main.tf of my vault module, Im doing something like
terraform {
required_version = ">= 0.12.2"
}
terraform {
backend "gcs" {
bucket = "app_tf_state_bucket"
prefix = "vault"
}
}
data "terraform_remote_state" "cluster_vault" {
backend = "gcs"
config = {
bucket = "cluster_tf_state_bucket"
}
}
module "vault" {
source = "../../../modules/vault"
env = "test"
region = "europe-west5"
storage_bucket_name = "${data.terraform_remote_state.cluster_vault.vault_storage_bucket_name}"
But when I run this code, I get
Error: Unsupported argument
on main.tf line 24, in module "vault":
24: storage_bucket_name = "${data.terraform_remote_state.cluster_vault.vault_storage_bucket_name}"
An argument named "storage_bucket_name" is not expected here.
I resolved the above issue by adding the below to the `variables.tf file
variable "storage_bucket_name"{
type = "string"
}
And now I run into the error
Error: Unsupported attribute
on main.tf line 24, in module "vault":
24: storage_bucket_name = "${data.terraform_remote_state.cluster_vault.vault_storage_bucket_name}"
This object has no argument, nested block, or exported attribute named
"vault_storage_bucket_name".
What am I missing here ?
The output values from the upstream state snapshot are exposed on terraform_remote_state via an attribute called outputs, so you need to include that in your expression:
storage_bucket_name = data.terraform_remote_state.cluster_vault.outputs.vault_storage_bucket_name
Note the extra .outputs before .vault_storage_bucket_name. That outputs attribute is a map value, so you can potentially also use the map as a whole in expressions. For example, you might want to create a Local Value if you expect to be referring to those remote attributes a lot and want to simplify the references:
locals {
vault_cluster = data.terraform_remote_state.cluster_vault.outputs
}
module "vault" {
source = "../../../modules/vault"
env = "test"
region = "europe-west5"
storage_bucket_name = local.vault_cluster.vault_storage_bucket_name
}
I am writing terraform script to create ASG on AWS. I tried to create it with terraform module to have a more reusable code. The problem is when I want to use variable from common-variable.tfvars on the module tf files, it keeps saying it is undefined and need to be declared. This way, the module will be less reuseable .
Here is an example
root
|
|___project 1
| |_____ main.tf
| |_____ common-variable.tfvars
|
|___ modules
|
|_____ a-module
|______ main.tf
So inside project 1 common-variable.tfvars, basically it looks like this
variable "a" {
description = "a variable"
default = "a"
}
variable "b" {
description = "a variable"
default = "b"
}
Inside a-module / main.tf looks like this
variable "name" {}
resource "aws_autoscaling_group" "asg-1" {
name = "${var.a}"
...
}
When I do terraform init, it says
resource 'aws_autoscaling_group.asg-1' config: unknown variable
referenced: 'a'. define it with 'variable' blocks
Any idea how i can use this common variable from within the module main .tf?
Update
I managed to pass terraform init by redeclaring the variable in each module. However, when i run terraform plan, this kind of error appears invalid value "common-variable.tfvars" for flag -var-file: multiple map declarations not supported for variables
Wrong tfvars format, should be key / value only, such as:
a = "a"
b = "b"
Second, check how do you refer the module, should be something like this:
source = "../modules/a-module"
You need to declare the variables required by the module within the module, and then pass them in when instantiating the module from your project.
Example stolen from hashicorp documentation
In your project:
module "assets_bucket" {
source = "./publish_bucket"
name = "assets"
}
module "media_bucket" {
source = "./publish_bucket"
name = "media"
}
In your module:
# publish_bucket/bucket-and-cloudfront.tf
variable "name" {} # this is the input parameter of the module
resource "aws_s3_bucket" "the_bucket" {
# ...
}
resource "aws_iam_user" "deploy_user" {
# ...
}