Feat/lifecycle hooks (#351)

* feat(update): add lifecycle hooks to the update action

* fix(ci): add bash tests for lifecycle-hooks to the ci workflow

* fix(ci): move integration tests to an isolated step

* fix(ci): fix malformed all-contributors json

* fix(ci): disable automatic bash test until we figure out a reasonable way to run it in circleci
This commit is contained in:
Simon Aronsson 2019-07-27 01:37:16 +02:00 committed by GitHub
parent 874180a518
commit bfae38dbf8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 499 additions and 73 deletions

View file

@ -160,7 +160,7 @@ func (client mockClient) StopContainer(c container.Container, d time.Duration) e
}
return nil
}
func (client mockClient) StartContainer(c container.Container) error {
func (client mockClient) StartContainer(c container.Container) (string, error) {
panic("Not implemented")
}
@ -173,6 +173,14 @@ func (client mockClient) RemoveImage(c container.Container) error {
return nil
}
func (client mockClient) GetContainer(containerID string) (container.Container, error) {
return container.Container{}, nil
}
func (client mockClient) ExecuteCommand(containerID string, command string) error {
return nil
}
func (client mockClient) IsContainerStale(c container.Container) (bool, error) {
panic("Not implemented")
}

View file

@ -61,8 +61,9 @@ func stopStaleContainer(container container.Container, client container.Client,
return
}
err := client.StopContainer(container, params.Timeout)
if err != nil {
executePreUpdateCommand(client, container)
if err := client.StopContainer(container, params.Timeout); err != nil {
log.Error(err)
}
}
@ -89,8 +90,10 @@ func restartStaleContainer(container container.Container, client container.Clien
}
if !params.NoRestart {
if err := client.StartContainer(container); err != nil {
if newContainerID, err := client.StartContainer(container); err != nil {
log.Error(err)
} else if container.Stale && params.LifecycleHooks {
executePostUpdateCommand(client, newContainerID)
}
}
@ -104,18 +107,49 @@ func restartStaleContainer(container container.Container, client container.Clien
func checkDependencies(containers []container.Container) {
for i, parent := range containers {
if parent.Stale {
if parent.ToRestart() {
continue
}
LinkLoop:
for _, linkName := range parent.Links() {
for _, child := range containers {
if child.Name() == linkName && child.Stale {
containers[i].Stale = true
if child.Name() == linkName && child.ToRestart() {
containers[i].Linked = true
break LinkLoop
}
}
}
}
}
func executePreUpdateCommand(client container.Client, container container.Container) {
command := container.GetLifecyclePreUpdateCommand()
if len(command) == 0 {
log.Debug("No pre-update command supplied. Skipping")
}
log.Info("Executing pre-update command.")
if err := client.ExecuteCommand(container.ID(), command); err != nil {
log.Error(err)
}
}
func executePostUpdateCommand(client container.Client, newContainerID string) {
newContainer, err := client.GetContainer(newContainerID)
if err != nil {
log.Error(err)
return
}
command := newContainer.GetLifecyclePostUpdateCommand()
if len(command) == 0 {
log.Debug("No post-update command supplied. Skipping")
}
log.Info("Executing post-update command.")
if err := client.ExecuteCommand(newContainerID, command); err != nil {
log.Error(err)
}
}

View file

@ -7,9 +7,10 @@ import (
// UpdateParams contains all different options available to alter the behavior of the Update func
type UpdateParams struct {
Filter t.Filter
Cleanup bool
NoRestart bool
Timeout time.Duration
MonitorOnly bool
Filter t.Filter
Cleanup bool
NoRestart bool
Timeout time.Duration
MonitorOnly bool
LifecycleHooks bool
}

View file

@ -88,6 +88,12 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
"S",
viper.GetBool("WATCHTOWER_INCLUDE_STOPPED"),
"Will also include created and exited containers")
flags.BoolP(
"enable-lifecycle-hooks",
"",
viper.GetBool("WATCHTOWER_LIFECYCLE_HOOKS"),
"Enable the execution of commands triggered by pre- and post-update lifecycle hooks")
}
// RegisterNotificationFlags that are used by watchtower to send notifications