From 97a3210eee7abf0faf0948aa80b41a801d7ae22f Mon Sep 17 00:00:00 2001 From: Sebastien Laithier Date: Wed, 10 May 2023 16:10:14 +0200 Subject: [PATCH] Adding build in CI, moving files to app folder --- .gitlab-ci.yml | 17 +++++++++ app/Vault/configuration.go | 61 ++++++++++++++++++++++++++++++ app/go.mod | 3 ++ app/main.go | 77 ++++++++++++++++++++++++++++++++++++++ app/varnish | 1 + 5 files changed, 159 insertions(+) create mode 100644 app/Vault/configuration.go create mode 100644 app/go.mod create mode 100644 app/main.go create mode 100644 app/varnish diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 0fae63e..4e8684d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,21 @@ +stages: + - lint + - build + lint: image: cytopia/golint:latest script: - golint main.go + +compile: + stage: build + image: golang:1.20.4-alpine + script: + - cd app/ + - go get ./... + - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o ../build/http-broadcaster main.go + - cp -r ../build/ + artifacts: + paths: + - build/ + expire_in: 1 week diff --git a/app/Vault/configuration.go b/app/Vault/configuration.go new file mode 100644 index 0000000..d3ecf77 --- /dev/null +++ b/app/Vault/configuration.go @@ -0,0 +1,61 @@ +package Vault + +import ( + "fmt" + "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. +// It uses the AppRole authentication method. +func getVarnishList() (string, error) { + config := vault.DefaultConfig() // modify for more granular configuration + + client, err := vault.NewClient(config) + if err != nil { + return "", fmt.Errorf("unable to initialize Vault client: %w", err) + } + + // Get roleID and secretID from ENV vars + roleID := os.Getenv("APPROLE_ROLE_ID") + 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") + } + + 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) + } + + authInfo, err := client.Auth().Login(context.Background(), appRoleAuth) + if err != nil { + return "", fmt.Errorf("unable to login to AppRole auth method: %w", err) + } + if authInfo == nil { + return "", fmt.Errorf("no auth info was returned after login") + } + + // 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 +} diff --git a/app/go.mod b/app/go.mod new file mode 100644 index 0000000..b7924ef --- /dev/null +++ b/app/go.mod @@ -0,0 +1,3 @@ +module http-broadcaster + +go 1.13 diff --git a/app/main.go b/app/main.go new file mode 100644 index 0000000..23c6fc9 --- /dev/null +++ b/app/main.go @@ -0,0 +1,77 @@ +package main + +import ( + "fmt" + "io" + "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() + status := SendToVarnish(url) + if status != "200 Purged" { + w.WriteHeader(405) + } + 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. + for i := 0; i < len(varnishList); i++ { + //status = "200 Purged" + client := &http.Client{} + domain := strings.Trim(varnishList[i], "\r\n") + req, err := http.NewRequest(MethodPurge, domain + url, nil) + if err != nil { + log.Fatal("NewRequest: %s", err) + } + resp, err := client.Do(req) + if err != nil { + log.Fatal("Client.do: %s", err) + } + //fmt.Printf("Resp: %v\n", resp) + if resp.StatusCode != 200 { + status = "405 Not Allowed" + } + fmt.Println("Purge URL" + " " + domain + url + " : " + status) + } + return status +} + +// HealthHandler handles healthcheck requests and return 200. +func HealthHandler(w http.ResponseWriter, r *http.Request) { + io.WriteString(w, "OK") +} + +func main() { + http.HandleFunc("/", PurgeHandler) + http.HandleFunc("/healthcheck", HealthHandler) + log.Fatal(http.ListenAndServe(":6081",nil)) +} diff --git a/app/varnish b/app/varnish new file mode 100644 index 0000000..70b3bbb --- /dev/null +++ b/app/varnish @@ -0,0 +1 @@ +http://10.13.32.1:6081,http://10.13.32.2:6081