DynamoDB and Implicit Dependencies
Overview
In this lab, we'll be doing the following:
- Deploy a DynamoDB database
- Understand Terraform's behavior when deploying resources in order
- Intentionally cause a dependency issue
- Visualize a Terraform configuration file
- Resolve the dependency issue
Pre-requisites
- Setup Keys and Permissions
- Setup your Local Environment and Install Extensions
- Configure the Credentials File
- Install Terraform
Config files
Create the core configuration files which we will populate in the succeeding steps.
touch main.tf
touch provider.tf
touch vars.tf
touch terraform.tfvars
Create the Provider file
provider.tf
### provider.tf
terraform {
required_version = ">= 0.12"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.16.0"
}
}
}
provider "aws" {
region = var.aws_region
shared_credentials_files = var.my_credentials
profile = var.my_profile
}
Create the Variable files
vars.tf
### vars.tf
# Variables for setting up terraform
variable "aws_region" {
description = "AWS region"
type = string
}
variable "my_credentials" {
description = "Credentials to be used to connect to AWS"
type = list(string)
}
variable "my_profile" {
description = "Profile to be used to connect to AWS"
type = string
}
terraform.tfvars
### terraform.tfvars
# Variables for setting up terraform
aws_region = "ap-southeast-1"
my_credentials = ["/mnt/c/Users/Eden.Jose/.aws/credentials"]
my_profile = "vscode-dev"
Create the Main file
main.tf
### main.tf
#----------------------------------------------------
resource "aws_dynamodb_table_item" "lab08-ddb-table-item" {
table_name = "lab08-ddb-table-item"
hash_key = "ddbHashKey"
item = <<ITEM
{
"ddbHashKey": {"S": "StartTheCountdown"},
"four": {"N": "44444"},
"three": {"N": "33333"},
"two": {"N": "22222"},
"one": {"N": "11111"}
}
ITEM
}
resource "aws_dynamodb_table" "lab08-ddb-table" {
name = "lab08-ddb-table"
hash_key = "ddbHashKey"
read_capacity = 10
write_capacity = 10
attribute {
name = "ddbHashKey"
type = "S"
}
}
Time to Apply!
But first, initialize the working directory.
terraform init
Verify if the config files are correctly formatted and syntactically valid.
terraform fmt
terraform validate
Next, do a dry-run of the changes before actually applying them.
terraform plan
If it doesn't return an error, run the changes.
terraform apply -auto-approve
Notice that when we try to provision the resources, it now returns a ResourceNotFoundException error message.
│ Error: ResourceNotFoundException: Requested resource not found
│
│ with aws_dynamodb_table_item.lab08-ddb-table-item,
│ on main.tf line 4, in resource "aws_dynamodb_table_item" "lab08-ddb-table-item":
│ 4: resource "aws_dynamodb_table_item" "lab08-ddb-table-item" {
Understanding the Error
Doing a quick Google search, we found what's causing the ResourceNotFoundException error:
From the docs it's either you don't have a Table with that name or it is in CREATING status.
I would double check to verify that the table does in fact exist, in the correct region, and you're using an access key that can reach it
This error actually means that the client cannot reach a table in your database. Here's a list of things to look into:
1. Your database is running
2. Your accessKey and secretKey are valid for the database
3. Your DB endpoint is valid and contains correct protocol ("http://" or "https://"), and correct hostname, and correct port
4. Your table was created in the database.
5. Your table was created in the database in the same region that you set as a parameter in credentials. Optional, because some
database environments (e.g. Testcontainers Dynalite) don't have an incorrect value for the region. And any nonempty region value will be correct
Visualize the Config file
To troubleshoot the issue, we can use the terraform graph command to visualize the configuration file. It will return a DOT-formatted "digraph" output which we can run through an online Graphviz tool. Copy the output.
terraform graph
digraph {
compound = "true"
newrank = "true"
subgraph "root" {
"[root] aws_dynamodb_table.lab08-ddb-table (expand)" [label = "aws_dynamodb_table.lab08-ddb-table", shape = "box"]
"[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)" [label = "aws_dynamodb_table_item.lab08-ddb-table-item", shape = "box"]
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" [label = "provider[\"registry.terraform.io/hashicorp/aws\"]", shape = "diamond"]
"[root] var.aws_region" [label = "var.aws_region", shape = "note"]
"[root] var.my_credentials" [label = "var.my_credentials", shape = "note"]
"[root] var.my_profile" [label = "var.my_profile", shape = "note"]
"[root] aws_dynamodb_table.lab08-ddb-table (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/aws\"]"
"[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/aws\"]"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"] (close)" -> "[root] aws_dynamodb_table.lab08-ddb-table (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"] (close)" -> "[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.aws_region"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.my_credentials"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.my_profile"
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/aws\"] (close)"
}
}
Open WebGraphviz in your web browser, paste the copied output to the field, and run Generate graph. From here we can see that table and table item are being deployed at the same time.

This is what's causing the error because the table has to exist first before the table item can be created.
Now that we know what the error means
Time to resolve the dependency issue. Under the aws_dynamodb_table_item resource block, we can see that it reference table_name and hash_key from the aws_dynamodb_table resource block.
We can use interpolation on these two fields to tell the table item to pull these two values from the aws_dynamodb_table resource, which means the first block must wait for the second block to finish.
table_name = aws_dynamodb_table.lab08-ddb-table.name
hash_key = aws_dynamodb_table.lab08-ddb-table.hash_key
Our new main.tf should now look like this.
main.tf
# lab08 - Deploy a DynamoDB and a table item.
#----------------------------------------------------
resource "aws_dynamodb_table_item" "lab08-ddb-table-item" {
table_name = aws_dynamodb_table.lab08-ddb-table.name
hash_key = aws_dynamodb_table.lab08-ddb-table.hash_key
item = <<ITEM
{
"ddbHashKey": {"S": "StartTheCountdown"},
"four": {"N": "44444"},
"three": {"N": "33333"},
"two": {"N": "22222"},
"one": {"N": "11111"}
}
ITEM
}
resource "aws_dynamodb_table" "lab08-ddb-table" {
name = "lab08-ddb-table"
hash_key = "ddbHashKey"
read_capacity = 10
write_capacity = 10
attribute {
name = "ddbHashKey"
type = "S"
}
}
Apply the changes again. It should now succeed.
terraform apply -auto-approve
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Let's run the graph command again and use the output in the online WebGraphviz
terraform graph
digraph {
compound = "true"
newrank = "true"
subgraph "root" {
"[root] aws_dynamodb_table.lab08-ddb-table (expand)" [label = "aws_dynamodb_table.lab08-ddb-table", shape = "box"]
"[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)" [label = "aws_dynamodb_table_item.lab08-ddb-table-item", shape = "box"]
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" [label = "provider[\"registry.terraform.io/hashicorp/aws\"]", shape = "diamond"]
"[root] var.aws_region" [label = "var.aws_region", shape = "note"]
"[root] var.my_credentials" [label = "var.my_credentials", shape = "note"]
"[root] var.my_profile" [label = "var.my_profile", shape = "note"]
"[root] aws_dynamodb_table.lab08-ddb-table (expand)" -> "[root] provider[\"registry.terraform.io/hashicorp/aws\"]"
"[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)" -> "[root] aws_dynamodb_table.lab08-ddb-table (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"] (close)" -> "[root] aws_dynamodb_table_item.lab08-ddb-table-item (expand)"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.aws_region"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.my_credentials"
"[root] provider[\"registry.terraform.io/hashicorp/aws\"]" -> "[root] var.my_profile"
"[root] root" -> "[root] provider[\"registry.terraform.io/hashicorp/aws\"] (close)"
}

The new graph should now display the flowchart which shows that implicit dependency is created between the table and table item.

Comparison of the code


Cleanup
To delete all the resources, just run the destroy command.
terraform destroy -auto-approve