github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/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  	//fetches the api requisites from gophercloud for the appropriate
    64  	//openstack variant
    65  	api, err := gophercloud.PopulateApi(b.config.RunConfig.OpenstackProvider)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	api.Region = b.config.AccessConfig.Region()
    70  
    71  	csp, err := gophercloud.ServersApi(auth, api)
    72  	if err != nil {
    73  		log.Printf("Region: %s", b.config.AccessConfig.Region())
    74  		return nil, err
    75  	}
    76  
    77  	// Setup the state bag and initial state for the steps
    78  	state := new(multistep.BasicStateBag)
    79  	state.Put("config", b.config)
    80  	state.Put("csp", csp)
    81  	state.Put("hook", hook)
    82  	state.Put("ui", ui)
    83  
    84  	// Build the steps
    85  	steps := []multistep.Step{
    86  		&StepKeyPair{
    87  			Debug:        b.config.PackerDebug,
    88  			DebugKeyPath: fmt.Sprintf("os_%s.pem", b.config.PackerBuildName),
    89  		},
    90  		&StepRunSourceServer{
    91  			Name:           b.config.ImageName,
    92  			Flavor:         b.config.Flavor,
    93  			SourceImage:    b.config.SourceImage,
    94  			SecurityGroups: b.config.SecurityGroups,
    95  			Networks:       b.config.Networks,
    96  		},
    97  		&StepAllocateIp{
    98  			FloatingIpPool: b.config.FloatingIpPool,
    99  			FloatingIp:     b.config.FloatingIp,
   100  		},
   101  		&common.StepConnectSSH{
   102  			SSHAddress:     SSHAddress(csp, b.config.SSHPort),
   103  			SSHConfig:      SSHConfig(b.config.SSHUsername),
   104  			SSHWaitTimeout: b.config.SSHTimeout(),
   105  		},
   106  		&common.StepProvision{},
   107  		&stepCreateImage{},
   108  	}
   109  
   110  	// Run!
   111  	if b.config.PackerDebug {
   112  		b.runner = &multistep.DebugRunner{
   113  			Steps:   steps,
   114  			PauseFn: common.MultistepDebugFn(ui),
   115  		}
   116  	} else {
   117  		b.runner = &multistep.BasicRunner{Steps: steps}
   118  	}
   119  
   120  	b.runner.Run(state)
   121  
   122  	// If there was an error, return that
   123  	if rawErr, ok := state.GetOk("error"); ok {
   124  		return nil, rawErr.(error)
   125  	}
   126  
   127  	// If there are no images, then just return
   128  	if _, ok := state.GetOk("image"); !ok {
   129  		return nil, nil
   130  	}
   131  
   132  	// Build the artifact and return it
   133  	artifact := &Artifact{
   134  		ImageId:        state.Get("image").(string),
   135  		BuilderIdValue: BuilderId,
   136  		Conn:           csp,
   137  	}
   138  
   139  	return artifact, nil
   140  }
   141  
   142  func (b *Builder) Cancel() {
   143  	if b.runner != nil {
   144  		log.Println("Cancelling the step runner...")
   145  		b.runner.Cancel()
   146  	}
   147  }