Skip to content

Commit

Permalink
[feat] Add cache purge support to the flarectl CLI. (#156)
Browse files Browse the repository at this point in the history
* The upcoming Purge by Host functionality has been added to the library
* flarectl now has a `purge` sub-command for purging from cache.

e.g
```
# Purge by host (upcoming)
flarectl zone purge --zone=example.com --hosts="repeater.example.com"

# Purge everything 
flarectl zone purge --zone=example.com --everything

# Purge by filename 
flarectl zone purge --zone=example.com \
  --files="http://repeater.example.com/styles.css,http://repeater.example.com/javascript.js"
```
  • Loading branch information
elithrar authored Nov 28, 2017
1 parent 890a43b commit f36897f
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 31 deletions.
59 changes: 32 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,45 @@
[![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.
> **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:
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
* 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.
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
- [x] Custom hostnames
- [x] Zone Lockdown and User-Agent Block rules
- [ ] Organization Administration
- [x] [Railgun](https://www.cloudflare.com/railgun/) administration
- [ ] [Keyless SSL](https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/)
- [x] [Origin CA](https://blog.cloudflare.com/universal-ssl-encryption-all-the-way-to-the-origin-for-free/)
- [x] [Load Balancing](https://blog.cloudflare.com/introducing-load-balancing-intelligent-failover-with-cloudflare/)
- [x] Firewall (partial)

Pull Requests are welcome, but please open an issue (or comment in an existing issue) to discuss any
non-trivial changes before submitting code.
* [x] DNS Records
* [x] Zones
* [x] Web Application Firewall (WAF)
* [x] Cloudflare IPs
* [x] User Administration (partial)
* [x] Virtual DNS Management
* [x] Custom hostnames
* [x] Zone Lockdown and User-Agent Block rules
* [x] Cache purging
* [ ] Organization Administration
* [x] [Railgun](https://www.cloudflare.com/railgun/) administration
* [ ] [Keyless SSL](https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/)
* [x] [Origin CA](https://blog.cloudflare.com/universal-ssl-encryption-all-the-way-to-the-origin-for-free/)
* [x] [Load Balancing](https://blog.cloudflare.com/introducing-load-balancing-intelligent-failover-with-cloudflare/)
* [x] Firewall (partial)

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

Expand Down Expand Up @@ -92,8 +96,9 @@ func main() {
}
```

Also refer to the [API documentation](https://godoc.org/github.com/cloudflare/cloudflare-go) for how
to use this package in-depth.
Also refer to the
[API documentation](https://godoc.org/github.com/cloudflare/cloudflare-go) for
how to use this package in-depth.

# License

Expand Down
27 changes: 27 additions & 0 deletions cmd/flarectl/flarectl.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,33 @@ func main() {
Action: zoneSettings,
Usage: "Settings for one zone",
},
{
Name: "purge",
Action: zoneCachePurge,
Usage: "(Selectively) Purge the cache for a zone",
Flags: []cli.Flag{
cli.StringFlag{
Name: "zone",
Usage: "zone name",
},
cli.BoolFlag{
Name: "everything",
Usage: "purge everything from cache for the zone",
},
cli.StringSliceFlag{
Name: "hosts",
Usage: "a list of hostnames to purge the cache for",
},
cli.StringSliceFlag{
Name: "tags",
Usage: "the cache tags to purge (Enterprise only)",
},
cli.StringSliceFlag{
Name: "files",
Usage: "a list of [exact] URLs to purge",
},
},
},
{
Name: "dns",
Aliases: []string{"d"},
Expand Down
67 changes: 67 additions & 0 deletions cmd/flarectl/zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package main

import (
"fmt"
"os"
"strings"

"github.com/cloudflare/cloudflare-go"
Expand Down Expand Up @@ -127,6 +128,66 @@ func zonePlan(*cli.Context) {
func zoneSettings(*cli.Context) {
}

func zoneCachePurge(c *cli.Context) {
if err := checkEnv(); err != nil {
fmt.Println(err)
cli.ShowSubcommandHelp(c)
return
}

if err := checkFlags(c, "zone"); err != nil {
cli.ShowSubcommandHelp(c)
return
}

zoneName := c.String("zone")
zoneID, err := api.ZoneIDByName(c.String("zone"))
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}

var resp cloudflare.PurgeCacheResponse

// Purge everything
if c.Bool("everything") {
resp, err = api.PurgeEverything(zoneID)
if err != nil {
fmt.Fprintf(os.Stderr, "Error purging all from zone %q: %s\n", zoneName, err)
return
}
} else {
var (
files = c.StringSlice("files")
tags = c.StringSlice("tags")
hosts = c.StringSlice("hosts")
)

if len(files) == 0 && len(tags) == 0 && len(hosts) == 0 {
fmt.Fprintln(os.Stderr, "You must provide at least one of the --files, --tags or --hosts flags")
return
}

// Purge selectively
purgeReq := cloudflare.PurgeCacheRequest{
Files: c.StringSlice("files"),
Tags: c.StringSlice("tags"),
Hosts: c.StringSlice("hosts"),
}

resp, err = api.PurgeCache(zoneID, purgeReq)
if err != nil {
fmt.Fprintf(os.Stderr, "Error purging the cache from zone %q: %s\n", zoneName, err)
return
}
}

output := make([][]string, 0, 1)
output = append(output, formatCacheResponse(resp))

writeTable(output, "ID")
}

func zoneRecords(c *cli.Context) {
if err := checkEnv(); err != nil {
fmt.Println(err)
Expand Down Expand Up @@ -196,3 +257,9 @@ func zoneRecords(c *cli.Context) {
}
writeTable(output, "ID", "Type", "Name", "Content", "Proxied", "TTL")
}

func formatCacheResponse(resp cloudflare.PurgeCacheResponse) []string {
return []string{
resp.Result.ID,
}
}
16 changes: 12 additions & 4 deletions zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,14 +213,22 @@ type ZoneAnalyticsOptions struct {

// 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"`
Everything bool `json:"purge_everything,omitempty"`
// Purge by filepath (exact match). Limit of 30
Files []string `json:"files,omitempty"`
// Purge by Tag (Enterprise only):
// https://support.cloudflare.com/hc/en-us/articles/206596608-How-to-Purge-Cache-Using-Cache-Tags-Enterprise-only-
Tags []string `json:"tags,omitempty"`
// Purge by hostname - e.g. "assets.example.com"
Hosts []string `json:"hosts,omitempty"`
}

// PurgeCacheResponse represents the response from the purge endpoint.
type PurgeCacheResponse struct {
Response
Result struct {
ID string `json:"id"`
} `json:"result"`
}

// newZone describes a new zone.
Expand Down Expand Up @@ -410,7 +418,7 @@ func (api *API) EditZone(zoneID string, zoneOpts ZoneOptions) (Zone, error) {
// 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})
res, err := api.makeRequest("DELETE", uri, PurgeCacheRequest{true, nil, nil, nil})
if err != nil {
return PurgeCacheResponse{}, errors.Wrap(err, errMakeRequestError)
}
Expand Down

0 comments on commit f36897f

Please sign in to comment.