github.com/leeclow-ops/gophercloud@v1.2.1/acceptance/openstack/loadbalancer/v2/loadbalancer.go (about) 1 package v2 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/leeclow-ops/gophercloud" 9 "github.com/leeclow-ops/gophercloud/acceptance/clients" 10 "github.com/leeclow-ops/gophercloud/acceptance/tools" 11 "github.com/leeclow-ops/gophercloud/openstack/loadbalancer/v2/l7policies" 12 "github.com/leeclow-ops/gophercloud/openstack/loadbalancer/v2/listeners" 13 "github.com/leeclow-ops/gophercloud/openstack/loadbalancer/v2/loadbalancers" 14 "github.com/leeclow-ops/gophercloud/openstack/loadbalancer/v2/monitors" 15 "github.com/leeclow-ops/gophercloud/openstack/loadbalancer/v2/pools" 16 th "github.com/leeclow-ops/gophercloud/testhelper" 17 ) 18 19 // CreateListener will create a listener for a given load balancer on a random 20 // port with a random name. An error will be returned if the listener could not 21 // be created. 22 func CreateListener(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*listeners.Listener, error) { 23 listenerName := tools.RandomString("TESTACCT-", 8) 24 listenerDescription := tools.RandomString("TESTACCT-DESC-", 8) 25 listenerPort := tools.RandomInt(1, 100) 26 27 t.Logf("Attempting to create listener %s on port %d", listenerName, listenerPort) 28 29 createOpts := listeners.CreateOpts{ 30 Name: listenerName, 31 Description: listenerDescription, 32 LoadbalancerID: lb.ID, 33 Protocol: listeners.ProtocolTCP, 34 ProtocolPort: listenerPort, 35 } 36 37 listener, err := listeners.Create(client, createOpts).Extract() 38 if err != nil { 39 return listener, err 40 } 41 42 t.Logf("Successfully created listener %s", listenerName) 43 44 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 45 return listener, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 46 } 47 48 th.AssertEquals(t, listener.Name, listenerName) 49 th.AssertEquals(t, listener.Description, listenerDescription) 50 th.AssertEquals(t, listener.Loadbalancers[0].ID, lb.ID) 51 th.AssertEquals(t, listener.Protocol, string(listeners.ProtocolTCP)) 52 th.AssertEquals(t, listener.ProtocolPort, listenerPort) 53 54 return listener, nil 55 } 56 57 // CreateListenerHTTP will create an HTTP-based listener for a given load 58 // balancer on a random port with a random name. An error will be returned 59 // if the listener could not be created. 60 func CreateListenerHTTP(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*listeners.Listener, error) { 61 tlsVersions := []listeners.TLSVersion{} 62 tlsVersionsExp := []string(nil) 63 listenerName := tools.RandomString("TESTACCT-", 8) 64 listenerDescription := tools.RandomString("TESTACCT-DESC-", 8) 65 listenerPort := tools.RandomInt(1, 100) 66 67 t.Logf("Attempting to create listener %s on port %d", listenerName, listenerPort) 68 69 headers := map[string]string{ 70 "X-Forwarded-For": "true", 71 } 72 73 // tls_version is only supported in microversion v2.17 introduced in victoria 74 if clients.IsReleasesAbove(t, "stable/ussuri") { 75 tlsVersions = []listeners.TLSVersion{"TLSv1.2", "TLSv1.3"} 76 tlsVersionsExp = []string{"TLSv1.2", "TLSv1.3"} 77 } 78 79 createOpts := listeners.CreateOpts{ 80 Name: listenerName, 81 Description: listenerDescription, 82 LoadbalancerID: lb.ID, 83 InsertHeaders: headers, 84 Protocol: listeners.ProtocolHTTP, 85 ProtocolPort: listenerPort, 86 TLSVersions: tlsVersions, 87 } 88 89 listener, err := listeners.Create(client, createOpts).Extract() 90 if err != nil { 91 return listener, err 92 } 93 94 t.Logf("Successfully created listener %s", listenerName) 95 96 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 97 return listener, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 98 } 99 100 th.AssertEquals(t, listener.Name, listenerName) 101 th.AssertEquals(t, listener.Description, listenerDescription) 102 th.AssertEquals(t, listener.Loadbalancers[0].ID, lb.ID) 103 th.AssertEquals(t, listener.Protocol, string(listeners.ProtocolHTTP)) 104 th.AssertEquals(t, listener.ProtocolPort, listenerPort) 105 th.AssertDeepEquals(t, listener.InsertHeaders, headers) 106 th.AssertDeepEquals(t, listener.TLSVersions, tlsVersionsExp) 107 108 return listener, nil 109 } 110 111 // CreateLoadBalancer will create a load balancer with a random name on a given 112 // subnet. An error will be returned if the loadbalancer could not be created. 113 func CreateLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, subnetID string, tags []string, policyID string) (*loadbalancers.LoadBalancer, error) { 114 lbName := tools.RandomString("TESTACCT-", 8) 115 lbDescription := tools.RandomString("TESTACCT-DESC-", 8) 116 117 t.Logf("Attempting to create loadbalancer %s on subnet %s", lbName, subnetID) 118 119 createOpts := loadbalancers.CreateOpts{ 120 Name: lbName, 121 Description: lbDescription, 122 VipSubnetID: subnetID, 123 AdminStateUp: gophercloud.Enabled, 124 } 125 if len(tags) > 0 { 126 createOpts.Tags = tags 127 } 128 129 if len(policyID) > 0 { 130 createOpts.VipQosPolicyID = policyID 131 } 132 133 lb, err := loadbalancers.Create(client, createOpts).Extract() 134 if err != nil { 135 return lb, err 136 } 137 138 t.Logf("Successfully created loadbalancer %s on subnet %s", lbName, subnetID) 139 t.Logf("Waiting for loadbalancer %s to become active", lbName) 140 141 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 142 return lb, err 143 } 144 145 t.Logf("LoadBalancer %s is active", lbName) 146 147 th.AssertEquals(t, lb.Name, lbName) 148 th.AssertEquals(t, lb.Description, lbDescription) 149 th.AssertEquals(t, lb.VipSubnetID, subnetID) 150 th.AssertEquals(t, lb.AdminStateUp, true) 151 152 if len(tags) > 0 { 153 th.AssertDeepEquals(t, lb.Tags, tags) 154 } 155 156 if len(policyID) > 0 { 157 th.AssertEquals(t, lb.VipQosPolicyID, policyID) 158 } 159 160 return lb, nil 161 } 162 163 // CreateLoadBalancerFullyPopulated will create a fully populated load balancer with a random name on a given 164 // subnet. It will contain a listener, l7policy, l7rule, pool, member and health monitor. 165 // An error will be returned if the loadbalancer could not be created. 166 func CreateLoadBalancerFullyPopulated(t *testing.T, client *gophercloud.ServiceClient, subnetID string, tags []string) (*loadbalancers.LoadBalancer, error) { 167 lbName := tools.RandomString("TESTACCT-", 8) 168 lbDescription := tools.RandomString("TESTACCT-DESC-", 8) 169 listenerName := tools.RandomString("TESTACCT-", 8) 170 listenerDescription := tools.RandomString("TESTACCT-DESC-", 8) 171 listenerPort := tools.RandomInt(1, 100) 172 policyName := tools.RandomString("TESTACCT-", 8) 173 policyDescription := tools.RandomString("TESTACCT-DESC-", 8) 174 poolName := tools.RandomString("TESTACCT-", 8) 175 poolDescription := tools.RandomString("TESTACCT-DESC-", 8) 176 memberName := tools.RandomString("TESTACCT-", 8) 177 memberPort := tools.RandomInt(100, 1000) 178 memberWeight := tools.RandomInt(1, 10) 179 180 t.Logf("Attempting to create fully populated loadbalancer %s on subnet %s which contains listener: %s, l7Policy: %s, pool %s, member %s", 181 lbName, subnetID, listenerName, policyName, poolName, memberName) 182 183 createOpts := loadbalancers.CreateOpts{ 184 Name: lbName, 185 Description: lbDescription, 186 VipSubnetID: subnetID, 187 AdminStateUp: gophercloud.Enabled, 188 Listeners: []listeners.CreateOpts{{ 189 Name: listenerName, 190 Description: listenerDescription, 191 Protocol: listeners.ProtocolHTTP, 192 ProtocolPort: listenerPort, 193 DefaultPool: &pools.CreateOpts{ 194 Name: poolName, 195 Description: poolDescription, 196 Protocol: pools.ProtocolHTTP, 197 LBMethod: pools.LBMethodLeastConnections, 198 Members: []pools.BatchUpdateMemberOpts{{ 199 Name: &memberName, 200 ProtocolPort: memberPort, 201 Weight: &memberWeight, 202 Address: "1.2.3.4", 203 SubnetID: &subnetID, 204 }}, 205 Monitor: &monitors.CreateOpts{ 206 Delay: 10, 207 Timeout: 5, 208 MaxRetries: 5, 209 MaxRetriesDown: 4, 210 Type: monitors.TypeHTTP, 211 }, 212 }, 213 L7Policies: []l7policies.CreateOpts{{ 214 Name: policyName, 215 Description: policyDescription, 216 Action: l7policies.ActionRedirectToURL, 217 RedirectURL: "http://www.example.com", 218 Rules: []l7policies.CreateRuleOpts{{ 219 RuleType: l7policies.TypePath, 220 CompareType: l7policies.CompareTypeStartWith, 221 Value: "/api", 222 }}, 223 }}, 224 }}, 225 } 226 if len(tags) > 0 { 227 createOpts.Tags = tags 228 } 229 230 lb, err := loadbalancers.Create(client, createOpts).Extract() 231 if err != nil { 232 return lb, err 233 } 234 235 t.Logf("Successfully created loadbalancer %s on subnet %s", lbName, subnetID) 236 t.Logf("Waiting for loadbalancer %s to become active", lbName) 237 238 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 239 return lb, err 240 } 241 242 t.Logf("LoadBalancer %s is active", lbName) 243 244 th.AssertEquals(t, lb.Name, lbName) 245 th.AssertEquals(t, lb.Description, lbDescription) 246 th.AssertEquals(t, lb.VipSubnetID, subnetID) 247 th.AssertEquals(t, lb.AdminStateUp, true) 248 249 th.AssertEquals(t, len(lb.Listeners), 1) 250 th.AssertEquals(t, lb.Listeners[0].Name, listenerName) 251 th.AssertEquals(t, lb.Listeners[0].Description, listenerDescription) 252 th.AssertEquals(t, lb.Listeners[0].ProtocolPort, listenerPort) 253 254 th.AssertEquals(t, len(lb.Listeners[0].L7Policies), 1) 255 th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Name, policyName) 256 th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Description, policyDescription) 257 th.AssertEquals(t, lb.Listeners[0].L7Policies[0].Description, policyDescription) 258 th.AssertEquals(t, len(lb.Listeners[0].L7Policies[0].Rules), 1) 259 260 th.AssertEquals(t, len(lb.Pools), 1) 261 th.AssertEquals(t, lb.Pools[0].Name, poolName) 262 th.AssertEquals(t, lb.Pools[0].Description, poolDescription) 263 264 th.AssertEquals(t, len(lb.Pools[0].Members), 1) 265 th.AssertEquals(t, lb.Pools[0].Members[0].Name, memberName) 266 th.AssertEquals(t, lb.Pools[0].Members[0].ProtocolPort, memberPort) 267 th.AssertEquals(t, lb.Pools[0].Members[0].Weight, memberWeight) 268 269 if len(tags) > 0 { 270 th.AssertDeepEquals(t, lb.Tags, tags) 271 } 272 273 return lb, nil 274 } 275 276 // CreateMember will create a member with a random name, port, address, and 277 // weight. An error will be returned if the member could not be created. 278 func CreateMember(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool, subnetID, subnetCIDR string) (*pools.Member, error) { 279 memberName := tools.RandomString("TESTACCT-", 8) 280 memberPort := tools.RandomInt(100, 1000) 281 memberWeight := tools.RandomInt(1, 10) 282 283 cidrParts := strings.Split(subnetCIDR, "/") 284 subnetParts := strings.Split(cidrParts[0], ".") 285 memberAddress := fmt.Sprintf("%s.%s.%s.%d", subnetParts[0], subnetParts[1], subnetParts[2], tools.RandomInt(10, 100)) 286 287 t.Logf("Attempting to create member %s", memberName) 288 289 createOpts := pools.CreateMemberOpts{ 290 Name: memberName, 291 ProtocolPort: memberPort, 292 Weight: &memberWeight, 293 Address: memberAddress, 294 SubnetID: subnetID, 295 } 296 297 t.Logf("Member create opts: %#v", createOpts) 298 299 member, err := pools.CreateMember(client, pool.ID, createOpts).Extract() 300 if err != nil { 301 return member, err 302 } 303 304 t.Logf("Successfully created member %s", memberName) 305 306 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 307 return member, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 308 } 309 310 th.AssertEquals(t, member.Name, memberName) 311 312 return member, nil 313 } 314 315 // CreateMonitor will create a monitor with a random name for a specific pool. 316 // An error will be returned if the monitor could not be created. 317 func CreateMonitor(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool) (*monitors.Monitor, error) { 318 monitorName := tools.RandomString("TESTACCT-", 8) 319 320 t.Logf("Attempting to create monitor %s", monitorName) 321 322 createOpts := monitors.CreateOpts{ 323 PoolID: pool.ID, 324 Name: monitorName, 325 Delay: 10, 326 Timeout: 5, 327 MaxRetries: 5, 328 MaxRetriesDown: 4, 329 Type: monitors.TypePING, 330 } 331 332 monitor, err := monitors.Create(client, createOpts).Extract() 333 if err != nil { 334 return monitor, err 335 } 336 337 t.Logf("Successfully created monitor: %s", monitorName) 338 339 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 340 return monitor, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 341 } 342 343 th.AssertEquals(t, monitor.Name, monitorName) 344 th.AssertEquals(t, monitor.Type, monitors.TypePING) 345 th.AssertEquals(t, monitor.Delay, 10) 346 th.AssertEquals(t, monitor.Timeout, 5) 347 th.AssertEquals(t, monitor.MaxRetries, 5) 348 th.AssertEquals(t, monitor.MaxRetriesDown, 4) 349 350 return monitor, nil 351 } 352 353 // CreatePool will create a pool with a random name with a specified listener 354 // and loadbalancer. An error will be returned if the pool could not be 355 // created. 356 func CreatePool(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*pools.Pool, error) { 357 poolName := tools.RandomString("TESTACCT-", 8) 358 poolDescription := tools.RandomString("TESTACCT-DESC-", 8) 359 360 t.Logf("Attempting to create pool %s", poolName) 361 362 createOpts := pools.CreateOpts{ 363 Name: poolName, 364 Description: poolDescription, 365 Protocol: pools.ProtocolTCP, 366 LoadbalancerID: lb.ID, 367 LBMethod: pools.LBMethodLeastConnections, 368 } 369 370 pool, err := pools.Create(client, createOpts).Extract() 371 if err != nil { 372 return pool, err 373 } 374 375 t.Logf("Successfully created pool %s", poolName) 376 377 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 378 return pool, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 379 } 380 381 th.AssertEquals(t, pool.Name, poolName) 382 th.AssertEquals(t, pool.Description, poolDescription) 383 th.AssertEquals(t, pool.Protocol, string(pools.ProtocolTCP)) 384 th.AssertEquals(t, pool.Loadbalancers[0].ID, lb.ID) 385 th.AssertEquals(t, pool.LBMethod, string(pools.LBMethodLeastConnections)) 386 387 return pool, nil 388 } 389 390 // CreatePoolHTTP will create an HTTP-based pool with a random name with a 391 // specified listener and loadbalancer. An error will be returned if the pool 392 // could not be created. 393 func CreatePoolHTTP(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*pools.Pool, error) { 394 poolName := tools.RandomString("TESTACCT-", 8) 395 poolDescription := tools.RandomString("TESTACCT-DESC-", 8) 396 397 t.Logf("Attempting to create pool %s", poolName) 398 399 createOpts := pools.CreateOpts{ 400 Name: poolName, 401 Description: poolDescription, 402 Protocol: pools.ProtocolHTTP, 403 LoadbalancerID: lb.ID, 404 LBMethod: pools.LBMethodLeastConnections, 405 } 406 407 pool, err := pools.Create(client, createOpts).Extract() 408 if err != nil { 409 return pool, err 410 } 411 412 t.Logf("Successfully created pool %s", poolName) 413 414 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 415 return pool, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 416 } 417 418 th.AssertEquals(t, pool.Name, poolName) 419 th.AssertEquals(t, pool.Description, poolDescription) 420 th.AssertEquals(t, pool.Protocol, string(pools.ProtocolHTTP)) 421 th.AssertEquals(t, pool.Loadbalancers[0].ID, lb.ID) 422 th.AssertEquals(t, pool.LBMethod, string(pools.LBMethodLeastConnections)) 423 424 return pool, nil 425 } 426 427 // CreateL7Policy will create a l7 policy with a random name with a specified listener 428 // and loadbalancer. An error will be returned if the l7 policy could not be 429 // created. 430 func CreateL7Policy(t *testing.T, client *gophercloud.ServiceClient, listener *listeners.Listener, lb *loadbalancers.LoadBalancer) (*l7policies.L7Policy, error) { 431 policyName := tools.RandomString("TESTACCT-", 8) 432 policyDescription := tools.RandomString("TESTACCT-DESC-", 8) 433 434 t.Logf("Attempting to create l7 policy %s", policyName) 435 436 createOpts := l7policies.CreateOpts{ 437 Name: policyName, 438 Description: policyDescription, 439 ListenerID: listener.ID, 440 Action: l7policies.ActionRedirectToURL, 441 RedirectURL: "http://www.example.com", 442 } 443 444 policy, err := l7policies.Create(client, createOpts).Extract() 445 if err != nil { 446 return policy, err 447 } 448 449 t.Logf("Successfully created l7 policy %s", policyName) 450 451 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 452 return policy, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 453 } 454 455 th.AssertEquals(t, policy.Name, policyName) 456 th.AssertEquals(t, policy.Description, policyDescription) 457 th.AssertEquals(t, policy.ListenerID, listener.ID) 458 th.AssertEquals(t, policy.Action, string(l7policies.ActionRedirectToURL)) 459 th.AssertEquals(t, policy.RedirectURL, "http://www.example.com") 460 461 return policy, nil 462 } 463 464 // CreateL7Rule creates a l7 rule for specified l7 policy. 465 func CreateL7Rule(t *testing.T, client *gophercloud.ServiceClient, policyID string, lb *loadbalancers.LoadBalancer) (*l7policies.Rule, error) { 466 t.Logf("Attempting to create l7 rule for policy %s", policyID) 467 468 createOpts := l7policies.CreateRuleOpts{ 469 RuleType: l7policies.TypePath, 470 CompareType: l7policies.CompareTypeStartWith, 471 Value: "/api", 472 } 473 474 rule, err := l7policies.CreateRule(client, policyID, createOpts).Extract() 475 if err != nil { 476 return rule, err 477 } 478 479 t.Logf("Successfully created l7 rule for policy %s", policyID) 480 481 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 482 return rule, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 483 } 484 485 th.AssertEquals(t, rule.RuleType, string(l7policies.TypePath)) 486 th.AssertEquals(t, rule.CompareType, string(l7policies.CompareTypeStartWith)) 487 th.AssertEquals(t, rule.Value, "/api") 488 489 return rule, nil 490 } 491 492 // DeleteL7Policy will delete a specified l7 policy. A fatal error will occur if 493 // the l7 policy could not be deleted. This works best when used as a deferred 494 // function. 495 func DeleteL7Policy(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID string) { 496 t.Logf("Attempting to delete l7 policy %s", policyID) 497 498 if err := l7policies.Delete(client, policyID).ExtractErr(); err != nil { 499 if _, ok := err.(gophercloud.ErrDefault404); !ok { 500 t.Fatalf("Unable to delete l7 policy: %v", err) 501 } 502 } 503 504 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 505 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 506 } 507 508 t.Logf("Successfully deleted l7 policy %s", policyID) 509 } 510 511 // DeleteL7Rule will delete a specified l7 rule. A fatal error will occur if 512 // the l7 rule could not be deleted. This works best when used as a deferred 513 // function. 514 func DeleteL7Rule(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID, ruleID string) { 515 t.Logf("Attempting to delete l7 rule %s", ruleID) 516 517 if err := l7policies.DeleteRule(client, policyID, ruleID).ExtractErr(); err != nil { 518 if _, ok := err.(gophercloud.ErrDefault404); !ok { 519 t.Fatalf("Unable to delete l7 rule: %v", err) 520 } 521 } 522 523 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 524 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 525 } 526 527 t.Logf("Successfully deleted l7 rule %s", ruleID) 528 } 529 530 // DeleteListener will delete a specified listener. A fatal error will occur if 531 // the listener could not be deleted. This works best when used as a deferred 532 // function. 533 func DeleteListener(t *testing.T, client *gophercloud.ServiceClient, lbID, listenerID string) { 534 t.Logf("Attempting to delete listener %s", listenerID) 535 536 if err := listeners.Delete(client, listenerID).ExtractErr(); err != nil { 537 if _, ok := err.(gophercloud.ErrDefault404); !ok { 538 t.Fatalf("Unable to delete listener: %v", err) 539 } 540 } 541 542 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 543 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 544 } 545 546 t.Logf("Successfully deleted listener %s", listenerID) 547 } 548 549 // DeleteMember will delete a specified member. A fatal error will occur if the 550 // member could not be deleted. This works best when used as a deferred 551 // function. 552 func DeleteMember(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID, memberID string) { 553 t.Logf("Attempting to delete member %s", memberID) 554 555 if err := pools.DeleteMember(client, poolID, memberID).ExtractErr(); err != nil { 556 if _, ok := err.(gophercloud.ErrDefault404); !ok { 557 t.Fatalf("Unable to delete member: %s", memberID) 558 } 559 } 560 561 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 562 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 563 } 564 565 t.Logf("Successfully deleted member %s", memberID) 566 } 567 568 // DeleteLoadBalancer will delete a specified loadbalancer. A fatal error will 569 // occur if the loadbalancer could not be deleted. This works best when used 570 // as a deferred function. 571 func DeleteLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, lbID string) { 572 t.Logf("Attempting to delete loadbalancer %s", lbID) 573 574 deleteOpts := loadbalancers.DeleteOpts{ 575 Cascade: false, 576 } 577 578 if err := loadbalancers.Delete(client, lbID, deleteOpts).ExtractErr(); err != nil { 579 if _, ok := err.(gophercloud.ErrDefault404); !ok { 580 t.Fatalf("Unable to delete loadbalancer: %v", err) 581 } 582 } 583 584 t.Logf("Waiting for loadbalancer %s to delete", lbID) 585 586 if err := WaitForLoadBalancerState(client, lbID, "DELETED"); err != nil { 587 t.Fatalf("Loadbalancer did not delete in time: %s", err) 588 } 589 590 t.Logf("Successfully deleted loadbalancer %s", lbID) 591 } 592 593 // CascadeDeleteLoadBalancer will perform a cascading delete on a loadbalancer. 594 // A fatal error will occur if the loadbalancer could not be deleted. This works 595 // best when used as a deferred function. 596 func CascadeDeleteLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, lbID string) { 597 t.Logf("Attempting to cascade delete loadbalancer %s", lbID) 598 599 deleteOpts := loadbalancers.DeleteOpts{ 600 Cascade: true, 601 } 602 603 if err := loadbalancers.Delete(client, lbID, deleteOpts).ExtractErr(); err != nil { 604 t.Fatalf("Unable to cascade delete loadbalancer: %v", err) 605 } 606 607 t.Logf("Waiting for loadbalancer %s to cascade delete", lbID) 608 609 if err := WaitForLoadBalancerState(client, lbID, "DELETED"); err != nil { 610 t.Fatalf("Loadbalancer did not delete in time.") 611 } 612 613 t.Logf("Successfully deleted loadbalancer %s", lbID) 614 } 615 616 // DeleteMonitor will delete a specified monitor. A fatal error will occur if 617 // the monitor could not be deleted. This works best when used as a deferred 618 // function. 619 func DeleteMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID, monitorID string) { 620 t.Logf("Attempting to delete monitor %s", monitorID) 621 622 if err := monitors.Delete(client, monitorID).ExtractErr(); err != nil { 623 if _, ok := err.(gophercloud.ErrDefault404); !ok { 624 t.Fatalf("Unable to delete monitor: %v", err) 625 } 626 } 627 628 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 629 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 630 } 631 632 t.Logf("Successfully deleted monitor %s", monitorID) 633 } 634 635 // DeletePool will delete a specified pool. A fatal error will occur if the 636 // pool could not be deleted. This works best when used as a deferred function. 637 func DeletePool(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID string) { 638 t.Logf("Attempting to delete pool %s", poolID) 639 640 if err := pools.Delete(client, poolID).ExtractErr(); err != nil { 641 if _, ok := err.(gophercloud.ErrDefault404); !ok { 642 t.Fatalf("Unable to delete pool: %v", err) 643 } 644 } 645 646 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 647 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 648 } 649 650 t.Logf("Successfully deleted pool %s", poolID) 651 } 652 653 // WaitForLoadBalancerState will wait until a loadbalancer reaches a given state. 654 func WaitForLoadBalancerState(client *gophercloud.ServiceClient, lbID, status string) error { 655 return tools.WaitFor(func() (bool, error) { 656 current, err := loadbalancers.Get(client, lbID).Extract() 657 if err != nil { 658 if httpStatus, ok := err.(gophercloud.ErrDefault404); ok { 659 if httpStatus.Actual == 404 { 660 if status == "DELETED" { 661 return true, nil 662 } 663 } 664 } 665 return false, err 666 } 667 668 if current.ProvisioningStatus == status { 669 return true, nil 670 } 671 672 if current.ProvisioningStatus == "ERROR" { 673 return false, fmt.Errorf("Load balancer is in ERROR state") 674 } 675 676 return false, nil 677 }) 678 }