github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/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  		if err == nil {
   139  			if len(resp.SpotInstanceRequests) > 0 {
   140  				return fmt.Errorf("Spot instance request is still here.")
   141  			}
   142  		}
   143  
   144  		// Verify the error is what we expect
   145  		ec2err, ok := err.(awserr.Error)
   146  		if !ok {
   147  			return err
   148  		}
   149  		if ec2err.Code() != "InvalidSpotInstanceRequestID.NotFound" {
   150  			return err
   151  		}
   152  
   153  		// Now check if the associated Spot Instance was also destroyed
   154  		instId := rs.Primary.Attributes["spot_instance_id"]
   155  		instResp, instErr := conn.DescribeInstances(&ec2.DescribeInstancesInput{
   156  			InstanceIds: []*string{aws.String(instId)},
   157  		})
   158  		if instErr == nil {
   159  			if len(instResp.Reservations) > 0 {
   160  				return fmt.Errorf("Instance still exists.")
   161  			}
   162  
   163  			return nil
   164  		}
   165  
   166  		// Verify the error is what we expect
   167  		ec2err, ok = err.(awserr.Error)
   168  		if !ok {
   169  			return err
   170  		}
   171  		if ec2err.Code() != "InvalidInstanceID.NotFound" {
   172  			return err
   173  		}
   174  	}
   175  
   176  	return nil
   177  }
   178  
   179  func testAccCheckAWSSpotInstanceRequestExists(
   180  	n string, sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   181  	return func(s *terraform.State) error {
   182  		rs, ok := s.RootModule().Resources[n]
   183  		if !ok {
   184  			return fmt.Errorf("Not found: %s", n)
   185  		}
   186  
   187  		if rs.Primary.ID == "" {
   188  			return fmt.Errorf("No SNS subscription with that ARN exists")
   189  		}
   190  
   191  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   192  
   193  		params := &ec2.DescribeSpotInstanceRequestsInput{
   194  			SpotInstanceRequestIds: []*string{&rs.Primary.ID},
   195  		}
   196  		resp, err := conn.DescribeSpotInstanceRequests(params)
   197  
   198  		if err != nil {
   199  			return err
   200  		}
   201  
   202  		if v := len(resp.SpotInstanceRequests); v != 1 {
   203  			return fmt.Errorf("Expected 1 request returned, got %d", v)
   204  		}
   205  
   206  		*sir = *resp.SpotInstanceRequests[0]
   207  
   208  		return nil
   209  	}
   210  }
   211  
   212  func testAccCheckAWSSpotInstanceRequestAttributes(
   213  	sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   214  	return func(s *terraform.State) error {
   215  		if *sir.SpotPrice != "0.050000" {
   216  			return fmt.Errorf("Unexpected spot price: %s", *sir.SpotPrice)
   217  		}
   218  		if *sir.State != "active" {
   219  			return fmt.Errorf("Unexpected request state: %s", *sir.State)
   220  		}
   221  		if *sir.Status.Code != "fulfilled" {
   222  			return fmt.Errorf("Unexpected bid status: %s", *sir.State)
   223  		}
   224  		return nil
   225  	}
   226  }
   227  
   228  func testAccCheckAWSSpotInstanceRequest_InstanceAttributes(
   229  	sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   230  	return func(s *terraform.State) error {
   231  		conn := testAccProvider.Meta().(*AWSClient).ec2conn
   232  		resp, err := conn.DescribeInstances(&ec2.DescribeInstancesInput{
   233  			InstanceIds: []*string{sir.InstanceId},
   234  		})
   235  		if err != nil {
   236  			if ec2err, ok := err.(awserr.Error); ok && ec2err.Code() == "InvalidInstanceID.NotFound" {
   237  				return fmt.Errorf("Spot Instance not found")
   238  			}
   239  			return err
   240  		}
   241  
   242  		// If nothing was found, then return no state
   243  		if len(resp.Reservations) == 0 {
   244  			return fmt.Errorf("Spot Instance not found")
   245  		}
   246  
   247  		instance := resp.Reservations[0].Instances[0]
   248  
   249  		var sgMatch bool
   250  		for _, s := range instance.SecurityGroups {
   251  			// Hardcoded name for the security group that should be added inside the
   252  			// VPC
   253  			if *s.GroupName == "tf_test_sg_ssh" {
   254  				sgMatch = true
   255  			}
   256  		}
   257  
   258  		if !sgMatch {
   259  			return fmt.Errorf("Error in matching Spot Instance Security Group, expected 'tf_test_sg_ssh', got %s", instance.SecurityGroups)
   260  		}
   261  
   262  		return nil
   263  	}
   264  }
   265  
   266  func testAccCheckAWSSpotInstanceRequestAttributesVPC(
   267  	sir *ec2.SpotInstanceRequest) resource.TestCheckFunc {
   268  	return func(s *terraform.State) error {
   269  		if sir.LaunchSpecification.SubnetId == nil {
   270  			return fmt.Errorf("SubnetID was not passed, but should have been for this instance to belong to a VPC")
   271  		}
   272  		return nil
   273  	}
   274  }
   275  
   276  const testAccAWSSpotInstanceRequestConfig = `
   277  resource "aws_key_pair" "debugging" {
   278  	key_name = "tmp-key"
   279  	public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   280  }
   281  
   282  resource "aws_spot_instance_request" "foo" {
   283  	ami = "ami-4fccb37f"
   284  	instance_type = "m1.small"
   285  	key_name = "${aws_key_pair.debugging.key_name}"
   286  
   287  	// base price is $0.044 hourly, so bidding above that should theoretically
   288  	// always fulfill
   289  	spot_price = "0.05"
   290  
   291  	// we wait for fulfillment because we want to inspect the launched instance
   292  	// and verify termination behavior
   293  	wait_for_fulfillment = true
   294  
   295  	tags {
   296  		Name = "terraform-test"
   297  	}
   298  }
   299  `
   300  
   301  const testAccAWSSpotInstanceRequestConfig_withBlockDuration = `
   302  resource "aws_key_pair" "debugging" {
   303  	key_name = "tmp-key"
   304  	public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   305  }
   306  
   307  resource "aws_spot_instance_request" "foo" {
   308  	ami = "ami-4fccb37f"
   309  	instance_type = "m1.small"
   310  	key_name = "${aws_key_pair.debugging.key_name}"
   311  
   312  	// base price is $0.044 hourly, so bidding above that should theoretically
   313  	// always fulfill
   314  	spot_price = "0.05"
   315  
   316  	// we wait for fulfillment because we want to inspect the launched instance
   317  	// and verify termination behavior
   318  	wait_for_fulfillment = true
   319  
   320  	block_duration_minutes = 60
   321  
   322  	tags {
   323  		Name = "terraform-test"
   324  	}
   325  }
   326  `
   327  
   328  const testAccAWSSpotInstanceRequestConfigVPC = `
   329  resource "aws_vpc" "foo_VPC" {
   330  	cidr_block = "10.1.0.0/16"
   331  }
   332  
   333  resource "aws_subnet" "foo_VPC" {
   334  	cidr_block = "10.1.1.0/24"
   335  	vpc_id = "${aws_vpc.foo_VPC.id}"
   336  }
   337  
   338  resource "aws_key_pair" "debugging" {
   339  	key_name = "tmp-key"
   340  	public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 phodgson@thoughtworks.com"
   341  }
   342  
   343  resource "aws_spot_instance_request" "foo_VPC" {
   344  	ami = "ami-4fccb37f"
   345  	instance_type = "m1.small"
   346  	key_name = "${aws_key_pair.debugging.key_name}"
   347  
   348  	// base price is $0.044 hourly, so bidding above that should theoretically
   349  	// always fulfill
   350  	spot_price = "0.05"
   351  
   352  	// VPC settings
   353  	subnet_id = "${aws_subnet.foo_VPC.id}"
   354  
   355  	// we wait for fulfillment because we want to inspect the launched instance
   356  	// and verify termination behavior
   357  	wait_for_fulfillment = true
   358  
   359  	tags {
   360  		Name = "terraform-test-VPC"
   361  	}
   362  }
   363  `
   364  
   365  const testAccAWSSpotInstanceRequestConfig_SubnetAndSG = `
   366  resource "aws_spot_instance_request" "foo" {
   367    ami                         = "ami-6f6d635f"
   368    spot_price                  = "0.05"
   369    instance_type               = "t1.micro"
   370    wait_for_fulfillment        = true
   371    subnet_id                   = "${aws_subnet.tf_test_subnet.id}"
   372    vpc_security_group_ids      = ["${aws_security_group.tf_test_sg_ssh.id}"]
   373    associate_public_ip_address = true
   374  }
   375  
   376  resource "aws_vpc" "default" {
   377    cidr_block           = "10.0.0.0/16"
   378    enable_dns_hostnames = true
   379  
   380    tags {
   381      Name = "tf_test_vpc"
   382    }
   383  }
   384  
   385  resource "aws_subnet" "tf_test_subnet" {
   386    vpc_id                  = "${aws_vpc.default.id}"
   387    cidr_block              = "10.0.0.0/24"
   388    map_public_ip_on_launch = true
   389  
   390    tags {
   391      Name = "tf_test_subnet"
   392    }
   393  }
   394  
   395  resource "aws_security_group" "tf_test_sg_ssh" {
   396    name        = "tf_test_sg_ssh"
   397    description = "tf_test_sg_ssh"
   398    vpc_id      = "${aws_vpc.default.id}"
   399  
   400    tags {
   401      Name = "tf_test_sg_ssh"
   402    }
   403  }
   404  `