@ -5,6 +5,7 @@ import (
"crypto/sha1"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"log"
"strings"
@ -32,67 +33,67 @@ func resourceAwsInstance() *schema.Resource {
MigrateState : resourceAwsInstanceMigrateState ,
Schema : map [ string ] * schema . Schema {
"ami" : & schema . Schema {
"ami" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"associate_public_ip_address" : & schema . Schema {
"associate_public_ip_address" : {
Type : schema . TypeBool ,
ForceNew : true ,
Computed : true ,
Optional : true ,
} ,
"availability_zone" : & schema . Schema {
"availability_zone" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"placement_group" : & schema . Schema {
"placement_group" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"instance_type" : & schema . Schema {
"instance_type" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"key_name" : & schema . Schema {
"key_name" : {
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
Computed : true ,
} ,
"subnet_id" : & schema . Schema {
"subnet_id" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"private_ip" : & schema . Schema {
"private_ip" : {
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
Computed : true ,
} ,
"source_dest_check" : & schema . Schema {
"source_dest_check" : {
Type : schema . TypeBool ,
Optional : true ,
Default : true ,
} ,
"user_data" : & schema . Schema {
"user_data" : {
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
@ -106,7 +107,7 @@ func resourceAwsInstance() *schema.Resource {
} ,
} ,
"security_groups" : & schema . Schema {
"security_groups" : {
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
@ -115,7 +116,7 @@ func resourceAwsInstance() *schema.Resource {
Set : schema . HashString ,
} ,
"vpc_security_group_ids" : & schema . Schema {
"vpc_security_group_ids" : {
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
@ -123,59 +124,59 @@ func resourceAwsInstance() *schema.Resource {
Set : schema . HashString ,
} ,
"public_dns" : & schema . Schema {
"public_dns" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"network_interface_id" : & schema . Schema {
"network_interface_id" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"public_ip" : & schema . Schema {
"public_ip" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"instance_state" : & schema . Schema {
"instance_state" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"private_dns" : & schema . Schema {
"private_dns" : {
Type : schema . TypeString ,
Computed : true ,
} ,
"ebs_optimized" : & schema . Schema {
"ebs_optimized" : {
Type : schema . TypeBool ,
Optional : true ,
ForceNew : true ,
} ,
"disable_api_termination" : & schema . Schema {
"disable_api_termination" : {
Type : schema . TypeBool ,
Optional : true ,
} ,
"instance_initiated_shutdown_behavior" : & schema . Schema {
"instance_initiated_shutdown_behavior" : {
Type : schema . TypeString ,
Optional : true ,
} ,
"monitoring" : & schema . Schema {
"monitoring" : {
Type : schema . TypeBool ,
Optional : true ,
} ,
"iam_instance_profile" : & schema . Schema {
"iam_instance_profile" : {
Type : schema . TypeString ,
ForceNew : true ,
Optional : true ,
} ,
"tenancy" : & schema . Schema {
"tenancy" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
@ -184,60 +185,60 @@ func resourceAwsInstance() *schema.Resource {
"tags" : tagsSchema ( ) ,
"block_device" : & schema . Schema {
"block_device" : {
Type : schema . TypeMap ,
Optional : true ,
Removed : "Split out into three sub-types; see Changelog and Docs" ,
} ,
"ebs_block_device" : & schema . Schema {
"ebs_block_device" : {
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"delete_on_termination" : & schema . Schema {
"delete_on_termination" : {
Type : schema . TypeBool ,
Optional : true ,
Default : true ,
ForceNew : true ,
} ,
"device_name" : & schema . Schema {
"device_name" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"encrypted" : & schema . Schema {
"encrypted" : {
Type : schema . TypeBool ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"iops" : & schema . Schema {
"iops" : {
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"snapshot_id" : & schema . Schema {
"snapshot_id" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"volume_size" : & schema . Schema {
"volume_size" : {
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"volume_type" : & schema . Schema {
"volume_type" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
@ -254,24 +255,24 @@ func resourceAwsInstance() *schema.Resource {
} ,
} ,
"ephemeral_block_device" : & schema . Schema {
"ephemeral_block_device" : {
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
ForceNew : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"device_name" : & schema . Schema {
"device_name" : {
Type : schema . TypeString ,
Required : true ,
} ,
"virtual_name" : & schema . Schema {
"virtual_name" : {
Type : schema . TypeString ,
Optional : true ,
} ,
"no_device" : & schema . Schema {
"no_device" : {
Type : schema . TypeBool ,
Optional : true ,
} ,
@ -289,41 +290,38 @@ func resourceAwsInstance() *schema.Resource {
} ,
} ,
"root_block_device" : & schema . Schema {
// TODO: This is a set because we don't support singleton
// sub-resources today. We'll enforce that the set only ever has
// length zero or one below. When TF gains support for
// sub-resources this can be converted.
Type : schema . TypeSet ,
"root_block_device" : {
Type : schema . TypeList ,
Optional : true ,
Computed : true ,
MaxItems : 1 ,
Elem : & schema . Resource {
// "You can only modify the volume size, volume type, and Delete on
// Termination flag on the block device mapping entry for the root
// device volume." - bit.ly/ec2bdmap
Schema : map [ string ] * schema . Schema {
"delete_on_termination" : & schema . Schema {
"delete_on_termination" : {
Type : schema . TypeBool ,
Optional : true ,
Default : true ,
ForceNew : true ,
} ,
"iops" : & schema . Schema {
"iops" : {
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"volume_size" : & schema . Schema {
"volume_size" : {
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
"volume_type" : & schema . Schema {
"volume_type" : {
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
@ -331,10 +329,6 @@ func resourceAwsInstance() *schema.Resource {
} ,
} ,
} ,
Set : func ( v interface { } ) int {
// there can be only one root device; no need to hash anything
return 0
} ,
} ,
} ,
}
@ -380,12 +374,12 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
// IAM instance profiles can take ~10 seconds to propagate in AWS:
// http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html#launch-instance-with-role-console
if isAWSErr ( err , "InvalidParameterValue" , "Invalid IAM Instance Profile" ) {
log . Print f ( "[DEBUG] Invalid IAM Instance Profile referenced, retrying..." )
log . Print ( "[DEBUG] Invalid IAM Instance Profile referenced, retrying..." )
return resource . RetryableError ( err )
}
// IAM roles can also take time to propagate in AWS:
if isAWSErr ( err , "InvalidParameterValue" , " has no associated IAM Roles" ) {
log . Print f ( "[DEBUG] IAM Instance Profile appears to have no IAM roles, retrying..." )
log . Print ( "[DEBUG] IAM Instance Profile appears to have no IAM roles, retrying..." )
return resource . RetryableError ( err )
}
return resource . NonRetryableError ( err )
@ -400,7 +394,7 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
return fmt . Errorf ( "Error launching source instance: %s" , err )
}
if runResp == nil || len ( runResp . Instances ) == 0 {
return fmt. Errorf ( "Error launching source instance: no instances returned in response" )
return errors. New ( "Error launching source instance: no instances returned in response" )
}
instance := runResp . Instances [ 0 ]
@ -804,7 +798,7 @@ func blockDeviceIsRoot(bd *ec2.InstanceBlockDeviceMapping, instance *ec2.Instanc
func fetchRootDeviceName ( ami string , conn * ec2 . EC2 ) ( * string , error ) {
if ami == "" {
return nil , fmt. Errorf ( "Cannot fetch root device name for blank AMI ID." )
return nil , errors. New ( "Cannot fetch root device name for blank AMI ID." )
}
log . Printf ( "[DEBUG] Describing AMI %q to get root block device name" , ami )
@ -911,7 +905,7 @@ func readBlockDeviceMappingsFromConfig(
}
if bdm . NoDevice == nil && aws . StringValue ( bdm . VirtualName ) == "" {
return nil , fmt. Errorf ( "virtual_name cannot be empty when no_device is false or undefined." )
return nil , errors. New ( "virtual_name cannot be empty when no_device is false or undefined." )
}
blockDevices = append ( blockDevices , bdm )
@ -919,9 +913,9 @@ func readBlockDeviceMappingsFromConfig(
}
if v , ok := d . GetOk ( "root_block_device" ) ; ok {
vL := v . ( * schema . Set ) . List ( )
vL := v . ( [ ] interface { } )
if len ( vL ) > 1 {
return nil , fmt. Errorf ( "Cannot specify more than one root_block_device." )
return nil , errors. New ( "Cannot specify more than one root_block_device." )
}
for _ , v := range vL {
bd := v . ( map [ string ] interface { } )
@ -946,7 +940,7 @@ func readBlockDeviceMappingsFromConfig(
ebs . Iops = aws . Int64 ( int64 ( v ) )
} else if v , ok := bd [ "iops" ] . ( int ) ; ok && v > 0 && * ebs . VolumeType != "io1" {
// Message user about incompatibility
log . Print f ( "[WARN] IOPs is only valid for storate type io1 for EBS Volumes" )
log . Print ( "[WARN] IOPs is only valid for storate type io1 for EBS Volumes" )
}
if dn , err := fetchRootDeviceName ( d . Get ( "ami" ) . ( string ) , conn ) ; err == nil {
@ -1096,7 +1090,7 @@ func buildAwsInstanceOpts(
// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html
sgs := v . ( * schema . Set ) . List ( )
if len ( sgs ) > 0 && hasSubnet {
log . Print f ( "[WARN] Deprecated. Attempting to use 'security_groups' within a VPC instance. Use 'vpc_security_group_ids' instead." )
log . Print ( "[WARN] Deprecated. Attempting to use 'security_groups' within a VPC instance. Use 'vpc_security_group_ids' instead." )
}
for _ , v := range sgs {
str := v . ( string )