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