github.com/jerryclinesmith/packer@v0.3.7/builder/openstack/builder.go (about) 1 // The openstack package contains a packer.Builder implementation that 2 // builds Images for openstack. 3 4 package openstack 5 6 import ( 7 //"fmt" 8 "github.com/mitchellh/multistep" 9 "github.com/mitchellh/packer/common" 10 "github.com/mitchellh/packer/packer" 11 "github.com/rackspace/gophercloud" 12 "log" 13 ) 14 15 // The unique ID for this builder 16 const BuilderId = "mitchellh.openstack" 17 18 type config struct { 19 common.PackerConfig `mapstructure:",squash"` 20 AccessConfig `mapstructure:",squash"` 21 ImageConfig `mapstructure:",squash"` 22 RunConfig `mapstructure:",squash"` 23 24 tpl *packer.ConfigTemplate 25 } 26 27 type Builder struct { 28 config config 29 runner multistep.Runner 30 } 31 32 func (b *Builder) Prepare(raws ...interface{}) error { 33 md, err := common.DecodeConfig(&b.config, raws...) 34 if err != nil { 35 return err 36 } 37 38 b.config.tpl, err = packer.NewConfigTemplate() 39 if err != nil { 40 return err 41 } 42 b.config.tpl.UserVars = b.config.PackerUserVars 43 44 // Accumulate any errors 45 errs := common.CheckUnusedConfig(md) 46 errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...) 47 errs = packer.MultiErrorAppend(errs, b.config.ImageConfig.Prepare(b.config.tpl)...) 48 errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...) 49 50 if errs != nil && len(errs.Errors) > 0 { 51 return errs 52 } 53 54 log.Printf("Config: %+v", b.config) 55 return nil 56 } 57 58 func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { 59 auth, err := b.config.AccessConfig.Auth() 60 if err != nil { 61 return nil, err 62 } 63 api := &gophercloud.ApiCriteria{ 64 Name: "cloudServersOpenStack", 65 Region: b.config.AccessConfig.Region(), 66 VersionId: "2", 67 UrlChoice: gophercloud.PublicURL, 68 } 69 csp, err := gophercloud.ServersApi(auth, *api) 70 if err != nil { 71 log.Printf("Region: %s", b.config.AccessConfig.Region()) 72 return nil, err 73 } 74 75 // Setup the state bag and initial state for the steps 76 state := new(multistep.BasicStateBag) 77 state.Put("config", b.config) 78 state.Put("csp", csp) 79 state.Put("hook", hook) 80 state.Put("ui", ui) 81 82 // Build the steps 83 steps := []multistep.Step{ 84 &StepKeyPair{}, 85 &StepRunSourceServer{ 86 Name: b.config.ImageName, 87 Flavor: b.config.Flavor, 88 SourceImage: b.config.SourceImage, 89 }, 90 &common.StepConnectSSH{ 91 SSHAddress: SSHAddress(csp, b.config.SSHPort), 92 SSHConfig: SSHConfig(b.config.SSHUsername), 93 SSHWaitTimeout: b.config.SSHTimeout(), 94 }, 95 &common.StepProvision{}, 96 &stepCreateImage{}, 97 } 98 99 // Run! 100 if b.config.PackerDebug { 101 b.runner = &multistep.DebugRunner{ 102 Steps: steps, 103 PauseFn: common.MultistepDebugFn(ui), 104 } 105 } else { 106 b.runner = &multistep.BasicRunner{Steps: steps} 107 } 108 109 b.runner.Run(state) 110 111 // If there was an error, return that 112 if rawErr, ok := state.GetOk("error"); ok { 113 return nil, rawErr.(error) 114 } 115 116 // If there are no images, then just return 117 if _, ok := state.GetOk("image"); !ok { 118 return nil, nil 119 } 120 121 // Build the artifact and return it 122 artifact := &Artifact{ 123 ImageId: state.Get("image").(string), 124 BuilderIdValue: BuilderId, 125 Conn: csp, 126 } 127 128 return artifact, nil 129 } 130 131 func (b *Builder) Cancel() { 132 if b.runner != nil { 133 log.Println("Cancelling the step runner...") 134 b.runner.Cancel() 135 } 136 }