github.com/gophercloud/gophercloud@v1.11.0/internal/acceptance/openstack/networking/v2/extensions/lbaas_v2/lbaas_v2.go (about) 1 package lbaas_v2 2 3 import ( 4 "fmt" 5 "strings" 6 "testing" 7 8 "github.com/gophercloud/gophercloud" 9 "github.com/gophercloud/gophercloud/internal/acceptance/tools" 10 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/l7policies" 11 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/listeners" 12 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/loadbalancers" 13 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/monitors" 14 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/lbaas_v2/pools" 15 th "github.com/gophercloud/gophercloud/testhelper" 16 ) 17 18 // CreateListener will create a listener for a given load balancer on a random 19 // port with a random name. An error will be returned if the listener could not 20 // be created. 21 func CreateListener(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*listeners.Listener, error) { 22 listenerName := tools.RandomString("TESTACCT-", 8) 23 listenerDescription := tools.RandomString("TESTACCT-DESC-", 8) 24 listenerPort := tools.RandomInt(1, 100) 25 26 t.Logf("Attempting to create listener %s on port %d", listenerName, listenerPort) 27 28 createOpts := listeners.CreateOpts{ 29 Name: listenerName, 30 Description: listenerDescription, 31 LoadbalancerID: lb.ID, 32 Protocol: listeners.ProtocolHTTP, 33 ProtocolPort: listenerPort, 34 } 35 36 listener, err := listeners.Create(client, createOpts).Extract() 37 if err != nil { 38 return listener, err 39 } 40 41 t.Logf("Successfully created listener %s", listenerName) 42 43 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 44 return listener, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 45 } 46 47 th.AssertEquals(t, listener.Name, listenerName) 48 th.AssertEquals(t, listener.Description, listenerDescription) 49 th.AssertEquals(t, listener.Loadbalancers[0].ID, lb.ID) 50 th.AssertEquals(t, listener.Protocol, string(listeners.ProtocolHTTP)) 51 th.AssertEquals(t, listener.ProtocolPort, listenerPort) 52 53 return listener, nil 54 } 55 56 // CreateLoadBalancer will create a load balancer with a random name on a given 57 // subnet. An error will be returned if the loadbalancer could not be created. 58 func CreateLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, subnetID string) (*loadbalancers.LoadBalancer, error) { 59 lbName := tools.RandomString("TESTACCT-", 8) 60 lbDescription := tools.RandomString("TESTACCT-DESC-", 8) 61 62 t.Logf("Attempting to create loadbalancer %s on subnet %s", lbName, subnetID) 63 64 createOpts := loadbalancers.CreateOpts{ 65 Name: lbName, 66 Description: lbDescription, 67 VipSubnetID: subnetID, 68 AdminStateUp: gophercloud.Enabled, 69 } 70 71 lb, err := loadbalancers.Create(client, createOpts).Extract() 72 if err != nil { 73 return lb, err 74 } 75 76 t.Logf("Successfully created loadbalancer %s on subnet %s", lbName, subnetID) 77 t.Logf("Waiting for loadbalancer %s to become active", lbName) 78 79 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 80 return lb, err 81 } 82 83 t.Logf("LoadBalancer %s is active", lbName) 84 85 th.AssertEquals(t, lb.Name, lbName) 86 th.AssertEquals(t, lb.Description, lbDescription) 87 th.AssertEquals(t, lb.VipSubnetID, subnetID) 88 th.AssertEquals(t, lb.AdminStateUp, true) 89 90 return lb, nil 91 } 92 93 // CreateMember will create a member with a random name, port, address, and 94 // weight. An error will be returned if the member could not be created. 95 func CreateMember(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool, subnetID, subnetCIDR string) (*pools.Member, error) { 96 memberName := tools.RandomString("TESTACCT-", 8) 97 memberPort := tools.RandomInt(100, 1000) 98 memberWeight := tools.RandomInt(1, 10) 99 100 cidrParts := strings.Split(subnetCIDR, "/") 101 subnetParts := strings.Split(cidrParts[0], ".") 102 memberAddress := fmt.Sprintf("%s.%s.%s.%d", subnetParts[0], subnetParts[1], subnetParts[2], tools.RandomInt(10, 100)) 103 104 t.Logf("Attempting to create member %s", memberName) 105 106 createOpts := pools.CreateMemberOpts{ 107 Name: memberName, 108 ProtocolPort: memberPort, 109 Weight: &memberWeight, 110 Address: memberAddress, 111 SubnetID: subnetID, 112 } 113 114 t.Logf("Member create opts: %#v", createOpts) 115 116 member, err := pools.CreateMember(client, pool.ID, createOpts).Extract() 117 if err != nil { 118 return member, err 119 } 120 121 t.Logf("Successfully created member %s", memberName) 122 123 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 124 return member, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 125 } 126 127 th.AssertEquals(t, member.Name, memberName) 128 129 return member, nil 130 } 131 132 // CreateMonitor will create a monitor with a random name for a specific pool. 133 // An error will be returned if the monitor could not be created. 134 func CreateMonitor(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer, pool *pools.Pool) (*monitors.Monitor, error) { 135 monitorName := tools.RandomString("TESTACCT-", 8) 136 137 t.Logf("Attempting to create monitor %s", monitorName) 138 139 createOpts := monitors.CreateOpts{ 140 PoolID: pool.ID, 141 Name: monitorName, 142 Delay: 10, 143 Timeout: 5, 144 MaxRetries: 5, 145 Type: monitors.TypePING, 146 } 147 148 monitor, err := monitors.Create(client, createOpts).Extract() 149 if err != nil { 150 return monitor, err 151 } 152 153 t.Logf("Successfully created monitor: %s", monitorName) 154 155 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 156 return monitor, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 157 } 158 159 th.AssertEquals(t, monitor.Name, monitorName) 160 th.AssertEquals(t, monitor.Type, monitors.TypePING) 161 162 return monitor, nil 163 } 164 165 // CreatePool will create a pool with a random name with a specified listener 166 // and loadbalancer. An error will be returned if the pool could not be 167 // created. 168 func CreatePool(t *testing.T, client *gophercloud.ServiceClient, lb *loadbalancers.LoadBalancer) (*pools.Pool, error) { 169 poolName := tools.RandomString("TESTACCT-", 8) 170 poolDescription := tools.RandomString("TESTACCT-DESC-", 8) 171 172 t.Logf("Attempting to create pool %s", poolName) 173 174 createOpts := pools.CreateOpts{ 175 Name: poolName, 176 Description: poolDescription, 177 Protocol: pools.ProtocolHTTP, 178 LoadbalancerID: lb.ID, 179 LBMethod: pools.LBMethodLeastConnections, 180 } 181 182 pool, err := pools.Create(client, createOpts).Extract() 183 if err != nil { 184 return pool, err 185 } 186 187 t.Logf("Successfully created pool %s", poolName) 188 189 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 190 return pool, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 191 } 192 193 th.AssertEquals(t, pool.Name, poolName) 194 th.AssertEquals(t, pool.Description, poolDescription) 195 th.AssertEquals(t, pool.Protocol, string(pools.ProtocolHTTP)) 196 th.AssertEquals(t, pool.Loadbalancers[0].ID, lb.ID) 197 th.AssertEquals(t, pool.LBMethod, string(pools.LBMethodLeastConnections)) 198 199 return pool, nil 200 } 201 202 // CreateL7Policy will create a l7 policy with a random name with a specified listener 203 // and loadbalancer. An error will be returned if the l7 policy could not be 204 // created. 205 func CreateL7Policy(t *testing.T, client *gophercloud.ServiceClient, listener *listeners.Listener, lb *loadbalancers.LoadBalancer) (*l7policies.L7Policy, error) { 206 policyName := tools.RandomString("TESTACCT-", 8) 207 policyDescription := tools.RandomString("TESTACCT-DESC-", 8) 208 209 t.Logf("Attempting to create l7 policy %s on the %s listener ID", policyName, listener.ID) 210 211 createOpts := l7policies.CreateOpts{ 212 Name: policyName, 213 Description: policyDescription, 214 ListenerID: listener.ID, 215 Action: l7policies.ActionRedirectToURL, 216 RedirectURL: "http://www.example.com", 217 } 218 219 policy, err := l7policies.Create(client, createOpts).Extract() 220 if err != nil { 221 return policy, err 222 } 223 224 t.Logf("Successfully created l7 policy %s", policyName) 225 226 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 227 return policy, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 228 } 229 230 th.AssertEquals(t, policy.Name, policyName) 231 th.AssertEquals(t, policy.Description, policyDescription) 232 th.AssertEquals(t, policy.ListenerID, listener.ID) 233 th.AssertEquals(t, policy.Action, string(l7policies.ActionRedirectToURL)) 234 th.AssertEquals(t, policy.RedirectURL, "http://www.example.com") 235 236 return policy, nil 237 } 238 239 // CreateL7Rule creates a l7 rule for specified l7 policy. 240 func CreateL7Rule(t *testing.T, client *gophercloud.ServiceClient, policyID string, lb *loadbalancers.LoadBalancer) (*l7policies.Rule, error) { 241 t.Logf("Attempting to create l7 rule for policy %s", policyID) 242 243 createOpts := l7policies.CreateRuleOpts{ 244 RuleType: l7policies.TypePath, 245 CompareType: l7policies.CompareTypeStartWith, 246 Value: "/api", 247 } 248 249 rule, err := l7policies.CreateRule(client, policyID, createOpts).Extract() 250 if err != nil { 251 return rule, err 252 } 253 254 t.Logf("Successfully created l7 rule for policy %s", policyID) 255 256 if err := WaitForLoadBalancerState(client, lb.ID, "ACTIVE"); err != nil { 257 return rule, fmt.Errorf("Timed out waiting for loadbalancer to become active: %s", err) 258 } 259 260 th.AssertEquals(t, rule.RuleType, string(l7policies.TypePath)) 261 th.AssertEquals(t, rule.CompareType, string(l7policies.CompareTypeStartWith)) 262 th.AssertEquals(t, rule.Value, "/api") 263 264 return rule, nil 265 } 266 267 // DeleteL7Policy will delete a specified l7 policy. A fatal error will occur if 268 // the l7 policy could not be deleted. This works best when used as a deferred 269 // function. 270 func DeleteL7Policy(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID string) { 271 t.Logf("Attempting to delete l7 policy %s", policyID) 272 273 if err := l7policies.Delete(client, policyID).ExtractErr(); err != nil { 274 if _, ok := err.(gophercloud.ErrDefault404); !ok { 275 t.Fatalf("Unable to delete l7 policy: %v", err) 276 } 277 } 278 279 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 280 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 281 } 282 283 t.Logf("Successfully deleted l7 policy %s", policyID) 284 } 285 286 // DeleteL7Rule will delete a specified l7 rule. A fatal error will occur if 287 // the l7 rule could not be deleted. This works best when used as a deferred 288 // function. 289 func DeleteL7Rule(t *testing.T, client *gophercloud.ServiceClient, lbID, policyID, ruleID string) { 290 t.Logf("Attempting to delete l7 rule %s", ruleID) 291 292 if err := l7policies.DeleteRule(client, policyID, ruleID).ExtractErr(); err != nil { 293 if _, ok := err.(gophercloud.ErrDefault404); !ok { 294 t.Fatalf("Unable to delete l7 rule: %v", err) 295 } 296 } 297 298 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 299 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 300 } 301 302 t.Logf("Successfully deleted l7 rule %s", ruleID) 303 } 304 305 // DeleteListener will delete a specified listener. A fatal error will occur if 306 // the listener could not be deleted. This works best when used as a deferred 307 // function. 308 func DeleteListener(t *testing.T, client *gophercloud.ServiceClient, lbID, listenerID string) { 309 t.Logf("Attempting to delete listener %s", listenerID) 310 311 if err := listeners.Delete(client, listenerID).ExtractErr(); err != nil { 312 if _, ok := err.(gophercloud.ErrDefault404); !ok { 313 t.Fatalf("Unable to delete listener: %v", err) 314 } 315 } 316 317 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 318 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 319 } 320 321 t.Logf("Successfully deleted listener %s", listenerID) 322 } 323 324 // DeleteMember will delete a specified member. A fatal error will occur if the 325 // member could not be deleted. This works best when used as a deferred 326 // function. 327 func DeleteMember(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID, memberID string) { 328 t.Logf("Attempting to delete member %s", memberID) 329 330 if err := pools.DeleteMember(client, poolID, memberID).ExtractErr(); err != nil { 331 if _, ok := err.(gophercloud.ErrDefault404); !ok { 332 t.Fatalf("Unable to delete member: %s", memberID) 333 } 334 } 335 336 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 337 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 338 } 339 340 t.Logf("Successfully deleted member %s", memberID) 341 } 342 343 // DeleteLoadBalancer will delete a specified loadbalancer. A fatal error will 344 // occur if the loadbalancer could not be deleted. This works best when used 345 // as a deferred function. 346 func DeleteLoadBalancer(t *testing.T, client *gophercloud.ServiceClient, lbID string) { 347 t.Logf("Attempting to delete loadbalancer %s", lbID) 348 349 if err := loadbalancers.Delete(client, lbID).ExtractErr(); err != nil { 350 if _, ok := err.(gophercloud.ErrDefault404); !ok { 351 t.Fatalf("Unable to delete loadbalancer: %v", err) 352 } 353 } 354 355 t.Logf("Waiting for loadbalancer %s to delete", lbID) 356 357 if err := WaitForLoadBalancerState(client, lbID, "DELETED"); err != nil { 358 t.Fatalf("Loadbalancer did not delete in time: %s", err) 359 } 360 361 t.Logf("Successfully deleted loadbalancer %s", lbID) 362 } 363 364 // DeleteMonitor will delete a specified monitor. A fatal error will occur if 365 // the monitor could not be deleted. This works best when used as a deferred 366 // function. 367 func DeleteMonitor(t *testing.T, client *gophercloud.ServiceClient, lbID, monitorID string) { 368 t.Logf("Attempting to delete monitor %s", monitorID) 369 370 if err := monitors.Delete(client, monitorID).ExtractErr(); err != nil { 371 if _, ok := err.(gophercloud.ErrDefault404); !ok { 372 t.Fatalf("Unable to delete monitor: %v", err) 373 } 374 } 375 376 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 377 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 378 } 379 380 t.Logf("Successfully deleted monitor %s", monitorID) 381 } 382 383 // DeletePool will delete a specified pool. A fatal error will occur if the 384 // pool could not be deleted. This works best when used as a deferred function. 385 func DeletePool(t *testing.T, client *gophercloud.ServiceClient, lbID, poolID string) { 386 t.Logf("Attempting to delete pool %s", poolID) 387 388 if err := pools.Delete(client, poolID).ExtractErr(); err != nil { 389 if _, ok := err.(gophercloud.ErrDefault404); !ok { 390 t.Fatalf("Unable to delete pool: %v", err) 391 } 392 } 393 394 if err := WaitForLoadBalancerState(client, lbID, "ACTIVE"); err != nil { 395 t.Fatalf("Timed out waiting for loadbalancer to become active: %s", err) 396 } 397 398 t.Logf("Successfully deleted pool %s", poolID) 399 } 400 401 // WaitForLoadBalancerState will wait until a loadbalancer reaches a given state. 402 func WaitForLoadBalancerState(client *gophercloud.ServiceClient, lbID, status string) error { 403 return tools.WaitFor(func() (bool, error) { 404 current, err := loadbalancers.Get(client, lbID).Extract() 405 if err != nil { 406 if httpStatus, ok := err.(gophercloud.ErrDefault404); ok { 407 if httpStatus.Actual == 404 { 408 if status == "DELETED" { 409 return true, nil 410 } 411 } 412 } 413 return false, err 414 } 415 416 if current.ProvisioningStatus == status { 417 return true, nil 418 } 419 420 if current.ProvisioningStatus == "ERROR" { 421 return false, fmt.Errorf("Load balancer is in ERROR state") 422 } 423 424 return false, nil 425 }) 426 }