github.com/phobos182/packer@v0.2.3-0.20130819023704-c84d2aeffc68/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 // Tags for the AMI 29 Tags map[string]string 30 31 tpl *packer.ConfigTemplate 32 } 33 34 type Builder struct { 35 config config 36 runner multistep.Runner 37 } 38 39 func (b *Builder) Prepare(raws ...interface{}) error { 40 md, err := common.DecodeConfig(&b.config, raws...) 41 if err != nil { 42 return err 43 } 44 45 b.config.tpl, err = packer.NewConfigTemplate() 46 if err != nil { 47 return err 48 } 49 b.config.tpl.UserVars = b.config.PackerUserVars 50 51 // Accumulate any errors 52 errs := common.CheckUnusedConfig(md) 53 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) 54 errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...) 55 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) 56 57 // Accumulate any errors 58 newTags := make(map[string]string) 59 for k, v := range b.config.Tags { 60 k, err = b.config.tpl.Process(k, nil) 61 if err != nil { 62 errs = packer.MultiErrorAppend(errs, 63 fmt.Errorf("Error processing tag key %s: %s", k, err)) 64 continue 65 } 66 67 v, err = b.config.tpl.Process(v, nil) 68 if err != nil { 69 errs = packer.MultiErrorAppend(errs, 70 fmt.Errorf("Error processing tag value '%s': %s", v, err)) 71 continue 72 } 73 74 newTags[k] = v 75 } 76 77 b.config.Tags = newTags 78 79 if errs != nil && len(errs.Errors) > 0 { 80 return errs 81 } 82 83 log.Printf("Config: %+v", b.config) 84 return nil 85 } 86 87 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 88 region, err := b.config.Region() 89 if err != nil { 90 return nil, err 91 } 92 93 auth, err := b.config.AccessConfig.Auth() 94 if err != nil { 95 return nil, err 96 } 97 98 ec2conn := ec2.New(auth, region) 99 100 // Setup the state bag and initial state for the steps 101 state := make(map[string]interface{}) 102 state["config"] = b.config 103 state["ec2"] = ec2conn 104 state["hook"] = hook 105 state["ui"] = ui 106 107 // Build the steps 108 steps := []multistep.Step{ 109 &awscommon.StepKeyPair{}, 110 &awscommon.StepSecurityGroup{ 111 SecurityGroupId: b.config.SecurityGroupId, 112 SSHPort: b.config.SSHPort, 113 VpcId: b.config.VpcId, 114 }, 115 &awscommon.StepRunSourceInstance{ 116 ExpectedRootDevice: "ebs", 117 InstanceType: b.config.InstanceType, 118 UserData: b.config.UserData, 119 UserDataFile: b.config.UserDataFile, 120 SourceAMI: b.config.SourceAmi, 121 IamInstanceProfile: b.config.IamInstanceProfile, 122 SubnetId: b.config.SubnetId, 123 BlockDevices: b.config.BlockDevices, 124 }, 125 &common.StepConnectSSH{ 126 SSHAddress: awscommon.SSHAddress(ec2conn, b.config.SSHPort), 127 SSHConfig: awscommon.SSHConfig(b.config.SSHUsername), 128 SSHWaitTimeout: b.config.SSHTimeout(), 129 }, 130 &common.StepProvision{}, 131 &stepStopInstance{}, 132 &stepCreateAMI{}, 133 &awscommon.StepCreateTags{Tags: b.config.Tags}, 134 &awscommon.StepModifyAMIAttributes{ 135 Description: b.config.AMIDescription, 136 Users: b.config.AMIUsers, 137 Groups: b.config.AMIGroups, 138 }, 139 } 140 141 // Run! 142 if b.config.PackerDebug { 143 b.runner = &multistep.DebugRunner{ 144 Steps: steps, 145 PauseFn: common.MultistepDebugFn(ui), 146 } 147 } else { 148 b.runner = &multistep.BasicRunner{Steps: steps} 149 } 150 151 b.runner.Run(state) 152 153 // If there was an error, return that 154 if rawErr, ok := state["error"]; ok { 155 return nil, rawErr.(error) 156 } 157 158 // If there are no AMIs, then just return 159 if _, ok := state["amis"]; !ok { 160 return nil, nil 161 } 162 163 // Build the artifact and return it 164 artifact := &awscommon.Artifact{ 165 Amis: state["amis"].(map[string]string), 166 BuilderIdValue: BuilderId, 167 Conn: ec2conn, 168 } 169 170 return artifact, nil 171 } 172 173 func (b *Builder) Cancel() { 174 if b.runner != nil { 175 log.Println("Cancelling the step runner...") 176 b.runner.Cancel() 177 } 178 }