github.com/rothwerx/packer@v0.9.0/builder/digitalocean/builder.go (about) 1 // The digitalocean package contains a packer.Builder implementation 2 // that builds DigitalOcean images (snapshots). 3 4 package digitalocean 5 6 import ( 7 "fmt" 8 "log" 9 "net/url" 10 11 "github.com/digitalocean/godo" 12 "github.com/mitchellh/multistep" 13 "github.com/mitchellh/packer/common" 14 "github.com/mitchellh/packer/helper/communicator" 15 "github.com/mitchellh/packer/packer" 16 "golang.org/x/oauth2" 17 ) 18 19 // The unique id for the builder 20 const BuilderId = "pearkes.digitalocean" 21 22 type Builder struct { 23 config Config 24 runner multistep.Runner 25 } 26 27 func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { 28 c, warnings, errs := NewConfig(raws...) 29 if errs != nil { 30 return warnings, errs 31 } 32 b.config = *c 33 34 return nil, nil 35 } 36 37 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 38 client := godo.NewClient(oauth2.NewClient(oauth2.NoContext, &apiTokenSource{ 39 AccessToken: b.config.APIToken, 40 })) 41 if b.config.APIURL != "" { 42 u, err := url.Parse(b.config.APIURL) 43 if err != nil { 44 return nil, fmt.Errorf("DigitalOcean: Invalid API URL, %s.", err) 45 } 46 client.BaseURL = u 47 } 48 49 // Set up the state 50 state := new(multistep.BasicStateBag) 51 state.Put("config", b.config) 52 state.Put("client", client) 53 state.Put("hook", hook) 54 state.Put("ui", ui) 55 56 // Build the steps 57 steps := []multistep.Step{ 58 &stepCreateSSHKey{ 59 Debug: b.config.PackerDebug, 60 DebugKeyPath: fmt.Sprintf("do_%s.pem", b.config.PackerBuildName), 61 }, 62 new(stepCreateDroplet), 63 new(stepDropletInfo), 64 &communicator.StepConnect{ 65 Config: &b.config.Comm, 66 Host: commHost, 67 SSHConfig: sshConfig, 68 }, 69 new(common.StepProvision), 70 new(stepShutdown), 71 new(stepPowerOff), 72 new(stepSnapshot), 73 } 74 75 // Run the steps 76 if b.config.PackerDebug { 77 b.runner = &multistep.DebugRunner{ 78 Steps: steps, 79 PauseFn: common.MultistepDebugFn(ui), 80 } 81 } else { 82 b.runner = &multistep.BasicRunner{Steps: steps} 83 } 84 85 b.runner.Run(state) 86 87 // If there was an error, return that 88 if rawErr, ok := state.GetOk("error"); ok { 89 return nil, rawErr.(error) 90 } 91 92 if _, ok := state.GetOk("snapshot_name"); !ok { 93 log.Println("Failed to find snapshot_name in state. Bug?") 94 return nil, nil 95 } 96 97 artifact := &Artifact{ 98 snapshotName: state.Get("snapshot_name").(string), 99 snapshotId: state.Get("snapshot_image_id").(int), 100 regionName: state.Get("region").(string), 101 client: client, 102 } 103 104 return artifact, nil 105 } 106 107 func (b *Builder) Cancel() { 108 if b.runner != nil { 109 log.Println("Cancelling the step runner...") 110 b.runner.Cancel() 111 } 112 }