Terraform - How to output input variable? - amazon-web-services

I have a custom terraform module which create an AWS EC2 instance, so it's relying on the aws provider.
This terraform custom module is used as a base to describes the instance i want to create, but I also need some other information that will be reused later.
For example, i want to define a description to the VM as an input variable, but i don't need to use it at all to create my vm with the aws provider.
I just want this input variable to be sent directly as an output so it can be re-used later once terraform has done its job.
ex
What I have as input variable
variable "description" {
type = string
description = "Description of the instance"
}
what I wanna put as output variable
output "description" {
value = module.ec2_instance.description
}
What my main module is doing
module "ec2_instance" {
source = "./modules/aws_ec2"
ami_id = var.ami_id
instance_name = var.hostname
disk_size = var.disk_size
create_disk = var.create_disk
availability_zone = var.availability_zone
disk_type = var.disk_type
// I don't need the description variable for the module to work, and I don't wanna do anything with it here, i need it later as output
}
I feel stupid because i searched the web for an answer and can't find anything to do that.
Can you help ?
Thanks
EDIT: Added example of code

If you have an input variable declared like this:
variable "description" {
type = string
}
...then you can return its value as an output value like this, in the same module where you declared it:
output "description" {
value = var.description
}

Related

Terraform Resource attribute not being removed when passing in empty values

I am working with a GCP Cloud Composer resource and added in a dynamic block to create an attribute for the resource to set allowed_ip_ranges which can be used as an IP filter for accessing the Apache Airflow Web UI.
I was able to get the allowed ranges setup and can update them in place to new values also.
If I attempt to pass in a blank list I am expecting the IP address(es) to be removed as attributes for the resource but Terraform seems to think that no changes are needed.
There is probably something wrong in my code but I am not sure what exactly I would need to do. Does it involve adding in a conditional expression to the for_each loop in the dynamic block?
Child module main.tf
web_server_network_access_control {
dynamic "allowed_ip_range" {
for_each = var.allowed_ip_range
content {
value = allowed_ip_range.value["value"]
description = allowed_ip_range.value["description"]
}
}
}
Child module variables.tf
variable "allowed_ip_range" {
description = "The IP ranges which are allowed to access the Apache Airflow Web Server UI."
type = list(map(string))
default = []
}
Parent module terraform.tfvars
allowed_ip_range = [
{
value = "11.0.0.2/32"
description = "Test dynamic block 1"
},
]
You can set the default value in your variables.tf file:
variable "allowed_ip_range" {
description = "The IP ranges which are allowed to access the Apache Airflow Web Server UI"
type = list(map(string))
default = [
{
value = "0.0.0.0/0"
description = "Allows access from all IPv4 addresses (default value)"
},
{
value = "::0/0"
description = "Allows access from all IPv6 addresses (default value)"
},
]
}
And when you will delete your variable from terraform.tfvars, you will have the default values

terraform 12 count date_template not working

I'm upgrading to terraform 12 and have an asg module that references a root repository. As part of this, it uses a data.template_file resource to attach user data to the asg which is then put in to log files on the instances. The module looks as follows;
module "cef_fleet" {
source = "git::ssh://git#github.com/asg-repo.git?ref=terraform12"
user_data_rendered = data.template_file.init.rendered
instance_type = var.instance_type
ami = var.ami
etc ...
which as you can see calls the data resource;
data "template_file" "init" {
count = signum(var.cluster_size_max)
template = file("${path.module}/template-files/init.sh")
vars = {
account_name = var.account_name
aws_account_number = var.aws_account_number
this works fine in terraform 11 but when I changed to terraoform 12 and try to apply I get this error:
*Because data.template_file.init has "count" set, its attributes must be
accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
data.template_file.init[count.index]*
if I change this in my module to user_data_rendered = data.template_file.init[count.index]
I then get this error;
The "count" object can be used only in "resource" and "data" blocks, and only
when the "count" argument is set.
I don't know what to do here. If I leave the .rendered in then it doesn't seem to recognise the [count.index] as I get the first error again. Has anyone any advice on what I need to do?

Terraform: How to pass output from one resource to another?

I'm using Aurora serverless Mysql and ECS and trying to use secrets generated by aws secret manager in a file named rds.tf and want to use it another resource in a file called ecs.tf
resource "random_password" "db_instance_aurora_password" {
length = 40
special = false
keepers = {
database_id = aws_secretsmanager_secret.db_instance_aurora_master_password.id
}
Above is rds.tf, which works and generates a random password. In my second file ecs.tf, I want to use the
resource "aws_ecs_task_definition" "task" {
family = var.service_name
container_definitions = templatefile("${path.module}/templates/task_definition.tpl", {
DB_USERNAME = var.db_username
DB_PASSWORD = random_password.db_instance_aurora_password.result
})
}
How to export, the output of the db_password and use it in another resource(ecs.tf)?
output "aurora_rds_cluster.master_password" {
description = "The master password"
value = random_password.db_instance_aurora_password.result }
If all terraform files are in one directory, you can just reference random_password resource as you do it for the database. Then you might not need to output it.
If it's separated, then you can use terraform modules to achieve what you need. In ECS terraform you can reference RDS module and you will have access to its output:
module "rds" {
source = "path/to/folder/with/rds/terraform"
}
resource "aws_ecs_task_definition" "task" {
family = var.service_name
container_definitions = templatefile("${path.module}/templates/task_definition.tpl", {
DB_USERNAME = var.db_username
DB_PASSWORD = module.rds.aurora_rds_cluster.master_password
})
}
Storing password in terraform's output will store it as a plain text. Even if you use encrypted S3 bucket, password can still be accessed at least by terraform. Another option to share password could be for example by using AWS Parameter Store. Module that creates password can store it in Param Store, and another module that needs a password can read it.
P.S. You might want to add sensitive = true to the password output in order to eliminate password value from logs.

Terraform random_string as password for linux machine

I want to use this to generate a random password for the linux machines in gcp.
My question is how I get the password afterwards.
Should I use the output for this or is it stored anywhere else?
I saw this code on the internet and was asking myself how they know the password then.
resource "random_string" "master_password" {
length = 16
special = true
}
resource "google_container_cluster" "test" {
name = "test"
zone = "europe-west1-d"
master_auth {
username = "client"
password = "${random_string.master_password.result}"
}
node_pool = [{
name = "pool"
autoscaling = {
min_node_count = 1
max_node_count = 3
}
node_config {
disk_size_gb = 100
machine_type = "n1-standard-2"
oauth_scopes = [
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
labels {
test = "true"
}
}
}]
}
The password will be stored in your state file. You can go digging around in there for it, but it is entirely possible that it's exact location in the file will change between Terraform versions.
The best way to get a consistent output is to, as you mentioned, use an output block. Then when you do a terraform apply there will be a nice human readable output of this password. Please note that anything with access to your state has access to that password, so keep the state secure.
If you use remote state (such as in an S3 bucket), you can also use terraform_remote_state to gain access to this from another Terraform run. You will need to explicitly output values you want to be available from terraform_remote_state.
Finally, be aware that if something captures the output of your terraform apply, it will also capture that output since terraform apply writes to STDOUT. This might happen if you use a CI tool. Just something to be aware of.

Terraform and DigitalOcean: assign volume to specific droplet created with count parameter

just started exploring terraform to spin up droplets and volumes on digital ocean.
My question is to know the right way to do the following:
create a certain number of droplet instances using count within digitalocean_dropletresource named ubuntu16
assign a digitalocean_volume only to one or a subset of previously created droplets.
How to do it?I was assuming to use droplets_id property on digitalocean_volume resource. Something like:
resource "digitalocean_volume" "foovolume" {
...
droplet_ids = ["${digitalocean_droplet.ubuntu16.0.id}"]
}
Validating it with terraform validate I got:
Error: digitalocean_volume.foovolume: "droplet_ids": this field cannot be set
Any advice? Thanks to any inputs on it.
Regards
The way the Terraform provider for DigtialOcean is currently implemented requires that you take the opposite approach. You can specify which volumes are attached to which Droplets by defining the volume_ids of the Droplet resource. For example:
resource "digitalocean_volume" "volume" {
region = "nyc3"
count = 3
name = "volume-${count.index + 1}"
size = 100
description = "an example volume"
}
resource "digitalocean_droplet" "web" {
count = 3
image = "ubuntu-17-10-x64"
name = "web-${count.index + 1}"
region = "nyc3"
size = "1gb"
volume_ids = ["${element(digitalocean_volume.volume.*.id, count.index)}"]
}
If you look at the docs for the volume resource, you'll see that droplet_ids is a "computed" field. This means that you are unable to set the field, and that its value is computed by Terraform via the provider's API.