railgun.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. package cloudflare
  2. import (
  3. "encoding/json"
  4. "net/url"
  5. "time"
  6. "github.com/pkg/errors"
  7. )
  8. // Railgun represents a Railgun's properties.
  9. type Railgun struct {
  10. ID string `json:"id"`
  11. Name string `json:"name"`
  12. Status string `json:"status"`
  13. Enabled bool `json:"enabled"`
  14. ZonesConnected int `json:"zones_connected"`
  15. Build string `json:"build"`
  16. Version string `json:"version"`
  17. Revision string `json:"revision"`
  18. ActivationKey string `json:"activation_key"`
  19. ActivatedOn time.Time `json:"activated_on"`
  20. CreatedOn time.Time `json:"created_on"`
  21. ModifiedOn time.Time `json:"modified_on"`
  22. UpgradeInfo struct {
  23. LatestVersion string `json:"latest_version"`
  24. DownloadLink string `json:"download_link"`
  25. } `json:"upgrade_info"`
  26. }
  27. // RailgunListOptions represents the parameters used to list railguns.
  28. type RailgunListOptions struct {
  29. Direction string
  30. }
  31. // railgunResponse represents the response from the Create Railgun and the Railgun Details endpoints.
  32. type railgunResponse struct {
  33. Response
  34. Result Railgun `json:"result"`
  35. }
  36. // railgunsResponse represents the response from the List Railguns endpoint.
  37. type railgunsResponse struct {
  38. Response
  39. Result []Railgun `json:"result"`
  40. }
  41. // CreateRailgun creates a new Railgun.
  42. //
  43. // API reference: https://api.cloudflare.com/#railgun-create-railgun
  44. func (api *API) CreateRailgun(name string) (Railgun, error) {
  45. uri := api.userBaseURL("") + "/railguns"
  46. params := struct {
  47. Name string `json:"name"`
  48. }{
  49. Name: name,
  50. }
  51. res, err := api.makeRequest("POST", uri, params)
  52. if err != nil {
  53. return Railgun{}, errors.Wrap(err, errMakeRequestError)
  54. }
  55. var r railgunResponse
  56. if err := json.Unmarshal(res, &r); err != nil {
  57. return Railgun{}, errors.Wrap(err, errUnmarshalError)
  58. }
  59. return r.Result, nil
  60. }
  61. // ListRailguns lists Railguns connected to an account.
  62. //
  63. // API reference: https://api.cloudflare.com/#railgun-list-railguns
  64. func (api *API) ListRailguns(options RailgunListOptions) ([]Railgun, error) {
  65. v := url.Values{}
  66. if options.Direction != "" {
  67. v.Set("direction", options.Direction)
  68. }
  69. uri := api.userBaseURL("") + "/railguns" + "?" + v.Encode()
  70. res, err := api.makeRequest("GET", uri, nil)
  71. if err != nil {
  72. return nil, errors.Wrap(err, errMakeRequestError)
  73. }
  74. var r railgunsResponse
  75. if err := json.Unmarshal(res, &r); err != nil {
  76. return nil, errors.Wrap(err, errUnmarshalError)
  77. }
  78. return r.Result, nil
  79. }
  80. // RailgunDetails returns the details for a Railgun.
  81. //
  82. // API reference: https://api.cloudflare.com/#railgun-railgun-details
  83. func (api *API) RailgunDetails(railgunID string) (Railgun, error) {
  84. uri := api.userBaseURL("") + "/railguns/" + railgunID
  85. res, err := api.makeRequest("GET", uri, nil)
  86. if err != nil {
  87. return Railgun{}, errors.Wrap(err, errMakeRequestError)
  88. }
  89. var r railgunResponse
  90. if err := json.Unmarshal(res, &r); err != nil {
  91. return Railgun{}, errors.Wrap(err, errUnmarshalError)
  92. }
  93. return r.Result, nil
  94. }
  95. // RailgunZones returns the zones that are currently using a Railgun.
  96. //
  97. // API reference: https://api.cloudflare.com/#railgun-get-zones-connected-to-a-railgun
  98. func (api *API) RailgunZones(railgunID string) ([]Zone, error) {
  99. uri := api.userBaseURL("") + "/railguns/" + railgunID + "/zones"
  100. res, err := api.makeRequest("GET", uri, nil)
  101. if err != nil {
  102. return nil, errors.Wrap(err, errMakeRequestError)
  103. }
  104. var r ZonesResponse
  105. if err := json.Unmarshal(res, &r); err != nil {
  106. return nil, errors.Wrap(err, errUnmarshalError)
  107. }
  108. return r.Result, nil
  109. }
  110. // enableRailgun enables (true) or disables (false) a Railgun for all zones connected to it.
  111. //
  112. // API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
  113. func (api *API) enableRailgun(railgunID string, enable bool) (Railgun, error) {
  114. uri := api.userBaseURL("") + "/railguns/" + railgunID
  115. params := struct {
  116. Enabled bool `json:"enabled"`
  117. }{
  118. Enabled: enable,
  119. }
  120. res, err := api.makeRequest("PATCH", uri, params)
  121. if err != nil {
  122. return Railgun{}, errors.Wrap(err, errMakeRequestError)
  123. }
  124. var r railgunResponse
  125. if err := json.Unmarshal(res, &r); err != nil {
  126. return Railgun{}, errors.Wrap(err, errUnmarshalError)
  127. }
  128. return r.Result, nil
  129. }
  130. // EnableRailgun enables a Railgun for all zones connected to it.
  131. //
  132. // API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
  133. func (api *API) EnableRailgun(railgunID string) (Railgun, error) {
  134. return api.enableRailgun(railgunID, true)
  135. }
  136. // DisableRailgun enables a Railgun for all zones connected to it.
  137. //
  138. // API reference: https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
  139. func (api *API) DisableRailgun(railgunID string) (Railgun, error) {
  140. return api.enableRailgun(railgunID, false)
  141. }
  142. // DeleteRailgun disables and deletes a Railgun.
  143. //
  144. // API reference: https://api.cloudflare.com/#railgun-delete-railgun
  145. func (api *API) DeleteRailgun(railgunID string) error {
  146. uri := api.userBaseURL("") + "/railguns/" + railgunID
  147. if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
  148. return errors.Wrap(err, errMakeRequestError)
  149. }
  150. return nil
  151. }
  152. // ZoneRailgun represents the status of a Railgun on a zone.
  153. type ZoneRailgun struct {
  154. ID string `json:"id"`
  155. Name string `json:"name"`
  156. Enabled bool `json:"enabled"`
  157. Connected bool `json:"connected"`
  158. }
  159. // zoneRailgunResponse represents the response from the Zone Railgun Details endpoint.
  160. type zoneRailgunResponse struct {
  161. Response
  162. Result ZoneRailgun `json:"result"`
  163. }
  164. // zoneRailgunsResponse represents the response from the Zone Railgun endpoint.
  165. type zoneRailgunsResponse struct {
  166. Response
  167. Result []ZoneRailgun `json:"result"`
  168. }
  169. // RailgunDiagnosis represents the test results from testing railgun connections
  170. // to a zone.
  171. type RailgunDiagnosis struct {
  172. Method string `json:"method"`
  173. HostName string `json:"host_name"`
  174. HTTPStatus int `json:"http_status"`
  175. Railgun string `json:"railgun"`
  176. URL string `json:"url"`
  177. ResponseStatus string `json:"response_status"`
  178. Protocol string `json:"protocol"`
  179. ElapsedTime string `json:"elapsed_time"`
  180. BodySize string `json:"body_size"`
  181. BodyHash string `json:"body_hash"`
  182. MissingHeaders string `json:"missing_headers"`
  183. ConnectionClose bool `json:"connection_close"`
  184. Cloudflare string `json:"cloudflare"`
  185. CFRay string `json:"cf-ray"`
  186. // NOTE: Cloudflare's online API documentation does not yet have definitions
  187. // for the following fields. See: https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection/
  188. CFWANError string `json:"cf-wan-error"`
  189. CFCacheStatus string `json:"cf-cache-status"`
  190. }
  191. // railgunDiagnosisResponse represents the response from the Test Railgun Connection enpoint.
  192. type railgunDiagnosisResponse struct {
  193. Response
  194. Result RailgunDiagnosis `json:"result"`
  195. }
  196. // ZoneRailguns returns the available Railguns for a zone.
  197. //
  198. // API reference: https://api.cloudflare.com/#railguns-for-a-zone-get-available-railguns
  199. func (api *API) ZoneRailguns(zoneID string) ([]ZoneRailgun, error) {
  200. uri := "/zones/" + zoneID + "/railguns"
  201. res, err := api.makeRequest("GET", uri, nil)
  202. if err != nil {
  203. return nil, errors.Wrap(err, errMakeRequestError)
  204. }
  205. var r zoneRailgunsResponse
  206. if err := json.Unmarshal(res, &r); err != nil {
  207. return nil, errors.Wrap(err, errUnmarshalError)
  208. }
  209. return r.Result, nil
  210. }
  211. // ZoneRailgunDetails returns the configuration for a given Railgun.
  212. //
  213. // API reference: https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
  214. func (api *API) ZoneRailgunDetails(zoneID, railgunID string) (ZoneRailgun, error) {
  215. uri := "/zones/" + zoneID + "/railguns/" + railgunID
  216. res, err := api.makeRequest("GET", uri, nil)
  217. if err != nil {
  218. return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
  219. }
  220. var r zoneRailgunResponse
  221. if err := json.Unmarshal(res, &r); err != nil {
  222. return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
  223. }
  224. return r.Result, nil
  225. }
  226. // TestRailgunConnection tests a Railgun connection for a given zone.
  227. //
  228. // API reference: https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection
  229. func (api *API) TestRailgunConnection(zoneID, railgunID string) (RailgunDiagnosis, error) {
  230. uri := "/zones/" + zoneID + "/railguns/" + railgunID + "/diagnose"
  231. res, err := api.makeRequest("GET", uri, nil)
  232. if err != nil {
  233. return RailgunDiagnosis{}, errors.Wrap(err, errMakeRequestError)
  234. }
  235. var r railgunDiagnosisResponse
  236. if err := json.Unmarshal(res, &r); err != nil {
  237. return RailgunDiagnosis{}, errors.Wrap(err, errUnmarshalError)
  238. }
  239. return r.Result, nil
  240. }
  241. // connectZoneRailgun connects (true) or disconnects (false) a Railgun for a given zone.
  242. //
  243. // API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
  244. func (api *API) connectZoneRailgun(zoneID, railgunID string, connect bool) (ZoneRailgun, error) {
  245. uri := "/zones/" + zoneID + "/railguns/" + railgunID
  246. params := struct {
  247. Connected bool `json:"connected"`
  248. }{
  249. Connected: connect,
  250. }
  251. res, err := api.makeRequest("PATCH", uri, params)
  252. if err != nil {
  253. return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
  254. }
  255. var r zoneRailgunResponse
  256. if err := json.Unmarshal(res, &r); err != nil {
  257. return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
  258. }
  259. return r.Result, nil
  260. }
  261. // ConnectZoneRailgun connects a Railgun for a given zone.
  262. //
  263. // API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
  264. func (api *API) ConnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
  265. return api.connectZoneRailgun(zoneID, railgunID, true)
  266. }
  267. // DisconnectZoneRailgun disconnects a Railgun for a given zone.
  268. //
  269. // API reference: https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
  270. func (api *API) DisconnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
  271. return api.connectZoneRailgun(zoneID, railgunID, false)
  272. }