Skip to content

Commit 755ecd8

Browse files
authored
Add TableReplicas Support for DynamoDB Table Replicas (#120)
fixes aws-controllers-k8s/community#2077 This PR implements support for managing DynamoDB table replicas through the `tableReplicas` field. This enhancement allows users to manage multi-region table replicas that automatically remain in sync. This is complemented by a `replicaDescription` field in the Table status for tracking replica states. ## Changes Overview - Added `tableReplicas` field to Table spec for defining replica configurations across regions - Added controller logic for replica lifecycle management (creation, updates, deletion) - Implemented validation rules: - DynamoDB Streams must be enabled with NEW_AND_OLD_IMAGES - Terminal error conditions for invalid configurations - E2E tests
1 parent 9a9fa52 commit 755ecd8

19 files changed

+1281
-36
lines changed

Diff for: apis/v1alpha1/ack-generate-metadata.yaml

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2025-02-20T18:05:49Z"
3-
build_hash: a326346bd3a6973254d247c9ab2dc76790c36241
2+
build_date: "2025-03-24T15:20:40Z"
3+
build_hash: 3722729cebe6d3c03c7e442655ef0846f91566a2
44
go_version: go1.24.0
5-
version: v0.43.2
6-
api_directory_checksum: 3bc0637159c94a74d2402d9a707f9c21339e9b45
5+
version: v0.43.2-7-g3722729
6+
api_directory_checksum: cb49386ebd7bb50e2521072a76262c72b9dbd285
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.32.6
99
generator_config_info:
10-
file_checksum: f6d68afa724d9e1d8fb6ce58da11ed0e5635f9d5
10+
file_checksum: 4533fa8aca3b134b5895ad6ce9a093c3446d99da
1111
original_file_name: generator.yaml
1212
last_modification:
1313
reason: API generation

Diff for: apis/v1alpha1/generator.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ operations:
2525
resources:
2626
Table:
2727
fields:
28+
TableReplicas:
29+
custom_field:
30+
list_of: CreateReplicationGroupMemberAction
31+
compare:
32+
is_ignored: true
2833
GlobalSecondaryIndexesDescriptions:
2934
custom_field:
3035
list_of: GlobalSecondaryIndexDescription
@@ -71,6 +76,7 @@ resources:
7176
code: ResourceNotFoundException
7277
terminal_codes:
7378
- InvalidParameter
79+
- ValidationException
7480
update_operation:
7581
custom_method_name: customUpdateTable
7682
hooks:

Diff for: apis/v1alpha1/table.go

+2-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: apis/v1alpha1/zz_generated.deepcopy.go

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: config/crd/bases/dynamodb.services.k8s.aws_tables.yaml

+39
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,45 @@ spec:
376376
The name of the table to create. You can also provide the Amazon Resource
377377
Name (ARN) of the table in this parameter.
378378
type: string
379+
tableReplicas:
380+
items:
381+
description: Represents a replica to be created.
382+
properties:
383+
globalSecondaryIndexes:
384+
items:
385+
description: Represents the properties of a replica global
386+
secondary index.
387+
properties:
388+
indexName:
389+
type: string
390+
provisionedThroughputOverride:
391+
description: |-
392+
Replica-specific provisioned throughput settings. If not specified, uses
393+
the source table's provisioned throughput settings.
394+
properties:
395+
readCapacityUnits:
396+
format: int64
397+
type: integer
398+
type: object
399+
type: object
400+
type: array
401+
kmsMasterKeyID:
402+
type: string
403+
provisionedThroughputOverride:
404+
description: |-
405+
Replica-specific provisioned throughput settings. If not specified, uses
406+
the source table's provisioned throughput settings.
407+
properties:
408+
readCapacityUnits:
409+
format: int64
410+
type: integer
411+
type: object
412+
regionName:
413+
type: string
414+
tableClassOverride:
415+
type: string
416+
type: object
417+
type: array
379418
tags:
380419
description: |-
381420
A list of key-value pairs to label the table. For more information, see Tagging

Diff for: generator.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ operations:
2525
resources:
2626
Table:
2727
fields:
28+
TableReplicas:
29+
custom_field:
30+
list_of: CreateReplicationGroupMemberAction
31+
compare:
32+
is_ignored: true
2833
GlobalSecondaryIndexesDescriptions:
2934
custom_field:
3035
list_of: GlobalSecondaryIndexDescription
@@ -71,6 +76,7 @@ resources:
7176
code: ResourceNotFoundException
7277
terminal_codes:
7378
- InvalidParameter
79+
- ValidationException
7480
update_operation:
7581
custom_method_name: customUpdateTable
7682
hooks:

Diff for: helm/crds/dynamodb.services.k8s.aws_tables.yaml

+39
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,45 @@ spec:
380380
The name of the table to create. You can also provide the Amazon Resource
381381
Name (ARN) of the table in this parameter.
382382
type: string
383+
tableReplicas:
384+
items:
385+
description: Represents a replica to be created.
386+
properties:
387+
globalSecondaryIndexes:
388+
items:
389+
description: Represents the properties of a replica global
390+
secondary index.
391+
properties:
392+
indexName:
393+
type: string
394+
provisionedThroughputOverride:
395+
description: |-
396+
Replica-specific provisioned throughput settings. If not specified, uses
397+
the source table's provisioned throughput settings.
398+
properties:
399+
readCapacityUnits:
400+
format: int64
401+
type: integer
402+
type: object
403+
type: object
404+
type: array
405+
kmsMasterKeyID:
406+
type: string
407+
provisionedThroughputOverride:
408+
description: |-
409+
Replica-specific provisioned throughput settings. If not specified, uses
410+
the source table's provisioned throughput settings.
411+
properties:
412+
readCapacityUnits:
413+
format: int64
414+
type: integer
415+
type: object
416+
regionName:
417+
type: string
418+
tableClassOverride:
419+
type: string
420+
type: object
421+
type: array
383422
tags:
384423
description: |-
385424
A list of key-value pairs to label the table. For more information, see Tagging

Diff for: pkg/resource/table/hooks.go

+34-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ package table
1515

1616
import (
1717
"context"
18+
"errors"
1819
"fmt"
1920
"strings"
2021
"time"
@@ -34,21 +35,25 @@ import (
3435

3536
var (
3637
ErrTableDeleting = fmt.Errorf(
37-
"Table in '%v' state, cannot be modified or deleted",
38+
"table in '%v' state, cannot be modified or deleted",
3839
svcsdktypes.TableStatusDeleting,
3940
)
4041
ErrTableCreating = fmt.Errorf(
41-
"Table in '%v' state, cannot be modified or deleted",
42+
"table in '%v' state, cannot be modified or deleted",
4243
svcsdktypes.TableStatusCreating,
4344
)
4445
ErrTableUpdating = fmt.Errorf(
45-
"Table in '%v' state, cannot be modified or deleted",
46+
"table in '%v' state, cannot be modified or deleted",
4647
svcsdktypes.TableStatusUpdating,
4748
)
4849
ErrTableGSIsUpdating = fmt.Errorf(
49-
"Table GSIs in '%v' state, cannot be modified or deleted",
50+
"table GSIs in '%v' state, cannot be modified or deleted",
5051
svcsdktypes.IndexStatusCreating,
5152
)
53+
ErrTableReplicasUpdating = fmt.Errorf(
54+
"table replica in '%v' state, cannot be modified or deleted",
55+
svcsdktypes.ReplicaStatusUpdating,
56+
)
5257
)
5358

5459
// TerminalStatuses are the status strings that are terminal states for a
@@ -74,12 +79,16 @@ var (
7479
)
7580
requeueWaitWhileUpdating = ackrequeue.NeededAfter(
7681
ErrTableUpdating,
77-
5*time.Second,
82+
10*time.Second,
7883
)
7984
requeueWaitGSIReady = ackrequeue.NeededAfter(
8085
ErrTableGSIsUpdating,
8186
10*time.Second,
8287
)
88+
requeueWaitReplicasActive = ackrequeue.NeededAfter(
89+
ErrTableReplicasUpdating,
90+
10*time.Second,
91+
)
8392
)
8493

8594
// tableHasTerminalStatus returns whether the supplied Dynamodb table is in a
@@ -224,6 +233,17 @@ func (rm *resourceManager) customUpdateTable(
224233
}
225234
return nil, err
226235
}
236+
case delta.DifferentAt("Spec.TableReplicas"):
237+
// Enabling replicas required streams enabled and StreamViewType to be NEW_AND_OLD_IMAGES
238+
// Version 2019.11.21 TableUpdate API requirement
239+
if !hasStreamSpecificationWithNewAndOldImages(desired) {
240+
msg := "table must have DynamoDB Streams enabled with StreamViewType set to NEW_AND_OLD_IMAGES for replica updates"
241+
rlog.Debug(msg)
242+
return nil, ackerr.NewTerminalError(errors.New(msg))
243+
}
244+
if err := rm.syncReplicas(ctx, latest, desired); err != nil {
245+
return nil, err
246+
}
227247
}
228248
}
229249

@@ -558,6 +578,15 @@ func customPreCompare(
558578
}
559579
}
560580

581+
// Handle ReplicaUpdates API comparison
582+
if len(a.ko.Spec.TableReplicas) != len(b.ko.Spec.TableReplicas) {
583+
delta.Add("Spec.TableReplicas", a.ko.Spec.TableReplicas, b.ko.Spec.TableReplicas)
584+
} else if a.ko.Spec.TableReplicas != nil && b.ko.Spec.TableReplicas != nil {
585+
if !equalReplicaArrays(a.ko.Spec.TableReplicas, b.ko.Spec.TableReplicas) {
586+
delta.Add("Spec.TableReplicas", a.ko.Spec.TableReplicas, b.ko.Spec.TableReplicas)
587+
}
588+
}
589+
561590
if a.ko.Spec.DeletionProtectionEnabled == nil {
562591
a.ko.Spec.DeletionProtectionEnabled = aws.Bool(false)
563592
}

0 commit comments

Comments
 (0)