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 `