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