Skip to content

Commit

Permalink
purger: add extra purger headers for vary support on nginx cache keys
Browse files Browse the repository at this point in the history
  • Loading branch information
morpheu committed Apr 7, 2022
1 parent 4419011 commit 7eaeee5
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 37 deletions.
2 changes: 1 addition & 1 deletion internal/pkg/rpaas/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,7 @@ func (m *k8sRpaasManager) PurgeCache(ctx context.Context, instanceName string, a
if !podStatus.Running {
continue
}
status, err = m.cacheManager.PurgeCache(podStatus.Address, args.Path, port, args.PreservePath)
status, err = m.cacheManager.PurgeCache(podStatus.Address, args.Path, port, args.PreservePath, args.ExtraHeaders)
if err != nil {
purgeErrors = multierror.Append(purgeErrors, errors.Wrapf(err, "pod %s failed", podStatus.Address))
continue
Expand Down
9 changes: 5 additions & 4 deletions internal/pkg/rpaas/k8s_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package rpaas
import (
"context"
"crypto/tls"
"net/http"
"regexp"
"testing"
"time"
Expand Down Expand Up @@ -80,12 +81,12 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
)

type fakeCacheManager struct {
purgeCacheFunc func(host, path string, port int32, preservePath bool) (bool, error)
purgeCacheFunc func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error)
}

func (f fakeCacheManager) PurgeCache(host, path string, port int32, preservePath bool) (bool, error) {
func (f fakeCacheManager) PurgeCache(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
if f.purgeCacheFunc != nil {
return f.purgeCacheFunc(host, path, port, preservePath)
return f.purgeCacheFunc(host, path, port, preservePath, extraHeaders)
}
return false, nil
}
Expand Down Expand Up @@ -1779,7 +1780,7 @@ func Test_k8sRpaasManager_PurgeCache(t *testing.T) {
instance: "my-instance",
args: PurgeCacheArgs{Path: "/index.html"},
cacheManager: fakeCacheManager{
purgeCacheFunc: func(host, path string, port int32, preservePath bool) (bool, error) {
purgeCacheFunc: func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
if host == "10.0.0.9" {
return false, nginxManager.NginxError{Msg: "some nginx error"}
}
Expand Down
8 changes: 5 additions & 3 deletions internal/pkg/rpaas/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"encoding/json"
"fmt"
"io"
"net/http"
"sort"
"strings"
"text/template"
Expand Down Expand Up @@ -151,12 +152,13 @@ type BindAppArgs struct {
}

type CacheManager interface {
PurgeCache(host, path string, port int32, preservePath bool) (bool, error)
PurgeCache(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error)
}

type PurgeCacheArgs struct {
Path string `json:"path" form:"path"`
PreservePath bool `json:"preserve_path" form:"preserve_path"`
Path string `json:"path" form:"path"`
PreservePath bool `json:"preserve_path" form:"preserve_path"`
ExtraHeaders http.Header `json:"extra_headers" form:"extra_headers"`
}

type PurgeCacheBulkResult struct {
Expand Down
61 changes: 41 additions & 20 deletions internal/pkg/rpaas/nginx/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,38 +54,59 @@ func vtsLocationMatch() string {
return defaultVTSLocationMatch
}

func (m NginxManager) PurgeCache(host, purgePath string, port int32, preservePath bool) (bool, error) {
func (m NginxManager) PurgeCache(host, purgePath string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
purged := false
for _, encoding := range []string{"gzip", "identity"} {
var err error
status := false
headers := map[string]string{"Accept-Encoding": encoding}
separator := "/"
if strings.HasPrefix(purgePath, "/") {
separator = ""
if len(extraHeaders) > 0 {
for header, _ := range extraHeaders {
headers[header] = extraHeaders.Get(header)
status, err = m.purge(host, purgePath, port, preservePath, headers)
if err != nil {
return false, err
}
}
} else {
status, err = m.purge(host, purgePath, port, preservePath, headers)
if err != nil {
return false, err
}
}
if status {
purged = true
}
}
return purged, nil
}

func (m NginxManager) purge(host, purgePath string, port int32, preservePath bool, headers map[string]string) (bool, error) {
separator := "/"
if strings.HasPrefix(purgePath, "/") {
separator = ""
}
if preservePath {
path := fmt.Sprintf("%s%s%s", defaultPurgeLocation, separator, purgePath)
status, err := m.purgeRequest(host, path, port, headers)
if err != nil {
return status, err
}
if preservePath {
path := fmt.Sprintf("%s%s%s", defaultPurgeLocation, separator, purgePath)
return status, nil
} else {
purged := false
for _, scheme := range []string{"http", "https"} {
path := fmt.Sprintf("%s/%s%s%s", defaultPurgeLocation, scheme, separator, purgePath)
status, err := m.purgeRequest(host, path, port, headers)
if err != nil {
return false, err
return status, err
}
if status {
purged = true
}
} else {
for _, scheme := range []string{"http", "https"} {
path := fmt.Sprintf("%s/%s%s%s", defaultPurgeLocation, scheme, separator, purgePath)
status, err := m.purgeRequest(host, path, port, headers)
if err != nil {
return false, err
}
if status {
purged = true
}
}
}

return purged, nil
}
return purged, nil
}

func (m NginxManager) purgeRequest(host, path string, port int32, headers map[string]string) (bool, error) {
Expand Down
20 changes: 19 additions & 1 deletion internal/pkg/rpaas/nginx/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func TestNginxManager_PurgeCache(t *testing.T) {
assertion func(*testing.T, error)
nginxResponse http.HandlerFunc
status bool
extraHeaders http.Header
}{
{
description: "returns not found error when nginx returns 404 and preservePath is false",
Expand Down Expand Up @@ -140,6 +141,23 @@ func TestNginxManager_PurgeCache(t *testing.T) {
},
status: true,
},
{
description: "requests with extra headers when preservePath is false",
purgePath: "/index.html",
preservePath: false,
assertion: func(t *testing.T, err error) {
require.NoError(t, err)
},
nginxResponse: func(w http.ResponseWriter, r *http.Request) {
if (r.Header.Get("Accept-Encoding") == "gzip") && (r.Header.Get("X-Custom-Header") == "custom-value") && (r.RequestURI == "/purge/http/index.html") {
w.WriteHeader(http.StatusOK)
} else {
w.WriteHeader(http.StatusNotFound)
}
},
status: true,
extraHeaders: http.Header{"X-Custom-Header": {"custom-value"}},
},
}

for _, tt := range testCases {
Expand All @@ -153,7 +171,7 @@ func TestNginxManager_PurgeCache(t *testing.T) {
port, err := strconv.ParseUint(url.Port(), 10, 16)
require.NoError(t, err)

purgeStatus, err := nginx.PurgeCache(url.Hostname(), tt.purgePath, int32(port), tt.preservePath)
purgeStatus, err := nginx.PurgeCache(url.Hostname(), tt.purgePath, int32(port), tt.preservePath, tt.extraHeaders)
tt.assertion(t, err)
assert.Equal(t, tt.status, purgeStatus)
})
Expand Down
2 changes: 1 addition & 1 deletion internal/purge/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func (p *PurgeAPI) PurgeCache(ctx context.Context, name string, args rpaas.Purge
if !pod.Running {
continue
}
if status, err = p.cacheManager.PurgeCache(pod.Address, args.Path, port, args.PreservePath); err != nil {
if status, err = p.cacheManager.PurgeCache(pod.Address, args.Path, port, args.PreservePath, args.ExtraHeaders); err != nil {
purgeErrors = multierror.Append(purgeErrors, errors.Wrapf(err, "pod %s:%d failed", pod.Address, port))
continue
}
Expand Down
14 changes: 7 additions & 7 deletions internal/purge/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ func bodyContent(rsp *httptest.ResponseRecorder) string {
}

type fakeCacheManager struct {
purgeCacheFunc func(host, path string, port int32, preservePath bool) (bool, error)
purgeCacheFunc func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error)
}

func (f fakeCacheManager) PurgeCache(host, path string, port int32, preservePath bool) (bool, error) {
func (f fakeCacheManager) PurgeCache(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
if f.purgeCacheFunc != nil {
return f.purgeCacheFunc(host, path, port, preservePath)
return f.purgeCacheFunc(host, path, port, preservePath, extraHeaders)
}
return false, nil
}
Expand All @@ -50,7 +50,7 @@ func TestCachePurge(t *testing.T) {
expectedStatus: http.StatusOK,
expectedBody: `{"path":"/index.html","instances_purged":2}`,
cacheManager: fakeCacheManager{
purgeCacheFunc: func(host, path string, port int32, preservePath bool) (bool, error) {
purgeCacheFunc: func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
return true, nil
},
},
Expand All @@ -70,7 +70,7 @@ func TestCachePurge(t *testing.T) {
expectedStatus: http.StatusOK,
expectedBody: `{"path":"/index.html","instances_purged":1,"error":"1 error occurred:\n\t* pod 172.0.2.2:8889 failed: some nginx error\n\n"}`,
cacheManager: fakeCacheManager{
purgeCacheFunc: func(host, path string, port int32, preservePath bool) (bool, error) {
purgeCacheFunc: func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
if host == "172.0.2.2" {
return false, nginxManager.NginxError{Msg: "some nginx error"}
}
Expand Down Expand Up @@ -134,7 +134,7 @@ func TestCachePurgeBulk(t *testing.T) {
expectedStatus: http.StatusOK,
expectedBody: `[{"path":"/index.html","instances_purged":2}]`,
cacheManager: fakeCacheManager{
purgeCacheFunc: func(host, path string, port int32, preservePath bool) (bool, error) {
purgeCacheFunc: func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
return true, nil
},
},
Expand All @@ -146,7 +146,7 @@ func TestCachePurgeBulk(t *testing.T) {
expectedStatus: http.StatusInternalServerError,
expectedBody: `[{"path":"/index.html","instances_purged":2},{"path":"/other.html","instances_purged":1,"error":"1 error occurred:\n\t* pod 172.0.2.2:8889 failed: some nginx error\n\n"}]`,
cacheManager: fakeCacheManager{
purgeCacheFunc: func(host, path string, port int32, preservePath bool) (bool, error) {
purgeCacheFunc: func(host, path string, port int32, preservePath bool, extraHeaders http.Header) (bool, error) {
if host == "172.0.2.2" && path == "/other.html" {
return false, nginxManager.NginxError{Msg: "some nginx error"}
}
Expand Down

0 comments on commit 7eaeee5

Please sign in to comment.