Skip to content

Commit 3e6e86f

Browse files
authored
Add e2e test that adopts bucket created in cloudformation (#149)
Issue [#2248](aws-controllers-k8s/community#2248) Description of changes: This test expects the ACK controller to always ignore AWS tags. It also attempts updating the tags and ensures the AWS tags injected by cloudformation are still ignored. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent b6698d9 commit 3e6e86f

11 files changed

+227
-11
lines changed

apis/v1alpha1/ack-generate-metadata.yaml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
ack_generate_info:
2-
build_date: "2025-02-06T03:32:53Z"
3-
build_hash: 8762917215d9902b2011a2b0b1b0c776855a683e
4-
go_version: go1.23.5
5-
version: v0.42.0
2+
build_date: "2025-02-17T21:07:14Z"
3+
build_hash: 11e0a33c63d0cfcd43042d8f8d07466fc1814135
4+
go_version: go1.24.0
5+
version: v0.42.0-2-g11e0a33
66
api_directory_checksum: 12d59cc27a5fc11bf285d7735d81240e980b1046
77
api_version: v1alpha1
88
aws_sdk_go_version: v1.32.6

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ go 1.22.0
55
toolchain go1.22.5
66

77
require (
8-
github.com/aws-controllers-k8s/runtime v0.42.0
8+
github.com/aws-controllers-k8s/runtime v0.43.0
99
github.com/aws/aws-sdk-go v1.49.0
1010
github.com/aws/aws-sdk-go-v2 v1.34.0
1111
github.com/aws/aws-sdk-go-v2/service/s3 v1.74.1

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
github.com/aws-controllers-k8s/runtime v0.42.0 h1:fVb3cOwUtn0ZwTSedapES+Rspb97S8BTxMqXJt6R5uM=
2-
github.com/aws-controllers-k8s/runtime v0.42.0/go.mod h1:Oy0JKvDxZMZ+SVupm4NZVqP00KLIIAMfk93KnOwlt5c=
1+
github.com/aws-controllers-k8s/runtime v0.43.0 h1:mCtMHO0rew84VbqotquvBirnKysbao+y2G3QI8bKZxM=
2+
github.com/aws-controllers-k8s/runtime v0.43.0/go.mod h1:Oy0JKvDxZMZ+SVupm4NZVqP00KLIIAMfk93KnOwlt5c=
33
github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY=
44
github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
55
github.com/aws/aws-sdk-go-v2 v1.34.0 h1:9iyL+cjifckRGEVpRKZP3eIxVlL06Qk1Tk13vreaVQU=

pkg/resource/bucket/manager.go

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

pkg/resource/bucket/tags.go

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

test/e2e/bootstrap_resources.py

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from acktest.bootstrapping.iam import Role
2121
from acktest.bootstrapping.s3 import Bucket
2222
from acktest.bootstrapping.sns import Topic
23+
from acktest.bootstrapping.cloudformation import Stack
2324
from e2e import bootstrap_directory
2425

2526
@dataclass
@@ -28,6 +29,7 @@ class BootstrapResources(Resources):
2829
AdoptionBucket: Bucket
2930
ReplicationRole: Role
3031
NotificationTopic: Topic
32+
StackBucket: Stack
3133

3234
_bootstrap_resources = None
3335

test/e2e/replacement_values.py

+1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@
2121
"ADOPTION_BUCKET_NAME": get_bootstrap_resources().AdoptionBucket.name,
2222
"REPLICATION_BUCKET_NAME": get_bootstrap_resources().ReplicationBucket.name,
2323
"NOTIFICATION_TOPIC_ARN": get_bootstrap_resources().NotificationTopic.arn,
24+
"STACK_BUCKET_NAME": get_bootstrap_resources().StackBucket.template["Resources"]["MyS3Bucket"]["Properties"]["BucketName"],
2425
}

test/e2e/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@38ce32256cc2552ab54e190cc8a8618e93af9e0c
1+
acktest @ git+https://github.com/aws-controllers-k8s/test-infra.git@a49300708a1a5586fec36fd28a2494d9cb2288ab
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
apiVersion: s3.services.k8s.aws/v1alpha1
2+
kind: Bucket
3+
metadata:
4+
name: $STACK_BUCKET_NAME
5+
annotations:
6+
services.k8s.aws/adoption-policy: $ADOPTION_POLICY
7+
services.k8s.aws/adoption-fields: "$ADOPTION_FIELDS"
8+
services.k8s.aws/deletion-policy: retain

test/e2e/service_bootstrap.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717
import json
1818
from pathlib import Path
1919

20+
from acktest.resources import random_suffix_name
2021
from acktest.bootstrapping import Resources, BootstrapFailureException
2122
from acktest.bootstrapping.iam import Role, UserPolicies
2223
from acktest.bootstrapping.s3 import Bucket
2324
from acktest.bootstrapping.sns import Topic
25+
from acktest.bootstrapping.cloudformation import Stack
2426
from e2e import bootstrap_directory
2527
from e2e.bootstrap_resources import BootstrapResources
2628

@@ -62,13 +64,30 @@ def service_bootstrap() -> Resources:
6264
]
6365
})
6466

67+
stack_bucket_name = random_suffix_name("stack-bucket", 24)
68+
template = {
69+
"AWSTemplateFormatVersion": "2010-09-09",
70+
"Resources": {
71+
"MyS3Bucket": {
72+
"Type": "AWS::S3::Bucket",
73+
"Properties": {
74+
"BucketName": stack_bucket_name,
75+
"VersioningConfiguration": {
76+
"Status": "Enabled"
77+
}
78+
}
79+
}
80+
}
81+
}
82+
6583
resources = BootstrapResources(
6684
ReplicationBucket=Bucket("ack-s3-replication", enable_versioning=True),
6785
AdoptionBucket=Bucket("ack-s3-annotation-adoption", enable_versioning=True),
6886
ReplicationRole=Role("ack-s3-replication-role", "s3.amazonaws.com",
6987
user_policies=UserPolicies("ack-s3-replication-policy", [replication_policy])
7088
),
71-
NotificationTopic=Topic("ack-s3-notification", policy=notification_policy)
89+
NotificationTopic=Topic("ack-s3-notification", policy=notification_policy),
90+
StackBucket=Stack(name_prefix=stack_bucket_name, template=template)
7291
)
7392

7493
try:

test/e2e/tests/test_bucket_adoption_policy.py

+85
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
CREATE_WAIT_AFTER_SECONDS = 10
3131
MODIFY_WAIT_AFTER_SECONDS = 10
3232
DELETE_WAIT_AFTER_SECONDS = 10
33+
ACK_SYSTEM_TAG_PREFIX = "services.k8s.aws/"
34+
AWS_SYSTEM_TAG_PREFIX = "aws:"
3335

3436
class AdoptionPolicy(str, Enum):
3537
NONE = ""
@@ -66,6 +68,36 @@ def adoption_policy_adopt_bucket(s3_client):
6668
_, deleted = k8s.delete_custom_resource(ref, DELETE_WAIT_AFTER_SECONDS)
6769
assert deleted
6870

71+
@pytest.fixture(scope="module")
72+
def adopt_stack_bucket(s3_client):
73+
replacements = REPLACEMENT_VALUES.copy()
74+
bucket_name = replacements["STACK_BUCKET_NAME"]
75+
replacements["ADOPTION_POLICY"] = AdoptionPolicy.ADOPT
76+
replacements["ADOPTION_FIELDS"] = f'{{\\\"name\\\": \\\"{bucket_name}\\\"}}'
77+
78+
resource_data = load_s3_resource(
79+
"bucket_adoption_stack",
80+
additional_replacements=replacements,
81+
)
82+
83+
# Create k8s resource
84+
ref = k8s.CustomResourceReference(
85+
CRD_GROUP, CRD_VERSION, "buckets",
86+
bucket_name, namespace="default")
87+
k8s.create_custom_resource(ref, resource_data)
88+
89+
time.sleep(CREATE_WAIT_AFTER_SECONDS)
90+
cr = k8s.wait_resource_consumed_by_controller(ref)
91+
92+
assert cr is not None
93+
assert k8s.get_resource_exists(ref)
94+
95+
yield (ref, cr)
96+
97+
_, deleted = k8s.delete_custom_resource(ref, DELETE_WAIT_AFTER_SECONDS)
98+
assert deleted
99+
100+
69101
@service_marker
70102
@pytest.mark.canary
71103
class TestAdoptionPolicyBucket:
@@ -101,4 +133,57 @@ def test_adoption_policy(
101133
versioning = latest.Versioning()
102134
assert versioning.status == status
103135

136+
def test_adoption_update_tags(
137+
self, s3_client, adopt_stack_bucket, s3_resource
138+
):
139+
(ref, cr) = adopt_stack_bucket
140+
141+
# Spec will be added by controller
142+
assert 'spec' in cr
143+
assert 'name' in cr['spec']
144+
assert 'tagSet' not in cr['spec']['tagging']
145+
bucket_name = cr['spec']['name']
104146

147+
updates = {
148+
"spec": {
149+
"tagging": {
150+
"tagSet": [
151+
{"key": "newKey", "value": "newVal"}
152+
]
153+
}
154+
}
155+
}
156+
157+
k8s.patch_custom_resource(ref, updates)
158+
time.sleep(MODIFY_WAIT_AFTER_SECONDS)
159+
160+
cr = k8s.wait_resource_consumed_by_controller(ref)
161+
assert cr is not None
162+
assert 'spec' in cr
163+
assert 'tagging' in cr['spec']
164+
assert 'tagSet' in cr['spec']['tagging']
165+
166+
latest = get_bucket(s3_resource, bucket_name)
167+
assert latest is not None
168+
tagging = latest.Tagging()
169+
170+
latest = cleanTags(tagging.tag_set)
171+
# +2 here because we want to see if we're also filtering
172+
# through the aws tags, besides just the ack tags
173+
assert len(tagging.tag_set) > len(latest) + 2
174+
desired = cr['spec']['tagging']['tagSet']
175+
for i in range(1):
176+
assert desired[i]["key"] == latest[i]["Key"]
177+
assert desired[i]["value"] == latest[i]["Value"]
178+
179+
180+
def cleanTags(tags: list,
181+
key_member_name: str = 'Key',
182+
) -> list:
183+
if isinstance(tags, list):
184+
return [
185+
t for t in tags if not t[key_member_name].startswith(AWS_SYSTEM_TAG_PREFIX)
186+
and not t[key_member_name].startswith(ACK_SYSTEM_TAG_PREFIX)
187+
]
188+
else:
189+
raise RuntimeError('tags parameter can only be list type')

0 commit comments

Comments
 (0)