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