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 }