github.com/sneal/packer@v0.5.2/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{}) ([]string, error) { 33 md, err := common.DecodeConfig(&b.config, raws...) 34 if err != nil { 35 return nil, err 36 } 37 38 b.config.tpl, err = packer.NewConfigTemplate() 39 if err != nil { 40 return nil, 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 nil, errs 52 } 53 54 log.Println(common.ScrubConfig(b.config, b.config.Password)) 55 return nil, 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 Debug: b.config.PackerDebug, 86 DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName), 87 }, 88 &StepRunSourceServer{ 89 Name: b.config.ImageName, 90 Flavor: b.config.Flavor, 91 SourceImage: b.config.SourceImage, 92 }, 93 &common.StepConnectSSH{ 94 SSHAddress: SSHAddress(csp, b.config.SSHPort), 95 SSHConfig: SSHConfig(b.config.SSHUsername), 96 SSHWaitTimeout: b.config.SSHTimeout(), 97 }, 98 &common.StepProvision{}, 99 &stepCreateImage{}, 100 } 101 102 // Run! 103 if b.config.PackerDebug { 104 b.runner = &multistep.DebugRunner{ 105 Steps: steps, 106 PauseFn: common.MultistepDebugFn(ui), 107 } 108 } else { 109 b.runner = &multistep.BasicRunner{Steps: steps} 110 } 111 112 b.runner.Run(state) 113 114 // If there was an error, return that 115 if rawErr, ok := state.GetOk("error"); ok { 116 return nil, rawErr.(error) 117 } 118 119 // If there are no images, then just return 120 if _, ok := state.GetOk("image"); !ok { 121 return nil, nil 122 } 123 124 // Build the artifact and return it 125 artifact := &Artifact{ 126 ImageId: state.Get("image").(string), 127 BuilderIdValue: BuilderId, 128 Conn: csp, 129 } 130 131 return artifact, nil 132 } 133 134 func (b *Builder) Cancel() { 135 if b.runner != nil { 136 log.Println("Cancelling the step runner...") 137 b.runner.Cancel() 138 } 139 }