2017-03-03 03:56:17 -05:00
|
|
|
package ecs
|
|
|
|
|
|
|
|
import (
|
2018-01-22 18:32:33 -05:00
|
|
|
"context"
|
2019-04-25 22:37:49 -04:00
|
|
|
"encoding/base64"
|
2017-03-03 03:56:17 -05:00
|
|
|
"fmt"
|
2017-05-25 21:49:35 -04:00
|
|
|
"io/ioutil"
|
2019-04-25 22:37:49 -04:00
|
|
|
"strconv"
|
2017-05-25 21:49:35 -04:00
|
|
|
|
2020-11-12 17:44:02 -05:00
|
|
|
"github.com/hashicorp/packer/packer-plugin-sdk/uuid"
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
|
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
|
2017-04-17 09:04:52 -04:00
|
|
|
"github.com/hashicorp/packer/packer"
|
2020-11-17 19:31:03 -05:00
|
|
|
"github.com/hashicorp/packer/packer-plugin-sdk/multistep"
|
2020-11-18 13:34:59 -05:00
|
|
|
confighelper "github.com/hashicorp/packer/packer-plugin-sdk/template/config"
|
2017-03-03 03:56:17 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
type stepCreateAlicloudInstance struct {
|
2019-08-22 16:59:38 -04:00
|
|
|
IOOptimized confighelper.Trilean
|
2017-03-03 03:56:17 -05:00
|
|
|
InstanceType string
|
|
|
|
UserData string
|
|
|
|
UserDataFile string
|
|
|
|
instanceId string
|
|
|
|
RegionId string
|
|
|
|
InternetChargeType string
|
|
|
|
InternetMaxBandwidthOut int
|
2018-03-13 04:04:50 -04:00
|
|
|
InstanceName string
|
2017-03-03 03:56:17 -05:00
|
|
|
ZoneId string
|
2019-04-25 22:37:49 -04:00
|
|
|
instance *ecs.Instance
|
|
|
|
}
|
|
|
|
|
|
|
|
var createInstanceRetryErrors = []string{
|
|
|
|
"IdempotentProcessing",
|
|
|
|
}
|
|
|
|
|
|
|
|
var deleteInstanceRetryErrors = []string{
|
|
|
|
"IncorrectInstanceStatus.Initializing",
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
|
|
|
|
2019-03-29 11:50:02 -04:00
|
|
|
func (s *stepCreateAlicloudInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
2019-04-25 22:37:49 -04:00
|
|
|
client := state.Get("client").(*ClientWrapper)
|
2017-03-03 03:56:17 -05:00
|
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
|
2019-04-25 22:37:49 -04:00
|
|
|
ui.Say("Creating instance...")
|
|
|
|
createInstanceRequest, err := s.buildCreateInstanceRequest(state)
|
|
|
|
if err != nil {
|
|
|
|
return halt(state, err, "")
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
createInstanceResponse, err := client.WaitForExpected(&WaitForExpectArgs{
|
|
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
|
|
return client.CreateInstance(createInstanceRequest)
|
|
|
|
},
|
|
|
|
EvalFunc: client.EvalCouldRetryResponse(createInstanceRetryErrors, EvalRetryErrorType),
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return halt(state, err, "Error creating instance")
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
instanceId := createInstanceResponse.(*ecs.CreateInstanceResponse).InstanceId
|
|
|
|
|
|
|
|
_, err = client.WaitForInstanceStatus(s.RegionId, instanceId, InstanceStatusStopped)
|
2017-03-03 03:56:17 -05:00
|
|
|
if err != nil {
|
2019-04-25 22:37:49 -04:00
|
|
|
return halt(state, err, "Error waiting create instance")
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
describeInstancesRequest := ecs.CreateDescribeInstancesRequest()
|
|
|
|
describeInstancesRequest.InstanceIds = fmt.Sprintf("[\"%s\"]", instanceId)
|
|
|
|
instances, err := client.DescribeInstances(describeInstancesRequest)
|
2017-03-03 03:56:17 -05:00
|
|
|
if err != nil {
|
2019-04-25 22:37:49 -04:00
|
|
|
return halt(state, err, "")
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
ui.Message(fmt.Sprintf("Created instance: %s", instanceId))
|
|
|
|
s.instance = &instances.Instances.Instance[0]
|
|
|
|
state.Put("instance", s.instance)
|
2019-12-13 14:57:01 -05:00
|
|
|
// instance_id is the generic term used so that users can have access to the
|
|
|
|
// instance id inside of the provisioners, used in step_provision.
|
|
|
|
state.Put("instance_id", instanceId)
|
2017-03-03 03:56:17 -05:00
|
|
|
|
|
|
|
return multistep.ActionContinue
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stepCreateAlicloudInstance) Cleanup(state multistep.StateBag) {
|
|
|
|
if s.instance == nil {
|
|
|
|
return
|
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
cleanUpMessage(state, "instance")
|
|
|
|
|
|
|
|
client := state.Get("client").(*ClientWrapper)
|
2017-03-03 03:56:17 -05:00
|
|
|
ui := state.Get("ui").(packer.Ui)
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
_, err := client.WaitForExpected(&WaitForExpectArgs{
|
|
|
|
RequestFunc: func() (responses.AcsResponse, error) {
|
|
|
|
request := ecs.CreateDeleteInstanceRequest()
|
|
|
|
request.InstanceId = s.instance.InstanceId
|
|
|
|
request.Force = requests.NewBoolean(true)
|
|
|
|
return client.DeleteInstance(request)
|
|
|
|
},
|
|
|
|
EvalFunc: client.EvalCouldRetryResponse(deleteInstanceRetryErrors, EvalRetryErrorType),
|
|
|
|
RetryTimes: shortRetryTimes,
|
|
|
|
})
|
|
|
|
|
2017-03-03 03:56:17 -05:00
|
|
|
if err != nil {
|
2019-04-25 22:37:49 -04:00
|
|
|
ui.Say(fmt.Sprintf("Failed to clean up instance %s: %s", s.instance.InstanceId, err))
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stepCreateAlicloudInstance) buildCreateInstanceRequest(state multistep.StateBag) (*ecs.CreateInstanceRequest, error) {
|
|
|
|
request := ecs.CreateCreateInstanceRequest()
|
|
|
|
request.ClientToken = uuid.TimeOrderedUUID()
|
|
|
|
request.RegionId = s.RegionId
|
|
|
|
request.InstanceType = s.InstanceType
|
|
|
|
request.InstanceName = s.InstanceName
|
|
|
|
request.ZoneId = s.ZoneId
|
|
|
|
|
|
|
|
sourceImage := state.Get("source_image").(*ecs.Image)
|
|
|
|
request.ImageId = sourceImage.ImageId
|
2017-03-03 03:56:17 -05:00
|
|
|
|
2019-04-25 22:37:49 -04:00
|
|
|
securityGroupId := state.Get("securitygroupid").(string)
|
|
|
|
request.SecurityGroupId = securityGroupId
|
|
|
|
|
|
|
|
networkType := state.Get("networktype").(InstanceNetWork)
|
|
|
|
if networkType == InstanceNetworkVpc {
|
|
|
|
vswitchId := state.Get("vswitchid").(string)
|
|
|
|
request.VSwitchId = vswitchId
|
|
|
|
|
|
|
|
userData, err := s.getUserData(state)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
request.UserData = userData
|
|
|
|
} else {
|
|
|
|
if s.InternetChargeType == "" {
|
|
|
|
s.InternetChargeType = "PayByTraffic"
|
|
|
|
}
|
|
|
|
|
|
|
|
if s.InternetMaxBandwidthOut == 0 {
|
|
|
|
s.InternetMaxBandwidthOut = 5
|
|
|
|
}
|
|
|
|
}
|
|
|
|
request.InternetChargeType = s.InternetChargeType
|
|
|
|
request.InternetMaxBandwidthOut = requests.Integer(convertNumber(s.InternetMaxBandwidthOut))
|
|
|
|
|
2019-08-22 16:59:38 -04:00
|
|
|
if s.IOOptimized.True() {
|
|
|
|
request.IoOptimized = IOOptimizedOptimized
|
2019-08-23 05:17:45 -04:00
|
|
|
} else if s.IOOptimized.False() {
|
2019-08-22 16:59:38 -04:00
|
|
|
request.IoOptimized = IOOptimizedNone
|
2019-04-25 22:37:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
config := state.Get("config").(*Config)
|
|
|
|
password := config.Comm.SSHPassword
|
|
|
|
if password == "" && config.Comm.WinRMPassword != "" {
|
|
|
|
password = config.Comm.WinRMPassword
|
|
|
|
}
|
|
|
|
request.Password = password
|
|
|
|
|
|
|
|
systemDisk := config.AlicloudImageConfig.ECSSystemDiskMapping
|
|
|
|
request.SystemDiskDiskName = systemDisk.DiskName
|
|
|
|
request.SystemDiskCategory = systemDisk.DiskCategory
|
|
|
|
request.SystemDiskSize = requests.Integer(convertNumber(systemDisk.DiskSize))
|
|
|
|
request.SystemDiskDescription = systemDisk.Description
|
|
|
|
|
|
|
|
imageDisks := config.AlicloudImageConfig.ECSImagesDiskMappings
|
|
|
|
var dataDisks []ecs.CreateInstanceDataDisk
|
|
|
|
for _, imageDisk := range imageDisks {
|
|
|
|
var dataDisk ecs.CreateInstanceDataDisk
|
|
|
|
dataDisk.DiskName = imageDisk.DiskName
|
|
|
|
dataDisk.Category = imageDisk.DiskCategory
|
|
|
|
dataDisk.Size = string(convertNumber(imageDisk.DiskSize))
|
|
|
|
dataDisk.SnapshotId = imageDisk.SnapshotId
|
|
|
|
dataDisk.Description = imageDisk.Description
|
|
|
|
dataDisk.DeleteWithInstance = strconv.FormatBool(imageDisk.DeleteWithInstance)
|
|
|
|
dataDisk.Device = imageDisk.Device
|
2019-08-22 16:52:29 -04:00
|
|
|
if imageDisk.Encrypted != confighelper.TriUnset {
|
|
|
|
dataDisk.Encrypted = strconv.FormatBool(imageDisk.Encrypted.True())
|
2019-04-26 03:12:07 -04:00
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
|
|
|
dataDisks = append(dataDisks, dataDisk)
|
|
|
|
}
|
|
|
|
request.DataDisk = &dataDisks
|
|
|
|
|
|
|
|
return request, nil
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *stepCreateAlicloudInstance) getUserData(state multistep.StateBag) (string, error) {
|
|
|
|
userData := s.UserData
|
2019-04-25 22:37:49 -04:00
|
|
|
|
2017-03-03 03:56:17 -05:00
|
|
|
if s.UserDataFile != "" {
|
|
|
|
data, err := ioutil.ReadFile(s.UserDataFile)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2019-04-25 22:37:49 -04:00
|
|
|
|
2017-03-03 03:56:17 -05:00
|
|
|
userData = string(data)
|
|
|
|
}
|
|
|
|
|
2019-04-25 22:37:49 -04:00
|
|
|
if userData != "" {
|
|
|
|
userData = base64.StdEncoding.EncodeToString([]byte(userData))
|
2018-10-30 08:15:47 -04:00
|
|
|
}
|
|
|
|
|
2019-04-25 22:37:49 -04:00
|
|
|
return userData, nil
|
|
|
|
|
2017-03-03 03:56:17 -05:00
|
|
|
}
|