diff --git a/internal/pkg/rpaas/k8s.go b/internal/pkg/rpaas/k8s.go index 3eaffcec1..f4ae23530 100644 --- a/internal/pkg/rpaas/k8s.go +++ b/internal/pkg/rpaas/k8s.go @@ -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 diff --git a/internal/pkg/rpaas/k8s_test.go b/internal/pkg/rpaas/k8s_test.go index 8eeffc7c7..6e22e83e7 100644 --- a/internal/pkg/rpaas/k8s_test.go +++ b/internal/pkg/rpaas/k8s_test.go @@ -7,6 +7,7 @@ package rpaas import ( "context" "crypto/tls" + "net/http" "regexp" "testing" "time" @@ -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 } @@ -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"} } diff --git a/internal/pkg/rpaas/manager.go b/internal/pkg/rpaas/manager.go index 94ecf23c3..55ebc2e0c 100644 --- a/internal/pkg/rpaas/manager.go +++ b/internal/pkg/rpaas/manager.go @@ -11,6 +11,7 @@ import ( "encoding/json" "fmt" "io" + "net/http" "sort" "strings" "text/template" @@ -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 { diff --git a/internal/pkg/rpaas/nginx/manager.go b/internal/pkg/rpaas/nginx/manager.go index 1cc687997..9f00b5192 100644 --- a/internal/pkg/rpaas/nginx/manager.go +++ b/internal/pkg/rpaas/nginx/manager.go @@ -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) { diff --git a/internal/pkg/rpaas/nginx/manager_test.go b/internal/pkg/rpaas/nginx/manager_test.go index db8d5800c..3cf2e55e2 100644 --- a/internal/pkg/rpaas/nginx/manager_test.go +++ b/internal/pkg/rpaas/nginx/manager_test.go @@ -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", @@ -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 { @@ -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) }) diff --git a/internal/purge/cache.go b/internal/purge/cache.go index c57ff29d4..74a7c13a9 100644 --- a/internal/purge/cache.go +++ b/internal/purge/cache.go @@ -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 } diff --git a/internal/purge/cache_test.go b/internal/purge/cache_test.go index d86333429..9a244f581 100644 --- a/internal/purge/cache_test.go +++ b/internal/purge/cache_test.go @@ -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 } @@ -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 }, }, @@ -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"} } @@ -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 }, }, @@ -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"} }