github.phpd.cn/hashicorp/packer@v1.3.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  	"log"
    11  
    12  	"github.com/aws/aws-sdk-go/service/ec2"
    13  	awscommon "github.com/hashicorp/packer/builder/amazon/common"
    14  	"github.com/hashicorp/packer/common"
    15  	"github.com/hashicorp/packer/helper/communicator"
    16  	"github.com/hashicorp/packer/helper/config"
    17  	"github.com/hashicorp/packer/helper/multistep"
    18  	"github.com/hashicorp/packer/packer"
    19  	"github.com/hashicorp/packer/template/interpolate"
    20  )
    21  
    22  // The unique ID for this builder
    23  const BuilderId = "mitchellh.amazonebs"
    24  
    25  type Config struct {
    26  	common.PackerConfig    `mapstructure:",squash"`
    27  	awscommon.AccessConfig `mapstructure:",squash"`
    28  	awscommon.AMIConfig    `mapstructure:",squash"`
    29  	awscommon.BlockDevices `mapstructure:",squash"`
    30  	awscommon.RunConfig    `mapstructure:",squash"`
    31  	VolumeRunTags          awscommon.TagMap `mapstructure:"run_volume_tags"`
    32  
    33  	ctx interpolate.Context
    34  }
    35  
    36  type Builder struct {
    37  	config Config
    38  	runner multistep.Runner
    39  }
    40  
    41  func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
    42  	b.config.ctx.Funcs = awscommon.TemplateFuncs
    43  	err := config.Decode(&b.config, &config.DecodeOpts{
    44  		Interpolate:        true,
    45  		InterpolateContext: &b.config.ctx,
    46  		InterpolateFilter: &interpolate.RenderFilter{
    47  			Exclude: []string{
    48  				"ami_description",
    49  				"run_tags",
    50  				"run_volume_tags",
    51  				"spot_tags",
    52  				"snapshot_tags",
    53  				"tags",
    54  			},
    55  		},
    56  	}, raws...)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	if b.config.PackerConfig.PackerForce {
    62  		b.config.AMIForceDeregister = true
    63  	}
    64  
    65  	// Accumulate any errors
    66  	var errs *packer.MultiError
    67  	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
    68  	errs = packer.MultiErrorAppend(errs,
    69  		b.config.AMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
    70  	errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
    71  	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
    72  
    73  	if b.config.IsSpotInstance() && ((b.config.AMIENASupport != nil && *b.config.AMIENASupport) || b.config.AMISriovNetSupport) {
    74  		errs = packer.MultiErrorAppend(errs,
    75  			fmt.Errorf("Spot instances do not support modification, which is required "+
    76  				"when either `ena_support` or `sriov_support` are set. Please ensure "+
    77  				"you use an AMI that already has either SR-IOV or ENA enabled."))
    78  	}
    79  
    80  	if errs != nil && len(errs.Errors) > 0 {
    81  		return nil, errs
    82  	}
    83  
    84  	packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
    85  	return nil, nil
    86  }
    87  
    88  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    89  
    90  	session, err := b.config.Session()
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	ec2conn := ec2.New(session)
    95  
    96  	// Setup the state bag and initial state for the steps
    97  	state := new(multistep.BasicStateBag)
    98  	state.Put("config", &b.config)
    99  	state.Put("ec2", ec2conn)
   100  	state.Put("awsSession", session)
   101  	state.Put("hook", hook)
   102  	state.Put("ui", ui)
   103  
   104  	var instanceStep multistep.Step
   105  
   106  	if b.config.IsSpotInstance() {
   107  		instanceStep = &awscommon.StepRunSpotInstance{
   108  			AssociatePublicIpAddress:          b.config.AssociatePublicIpAddress,
   109  			BlockDevices:                      b.config.BlockDevices,
   110  			BlockDurationMinutes:              b.config.BlockDurationMinutes,
   111  			Ctx:                               b.config.ctx,
   112  			Comm:                              &b.config.RunConfig.Comm,
   113  			Debug:                             b.config.PackerDebug,
   114  			EbsOptimized:                      b.config.EbsOptimized,
   115  			ExpectedRootDevice:                "ebs",
   116  			IamInstanceProfile:                b.config.IamInstanceProfile,
   117  			InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
   118  			InstanceType:                      b.config.InstanceType,
   119  			SourceAMI:                         b.config.SourceAmi,
   120  			SpotPrice:                         b.config.SpotPrice,
   121  			SpotPriceProduct:                  b.config.SpotPriceAutoProduct,
   122  			SpotTags:                          b.config.SpotTags,
   123  			Tags:                              b.config.RunTags,
   124  			UserData:                          b.config.UserData,
   125  			UserDataFile:                      b.config.UserDataFile,
   126  			VolumeTags:                        b.config.VolumeRunTags,
   127  		}
   128  	} else {
   129  		instanceStep = &awscommon.StepRunSourceInstance{
   130  			AssociatePublicIpAddress:          b.config.AssociatePublicIpAddress,
   131  			BlockDevices:                      b.config.BlockDevices,
   132  			Comm:                              &b.config.RunConfig.Comm,
   133  			Ctx:                               b.config.ctx,
   134  			Debug:                             b.config.PackerDebug,
   135  			EbsOptimized:                      b.config.EbsOptimized,
   136  			EnableT2Unlimited:                 b.config.EnableT2Unlimited,
   137  			ExpectedRootDevice:                "ebs",
   138  			IamInstanceProfile:                b.config.IamInstanceProfile,
   139  			InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
   140  			InstanceType:                      b.config.InstanceType,
   141  			IsRestricted:                      b.config.IsChinaCloud() || b.config.IsGovCloud(),
   142  			SourceAMI:                         b.config.SourceAmi,
   143  			Tags:                              b.config.RunTags,
   144  			UserData:                          b.config.UserData,
   145  			UserDataFile:                      b.config.UserDataFile,
   146  			VolumeTags:                        b.config.VolumeRunTags,
   147  		}
   148  	}
   149  
   150  	// Build the steps
   151  	steps := []multistep.Step{
   152  		&awscommon.StepPreValidate{
   153  			DestAmiName:     b.config.AMIName,
   154  			ForceDeregister: b.config.AMIForceDeregister,
   155  		},
   156  		&awscommon.StepSourceAMIInfo{
   157  			SourceAmi:                b.config.SourceAmi,
   158  			EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
   159  			EnableAMIENASupport:      b.config.AMIENASupport,
   160  			AmiFilters:               b.config.SourceAmiFilter,
   161  			AMIVirtType:              b.config.AMIVirtType,
   162  		},
   163  		&awscommon.StepNetworkInfo{
   164  			VpcId:               b.config.VpcId,
   165  			VpcFilter:           b.config.VpcFilter,
   166  			SecurityGroupIds:    b.config.SecurityGroupIds,
   167  			SecurityGroupFilter: b.config.SecurityGroupFilter,
   168  			SubnetId:            b.config.SubnetId,
   169  			SubnetFilter:        b.config.SubnetFilter,
   170  			AvailabilityZone:    b.config.AvailabilityZone,
   171  		},
   172  		&awscommon.StepKeyPair{
   173  			Debug:        b.config.PackerDebug,
   174  			Comm:         &b.config.RunConfig.Comm,
   175  			DebugKeyPath: fmt.Sprintf("ec2_%s.pem", b.config.PackerBuildName),
   176  		},
   177  		&awscommon.StepSecurityGroup{
   178  			SecurityGroupFilter:   b.config.SecurityGroupFilter,
   179  			SecurityGroupIds:      b.config.SecurityGroupIds,
   180  			CommConfig:            &b.config.RunConfig.Comm,
   181  			TemporarySGSourceCidr: b.config.TemporarySGSourceCidr,
   182  		},
   183  		&awscommon.StepCleanupVolumes{
   184  			BlockDevices: b.config.BlockDevices,
   185  		},
   186  		instanceStep,
   187  		&awscommon.StepGetPassword{
   188  			Debug:     b.config.PackerDebug,
   189  			Comm:      &b.config.RunConfig.Comm,
   190  			Timeout:   b.config.WindowsPasswordTimeout,
   191  			BuildName: b.config.PackerBuildName,
   192  		},
   193  		&communicator.StepConnect{
   194  			Config: &b.config.RunConfig.Comm,
   195  			Host: awscommon.SSHHost(
   196  				ec2conn,
   197  				b.config.Comm.SSHInterface),
   198  			SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(),
   199  		},
   200  		&common.StepProvision{},
   201  		&common.StepCleanupTempKeys{
   202  			Comm: &b.config.RunConfig.Comm,
   203  		},
   204  		&awscommon.StepStopEBSBackedInstance{
   205  			Skip:                b.config.IsSpotInstance(),
   206  			DisableStopInstance: b.config.DisableStopInstance,
   207  		},
   208  		&awscommon.StepModifyEBSBackedInstance{
   209  			EnableAMISriovNetSupport: b.config.AMISriovNetSupport,
   210  			EnableAMIENASupport:      b.config.AMIENASupport,
   211  		},
   212  		&awscommon.StepDeregisterAMI{
   213  			AccessConfig:        &b.config.AccessConfig,
   214  			ForceDeregister:     b.config.AMIForceDeregister,
   215  			ForceDeleteSnapshot: b.config.AMIForceDeleteSnapshot,
   216  			AMIName:             b.config.AMIName,
   217  			Regions:             b.config.AMIRegions,
   218  		},
   219  		&stepCreateAMI{},
   220  		&awscommon.StepCreateEncryptedAMICopy{
   221  			KeyID:             b.config.AMIKmsKeyId,
   222  			EncryptBootVolume: b.config.AMIEncryptBootVolume,
   223  			Name:              b.config.AMIName,
   224  			AMIMappings:       b.config.AMIBlockDevices.AMIMappings,
   225  		},
   226  		&awscommon.StepAMIRegionCopy{
   227  			AccessConfig:      &b.config.AccessConfig,
   228  			Regions:           b.config.AMIRegions,
   229  			RegionKeyIds:      b.config.AMIRegionKMSKeyIDs,
   230  			EncryptBootVolume: b.config.AMIEncryptBootVolume,
   231  			Name:              b.config.AMIName,
   232  		},
   233  		&awscommon.StepModifyAMIAttributes{
   234  			Description:    b.config.AMIDescription,
   235  			Users:          b.config.AMIUsers,
   236  			Groups:         b.config.AMIGroups,
   237  			ProductCodes:   b.config.AMIProductCodes,
   238  			SnapshotUsers:  b.config.SnapshotUsers,
   239  			SnapshotGroups: b.config.SnapshotGroups,
   240  			Ctx:            b.config.ctx,
   241  		},
   242  		&awscommon.StepCreateTags{
   243  			Tags:         b.config.AMITags,
   244  			SnapshotTags: b.config.SnapshotTags,
   245  			Ctx:          b.config.ctx,
   246  		},
   247  	}
   248  
   249  	// Run!
   250  	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
   251  	b.runner.Run(state)
   252  	// If there was an error, return that
   253  	if rawErr, ok := state.GetOk("error"); ok {
   254  		return nil, rawErr.(error)
   255  	}
   256  
   257  	// If there are no AMIs, then just return
   258  	if _, ok := state.GetOk("amis"); !ok {
   259  		return nil, nil
   260  	}
   261  
   262  	// Build the artifact and return it
   263  	artifact := &awscommon.Artifact{
   264  		Amis:           state.Get("amis").(map[string]string),
   265  		BuilderIdValue: BuilderId,
   266  		Session:        session,
   267  	}
   268  
   269  	return artifact, nil
   270  }
   271  
   272  func (b *Builder) Cancel() {
   273  	if b.runner != nil {
   274  		log.Println("Cancelling the step runner...")
   275  		b.runner.Cancel()
   276  	}
   277  }