diff --git a/README.md b/README.md index a61a35f..ea8c8aa 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ docker run --rm v2tec/watchtower --help * `--label-enable` Watch containers where the `com.centurylinklabs.watchtower.enable` label is set to true. * `--cleanup` Remove old images after updating. When this flag is specified, watchtower will remove the old image after restarting a container with a new image. Use this option to prevent the accumulation of orphaned images on your system as containers are updated. * `--tlsverify` Use TLS when connecting to the Docker socket and verify the server's certificate. +* `--enable-update-commands` Enable the execution of *pre-update* and *post-update* commands on containers updated by watchtower. * `--debug` Enable debug mode. When this option is specified you'll see more verbose logging in the watchtower log file. * `--help` Show documentation about the supported flags. @@ -275,16 +276,23 @@ docker run -d \ -e WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA=true \ v2tec/watchtower ``` + ## Executing commands before and after updating It is possible to execute a *pre-update* command and a *post-update* command inside every container updated by watchtower. The *pre-update* command is executed before stopping the container, and the *post-update* command is -executed after restarting the container. +executed after restarting the container. + +This feature is disabled by default. To enable it, you need to set the option +`--enable-update-commands` on the command line, or set the environment variable +`WATCHTOWER_ENABLE_UPDATE_COMMANDS` to true. Both commands are shell commands executed with `sh`, and therefore require the container to provide the `sh` executable. +### Specifying update commands + The commands are specified using docker container labels, with *com.centurylinklabs.watchtower.pre-update-command* for the *pre-update* command and *com.centurylinklabs.watchtower.post-update-command* for the @@ -306,6 +314,8 @@ docker run -d \ someimage ``` +### Execution failure + The failure of a command to execute, identified by an exit code different than 0, should not prevent watchtower from updating the container. Only an error log statement containing the exit code will be reported. \ No newline at end of file diff --git a/actions/update.go b/actions/update.go index 7bf6f4a..5fba7ce 100644 --- a/actions/update.go +++ b/actions/update.go @@ -16,7 +16,7 @@ var ( // used to start those containers have been updated. If a change is detected in // any of the images, the associated containers are stopped and restarted with // the new image. -func Update(client container.Client, filter container.Filter, cleanup bool, noRestart bool, timeout time.Duration) error { +func Update(client container.Client, filter container.Filter, cleanup bool, noRestart bool, timeout time.Duration, enableUpdateCmd bool) error { log.Debug("Checking containers for updated images") containers, err := client.ListContainers(filter) @@ -52,7 +52,7 @@ func Update(client container.Client, filter container.Filter, cleanup bool, noRe // Execute the pre-update command if it is defined. preUpdateCommand := container.PreUpdateCommand() - if len(preUpdateCommand) > 0 { + if enableUpdateCmd && len(preUpdateCommand) > 0 { log.Info("Executing pre-update command.") if err := client.ExecuteCommand(container, preUpdateCommand); err != nil { log.Error(err) @@ -92,7 +92,7 @@ func Update(client container.Client, filter container.Filter, cleanup bool, noRe log.Error(err) } else { // Execute the post-update command if it is defined. - if len(postUpdateCommand) > 0 { + if enableUpdateCmd && len(postUpdateCommand) > 0 { log.Info("Executing post-update command.") if err := client.ExecuteCommand(container, postUpdateCommand); err != nil { log.Error(err) diff --git a/main.go b/main.go index 2b6fba5..8c2b349 100644 --- a/main.go +++ b/main.go @@ -25,13 +25,14 @@ var commit = "unknown" var date = "unknown" var ( - client container.Client - scheduleSpec string - cleanup bool - noRestart bool - enableLabel bool - notifier *notifications.Notifier - timeout time.Duration + client container.Client + scheduleSpec string + cleanup bool + noRestart bool + enableLabel bool + notifier *notifications.Notifier + timeout time.Duration + enableUpdateCmd bool ) func init() { @@ -84,10 +85,10 @@ func main() { EnvVar: "DOCKER_TLS_VERIFY", }, cli.DurationFlag{ - Name: "stop-timeout", - Usage: "timeout before container is forcefully stopped", - Value: time.Second * 10, - EnvVar: "WATCHTOWER_TIMEOUT", + Name: "stop-timeout", + Usage: "timeout before container is forcefully stopped", + Value: time.Second * 10, + EnvVar: "WATCHTOWER_TIMEOUT", }, cli.BoolFlag{ Name: "label-enable", @@ -171,6 +172,11 @@ func main() { Usage: "The MSTeams notifier will try to extract log entry fields as MSTeams message facts", EnvVar: "WATCHTOWER_NOTIFICATION_MSTEAMS_USE_LOG_DATA", }, + cli.BoolFlag{ + Name: "enable-update-commands", + Usage: "Enable the execution of pre-update and post-update commands", + EnvVar: "WATCHTOWER_ENABLE_UPDATE_COMMANDS", + }, } if err := app.Run(os.Args); err != nil { @@ -201,6 +207,7 @@ func before(c *cli.Context) error { log.Fatal("Please specify a positive value for timeout value.") } enableLabel = c.GlobalBool("label-enable") + enableUpdateCmd = c.GlobalBool("enable-update-commands") // configure environment vars for client err := envConfig(c) @@ -234,7 +241,7 @@ func start(c *cli.Context) error { case v := <-tryLockSem: defer func() { tryLockSem <- v }() notifier.StartNotification() - if err := actions.Update(client, filter, cleanup, noRestart, timeout); err != nil { + if err := actions.Update(client, filter, cleanup, noRestart, timeout, enableUpdateCmd); err != nil { log.Println(err) } notifier.SendNotification()