github.phpd.cn/hashicorp/packer@v1.3.2/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  	packer.LogSecretFilter.Set(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  			Comm:         &b.config.Comm,
   100  			DebugKeyPath: fmt.Sprintf("ecs_%s.pem", b.config.PackerBuildName),
   101  			RegionId:     b.config.AlicloudRegion,
   102  		},
   103  	}
   104  	if b.chooseNetworkType() == VpcNet {
   105  		steps = append(steps,
   106  			&stepConfigAlicloudVPC{
   107  				VpcId:     b.config.VpcId,
   108  				CidrBlock: b.config.CidrBlock,
   109  				VpcName:   b.config.VpcName,
   110  			},
   111  			&stepConfigAlicloudVSwitch{
   112  				VSwitchId:   b.config.VSwitchId,
   113  				ZoneId:      b.config.ZoneId,
   114  				CidrBlock:   b.config.CidrBlock,
   115  				VSwitchName: b.config.VSwitchName,
   116  			})
   117  	}
   118  	steps = append(steps,
   119  		&stepConfigAlicloudSecurityGroup{
   120  			SecurityGroupId:   b.config.SecurityGroupId,
   121  			SecurityGroupName: b.config.SecurityGroupId,
   122  			RegionId:          b.config.AlicloudRegion,
   123  		},
   124  		&stepCreateAlicloudInstance{
   125  			IOOptimized:             b.config.IOOptimized,
   126  			InstanceType:            b.config.InstanceType,
   127  			UserData:                b.config.UserData,
   128  			UserDataFile:            b.config.UserDataFile,
   129  			RegionId:                b.config.AlicloudRegion,
   130  			InternetChargeType:      b.config.InternetChargeType,
   131  			InternetMaxBandwidthOut: b.config.InternetMaxBandwidthOut,
   132  			InstanceName:            b.config.InstanceName,
   133  			ZoneId:                  b.config.ZoneId,
   134  		})
   135  	if b.chooseNetworkType() == VpcNet {
   136  		steps = append(steps, &stepConfigAlicloudEIP{
   137  			AssociatePublicIpAddress: b.config.AssociatePublicIpAddress,
   138  			RegionId:                 b.config.AlicloudRegion,
   139  			InternetChargeType:       b.config.InternetChargeType,
   140  			InternetMaxBandwidthOut:  b.config.InternetMaxBandwidthOut,
   141  			SSHPrivateIp:             b.config.SSHPrivateIp,
   142  		})
   143  	} else {
   144  		steps = append(steps, &stepConfigAlicloudPublicIP{
   145  			RegionId:     b.config.AlicloudRegion,
   146  			SSHPrivateIp: b.config.SSHPrivateIp,
   147  		})
   148  	}
   149  	steps = append(steps,
   150  		&stepAttachKeyPair{},
   151  		&stepRunAlicloudInstance{},
   152  		&stepMountAlicloudDisk{},
   153  		&communicator.StepConnect{
   154  			Config: &b.config.RunConfig.Comm,
   155  			Host: SSHHost(
   156  				client,
   157  				b.config.SSHPrivateIp),
   158  			SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(),
   159  		},
   160  		&common.StepProvision{},
   161  		&common.StepCleanupTempKeys{
   162  			Comm: &b.config.RunConfig.Comm,
   163  		},
   164  		&stepStopAlicloudInstance{
   165  			ForceStop:   b.config.ForceStopInstance,
   166  			DisableStop: b.config.DisableStopInstance,
   167  		},
   168  		&stepDeleteAlicloudImageSnapshots{
   169  			AlicloudImageForceDeleteSnapshots: b.config.AlicloudImageForceDeleteSnapshots,
   170  			AlicloudImageForceDelete:          b.config.AlicloudImageForceDelete,
   171  			AlicloudImageName:                 b.config.AlicloudImageName,
   172  		},
   173  		&stepCreateAlicloudImage{},
   174  		&stepCreateTags{
   175  			Tags: b.config.AlicloudImageTags,
   176  		},
   177  		&stepRegionCopyAlicloudImage{
   178  			AlicloudImageDestinationRegions: b.config.AlicloudImageDestinationRegions,
   179  			AlicloudImageDestinationNames:   b.config.AlicloudImageDestinationNames,
   180  			RegionId:                        b.config.AlicloudRegion,
   181  		},
   182  		&stepShareAlicloudImage{
   183  			AlicloudImageShareAccounts:   b.config.AlicloudImageShareAccounts,
   184  			AlicloudImageUNShareAccounts: b.config.AlicloudImageUNShareAccounts,
   185  			RegionId:                     b.config.AlicloudRegion,
   186  		})
   187  
   188  	// Run!
   189  	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
   190  	b.runner.Run(state)
   191  
   192  	// If there was an error, return that
   193  	if rawErr, ok := state.GetOk("error"); ok {
   194  		return nil, rawErr.(error)
   195  	}
   196  
   197  	// If there are no ECS images, then just return
   198  	if _, ok := state.GetOk("alicloudimages"); !ok {
   199  		return nil, nil
   200  	}
   201  
   202  	// Build the artifact and return it
   203  	artifact := &Artifact{
   204  		AlicloudImages: state.Get("alicloudimages").(map[string]string),
   205  		BuilderIdValue: BuilderId,
   206  		Client:         client,
   207  	}
   208  
   209  	return artifact, nil
   210  }
   211  
   212  func (b *Builder) Cancel() {
   213  	if b.runner != nil {
   214  		log.Println("Cancelling the step runner...")
   215  		b.runner.Cancel()
   216  	}
   217  }
   218  
   219  func (b *Builder) chooseNetworkType() InstanceNetWork {
   220  	if b.isVpcNetRequired() {
   221  		return VpcNet
   222  	} else {
   223  		return ClassicNet
   224  	}
   225  }
   226  
   227  func (b *Builder) isVpcNetRequired() bool {
   228  	// UserData and KeyPair only works in VPC
   229  	return b.isVpcSpecified() || b.isUserDataNeeded() || b.isKeyPairNeeded()
   230  }
   231  
   232  func (b *Builder) isVpcSpecified() bool {
   233  	return b.config.VpcId != "" || b.config.VSwitchId != ""
   234  }
   235  
   236  func (b *Builder) isUserDataNeeded() bool {
   237  	// Public key setup requires userdata
   238  	if b.config.RunConfig.Comm.SSHPrivateKeyFile != "" {
   239  		return true
   240  	}
   241  
   242  	return b.config.UserData != "" || b.config.UserDataFile != ""
   243  }
   244  
   245  func (b *Builder) isKeyPairNeeded() bool {
   246  	return b.config.Comm.SSHKeyPairName != "" || b.config.Comm.SSHTemporaryKeyPairName != ""
   247  }