1c7b23357d
Tencent Cloud key pair cannot be removed if it is in a image, so when user doesn't specify any log in method, such as ssh_password, temporary key pair will be created and used, which eventually will always fail. This patch detach temporary key pair before creating image, so in cleanup step, it can be deleted correctly. Note that if user specifies a private key pair, we do not detach it, because user might want to use it when creating new instances from this image.
151 lines
4.2 KiB
Go
151 lines
4.2 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,
|
|
HostName: b.config.HostName,
|
|
InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
|
|
AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
|
|
},
|
|
&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
|
|
}
|