ZhiQiang Fan 7235a4a775 feature: support data disks for tencentcloud builder
Data disk is an important feature for instances and images, this
patch implements the basic functionality of it. More work needs
to be done to make it friendly to users. Docs has pointed out
current limitation.

Also update dependencies because this feature requires new code in
tencentcloud go sdk.
2019-06-30 00:05:38 +08:00

153 lines
4.3 KiB
Go

package cvm
import (
"context"
"fmt"
"log"
"github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/communicator"
"github.com/hashicorp/packer/helper/config"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
const BuilderId = "tencent.cloud"
type Config struct {
common.PackerConfig `mapstructure:",squash"`
TencentCloudAccessConfig `mapstructure:",squash"`
TencentCloudImageConfig `mapstructure:",squash"`
TencentCloudRunConfig `mapstructure:",squash"`
ctx interpolate.Context
}
type Builder struct {
config Config
runner multistep.Runner
}
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
err := config.Decode(&b.config, &config.DecodeOpts{
Interpolate: true,
InterpolateContext: &b.config.ctx,
InterpolateFilter: &interpolate.RenderFilter{
Exclude: []string{
"run_command",
},
},
}, raws...)
b.config.ctx.EnableEnv = true
if err != nil {
return nil, err
}
// Accumulate any errors
var errs *packer.MultiError
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudAccessConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudImageConfig.Prepare(&b.config.ctx)...)
errs = packer.MultiErrorAppend(errs, b.config.TencentCloudRunConfig.Prepare(&b.config.ctx)...)
if errs != nil && len(errs.Errors) > 0 {
return nil, errs
}
packer.LogSecretFilter.Set(b.config.SecretId, b.config.SecretKey)
log.Println(b.config)
return nil, nil
}
func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (packer.Artifact, error) {
cvmClient, vpcClient, err := b.config.Client()
if err != nil {
return nil, err
}
state := new(multistep.BasicStateBag)
state.Put("config", &b.config)
state.Put("cvm_client", cvmClient)
state.Put("vpc_client", vpcClient)
state.Put("hook", hook)
state.Put("ui", ui)
var steps []multistep.Step
// Build the steps
steps = []multistep.Step{
&stepCheckSourceImage{b.config.SourceImageId},
&stepConfigKeyPair{
Debug: b.config.PackerDebug,
Comm: &b.config.Comm,
DebugKeyPath: fmt.Sprintf("cvm_%s.pem", b.config.PackerBuildName),
},
&stepConfigVPC{
VpcId: b.config.VpcId,
CidrBlock: b.config.CidrBlock,
VpcName: b.config.VpcName,
},
&stepConfigSubnet{
SubnetId: b.config.SubnetId,
SubnetCidrBlock: b.config.SubnectCidrBlock,
SubnetName: b.config.SubnetName,
Zone: b.config.Zone,
},
&stepConfigSecurityGroup{
SecurityGroupId: b.config.SecurityGroupId,
SecurityGroupName: b.config.SecurityGroupName,
Description: "a simple security group",
},
&stepRunInstance{
InstanceType: b.config.InstanceType,
UserData: b.config.UserData,
UserDataFile: b.config.UserDataFile,
ZoneId: b.config.Zone,
InstanceName: b.config.InstanceName,
DiskType: b.config.DiskType,
DiskSize: b.config.DiskSize,
DataDisks: b.config.DataDisks,
HostName: b.config.HostName,
InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
Tags: b.config.RunTags,
},
&communicator.StepConnect{
Config: &b.config.TencentCloudRunConfig.Comm,
SSHConfig: b.config.TencentCloudRunConfig.Comm.SSHConfigFunc(),
Host: SSHHost(b.config.AssociatePublicIpAddress),
},
&common.StepProvision{},
&common.StepCleanupTempKeys{
Comm: &b.config.TencentCloudRunConfig.Comm,
},
// We need this step to detach temporary key from instance, otherwise
// it always fails to delete the key.
&stepDetachTempKeyPair{},
&stepCreateImage{},
&stepShareImage{
b.config.ImageShareAccounts,
},
&stepCopyImage{
DesinationRegions: b.config.ImageCopyRegions,
SourceRegion: b.config.Region,
},
}
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
b.runner.Run(ctx, state)
if rawErr, ok := state.GetOk("error"); ok {
return nil, rawErr.(error)
}
if _, ok := state.GetOk("image"); !ok {
return nil, nil
}
artifact := &Artifact{
TencentCloudImages: state.Get("tencentcloudimages").(map[string]string),
BuilderIdValue: BuilderId,
Client: cvmClient,
}
return artifact, nil
}