Is it possible to update existing Dynamo DB table from Terraform - amazon-dynamodb

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
}

Related

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"
}
}
}

Amazon DynamoDBv2 QueryOperationConfig SelectValues.Count not working

I have this piece of code like this:
var options = new DynamoDBOperationConfig
{
ConditionalOperator = ConditionalOperatorValues.Or,
OverrideTableName = nameTable,
ConsistentRead = true
};
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count
};
result = context.FromQueryAsync<TEntity>(queryConfig, options).GetRemainingAsync().Result;
as per the documentation, it should return just the count of values that match the filter, at least, the piece of code in the SelectValues class says that
//
// Summary:
// An enumeration of all supported Select values for Query and Scan. Value of Count
// will force service to return the number of items, not the items themselves.
but result is always an empty list; how can i make the count work ?
If you are still looking for the answer, this is the solution:
new QueryOperationConfig()
{
IndexName = indexName,
Filter = queryFilter,
Select = SelectValues.Count,
ConsistentRead = true
};
var table = context.GetTargetTable<TEntity>();
var search = table.Query(queryConfig);
result = search.Count;
Having ConsistentRead set to true will cause it to give you real time updates when the table is updated.
It's not working on Document level...
You can try to do this in low level model.
int count = 0;
Dictionary<string, AttributeValue> lastKey = null;
do
{
var request = new QueryRequest
{
TableName = "tableNmae",
IndexName = "indexName",
KeyConditionExpression = "ID= :v_ID",
ExpressionAttributeValues = new Dictionary<string, AttributeValue>
{
{
":v_ID",
new AttributeValue
{
N = "1"
}
}
},
ConsistentRead = false,
Select = Select.COUNT,
ExclusiveStartKey = lastKey
};
var respone = await tableClient.QueryAsync(request);
count += respone.Count;
lastKey = respone.LastEvaluatedKey;
} while (lastKey != null && lastKey.Count != 0);

System.Data.SQLite transaction lock whole database

I'm trying to insert into 2 different tables from different transactions. Unfortunally I'm getting "database locked" exeption onto cn2.Execute...
var cb = new System.Data.SQLite.SQLiteConnectionStringBuilder
{
BinaryGUID = true,
DataSource = string.Format("file:SqliteTest-{0:N}.db", Guid.NewGuid()),
FailIfMissing = false,
JournalMode = System.Data.SQLite.SQLiteJournalModeEnum.Wal,
LegacyFormat = false,
Pooling = true,
SyncMode = System.Data.SQLite.SynchronizationModes.Normal,
DefaultIsolationLevel = System.Data.IsolationLevel.ReadCommitted
};
using (var cn1 = new System.Data.SQLite.SQLiteConnection(cb.ToString()))
{
cn1.Open();
cn1.Execute("create table t_1(uuid BLOB not null primary key, ts INTEGER not null);");
cn1.Execute("create table t_2(uuid BLOB not null primary key, ts INTEGER not null);");
using (var cn2 = (System.Data.SQLite.SQLiteConnection)cn1.Clone())
{
using (var tr1 = cn1.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
using (var tr2 = cn2.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
cn1.Execute("insert into t_1(uuid,ts) values(#uuid, #ts);",
new { uuid = Guid.NewGuid(), ts = DateTime.UtcNow.Ticks }, tr1);
cn2.Execute("insert into t_2(uuid,ts) values(#uuid, #ts);",
new { uuid = Guid.NewGuid(), ts = DateTime.UtcNow.Ticks }, tr2);
}
}
}

update entity after search

I want to update information in my graph entity named type[USERS] with properties:
but when update a particular entity after search, it was duplicated.
Thank you
let existElement = graph.searchForEntity(properties: [(key: "username", value: username),("id", id)])
if existElement.count == 1 {
existElement[0]["id"] = id
existElement[0]["username"] = username
existElement[0]["password"] = password
existElement[0]["nome"] = nome
existElement[0]["data_cerazione"] = NSDate()
// salviamoIlDatabase
graph.async() { (success: Bool, error: NSError?) in
if let e = error { // se c'รจ un errore...
print(e.localizedDescription) // lo stampiamo in console
}
}
}

Resources