MongoDB Atlas Provider - Terraform - azure

I am not able to figure out below in Terraform (>= 0.13) using MongoDB Atlas provider (version >= 0.9.1)
How to set below 2 properties. Did a lot of google search with no luck
As per the documentation here:
https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/cluster
I would like to set below 2 properties:
providerSettings.autoScaling.compute.maxInstanceSize
providerSettings.autoScaling.compute.minInstanceSize
I have not tried above keys as it has . in it
tried below with no luck
providerAutoScalingComputeMaxInstanceSize = "M20"
providerAutoScalingComputeMinInstanceSize = "M10"
provider_autoScaling_compute_maxInstanceSize = "M20"
provider_autoScaling_compute_minInstanceSize = "M10"
On terraform plan. I see error:
Error: Unsupported argument
on .terraform/modules/mongodb_test_b/main.tf line 10, in resource "mongodbatlas_cluster" "mongodbatlas_cluster":
10: providerAutoScalingComputeMaxInstanceSize = var.providerAutoScalingComputeMaxInstanceSize
An argument named "providerAutoScalingComputeMaxInstanceSize" is not expected
here.
Error: Unsupported argument
on .terraform/modules/mongodb_test_b/main.tf line 12, in resource "mongodbatlas_cluster" "mongodbatlas_cluster":
12: providerAutoScalingComputeMinInstanceSize = var.providerAutoScalingComputeMinInstanceSize
An argument named "providerAutoScalingComputeMinInstanceSize" is not expected
here.
Code snippet
resource "mongodbatlas_cluster" "mongodbatlas_cluster" {
project_id = var.project_id
provider_name = var.provider_name
name = var.name
provider_instance_size_name = var.provider_instance_size_name
provider_disk_type_name = var.provider_disk_type_name
auto_scaling_compute_enabled = var.auto_scaling_compute_enabled
providerAutoScalingComputeMaxInstanceSize = var.providerAutoScalingComputeMaxInstanceSize
auto_scaling_compute_scale_down_enabled = var.auto_scaling_compute_scale_down_enabled
providerAutoScalingComputeMinInstanceSize = var.providerAutoScalingComputeMinInstanceSize
pit_enabled = var.pit_enabled
cluster_type = var.cluster_type
replication_specs {
num_shards = var.replication_specs_num_shards
regions_config {
region_name = var.region_name
electable_nodes = var.replication_specs_regions_config_electable_nodes
priority = var.replication_specs_regions_config_priority
read_only_nodes = var.replication_specs_regions_config_read_only_nodes
analytics_nodes = var.analytics_nodes
}
}
mongo_db_major_version = var.mongo_db_major_version
provider_backup_enabled = var.provider_backup_enabled
auto_scaling_disk_gb_enabled = var.auto_scaling_disk_gb_enabled
}
Any assistance. Much appreciated.

You are using the wrong argument names, you need these two:
provider_auto_scaling_compute_min_instance_size [1]
provider_auto_scaling_compute_max_instance_size [2]
Your code should look like this:
provider_auto_scaling_compute_max_instance_size = var.providerAutoScalingComputeMaxInstanceSize
provider_auto_scaling_compute_min_instance_size = var.providerAutoScalingComputeMinInstanceSize
You might also consider naming your variables differently, i.e., using the same names for those as for the argument names as that helps with mapping between what an argument is and what value will it have.
[1] https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/cluster#provider_auto_scaling_compute_min_instance_size
[2] https://registry.terraform.io/providers/mongodb/mongodbatlas/latest/docs/resources/cluster#provider_auto_scaling_compute_max_instance_size

Related

The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created

I want to exempt certain policies for an Azure VM. I have the following terraform code to exempt the policies.
It uses locals to identify the scope on which policies should be exempt.
locals {
exemption_scope = try({
mg = length(regexall("(\\/managementGroups\\/)", var.scope)) > 0 ? 1 : 0,
sub = length(split("/", var.scope)) == 3 ? 1 : 0,
rg = length(regexall("(\\/managementGroups\\/)", var.scope)) < 1 ? length(split("/", var.scope)) == 5 ? 1 : 0 : 0,
resource = length(split("/", var.scope)) >= 6 ? 1 : 0,
})
expires_on = var.expires_on != null ? "${var.expires_on}T23:00:00Z" : null
metadata = var.metadata != null ? jsonencode(var.metadata) : null
# generate reference Ids when unknown, assumes the set was created with the initiative module
policy_definition_reference_ids = length(var.member_definition_names) > 0 ? [for name in var.member_definition_names :
replace(substr(title(replace(name, "/-|_|\\s/", " ")), 0, 64), "/\\s/", "")
] : var.policy_definition_reference_ids
exemption_id = try(
azurerm_management_group_policy_exemption.management_group_exemption[0].id,
azurerm_subscription_policy_exemption.subscription_exemption[0].id,
azurerm_resource_group_policy_exemption.resource_group_exemption[0].id,
azurerm_resource_policy_exemption.resource_exemption[0].id,
"")
}
and the above local is used like mentioned below
resource "azurerm_management_group_policy_exemption" "management_group_exemption" {
count = local.exemption_scope.mg
name = var.name
display_name = var.display_name
description = var.description
management_group_id = var.scope
policy_assignment_id = var.policy_assignment_id
exemption_category = var.exemption_category
expires_on = local.expires_on
policy_definition_reference_ids = local.policy_definition_reference_ids
metadata = local.metadata
}
Both the locals and azurerm_management_group_policy_exemption are part of the same module file. And Policy exemption is applied like mentioned below
module exemption_jumpbox_sql_vulnerability_assessment {
count = var.enable_jumpbox == true ? 1 : 0
source = "../policy_exemption"
name = "Exemption - SQL servers on machines should have vulnerability"
display_name = "Exemption - SQL servers on machines should have vulnerability"
description = "Not required for Jumpbox"
scope = module.create_jumbox_vm[0].virtual_machine_id
policy_assignment_id = module.security_center.azurerm_subscription_policy_assignment_id
policy_definition_reference_ids = var.exemption_policy_definition_ids
exemption_category = "Waiver"
depends_on = [module.create_jumbox_vm,module.security_center]
}
It works for an existing Azure VM. However it throws the following error while trying to provision the Azure VM and apply the policy exemption on this Azure VM.
Ideally, module.exemption_jumpbox_sql_vulnerability_assessment should get executed only after [module.create_jumbox_vm as it is defined as a dependent. But not sure why it is throwing the error
│ The "count" value depends on resource attributes that cannot be determined
│ until apply, so Terraform cannot predict how many instances will be
│ created. To work around this, use the -target argument to first apply only
│ the resources that the count depends on.
I tried to reproduce the scenario in my environment.
resource "azurerm_management_group_policy_exemption" "management_group_exemption" {
count = local.exemption_scope.mg
name = var.name
display_name = var.display_name
description = var.description
management_group_id = var.scope
policy_assignment_id = var.policy_assignment_id
exemption_category = var.exemption_category
expires_on = local.expires_on
policy_definition_reference_ids = local.policy_definition_reference_ids
metadata = local.metadata
}
locals {
exemption_scope = try({
...
})
Received the same error:
The "count" value depends on resource attributes that cannot be determined
│ until apply, so Terraform cannot predict how many instances will be
│ created. To work around this, use the -target argument to first apply only
│ the resources that the count depends on.
Referring to local values , the values will be known on the apply time only, and not during the apply time .So if it is not dependent on other sources , it will expmpt policies but it is dependent on the VM which may be still in process of creation.
So target only the resource that is dependent on first ,as only when vm is created is when the exemption policy can be assigned to that vm.
Check count:using-expressions-in-count | Terraform | HashiCorp Developer
Also note that while using terraform count argument with Azure Virtual Machines ,NIC resource also to be created for each Virtual Machine resource.
resource "azurerm_network_interface" "nic" {
count = var.vm_count
name = "${var.vm_name_pfx}-${count.index}-nic"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
//tags = var.tags
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.internal.id
private_ip_address_allocation = "Dynamic"
}
}
Reference: terraform-azurerm-policy-exemptions/examples/count at main · AnsumanBal-MT/terraform-azurerm-policy-exemptions · GitHub

Terraform using outputs from multiple occurrences of a module created using for each

I have a problem that occurred to me after changing my code when it changed the number of "instances" of a sub-module from one to a dynamic number (using for each). The sub-module is not of my authorship, I use ready-made code from the registry, its initialization looks like this, among other things:
module "container_definition_sidecar" {
source = "cloudposse/ecs-container-definition/aws"
version = "v0.46.0"
for_each = var.sidecars
container_name = each.value.container_name
container_image = each.value.container_image
...
Why does I write sub-module? Because I already use the above fragment in my own module called simply "ECS", which is initialized like this:
module "ecs-service" {
source = "./ecs-service"
environment = "test"
awslogs_group = "/ecs/fargate-task-definition"
awslogs_stream_prefix = "ecs"
container_name = "my_container"
container_image = "nginx:latest"
...
sidecars = {
first_sidecar = {
container_name = "logzio-log-router"
container_image = "12345.dkr.ecr.us-east-2.amazonaws.com/aws-for-fluent-bit:latest"
}
second_sidecar = {...}
}
Now, where is the problem?
Where, using jsonencode, I need to get the output, which according to the documentation is called "json_map_object" for each called to life module.container_definition_sidecar
resource "aws_ecs_task_definition" "task_definition" {
family = var.family_name
network_mode = "awsvpc"
requires_compatibilities = [ "FARGATE" ]
container_definitions = jsonencode([module.container_definition_sidecar[*].json_map_object])
When I try use [*] I receive such error:
Error: Unsupported attribute
│
│ on ecs-service/main.tf line 111, in resource "aws_ecs_task_definition" "task_definition":
│ 111: container_definitions = jsonencode([module.container_definition_sidecar.*.json_map_object])
│
│ This object does not have an attribute named "json_map_object".
And the only situation in which the code passes is when I manually type e.g.:
container_definitions = jsonencode([module.container_definition_sidecar["first_sidecar"].json_map_object, module.container_definition_sidecar["second_sidecar"].json_map_object])
However, of course, I don't want to manually provide keys ["first_sidecar"], ["second_sidecar"] and etc. in my function. But don't know how to handle that dynamically
I'll just add that from where the jsonencode is executed I don't have access to the references of the ecs-service module, so I can't go through it and extract the sidecar call keys.
Ok, I solved my own issue using by making this code - writing because maybe someone will find it useful:
container_definitions = jsonencode([for key in range(length(var.sidecars)): module.container_definition_sidecar[keys(var.sidecars)[key]].json_map_object])
That is, I make a FOR loop for as many times as the number of keys in the map object. Then I use the built-in keys() function in which I point to the map, and the numeric value of the key I want to get (not the name of the key, but the value as in the index). Thanks to the for loop, the construction of this is done dynamically, as many times as there are nodes in the map object.

Iterate through a conditional for_each map of strings

Trying to put something together to get passed a limitation of the tfe plugin.
I have 200+ workspaces that I manage with a variable in Terraform Cloud that I need to update. All workspaces that I need to update start with "dev-workspace" in this case.
I have a data block with the following:
data "tfe_workspace_ids" "all" {
names = ["*"]
organization = "myorganization"
}
I can't do a wildcard search for these workspaces due to a limitation of the module. This data block returns a map of strings that include all of my workspaces:
aa = {
"dev-workspace-1" = "ws-anonymized"
"dev-workspace-2" = "ws-ws-anonymized"
"dev-workspace-3" = "ws-ws-anonymized"
"test-workspace-1" = "ws-ws-anonymized"
"prod-workspace-1" = "ws-ws-anonymized"
}
My problem is that I need to take this map of strings and filter it down to just return the ones that have "dev-workspace" in the key. I've tried something like the following:
resource "tfe_variable" "dev-workspace" {
for_each = contains(data.tfe_workspace_ids.all.ids, "dev-workspace")
key = "access_key"
value = "XXXX"
category = "terraform"
workspace_id = each.value
sensitive = true
description = "AWS IAM secret access key."
}
But it doesn't look like you can use contains in this manner with for_each:
Error: Error in function call
on main.tf line 16, in resource "tfe_variable" "dev-workspace":
16: for_each = contains(data.tfe_workspace_ids.all.ids, "dev-workspace")
|----------------
| data.tfe_workspace_ids.all.ids is map of string with 284 elements
Call to function "contains" failed: argument must be list, tuple, or set.
I'm not really sure what to do here, but have tried this several ways and can't figure it out. Thanks for any help.
If you want to filter, your resource could be (you have to change var.aa to the value of data.tfe_workspace_ids which produces the input map):
variable "aa" {
default = {
"dev-workspace-1" = "ws-anonymized"
"dev-workspace-2" = "ws-ws-anonymized"
"dev-workspace-3" = "ws-ws-anonymized"
"test-workspace-1" = "ws-ws-anonymized"
"prod-workspace-1" = "ws-ws-anonymized"
}
}
resource "tfe_variable" "dev-workspace" {
for_each = {for k, v in var.aa:
k => v if length(regexall("dev-workspace", k)) > 0}
key = "access_key"
value = "XXXX"
category = "terraform"
workspace_id = each.value
sensitive = true
description = "AWS IAM secret access key."
}

Unable to properly reference a value from a list within a map

I'm trying to reference a value within a list from a map but can't seem to get terraform to recognize that its a string.
Below is my module that I'm working on along with the variable defined.
resource "aws_transfer_user" "aws_transfer_users" {
for_each = var.transfer_users_and_keys
server_id = aws_transfer_server.aws_transfer_service.id
user_name = each.key
role = aws_iam_role.aws_transfer_role.arn
home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.transfer_users_and_keys[each.key])
tags = {
Name = each.key
Project = var.product_name
Terraform = true
}
}
variable "transfer_users_and_keys" {
type = map(list(string))
}
For some reason when I call the value from the list it gives me the following error:
on main.tf line 38, in resource "aws_transfer_user" "aws_transfer_users":
38: home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.tran
sfer_users_and_keys[each.key])
|----------------
| each.value[1] is "bucket-dev-client"
| var.transfer_users_and_keys is map of list of string with 2 elements
The given key does not identify an element in this collection value.
Here is my variable that I'm creating:
transfer_users_and_keys = {
format("key-%s",local.environment) = ["value.pub",tostring(local.sftp_bucket[0])]
format("key-%s02",local.environment) = ["value02.pub",local.sftp_bucket]
}
sftp_bucket = [format("bucket-%s-client",local.environment)]
The goal here is to build out the home_directory based on the 2nd value in the "transfer_users_and_keys" variable (tostring(local.sftp_bucket[0])).
When using for_each, you don't need to keep referencing the variable and indexing it. Change:
home_directory = format("/%s/%s",var.transfer_users_and_keys[each.value[1]],var.transfer_users_and_keys[each.key])
to simply
home_directory = format("/%s/%s", each.value[1], each.key)

I need my module to return either a list of items if input is a non-empty list or an empty list

My module takes a possibly-empty-list as input, and if that list is non-empty, creates some resources and returns a specific attribute that I need outside of the module, like so:
variable contexts {
type = "list"
}
resource "pagerduty_service" "p1" {
count = "${length(var.contexts)}"
name = "p1-${element(var.contexts, count.index)}"
description = "p1-${element(var.contexts, count.index)}"
auto_resolve_timeout = 14400
acknowledgement_timeout = 1800
escalation_policy = "${pagerduty_escalation_policy.p1.id}"
alert_creation = "create_alerts_and_incidents"
incident_urgency_rule {
type = "constant"
urgency = "high"
}
}
data "pagerduty_vendor" "cloudwatch" {
name = "Cloudwatch"
}
resource "pagerduty_service_integration" "p1_cloudwatch" {
count = "${length(var.contexts)}"
name = "Amazon Cloudwatch"
vendor = "${data.pagerduty_vendor.cloudwatch.id}"
service = "${element(pagerduty_service.p1.*.id, count.index)}"
}
output "integration_keys" {
value = "${pagerduty_service_integration.*.integration_keys}"
}
The trouble I am having is that when this module is run first with a non-empty list, thus creating the resources, it works fine. If I run it again, it fails with this exception:
* module.pagerduty.output.integration_keys: Resource 'pagerduty_service_integration.possibly_empty_resource_list' does not have attribute 'integration_key' for variable 'pagerduty_service_integration.possibly_empty_resource_list.*.integration_key'
I can't figure out a nice way to have this output return an empty list if the possibly_empty_resource_list is empty.
Any ideas?
EDIT:
I tried performing a ternary check on the output, but for some reason, using a list is not supported so this won't work however I hope it illustrates what I am trying to do:
"${length(var.contexts) > 0 ? pagerduty_service_integration.*.integration_keys : list()}"
Solution:
output "instance_id" {
value = "${element(concat(aws_instance.example.*.id, list("")), 0)}"
}
There's a section at the very bottom of the terraform upgrade to 0.11 guide here: https://www.terraform.io/upgrade-guides/0-11.html that shows what I use for counted resources
ex:
output "instance_id" { value = "${element(concat(aws_instance.example.*.id, list("")), 0)}" }
(moved over from a comment)

Resources