Terraform RDS Option group options are keeps re-applying the same changes with dynamic block - terraform-provider-aws

I have a Terraform RDS Code, i am Using Dynamic Blocks with For each, when i do terraform plan the option group options are re-applying each time. Can some one please help me? i think it is a Bug,
Can someone please help me?
main.tf
resource "aws_db_option_group" "without_s3_integration" {
#count = "${var.enable_s3_integration == false ? 1 : 0}"
name = lower("${var.db_name}-${formatdate("YYYY-MM-DD-hhmm", timestamp())}-og")
option_group_description = format("Option group for %s", var.db_name)
engine_name = var.engine_name
major_engine_version = var.major_engine_version
option {
option_name = "Timezone"
option_settings {
name = "TIME_ZONE"
value = "US/Eastern"
}
}
dynamic "option" {
#for_each = var.option_group_add_sqlt == false ? [] : [var.option_group_add_sqlt]
for_each = range(var.option_group_add_sqlt == true ? 1 : 0)
content {
option_name = "SQLT"
option_settings {
name = "LICENSE_PACK"
value = "T"
}
}
}
variable.tf
variable "option_group_add_sqlt"{
description = "Add SQLT to option group"
type = bool
default = true
}
variable "option_group_add_utlmail"{
description = "Add utlmail to option group"
type = bool
default = true
}
variable "option_group_add_oem"{
description = "Add oem to option group"
type = bool
default = false
}
variable "enable_s3_integration"{
description = "Indicates if S3 integration should be turned on or not"
type = bool
default = true
}
terraform plan
# aws_db_option_group.without_s3_integration will be updated in-place
~ resource "aws_db_option_group" "without_s3_integration" {
id = "rajtest4-2021-05-13-1621-og"
name = "rajtest4-2021-05-13-1621-og"
tags = {
"Author" = "Effectual Terraform script"
"Date" = "2021-05-13T16:21:54Z"
}
# (4 unchanged attributes hidden)
- option {
- db_security_group_memberships = [] -> null
- option_name = "S3_INTEGRATION" -> null
- port = 0 -> null
- version = "1.0" -> null
- vpc_security_group_memberships = [] -> null
}
+ option {
+ db_security_group_memberships = []
+ option_name = "S3_INTEGRATION"
+ version = "1.0"
+ vpc_security_group_memberships = []
}
- option {
- db_security_group_memberships = [] -> null
- option_name = "SQLT" -> null
- port = 0 -> null
- version = "2018-07-25.v1" -> null
- vpc_security_group_memberships = [] -> null
- option_settings {
- name = "LICENSE_PACK" -> null
- value = "T" -> null
}
}
+ option {
+ db_security_group_memberships = []
+ option_name = "SQLT"
+ vpc_security_group_memberships = []
+ option_settings {
+ name = "LICENSE_PACK"
+ value = "T"
}
}
- option {
- db_security_group_memberships = [] -> null
- option_name = "Timezone" -> null
- port = 0 -> null
- vpc_security_group_memberships = [] -> null
- option_settings {
- name = "TIME_ZONE" -> null
- value = "US/Eastern" -> null
}
}
+ option {
+ db_security_group_memberships = []
+ option_name = "Timezone"
+ vpc_security_group_memberships = []
+ option_settings {
+ name = "TIME_ZONE"
+ value = "US/Eastern"
}
}
+ option {
+ db_security_group_memberships = []
+ option_name = "UTL_MAIL"
+ vpc_security_group_memberships = []
}
}
Plan: 0 to add, 2 to change, 0 to destroy.
i am not sure why it is deleting adding the options. When i do terraform plan after terraform apply. it should not do any changes rite since i did not add anything extra, why terraform is always adding the resources and deleting it? is there any way to prevent happening like this?

I had this issue today. Analyzing the plan, I can check that the only change was in the version field of the S3_INTEGRATION option
So, I update my code from this:
option {
option_name = "S3_INTEGRATION"
}
To this
option {
option_name = "S3_INTEGRATION"
version = "1.0"
}

Related

Is it possible to update existing Dynamo DB table from Terraform

I am trying to create a terraform module with the help of which I can make an entry to existing Dynamo DB table.
I have got this code which create dynamo DB table
resource "aws_dynamodb_table" "basic-dynamodb-table" {
name = "GameScores"
billing_mode = "PROVISIONED"
read_capacity = 20
write_capacity = 20
hash_key = "UserId"
range_key = "GameTitle"
attribute {
name = "UserId"
type = "S"
}
attribute {
name = "GameTitle"
type = "S"
}
attribute {
name = "TopScore"
type = "N"
}
ttl {
attribute_name = "TimeToExist"
enabled = false
}
global_secondary_index {
name = "GameTitleIndex"
hash_key = "GameTitle"
range_key = "TopScore"
write_capacity = 10
read_capacity = 10
projection_type = "INCLUDE"
non_key_attributes = ["UserId"]
}
tags = {
Name = "dynamodb-table-1"
Environment = "production"
}
}
Is there any way I can make changes in existing dynamo db table.
For adding entries to a table you can take a look at the aws_dynamodb_table_item resource. Here is an example that you can use to add an entry to your table:
resource "aws_dynamodb_table_item" "item1" {
table_name = aws_dynamodb_table.basic-dynamodb-table.name
hash_key = aws_dynamodb_table.basic-dynamodb-table.hash_key
range_key = aws_dynamodb_table.basic-dynamodb-table.range_key
item = <<ITEM
{
"UserId": {"S": "user"},
"GameTitle": {"S": "gamex"},
"TopScore": {"N": "42"}
}
ITEM
}

terraform nested dynamic block with nested map

I'm trying to get tf 0.12.x new dynamic feature to work with a nested map, config is below.
As you can see below (simplified for this) I'm defining all the variables and adding variable required_resource_access which contains a map.
I was hoping to use new dynamic feature to create read this map in a nested dyanmic block.
variable prefix {
description = "Prefix to applied to all top level resources"
default = "abx"
}
variable suffix {
description = "Suffix to applied to all valid top level resources, usually this is 2 letter region code such as we (westeurope), ne (northeurope)."
default = "we"
}
variable env {
description = "3 letter environment code appied to all top level resources"
default = "dev"
}
variable location {
description = "Where to create all resources in Azure"
default = "westeurope"
}
variable available_to_other_tenants {
default = false
}
variable oauth2_allow_implicit_flow {
default = true
}
variable public_client {
default = false
}
# other option is native
variable application_type {
default = "webapp/api"
}
variable required_resource_access {
type = list(object({
resource_app_id = string
resource_access = object({
id = string
type = string
})
}))
default = [{
resource_app_id = "00000003-0000-0000-c000-000000000000"
resource_access = {
id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
type = "Role"
}
}]
}
variable reply_urls {
default = []
}
variable group_membership_claims {
default = "All"
}
resource "azuread_application" "bootstrap" {
name = "${var.prefix}-${var.env}-spn"
homepage = "http://${var.prefix}-${var.env}-spn"
identifier_uris = ["http://${var.prefix}-${var.env}-spn"]
reply_urls = var.reply_urls
available_to_other_tenants = var.available_to_other_tenants
oauth2_allow_implicit_flow = var.oauth2_allow_implicit_flow
type = var.application_type
group_membership_claims = var.group_membership_claims
dynamic "required_resource_access" {
for_each = var.required_resource_access
content {
resource_app_id = required_resource_access.value["resource_app_id"]
dynamic "resource_access" {
for_each = required_resource_access.value["resource_access"]
content {
id = resource_access.value["id"]
type = resource_access.value["type"]
}
}
}
}
}
But for reasons beyond my knowledge it keeps giving me this error (notice it's priting it twice as well), I've tried a few other options but this is the closest I managed to get where it would at least give me a meaningful error.
------------------------------------------------------------------------
Error: Invalid index
on pe_kubernetes.tf line 24, in resource "azuread_application" "bootstrap":
24: id = resource_access.value["id"]
|----------------
| resource_access.value is "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
This value does not have any indices.
Error: Invalid index
on pe_kubernetes.tf line 24, in resource "azuread_application" "bootstrap":
24: id = resource_access.value["id"]
|----------------
| resource_access.value is "Role"
This value does not have any indices.
Error: Invalid index
on pe_kubernetes.tf line 25, in resource "azuread_application" "bootstrap":
25: type = resource_access.value["type"]
|----------------
| resource_access.value is "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
This value does not have any indices.
Error: Invalid index
on pe_kubernetes.tf line 25, in resource "azuread_application" "bootstrap":
25: type = resource_access.value["type"]
|----------------
| resource_access.value is "Role"
This value does not have any indices.
Spent the best part of 2 days on this with no luck so any help or pointers would be much appreciated!
I had some time to test my comment...
If I change the resource_access to a list it works.
See code below:
variable required_resource_access {
type = list(object({
resource_app_id = string
resource_access = list(object({
id = string
type = string
}))
}))
default = [{
resource_app_id = "00000003-0000-0000-c000-000000000000"
resource_access = [{
id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
type = "Role"
}]
}]
}
resource "azuread_application" "bootstrap" {
name = "test"
type = "webapp/api"
group_membership_claims = "All"
dynamic "required_resource_access" {
for_each = var.required_resource_access
content {
resource_app_id = required_resource_access.value["resource_app_id"]
dynamic "resource_access" {
for_each = required_resource_access.value["resource_access"]
content {
id = resource_access.value["id"]
type = resource_access.value["type"]
}
}
}
}
}
And the plan shows:
Terraform will perform the following actions:
# azuread_application.bootstrap will be created
+ resource "azuread_application" "bootstrap" {
+ application_id = (known after apply)
+ available_to_other_tenants = false
+ group_membership_claims = "All"
+ homepage = (known after apply)
+ id = (known after apply)
+ identifier_uris = (known after apply)
+ name = "test"
+ oauth2_allow_implicit_flow = true
+ object_id = (known after apply)
+ owners = (known after apply)
+ public_client = (known after apply)
+ reply_urls = (known after apply)
+ type = "webapp/api"
+ oauth2_permissions {
+ admin_consent_description = (known after apply)
...
}
+ required_resource_access {
+ resource_app_id = "00000003-0000-0000-c000-000000000000"
+ resource_access {
+ id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61"
+ type = "Role"
}
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
I removed a lot of your variables an some of the optional Arguments for azuread_application to keep the code as small as possible, but the same principle applies to your code, use lists on for_each or it will loop on the object properties.

Dynamically importing secondary indexes in terraform for dynamodb

I'm trying to import a couple of dynamodb tables to terraform. I'm stuck on how to dynamically handle global secondary indexes between environments.
I have a module and two state files for each environment.
How can i dynamically enter these variables using count , that change between environments,
For example in the below example there are 4 indexes but for a particular index in prod account the read capacity and write capacity changes, whereas all other variables remain constant.
ie last-index has different read and write capacity values for both prod and nonprod
How can it be implemented in terraform?
Module:
locals {
name = ["xxx-index","xxx-index","xxx-index","xxx-index","last-index"]
write_capacity = [ 5,5,5,5,5]
read_capacity = [ 5,5,5,5,5]
range_key = ["xxx","xxx","xxx","xxx","xxx"]
}
global_secondary_index {
count = "${length(local.name)}"
name = "${element(local.name, count.index)}"
write_capacity = "${element(local.write_capacity, count.index)"
read_capacity = "${element(local.read_capacity, count.index)"
hash_key = "userId"
range_key = "${element(local.range_key,count.index)}"
projection_type = "ALL"
}
Terraform -version Terraform v0.11.13
+ provider.aws v2.25.0
There is no reasonable answer to this question for Terraform 0.11. It lacks the primitives required to describe the transform you are looking for, and it doesn't support dynamically generating nested blocks.
The closest supported thing in Terraform 0.11 would be to fix the number of indices as constant but still vary the individual parts, like this:
resource "aws_dynamodb_table" "example" {
# ...
global_secondary_index {
name = "${local.name[0]}"
write_capacity = "${local.write_capacity[0]}"
read_capacity = "${local.read_capacity[0]}"
range_key = "${local.range_key[0]}"
hash_key = "userId"
projection_type = "ALL"
}
global_secondary_index {
name = "${local.name[1]}"
write_capacity = "${local.write_capacity[1]}"
read_capacity = "${local.read_capacity[1]}"
range_key = "${local.range_key[1]}"
hash_key = "userId"
projection_type = "ALL"
}
global_secondary_index {
name = "${local.name[2]}"
write_capacity = "${local.write_capacity[2]}"
read_capacity = "${local.read_capacity[2]}"
range_key = "${local.range_key[2]}"
hash_key = "userId"
projection_type = "ALL"
}
global_secondary_index {
name = "${local.name[3]}"
write_capacity = "${local.write_capacity[3]}"
read_capacity = "${local.read_capacity[3]}"
range_key = "${local.range_key[3]}"
hash_key = "userId"
projection_type = "ALL"
}
global_secondary_index {
name = "${local.name[4]}"
write_capacity = "${local.write_capacity[4]}"
read_capacity = "${local.read_capacity[4]}"
range_key = "${local.range_key[4]}"
hash_key = "userId"
projection_type = "ALL"
}
}
The new Terraform 0.12 feature that was added to deal with this use-case is dynamic blocks, which allow producing zero or more blocks of a particular type based on a collection value.
For example:
locals {
indices = {
"xxx-index" = {
write_capacity = 5
read_capacity = 5
range_key = "xxx"
},
"last-index" = {
write_capacity = 5
read_capacity = 5
range_key = "xxx"
},
}
}
resource "aws_dynamodb_table" "example" {
# ...
dynamic "global_secondary_index" {
for_each = local.indices
content {
name = global_secondary_index.key
write_capacity = global_secondary_index.value.write_capacity
read_capacity = global_secondary_index.value.read_capacity
range_key = global_secondary_index.value.range_key
hash_key = "userId"
projection_type = "ALL"
}
}
}

Why are instance being already created being deleted and recreated?

I have created the resources with Terraform 0.12.6. However, without making any changes to the code and doing "terraform apply" the process wants to destroy the existing EC2 and rebuild them. I would like to know why it is doing so and what is incorrect below.
resource "aws_instance" "web_ui" {
count = 2
ami = data.aws_ami.ami.id
instance_type = var.type_m5lg
associate_public_ip_address = false
key_name = var.key_name
security_groups = [var.vpc_security_group_ids, var.sg_devops, var.sg_common]
subnet_id = (data.aws_subnet.subnetid)[count.index].id
root_block_device {
delete_on_termination = true
}
ebs_block_device {
device_name = "/dev/sdb"
volume_size = "200"
volume_type = "gp2"
delete_on_termination = true
}
tags = "${merge(
local.common_tags,
map(
"Name", "${var.name}-${var.prog}-${var.env}${count.index + 1}-${var.ec2_name_web}-use1.xyz.com"
)
)}"
}
Changing the
security_groups = [var.vpc_security_group_ids, var.sg_devops, var.sg_common]
TO
vpc_security_group_ids = [var.vpc_security_group_ids, var.sg_devops, var.sg_common]
fixed the issue.
Based on the comment from #stack72 hashicorp/terraform#7853

Range of all linkAttributed String in MutableAttributedString in swift

I have a mutableAttributedString in which few strings are linkAttributed,I want to find the Range of all link attributed string. How to do that in swift3 ?
When user start type # in textview i show list of few name. If user select any row then following method gets called.
func didSelectMemberId(_ model: BaseModel) {
var fullName = ""
if model.entityType == ReceiverType.Active.rawValue{
fullName = model.name
}else{
fullName = AtMention + model.name + " " + model.name2
}
let attributedString = NSMutableAttributedString(string:fullName, attributes:[NSFontAttributeName:(appNeedsAutoResize ? (UIUtils.getFontForApproprieteField(.headlineWithoutBold).font) : UIFont.systemFont(ofSize: 14))])
attributedString.addAttribute(NSLinkAttributeName, value: "connectmention://\(model.entityId.stringValue())", range: NSRange(location: 0, length: fullName.length))
attributedString.append(NSAttributedString(string: emptySpaceStringByUC, attributes:[NSFontAttributeName:(appNeedsAutoResize ? (UIUtils.getFontForApproprieteField(.headlineWithoutBold).font) : UIFont.systemFont(ofSize: 14))]))
self.composeBar.textView.textStorage.insert(attributedString, at:self.composeBar.textView.selectedRange.location)
}
self.composeBar.textView.selectedRange = NSMakeRange(self.composeBar.textView.selectedRange.location+fullName.length, 0 )
To get the link proprty I am using the following method
func getlinkActionRange(attributeString: NSAttributedString) -> [MentionStruct] {
var arrMentions = [MentionStruct]()
_ = attributeString.enumerateAttribute(NSLinkAttributeName, in: NSRange.init(location: 0, length: attributeString.length), options: [], using: { (value, range, stop) in
if let url = value {
let occurrence = (attributeString.string as NSString).substring(with:range)
arrMentions.append(MentionStruct(link: url as! String, text: occurrence, range: range))
}
})
return arrMentions
}
If user type anything after inserting that name , that type string also coming.

Resources