Skip to content

Commit 5a5eac8

Browse files
author
John Titus
authored
Merge pull request #6 from rackspace-infrastructure-automation/indexes
Add additional indexes, tags, streams, update docs, tests, examples
2 parents 8711b2f + bf415d3 commit 5a5eac8

File tree

6 files changed

+321
-36
lines changed

6 files changed

+321
-36
lines changed

README.md

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,76 @@
1+
# aws-terraform-dynamo
2+
3+
This module creates an AWS DynamoDB table.
4+
5+
## Basic Usage
6+
7+
```HCL
8+
module "basic" {
9+
source = "git@github.com:rackspace-infrastructure-automation/aws-terraform-dynamo/?ref=v0.0.3"
10+
11+
attributes = [
12+
{
13+
name = "TestHashKey"
14+
type = "S"
15+
},
16+
]
17+
18+
environment = "Test"
19+
hash_key = "MyHashKey"
20+
read_capacity_units = 10
21+
table_name = "myexampletable"
22+
tags = "${local.tags}"
23+
write_capacity_units = 5
24+
}
25+
```
26+
27+
## Known Bugs
28+
29+
When using the index maps for GSI's and LSI's there is a bug in the Terraform AWS provider which stores the order of `non_key_attributes` in the state file in an order that may not match what you pass in.
30+
31+
If a subsequent plan shows changes for your indexes look for lines similar to the below in the output:
32+
33+
```
34+
global_secondary_index.1708383685.non_key_attributes.0: "data2" => ""
35+
global_secondary_index.1708383685.non_key_attributes.1: "data1" => ""
36+
global_secondary_index.1708383685.non_key_attributes.2: "data3" => ""
37+
```
38+
39+
The input data was `["data1", "data2", "data3"]` and we can see that attributes 0, 1, and 2 do not follow this same order.
40+
41+
The resolution at the moment is to edit the list in your map to match the order in the state file. This should result in a clean plan when no other changes are present.
42+
43+
**References:**
44+
45+
[global secondary index always recreated #3828](https://github.com/terraform-providers/terraform-provider-aws/issues/3828)
46+
47+
[DynamoDB Non-Key Attributes Ordering #3807](https://github.com/terraform-providers/terraform-provider-aws/issues/3807)
48+
149
## Inputs
250

351
| Name | Description | Type | Default | Required |
452
|------|-------------|:----:|:-----:|:-----:|
5-
| attributes | List of nested attribute definitions. Only required for hash_key (always) and range_key (if used) attributes. Attributes have name and type. Type must be a scalar type: S, N, or B for (S)tring, (N)umber or (B)inary data. i.e. [{ name=<hash_key> type=<data_type>}] | list | n/a | yes |
53+
| attributes | List of nested attribute definitions. Only required for hash_key's (always) and range_key's (if used) attributes. Attributes have name and type. Type must be a scalar type: S, N, or B for (S)tring, (N)umber or (B)inary data. i.e. [{ name=<hash_key> type=<data_type>}]. Terraform documentation: [A note about attributes](https://www.terraform.io/docs/providers/aws/r/dynamodb_table.html#a-note-about-attributes) | list | n/a | yes |
654
| enable\_pay\_per\_request | Controls how you are charged for read and write throughput and how you manage capacity. If True, DynamoDB charges you for the data reads and writes your application performs on your tables. You do not need to specify how much read and write throughput you expect your application to perform because DynamoDB instantly accommodates your workloads as they ramp up or down. [On-Demand Pricing](https://aws.amazon.com/dynamodb/pricing/on-demand/) If False, you specify the number of `read_capacity_units` and `write_capacity_units` per second that you expect your workload to require. [Provisioned Pricing](https://aws.amazon.com/dynamodb/pricing/provisioned/) | string | `"false"` | no |
7-
| hash\_key | ** Forces new resource ** Must contain only alphanumberic characters, dash (-), underscore (_) or dot (.). Needs to be defined by type in attributes. | string | n/a | yes |
55+
| environment | Application environment for which this resource is being created. Preferred values are Development, Integration, PreProduction, Production, QA, Staging, or Test. | string | `"Development"` | no |
56+
| global\_secondary\_index\_maps | A list of maps for each [global secondary index (GSI)](https://www.terraform.io/docs/providers/aws/r/dynamodb_table.html#global_secondary_index-1). Please see [examples](./examples) for usage. | list | `<list>` | no |
57+
| hash\_key | **Forces new resource!** Must contain only alphanumberic characters, dash (-), underscore (_) or dot (.). Needs to be defined by type in attributes. | string | n/a | yes |
58+
| local\_secondary\_index\_maps | A list of maps for each [local secondary index (LSI)](https://www.terraform.io/docs/providers/aws/r/dynamodb_table.html#local_secondary_index-1). Please see [examples](./examples) for usage. | list | `<list>` | no |
859
| point\_in\_time\_recovery | Enable point in time recovery for the table. | string | `"false"` | no |
9-
| range\_key | ** Forces new resource ** RangeType PrimaryKey Name. If used, it will need to be defined by type in attributes | string | `""` | no |
60+
| range\_key | **Forces new resource!** RangeType PrimaryKey Name. If used, it will need to be defined by type in attributes | string | `""` | no |
1061
| read\_capacity\_units | Provisioned read throughput. Should be between 5 and 10000. Ignored if `enable_pay_per_request` is set to `true`. | string | `"5"` | no |
11-
| table\_encryption | Server side table encryption at rest. i.e. true | false | string | `"true"` | no |
62+
| stream\_enabled | Enable the stream setting on the table. | string | `"false"` | no |
63+
| stream\_view\_type | If using `stream_enabled, you can specify a valid DynamoDB StreamViewType; must be one of: `KEYS_ONLY`, `NEW_IMAGE`. `OLD_IMAGE`, `NEW_AND_OLD_IMAGES` | string | `""` | no |
64+
| table\_encryption\_cmk | You may choose to use an [AWS Managed CMK](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-managed-cmk) by setting this to `true`. Otherwise, server side table encryption defaults to an [AWS Owned CMK](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#aws-owned-cmk). | string | `"false"` | no |
1265
| table\_name | The name of the table, this needs to be unique within a region. | string | n/a | yes |
66+
| tags | Custom tags to apply to all resources. | map | `<map>` | no |
1367
| write\_capacity\_units | Provisioned write throughput. Should be between 5 and 10000. Ignored if `enable_pay_per_request` is set to `true`. | string | `"10"` | no |
1468

1569
## Outputs
1670

1771
| Name | Description |
1872
|------|-------------|
73+
| stream\_arn | ARN for the stream if `stream_enabled` was set to `true`, otherwise returns a string of "null". |
1974
| table\_arn | Table ARN |
2075
| table\_name | Table Name |
2176

examples/example.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ provider "aws" {
44
}
55

66
module "dynamo_table_provisioned" {
7-
source = "git@github.com/rackspace-infrastructure-automation/aws-terraform-dynamo//?ref=v0.0.2"
7+
source = "git@github.com/rackspace-infrastructure-automation/aws-terraform-dynamo//?ref=v0.0.3"
88

99
table_name = "<TableName>"
1010
hash_key = "<HashKeyName>"
@@ -30,7 +30,7 @@ module "dynamo_table_provisioned" {
3030
}
3131

3232
module "dynamo_table_pay_per_requst" {
33-
source = "git@github.com/rackspace-infrastructure-automation/aws-terraform-dynamo//?ref=v0.0.2"
33+
source = "git@github.com/rackspace-infrastructure-automation/aws-terraform-dynamo//?ref=v0.0.3"
3434

3535
table_name = "<TableName>"
3636
hash_key = "<HashKeyName>"

main.tf

Lines changed: 78 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,85 @@
1-
resource "aws_dynamodb_table" "basic-dynamodb-table" {
2-
name = "${var.table_name}"
3-
billing_mode = "${var.enable_pay_per_request ? "PAY_PER_REQUEST":"PROVISIONED"}"
4-
read_capacity = "${var.read_capacity_units}"
5-
write_capacity = "${var.write_capacity_units}"
6-
hash_key = "${var.hash_key}"
7-
range_key = "${var.range_key}"
8-
9-
attribute = "${var.attributes}"
1+
/**
2+
* # aws-terraform-dynamo
3+
*
4+
* This module creates an AWS DynamoDB table.
5+
*
6+
* ## Basic Usage
7+
*
8+
* ```HCL
9+
* module "basic" {
10+
* source = "git@github.com:rackspace-infrastructure-automation/aws-terraform-dynamo/?ref=v0.0.3"
11+
*
12+
* attributes = [
13+
* {
14+
* name = "TestHashKey"
15+
* type = "S"
16+
* },
17+
* ]
18+
*
19+
* environment = "Test"
20+
* hash_key = "MyHashKey"
21+
* read_capacity_units = 10
22+
* table_name = "myexampletable"
23+
* tags = "${local.tags}"
24+
* write_capacity_units = 5
25+
* }
26+
* ```
27+
*
28+
* ## Known Bugs
29+
*
30+
* When using the index maps for GSI's and LSI's there is a bug in the Terraform AWS provider which stores the order of `non_key_attributes` in the state file in an order that may not match what you pass in.
31+
*
32+
* If a subsequent plan shows changes for your indexes look for lines similar to the below in the output:
33+
*
34+
* ```
35+
* global_secondary_index.1708383685.non_key_attributes.0: "data2" => ""
36+
* global_secondary_index.1708383685.non_key_attributes.1: "data1" => ""
37+
* global_secondary_index.1708383685.non_key_attributes.2: "data3" => ""
38+
* ```
39+
*
40+
* The input data was `["data1", "data2", "data3"]` and we can see that attributes 0, 1, and 2 do not follow this same order.
41+
*
42+
* The resolution at the moment is to edit the list in your map to match the order in the state file. This should result in a clean plan when no other changes are present.
43+
*
44+
* **References:**
45+
*
46+
* [global secondary index always recreated #3828](https://github.com/terraform-providers/terraform-provider-aws/issues/3828)
47+
*
48+
* [DynamoDB Non-Key Attributes Ordering #3807](https://github.com/terraform-providers/terraform-provider-aws/issues/3807)
49+
*/
1050

11-
server_side_encryption {
12-
enabled = "${var.table_encryption}"
51+
locals {
52+
tags {
53+
Environment = "${var.environment}"
54+
Name = "${var.table_name}"
55+
ServiceProvider = "Rackspace"
1356
}
57+
}
58+
59+
resource "aws_dynamodb_table" "basic-dynamodb-table" {
60+
billing_mode = "${var.enable_pay_per_request ? "PAY_PER_REQUEST" : "PROVISIONED" }"
61+
hash_key = "${var.hash_key}"
62+
name = "${var.table_name}"
63+
range_key = "${var.range_key}"
64+
read_capacity = "${var.read_capacity_units}"
65+
stream_enabled = "${var.stream_enabled}"
66+
stream_view_type = "${var.stream_enabled ? var.stream_view_type : "" }"
67+
write_capacity = "${var.write_capacity_units}"
68+
69+
attribute = "${var.attributes}"
70+
global_secondary_index = "${var.global_secondary_index_maps}"
71+
local_secondary_index = "${var.local_secondary_index_maps}"
1472

1573
point_in_time_recovery {
1674
enabled = "${var.point_in_time_recovery}"
1775
}
76+
77+
server_side_encryption {
78+
enabled = "${var.table_encryption_cmk}"
79+
}
80+
81+
tags = "${merge(
82+
local.tags,
83+
var.tags
84+
)}"
1885
}

outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
output "stream_arn" {
2+
description = "ARN for the stream if `stream_enabled` was set to `true`, otherwise returns a string of \"null\"."
3+
value = "${var.stream_enabled == "true" ? aws_dynamodb_table.basic-dynamodb-table.stream_arn : "null" }"
4+
}
5+
16
output "table_arn" {
27
description = "Table ARN"
38
value = "${aws_dynamodb_table.basic-dynamodb-table.arn}"

tests/default/main.tf

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,145 @@ provider "aws" {
33
region = "us-west-2"
44
}
55

6+
locals {
7+
tags = {
8+
Terraform = "true"
9+
}
10+
}
11+
612
resource "random_string" "rstring" {
713
length = 8
814
upper = false
915
special = false
1016
}
1117

1218
module "dynamo" {
13-
source = "../../module"
14-
table_name = "${random_string.rstring.result}-testTable"
19+
source = "../../module"
20+
21+
attributes = [
22+
{
23+
name = "TestHashKey"
24+
type = "S"
25+
},
26+
]
27+
1528
hash_key = "TestHashKey"
1629
read_capacity_units = 6
30+
table_name = "${random_string.rstring.result}-testTable"
31+
tags = "${local.tags}"
1732
write_capacity_units = 11
33+
}
34+
35+
module "advanced" {
36+
source = "../../module"
1837

1938
attributes = [
2039
{
2140
name = "TestHashKey"
2241
type = "S"
2342
},
43+
{
44+
name = "TestRangeKey"
45+
type = "S"
46+
},
2447
]
48+
49+
environment = "Test"
50+
hash_key = "TestHashKey"
51+
point_in_time_recovery = true
52+
range_key = "TestRangeKey"
53+
read_capacity_units = 20
54+
table_encryption_cmk = true
55+
table_name = "${random_string.rstring.result}-advanced"
56+
tags = "${local.tags}"
57+
write_capacity_units = 5
58+
}
59+
60+
module "complex" {
61+
source = "../../module"
62+
63+
attributes = [
64+
{
65+
name = "TestHashKey"
66+
type = "S"
67+
},
68+
{
69+
name = "TestRangeKey"
70+
type = "S"
71+
},
72+
{
73+
name = "GsiHashKey01"
74+
type = "S"
75+
},
76+
{
77+
name = "GsiHashKey02"
78+
type = "S"
79+
},
80+
{
81+
name = "GsiRangeKey01"
82+
type = "S"
83+
},
84+
{
85+
name = "GsiRangeKey02"
86+
type = "S"
87+
},
88+
]
89+
90+
environment = "Test"
91+
92+
global_secondary_index_maps = [
93+
{
94+
name = "TestGSIProject"
95+
write_capacity = "5"
96+
read_capacity = "10"
97+
hash_key = "GsiHashKey01"
98+
range_key = "GsiRangeKey01"
99+
projection_type = "ALL"
100+
},
101+
{
102+
name = "TestGSIInclude"
103+
write_capacity = "5"
104+
read_capacity = "10"
105+
hash_key = "GsiHashKey02"
106+
range_key = "GsiRangeKey02"
107+
projection_type = "INCLUDE"
108+
109+
non_key_attributes = [
110+
"data2",
111+
"data1",
112+
"data3",
113+
]
114+
},
115+
]
116+
117+
hash_key = "TestHashKey"
118+
119+
local_secondary_index_maps = [
120+
{
121+
name = "TestLSIProjectAll"
122+
range_key = "TestRangeKey"
123+
projection_type = "ALL"
124+
},
125+
{
126+
name = "TestLSIInclude"
127+
range_key = "TestRangeKey"
128+
projection_type = "INCLUDE"
129+
130+
non_key_attributes = [
131+
"data1",
132+
"data2",
133+
"data3",
134+
]
135+
},
136+
]
137+
138+
point_in_time_recovery = true
139+
range_key = "TestRangeKey"
140+
read_capacity_units = 20
141+
stream_enabled = true
142+
stream_view_type = "NEW_AND_OLD_IMAGES"
143+
table_encryption_cmk = true
144+
table_name = "${random_string.rstring.result}-complex"
145+
tags = "${local.tags}"
146+
write_capacity_units = 5
25147
}

0 commit comments

Comments
 (0)