github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/alicloud/ecs/builder.go (about)

     1  // The alicloud  contains a packer.Builder implementation that
     2  // builds ecs images for alicloud.
     3  package ecs
     4  
     5  import (
     6  	"log"
     7  
     8  	"fmt"
     9  	"github.com/hashicorp/packer/common"
    10  	"github.com/hashicorp/packer/helper/communicator"
    11  	"github.com/hashicorp/packer/helper/config"
    12  	"github.com/hashicorp/packer/packer"
    13  	"github.com/hashicorp/packer/template/interpolate"
    14  	"github.com/mitchellh/multistep"
    15  )
    16  
    17  // The unique ID for this builder
    18  const BuilderId = "alibaba.alicloud"
    19  
    20  type Config struct {
    21  	common.PackerConfig  `mapstructure:",squash"`
    22  	AlicloudAccessConfig `mapstructure:",squash"`
    23  	AlicloudImageConfig  `mapstructure:",squash"`
    24  	RunConfig            `mapstructure:",squash"`
    25  
    26  	ctx interpolate.Context
    27  }
    28  
    29  type Builder struct {
    30  	config Config
    31  	runner multistep.Runner
    32  }
    33  
    34  type InstanceNetWork string
    35  
    36  const (
    37  	ClassicNet                     = InstanceNetWork("classic")
    38  	VpcNet                         = InstanceNetWork("vpc")
    39  	ALICLOUD_DEFAULT_SHORT_TIMEOUT = 180
    40  	ALICLOUD_DEFAULT_TIMEOUT       = 1800
    41  	ALICLOUD_DEFAULT_LONG_TIMEOUT  = 3600
    42  )
    43  
    44  func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
    45  	err := config.Decode(&b.config, &config.DecodeOpts{
    46  		Interpolate:        true,
    47  		InterpolateContext: &b.config.ctx,
    48  		InterpolateFilter: &interpolate.RenderFilter{
    49  			Exclude: []string{
    50  				"run_command",
    51  			},
    52  		},
    53  	}, raws...)
    54  	b.config.ctx.EnableEnv = true
    55  	if err != nil {
    56  		return nil, err
    57  	}
    58  
    59  	// Accumulate any errors
    60  	var errs *packer.MultiError
    61  	errs = packer.MultiErrorAppend(errs, b.config.AlicloudAccessConfig.Prepare(&b.config.ctx)...)
    62  	errs = packer.MultiErrorAppend(errs, b.config.AlicloudImageConfig.Prepare(&b.config.ctx)...)
    63  	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)
    64  
    65  	if errs != nil && len(errs.Errors) > 0 {
    66  		return nil, errs
    67  	}
    68  
    69  	log.Println(common.ScrubConfig(b.config, b.config.AlicloudAccessKey, b.config.AlicloudSecretKey))
    70  	return nil, nil
    71  }
    72  
    73  func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
    74  
    75  	client, err := b.config.Client()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	state := new(multistep.BasicStateBag)
    80  	state.Put("config", b.config)
    81  	state.Put("client", client)
    82  	state.Put("hook", hook)
    83  	state.Put("ui", ui)
    84  	state.Put("networktype", b.chooseNetworkType())
    85  	var steps []multistep.Step
    86  
    87  	// Build the steps
    88  	steps = []multistep.Step{
    89  		&stepPreValidate{
    90  			AlicloudDestImageName: b.config.AlicloudImageName,
    91  			ForceDelete:           b.config.AlicloudImageForceDetele,
    92  		},
    93  		&stepCheckAlicloudSourceImage{
    94  			SourceECSImageId: b.config.AlicloudSourceImage,
    95  		},
    96  		&StepConfigAlicloudKeyPair{
    97  			Debug:                b.config.PackerDebug,
    98  			KeyPairName:          b.config.SSHKeyPairName,
    99  			PrivateKeyFile:       b.config.Comm.SSHPrivateKey,
   100  			TemporaryKeyPairName: b.config.TemporaryKeyPairName,
   101  			SSHAgentAuth:         b.config.Comm.SSHAgentAuth,
   102  			DebugKeyPath:         fmt.Sprintf("ecs_%s.pem", b.config.PackerBuildName),
   103  			RegionId:             b.config.AlicloudRegion,
   104  		},
   105  	}
   106  	if b.chooseNetworkType() == VpcNet {
   107  		steps = append(steps,
   108  			&stepConfigAlicloudVPC{
   109  				VpcId:     b.config.VpcId,
   110  				CidrBlock: b.config.CidrBlock,
   111  				VpcName:   b.config.VpcName,
   112  			},
   113  			&stepConfigAlicloudVSwitch{
   114  				VSwitchId:   b.config.VSwitchId,
   115  				ZoneId:      b.config.ZoneId,
   116  				CidrBlock:   b.config.CidrBlock,
   117  				VSwitchName: b.config.VSwitchName,
   118  			})
   119  	}
   120  	steps = append(steps,
   121  		&stepConfigAlicloudSecurityGroup{
   122  			SecurityGroupId:   b.config.SecurityGroupId,
   123  			SecurityGroupName: b.config.SecurityGroupId,
   124  			RegionId:          b.config.AlicloudRegion,
   125  		},
   126  		&stepCreateAlicloudInstance{
   127  			IOOptimized:             b.config.IOOptimized,
   128  			InstanceType:            b.config.InstanceType,
   129  			UserData:                b.config.UserData,
   130  			UserDataFile:            b.config.UserDataFile,
   131  			RegionId:                b.config.AlicloudRegion,
   132  			InternetChargeType:      b.config.InternetChargeType,
   133  			InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
   134  			InstnaceName:            b.config.InstanceName,
   135  			ZoneId:                  b.config.ZoneId,
   136  		})
   137  	if b.chooseNetworkType() == VpcNet {
   138  		steps = append(steps, &setpConfigAlicloudEIP{
   139  			AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
   140  			RegionId:                 b.config.AlicloudRegion,
   141  			InternetChargeType:       b.config.InternetChargeType,
   142  		})
   143  	} else {
   144  		steps = append(steps, &stepConfigAlicloudPublicIP{
   145  			RegionId: b.config.AlicloudRegion,
   146  		})
   147  	}
   148  	steps = append(steps,
   149  		&stepRunAlicloudInstance{},
   150  		&stepMountAlicloudDisk{},
   151  		&stepAttachKeyPar{},
   152  		&communicator.StepConnect{
   153  			Config: &b.config.RunConfig.Comm,
   154  			Host: SSHHost(
   155  				client,
   156  				b.config.SSHPrivateIp),
   157  			SSHConfig: SSHConfig(
   158  				b.config.RunConfig.Comm.SSHAgentAuth,
   159  				b.config.RunConfig.Comm.SSHUsername,
   160  				b.config.RunConfig.Comm.SSHPassword),
   161  		},
   162  		&common.StepProvision{},
   163  		&stepStopAlicloudInstance{
   164  			ForceStop: b.config.ForceStopInstance,
   165  		},
   166  		&stepDeleteAlicloudImageSnapshots{
   167  			AlicloudImageForceDeteleSnapshots: b.config.AlicloudImageForceDeteleSnapshots,
   168  			AlicloudImageForceDetele:          b.config.AlicloudImageForceDetele,
   169  			AlicloudImageName:                 b.config.AlicloudImageName,
   170  		},
   171  		&stepCreateAlicloudImage{},
   172  		&setpRegionCopyAlicloudImage{
   173  			AlicloudImageDestinationRegions: b.config.AlicloudImageDestinationRegions,
   174  			AlicloudImageDestinationNames:   b.config.AlicloudImageDestinationNames,
   175  			RegionId:                        b.config.AlicloudRegion,
   176  		},
   177  		&setpShareAlicloudImage{
   178  			AlicloudImageShareAccounts:   b.config.AlicloudImageShareAccounts,
   179  			AlicloudImageUNShareAccounts: b.config.AlicloudImageUNShareAccounts,
   180  			RegionId:                     b.config.AlicloudRegion,
   181  		})
   182  
   183  	// Run!
   184  	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
   185  	b.runner.Run(state)
   186  
   187  	// If there was an error, return that
   188  	if rawErr, ok := state.GetOk("error"); ok {
   189  		return nil, rawErr.(error)
   190  	}
   191  
   192  	// If there are no ECS images, then just return
   193  	if _, ok := state.GetOk("alicloudimages"); !ok {
   194  		return nil, nil
   195  	}
   196  
   197  	// Build the artifact and return it
   198  	artifact := &Artifact{
   199  		AlicloudImages: state.Get("alicloudimages").(map[string]string),
   200  		BuilderIdValue: BuilderId,
   201  		Client:         client,
   202  	}
   203  
   204  	return artifact, nil
   205  }
   206  
   207  func (b *Builder) Cancel() {
   208  	if b.runner != nil {
   209  		log.Println("Cancelling the step runner...")
   210  		b.runner.Cancel()
   211  	}
   212  }
   213  
   214  func (b *Builder) chooseNetworkType() InstanceNetWork {
   215  	if b.isVpcNetRequired() {
   216  		return VpcNet
   217  	} else {
   218  		return ClassicNet
   219  	}
   220  }
   221  
   222  func (b *Builder) isVpcNetRequired() bool {
   223  	// UserData and KeyPair only works in VPC
   224  	return b.isVpcSpecified() || b.isUserDataNeeded() || b.isKeyPairNeeded()
   225  }
   226  
   227  func (b *Builder) isVpcSpecified() bool {
   228  	return b.config.VpcId != "" || b.config.VSwitchId != ""
   229  }
   230  
   231  func (b *Builder) isUserDataNeeded() bool {
   232  	// Public key setup requires userdata
   233  	if b.config.RunConfig.Comm.SSHPrivateKey != "" {
   234  		return true
   235  	}
   236  
   237  	return b.config.UserData != "" || b.config.UserDataFile != ""
   238  }
   239  
   240  func (b *Builder) isKeyPairNeeded() bool {
   241  	return b.config.SSHKeyPairName != "" || b.config.TemporaryKeyPairName != ""
   242  }