From 057ab28d4c1d89e4e53639bfcf711f2ce485632b Mon Sep 17 00:00:00 2001 From: Ciprian Hacman Date: Wed, 4 Nov 2020 12:05:00 +0200 Subject: [PATCH] Update LaunchTemplate tags on changes --- .../awstasks/launchtemplate_target_api.go | 7 ++- upup/pkg/fi/cloudup/awsup/aws_apitarget.go | 10 ++++ upup/pkg/fi/cloudup/awsup/aws_cloud.go | 53 +++++++++++++++++-- upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go | 4 ++ 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/upup/pkg/fi/cloudup/awstasks/launchtemplate_target_api.go b/upup/pkg/fi/cloudup/awstasks/launchtemplate_target_api.go index f397bda177..c3a3fb0273 100644 --- a/upup/pkg/fi/cloudup/awstasks/launchtemplate_target_api.go +++ b/upup/pkg/fi/cloudup/awstasks/launchtemplate_target_api.go @@ -149,7 +149,6 @@ func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, e, changes *LaunchT } e.ID = output.LaunchTemplate.LaunchTemplateId } else { - // TODO: Update the LaunchTemplate tags input := &ec2.CreateLaunchTemplateVersionInput{ LaunchTemplateName: t.Name, LaunchTemplateData: data, @@ -157,6 +156,12 @@ func (t *LaunchTemplate) RenderAWS(c *awsup.AWSAPITarget, a, e, changes *LaunchT if _, err = c.Cloud.EC2().CreateLaunchTemplateVersion(input); err != nil { return fmt.Errorf("error creating LaunchTemplateVersion: %v", err) } + if changes.Tags != nil { + err = c.UpdateTags(fi.StringValue(a.ID), e.Tags) + if err != nil { + return fmt.Errorf("error updating LaunchTemplate tags: %v", err) + } + } e.ID = a.ID } diff --git a/upup/pkg/fi/cloudup/awsup/aws_apitarget.go b/upup/pkg/fi/cloudup/awsup/aws_apitarget.go index 22536f9b55..4e757e8616 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_apitarget.go +++ b/upup/pkg/fi/cloudup/awsup/aws_apitarget.go @@ -50,9 +50,19 @@ func (t *AWSAPITarget) AddAWSTags(id string, expected map[string]string) error { return t.Cloud.AddAWSTags(id, expected) } +func (t *AWSAPITarget) GetTags(id string) (map[string]string, error) { + return t.Cloud.GetTags(id) +} +func (t *AWSAPITarget) CreateTags(id string, tags map[string]string) error { + return t.Cloud.CreateTags(id, tags) +} func (t *AWSAPITarget) DeleteTags(id string, tags map[string]string) error { return t.Cloud.DeleteTags(id, tags) } +func (t *AWSAPITarget) UpdateTags(id string, tags map[string]string) error { + return t.Cloud.UpdateTags(id, tags) +} + func (t *AWSAPITarget) AddELBV2Tags(ResourceArn string, expected map[string]string) error { actual, err := t.Cloud.GetELBV2Tags(ResourceArn) if err != nil { diff --git a/upup/pkg/fi/cloudup/awsup/aws_cloud.go b/upup/pkg/fi/cloudup/awsup/aws_cloud.go index dc79952b03..9587becd2c 100644 --- a/upup/pkg/fi/cloudup/awsup/aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/aws_cloud.go @@ -122,9 +122,12 @@ type AWSCloud interface { // GetTags will fetch the tags for the specified resource, retrying (up to MaxDescribeTagsAttempts) if it hits an eventual-consistency type error GetTags(resourceId string) (map[string]string, error) - - // CreateTags will add tags to the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error + // CreateTags will add/modify tags to the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error CreateTags(resourceId string, tags map[string]string) error + // DeleteTags will remove tags from the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error + DeleteTags(resourceId string, tags map[string]string) error + // UpdateTags will update tags of the specified resource to match tags, using getTags(), createTags() and deleteTags() + UpdateTags(resourceId string, tags map[string]string) error AddAWSTags(id string, expected map[string]string) error GetELBTags(loadBalancerName string) (map[string]string, error) @@ -137,9 +140,6 @@ type AWSCloud interface { RemoveELBTags(loadBalancerName string, tags map[string]string) error RemoveELBV2Tags(ResourceArn string, tags map[string]string) error - // DeleteTags will delete tags from the specified resource, retrying up to MaxCreateTagsAttempts times if it hits an eventual-consistency type error - DeleteTags(id string, tags map[string]string) error - // DescribeInstance is a helper that queries for the specified instance by id DescribeInstance(instanceID string) (*ec2.Instance, error) @@ -1079,6 +1079,49 @@ func deleteTags(c AWSCloud, resourceID string, tags map[string]string) error { } } +// UpdateTags will update tags of the specified resource to match tags, +// using getTags(), createTags() and deleteTags() +func (c *awsCloudImplementation) UpdateTags(resourceID string, tags map[string]string) error { + return updateTags(c, resourceID, tags) +} + +func updateTags(c AWSCloud, resourceID string, expectedTags map[string]string) error { + actual, err := getTags(c, resourceID) + if err != nil { + return err + } + + missing := make(map[string]string) + for k, v := range expectedTags { + if actual[k] != v { + missing[k] = v + } + } + if len(missing) > 0 { + klog.V(4).Infof("Adding tags to %q: %v", resourceID, missing) + err = createTags(c, resourceID, missing) + if err != nil { + return err + } + } + + extra := make(map[string]string) + for k, v := range actual { + if _, ok := expectedTags[k]; !ok { + extra[k] = v + } + } + if len(extra) > 0 { + klog.V(4).Infof("Removing tags from %q: %v", resourceID, missing) + err := deleteTags(c, resourceID, extra) + if err != nil { + return err + } + } + + return nil +} + func (c *awsCloudImplementation) AddAWSTags(id string, expected map[string]string) error { return addAWSTags(c, id, expected) } diff --git a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go index adfbd57560..43f605f24a 100644 --- a/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go +++ b/upup/pkg/fi/cloudup/awsup/mock_aws_cloud.go @@ -158,6 +158,10 @@ func (c *MockAWSCloud) GetTags(resourceID string) (map[string]string, error) { return getTags(c, resourceID) } +func (c *MockAWSCloud) UpdateTags(id string, tags map[string]string) error { + return updateTags(c, id, tags) +} + func (c *MockAWSCloud) GetELBTags(loadBalancerName string) (map[string]string, error) { return getELBTags(c, loadBalancerName) }