Skip to content

Commit ac13306

Browse files
committed
feat: Add contributorInsights field to Table resource
1 parent bbd377c commit ac13306

15 files changed

+210
-4
lines changed

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

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
ack_generate_info:
2-
build_date: "2025-03-28T01:43:12Z"
2+
build_date: "2025-04-01T00:50:24Z"
33
build_hash: 980cb1e4734f673d16101cf55206b84ca639ec01
44
go_version: go1.24.1
55
version: v0.44.0
6-
api_directory_checksum: cb49386ebd7bb50e2521072a76262c72b9dbd285
6+
api_directory_checksum: 2f94829f12ad90f9c36c48823459c161c1670093
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.32.6
99
generator_config_info:
10-
file_checksum: 4533fa8aca3b134b5895ad6ce9a093c3446d99da
10+
file_checksum: e7e79c3c7c21273967ca24947fda0f26b344c8f0
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
@@ -70,6 +70,10 @@ resources:
7070
service_name: kms
7171
resource: Key
7272
path: Status.ACKResourceMetadata.ARN
73+
ContributorInsights:
74+
from:
75+
operation: UpdateContributorInsights
76+
path: ContributorInsightsAction
7377
exceptions:
7478
errors:
7579
404:
@@ -86,6 +90,8 @@ resources:
8690
template_path: hooks/table/sdk_create_post_set_output.go.tpl
8791
sdk_read_one_post_set_output:
8892
template_path: hooks/table/sdk_read_one_post_set_output.go.tpl
93+
sdk_update_pre_build_request:
94+
template_path: hooks/table/sdk_update_pre_build_request.go.tpl
8995
sdk_delete_pre_build_request:
9096
template_path: hooks/table/sdk_delete_pre_build_request.go.tpl
9197
synced:

Diff for: apis/v1alpha1/table.go

+2
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

+5
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

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ spec:
8888
pointInTimeRecoveryEnabled:
8989
type: boolean
9090
type: object
91+
contributorInsights:
92+
description: Represents the contributor insights action.
93+
type: string
9194
deletionProtectionEnabled:
9295
description: |-
9396
Indicates whether deletion protection is to be enabled (true) or disabled

Diff for: generator.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ resources:
7070
service_name: kms
7171
resource: Key
7272
path: Status.ACKResourceMetadata.ARN
73+
ContributorInsights:
74+
from:
75+
operation: UpdateContributorInsights
76+
path: ContributorInsightsAction
7377
exceptions:
7478
errors:
7579
404:
@@ -86,6 +90,8 @@ resources:
8690
template_path: hooks/table/sdk_create_post_set_output.go.tpl
8791
sdk_read_one_post_set_output:
8892
template_path: hooks/table/sdk_read_one_post_set_output.go.tpl
93+
sdk_update_pre_build_request:
94+
template_path: hooks/table/sdk_update_pre_build_request.go.tpl
8995
sdk_delete_pre_build_request:
9096
template_path: hooks/table/sdk_delete_pre_build_request.go.tpl
9197
synced:

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

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ spec:
8888
pointInTimeRecoveryEnabled:
8989
type: boolean
9090
type: object
91+
contributorInsights:
92+
description: Represents the contributor insights action.
93+
type: string
9194
deletionProtectionEnabled:
9295
description: |-
9396
Indicates whether deletion protection is to be enabled (true) or disabled

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

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

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

+83-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
corev1 "k8s.io/api/core/v1"
3232

3333
"github.com/aws-controllers-k8s/dynamodb-controller/apis/v1alpha1"
34+
svcapitypes "github.com/aws-controllers-k8s/dynamodb-controller/apis/v1alpha1"
3435
)
3536

3637
var (
@@ -133,7 +134,9 @@ func isTableUpdating(r *resource) bool {
133134
return false
134135
}
135136
dbis := *r.ko.Status.TableStatus
136-
return dbis == string(v1alpha1.TableStatus_SDK_UPDATING)
137+
return dbis == string(v1alpha1.TableStatus_SDK_UPDATING) ||
138+
*r.ko.Spec.ContributorInsights == string(svcsdktypes.ContributorInsightsStatusEnabling) ||
139+
*r.ko.Spec.ContributorInsights == string(svcsdktypes.ContributorInsightsStatusDisabling)
137140
}
138141

139142
func (rm *resourceManager) customUpdateTable(
@@ -212,6 +215,13 @@ func (rm *resourceManager) customUpdateTable(
212215
}
213216
}
214217

218+
if delta.DifferentAt("Spec.ContributorInsights") {
219+
err = rm.updateContributorInsights(ctx, desired)
220+
if err != nil {
221+
return &resource{ko}, err
222+
}
223+
}
224+
215225
// We want to update fast fields first
216226
// Then attributes
217227
// then GSI
@@ -590,6 +600,10 @@ func customPreCompare(
590600
if a.ko.Spec.DeletionProtectionEnabled == nil {
591601
a.ko.Spec.DeletionProtectionEnabled = aws.Bool(false)
592602
}
603+
604+
if a.ko.Spec.ContributorInsights == nil && *b.ko.Spec.ContributorInsights == string(svcsdktypes.ContributorInsightsStatusDisabled) {
605+
a.ko.Spec.ContributorInsights = aws.String(string(svcsdktypes.ContributorInsightsStatusDisabled))
606+
}
593607
}
594608

595609
// equalAttributeDefinitions return whether two AttributeDefinition arrays are equal or not.
@@ -724,3 +738,71 @@ func equalLocalSecondaryIndexes(
724738
}
725739
return true
726740
}
741+
742+
// setContributorInsights retrieves the table's cloudformationInsights
743+
// configuration
744+
func (rm *resourceManager) setContributorInsights(
745+
ctx context.Context,
746+
r *resource,
747+
ko *svcapitypes.Table,
748+
) (err error) {
749+
rlog := ackrtlog.FromContext(ctx)
750+
exit := rlog.Trace("rm.setCloudformationInsights")
751+
defer func() {
752+
exit(err)
753+
}()
754+
755+
resp, err := rm.sdkapi.DescribeContributorInsights(
756+
ctx,
757+
&svcsdk.DescribeContributorInsightsInput{
758+
TableName: r.ko.Spec.TableName,
759+
},
760+
)
761+
rm.metrics.RecordAPICall("READ_ONE", "DescribeContributorInsights", err)
762+
if err != nil {
763+
return err
764+
}
765+
766+
switch resp.ContributorInsightsStatus {
767+
case svcsdktypes.ContributorInsightsStatusEnabled:
768+
ko.Spec.ContributorInsights = aws.String(string(svcsdktypes.ContributorInsightsActionEnable))
769+
case svcsdktypes.ContributorInsightsStatusDisabled:
770+
ko.Spec.ContributorInsights = aws.String(string(svcsdktypes.ContributorInsightsActionDisable))
771+
default:
772+
ko.Spec.ContributorInsights = aws.String(string(resp.ContributorInsightsStatus))
773+
774+
}
775+
776+
return nil
777+
}
778+
779+
func (rm *resourceManager) updateContributorInsights(
780+
ctx context.Context,
781+
r *resource,
782+
) (err error) {
783+
rlog := ackrtlog.FromContext(ctx)
784+
exit := rlog.Trace("rm.updateCloudformationInsights")
785+
defer func() {
786+
exit(err)
787+
}()
788+
var insight svcsdktypes.ContributorInsightsAction
789+
if r.ko.Spec.ContributorInsights != nil {
790+
insight = svcsdktypes.ContributorInsightsAction(*r.ko.Spec.ContributorInsights)
791+
} else {
792+
insight = svcsdktypes.ContributorInsightsActionDisable
793+
}
794+
795+
_, err = rm.sdkapi.UpdateContributorInsights(
796+
ctx,
797+
&svcsdk.UpdateContributorInsightsInput{
798+
TableName: r.ko.Spec.TableName,
799+
ContributorInsightsAction: insight,
800+
},
801+
)
802+
rm.metrics.RecordAPICall("READ_ONE", "UpdateContributorInsights", err)
803+
if err != nil {
804+
return err
805+
}
806+
807+
return nil
808+
}

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

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

Diff for: templates/hooks/table/sdk_create_post_set_output.go.tpl

+4
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
if err := rm.syncTTL(ctx, desired, &resource{ko}); err != nil {
33
return nil, err
44
}
5+
}
6+
7+
if desired.ko.Spec.ContributorInsights != nil {
8+
ackcondition.SetSynced(&resource{ko}, corev1.ConditionFalse, nil, nil)
59
}

Diff for: templates/hooks/table/sdk_read_one_post_set_output.go.tpl

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
err = rm.setContributorInsights(ctx, r, ko)
2+
if err != nil {
3+
return &resource{ko}, err
4+
}
5+
16
if resp.Table.GlobalSecondaryIndexes != nil {
27
f := []*svcapitypes.GlobalSecondaryIndexDescription{}
38
for _, fIter := range resp.Table.GlobalSecondaryIndexes {

Diff for: test/e2e/resources/table_insights.yaml

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Table used to test multiple interfering updates at once
2+
apiVersion: dynamodb.services.k8s.aws/v1alpha1
3+
kind: Table
4+
metadata:
5+
name: $TABLE_NAME
6+
spec:
7+
tableName: $TABLE_NAME
8+
billingMode: PAY_PER_REQUEST
9+
tableClass: STANDARD
10+
contributorInsights: ENABLE
11+
attributeDefinitions:
12+
- attributeName: Bill
13+
attributeType: S
14+
- attributeName: Total
15+
attributeType: S
16+
keySchema:
17+
- attributeName: Bill
18+
keyType: HASH
19+
- attributeName: Total
20+
keyType: RANGE

Diff for: test/e2e/table.py

+12
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,18 @@ def get(table_name):
236236
except c.exceptions.ResourceNotFoundException:
237237
return None
238238

239+
def get_insights(table_name):
240+
"""Returns a dict containing the Role record from the IAM API.
241+
242+
If no such Table exists, returns None.
243+
"""
244+
c = boto3.client('dynamodb', region_name=get_region())
245+
try:
246+
resp = c.describe_contributor_insights(TableName=table_name)
247+
return resp['ContributorInsightsStatus']
248+
except c.exceptions.ResourceNotFoundException:
249+
return None
250+
239251

240252
def get_time_to_live(table_name):
241253
"""Returns the TTL specification for the table with a supplied name.

Diff for: test/e2e/tests/test_table.py

+42
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,18 @@ def table_basic():
136136
except:
137137
pass
138138

139+
@pytest.fixture(scope="function")
140+
def table_insights():
141+
resource_name = random_suffix_name("table-insights", 32)
142+
(ref, cr) = create_table(resource_name, "table_insights")
143+
144+
yield ref, cr
145+
try:
146+
_, deleted = k8s.delete_custom_resource(ref, wait_periods=3, period_length=10)
147+
assert deleted
148+
except:
149+
pass
150+
139151
@pytest.fixture(scope="module")
140152
def table_basic_pay_per_request():
141153
resource_name = random_suffix_name("table-basic-pay-per-request", 32)
@@ -153,6 +165,9 @@ def table_basic_pay_per_request():
153165
class TestTable:
154166
def table_exists(self, table_name: str) -> bool:
155167
return table.get(table_name) is not None
168+
169+
def table_insight_status(self, table_name: str, status: str) -> bool:
170+
return table.get(table_name) is not None
156171

157172
def test_create_delete(self, table_lsi):
158173
(ref, res) = table_lsi
@@ -452,6 +467,33 @@ def test_update_provisioned_throughput(self, table_lsi):
452467
timeout_seconds=MODIFY_WAIT_AFTER_SECONDS,
453468
interval_seconds=3,
454469
)
470+
471+
def test_update_insights(self, table_insights):
472+
(ref, res) = table_insights
473+
474+
table_name = res["spec"]["tableName"]
475+
assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5)
476+
477+
cr = k8s.get_resource(ref)
478+
479+
# Check DynamoDB Table exists
480+
assert self.table_exists(table_name)
481+
assert cr['spec']['contributorInsights'] == "ENABLE"
482+
assert self.table_insight_status(table_name, "ENABLED")
483+
484+
# Set provisionedThroughput
485+
updates = {
486+
"spec": {
487+
"contributorInsights": "DISABLE"
488+
}
489+
}
490+
# Patch k8s resource
491+
k8s.patch_custom_resource(ref, updates)
492+
assert k8s.wait_on_condition(ref, "ACK.ResourceSynced", "True", wait_periods=5)
493+
cr = k8s.get_resource(ref)
494+
assert cr['spec']['contributorInsights'] == "DISABLE"
495+
assert self.table_insight_status(table_name, "DISABLED")
496+
455497

456498
def test_enable_sse_specification(self, table_lsi):
457499
(ref, res) = table_lsi

0 commit comments

Comments
 (0)