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