Watchtower HTTP API based updates (#432)
* Added HTTP API trigger to update running images * Adds HTTP API authentication token parameter and handling * Exposes port 8080 in Dockerfile to allow inter-container update triggering via HTTP API * Fixes codacy issue * Adds API usage doc * Fix grammar * Moves api logic to a package of its own * Makes WT exit if token has not been set in HTTP API mode * Adds lock to prevent concurrent updates when in HTTP API mode Co-authored-by: Simon Aronsson <simme@arcticbit.se>pull/509/head^2
parent
557f4abcb4
commit
0217e116c4
@ -0,0 +1,35 @@
|
|||||||
|
Watchtower provides an HTTP API mode that enables an HTTP endpoint that can be requested to trigger container updating. The current available endpoint list is:
|
||||||
|
|
||||||
|
- `/v1/update` - triggers an update for all of the containers monitored by this Watchtower instance.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
To enable this mode, use the flag `--http-api`. For example, in a Docker Compose config file:
|
||||||
|
|
||||||
|
```json
|
||||||
|
version: '3'
|
||||||
|
|
||||||
|
services:
|
||||||
|
app-monitored-by-watchtower:
|
||||||
|
image: myapps/monitored-by-watchtower
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=true"
|
||||||
|
|
||||||
|
watchtower:
|
||||||
|
image: containrrr/watchtower
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
command: --debug --http-api
|
||||||
|
environment:
|
||||||
|
- WATCHTOWER_HTTP_API_TOKEN=mytoken
|
||||||
|
labels:
|
||||||
|
- "com.centurylinklabs.watchtower.enable=false"
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that there is an environment variable named WATCHTOWER_HTTP_API_TOKEN. To prevent external services from accidentally triggering image updates, all of the requests have to contain a "Token" field, valued as the token defined in WATCHTOWER_HTTP_API_TOKEN, in their headers. In this case, there is a port bind to the host machine, allowing to request localhost:8080 to reach Watchtower. The following `curl` command would trigger an image update:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Token: mytoken" localhost:8080/v1/update
|
||||||
|
```
|
@ -0,0 +1,61 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"net/http"
|
||||||
|
"errors"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
lock chan bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
lock = make(chan bool, 1)
|
||||||
|
lock <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupHTTPUpdates(apiToken string, updateFunction func()) error {
|
||||||
|
if apiToken == "" {
|
||||||
|
return errors.New("API token is empty or has not been set. Not starting API.")
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Watchtower HTTP API started.")
|
||||||
|
|
||||||
|
http.HandleFunc("/v1/update", func(w http.ResponseWriter, r *http.Request){
|
||||||
|
log.Info("Updates triggered by HTTP API request.")
|
||||||
|
|
||||||
|
_, err := io.Copy(os.Stdout, r.Body)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.Header.Get("Token") != apiToken {
|
||||||
|
log.Println("Invalid token. Not updating.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("Valid token found. Attempting to update.")
|
||||||
|
|
||||||
|
select {
|
||||||
|
case chanValue := <- lock:
|
||||||
|
defer func() { lock <- chanValue }()
|
||||||
|
updateFunction()
|
||||||
|
default:
|
||||||
|
log.Debug("Skipped. Another update already running.")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WaitForHTTPUpdates() error {
|
||||||
|
log.Fatal(http.ListenAndServe(":8080", nil))
|
||||||
|
os.Exit(0)
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
Reference in New Issue