Merge pull request #7037 from hashicorp/b-cloudflare-lib-upgrade
provider/cloudflare: Upgrade library to github.com/cloudflare/cloudflare-go
This commit is contained in:
commit
3d4bc56d97
|
@ -1,10 +1,10 @@
|
||||||
package cloudflare
|
package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
// NOTE: Temporary until they merge my PR:
|
"github.com/cloudflare/cloudflare-go"
|
||||||
"github.com/mitchellh/cloudflare-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -14,7 +14,10 @@ type Config struct {
|
||||||
|
|
||||||
// Client() returns a new client for accessing cloudflare.
|
// Client() returns a new client for accessing cloudflare.
|
||||||
func (c *Config) Client() (*cloudflare.API, error) {
|
func (c *Config) Client() (*cloudflare.API, error) {
|
||||||
client := cloudflare.New(c.Token, c.Email)
|
client, err := cloudflare.New(c.Token, c.Email)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating new CloudFlare client: %s", err)
|
||||||
|
}
|
||||||
log.Printf("[INFO] CloudFlare Client configured for user: %s", c.Email)
|
log.Printf("[INFO] CloudFlare Client configured for user: %s", c.Email)
|
||||||
return client, nil
|
return client, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflare-go"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
// NOTE: Temporary until they merge my PR:
|
|
||||||
"github.com/mitchellh/cloudflare-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func resourceCloudFlareRecord() *schema.Resource {
|
func resourceCloudFlareRecord() *schema.Resource {
|
||||||
|
@ -103,7 +101,13 @@ func resourceCloudFlareRecordCreate(d *schema.ResourceData, meta interface{}) er
|
||||||
return fmt.Errorf("Failed to create record: %s", err)
|
return fmt.Errorf("Failed to create record: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.SetId(r.ID)
|
// In the Event that the API returns an empty DNS Record, we verify that the
|
||||||
|
// ID returned is not the default ""
|
||||||
|
if r.Result.ID == "" {
|
||||||
|
return fmt.Errorf("Failed to find record in Creat response; Record was empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(r.Result.ID)
|
||||||
|
|
||||||
log.Printf("[INFO] CloudFlare Record ID: %s", d.Id())
|
log.Printf("[INFO] CloudFlare Record ID: %s", d.Id())
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflare-go"
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
|
||||||
// NOTE: Temporary until they merge my PR:
|
|
||||||
"github.com/mitchellh/cloudflare-go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAccCloudFlareRecord_Basic(t *testing.T) {
|
func TestAccCloudFlareRecord_Basic(t *testing.T) {
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
# cloudflare-go
|
||||||
|
|
||||||
|
[![GoDoc](https://img.shields.io/badge/godoc-reference-5673AF.svg?style=flat-square)](https://godoc.org/github.com/cloudflare/cloudflare-go)
|
||||||
|
[![Build Status](https://img.shields.io/travis/cloudflare/cloudflare-go/master.svg?style=flat-square)](https://travis-ci.org/cloudflare/cloudflare-go)
|
||||||
|
[![Go Report Card](https://goreportcard.com/badge/github.com/cloudflare/cloudflare-go?style=flat-square)](https://goreportcard.com/report/github.com/cloudflare/cloudflare-go)
|
||||||
|
|
||||||
|
> **Note**: This library is under active development as we expand it to cover our (expanding!) API.
|
||||||
|
Consider the public API of this package a little unstable as we work towards a v1.0.
|
||||||
|
|
||||||
|
A Go library for interacting with [CloudFlare's API v4](https://api.cloudflare.com/). This library
|
||||||
|
allows you to:
|
||||||
|
|
||||||
|
* Manage and automate changes to your DNS records within CloudFlare
|
||||||
|
* Manage and automate changes to your zones (domains) on CloudFlare, including adding new zones to
|
||||||
|
your account
|
||||||
|
* List and modify the status of WAF (Web Application Firewall) rules for your zones
|
||||||
|
* Fetch CloudFlare's IP ranges for automating your firewall whitelisting
|
||||||
|
|
||||||
|
A command-line client, [flarectl](cmd/flarectl), is also available as part of this project.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
The current feature list includes:
|
||||||
|
|
||||||
|
- [x] DNS Records
|
||||||
|
- [x] Zones
|
||||||
|
- [x] Web Application Firewall (WAF)
|
||||||
|
- [x] CloudFlare IPs
|
||||||
|
- [x] User Administration (partial)
|
||||||
|
- [x] Virtual DNS Management
|
||||||
|
- [ ] Organization Administration
|
||||||
|
- [ ] [Railgun](https://www.cloudflare.com/railgun/) administration
|
||||||
|
- [ ] [Keyless SSL](https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/)
|
||||||
|
- [ ] [Origin CA](https://blog.cloudflare.com/universal-ssl-encryption-all-the-way-to-the-origin-for-free/)
|
||||||
|
|
||||||
|
Pull Requests are welcome, but please open an issue (or comment in an existing issue) to discuss any
|
||||||
|
non-trivial changes before submitting code.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
You need a working Go environment.
|
||||||
|
|
||||||
|
```
|
||||||
|
go get github.com/cloudflare/cloudflare-go
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflare-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Construct a new API object
|
||||||
|
api, err := cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch user details on the account
|
||||||
|
u, err := api.UserDetails()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Print user details
|
||||||
|
fmt.Println(u)
|
||||||
|
|
||||||
|
// Fetch the zone ID
|
||||||
|
id, err := api.ZoneIDByName("example.com") // Assuming example.com exists in your CloudFlare account already
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch zone details
|
||||||
|
zone, err := api.ZoneDetails(id)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Print zone details
|
||||||
|
fmt.Println(zone)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Also refer to the [API documentation](https://godoc.org/github.com/cloudflare/cloudflare-go) for how
|
||||||
|
to use this package in-depth.
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
BSD licensed. See the [LICENSE](LICENSE) file for details.
|
|
@ -0,0 +1,317 @@
|
||||||
|
// Package cloudflare implements the CloudFlare v4 API.
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
const apiURL = "https://api.cloudflare.com/client/v4"
|
||||||
|
|
||||||
|
// API holds the configuration for the current API client. A client should not
|
||||||
|
// be modified concurrently.
|
||||||
|
type API struct {
|
||||||
|
APIKey string
|
||||||
|
APIEmail string
|
||||||
|
BaseURL string
|
||||||
|
headers http.Header
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates a new CloudFlare v4 API client.
|
||||||
|
func New(key, email string, opts ...Option) (*API, error) {
|
||||||
|
if key == "" || email == "" {
|
||||||
|
return nil, errors.New(errEmptyCredentials)
|
||||||
|
}
|
||||||
|
|
||||||
|
api := &API{
|
||||||
|
APIKey: key,
|
||||||
|
APIEmail: email,
|
||||||
|
BaseURL: apiURL,
|
||||||
|
headers: make(http.Header),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := api.parseOptions(opts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "options parsing failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to http.DefaultClient if the package user does not provide
|
||||||
|
// their own.
|
||||||
|
if api.httpClient == nil {
|
||||||
|
api.httpClient = http.DefaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
return api, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneIDByName retrieves a zone's ID from the name.
|
||||||
|
func (api *API) ZoneIDByName(zoneName string) (string, error) {
|
||||||
|
res, err := api.ListZones(zoneName)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "ListZones command failed")
|
||||||
|
}
|
||||||
|
for _, zone := range res {
|
||||||
|
if zone.Name == zoneName {
|
||||||
|
return zone.ID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", errors.New("Zone could not be found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// makeRequest makes a HTTP request and returns the body as a byte slice,
|
||||||
|
// closing it before returnng. params will be serialized to JSON.
|
||||||
|
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
|
||||||
|
// Replace nil with a JSON object if needed
|
||||||
|
var reqBody io.Reader
|
||||||
|
if params != nil {
|
||||||
|
json, err := json.Marshal(params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "error marshalling params to JSON")
|
||||||
|
}
|
||||||
|
reqBody = bytes.NewReader(json)
|
||||||
|
} else {
|
||||||
|
reqBody = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := api.request(method, uri, reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "could not read response body")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch resp.StatusCode {
|
||||||
|
case http.StatusOK:
|
||||||
|
break
|
||||||
|
case http.StatusUnauthorized:
|
||||||
|
return nil, errors.Errorf("HTTP status %d: invalid credentials", resp.StatusCode)
|
||||||
|
case http.StatusForbidden:
|
||||||
|
return nil, errors.Errorf("HTTP status %d: insufficient permissions", resp.StatusCode)
|
||||||
|
default:
|
||||||
|
var s string
|
||||||
|
if body != nil {
|
||||||
|
s = string(body)
|
||||||
|
}
|
||||||
|
return nil, errors.Errorf("HTTP status %d: content %q", resp.StatusCode, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return body, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// request makes a HTTP request to the given API endpoint, returning the raw
|
||||||
|
// *http.Response, or an error if one occurred. The caller is responsible for
|
||||||
|
// closing the response body.
|
||||||
|
func (api *API) request(method, uri string, reqBody io.Reader) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest(method, api.BaseURL+uri, reqBody)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "HTTP request creation failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply any user-defined headers first.
|
||||||
|
req.Header = api.headers
|
||||||
|
req.Header.Set("X-Auth-Key", api.APIKey)
|
||||||
|
req.Header.Set("X-Auth-Email", api.APIEmail)
|
||||||
|
|
||||||
|
resp, err := api.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "HTTP request failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResponseInfo contains a code and message returned by the API as errors or
|
||||||
|
// informational messages inside the response.
|
||||||
|
type ResponseInfo struct {
|
||||||
|
Code int `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response is a template. There will also be a result struct. There will be a
|
||||||
|
// unique response type for each response, which will include this type.
|
||||||
|
type Response struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Errors []ResponseInfo `json:"errors"`
|
||||||
|
Messages []ResponseInfo `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResultInfo contains metadata about the Response.
|
||||||
|
type ResultInfo struct {
|
||||||
|
Page int `json:"page"`
|
||||||
|
PerPage int `json:"per_page"`
|
||||||
|
Count int `json:"count"`
|
||||||
|
Total int `json:"total_count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// User describes a user account.
|
||||||
|
type User struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Telephone string `json:"telephone"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
Zipcode string `json:"zipcode"`
|
||||||
|
CreatedOn time.Time `json:"created_on"`
|
||||||
|
ModifiedOn time.Time `json:"modified_on"`
|
||||||
|
APIKey string `json:"api_key"`
|
||||||
|
TwoFA bool `json:"two_factor_authentication_enabled"`
|
||||||
|
Betas []string `json:"betas"`
|
||||||
|
Organizations []Organization `json:"organizations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserResponse wraps a response containing User accounts.
|
||||||
|
type UserResponse struct {
|
||||||
|
Response
|
||||||
|
Result User `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Owner describes the resource owner.
|
||||||
|
type Owner struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
OwnerType string `json:"owner_type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSRecord represents a DNS record in a zone.
|
||||||
|
type DNSRecord struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Proxiable bool `json:"proxiable,omitempty"`
|
||||||
|
Proxied bool `json:"proxied,omitempty"`
|
||||||
|
TTL int `json:"ttl,omitempty"`
|
||||||
|
Locked bool `json:"locked,omitempty"`
|
||||||
|
ZoneID string `json:"zone_id,omitempty"`
|
||||||
|
ZoneName string `json:"zone_name,omitempty"`
|
||||||
|
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||||
|
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||||
|
Data interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
|
||||||
|
Meta interface{} `json:"meta,omitempty"`
|
||||||
|
Priority int `json:"priority,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSRecordResponse represents the response from the DNS endpoint.
|
||||||
|
type DNSRecordResponse struct {
|
||||||
|
Response
|
||||||
|
Result DNSRecord `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DNSListResponse represents the response from the list DNS records endpoint.
|
||||||
|
type DNSListResponse struct {
|
||||||
|
Response
|
||||||
|
Result []DNSRecord `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeylessSSL represents Keyless SSL configuration.
|
||||||
|
type KeylessSSL struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Port int `json:"port"`
|
||||||
|
Status string `json:"success"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Permissions []string `json:"permissions"`
|
||||||
|
CreatedOn time.Time `json:"created_on"`
|
||||||
|
ModifiedOn time.Time `json:"modifed_on"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeylessSSLResponse represents the response from the Keyless SSL endpoint.
|
||||||
|
type KeylessSSLResponse struct {
|
||||||
|
Response
|
||||||
|
Result []KeylessSSL `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomPage represents a custom page configuration.
|
||||||
|
type CustomPage struct {
|
||||||
|
CreatedOn string `json:"created_on"`
|
||||||
|
ModifiedOn time.Time `json:"modified_on"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
State string `json:"state"`
|
||||||
|
RequiredTokens []string `json:"required_tokens"`
|
||||||
|
PreviewTarget string `json:"preview_target"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CustomPageResponse represents the response from the custom pages endpoint.
|
||||||
|
type CustomPageResponse struct {
|
||||||
|
Response
|
||||||
|
Result []CustomPage `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAFPackage represents a WAF package configuration.
|
||||||
|
type WAFPackage struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
ZoneID string `json:"zone_id"`
|
||||||
|
DetectionMode string `json:"detection_mode"`
|
||||||
|
Sensitivity string `json:"sensitivity"`
|
||||||
|
ActionMode string `json:"action_mode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAFPackagesResponse represents the response from the WAF packages endpoint.
|
||||||
|
type WAFPackagesResponse struct {
|
||||||
|
Response
|
||||||
|
Result []WAFPackage `json:"result"`
|
||||||
|
ResultInfo ResultInfo `json:"result_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAFRule represents a WAF rule.
|
||||||
|
type WAFRule struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Priority string `json:"priority"`
|
||||||
|
PackageID string `json:"package_id"`
|
||||||
|
Group struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
} `json:"group"`
|
||||||
|
Mode string `json:"mode"`
|
||||||
|
DefaultMode string `json:"default_mode"`
|
||||||
|
AllowedModes []string `json:"allowed_modes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAFRulesResponse represents the response from the WAF rule endpoint.
|
||||||
|
type WAFRulesResponse struct {
|
||||||
|
Response
|
||||||
|
Result []WAFRule `json:"result"`
|
||||||
|
ResultInfo ResultInfo `json:"result_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurgeCacheRequest represents the request format made to the purge endpoint.
|
||||||
|
type PurgeCacheRequest struct {
|
||||||
|
Everything bool `json:"purge_everything,omitempty"`
|
||||||
|
Files []string `json:"files,omitempty"`
|
||||||
|
Tags []string `json:"tags,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurgeCacheResponse represents the response from the purge endpoint.
|
||||||
|
type PurgeCacheResponse struct {
|
||||||
|
Response
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPRanges contains lists of IPv4 and IPv6 CIDRs
|
||||||
|
type IPRanges struct {
|
||||||
|
IPv4CIDRs []string `json:"ipv4_cidrs"`
|
||||||
|
IPv6CIDRs []string `json:"ipv6_cidrs"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPsResponse is the API response containing a list of IPs
|
||||||
|
type IPsResponse struct {
|
||||||
|
Response
|
||||||
|
Result IPRanges `json:"result"`
|
||||||
|
}
|
|
@ -7,34 +7,30 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
// CreateDNSRecord creates a DNS record for the zone identifier.
|
||||||
Create a DNS record.
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
|
||||||
API reference:
|
// POST /zones/:zone_identifier/dns_records
|
||||||
https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record
|
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (*DNSRecordResponse, error) {
|
||||||
POST /zones/:zone_identifier/dns_records
|
|
||||||
*/
|
|
||||||
func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (DNSRecord, error) {
|
|
||||||
uri := "/zones/" + zoneID + "/dns_records"
|
uri := "/zones/" + zoneID + "/dns_records"
|
||||||
res, err := api.makeRequest("POST", uri, rr)
|
res, err := api.makeRequest("POST", uri, rr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DNSRecord{}, errors.Wrap(err, errMakeRequestError)
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
}
|
}
|
||||||
var r DNSRecordResponse
|
|
||||||
err = json.Unmarshal(res, &r)
|
var recordResp *DNSRecordResponse
|
||||||
|
err = json.Unmarshal(res, &recordResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return DNSRecord{}, errors.Wrap(err, errUnmarshalError)
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
}
|
}
|
||||||
return r.Result, nil
|
|
||||||
|
return recordResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// DNSRecords returns a slice of DNS records for the given zone identifier.
|
||||||
Fetches DNS records for a zone.
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
|
||||||
API reference:
|
// GET /zones/:zone_identifier/dns_records
|
||||||
https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records
|
|
||||||
GET /zones/:zone_identifier/dns_records
|
|
||||||
*/
|
|
||||||
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
||||||
// Construct a query string
|
// Construct a query string
|
||||||
v := url.Values{}
|
v := url.Values{}
|
||||||
|
@ -64,13 +60,11 @@ func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) {
|
||||||
return r.Result, nil
|
return r.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// DNSRecord returns a single DNS record for the given zone & record
|
||||||
Fetches a single DNS record.
|
// identifiers.
|
||||||
|
// API reference:
|
||||||
API reference:
|
// https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
|
||||||
https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details
|
// GET /zones/:zone_identifier/dns_records/:identifier
|
||||||
GET /zones/:zone_identifier/dns_records/:identifier
|
|
||||||
*/
|
|
||||||
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
||||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||||
res, err := api.makeRequest("GET", uri, nil)
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
@ -85,13 +79,11 @@ func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) {
|
||||||
return r.Result, nil
|
return r.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// UpdateDNSRecord updates a single DNS record for the given zone & record
|
||||||
Change a DNS record.
|
// identifiers.
|
||||||
|
// API reference:
|
||||||
API reference:
|
// https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
|
||||||
https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record
|
// PUT /zones/:zone_identifier/dns_records/:identifier
|
||||||
PUT /zones/:zone_identifier/dns_records/:identifier
|
|
||||||
*/
|
|
||||||
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
||||||
rec, err := api.DNSRecord(zoneID, recordID)
|
rec, err := api.DNSRecord(zoneID, recordID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -112,13 +104,11 @@ func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// DeleteDNSRecord deletes a single DNS record for the given zone & record
|
||||||
Delete a DNS record.
|
// identifiers.
|
||||||
|
// API reference:
|
||||||
API reference:
|
// https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
|
||||||
https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record
|
// DELETE /zones/:zone_identifier/dns_records/:identifier
|
||||||
DELETE /zones/:zone_identifier/dns_records/:identifier
|
|
||||||
*/
|
|
||||||
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
|
func (api *API) DeleteDNSRecord(zoneID, recordID string) error {
|
||||||
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
uri := "/zones/" + zoneID + "/dns_records/" + recordID
|
||||||
res, err := api.makeRequest("DELETE", uri, nil)
|
res, err := api.makeRequest("DELETE", uri, nil)
|
|
@ -0,0 +1,47 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
// Error messages
|
||||||
|
const (
|
||||||
|
errEmptyCredentials = "invalid credentials: key & email must not be empty"
|
||||||
|
errMakeRequestError = "error from makeRequest"
|
||||||
|
errUnmarshalError = "error unmarshalling the JSON response"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ Error = &UserError{}
|
||||||
|
|
||||||
|
// Error represents an error returned from this library.
|
||||||
|
type Error interface {
|
||||||
|
error
|
||||||
|
// Raised when user credentials or configuration is invalid.
|
||||||
|
User() bool
|
||||||
|
// Raised when a parsing error (e.g. JSON) occurs.
|
||||||
|
Parse() bool
|
||||||
|
// Raised when a network error occurs.
|
||||||
|
Network() bool
|
||||||
|
// Contains the most recent error.
|
||||||
|
}
|
||||||
|
|
||||||
|
// UserError represents a user-generated error.
|
||||||
|
type UserError struct {
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// User is a user-caused error.
|
||||||
|
func (e *UserError) User() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Network error.
|
||||||
|
func (e *UserError) Network() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse error.
|
||||||
|
func (e *UserError) Parse() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error wraps the underlying error.
|
||||||
|
func (e *UserError) Error() string {
|
||||||
|
return e.Err.Error()
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
// CreateKeyless creates a new Keyless SSL configuration for the zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-create-a-keyless-ssl-configuration
|
||||||
|
// POST /zones/:zone_identifier/keyless_certificates
|
||||||
|
func (api *API) CreateKeyless() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListKeyless lists Keyless SSL configurations for a zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-list-keyless-ssls
|
||||||
|
// GET /zones/:zone_identifier/keyless_certificates
|
||||||
|
func (api *API) ListKeyless() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keyless provides the configuration for a given Keyless SSL identifier.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-keyless-ssl-details
|
||||||
|
// GET /zones/:zone_identifier/keyless_certificates/:identifier
|
||||||
|
func (api *API) Keyless() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateKeyless updates an existing Keyless SSL configuration.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-update-keyless-configuration
|
||||||
|
// PATCH /zones/:zone_identifier/keyless_certificates/:identifier
|
||||||
|
func (api *API) UpdateKeyless() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteKeyless deletes an existing Keyless SSL configuration.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-delete-keyless-configuration
|
||||||
|
// DELETE /zones/:zone_identifier/keyless_certificates/:identifier
|
||||||
|
func (api *API) DeleteKeyless() {
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
// Option is a functional option for configuring the API client.
|
||||||
|
type Option func(*API) error
|
||||||
|
|
||||||
|
// HTTPClient accepts a custom *http.Client for making API calls.
|
||||||
|
func HTTPClient(client *http.Client) Option {
|
||||||
|
return func(api *API) error {
|
||||||
|
api.httpClient = client
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers allows you to set custom HTTP headers when making API calls (e.g. for
|
||||||
|
// satisfying HTTP proxies, or for debugging).
|
||||||
|
func Headers(headers http.Header) Option {
|
||||||
|
return func(api *API) error {
|
||||||
|
api.headers = headers
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseOptions parses the supplied options functions and returns a configured
|
||||||
|
// *API instance.
|
||||||
|
func (api *API) parseOptions(opts ...Option) error {
|
||||||
|
// Range over each options function and apply it to our API type to
|
||||||
|
// configure it. Options functions are applied in order, with any
|
||||||
|
// conflicting options overriding earlier calls.
|
||||||
|
for _, option := range opts {
|
||||||
|
err := option(api)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
// Organization represents a multi-user organization.
|
||||||
|
type Organization struct {
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
Permissions []string `json:"permissions,omitempty"`
|
||||||
|
Roles []string `json:"roles,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrganizationResponse represents the response from the Organization endpoint.
|
||||||
|
type OrganizationResponse struct {
|
||||||
|
Response
|
||||||
|
Result []Organization `json:"result"`
|
||||||
|
ResultInfo ResultInfo `json:"result_info"`
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ package cloudflare
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
@ -32,13 +33,13 @@ Valid IDs are:
|
||||||
cache_level
|
cache_level
|
||||||
disable_apps
|
disable_apps
|
||||||
disable_performance
|
disable_performance
|
||||||
|
disable_railgun
|
||||||
disable_security
|
disable_security
|
||||||
edge_cache_ttl
|
edge_cache_ttl
|
||||||
email_obfuscation
|
email_obfuscation
|
||||||
forwarding_url
|
forwarding_url
|
||||||
ip_geolocation
|
ip_geolocation
|
||||||
mirage
|
mirage
|
||||||
railgun
|
|
||||||
rocket_loader
|
rocket_loader
|
||||||
security_level
|
security_level
|
||||||
server_side_exclude
|
server_side_exclude
|
||||||
|
@ -60,13 +61,13 @@ var PageRuleActions = map[string]string{
|
||||||
"cache_level": "Cache Level", // Value of type string
|
"cache_level": "Cache Level", // Value of type string
|
||||||
"disable_apps": "Disable Apps", // Value of type interface{}
|
"disable_apps": "Disable Apps", // Value of type interface{}
|
||||||
"disable_performance": "Disable Performance", // Value of type interface{}
|
"disable_performance": "Disable Performance", // Value of type interface{}
|
||||||
|
"disable_railgun": "Disable Railgun", // Value of type string
|
||||||
"disable_security": "Disable Security", // Value of type interface{}
|
"disable_security": "Disable Security", // Value of type interface{}
|
||||||
"edge_cache_ttl": "Edge Cache TTL", // Value of type int
|
"edge_cache_ttl": "Edge Cache TTL", // Value of type int
|
||||||
"email_obfuscation": "Email Obfuscation", // Value of type string
|
"email_obfuscation": "Email Obfuscation", // Value of type string
|
||||||
"forwarding_url": "Forwarding URL", // Value of type map[string]interface
|
"forwarding_url": "Forwarding URL", // Value of type map[string]interface
|
||||||
"ip_geolocation": "IP Geolocation Header", // Value of type string
|
"ip_geolocation": "IP Geolocation Header", // Value of type string
|
||||||
"mirage": "Mirage", // Value of type string
|
"mirage": "Mirage", // Value of type string
|
||||||
"railgun": "Railgun", // Value of type string
|
|
||||||
"rocket_loader": "Rocker Loader", // Value of type string
|
"rocket_loader": "Rocker Loader", // Value of type string
|
||||||
"security_level": "Security Level", // Value of type string
|
"security_level": "Security Level", // Value of type string
|
||||||
"server_side_exclude": "Server Side Excludes", // Value of type string
|
"server_side_exclude": "Server Side Excludes", // Value of type string
|
||||||
|
@ -82,8 +83,8 @@ type PageRule struct {
|
||||||
Actions []PageRuleAction `json:"actions"`
|
Actions []PageRuleAction `json:"actions"`
|
||||||
Priority int `json:"priority"`
|
Priority int `json:"priority"`
|
||||||
Status string `json:"status"` // can be: active, paused
|
Status string `json:"status"` // can be: active, paused
|
||||||
ModifiedOn string `json:"modified_on,omitempty"`
|
ModifiedOn time.Time `json:"modified_on,omitempty"`
|
||||||
CreatedOn string `json:"created_on,omitempty"`
|
CreatedOn time.Time `json:"created_on,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PageRuleDetailResponse is the API response, containing a single PageRule.
|
// PageRuleDetailResponse is the API response, containing a single PageRule.
|
|
@ -0,0 +1,311 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Railgun represents a Railgun's properties.
|
||||||
|
type Railgun struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
ZonesConnected int `json:"zones_connected"`
|
||||||
|
Build string `json:"build"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Revision string `json:"revision"`
|
||||||
|
ActivationKey string `json:"activation_key"`
|
||||||
|
ActivatedOn time.Time `json:"activated_on"`
|
||||||
|
CreatedOn time.Time `json:"created_on"`
|
||||||
|
ModifiedOn time.Time `json:"modified_on"`
|
||||||
|
UpgradeInfo struct {
|
||||||
|
LatestVersion string `json:"latest_version"`
|
||||||
|
DownloadLink string `json:"download_link"`
|
||||||
|
} `json:"upgrade_info"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RailgunListOptions represents the parameters used to list railguns.
|
||||||
|
type RailgunListOptions struct {
|
||||||
|
Direction string
|
||||||
|
}
|
||||||
|
|
||||||
|
// railgunResponse represents the response from the Create Railgun and the Railgun Details endpoints.
|
||||||
|
type railgunResponse struct {
|
||||||
|
Response
|
||||||
|
Result Railgun `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// railgunsResponse represents the response from the List Railguns endpoint.
|
||||||
|
type railgunsResponse struct {
|
||||||
|
Response
|
||||||
|
Result []Railgun `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRailgun creates a new Railgun.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-create-railgun
|
||||||
|
// POST /railguns
|
||||||
|
func (api *API) CreateRailgun(name string) (Railgun, error) {
|
||||||
|
uri := "/railguns"
|
||||||
|
params := struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
}{
|
||||||
|
Name: name,
|
||||||
|
}
|
||||||
|
res, err := api.makeRequest("POST", uri, params)
|
||||||
|
if err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r railgunResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListRailguns lists Railguns connected to an account.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-list-railguns
|
||||||
|
// GET /railguns
|
||||||
|
func (api *API) ListRailguns(options RailgunListOptions) ([]Railgun, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
if options.Direction != "" {
|
||||||
|
v.Set("direction", options.Direction)
|
||||||
|
}
|
||||||
|
uri := "/railguns" + "?" + v.Encode()
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r railgunsResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RailgunDetails returns the details for a Railgun.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-railgun-details
|
||||||
|
// GET /railguns/:identifier
|
||||||
|
func (api *API) RailgunDetails(railgunID string) (Railgun, error) {
|
||||||
|
uri := "/railguns/" + railgunID
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r railgunResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RailgunZones returns the zones that are currently using a Railgun.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-get-zones-connected-to-a-railgun
|
||||||
|
// GET /railguns/:identifier/zones
|
||||||
|
func (api *API) RailgunZones(railgunID string) ([]Zone, error) {
|
||||||
|
uri := "/railguns/" + railgunID + "/zones"
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r ZonesResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// enableRailgun enables (true) or disables (false) a Railgun for all zones connected to it.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||||
|
// PATCH /railguns/:identifier
|
||||||
|
func (api *API) enableRailgun(railgunID string, enable bool) (Railgun, error) {
|
||||||
|
uri := "/railguns/" + railgunID
|
||||||
|
params := struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}{
|
||||||
|
Enabled: enable,
|
||||||
|
}
|
||||||
|
res, err := api.makeRequest("PATCH", uri, params)
|
||||||
|
if err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r railgunResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return Railgun{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnableRailgun enables a Railgun for all zones connected to it.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||||
|
// PATCH /railguns/:identifier
|
||||||
|
func (api *API) EnableRailgun(railgunID string) (Railgun, error) {
|
||||||
|
return api.enableRailgun(railgunID, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DisableRailgun enables a Railgun for all zones connected to it.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
||||||
|
// PATCH /railguns/:identifier
|
||||||
|
func (api *API) DisableRailgun(railgunID string) (Railgun, error) {
|
||||||
|
return api.enableRailgun(railgunID, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteRailgun disables and deletes a Railgun.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-delete-railgun
|
||||||
|
// DELETE /railguns/:identifier
|
||||||
|
func (api *API) DeleteRailgun(railgunID string) error {
|
||||||
|
uri := "/railguns/" + railgunID
|
||||||
|
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||||
|
return errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneRailgun represents the status of a Railgun on a zone.
|
||||||
|
type ZoneRailgun struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneRailgunResponse represents the response from the Zone Railgun Details endpoint.
|
||||||
|
type zoneRailgunResponse struct {
|
||||||
|
Response
|
||||||
|
Result ZoneRailgun `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneRailgunsResponse represents the response from the Zone Railgun endpoint.
|
||||||
|
type zoneRailgunsResponse struct {
|
||||||
|
Response
|
||||||
|
Result []ZoneRailgun `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// RailgunDiagnosis represents the test results from testing railgun connections
|
||||||
|
// to a zone.
|
||||||
|
type RailgunDiagnosis struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
HostName string `json:"host_name"`
|
||||||
|
HTTPStatus int `json:"http_status"`
|
||||||
|
Railgun string `json:"railgun"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
ResponseStatus string `json:"response_status"`
|
||||||
|
Protocol string `json:"protocol"`
|
||||||
|
ElapsedTime string `json:"elapsed_time"`
|
||||||
|
BodySize string `json:"body_size"`
|
||||||
|
BodyHash string `json:"body_hash"`
|
||||||
|
MissingHeaders string `json:"missing_headers"`
|
||||||
|
ConnectionClose bool `json:"connection_close"`
|
||||||
|
Cloudflare string `json:"cloudflare"`
|
||||||
|
CFRay string `json:"cf-ray"`
|
||||||
|
// NOTE: CloudFlare's online API documentation does not yet have definitions
|
||||||
|
// for the following fields. See: https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection/
|
||||||
|
CFWANError string `json:"cf-wan-error"`
|
||||||
|
CFCacheStatus string `json:"cf-cache-status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// railgunDiagnosisResponse represents the response from the Test Railgun Connection enpoint.
|
||||||
|
type railgunDiagnosisResponse struct {
|
||||||
|
Response
|
||||||
|
Result RailgunDiagnosis `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneRailguns returns the available Railguns for a zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railguns-for-a-zone-get-available-railguns
|
||||||
|
// GET /zones/:zone_identifier/railguns
|
||||||
|
func (api *API) ZoneRailguns(zoneID string) ([]ZoneRailgun, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/railguns"
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneRailgunsResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Railgun returns the configuration for a given Railgun.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
|
||||||
|
// GET /zones/:zone_identifier/railguns/:identifier
|
||||||
|
func (api *API) ZoneRailgunDetails(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/railguns/" + railgunID
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneRailgunResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestRailgunResponse tests a Railgun connection for a given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railgun-connections-for-a-zone-test-railgun-connection
|
||||||
|
// GET /zones/:zone_identifier/railguns/:identifier/diagnose
|
||||||
|
func (api *API) TestRailgunConnection(zoneID, railgunID string) (RailgunDiagnosis, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/railguns/" + railgunID + "/diagnose"
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return RailgunDiagnosis{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r railgunDiagnosisResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return RailgunDiagnosis{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// connectZoneRailgun connects (true) or disconnects (false) a Railgun for a given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||||
|
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||||
|
func (api *API) connectZoneRailgun(zoneID, railgunID string, connect bool) (ZoneRailgun, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/railguns/" + railgunID
|
||||||
|
params := struct {
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
}{
|
||||||
|
Connected: connect,
|
||||||
|
}
|
||||||
|
res, err := api.makeRequest("PATCH", uri, params)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneRailgun{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneRailgunResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return ZoneRailgun{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneRailgun connects a Railgun for a given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||||
|
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||||
|
func (api *API) ConnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||||
|
return api.connectZoneRailgun(zoneID, railgunID, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneRailgun disconnects a Railgun for a given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
||||||
|
// PATCH /zones/:zone_identifier/railguns/:identifier
|
||||||
|
func (api *API) DisconnectZoneRailgun(zoneID, railgunID string) (ZoneRailgun, error) {
|
||||||
|
return api.connectZoneRailgun(zoneID, railgunID, false)
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ZoneCustomSSL represents custom SSL certificate metadata.
|
||||||
|
type ZoneCustomSSL struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Hosts []string `json:"hosts"`
|
||||||
|
Issuer string `json:"issuer"`
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
BundleMethod string `json:"bundle_method"`
|
||||||
|
ZoneID string `json:"zone_id"`
|
||||||
|
UploadedOn time.Time `json:"uploaded_on"`
|
||||||
|
ModifiedOn time.Time `json:"modified_on"`
|
||||||
|
ExpiresOn time.Time `json:"expires_on"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
KeylessServer KeylessSSL `json:"keyless_server"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneCustomSSLResponse represents the response from the zone SSL details endpoint.
|
||||||
|
type zoneCustomSSLResponse struct {
|
||||||
|
Response
|
||||||
|
Result ZoneCustomSSL `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneCustomSSLsResponse represents the response from the zone SSL list endpoint.
|
||||||
|
type zoneCustomSSLsResponse struct {
|
||||||
|
Response
|
||||||
|
Result []ZoneCustomSSL `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneCustomSSLOptions represents the parameters to create or update an existing
|
||||||
|
// custom SSL configuration.
|
||||||
|
type ZoneCustomSSLOptions struct {
|
||||||
|
Certificate string `json:"certificate"`
|
||||||
|
PrivateKey string `json:"private_key"`
|
||||||
|
BundleMethod string `json:"bundle_method,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneCustomSSLPriority represents a certificate's ID and priority. It is a
|
||||||
|
// subset of ZoneCustomSSL used for patch requests.
|
||||||
|
type ZoneCustomSSLPriority struct {
|
||||||
|
ID string `json:"ID"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSSL allows you to add a custom SSL certificate to the given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-create-ssl-configuration
|
||||||
|
// POST /zones/:zone_identifier/custom_certificates
|
||||||
|
func (api *API) CreateSSL(zoneID string, options ZoneCustomSSLOptions) (ZoneCustomSSL, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates"
|
||||||
|
res, err := api.makeRequest("POST", uri, options)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneCustomSSLResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSSL lists the custom certificates for the given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-list-ssl-configurations
|
||||||
|
// GET /zones/:zone_identifier/custom_certificates
|
||||||
|
func (api *API) ListSSL(zoneID string) ([]ZoneCustomSSL, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates"
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneCustomSSLsResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SSLDetails returns the configuration details for a custom SSL certificate.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-ssl-configuration-details
|
||||||
|
// GET /zones/:zone_identifier/custom_certificates/:identifier
|
||||||
|
func (api *API) SSLDetails(zoneID, certificateID string) (ZoneCustomSSL, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneCustomSSLResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateSSL updates (replaces) a custom SSL certificate.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-update-ssl-configuration
|
||||||
|
// PATCH /zones/:zone_identifier/custom_certificates/:identifier
|
||||||
|
func (api *API) UpdateSSL(zoneID, certificateID string, options ZoneCustomSSLOptions) (ZoneCustomSSL, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||||
|
res, err := api.makeRequest("PATCH", uri, options)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneCustomSSLResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return ZoneCustomSSL{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReprioritizeSSL allows you to change the priority (which is served for a given
|
||||||
|
// request) of custom SSL certificates associated with the given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-re-prioritize-ssl-certificates
|
||||||
|
// PUT /zones/:zone_identifier/custom_certificates/prioritize
|
||||||
|
func (api *API) ReprioritizeSSL(zoneID string, p []ZoneCustomSSLPriority) ([]ZoneCustomSSL, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates/prioritize"
|
||||||
|
params := struct {
|
||||||
|
Certificates []ZoneCustomSSLPriority `json:"certificates"`
|
||||||
|
}{
|
||||||
|
Certificates: p,
|
||||||
|
}
|
||||||
|
res, err := api.makeRequest("PUT", uri, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneCustomSSLsResponse
|
||||||
|
if err := json.Unmarshal(res, &r); err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSSL deletes a custom SSL certificate from the given zone.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#custom-ssl-for-a-zone-delete-an-ssl-certificate
|
||||||
|
// DELETE /zones/:zone_identifier/custom_certificates/:identifier
|
||||||
|
func (api *API) DeleteSSL(zoneID, certificateID string) error {
|
||||||
|
uri := "/zones/" + zoneID + "/custom_certificates/" + certificateID
|
||||||
|
if _, err := api.makeRequest("DELETE", uri, nil); err != nil {
|
||||||
|
return errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,30 +6,30 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
// UserDetails provides information about the logged-in user.
|
||||||
Information about the logged-in user.
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#user-user-details
|
||||||
API reference: https://api.cloudflare.com/#user-user-details
|
// GET /user
|
||||||
*/
|
func (api *API) UserDetails() (User, error) {
|
||||||
func (api API) UserDetails() (User, error) {
|
|
||||||
var r UserResponse
|
var r UserResponse
|
||||||
res, err := api.makeRequest("GET", "/user", nil)
|
res, err := api.makeRequest("GET", "/user", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return User{}, errors.Wrap(err, errMakeRequestError)
|
return User{}, errors.Wrap(err, errMakeRequestError)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(res, &r)
|
err = json.Unmarshal(res, &r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return User{}, errors.Wrap(err, errUnmarshalError)
|
return User{}, errors.Wrap(err, errUnmarshalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Result, nil
|
return r.Result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// UpdateUser updates the properties of the given user.
|
||||||
Update user properties.
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#user-update-user
|
||||||
API reference: https://api.cloudflare.com/#user-update-user
|
// PATCH /user
|
||||||
*/
|
func (api *API) UpdateUser() (User, error) {
|
||||||
func (api API) UpdateUser() (User, error) {
|
|
||||||
// api.makeRequest("PATCH", "/user", user)
|
// api.makeRequest("PATCH", "/user", user)
|
||||||
return User{}, nil
|
return User{}, nil
|
||||||
}
|
}
|
|
@ -0,0 +1,130 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// VirtualDNS represents a Virtual DNS configuration.
|
||||||
|
type VirtualDNS struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
OriginIPs []string `json:"origin_ips"`
|
||||||
|
VirtualDNSIPs []string `json:"virtual_dns_ips"`
|
||||||
|
MinimumCacheTTL uint `json:"minimum_cache_ttl"`
|
||||||
|
MaximumCacheTTL uint `json:"maximum_cache_ttl"`
|
||||||
|
DeprecateAnyRequests bool `json:"deprecate_any_requests"`
|
||||||
|
ModifiedOn string `json:"modified_on"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VirtualDNSResponse represents a Virtual DNS response.
|
||||||
|
type VirtualDNSResponse struct {
|
||||||
|
Response
|
||||||
|
Result *VirtualDNS `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VirtualDNSListResponse represents an array of Virtual DNS responses.
|
||||||
|
type VirtualDNSListResponse struct {
|
||||||
|
Response
|
||||||
|
Result []*VirtualDNS `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateVirtualDNS creates a new Virtual DNS cluster.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#virtual-dns-users--create-a-virtual-dns-cluster
|
||||||
|
// POST /user/virtual_dns
|
||||||
|
func (api *API) CreateVirtualDNS(v *VirtualDNS) (*VirtualDNS, error) {
|
||||||
|
res, err := api.makeRequest("POST", "/user/virtual_dns", v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &VirtualDNSResponse{}
|
||||||
|
err = json.Unmarshal(res, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VirtualDNS fetches a single virtual DNS cluster.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#virtual-dns-users--get-a-virtual-dns-cluster
|
||||||
|
// GET /user/virtual_dns/:identifier
|
||||||
|
func (api *API) VirtualDNS(virtualDNSID string) (*VirtualDNS, error) {
|
||||||
|
uri := "/user/virtual_dns/" + virtualDNSID
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &VirtualDNSResponse{}
|
||||||
|
err = json.Unmarshal(res, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListVirtualDNS lists the virtual DNS clusters associated with an account.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#virtual-dns-users--get-virtual-dns-clusters
|
||||||
|
// GET /user/virtual_dns
|
||||||
|
func (api *API) ListVirtualDNS() ([]*VirtualDNS, error) {
|
||||||
|
res, err := api.makeRequest("GET", "/user/virtual_dns", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &VirtualDNSListResponse{}
|
||||||
|
err = json.Unmarshal(res, &response)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateVirtualDNS updates a Virtual DNS cluster.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#virtual-dns-users--modify-a-virtual-dns-cluster
|
||||||
|
// PATCH /user/virtual_dns/:identifier
|
||||||
|
func (api *API) UpdateVirtualDNS(virtualDNSID string, vv VirtualDNS) error {
|
||||||
|
uri := "/user/virtual_dns/" + virtualDNSID
|
||||||
|
res, err := api.makeRequest("PUT", uri, vv)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &VirtualDNSResponse{}
|
||||||
|
err = json.Unmarshal(res, &response)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteVirtualDNS deletes a Virtual DNS cluster. Note that this cannot be
|
||||||
|
// undone, and will stop all traffic to that cluster.
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#virtual-dns-users--delete-a-virtual-dns-cluster
|
||||||
|
// DELETE /user/virtual_dns/:identifier
|
||||||
|
func (api *API) DeleteVirtualDNS(virtualDNSID string) error {
|
||||||
|
uri := "/user/virtual_dns/" + virtualDNSID
|
||||||
|
res, err := api.makeRequest("DELETE", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
response := &VirtualDNSResponse{}
|
||||||
|
err = json.Unmarshal(res, &response)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ListWAFPackages returns a slice of the WAF packages for the given zone.
|
||||||
func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
|
func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
|
||||||
var p WAFPackagesResponse
|
var p WAFPackagesResponse
|
||||||
var packages []WAFPackage
|
var packages []WAFPackage
|
||||||
|
@ -24,12 +25,13 @@ func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) {
|
||||||
// TODO: Provide an actual error message instead of always returning nil
|
// TODO: Provide an actual error message instead of always returning nil
|
||||||
return []WAFPackage{}, err
|
return []WAFPackage{}, err
|
||||||
}
|
}
|
||||||
for pi, _ := range p.Result {
|
for pi := range p.Result {
|
||||||
packages = append(packages, p.Result[pi])
|
packages = append(packages, p.Result[pi])
|
||||||
}
|
}
|
||||||
return packages, nil
|
return packages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListWAFRules returns a slice of the WAF rules for the given WAF package.
|
||||||
func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
|
func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
|
||||||
var r WAFRulesResponse
|
var r WAFRulesResponse
|
||||||
var rules []WAFRule
|
var rules []WAFRule
|
||||||
|
@ -48,7 +50,7 @@ func (api *API) ListWAFRules(zoneID, packageID string) ([]WAFRule, error) {
|
||||||
// TODO: Provide an actual error message instead of always returning nil
|
// TODO: Provide an actual error message instead of always returning nil
|
||||||
return []WAFRule{}, err
|
return []WAFRule{}, err
|
||||||
}
|
}
|
||||||
for ri, _ := range r.Result {
|
for ri := range r.Result {
|
||||||
rules = append(rules, r.Result[ri])
|
rules = append(rules, r.Result[ri])
|
||||||
}
|
}
|
||||||
return rules, nil
|
return rules, nil
|
|
@ -0,0 +1,502 @@
|
||||||
|
package cloudflare
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Zone describes a CloudFlare zone.
|
||||||
|
type Zone struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
DevMode int `json:"development_mode"`
|
||||||
|
OriginalNS []string `json:"original_name_servers"`
|
||||||
|
OriginalRegistrar string `json:"original_registrar"`
|
||||||
|
OriginalDNSHost string `json:"original_dnshost"`
|
||||||
|
CreatedOn string `json:"created_on"`
|
||||||
|
ModifiedOn string `json:"modified_on"`
|
||||||
|
NameServers []string `json:"name_servers"`
|
||||||
|
Owner Owner `json:"owner"`
|
||||||
|
Permissions []string `json:"permissions"`
|
||||||
|
Plan ZonePlan `json:"plan"`
|
||||||
|
PlanPending ZonePlan `json:"plan_pending,omitempty"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Paused bool `json:"paused"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Host struct {
|
||||||
|
Name string
|
||||||
|
Website string
|
||||||
|
} `json:"host"`
|
||||||
|
VanityNS []string `json:"vanity_name_servers"`
|
||||||
|
Betas []string `json:"betas"`
|
||||||
|
DeactReason string `json:"deactivation_reason"`
|
||||||
|
Meta ZoneMeta `json:"meta"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneMeta metadata about a zone.
|
||||||
|
type ZoneMeta struct {
|
||||||
|
// custom_certificate_quota is broken - sometimes it's a string, sometimes a number!
|
||||||
|
// CustCertQuota int `json:"custom_certificate_quota"`
|
||||||
|
PageRuleQuota int `json:"page_rule_quota"`
|
||||||
|
WildcardProxiable bool `json:"wildcard_proxiable"`
|
||||||
|
PhishingDetected bool `json:"phishing_detected"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZonePlan contains the plan information for a zone.
|
||||||
|
type ZonePlan struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
Price int `json:"price,omitempty"`
|
||||||
|
Currency string `json:"currency,omitempty"`
|
||||||
|
Frequency string `json:"frequency,omitempty"`
|
||||||
|
LegacyID string `json:"legacy_id,omitempty"`
|
||||||
|
IsSubscribed bool `json:"is_subscribed,omitempty"`
|
||||||
|
CanSubscribe bool `json:"can_subscribe,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneID contains only the zone ID.
|
||||||
|
type ZoneID struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneResponse represents the response from the Zone endpoint containing a single zone.
|
||||||
|
type ZoneResponse struct {
|
||||||
|
Response
|
||||||
|
Result Zone `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZonesResponse represents the response from the Zone endpoint containing an array of zones.
|
||||||
|
type ZonesResponse struct {
|
||||||
|
Response
|
||||||
|
Result []Zone `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneIDResponse represents the response from the Zone endpoint, containing only a zone ID.
|
||||||
|
type ZoneIDResponse struct {
|
||||||
|
Response
|
||||||
|
Result ZoneID `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableZonePlansResponse represents the response from the Available Plans endpoint.
|
||||||
|
type AvailableZonePlansResponse struct {
|
||||||
|
Response
|
||||||
|
Result []ZonePlan `json:"result"`
|
||||||
|
ResultInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZonePlanResponse represents the response from the Plan Details endpoint.
|
||||||
|
type ZonePlanResponse struct {
|
||||||
|
Response
|
||||||
|
Result ZonePlan `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneSetting contains settings for a zone.
|
||||||
|
type ZoneSetting struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Editable bool `json:"editable"`
|
||||||
|
ModifiedOn string `json:"modified_on"`
|
||||||
|
Value interface{} `json:"value"`
|
||||||
|
TimeRemaining int `json:"time_remaining"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneSettingResponse represents the response from the Zone Setting endpoint.
|
||||||
|
type ZoneSettingResponse struct {
|
||||||
|
Response
|
||||||
|
Result []ZoneSetting `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalyticsData contains totals and timeseries analytics data for a zone.
|
||||||
|
type ZoneAnalyticsData struct {
|
||||||
|
Totals ZoneAnalytics `json:"totals"`
|
||||||
|
Timeseries []ZoneAnalytics `json:"timeseries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneAnalyticsDataResponse represents the response from the Zone Analytics Dashboard endpoint.
|
||||||
|
type zoneAnalyticsDataResponse struct {
|
||||||
|
Response
|
||||||
|
Result ZoneAnalyticsData `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalyticsColocation contains analytics data by datacenter.
|
||||||
|
type ZoneAnalyticsColocation struct {
|
||||||
|
ColocationID string `json:"colo_id"`
|
||||||
|
Timeseries []ZoneAnalytics `json:"timeseries"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// zoneAnalyticsColocationResponse represents the response from the Zone Analytics By Co-location endpoint.
|
||||||
|
type zoneAnalyticsColocationResponse struct {
|
||||||
|
Response
|
||||||
|
Result []ZoneAnalyticsColocation `json:"result"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalytics contains analytics data for a zone.
|
||||||
|
type ZoneAnalytics struct {
|
||||||
|
Since time.Time `json:"since"`
|
||||||
|
Until time.Time `json:"until"`
|
||||||
|
Requests struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
Cached int `json:"cached"`
|
||||||
|
Uncached int `json:"uncached"`
|
||||||
|
ContentType map[string]int `json:"content_type"`
|
||||||
|
Country map[string]int `json:"country"`
|
||||||
|
SSL struct {
|
||||||
|
Encrypted int `json:"encrypted"`
|
||||||
|
Unencrypted int `json:"unencrypted"`
|
||||||
|
} `json:"ssl"`
|
||||||
|
HTTPStatus map[string]int `json:"http_status"`
|
||||||
|
} `json:"requests"`
|
||||||
|
Bandwidth struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
Cached int `json:"cached"`
|
||||||
|
Uncached int `json:"uncached"`
|
||||||
|
ContentType map[string]int `json:"content_type"`
|
||||||
|
Country map[string]int `json:"country"`
|
||||||
|
SSL struct {
|
||||||
|
Encrypted int `json:"encrypted"`
|
||||||
|
Unencrypted int `json:"unencrypted"`
|
||||||
|
} `json:"ssl"`
|
||||||
|
} `json:"bandwidth"`
|
||||||
|
Threats struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
Country map[string]int `json:"country"`
|
||||||
|
Type map[string]int `json:"type"`
|
||||||
|
} `json:"threats"`
|
||||||
|
Pageviews struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
SearchEngines map[string]int `json:"search_engines"`
|
||||||
|
} `json:"pageviews"`
|
||||||
|
Uniques struct {
|
||||||
|
All int `json:"all"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalyticsOptions represents the optional parameters in Zone Analytics
|
||||||
|
// endpoint requests.
|
||||||
|
type ZoneAnalyticsOptions struct {
|
||||||
|
Since *time.Time
|
||||||
|
Until *time.Time
|
||||||
|
Continuous *bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// newZone describes a new zone.
|
||||||
|
type newZone struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
JumpStart bool `json:"jump_start"`
|
||||||
|
// We use a pointer to get a nil type when the field is empty.
|
||||||
|
// This allows us to completely omit this with json.Marshal().
|
||||||
|
Organization *Organization `json:"organization,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateZone creates a zone on an account.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-create-a-zone
|
||||||
|
func (api *API) CreateZone(name string, jumpstart bool, org Organization) (Zone, error) {
|
||||||
|
var newzone newZone
|
||||||
|
newzone.Name = name
|
||||||
|
newzone.JumpStart = jumpstart
|
||||||
|
if org.ID != "" {
|
||||||
|
newzone.Organization = &org
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := api.makeRequest("POST", "/zones", newzone)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r ZoneResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneActivationCheck initiates another zone activation check for newly-created zones.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-initiate-another-zone-activation-check
|
||||||
|
func (api *API) ZoneActivationCheck(zoneID string) (Response, error) {
|
||||||
|
res, err := api.makeRequest("PUT", "/zones/"+zoneID+"/activation_check", nil)
|
||||||
|
if err != nil {
|
||||||
|
return Response{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r Response
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return Response{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListZones lists zones on an account. Optionally takes a list of zone names
|
||||||
|
// to filter against.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-list-zones
|
||||||
|
func (api *API) ListZones(z ...string) ([]Zone, error) {
|
||||||
|
v := url.Values{}
|
||||||
|
var res []byte
|
||||||
|
var r ZonesResponse
|
||||||
|
var zones []Zone
|
||||||
|
var err error
|
||||||
|
if len(z) > 0 {
|
||||||
|
for _, zone := range z {
|
||||||
|
v.Set("name", zone)
|
||||||
|
res, err = api.makeRequest("GET", "/zones?"+v.Encode(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
if !r.Success {
|
||||||
|
// TODO: Provide an actual error message instead of always returning nil
|
||||||
|
return []Zone{}, err
|
||||||
|
}
|
||||||
|
for zi := range r.Result {
|
||||||
|
zones = append(zones, r.Result[zi])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Paginate here. We only grab the first page of results.
|
||||||
|
// Could do this concurrently after the first request by creating a
|
||||||
|
// sync.WaitGroup or just a channel + workers.
|
||||||
|
res, err = api.makeRequest("GET", "/zones", nil)
|
||||||
|
if err != nil {
|
||||||
|
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
zones = r.Result
|
||||||
|
}
|
||||||
|
|
||||||
|
return zones, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneDetails fetches information about a zone.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-zone-details
|
||||||
|
func (api *API) ZoneDetails(zoneID string) (Zone, error) {
|
||||||
|
res, err := api.makeRequest("GET", "/zones"+zoneID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r ZoneResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneOptions is a subset of Zone, for editable options.
|
||||||
|
type ZoneOptions struct {
|
||||||
|
// FIXME(jamesog): Using omitempty here means we can't disable Paused.
|
||||||
|
// Currently unsure how to work around this.
|
||||||
|
Paused bool `json:"paused,omitempty"`
|
||||||
|
VanityNS []string `json:"vanity_name_servers,omitempty"`
|
||||||
|
Plan *ZonePlan `json:"plan,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneSetPaused pauses CloudFlare service for the entire zone, sending all
|
||||||
|
// traffic direct to the origin.
|
||||||
|
func (api *API) ZoneSetPaused(zoneID string, paused bool) (Zone, error) {
|
||||||
|
zoneopts := ZoneOptions{Paused: paused}
|
||||||
|
zone, err := api.EditZone(zoneID, zoneopts)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneSetVanityNS sets custom nameservers for the zone.
|
||||||
|
// These names must be within the same zone.
|
||||||
|
func (api *API) ZoneSetVanityNS(zoneID string, ns []string) (Zone, error) {
|
||||||
|
zoneopts := ZoneOptions{VanityNS: ns}
|
||||||
|
zone, err := api.EditZone(zoneID, zoneopts)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneSetPlan changes the zone plan.
|
||||||
|
func (api *API) ZoneSetPlan(zoneID string, plan ZonePlan) (Zone, error) {
|
||||||
|
zoneopts := ZoneOptions{Plan: &plan}
|
||||||
|
zone, err := api.EditZone(zoneID, zoneopts)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return zone, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EditZone edits the given zone.
|
||||||
|
// This is usually called by ZoneSetPaused, ZoneSetVanityNS or ZoneSetPlan.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-edit-zone-properties
|
||||||
|
func (api *API) EditZone(zoneID string, zoneOpts ZoneOptions) (Zone, error) {
|
||||||
|
res, err := api.makeRequest("PATCH", "/zones/"+zoneID, zoneOpts)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r ZoneResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return Zone{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurgeEverything purges the cache for the given zone.
|
||||||
|
// Note: this will substantially increase load on the origin server for that
|
||||||
|
// zone if there is a high cached vs. uncached request ratio.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-purge-all-files
|
||||||
|
func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/purge_cache"
|
||||||
|
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, nil, nil})
|
||||||
|
if err != nil {
|
||||||
|
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r PurgeCacheResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PurgeCache purges the cache using the given PurgeCacheRequest (zone/url/tag).
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-purge-individual-files-by-url-and-cache-tags
|
||||||
|
func (api *API) PurgeCache(zoneID string, pcr PurgeCacheRequest) (PurgeCacheResponse, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/purge_cache"
|
||||||
|
res, err := api.makeRequest("DELETE", uri, pcr)
|
||||||
|
if err != nil {
|
||||||
|
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r PurgeCacheResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteZone deletes the given zone.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-delete-a-zone
|
||||||
|
func (api *API) DeleteZone(zoneID string) (ZoneID, error) {
|
||||||
|
res, err := api.makeRequest("DELETE", "/zones"+zoneID, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneID{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r ZoneIDResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneID{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AvailableZonePlans returns information about all plans available to the specified zone.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-plan-available-plans
|
||||||
|
func (api *API) AvailableZonePlans(zoneID string) ([]ZonePlan, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/available_plans"
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return []ZonePlan{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r AvailableZonePlansResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return []ZonePlan{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZonePlanDetails returns information about a zone plan.
|
||||||
|
//
|
||||||
|
// API reference: https://api.cloudflare.com/#zone-plan-plan-details
|
||||||
|
func (api *API) ZonePlanDetails(zoneID, planID string) (ZonePlan, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/available_plans/" + planID
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ZonePlan{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r ZonePlanResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return ZonePlan{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode encodes non-nil fields into URL encoded form.
|
||||||
|
func (o ZoneAnalyticsOptions) encode() string {
|
||||||
|
v := url.Values{}
|
||||||
|
if o.Since != nil {
|
||||||
|
v.Set("since", (*o.Since).Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
if o.Until != nil {
|
||||||
|
v.Set("until", (*o.Until).Format(time.RFC3339))
|
||||||
|
}
|
||||||
|
if o.Continuous != nil {
|
||||||
|
v.Set("continuous", fmt.Sprintf("%t", *o.Continuous))
|
||||||
|
}
|
||||||
|
return v.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalyticsDashboard returns zone analytics information.
|
||||||
|
//
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#zone-analytics-dashboard
|
||||||
|
// GET /zones/:zone_identifier/analytics/dashboard
|
||||||
|
func (api *API) ZoneAnalyticsDashboard(zoneID string, options ZoneAnalyticsOptions) (ZoneAnalyticsData, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/analytics/dashboard" + "?" + options.encode()
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneAnalyticsData{}, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneAnalyticsDataResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return ZoneAnalyticsData{}, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ZoneAnalyticsByColocation returns zone analytics information by datacenter.
|
||||||
|
//
|
||||||
|
// API reference:
|
||||||
|
// https://api.cloudflare.com/#zone-analytics-analytics-by-co-locations
|
||||||
|
// GET /zones/:zone_identifier/analytics/colos
|
||||||
|
func (api *API) ZoneAnalyticsByColocation(zoneID string, options ZoneAnalyticsOptions) ([]ZoneAnalyticsColocation, error) {
|
||||||
|
uri := "/zones/" + zoneID + "/analytics/colos" + "?" + options.encode()
|
||||||
|
res, err := api.makeRequest("GET", uri, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errMakeRequestError)
|
||||||
|
}
|
||||||
|
var r zoneAnalyticsColocationResponse
|
||||||
|
err = json.Unmarshal(res, &r)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, errUnmarshalError)
|
||||||
|
}
|
||||||
|
return r.Result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Zone Settings
|
||||||
|
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-all-zone-settings
|
||||||
|
// e.g.
|
||||||
|
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-always-online-setting
|
||||||
|
// https://api.cloudflare.com/#zone-settings-for-a-zone-change-always-online-setting
|
|
@ -1,23 +0,0 @@
|
||||||
language: go
|
|
||||||
sudo: false
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- go: 1.4
|
|
||||||
- go: 1.5
|
|
||||||
- go: 1.6
|
|
||||||
- go: tip
|
|
||||||
allow_failures:
|
|
||||||
- go: tip
|
|
||||||
|
|
||||||
script:
|
|
||||||
- go get -t -v $(go list ./... | grep -v '/vendor/')
|
|
||||||
- diff -u <(echo -n) <(gofmt -d .)
|
|
||||||
- go vet $(go list ./... | grep -v '/vendor/')
|
|
||||||
- go test -v -race ./...
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email:
|
|
||||||
recipients:
|
|
||||||
- jamesog@cloudflare.com
|
|
||||||
- msilverlock@cloudflare.com
|
|
|
@ -1,44 +0,0 @@
|
||||||
[![GoDoc](https://godoc.org/github.com/cloudflare/cloudflare-go?status.svg)](https://godoc.org/github.com/cloudflare/cloudflare-go)
|
|
||||||
|
|
||||||
# cloudflare
|
|
||||||
|
|
||||||
A Go library for interacting with [CloudFlare's API v4](https://api.cloudflare.com/).
|
|
||||||
|
|
||||||
# Installation
|
|
||||||
|
|
||||||
You need a working Go environment.
|
|
||||||
|
|
||||||
```
|
|
||||||
go get github.com/cloudflare/cloudflare-go
|
|
||||||
```
|
|
||||||
|
|
||||||
# Getting Started
|
|
||||||
|
|
||||||
```
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/cloudflare/cloudflare-go"
|
|
||||||
)
|
|
||||||
|
|
||||||
var api *cloudflare.API
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// Construct a new API object
|
|
||||||
api = cloudflare.New(os.Getenv("CF_API_KEY"), os.Getenv("CF_API_EMAIL"))
|
|
||||||
|
|
||||||
// Fetch the list of zones on the account
|
|
||||||
zones, err := api.ListZones()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
// Print the zone names
|
|
||||||
for _, z := range zones {
|
|
||||||
fmt.Println(z.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
An example application, [flarectl](cmd/flarectl), is in this repository.
|
|
|
@ -1,451 +0,0 @@
|
||||||
/*
|
|
||||||
Package cloudflare implements the CloudFlare v4 API.
|
|
||||||
|
|
||||||
New API requests created like:
|
|
||||||
|
|
||||||
api := cloudflare.New(apikey, apiemail)
|
|
||||||
|
|
||||||
*/
|
|
||||||
package cloudflare
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
const apiURL = "https://api.cloudflare.com/client/v4"
|
|
||||||
|
|
||||||
// Error messages
|
|
||||||
const errMakeRequestError = "Error from makeRequest"
|
|
||||||
const errUnmarshalError = "Error unmarshalling JSON"
|
|
||||||
|
|
||||||
type API struct {
|
|
||||||
APIKey string
|
|
||||||
APIEmail string
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes the API configuration.
|
|
||||||
func New(key, email string) *API {
|
|
||||||
return &API{key, email}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializes a new zone.
|
|
||||||
func NewZone() *Zone {
|
|
||||||
return &Zone{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ZoneIDByName retrieves a zone's ID from the name.
|
|
||||||
func (api *API) ZoneIDByName(zoneName string) (string, error) {
|
|
||||||
res, err := api.ListZones(zoneName)
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err, "ListZones command failed")
|
|
||||||
}
|
|
||||||
for _, zone := range res {
|
|
||||||
if zone.Name == zoneName {
|
|
||||||
return zone.ID, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", errors.New("Zone could not be found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Params can be turned into a URL query string or a body
|
|
||||||
// TODO: Give this func a better name
|
|
||||||
func (api *API) makeRequest(method, uri string, params interface{}) ([]byte, error) {
|
|
||||||
// Replace nil with a JSON object if needed
|
|
||||||
var reqBody io.Reader
|
|
||||||
if params != nil {
|
|
||||||
json, err := json.Marshal(params)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "Error marshalling params to JSON")
|
|
||||||
}
|
|
||||||
reqBody = bytes.NewReader(json)
|
|
||||||
} else {
|
|
||||||
reqBody = nil
|
|
||||||
}
|
|
||||||
req, err := http.NewRequest(method, apiURL+uri, reqBody)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "HTTP request creation failed")
|
|
||||||
}
|
|
||||||
req.Header.Add("X-Auth-Key", api.APIKey)
|
|
||||||
req.Header.Add("X-Auth-Email", api.APIEmail)
|
|
||||||
// Could be application/json or multipart/form-data
|
|
||||||
// req.Header.Add("Content-Type", "application/json")
|
|
||||||
client := &http.Client{}
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "HTTP request failed")
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
resBody, err := ioutil.ReadAll(resp.Body)
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.Wrap(err, "Error returned from API")
|
|
||||||
} else if resBody != nil {
|
|
||||||
return nil, errors.New(string(resBody))
|
|
||||||
} else {
|
|
||||||
return nil, errors.New(resp.Status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resBody, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Response struct is a template. There will also be a result struct.
|
|
||||||
// There will be a unique response type for each response, which will include
|
|
||||||
// this type.
|
|
||||||
type Response struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ResultInfo struct {
|
|
||||||
Page int `json:"page"`
|
|
||||||
PerPage int `json:"per_page"`
|
|
||||||
Count int `json:"count"`
|
|
||||||
Total int `json:"total_count"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// An Organization describes a multi-user organization. (Enterprise only.)
|
|
||||||
type Organization struct {
|
|
||||||
ID string
|
|
||||||
Name string
|
|
||||||
Status string
|
|
||||||
Permissions []string
|
|
||||||
Roles []string
|
|
||||||
}
|
|
||||||
|
|
||||||
// A User describes a user account.
|
|
||||||
type User struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Telephone string `json:"telephone"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
Zipcode string `json:"zipcode"`
|
|
||||||
CreatedOn string `json:"created_on"` // Should this be a time.Date?
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
APIKey string `json:"api_key"`
|
|
||||||
TwoFA bool `json:"two_factor_authentication_enabled"`
|
|
||||||
Betas []string `json:"betas"`
|
|
||||||
Organizations []Organization `json:"organizations"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result User `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Owner struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
OwnerType string `json:"owner_type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// A Zone describes a CloudFlare zone.
|
|
||||||
type Zone struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
DevMode int `json:"development_mode"`
|
|
||||||
OriginalNS []string `json:"original_name_servers"`
|
|
||||||
OriginalRegistrar string `json:"original_registrar"`
|
|
||||||
OriginalDNSHost string `json:"original_dnshost"`
|
|
||||||
CreatedOn string `json:"created_on"`
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
NameServers []string `json:"name_servers"`
|
|
||||||
Owner Owner `json:"owner"`
|
|
||||||
Permissions []string `json:"permissions"`
|
|
||||||
Plan ZonePlan `json:"plan"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Paused bool `json:"paused"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
Host struct {
|
|
||||||
Name string
|
|
||||||
Website string
|
|
||||||
} `json:"host"`
|
|
||||||
VanityNS []string `json:"vanity_name_servers"`
|
|
||||||
Betas []string `json:"betas"`
|
|
||||||
DeactReason string `json:"deactivation_reason"`
|
|
||||||
Meta ZoneMeta `json:"meta"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains metadata about a zone.
|
|
||||||
type ZoneMeta struct {
|
|
||||||
// custom_certificate_quota is broken - sometimes it's a string, sometimes a number!
|
|
||||||
// CustCertQuota int `json:"custom_certificate_quota"`
|
|
||||||
PageRuleQuota int `json:"page_rule_quota"`
|
|
||||||
WildcardProxiable bool `json:"wildcard_proxiable"`
|
|
||||||
PhishingDetected bool `json:"phishing_detected"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Contains the plan information for a zone.
|
|
||||||
type ZonePlan struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Price int `json:"price"`
|
|
||||||
Currency string `json:"currency"`
|
|
||||||
Frequency string `json:"frequency"`
|
|
||||||
LegacyID string `json:"legacy_id"`
|
|
||||||
IsSubscribed bool `json:"is_subscribed"`
|
|
||||||
CanSubscribe bool `json:"can_subscribe"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZoneResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []Zone `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZonePlanResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []ZonePlan `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// type zoneSetting struct {
|
|
||||||
// ID string `json:"id"`
|
|
||||||
// Editable bool `json:"editable"`
|
|
||||||
// ModifiedOn string `json:"modified_on"`
|
|
||||||
// }
|
|
||||||
// type zoneSettingStringVal struct {
|
|
||||||
// zoneSetting
|
|
||||||
// Value string `json:"value"`
|
|
||||||
// }
|
|
||||||
// type zoneSettingIntVal struct {
|
|
||||||
// zoneSetting
|
|
||||||
// Value int64 `json:"value"`
|
|
||||||
// }
|
|
||||||
|
|
||||||
type ZoneSetting struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Editable bool `json:"editable"`
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
Value interface{} `json:"value"`
|
|
||||||
TimeRemaining int `json:"time_remaining"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZoneSettingResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []ZoneSetting `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Describes a DNS record for a zone.
|
|
||||||
type DNSRecord struct {
|
|
||||||
ID string `json:"id,omitempty"`
|
|
||||||
Type string `json:"type,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Content string `json:"content,omitempty"`
|
|
||||||
Proxiable bool `json:"proxiable,omitempty"`
|
|
||||||
Proxied bool `json:"proxied,omitempty"`
|
|
||||||
TTL int `json:"ttl,omitempty"`
|
|
||||||
Locked bool `json:"locked,omitempty"`
|
|
||||||
ZoneID string `json:"zone_id,omitempty"`
|
|
||||||
ZoneName string `json:"zone_name,omitempty"`
|
|
||||||
CreatedOn string `json:"created_on,omitempty"`
|
|
||||||
ModifiedOn string `json:"modified_on,omitempty"`
|
|
||||||
Data interface{} `json:"data,omitempty"` // data returned by: SRV, LOC
|
|
||||||
Meta interface{} `json:"meta,omitempty"`
|
|
||||||
Priority int `json:"priority,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// The response for creating or updating a DNS record.
|
|
||||||
type DNSRecordResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []interface{} `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result DNSRecord `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// The response for listing DNS records.
|
|
||||||
type DNSListResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []interface{} `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []DNSRecord `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Railgun status for a zone.
|
|
||||||
type ZoneRailgun struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"string"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Connected bool `json:"connected"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZoneRailgunResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []ZoneRailgun `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom SSL certificates for a zone.
|
|
||||||
type ZoneCustomSSL struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Hosts []string `json:"hosts"`
|
|
||||||
Issuer string `json:"issuer"`
|
|
||||||
Priority int `json:"priority"`
|
|
||||||
Status string `json:"success"`
|
|
||||||
BundleMethod string `json:"bundle_method"`
|
|
||||||
ZoneID string `json:"zone_id"`
|
|
||||||
Permissions []string `json:"permissions"`
|
|
||||||
UploadedOn string `json:"uploaded_on"`
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
ExpiresOn string `json:"expires_on"`
|
|
||||||
KeylessServer KeylessSSL `json:"keyless_server"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ZoneCustomSSLResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []ZoneCustomSSL `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeylessSSL struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Host string `json:"host"`
|
|
||||||
Port int `json:"port"`
|
|
||||||
Status string `json:"success"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
Permissions []string `json:"permissions"`
|
|
||||||
CreatedOn string `json:"created_on"`
|
|
||||||
ModifiedOn string `json:"modifed_on"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type KeylessSSLResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []KeylessSSL `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Railgun struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Status string `json:"success"`
|
|
||||||
Enabled bool `json:"enabled"`
|
|
||||||
ZonesConnected int `json:"zones_connected"`
|
|
||||||
Build string `json:"build"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
Revision string `json:"revision"`
|
|
||||||
ActivationKey string `json:"activation_key"`
|
|
||||||
ActivatedOn string `json:"activated_on"`
|
|
||||||
CreatedOn string `json:"created_on"`
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
// XXX: UpgradeInfo struct {
|
|
||||||
// version string
|
|
||||||
// url string
|
|
||||||
// } `json:"upgrade_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RailgunResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []Railgun `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Custom error pages.
|
|
||||||
type CustomPage struct {
|
|
||||||
CreatedOn string `json:"created_on"`
|
|
||||||
ModifiedOn string `json:"modified_on"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
State string `json:"state"`
|
|
||||||
RequiredTokens []string `json:"required_tokens"`
|
|
||||||
PreviewTarget string `json:"preview_target"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CustomPageResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result []CustomPage `json:"result"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// WAF packages
|
|
||||||
type WAFPackage struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
ZoneID string `json:"zone_id"`
|
|
||||||
DetectionMode string `json:"detection_mode"`
|
|
||||||
Sensitivity string `json:"sensitivity"`
|
|
||||||
ActionMode string `json:"action_mode"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WAFPackagesResponse struct {
|
|
||||||
Result []WAFPackage `json:"result"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
ResultInfo struct {
|
|
||||||
Page uint `json:"page"`
|
|
||||||
PerPage uint `json:"per_page"`
|
|
||||||
Count uint `json:"count"`
|
|
||||||
TotalCount uint `json:"total_count"`
|
|
||||||
} `json:"result_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WAFRule struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Priority string `json:"priority"`
|
|
||||||
PackageID string `json:"package_id"`
|
|
||||||
Group struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
} `json:"group"`
|
|
||||||
Mode string `json:"mode"`
|
|
||||||
DefaultMode string `json:"default_mode"`
|
|
||||||
AllowedModes []string `json:"allowed_modes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WAFRulesResponse struct {
|
|
||||||
Result []WAFRule `json:"result"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
ResultInfo struct {
|
|
||||||
Page uint `json:"page"`
|
|
||||||
PerPage uint `json:"per_page"`
|
|
||||||
Count uint `json:"count"`
|
|
||||||
TotalCount uint `json:"total_count"`
|
|
||||||
} `json:"result_info"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type PurgeCacheRequest struct {
|
|
||||||
Everything bool `json:"purge_everything,omitempty"`
|
|
||||||
Files []string `json:"files,omitempty"`
|
|
||||||
Tags []string `json:"tags,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type PurgeCacheResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPs contains a list of IPv4 and IPv6 CIDRs
|
|
||||||
type IPRanges struct {
|
|
||||||
IPv4CIDRs []string `json:"ipv4_cidrs"`
|
|
||||||
IPv6CIDRs []string `json:"ipv6_cidrs"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPsResponse is the API response containing a list of IPs
|
|
||||||
type IPsResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
Errors []string `json:"errors"`
|
|
||||||
Messages []string `json:"messages"`
|
|
||||||
Result IPRanges `json:"result"`
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package cloudflare
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-create-a-keyless-ssl-configuration
|
|
||||||
// POST /zones/:zone_identifier/keyless_certificates
|
|
||||||
func (c *API) CreateKeyless() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-list-keyless-ssls
|
|
||||||
// GET /zones/:zone_identifier/keyless_certificates
|
|
||||||
func (c *API) ListKeyless() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-keyless-ssl-details
|
|
||||||
// GET /zones/:zone_identifier/keyless_certificates/:identifier
|
|
||||||
func (c *API) Keyless() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-update-keyless-configuration
|
|
||||||
// PATCH /zones/:zone_identifier/keyless_certificates/:identifier
|
|
||||||
func (c *API) UpdateKeyless() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#keyless-ssl-for-a-zone-delete-keyless-configuration
|
|
||||||
// DELETE /zones/:zone_identifier/keyless_certificates/:identifier
|
|
||||||
func (c *API) DeleteKeyless() {
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package cloudflare
|
|
||||||
|
|
||||||
// Railgun
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railgun-create-railgun
|
|
||||||
// POST /railguns
|
|
||||||
func (c *API) CreateRailgun() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railgun-railgun-details
|
|
||||||
// GET /railguns/:identifier
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railgun-get-zones-connected-to-a-railgun
|
|
||||||
// GET /railguns/:identifier/zones
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railgun-enable-or-disable-a-railgun
|
|
||||||
// PATCH /railguns/:identifier
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railgun-delete-railgun
|
|
||||||
// DELETE /railguns/:identifier
|
|
||||||
|
|
||||||
// Zone railgun info
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railguns-for-a-zone-get-available-railguns
|
|
||||||
// GET /zones/:zone_identifier/railguns
|
|
||||||
func (c *API) Railguns() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railguns-for-a-zone-get-railgun-details
|
|
||||||
// GET /zones/:zone_identifier/railguns/:identifier
|
|
||||||
func (c *API) Railgun() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#railguns-for-a-zone-connect-or-disconnect-a-railgun
|
|
||||||
// PATCH /zones/:zone_identifier/railguns/:identifier
|
|
||||||
func (c *API) ZoneRailgun(connected bool) {
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
package cloudflare
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-create-ssl-configuration
|
|
||||||
// POST /zones/:zone_identifier/custom_certificates
|
|
||||||
func (c *API) CreateSSL() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-list-ssl-configurations
|
|
||||||
// GET /zones/:zone_identifier/custom_certificates
|
|
||||||
func (c *API) ListSSL() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-ssl-configuration-details
|
|
||||||
// GET /zones/:zone_identifier/custom_certificates/:identifier
|
|
||||||
func (c *API) SSLDetails() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-update-ssl-configuration
|
|
||||||
// PATCH /zones/:zone_identifier/custom_certificates/:identifier
|
|
||||||
func (c *API) UpdateSSL() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-re-prioritize-ssl-certificates
|
|
||||||
// PUT /zones/:zone_identifier/custom_certificates/prioritize
|
|
||||||
func (c *API) ReprioSSL() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#custom-ssl-for-a-zone-delete-an-ssl-certificate
|
|
||||||
// DELETE /zones/:zone_identifier/custom_certificates/:identifier
|
|
||||||
func (c *API) DeleteSSL() {
|
|
||||||
}
|
|
|
@ -1,145 +0,0 @@
|
||||||
package cloudflare
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"net/url"
|
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
Creates a zone on an account.
|
|
||||||
|
|
||||||
API reference: https://api.cloudflare.com/#zone-create-a-zone
|
|
||||||
*/
|
|
||||||
func (api *API) CreateZone(z Zone) {
|
|
||||||
// res, err := api.makeRequest("POST", "/zones", z)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
List zones on an account. Optionally takes a list of zones to filter results.
|
|
||||||
|
|
||||||
API reference: https://api.cloudflare.com/#zone-list-zones
|
|
||||||
*/
|
|
||||||
func (api *API) ListZones(z ...string) ([]Zone, error) {
|
|
||||||
v := url.Values{}
|
|
||||||
var res []byte
|
|
||||||
var r ZoneResponse
|
|
||||||
var zones []Zone
|
|
||||||
var err error
|
|
||||||
if len(z) > 0 {
|
|
||||||
for _, zone := range z {
|
|
||||||
v.Set("name", zone)
|
|
||||||
res, err = api.makeRequest("GET", "/zones?"+v.Encode(), nil)
|
|
||||||
if err != nil {
|
|
||||||
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(res, &r)
|
|
||||||
if err != nil {
|
|
||||||
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
|
||||||
}
|
|
||||||
if !r.Success {
|
|
||||||
// TODO: Provide an actual error message instead of always returning nil
|
|
||||||
return []Zone{}, err
|
|
||||||
}
|
|
||||||
for zi, _ := range r.Result {
|
|
||||||
zones = append(zones, r.Result[zi])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
res, err = api.makeRequest("GET", "/zones", nil)
|
|
||||||
if err != nil {
|
|
||||||
return []Zone{}, errors.Wrap(err, errMakeRequestError)
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(res, &r)
|
|
||||||
if err != nil {
|
|
||||||
return []Zone{}, errors.Wrap(err, errUnmarshalError)
|
|
||||||
}
|
|
||||||
zones = r.Result
|
|
||||||
}
|
|
||||||
|
|
||||||
return zones, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fetches information about a zone.
|
|
||||||
|
|
||||||
|
|
||||||
https://api.cloudflare.com/#zone-zone-details
|
|
||||||
GET /zones/:id
|
|
||||||
*/
|
|
||||||
func (api *API) ZoneDetails(z Zone) {
|
|
||||||
// XXX: Should we make the user get the zone ID themselves with ListZones, or do the hard work here?
|
|
||||||
// ListZones gives the same information as this endpoint anyway so perhaps this is of limited use?
|
|
||||||
// Maybe for users who already know the ID or fetched it in another call.
|
|
||||||
type result struct {
|
|
||||||
Response
|
|
||||||
Result Zone `json:"result"`
|
|
||||||
}
|
|
||||||
// If z has an ID then query for that directly, else call ListZones to
|
|
||||||
// fetch by name.
|
|
||||||
// var zone Zone
|
|
||||||
if z.ID != "" {
|
|
||||||
// res, _ := makeRequest(c, "GET", "/zones/"+z.ID, nil)
|
|
||||||
// zone = res.Result
|
|
||||||
} else {
|
|
||||||
// zones, err := ListZones(c, z.Name)
|
|
||||||
// if err != nil {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// Only one zone should have been returned
|
|
||||||
// zone := zones[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#zone-edit-zone-properties
|
|
||||||
// PATCH /zones/:id
|
|
||||||
func EditZone() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#zone-purge-all-files
|
|
||||||
// DELETE /zones/:id/purge_cache
|
|
||||||
func (api *API) PurgeEverything(zoneID string) (PurgeCacheResponse, error) {
|
|
||||||
uri := "/zones/" + zoneID + "/purge_cache"
|
|
||||||
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, nil, nil})
|
|
||||||
if err != nil {
|
|
||||||
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
|
||||||
}
|
|
||||||
var r PurgeCacheResponse
|
|
||||||
err = json.Unmarshal(res, &r)
|
|
||||||
if err != nil {
|
|
||||||
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#zone-purge-individual-files-by-url-and-cache-tags
|
|
||||||
// DELETE /zones/:id/purge_cache
|
|
||||||
func (api *API) PurgeCache(zoneID string, pcr PurgeCacheRequest) (PurgeCacheResponse, error) {
|
|
||||||
uri := "/zones/" + zoneID + "/purge_cache"
|
|
||||||
res, err := api.makeRequest("DELETE", uri, pcr)
|
|
||||||
if err != nil {
|
|
||||||
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
|
|
||||||
}
|
|
||||||
var r PurgeCacheResponse
|
|
||||||
err = json.Unmarshal(res, &r)
|
|
||||||
if err != nil {
|
|
||||||
return PurgeCacheResponse{}, errors.Wrap(err, errUnmarshalError)
|
|
||||||
}
|
|
||||||
return r, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://api.cloudflare.com/#zone-delete-a-zone
|
|
||||||
// DELETE /zones/:id
|
|
||||||
func DeleteZone() {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zone Plan
|
|
||||||
// https://api.cloudflare.com/#zone-plan-available-plans
|
|
||||||
// https://api.cloudflare.com/#zone-plan-plan-details
|
|
||||||
|
|
||||||
// Zone Settings
|
|
||||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-all-zone-settings
|
|
||||||
// e.g.
|
|
||||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-get-always-online-setting
|
|
||||||
// https://api.cloudflare.com/#zone-settings-for-a-zone-change-always-online-setting
|
|
|
@ -530,6 +530,12 @@
|
||||||
"path": "github.com/cenkalti/backoff",
|
"path": "github.com/cenkalti/backoff",
|
||||||
"revision": "4dc77674aceaabba2c7e3da25d4c823edfb73f99"
|
"revision": "4dc77674aceaabba2c7e3da25d4c823edfb73f99"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"checksumSHA1": "JJWLM3YJwgJD4vOLZnOYi1C2k0E=",
|
||||||
|
"path": "github.com/cloudflare/cloudflare-go",
|
||||||
|
"revision": "746075f034254832ead032aee02ac072636ff25a",
|
||||||
|
"revisionTime": "2016-06-01T21:42:51Z"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"comment": "v2.3.0-alpha.0-652-ge552791",
|
"comment": "v2.3.0-alpha.0-652-ge552791",
|
||||||
"path": "github.com/coreos/etcd/client",
|
"path": "github.com/coreos/etcd/client",
|
||||||
|
@ -989,10 +995,6 @@
|
||||||
"path": "github.com/mitchellh/cli",
|
"path": "github.com/mitchellh/cli",
|
||||||
"revision": "83f97d41cf100ee5f33944a8815c167d5e4aa272"
|
"revision": "83f97d41cf100ee5f33944a8815c167d5e4aa272"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"path": "github.com/mitchellh/cloudflare-go",
|
|
||||||
"revision": "84c7a0993a06d555dbfddd2b32f5fa9b92fa1dc1"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"path": "github.com/mitchellh/colorstring",
|
"path": "github.com/mitchellh/colorstring",
|
||||||
"revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"
|
"revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"
|
||||||
|
|
Loading…
Reference in New Issue