github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/amazon/common/run_config.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "net" 6 "os" 7 "regexp" 8 "strings" 9 "time" 10 11 "github.com/hashicorp/packer/common/uuid" 12 "github.com/hashicorp/packer/helper/communicator" 13 "github.com/hashicorp/packer/template/interpolate" 14 ) 15 16 var reShutdownBehavior = regexp.MustCompile("^(stop|terminate)$") 17 18 type AmiFilterOptions struct { 19 Filters map[*string]*string 20 Owners []*string 21 MostRecent bool `mapstructure:"most_recent"` 22 } 23 24 func (d *AmiFilterOptions) Empty() bool { 25 return len(d.Owners) == 0 && len(d.Filters) == 0 26 } 27 28 // RunConfig contains configuration for running an instance from a source 29 // AMI and details on how to access that launched image. 30 type RunConfig struct { 31 AssociatePublicIpAddress bool `mapstructure:"associate_public_ip_address"` 32 AvailabilityZone string `mapstructure:"availability_zone"` 33 DisableStopInstance bool `mapstructure:"disable_stop_instance"` 34 EbsOptimized bool `mapstructure:"ebs_optimized"` 35 EnableT2Unlimited bool `mapstructure:"enable_t2_unlimited"` 36 IamInstanceProfile string `mapstructure:"iam_instance_profile"` 37 InstanceInitiatedShutdownBehavior string `mapstructure:"shutdown_behavior"` 38 InstanceType string `mapstructure:"instance_type"` 39 RunTags map[string]string `mapstructure:"run_tags"` 40 SecurityGroupId string `mapstructure:"security_group_id"` 41 SecurityGroupIds []string `mapstructure:"security_group_ids"` 42 SourceAmi string `mapstructure:"source_ami"` 43 SourceAmiFilter AmiFilterOptions `mapstructure:"source_ami_filter"` 44 SpotPrice string `mapstructure:"spot_price"` 45 SpotPriceAutoProduct string `mapstructure:"spot_price_auto_product"` 46 SpotTags map[string]string `mapstructure:"spot_tags"` 47 SubnetId string `mapstructure:"subnet_id"` 48 TemporaryKeyPairName string `mapstructure:"temporary_key_pair_name"` 49 TemporarySGSourceCidr string `mapstructure:"temporary_security_group_source_cidr"` 50 UserData string `mapstructure:"user_data"` 51 UserDataFile string `mapstructure:"user_data_file"` 52 VpcId string `mapstructure:"vpc_id"` 53 WindowsPasswordTimeout time.Duration `mapstructure:"windows_password_timeout"` 54 55 // Communicator settings 56 Comm communicator.Config `mapstructure:",squash"` 57 SSHKeyPairName string `mapstructure:"ssh_keypair_name"` 58 SSHInterface string `mapstructure:"ssh_interface"` 59 } 60 61 func (c *RunConfig) Prepare(ctx *interpolate.Context) []error { 62 // If we are not given an explicit ssh_keypair_name or 63 // ssh_private_key_file, then create a temporary one, but only if the 64 // temporary_key_pair_name has not been provided and we are not using 65 // ssh_password. 66 if c.SSHKeyPairName == "" && c.TemporaryKeyPairName == "" && 67 c.Comm.SSHPrivateKey == "" && c.Comm.SSHPassword == "" { 68 69 c.TemporaryKeyPairName = fmt.Sprintf("packer_%s", uuid.TimeOrderedUUID()) 70 } 71 72 if c.WindowsPasswordTimeout == 0 { 73 c.WindowsPasswordTimeout = 20 * time.Minute 74 } 75 76 if c.RunTags == nil { 77 c.RunTags = make(map[string]string) 78 } 79 80 // Validation 81 errs := c.Comm.Prepare(ctx) 82 83 // Validating ssh_interface 84 if c.SSHInterface != "public_ip" && 85 c.SSHInterface != "private_ip" && 86 c.SSHInterface != "public_dns" && 87 c.SSHInterface != "private_dns" && 88 c.SSHInterface != "" { 89 errs = append(errs, fmt.Errorf("Unknown interface type: %s", c.SSHInterface)) 90 } 91 92 if c.SSHKeyPairName != "" { 93 if c.Comm.Type == "winrm" && c.Comm.WinRMPassword == "" && c.Comm.SSHPrivateKey == "" { 94 errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided to retrieve the winrm password when using ssh_keypair_name.")) 95 } else if c.Comm.SSHPrivateKey == "" && !c.Comm.SSHAgentAuth { 96 errs = append(errs, fmt.Errorf("ssh_private_key_file must be provided or ssh_agent_auth enabled when ssh_keypair_name is specified.")) 97 } 98 } 99 100 if c.SourceAmi == "" && c.SourceAmiFilter.Empty() { 101 errs = append(errs, fmt.Errorf("A source_ami or source_ami_filter must be specified")) 102 } 103 104 if c.InstanceType == "" { 105 errs = append(errs, fmt.Errorf("An instance_type must be specified")) 106 } 107 108 if c.SpotPrice == "auto" { 109 if c.SpotPriceAutoProduct == "" { 110 errs = append(errs, fmt.Errorf( 111 "spot_price_auto_product must be specified when spot_price is auto")) 112 } 113 } 114 115 if c.SpotPriceAutoProduct != "" { 116 if c.SpotPrice != "auto" { 117 errs = append(errs, fmt.Errorf( 118 "spot_price should be set to auto when spot_price_auto_product is specified")) 119 } 120 } 121 122 if c.SpotTags != nil { 123 if c.SpotPrice == "" || c.SpotPrice == "0" { 124 errs = append(errs, fmt.Errorf( 125 "spot_tags should not be set when not requesting a spot instance")) 126 } 127 } 128 129 if c.UserData != "" && c.UserDataFile != "" { 130 errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) 131 } else if c.UserDataFile != "" { 132 if _, err := os.Stat(c.UserDataFile); err != nil { 133 errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) 134 } 135 } 136 137 if c.SecurityGroupId != "" { 138 if len(c.SecurityGroupIds) > 0 { 139 errs = append(errs, fmt.Errorf("Only one of security_group_id or security_group_ids can be specified.")) 140 } else { 141 c.SecurityGroupIds = []string{c.SecurityGroupId} 142 c.SecurityGroupId = "" 143 } 144 } 145 146 if c.TemporarySGSourceCidr == "" { 147 c.TemporarySGSourceCidr = "0.0.0.0/0" 148 } else { 149 if _, _, err := net.ParseCIDR(c.TemporarySGSourceCidr); err != nil { 150 errs = append(errs, fmt.Errorf("Error parsing temporary_security_group_source_cidr: %s", err.Error())) 151 } 152 } 153 154 if c.InstanceInitiatedShutdownBehavior == "" { 155 c.InstanceInitiatedShutdownBehavior = "stop" 156 } else if !reShutdownBehavior.MatchString(c.InstanceInitiatedShutdownBehavior) { 157 errs = append(errs, fmt.Errorf("shutdown_behavior only accepts 'stop' or 'terminate' values.")) 158 } 159 160 if c.EnableT2Unlimited { 161 if c.SpotPrice != "" { 162 errs = append(errs, fmt.Errorf("Error: T2 Unlimited cannot be used in conjuction with Spot Instances")) 163 } 164 firstDotIndex := strings.Index(c.InstanceType, ".") 165 if firstDotIndex == -1 { 166 errs = append(errs, fmt.Errorf("Error determining main Instance Type from: %s", c.InstanceType)) 167 } else if c.InstanceType[0:firstDotIndex] != "t2" { 168 errs = append(errs, fmt.Errorf("Error: T2 Unlimited enabled with a non-T2 Instance Type: %s", c.InstanceType)) 169 } 170 } 171 172 return errs 173 } 174 175 func (c *RunConfig) IsSpotInstance() bool { 176 return c.SpotPrice != "" && c.SpotPrice != "0" 177 }