github.com/sneal/packer@v0.5.2/builder/amazon/ebs/builder.go (about)

     1  // The amazonebs package contains a packer.Builder implementation that
     2  // builds AMIs for Amazon EC2.
     3  //
     4  // In general, there are two types of AMIs that can be created: ebs-backed or
     5  // instance-store. This builder _only_ builds ebs-backed images.
     6  package ebs
     7  
     8  import (
     9  	"fmt"
    10  	"github.com/mitchellh/goamz/ec2"
    11  	"github.com/mitchellh/multistep"
    12  	awscommon "github.com/mitchellh/packer/builder/amazon/common"
    13  	"github.com/mitchellh/packer/common"
    14  	"github.com/mitchellh/packer/packer"
    15  	"log"
    16  )
    17  
    18  // The unique ID for this builder
    19  const BuilderId = "mitchellh.amazonebs"
    20  
    21  type config struct {
    22  	common.PackerConfig    `mapstructure:",squash"`
    23  	awscommon.AccessConfig `mapstructure:",squash"`
    24  	awscommon.AMIConfig    `mapstructure:",squash"`
    25  	awscommon.BlockDevices `mapstructure:",squash"`
    26  	awscommon.RunConfig    `mapstructure:",squash"`
    27  
    28  	tpl *packer.ConfigTemplate
    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  	md, err := common.DecodeConfig(&b.config, raws...)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	b.config.tpl, err = packer.NewConfigTemplate()
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	b.config.tpl.UserVars = b.config.PackerUserVars
    47  	b.config.tpl.Funcs(awscommon.TemplateFuncs)
    48  
    49  	// Accumulate any errors
    50  	errs := common.CheckUnusedConfig(md)
    51  	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(b.config.tpl)...)
    52  	errs = packer.MultiErrorAppend(errs, b.config.AMIConfig.Prepare(b.config.tpl)...)
    53  	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(b.config.tpl)...)
    54  
    55  	if errs != nil && len(errs.Errors) > 0 {
    56  		return nil, errs
    57  	}
    58  
    59  	log.Println(common.ScrubConfig(b.config, b.config.AccessKey, b.config.SecretKey))
    60  	return nil, nil
    61  }
    62  
    63  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    64  	region, err := b.config.Region()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	auth, err := b.config.AccessConfig.Auth()
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	ec2conn := ec2.New(auth, region)
    75  
    76  	// Setup the state bag and initial state for the steps
    77  	state := new(multistep.BasicStateBag)
    78  	state.Put("config", b.config)
    79  	state.Put("ec2", ec2conn)
    80  	state.Put("hook", hook)
    81  	state.Put("ui", ui)
    82  
    83  	// Build the steps
    84  	steps := []multistep.Step{
    85  		&awscommon.StepKeyPair{
    86  			Debug:        b.config.PackerDebug,
    87  			DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName),
    88  			KeyPairName:  b.config.TemporaryKeyPairName,
    89  		},
    90  		&awscommon.StepSecurityGroup{
    91  			SecurityGroupIds: b.config.SecurityGroupIds,
    92  			SSHPort:          b.config.SSHPort,
    93  			VpcId:            b.config.VpcId,
    94  		},
    95  		&awscommon.StepRunSourceInstance{
    96  			Debug:                    b.config.PackerDebug,
    97  			ExpectedRootDevice:       "ebs",
    98  			InstanceType:             b.config.InstanceType,
    99  			UserData:                 b.config.UserData,
   100  			UserDataFile:             b.config.UserDataFile,
   101  			SourceAMI:                b.config.SourceAmi,
   102  			IamInstanceProfile:       b.config.IamInstanceProfile,
   103  			SubnetId:                 b.config.SubnetId,
   104  			AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
   105  			AvailabilityZone:         b.config.AvailabilityZone,
   106  			BlockDevices:             b.config.BlockDevices,
   107  			Tags:                     b.config.RunTags,
   108  		},
   109  		&common.StepConnectSSH{
   110  			SSHAddress:     awscommon.SSHAddress(ec2conn, b.config.SSHPort),
   111  			SSHConfig:      awscommon.SSHConfig(b.config.SSHUsername),
   112  			SSHWaitTimeout: b.config.SSHTimeout(),
   113  		},
   114  		&common.StepProvision{},
   115  		&stepStopInstance{},
   116  		&stepCreateAMI{},
   117  		&awscommon.StepAMIRegionCopy{
   118  			Regions: b.config.AMIRegions,
   119  		},
   120  		&awscommon.StepModifyAMIAttributes{
   121  			Description: b.config.AMIDescription,
   122  			Users:       b.config.AMIUsers,
   123  			Groups:      b.config.AMIGroups,
   124  		},
   125  		&awscommon.StepCreateTags{
   126  			Tags: b.config.AMITags,
   127  		},
   128  	}
   129  
   130  	// Run!
   131  	if b.config.PackerDebug {
   132  		b.runner = &multistep.DebugRunner{
   133  			Steps:   steps,
   134  			PauseFn: common.MultistepDebugFn(ui),
   135  		}
   136  	} else {
   137  		b.runner = &multistep.BasicRunner{Steps: steps}
   138  	}
   139  
   140  	b.runner.Run(state)
   141  
   142  	// If there was an error, return that
   143  	if rawErr, ok := state.GetOk("error"); ok {
   144  		return nil, rawErr.(error)
   145  	}
   146  
   147  	// If there are no AMIs, then just return
   148  	if _, ok := state.GetOk("amis"); !ok {
   149  		return nil, nil
   150  	}
   151  
   152  	// Build the artifact and return it
   153  	artifact := &awscommon.Artifact{
   154  		Amis:           state.Get("amis").(map[string]string),
   155  		BuilderIdValue: BuilderId,
   156  		Conn:           ec2conn,
   157  	}
   158  
   159  	return artifact, nil
   160  }
   161  
   162  func (b *Builder) Cancel() {
   163  	if b.runner != nil {
   164  		log.Println("Cancelling the step runner...")
   165  		b.runner.Cancel()
   166  	}
   167  }