How to Output Values From Another File in Terraform - terraform

I have two folders with a few files in each folder
services
dns.tf
app
outputs.tf
In the dns.tf I have the following:
resource "cloudflare_record" "pgsql_master_record" {
count = var.pgsql_enabled ? 1 : 0
zone_id = data.cloudflare_zone.this.id
name = "${var.name}.pg.${var.jurisdiction}"
value = module.db[0].primary.ip_address.0.ip_address
type = "A"
ttl = 3600
}
resource "cloudflare_record" "redis_master_record" {
count = var.redis_enabled ? 1 : 0
zone_id = data.cloudflare_zone.this.id
name = "${var.name}.redis.${var.jurisdiction}"
value = module.redis[0].host
type = "A"
ttl = 3600
}
And in my app outputs.tf I'd like to add outputs for the above resources
output "psql_master_record" {
value = cloudflare_record.pgsql_master_record[*].hostname
}
output "redis_master_record" {
value = cloudflare_record.redis_master_record[*].hostname
}
But I keep getting this error:
A managed resource "cloudflare_record" "redis_master_record" has not been declared in the root module.

You can't do it.
Your dns.tf and outputs.tf should be in the same folder
Or as example, you can use data block with remote state
In Terraform, you can output values from a configuration using the output block. These outputs can then be referenced within the same configuration using interpolation syntax, or from another configuration using the terraform_remote_state data source.
Here's an example of how you might use the output block to output the value of an EC2 instance's ID:
resource "aws_instance" "example" {
# ...
}
output "instance_id" {
value = aws_instance.example.id
}
You can then reference the output value within the same configuration using "output.instance_id.value".
To use the output value from another configuration, you'll first need to create a data source for the remote state using the terraform_remote_state data source. Here's an example of how you might do that:
data "terraform_remote_state" "example" {
backend = "s3"
config {
bucket = "my-tf-state-bucket"
key = "path/to/state/file"
region = "us-west-2"
}
}
Then, you can reference the output value from the remote configuration using "data.terraform_remote_state.example.output.instance_id.value".

As far as I know, you have to run terraform per directory. In the same directory you can have multiple terraform files and use variables from file A in file B. You are currently splitting it in 2 directories, that is only possible with a module approach. And this does not work out-of-the-box.
This thread should clarify it.

Related

Terraform assigning outputs to variable or pulling output from stateful and using it

I am working with terraform and trying to output the security group ID in the form of an output and pull it from the local terraform state file and use that information in a different resource in my case it would be a aws_eks_cluster in the vpc_config session.
In the module that has the security group:
output "security_group_id" {
value = aws_security_group.a_group.id
}
In the module that reads the output (the backend config dependends on which backend type you are using and how it is configured):
data "terraform_remote_state" "security_group" {
backend = "s3"
config {
bucket = "your-terraform-state-files"
key = "your-state-file-key.tfstate"
region = "us-east-1"
}
}
locals {
the_security_group_id = data.terraform_remote_state.security_group.outputs.security_group_id
}

Terraform output variables as input

I'm new to Terraform and trying to wrap my head around the use of output variables. we are on AKS, and I'm deploying the following resources: resource group, log analytics workspace, Azure Kubernetes. When Log analytics is deployed, I capture the workspace ID into an output variable. Now, when Terraform deploys Kubernetes, it needs to know the workspace ID, how can I pass the output value to the addon_profile (last line in the code below)?
Error:
environment = "${log_analytics_workspace_id.value}"
A managed resource "log_analytics_workspace_id" "value" has not been declared in the root module.
Code:
resource "azurerm_resource_group" "test" {
name = "${var.log}"
location = "${var.location}"
}
resource "azurerm_log_analytics_workspace" "test" {
name = "${var.logname}"
location = "${azurerm_resource_group.loganalytics.location}"
resource_group_name = "${azurerm_resource_group.loganalytics.name}"
sku = "PerGB2018"
retention_in_days = 30
}
**output "log_analytics_workspace_id" {
value = "${azurerm_log_analytics_workspace.test.workspace_id}"
}**
....................................................
addon_profile {
oms_agent {
enabled = true
**log_analytics_workspace_id = "${log_analytics_workspace_id.value}"**
}
}
Terraform's output values are like the "return values" of a module. In order to declare and use the log_analytics_workspace_id output value, you would need to put all of the code for the creation of the resource group, log analytics workspace, and Azure Kubernetes infrastructure into a single Terraform module, and then reference the output value from outside of the module:
# declare your module here, which contains creation code for all your Azure infrastructure + the output variable
module "azure_analytics" {
source = "git::ssh://git#github.com..."
}
# now, you can reference the output variable in your addon_profile from outside the module:
addon_profile {
oms_agent {
enabled = true
log_analytics_workspace_id = "${module.azure_analytics.log_analytics_workspace_id}"
}
}
On the other hand, if you just want to use the workspace_id value from your azurerm_log_analytics_workspace within the same code, just reference it like azurerm_log_analytics_workspace.test.workspace_id.

How to do a terraform module of data sources?

I want to do a module of data sources, but I am unsure how to declare them? The different accounts are gonna use the same, and they are already in place.
the data sources are regarding iam and policies.
I know usually you do :
module "iam" {
source = "folder"
name = "blabla"
... }
Thanks a lot!
You could create an own 'environment' for that. Let's name it general.
If you assign an own backend for it and configure it to use an S3 bucket as remote storage (recommended anyways if you work with multiple contributors), you can work with terraform_remote_state.
Just import the state of general into your environment with
data "terraform_remote_state" "general" {
backend = "s3"
config {
region = "..." # e.g. "eu-central-1"
bucket = "..." # the remote-storage bucket name of 'general'
key = "..." # e.g. "environments/general/terraform.tfstate" (as defined in the 'general' backend!
}
}
You can then access the resources from that state with ami = "${data.terraform_remote_state.general.ami}" if you declared them as output variable:
output "ami" {
description = "The ID of the default EC2 AMI"
value = "${var.ami}"
}
Of course you can also output resource attributes:
output "vpc_id" {
description = "The ID of the created VPC"
value = "${aws_vpc.vpc.id}"
}

concatenate two variables in terraform

i'm trying to create a kubernetes cluster from kops using terraform,following code is a part of infrastructure, i'm trying to create the name concatenate with two variables, and i'm getting illegal char error line two, error happens because im trying to define the name with concatenate variables. is it possible in terraform?
resource "aws_autoscaling_group" "master-kubernetes" {
name = "master-"${var.zone}".masters."${var.cluster_name}""
launch_configuration = "${aws_launch_configuration.master-kubernetes.id}"
max_size = 1
min_size = 1
vpc_zone_identifier = ["${aws_subnet.subnet-kubernetes.id}"]
With latest terraform 0.12.x terraform format doc , you could do better like:
resource "aws_autoscaling_group" "master-kubernetes" {
name = format("master-%s.masters.%s", var.zone, var.cluster_name)
}
Try this:
resource "aws_autoscaling_group" "master-kubernetes" {
name = "master-${var.zone}.masters.${var.cluster_name}"
# ... other params ...
}
I would say rather concatenating at resource level use the locals first define a variable in locals and then you can utilize it at resource level
Locals declaration
locals {
rds_instance_name = "${var.env}-${var.rds_name}"
}
Resource Level declaration
resource "aws_db_instance" "default_mssql" {
count = var.db_create ? 1 : 0
name = local.rds_instance_name
........
}
This is as simple as its need to be ....

Is it possible to access module state in a terraform remote state file?

If a terraform script uses a module that has outputs, it's possible to access those module outputs in using the -module option for the terraform output command:
$ terraform output --help
Usage: terraform output [options] [NAME]
Reads an output variable from a Terraform state file and prints
the value. If NAME is not specified, all outputs are printed.
Options:
-state=path Path to the state file to read. Defaults to
"terraform.tfstate".
-no-color If specified, output won't contain any color.
-module=name If specified, returns the outputs for a
specific module
-json If specified, machine readable output will be
printed in JSON format
If I store that state file in S3 or some such, I can then reference the outputs of the main script by using the terraform_remote_state data provider.
data "terraform_remote_state" "base_networking" {
backend = "s3"
config {
bucket = "${var.remote_state_bucket}"
region = "${var.remote_state_region}"
key = "${var.networking_remote_state_key}"
}
}
resource "aws_instance" "my_instance" {
subnets = "${data.terraform_remote_state.base_networking.vpc_id}"
}
Is it possible to access the module outputs that are present in the state file as well? I'm looking for something like "${data.terraform_remote_state.base_networking.module.<module_name>.<output>}" or similar.
Yes, you can access remote state outputs from your own modules. You just need to "propagate" the outputs.
E.g., let's say you have something like this, your base_networking infrastructure, which contains a module for creating your VPC, and you want that VPC ID to be accessible via remote state:
base_networking/
main.tf
outputs.tf
vpc/
main.tf
outputs.tf
In base_networking/main.tf you create your VPC using your base_networking/vpc module:
module "vpc" {
source = "./vpc"
region = "${var.region}"
name = "${var.vpc_name}"
cidr = "${var.vpc_cidr}"
}
In base_networking/vpc/outputs.tf in your module you have an id output:
output "id" {
value = "${aws_vpc.vpc.id}"
}
In base_networking/outputs.tf you also have a vpc_id output that propagates module.vpc.id:
output "vpc_id" {
value = "${module.vpc.id}"
With that you can now access vpc_id using something like:
data "terraform_remote_state" "base_networking" {
backend = "s3"
config = {
bucket = "${var.remote_state_bucket}"
region = "${var.remote_state_region}"
key = "${var.networking_remote_state_key}"
}
}
[...]
vpc_id = "${data.terraform_remote_state.base_networking.vpc_id}"

Resources