diff --git a/README.md b/README.md index 5e43473..578768c 100644 --- a/README.md +++ b/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) - diff --git a/actions/update.go b/actions/update.go index 6d04fa1..c430b4e 100644 --- a/actions/update.go +++ b/actions/update.go @@ -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) } } diff --git a/container/client.go b/container/client.go index 98041a6..7b9adc9 100644 --- a/container/client.go +++ b/container/client.go @@ -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 diff --git a/container/command_info.go b/container/command_info.go deleted file mode 100644 index 08b0a37..0000000 --- a/container/command_info.go +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/container/container.go b/container/container.go index 702949d..3173ac6 100644 --- a/container/container.go +++ b/container/container.go @@ -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