github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/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  	"log"
     9  
    10  	"github.com/hashicorp/packer/common"
    11  	"github.com/hashicorp/packer/helper/communicator"
    12  	"github.com/hashicorp/packer/helper/config"
    13  	"github.com/hashicorp/packer/packer"
    14  	"github.com/hashicorp/packer/template/interpolate"
    15  	"github.com/mitchellh/multistep"
    16  )
    17  
    18  // The unique ID for this builder
    19  const BuilderId = "mitchellh.openstack"
    20  
    21  type Config struct {
    22  	common.PackerConfig `mapstructure:",squash"`
    23  
    24  	AccessConfig `mapstructure:",squash"`
    25  	ImageConfig  `mapstructure:",squash"`
    26  	RunConfig    `mapstructure:",squash"`
    27  
    28  	ctx interpolate.Context
    29  }
    30  
    31  type Builder struct {
    32  	config Config
    33  	runner multistep.Runner
    34  }
    35  
    36  func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
    37  	err := config.Decode(&b.config, &config.DecodeOpts{
    38  		Interpolate:        true,
    39  		InterpolateContext: &b.config.ctx,
    40  	}, raws...)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	// Accumulate any errors
    46  	var errs *packer.MultiError
    47  	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
    48  	errs = packer.MultiErrorAppend(errs, b.config.ImageConfig.Prepare(&b.config.ctx)...)
    49  	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
    50  
    51  	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  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    60  	computeClient, err := b.config.computeV2Client()
    61  	if err != nil {
    62  		return nil, fmt.Errorf("Error initializing compute client: %s", err)
    63  	}
    64  
    65  	// Setup the state bag and initial state for the steps
    66  	state := new(multistep.BasicStateBag)
    67  	state.Put("config", b.config)
    68  	state.Put("hook", hook)
    69  	state.Put("ui", ui)
    70  
    71  	// Build the steps
    72  	steps := []multistep.Step{
    73  		&StepLoadExtensions{},
    74  		&StepLoadFlavor{
    75  			Flavor: b.config.Flavor,
    76  		},
    77  		&StepKeyPair{
    78  			Debug:                b.config.PackerDebug,
    79  			DebugKeyPath:         fmt.Sprintf("os_%s.pem", b.config.PackerBuildName),
    80  			KeyPairName:          b.config.SSHKeyPairName,
    81  			TemporaryKeyPairName: b.config.TemporaryKeyPairName,
    82  			PrivateKeyFile:       b.config.RunConfig.Comm.SSHPrivateKey,
    83  			SSHAgentAuth:         b.config.RunConfig.Comm.SSHAgentAuth,
    84  		},
    85  		&StepRunSourceServer{
    86  			Name:             b.config.ImageName,
    87  			SourceImage:      b.config.SourceImage,
    88  			SourceImageName:  b.config.SourceImageName,
    89  			SecurityGroups:   b.config.SecurityGroups,
    90  			Networks:         b.config.Networks,
    91  			AvailabilityZone: b.config.AvailabilityZone,
    92  			UserData:         b.config.UserData,
    93  			UserDataFile:     b.config.UserDataFile,
    94  			ConfigDrive:      b.config.ConfigDrive,
    95  			InstanceMetadata: b.config.InstanceMetadata,
    96  		},
    97  		&StepGetPassword{
    98  			Debug: b.config.PackerDebug,
    99  			Comm:  &b.config.RunConfig.Comm,
   100  		},
   101  		&StepWaitForRackConnect{
   102  			Wait: b.config.RackconnectWait,
   103  		},
   104  		&StepAllocateIp{
   105  			FloatingIpPool: b.config.FloatingIpPool,
   106  			FloatingIp:     b.config.FloatingIp,
   107  			ReuseIps:       b.config.ReuseIps,
   108  		},
   109  		&communicator.StepConnect{
   110  			Config: &b.config.RunConfig.Comm,
   111  			Host: CommHost(
   112  				computeClient,
   113  				b.config.SSHInterface,
   114  				b.config.SSHIPVersion),
   115  			SSHConfig: SSHConfig(
   116  				b.config.RunConfig.Comm.SSHAgentAuth,
   117  				b.config.RunConfig.Comm.SSHUsername,
   118  				b.config.RunConfig.Comm.SSHPassword),
   119  		},
   120  		&common.StepProvision{},
   121  		&StepStopServer{},
   122  		&stepCreateImage{},
   123  		&stepUpdateImageVisibility{},
   124  		&stepAddImageMembers{},
   125  	}
   126  
   127  	// Run!
   128  	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
   129  	b.runner.Run(state)
   130  
   131  	// If there was an error, return that
   132  	if rawErr, ok := state.GetOk("error"); ok {
   133  		return nil, rawErr.(error)
   134  	}
   135  
   136  	// If there are no images, then just return
   137  	if _, ok := state.GetOk("image"); !ok {
   138  		return nil, nil
   139  	}
   140  
   141  	// Build the artifact and return it
   142  	artifact := &Artifact{
   143  		ImageId:        state.Get("image").(string),
   144  		BuilderIdValue: BuilderId,
   145  		Client:         computeClient,
   146  	}
   147  
   148  	return artifact, nil
   149  }
   150  
   151  func (b *Builder) Cancel() {
   152  	if b.runner != nil {
   153  		log.Println("Cancelling the step runner...")
   154  		b.runner.Cancel()
   155  	}
   156  }