github.com/homburg/packer@v0.6.1-0.20140528012651-1dcaf1716848/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 "github.com/mitchellh/goamz/ec2" 11 "github.com/mitchellh/multistep" 12 awscommon "github.com/mitchellh/packer/builder/amazon/common" 13 "github.com/mitchellh/packer/common" 14 "github.com/mitchellh/packer/packer" 15 "log" 16 ) 17 18 // The unique ID for this builder 19 const BuilderId = "mitchellh.amazonebs" 20 21 type config struct { 22 common.PackerConfig `mapstructure:",squash"` 23 awscommon.AccessConfig `mapstructure:",squash"` 24 awscommon.AMIConfig `mapstructure:",squash"` 25 awscommon.BlockDevices `mapstructure:",squash"` 26 awscommon.RunConfig `mapstructure:",squash"` 27 28 tpl *packer.ConfigTemplate 29 } 30 31 type Builder struct { 32 config config 33 runner multistep.Runner 34 } 35 36 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 37 md, err := common.DecodeConfig(&b.config, raws...) 38 if err != nil { 39 return nil, err 40 } 41 42 b.config.tpl, err = packer.NewConfigTemplate() 43 if err != nil { 44 return nil, err 45 } 46 b.config.tpl.UserVars = b.config.PackerUserVars 47 b.config.tpl.Funcs(awscommon.TemplateFuncs) 48 49 // Accumulate any errors 50 errs := common.CheckUnusedConfig(md) 51 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) 52 errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) 53 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) 54 55 if errs != nil && len(errs.Errors) > 0 { 56 return nil, errs 57 } 58 59 log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey)) 60 return nil, nil 61 } 62 63 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 64 region, err := b.config.Region() 65 if err != nil { 66 return nil, err 67 } 68 69 auth, err := b.config.AccessConfig.Auth() 70 if err != nil { 71 return nil, err 72 } 73 74 ec2conn := ec2.New(auth, region) 75 76 // Setup the state bag and initial state for the steps 77 state := new(multistep.BasicStateBag) 78 state.Put("config", b.config) 79 state.Put("ec2", ec2conn) 80 state.Put("hook", hook) 81 state.Put("ui", ui) 82 83 // Build the steps 84 steps := []multistep.Step{ 85 &awscommon.StepKeyPair{ 86 Debug: b.config.PackerDebug, 87 DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName), 88 KeyPairName: b.config.TemporaryKeyPairName, 89 PrivateKeyFile: b.config.SSHPrivateKeyFile, 90 }, 91 &awscommon.StepSecurityGroup{ 92 SecurityGroupIds: b.config.SecurityGroupIds, 93 SSHPort: b.config.SSHPort, 94 VpcId: b.config.VpcId, 95 }, 96 &awscommon.StepRunSourceInstance{ 97 Debug: b.config.PackerDebug, 98 ExpectedRootDevice: "ebs", 99 InstanceType: b.config.InstanceType, 100 UserData: b.config.UserData, 101 UserDataFile: b.config.UserDataFile, 102 SourceAMI: b.config.SourceAmi, 103 IamInstanceProfile: b.config.IamInstanceProfile, 104 SubnetId: b.config.SubnetId, 105 AssociatePublicIpAddress: b.config.AssociatePublicIpAddress, 106 AvailabilityZone: b.config.AvailabilityZone, 107 BlockDevices: b.config.BlockDevices, 108 Tags: b.config.RunTags, 109 }, 110 &common.StepConnectSSH{ 111 SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort), 112 SSHConfig: awscommon.SSHConfig(b.config.SSHUsername), 113 SSHWaitTimeout: b.config.SSHTimeout(), 114 }, 115 &common.StepProvision{}, 116 &stepStopInstance{}, 117 &stepCreateAMI{}, 118 &awscommon.StepAMIRegionCopy{ 119 Regions: b.config.AMIRegions, 120 }, 121 &awscommon.StepModifyAMIAttributes{ 122 Description: b.config.AMIDescription, 123 Users: b.config.AMIUsers, 124 Groups: b.config.AMIGroups, 125 }, 126 &awscommon.StepCreateTags{ 127 Tags: b.config.AMITags, 128 }, 129 } 130 131 // Run! 132 if b.config.PackerDebug { 133 b.runner = &multistep.DebugRunner{ 134 Steps: steps, 135 PauseFn: common.MultistepDebugFn(ui), 136 } 137 } else { 138 b.runner = &multistep.BasicRunner{Steps: steps} 139 } 140 141 b.runner.Run(state) 142 143 // If there was an error, return that 144 if rawErr, ok := state.GetOk("error"); ok { 145 return nil, rawErr.(error) 146 } 147 148 // If there are no AMIs, then just return 149 if _, ok := state.GetOk("amis"); !ok { 150 return nil, nil 151 } 152 153 // Build the artifact and return it 154 artifact := &awscommon.Artifact{ 155 Amis: state.Get("amis").(map[string]string), 156 BuilderIdValue: BuilderId, 157 Conn: ec2conn, 158 } 159 160 return artifact, nil 161 } 162 163 func (b *Builder) Cancel() { 164 if b.runner != nil { 165 log.Println("Cancelling the step runner...") 166 b.runner.Cancel() 167 } 168 }