mirror of
https://github.com/containrrr/watchtower.git
synced 2025-12-16 15:10:12 +01:00
Use simple string instead of JSON string for pre/post update commands.
This commit is contained in:
parent
25c7853f03
commit
78a375f86e
5 changed files with 26 additions and 88 deletions
26
README.md
26
README.md
|
|
@ -280,35 +280,23 @@ docker run -d \
|
|||
For every container that could be updated by watchtower, it is possible to
|
||||
specify a command that will be executed before stopping the container (a
|
||||
`pre-update` command), and a command that will be executed after restarting the
|
||||
container (a `post-update` command).
|
||||
|
||||
These commands are specified using the *com.centurylinklabs.watchtower.pre-update-command*
|
||||
and the *com.centurylinklabs.watchtower.post-update-command* labels. The values
|
||||
of these labels are JSON formatted strings that describes the commands.
|
||||
container (a `post-update` command). These commands are specified using the
|
||||
*com.centurylinklabs.watchtower.pre-update-command* and the
|
||||
*com.centurylinklabs.watchtower.post-update-command* labels.
|
||||
|
||||
These labels can be declared as instructions in a Dockerfile:
|
||||
|
||||
```docker
|
||||
LABEL com.centurylinklabs.watchtower.pre-update-command='{"Cmd": ["sh", "-c", "/dump-data.sh"]}'
|
||||
LABEL com.centurylinklabs.watchtower.post-update-command='{"Cmd": ["sh", "-c", "/restore-data.sh"]}'
|
||||
LABEL com.centurylinklabs.watchtower.pre-update-command="/dump-data.sh"
|
||||
LABEL com.centurylinklabs.watchtower.post-update-command="/restore-data.sh"
|
||||
```
|
||||
|
||||
Or be specified as part of the `docker run` command line:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--label=com.centurylinklabs.watchtower.pre-update-command='{"Cmd": ["sh", "-c", "/dump-data.sh"]}' \
|
||||
--label=com.centurylinklabs.watchtower.post-update-command='{"Cmd": ["sh", "-c", "/restore-data.sh"]}' \
|
||||
--label=com.centurylinklabs.watchtower.pre-update-command="/dump-data.sh" \
|
||||
--label=com.centurylinklabs.watchtower.post-update-command="/restore-data.sh" \
|
||||
someimage
|
||||
```
|
||||
|
||||
The JSON object is made of the following fields:
|
||||
|
||||
* `Cmd`: the command to execute, as an array of strings (required)
|
||||
* `User`: a string representing a username or a UID. It is of the form `user`,
|
||||
`user:group`, `uid`, or `uid:gid` (optional)
|
||||
* `Privileged`: `true` if the command should be given extended privileges,
|
||||
`false` otherwise (optional, default to `false`)
|
||||
* `Env`: a list of instructions to set enviroment variables, for example
|
||||
`["FOO=bar", BAZ=quux]` (optional)
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,10 @@ func Update(client container.Client, filter container.Filter, cleanup bool, noRe
|
|||
if container.Stale {
|
||||
|
||||
// Execute the pre-update command if it is defined.
|
||||
preUpdateCommandInfo, err := container.PreUpdateCommandInfo()
|
||||
if err != nil {
|
||||
log.Error("Error while reading pre-update command info.")
|
||||
log.Error(err)
|
||||
} else if preUpdateCommandInfo.IsDefined() {
|
||||
preUpdateCommand := container.PreUpdateCommand()
|
||||
if len(preUpdateCommand) > 0 {
|
||||
log.Info("Executing pre-update command.")
|
||||
if err := client.ExecuteCommand(container, preUpdateCommandInfo); err != nil {
|
||||
if err := client.ExecuteCommand(container, preUpdateCommand); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -87,13 +84,10 @@ func Update(client container.Client, filter container.Filter, cleanup bool, noRe
|
|||
log.Error(err)
|
||||
} else {
|
||||
// Execute the post-update command if it is defined.
|
||||
postUpdateCommandInfo, err := container.PostUpdateCommandInfo()
|
||||
if err != nil {
|
||||
log.Error("Error while reading post-update command info.")
|
||||
log.Error(err)
|
||||
} else if postUpdateCommandInfo.IsDefined() {
|
||||
postUpdateCommand := container.PostUpdateCommand()
|
||||
if len(postUpdateCommand) > 0 {
|
||||
log.Info("Executing post-update command.")
|
||||
if err := client.ExecuteCommand(container, postUpdateCommandInfo); err != nil {
|
||||
if err := client.ExecuteCommand(container, postUpdateCommand); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ type Client interface {
|
|||
RenameContainer(Container, string) error
|
||||
IsContainerStale(Container) (bool, error)
|
||||
RemoveImage(Container) error
|
||||
ExecuteCommand(Container, CommandInfo) error
|
||||
ExecuteCommand(Container, string) error
|
||||
}
|
||||
|
||||
// NewClient returns a new Client instance which can be used to interact with
|
||||
|
|
@ -223,7 +223,7 @@ func (client dockerClient) IsContainerStale(c Container) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
func (client dockerClient) ExecuteCommand(c Container, commandInfo CommandInfo) error {
|
||||
func (client dockerClient) ExecuteCommand(c Container, command string) error {
|
||||
bg := context.Background()
|
||||
|
||||
// Get the id of the actual container
|
||||
|
|
@ -235,14 +235,11 @@ func (client dockerClient) ExecuteCommand(c Container, commandInfo CommandInfo)
|
|||
|
||||
// Create the exec
|
||||
execConfig := types.ExecConfig{
|
||||
User: commandInfo.User,
|
||||
Privileged: commandInfo.Privileged,
|
||||
Tty: true,
|
||||
AttachStderr: true,
|
||||
AttachStdout: true,
|
||||
Detach: false,
|
||||
Env: commandInfo.Env,
|
||||
Cmd: commandInfo.Cmd,
|
||||
Cmd: []string{"sh", "-c", command},
|
||||
}
|
||||
exec, err := client.api.ContainerExecCreate(bg, containerID, execConfig)
|
||||
if err != nil {
|
||||
|
|
@ -257,13 +254,13 @@ func (client dockerClient) ExecuteCommand(c Container, commandInfo CommandInfo)
|
|||
}
|
||||
|
||||
// Inspect the exec to get the exit code and print a message if the
|
||||
// exit code is not success
|
||||
// exit code is not success.
|
||||
execInspect, err := client.api.ContainerExecInspect(bg, exec.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if execInspect.ExitCode > 0 {
|
||||
log.Error("Failed to execute command.")
|
||||
log.Errorf("Command exited with code %v.", execInspect.ExitCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
package container
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// CommandInfo is the data structure used to encode information about a
|
||||
// pre/post-update command.
|
||||
type CommandInfo struct {
|
||||
User string
|
||||
Privileged bool
|
||||
Env []string
|
||||
Cmd []string
|
||||
}
|
||||
|
||||
// ReadCommandInfoFromJSON takes a JSON formatted description of a
|
||||
// pre/post-update as input and returns the parsed data as a CommandInfo.
|
||||
func ReadCommandInfoFromJSON(commandInfoJSON string) (CommandInfo, error) {
|
||||
commandInfo := CommandInfo{}
|
||||
|
||||
err := json.Unmarshal([]byte(commandInfoJSON), &commandInfo)
|
||||
if err != nil {
|
||||
return CommandInfo{}, err
|
||||
}
|
||||
|
||||
return commandInfo, nil
|
||||
}
|
||||
|
||||
// IsDefined returns true if a CommandInfo actually contains a command to
|
||||
// execute or false otherwise.
|
||||
func (commandInfo CommandInfo) IsDefined() bool {
|
||||
return commandInfo.Cmd != nil && len(commandInfo.Cmd) > 0
|
||||
}
|
||||
|
|
@ -119,34 +119,26 @@ func (c Container) StopSignal() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// PreUpdateCommandInfo returns the pre-update command set in the container's
|
||||
// PreUpdateCommand returns the pre-update command set in the container's
|
||||
// metadata or an empty string if the user did not set it.
|
||||
func (c Container) PreUpdateCommandInfo() (CommandInfo, error) {
|
||||
func (c Container) PreUpdateCommand() string {
|
||||
if val, ok := c.containerInfo.Config.Labels[preUpdateCommandLabel]; ok {
|
||||
|
||||
commandInfo, err := ReadCommandInfoFromJSON(val)
|
||||
if err != nil {
|
||||
return CommandInfo{}, err
|
||||
}
|
||||
return commandInfo, nil
|
||||
return val
|
||||
}
|
||||
|
||||
return CommandInfo{}, nil
|
||||
return ""
|
||||
}
|
||||
|
||||
// PostUpdateCommandInfo returns the post-update command set in the container's
|
||||
// PostUpdateCommand returns the post-update command set in the container's
|
||||
// metadata or an empty string if the user did not set it.
|
||||
func (c Container) PostUpdateCommandInfo() (CommandInfo, error) {
|
||||
func (c Container) PostUpdateCommand() string {
|
||||
if val, ok := c.containerInfo.Config.Labels[postUpdateCommandLabel]; ok {
|
||||
|
||||
commandInfo, err := ReadCommandInfoFromJSON(val)
|
||||
if err != nil {
|
||||
return CommandInfo{}, err
|
||||
}
|
||||
return commandInfo, nil
|
||||
return val
|
||||
}
|
||||
|
||||
return CommandInfo{}, nil
|
||||
return ""
|
||||
}
|
||||
|
||||
// Ideally, we'd just be able to take the ContainerConfig from the old container
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue