github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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/packer" 18 "github.com/hashicorp/packer/template/interpolate" 19 "github.com/mitchellh/multistep" 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 map[string]string `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 "snapshot_tags", 52 "tags", 53 }, 54 }, 55 }, raws...) 56 if err != nil { 57 return nil, err 58 } 59 60 if b.config.PackerConfig.PackerForce { 61 b.config.AMIForceDeregister = true 62 } 63 64 // Accumulate any errors 65 var errs *packer.MultiError 66 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...) 67 errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...) 68 errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(&b.config.ctx)...) 69 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...) 70 71 if errs != nil && len(errs.Errors) > 0 { 72 return nil, errs 73 } 74 75 log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey)) 76 return nil, nil 77 } 78 79 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 80 81 session, err := b.config.Session() 82 if err != nil { 83 return nil, err 84 } 85 ec2conn := ec2.New(session) 86 87 // If the subnet is specified but not the VpcId or AZ, try to determine them automatically 88 if b.config.SubnetId != "" && (b.config.AvailabilityZone == "" || b.config.VpcId == "") { 89 log.Printf("[INFO] Finding AZ and VpcId for the given subnet '%s'", b.config.SubnetId) 90 resp, err := ec2conn.DescribeSubnets(&ec2.DescribeSubnetsInput{SubnetIds: []*string{&b.config.SubnetId}}) 91 if err != nil { 92 return nil, err 93 } 94 if b.config.AvailabilityZone == "" { 95 b.config.AvailabilityZone = *resp.Subnets[0].AvailabilityZone 96 log.Printf("[INFO] AvailabilityZone found: '%s'", b.config.AvailabilityZone) 97 } 98 if b.config.VpcId == "" { 99 b.config.VpcId = *resp.Subnets[0].VpcId 100 log.Printf("[INFO] VpcId found: '%s'", b.config.VpcId) 101 } 102 } 103 104 // Setup the state bag and initial state for the steps 105 state := new(multistep.BasicStateBag) 106 state.Put("config", b.config) 107 state.Put("ec2", ec2conn) 108 state.Put("hook", hook) 109 state.Put("ui", ui) 110 111 // Build the steps 112 steps := []multistep.Step{ 113 &awscommon.StepPreValidate{ 114 DestAmiName: b.config.AMIName, 115 ForceDeregister: b.config.AMIForceDeregister, 116 }, 117 &awscommon.StepSourceAMIInfo{ 118 SourceAmi: b.config.SourceAmi, 119 EnableAMISriovNetSupport: b.config.AMISriovNetSupport, 120 EnableAMIENASupport: b.config.AMIENASupport, 121 AmiFilters: b.config.SourceAmiFilter, 122 }, 123 &awscommon.StepKeyPair{ 124 Debug: b.config.PackerDebug, 125 SSHAgentAuth: b.config.Comm.SSHAgentAuth, 126 DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName), 127 KeyPairName: b.config.SSHKeyPairName, 128 TemporaryKeyPairName: b.config.TemporaryKeyPairName, 129 PrivateKeyFile: b.config.RunConfig.Comm.SSHPrivateKey, 130 }, 131 &awscommon.StepSecurityGroup{ 132 SecurityGroupIds: b.config.SecurityGroupIds, 133 CommConfig: &b.config.RunConfig.Comm, 134 VpcId: b.config.VpcId, 135 }, 136 &stepCleanupVolumes{ 137 BlockDevices: b.config.BlockDevices, 138 }, 139 &awscommon.StepRunSourceInstance{ 140 Debug: b.config.PackerDebug, 141 ExpectedRootDevice: "ebs", 142 SpotPrice: b.config.SpotPrice, 143 SpotPriceProduct: b.config.SpotPriceAutoProduct, 144 InstanceType: b.config.InstanceType, 145 UserData: b.config.UserData, 146 UserDataFile: b.config.UserDataFile, 147 SourceAMI: b.config.SourceAmi, 148 IamInstanceProfile: b.config.IamInstanceProfile, 149 SubnetId: b.config.SubnetId, 150 AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, 151 EbsOptimized: b.config.EbsOptimized, 152 AvailabilityZone: b.config.AvailabilityZone, 153 BlockDevices: b.config.BlockDevices, 154 Tags: b.config.RunTags, 155 Ctx: b.config.ctx, 156 InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior, 157 }, 158 &awscommon.StepTagEBSVolumes{ 159 VolumeRunTags: b.config.VolumeRunTags, 160 Ctx: b.config.ctx, 161 }, 162 &awscommon.StepGetPassword{ 163 Debug: b.config.PackerDebug, 164 Comm: &b.config.RunConfig.Comm, 165 Timeout: b.config.WindowsPasswordTimeout, 166 }, 167 &communicator.StepConnect{ 168 Config: &b.config.RunConfig.Comm, 169 Host: awscommon.SSHHost( 170 ec2conn, 171 b.config.SSHPrivateIp), 172 SSHConfig: awscommon.SSHConfig( 173 b.config.RunConfig.Comm.SSHAgentAuth, 174 b.config.RunConfig.Comm.SSHUsername, 175 b.config.RunConfig.Comm.SSHPassword), 176 }, 177 &common.StepProvision{}, 178 &awscommon.StepStopEBSBackedInstance{ 179 SpotPrice: b.config.SpotPrice, 180 DisableStopInstance: b.config.DisableStopInstance, 181 }, 182 &awscommon.StepModifyEBSBackedInstance{ 183 EnableAMISriovNetSupport: b.config.AMISriovNetSupport, 184 EnableAMIENASupport: b.config.AMIENASupport, 185 }, 186 &awscommon.StepDeregisterAMI{ 187 AccessConfig: &b.config.AccessConfig, 188 ForceDeregister: b.config.AMIForceDeregister, 189 ForceDeleteSnapshot: b.config.AMIForceDeleteSnapshot, 190 AMIName: b.config.AMIName, 191 Regions: b.config.AMIRegions, 192 }, 193 &stepCreateAMI{}, 194 &awscommon.StepCreateEncryptedAMICopy{ 195 KeyID: b.config.AMIKmsKeyId, 196 EncryptBootVolume: b.config.AMIEncryptBootVolume, 197 Name: b.config.AMIName, 198 AMIMappings: b.config.AMIBlockDevices.AMIMappings, 199 }, 200 &awscommon.StepAMIRegionCopy{ 201 AccessConfig: &b.config.AccessConfig, 202 Regions: b.config.AMIRegions, 203 RegionKeyIds: b.config.AMIRegionKMSKeyIDs, 204 EncryptBootVolume: b.config.AMIEncryptBootVolume, 205 Name: b.config.AMIName, 206 }, 207 &awscommon.StepModifyAMIAttributes{ 208 Description: b.config.AMIDescription, 209 Users: b.config.AMIUsers, 210 Groups: b.config.AMIGroups, 211 ProductCodes: b.config.AMIProductCodes, 212 SnapshotUsers: b.config.SnapshotUsers, 213 SnapshotGroups: b.config.SnapshotGroups, 214 Ctx: b.config.ctx, 215 }, 216 &awscommon.StepCreateTags{ 217 Tags: b.config.AMITags, 218 SnapshotTags: b.config.SnapshotTags, 219 Ctx: b.config.ctx, 220 }, 221 } 222 223 // Run! 224 b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) 225 b.runner.Run(state) 226 227 // If there was an error, return that 228 if rawErr, ok := state.GetOk("error"); ok { 229 return nil, rawErr.(error) 230 } 231 232 // If there are no AMIs, then just return 233 if _, ok := state.GetOk("amis"); !ok { 234 return nil, nil 235 } 236 237 // Build the artifact and return it 238 artifact := &awscommon.Artifact{ 239 Amis: state.Get("amis").(map[string]string), 240 BuilderIdValue: BuilderId, 241 Conn: ec2conn, 242 } 243 244 return artifact, nil 245 } 246 247 func (b *Builder) Cancel() { 248 if b.runner != nil { 249 log.Println("Cancelling the step runner...") 250 b.runner.Cancel() 251 } 252 }