I'm trying to deploy an Azure application gateway in Terraform, in particular I need to create a nested dynamic blocks.
I have tried to implement this (this part of the code is in a file called application_gateway.tf):
dynamic "url_path_map" {
for_each = var.path_maps
content {
name = outer_block.value["name"]
default_backend_address_pool_name = outer_block.value["backend"]
default_backend_http_settings_name = outer_block.value["backend_set"]
dynamic "url_path_rule" {
for_each = url_path_map.value["upm"]
content{
name = url_path_rule.value["name_rule"]
paths = url_path_rule.value["path"]
backend_address_pool_name = url_path_rule.value["backend"]
backend_http_settings_name = url_path_rule.value["backend_set"]
}
}
}
}
The correspective variables.tf file is:
variable "path_maps" {
default = []
type = list(object({
name = string
backend = string
backend_set = string
upm = list(object({
name_rule = string
path = string
backend = string
backend_set = string
}))
}))
}
With the following module call (this part of the script is in another file called main.tf):
module "application_gateway" {
source = "../modules/resources-hub/application_gateway"
resource_group_name = module.resource_group.name
resource_group_location = module.resource_group.location
subnet_id = module.agw_subnet.id
public_ip_address_id = module.app_gw_pip.id
firewall_policy_id = module.agw_web_application_firewall.id
log_analytics_workspace_id = module.log_analytics_workspace.id
path_maps = [{name = "dev_url_path_name", backend = "devBackend", backend_set = "devHttpSetting", name_rule = "dev_path_rule_name_app", path = "/app/*"},
{name = "tst_url_path_name", backend = "tstBackend", backend_set = "tstHttpSetting", name_rule = "dev_path_rule_name_edp", path = "/edp/*"},
{name = "uat_url_path_name", backend = "uatBackend", backend_set = "uatHttpSetting", name_rule = "dev_path_rule_name_internal", path = "/internal/*"}]
}
At the end, what I would like to obtain is this but using the nested dynamic blocks:
url_path_map {
name = "dev_url_path_name"
default_backend_address_pool_name = "devBackend"
default_backend_http_settings_name = "devHttpSetting"
path_rule {
name = "dev_path_rule_name_app_edp"
paths = ["/app/*"]
backend_address_pool_name = "devBackend"
backend_http_settings_name = "devHttpSetting"
}
path_rule {
name = "dev_path_rule_name_internal"
paths = ["/edp/*"]
backend_address_pool_name = "devBackend"
backend_http_settings_name = "devHttpSetting"
}
path_rule {
name = "dev_path_rule_name_internal"
paths = ["/internal/*"]
backend_address_pool_name = "sinkPool"
backend_http_settings_name = "devHttpSetting"
}
}
This is the error that I get if I run "terraform validate":
enter image description here
Thank you in advance!
I have tried the code above but I got the error in the image.
The first problem is on the definition of the variable "path_maps", because is different as the path_maps format that you are passing to the module.
You can modify the path_maps before passing to the module with the correct format, or you can change variable to fit the format that you define.
thats why you are getting the error that "upm" is required
Related
I have the following list of objects defined as a local:
agw_configs = [
{
env = "dev"
function = "events"
backend_pool_fqdn = "dev.servicebus.windows.net"
cookie_based_affinity = "Enabled"
https_listener_hostname = "ingestiondev.co.uk"
},
{
env = "test"
function = "events"
backend_pool_fqdn = "test.servicebus.windows.net"
cookie_based_affinity = "Enabled"
https_listener_hostname = "ingestiontest.co.uk"
}
]
I now want to use multiple dynamic blocks within an Azure application gateway resource to create various settings for each environment. However I cannot figure out how to do this and keep getting undeclared resource errors. Here is my current config:
resource "azurerm_application_gateway" "application_gateway" {
name = local.application_gateway_name
resource_group_name = var.resource_group_name
location = var.location
sku {
name = var.sku.size
tier = var.sku.tier
capacity = var.sku.capacity
}
...
dynamic "backend_address_pool" {
for_each = local.agw_configs
content {
name = "${var.region}-${agw_configs.value.env}-${agw_configs.value.function}-beap"
fqdns = [agw_configs.value.backend_pool_fqdn]
}
}
Feels like i am almost there but not sure where I am going wrong
See an example that it works:
1/ Define the variable - with the
variable "backend_pools" {
type = map(string({
fqdn = string
ip_addresses = string
}))
#Define default value
default = {
"Pool1" = {
fqdns = "fqdns1"
ip_addresses = "10.0.0.0"
}
"pool2" = {
fqdns = "fqdns1"
ip_addresses = "10.10.0.0"
}
Then you can use the var from dynamic block into your azurerm_application_gateway block:
dynamic "backend_address_pool" {
for_each = var.backend_pools
content {
fqdns = backend_address_pool.value.fqdn
ip_addresses = backend_address_pool.value.ip_addresses
}
}
im trying to create an instance group with reference to an GCE, but im unable to refer to the id from instance group to link to the GCE
variable "compute_engine_instances" {
type = map(object({
instance_name = string
machine_type = string
zone = string
tags = list(string)
image_name = string
image_project = string
labels =object({
app_id = number
cost_center = string
owner = string
email = string
})
}))
}
module "qat_hosted_pacs_compute_engines" {
source = "../modules/compute_engine"
for_each = var.compute_engine_instances
project_id = var.project_id
instance_name = each.value.instance_name
machine_type = each.value.machine_type
tags = each.value.tags
labels = each.value.labels
subnetwork = var.subnetwork
zone = each.value.zone
image_name = each.value.image_name
image_project = each.value.image_project
}
variable "instance_group" {
type = map(object({
group_manager_name = string
zone = string
}))
}
module "qat_hosted_pacs_app_grp" {
source = "../modules/instance_groups"
for_each = var.instance_group
group_manager_name = each.value.group_manager_name
zone = each.value.zone
project_id = var.project_id
instances = module.qat_hosted_pacs_compute_engines.vm_name #unable to figure out how to reference the GCE
}
#output.tf looks like this for compute engine module
output "compute_engine_instances" {
value = {
for k, v in module.qat_hosted_pacs_compute_engines : k => v.vm_name
}
}
The root module looks like this for compute engine
data "google_compute_image" "compute_image" {
name = var.image_name
project = var.image_project
}
resource "google_compute_instance" "generic_instance" {
project = var.project_id
name = var.instance_name
machine_type = var.machine_type
zone = var.zone
tags = var.tags
labels = var.labels
boot_disk {
initialize_params {
image = data.google_compute_image.compute_image.self_link
}
auto_delete = true
}
network_interface {
subnetwork = var.subnetwork
}
}
#outputs.tf here looks like this for gce resource
output "vm_name" {
value = google_compute_instance.generic_instance.id
description = "The name of the VM"
}
And the instance group manager looks like this
resource "google_compute_instance_group" "igm" {
name = var.group_manager_name
zone = var.zone
project = var.project_id
instances = var.instances
named_port {
name = "http"
port = "8080"
}
named_port {
name = "https"
port = "8443"
}
lifecycle {
create_before_destroy = true
}
}
i get the foll. error
Error: Unsupported attribute
on main.tf line 45, in module "qat_hosted_pacs_app_grp":
45: instances = module.qat_hosted_pacs_compute_engines.vm_name
|----------------
| module.qat_hosted_pacs_compute_engines is object with 2 attributes
This object does not have an attribute named "vm_name".
terraform tf vars file
compute_engine_instances ={
"test-adi"={
instance_name = "test-vm"
machine_type = "n1-standard-1"
zone = "us-east4-b"
tags = ["foo","bar"]
image_name = "gold-centos-7"
image_project = "dev-cietools"
labels = {
app_id = "56"
cost_center = "156"
owner = "ops"
email = "ops"
}}
"test-adi-2"={
instance_name = "test-vm-2"
machine_type = "n1-standard-1"
zone = "us-east4-b"
tags = ["foo","bar"]
image_name = "centos-7"
image_project = "dev-cietools"
labels = {
app_id = "56"
cost_center = "856"
owner = "ops"
email = "ops"
}
}
}
subnetwork = "sandbox-us-east4"
project_id = "cloudops-dev01-sb"
instance_group = {
"igm" = {
group_manager_name = "test"
zone = "us-east4-b"
}
}
Since you used for_each in your google_compute_instance_group module, you have to use key to refer to individual instances of the module, e.g.
instances = module.qat_hosted_pacs_compute_engines["test-adi"].vm_name
or if you want to pass all vm_name created for all values of for_each, you can do:
instances = values(module.qat_hosted_pacs_compute_engines)[*].vm_name
I have a resource that creates a target group. I would like to modify the resource with a capability of creating n number of target groups with a specific naming convention.
resource "aws_lb_target_group" "main" {
name = "${var.name}-tg"
port = var.forward_port
protocol = var.forward_protocol
target_type = var.target_type
deregistration_delay = var.deregistration_delay
health_check {
interval = var.interval
path = var.path
}
stickiness {
type = var.cookie_type
}
}
I want to modify it in such a way that if only one target group is created it should name it as test-tg, but if there are more than one target group then it should add index to name like test-tg1. Also each target group can have their own specific set of variable value. How can I achieve that?
You can use for_each in that case as you want to create multiple TGs with different configurations. Create a variable with map(object()) type which allows you to put the values the way you expect. I have put a sample code. Take a reference of below.
Please put the values of below vars in terraform.tfvars file
cookie_type, path, deregistration_delay
var.tf
variable "TG_conf" {
type = map(object({
port = string
protocol = string
target_type = string
interval = string
cookie_type = string
path = string
deregistration_delay = string
}))
}
terrafor.tfvars
TG_conf = {
"test-tg" = {
port = 80
protocol = HTTP
target_type = "instance
interval = "5"
cookie_type = string
path = string
deregistration_delay = string
}
alb.tf
resource "aws_lb_target_group" "main" {
for_each = var.TG_conf
name = "${each.key}"
port = each.value.port
protocol = each.value.protocol
target_type = each.value.target_type
deregistration_delay = each.value.deregistration_delay
health_check {
interval = each.value.interval
path = each.value.path
}
stickiness {
type = each.value.cookie_type
}
}
I'm trying to create cloudwatch alarms for some specific load balancers.
What if I have to create 100 cloudwatch alarms, do I need to populate the tfvars the way, I'm updating it currently, or is there any other way which is more optimized.
Following is my code.
main.tf
resource "aws_cloudwatch_metric_alarm" "UnHealthyHosts" {
for_each = var.cloudwatch_alarms_map
alarm_name = each.key
comparison_operator = var.cloudwatch_alarm_operator
evaluation_periods = var.cloudwatch_alarm_evaluation_periods
metric_name = var.cloudwatch_alarm_metric
namespace = each.value["alarm_namespace"]
period = var.cloudwatch_alarm_period
statistic = var.cloudwatch_alarm_statistic
threshold = var.cloudwatch_alarm_threshold
alarm_description = var.cloudwatch_alarm_description
actions_enabled = var.cloudwatch_alarm_actions_enabled
alarm_actions = [aws_sns_topic.sns.arn]
dimensions = {
TargetGroup = each.value["target_group_arn"]
LoadBalancer = each.value["load_balancer_arn"]
}
}
variables.tf
variable "cloudwatch_alarms_map" {
type = map(object({
alarm_namespace = string # eg: AWS/ApplicationELB
target_group_arn = string
load_balancer_arn = string
}))
default = {}
}
terraform.tfvars
cloudwatch_alarms_map = {
app1-unhealthy-alarm = {
target_group_arn_suffix = "targetgroup/sample-app1-tg/12de123e123123aa"
load_balancer_arn_suffix = "app/sample-alb-app1-lb/12c5732bd012e47a"
alarm_namespace = "AWS/ApplicationELB"
}
app2-unhealthy-alarm = {
target_group_arn_suffix = "targetgroup/sample-app2-tg/313e7f1ad4a2e373"
load_balancer_arn_suffix = "app/sample-alb-app2-lb/f2c5132bd012e47a"
alarm_namespace = "AWS/ApplicationELB"
}
}
How to reference List of objects variables in terraform module block
Variables.tf
variable "list_views_datasets" {
description = "List of Views in the Datasets"
type = list(object({
dataset_id = string
dataset_name = string
views = list(object({
view_id = string,
query = string,
use_legacy_sql = bool,
labels = map(string),
}))
}))
default = []
}
tfvars:
list_views_datasets = [
{
dataset_id = "testservice"
dataset_name = "testservice"
views = [
{
view_id = "issue-data",
use_legacy_sql = false,
query = ".test.sql"
# unfortunately we have to repeat the project id, dataset id and table id in here.
labels = {
env = "dev"
billable = "true"
owner = "dev"
}
},
]
},
Main.tf
module "bigquery_views" {
source = "terraform-google-modules/bigquery/google"
version = "4.3.0"
depends_on = [module.bigquery]
for_each = { for list_view in var.list_views_datasets : list_view.dataset_id => list_view }
dataset_id = each.value.dataset_id
dataset_name = each.value.dataset_name
description = var.views_description
project_id = var.project_id
location = var.location
views = {
view_id = each.value.views[view_id]
labels = each.value.views[labels]
query = file(each.value.views[query])
use_legacy_sql = each.value.views[use_legacy_sql]
}
dataset_labels = var.dataset_labels
access = [
{
role = "roles/bigquery.dataOwner"
special_group = "projectOwners"
}
]
}
Now i am planning to reference the variable in my module block but i am not sure whether i have referenced corretly the views, query,
labels value in my mobule block
Sadly you can't do this. You have to pass entire list_views_datasets into your module as one variable, or use for_each at the module level. In the second case you will create multiple modules.