/acceptance/openstack/networking/v2/extensions/lbaas_v2/lbaas_v2.go

https://github.com/gophercloud/gophercloud · Go · 426 lines · 296 code · 93 blank · 37 comment · 74 complexity · 2023bdcbdaa255f2bd7b684959c12835 MD5 · raw file

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