From eb1ac630d75654efb0b31f981404e242c5b9cfe2 Mon Sep 17 00:00:00 2001 From: ci-robot Date: Sat, 29 Nov 2025 03:25:07 +0000 Subject: [PATCH] Update to ACK runtime `v0.56.0`, code-generator `v0.56.0` --- .github/workflows/postsubmit.yaml | 10 +++++++ apis/v1alpha1/ack-generate-metadata.yaml | 6 ++-- config/controller/kustomization.yaml | 2 +- go.mod | 2 +- go.sum | 4 +-- helm/Chart.yaml | 4 +-- helm/templates/NOTES.txt | 2 +- helm/values.yaml | 5 +++- pkg/resource/capacity_reservation/manager.go | 29 ++++++++++++++----- pkg/resource/capacity_reservation/tags.go | 12 ++++---- pkg/resource/dhcp_options/manager.go | 29 ++++++++++++++----- pkg/resource/dhcp_options/tags.go | 12 ++++---- pkg/resource/elastic_ip_address/manager.go | 29 ++++++++++++++----- pkg/resource/elastic_ip_address/tags.go | 12 ++++---- pkg/resource/flow_log/manager.go | 29 ++++++++++++++----- pkg/resource/flow_log/tags.go | 12 ++++---- pkg/resource/instance/manager.go | 29 ++++++++++++++----- pkg/resource/instance/tags.go | 12 ++++---- pkg/resource/internet_gateway/manager.go | 29 ++++++++++++++----- pkg/resource/internet_gateway/tags.go | 12 ++++---- pkg/resource/launch_template/manager.go | 29 ++++++++++++++----- pkg/resource/launch_template/tags.go | 12 ++++---- pkg/resource/nat_gateway/manager.go | 29 ++++++++++++++----- pkg/resource/nat_gateway/tags.go | 12 ++++---- pkg/resource/network_acl/manager.go | 29 ++++++++++++++----- pkg/resource/network_acl/tags.go | 12 ++++---- pkg/resource/route_table/manager.go | 29 ++++++++++++++----- pkg/resource/route_table/tags.go | 12 ++++---- pkg/resource/security_group/manager.go | 29 ++++++++++++++----- pkg/resource/security_group/tags.go | 12 ++++---- pkg/resource/subnet/manager.go | 29 ++++++++++++++----- pkg/resource/subnet/tags.go | 12 ++++---- pkg/resource/transit_gateway/manager.go | 29 ++++++++++++++----- pkg/resource/transit_gateway/tags.go | 12 ++++---- .../transit_gateway_vpc_attachment/manager.go | 29 ++++++++++++++----- .../transit_gateway_vpc_attachment/tags.go | 12 ++++---- pkg/resource/vpc/manager.go | 29 ++++++++++++++----- pkg/resource/vpc/tags.go | 12 ++++---- pkg/resource/vpc_endpoint/manager.go | 29 ++++++++++++++----- pkg/resource/vpc_endpoint/tags.go | 12 ++++---- .../manager.go | 29 ++++++++++++++----- .../tags.go | 12 ++++---- .../vpc_peering_connection/manager.go | 29 ++++++++++++++----- pkg/resource/vpc_peering_connection/tags.go | 12 ++++---- 44 files changed, 510 insertions(+), 263 deletions(-) create mode 100644 .github/workflows/postsubmit.yaml diff --git a/.github/workflows/postsubmit.yaml b/.github/workflows/postsubmit.yaml new file mode 100644 index 00000000..db87c26c --- /dev/null +++ b/.github/workflows/postsubmit.yaml @@ -0,0 +1,10 @@ +name: Hydrate Go Proxy + +on: + push: + branches: + - main + +jobs: + call-hydrate-go-proxy: + uses: aws-controllers-k8s/.github/.github/workflows/reusable-postsubmit.yaml@main diff --git a/apis/v1alpha1/ack-generate-metadata.yaml b/apis/v1alpha1/ack-generate-metadata.yaml index 8f341e3c..b7e1c99e 100755 --- a/apis/v1alpha1/ack-generate-metadata.yaml +++ b/apis/v1alpha1/ack-generate-metadata.yaml @@ -1,8 +1,8 @@ ack_generate_info: - build_date: "2025-11-12T23:05:25Z" - build_hash: c833f2d14f4fe8953663ff92f4661ae5fb01b8c8 + build_date: "2025-11-29T03:24:03Z" + build_hash: 23c7074fa310ad1ccb38946775397c203b49f024 go_version: go1.25.4 - version: v0.53.1 + version: v0.56.0 api_directory_checksum: 5a5c93e3d4865ea08d8a47b2500551112ea831b9 api_version: v1alpha1 aws_sdk_go_version: v1.32.6 diff --git a/config/controller/kustomization.yaml b/config/controller/kustomization.yaml index 3a9f43a7..06b643df 100644 --- a/config/controller/kustomization.yaml +++ b/config/controller/kustomization.yaml @@ -6,4 +6,4 @@ kind: Kustomization images: - name: controller newName: public.ecr.aws/aws-controllers-k8s/ec2-controller - newTag: 1.7.1 + newTag: 1.8.0 diff --git a/go.mod b/go.mod index d8d16dbf..56779277 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.0 toolchain go1.24.1 require ( - github.com/aws-controllers-k8s/runtime v0.53.1 + github.com/aws-controllers-k8s/runtime v0.56.0 github.com/aws/aws-sdk-go v1.49.0 github.com/aws/aws-sdk-go-v2 v1.35.0 github.com/aws/aws-sdk-go-v2/service/ec2 v1.202.1 diff --git a/go.sum b/go.sum index b4d39e2d..64cd2cc7 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -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.56.0 h1:xT03K82QkY7EpdUDhVKvDY7hLddA+XnKY0xDAePALhM= +github.com/aws-controllers-k8s/runtime v0.56.0/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.35.0 h1:jTPxEJyzjSuuz0wB+302hr8Eu9KUI+Zv8zlujMGJpVI= diff --git a/helm/Chart.yaml b/helm/Chart.yaml index e6702dae..563d55a0 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v1 name: ec2-chart description: A Helm chart for the ACK service controller for Amazon Elastic Cloud Compute (EC2) -version: 1.7.1 -appVersion: 1.7.1 +version: 1.8.0 +appVersion: 1.8.0 home: https://github.com/aws-controllers-k8s/ec2-controller icon: https://raw.githubusercontent.com/aws/eks-charts/master/docs/logo/aws.png sources: diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt index d8676084..679dc59b 100644 --- a/helm/templates/NOTES.txt +++ b/helm/templates/NOTES.txt @@ -1,5 +1,5 @@ {{ .Chart.Name }} has been installed. -This chart deploys "public.ecr.aws/aws-controllers-k8s/ec2-controller:1.7.1". +This chart deploys "public.ecr.aws/aws-controllers-k8s/ec2-controller:1.8.0". Check its status by running: kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/instance={{ .Release.Name }}" diff --git a/helm/values.yaml b/helm/values.yaml index 9b6968b0..78acaac2 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -4,7 +4,7 @@ image: repository: public.ecr.aws/aws-controllers-k8s/ec2-controller - tag: 1.7.1 + tag: 1.8.0 pullPolicy: IfNotPresent pullSecrets: [] @@ -120,8 +120,11 @@ watchSelectors: "" resourceTags: # Configures the ACK service controller to always set key/value pairs tags on # resources that it manages. + # Note: Tags with empty values are automatically skipped to keep resources clean. - services.k8s.aws/controller-version=%CONTROLLER_SERVICE%-%CONTROLLER_VERSION% - services.k8s.aws/namespace=%K8S_NAMESPACE% + - app.kubernetes.io/managed-by=%MANAGED_BY% + - kro.run/kro-version=%KRO_VERSION% # Set to "retain" to keep all AWS resources intact even after the K8s resources # have been deleted. By default, the ACK controller will delete the AWS resource diff --git a/pkg/resource/capacity_reservation/manager.go b/pkg/resource/capacity_reservation/manager.go index 1ed5b4cd..3ba3c829 100644 --- a/pkg/resource/capacity_reservation/manager.go +++ b/pkg/resource/capacity_reservation/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/capacity_reservation/tags.go b/pkg/resource/capacity_reservation/tags.go index c11e156c..789bfe69 100644 --- a/pkg/resource/capacity_reservation/tags.go +++ b/pkg/resource/capacity_reservation/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.CapacityReservation{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.CapacityReservation{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/dhcp_options/manager.go b/pkg/resource/dhcp_options/manager.go index fc93b2cd..c7d1d54c 100644 --- a/pkg/resource/dhcp_options/manager.go +++ b/pkg/resource/dhcp_options/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/dhcp_options/tags.go b/pkg/resource/dhcp_options/tags.go index 77524501..3093bc6f 100644 --- a/pkg/resource/dhcp_options/tags.go +++ b/pkg/resource/dhcp_options/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.DHCPOptions{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.DHCPOptions{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/elastic_ip_address/manager.go b/pkg/resource/elastic_ip_address/manager.go index 51f47a3b..53220627 100644 --- a/pkg/resource/elastic_ip_address/manager.go +++ b/pkg/resource/elastic_ip_address/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/elastic_ip_address/tags.go b/pkg/resource/elastic_ip_address/tags.go index 2f7a79f8..7f2414f3 100644 --- a/pkg/resource/elastic_ip_address/tags.go +++ b/pkg/resource/elastic_ip_address/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.ElasticIPAddress{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.ElasticIPAddress{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/flow_log/manager.go b/pkg/resource/flow_log/manager.go index a37d95de..d2c41f41 100644 --- a/pkg/resource/flow_log/manager.go +++ b/pkg/resource/flow_log/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/flow_log/tags.go b/pkg/resource/flow_log/tags.go index 45ed0517..a00299f8 100644 --- a/pkg/resource/flow_log/tags.go +++ b/pkg/resource/flow_log/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.FlowLog{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.FlowLog{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/instance/manager.go b/pkg/resource/instance/manager.go index c33f8c1b..fc991ceb 100644 --- a/pkg/resource/instance/manager.go +++ b/pkg/resource/instance/manager.go @@ -306,13 +306,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -320,7 +333,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/instance/tags.go b/pkg/resource/instance/tags.go index 48673f18..e040eb0c 100644 --- a/pkg/resource/instance/tags.go +++ b/pkg/resource/instance/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.Instance{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.Instance{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/internet_gateway/manager.go b/pkg/resource/internet_gateway/manager.go index 926b6669..49cd4ac6 100644 --- a/pkg/resource/internet_gateway/manager.go +++ b/pkg/resource/internet_gateway/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/internet_gateway/tags.go b/pkg/resource/internet_gateway/tags.go index 0e61157f..aa8223c0 100644 --- a/pkg/resource/internet_gateway/tags.go +++ b/pkg/resource/internet_gateway/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.InternetGateway{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.InternetGateway{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/launch_template/manager.go b/pkg/resource/launch_template/manager.go index 68536d38..6775dc96 100644 --- a/pkg/resource/launch_template/manager.go +++ b/pkg/resource/launch_template/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/launch_template/tags.go b/pkg/resource/launch_template/tags.go index bfbb7f05..6bd5b872 100644 --- a/pkg/resource/launch_template/tags.go +++ b/pkg/resource/launch_template/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.LaunchTemplate{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.LaunchTemplate{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/nat_gateway/manager.go b/pkg/resource/nat_gateway/manager.go index e18337e1..f5fdca09 100644 --- a/pkg/resource/nat_gateway/manager.go +++ b/pkg/resource/nat_gateway/manager.go @@ -305,13 +305,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -319,7 +332,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/nat_gateway/tags.go b/pkg/resource/nat_gateway/tags.go index cabf544d..e4e1134e 100644 --- a/pkg/resource/nat_gateway/tags.go +++ b/pkg/resource/nat_gateway/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.NATGateway{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.NATGateway{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/network_acl/manager.go b/pkg/resource/network_acl/manager.go index a5d07680..d3d34db6 100644 --- a/pkg/resource/network_acl/manager.go +++ b/pkg/resource/network_acl/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/network_acl/tags.go b/pkg/resource/network_acl/tags.go index 43e18125..cd9ff0cb 100644 --- a/pkg/resource/network_acl/tags.go +++ b/pkg/resource/network_acl/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.NetworkACL{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.NetworkACL{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/route_table/manager.go b/pkg/resource/route_table/manager.go index 8771860c..4fb23db8 100644 --- a/pkg/resource/route_table/manager.go +++ b/pkg/resource/route_table/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/route_table/tags.go b/pkg/resource/route_table/tags.go index 96095dfe..2ad0472d 100644 --- a/pkg/resource/route_table/tags.go +++ b/pkg/resource/route_table/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.RouteTable{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.RouteTable{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/security_group/manager.go b/pkg/resource/security_group/manager.go index a1bb1f56..c8cc7930 100644 --- a/pkg/resource/security_group/manager.go +++ b/pkg/resource/security_group/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/security_group/tags.go b/pkg/resource/security_group/tags.go index d0da2103..bd9455a5 100644 --- a/pkg/resource/security_group/tags.go +++ b/pkg/resource/security_group/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.SecurityGroup{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.SecurityGroup{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/subnet/manager.go b/pkg/resource/subnet/manager.go index 2d9ae22f..2c91f45a 100644 --- a/pkg/resource/subnet/manager.go +++ b/pkg/resource/subnet/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/subnet/tags.go b/pkg/resource/subnet/tags.go index c544bb3b..4eceefd0 100644 --- a/pkg/resource/subnet/tags.go +++ b/pkg/resource/subnet/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.Subnet{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.Subnet{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/transit_gateway/manager.go b/pkg/resource/transit_gateway/manager.go index 44b7b164..ecb259f8 100644 --- a/pkg/resource/transit_gateway/manager.go +++ b/pkg/resource/transit_gateway/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/transit_gateway/tags.go b/pkg/resource/transit_gateway/tags.go index 13781d02..dc2bf396 100644 --- a/pkg/resource/transit_gateway/tags.go +++ b/pkg/resource/transit_gateway/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.TransitGateway{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.TransitGateway{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/transit_gateway_vpc_attachment/manager.go b/pkg/resource/transit_gateway_vpc_attachment/manager.go index 43079ffe..7500b080 100644 --- a/pkg/resource/transit_gateway_vpc_attachment/manager.go +++ b/pkg/resource/transit_gateway_vpc_attachment/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/transit_gateway_vpc_attachment/tags.go b/pkg/resource/transit_gateway_vpc_attachment/tags.go index 48b12c17..2020f6bb 100644 --- a/pkg/resource/transit_gateway_vpc_attachment/tags.go +++ b/pkg/resource/transit_gateway_vpc_attachment/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.TransitGatewayVPCAttachment{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.TransitGatewayVPCAttachment{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/vpc/manager.go b/pkg/resource/vpc/manager.go index 8f4866d0..15b6a55b 100644 --- a/pkg/resource/vpc/manager.go +++ b/pkg/resource/vpc/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/vpc/tags.go b/pkg/resource/vpc/tags.go index dcb6464a..345107ea 100644 --- a/pkg/resource/vpc/tags.go +++ b/pkg/resource/vpc/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.VPC{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.VPC{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/vpc_endpoint/manager.go b/pkg/resource/vpc_endpoint/manager.go index faec8438..21b5e7e7 100644 --- a/pkg/resource/vpc_endpoint/manager.go +++ b/pkg/resource/vpc_endpoint/manager.go @@ -306,13 +306,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -320,7 +333,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/vpc_endpoint/tags.go b/pkg/resource/vpc_endpoint/tags.go index 1ee5e00d..49dea4b7 100644 --- a/pkg/resource/vpc_endpoint/tags.go +++ b/pkg/resource/vpc_endpoint/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.VPCEndpoint{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.VPCEndpoint{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/vpc_endpoint_service_configuration/manager.go b/pkg/resource/vpc_endpoint_service_configuration/manager.go index a35b3884..fe10fe77 100644 --- a/pkg/resource/vpc_endpoint_service_configuration/manager.go +++ b/pkg/resource/vpc_endpoint_service_configuration/manager.go @@ -305,13 +305,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -319,7 +332,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/vpc_endpoint_service_configuration/tags.go b/pkg/resource/vpc_endpoint_service_configuration/tags.go index 48708510..fbd1da95 100644 --- a/pkg/resource/vpc_endpoint_service_configuration/tags.go +++ b/pkg/resource/vpc_endpoint_service_configuration/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.VPCEndpointServiceConfiguration{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.VPCEndpointServiceConfiguration{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } } diff --git a/pkg/resource/vpc_peering_connection/manager.go b/pkg/resource/vpc_peering_connection/manager.go index 22488ef7..32c3f969 100644 --- a/pkg/resource/vpc_peering_connection/manager.go +++ b/pkg/resource/vpc_peering_connection/manager.go @@ -297,13 +297,26 @@ func (rm *resourceManager) EnsureTags( return nil } -// 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) { r := rm.concreteResource(res) if r == nil || r.ko == nil { return @@ -311,7 +324,7 @@ func (rm *resourceManager) FilterSystemTags(res acktypes.AWSResource) { var existingTags []*svcapitypes.Tag existingTags = r.ko.Spec.Tags resourceTags, tagKeyOrder := convertToOrderedACKTags(existingTags) - ignoreSystemTags(resourceTags) + ignoreSystemTags(resourceTags, systemTags) r.ko.Spec.Tags = fromACKTags(resourceTags, tagKeyOrder) } diff --git a/pkg/resource/vpc_peering_connection/tags.go b/pkg/resource/vpc_peering_connection/tags.go index 634e5e9b..45b9cc31 100644 --- a/pkg/resource/vpc_peering_connection/tags.go +++ b/pkg/resource/vpc_peering_connection/tags.go @@ -25,9 +25,8 @@ import ( ) var ( - _ = svcapitypes.VPCPeeringConnection{} - _ = acktags.NewTags() - ACKSystemTags = []string{"services.k8s.aws/namespace", "services.k8s.aws/controller-version"} + _ = svcapitypes.VPCPeeringConnection{} + _ = acktags.NewTags() ) // convertToOrderedACKTags converts the tags parameter into 'acktags.Tags' shape. @@ -79,13 +78,14 @@ func fromACKTags(tags acktags.Tags, keyOrder []string) []*svcapitypes.Tag { } // 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) } }