builder.go 3.63 KB
Newer Older
1 2 3 4 5 6
// The openstack package contains a packer.Builder implementation that
// builds Images for openstack.

package openstack

import (
7
	"fmt"
8 9 10 11
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/common"
	"github.com/mitchellh/packer/packer"
	"log"
12 13

	"github.com/mitchellh/gophercloud-fork-40444fb"
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
)

// The unique ID for this builder
const BuilderId = "mitchellh.openstack"

type config struct {
	common.PackerConfig `mapstructure:",squash"`
	AccessConfig        `mapstructure:",squash"`
	ImageConfig         `mapstructure:",squash"`
	RunConfig           `mapstructure:",squash"`

	tpl *packer.ConfigTemplate
}

type Builder struct {
	config config
	runner multistep.Runner
}

33
func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
34 35
	md, err := common.DecodeConfig(&b.config, raws...)
	if err != nil {
36
		return nil, err
37 38 39 40
	}

	b.config.tpl, err = packer.NewConfigTemplate()
	if err != nil {
41
		return nil, err
42 43 44 45 46 47 48 49 50 51
	}
	b.config.tpl.UserVars = b.config.PackerUserVars

	// Accumulate any errors
	errs := common.CheckUnusedConfig(md)
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...)
	errs = packer.MultiErrorAppend(errs, b.config.ImageConfig.Prepare(b.config.tpl)...)
	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...)

	if errs != nil && len(errs.Errors) > 0 {
52
		return nil, errs
53 54
	}

55
	log.Println(common.ScrubConfig(b.config, b.config.Password))
56
	return nil, nil
57 58 59 60 61 62 63
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	auth, err := b.config.AccessConfig.Auth()
	if err != nil {
		return nil, err
	}
64 65 66 67 68
	//fetches the api requisites from gophercloud for the appropriate
	//openstack variant
	api, err := gophercloud.PopulateApi(b.config.RunConfig.OpenstackProvider)
	if err != nil {
		return nil, err
69
	}
70 71 72
	api.Region = b.config.AccessConfig.Region()

	csp, err := gophercloud.ServersApi(auth, api)
73
	if err != nil {
74
		log.Printf("Region: %s", b.config.AccessConfig.Region())
75 76
		return nil, err
	}
77

78
	// Setup the state bag and initial state for the steps
79 80 81 82 83
	state := new(multistep.BasicStateBag)
	state.Put("config", b.config)
	state.Put("csp", csp)
	state.Put("hook", hook)
	state.Put("ui", ui)
84 85 86

	// Build the steps
	steps := []multistep.Step{
87 88 89
		&StepKeyPair{
			Debug:        b.config.PackerDebug,
			DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName),
Mitchell Hashimoto's avatar
fmt  
Mitchell Hashimoto committed
90
		},
91
		&StepRunSourceServer{
Kgespada's avatar
Kgespada committed
92 93 94 95
			Name:           b.config.ImageName,
			Flavor:         b.config.Flavor,
			SourceImage:    b.config.SourceImage,
			SecurityGroups: b.config.SecurityGroups,
96
			Networks:       b.config.Networks,
97
		},
98 99 100 101
		&StepAllocateIp{
			FloatingIpPool: b.config.FloatingIpPool,
			FloatingIp:     b.config.FloatingIp,
		},
102
		&common.StepConnectSSH{
103
			SSHAddress:     SSHAddress(csp, b.config.SSHPort),
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
			SSHConfig:      SSHConfig(b.config.SSHUsername),
			SSHWaitTimeout: b.config.SSHTimeout(),
		},
		&common.StepProvision{},
		&stepCreateImage{},
	}

	// Run!
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}

	b.runner.Run(state)

	// If there was an error, return that
124
	if rawErr, ok := state.GetOk("error"); ok {
125 126 127
		return nil, rawErr.(error)
	}

128 129 130 131 132
	// If there are no images, then just return
	if _, ok := state.GetOk("image"); !ok {
		return nil, nil
	}

133 134
	// Build the artifact and return it
	artifact := &Artifact{
135
		ImageId:        state.Get("image").(string),
136 137 138 139 140
		BuilderIdValue: BuilderId,
		Conn:           csp,
	}

	return artifact, nil
141 142 143 144 145 146 147 148
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}