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