2014-06-27 18:47:19 +02:00
package aws
import (
2014-10-17 18:12:45 +02:00
"bytes"
2014-08-22 17:46:48 +02:00
"crypto/sha1"
2015-03-13 16:54:00 +01:00
"encoding/base64"
2014-08-22 17:46:48 +02:00
"encoding/hex"
2017-02-01 22:25:07 +01:00
"errors"
2014-06-27 18:47:19 +02:00
"fmt"
"log"
2014-07-28 18:47:40 +02:00
"strings"
2014-07-01 19:10:11 +02:00
"time"
2014-06-27 18:47:19 +02:00
2015-06-03 20:36:57 +02:00
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
2014-08-22 03:38:43 +02:00
"github.com/hashicorp/terraform/helper/hashcode"
2014-07-01 19:10:11 +02:00
"github.com/hashicorp/terraform/helper/resource"
2014-08-22 03:38:43 +02:00
"github.com/hashicorp/terraform/helper/schema"
2014-06-27 18:47:19 +02:00
)
2014-08-22 03:38:43 +02:00
func resourceAwsInstance ( ) * schema . Resource {
return & schema . Resource {
Create : resourceAwsInstanceCreate ,
Read : resourceAwsInstanceRead ,
Update : resourceAwsInstanceUpdate ,
Delete : resourceAwsInstanceDelete ,
2016-05-13 20:27:23 +02:00
Importer : & schema . ResourceImporter {
State : schema . ImportStatePassthrough ,
} ,
2014-08-22 03:38:43 +02:00
2015-02-24 18:00:22 +01:00
SchemaVersion : 1 ,
MigrateState : resourceAwsInstanceMigrateState ,
2017-05-22 09:27:06 +02:00
Timeouts : & schema . ResourceTimeout {
Create : schema . DefaultTimeout ( 10 * time . Minute ) ,
Update : schema . DefaultTimeout ( 10 * time . Minute ) ,
Delete : schema . DefaultTimeout ( 10 * time . Minute ) ,
} ,
2014-08-22 03:38:43 +02:00
Schema : map [ string ] * schema . Schema {
2017-02-01 22:25:07 +01:00
"ami" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"associate_public_ip_address" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeBool ,
ForceNew : true ,
2016-10-24 18:24:54 +02:00
Computed : true ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
Optional : true ,
2014-08-22 03:38:43 +02:00
} ,
2017-02-01 22:25:07 +01:00
"availability_zone" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"placement_group" : {
2015-04-02 08:33:16 +02:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"instance_type" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Required : true ,
} ,
2017-02-01 22:25:07 +01:00
"key_name" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
2014-08-22 21:20:06 +02:00
Optional : true ,
2014-08-22 03:38:43 +02:00
ForceNew : true ,
2014-08-22 21:20:06 +02:00
Computed : true ,
2014-08-22 03:38:43 +02:00
} ,
2017-02-01 22:25:07 +01:00
"subnet_id" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"private_ip" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Optional : true ,
2014-09-18 22:26:49 +02:00
ForceNew : true ,
2014-08-22 03:38:43 +02:00
Computed : true ,
} ,
2017-02-01 22:25:07 +01:00
"source_dest_check" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeBool ,
Optional : true ,
2015-06-03 22:54:01 +02:00
Default : true ,
2017-04-28 22:35:54 +02:00
DiffSuppressFunc : func ( k , old , new string , d * schema . ResourceData ) bool {
// Suppress diff if network_interface is set
_ , ok := d . GetOk ( "network_interface" )
return ok
} ,
2014-08-22 03:38:43 +02:00
} ,
2017-02-01 22:25:07 +01:00
"user_data" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Optional : true ,
ForceNew : true ,
2014-08-22 17:46:48 +02:00
StateFunc : func ( v interface { } ) string {
2014-08-23 03:11:06 +02:00
switch v . ( type ) {
case string :
2016-05-17 16:15:15 +02:00
return userDataHashSum ( v . ( string ) )
2014-08-23 03:11:06 +02:00
default :
return ""
}
2014-08-22 17:46:48 +02:00
} ,
2014-08-22 03:38:43 +02:00
} ,
2017-02-01 22:25:07 +01:00
"security_groups" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeSet ,
Optional : true ,
2014-08-28 00:26:15 +02:00
Computed : true ,
2016-03-10 21:51:30 +01:00
ForceNew : true ,
2014-08-22 03:38:43 +02:00
Elem : & schema . Schema { Type : schema . TypeString } ,
2015-04-09 15:38:16 +02:00
Set : schema . HashString ,
2014-08-22 03:38:43 +02:00
} ,
2017-02-01 22:25:07 +01:00
"vpc_security_group_ids" : {
2015-03-07 07:04:53 +01:00
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
Elem : & schema . Schema { Type : schema . TypeString } ,
2016-02-08 00:51:26 +01:00
Set : schema . HashString ,
2015-03-07 07:04:53 +01:00
} ,
2017-02-01 22:25:07 +01:00
"public_dns" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Computed : true ,
} ,
2017-04-25 00:06:28 +02:00
// TODO: Deprecate me v0.10.0
2017-02-01 22:25:07 +01:00
"network_interface_id" : {
2017-04-25 00:06:28 +02:00
Type : schema . TypeString ,
Computed : true ,
Deprecated : "Please use `primary_network_interface_id` instead" ,
} ,
"primary_network_interface_id" : {
2016-07-25 20:52:40 +02:00
Type : schema . TypeString ,
Computed : true ,
} ,
2017-04-25 00:06:28 +02:00
"network_interface" : {
ConflictsWith : [ ] string { "associate_public_ip_address" , "subnet_id" , "private_ip" , "vpc_security_group_ids" , "security_groups" , "ipv6_addresses" , "ipv6_address_count" , "source_dest_check" } ,
Type : schema . TypeSet ,
2017-04-19 23:30:58 +02:00
Optional : true ,
Computed : true ,
2017-04-25 00:06:28 +02:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
"delete_on_termination" : {
Type : schema . TypeBool ,
Default : false ,
Optional : true ,
ForceNew : true ,
} ,
"network_interface_id" : {
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
"device_index" : {
Type : schema . TypeInt ,
Required : true ,
ForceNew : true ,
} ,
} ,
} ,
2017-04-19 23:30:58 +02:00
} ,
2017-02-01 22:25:07 +01:00
"public_ip" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Computed : true ,
} ,
2017-02-01 22:25:07 +01:00
"instance_state" : {
2015-09-17 12:26:38 +02:00
Type : schema . TypeString ,
Computed : true ,
} ,
2017-02-01 22:25:07 +01:00
"private_dns" : {
2014-08-22 03:38:43 +02:00
Type : schema . TypeString ,
Computed : true ,
} ,
2014-09-03 12:18:40 +02:00
2017-02-01 22:25:07 +01:00
"ebs_optimized" : {
2014-09-03 12:18:40 +02:00
Type : schema . TypeBool ,
Optional : true ,
2016-01-11 08:16:49 +01:00
ForceNew : true ,
2014-09-03 12:18:40 +02:00
} ,
2014-10-09 01:43:13 +02:00
2017-02-01 22:25:07 +01:00
"disable_api_termination" : {
2015-05-15 21:18:05 +02:00
Type : schema . TypeBool ,
Optional : true ,
} ,
2017-02-01 22:25:07 +01:00
"instance_initiated_shutdown_behavior" : {
2015-07-18 18:45:34 +02:00
Type : schema . TypeString ,
Optional : true ,
} ,
2015-07-29 22:54:56 +02:00
2017-02-01 22:25:07 +01:00
"monitoring" : {
2015-06-25 16:58:28 +02:00
Type : schema . TypeBool ,
Optional : true ,
} ,
2017-02-01 22:25:07 +01:00
"iam_instance_profile" : {
2014-09-28 20:51:49 +02:00
Type : schema . TypeString ,
2014-09-23 20:06:30 +02:00
Optional : true ,
} ,
2015-02-24 18:00:22 +01:00
2017-03-01 17:16:59 +01:00
"ipv6_address_count" : {
Type : schema . TypeInt ,
Optional : true ,
ForceNew : true ,
2017-05-10 16:20:48 +02:00
Computed : true ,
2017-03-01 17:16:59 +01:00
} ,
"ipv6_addresses" : {
Type : schema . TypeList ,
Optional : true ,
Computed : true ,
ForceNew : true ,
Elem : & schema . Schema {
Type : schema . TypeString ,
} ,
} ,
2017-02-01 22:25:07 +01:00
"tenancy" : {
2014-11-04 12:08:30 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2015-02-24 18:00:22 +01:00
2014-10-13 22:55:59 +02:00
"tags" : tagsSchema ( ) ,
2014-10-17 18:12:45 +02:00
2017-04-26 21:50:06 +02:00
"volume_tags" : tagsSchemaComputed ( ) ,
2017-04-26 00:12:38 +02:00
2017-02-01 22:25:07 +01:00
"block_device" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeMap ,
Optional : true ,
Removed : "Split out into three sub-types; see Changelog and Docs" ,
} ,
2017-02-01 22:25:07 +01:00
"ebs_block_device" : {
2014-10-17 18:12:45 +02:00
Type : schema . TypeSet ,
Optional : true ,
2014-12-25 21:58:26 +01:00
Computed : true ,
2014-10-17 18:12:45 +02:00
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2017-02-01 22:25:07 +01:00
"delete_on_termination" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeBool ,
Optional : true ,
Default : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"device_name" : {
2014-10-17 18:12:45 +02:00
Type : schema . TypeString ,
Required : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"encrypted" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeBool ,
2014-11-22 10:50:22 +01:00
Optional : true ,
2015-02-24 18:00:22 +01:00
Computed : true ,
2014-11-22 10:50:22 +01:00
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"iops" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeInt ,
2014-10-17 18:12:45 +02:00
Optional : true ,
2014-12-25 18:21:05 +01:00
Computed : true ,
2014-10-17 18:12:45 +02:00
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"snapshot_id" : {
2014-10-17 18:12:45 +02:00
Type : schema . TypeString ,
Optional : true ,
2014-12-25 18:21:05 +01:00
Computed : true ,
2014-10-17 18:12:45 +02:00
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"volume_size" : {
2014-10-17 18:12:45 +02:00
Type : schema . TypeInt ,
Optional : true ,
2014-12-25 18:21:05 +01:00
Computed : true ,
2014-10-17 18:12:45 +02:00
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"volume_type" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeString ,
2014-10-17 18:12:45 +02:00
Optional : true ,
2015-02-24 18:00:22 +01:00
Computed : true ,
2014-10-17 18:12:45 +02:00
ForceNew : true ,
} ,
2015-02-24 18:00:22 +01:00
} ,
} ,
Set : func ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
buf . WriteString ( fmt . Sprintf ( "%s-" , m [ "device_name" ] . ( string ) ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , m [ "snapshot_id" ] . ( string ) ) )
return hashcode . String ( buf . String ( ) )
} ,
} ,
2014-10-17 18:12:45 +02:00
2017-02-01 22:25:07 +01:00
"ephemeral_block_device" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeSet ,
Optional : true ,
Computed : true ,
ForceNew : true ,
Elem : & schema . Resource {
Schema : map [ string ] * schema . Schema {
2017-02-01 22:25:07 +01:00
"device_name" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeString ,
Required : true ,
2014-10-17 18:12:45 +02:00
} ,
2015-03-03 07:07:36 +01:00
2017-02-01 22:25:07 +01:00
"virtual_name" : {
2015-02-24 18:00:22 +01:00
Type : schema . TypeString ,
2016-12-08 11:03:51 +01:00
Optional : true ,
} ,
2017-02-01 22:25:07 +01:00
"no_device" : {
2016-12-08 11:03:51 +01:00
Type : schema . TypeBool ,
Optional : true ,
2015-03-03 07:07:36 +01:00
} ,
2014-10-17 18:12:45 +02:00
} ,
} ,
2015-02-24 18:00:22 +01:00
Set : func ( v interface { } ) int {
var buf bytes . Buffer
m := v . ( map [ string ] interface { } )
buf . WriteString ( fmt . Sprintf ( "%s-" , m [ "device_name" ] . ( string ) ) )
buf . WriteString ( fmt . Sprintf ( "%s-" , m [ "virtual_name" ] . ( string ) ) )
2016-12-08 11:03:51 +01:00
if v , ok := m [ "no_device" ] . ( bool ) ; ok && v {
buf . WriteString ( fmt . Sprintf ( "%t-" , v ) )
}
2015-02-24 18:00:22 +01:00
return hashcode . String ( buf . String ( ) )
} ,
2014-10-17 18:12:45 +02:00
} ,
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
2017-02-01 22:25:07 +01:00
"root_block_device" : {
Type : schema . TypeList ,
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
Optional : true ,
Computed : true ,
2017-02-01 22:25:07 +01:00
MaxItems : 1 ,
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
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 {
2017-02-01 22:25:07 +01:00
"delete_on_termination" : {
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
Type : schema . TypeBool ,
Optional : true ,
Default : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"iops" : {
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"volume_size" : {
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
Type : schema . TypeInt ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
2017-02-01 22:25:07 +01:00
"volume_type" : {
providers/aws: add root_block_device to aws_instance
AWS provides a single `BlockDeviceMapping` to manage three different
kinds of block devices:
(a) The root volume
(b) Ephemeral storage
(c) Additional EBS volumes
Each of these types has slightly different semantics [1].
(a) The root volume is defined by the AMI; it can only be customized
with `volume_size`, `volume_type`, and `delete_on_termination`.
(b) Ephemeral storage is made available based on instance type [2]. It's
attached automatically if _no_ block device mappings are specified, and
must otherwise be defined with block device mapping entries that contain
only DeviceName set to a device like "/dev/sdX" and VirtualName set to
"ephemeralN".
(c) Additional EBS volumes are controlled by mappings that omit
`virtual_name` and can specify `volume_size`, `volume_type`,
`delete_on_termination`, `snapshot_id`, and `encryption`.
After deciding to ignore root block devices to fix #859, we had users
with configurations that were attempting to manage the root block device chime
in on #913.
Terraform does not have the primitives to be able to properly handle a
single collection of resources that is partially managed and partially
computed, so our strategy here is to break out logical sub-resources for
Terraform and hide the BlockDeviceMapping inside the provider
implementation.
Now (a) is supported by the `root_block_device` sub-resource, and (b)
and (c) are still both merged together under `block_device`, though I
have yet to see ephemeral block devices working properly.
Looking into possibly separating out `ephemeral_block_device` and
`ebs_block_device` sub-resources as well, which seem like the logical
next step. We'll wait until the next big release for this, though, since
it will break backcompat.
[1] http://bit.ly/ec2bdmap
[2] http://bit.ly/instancestorebytype
Fixes #913
Refs #858
2015-02-18 18:45:30 +01:00
Type : schema . TypeString ,
Optional : true ,
Computed : true ,
ForceNew : true ,
} ,
} ,
} ,
} ,
2014-08-22 03:38:43 +02:00
} ,
}
}
func resourceAwsInstanceCreate ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-06-27 18:47:19 +02:00
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
instanceOpts , err := buildAwsInstanceOpts ( d , meta )
if err != nil {
return err
2014-07-29 14:06:53 +02:00
}
2014-07-15 06:56:37 +02:00
// Build the creation struct
2015-04-16 19:01:10 +02:00
runOpts := & ec2 . RunInstancesInput {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
BlockDeviceMappings : instanceOpts . BlockDeviceMappings ,
2015-08-17 20:27:16 +02:00
DisableApiTermination : instanceOpts . DisableAPITermination ,
EbsOptimized : instanceOpts . EBSOptimized ,
2015-06-25 16:58:28 +02:00
Monitoring : instanceOpts . Monitoring ,
2015-08-17 20:27:16 +02:00
IamInstanceProfile : instanceOpts . IAMInstanceProfile ,
ImageId : instanceOpts . ImageID ,
2015-07-18 18:45:34 +02:00
InstanceInitiatedShutdownBehavior : instanceOpts . InstanceInitiatedShutdownBehavior ,
2015-08-18 21:40:01 +02:00
InstanceType : instanceOpts . InstanceType ,
KeyName : instanceOpts . KeyName ,
MaxCount : aws . Int64 ( int64 ( 1 ) ) ,
MinCount : aws . Int64 ( int64 ( 1 ) ) ,
NetworkInterfaces : instanceOpts . NetworkInterfaces ,
Placement : instanceOpts . Placement ,
PrivateIpAddress : instanceOpts . PrivateIPAddress ,
SecurityGroupIds : instanceOpts . SecurityGroupIDs ,
SecurityGroups : instanceOpts . SecurityGroups ,
SubnetId : instanceOpts . SubnetID ,
UserData : instanceOpts . UserData64 ,
2015-02-24 18:00:22 +01:00
}
2017-05-10 16:20:48 +02:00
ipv6Count , ipv6CountOk := d . GetOk ( "ipv6_address_count" )
ipv6Address , ipv6AddressOk := d . GetOk ( "ipv6_addresses" )
if ipv6AddressOk && ipv6CountOk {
return fmt . Errorf ( "Only 1 of `ipv6_address_count` or `ipv6_addresses` can be specified" )
}
if ipv6CountOk {
runOpts . Ipv6AddressCount = aws . Int64 ( int64 ( ipv6Count . ( int ) ) )
2017-03-01 17:16:59 +01:00
}
2017-05-10 16:20:48 +02:00
if ipv6AddressOk {
ipv6Addresses := make ( [ ] * ec2 . InstanceIpv6Address , len ( ipv6Address . ( [ ] interface { } ) ) )
for _ , address := range ipv6Address . ( [ ] interface { } ) {
2017-03-01 17:16:59 +01:00
ipv6Address := & ec2 . InstanceIpv6Address {
Ipv6Address : aws . String ( address . ( string ) ) ,
}
ipv6Addresses = append ( ipv6Addresses , ipv6Address )
}
runOpts . Ipv6Addresses = ipv6Addresses
}
2017-04-28 02:09:18 +02:00
restricted := meta . ( * AWSClient ) . IsGovCloud ( ) || meta . ( * AWSClient ) . IsChinaCloud ( )
if ! restricted {
tagsSpec := make ( [ ] * ec2 . TagSpecification , 0 )
2017-04-26 00:12:38 +02:00
2017-04-28 02:09:18 +02:00
if v , ok := d . GetOk ( "tags" ) ; ok {
tags := tagsFromMap ( v . ( map [ string ] interface { } ) )
2017-04-26 00:12:38 +02:00
2017-04-28 02:09:18 +02:00
spec := & ec2 . TagSpecification {
ResourceType : aws . String ( "instance" ) ,
Tags : tags ,
}
tagsSpec = append ( tagsSpec , spec )
2017-04-26 00:12:38 +02:00
}
2017-04-28 02:09:18 +02:00
if v , ok := d . GetOk ( "volume_tags" ) ; ok {
tags := tagsFromMap ( v . ( map [ string ] interface { } ) )
2017-04-26 00:12:38 +02:00
2017-04-28 02:09:18 +02:00
spec := & ec2 . TagSpecification {
ResourceType : aws . String ( "volume" ) ,
Tags : tags ,
}
2017-04-26 00:12:38 +02:00
2017-04-28 02:09:18 +02:00
tagsSpec = append ( tagsSpec , spec )
2017-04-26 00:12:38 +02:00
}
2017-04-28 02:09:18 +02:00
if len ( tagsSpec ) > 0 {
runOpts . TagSpecifications = tagsSpec
}
2017-04-26 00:12:38 +02:00
}
2014-07-15 06:56:37 +02:00
// Create the instance
2015-07-28 22:29:46 +02:00
log . Printf ( "[DEBUG] Run configuration: %s" , runOpts )
2015-05-21 21:58:34 +02:00
var runResp * ec2 . Reservation
2016-08-05 08:12:27 +02:00
err = resource . Retry ( 15 * time . Second , func ( ) * resource . RetryError {
2016-07-07 22:24:17 +02:00
var err error
2015-05-21 21:58:34 +02:00
runResp , err = conn . RunInstances ( runOpts )
2016-08-05 08:12:27 +02:00
// IAM instance profiles can take ~10 seconds to propagate in AWS:
2016-07-07 22:24:17 +02:00
// 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" ) {
2017-02-01 22:25:07 +01:00
log . Print ( "[DEBUG] Invalid IAM Instance Profile referenced, retrying..." )
2016-07-07 22:24:17 +02:00
return resource . RetryableError ( err )
2015-05-21 21:58:34 +02:00
}
2016-08-05 08:12:27 +02:00
// IAM roles can also take time to propagate in AWS:
if isAWSErr ( err , "InvalidParameterValue" , " has no associated IAM Roles" ) {
2017-02-01 22:25:07 +01:00
log . Print ( "[DEBUG] IAM Instance Profile appears to have no IAM roles, retrying..." )
2016-08-05 08:12:27 +02:00
return resource . RetryableError ( err )
}
2016-07-07 22:24:17 +02:00
return resource . NonRetryableError ( err )
} )
// Warn if the AWS Error involves group ids, to help identify situation
// where a user uses group ids in security_groups for the Default VPC.
// See https://github.com/hashicorp/terraform/issues/3798
if isAWSErr ( err , "InvalidParameterValue" , "groupId is invalid" ) {
return fmt . Errorf ( "Error launching instance, possible mismatch of Security Group IDs and Names. See AWS Instance docs here: %s.\n\n\tAWS Error: %s" , "https://terraform.io/docs/providers/aws/r/instance.html" , err . ( awserr . Error ) . Message ( ) )
2015-05-21 21:58:34 +02:00
}
2014-06-27 18:47:19 +02:00
if err != nil {
2014-08-22 03:38:43 +02:00
return fmt . Errorf ( "Error launching source instance: %s" , err )
2014-06-27 18:47:19 +02:00
}
2015-12-08 21:22:51 +01:00
if runResp == nil || len ( runResp . Instances ) == 0 {
2017-02-01 22:25:07 +01:00
return errors . New ( "Error launching source instance: no instances returned in response" )
2015-12-08 21:22:51 +01:00
}
2014-06-27 18:47:19 +02:00
2015-04-16 19:01:10 +02:00
instance := runResp . Instances [ 0 ]
2015-08-17 20:27:16 +02:00
log . Printf ( "[INFO] Instance ID: %s" , * instance . InstanceId )
2014-06-27 18:47:19 +02:00
// Store the resulting ID so we can look this up later
2015-08-17 20:27:16 +02:00
d . SetId ( * instance . InstanceId )
2014-06-27 18:47:19 +02:00
// Wait for the instance to become running so we can get some attributes
// that aren't available until later.
log . Printf (
"[DEBUG] Waiting for instance (%s) to become running" ,
2015-08-17 20:27:16 +02:00
* instance . InstanceId )
2014-07-01 19:10:11 +02:00
stateConf := & resource . StateChangeConf {
2014-07-28 18:10:28 +02:00
Pending : [ ] string { "pending" } ,
2016-01-21 02:20:41 +01:00
Target : [ ] string { "running" } ,
2017-05-16 07:04:56 +02:00
Refresh : InstanceStateRefreshFunc ( conn , * instance . InstanceId , "terminated" ) ,
2017-05-22 09:27:06 +02:00
Timeout : d . Timeout ( schema . TimeoutCreate ) ,
2014-07-28 18:10:28 +02:00
Delay : 10 * time . Second ,
MinTimeout : 3 * time . Second ,
2014-07-01 19:10:11 +02:00
}
instanceRaw , err := stateConf . WaitForState ( )
2014-06-27 18:47:19 +02:00
if err != nil {
2014-08-22 03:38:43 +02:00
return fmt . Errorf (
2014-06-27 18:47:19 +02:00
"Error waiting for instance (%s) to become ready: %s" ,
2015-08-17 20:27:16 +02:00
* instance . InstanceId , err )
2014-06-27 18:47:19 +02:00
}
2014-07-01 19:10:11 +02:00
2014-06-27 18:47:19 +02:00
instance = instanceRaw . ( * ec2 . Instance )
2014-07-15 02:24:10 +02:00
// Initialize the connection info
2015-08-17 20:27:16 +02:00
if instance . PublicIpAddress != nil {
2015-03-05 16:45:39 +01:00
d . SetConnInfo ( map [ string ] string {
"type" : "ssh" ,
2015-08-17 20:27:16 +02:00
"host" : * instance . PublicIpAddress ,
2015-03-05 16:45:39 +01:00
} )
2015-08-17 20:27:16 +02:00
} else if instance . PrivateIpAddress != nil {
2015-04-22 12:25:28 +02:00
d . SetConnInfo ( map [ string ] string {
"type" : "ssh" ,
2015-08-17 20:27:16 +02:00
"host" : * instance . PrivateIpAddress ,
2015-04-22 12:25:28 +02:00
} )
2015-03-05 16:45:39 +01:00
}
2014-07-15 02:24:10 +02:00
2014-07-14 23:16:59 +02:00
// Update if we need to
2014-08-22 03:38:43 +02:00
return resourceAwsInstanceUpdate ( d , meta )
2014-07-14 23:16:59 +02:00
}
2014-08-22 03:38:43 +02:00
func resourceAwsInstanceRead ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-06-27 18:47:19 +02:00
2015-04-16 19:01:10 +02:00
resp , err := conn . DescribeInstances ( & ec2 . DescribeInstancesInput {
2015-08-17 20:27:16 +02:00
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
2015-03-05 16:45:39 +01:00
} )
2014-06-27 18:47:19 +02:00
if err != nil {
// If the instance was not found, return nil so that we can show
// that the instance is gone.
2015-05-20 13:21:23 +02:00
if ec2err , ok := err . ( awserr . Error ) ; ok && ec2err . Code ( ) == "InvalidInstanceID.NotFound" {
2014-08-22 03:38:43 +02:00
d . SetId ( "" )
return nil
2014-06-27 18:47:19 +02:00
}
// Some other error, report it
2014-08-22 03:38:43 +02:00
return err
2014-06-27 18:47:19 +02:00
}
// If nothing was found, then return no state
if len ( resp . Reservations ) == 0 {
2014-08-22 03:38:43 +02:00
d . SetId ( "" )
return nil
2014-06-27 18:47:19 +02:00
}
2015-04-16 19:01:10 +02:00
instance := resp . Reservations [ 0 ] . Instances [ 0 ]
2014-06-27 18:47:19 +02:00
2015-09-17 12:26:38 +02:00
if instance . State != nil {
// If the instance is terminated, then it is gone
if * instance . State . Name == "terminated" {
d . SetId ( "" )
return nil
}
d . Set ( "instance_state" , instance . State . Name )
2014-06-27 18:47:19 +02:00
}
2015-03-19 16:07:46 +01:00
if instance . Placement != nil {
d . Set ( "availability_zone" , instance . Placement . AvailabilityZone )
}
if instance . Placement . Tenancy != nil {
d . Set ( "tenancy" , instance . Placement . Tenancy )
}
2015-08-17 20:27:16 +02:00
d . Set ( "ami" , instance . ImageId )
2015-06-16 20:23:50 +02:00
d . Set ( "instance_type" , instance . InstanceType )
2014-08-22 03:38:43 +02:00
d . Set ( "key_name" , instance . KeyName )
2015-08-17 20:27:16 +02:00
d . Set ( "public_dns" , instance . PublicDnsName )
d . Set ( "public_ip" , instance . PublicIpAddress )
d . Set ( "private_dns" , instance . PrivateDnsName )
d . Set ( "private_ip" , instance . PrivateIpAddress )
2015-09-05 02:20:58 +02:00
d . Set ( "iam_instance_profile" , iamInstanceProfileArnToName ( instance . IamInstanceProfile ) )
2015-09-03 21:43:41 +02:00
2017-04-25 00:06:28 +02:00
// Set configured Network Interface Device Index Slice
// We only want to read, and populate state for the configured network_interface attachments. Otherwise, other
// resources have the potential to attach network interfaces to the instance, and cause a perpetual create/destroy
// diff. We should only read on changes configured for this specific resource because of this.
var configuredDeviceIndexes [ ] int
if v , ok := d . GetOk ( "network_interface" ) ; ok {
vL := v . ( * schema . Set ) . List ( )
for _ , vi := range vL {
mVi := vi . ( map [ string ] interface { } )
configuredDeviceIndexes = append ( configuredDeviceIndexes , mVi [ "device_index" ] . ( int ) )
}
}
2017-03-02 22:00:24 +01:00
var ipv6Addresses [ ] string
2015-03-05 16:45:39 +01:00
if len ( instance . NetworkInterfaces ) > 0 {
2017-04-25 00:06:28 +02:00
var primaryNetworkInterface ec2 . InstanceNetworkInterface
var networkInterfaces [ ] map [ string ] interface { }
for _ , iNi := range instance . NetworkInterfaces {
ni := make ( map [ string ] interface { } )
if * iNi . Attachment . DeviceIndex == 0 {
primaryNetworkInterface = * iNi
}
// If the attached network device is inside our configuration, refresh state with values found.
// Otherwise, assume the network device was attached via an outside resource.
for _ , index := range configuredDeviceIndexes {
if index == int ( * iNi . Attachment . DeviceIndex ) {
ni [ "device_index" ] = * iNi . Attachment . DeviceIndex
ni [ "network_interface_id" ] = * iNi . NetworkInterfaceId
ni [ "delete_on_termination" ] = * iNi . Attachment . DeleteOnTermination
2017-03-01 17:16:59 +01:00
}
2016-05-30 00:01:58 +02:00
}
2017-04-25 00:06:28 +02:00
// Don't add empty network interfaces to schema
if len ( ni ) == 0 {
continue
}
networkInterfaces = append ( networkInterfaces , ni )
2016-05-30 00:01:58 +02:00
}
2017-04-25 00:06:28 +02:00
if err := d . Set ( "network_interface" , networkInterfaces ) ; err != nil {
return fmt . Errorf ( "Error setting network_interfaces: %v" , err )
2016-05-30 00:01:58 +02:00
}
2017-04-25 00:06:28 +02:00
// Set primary network interface details
d . Set ( "subnet_id" , primaryNetworkInterface . SubnetId )
d . Set ( "network_interface_id" , primaryNetworkInterface . NetworkInterfaceId ) // TODO: Deprecate me v0.10.0
d . Set ( "primary_network_interface_id" , primaryNetworkInterface . NetworkInterfaceId )
d . Set ( "associate_public_ip_address" , primaryNetworkInterface . Association != nil )
d . Set ( "ipv6_address_count" , len ( primaryNetworkInterface . Ipv6Addresses ) )
2017-04-28 22:35:54 +02:00
d . Set ( "source_dest_check" , * primaryNetworkInterface . SourceDestCheck )
2017-04-25 00:06:28 +02:00
for _ , address := range primaryNetworkInterface . Ipv6Addresses {
ipv6Addresses = append ( ipv6Addresses , * address . Ipv6Address )
}
2015-03-05 16:45:39 +01:00
} else {
2015-08-17 20:27:16 +02:00
d . Set ( "subnet_id" , instance . SubnetId )
2017-04-25 00:06:28 +02:00
d . Set ( "network_interface_id" , "" ) // TODO: Deprecate me v0.10.0
d . Set ( "primary_network_interface_id" , "" )
2015-03-05 16:45:39 +01:00
}
2017-03-02 22:00:24 +01:00
if err := d . Set ( "ipv6_addresses" , ipv6Addresses ) ; err != nil {
2017-03-07 23:03:45 +01:00
log . Printf ( "[WARN] Error setting ipv6_addresses for AWS Instance (%s): %s" , d . Id ( ) , err )
2017-03-02 22:00:24 +01:00
}
2015-08-17 20:27:16 +02:00
d . Set ( "ebs_optimized" , instance . EbsOptimized )
2015-09-02 20:04:45 +02:00
if instance . SubnetId != nil && * instance . SubnetId != "" {
d . Set ( "source_dest_check" , instance . SourceDestCheck )
}
2015-06-25 16:58:28 +02:00
if instance . Monitoring != nil && instance . Monitoring . State != nil {
2015-06-25 18:07:11 +02:00
monitoringState := * instance . Monitoring . State
d . Set ( "monitoring" , monitoringState == "enabled" || monitoringState == "pending" )
2015-06-25 16:58:28 +02:00
}
2015-05-12 21:58:10 +02:00
d . Set ( "tags" , tagsToMap ( instance . Tags ) )
2014-08-22 03:38:43 +02:00
2017-04-26 00:12:38 +02:00
if err := readVolumeTags ( conn , d ) ; err != nil {
return err
}
2017-01-18 18:19:44 +01:00
if err := readSecurityGroups ( d , instance ) ; err != nil {
return err
2014-07-15 06:56:37 +02:00
}
2015-02-18 23:45:13 +01:00
2015-04-16 19:01:10 +02:00
if err := readBlockDevices ( d , instance , conn ) ; err != nil {
2014-10-17 18:12:45 +02:00
return err
}
2016-04-22 18:37:27 +02:00
if _ , ok := d . GetOk ( "ephemeral_block_device" ) ; ! ok {
d . Set ( "ephemeral_block_device" , [ ] interface { } { } )
}
// Instance attributes
{
attr , err := conn . DescribeInstanceAttribute ( & ec2 . DescribeInstanceAttributeInput {
Attribute : aws . String ( "disableApiTermination" ) ,
InstanceId : aws . String ( d . Id ( ) ) ,
} )
if err != nil {
return err
}
d . Set ( "disable_api_termination" , attr . DisableApiTermination . Value )
}
2016-05-17 16:15:15 +02:00
{
attr , err := conn . DescribeInstanceAttribute ( & ec2 . DescribeInstanceAttributeInput {
Attribute : aws . String ( ec2 . InstanceAttributeNameUserData ) ,
InstanceId : aws . String ( d . Id ( ) ) ,
} )
if err != nil {
return err
}
if attr . UserData . Value != nil {
d . Set ( "user_data" , userDataHashSum ( * attr . UserData . Value ) )
}
}
2014-10-17 18:12:45 +02:00
2014-08-22 03:38:43 +02:00
return nil
2014-06-27 18:47:19 +02:00
}
2014-07-01 19:10:11 +02:00
2014-11-21 17:58:34 +01:00
func resourceAwsInstanceUpdate ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2015-04-16 19:01:10 +02:00
d . Partial ( true )
2017-04-26 00:12:38 +02:00
2017-04-28 02:09:18 +02:00
restricted := meta . ( * AWSClient ) . IsGovCloud ( ) || meta . ( * AWSClient ) . IsChinaCloud ( )
if d . HasChange ( "tags" ) {
provider/aws: Fall back to old tagging mechanism for AWS gov and aws China (#14627)
Fixes: #14535
When in a `restricted` cloud, we should fall back to the old method of
tagging. Before this change we saw the following:
```
% terraform apply ✭
aws_instance.foo: Creating...
ami: "" => "ami-0fa3c42c"
associate_public_ip_address: "" => "<computed>"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_state: "" => "<computed>"
instance_type: "" => "m1.small"
ipv6_address_count: "" => "<computed>"
ipv6_addresses.#: "" => "<computed>"
key_name: "" => "<computed>"
network_interface.#: "" => "<computed>"
network_interface_id: "" => "<computed>"
placement_group: "" => "<computed>"
primary_network_interface_id: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "<computed>"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "<computed>"
source_dest_check: "" => "true"
subnet_id: "" => "<computed>"
tags.%: "" => "1"
tags.foo: "" => "bar"
tenancy: "" => "<computed>"
volume_tags.%: "" => "<computed>"
vpc_security_group_ids.#: "" => "<computed>"
aws_instance.foo: Creation complete (ID: i-0009f227ae24791b9)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
% terraform plan ✭
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
aws_instance.foo: Refreshing state... (ID: i-0009f227ae24791b9)
The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.
Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.
~ aws_instance.foo
tags.%: "0" => "1"
tags.foo: "" => "bar"
Plan: 0 to add, 1 to change, 0 to destroy.
```
After this patch, we see the following:
```
% terraform apply ✹ ✭
[WARN] /Users/stacko/Code/go/bin/terraform-provider-aws overrides an internal plugin for aws-provider.
If you did not expect to see this message you will need to remove the old plugin.
See https://www.terraform.io/docs/internals/internal-plugins.html
aws_instance.foo: Creating...
ami: "" => "ami-0fa3c42c"
associate_public_ip_address: "" => "<computed>"
availability_zone: "" => "<computed>"
ebs_block_device.#: "" => "<computed>"
ephemeral_block_device.#: "" => "<computed>"
instance_state: "" => "<computed>"
instance_type: "" => "m1.small"
ipv6_address_count: "" => "<computed>"
ipv6_addresses.#: "" => "<computed>"
key_name: "" => "<computed>"
network_interface.#: "" => "<computed>"
network_interface_id: "" => "<computed>"
placement_group: "" => "<computed>"
primary_network_interface_id: "" => "<computed>"
private_dns: "" => "<computed>"
private_ip: "" => "<computed>"
public_dns: "" => "<computed>"
public_ip: "" => "<computed>"
root_block_device.#: "" => "<computed>"
security_groups.#: "" => "<computed>"
source_dest_check: "" => "true"
subnet_id: "" => "<computed>"
tags.%: "" => "1"
tags.foo: "" => "bar"
tenancy: "" => "<computed>"
volume_tags.%: "" => "<computed>"
vpc_security_group_ids.#: "" => "<computed>"
aws_instance.foo: Creation complete (ID: i-04cd122e28f167a14)
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
% terraform plan ✹ ✭
[WARN] /Users/stacko/Code/go/bin/terraform-provider-aws overrides an internal plugin for aws-provider.
If you did not expect to see this message you will need to remove the old plugin.
See https://www.terraform.io/docs/internals/internal-plugins.html
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
aws_instance.foo: Refreshing state... (ID: i-04cd122e28f167a14)
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, Terraform
doesn't need to do anything.
```
2017-05-18 16:28:37 +02:00
if ! d . IsNewResource ( ) || restricted {
2017-04-28 02:09:18 +02:00
if err := setTags ( conn , d ) ; err != nil {
return err
} else {
d . SetPartial ( "tags" )
}
2017-04-26 00:12:38 +02:00
}
}
2017-04-28 02:09:18 +02:00
if d . HasChange ( "volume_tags" ) {
if ! d . IsNewResource ( ) || ! restricted {
if err := setVolumeTags ( conn , d ) ; err != nil {
return err
} else {
d . SetPartial ( "volume_tags" )
}
2017-04-26 00:12:38 +02:00
}
2015-05-20 22:33:01 +02:00
}
2014-11-21 17:58:34 +01:00
2017-03-21 19:26:41 +01:00
if d . HasChange ( "iam_instance_profile" ) && ! d . IsNewResource ( ) {
2017-02-10 19:05:29 +01:00
request := & ec2 . DescribeIamInstanceProfileAssociationsInput {
Filters : [ ] * ec2 . Filter {
2017-04-26 00:12:38 +02:00
{
2017-02-10 19:05:29 +01:00
Name : aws . String ( "instance-id" ) ,
Values : [ ] * string { aws . String ( d . Id ( ) ) } ,
} ,
} ,
}
resp , err := conn . DescribeIamInstanceProfileAssociations ( request )
if err != nil {
return err
}
// An Iam Instance Profile has been provided and is pending a change
// This means it is an association or a replacement to an association
if _ , ok := d . GetOk ( "iam_instance_profile" ) ; ok {
// Does not have an Iam Instance Profile associated with it, need to associate
if len ( resp . IamInstanceProfileAssociations ) == 0 {
_ , err := conn . AssociateIamInstanceProfile ( & ec2 . AssociateIamInstanceProfileInput {
InstanceId : aws . String ( d . Id ( ) ) ,
IamInstanceProfile : & ec2 . IamInstanceProfileSpecification {
Name : aws . String ( d . Get ( "iam_instance_profile" ) . ( string ) ) ,
} ,
} )
if err != nil {
return err
}
} else {
// Has an Iam Instance Profile associated with it, need to replace the association
associationId := resp . IamInstanceProfileAssociations [ 0 ] . AssociationId
_ , err := conn . ReplaceIamInstanceProfileAssociation ( & ec2 . ReplaceIamInstanceProfileAssociationInput {
AssociationId : associationId ,
IamInstanceProfile : & ec2 . IamInstanceProfileSpecification {
Name : aws . String ( d . Get ( "iam_instance_profile" ) . ( string ) ) ,
} ,
} )
if err != nil {
return err
}
}
// An Iam Instance Profile has _not_ been provided but is pending a change. This means there is a pending removal
} else {
if len ( resp . IamInstanceProfileAssociations ) > 0 {
// Has an Iam Instance Profile associated with it, need to remove the association
associationId := resp . IamInstanceProfileAssociations [ 0 ] . AssociationId
_ , err := conn . DisassociateIamInstanceProfile ( & ec2 . DisassociateIamInstanceProfileInput {
AssociationId : associationId ,
} )
if err != nil {
return err
}
}
}
}
2017-04-25 00:06:28 +02:00
// SourceDestCheck can only be modified on an instance without manually specified network interfaces.
// SourceDestCheck, in that case, is configured at the network interface level
if _ , ok := d . GetOk ( "network_interface" ) ; ! ok {
if d . HasChange ( "source_dest_check" ) || d . IsNewResource ( ) {
// SourceDestCheck can only be set on VPC instances // AWS will return an error of InvalidParameterCombination if we attempt
// to modify the source_dest_check of an instance in EC2 Classic
log . Printf ( "[INFO] Modifying `source_dest_check` on Instance %s" , d . Id ( ) )
_ , err := conn . ModifyInstanceAttribute ( & ec2 . ModifyInstanceAttributeInput {
InstanceId : aws . String ( d . Id ( ) ) ,
SourceDestCheck : & ec2 . AttributeBooleanValue {
Value : aws . Bool ( d . Get ( "source_dest_check" ) . ( bool ) ) ,
} ,
} )
if err != nil {
if ec2err , ok := err . ( awserr . Error ) ; ok {
// Tolerate InvalidParameterCombination error in Classic, otherwise
// return the error
if "InvalidParameterCombination" != ec2err . Code ( ) {
return err
}
log . Printf ( "[WARN] Attempted to modify SourceDestCheck on non VPC instance: %s" , ec2err . Message ( ) )
2016-08-25 23:11:01 +02:00
}
2015-10-02 00:00:30 +02:00
}
2015-03-18 20:54:44 +01:00
}
2014-11-21 17:58:34 +01:00
}
2015-04-22 00:07:30 +02:00
if d . HasChange ( "vpc_security_group_ids" ) {
var groups [ ] * string
2015-06-11 14:59:42 +02:00
if v := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; v . Len ( ) > 0 {
for _ , v := range v . List ( ) {
2015-04-22 00:07:30 +02:00
groups = append ( groups , aws . String ( v . ( string ) ) )
}
}
2017-05-09 00:30:22 +02:00
// If a user has multiple network interface attachments on the target EC2 instance, simply modifying the
// instance attributes via a `ModifyInstanceAttributes()` request would fail with the following error message:
// "There are multiple interfaces attached to instance 'i-XX'. Please specify an interface ID for the operation instead."
// Thus, we need to actually modify the primary network interface for the new security groups, as the primary
// network interface is where we modify/create security group assignments during Create.
log . Printf ( "[INFO] Modifying `vpc_security_group_ids` on Instance %q" , d . Id ( ) )
instances , err := conn . DescribeInstances ( & ec2 . DescribeInstancesInput {
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
2015-04-22 00:07:30 +02:00
} )
if err != nil {
return err
}
2017-05-09 00:30:22 +02:00
instance := instances . Reservations [ 0 ] . Instances [ 0 ]
var primaryInterface ec2 . InstanceNetworkInterface
for _ , ni := range instance . NetworkInterfaces {
if * ni . Attachment . DeviceIndex == 0 {
primaryInterface = * ni
}
}
if primaryInterface . NetworkInterfaceId == nil {
log . Print ( "[Error] Attempted to set vpc_security_group_ids on an instance without a primary network interface" )
return fmt . Errorf (
"Failed to update vpc_security_group_ids on %q, which does not contain a primary network interface" ,
d . Id ( ) )
}
if _ , err := conn . ModifyNetworkInterfaceAttribute ( & ec2 . ModifyNetworkInterfaceAttributeInput {
NetworkInterfaceId : primaryInterface . NetworkInterfaceId ,
Groups : groups ,
} ) ; err != nil {
return err
}
2015-05-15 21:18:05 +02:00
}
2015-04-22 00:07:30 +02:00
2017-02-16 15:43:09 +01:00
if d . HasChange ( "instance_type" ) && ! d . IsNewResource ( ) {
log . Printf ( "[INFO] Stopping Instance %q for instance_type change" , d . Id ( ) )
_ , err := conn . StopInstances ( & ec2 . StopInstancesInput {
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
} )
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "pending" , "running" , "shutting-down" , "stopped" , "stopping" } ,
Target : [ ] string { "stopped" } ,
2017-05-16 07:04:56 +02:00
Refresh : InstanceStateRefreshFunc ( conn , d . Id ( ) , "" ) ,
2017-05-22 09:27:06 +02:00
Timeout : d . Timeout ( schema . TimeoutUpdate ) ,
2017-02-16 15:43:09 +01:00
Delay : 10 * time . Second ,
MinTimeout : 3 * time . Second ,
}
_ , err = stateConf . WaitForState ( )
if err != nil {
return fmt . Errorf (
"Error waiting for instance (%s) to stop: %s" , d . Id ( ) , err )
}
log . Printf ( "[INFO] Modifying instance type %s" , d . Id ( ) )
_ , err = conn . ModifyInstanceAttribute ( & ec2 . ModifyInstanceAttributeInput {
InstanceId : aws . String ( d . Id ( ) ) ,
InstanceType : & ec2 . AttributeValue {
Value : aws . String ( d . Get ( "instance_type" ) . ( string ) ) ,
} ,
} )
if err != nil {
return err
}
log . Printf ( "[INFO] Starting Instance %q after instance_type change" , d . Id ( ) )
_ , err = conn . StartInstances ( & ec2 . StartInstancesInput {
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
} )
stateConf = & resource . StateChangeConf {
Pending : [ ] string { "pending" , "stopped" } ,
Target : [ ] string { "running" } ,
2017-05-16 07:04:56 +02:00
Refresh : InstanceStateRefreshFunc ( conn , d . Id ( ) , "terminated" ) ,
2017-05-22 09:27:06 +02:00
Timeout : d . Timeout ( schema . TimeoutUpdate ) ,
2017-02-16 15:43:09 +01:00
Delay : 10 * time . Second ,
MinTimeout : 3 * time . Second ,
}
_ , err = stateConf . WaitForState ( )
if err != nil {
return fmt . Errorf (
"Error waiting for instance (%s) to become ready: %s" ,
d . Id ( ) , err )
}
}
2015-05-15 21:18:05 +02:00
if d . HasChange ( "disable_api_termination" ) {
_ , err := conn . ModifyInstanceAttribute ( & ec2 . ModifyInstanceAttributeInput {
2015-08-17 20:27:16 +02:00
InstanceId : aws . String ( d . Id ( ) ) ,
DisableApiTermination : & ec2 . AttributeBooleanValue {
2015-07-28 22:29:46 +02:00
Value : aws . Bool ( d . Get ( "disable_api_termination" ) . ( bool ) ) ,
2015-05-15 21:18:05 +02:00
} ,
} )
if err != nil {
return err
}
2015-04-22 00:07:30 +02:00
}
2015-07-18 18:45:34 +02:00
if d . HasChange ( "instance_initiated_shutdown_behavior" ) {
log . Printf ( "[INFO] Modifying instance %s" , d . Id ( ) )
_ , err := conn . ModifyInstanceAttribute ( & ec2 . ModifyInstanceAttributeInput {
2015-08-18 21:40:01 +02:00
InstanceId : aws . String ( d . Id ( ) ) ,
2015-07-18 18:45:34 +02:00
InstanceInitiatedShutdownBehavior : & ec2 . AttributeValue {
Value : aws . String ( d . Get ( "instance_initiated_shutdown_behavior" ) . ( string ) ) ,
} ,
} )
if err != nil {
return err
}
}
2015-07-29 22:54:56 +02:00
2015-07-20 19:32:58 +02:00
if d . HasChange ( "monitoring" ) {
var mErr error
if d . Get ( "monitoring" ) . ( bool ) {
log . Printf ( "[DEBUG] Enabling monitoring for Instance (%s)" , d . Id ( ) )
_ , mErr = conn . MonitorInstances ( & ec2 . MonitorInstancesInput {
2015-08-17 20:27:16 +02:00
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
2015-07-20 19:32:58 +02:00
} )
} else {
log . Printf ( "[DEBUG] Disabling monitoring for Instance (%s)" , d . Id ( ) )
_ , mErr = conn . UnmonitorInstances ( & ec2 . UnmonitorInstancesInput {
2015-08-17 20:27:16 +02:00
InstanceIds : [ ] * string { aws . String ( d . Id ( ) ) } ,
2015-07-20 19:32:58 +02:00
} )
}
if mErr != nil {
return fmt . Errorf ( "[WARN] Error updating Instance monitoring: %s" , mErr )
}
}
2015-02-21 21:26:46 +01:00
// TODO(mitchellh): wait for the attributes we modified to
// persist the change...
2015-04-16 19:01:10 +02:00
d . Partial ( false )
2014-11-21 17:58:34 +01:00
2015-04-16 19:01:10 +02:00
return resourceAwsInstanceRead ( d , meta )
2014-11-21 17:58:34 +01:00
}
func resourceAwsInstanceDelete ( d * schema . ResourceData , meta interface { } ) error {
2015-04-16 22:05:55 +02:00
conn := meta . ( * AWSClient ) . ec2conn
2014-11-21 17:58:34 +01:00
2017-05-22 09:27:06 +02:00
if err := awsTerminateInstance ( conn , d . Id ( ) , d ) ; err != nil {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
return err
2014-11-21 17:58:34 +01:00
}
d . SetId ( "" )
2014-08-22 03:38:43 +02:00
return nil
2014-06-27 18:47:19 +02:00
}
2014-07-01 19:10:11 +02:00
// InstanceStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch
// an EC2 instance.
2017-05-16 07:04:56 +02:00
func InstanceStateRefreshFunc ( conn * ec2 . EC2 , instanceID , failState string ) resource . StateRefreshFunc {
2014-07-01 19:10:11 +02:00
return func ( ) ( interface { } , string , error ) {
2015-04-16 19:01:10 +02:00
resp , err := conn . DescribeInstances ( & ec2 . DescribeInstancesInput {
2015-08-17 20:27:16 +02:00
InstanceIds : [ ] * string { aws . String ( instanceID ) } ,
2015-03-05 16:45:39 +01:00
} )
2014-07-01 19:10:11 +02:00
if err != nil {
2015-05-20 13:21:23 +02:00
if ec2err , ok := err . ( awserr . Error ) ; ok && ec2err . Code ( ) == "InvalidInstanceID.NotFound" {
2014-07-01 19:10:11 +02:00
// Set this to nil as if we didn't find anything.
resp = nil
} else {
log . Printf ( "Error on InstanceStateRefresh: %s" , err )
return nil , "" , err
}
}
if resp == nil || len ( resp . Reservations ) == 0 || len ( resp . Reservations [ 0 ] . Instances ) == 0 {
// Sometimes AWS just has consistency issues and doesn't see
// our instance yet. Return an empty state.
return nil , "" , nil
}
2015-04-16 19:01:10 +02:00
i := resp . Reservations [ 0 ] . Instances [ 0 ]
2017-05-15 10:31:12 +02:00
state := * i . State . Name
2017-05-16 07:04:56 +02:00
if state == failState {
return i , state , fmt . Errorf ( "Failed to reach target state. Reason: %s" ,
2017-05-15 10:31:12 +02:00
stringifyStateReason ( i . StateReason ) )
}
return i , state , nil
2014-07-01 19:10:11 +02:00
}
}
2014-10-17 18:12:45 +02:00
2017-05-15 10:31:12 +02:00
func stringifyStateReason ( sr * ec2 . StateReason ) string {
if sr . Message != nil {
return * sr . Message
}
if sr . Code != nil {
return * sr . Code
}
return sr . String ( )
}
2015-04-16 19:01:10 +02:00
func readBlockDevices ( d * schema . ResourceData , instance * ec2 . Instance , conn * ec2 . EC2 ) error {
ibds , err := readBlockDevicesFromInstance ( instance , conn )
2015-02-24 18:00:22 +01:00
if err != nil {
return err
}
if err := d . Set ( "ebs_block_device" , ibds [ "ebs" ] ) ; err != nil {
return err
}
2016-04-22 18:37:27 +02:00
// This handles the import case which needs to be defaulted to empty
if _ , ok := d . GetOk ( "root_block_device" ) ; ! ok {
if err := d . Set ( "root_block_device" , [ ] interface { } { } ) ; err != nil {
return err
}
}
2015-02-24 18:00:22 +01:00
if ibds [ "root" ] != nil {
2016-04-22 18:37:27 +02:00
roots := [ ] interface { } { ibds [ "root" ] }
if err := d . Set ( "root_block_device" , roots ) ; err != nil {
2015-02-24 18:00:22 +01:00
return err
}
2014-07-01 19:10:11 +02:00
}
2015-02-24 18:00:22 +01:00
return nil
2014-07-01 19:10:11 +02:00
}
2014-10-17 18:12:45 +02:00
2015-04-16 19:01:10 +02:00
func readBlockDevicesFromInstance ( instance * ec2 . Instance , conn * ec2 . EC2 ) ( map [ string ] interface { } , error ) {
2015-02-24 18:00:22 +01:00
blockDevices := make ( map [ string ] interface { } )
blockDevices [ "ebs" ] = make ( [ ] map [ string ] interface { } , 0 )
blockDevices [ "root" ] = nil
2015-04-16 19:01:10 +02:00
instanceBlockDevices := make ( map [ string ] * ec2 . InstanceBlockDeviceMapping )
2015-02-24 18:00:22 +01:00
for _ , bd := range instance . BlockDeviceMappings {
2015-08-17 20:27:16 +02:00
if bd . Ebs != nil {
2015-10-08 14:48:04 +02:00
instanceBlockDevices [ * bd . Ebs . VolumeId ] = bd
2015-02-24 18:00:22 +01:00
}
}
2015-03-19 19:14:31 +01:00
if len ( instanceBlockDevices ) == 0 {
return nil , nil
}
2015-04-16 19:01:10 +02:00
volIDs := make ( [ ] * string , 0 , len ( instanceBlockDevices ) )
2015-02-24 18:00:22 +01:00
for volID := range instanceBlockDevices {
2015-04-16 19:01:10 +02:00
volIDs = append ( volIDs , aws . String ( volID ) )
2015-02-24 18:00:22 +01:00
}
// Need to call DescribeVolumes to get volume_size and volume_type for each
// EBS block device
2015-04-16 19:01:10 +02:00
volResp , err := conn . DescribeVolumes ( & ec2 . DescribeVolumesInput {
2015-08-17 20:27:16 +02:00
VolumeIds : volIDs ,
2015-02-24 18:00:22 +01:00
} )
if err != nil {
return nil , err
}
for _ , vol := range volResp . Volumes {
2015-08-17 20:27:16 +02:00
instanceBd := instanceBlockDevices [ * vol . VolumeId ]
2015-02-24 18:00:22 +01:00
bd := make ( map [ string ] interface { } )
2015-08-17 20:27:16 +02:00
if instanceBd . Ebs != nil && instanceBd . Ebs . DeleteOnTermination != nil {
bd [ "delete_on_termination" ] = * instanceBd . Ebs . DeleteOnTermination
2015-02-24 18:00:22 +01:00
}
if vol . Size != nil {
bd [ "volume_size" ] = * vol . Size
}
if vol . VolumeType != nil {
bd [ "volume_type" ] = * vol . VolumeType
}
2015-08-17 20:27:16 +02:00
if vol . Iops != nil {
bd [ "iops" ] = * vol . Iops
2015-02-24 18:00:22 +01:00
}
if blockDeviceIsRoot ( instanceBd , instance ) {
blockDevices [ "root" ] = bd
} else {
2015-03-23 17:58:45 +01:00
if instanceBd . DeviceName != nil {
bd [ "device_name" ] = * instanceBd . DeviceName
}
2015-02-24 18:00:22 +01:00
if vol . Encrypted != nil {
bd [ "encrypted" ] = * vol . Encrypted
}
2015-08-17 20:27:16 +02:00
if vol . SnapshotId != nil {
bd [ "snapshot_id" ] = * vol . SnapshotId
2015-02-24 18:00:22 +01:00
}
blockDevices [ "ebs" ] = append ( blockDevices [ "ebs" ] . ( [ ] map [ string ] interface { } ) , bd )
}
}
return blockDevices , nil
}
2015-04-16 19:01:10 +02:00
func blockDeviceIsRoot ( bd * ec2 . InstanceBlockDeviceMapping , instance * ec2 . Instance ) bool {
2015-10-08 14:48:04 +02:00
return bd . DeviceName != nil &&
2015-02-24 18:00:22 +01:00
instance . RootDeviceName != nil &&
2015-10-08 14:48:04 +02:00
* bd . DeviceName == * instance . RootDeviceName
2014-10-17 18:12:45 +02:00
}
2015-03-23 17:58:45 +01:00
2015-04-16 19:01:10 +02:00
func fetchRootDeviceName ( ami string , conn * ec2 . EC2 ) ( * string , error ) {
2015-03-23 17:58:45 +01:00
if ami == "" {
2017-02-01 22:25:07 +01:00
return nil , errors . New ( "Cannot fetch root device name for blank AMI ID." )
2015-03-23 17:58:45 +01:00
}
log . Printf ( "[DEBUG] Describing AMI %q to get root block device name" , ami )
2015-06-08 18:00:05 +02:00
res , err := conn . DescribeImages ( & ec2 . DescribeImagesInput {
2015-08-17 20:27:16 +02:00
ImageIds : [ ] * string { aws . String ( ami ) } ,
2015-06-08 18:00:05 +02:00
} )
if err != nil {
2015-03-23 17:58:45 +01:00
return nil , err
}
2015-06-08 18:00:05 +02:00
// For a bad image, we just return nil so we don't block a refresh
if len ( res . Images ) == 0 {
return nil , nil
}
image := res . Images [ 0 ]
rootDeviceName := image . RootDeviceName
2016-12-01 14:53:14 +01:00
// Instance store backed AMIs do not provide a root device name.
if * image . RootDeviceType == ec2 . DeviceTypeInstanceStore {
return nil , nil
}
2015-06-08 18:00:05 +02:00
// Some AMIs have a RootDeviceName like "/dev/sda1" that does not appear as a
// DeviceName in the BlockDeviceMapping list (which will instead have
// something like "/dev/sda")
//
// While this seems like it breaks an invariant of AMIs, it ends up working
// on the AWS side, and AMIs like this are common enough that we need to
// special case it so Terraform does the right thing.
//
// Our heuristic is: if the RootDeviceName does not appear in the
// BlockDeviceMapping, assume that the DeviceName of the first
// BlockDeviceMapping entry serves as the root device.
rootDeviceNameInMapping := false
for _ , bdm := range image . BlockDeviceMappings {
if bdm . DeviceName == image . RootDeviceName {
rootDeviceNameInMapping = true
}
}
if ! rootDeviceNameInMapping && len ( image . BlockDeviceMappings ) > 0 {
rootDeviceName = image . BlockDeviceMappings [ 0 ] . DeviceName
}
2015-07-28 22:29:46 +02:00
if rootDeviceName == nil {
return nil , fmt . Errorf ( "[WARN] Error finding Root Device Name for AMI (%s)" , ami )
}
2015-07-07 23:12:41 +02:00
2015-06-08 18:00:05 +02:00
return rootDeviceName , nil
2014-10-17 18:12:45 +02:00
}
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
2017-04-25 00:06:28 +02:00
func buildNetworkInterfaceOpts ( d * schema . ResourceData , groups [ ] * string , nInterfaces interface { } ) [ ] * ec2 . InstanceNetworkInterfaceSpecification {
networkInterfaces := [ ] * ec2 . InstanceNetworkInterfaceSpecification { }
// Get necessary items
associatePublicIPAddress := d . Get ( "associate_public_ip_address" ) . ( bool )
subnet , hasSubnet := d . GetOk ( "subnet_id" )
if hasSubnet && associatePublicIPAddress {
// If we have a non-default VPC / Subnet specified, we can flag
// AssociatePublicIpAddress to get a Public IP assigned. By default these are not provided.
// You cannot specify both SubnetId and the NetworkInterface.0.* parameters though, otherwise
// you get: Network interfaces and an instance-level subnet ID may not be specified on the same request
// You also need to attach Security Groups to the NetworkInterface instead of the instance,
// to avoid: Network interfaces and an instance-level security groups may not be specified on
// the same request
ni := & ec2 . InstanceNetworkInterfaceSpecification {
AssociatePublicIpAddress : aws . Bool ( associatePublicIPAddress ) ,
DeviceIndex : aws . Int64 ( int64 ( 0 ) ) ,
SubnetId : aws . String ( subnet . ( string ) ) ,
Groups : groups ,
}
if v , ok := d . GetOk ( "private_ip" ) ; ok {
ni . PrivateIpAddress = aws . String ( v . ( string ) )
}
if v := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; v . Len ( ) > 0 {
for _ , v := range v . List ( ) {
ni . Groups = append ( ni . Groups , aws . String ( v . ( string ) ) )
}
}
networkInterfaces = append ( networkInterfaces , ni )
} else {
// If we have manually specified network interfaces, build and attach those here.
vL := nInterfaces . ( * schema . Set ) . List ( )
for _ , v := range vL {
ini := v . ( map [ string ] interface { } )
ni := & ec2 . InstanceNetworkInterfaceSpecification {
DeviceIndex : aws . Int64 ( int64 ( ini [ "device_index" ] . ( int ) ) ) ,
NetworkInterfaceId : aws . String ( ini [ "network_interface_id" ] . ( string ) ) ,
DeleteOnTermination : aws . Bool ( ini [ "delete_on_termination" ] . ( bool ) ) ,
}
networkInterfaces = append ( networkInterfaces , ni )
}
}
return networkInterfaces
}
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
func readBlockDeviceMappingsFromConfig (
d * schema . ResourceData , conn * ec2 . EC2 ) ( [ ] * ec2 . BlockDeviceMapping , error ) {
blockDevices := make ( [ ] * ec2 . BlockDeviceMapping , 0 )
if v , ok := d . GetOk ( "ebs_block_device" ) ; ok {
vL := v . ( * schema . Set ) . List ( )
for _ , v := range vL {
bd := v . ( map [ string ] interface { } )
2015-08-17 20:27:16 +02:00
ebs := & ec2 . EbsBlockDevice {
2015-07-28 22:29:46 +02:00
DeleteOnTermination : aws . Bool ( bd [ "delete_on_termination" ] . ( bool ) ) ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "snapshot_id" ] . ( string ) ; ok && v != "" {
2015-08-17 20:27:16 +02:00
ebs . SnapshotId = aws . String ( v )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "encrypted" ] . ( bool ) ; ok && v {
2015-07-28 22:29:46 +02:00
ebs . Encrypted = aws . Bool ( v )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "volume_size" ] . ( int ) ; ok && v != 0 {
2015-07-28 22:29:46 +02:00
ebs . VolumeSize = aws . Int64 ( int64 ( v ) )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "volume_type" ] . ( string ) ; ok && v != "" {
ebs . VolumeType = aws . String ( v )
2017-03-07 13:44:39 +01:00
if "io1" == strings . ToLower ( v ) {
// Condition: This parameter is required for requests to create io1
// volumes; it is not used in requests to create gp2, st1, sc1, or
// standard volumes.
// See: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_EbsBlockDevice.html
if v , ok := bd [ "iops" ] . ( int ) ; ok && v > 0 {
ebs . Iops = aws . Int64 ( int64 ( v ) )
}
}
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
blockDevices = append ( blockDevices , & ec2 . BlockDeviceMapping {
DeviceName : aws . String ( bd [ "device_name" ] . ( string ) ) ,
2015-08-17 20:27:16 +02:00
Ebs : ebs ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
} )
}
}
if v , ok := d . GetOk ( "ephemeral_block_device" ) ; ok {
vL := v . ( * schema . Set ) . List ( )
for _ , v := range vL {
bd := v . ( map [ string ] interface { } )
2016-12-08 11:03:51 +01:00
bdm := & ec2 . BlockDeviceMapping {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
DeviceName : aws . String ( bd [ "device_name" ] . ( string ) ) ,
VirtualName : aws . String ( bd [ "virtual_name" ] . ( string ) ) ,
2016-12-08 11:03:51 +01:00
}
if v , ok := bd [ "no_device" ] . ( bool ) ; ok && v {
bdm . NoDevice = aws . String ( "" )
// When NoDevice is true, just ignore VirtualName since it's not needed
bdm . VirtualName = nil
}
if bdm . NoDevice == nil && aws . StringValue ( bdm . VirtualName ) == "" {
2017-02-01 22:25:07 +01:00
return nil , errors . New ( "virtual_name cannot be empty when no_device is false or undefined." )
2016-12-08 11:03:51 +01:00
}
blockDevices = append ( blockDevices , bdm )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
}
if v , ok := d . GetOk ( "root_block_device" ) ; ok {
2017-02-01 22:25:07 +01:00
vL := v . ( [ ] interface { } )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
if len ( vL ) > 1 {
2017-02-01 22:25:07 +01:00
return nil , errors . New ( "Cannot specify more than one root_block_device." )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
for _ , v := range vL {
bd := v . ( map [ string ] interface { } )
2015-08-17 20:27:16 +02:00
ebs := & ec2 . EbsBlockDevice {
2015-07-28 22:29:46 +02:00
DeleteOnTermination : aws . Bool ( bd [ "delete_on_termination" ] . ( bool ) ) ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "volume_size" ] . ( int ) ; ok && v != 0 {
2015-07-28 22:29:46 +02:00
ebs . VolumeSize = aws . Int64 ( int64 ( v ) )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if v , ok := bd [ "volume_type" ] . ( string ) ; ok && v != "" {
ebs . VolumeType = aws . String ( v )
}
2016-07-25 13:32:24 +02:00
if v , ok := bd [ "iops" ] . ( int ) ; ok && v > 0 && * ebs . VolumeType == "io1" {
// Only set the iops attribute if the volume type is io1. Setting otherwise
// can trigger a refresh/plan loop based on the computed value that is given
// from AWS, and prevent us from specifying 0 as a valid iops.
// See https://github.com/hashicorp/terraform/pull/4146
// See https://github.com/hashicorp/terraform/issues/7765
2015-08-17 20:27:16 +02:00
ebs . Iops = aws . Int64 ( int64 ( v ) )
2016-07-25 13:32:24 +02:00
} else if v , ok := bd [ "iops" ] . ( int ) ; ok && v > 0 && * ebs . VolumeType != "io1" {
// Message user about incompatibility
2017-02-01 22:25:07 +01:00
log . Print ( "[WARN] IOPs is only valid for storate type io1 for EBS Volumes" )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if dn , err := fetchRootDeviceName ( d . Get ( "ami" ) . ( string ) , conn ) ; err == nil {
if dn == nil {
return nil , fmt . Errorf (
"Expected 1 AMI for ID: %s, got none" ,
d . Get ( "ami" ) . ( string ) )
}
blockDevices = append ( blockDevices , & ec2 . BlockDeviceMapping {
DeviceName : dn ,
2015-08-17 20:27:16 +02:00
Ebs : ebs ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
} )
} else {
return nil , err
}
}
}
return blockDevices , nil
}
2017-04-26 00:12:38 +02:00
func readVolumeTags ( conn * ec2 . EC2 , d * schema . ResourceData ) error {
volumeIds , err := getAwsInstanceVolumeIds ( conn , d )
if err != nil {
return err
}
tagsResp , err := conn . DescribeTags ( & ec2 . DescribeTagsInput {
Filters : [ ] * ec2 . Filter {
{
Name : aws . String ( "resource-id" ) ,
Values : volumeIds ,
} ,
} ,
} )
if err != nil {
return err
}
var tags [ ] * ec2 . Tag
for _ , t := range tagsResp . Tags {
tag := & ec2 . Tag {
Key : t . Key ,
Value : t . Value ,
}
tags = append ( tags , tag )
}
d . Set ( "volume_tags" , tagsToMap ( tags ) )
return nil
}
2017-01-18 18:19:44 +01:00
// Determine whether we're referring to security groups with
// IDs or names. We use a heuristic to figure this out. By default,
// we use IDs if we're in a VPC. However, if we previously had an
// all-name list of security groups, we use names. Or, if we had any
// IDs, we use IDs.
func readSecurityGroups ( d * schema . ResourceData , instance * ec2 . Instance ) error {
useID := instance . SubnetId != nil && * instance . SubnetId != ""
if v := d . Get ( "security_groups" ) ; v != nil {
match := useID
sgs := v . ( * schema . Set ) . List ( )
if len ( sgs ) > 0 {
match = false
for _ , v := range v . ( * schema . Set ) . List ( ) {
if strings . HasPrefix ( v . ( string ) , "sg-" ) {
match = true
break
}
}
}
useID = match
}
// Build up the security groups
sgs := make ( [ ] string , 0 , len ( instance . SecurityGroups ) )
if useID {
for _ , sg := range instance . SecurityGroups {
sgs = append ( sgs , * sg . GroupId )
}
log . Printf ( "[DEBUG] Setting Security Group IDs: %#v" , sgs )
if err := d . Set ( "vpc_security_group_ids" , sgs ) ; err != nil {
return err
}
if err := d . Set ( "security_groups" , [ ] string { } ) ; err != nil {
return err
}
} else {
for _ , sg := range instance . SecurityGroups {
sgs = append ( sgs , * sg . GroupName )
}
log . Printf ( "[DEBUG] Setting Security Group Names: %#v" , sgs )
if err := d . Set ( "security_groups" , sgs ) ; err != nil {
return err
}
if err := d . Set ( "vpc_security_group_ids" , [ ] string { } ) ; err != nil {
return err
}
}
return nil
}
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
type awsInstanceOpts struct {
2015-07-29 22:54:56 +02:00
BlockDeviceMappings [ ] * ec2 . BlockDeviceMapping
DisableAPITermination * bool
EBSOptimized * bool
Monitoring * ec2 . RunInstancesMonitoringEnabled
2015-08-18 21:40:01 +02:00
IAMInstanceProfile * ec2 . IamInstanceProfileSpecification
2015-07-29 22:54:56 +02:00
ImageID * string
InstanceInitiatedShutdownBehavior * string
2015-08-18 21:40:01 +02:00
InstanceType * string
2015-07-29 22:54:56 +02:00
KeyName * string
NetworkInterfaces [ ] * ec2 . InstanceNetworkInterfaceSpecification
Placement * ec2 . Placement
PrivateIPAddress * string
SecurityGroupIDs [ ] * string
SecurityGroups [ ] * string
SpotPlacement * ec2 . SpotPlacement
SubnetID * string
UserData64 * string
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
func buildAwsInstanceOpts (
d * schema . ResourceData , meta interface { } ) ( * awsInstanceOpts , error ) {
conn := meta . ( * AWSClient ) . ec2conn
opts := & awsInstanceOpts {
2015-08-04 13:09:47 +02:00
DisableAPITermination : aws . Bool ( d . Get ( "disable_api_termination" ) . ( bool ) ) ,
EBSOptimized : aws . Bool ( d . Get ( "ebs_optimized" ) . ( bool ) ) ,
ImageID : aws . String ( d . Get ( "ami" ) . ( string ) ) ,
InstanceType : aws . String ( d . Get ( "instance_type" ) . ( string ) ) ,
}
if v := d . Get ( "instance_initiated_shutdown_behavior" ) . ( string ) ; v != "" {
opts . InstanceInitiatedShutdownBehavior = aws . String ( v )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
2015-06-25 16:58:28 +02:00
opts . Monitoring = & ec2 . RunInstancesMonitoringEnabled {
2015-07-28 22:29:46 +02:00
Enabled : aws . Bool ( d . Get ( "monitoring" ) . ( bool ) ) ,
2015-06-25 16:58:28 +02:00
}
2015-08-17 20:27:16 +02:00
opts . IAMInstanceProfile = & ec2 . IamInstanceProfileSpecification {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
Name : aws . String ( d . Get ( "iam_instance_profile" ) . ( string ) ) ,
}
2016-04-13 17:20:20 +02:00
user_data := d . Get ( "user_data" ) . ( string )
2016-12-20 22:37:50 +01:00
opts . UserData64 = aws . String ( base64Encode ( [ ] byte ( user_data ) ) )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
// check for non-default Subnet, and cast it to a String
subnet , hasSubnet := d . GetOk ( "subnet_id" )
subnetID := subnet . ( string )
// Placement is used for aws_instance; SpotPlacement is used for
// aws_spot_instance_request. They represent the same data. :-|
opts . Placement = & ec2 . Placement {
AvailabilityZone : aws . String ( d . Get ( "availability_zone" ) . ( string ) ) ,
GroupName : aws . String ( d . Get ( "placement_group" ) . ( string ) ) ,
}
opts . SpotPlacement = & ec2 . SpotPlacement {
AvailabilityZone : aws . String ( d . Get ( "availability_zone" ) . ( string ) ) ,
GroupName : aws . String ( d . Get ( "placement_group" ) . ( string ) ) ,
}
if v := d . Get ( "tenancy" ) . ( string ) ; v != "" {
opts . Placement . Tenancy = aws . String ( v )
}
associatePublicIPAddress := d . Get ( "associate_public_ip_address" ) . ( bool )
var groups [ ] * string
if v := d . Get ( "security_groups" ) ; v != nil {
// Security group names.
// For a nondefault VPC, you must use security group IDs instead.
// See http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_RunInstances.html
sgs := v . ( * schema . Set ) . List ( )
if len ( sgs ) > 0 && hasSubnet {
2017-02-01 22:25:07 +01:00
log . Print ( "[WARN] Deprecated. Attempting to use 'security_groups' within a VPC instance. Use 'vpc_security_group_ids' instead." )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
for _ , v := range sgs {
str := v . ( string )
groups = append ( groups , aws . String ( str ) )
}
}
2017-04-25 00:06:28 +02:00
networkInterfaces , interfacesOk := d . GetOk ( "network_interface" )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
2017-04-25 16:06:28 +02:00
// If setting subnet and public address, OR manual network interfaces, populate those now.
if hasSubnet && associatePublicIPAddress || interfacesOk {
// Otherwise we're attaching (a) network interface(s)
opts . NetworkInterfaces = buildNetworkInterfaceOpts ( d , groups , networkInterfaces )
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
} else {
2017-04-25 16:06:28 +02:00
// If simply specifying a subnetID, privateIP, Security Groups, or VPC Security Groups, build these now
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
if subnetID != "" {
opts . SubnetID = aws . String ( subnetID )
}
if v , ok := d . GetOk ( "private_ip" ) ; ok {
opts . PrivateIPAddress = aws . String ( v . ( string ) )
}
if opts . SubnetID != nil &&
* opts . SubnetID != "" {
opts . SecurityGroupIDs = groups
} else {
opts . SecurityGroups = groups
}
2015-06-11 14:59:42 +02:00
if v := d . Get ( "vpc_security_group_ids" ) . ( * schema . Set ) ; v . Len ( ) > 0 {
for _ , v := range v . List ( ) {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
opts . SecurityGroupIDs = append ( opts . SecurityGroupIDs , aws . String ( v . ( string ) ) )
}
}
}
if v , ok := d . GetOk ( "key_name" ) ; ok {
opts . KeyName = aws . String ( v . ( string ) )
}
blockDevices , err := readBlockDeviceMappingsFromConfig ( d , conn )
if err != nil {
return nil , err
}
if len ( blockDevices ) > 0 {
opts . BlockDeviceMappings = blockDevices
}
return opts , nil
}
2017-05-22 09:27:06 +02:00
func awsTerminateInstance ( conn * ec2 . EC2 , id string , d * schema . ResourceData ) error {
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
log . Printf ( "[INFO] Terminating instance: %s" , id )
req := & ec2 . TerminateInstancesInput {
2015-08-17 20:27:16 +02:00
InstanceIds : [ ] * string { aws . String ( id ) } ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
}
if _ , err := conn . TerminateInstances ( req ) ; err != nil {
return fmt . Errorf ( "Error terminating instance: %s" , err )
}
log . Printf ( "[DEBUG] Waiting for instance (%s) to become terminated" , id )
stateConf := & resource . StateChangeConf {
Pending : [ ] string { "pending" , "running" , "shutting-down" , "stopped" , "stopping" } ,
2016-01-21 02:20:41 +01:00
Target : [ ] string { "terminated" } ,
2017-05-16 07:04:56 +02:00
Refresh : InstanceStateRefreshFunc ( conn , id , "" ) ,
2017-05-22 09:27:06 +02:00
Timeout : d . Timeout ( schema . TimeoutDelete ) ,
provider/aws: spot_instance_request
This is an iteration on the great work done by @dalehamel in PRs #2095
and #2109.
The core team went back and forth on how to best model Spot Instance
Requests, requesting and then rejecting a separate-resource
implementation in #2109.
After more internal discussion, we landed once again on a separate
resource to model Spot Instance Requests. Out of respect for
@dalehamel's already-significant donated time, with this I'm attempting
to pick up the work to take this across the finish line.
Important architectural decisions represented here:
* Spot Instance Requests are always of type "persistent", to properly
match Terraform's declarative model.
* The spot_instance_request resource exports several attributes that
are expected to be constantly changing as the spot market changes:
spot_bid_status, spot_request_state, and instance_id. Creating
additional resource dependencies based on these attributes is not
recommended, as Terraform diffs will be continually generated to keep
up with the live changes.
* When a Spot Instance Request is deleted/canceled, an attempt is made
to terminate the last-known attached spot instance. Race conditions
dictate that this attempt cannot guarantee that the associated spot
instance is terminated immediately.
Implementation notes:
* This version of aws_spot_instance_request borrows a lot of common
code from aws_instance.
* In order to facilitate borrowing, we introduce `awsInstanceOpts`, an
internal representation of instance details that's meant to be shared
between resources. The goal here would be to refactor ASG Launch
Configurations to use the same struct.
* The new aws_spot_instance_request acc. test is passing.
* All aws_instance acc. tests remain passing.
2015-06-05 17:12:09 +02:00
Delay : 10 * time . Second ,
MinTimeout : 3 * time . Second ,
}
_ , err := stateConf . WaitForState ( )
if err != nil {
return fmt . Errorf (
"Error waiting for instance (%s) to terminate: %s" , id , err )
}
return nil
}
2015-09-03 21:43:41 +02:00
2015-09-05 02:20:58 +02:00
func iamInstanceProfileArnToName ( ip * ec2 . IamInstanceProfile ) string {
2015-09-06 19:01:57 +02:00
if ip == nil || ip . Arn == nil {
2015-09-05 02:20:58 +02:00
return ""
}
2015-10-28 03:30:11 +01:00
parts := strings . Split ( * ip . Arn , "/" )
return parts [ len ( parts ) - 1 ]
2015-09-03 21:43:41 +02:00
}
2016-05-17 16:15:15 +02:00
func userDataHashSum ( user_data string ) string {
// Check whether the user_data is not Base64 encoded.
// Always calculate hash of base64 decoded value since we
// check against double-encoding when setting it
v , base64DecodeError := base64 . StdEncoding . DecodeString ( user_data )
if base64DecodeError != nil {
v = [ ] byte ( user_data )
}
hash := sha1 . Sum ( v )
return hex . EncodeToString ( hash [ : ] )
}
2017-04-26 00:12:38 +02:00
func getAwsInstanceVolumeIds ( conn * ec2 . EC2 , d * schema . ResourceData ) ( [ ] * string , error ) {
volumeIds := make ( [ ] * string , 0 )
opts := & ec2 . DescribeVolumesInput {
Filters : [ ] * ec2 . Filter {
{
Name : aws . String ( "attachment.instance-id" ) ,
Values : [ ] * string { aws . String ( d . Id ( ) ) } ,
} ,
} ,
}
resp , err := conn . DescribeVolumes ( opts )
if err != nil {
return nil , err
}
for _ , v := range resp . Volumes {
volumeIds = append ( volumeIds , v . VolumeId )
}
return volumeIds , nil
}