diff --git a/go.mod b/go.mod index 29829ebe..bccf7826 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/aws-controllers-k8s/pkg v0.0.19 - github.com/aws-controllers-k8s/runtime v0.54.0 + github.com/aws-controllers-k8s/runtime v0.54.1 github.com/aws/aws-sdk-go v1.49.0 github.com/aws/aws-sdk-go-v2 v1.32.7 github.com/dlclark/regexp2 v1.10.0 // indirect diff --git a/go.sum b/go.sum index 2198a935..91568a5d 100644 --- a/go.sum +++ b/go.sum @@ -73,8 +73,12 @@ github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:l github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws-controllers-k8s/pkg v0.0.19 h1:q/NhMvj6fCkHAJTyasrOWNdYME9/eCdeA5tStz4hHb8= github.com/aws-controllers-k8s/pkg v0.0.19/go.mod h1:VvdjLWmR6IJ3KU8KByKiq/lJE8M+ur2piXysXKTGUS0= +github.com/aws-controllers-k8s/runtime v0.53.1 h1:l9MkR1KfZW8H8icT5rrRK3pdnVVA4io/eINVe5aspWs= +github.com/aws-controllers-k8s/runtime v0.53.1/go.mod h1:OkUJN+Ds799JLYZsMJrO2vDJ4snxUeHK2MgrQHbU+Qc= github.com/aws-controllers-k8s/runtime v0.54.0 h1:RWv5cVb428styiRTHugRF8bMWjXkgsDc5E6Q/BoD8gA= github.com/aws-controllers-k8s/runtime v0.54.0/go.mod h1:OkUJN+Ds799JLYZsMJrO2vDJ4snxUeHK2MgrQHbU+Qc= +github.com/aws-controllers-k8s/runtime v0.54.1 h1:0mbCJELz3t7jbG4abNecF0yeRd8YeFZQPr7nnzr8DC8= +github.com/aws-controllers-k8s/runtime v0.54.1/go.mod h1:OkUJN+Ds799JLYZsMJrO2vDJ4snxUeHK2MgrQHbU+Qc= github.com/aws/aws-sdk-go v1.49.0 h1:g9BkW1fo9GqKfwg2+zCD+TW/D36Ux+vtfJ8guF4AYmY= github.com/aws/aws-sdk-go v1.49.0/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw= diff --git a/pkg/generate/ack/runtime_test.go b/pkg/generate/ack/runtime_test.go index 20e211b0..60ff95d4 100644 --- a/pkg/generate/ack/runtime_test.go +++ b/pkg/generate/ack/runtime_test.go @@ -147,7 +147,7 @@ func (frm *fakeRM) EnsureTags( return nil } -func (frm *fakeRM) FilterSystemTags(acktypes.AWSResource) {} +func (frm *fakeRM) FilterSystemTags(acktypes.AWSResource, []string) {} // This test is mostly just a hack to introduce a Go module dependency between // the ACK runtime library and the code generator. The code generator doesn't diff --git a/templates/pkg/resource/manager.go.tpl b/templates/pkg/resource/manager.go.tpl index 01188517..fde8e633 100644 --- a/templates/pkg/resource/manager.go.tpl +++ b/templates/pkg/resource/manager.go.tpl @@ -312,13 +312,26 @@ func (rm *resourceManager) EnsureTags( {{- end }} } -// FilterAWSTags ignores tags that have keys that start with "aws:" -// is needed to ensure the controller does not attempt to remove -// tags set by AWS. This function needs to be called after each Read -// operation. -// Eg. resources created with cloudformation have tags that cannot be -//removed by an ACK controller -func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { +// FilterSystemTags removes system-managed tags from the resource's tag collection +// to prevent the controller from attempting to manage them. This includes: +// - Tags with keys starting with "aws:" (AWS-managed system tags) +// - Tags specified via the --resource-tags startup flag (controller-level tags) +// - Tags injected by AWS services (e.g., CloudFormation, EKS, etc.) +// +// This filtering is essential because: +// 1. AWS services automatically add system tags that cannot be modified by users +// 2. Attempting to remove these tags would result in API errors +// 3. The controller should only manage user-defined tags, not system tags +// +// Must be called after each Read operation to ensure the resource state +// reflects only manageable tags. This prevents unnecessary update attempts +// and maintains consistency between desired and actual resource state. +// +// Example system tags that are filtered: +// - aws:cloudformation:stack-name (CloudFormation) +// - aws:eks:cluster-name (EKS) +// - services.k8s.aws/* (Kubernetes-managed) +func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource, systemTags []string) { {{- if $hookCode := Hook .CRD "filter_tags" }} {{ $hookCode }} {{ else }} @@ -342,7 +355,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { {{ end -}} existingTags = r.ko.Spec.{{ $tagField.Path }} resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) {{ GoCodeInitializeNestedStructField .CRD "r.ko" $tagField "svcapitypes" 1 -}} r.ko.Spec.{{ $tagField.Path }} = fromACKTags(resourceTags, tagKeyOrder) {{- end }} diff --git a/templates/pkg/resource/tags.go.tpl b/templates/pkg/resource/tags.go.tpl index 27f0b592..d715f44b 100644 --- a/templates/pkg/resource/tags.go.tpl +++ b/templates/pkg/resource/tags.go.tpl @@ -11,7 +11,6 @@ import( var ( _ = svcapitypes.{{ .CRD.Kind }}{} _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} ) {{- if $hookCode := Hook .CRD "convert_tags" }} @@ -59,13 +58,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) {{ $tagFieldGoType }} { {{ end }} // ignoreSystemTags ignores tags that have keys that start with "aws:" -// and ACKSystemTags, to avoid patching them to the resourceSpec. +// and systemTags defined on startup via the --resource-tags flag, +// to avoid patching them to the resourceSpec. // Eg. resources created with cloudformation have tags that cannot be // removed by an ACK controller -func ignoreSystemTags(tags acktags.Tags) { +func ignoreSystemTags(tags acktags.Tags, systemTags []string) { for k := range tags { if strings.HasPrefix(k, "aws:") || - slices.Contains(ACKSystemTags, k) { + slices.Contains(systemTags, k) { delete(tags, k) } }