How do I populate sourceInfo in SSM Association using TerraForm - amazon-web-services

I am building a very basic Systems Manager Association in TerraForm but I do not understand what the sourceInfo field is asking for. It requires a string but even simple strings like "test" cause it to reject the input.
resource "aws_ssm_association" "sslscanssm" {
name = "AWS-RunInspecChecks"
association_name = "test"
targets = {
key = "tag:os"
values = ["linux"]
}
parameters {
sourceType = "GitHub"
sourceInfo = "{"owner":"awslabs","repository":"amazon-ssm","path":"Compliance/InSpec/PortCheck","getOptions":"branch:master"}"
#^this line doesn't work
#sourceInfo = "test"
#^this line doesn't work either
}
}

Instead of escaping all of your strings you could also use the jsonencode function to turn a map into the JSON you want:
locals {
source_info = {
owner = "awslabs"
repository = "amazon-ssm"
path = "Compliance/InSpec/PortCheck"
getOptions = "branch:master"
}
}
resource "aws_ssm_association" "sslscanssm" {
name = "AWS-RunInspecChecks"
association_name = "test"
targets = {
key = "tag:os"
values = ["linux"]
}
parameters {
sourceType = "GitHub"
sourceInfo = "${jsonencode(local.source_info)}"
}
}

I wasn't aware sourceInfo expects parentheses and all inner double quotes to be escaped or it won't work.
resource "aws_ssm_association" "sslscanssm" {
name = "AWS-RunInspecChecks"
association_name = "test"
targets = {
key = "tag:os"
values = ["linux"]
}
parameters {
sourceType = "GitHub"
sourceInfo = "{\"owner\":\"awslabs\",\"repository\":\"amazon-ssm\",\"path\":\"Compliance/InSpec/PortCheck\",\"getOptions\":\"branch:master\"}"
}
}

There is a mistake in the code shared (no equal sign after targets but after parameters). The correct syntax of the resource is :
resource "aws_ssm_association" "sslscanssm" {
name = "AWS-RunInspecChecks"
association_name = "test"
targets {
key = "tag:os"
values = ["linux"]
}
parameters = {
sourceType = "GitHub"
sourceInfo = "${jsonencode(local.source_info)}"
}
}

Related

Terraform dynamic variable lookup

I am writing some terraform code that looks up the ami based on a variable called fortios_version. I seem to not understand how to have a map pass back a map value. Here is my code...
variable "fortios_version" {
type = string
}
variable "fortios_map" {
type = map
default = {
"7.2.0" = "fgtvmbyolami-7-2-0"
"6.4.8" = "fgtvmbyolami-6-4-8"
}
}
variable "fgtvmbyolami-7-2-0" {
type = map
default = {
us-east-1 = "ami-08a9244de2d3b3cfa"
us-east-2 = "ami-0b07d15df1781b3d8"
}
}
My aws instance code:
ami = lookup(lookup(var.fortios_map[var.fortios_version]), var.region)
My variable:
fortios_version: "7.2.0"
I hope I am making sense. I have played with different variations all day with no luck.
You can't dynamically refer to fgtvmbyolami-7-2-0 based on the output of fortios_map. It would be best to re-organize your variables:
variable "fortios_version" {
type = string
}
variable "fortios_map" {
type = map
default = {
"7.2.0" = "fgtvmbyolami-7-2-0"
"6.4.8" = "fgtvmbyolami-6-4-8"
}
}
variable "amis" {
type = map
default = {
"fgtvmbyolami-7-2-0" = {
us-east-1 = "ami-08a9244de2d3b3cfa"
us-east-2 = "ami-0b07d15df1781b3d8"
},
"fgtvmbyolami-6-4-8" = {
us-east-1 = "ami-08a92333cfa"
us-east-2 = "ami-0b07dgggg781b3d8"
}
}
}
then
ami = var.amis[var.fortios_map[var.fortios_version]][var.region]
You can expand this to ad lookup in to have some default values for each map.

Terraform - Optional Nested Variable

I'm trying to create a module for Sagemaker endpoints. There's an optional object variable called async_inference_config. If you omit it, the endpoint being deployed is synchronous, but if you include it, the endpoint deployed is asynchronous. To satisfy both of these usecases, the async_inference_config needs to be an optional block.
I am unsure of how to make this block optional though.
Any guidance would be greatly appreciated. See example below of structure of the optional parameter.
Example:
resource "aws_sagemaker_endpoint_configuration" "sagemaker_endpoint_configuration" {
count = var.create ? 1 : 0
name = var.endpoint_configuration_name
production_variants {
instance_type = var.instance_type
initial_instance_count = var.instance_count
model_name = var.model_name
variant_name = var.variant_name
}
async_inference_config {
output_config {
s3_output_path = var.s3_output_path
}
client_config {
max_concurrent_invocations_per_instance = var.max_concurrent_invocations_per_instance
}
}
lifecycle {
create_before_destroy = true
ignore_changes = ["name"]
}
tags = var.tags
depends_on = [aws_sagemaker_model.sagemaker_model]
}
Update: What I tried based on the below suggestion, which seemed to work
dynamic "async_inference_config" {
for_each = var.async_inference_config == null ? [] : [true]
content {
output_config {
s3_output_path = lookup(var.async_inference_config, "s3_output_path", null)
}
client_config {
max_concurrent_invocations_per_instance = lookup(var.async_inference_config, "max_concurrent_invocations_per_instance", null)
}
}
}
You could use a dynamic block [1] in combination with for_each meta-argument [2]. It would look something like:
dynamic "async_inference_config" {
for_each = var.s3_output_path != null && var.max_concurrent_invocations_per_instance != null ? [1] : []
content {
output_config {
s3_output_path = var.s3_output_path
}
client_config {
max_concurrent_invocations_per_instance = var.max_concurrent_invocations_per_instance
}
}
}
Of course, you could come up with a different variable, say enable_async_inference_config (probalby of type bool) and base the for_each on that, e.g.:
dynamic "async_inference_config" {
for_each = var.enable_async_inference_config ? [1] : []
content {
output_config {
s3_output_path = var.s3_output_path
}
client_config {
max_concurrent_invocations_per_instance = var.max_concurrent_invocations_per_instance
}
}
}
[1] https://www.terraform.io/language/expressions/dynamic-blocks
[2] https://www.terraform.io/language/meta-arguments/for_each

How to add and reference a map of map as a local variable in terraform?

I want to create a map of map as a local variable. I am using this
locals {
region_map = {
mumbai = {
is_second_execution = true
cg_ip_address = "ip.add.re.ss"
}
}
}
Now I am referencing it as
module "mumbai" {
source = "./site-to-site-vpn-setup"
providers = { aws = aws.mumbai }
is_second_execution = lookup(local.region_map, local.region_map["mumbai"]["is_second_execution"], false)
cg_ip_address = lookup(local.region_map, local.region_map["mumbai"]["cg_ip_address"], "")
}
but upon doing terrafrom plan the cg_ip_address is being set to null.
Also If I add another module say "saopaulo" and I need to pass default values of is_second_execution and cg_ip_address for it without adding saopaulo in the map, how do I do that?
The lookup built-in function [1] has the following syntax:
lookup(map, key, default)
Since you have a map of maps, that means that the first argument is the map (local.region_map.mumbai), the second is the key you are looking for (cg_ip_address) and the third argument is the default value. So in your case you have to change the lookup to this:
module "mumbai" {
source = "./site-to-site-vpn-setup"
providers = { aws = aws.mumbai }
is_second_execution = lookup(local.region_map.mumbai, "is_second_execution", false)
cg_ip_address = lookup(local.region_map.mumbai, "cg_ip_address", "")
}
[1] https://www.terraform.io/language/functions/lookup

Terraform count calling module output(return) error

I need to return output of name and id only
root main.tf
# Azure Provider configuration
provider "azurerm" {
features {}
}
module "rg" {
source = "../../modules/rg"
count = length(var.resource_groups)
resource_group_name = var.resource_groups[count.index].name
tags = {}
location = westus2
lookup = false
}
module/rg/main.tf
resource "azurerm_resource_group" "rg" {
count = var.lookup == true ? 0 : 1
name = var.resource_group_name
location = var.location
tags = var.tags
}
output "rg_id" {
description = "The id of the newly created rg"
value = azurerm_resource_group.rg[count_index].id # azurerm_resource_group.rg, this statement will work
}
output "rg_name" {
description = "The name of the newly created rg"
value = azurerm_resource_group.rg[count_index].name # azurerm_resource_group.rg, this statement will work
}
I am getting below error:
A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
I think the following should address your issue:
output "rg_id" {
description = "The id of the newly created rg"
value = var.lookup == true ? azurerm_resource_group.rg[0].id : null
}
output "rg_name" {
description = "The name of the newly created rg"
value = var.lookup == true ? azurerm_resource_group.rg[0].name : null
}

Value for Terraform Composer airflow_config_override secrets-backend_kwargs

I need to change, using Terraform, the default project_id in my Composer environment so that I can access secrets from another project. To do so, according to Terraform, I need the variable airflow_config_overrides. I guess I should have something like this:
resource "google_composer_environment" "test" {
# ...
config {
software_config {
airflow_config_overrides = {
secrets-backend = "airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend",
secrets-backend_kwargs = {"project_id":"9999999999999"}
}
}
}
}
The secrets-backend section-key seems to be working. On the other hand, secrets-backend_kwargs is returning the following error:
Inappropriate value for attribute "airflow_config_overrides": element "secrets-backend_kwargs": string required
It seems that the problem is that GCP expects a JSON format and Terraform requires a string. How can I get Terraform to provide it in the format needed?
You can convert a map such as {"project_id":"9999999999999"} into a JSON encoded string by using the jsonencode function.
So merging the example given in the google_composer_environment resource documentation with your config in the question you can do something like this:
resource "google_composer_environment" "test" {
name = "mycomposer"
region = "us-central1"
config {
software_config {
airflow_config_overrides = {
secrets-backend = "airflow.providers.google.cloud.secrets.secret_manager.CloudSecretManagerBackend",
secrets-backend_kwargs = jsonencode({"project_id":"9999999999999"})
}
pypi_packages = {
numpy = ""
scipy = "==1.1.0"
}
env_variables = {
FOO = "bar"
}
}
}
}