diff --git a/pkg/cloud/aws/actuators/machine/actuator.go b/pkg/cloud/aws/actuators/machine/actuator.go index e376923c65..0540a89eb0 100644 --- a/pkg/cloud/aws/actuators/machine/actuator.go +++ b/pkg/cloud/aws/actuators/machine/actuator.go @@ -69,6 +69,21 @@ type ActuatorParams struct { AwsClientBuilder awsclient.AwsClientBuilderFuncType } +// Scan machine tags, and return a deduped tags list +func removeDuplicatedTags(tags []*ec2.Tag) []*ec2.Tag { + m := make(map[string]bool) + result := []*ec2.Tag{} + + // look for duplicates + for _, entry := range tags { + if _, value := m[*entry.Key]; !value { + m[*entry.Key] = true + result = append(result, entry) + } + } + return result +} + // NewActuator returns a new AWS Actuator func NewActuator(params ActuatorParams) (*Actuator, error) { actuator := &Actuator{ @@ -339,16 +354,16 @@ func (a *Actuator) CreateMachine(cluster *clusterv1.Cluster, machine *clusterv1. return nil, err } // Add tags to the created machine - tagList := []*ec2.Tag{} + rawTagList := []*ec2.Tag{} for _, tag := range machineProviderConfig.Tags { - tagList = append(tagList, &ec2.Tag{Key: aws.String(tag.Name), Value: aws.String(tag.Value)}) + rawTagList = append(rawTagList, &ec2.Tag{Key: aws.String(tag.Name), Value: aws.String(tag.Value)}) } - tagList = append(tagList, []*ec2.Tag{ + rawTagList = append(rawTagList, []*ec2.Tag{ {Key: aws.String("clusterid"), Value: aws.String(clusterID)}, {Key: aws.String("kubernetes.io/cluster/" + clusterID), Value: aws.String("owned")}, {Key: aws.String("Name"), Value: aws.String(machine.Name)}, }...) - + tagList := removeDuplicatedTags(rawTagList) tagInstance := &ec2.TagSpecification{ ResourceType: aws.String("instance"), Tags: tagList, diff --git a/pkg/cloud/aws/actuators/machine/actuator_test.go b/pkg/cloud/aws/actuators/machine/actuator_test.go index c1b62efb34..be857ac83e 100644 --- a/pkg/cloud/aws/actuators/machine/actuator_test.go +++ b/pkg/cloud/aws/actuators/machine/actuator_test.go @@ -4,6 +4,7 @@ import ( "bytes" "errors" "fmt" + "reflect" "strings" "testing" "time" @@ -292,3 +293,49 @@ func mockTerminateInstances(mockAWSClient *mockaws.MockClient) { mockAWSClient.EXPECT().TerminateInstances(gomock.Any()).Return( &ec2.TerminateInstancesOutput{}, nil) } + +func TestRemoveDuplicatedTags(t *testing.T) { + cases := []struct { + tagList []*ec2.Tag + expected []*ec2.Tag + }{ + { + // empty tags + tagList: []*ec2.Tag{}, + expected: []*ec2.Tag{}, + }, + { + // no duplicate tags + tagList: []*ec2.Tag{ + {Key: aws.String("clusterID"), Value: aws.String("test-ClusterIDValue")}, + {Key: aws.String("clusterName"), Value: aws.String("test-ClusterNameValue")}, + }, + expected: []*ec2.Tag{ + {Key: aws.String("clusterID"), Value: aws.String("test-ClusterIDValue")}, + {Key: aws.String("clusterName"), Value: aws.String("test-ClusterNameValue")}, + }, + }, + { + // multiple duplicate tags + tagList: []*ec2.Tag{ + {Key: aws.String("clusterID"), Value: aws.String("test-ClusterIDValue")}, + {Key: aws.String("clusterName"), Value: aws.String("test-ClusterNameValue")}, + {Key: aws.String("clusterSize"), Value: aws.String("test-ClusterSizeValue")}, + {Key: aws.String("clusterName"), Value: aws.String("test-ClusterNameDuplicatedValue")}, + {Key: aws.String("clusterSize"), Value: aws.String("test-ClusterSizeDuplicatedValue")}, + }, + expected: []*ec2.Tag{ + {Key: aws.String("clusterID"), Value: aws.String("test-ClusterIDValue")}, + {Key: aws.String("clusterName"), Value: aws.String("test-ClusterNameValue")}, + {Key: aws.String("clusterSize"), Value: aws.String("test-ClusterSizeValue")}, + }, + }, + } + + for i, c := range cases { + actual := removeDuplicatedTags(c.tagList) + if !reflect.DeepEqual(c.expected, actual) { + t.Errorf("test #%d: expected %+v, got %+v", i, c.expected, actual) + } + } +}