/vendor/github.com/gophercloud/gophercloud/acceptance/openstack/loadbalancer/v2/loadbalancer.go

https://github.com/cnych/opdemo · Go · 463 lines · 321 code · 102 blank · 40 comment · 80 complexity · b91c7e257755bedff208a9f773bdeea1 MD5 · raw file

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