mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-22 05:40:50 +02:00
Allow running periodic updates with enabled HTTP API (#916)
* Allow running periodic updates with enabled HTTP API * Add --http-api-periodic-polls to docs
This commit is contained in:
parent
e308521a95
commit
6b155a111a
6 changed files with 55 additions and 12 deletions
25
cmd/root.go
25
cmd/root.go
|
@ -156,6 +156,7 @@ func Run(c *cobra.Command, names []string) {
|
||||||
runOnce, _ := c.PersistentFlags().GetBool("run-once")
|
runOnce, _ := c.PersistentFlags().GetBool("run-once")
|
||||||
enableUpdateAPI, _ := c.PersistentFlags().GetBool("http-api-update")
|
enableUpdateAPI, _ := c.PersistentFlags().GetBool("http-api-update")
|
||||||
enableMetricsAPI, _ := c.PersistentFlags().GetBool("http-api-metrics")
|
enableMetricsAPI, _ := c.PersistentFlags().GetBool("http-api-metrics")
|
||||||
|
unblockHTTPAPI, _ := c.PersistentFlags().GetBool("http-api-periodic-polls")
|
||||||
apiToken, _ := c.PersistentFlags().GetString("http-api-token")
|
apiToken, _ := c.PersistentFlags().GetString("http-api-token")
|
||||||
|
|
||||||
if rollingRestart && monitorOnly {
|
if rollingRestart && monitorOnly {
|
||||||
|
@ -180,10 +181,14 @@ func Run(c *cobra.Command, names []string) {
|
||||||
logNotifyExit(err)
|
logNotifyExit(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The lock is shared between the scheduler and the HTTP API. It only allows one update to run at a time.
|
||||||
|
updateLock := make(chan bool, 1)
|
||||||
|
updateLock <- true
|
||||||
|
|
||||||
httpAPI := api.New(apiToken)
|
httpAPI := api.New(apiToken)
|
||||||
|
|
||||||
if enableUpdateAPI {
|
if enableUpdateAPI {
|
||||||
updateHandler := update.New(func() { runUpdatesWithNotifications(filter) })
|
updateHandler := update.New(func() { runUpdatesWithNotifications(filter) }, updateLock)
|
||||||
httpAPI.RegisterFunc(updateHandler.Path, updateHandler.Handle)
|
httpAPI.RegisterFunc(updateHandler.Path, updateHandler.Handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +197,11 @@ func Run(c *cobra.Command, names []string) {
|
||||||
httpAPI.RegisterHandler(metricsHandler.Path, metricsHandler.Handle)
|
httpAPI.RegisterHandler(metricsHandler.Path, metricsHandler.Handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := httpAPI.Start(enableUpdateAPI); err != nil {
|
if err := httpAPI.Start(enableUpdateAPI && !unblockHTTPAPI); err != nil {
|
||||||
log.Error("failed to start API", err)
|
log.Error("failed to start API", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := runUpgradesOnSchedule(c, filter, filterDesc); err != nil {
|
if err := runUpgradesOnSchedule(c, filter, filterDesc, updateLock); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,17 +280,19 @@ func writeStartupMessage(c *cobra.Command, sched time.Time, filtering string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runUpgradesOnSchedule(c *cobra.Command, filter t.Filter, filtering string) error {
|
func runUpgradesOnSchedule(c *cobra.Command, filter t.Filter, filtering string, lock chan bool) error {
|
||||||
tryLockSem := make(chan bool, 1)
|
if lock == nil {
|
||||||
tryLockSem <- true
|
lock = make(chan bool, 1)
|
||||||
|
lock <- true
|
||||||
|
}
|
||||||
|
|
||||||
scheduler := cron.New()
|
scheduler := cron.New()
|
||||||
err := scheduler.AddFunc(
|
err := scheduler.AddFunc(
|
||||||
scheduleSpec,
|
scheduleSpec,
|
||||||
func() {
|
func() {
|
||||||
select {
|
select {
|
||||||
case v := <-tryLockSem:
|
case v := <-lock:
|
||||||
defer func() { tryLockSem <- v }()
|
defer func() { lock <- v }()
|
||||||
metric := runUpdatesWithNotifications(filter)
|
metric := runUpdatesWithNotifications(filter)
|
||||||
metrics.RegisterScan(metric)
|
metrics.RegisterScan(metric)
|
||||||
default:
|
default:
|
||||||
|
@ -316,7 +323,7 @@ func runUpgradesOnSchedule(c *cobra.Command, filter t.Filter, filtering string)
|
||||||
<-interrupt
|
<-interrupt
|
||||||
scheduler.Stop()
|
scheduler.Stop()
|
||||||
log.Info("Waiting for running update to be finished...")
|
log.Info("Waiting for running update to be finished...")
|
||||||
<-tryLockSem
|
<-lock
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,6 +255,16 @@ Environment Variable: WATCHTOWER_HTTP_API_TOKEN
|
||||||
Default: -
|
Default: -
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## HTTP API periodic polls
|
||||||
|
Keep running periodic updates if the HTTP API mode is enabled, otherwise the HTTP API would prevent periodic polls.
|
||||||
|
|
||||||
|
```
|
||||||
|
Argument: --http-api-periodic-polls
|
||||||
|
Environment Variable: WATCHTOWER_HTTP_API_PERIODIC_POLLS
|
||||||
|
Type: Boolean
|
||||||
|
Default: false
|
||||||
|
```
|
||||||
|
|
||||||
## Filter by scope
|
## Filter by scope
|
||||||
Update containers that have a `com.centurylinklabs.watchtower.scope` label set with the same value as the given argument.
|
Update containers that have a `com.centurylinklabs.watchtower.scope` label set with the same value as the given argument.
|
||||||
This enables [running multiple instances](https://containrrr.github.io/watchtower/running-multiple-instances).
|
This enables [running multiple instances](https://containrrr.github.io/watchtower/running-multiple-instances).
|
||||||
|
|
|
@ -28,6 +28,8 @@ services:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
```
|
```
|
||||||
|
|
||||||
|
By default, enabling this mode prevents periodic polls (i.e. what is specified using `--interval` or `--schedule`). To run periodic updates regardless, pass `--http-api-periodic-polls`.
|
||||||
|
|
||||||
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:
|
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
|
```bash
|
||||||
|
|
|
@ -151,6 +151,11 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
|
||||||
"",
|
"",
|
||||||
viper.GetString("WATCHTOWER_HTTP_API_TOKEN"),
|
viper.GetString("WATCHTOWER_HTTP_API_TOKEN"),
|
||||||
"Sets an authentication token to HTTP API requests.")
|
"Sets an authentication token to HTTP API requests.")
|
||||||
|
flags.BoolP(
|
||||||
|
"http-api-periodic-polls",
|
||||||
|
"",
|
||||||
|
viper.GetBool("WATCHTOWER_HTTP_API_PERIODIC_POLLS"),
|
||||||
|
"Also run periodic updates (specified with --interval and --schedule) if HTTP API is enabled")
|
||||||
// https://no-color.org/
|
// https://no-color.org/
|
||||||
flags.BoolP(
|
flags.BoolP(
|
||||||
"no-color",
|
"no-color",
|
||||||
|
|
|
@ -79,3 +79,18 @@ func testGetSecretsFromFiles(t *testing.T, flagName string, expected string) {
|
||||||
|
|
||||||
assert.Equal(t, expected, value)
|
assert.Equal(t, expected, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHTTPAPIPeriodicPollsFlag(t *testing.T) {
|
||||||
|
cmd := new(cobra.Command)
|
||||||
|
SetDefaults()
|
||||||
|
RegisterDockerFlags(cmd)
|
||||||
|
RegisterSystemFlags(cmd)
|
||||||
|
|
||||||
|
err := cmd.ParseFlags([]string{"--http-api-periodic-polls"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
periodicPolls, err := cmd.PersistentFlags().GetBool("http-api-periodic-polls")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Equal(t, true, periodicPolls)
|
||||||
|
}
|
||||||
|
|
|
@ -13,9 +13,13 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// New is a factory function creating a new Handler instance
|
// New is a factory function creating a new Handler instance
|
||||||
func New(updateFn func()) *Handler {
|
func New(updateFn func(), updateLock chan bool) *Handler {
|
||||||
|
if updateLock != nil {
|
||||||
|
lock = updateLock
|
||||||
|
} else {
|
||||||
lock = make(chan bool, 1)
|
lock = make(chan bool, 1)
|
||||||
lock <- true
|
lock <- true
|
||||||
|
}
|
||||||
|
|
||||||
return &Handler{
|
return &Handler{
|
||||||
fn: updateFn,
|
fn: updateFn,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue