github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/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 }