Terraform outputs for resources with count - terraform

I have my s3 resource in terraform with configuration:
locals {
bucket_count = "${length(var.s3_config["bucket_names"])}"
}
resource "aws_s3_bucket" "s3_bucket" {
count = "${local.bucket_count}"
bucket = "${format("%s-%s", element(var.s3_config["bucket_names"], count.index), var.region)}"
acl = "private"
region = "${var.region}"
tags {
Name = "${format("%s-%s", element(var.s3_config["bucket_names"], count.index), var.region)}"
}
}
and i want to set output variable for all created bucket so i created file names outputs.tf with content
output "buckets" {
value = "${aws_s3_bucket.s3_bucket.*.bucket}"
}
output "buckets_arns" {
value = "${aws_s3_bucket.s3_bucket.*.arn}"
}
when i apply configuration its ok i see outputs in terraform.tfstate file but when i call terraform output i see information that is no output or output is empty what i do wrong ?

Try this:
output "buckets" {
value = ["${aws_s3_bucket.s3_bucket.*.bucket}"]
}
output "buckets_arns" {
value = ["${aws_s3_bucket.s3_bucket.*.arn}"]
}

Related

How to add value(s) to an object from Terraform jsondecode without copying values over to another variable?

I have a following example of Terraform resources where I fetch values from secrets manager and pass them to the Lambda function. The question is how can I add extra values to an object before passing it to environment variable without replicating the values?
resource "aws_secretsmanager_secret" "example" {
name = "example"
}
resource "aws_secretsmanager_secret_version" "example" {
secret_id = aws_secretsmanager_secret.example.id
secret_string = <<EOF
{
"FOO": "bar"
}
EOF
}
data "aws_secretsmanager_secret_version" "example" {
secret_id = aws_secretsmanager_secret.example.id
depends_on = [aws_secretsmanager_secret_version.example]
}
locals {
original_secrets = jsondecode(
data.aws_secretsmanager_secret_version.example.secret_string
)
}
resource "aws_lambda_function" "example" {
...
environment {
variables = local.original_secrets
}
}
As a pseudo code I'd like to do something like this:
local.original_secrets["LOG_LEVEL"] = "debug"
The current approach I have is just to replicate the original values and add a new but of course this is not DRY.
locals {
...
updated_secrets = {
FOO = try(local.original_secrets.FOO, "")
DEBUG = "false"
}
}
You can use Terraform merge function to produce new combined map of environment variables.
lambda_environment_variables = merge(local.lambda_secrets, local.environment_variables)

How to append string and variable in terraform

How can I concatenate string and a variable in terraform. I am using terraform version 1.7
Name = "Test (Environment_Name)" where environment_name will be test,stage and prod.
resource "fusionauth_tenant" "tanant" {
name = "Test (Environment_name)"
email_configuration {
default_from_name = "FusionAuth [Environment_name]"
verification_email_template_id = fusionauth_email.verification_template.id
}
Examples of how to append a string and a variable.
settings.tf:
locals {
bucket_prefix = "test-bucket"
}
And then you want to create three S3 buckets.
s3.tf:
resource "aws_s3_bucket" "a" {
bucket = "${local.bucket_prefix}-app"
}
//name = test-bucket-app
resource "aws_s3_bucket" "b" {
bucket = local.bucket_prefix
}
//name = test-bucket
resource "aws_s3_bucket" "c" {
bucket = "my-bucket"
}
//name = my-bucket
If you want to append a variable from var or get a name from a resource, it will follow the same pattern. It will always be:
"${var.name.value}-my-string"

In terraform, how can I get the result of a data resource?

terraform v0.12.17. I've read Data Source: aws_ebs_snapshot but it doesn't show me how I can use the results.
Say I want to create an AWS volume from the latest AWS snapshot. How can I use the data{} resource to get the latest snapshot and then use it to create a volume?
provider "aws" {
region = "us-east-1"
}
data "aws_ebs_snapshot_ids" "jenkins_master" {
filter {
name = "tag:Name"
values = ["jenkins-master"]
}
}
resource "aws_ebs_volume" "jenkins_master_ebs" {
availability_zone = "us-east-1a"
size = ??? // taken from result of above data{}
snapshot_id = ??? // taken from result of above data{}
tags = {
Name = "jenkins-master-ebs"
}
}
Acording to Terraform documentation, you'll get a list of ids, so you can use something like this:
resource "aws_ebs_volume" "jenkins_master_ebs" {
availability_zone = "us-east-1a"
size = 50 # Your custom size
snapshot_id = data.aws_ebs_snapshot_ids.jenkins_master.ids.0 # First element
tags = {
Name = "jenkins-master-ebs"
}
}

Can I Pass Terraform output / resources.id values into any variable present in variable.tf file?

I need to have "client_secret" output value as an input for "tenant_app_password"
variables.tf
variable "tenant_app_password" {
description = ""
}
Create-service-principal.tf
resource "random_string" "password" {
length = 32
special = true
}
# Create Service Principal Password
resource "azuread_service_principal_password" "test_sp_pwd" {
service_principal_id = azuread_service_principal.test_sp.id
value = random_string.password.result
end_date = "2020-01-12T07:10:53+00:00"
}
OUTPUT
output "client_secret" {
value = "${azuread_service_principal_password.wvd_sp_pwd.value}"
sensitive = true
}
Is we have any possible way ???
I'm assuming you want to use the output of one Terraform run in another one. You can do this by using a remote state datasource provider.
You cannot put the original output in a variable, but you can use the remote output as a variable directly in another template. For example, in your second template:
// set up the remote state data source
data "terraform_remote_state" "foo" {
backend = "s3"
config = {
bucket = "<your bucket name>"
key = "<your statefile name.tfstate"
region = "<your region>"
}
}
// use it
resource "kubernetes_secret" "bar" {
metadata {
name = "bar"
}
data = {
client_secret = data.terraform_remote_state.foo.outputs.client_secret
}
}
Also check out this question.

Terraform azure-remove subcription details from output

I declared security group in following way:
resource "azurerm_network_security_group" "wan" {
count = "${var.enable_wan_subnet ? 1 : 0}"
provider = "azurerm.base"
name = "${format("%s-%s", var.environment_name, "WAN-Subnet-Security-Group")}"
location = "${azurerm_resource_group.this.location}"
resource_group_name = "${azurerm_resource_group.this.name}"
tags = "${
merge(map("Name", format("%s-%s-%s",var.environment_name,"WAN-Subnets", "Security-Group")),
var.tags_global,
var.tags_module)
}"
}
and created output for that security group:
output "security_groups_id_wan" {
value = "${azurerm_network_security_group.wan.*.id}"
depends_on = [
"azurerm_subnet.wan",
]
}
In output i'm getting
Actual output
security_groups_id_wan = [
/subscriptions/111-222-333-4445/resourceGroups/default_resource_group/providers/Microsoft.Network/networkSecurityGroups/DF-DTAP-WAN-Subnet-Security-Group
]
How, from output, to remove all except resource name (DF-DTAP-WAN-Subnet-Security-Group)
Desired output:
security_groups_id_wan = [
DF-DTAP-WAN-Subnet-Security-Group
]
You can just use the Terraform functions and change the output value like this:
output "security_groups_id_wan" {
value = "${slice(split("/",azurerm_network_security_group.wan.*.id), length(split("/",azurerm_network_security_group.wan.*.id))-1, length(split("/",azurerm_network_security_group.wan.*.id)))}"
depends_on = [
"azurerm_subnet.wan",
]
}
With the functions, you can output every resource as you need. For more details, see Terraform Supported built-in functions.
Update
The test with an existing NSG through the Terraform data and the template here:
data "azurerm_network_security_group" "test" {
name = "azureUbuntu18-nsg"
resource_group_name = "charles"
}
output "substring" {
value = "${slice(split("/",data.azurerm_network_security_group.test.id), length(split("/",data.azurerm_network_security_group.test.id))-1, length(split("/",data.azurerm_network_security_group.test.id)))}"
}
The screenshot of the result here:
You built that name yourself with "${format("%s-%s", var.environment_name, "WAN-Subnet-Security-Group")}" so why not just output that?
To save repeating yourself you could put that in a local and refer to it in both the resource and the output:
locals {
security_group_name = "${format("%s-%s", var.environment_name, "WAN-Subnet-Security-Group")}"
}
resource "azurerm_network_security_group" "wan" {
count = "${var.enable_wan_subnet ? 1 : 0}"
provider = "azurerm.base"
name = "${local.security_group_name}"
# ...
}
output "security_groups_id_wan" {
value = "${local.security_group_name}"
}
Note that you also didn't need the depends_on because a) it's an output, it happens at the end of things anyway and b) you already have an implicit dependency on that resource because you used an interpolation that included the resource.
You can read more about Terraform dependencies via the Hashicorp Learn platform.
Addition to #Charles Xu's answer:Had to convert list to string first
output "subnets_id_wan" {
value = "${slice(split("/",join(",",azurerm_subnet.wan.*.id)), length(split("/",join(",",azurerm_subnet.wan.*.id)))-1, length(split("/",join(",",azurerm_subnet.wan.*.id))))}"
depends_on = [
"azurerm_subnet.wan",
]
}

Resources