Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue #4449 Fix the issue using Arn field instead of Name in IamInstanceProfileSpecification #4511

Merged
merged 3 commits into from
May 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions aws/resource_aws_spot_fleet_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ func resourceAwsSpotFleetRequest() *schema.Resource {
ForceNew: true,
Optional: true,
},
"iam_instance_profile_arn": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please

  • Document the new argument in the argument reference near the existing iam_instance_profile argument
  • Add a simple acceptance test to cover this new argument? Copy pasting an existing test and test configuration that uses iam_instance_profile is fine 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documented the new argument under launch_specification section and added the acceptance test.

Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
"ami": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -376,6 +381,12 @@ func buildSpotFleetLaunchSpecification(d map[string]interface{}, meta interface{
}
}

if v, ok := d["iam_instance_profile_arn"]; ok {
opts.IamInstanceProfile = &ec2.IamInstanceProfileSpecification{
Arn: aws.String(v.(string)),
}
}

if v, ok := d["user_data"]; ok {
opts.UserData = aws.String(base64Encode([]byte(v.(string))))
}
Expand Down Expand Up @@ -939,6 +950,10 @@ func launchSpecToMap(l *ec2.SpotFleetLaunchSpecification, rootDevName *string) m
m["iam_instance_profile"] = aws.StringValue(l.IamInstanceProfile.Name)
}

if l.IamInstanceProfile != nil && l.IamInstanceProfile.Arn != nil {
m["iam_instance_profile_arn"] = aws.StringValue(l.IamInstanceProfile.Arn)
}

if l.UserData != nil {
m["user_data"] = userDataHashSum(aws.StringValue(l.UserData))
}
Expand Down
167 changes: 167 additions & 0 deletions aws/resource_aws_spot_fleet_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"log"
"regexp"
"testing"
"time"

Expand Down Expand Up @@ -107,6 +108,30 @@ func TestAccAWSSpotFleetRequest_instanceInterruptionBehavior(t *testing.T) {
})
}

func TestAccAWSSpotFleetRequest_iamInstanceProfileArn(t *testing.T) {
var sfr ec2.SpotFleetRequestConfig
rName := acctest.RandString(10)
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSpotFleetRequestDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSSpotFleetRequestConfigIamInstanceProfileArn(rName, rInt),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSSpotFleetRequestExists(
"aws_spot_fleet_request.foo", &sfr),
resource.TestCheckResourceAttr(
"aws_spot_fleet_request.foo", "spot_request_state", "active"),
testAccCheckAWSSpotFleetRequest_IamInstanceProfileArn(&sfr),
),
},
},
})
}

func TestAccAWSSpotFleetRequest_changePriceForcesNewRequest(t *testing.T) {
var before, after ec2.SpotFleetRequestConfig
rName := acctest.RandString(10)
Expand Down Expand Up @@ -602,6 +627,29 @@ func TestAccAWSSpotFleetRequest_WithELBs(t *testing.T) {
})
}

func testAccCheckAWSSpotFleetRequest_IamInstanceProfileArn(
sfr *ec2.SpotFleetRequestConfig) resource.TestCheckFunc {
return func(s *terraform.State) error {
if len(sfr.SpotFleetRequestConfig.LaunchSpecifications) == 0 {
return errors.New("Missing launch specification")
}

spec := *sfr.SpotFleetRequestConfig.LaunchSpecifications[0]

profile := spec.IamInstanceProfile
if profile == nil {
return fmt.Errorf("Expected IamInstanceProfile to be set, got nil")
}
//Validate the string whether it is ARN
re := regexp.MustCompile("arn:aws:iam::\\d{12}:instance-profile/?[a-zA-Z0-9+=,.@-_].*")
if !re.MatchString(*profile.Arn) {
return fmt.Errorf("Expected IamInstanceProfile input as ARN, got %s", *profile.Arn)
}

return nil
}
}

func TestAccAWSSpotFleetRequest_WithTargetGroups(t *testing.T) {
var sfr ec2.SpotFleetRequestConfig
rName := acctest.RandString(10)
Expand Down Expand Up @@ -757,6 +805,125 @@ resource "aws_spot_fleet_request" "foo" {
`, rName, rInt, rInt, rName)
}

func testAccAWSSpotFleetRequestConfigIamInstanceProfileArn(rName string, rInt int) string {
return fmt.Sprintf(`
resource "aws_key_pair" "debugging" {
key_name = "tmp-key-%s"
public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
}

resource "aws_iam_policy" "test-policy" {
name = "test-policy-%d"
path = "/"
description = "Spot Fleet Request ACCTest Policy"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"ec2:DescribeImages",
"ec2:DescribeSubnets",
"ec2:RequestSpotInstances",
"ec2:TerminateInstances",
"ec2:DescribeInstanceStatus",
"iam:PassRole"
],
"Resource": ["*"]
}]
}
EOF
}

resource "aws_iam_policy_attachment" "test-attach" {
name = "test-attachment-%d"
roles = ["${aws_iam_role.test-role.name}"]
policy_arn = "${aws_iam_policy.test-policy.arn}"
}

resource "aws_iam_role" "test-role" {
name = "test-role-%s"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"spotfleet.amazonaws.com",
"ec2.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}

resource "aws_iam_role" "test-role1" {
name = "tf-test-role1-%s"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": [
"spotfleet.amazonaws.com",
"ec2.amazonaws.com"
]
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}

resource "aws_iam_role_policy" "test-role-policy1" {
name = "tf-test-role-policy1-%s"
role = "${aws_iam_role.test-role1.name}"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
}
EOF
}

resource "aws_iam_instance_profile" "test-iam-instance-profile1" {
name = "tf-test-profile1-%s"
role = "${aws_iam_role.test-role1.name}"
}

resource "aws_spot_fleet_request" "foo" {
iam_fleet_role = "${aws_iam_role.test-role.arn}"
spot_price = "0.005"
target_capacity = 2
valid_until = "2019-11-04T20:44:20Z"
terminate_instances_with_expiration = true
instance_interruption_behaviour = "stop"
wait_for_fulfillment = true
launch_specification {
instance_type = "m1.small"
ami = "ami-516b9131"
key_name = "${aws_key_pair.debugging.key_name}"
iam_instance_profile_arn = "${aws_iam_instance_profile.test-iam-instance-profile1.arn}"
}
depends_on = ["aws_iam_policy_attachment.test-attach"]
}
`, rName, rInt, rInt, rName, rName, rName, rName)
}

func testAccAWSSpotFleetRequestConfigChangeSpotBidPrice(rName string, rInt int) string {
return fmt.Sprintf(`
resource "aws_key_pair" "debugging" {
Expand Down
27 changes: 15 additions & 12 deletions website/docs/r/spot_fleet_request.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,22 @@ resource "aws_spot_fleet_request" "cheap_compute" {
valid_until = "2019-11-04T20:44:20Z"

launch_specification {
instance_type = "m4.10xlarge"
ami = "ami-1234"
spot_price = "2.793"
placement_tenancy = "dedicated"
instance_type = "m4.10xlarge"
ami = "ami-1234"
spot_price = "2.793"
placement_tenancy = "dedicated"
iam_instance_profile_arn = "${aws_iam_instance_profile.example.arn}"
}

launch_specification {
instance_type = "m4.4xlarge"
ami = "ami-5678"
key_name = "my-key"
spot_price = "1.117"
availability_zone = "us-west-1a"
subnet_id = "subnet-1234"
weighted_capacity = 35
instance_type = "m4.4xlarge"
ami = "ami-5678"
key_name = "my-key"
spot_price = "1.117"
iam_instance_profile_arn = "${aws_iam_instance_profile.example.arn}"
availability_zone = "us-west-1a"
subnet_id = "subnet-1234"
weighted_capacity = 35

root_block_device {
volume_size = "300"
Expand Down Expand Up @@ -95,7 +97,8 @@ across different markets and instance types.
**Note:** This takes in similar but not
identical inputs as [`aws_instance`](instance.html). There are limitations on
what you can specify. See the list of officially supported inputs in the
[reference documentation](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SpotFleetLaunchSpecification.html). Any normal [`aws_instance`](instance.html) parameter that corresponds to those inputs may be used.
[reference documentation](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_SpotFleetLaunchSpecification.html). Any normal [`aws_instance`](instance.html) parameter that corresponds to those inputs may be used and it have
a additional parameter `iam_instance_profile_arn` takes `aws_iam_instance_profile` attribute `arn` as input.

* `spot_price` - (Required) The bid price per unit hour.
* `wait_for_fulfillment` - (Optional; Default: false) If set, Terraform will
Expand Down