github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/ebs/builder.go (about) 1 // The amazonebs package contains a packer.Builder implementation that 2 // builds AMIs for Amazon EC2. 3 // 4 // In general, there are two types of AMIs that can be created: ebs-backed or 5 // instance-store. This builder _only_ builds ebs-backed images. 6 package ebs 7 8 import ( 9 "fmt" 10 "log" 11 12 "github.com/aws/aws-sdk-go/service/ec2" 13 awscommon "github.com/hashicorp/packer/builder/amazon/common" 14 "github.com/hashicorp/packer/common" 15 "github.com/hashicorp/packer/helper/communicator" 16 "github.com/hashicorp/packer/helper/config" 17 "github.com/hashicorp/packer/helper/multistep" 18 "github.com/hashicorp/packer/packer" 19 "github.com/hashicorp/packer/template/interpolate" 20 ) 21 22 // The unique ID for this builder 23 const BuilderId = "mitchellh.amazonebs" 24 25 type Config struct { 26 common.PackerConfig `mapstructure:",squash"` 27 awscommon.AccessConfig `mapstructure:",squash"` 28 awscommon.AMIConfig `mapstructure:",squash"` 29 awscommon.BlockDevices `mapstructure:",squash"` 30 awscommon.RunConfig `mapstructure:",squash"` 31 VolumeRunTags awscommon.TagMap `mapstructure:"run_volume_tags"` 32 33 ctx interpolate.Context 34 } 35 36 type Builder struct { 37 config Config 38 runner multistep.Runner 39 } 40 41 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 42 b.config.ctx.Funcs = awscommon.TemplateFuncs 43 err := config.Decode(&b.config, &config.DecodeOpts{ 44 Interpolate: true, 45 InterpolateContext: &b.config.ctx, 46 InterpolateFilter: &interpolate.RenderFilter{ 47 Exclude: []string{ 48 "ami_description", 49 "run_tags", 50 "run_volume_tags", 51 "spot_tags", 52 "snapshot_tags", 53 "tags", 54 }, 55 }, 56 }, raws...) 57 if err != nil { 58 return nil, err 59 } 60 61 if b.config.PackerConfig.PackerForce { 62 b.config.AMIForceDeregister = true 63 } 64 65 // Accumulate any errors 66 var errs *packer.MultiError 67 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...) 68 errs = packer.MultiErrorAppend(errs, 69 b.config.AMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...) 70 errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...) 71 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) 72 73 if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) { 74 errs = packer.MultiErrorAppend(errs, 75 fmt.Errorf("Spot instances do not support modification, which is required "+ 76 "when either `ena_support` or `sriov_support` are set. Please ensure "+ 77 "you use an AMI that already has either SR-IOV or ENA enabled.")) 78 } 79 80 if errs != nil && len(errs.Errors) > 0 { 81 return nil, errs 82 } 83 84 packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token) 85 return nil, nil 86 } 87 88 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 89 90 session, err := b.config.Session() 91 if err != nil { 92 return nil, err 93 } 94 ec2conn := ec2.New(session) 95 96 // Setup the state bag and initial state for the steps 97 state := new(multistep.BasicStateBag) 98 state.Put("config", &b.config) 99 state.Put("ec2", ec2conn) 100 state.Put("awsSession", session) 101 state.Put("hook", hook) 102 state.Put("ui", ui) 103 104 var instanceStep multistep.Step 105 106 if b.config.IsSpotInstance() { 107 instanceStep = &awscommon.StepRunSpotInstance{ 108 AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, 109 BlockDevices: b.config.BlockDevices, 110 BlockDurationMinutes: b.config.BlockDurationMinutes, 111 Ctx: b.config.ctx, 112 Comm: &b.config.RunConfig.Comm, 113 Debug: b.config.PackerDebug, 114 EbsOptimized: b.config.EbsOptimized, 115 ExpectedRootDevice: "ebs", 116 IamInstanceProfile: b.config.IamInstanceProfile, 117 InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, 118 InstanceType: b.config.InstanceType, 119 SourceAMI: b.config.SourceAmi, 120 SpotPrice: b.config.SpotPrice, 121 SpotPriceProduct: b.config.SpotPriceAutoProduct, 122 SpotTags: b.config.SpotTags, 123 Tags: b.config.RunTags, 124 UserData: b.config.UserData, 125 UserDataFile: b.config.UserDataFile, 126 VolumeTags: b.config.VolumeRunTags, 127 } 128 } else { 129 instanceStep = &awscommon.StepRunSourceInstance{ 130 AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, 131 BlockDevices: b.config.BlockDevices, 132 Comm: &b.config.RunConfig.Comm, 133 Ctx: b.config.ctx, 134 Debug: b.config.PackerDebug, 135 EbsOptimized: b.config.EbsOptimized, 136 EnableT2Unlimited: b.config.EnableT2Unlimited, 137 ExpectedRootDevice: "ebs", 138 IamInstanceProfile: b.config.IamInstanceProfile, 139 InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, 140 InstanceType: b.config.InstanceType, 141 IsRestricted: b.config.IsChinaCloud() || b.config.IsGovCloud(), 142 SourceAMI: b.config.SourceAmi, 143 Tags: b.config.RunTags, 144 UserData: b.config.UserData, 145 UserDataFile: b.config.UserDataFile, 146 VolumeTags: b.config.VolumeRunTags, 147 } 148 } 149 150 // Build the steps 151 steps := []multistep.Step{ 152 &awscommon.StepPreValidate{ 153 DestAmiName: b.config.AMIName, 154 ForceDeregister: b.config.AMIForceDeregister, 155 }, 156 &awscommon.StepSourceAMIInfo{ 157 SourceAmi: b.config.SourceAmi, 158 EnableAMISriovNetSupport: b.config.AMISriovNetSupport, 159 EnableAMIENASupport: b.config.AMIENASupport, 160 AmiFilters: b.config.SourceAmiFilter, 161 AMIVirtType: b.config.AMIVirtType, 162 }, 163 &awscommon.StepNetworkInfo{ 164 VpcId: b.config.VpcId, 165 VpcFilter: b.config.VpcFilter, 166 SecurityGroupIds: b.config.SecurityGroupIds, 167 SecurityGroupFilter: b.config.SecurityGroupFilter, 168 SubnetId: b.config.SubnetId, 169 SubnetFilter: b.config.SubnetFilter, 170 AvailabilityZone: b.config.AvailabilityZone, 171 }, 172 &awscommon.StepKeyPair{ 173 Debug: b.config.PackerDebug, 174 Comm: &b.config.RunConfig.Comm, 175 DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName), 176 }, 177 &awscommon.StepSecurityGroup{ 178 SecurityGroupFilter: b.config.SecurityGroupFilter, 179 SecurityGroupIds: b.config.SecurityGroupIds, 180 CommConfig: &b.config.RunConfig.Comm, 181 TemporarySGSourceCidr: b.config.TemporarySGSourceCidr, 182 }, 183 &awscommon.StepCleanupVolumes{ 184 BlockDevices: b.config.BlockDevices, 185 }, 186 instanceStep, 187 &awscommon.StepGetPassword{ 188 Debug: b.config.PackerDebug, 189 Comm: &b.config.RunConfig.Comm, 190 Timeout: b.config.WindowsPasswordTimeout, 191 BuildName: b.config.PackerBuildName, 192 }, 193 &communicator.StepConnect{ 194 Config: &b.config.RunConfig.Comm, 195 Host: awscommon.SSHHost( 196 ec2conn, 197 b.config.Comm.SSHInterface), 198 SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(), 199 }, 200 &common.StepProvision{}, 201 &common.StepCleanupTempKeys{ 202 Comm: &b.config.RunConfig.Comm, 203 }, 204 &awscommon.StepStopEBSBackedInstance{ 205 Skip: b.config.IsSpotInstance(), 206 DisableStopInstance: b.config.DisableStopInstance, 207 }, 208 &awscommon.StepModifyEBSBackedInstance{ 209 EnableAMISriovNetSupport: b.config.AMISriovNetSupport, 210 EnableAMIENASupport: b.config.AMIENASupport, 211 }, 212 &awscommon.StepDeregisterAMI{ 213 AccessConfig: &b.config.AccessConfig, 214 ForceDeregister: b.config.AMIForceDeregister, 215 ForceDeleteSnapshot: b.config.AMIForceDeleteSnapshot, 216 AMIName: b.config.AMIName, 217 Regions: b.config.AMIRegions, 218 }, 219 &stepCreateAMI{}, 220 &awscommon.StepCreateEncryptedAMICopy{ 221 KeyID: b.config.AMIKmsKeyId, 222 EncryptBootVolume: b.config.AMIEncryptBootVolume, 223 Name: b.config.AMIName, 224 AMIMappings: b.config.AMIBlockDevices.AMIMappings, 225 }, 226 &awscommon.StepAMIRegionCopy{ 227 AccessConfig: &b.config.AccessConfig, 228 Regions: b.config.AMIRegions, 229 RegionKeyIds: b.config.AMIRegionKMSKeyIDs, 230 EncryptBootVolume: b.config.AMIEncryptBootVolume, 231 Name: b.config.AMIName, 232 }, 233 &awscommon.StepModifyAMIAttributes{ 234 Description: b.config.AMIDescription, 235 Users: b.config.AMIUsers, 236 Groups: b.config.AMIGroups, 237 ProductCodes: b.config.AMIProductCodes, 238 SnapshotUsers: b.config.SnapshotUsers, 239 SnapshotGroups: b.config.SnapshotGroups, 240 Ctx: b.config.ctx, 241 }, 242 &awscommon.StepCreateTags{ 243 Tags: b.config.AMITags, 244 SnapshotTags: b.config.SnapshotTags, 245 Ctx: b.config.ctx, 246 }, 247 } 248 249 // Run! 250 b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) 251 b.runner.Run(state) 252 // If there was an error, return that 253 if rawErr, ok := state.GetOk("error"); ok { 254 return nil, rawErr.(error) 255 } 256 257 // If there are no AMIs, then just return 258 if _, ok := state.GetOk("amis"); !ok { 259 return nil, nil 260 } 261 262 // Build the artifact and return it 263 artifact := &awscommon.Artifact{ 264 Amis: state.Get("amis").(map[string]string), 265 BuilderIdValue: BuilderId, 266 Session: session, 267 } 268 269 return artifact, nil 270 } 271 272 func (b *Builder) Cancel() { 273 if b.runner != nil { 274 log.Println("Cancelling the step runner...") 275 b.runner.Cancel() 276 } 277 }