github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/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/helper/multistep"
    14  	"github.com/hashicorp/packer/packer"
    15  	"github.com/hashicorp/packer/template/interpolate"
    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  	// By default, instance name is same as image name
    56  	if b.config.InstanceName == "" {
    57  		b.config.InstanceName = b.config.ImageName
    58  	}
    59  
    60  	log.Println(common.ScrubConfig(b.config, b.config.Password))
    61  	return nil, nil
    62  }
    63  
    64  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    65  	computeClient, err := b.config.computeV2Client()
    66  	if err != nil {
    67  		return nil, fmt.Errorf("Error initializing compute client: %s", err)
    68  	}
    69  
    70  	// Setup the state bag and initial state for the steps
    71  	state := new(multistep.BasicStateBag)
    72  	state.Put("config", b.config)
    73  	state.Put("hook", hook)
    74  	state.Put("ui", ui)
    75  
    76  	// Build the steps
    77  	steps := []multistep.Step{
    78  		&StepLoadFlavor{
    79  			Flavor: b.config.Flavor,
    80  		},
    81  		&StepKeyPair{
    82  			Debug:                b.config.PackerDebug,
    83  			DebugKeyPath:         fmt.Sprintf("os_%s.pem", b.config.PackerBuildName),
    84  			KeyPairName:          b.config.SSHKeyPairName,
    85  			TemporaryKeyPairName: b.config.TemporaryKeyPairName,
    86  			PrivateKeyFile:       b.config.RunConfig.Comm.SSHPrivateKey,
    87  			SSHAgentAuth:         b.config.RunConfig.Comm.SSHAgentAuth,
    88  		},
    89  		&StepRunSourceServer{
    90  			Name:             b.config.InstanceName,
    91  			SourceImage:      b.config.SourceImage,
    92  			SourceImageName:  b.config.SourceImageName,
    93  			SecurityGroups:   b.config.SecurityGroups,
    94  			Networks:         b.config.Networks,
    95  			AvailabilityZone: b.config.AvailabilityZone,
    96  			UserData:         b.config.UserData,
    97  			UserDataFile:     b.config.UserDataFile,
    98  			ConfigDrive:      b.config.ConfigDrive,
    99  			InstanceMetadata: b.config.InstanceMetadata,
   100  		},
   101  		&StepGetPassword{
   102  			Debug: b.config.PackerDebug,
   103  			Comm:  &b.config.RunConfig.Comm,
   104  		},
   105  		&StepWaitForRackConnect{
   106  			Wait: b.config.RackconnectWait,
   107  		},
   108  		&StepAllocateIp{
   109  			FloatingIpPool: b.config.FloatingIpPool,
   110  			FloatingIp:     b.config.FloatingIp,
   111  			ReuseIps:       b.config.ReuseIps,
   112  		},
   113  		&communicator.StepConnect{
   114  			Config: &b.config.RunConfig.Comm,
   115  			Host: CommHost(
   116  				computeClient,
   117  				b.config.SSHInterface,
   118  				b.config.SSHIPVersion),
   119  			SSHConfig: SSHConfig(
   120  				b.config.RunConfig.Comm.SSHAgentAuth,
   121  				b.config.RunConfig.Comm.SSHUsername,
   122  				b.config.RunConfig.Comm.SSHPassword),
   123  		},
   124  		&common.StepProvision{},
   125  		&StepStopServer{},
   126  		&stepCreateImage{},
   127  		&stepUpdateImageVisibility{},
   128  		&stepAddImageMembers{},
   129  	}
   130  
   131  	// Run!
   132  	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
   133  	b.runner.Run(state)
   134  
   135  	// If there was an error, return that
   136  	if rawErr, ok := state.GetOk("error"); ok {
   137  		return nil, rawErr.(error)
   138  	}
   139  
   140  	// If there are no images, then just return
   141  	if _, ok := state.GetOk("image"); !ok {
   142  		return nil, nil
   143  	}
   144  
   145  	// Build the artifact and return it
   146  	artifact := &Artifact{
   147  		ImageId:        state.Get("image").(string),
   148  		BuilderIdValue: BuilderId,
   149  		Client:         computeClient,
   150  	}
   151  
   152  	return artifact, nil
   153  }
   154  
   155  func (b *Builder) Cancel() {
   156  	if b.runner != nil {
   157  		log.Println("Cancelling the step runner...")
   158  		b.runner.Cancel()
   159  	}
   160  }