Merge pull request #7574 from lrxcy/add_support_encryption
support encryption with default service key
This commit is contained in:
commit
4639f92f63
|
@ -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
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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"`
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue