github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_spot_instance_request_test.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/aws/awserr"
     9  	"github.com/aws/aws-sdk-go/service/ec2"
    10  	"github.com/hashicorp/terraform/helper/acctest"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/terraform"
    13  )
    14  
    15  func TestAccAWSSpotInstanceRequest_basic(t *testing.T) {
    16  	var sir ec2.SpotInstanceRequest
    17  	rInt := acctest.RandInt()
    18  
    19  	resource.Test(t, resource.TestCase{
    20  		PreCheck:     func() { testAccPreCheck(t) },
    21  		Providers:    testAccProviders,
    22  		CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy,
    23  		Steps: []resource.TestStep{
    24  			{
    25  				Config: testAccAWSSpotInstanceRequestConfig(rInt),
    26  				Check: resource.ComposeTestCheckFunc(
    27  					testAccCheckAWSSpotInstanceRequestExists(
    28  						"aws_spot_instance_request.foo", &sir),
    29  					testAccCheckAWSSpotInstanceRequestAttributes(&sir),
    30  					testCheckKeyPair(fmt.Sprintf("tmp-key-%d", rInt), &sir),
    31  					resource.TestCheckResourceAttr(
    32  						"aws_spot_instance_request.foo", "spot_bid_status", "fulfilled"),
    33  					resource.TestCheckResourceAttr(
    34  						"aws_spot_instance_request.foo", "spot_request_state", "active"),
    35  				),
    36  			},
    37  		},
    38  	})
    39  }
    40  
    41  func TestAccAWSSpotInstanceRequest_withBlockDuration(t *testing.T) {
    42  	var sir ec2.SpotInstanceRequest
    43  	rInt := acctest.RandInt()
    44  
    45  	resource.Test(t, resource.TestCase{
    46  		PreCheck:     func() { testAccPreCheck(t) },
    47  		Providers:    testAccProviders,
    48  		CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy,
    49  		Steps: []resource.TestStep{
    50  			{
    51  				Config: testAccAWSSpotInstanceRequestConfig_withBlockDuration(rInt),
    52  				Check: resource.ComposeTestCheckFunc(
    53  					testAccCheckAWSSpotInstanceRequestExists(
    54  						"aws_spot_instance_request.foo", &sir),
    55  					testAccCheckAWSSpotInstanceRequestAttributes(&sir),
    56  					testCheckKeyPair(fmt.Sprintf("tmp-key-%d", rInt), &sir),
    57  					resource.TestCheckResourceAttr(
    58  						"aws_spot_instance_request.foo", "spot_bid_status", "fulfilled"),
    59  					resource.TestCheckResourceAttr(
    60  						"aws_spot_instance_request.foo", "spot_request_state", "active"),
    61  					resource.TestCheckResourceAttr(
    62  						"aws_spot_instance_request.foo", "block_duration_minutes", "60"),
    63  				),
    64  			},
    65  		},
    66  	})
    67  }
    68  
    69  func TestAccAWSSpotInstanceRequest_vpc(t *testing.T) {
    70  	var sir ec2.SpotInstanceRequest
    71  	rInt := acctest.RandInt()
    72  
    73  	resource.Test(t, resource.TestCase{
    74  		PreCheck:     func() { testAccPreCheck(t) },
    75  		Providers:    testAccProviders,
    76  		CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy,
    77  		Steps: []resource.TestStep{
    78  			{
    79  				Config: testAccAWSSpotInstanceRequestConfigVPC(rInt),
    80  				Check: resource.ComposeTestCheckFunc(
    81  					testAccCheckAWSSpotInstanceRequestExists(
    82  						"aws_spot_instance_request.foo_VPC", &sir),
    83  					testAccCheckAWSSpotInstanceRequestAttributes(&sir),
    84  					testCheckKeyPair(fmt.Sprintf("tmp-key-%d", rInt), &sir),
    85  					testAccCheckAWSSpotInstanceRequestAttributesVPC(&sir),
    86  					resource.TestCheckResourceAttr(
    87  						"aws_spot_instance_request.foo_VPC", "spot_bid_status", "fulfilled"),
    88  					resource.TestCheckResourceAttr(
    89  						"aws_spot_instance_request.foo_VPC", "spot_request_state", "active"),
    90  				),
    91  			},
    92  		},
    93  	})
    94  }
    95  
    96  func TestAccAWSSpotInstanceRequest_SubnetAndSG(t *testing.T) {
    97  	var sir ec2.SpotInstanceRequest
    98  	rInt := acctest.RandInt()
    99  
   100  	resource.Test(t, resource.TestCase{
   101  		PreCheck:     func() { testAccPreCheck(t) },
   102  		Providers:    testAccProviders,
   103  		CheckDestroy: testAccCheckAWSSpotInstanceRequestDestroy,
   104  		Steps: []resource.TestStep{
   105  			{
   106  				Config: testAccAWSSpotInstanceRequestConfig_SubnetAndSG(rInt),
   107  				Check: resource.ComposeTestCheckFunc(
   108  					testAccCheckAWSSpotInstanceRequestExists(
   109  						"aws_spot_instance_request.foo", &sir),
   110  					testAccCheckAWSSpotInstanceRequest_InstanceAttributes(&sir, rInt),
   111  				),
   112  			},
   113  		},
   114  	})
   115  }
   116  
   117  func testCheckKeyPair(keyName string, sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   118  	return func(*terraform.State) error {
   119  		if sir.LaunchSpecification.KeyName == nil {
   120  			return fmt.Errorf("No Key Pair found, expected(%s)", keyName)
   121  		}
   122  		if sir.LaunchSpecification.KeyName != nil && *sir.LaunchSpecification.KeyName != keyName {
   123  			return fmt.Errorf("Bad key name, expected (%s), got (%s)", keyName, *sir.LaunchSpecification.KeyName)
   124  		}
   125  
   126  		return nil
   127  	}
   128  }
   129  
   130  func testAccCheckAWSSpotInstanceRequestDestroy(s *terraform.State) error {
   131  	conn := testAccProvider.Meta().(*AWSClient).ec2conn
   132  
   133  	for _, rs := range s.RootModule().Resources {
   134  		if rs.Type != "aws_spot_instance_request" {
   135  			continue
   136  		}
   137  
   138  		req := &ec2.DescribeSpotInstanceRequestsInput{
   139  			SpotInstanceRequestIds: []*string{aws.String(rs.Primary.ID)},
   140  		}
   141  
   142  		resp, err := conn.DescribeSpotInstanceRequests(req)
   143  		var s *ec2.SpotInstanceRequest
   144  		if err == nil {
   145  			for _, sir := range resp.SpotInstanceRequests {
   146  				if sir.SpotInstanceRequestId != nil && *sir.SpotInstanceRequestId == rs.Primary.ID {
   147  					s = sir
   148  				}
   149  				continue
   150  			}
   151  		}
   152  
   153  		if s == nil {
   154  			// not found
   155  			return nil
   156  		}
   157  
   158  		if *s.State == "canceled" {
   159  			// Requests stick around for a while, so we make sure it's cancelled
   160  			return nil
   161  		}
   162  
   163  		// Verify the error is what we expect
   164  		ec2err, ok := err.(awserr.Error)
   165  		if !ok {
   166  			return err
   167  		}
   168  		if ec2err.Code() != "InvalidSpotInstanceRequestID.NotFound" {
   169  			return err
   170  		}
   171  
   172  		// Now check if the associated Spot Instance was also destroyed
   173  		instId := rs.Primary.Attributes["spot_instance_id"]
   174  		instResp, instErr := conn.DescribeInstances(&ec2.DescribeInstancesInput{
   175  			InstanceIds: []*string{aws.String(instId)},
   176  		})
   177  		if instErr == nil {
   178  			if len(instResp.Reservations) > 0 {
   179  				return fmt.Errorf("Instance still exists.")
   180  			}
   181  
   182  			return nil
   183  		}
   184  
   185  		// Verify the error is what we expect
   186  		ec2err, ok = err.(awserr.Error)
   187  		if !ok {
   188  			return err
   189  		}
   190  		if ec2err.Code() != "InvalidInstanceID.NotFound" {
   191  			return err
   192  		}
   193  	}
   194  
   195  	return nil
   196  }
   197  
   198  func testAccCheckAWSSpotInstanceRequestExists(
   199  	n string, sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   200  	return func(s *terraform.State) error {
   201  		rs, ok := s.RootModule().Resources[n]
   202  		if !ok {
   203  			return fmt.Errorf("Not found: %s", n)
   204  		}
   205  
   206  		if rs.Primary.ID == "" {
   207  			return fmt.Errorf("No SNS subscription with that ARN exists")
   208  		}
   209  
   210  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   211  
   212  		params := &ec2.DescribeSpotInstanceRequestsInput{
   213  			SpotInstanceRequestIds: []*string{&rs.Primary.ID},
   214  		}
   215  		resp, err := conn.DescribeSpotInstanceRequests(params)
   216  
   217  		if err != nil {
   218  			return err
   219  		}
   220  
   221  		if v := len(resp.SpotInstanceRequests); v != 1 {
   222  			return fmt.Errorf("Expected 1 request returned, got %d", v)
   223  		}
   224  
   225  		*sir = *resp.SpotInstanceRequests[0]
   226  
   227  		return nil
   228  	}
   229  }
   230  
   231  func testAccCheckAWSSpotInstanceRequestAttributes(
   232  	sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   233  	return func(s *terraform.State) error {
   234  		if *sir.SpotPrice != "0.050000" {
   235  			return fmt.Errorf("Unexpected spot price: %s", *sir.SpotPrice)
   236  		}
   237  		if *sir.State != "active" {
   238  			return fmt.Errorf("Unexpected request state: %s", *sir.State)
   239  		}
   240  		if *sir.Status.Code != "fulfilled" {
   241  			return fmt.Errorf("Unexpected bid status: %s", *sir.State)
   242  		}
   243  		return nil
   244  	}
   245  }
   246  
   247  func testAccCheckAWSSpotInstanceRequest_InstanceAttributes(
   248  	sir *ec2.SpotInstanceRequest, rInt int) resource.TestCheckFunc {
   249  	return func(s *terraform.State) error {
   250  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   251  		resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{
   252  			InstanceIds: []*string{sir.InstanceId},
   253  		})
   254  		if err != nil {
   255  			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" {
   256  				return fmt.Errorf("Spot Instance not found")
   257  			}
   258  			return err
   259  		}
   260  
   261  		// If nothing was found, then return no state
   262  		if len(resp.Reservations) == 0 {
   263  			return fmt.Errorf("Spot Instance not found")
   264  		}
   265  
   266  		instance := resp.Reservations[0].Instances[0]
   267  
   268  		var sgMatch bool
   269  		for _, s := range instance.SecurityGroups {
   270  			// Hardcoded name for the security group that should be added inside the
   271  			// VPC
   272  			if *s.GroupName == fmt.Sprintf("tf_test_sg_ssh-%d", rInt) {
   273  				sgMatch = true
   274  			}
   275  		}
   276  
   277  		if !sgMatch {
   278  			return fmt.Errorf("Error in matching Spot Instance Security Group, expected 'tf_test_sg_ssh-%d', got %s", rInt, instance.SecurityGroups)
   279  		}
   280  
   281  		return nil
   282  	}
   283  }
   284  
   285  func testAccCheckAWSSpotInstanceRequestAttributesVPC(
   286  	sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   287  	return func(s *terraform.State) error {
   288  		if sir.LaunchSpecification.SubnetId == nil {
   289  			return fmt.Errorf("SubnetID was not passed, but should have been for this instance to belong to a VPC")
   290  		}
   291  		return nil
   292  	}
   293  }
   294  
   295  func testAccAWSSpotInstanceRequestConfig(rInt int) string {
   296  	return fmt.Sprintf(`
   297  	resource "aws_key_pair" "debugging" {
   298  		key_name = "tmp-key-%d"
   299  		public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   300  	}
   301  
   302  	resource "aws_spot_instance_request" "foo" {
   303  		ami = "ami-4fccb37f"
   304  		instance_type = "m1.small"
   305  		key_name = "${aws_key_pair.debugging.key_name}"
   306  
   307  		// base price is $0.044 hourly, so bidding above that should theoretically
   308  		// always fulfill
   309  		spot_price = "0.05"
   310  
   311  		// we wait for fulfillment because we want to inspect the launched instance
   312  		// and verify termination behavior
   313  		wait_for_fulfillment = true
   314  
   315  		tags {
   316  			Name = "terraform-test"
   317  		}
   318  	}`, rInt)
   319  }
   320  
   321  func testAccAWSSpotInstanceRequestConfig_withBlockDuration(rInt int) string {
   322  	return fmt.Sprintf(`
   323  	resource "aws_key_pair" "debugging" {
   324  		key_name = "tmp-key-%d"
   325  		public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   326  	}
   327  
   328  	resource "aws_spot_instance_request" "foo" {
   329  		ami = "ami-4fccb37f"
   330  		instance_type = "m1.small"
   331  		key_name = "${aws_key_pair.debugging.key_name}"
   332  
   333  		// base price is $0.044 hourly, so bidding above that should theoretically
   334  		// always fulfill
   335  		spot_price = "0.05"
   336  
   337  		// we wait for fulfillment because we want to inspect the launched instance
   338  		// and verify termination behavior
   339  		wait_for_fulfillment = true
   340  
   341  		block_duration_minutes = 60
   342  
   343  		tags {
   344  			Name = "terraform-test"
   345  		}
   346  	}`, rInt)
   347  }
   348  
   349  func testAccAWSSpotInstanceRequestConfigVPC(rInt int) string {
   350  	return fmt.Sprintf(`
   351  	resource "aws_vpc" "foo_VPC" {
   352  		cidr_block = "10.1.0.0/16"
   353  	}
   354  
   355  	resource "aws_subnet" "foo_VPC" {
   356  		cidr_block = "10.1.1.0/24"
   357  		vpc_id = "${aws_vpc.foo_VPC.id}"
   358  	}
   359  
   360  	resource "aws_key_pair" "debugging" {
   361  		key_name = "tmp-key-%d"
   362  		public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   363  	}
   364  
   365  	resource "aws_spot_instance_request" "foo_VPC" {
   366  		ami = "ami-4fccb37f"
   367  		instance_type = "m1.small"
   368  		key_name = "${aws_key_pair.debugging.key_name}"
   369  
   370  		// base price is $0.044 hourly, so bidding above that should theoretically
   371  		// always fulfill
   372  		spot_price = "0.05"
   373  
   374  		// VPC settings
   375  		subnet_id = "${aws_subnet.foo_VPC.id}"
   376  
   377  		// we wait for fulfillment because we want to inspect the launched instance
   378  		// and verify termination behavior
   379  		wait_for_fulfillment = true
   380  
   381  		tags {
   382  			Name = "terraform-test-VPC"
   383  		}
   384  	}`, rInt)
   385  }
   386  
   387  func testAccAWSSpotInstanceRequestConfig_SubnetAndSG(rInt int) string {
   388  	return fmt.Sprintf(`
   389  	resource "aws_spot_instance_request" "foo" {
   390  		ami                         = "ami-4fccb37f"
   391  		instance_type               = "m1.small"
   392  		spot_price                  = "0.05"
   393  		wait_for_fulfillment        = true
   394  		subnet_id                   = "${aws_subnet.tf_test_subnet.id}"
   395  		vpc_security_group_ids      = ["${aws_security_group.tf_test_sg_ssh.id}"]
   396  		associate_public_ip_address = true
   397  	}
   398  
   399  	resource "aws_vpc" "default" {
   400  		cidr_block           = "10.0.0.0/16"
   401  		enable_dns_hostnames = true
   402  
   403  		tags {
   404  			Name = "tf_test_vpc"
   405  		}
   406  	}
   407  
   408  	resource "aws_subnet" "tf_test_subnet" {
   409  		vpc_id                  = "${aws_vpc.default.id}"
   410  		cidr_block              = "10.0.0.0/24"
   411  		map_public_ip_on_launch = true
   412  
   413  		tags {
   414  			Name = "tf_test_subnet-%d"
   415  		}
   416  	}
   417  
   418  	resource "aws_security_group" "tf_test_sg_ssh" {
   419  		name        = "tf_test_sg_ssh-%d"
   420  		description = "tf_test_sg_ssh"
   421  		vpc_id      = "${aws_vpc.default.id}"
   422  
   423  		tags {
   424  			Name = "tf_test_sg_ssh-%d"
   425  		}
   426  	}`, rInt, rInt, rInt)
   427  }