load_balancing.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. package cloudflare
  2. import (
  3. "encoding/json"
  4. "time"
  5. "github.com/pkg/errors"
  6. )
  7. // LoadBalancerPool represents a load balancer pool's properties.
  8. type LoadBalancerPool struct {
  9. ID string `json:"id,omitempty"`
  10. CreatedOn *time.Time `json:"created_on,omitempty"`
  11. ModifiedOn *time.Time `json:"modified_on,omitempty"`
  12. Description string `json:"description"`
  13. Name string `json:"name"`
  14. Enabled bool `json:"enabled"`
  15. MinimumOrigins int `json:"minimum_origins,omitempty"`
  16. Monitor string `json:"monitor,omitempty"`
  17. Origins []LoadBalancerOrigin `json:"origins"`
  18. NotificationEmail string `json:"notification_email,omitempty"`
  19. // CheckRegions defines the geographic region(s) from where to run health-checks from - e.g. "WNAM", "WEU", "SAF", "SAM".
  20. // Providing a null/empty value means "all regions", which may not be available to all plan types.
  21. CheckRegions []string `json:"check_regions"`
  22. }
  23. // LoadBalancerOrigin represents a Load Balancer origin's properties.
  24. type LoadBalancerOrigin struct {
  25. Name string `json:"name"`
  26. Address string `json:"address"`
  27. Enabled bool `json:"enabled"`
  28. Weight float64 `json:"weight"`
  29. }
  30. // LoadBalancerMonitor represents a load balancer monitor's properties.
  31. type LoadBalancerMonitor struct {
  32. ID string `json:"id,omitempty"`
  33. CreatedOn *time.Time `json:"created_on,omitempty"`
  34. ModifiedOn *time.Time `json:"modified_on,omitempty"`
  35. Type string `json:"type"`
  36. Description string `json:"description"`
  37. Method string `json:"method"`
  38. Path string `json:"path"`
  39. Header map[string][]string `json:"header"`
  40. Timeout int `json:"timeout"`
  41. Retries int `json:"retries"`
  42. Interval int `json:"interval"`
  43. Port uint16 `json:"port,omitempty"`
  44. ExpectedBody string `json:"expected_body"`
  45. ExpectedCodes string `json:"expected_codes"`
  46. FollowRedirects bool `json:"follow_redirects"`
  47. AllowInsecure bool `json:"allow_insecure"`
  48. ProbeZone string `json:"probe_zone"`
  49. }
  50. // LoadBalancer represents a load balancer's properties.
  51. type LoadBalancer struct {
  52. ID string `json:"id,omitempty"`
  53. CreatedOn *time.Time `json:"created_on,omitempty"`
  54. ModifiedOn *time.Time `json:"modified_on,omitempty"`
  55. Description string `json:"description"`
  56. Name string `json:"name"`
  57. TTL int `json:"ttl,omitempty"`
  58. FallbackPool string `json:"fallback_pool"`
  59. DefaultPools []string `json:"default_pools"`
  60. RegionPools map[string][]string `json:"region_pools"`
  61. PopPools map[string][]string `json:"pop_pools"`
  62. Proxied bool `json:"proxied"`
  63. Enabled *bool `json:"enabled,omitempty"`
  64. Persistence string `json:"session_affinity,omitempty"`
  65. PersistenceTTL int `json:"session_affinity_ttl,omitempty"`
  66. // SteeringPolicy controls pool selection logic.
  67. // "off" select pools in DefaultPools order
  68. // "geo" select pools based on RegionPools/PopPools
  69. // "dynamic_latency" select pools based on RTT (requires health checks)
  70. // "random" selects pools in a random order
  71. // "" maps to "geo" if RegionPools or PopPools have entries otherwise "off"
  72. SteeringPolicy string `json:"steering_policy,omitempty"`
  73. }
  74. // LoadBalancerOriginHealth represents the health of the origin.
  75. type LoadBalancerOriginHealth struct {
  76. Healthy bool `json:"healthy,omitempty"`
  77. RTT Duration `json:"rtt,omitempty"`
  78. FailureReason string `json:"failure_reason,omitempty"`
  79. ResponseCode int `json:"response_code,omitempty"`
  80. }
  81. // LoadBalancerPoolPopHealth represents the health of the pool for given PoP.
  82. type LoadBalancerPoolPopHealth struct {
  83. Healthy bool `json:"healthy,omitempty"`
  84. Origins []map[string]LoadBalancerOriginHealth `json:"origins,omitempty"`
  85. }
  86. // LoadBalancerPoolHealth represents the healthchecks from different PoPs for a pool.
  87. type LoadBalancerPoolHealth struct {
  88. ID string `json:"pool_id,omitempty"`
  89. PopHealth map[string]LoadBalancerPoolPopHealth `json:"pop_health,omitempty"`
  90. }
  91. // loadBalancerPoolResponse represents the response from the load balancer pool endpoints.
  92. type loadBalancerPoolResponse struct {
  93. Response
  94. Result LoadBalancerPool `json:"result"`
  95. }
  96. // loadBalancerPoolListResponse represents the response from the List Pools endpoint.
  97. type loadBalancerPoolListResponse struct {
  98. Response
  99. Result []LoadBalancerPool `json:"result"`
  100. ResultInfo ResultInfo `json:"result_info"`
  101. }
  102. // loadBalancerMonitorResponse represents the response from the load balancer monitor endpoints.
  103. type loadBalancerMonitorResponse struct {
  104. Response
  105. Result LoadBalancerMonitor `json:"result"`
  106. }
  107. // loadBalancerMonitorListResponse represents the response from the List Monitors endpoint.
  108. type loadBalancerMonitorListResponse struct {
  109. Response
  110. Result []LoadBalancerMonitor `json:"result"`
  111. ResultInfo ResultInfo `json:"result_info"`
  112. }
  113. // loadBalancerResponse represents the response from the load balancer endpoints.
  114. type loadBalancerResponse struct {
  115. Response
  116. Result LoadBalancer `json:"result"`
  117. }
  118. // loadBalancerListResponse represents the response from the List Load Balancers endpoint.
  119. type loadBalancerListResponse struct {
  120. Response
  121. Result []LoadBalancer `json:"result"`
  122. ResultInfo ResultInfo `json:"result_info"`
  123. }
  124. // loadBalancerPoolHealthResponse represents the response from the Pool Health Details endpoint.
  125. type loadBalancerPoolHealthResponse struct {
  126. Response
  127. Result LoadBalancerPoolHealth `json:"result"`
  128. }
  129. // CreateLoadBalancerPool creates a new load balancer pool.
  130. //
  131. // API reference: https://api.cloudflare.com/#load-balancer-pools-create-a-pool
  132. func (api *API) CreateLoadBalancerPool(pool LoadBalancerPool) (LoadBalancerPool, error) {
  133. uri := api.userBaseURL("/user") + "/load_balancers/pools"
  134. res, err := api.makeRequest("POST", uri, pool)
  135. if err != nil {
  136. return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
  137. }
  138. var r loadBalancerPoolResponse
  139. if err := json.Unmarshal(res, &r); err != nil {
  140. return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
  141. }
  142. return r.Result, nil
  143. }
  144. // ListLoadBalancerPools lists load balancer pools connected to an account.
  145. //
  146. // API reference: https://api.cloudflare.com/#load-balancer-pools-list-pools
  147. func (api *API) ListLoadBalancerPools() ([]LoadBalancerPool, error) {
  148. uri := api.userBaseURL("/user") + "/load_balancers/pools"
  149. res, err := api.makeRequest("GET", uri, nil)
  150. if err != nil {
  151. return nil, errors.Wrap(err, errMakeRequestError)
  152. }
  153. var r loadBalancerPoolListResponse
  154. if err := json.Unmarshal(res, &r); err != nil {
  155. return nil, errors.Wrap(err, errUnmarshalError)
  156. }
  157. return r.Result, nil
  158. }
  159. // LoadBalancerPoolDetails returns the details for a load balancer pool.
  160. //
  161. // API reference: https://api.cloudflare.com/#load-balancer-pools-pool-details
  162. func (api *API) LoadBalancerPoolDetails(poolID string) (LoadBalancerPool, error) {
  163. uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID
  164. res, err := api.makeRequest("GET", uri, nil)
  165. if err != nil {
  166. return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
  167. }
  168. var r loadBalancerPoolResponse
  169. if err := json.Unmarshal(res, &r); err != nil {
  170. return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
  171. }
  172. return r.Result, nil
  173. }
  174. // DeleteLoadBalancerPool disables and deletes a load balancer pool.
  175. //
  176. // API reference: https://api.cloudflare.com/#load-balancer-pools-delete-a-pool
  177. func (api *API) DeleteLoadBalancerPool(poolID string) error {
  178. uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID
  179. if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
  180. return errors.Wrap(err, errMakeRequestError)
  181. }
  182. return nil
  183. }
  184. // ModifyLoadBalancerPool modifies a configured load balancer pool.
  185. //
  186. // API reference: https://api.cloudflare.com/#load-balancer-pools-modify-a-pool
  187. func (api *API) ModifyLoadBalancerPool(pool LoadBalancerPool) (LoadBalancerPool, error) {
  188. uri := api.userBaseURL("/user") + "/load_balancers/pools/" + pool.ID
  189. res, err := api.makeRequest("PUT", uri, pool)
  190. if err != nil {
  191. return LoadBalancerPool{}, errors.Wrap(err, errMakeRequestError)
  192. }
  193. var r loadBalancerPoolResponse
  194. if err := json.Unmarshal(res, &r); err != nil {
  195. return LoadBalancerPool{}, errors.Wrap(err, errUnmarshalError)
  196. }
  197. return r.Result, nil
  198. }
  199. // CreateLoadBalancerMonitor creates a new load balancer monitor.
  200. //
  201. // API reference: https://api.cloudflare.com/#load-balancer-monitors-create-a-monitor
  202. func (api *API) CreateLoadBalancerMonitor(monitor LoadBalancerMonitor) (LoadBalancerMonitor, error) {
  203. uri := api.userBaseURL("/user") + "/load_balancers/monitors"
  204. res, err := api.makeRequest("POST", uri, monitor)
  205. if err != nil {
  206. return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
  207. }
  208. var r loadBalancerMonitorResponse
  209. if err := json.Unmarshal(res, &r); err != nil {
  210. return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
  211. }
  212. return r.Result, nil
  213. }
  214. // ListLoadBalancerMonitors lists load balancer monitors connected to an account.
  215. //
  216. // API reference: https://api.cloudflare.com/#load-balancer-monitors-list-monitors
  217. func (api *API) ListLoadBalancerMonitors() ([]LoadBalancerMonitor, error) {
  218. uri := api.userBaseURL("/user") + "/load_balancers/monitors"
  219. res, err := api.makeRequest("GET", uri, nil)
  220. if err != nil {
  221. return nil, errors.Wrap(err, errMakeRequestError)
  222. }
  223. var r loadBalancerMonitorListResponse
  224. if err := json.Unmarshal(res, &r); err != nil {
  225. return nil, errors.Wrap(err, errUnmarshalError)
  226. }
  227. return r.Result, nil
  228. }
  229. // LoadBalancerMonitorDetails returns the details for a load balancer monitor.
  230. //
  231. // API reference: https://api.cloudflare.com/#load-balancer-monitors-monitor-details
  232. func (api *API) LoadBalancerMonitorDetails(monitorID string) (LoadBalancerMonitor, error) {
  233. uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitorID
  234. res, err := api.makeRequest("GET", uri, nil)
  235. if err != nil {
  236. return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
  237. }
  238. var r loadBalancerMonitorResponse
  239. if err := json.Unmarshal(res, &r); err != nil {
  240. return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
  241. }
  242. return r.Result, nil
  243. }
  244. // DeleteLoadBalancerMonitor disables and deletes a load balancer monitor.
  245. //
  246. // API reference: https://api.cloudflare.com/#load-balancer-monitors-delete-a-monitor
  247. func (api *API) DeleteLoadBalancerMonitor(monitorID string) error {
  248. uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitorID
  249. if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
  250. return errors.Wrap(err, errMakeRequestError)
  251. }
  252. return nil
  253. }
  254. // ModifyLoadBalancerMonitor modifies a configured load balancer monitor.
  255. //
  256. // API reference: https://api.cloudflare.com/#load-balancer-monitors-modify-a-monitor
  257. func (api *API) ModifyLoadBalancerMonitor(monitor LoadBalancerMonitor) (LoadBalancerMonitor, error) {
  258. uri := api.userBaseURL("/user") + "/load_balancers/monitors/" + monitor.ID
  259. res, err := api.makeRequest("PUT", uri, monitor)
  260. if err != nil {
  261. return LoadBalancerMonitor{}, errors.Wrap(err, errMakeRequestError)
  262. }
  263. var r loadBalancerMonitorResponse
  264. if err := json.Unmarshal(res, &r); err != nil {
  265. return LoadBalancerMonitor{}, errors.Wrap(err, errUnmarshalError)
  266. }
  267. return r.Result, nil
  268. }
  269. // CreateLoadBalancer creates a new load balancer.
  270. //
  271. // API reference: https://api.cloudflare.com/#load-balancers-create-a-load-balancer
  272. func (api *API) CreateLoadBalancer(zoneID string, lb LoadBalancer) (LoadBalancer, error) {
  273. uri := "/zones/" + zoneID + "/load_balancers"
  274. res, err := api.makeRequest("POST", uri, lb)
  275. if err != nil {
  276. return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
  277. }
  278. var r loadBalancerResponse
  279. if err := json.Unmarshal(res, &r); err != nil {
  280. return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
  281. }
  282. return r.Result, nil
  283. }
  284. // ListLoadBalancers lists load balancers configured on a zone.
  285. //
  286. // API reference: https://api.cloudflare.com/#load-balancers-list-load-balancers
  287. func (api *API) ListLoadBalancers(zoneID string) ([]LoadBalancer, error) {
  288. uri := "/zones/" + zoneID + "/load_balancers"
  289. res, err := api.makeRequest("GET", uri, nil)
  290. if err != nil {
  291. return nil, errors.Wrap(err, errMakeRequestError)
  292. }
  293. var r loadBalancerListResponse
  294. if err := json.Unmarshal(res, &r); err != nil {
  295. return nil, errors.Wrap(err, errUnmarshalError)
  296. }
  297. return r.Result, nil
  298. }
  299. // LoadBalancerDetails returns the details for a load balancer.
  300. //
  301. // API reference: https://api.cloudflare.com/#load-balancers-load-balancer-details
  302. func (api *API) LoadBalancerDetails(zoneID, lbID string) (LoadBalancer, error) {
  303. uri := "/zones/" + zoneID + "/load_balancers/" + lbID
  304. res, err := api.makeRequest("GET", uri, nil)
  305. if err != nil {
  306. return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
  307. }
  308. var r loadBalancerResponse
  309. if err := json.Unmarshal(res, &r); err != nil {
  310. return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
  311. }
  312. return r.Result, nil
  313. }
  314. // DeleteLoadBalancer disables and deletes a load balancer.
  315. //
  316. // API reference: https://api.cloudflare.com/#load-balancers-delete-a-load-balancer
  317. func (api *API) DeleteLoadBalancer(zoneID, lbID string) error {
  318. uri := "/zones/" + zoneID + "/load_balancers/" + lbID
  319. if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
  320. return errors.Wrap(err, errMakeRequestError)
  321. }
  322. return nil
  323. }
  324. // ModifyLoadBalancer modifies a configured load balancer.
  325. //
  326. // API reference: https://api.cloudflare.com/#load-balancers-modify-a-load-balancer
  327. func (api *API) ModifyLoadBalancer(zoneID string, lb LoadBalancer) (LoadBalancer, error) {
  328. uri := "/zones/" + zoneID + "/load_balancers/" + lb.ID
  329. res, err := api.makeRequest("PUT", uri, lb)
  330. if err != nil {
  331. return LoadBalancer{}, errors.Wrap(err, errMakeRequestError)
  332. }
  333. var r loadBalancerResponse
  334. if err := json.Unmarshal(res, &r); err != nil {
  335. return LoadBalancer{}, errors.Wrap(err, errUnmarshalError)
  336. }
  337. return r.Result, nil
  338. }
  339. // PoolHealthDetails fetches the latest healtcheck details for a single pool.
  340. //
  341. // API reference: https://api.cloudflare.com/#load-balancer-pools-pool-health-details
  342. func (api *API) PoolHealthDetails(poolID string) (LoadBalancerPoolHealth, error) {
  343. uri := api.userBaseURL("/user") + "/load_balancers/pools/" + poolID + "/health"
  344. res, err := api.makeRequest("GET", uri, nil)
  345. if err != nil {
  346. return LoadBalancerPoolHealth{}, errors.Wrap(err, errMakeRequestError)
  347. }
  348. var r loadBalancerPoolHealthResponse
  349. if err := json.Unmarshal(res, &r); err != nil {
  350. return LoadBalancerPoolHealth{}, errors.Wrap(err, errUnmarshalError)
  351. }
  352. return r.Result, nil
  353. }