Skip to content

Commit

Permalink
Adds support for Tiered Caching
Browse files Browse the repository at this point in the history
Adds support for utilizing previously undocumented APIs for Tiered Caching endpoints. It allows for setting zones to utilize either generic, smart or off.

Implementation:

* Adds three new api methods for manipulating tiered cache settings
  * GetTieredCache which returns the current setting
  * SetTieredCache which allows for manipulation of existing settings
  * DeleteTieredCache which allows for unsetting tiered cache
  • Loading branch information
Mikey Sleevi committed Dec 21, 2022
1 parent e3f6574 commit 6e8972f
Show file tree
Hide file tree
Showing 2 changed files with 621 additions and 0 deletions.
300 changes: 300 additions & 0 deletions tiered_cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
package cloudflare

import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"time"
)

type TieredCacheType int

const (
TieredCacheOff TieredCacheType = 0
TieredCacheGeneric TieredCacheType = 1
TieredCacheSmart TieredCacheType = 2
)

type TieredCache struct {
Type TieredCacheType
LastModified time.Time
}

const notFoundError = "Unable to retrieve tiered_cache_smart_topology_enable setting value. The zone setting does not exist. (1142)"

// GetTieredCache allows you to retrive the current Tiered Cache Settings for a Zone
// This function does not support custom topologies, only Generic and Smart Tiered Caching
//
// API Reference: TODO
func (api *API) GetTieredCache(ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
var lastModified time.Time

generic, err := getGenericTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}
lastModified = generic.LastModified

smart, err := getSmartTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}

if smart.LastModified.After(lastModified) {
lastModified = smart.LastModified
}

if generic.Type == TieredCacheOff {
return TieredCache{Type: TieredCacheOff, LastModified: lastModified}, nil
}

if smart.Type == TieredCacheOff {
return TieredCache{Type: TieredCacheGeneric, LastModified: lastModified}, nil
}

return TieredCache{Type: TieredCacheSmart, LastModified: lastModified}, nil
}

// SetTieredCache allows you to set a zone's tiered cache topology between the available types
// Using the value of TieredCacheOff will disable Tiered Cache entirely
//
// API Reference: TODO
func (api *API) SetTieredCache(ctx context.Context, rc *ResourceContainer, value TieredCacheType) (TieredCache, error) {
if value == TieredCacheOff {
return api.DeleteTieredCache(ctx, rc)
}

var lastModified time.Time

if value == TieredCacheGeneric {
result, err := deleteSmartTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}
lastModified = result.LastModified

result, err = enableGenericTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}

if result.LastModified.After(lastModified) {
lastModified = result.LastModified
}
return TieredCache{Type: TieredCacheGeneric, LastModified: lastModified}, nil
}

result, err := enableGenericTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}
lastModified = result.LastModified

result, err = enableSmartTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}

if result.LastModified.After(lastModified) {
lastModified = result.LastModified
}
return TieredCache{Type: TieredCacheSmart, LastModified: lastModified}, nil
}

// DeleteTieredCache allows you to delete the tiered cache settings for a zone
// This is equivalent to using SetTieredCache with the value of TieredCacheOff
//
// API Reference: TODO
func (api *API) DeleteTieredCache(ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
var lastModified time.Time

result, err := deleteSmartTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}
lastModified = result.LastModified

result, err = disableGenericTieredCache(api, ctx, rc)
if err != nil {
return TieredCache{}, err
}

if result.LastModified.After(lastModified) {
lastModified = result.LastModified
}
return TieredCache{Type: TieredCacheOff, LastModified: lastModified}, nil
}

type tieredCacheResult struct {
ID string `json:"id"`
Value string `json:"value,omitempty"`
LastModified time.Time `json:"modified_on"`
}

type tieredCacheResponse struct {
Result tieredCacheResult `json:"result"`
Response
}

type tieredCacheSetting struct {
Value string `json:"value"`
}

func getGenericTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/argo/tiered_caching", rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to retrieve generic tiered cache failed")
}

if response.Result.Value == "off" {
return TieredCache{Type: TieredCacheOff, LastModified: response.Result.LastModified}, nil
}

return TieredCache{Type: TieredCacheGeneric, LastModified: response.Result.LastModified}, nil
}

func getSmartTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/cache/tiered_cache_smart_topology_enable", rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
if err != nil {
if err.Error() == notFoundError {
return TieredCache{Type: TieredCacheOff}, nil
}
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to retrieve smart tiered cache failed")
}

if response.Result.Value == "off" {
return TieredCache{Type: TieredCacheOff, LastModified: response.Result.LastModified}, nil
}
return TieredCache{Type: TieredCacheSmart, LastModified: response.Result.LastModified}, nil
}

func enableGenericTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/argo/tiered_caching", rc.Identifier)
setting := tieredCacheSetting{
Value: "on",
}
body, err := json.Marshal(setting)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, body)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to enable generic tiered cache failed")
}

return TieredCache{Type: TieredCacheGeneric, LastModified: response.Result.LastModified}, nil
}

func enableSmartTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/cache/tiered_cache_smart_topology_enable", rc.Identifier)
setting := tieredCacheSetting{
Value: "on",
}
body, err := json.Marshal(setting)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, body)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to enable smart tiered cache failed")
}

return TieredCache{Type: TieredCacheSmart, LastModified: response.Result.LastModified}, nil
}

func disableGenericTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/argo/tiered_caching", rc.Identifier)
setting := tieredCacheSetting{
Value: "off",
}
body, err := json.Marshal(setting)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

res, err := api.makeRequestContext(ctx, http.MethodPatch, uri, body)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to disable generic tiered cache failed")
}

return TieredCache{Type: TieredCacheOff, LastModified: response.Result.LastModified}, nil
}

func deleteSmartTieredCache(api *API, ctx context.Context, rc *ResourceContainer) (TieredCache, error) {
uri := fmt.Sprintf("/zones/%s/cache/tiered_cache_smart_topology_enable", rc.Identifier)
res, err := api.makeRequestContext(ctx, http.MethodDelete, uri, nil)
if err != nil {
if err.Error() == notFoundError {
return TieredCache{Type: TieredCacheOff}, nil
}
return TieredCache{Type: TieredCacheOff}, err
}

var response tieredCacheResponse
err = json.Unmarshal(res, &response)
if err != nil {
return TieredCache{Type: TieredCacheOff}, err
}

if !response.Success {
return TieredCache{Type: TieredCacheOff}, errors.New("Request to disable smart tiered cache failed")
}

return TieredCache{Type: TieredCacheOff, LastModified: response.Result.LastModified}, nil
}
Loading

0 comments on commit 6e8972f

Please sign in to comment.