From b8a3e3b8f4c63af6520f04b1f294894a198058bb Mon Sep 17 00:00:00 2001 From: "bozhi.ch" Date: Sun, 16 Sep 2018 18:16:13 +0800 Subject: [PATCH] support adding tags to image --- builder/alicloud/ecs/builder.go | 3 + builder/alicloud/ecs/builder_acc_test.go | 72 +++++++++++++++++++ builder/alicloud/ecs/image_config.go | 23 +++--- builder/alicloud/ecs/image_config_test.go | 18 +++++ builder/alicloud/ecs/step_create_tags.go | 41 +++++++++++ .../source/docs/builders/alicloud-ecs.html.md | 2 + 6 files changed, 148 insertions(+), 11 deletions(-) create mode 100644 builder/alicloud/ecs/step_create_tags.go diff --git a/builder/alicloud/ecs/builder.go b/builder/alicloud/ecs/builder.go index 3b2688b1f..ed75de142 100644 --- a/builder/alicloud/ecs/builder.go +++ b/builder/alicloud/ecs/builder.go @@ -169,6 +169,9 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe AlicloudImageName: b.config.AlicloudImageName, }, &stepCreateAlicloudImage{}, + &stepCreateTags{ + Tags: b.config.AlicloudImageTags, + }, &stepRegionCopyAlicloudImage{ AlicloudImageDestinationRegions: b.config.AlicloudImageDestinationRegions, AlicloudImageDestinationNames: b.config.AlicloudImageDestinationNames, diff --git a/builder/alicloud/ecs/builder_acc_test.go b/builder/alicloud/ecs/builder_acc_test.go index 415bfcf8b..77094f019 100644 --- a/builder/alicloud/ecs/builder_acc_test.go +++ b/builder/alicloud/ecs/builder_acc_test.go @@ -113,6 +113,17 @@ func TestBuilderAcc_forceDeleteSnapshot(t *testing.T) { }) } +func TestBuilderAcc_imageTags(t *testing.T) { + builderT.Test(t, builderT.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Builder: &Builder{}, + Template: testBuilderAccImageTags, + Check: checkImageTags(), + }) +} + func checkSnapshotsDeleted(snapshotIds []string) builderT.TestCheckFunc { return func(artifacts []packer.Artifact) error { // Verify the snapshots are gone @@ -207,6 +218,51 @@ func checkRegionCopy(regions []string) builderT.TestCheckFunc { } } +func checkImageTags() builderT.TestCheckFunc { + return func(artifacts []packer.Artifact) error { + if len(artifacts) > 1 { + return fmt.Errorf("more than 1 artifact") + } + // Get the actual *Artifact pointer so we can access the AMIs directly + artifactRaw := artifacts[0] + artifact, ok := artifactRaw.(*Artifact) + if !ok { + return fmt.Errorf("unknown artifact: %#v", artifactRaw) + } + // describe the image, get block devices with a snapshot + client, _ := testAliyunClient() + tags, _, err := client.DescribeTags( + &ecs.DescribeTagsArgs{ + RegionId: "cn-beijing", + ResourceType: ecs.TagResourceImage, + ResourceId: artifact.AlicloudImages["cn-beijing"], + }) + if err != nil { + return fmt.Errorf("Error retrieving Image Attributes for ECS Image Artifact (%#v) "+ + "in ECS Image Tags Test: %s", artifact, err) + } + failed := false + if len(tags) != 2 { + failed = true + } + if !failed { + for i := 0; i < len(tags); i++ { + if tags[i].TagKey == "TagKey1" && tags[i].TagValue != "TagValue1" { + failed = true + } else if tags[i].TagKey == "TagKey2" && tags[i].TagValue != "TagValue2" { + failed = true + } else if tags[i].TagKey != "TagKey1" && tags[i].TagKey != "TagKey2" { + failed = true + } + } + } + if failed { + return fmt.Errorf("tags is not correctly set %#v", tags) + } + return nil + } +} + func testAccPreCheck(t *testing.T) { if v := os.Getenv("ALICLOUD_ACCESS_KEY"); v == "" { t.Fatal("ALICLOUD_ACCESS_KEY must be set for acceptance tests") @@ -306,6 +362,22 @@ const testBuilderAccSharing = ` } ` +const testBuilderAccImageTags = ` +{ "builders": [{ + "type": "test", + "region": "cn-beijing", + "instance_type": "ecs.n1.tiny", + "source_image":"ubuntu_16_0402_64_20G_alibase_20180409.vhd", + "ssh_username": "root", + "io_optimized":"true", + "image_name": "packer-test_{{timestamp}}", + "tags": { + "TagKey1": "TagValue1", + "TagKey2": "TagValue2" + } + }] +}` + func buildForceDeregisterConfig(val, name string) string { return fmt.Sprintf(testBuilderAccForceDelete, val, name) } diff --git a/builder/alicloud/ecs/image_config.go b/builder/alicloud/ecs/image_config.go index d747009ef..32ca0ddca 100644 --- a/builder/alicloud/ecs/image_config.go +++ b/builder/alicloud/ecs/image_config.go @@ -25,17 +25,18 @@ type AlicloudDiskDevices struct { } type AlicloudImageConfig struct { - AlicloudImageName string `mapstructure:"image_name"` - AlicloudImageVersion string `mapstructure:"image_version"` - AlicloudImageDescription string `mapstructure:"image_description"` - AlicloudImageShareAccounts []string `mapstructure:"image_share_account"` - AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"` - AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"` - AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"` - AlicloudImageForceDelete bool `mapstructure:"image_force_delete"` - AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"` - AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"` - AlicloudImageSkipRegionValidation bool `mapstructure:"skip_region_validation"` + AlicloudImageName string `mapstructure:"image_name"` + AlicloudImageVersion string `mapstructure:"image_version"` + AlicloudImageDescription string `mapstructure:"image_description"` + AlicloudImageShareAccounts []string `mapstructure:"image_share_account"` + AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"` + AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"` + AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"` + AlicloudImageForceDelete bool `mapstructure:"image_force_delete"` + AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"` + AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"` + AlicloudImageSkipRegionValidation bool `mapstructure:"skip_region_validation"` + AlicloudImageTags map[string]string `mapstructure:"tags"` AlicloudDiskDevices `mapstructure:",squash"` } diff --git a/builder/alicloud/ecs/image_config_test.go b/builder/alicloud/ecs/image_config_test.go index bb4581871..949511ef0 100644 --- a/builder/alicloud/ecs/image_config_test.go +++ b/builder/alicloud/ecs/image_config_test.go @@ -55,6 +55,24 @@ func TestAMIConfigPrepare_regions(t *testing.T) { } +func TestECSImageConfigPrepare_imageTags(t *testing.T) { + c := testAlicloudImageConfig() + c.AlicloudImageTags = map[string]string{ + "TagKey1": "TagValue1", + "TagKey2": "TagValue2", + } + if err := c.Prepare(nil); len(err) != 0 { + t.Fatalf("err: %s", err) + } + if len(c.AlicloudImageTags) != 2 || c.AlicloudImageTags["TagKey1"] != "TagValue1" || + c.AlicloudImageTags["TagKey2"] != "TagValue2" { + t.Fatalf("invalid value, expected: %s, actual: %s", map[string]string{ + "TagKey1": "TagValue1", + "TagKey2": "TagValue2", + }, c.AlicloudImageTags) + } +} + func regionsToString() []string { var regions []string for _, region := range common.ValidRegions { diff --git a/builder/alicloud/ecs/step_create_tags.go b/builder/alicloud/ecs/step_create_tags.go new file mode 100644 index 000000000..36fd0022e --- /dev/null +++ b/builder/alicloud/ecs/step_create_tags.go @@ -0,0 +1,41 @@ +package ecs + +import ( + "context" + "fmt" + "github.com/denverdino/aliyungo/common" + "github.com/denverdino/aliyungo/ecs" + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +type stepCreateTags struct { + Tags map[string]string +} + +func (s *stepCreateTags) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + config := state.Get("config").(Config) + client := state.Get("client").(*ecs.Client) + ui := state.Get("ui").(packer.Ui) + imageId := state.Get("alicloudimage").(string) + if len(s.Tags) == 0 { + return multistep.ActionContinue + } + ui.Say(fmt.Sprintf("Adding tags(%s) to image: %s", s.Tags, imageId)) + err := client.AddTags(&ecs.AddTagsArgs{ + ResourceId: imageId, + ResourceType: ecs.TagResourceImage, + RegionId: common.Region(config.AlicloudRegion), + Tag: s.Tags, + }) + if err != nil { + err := fmt.Errorf("Error Adding tags to image: %s", err) + state.Put("error", err) + ui.Say(err.Error()) + return multistep.ActionHalt + } + return multistep.ActionContinue +} +func (s *stepCreateTags) Cleanup(state multistep.StateBag) { + // Nothing need to do, tags will be cleaned when the resource is cleaned +} diff --git a/website/source/docs/builders/alicloud-ecs.html.md b/website/source/docs/builders/alicloud-ecs.html.md index 266b59445..97c08cd84 100644 --- a/website/source/docs/builders/alicloud-ecs.html.md +++ b/website/source/docs/builders/alicloud-ecs.html.md @@ -190,6 +190,8 @@ builder. - `zone_id` (string) - ID of the zone to which the disk belongs. +- `tags` (object of key/value strings) - Tags applied to the destination image. + ## Basic Example Here is a basic example for Alicloud.