Merge pull request #7574 from lrxcy/add_support_encryption

support encryption with default service key
This commit is contained in:
chhaj5236 2019-04-27 10:35:13 +08:00 committed by GitHub
commit 4639f92f63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 319 additions and 49 deletions

View File

@ -2,11 +2,12 @@ package ecs
import ( import (
"fmt" "fmt"
"os"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/template/interpolate" "github.com/hashicorp/packer/template/interpolate"
"github.com/hashicorp/packer/version" "github.com/hashicorp/packer/version"
"os"
"time"
) )
// Config of alicloud // Config of alicloud

View File

@ -82,7 +82,7 @@ func (a *Artifact) Destroy() error {
continue continue
} }
if images[0].IsCopied { if images[0].IsCopied && images[0].Status != ImageStatusAvailable {
copyingImages[regionId] = imageId copyingImages[regionId] = imageId
} else { } else {
sourceImage[regionId] = &images[0] sourceImage[regionId] = &images[0]

View File

@ -3,12 +3,13 @@ package ecs
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
builderT "github.com/hashicorp/packer/helper/builder/testing"
"github.com/hashicorp/packer/packer"
"os" "os"
"strings" "strings"
"testing" "testing"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
builderT "github.com/hashicorp/packer/helper/builder/testing"
"github.com/hashicorp/packer/packer"
) )
const defaultTestRegion = "cn-beijing" const defaultTestRegion = "cn-beijing"
@ -609,6 +610,200 @@ func checkImageTags() builderT.TestCheckFunc {
} }
} }
func TestBuilderAcc_dataDiskEncrypted(t *testing.T) {
t.Parallel()
builderT.Test(t, builderT.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Builder: &Builder{},
Template: testBuilderAccDataDiskEncrypted,
Check: checkDataDiskEncrypted(),
})
}
const testBuilderAccDataDiskEncrypted = `
{ "builders": [{
"type": "test",
"region": "cn-beijing",
"instance_type": "ecs.n1.tiny",
"source_image":"ubuntu_18_04_64_20G_alibase_20190223.vhd",
"io_optimized":"true",
"ssh_username":"root",
"image_name": "packer-test-dataDiskEncrypted_{{timestamp}}",
"image_disk_mappings": [
{
"disk_name": "data_disk1",
"disk_size": 25,
"disk_encrypted": true,
"disk_delete_with_instance": true
},
{
"disk_name": "data_disk2",
"disk_size": 35,
"disk_encrypted": false,
"disk_delete_with_instance": true
},
{
"disk_name": "data_disk3",
"disk_size": 45,
"disk_delete_with_instance": true
}
]
}]
}`
func checkDataDiskEncrypted() 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)
}
imageId := artifact.AlicloudImages[defaultTestRegion]
// describe the image, get block devices with a snapshot
client, _ := testAliyunClient()
describeImagesRequest := ecs.CreateDescribeImagesRequest()
describeImagesRequest.RegionId = defaultTestRegion
describeImagesRequest.ImageId = imageId
imagesResponse, err := client.DescribeImages(describeImagesRequest)
if err != nil {
return fmt.Errorf("describe images failed due to %s", err)
}
if len(imagesResponse.Images.Image) == 0 {
return fmt.Errorf("image %s generated can not be found", imageId)
}
image := imagesResponse.Images.Image[0]
var snapshotIds []string
for _, mapping := range image.DiskDeviceMappings.DiskDeviceMapping {
snapshotIds = append(snapshotIds, mapping.SnapshotId)
}
data, _ := json.Marshal(snapshotIds)
describeSnapshotRequest := ecs.CreateDescribeSnapshotsRequest()
describeSnapshotRequest.RegionId = defaultTestRegion
describeSnapshotRequest.SnapshotIds = string(data)
describeSnapshotsResponse, err := client.DescribeSnapshots(describeSnapshotRequest)
if err != nil {
return fmt.Errorf("describe data snapshots failed due to %s", err)
}
if len(describeSnapshotsResponse.Snapshots.Snapshot) != 4 {
return fmt.Errorf("expect %d data snapshots but got %d", len(snapshotIds), len(describeSnapshotsResponse.Snapshots.Snapshot))
}
snapshots := describeSnapshotsResponse.Snapshots.Snapshot
for _, snapshot := range snapshots {
if snapshot.SourceDiskType == DiskTypeSystem {
if snapshot.Encrypted != false {
return fmt.Errorf("the system snapshot expected to be non-encrypted but got true")
}
continue
}
if snapshot.SourceDiskSize == "25" && snapshot.Encrypted != true {
return fmt.Errorf("the first snapshot expected to be encrypted but got false")
}
if snapshot.SourceDiskSize == "35" && snapshot.Encrypted != false {
return fmt.Errorf("the second snapshot expected to be non-encrypted but got true")
}
if snapshot.SourceDiskSize == "45" && snapshot.Encrypted != false {
return fmt.Errorf("the third snapshot expected to be non-encrypted but got true")
}
}
return nil
}
}
func TestBuilderAcc_systemDiskEncrypted(t *testing.T) {
t.Parallel()
builderT.Test(t, builderT.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Builder: &Builder{},
Template: testBuilderAccSystemDiskEncrypted,
Check: checkSystemDiskEncrypted(),
})
}
const testBuilderAccSystemDiskEncrypted = `
{
"builders": [{
"type": "test",
"region": "cn-beijing",
"instance_type": "ecs.n1.tiny",
"source_image":"ubuntu_18_04_64_20G_alibase_20190223.vhd",
"io_optimized":"true",
"ssh_username":"root",
"image_name": "packer-test_{{timestamp}}",
"image_encrypted": "true"
}]
}`
func checkSystemDiskEncrypted() 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()
imageId := artifact.AlicloudImages[defaultTestRegion]
describeImagesRequest := ecs.CreateDescribeImagesRequest()
describeImagesRequest.RegionId = defaultTestRegion
describeImagesRequest.ImageId = imageId
describeImagesRequest.Status = ImageStatusQueried
imagesResponse, err := client.DescribeImages(describeImagesRequest)
if err != nil {
return fmt.Errorf("describe images failed due to %s", err)
}
if len(imagesResponse.Images.Image) == 0 {
return fmt.Errorf("image %s generated can not be found", imageId)
}
image := imagesResponse.Images.Image[0]
if image.IsCopied == false {
return fmt.Errorf("image %s generated expexted to be copied but false", image.ImageId)
}
describeSnapshotRequest := ecs.CreateDescribeSnapshotsRequest()
describeSnapshotRequest.RegionId = defaultTestRegion
describeSnapshotRequest.SnapshotIds = fmt.Sprintf("[\"%s\"]", image.DiskDeviceMappings.DiskDeviceMapping[0].SnapshotId)
describeSnapshotsResponse, err := client.DescribeSnapshots(describeSnapshotRequest)
if err != nil {
return fmt.Errorf("describe system snapshots failed due to %s", err)
}
snapshots := describeSnapshotsResponse.Snapshots.Snapshot[0]
if snapshots.Encrypted != true {
return fmt.Errorf("system snapshot of image %s expected to be encrypted but got false", imageId)
}
return nil
}
}
func testAccPreCheck(t *testing.T) { func testAccPreCheck(t *testing.T) {
if v := os.Getenv("ALICLOUD_ACCESS_KEY"); v == "" { if v := os.Getenv("ALICLOUD_ACCESS_KEY"); v == "" {
t.Fatal("ALICLOUD_ACCESS_KEY must be set for acceptance tests") t.Fatal("ALICLOUD_ACCESS_KEY must be set for acceptance tests")

View File

@ -2,10 +2,11 @@ package ecs
import ( import (
"fmt" "fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"time"
) )
type ClientWrapper struct { type ClientWrapper struct {

View File

@ -2,9 +2,10 @@ package ecs
import ( import (
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"testing" "testing"
"time" "time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
) )
func TestWaitForExpectedExceedRetryTimes(t *testing.T) { func TestWaitForExpectedExceedRetryTimes(t *testing.T) {

View File

@ -16,6 +16,7 @@ type AlicloudDiskDevice struct {
Description string `mapstructure:"disk_description"` Description string `mapstructure:"disk_description"`
DeleteWithInstance bool `mapstructure:"disk_delete_with_instance"` DeleteWithInstance bool `mapstructure:"disk_delete_with_instance"`
Device string `mapstructure:"disk_device"` Device string `mapstructure:"disk_device"`
Encrypted *bool `mapstructure:"disk_encrypted"`
} }
type AlicloudDiskDevices struct { type AlicloudDiskDevices struct {
@ -31,6 +32,7 @@ type AlicloudImageConfig struct {
AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"` AlicloudImageUNShareAccounts []string `mapstructure:"image_unshare_account"`
AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"` AlicloudImageDestinationRegions []string `mapstructure:"image_copy_regions"`
AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"` AlicloudImageDestinationNames []string `mapstructure:"image_copy_names"`
ImageEncrypted *bool `mapstructure:"image_encrypted"`
AlicloudImageForceDelete bool `mapstructure:"image_force_delete"` AlicloudImageForceDelete bool `mapstructure:"image_force_delete"`
AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"` AlicloudImageForceDeleteSnapshots bool `mapstructure:"image_force_delete_snapshots"`
AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"` AlicloudImageForceDeleteInstances bool `mapstructure:"image_force_delete_instances"`

View File

@ -3,6 +3,7 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"

View File

@ -3,6 +3,7 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"

View File

@ -3,6 +3,7 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/errors"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"

View File

@ -3,6 +3,7 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"

View File

@ -4,6 +4,7 @@ import (
"context" "context"
errorsNew "errors" errorsNew "errors"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"

View File

@ -3,6 +3,7 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"

View File

@ -3,12 +3,15 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/hashicorp/packer/common/random"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/common/uuid" "github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"time"
) )
type stepCreateAlicloudImage struct { type stepCreateAlicloudImage struct {
@ -26,10 +29,15 @@ func (s *stepCreateAlicloudImage) Run(ctx context.Context, state multistep.State
client := state.Get("client").(*ClientWrapper) client := state.Get("client").(*ClientWrapper)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
// Create the alicloud image tempImageName := config.AlicloudImageName
ui.Say(fmt.Sprintf("Creating image: %s", config.AlicloudImageName)) if config.ImageEncrypted != nil && *config.ImageEncrypted {
tempImageName = fmt.Sprintf("packer_%s", random.AlphaNum(7))
ui.Say(fmt.Sprintf("Creating temporary image for encryption: %s", tempImageName))
} else {
ui.Say(fmt.Sprintf("Creating image: %s", tempImageName))
}
createImageRequest := s.buildCreateImageRequest(state) createImageRequest := s.buildCreateImageRequest(state, tempImageName)
createImageResponse, err := client.WaitForExpected(&WaitForExpectArgs{ createImageResponse, err := client.WaitForExpected(&WaitForExpectArgs{
RequestFunc: func() (responses.AcsResponse, error) { RequestFunc: func() (responses.AcsResponse, error) {
return client.CreateImage(createImageRequest) return client.CreateImage(createImageRequest)
@ -43,20 +51,12 @@ func (s *stepCreateAlicloudImage) Run(ctx context.Context, state multistep.State
imageId := createImageResponse.(*ecs.CreateImageResponse).ImageId imageId := createImageResponse.(*ecs.CreateImageResponse).ImageId
_, err = client.WaitForImageStatus(config.AlicloudRegion, imageId, ImageStatusAvailable, time.Duration(s.WaitSnapshotReadyTimeout)*time.Second) imagesResponse, err := client.WaitForImageStatus(config.AlicloudRegion, imageId, ImageStatusAvailable, time.Duration(s.WaitSnapshotReadyTimeout)*time.Second)
if err != nil { if err != nil {
return halt(state, err, "Timeout waiting for image to be created") return halt(state, err, "Timeout waiting for image to be created")
} }
describeImagesRequest := ecs.CreateDescribeImagesRequest() images := imagesResponse.(*ecs.DescribeImagesResponse).Images.Image
describeImagesRequest.ImageId = imageId
describeImagesRequest.RegionId = config.AlicloudRegion
imagesResponse, err := client.DescribeImages(describeImagesRequest)
if err != nil {
return halt(state, err, "")
}
images := imagesResponse.Images.Image
if len(images) == 0 { if len(images) == 0 {
return halt(state, err, "Unable to find created image") return halt(state, err, "Unable to find created image")
} }
@ -83,17 +83,24 @@ func (s *stepCreateAlicloudImage) Cleanup(state multistep.StateBag) {
return return
} }
config := state.Get("config").(*Config)
encryptedSet := config.ImageEncrypted != nil && *config.ImageEncrypted
_, cancelled := state.GetOk(multistep.StateCancelled) _, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted) _, halted := state.GetOk(multistep.StateHalted)
if !cancelled && !halted {
if !cancelled && !halted && !encryptedSet {
return return
} }
client := state.Get("client").(*ClientWrapper) client := state.Get("client").(*ClientWrapper)
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
config := state.Get("config").(*Config)
ui.Say("Deleting the image because of cancellation or error...") if !cancelled && !halted && encryptedSet {
ui.Say(fmt.Sprintf("Deleting temporary image %s(%s) and related snapshots after finishing encryption...", s.image.ImageId, s.image.ImageName))
} else {
ui.Say("Deleting the image and related snapshots because of cancellation or error...")
}
deleteImageRequest := ecs.CreateDeleteImageRequest() deleteImageRequest := ecs.CreateDeleteImageRequest()
deleteImageRequest.RegionId = config.AlicloudRegion deleteImageRequest.RegionId = config.AlicloudRegion
@ -102,15 +109,25 @@ func (s *stepCreateAlicloudImage) Cleanup(state multistep.StateBag) {
ui.Error(fmt.Sprintf("Error deleting image, it may still be around: %s", err)) ui.Error(fmt.Sprintf("Error deleting image, it may still be around: %s", err))
return return
} }
//Delete the snapshot of this image
for _, diskDevices := range s.image.DiskDeviceMappings.DiskDeviceMapping {
deleteSnapshotRequest := ecs.CreateDeleteSnapshotRequest()
deleteSnapshotRequest.SnapshotId = diskDevices.SnapshotId
if _, err := client.DeleteSnapshot(deleteSnapshotRequest); err != nil {
ui.Error(fmt.Sprintf("Error deleting snapshot, it may still be around: %s", err))
return
}
}
} }
func (s *stepCreateAlicloudImage) buildCreateImageRequest(state multistep.StateBag) *ecs.CreateImageRequest { func (s *stepCreateAlicloudImage) buildCreateImageRequest(state multistep.StateBag, imageName string) *ecs.CreateImageRequest {
config := state.Get("config").(*Config) config := state.Get("config").(*Config)
request := ecs.CreateCreateImageRequest() request := ecs.CreateCreateImageRequest()
request.ClientToken = uuid.TimeOrderedUUID() request.ClientToken = uuid.TimeOrderedUUID()
request.RegionId = config.AlicloudRegion request.RegionId = config.AlicloudRegion
request.ImageName = config.AlicloudImageName request.ImageName = imageName
request.ImageVersion = config.AlicloudImageVersion request.ImageVersion = config.AlicloudImageVersion
request.Description = config.AlicloudImageDescription request.Description = config.AlicloudImageDescription

View File

@ -172,6 +172,9 @@ func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.
dataDisk.Description = imageDisk.Description dataDisk.Description = imageDisk.Description
dataDisk.DeleteWithInstance = strconv.FormatBool(imageDisk.DeleteWithInstance) dataDisk.DeleteWithInstance = strconv.FormatBool(imageDisk.DeleteWithInstance)
dataDisk.Device = imageDisk.Device dataDisk.Device = imageDisk.Device
if imageDisk.Encrypted != nil {
dataDisk.Encrypted = strconv.FormatBool(*imageDisk.Encrypted)
}
dataDisks = append(dataDisks, dataDisk) dataDisks = append(dataDisks, dataDisk)
} }

View File

@ -3,11 +3,12 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
"time"
) )
type stepCreateAlicloudSnapshot struct { type stepCreateAlicloudSnapshot struct {

View File

@ -3,7 +3,9 @@ package ecs
import ( import (
"context" "context"
"fmt" "fmt"
"time"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs" "github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/packer"
@ -16,17 +18,27 @@ type stepRegionCopyAlicloudImage struct {
} }
func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
if config.ImageEncrypted != nil {
s.AlicloudImageDestinationRegions = append(s.AlicloudImageDestinationRegions, s.RegionId)
s.AlicloudImageDestinationNames = append(s.AlicloudImageDestinationNames, config.AlicloudImageName)
}
if len(s.AlicloudImageDestinationRegions) == 0 { if len(s.AlicloudImageDestinationRegions) == 0 {
return multistep.ActionContinue return multistep.ActionContinue
} }
client := state.Get("client").(*ClientWrapper) client := state.Get("client").(*ClientWrapper)
imageId := state.Get("alicloudimage").(string) ui := state.Get("ui").(packer.Ui)
alicloudImages := state.Get("alicloudimages").(map[string]string)
srcImageId := state.Get("alicloudimage").(string)
alicloudImages := state.Get("alicloudimages").(map[string]string)
numberOfName := len(s.AlicloudImageDestinationNames) numberOfName := len(s.AlicloudImageDestinationNames)
ui.Say(fmt.Sprintf("Coping image %s from %s...", srcImageId, s.RegionId))
for index, destinationRegion := range s.AlicloudImageDestinationRegions { for index, destinationRegion := range s.AlicloudImageDestinationRegions {
if destinationRegion == s.RegionId { if destinationRegion == s.RegionId && config.ImageEncrypted == nil {
continue continue
} }
@ -37,30 +49,48 @@ func (s *stepRegionCopyAlicloudImage) Run(ctx context.Context, state multistep.S
copyImageRequest := ecs.CreateCopyImageRequest() copyImageRequest := ecs.CreateCopyImageRequest()
copyImageRequest.RegionId = s.RegionId copyImageRequest.RegionId = s.RegionId
copyImageRequest.ImageId = imageId copyImageRequest.ImageId = srcImageId
copyImageRequest.DestinationRegionId = destinationRegion copyImageRequest.DestinationRegionId = destinationRegion
copyImageRequest.DestinationImageName = ecsImageName copyImageRequest.DestinationImageName = ecsImageName
if config.ImageEncrypted != nil {
copyImageRequest.Encrypted = requests.NewBoolean(*config.ImageEncrypted)
}
image, err := client.CopyImage(copyImageRequest) imageResponse, err := client.CopyImage(copyImageRequest)
if err != nil { if err != nil {
return halt(state, err, "Error copying images") return halt(state, err, "Error copying images")
} }
alicloudImages[destinationRegion] = image.ImageId alicloudImages[destinationRegion] = imageResponse.ImageId
ui.Message(fmt.Sprintf("Copy image from %s(%s) to %s(%s)", s.RegionId, srcImageId, destinationRegion, imageResponse.ImageId))
} }
if config.ImageEncrypted != nil {
if _, err := client.WaitForImageStatus(s.RegionId, alicloudImages[s.RegionId], ImageStatusAvailable, time.Duration(ALICLOUD_DEFAULT_LONG_TIMEOUT)*time.Second); err != nil {
return halt(state, err, fmt.Sprintf("Timeout waiting image %s finish copying", alicloudImages[s.RegionId]))
}
}
return multistep.ActionContinue return multistep.ActionContinue
} }
func (s *stepRegionCopyAlicloudImage) Cleanup(state multistep.StateBag) { func (s *stepRegionCopyAlicloudImage) Cleanup(state multistep.StateBag) {
_, cancelled := state.GetOk(multistep.StateCancelled) _, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted) _, halted := state.GetOk(multistep.StateHalted)
if cancelled || halted {
if !cancelled && !halted {
return
}
ui := state.Get("ui").(packer.Ui) ui := state.Get("ui").(packer.Ui)
ui.Say(fmt.Sprintf("Stopping copy image because cancellation or error..."))
client := state.Get("client").(*ClientWrapper) client := state.Get("client").(*ClientWrapper)
alicloudImages := state.Get("alicloudimages").(map[string]string) alicloudImages := state.Get("alicloudimages").(map[string]string)
ui.Say(fmt.Sprintf("Stopping copy image because cancellation or error...")) srcImageId := state.Get("alicloudimage").(string)
for copiedRegionId, copiedImageId := range alicloudImages { for copiedRegionId, copiedImageId := range alicloudImages {
if copiedRegionId == s.RegionId { if copiedImageId == srcImageId {
continue continue
} }
@ -68,8 +98,8 @@ func (s *stepRegionCopyAlicloudImage) Cleanup(state multistep.StateBag) {
cancelCopyImageRequest.RegionId = copiedRegionId cancelCopyImageRequest.RegionId = copiedRegionId
cancelCopyImageRequest.ImageId = copiedImageId cancelCopyImageRequest.ImageId = copiedImageId
if _, err := client.CancelCopyImage(cancelCopyImageRequest); err != nil { if _, err := client.CancelCopyImage(cancelCopyImageRequest); err != nil {
ui.Say(fmt.Sprintf("Error cancelling copy image: %v", err))
} ui.Error(fmt.Sprintf("Error cancelling copy image: %v", err))
} }
} }
} }

View File

@ -73,6 +73,12 @@ builder.
- `image_copy_regions` (array of string) - Copy to the destination regionIds. - `image_copy_regions` (array of string) - Copy to the destination regionIds.
- `image_encrypted` (boolean) - Whether or not to encrypt the target images, including those copied if `image_copy_regions` is specified. If this option
is set to true, a temporary image will be created from the provisioned
instance in the main region and an encrypted copy will be generated in the
same region. By default, Packer will keep the encryption setting to what
it was in the source image.
- `image_description` (string) - The description of the image, with a length - `image_description` (string) - The description of the image, with a length
limit of 0 to 256 characters. Leaving it blank means null, which is the limit of 0 to 256 characters. Leaving it blank means null, which is the
default value. It cannot begin with `http://` or `https://`. default value. It cannot begin with `http://` or `https://`.
@ -148,6 +154,13 @@ builder.
Snapshots from on or before July 15, 2013 cannot be used to create a Snapshots from on or before July 15, 2013 cannot be used to create a
disk. disk.
- `disk_encrypted` (boolean) - Whether or not to encrypt the data disk.
If this option is set to true, the data disk will be encryped and corresponding snapshot in the target image will also be encrypted. By
default, if this is an extra data disk, Packer will not encrypt the
data disk. Otherwise, Packer will keep the encryption setting to what
it was in the source image. Please refer to Introduction of [ECS disk encryption](https://www.alibabacloud.com/help/doc-detail/59643.htm)
for more details.
- `image_ignore_data_disks`(boolean) - If this value is true, the image - `image_ignore_data_disks`(boolean) - If this value is true, the image
created will not include any snapshot of data disks. This option would be created will not include any snapshot of data disks. This option would be
useful for any circumstance that default data disks with instance types are useful for any circumstance that default data disks with instance types are