IaC
TIP
Одна из главных особенностей - это использование единой JSON-схемы
не только для генерации кода, но и для описания схемы таблицы в DynamoDB
используя IaC инструменты.
WARNING
Ниже представлены варианты как можно работать с JSON-схемой и IaC-инструментами.
Это лишь несколько вариантов, а конкретная реализация может иметь совершенно другие способы и структуры в зависимости от конкретных нужд и соглашений внутри ваших проектов.
GoDyno никак не регламентирует использование IaC инструментов.
🌍 Terraform
Пример модуля для описания DynamoDB таблицы
bash
project/
├── main.tf
└── modules/
└── dynamodb/
├── dynamo.tf
├── variables.tf
└── outputs.tf
hcl
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# --- >
module "schema_table" {
source = "./modules/dynamodb"
schema = jsondecode(file("${path.module}/schema.json"))
}
# --- >
output "table_name" {
value = module.schema_table.table_name
}
output "table_arn" {
value = module.schema_table.table_arn
}
hcl
locals {
key_attributes = var.schema.attributes
gsi_indexes = [
for idx in var.schema.secondary_indexes : idx
if try(idx.type, "GSI") == "GSI"
]
lsi_indexes = [
for idx in var.schema.secondary_indexes : idx
if try(idx.type, "LSI") == "LSI"
]
}
# --- >
resource "aws_dynamodb_table" "this" {
name = var.schema.table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = var.schema.hash_key
range_key = var.schema.range_key
dynamic "attribute" {
for_each = local.key_attributes
content {
name = attribute.value.name
type = attribute.value.type
}
}
dynamic "global_secondary_index" {
for_each = local.gsi_indexes
content {
name = global_secondary_index.value.name
hash_key = global_secondary_index.value.hash_key
range_key = try(global_secondary_index.value.range_key, null)
projection_type = global_secondary_index.value.projection_type
non_key_attributes = global_secondary_index.value.projection_type == "INCLUDE" ? global_secondary_index.value.non_key_attributes : null
}
}
dynamic "local_secondary_index" {
for_each = local.lsi_indexes
content {
name = local_secondary_index.value.name
range_key = local_secondary_index.value.range_key
projection_type = local_secondary_index.value.projection_type
non_key_attributes = local_secondary_index.value.projection_type == "INCLUDE" ? local_secondary_index.value.non_key_attributes : null
}
}
tags = {
Name = var.schema.table_name
ManagedBy = "go-dyno"
}
}
hcl
variable "schema" {
type = object({
table_name = string
hash_key = string
range_key = optional(string)
attributes = list(object({
name = string
type = string
}))
common_attributes = optional(list(object({
name = string
type = string
})), [])
secondary_indexes = optional(list(object({
name = string
type = optional(string, "GSI")
hash_key = optional(string)
range_key = optional(string)
projection_type = string
non_key_attributes = optional(list(string), [])
read_capacity = optional(number)
write_capacity = optional(number)
})), [])
})
description = "DynamoDB table schema from go-dyno JSON"
}
hcl
output "table_name" {
description = "Name of the DynamoDB table"
value = aws_dynamodb_table.this.name
}
output "table_arn" {
description = "ARN of the DynamoDB table"
value = aws_dynamodb_table.this.arn
}
output "table_id" {
description = "ID of the DynamoDB table"
value = aws_dynamodb_table.this.id
}
output "hash_key" {
description = "Hash key of the table"
value = aws_dynamodb_table.this.hash_key
}
output "range_key" {
description = "Range key of the table"
value = aws_dynamodb_table.this.range_key
}
Применение
bash
terraform init && terraform apply
Пример в один файл
variable "schema" {
type = object({
table_name = string
hash_key = string
range_key = optional(string)
attributes = list(object({
name = string
type = string
}))
secondary_indexes = optional(list(object({
name = string
type = optional(string, "GSI")
hash_key = optional(string)
range_key = optional(string)
projection_type = string
non_key_attributes = optional(list(string))
read_capacity = optional(number)
write_capacity = optional(number)
})))
})
}
locals {
gsi_indexes = [
for idx in coalesce(var.schema.secondary_indexes, []) : idx
if lookup(idx, "type", "GSI") == "GSI"
]
lsi_indexes = [
for idx in coalesce(var.schema.secondary_indexes, []) : idx
if lookup(idx, "type", "LSI") == "LSI"
]
}
resource "aws_dynamodb_table" "this" {
name = var.schema.table_name
billing_mode = "PAY_PER_REQUEST"
hash_key = var.schema.hash_key
range_key = var.schema.range_key
dynamic "attribute" {
for_each = var.schema.attributes
content {
name = attribute.value.name
type = attribute.value.type
}
}
dynamic "global_secondary_index" {
for_each = local.gsi_indexes
content {
name = global_secondary_index.value.name
hash_key = global_secondary_index.value.hash_key
range_key = lookup(global_secondary_index.value, "range_key", null)
projection_type = global_secondary_index.value.projection_type
read_capacity = global_secondary_index.value.read_capacity
write_capacity = global_secondary_index.value.write_capacity
non_key_attributes = global_secondary_index.value.projection_type == "INCLUDE" ? global_secondary_index.value.non_key_attributes : null
}
}
dynamic "local_secondary_index" {
for_each = local.lsi_indexes
content {
name = local_secondary_index.value.name
range_key = local_secondary_index.value.range_key
projection_type = local_secondary_index.value.projection_type
non_key_attributes = local_secondary_index.value.projection_type == "INCLUDE" ? local_secondary_index.value.non_key_attributes : null
}
}
}
Применение
bash
# как пример, динамически задаем шаблон через EnvVar
export TF_VAR_schema=$(cat schema.json)
terraform init && terraform apply