Hedronite · Go Lesson · Polyglot-Dev / Go · Fri 2026-09-11

AWS SDK Go v2: DynamoDB DescribeTable — Terraform lock inventory

Partial backend config names a lock table. Prove the table exists and that its key schema still says LockID.

Lesson Class: DevOps-Go (aws-sdk-go-v2 DynamoDB)
Paired Ops: Terraform partial backend config: S3 keys at init time
Paired Dev: HCL backend blocks: partial config and init-time injection
Paired Cert: Associate remote backends, partial config, and state migration
Grounding: Brikman Ch.3 Shared Storage · Lab 31 table name
Describe
Load config; DescribeTable once.
LockID
Require the exact hash key name.
WARN
Fail CI when the schema drifts.
The lock table name in backend.hcl must still be LockID underneath.

Partial backend config names a lock table. Prove the table exists and that its key schema still says LockID.

§I — Frame

Ops and HCL today inject dynamodb_table through backend.hcl. September 5 listed S3 state objects. August 18 explained why the hash key must be exactly LockID. This companion is a small Go inventory: load default AWS config, DescribeTable, print status and key schema, WARN when LockID is missing.

§II — Sketch

package main

import (
  "context"
  "fmt"
  "log"
  "os"

  "github.com/aws/aws-sdk-go-v2/aws"
  "github.com/aws/aws-sdk-go-v2/config"
  "github.com/aws/aws-sdk-go-v2/service/dynamodb"
)

func main() {
  ctx := context.Background()
  table := os.Getenv("TF_LOCK_TABLE")
  if table == "" {
    log.Fatal("TF_LOCK_TABLE is required")
  }

  cfg, err := config.LoadDefaultConfig(ctx)
  if err != nil {
    log.Fatalf("config: %v", err)
  }

  client := dynamodb.NewFromConfig(cfg)
  out, err := client.DescribeTable(ctx, &dynamodb.DescribeTableInput{
    TableName: aws.String(table),
  })
  if err != nil {
    log.Fatalf("DescribeTable: %v", err)
  }

  desc := out.Table
  fmt.Printf("table=%s status=%s\n", aws.ToString(desc.TableName), desc.TableStatus)

  hasLockID := false
  for _, kd := range desc.KeySchema {
    fmt.Printf("key name=%s type=%s\n", aws.ToString(kd.AttributeName), kd.KeyType)
    if aws.ToString(kd.AttributeName) == "LockID" {
      hasLockID = true
    }
  }
  if !hasLockID {
    fmt.Println("WARN: hash key LockID not found; Terraform S3 locking will fail")
  }
}

§III — Operator notes

Set TF_LOCK_TABLE from the same value you put in backend.hcl. Run this after someone "helps" by recreating the table with a lowercase lockid attribute. Brikman is exact: the primary key attribute name is LockID.

This program does not call Scan for active locks. Active lock items are an operations incident surface already covered under force-unlock discipline. Inventory the schema first.

Config chain matches the September 5 and September 10 companions: config.LoadDefaultConfig then service client. Region comes from the environment or shared config; align it with the backend region.

§IV — Closing

Partial config can point at a missing or miskeyed table. A one-page DescribeTable check catches that before the first CI apply waits on a lock that can never be written. Wire TF_LOCK_TABLE next to the backend.hcl generator and fail the pipeline on WARN.

Related