Terraform Variable Composition - terraform

I have a variable that defines the query parameters in my API Gateway resource. Every resource has a base set of default query parameters. Some resources have the base set plus an additional parameter.
# base set of query parameters that apply to all resources
variable "parameters_default" {
default = {
"method.request.querystring.brokerage" = false
"method.request.querystring.account_alias" = false
"method.request.querystring.start_date" = false
"method.request.querystring.end_date" = false
"method.request.querystring.valuation_date" = false
}
}
# additional query parameter that applies to only one resource
variable "parameters_special_resource" {
default = {
"method.request.querystring.brokerage" = false
"method.request.querystring.account_alias" = false
"method.request.querystring.start_date" = false
"method.request.querystring.end_date" = false
"method.request.querystring.valuation_date" = false
"method.request.querystring.top" = false
}
}
Instead of having to redefine all the baseline query parameters, I want to use the baseline to compose the second one. Something like this
# compose the parameters_special_resource variable using parameters_special_resource
variable "parameters_special_resource" {
# baseline parameters_special_resource
default = {
"method.request.querystring.top" = false
}
}
How is this done?

Its not possible to create dynamic variables. Instead you should use locals and merge:
# base set of query parameters that apply to all resources
variable "parameters_default" {
default = {
"method.request.querystring.brokerage" = false
"method.request.querystring.account_alias" = false
"method.request.querystring.start_date" = false
"method.request.querystring.end_date" = false
"method.request.querystring.valuation_date" = false
}
}
# additional query parameter that applies to only one resource
variable "parameters_special_resource" {
default = {
"method.request.querystring.top" = false
}
}
locals {
# marge base and special paramters
parameters_special_resource = merge(var.parameters_default, var.parameters_special_resource)
}
Then you use local.parameters_special_resource in your code.

Related

terraform dynamicly attach subnetwork with dynamic nat_ip

This is an example of my code
What I need ? - I need network interfaces to dynamically connect to the instance, but only one interface should have an external address (nat_ip = ...)
dynamic "network_interface" {
for_each = var.server_network
content {
subnetwork = network_interface.value["subnetwork_name"]
dynamic "access_config" {
HERE i need expression like: if nat_ip is true then do create access_config
if false access_config = omit
for_each = var.server_network.value["nat_ip"]
content {
nat_ip = google_compute_address.static_ip.address
}
}
}
}
inputs in module:
module "vps-test" {
source = "../module"
......
server_network = {
common_network = {
subnetwork_name = (data.terraform_remote_state.network.outputs.subnetwork_vpc_production_common_name)
nat_ip = true
},
custom_network = {
subnetwork_name = "10.10.0.1/24"
nat_ip = false
}
}
}
You can achieve this using the ternary expression [1]:
dynamic "access_config" {
for_each = network_interface.value.nat_ip ? [1] : []
content {
nat_ip = google_compute_address.static_ip.address
}
}
The ternary expression evaluates the condition (left most part) which is network_interface.value.nat_ip in this case. Since it is already a bool value, there is no need to compare it to another value, which you would have to do if it were string or number type.
The condition can evaluate to true or false. If it evaluates to true, the part after the ? will be assigned to the argument. If it evaluates to false, the part after : will be assigned to the argument.
The for_each will be used for exactly one element ([1] in this case) if the ternary operator evaluates to true or for none (i.e., it will not be used) if it evaluates to false. In the latter case, that means that there will be no nat_ip. In the former, that means there will be a nat_ip argument defined with the value coming from the resource attribute reference: google_compute_address.static_ip.address.
[1] https://developer.hashicorp.com/terraform/language/expressions/conditionals

Terraform | How to ignore changes for lambda transform params in AWS Kinesis Firehose Delivery Stream

I have some Kinesis Firehose Delivery Stream resources created via Terraform. Due to a known bug (https://github.com/hashicorp/terraform-provider-aws/issues/9827) , when lambda transform params are kept default, Terraform avoids them to be written in state file and Every plan/apply is trying to create them again. Because of this issue, I'm trying to add ignore_lifecycle to them.
This is one of my resources;
resource "aws_kinesis_firehose_delivery_stream" "some_stream" {
name = "some_name"
destination = ""
s3_configuration {
role_arn = "some_name"
bucket_arn = "arn:aws:s3:::somebucket"
prefix = "some/prefix/"
buffer_size = 64
buffer_interval = 60
compression_format = "GZIP"
cloudwatch_logging_options {
enabled = true
log_group_name = aws_cloudwatch_log_group.some_log_group.name
log_stream_name = aws_cloudwatch_log_stream.some_log_stream.name
}
}
elasticsearch_configuration {
domain_arn = "arn:aws:es:some-es-domain"
role_arn = "arn:aws:iam::some-role"
index_name = "some-index"
index_rotation_period = "OneDay"
buffering_interval = 60
buffering_size = 64
retry_duration = 300
s3_backup_mode = "AllDocuments"
cloudwatch_logging_options {
enabled = true
log_group_name = aws_cloudwatch_log_group.some_log_group.name
log_stream_name = aws_cloudwatch_log_stream.some_log_stream.name
}
processing_configuration {
enabled = "true"
processors {
type = "Lambda"
parameters {
parameter_name = "LambdaArn"
parameter_value = "arn:aws:lambda:some-lambda"
}
parameters {
parameter_name = "BufferSizeInMBs"
parameter_value = "3"
}
parameters {
parameter_name = "BufferIntervalInSeconds"
parameter_value = "60"
}
}
}
}
}
In the resource above BufferSizeInMBs and BufferIntervalInSeconds are constantly changing. I'm trying to ignore these two without touching the LambdaArn but since all of them are using the same structure below, I couldn't quite figure it out how to do that, I don't even know it's possible or not.
parameters {
parameter_name = ""
parameter_value = ""
}
I tried this;
lifecycle {
ignore_changes = [elasticsearch_configuration.0.processing_configuration.0.processors]
}
But this doesn't exclude the parameter_name = "LambdaArn"
To go further,
I tried something like;
lifecycle {
ignore_changes=[elasticsearch_configuration.0.processing_configuration.0.processors[1],elasticsearch_configuration.0.processing_configuration.0.processors[2]]
]
}
But it didn't work. It didn't give an error, but didn't ignore the changes either. My Terraform version is 1.1.6 and provider version is ~3.0 (3.75.1 to be exact)
Any help will be highly appreciated,
Thank you very much,
Best Regards.

How do I make a block optional in a module?

I have this resource in my module: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/compute_router
I merely want to make advertised_ip_ranges optional via a variable.
I my module I do this:
resource "google_compute_router" "my-router" {
.....
bgp {
.....
advertised_ip_ranges = var.advertised_ip_ranges
I tried the following, but nothing is working
setting var.advertised_ip_ranges = {} throws this error: An argument named "advertised_ip_ranges" is not expected here. Did you mean to define a block of type "advertised_ip_ranges"?
setting var.advertised_ip_ranges = null throws the same error.
I just want to be able to ignore and not set advertised_ip_ranges via the variable.
You can set it based on a variable, but you'll need to use dynamic.
For example:
variable "advertised_ip_ranges" {
type = set(map(string))
default = []
# Requires Terraform 1.1+
# Other option is to default to `null`, and add check in `dynamic`.
nullable = false
}
resource "google_compute_router" "my_router" {
bgp {
dynamic "advertised_ip_ranges" {
for_each = var.advertised_ip_ranges
# Without `nullable`:
# for_each = coalesce(var.advertised_ip_ranges, [])
content {
# Mandatory
range = advertised_ip_ranges.value.range
# Optional
description = lookup(advertised_ip_ranges.value, "description", null)
}
# ...
}
# ...
}

How do I create RDS parameter groups from an arbitrary number of input parameters?

I have a four different environments:
dev
sit
uat
prod
The parameter group values differ for each environment. Below value will go in variable file for each environment.
Below are the parameters of an example AWS RDS parameter group. In other environments, there may be more or less parameters:
parameter {
name = "character_set_client"
value = "utf8mb4"
}
parameter {
name = "character_set_connection"
value = "utf8mb4"
}
parameter {
name = "character_set_server"
value = "utf8mb4"
}
parameter {
name = "log_bin_trust_function_creators"
value = "1"
}
I'm curious how to represent this in variables and how to write the resources to use those variables to make RDS Parameter Groups with an arbitrary number of parameters.
How do I create RDS parameter groups from an arbitrary number of input parameters?
You can use a dynamic block:
dynamic "parameter" {
for_each = var.parameters
content {
name = parameter.value.name
value = parameter.value.value
}
}
The variable can be a list of maps:
variable "parameters" {
type = list(map(string))
default = []
}
terraform.tfvars:
parameters = [
{
name = "character_set_connection"
value = "utf8mb4"
},
{
name = "character_set_server"
value = "utf8mb4"
},
{
name = "log_bin_trust_function_creators"
value = "1"
}
]

How to perform a Jooq code re-generation?

I'm using Jooq and gradle-jooq-plugin for code generation. It works fine, but I'm having a problem getting the generated code to update when a table is added or a column is dropped. I was able to force an update by changing the "packageName" config parameter and build a new package. And by going back to the original name the code was updated as expected.
What would be the correct way to re-generate code after schema change with my setup?
jooq {
version = '3.13.1'
edition = 'OSS'
generateSchemaSourceOnCompilation = true
sample(sourceSets.main) {
jdbc {
driver = 'org.postgresql.Driver'
url = 'jdbc:postgresql://0.0.0.0:5432/victor'
user = 'postgres'
password = 'docker'
properties {
property {
key = 'ssl'
value = 'false'
}
}
}
generator {
name = 'org.jooq.codegen.DefaultGenerator'
strategy {
name = 'org.jooq.codegen.DefaultGeneratorStrategy'
}
database {
name = 'org.jooq.meta.postgres.PostgresDatabase'
inputSchema = 'public'
forcedTypes {
forcedType {
name = 'varchar'
expression = '.*'
types = 'INET'
}
}
}
generate {
relations = true
deprecated = false
records = true
immutablePojos = true
fluentSetters = true
}
target {
packageName = 'net.bravo.victor.model'
directory = 'src/'
}
}
}
I'm using https://github.com/etiennestuder/gradle-jooq-plugin
plugins {
id 'nu.studer.jooq' version '4.1'
}
I am not sure whether it is correct way but for me works this:
generateNavigoJooqSchemaSource {
dependsOn cleanGenerateNavigoJooqSchemaSource
}
task buildJooq(dependsOn: generateNavigoJooqSchemaSource)
So I have created task name (buildJooq) I can remember that depends on generate task (generateNavigoJooqSchemaSource) and that depends on clean (cleanGenerateNavigoJooqSchemaSource) task.
Previously I have used this code which works too:
tasks.named("generateNavigoJooqSchemaSource").configure {
outputs.upToDateWhen { false }
}
It also forces run every time.

Resources