From b64d359c2798b9e4285979cdf5eb482a97afabdf Mon Sep 17 00:00:00 2001 From: Kirby Date: Thu, 25 May 2023 10:53:55 +0200 Subject: [PATCH] Refactoring project, adding BAN handling with X-Cache-Tags --- app/Http/utils.go | 32 ++++++++++ app/Varnish/utils.go | 88 ++++++++++++++++++++++++++++ app/Vault/configuration.go | 63 ++++++++------------ app/go.mod | 28 ++++++++- app/go.sum | 117 +++++++++++++++++++++++++++++++++++++ app/main.go | 68 +-------------------- app/varnish | 2 +- 7 files changed, 293 insertions(+), 105 deletions(-) create mode 100644 app/Http/utils.go create mode 100644 app/Varnish/utils.go create mode 100644 app/go.sum diff --git a/app/Http/utils.go b/app/Http/utils.go new file mode 100644 index 0000000..ded8a8d --- /dev/null +++ b/app/Http/utils.go @@ -0,0 +1,32 @@ +// Package http provides functions to handle incoming HTTP requests +package http + +import ( + varnish "http-broadcaster/Varnish" + "io" + "log" + "net/http" +) + +// RequestHandler handles requests to broadcast to all varnish instances. +func RequestHandler(w http.ResponseWriter, r *http.Request) { + url := r.URL.String() + method := r.Method + tag := r.Header.Get("X-Cache-Tags") + remoteAddr := r.RemoteAddr + status := varnish.SendToVarnish(method, url, tag) + if status != "200 Purged" { + w.WriteHeader(405) + } + if tag != "" { + log.Println(remoteAddr + " Requested ban on X-Cache-Tags : " + tag + " , status: " + status) + } else { + log.Println(remoteAddr + " Requested purge on URI :" + url + " , status: " + status) + } + io.WriteString(w, status) +} + +// HealthHandler handles healthcheck requests and return 200. +func HealthHandler(w http.ResponseWriter, _ *http.Request) { + io.WriteString(w, "OK") +} diff --git a/app/Varnish/utils.go b/app/Varnish/utils.go new file mode 100644 index 0000000..df1617e --- /dev/null +++ b/app/Varnish/utils.go @@ -0,0 +1,88 @@ +// Package varnish provides functions to build the list of varnish servers that will be used +package varnish + +import ( + "context" + "log" + "net/http" + "os" + "strings" + + vault "http-broadcaster/Vault" +) + +var ( + varnishList = InitializeVarnishList() + status = "200 Purged" +) + +// InitializeVarnishList sets varnishList variable according to the LIST_METHOD env var +func InitializeVarnishList() []string { + switch method := os.Getenv("LIST_METHOD"); method { + case "vault": + return GetVarnishListFromVault() + case "file": + return GetVarnishListFromFile() + default: + panic("LIST_METHOD empty, no provided method to retrieve varnish list") + } +} + +// GetVarnishListFromVault builds a list of varnish servers from Vault. +func GetVarnishListFromVault() []string { + var value []string + client := vault.InitVaultConnection() + secret, err := client.KVv2("app").Get(context.Background(), "http-broadcaster/stg/envVars") + if err != nil { + log.Fatal("unable to read secret: %w", err) + return value + } + + // selecting list key from retrieved secret + list, ok := secret.Data["varnish_list"].(string) + if !ok { + log.Fatal("value type assertion failed: %T %#v", secret.Data["varnish_list"], secret.Data["varnish_list"]) + return value + } + value = strings.Split(string(list), ",") + return value +} + +// GetVarnishListFromFile reads the list of varnish servers from a file on disk. +func GetVarnishListFromFile() []string { + Data, err := os.ReadFile("./varnish") + if err != nil { + log.Fatal(err) + } + sliceData := strings.Split(string(Data), ",") + return sliceData +} + +// SendToVarnish send to all varnish servers define in varnishList the request with the PURGE or BAN method +// and the X-Cache-Tags header if necessary. +func SendToVarnish(method string, url string, tag string) string { + status = "200 Purged" + + // Take url to ban as argument. + // Loop over the list of Varnish servers and send PURGE request to each. + // Update status variable to check if servers have successfully purge url. + for i := 0; i < len(varnishList); i++ { + client := &http.Client{} + domain := strings.Trim(varnishList[i], "\r\n") + req, err := http.NewRequest(method, domain+url, nil) + if err != nil { + log.Fatal("Create new request : %s", err) + } + if tag != "" { + req.Header.Add("X-Cache-Tags", tag) + } + resp, err := client.Do(req) + if err != nil { + log.Fatal("Send new request : ", err) + } + if resp.StatusCode != 200 { + status = "405 Not Allowed" + } + } + return status +} diff --git a/app/Vault/configuration.go b/app/Vault/configuration.go index d3ecf77..2e67fac 100644 --- a/app/Vault/configuration.go +++ b/app/Vault/configuration.go @@ -1,61 +1,48 @@ -package Vault +// Package vault provides functions to retrieve info from Hashicorp Vault +package vault import ( - "fmt" - "os" - vault "github.com/hashicorp/vault/api" - auth "github.com/hashicorp/vault/api/auth/approle" + "context" + "log" + "os" + + vault "github.com/hashicorp/vault/api" + auth "github.com/hashicorp/vault/api/auth/approle" ) -// getVarnishList retrieve the list of varnish servers to send PURGE to. +// InitVaultConnection builds a client connection to vault and return it. // It uses the AppRole authentication method. -func getVarnishList() (string, error) { - config := vault.DefaultConfig() // modify for more granular configuration - +// APPROLE_ROLEID and APPROLE_SECRETID are fed from environment variables. +func InitVaultConnection() *vault.Client { + config := vault.DefaultConfig() client, err := vault.NewClient(config) if err != nil { - return "", fmt.Errorf("unable to initialize Vault client: %w", err) + log.Fatal("unable to initialize Vault client: %w", err) + return client } - - // Get roleID and secretID from ENV vars - roleID := os.Getenv("APPROLE_ROLE_ID") + roleID := os.Getenv("APPROLE_ROLEID") if roleID == "" { - return "", fmt.Errorf("no role ID was provided in APPROLE_ROLE_ID env var") - } - secretID := os.Getenv("APPROLE_SECRET_ID") - if secretID == "" { - return "", fmt.Errorf("no secret ID was provided in APPROLE_SECRET_ID env var") + log.Fatal("no role ID was provided in APPROLE_ROLEID env var") + return client } + secretID := &auth.SecretID{FromEnv: "APPROLE_SECRETID"} appRoleAuth, err := auth.NewAppRoleAuth( roleID, secretID, - auth.WithWrappingToken(), // Only required if the secret ID is response-wrapped. ) if err != nil { - return "", fmt.Errorf("unable to initialize AppRole auth method: %w", err) + log.Fatal("unable to initialize AppRole auth method: %w", err) + return client } - authInfo, err := client.Auth().Login(context.Background(), appRoleAuth) if err != nil { - return "", fmt.Errorf("unable to login to AppRole auth method: %w", err) + log.Fatal("unable to login to AppRole auth method: %w", err) + return client } if authInfo == nil { - return "", fmt.Errorf("no auth info was returned after login") + log.Fatal("no auth info returned after login") + return client } - - // get secret from the default mount path for KV v2 in dev mode, "secret" - secret, err := client.KVv2("app").Get(context.Background(), "http-broadcaster/stg/varnish_list") - if err != nil { - return "", fmt.Errorf("unable to read secret: %w", err) - } - - // data map can contain more than one key-value pair, - // in this case we're just grabbing one of them - value, ok := secret.Data["list"].(string) - if !ok { - return "", fmt.Errorf("value type assertion failed: %T %#v", secret.Data["list"], secret.Data["list"]) - } - - return value, nil + return client } diff --git a/app/go.mod b/app/go.mod index b7924ef..cace461 100644 --- a/app/go.mod +++ b/app/go.mod @@ -1,3 +1,29 @@ module http-broadcaster -go 1.13 +go 1.20 + +require ( + github.com/hashicorp/vault/api v1.9.1 + github.com/hashicorp/vault/api/auth/approle v0.4.0 +) + +require ( + github.com/cenkalti/backoff/v3 v3.0.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-retryablehttp v0.6.6 // indirect + github.com/hashicorp/go-rootcerts v1.0.2 // indirect + github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 // indirect + github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 // indirect + github.com/hashicorp/go-sockaddr v1.0.2 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/ryanuber/go-glob v1.0.0 // indirect + golang.org/x/crypto v0.6.0 // indirect + golang.org/x/net v0.7.0 // indirect + golang.org/x/text v0.7.0 // indirect + golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 // indirect + gopkg.in/square/go-jose.v2 v2.5.1 // indirect +) diff --git a/app/go.sum b/app/go.sum new file mode 100644 index 0000000..5415064 --- /dev/null +++ b/app/go.sum @@ -0,0 +1,117 @@ +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c= +github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= +github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +github.com/hashicorp/go-hclog v0.16.2 h1:K4ev2ib4LdQETX5cSZBG0DVLk1jwGqSPXBjdah3veNs= +github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= +github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6 h1:om4Al8Oy7kCm/B86rLCLah4Dt5Aa0Fr5rYBG60OzwHQ= +github.com/hashicorp/go-secure-stdlib/parseutil v0.1.6/go.mod h1:QmrqtbKuxxSWTN3ETMPuB+VtEiBJ/A9XhoYGv8E1uD8= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.1/go.mod h1:gKOamz3EwoIoJq7mlMIRBpVTAUn8qPCrEclOKKWhD3U= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= +github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= +github.com/hashicorp/go-sockaddr v1.0.2 h1:ztczhD1jLxIRjVejw8gFomI1BQZOe2WoVOu0SyteCQc= +github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/vault/api v1.9.0/go.mod h1:lloELQP4EyhjnCQhF8agKvWIVTmxbpEJj70b98959sM= +github.com/hashicorp/vault/api v1.9.1 h1:LtY/I16+5jVGU8rufyyAkwopgq/HpUnxFBg+QLOAV38= +github.com/hashicorp/vault/api v1.9.1/go.mod h1:78kktNcQYbBGSrOjQfHjXN32OhhxXnbYl3zxpd2uPUs= +github.com/hashicorp/vault/api/auth/approle v0.4.0 h1:tjJHoUkPx8zRoFlFy86uvgg/1gpTnDPp0t0BYWTKjjw= +github.com/hashicorp/vault/api/auth/approle v0.4.0/go.mod h1:D2gEpR0aS/F/MEcSjmhUlOsuK1RMVZojsnIQAEf0EV0= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= +github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1 h1:NusfzzA6yGQ+ua51ck7E3omNUX/JuqbFSaRGqU8CcLI= +golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/app/main.go b/app/main.go index e9011ec..ea26343 100644 --- a/app/main.go +++ b/app/main.go @@ -2,81 +2,19 @@ package main import ( - "io" + h "http-broadcaster/Http" "log" "net/http" "os" - "strings" ) -const ( - // MethodPurge declaration for Varnish. - MethodPurge = "PURGE" -) - -var ( - varnishList = MakeVarnishList() - status = "200 Purged" -) - -// MakeVarnishList reads the list of varnish servers from a file on disk. -func MakeVarnishList() []string { - Data, err := os.ReadFile("./varnish") - if err != nil { - log.Fatal(err) - } - sliceData := strings.Split(string(Data), ",") - return sliceData -} - -// PurgeHandler handles PURGE request to broadcast it to all varnish instances. -func PurgeHandler(w http.ResponseWriter, r *http.Request) { - url := r.URL.String() - remoteAddr := r.RemoteAddr - status := SendToVarnish(url) - if status != "200 Purged" { - w.WriteHeader(405) - } - log.Println(remoteAddr + " Requested purge on " + url + " : " + status) - io.WriteString(w, status) -} - -// SendToVarnish send to all varnish servers define in varnishList the PURGE request. -func SendToVarnish(url string) string { - status = "200 Purged" - // Take url to ban as argument. - // Loop over the list of Varnish servers and send PURGE request to each. - // Update status variable to check if servers have successfully purge url. - for i := 0; i < len(varnishList); i++ { - client := &http.Client{} - domain := strings.Trim(varnishList[i], "\r\n") - req, err := http.NewRequest(MethodPurge, domain+url, nil) - if err != nil { - log.Fatal("Create new request : %s", err) - } - resp, err := client.Do(req) - if err != nil { - log.Fatal("Send new request : %s", err) - } - if resp.StatusCode != 200 { - status = "405 Not Allowed" - } - } - return status -} - -// HealthHandler handles healthcheck requests and return 200. -func HealthHandler(w http.ResponseWriter, _ *http.Request) { - io.WriteString(w, "OK") -} - func main() { logFile, err := os.OpenFile("./log/purge.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) if err != nil { panic(err) } log.SetOutput(logFile) - http.HandleFunc("/", PurgeHandler) - http.HandleFunc("/healthcheck", HealthHandler) + http.HandleFunc("/", h.RequestHandler) + http.HandleFunc("/healthcheck", h.HealthHandler) log.Fatal(http.ListenAndServe(":6081", nil)) } diff --git a/app/varnish b/app/varnish index 70b3bbb..379800e 100644 --- a/app/varnish +++ b/app/varnish @@ -1 +1 @@ -http://10.13.32.1:6081,http://10.13.32.2:6081 +http://10.13.20.16:80