github.phpd.cn/hashicorp/packer@v1.3.2/builder/alicloud/ecs/builder.go (about) 1 // The alicloud contains a packer.Builder implementation that 2 // builds ecs images for alicloud. 3 package ecs 4 5 import ( 6 "log" 7 8 "fmt" 9 10 "github.com/hashicorp/packer/common" 11 "github.com/hashicorp/packer/helper/communicator" 12 "github.com/hashicorp/packer/helper/config" 13 "github.com/hashicorp/packer/helper/multistep" 14 "github.com/hashicorp/packer/packer" 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 // The unique ID for this builder 19 const BuilderId = "alibaba.alicloud" 20 21 type Config struct { 22 common.PackerConfig `mapstructure:",squash"` 23 AlicloudAccessConfig `mapstructure:",squash"` 24 AlicloudImageConfig `mapstructure:",squash"` 25 RunConfig `mapstructure:",squash"` 26 27 ctx interpolate.Context 28 } 29 30 type Builder struct { 31 config Config 32 runner multistep.Runner 33 } 34 35 type InstanceNetWork string 36 37 const ( 38 ClassicNet = InstanceNetWork("classic") 39 VpcNet = InstanceNetWork("vpc") 40 ALICLOUD_DEFAULT_SHORT_TIMEOUT = 180 41 ALICLOUD_DEFAULT_TIMEOUT = 1800 42 ALICLOUD_DEFAULT_LONG_TIMEOUT = 3600 43 ) 44 45 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 46 err := config.Decode(&b.config, &config.DecodeOpts{ 47 Interpolate: true, 48 InterpolateContext: &b.config.ctx, 49 InterpolateFilter: &interpolate.RenderFilter{ 50 Exclude: []string{ 51 "run_command", 52 }, 53 }, 54 }, raws...) 55 b.config.ctx.EnableEnv = true 56 if err != nil { 57 return nil, err 58 } 59 60 // Accumulate any errors 61 var errs *packer.MultiError 62 errs = packer.MultiErrorAppend(errs, b.config.AlicloudAccessConfig.Prepare(&b.config.ctx)...) 63 errs = packer.MultiErrorAppend(errs, b.config.AlicloudImageConfig.Prepare(&b.config.ctx)...) 64 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) 65 66 if errs != nil && len(errs.Errors) > 0 { 67 return nil, errs 68 } 69 70 packer.LogSecretFilter.Set(b.config.AlicloudAccessKey, b.config.AlicloudSecretKey) 71 return nil, nil 72 } 73 74 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 75 76 client, err := b.config.Client() 77 if err != nil { 78 return nil, err 79 } 80 state := new(multistep.BasicStateBag) 81 state.Put("config", &b.config) 82 state.Put("client", client) 83 state.Put("hook", hook) 84 state.Put("ui", ui) 85 state.Put("networktype", b.chooseNetworkType()) 86 var steps []multistep.Step 87 88 // Build the steps 89 steps = []multistep.Step{ 90 &stepPreValidate{ 91 AlicloudDestImageName: b.config.AlicloudImageName, 92 ForceDelete: b.config.AlicloudImageForceDelete, 93 }, 94 &stepCheckAlicloudSourceImage{ 95 SourceECSImageId: b.config.AlicloudSourceImage, 96 }, 97 &stepConfigAlicloudKeyPair{ 98 Debug: b.config.PackerDebug, 99 Comm: &b.config.Comm, 100 DebugKeyPath: fmt.Sprintf("ecs_%s.pem", b.config.PackerBuildName), 101 RegionId: b.config.AlicloudRegion, 102 }, 103 } 104 if b.chooseNetworkType() == VpcNet { 105 steps = append(steps, 106 &stepConfigAlicloudVPC{ 107 VpcId: b.config.VpcId, 108 CidrBlock: b.config.CidrBlock, 109 VpcName: b.config.VpcName, 110 }, 111 &stepConfigAlicloudVSwitch{ 112 VSwitchId: b.config.VSwitchId, 113 ZoneId: b.config.ZoneId, 114 CidrBlock: b.config.CidrBlock, 115 VSwitchName: b.config.VSwitchName, 116 }) 117 } 118 steps = append(steps, 119 &stepConfigAlicloudSecurityGroup{ 120 SecurityGroupId: b.config.SecurityGroupId, 121 SecurityGroupName: b.config.SecurityGroupId, 122 RegionId: b.config.AlicloudRegion, 123 }, 124 &stepCreateAlicloudInstance{ 125 IOOptimized: b.config.IOOptimized, 126 InstanceType: b.config.InstanceType, 127 UserData: b.config.UserData, 128 UserDataFile: b.config.UserDataFile, 129 RegionId: b.config.AlicloudRegion, 130 InternetChargeType: b.config.InternetChargeType, 131 InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut, 132 InstanceName: b.config.InstanceName, 133 ZoneId: b.config.ZoneId, 134 }) 135 if b.chooseNetworkType() == VpcNet { 136 steps = append(steps, &stepConfigAlicloudEIP{ 137 AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, 138 RegionId: b.config.AlicloudRegion, 139 InternetChargeType: b.config.InternetChargeType, 140 InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut, 141 SSHPrivateIp: b.config.SSHPrivateIp, 142 }) 143 } else { 144 steps = append(steps, &stepConfigAlicloudPublicIP{ 145 RegionId: b.config.AlicloudRegion, 146 SSHPrivateIp: b.config.SSHPrivateIp, 147 }) 148 } 149 steps = append(steps, 150 &stepAttachKeyPair{}, 151 &stepRunAlicloudInstance{}, 152 &stepMountAlicloudDisk{}, 153 &communicator.StepConnect{ 154 Config: &b.config.RunConfig.Comm, 155 Host: SSHHost( 156 client, 157 b.config.SSHPrivateIp), 158 SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(), 159 }, 160 &common.StepProvision{}, 161 &common.StepCleanupTempKeys{ 162 Comm: &b.config.RunConfig.Comm, 163 }, 164 &stepStopAlicloudInstance{ 165 ForceStop: b.config.ForceStopInstance, 166 DisableStop: b.config.DisableStopInstance, 167 }, 168 &stepDeleteAlicloudImageSnapshots{ 169 AlicloudImageForceDeleteSnapshots: b.config.AlicloudImageForceDeleteSnapshots, 170 AlicloudImageForceDelete: b.config.AlicloudImageForceDelete, 171 AlicloudImageName: b.config.AlicloudImageName, 172 }, 173 &stepCreateAlicloudImage{}, 174 &stepCreateTags{ 175 Tags: b.config.AlicloudImageTags, 176 }, 177 &stepRegionCopyAlicloudImage{ 178 AlicloudImageDestinationRegions: b.config.AlicloudImageDestinationRegions, 179 AlicloudImageDestinationNames: b.config.AlicloudImageDestinationNames, 180 RegionId: b.config.AlicloudRegion, 181 }, 182 &stepShareAlicloudImage{ 183 AlicloudImageShareAccounts: b.config.AlicloudImageShareAccounts, 184 AlicloudImageUNShareAccounts: b.config.AlicloudImageUNShareAccounts, 185 RegionId: b.config.AlicloudRegion, 186 }) 187 188 // Run! 189 b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) 190 b.runner.Run(state) 191 192 // If there was an error, return that 193 if rawErr, ok := state.GetOk("error"); ok { 194 return nil, rawErr.(error) 195 } 196 197 // If there are no ECS images, then just return 198 if _, ok := state.GetOk("alicloudimages"); !ok { 199 return nil, nil 200 } 201 202 // Build the artifact and return it 203 artifact := &Artifact{ 204 AlicloudImages: state.Get("alicloudimages").(map[string]string), 205 BuilderIdValue: BuilderId, 206 Client: client, 207 } 208 209 return artifact, nil 210 } 211 212 func (b *Builder) Cancel() { 213 if b.runner != nil { 214 log.Println("Cancelling the step runner...") 215 b.runner.Cancel() 216 } 217 } 218 219 func (b *Builder) chooseNetworkType() InstanceNetWork { 220 if b.isVpcNetRequired() { 221 return VpcNet 222 } else { 223 return ClassicNet 224 } 225 } 226 227 func (b *Builder) isVpcNetRequired() bool { 228 // UserData and KeyPair only works in VPC 229 return b.isVpcSpecified() || b.isUserDataNeeded() || b.isKeyPairNeeded() 230 } 231 232 func (b *Builder) isVpcSpecified() bool { 233 return b.config.VpcId != "" || b.config.VSwitchId != "" 234 } 235 236 func (b *Builder) isUserDataNeeded() bool { 237 // Public key setup requires userdata 238 if b.config.RunConfig.Comm.SSHPrivateKeyFile != "" { 239 return true 240 } 241 242 return b.config.UserData != "" || b.config.UserDataFile != "" 243 } 244 245 func (b *Builder) isKeyPairNeeded() bool { 246 return b.config.Comm.SSHKeyPairName != "" || b.config.Comm.SSHTemporaryKeyPairName != "" 247 }