github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/amazon/common/run_config.go (about)

     1  package common
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/mitchellh/packer/common/uuid"
    10  	"github.com/mitchellh/packer/packer"
    11  )
    12  
    13  // RunConfig contains configuration for running an instance from a source
    14  // AMI and details on how to access that launched image.
    15  type RunConfig struct {
    16  	AssociatePublicIpAddress bool              `mapstructure:"associate_public_ip_address"`
    17  	AvailabilityZone         string            `mapstructure:"availability_zone"`
    18  	IamInstanceProfile       string            `mapstructure:"iam_instance_profile"`
    19  	InstanceType             string            `mapstructure:"instance_type"`
    20  	RunTags                  map[string]string `mapstructure:"run_tags"`
    21  	SourceAmi                string            `mapstructure:"source_ami"`
    22  	SpotPrice                string            `mapstructure:"spot_price"`
    23  	SpotPriceAutoProduct     string            `mapstructure:"spot_price_auto_product"`
    24  	RawSSHTimeout            string            `mapstructure:"ssh_timeout"`
    25  	SSHUsername              string            `mapstructure:"ssh_username"`
    26  	SSHPrivateKeyFile        string            `mapstructure:"ssh_private_key_file"`
    27  	SSHPrivateIp             bool              `mapstructure:"ssh_private_ip"`
    28  	SSHPort                  int               `mapstructure:"ssh_port"`
    29  	SecurityGroupId          string            `mapstructure:"security_group_id"`
    30  	SecurityGroupIds         []string          `mapstructure:"security_group_ids"`
    31  	SubnetId                 string            `mapstructure:"subnet_id"`
    32  	TemporaryKeyPairName     string            `mapstructure:"temporary_key_pair_name"`
    33  	UserData                 string            `mapstructure:"user_data"`
    34  	UserDataFile             string            `mapstructure:"user_data_file"`
    35  	VpcId                    string            `mapstructure:"vpc_id"`
    36  
    37  	// Unexported fields that are calculated from others
    38  	sshTimeout time.Duration
    39  }
    40  
    41  func (c *RunConfig) Prepare(t *packer.ConfigTemplate) []error {
    42  	if t == nil {
    43  		var err error
    44  		t, err = packer.NewConfigTemplate()
    45  		if err != nil {
    46  			return []error{err}
    47  		}
    48  	}
    49  
    50  	templates := map[string]*string{
    51  		"iam_instance_profile":    &c.IamInstanceProfile,
    52  		"instance_type":           &c.InstanceType,
    53  		"spot_price":              &c.SpotPrice,
    54  		"spot_price_auto_product": &c.SpotPriceAutoProduct,
    55  		"ssh_timeout":             &c.RawSSHTimeout,
    56  		"ssh_username":            &c.SSHUsername,
    57  		"ssh_private_key_file":    &c.SSHPrivateKeyFile,
    58  		"source_ami":              &c.SourceAmi,
    59  		"subnet_id":               &c.SubnetId,
    60  		"temporary_key_pair_name": &c.TemporaryKeyPairName,
    61  		"vpc_id":                  &c.VpcId,
    62  		"availability_zone":       &c.AvailabilityZone,
    63  		"user_data":               &c.UserData,
    64  		"user_data_file":          &c.UserDataFile,
    65  		"security_group_id":       &c.SecurityGroupId,
    66  	}
    67  
    68  	errs := make([]error, 0)
    69  	for n, ptr := range templates {
    70  		var err error
    71  		*ptr, err = t.Process(*ptr, nil)
    72  		if err != nil {
    73  			errs = append(
    74  				errs, fmt.Errorf("Error processing %s: %s", n, err))
    75  		}
    76  	}
    77  
    78  	// Defaults
    79  	if c.SSHPort == 0 {
    80  		c.SSHPort = 22
    81  	}
    82  
    83  	if c.RawSSHTimeout == "" {
    84  		c.RawSSHTimeout = "5m"
    85  	}
    86  
    87  	if c.TemporaryKeyPairName == "" {
    88  		c.TemporaryKeyPairName = fmt.Sprintf(
    89  			"packer %s", uuid.TimeOrderedUUID())
    90  	}
    91  
    92  	// Validation
    93  	var err error
    94  	if c.SourceAmi == "" {
    95  		errs = append(errs, errors.New("A source_ami must be specified"))
    96  	}
    97  
    98  	if c.InstanceType == "" {
    99  		errs = append(errs, errors.New("An instance_type must be specified"))
   100  	}
   101  
   102  	if c.SpotPrice == "auto" {
   103  		if c.SpotPriceAutoProduct == "" {
   104  			errs = append(errs, errors.New(
   105  				"spot_price_auto_product must be specified when spot_price is auto"))
   106  		}
   107  	}
   108  
   109  	if c.SSHUsername == "" {
   110  		errs = append(errs, errors.New("An ssh_username must be specified"))
   111  	}
   112  
   113  	if c.UserData != "" && c.UserDataFile != "" {
   114  		errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified."))
   115  	} else if c.UserDataFile != "" {
   116  		if _, err := os.Stat(c.UserDataFile); err != nil {
   117  			errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile))
   118  		}
   119  	}
   120  
   121  	if c.SecurityGroupId != "" {
   122  		if len(c.SecurityGroupIds) > 0 {
   123  			errs = append(errs, fmt.Errorf("Only one of security_group_id or security_group_ids can be specified."))
   124  		} else {
   125  			c.SecurityGroupIds = []string{c.SecurityGroupId}
   126  			c.SecurityGroupId = ""
   127  		}
   128  	}
   129  
   130  	sliceTemplates := map[string][]string{
   131  		"security_group_ids": c.SecurityGroupIds,
   132  	}
   133  
   134  	for n, slice := range sliceTemplates {
   135  		for i, elem := range slice {
   136  			var err error
   137  			slice[i], err = t.Process(elem, nil)
   138  			if err != nil {
   139  				errs = append(
   140  					errs, fmt.Errorf("Error processing %s[%d]: %s", n, i, err))
   141  			}
   142  		}
   143  	}
   144  
   145  	newTags := make(map[string]string)
   146  	for k, v := range c.RunTags {
   147  		k, err := t.Process(k, nil)
   148  		if err != nil {
   149  			errs = append(errs,
   150  				fmt.Errorf("Error processing tag key %s: %s", k, err))
   151  			continue
   152  		}
   153  
   154  		v, err := t.Process(v, nil)
   155  		if err != nil {
   156  			errs = append(errs,
   157  				fmt.Errorf("Error processing tag value '%s': %s", v, err))
   158  			continue
   159  		}
   160  
   161  		newTags[k] = v
   162  	}
   163  
   164  	c.RunTags = newTags
   165  
   166  	c.sshTimeout, err = time.ParseDuration(c.RawSSHTimeout)
   167  	if err != nil {
   168  		errs = append(errs, fmt.Errorf("Failed parsing ssh_timeout: %s", err))
   169  	}
   170  
   171  	return errs
   172  }
   173  
   174  func (c *RunConfig) SSHTimeout() time.Duration {
   175  	return c.sshTimeout
   176  }