diff --git a/builtin/providers/cloudflare/config.go b/builtin/providers/cloudflare/config.go index e11fa8ec16..8fabbed770 100644 --- a/builtin/providers/cloudflare/config.go +++ b/builtin/providers/cloudflare/config.go @@ -1,10 +1,10 @@ package cloudflare import ( + "fmt" "log" - // NOTE: Temporary until they merge my PR: - "github.com/mitchellh/cloudflare-go" + "github.com/cloudflare/cloudflare-go" ) type Config struct { @@ -14,7 +14,10 @@ type Config struct { // Client() returns a new client for accessing cloudflare. 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) return client, nil } diff --git a/builtin/providers/cloudflare/resource_cloudflare_record.go b/builtin/providers/cloudflare/resource_cloudflare_record.go index ad478dc7dd..a738aa7262 100644 --- a/builtin/providers/cloudflare/resource_cloudflare_record.go +++ b/builtin/providers/cloudflare/resource_cloudflare_record.go @@ -4,10 +4,8 @@ import ( "fmt" "log" + "github.com/cloudflare/cloudflare-go" "github.com/hashicorp/terraform/helper/schema" - - // NOTE: Temporary until they merge my PR: - "github.com/mitchellh/cloudflare-go" ) 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) } - 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()) diff --git a/builtin/providers/cloudflare/resource_cloudflare_record_test.go b/builtin/providers/cloudflare/resource_cloudflare_record_test.go index 8044eef064..81a16eb1ee 100644 --- a/builtin/providers/cloudflare/resource_cloudflare_record_test.go +++ b/builtin/providers/cloudflare/resource_cloudflare_record_test.go @@ -5,11 +5,9 @@ import ( "os" "testing" + "github.com/cloudflare/cloudflare-go" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" - - // NOTE: Temporary until they merge my PR: - "github.com/mitchellh/cloudflare-go" ) func TestAccCloudFlareRecord_Basic(t *testing.T) { diff --git a/vendor/github.com/mitchellh/cloudflare-go/LICENSE b/vendor/github.com/cloudflare/cloudflare-go/LICENSE similarity index 100% rename from vendor/github.com/mitchellh/cloudflare-go/LICENSE rename to vendor/github.com/cloudflare/cloudflare-go/LICENSE diff --git a/vendor/github.com/cloudflare/cloudflare-go/README.md b/vendor/github.com/cloudflare/cloudflare-go/README.md new file mode 100644 index 0000000000..6515bdda4d --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/README.md @@ -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. diff --git a/vendor/github.com/cloudflare/cloudflare-go/cloudflare.go b/vendor/github.com/cloudflare/cloudflare-go/cloudflare.go new file mode 100644 index 0000000000..ae8812fa06 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/cloudflare.go @@ -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"` +} diff --git a/vendor/github.com/mitchellh/cloudflare-go/cpage.go b/vendor/github.com/cloudflare/cloudflare-go/cpage.go similarity index 100% rename from vendor/github.com/mitchellh/cloudflare-go/cpage.go rename to vendor/github.com/cloudflare/cloudflare-go/cpage.go diff --git a/vendor/github.com/mitchellh/cloudflare-go/dns.go b/vendor/github.com/cloudflare/cloudflare-go/dns.go similarity index 60% rename from vendor/github.com/mitchellh/cloudflare-go/dns.go rename to vendor/github.com/cloudflare/cloudflare-go/dns.go index b51c9c0f47..9340c840f8 100644 --- a/vendor/github.com/mitchellh/cloudflare-go/dns.go +++ b/vendor/github.com/cloudflare/cloudflare-go/dns.go @@ -7,34 +7,30 @@ import ( "github.com/pkg/errors" ) -/* -Create a DNS record. - -API reference: - https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record - POST /zones/:zone_identifier/dns_records -*/ -func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (DNSRecord, error) { +// CreateDNSRecord creates a DNS record for the zone identifier. +// API reference: +// https://api.cloudflare.com/#dns-records-for-a-zone-create-dns-record +// POST /zones/:zone_identifier/dns_records +func (api *API) CreateDNSRecord(zoneID string, rr DNSRecord) (*DNSRecordResponse, error) { uri := "/zones/" + zoneID + "/dns_records" res, err := api.makeRequest("POST", uri, rr) 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 { - return DNSRecord{}, errors.Wrap(err, errUnmarshalError) + return nil, errors.Wrap(err, errUnmarshalError) } - return r.Result, nil -} -/* -Fetches DNS records for a zone. + return recordResp, nil +} -API reference: - https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records - GET /zones/:zone_identifier/dns_records -*/ +// DNSRecords returns a slice of DNS records for the given zone identifier. +// API reference: +// 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) { // Construct a query string v := url.Values{} @@ -64,13 +60,11 @@ func (api *API) DNSRecords(zoneID string, rr DNSRecord) ([]DNSRecord, error) { return r.Result, nil } -/* -Fetches a single DNS record. - -API reference: - https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details - GET /zones/:zone_identifier/dns_records/:identifier -*/ +// DNSRecord returns a single DNS record for the given zone & record +// identifiers. +// API reference: +// https://api.cloudflare.com/#dns-records-for-a-zone-dns-record-details +// GET /zones/:zone_identifier/dns_records/:identifier func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) { uri := "/zones/" + zoneID + "/dns_records/" + recordID res, err := api.makeRequest("GET", uri, nil) @@ -85,13 +79,11 @@ func (api *API) DNSRecord(zoneID, recordID string) (DNSRecord, error) { return r.Result, nil } -/* -Change a DNS record. - -API reference: - https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record - PUT /zones/:zone_identifier/dns_records/:identifier -*/ +// UpdateDNSRecord updates a single DNS record for the given zone & record +// identifiers. +// API reference: +// https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record +// PUT /zones/:zone_identifier/dns_records/:identifier func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error { rec, err := api.DNSRecord(zoneID, recordID) if err != nil { @@ -112,13 +104,11 @@ func (api *API) UpdateDNSRecord(zoneID, recordID string, rr DNSRecord) error { return nil } -/* -Delete a DNS record. - -API reference: - https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record - DELETE /zones/:zone_identifier/dns_records/:identifier -*/ +// DeleteDNSRecord deletes a single DNS record for the given zone & record +// identifiers. +// API reference: +// https://api.cloudflare.com/#dns-records-for-a-zone-delete-dns-record +// DELETE /zones/:zone_identifier/dns_records/:identifier func (api *API) DeleteDNSRecord(zoneID, recordID string) error { uri := "/zones/" + zoneID + "/dns_records/" + recordID res, err := api.makeRequest("DELETE", uri, nil) diff --git a/vendor/github.com/cloudflare/cloudflare-go/errors.go b/vendor/github.com/cloudflare/cloudflare-go/errors.go new file mode 100644 index 0000000000..a909d2170a --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/errors.go @@ -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() +} diff --git a/vendor/github.com/mitchellh/cloudflare-go/ips.go b/vendor/github.com/cloudflare/cloudflare-go/ips.go similarity index 100% rename from vendor/github.com/mitchellh/cloudflare-go/ips.go rename to vendor/github.com/cloudflare/cloudflare-go/ips.go diff --git a/vendor/github.com/cloudflare/cloudflare-go/keyless.go b/vendor/github.com/cloudflare/cloudflare-go/keyless.go new file mode 100644 index 0000000000..7c38b1efd1 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/keyless.go @@ -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() { +} diff --git a/vendor/github.com/cloudflare/cloudflare-go/options.go b/vendor/github.com/cloudflare/cloudflare-go/options.go new file mode 100644 index 0000000000..33ad18c1d6 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/options.go @@ -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 +} diff --git a/vendor/github.com/cloudflare/cloudflare-go/organizations.go b/vendor/github.com/cloudflare/cloudflare-go/organizations.go new file mode 100644 index 0000000000..38ac61b1e5 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/organizations.go @@ -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"` +} diff --git a/vendor/github.com/mitchellh/cloudflare-go/pagerules.go b/vendor/github.com/cloudflare/cloudflare-go/pagerules.go similarity index 97% rename from vendor/github.com/mitchellh/cloudflare-go/pagerules.go rename to vendor/github.com/cloudflare/cloudflare-go/pagerules.go index fae180d712..a382829a2f 100644 --- a/vendor/github.com/mitchellh/cloudflare-go/pagerules.go +++ b/vendor/github.com/cloudflare/cloudflare-go/pagerules.go @@ -2,6 +2,7 @@ package cloudflare import ( "encoding/json" + "time" "github.com/pkg/errors" ) @@ -32,13 +33,13 @@ Valid IDs are: cache_level disable_apps disable_performance + disable_railgun disable_security edge_cache_ttl email_obfuscation forwarding_url ip_geolocation mirage - railgun rocket_loader security_level server_side_exclude @@ -60,13 +61,13 @@ var PageRuleActions = map[string]string{ "cache_level": "Cache Level", // Value of type string "disable_apps": "Disable Apps", // 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{} "edge_cache_ttl": "Edge Cache TTL", // Value of type int "email_obfuscation": "Email Obfuscation", // Value of type string "forwarding_url": "Forwarding URL", // Value of type map[string]interface "ip_geolocation": "IP Geolocation Header", // Value of type string "mirage": "Mirage", // Value of type string - "railgun": "Railgun", // Value of type string "rocket_loader": "Rocker Loader", // Value of type string "security_level": "Security Level", // 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"` Priority int `json:"priority"` Status string `json:"status"` // can be: active, paused - ModifiedOn string `json:"modified_on,omitempty"` - CreatedOn string `json:"created_on,omitempty"` + ModifiedOn time.Time `json:"modified_on,omitempty"` + CreatedOn time.Time `json:"created_on,omitempty"` } // PageRuleDetailResponse is the API response, containing a single PageRule. diff --git a/vendor/github.com/cloudflare/cloudflare-go/railgun.go b/vendor/github.com/cloudflare/cloudflare-go/railgun.go new file mode 100644 index 0000000000..8af60be56b --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/railgun.go @@ -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) +} diff --git a/vendor/github.com/cloudflare/cloudflare-go/ssl.go b/vendor/github.com/cloudflare/cloudflare-go/ssl.go new file mode 100644 index 0000000000..d352fad408 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/ssl.go @@ -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 +} diff --git a/vendor/github.com/mitchellh/cloudflare-go/user.go b/vendor/github.com/cloudflare/cloudflare-go/user.go similarity index 52% rename from vendor/github.com/mitchellh/cloudflare-go/user.go rename to vendor/github.com/cloudflare/cloudflare-go/user.go index 8c2344453e..c4b37b61b4 100644 --- a/vendor/github.com/mitchellh/cloudflare-go/user.go +++ b/vendor/github.com/cloudflare/cloudflare-go/user.go @@ -6,30 +6,30 @@ import ( "github.com/pkg/errors" ) -/* -Information about the logged-in user. - -API reference: https://api.cloudflare.com/#user-user-details -*/ -func (api API) UserDetails() (User, error) { +// UserDetails provides information about the logged-in user. +// API reference: +// https://api.cloudflare.com/#user-user-details +// GET /user +func (api *API) UserDetails() (User, error) { var r UserResponse res, err := api.makeRequest("GET", "/user", nil) if err != nil { return User{}, errors.Wrap(err, errMakeRequestError) } + err = json.Unmarshal(res, &r) if err != nil { return User{}, errors.Wrap(err, errUnmarshalError) } + return r.Result, nil } -/* -Update user properties. - -API reference: https://api.cloudflare.com/#user-update-user -*/ -func (api API) UpdateUser() (User, error) { +// UpdateUser updates the properties of the given user. +// API reference: +// https://api.cloudflare.com/#user-update-user +// PATCH /user +func (api *API) UpdateUser() (User, error) { // api.makeRequest("PATCH", "/user", user) return User{}, nil } diff --git a/vendor/github.com/cloudflare/cloudflare-go/virtualdns.go b/vendor/github.com/cloudflare/cloudflare-go/virtualdns.go new file mode 100644 index 0000000000..a0db270b67 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/virtualdns.go @@ -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 +} diff --git a/vendor/github.com/mitchellh/cloudflare-go/waf.go b/vendor/github.com/cloudflare/cloudflare-go/waf.go similarity index 86% rename from vendor/github.com/mitchellh/cloudflare-go/waf.go rename to vendor/github.com/cloudflare/cloudflare-go/waf.go index f3dbe5cfeb..248ba6009d 100644 --- a/vendor/github.com/mitchellh/cloudflare-go/waf.go +++ b/vendor/github.com/cloudflare/cloudflare-go/waf.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" ) +// ListWAFPackages returns a slice of the WAF packages for the given zone. func (api *API) ListWAFPackages(zoneID string) ([]WAFPackage, error) { var p WAFPackagesResponse 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 return []WAFPackage{}, err } - for pi, _ := range p.Result { + for pi := range p.Result { packages = append(packages, p.Result[pi]) } 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) { var r WAFRulesResponse 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 return []WAFRule{}, err } - for ri, _ := range r.Result { + for ri := range r.Result { rules = append(rules, r.Result[ri]) } return rules, nil diff --git a/vendor/github.com/cloudflare/cloudflare-go/zone.go b/vendor/github.com/cloudflare/cloudflare-go/zone.go new file mode 100644 index 0000000000..e80042ede8 --- /dev/null +++ b/vendor/github.com/cloudflare/cloudflare-go/zone.go @@ -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 diff --git a/vendor/github.com/mitchellh/cloudflare-go/.travis.yml b/vendor/github.com/mitchellh/cloudflare-go/.travis.yml deleted file mode 100644 index cb3b857f84..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/.travis.yml +++ /dev/null @@ -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 diff --git a/vendor/github.com/mitchellh/cloudflare-go/README.md b/vendor/github.com/mitchellh/cloudflare-go/README.md deleted file mode 100644 index e8551fa417..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/README.md +++ /dev/null @@ -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. diff --git a/vendor/github.com/mitchellh/cloudflare-go/cloudflare.go b/vendor/github.com/mitchellh/cloudflare-go/cloudflare.go deleted file mode 100644 index 24fa03ed9b..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/cloudflare.go +++ /dev/null @@ -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"` -} diff --git a/vendor/github.com/mitchellh/cloudflare-go/keyless.go b/vendor/github.com/mitchellh/cloudflare-go/keyless.go deleted file mode 100644 index f12c3910cd..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/keyless.go +++ /dev/null @@ -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() { -} diff --git a/vendor/github.com/mitchellh/cloudflare-go/railgun.go b/vendor/github.com/mitchellh/cloudflare-go/railgun.go deleted file mode 100644 index a4769d2069..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/railgun.go +++ /dev/null @@ -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) { -} diff --git a/vendor/github.com/mitchellh/cloudflare-go/ssl.go b/vendor/github.com/mitchellh/cloudflare-go/ssl.go deleted file mode 100644 index 8dfc74f99c..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/ssl.go +++ /dev/null @@ -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() { -} diff --git a/vendor/github.com/mitchellh/cloudflare-go/zone.go b/vendor/github.com/mitchellh/cloudflare-go/zone.go deleted file mode 100644 index 7a681c5deb..0000000000 --- a/vendor/github.com/mitchellh/cloudflare-go/zone.go +++ /dev/null @@ -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 diff --git a/vendor/vendor.json b/vendor/vendor.json index 77438cecdb..77661bffaa 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -530,6 +530,12 @@ "path": "github.com/cenkalti/backoff", "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", "path": "github.com/coreos/etcd/client", @@ -989,10 +995,6 @@ "path": "github.com/mitchellh/cli", "revision": "83f97d41cf100ee5f33944a8815c167d5e4aa272" }, - { - "path": "github.com/mitchellh/cloudflare-go", - "revision": "84c7a0993a06d555dbfddd2b32f5fa9b92fa1dc1" - }, { "path": "github.com/mitchellh/colorstring", "revision": "8631ce90f28644f54aeedcb3e389a85174e067d1"