Compare commits
15 Commits
0422153f4c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 60ab4ff110 | |||
| 4219a7d001 | |||
| 7ffefb1159 | |||
| b64d359c27 | |||
| b94c8800b0 | |||
|
|
85b0cffdad | ||
|
|
17579b6f0b | ||
|
|
923952e8f6 | ||
|
|
35638213c5 | ||
|
|
5779e2c39e | ||
|
|
ddb30a3a5a | ||
|
|
f6173a09b2 | ||
|
|
f3be636af4 | ||
|
|
73a92f6dd9 | ||
|
|
0d2eaa3c09 |
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.idea/*
|
||||
*.swp
|
||||
*.log
|
||||
varnish_list
|
||||
helm/charts/*
|
||||
Chart.lock
|
||||
app/*.log
|
||||
app/http-broadcaster
|
||||
@@ -6,6 +6,7 @@ linter:
|
||||
stage: lint
|
||||
image: cytopia/golint:latest
|
||||
script:
|
||||
- cd app/
|
||||
- golint main.go
|
||||
|
||||
compile:
|
||||
@@ -15,7 +16,7 @@ compile:
|
||||
- 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/
|
||||
- cp -r log/ ../build/
|
||||
artifacts:
|
||||
paths:
|
||||
- build/
|
||||
|
||||
61
Dockerfile
Normal file
61
Dockerfile
Normal file
@@ -0,0 +1,61 @@
|
||||
########################
|
||||
# BASE
|
||||
########################
|
||||
FROM golang:1.23.3-alpine as base
|
||||
|
||||
ENV CGO_ENABLED=0 \
|
||||
GOOS=linux \
|
||||
GOARCH=amd64
|
||||
|
||||
ARG APP_UID=1000
|
||||
ARG APP_GID=1000
|
||||
RUN addgroup -S app -g ${APP_GID} && adduser -u ${APP_UID} -S -D -G app app
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache bash ca-certificates tzdata curl \
|
||||
&& update-ca-certificates
|
||||
|
||||
ENV TZ="Europe/Paris"
|
||||
|
||||
COPY ./app /app
|
||||
WORKDIR /app
|
||||
COPY ./docker/config/env.local /vault/secrets/.env
|
||||
|
||||
RUN go mod download && go mod verify
|
||||
|
||||
########################
|
||||
# BUILD
|
||||
########################
|
||||
FROM base as build-env
|
||||
|
||||
RUN go build -ldflags="-w -s" -o /http-broadcaster
|
||||
|
||||
########################
|
||||
# PROD ENV ###
|
||||
########################
|
||||
FROM alpine:3.20 as prod
|
||||
|
||||
ARG APP_UID=1000
|
||||
ARG APP_GID=1000
|
||||
RUN addgroup -S app -g ${APP_GID} && adduser -u ${APP_UID} -S -D -G app app
|
||||
|
||||
RUN apk update \
|
||||
&& apk add --no-cache bash ca-certificates tzdata curl \
|
||||
&& update-ca-certificates
|
||||
|
||||
ENV TZ="Europe/Paris"
|
||||
COPY --from=build-env /http-broadcaster /usr/local/bin/http-broadcaster
|
||||
RUN chmod +x /usr/local/bin/http-broadcaster
|
||||
RUN mkdir /app && chown ${APP_UID}:${APP_GID} /app
|
||||
|
||||
USER app
|
||||
|
||||
########################
|
||||
# DEV
|
||||
########################
|
||||
FROM base as dev
|
||||
|
||||
COPY --from=build-env /http-broadcaster /usr/local/bin/http-broadcaster
|
||||
RUN chmod +x /usr/local/bin/http-broadcaster
|
||||
|
||||
ENTRYPOINT ["http-broadcaster"]
|
||||
111
README.md
111
README.md
@@ -1,92 +1,35 @@
|
||||
# http-broadcaster
|
||||
|
||||
|
||||
|
||||
## Getting started
|
||||
|
||||
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
|
||||
|
||||
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
|
||||
|
||||
## Add your files
|
||||
|
||||
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
|
||||
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
|
||||
|
||||
```
|
||||
cd existing_repo
|
||||
git remote add origin https://gitlab.infolegale.net/infrastructure/http-broadcaster.git
|
||||
git branch -M main
|
||||
git push -uf origin main
|
||||
```
|
||||
|
||||
## Integrate with your tools
|
||||
|
||||
- [ ] [Set up project integrations](https://gitlab.infolegale.net/infrastructure/http-broadcaster/-/settings/integrations)
|
||||
|
||||
## Collaborate with your team
|
||||
|
||||
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
|
||||
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
|
||||
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
|
||||
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
|
||||
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
|
||||
|
||||
## Test and Deploy
|
||||
|
||||
Use the built-in continuous integration in GitLab.
|
||||
|
||||
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
|
||||
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
|
||||
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
|
||||
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
|
||||
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
|
||||
|
||||
***
|
||||
|
||||
# Editing this README
|
||||
|
||||
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
|
||||
|
||||
## Suggestions for a good README
|
||||
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
|
||||
|
||||
## Name
|
||||
Choose a self-explaining name for your project.
|
||||
|
||||
## Description
|
||||
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
|
||||
Un démon simple écrit en Go qui prend une requête PURGE en entrée et la transmet à plusieurs serveurs varnish.
|
||||
|
||||
## Badges
|
||||
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
|
||||
## Déploiement
|
||||
Le projet se déploie via les pipelines Gitlab en stg et en prod, via un déclenchement manuel.
|
||||
Le sidecar vault va déposer un fichier (/vault/secrets/.env) contenant les variables d'environnements.
|
||||
|
||||
## Visuals
|
||||
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
|
||||
## Configuration
|
||||
Arguments de lancement :
|
||||
* -l (--log) : emplacement du fichier de log. (Default : /app/http-broadcaster.log)
|
||||
* -e (--envfile) : emplacement du fichier de variables d'environnement. (Default : /vault/secrets/.env)
|
||||
* --metrics : active l'exposition des métriques prometheus sur /metrics. (Default : false)
|
||||
|
||||
## Installation
|
||||
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
|
||||
### Variables d'environement
|
||||
|
||||
La liste de serveurs Varnish peut être fournie directement dans un fichier d'env :
|
||||
* VARNISH_SERVERS: list of varnish backend servers. Ex "http://10.13.32.1:6081,http://10.13.32.2:6081"
|
||||
* CLIENT_LIST : list of IPs in CIDR format (0.0.0.0/32) of authorized client to do purge/ban requests.
|
||||
|
||||
## Fonctionnalites
|
||||
|
||||
* Génère la liste des serveurs Varnish à partir des variables d'environnement.
|
||||
* Ecoute sur le port 6081.
|
||||
* Healthcheck disponible sur l'uri /healthcheck pour vérifier son bon fonctionnement. Renvoie un code HTTP 200 et le message "OK".
|
||||
* Metriques Prometheus disponible (désactivée par défaut).
|
||||
* Traite les requêtes entrantes en récupérant 3 éléments et en les intégrant à la requête transmise aux serveurs Varnish :
|
||||
- La méthode (PURGE ou BAN par exemple)
|
||||
- L'url : / pour BAN, /codes/api/greffes/0101 par exemple pour PURGE.
|
||||
- Le header X-Cache-Tags : dans le cas d'un BAN ce header contient une valeur.
|
||||
|
||||
## Usage
|
||||
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
|
||||
|
||||
## Support
|
||||
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
|
||||
|
||||
## Roadmap
|
||||
If you have ideas for releases in the future, it is a good idea to list them in the README.
|
||||
|
||||
## Contributing
|
||||
State if you are open to contributions and what your requirements are for accepting them.
|
||||
|
||||
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
|
||||
|
||||
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
|
||||
|
||||
## Authors and acknowledgment
|
||||
Show your appreciation to those who have contributed to the project.
|
||||
|
||||
## License
|
||||
For open source projects, say how it is licensed.
|
||||
|
||||
## Project status
|
||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||
Les interactions se font via le protocol HTTP. Les applications où les utilisateurs envoient une requête de méthode PURGE vers le démon.
|
||||
Une fois le traitement d'une requête effectuée, le démon renvoie 200 si tout est ok, 405 dans le cas contraire.
|
||||
|
||||
2
app/.env.example
Normal file
2
app/.env.example
Normal file
@@ -0,0 +1,2 @@
|
||||
CLIENT_LIST="127.0.0.1/32"
|
||||
VARNISH_SERVERS="127.0.0.1:6081"
|
||||
114
app/Http/utils.go
Normal file
114
app/Http/utils.go
Normal file
@@ -0,0 +1,114 @@
|
||||
// Package http provides functions to handle incoming HTTP requests
|
||||
package http
|
||||
|
||||
import (
|
||||
prometheus "http-broadcaster/Prometheus"
|
||||
tools "http-broadcaster/Tools"
|
||||
varnish "http-broadcaster/Varnish"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// logRequest print the requests and wanted informations in log file
|
||||
func logRequest(t time.Time, r *http.Request, s int, h map[string]string) {
|
||||
// Test if X-Cache-Tags header is empty
|
||||
if len(h) == 0 {
|
||||
log.Printf("%s %s - - %s \"%s %s %s\" %d 0 \"-\" \"%s\" %d\n",
|
||||
r.Host,
|
||||
r.Header["X-Forwarded-For"][0],
|
||||
t.Format("[02/Jan/2006:15:04:05 -0700]"),
|
||||
r.Method,
|
||||
r.URL.Path,
|
||||
r.Proto,
|
||||
s,
|
||||
r.UserAgent(),
|
||||
time.Since(t).Milliseconds(),
|
||||
)
|
||||
} else {
|
||||
var header string
|
||||
if h["X-Cache-Tags"] != "" {
|
||||
header = h["X-Cache-Tags"]
|
||||
} else {
|
||||
header = h["ApiPlatform-Ban-Regex"]
|
||||
}
|
||||
log.Printf("%s %s - - %s \"%s %s %s\" %d 0 \"-\" \"%s\" %d %s\n",
|
||||
r.Host,
|
||||
r.Header["X-Forwarded-For"][0],
|
||||
t.Format("[02/Jan/2006:15:04:05 -0700]"),
|
||||
r.Method,
|
||||
r.URL.Path,
|
||||
r.Proto,
|
||||
s,
|
||||
r.UserAgent(),
|
||||
time.Since(t).Milliseconds(),
|
||||
header,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// checkAllowedIP verify if the IPs is authorized to do BAN/PURGE request.
|
||||
func checkAllowedIP(ip string) bool {
|
||||
return tools.IPAllowed(ip)
|
||||
}
|
||||
|
||||
// RequestHandler handles requests to broadcast to all varnish instances.
|
||||
func RequestHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var tag = make(map[string]string)
|
||||
ipAddress := r.RemoteAddr
|
||||
// check x-forwarded-for instead of RemoteAddr header because kube
|
||||
//ip, err := netip.ParseAddr(r.Header["X-Forwarded-For"][0])
|
||||
fwdAddress := r.Header.Get("X-Forwarded-For")
|
||||
if fwdAddress != "" {
|
||||
// Case there is a single IP in the header
|
||||
ipAddress = fwdAddress
|
||||
|
||||
ips := strings.Split(fwdAddress, ",")
|
||||
if len(ips) > 1 {
|
||||
ipAddress = ips[0]
|
||||
}
|
||||
}
|
||||
|
||||
// If IP is not authorized to do purge/ban requests, respond with 401.
|
||||
if !checkAllowedIP(ipAddress) {
|
||||
log.Printf("Client ip not authorized : %v", ipAddress)
|
||||
w.WriteHeader(401)
|
||||
_, _ = io.WriteString(w, strconv.Itoa(401))
|
||||
return
|
||||
}
|
||||
// If metrics are not enabled, return 404 on /metrics path.
|
||||
if r.URL.Path == "/metrics" && !prometheus.MetricsEnabled {
|
||||
w.WriteHeader(404)
|
||||
_, _ = io.WriteString(w, strconv.Itoa(404))
|
||||
return
|
||||
}
|
||||
t := time.Now()
|
||||
url := r.URL.String()
|
||||
method := r.Method
|
||||
h := r.Header.Get("X-Cache-Tags")
|
||||
if h != "" {
|
||||
tag["X-Cache-Tags"] = h
|
||||
}
|
||||
h = r.Header.Get("ApiPlatform-Ban-Regex")
|
||||
if h != "" {
|
||||
tag["ApiPlatform-Ban-Regex"] = h
|
||||
}
|
||||
status := varnish.SendToVarnish(method, url, tag)
|
||||
if prometheus.MetricsEnabled {
|
||||
prometheus.IncrementClientCounterVec(method)
|
||||
}
|
||||
// Return HTTP code 405 if not all varnish servers returned 200.
|
||||
if status != 200 {
|
||||
w.WriteHeader(405)
|
||||
}
|
||||
logRequest(t, r, status, tag)
|
||||
_, _ = io.WriteString(w, strconv.Itoa(status))
|
||||
}
|
||||
|
||||
// HealthHandler handles healthcheck requests and return 200.
|
||||
func HealthHandler(w http.ResponseWriter, _ *http.Request) {
|
||||
_, _ = io.WriteString(w, "OK")
|
||||
}
|
||||
76
app/Prometheus/utils.go
Normal file
76
app/Prometheus/utils.go
Normal file
@@ -0,0 +1,76 @@
|
||||
// Package prometheus provides useful functions to initialize and populate metrics
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/collectors"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
// Metrics structure for storing counter
|
||||
type Metrics struct {
|
||||
ClientHTTPReqs *prometheus.CounterVec
|
||||
BackendHTTPReqs *prometheus.CounterVec
|
||||
}
|
||||
|
||||
var (
|
||||
// HTTPCounter Metrics
|
||||
HTTPCounter = initializeHTTPReqCounter()
|
||||
// Reg is a custom registry to have more control on metrics exported.
|
||||
Reg = prometheus.NewRegistry()
|
||||
// MetricsEnabled is the flag used to enable the prometheus metrics backend.
|
||||
MetricsEnabled = false
|
||||
)
|
||||
|
||||
// InitMetrics enable the metrics functionality if the flags is passed as an argument
|
||||
func InitMetrics(m bool) {
|
||||
if m {
|
||||
MetricsEnabled = true
|
||||
initPrometheusRegistry()
|
||||
// Define custom promhttp handler that expose just our custom registry.
|
||||
http.Handle("/metrics", promhttp.HandlerFor(Reg, promhttp.HandlerOpts{
|
||||
EnableOpenMetrics: true,
|
||||
Registry: Reg,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
// InitPrometheusRegistry initialize registry and counters if metrics flag pass as argument.
|
||||
func initPrometheusRegistry() {
|
||||
// We use a custom registry to better now what metrics are exposed.
|
||||
Reg = prometheus.NewRegistry()
|
||||
Reg.MustRegister(HTTPCounter.ClientHTTPReqs)
|
||||
Reg.MustRegister(HTTPCounter.BackendHTTPReqs)
|
||||
Reg.MustRegister(collectors.NewBuildInfoCollector())
|
||||
}
|
||||
|
||||
// IncrementClientCounterVec increments the counter with method label provided.
|
||||
func IncrementClientCounterVec(m string) {
|
||||
HTTPCounter.ClientHTTPReqs.WithLabelValues(m).Inc()
|
||||
}
|
||||
|
||||
// IncrementBackendCounterVec increments the counter with method label provided.
|
||||
func IncrementBackendCounterVec(m string) {
|
||||
HTTPCounter.BackendHTTPReqs.WithLabelValues(m).Inc()
|
||||
}
|
||||
|
||||
// InitializeHTTPReqCounter inits the httpReqs counter that will be exported.
|
||||
func initializeHTTPReqCounter() *Metrics {
|
||||
HTTPCounters := &Metrics{
|
||||
ClientHTTPReqs: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "client_http_requests_total",
|
||||
Help: "How many HTTP requests processed, partitioned by HTTP method.",
|
||||
},
|
||||
[]string{"method"},
|
||||
),
|
||||
BackendHTTPReqs: prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "backend_http_requests_total",
|
||||
Help: "How many HTTP requests sent to backend, partitioned by HTTP method.",
|
||||
},
|
||||
[]string{"method"},
|
||||
),
|
||||
}
|
||||
return HTTPCounters
|
||||
}
|
||||
64
app/Tools/utils.go
Normal file
64
app/Tools/utils.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package Tools
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/netip"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
var (
|
||||
// ClientList contains IPs/networks authorized to do purge/ban
|
||||
ClientList []netip.Prefix
|
||||
)
|
||||
|
||||
// ReadDotEnvFile reads environment variables from .env file
|
||||
func ReadDotEnvFile(f string) {
|
||||
err := godotenv.Load(f)
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
}
|
||||
|
||||
// InitLog ensure log file exists and set appropriate flags (remove timestamp at start of line).
|
||||
func InitLog(p string) {
|
||||
logFile, err := os.OpenFile(p, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
log.SetOutput(logFile)
|
||||
log.SetFlags(log.Flags() &^ (log.Ldate | log.Ltime))
|
||||
}
|
||||
|
||||
// InitAllowedIPList initialize the list of client authorized to do purge/ban requests
|
||||
func InitAllowedIPList(l string) []netip.Prefix {
|
||||
list := []netip.Prefix{}
|
||||
if l != "" {
|
||||
sliceData := strings.Split(l, ",")
|
||||
for i := 0; i < len(sliceData); i++ {
|
||||
t, err := netip.ParsePrefix(sliceData[i])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
list = append(list, t)
|
||||
}
|
||||
return list
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
// IPAllowed check if the IP is authorized to do BAN/PURGE requests
|
||||
func IPAllowed(ip string) bool {
|
||||
ipAddr, err := netip.ParseAddr(ip)
|
||||
if err != nil {
|
||||
log.Printf("Ip address wrong format %s", err)
|
||||
}
|
||||
for i := 0; i < len(ClientList); i++ {
|
||||
if ClientList[i].Contains(ipAddr) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
64
app/Varnish/utils.go
Normal file
64
app/Varnish/utils.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Package varnish provides functions to build the list of varnish servers that will be used
|
||||
package varnish
|
||||
|
||||
import (
|
||||
prometheus2 "http-broadcaster/Prometheus"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// VarnishList contains the list of varnish servers.
|
||||
VarnishList []string
|
||||
status = 200
|
||||
)
|
||||
|
||||
// InitializeVarnishList sets varnishList variable according to the LIST_METHOD env var
|
||||
func InitializeVarnishList(l string) []string {
|
||||
data := os.Getenv("VARNISH_SERVERS")
|
||||
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 map[string]string) int {
|
||||
status = 200
|
||||
|
||||
// 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{
|
||||
Timeout: 10 * time.Second,
|
||||
}
|
||||
// sanitize varnish server host.
|
||||
domain := strings.Trim(VarnishList[i], "\r\n")
|
||||
req, err := http.NewRequest(method, domain+url, nil)
|
||||
if err != nil {
|
||||
log.Println("Create new request : ", err)
|
||||
}
|
||||
// If X-Cache-Tags header is not empty with pass it to varnish.
|
||||
if tag["X-Cache-Tags"] != "" {
|
||||
req.Header.Add("X-Cache-Tags", tag["X-Cache-Tags"])
|
||||
}
|
||||
if tag["ApiPlatform-Ban-Regex"] != "" {
|
||||
req.Header.Add("ApiPlatform-Ban-Regex", tag["ApiPlatform-Ban-Regex"])
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Println("Send new request : ", err)
|
||||
}
|
||||
if prometheus2.MetricsEnabled {
|
||||
prometheus2.IncrementBackendCounterVec(method)
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
status = 405
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
return status
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
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
|
||||
}
|
||||
24
app/go.mod
24
app/go.mod
@@ -1,3 +1,25 @@
|
||||
module http-broadcaster
|
||||
|
||||
go 1.13
|
||||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/alexflint/go-arg v1.5.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/alexflint/go-scalar v1.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
)
|
||||
|
||||
138
app/go.sum
Normal file
138
app/go.sum
Normal file
@@ -0,0 +1,138 @@
|
||||
github.com/alecthomas/kingpin/v2 v2.3.1 h1:ANLJcKmQm4nIaog7xdr/id6FM6zm5hHnfZrvtKPxqGg=
|
||||
github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc=
|
||||
github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo=
|
||||
github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA=
|
||||
github.com/alexflint/go-arg v1.5.0 h1:rwMKGiaQuRbXfZNyRUvIfke63QvOBt1/QTshlGQHohM=
|
||||
github.com/alexflint/go-arg v1.5.0/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8=
|
||||
github.com/alexflint/go-arg v1.5.1 h1:nBuWUCpuRy0snAG+uIJ6N0UvYxpxA0/ghA/AaHxlT8Y=
|
||||
github.com/alexflint/go-arg v1.5.1/go.mod h1:A7vTJzvjoaSTypg4biM5uYNTkJ27SkNTArtYXnlqVO8=
|
||||
github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM=
|
||||
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
||||
github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
|
||||
github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
|
||||
github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
|
||||
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/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
|
||||
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
|
||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
|
||||
github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
|
||||
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg=
|
||||
github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
|
||||
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
|
||||
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/xhit/go-str2duration v1.2.0 h1:BcV5u025cITWxEQKGWr1URRzrcXtu7uk8+luz3Yuhwc=
|
||||
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
0
app/log/.gitkeep
Normal file
0
app/log/.gitkeep
Normal file
90
app/main.go
90
app/main.go
@@ -1,77 +1,35 @@
|
||||
// Receive http PURGE request and broadcast it to several Varnish servers.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
h "http-broadcaster/Http"
|
||||
prometheus2 "http-broadcaster/Prometheus"
|
||||
tools "http-broadcaster/Tools"
|
||||
varnish "http-broadcaster/Varnish"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
const (
|
||||
// MethodPurge declaration for Varnish.
|
||||
MethodPurge = "PURGE"
|
||||
"github.com/alexflint/go-arg"
|
||||
)
|
||||
|
||||
var (
|
||||
varnishList = MakeVarnishList()
|
||||
status = "200 Purged"
|
||||
args struct {
|
||||
Log string `arg:"-l,--logfile" help:"location of output logfile." default:"/app/http-broadcaster.log"`
|
||||
EnvFile string `arg:"-e,--envfile" help:"location of file containing environment variables." default:"/vault/secrets/.env"`
|
||||
Metrics bool `arg:"--metrics" help:"enable prometheus exporter on /metrics." default:"false"`
|
||||
}
|
||||
)
|
||||
|
||||
// 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))
|
||||
arg.MustParse(&args)
|
||||
tools.InitLog(args.Log)
|
||||
tools.ReadDotEnvFile(args.EnvFile)
|
||||
tools.ClientList = tools.InitAllowedIPList(os.Getenv("CLIENT_LIST"))
|
||||
varnish.VarnishList = varnish.InitializeVarnishList(os.Getenv("VARNISH_SERVERS"))
|
||||
prometheus2.InitMetrics(args.Metrics)
|
||||
|
||||
http.HandleFunc("/", h.RequestHandler)
|
||||
http.HandleFunc("/healthcheck", h.HealthHandler)
|
||||
log.Fatal(http.ListenAndServe(":6081", nil))
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
http://10.13.32.1:6081,http://10.13.32.2:6081
|
||||
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
|
||||
version: '0.1'
|
||||
services:
|
||||
broadcaster:
|
||||
container_name: httpbroadcaster
|
||||
build:
|
||||
context: ./
|
||||
target: dev
|
||||
ports:
|
||||
- "6081:6081"
|
||||
volumes:
|
||||
- ./app/:/app/
|
||||
networks:
|
||||
- http-broadcaster
|
||||
networks:
|
||||
http-broadcaster:
|
||||
driver: bridge
|
||||
1
docker/config/env.local
Normal file
1
docker/config/env.local
Normal file
@@ -0,0 +1 @@
|
||||
VARNISH_SERVERS="http://192.168.1.2:6081,http://192.168.1.1:6081"
|
||||
Reference in New Issue
Block a user