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 `