mirror of
https://github.com/containrrr/watchtower.git
synced 2025-09-21 21:30:48 +02:00
Adding new runtime param delay-days that is used to control whether container is updated to new image immediately or wait until the indicated days have passed
This commit is contained in:
parent
0a14f3aa9c
commit
a8279b47fe
5 changed files with 59 additions and 4 deletions
|
@ -39,6 +39,7 @@ var (
|
|||
disableContainers []string
|
||||
notifier t.Notifier
|
||||
timeout time.Duration
|
||||
delayDays int
|
||||
lifecycleHooks bool
|
||||
rollingRestart bool
|
||||
scope string
|
||||
|
@ -96,6 +97,7 @@ func PreRun(cmd *cobra.Command, _ []string) {
|
|||
|
||||
enableLabel, _ = f.GetBool("label-enable")
|
||||
disableContainers, _ = f.GetStringSlice("disable-containers")
|
||||
delayDays, _ = f.GetInt("delay-days")
|
||||
lifecycleHooks, _ = f.GetBool("enable-lifecycle-hooks")
|
||||
rollingRestart, _ = f.GetBool("rolling-restart")
|
||||
scope, _ = f.GetString("scope")
|
||||
|
@ -364,6 +366,7 @@ func runUpdatesWithNotifications(filter t.Filter) *metrics.Metric {
|
|||
NoRestart: noRestart,
|
||||
Timeout: timeout,
|
||||
MonitorOnly: monitorOnly,
|
||||
DelayDays: delayDays,
|
||||
LifecycleHooks: lifecycleHooks,
|
||||
RollingRestart: rollingRestart,
|
||||
LabelPrecedence: labelPrecedence,
|
||||
|
|
|
@ -381,6 +381,16 @@ Environment Variable: WATCHTOWER_HTTP_API_METRICS
|
|||
Default: false
|
||||
```
|
||||
|
||||
## Delayed Update
|
||||
Only update container to latest version of image if some number of days have passed since it has been published. This option may be useful for those who wish to avoid updating prior to the new version having some time in the field prior to updating in case there are critical defects found and released in a subsequent version.
|
||||
|
||||
```text
|
||||
Argument: --delay-days
|
||||
Environment Variable: WATCHTOWER_DELAY_DAYS
|
||||
Type: Integer
|
||||
Default: false
|
||||
```
|
||||
|
||||
## Scheduling
|
||||
[Cron expression](https://pkg.go.dev/github.com/robfig/cron@v1.2.0?tab=doc#hdr-CRON_Expression_Format) in 6 fields (rather than the traditional 5) which defines when and how often to check for new images. Either `--interval` or the schedule expression
|
||||
can be defined, but not both. An example: `--schedule "0 0 4 * * *"`
|
||||
|
|
|
@ -147,6 +147,12 @@ func RegisterSystemFlags(rootCmd *cobra.Command) {
|
|||
envBool("WATCHTOWER_LIFECYCLE_HOOKS"),
|
||||
"Enable the execution of commands triggered by pre- and post-update lifecycle hooks")
|
||||
|
||||
flags.IntP(
|
||||
"delay-days",
|
||||
"0",
|
||||
envInt("WATCHTOWER_DELAY_DAYS"),
|
||||
"Number of days to wait for new image version to be in place prior to installing it")
|
||||
|
||||
flags.BoolP(
|
||||
"rolling-restart",
|
||||
"",
|
||||
|
|
|
@ -325,10 +325,25 @@ func (client dockerClient) IsContainerStale(container t.Container, params t.Upda
|
|||
return false, container.SafeImageID(), err
|
||||
}
|
||||
|
||||
return client.HasNewImage(ctx, container)
|
||||
return client.HasNewImage(ctx, container, params)
|
||||
}
|
||||
|
||||
func (client dockerClient) HasNewImage(ctx context.Context, container t.Container) (hasNew bool, latestImage t.ImageID, err error) {
|
||||
// Date strings sometimes vary in how many digits after the decimal point are present. This function
|
||||
// standardizes them by removing the milliseconds.
|
||||
func truncateMilliseconds(dateString string) string {
|
||||
// Find the position of the dot (.) in the date string
|
||||
dotIndex := strings.Index(dateString, ".")
|
||||
|
||||
// If the dot is found, truncate the string before the dot
|
||||
if dotIndex != -1 {
|
||||
return dateString[:dotIndex] + "Z"
|
||||
}
|
||||
|
||||
// If the dot is not found, return the original string
|
||||
return dateString
|
||||
}
|
||||
|
||||
func (client dockerClient) HasNewImage(ctx context.Context, container t.Container, params t.UpdateParams) (hasNew bool, latestImage t.ImageID, err error) {
|
||||
currentImageID := t.ImageID(container.ContainerInfo().ContainerJSONBase.Image)
|
||||
imageName := container.ImageName()
|
||||
|
||||
|
@ -339,10 +354,30 @@ func (client dockerClient) HasNewImage(ctx context.Context, container t.Containe
|
|||
|
||||
newImageID := t.ImageID(newImageInfo.ID)
|
||||
if newImageID == currentImageID {
|
||||
log.Debugf("No new images found for %s", container.Name())
|
||||
log.Debugf("No new images found for %s [ imageID %s ]", container.Name(), newImageID.ShortID())
|
||||
return false, currentImageID, nil
|
||||
}
|
||||
|
||||
// Disabled by default
|
||||
if params.DelayDays > 0 {
|
||||
// Define the layout string for the date format without milliseconds
|
||||
layout := "2006-01-02T15:04:05Z"
|
||||
newImageDate, error := time.Parse(layout, truncateMilliseconds(newImageInfo.Created))
|
||||
|
||||
if error != nil {
|
||||
log.Errorf("Error parsing Created date (%s) for container %s latest label. Error: %s", newImageInfo.Created, container.Name(), error)
|
||||
return false, currentImageID, nil
|
||||
} else {
|
||||
requiredDays := params.DelayDays
|
||||
diffDays := int(time.Since(newImageDate).Hours() / 24)
|
||||
|
||||
if diffDays < requiredDays {
|
||||
log.Infof("New image found for %s that is %d days since publication but update delayed until %d days", container.Name(), diffDays, requiredDays)
|
||||
return false, currentImageID, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Found new %s image (%s)", imageName, newImageID.ShortID())
|
||||
return true, newImageID, nil
|
||||
}
|
||||
|
|
|
@ -11,7 +11,8 @@ type UpdateParams struct {
|
|||
NoRestart bool
|
||||
Timeout time.Duration
|
||||
MonitorOnly bool
|
||||
NoPull bool
|
||||
NoPull bool
|
||||
DelayDays int
|
||||
LifecycleHooks bool
|
||||
RollingRestart bool
|
||||
LabelPrecedence bool
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue