Possibility to define a cron expression which specifies when to check for updated images. This allows to have a schedule in which updates should be made and therefore one could define a maintenance window.

This commit is contained in:
Fabrizio Steiner 2016-12-30 00:23:02 +01:00
parent 5902e9e0be
commit 525dfea3f2
2 changed files with 58 additions and 24 deletions

81
main.go
View file

@ -4,20 +4,21 @@ import (
"fmt"
"os"
"os/signal"
"sync"
"syscall"
"time"
"strconv"
log "github.com/Sirupsen/logrus"
"github.com/robfig/cron"
"github.com/urfave/cli"
"github.com/v2tec/watchtower/actions"
"github.com/v2tec/watchtower/container"
)
var (
wg sync.WaitGroup
client container.Client
pollInterval time.Duration
scheduleSpec string
cleanup bool
noRestart bool
)
@ -45,6 +46,11 @@ func main() {
Value: 300,
EnvVar: "WATCHTOWER_POLL_INTERVAL",
},
cli.StringFlag{
Name: "schedule, s",
Usage: "the cron expression which defines when to update",
EnvVar: "WATCHTOWER_SCHEDULE",
},
cli.BoolFlag{
Name: "no-pull",
Usage: "do not pull new images",
@ -86,7 +92,17 @@ func before(c *cli.Context) error {
log.SetLevel(log.DebugLevel)
}
pollInterval = time.Duration(c.Int("interval")) * time.Second
pollingSet := c.IsSet("interval")
cronSet := c.IsSet("schedule")
if pollingSet && cronSet {
log.Fatal("Only schedule or interval can be defined, not both.")
} else if cronSet {
scheduleSpec = c.String("schedule")
} else {
scheduleSpec = "@every " + strconv.Itoa(c.Int("interval")) + "s"
}
cleanup = c.GlobalBool("cleanup")
noRestart = c.GlobalBool("no-restart")
@ -97,40 +113,57 @@ func before(c *cli.Context) error {
}
client = container.NewClient(!c.GlobalBool("no-pull"))
handleSignals()
return nil
}
func start(c *cli.Context) {
func start(c *cli.Context) error {
names := c.Args()
if err := actions.CheckPrereqs(client, cleanup); err != nil {
log.Fatal(err)
}
for {
wg.Add(1)
if err := actions.Update(client, names, cleanup, noRestart); err != nil {
fmt.Println(err)
}
wg.Done()
tryLockSem := make(chan bool, 1)
tryLockSem <- true
time.Sleep(pollInterval)
cron := cron.New()
err := cron.AddFunc(
scheduleSpec,
func() {
select {
case v := <-tryLockSem:
defer func() { tryLockSem <- v }()
if err := actions.Update(client, names, cleanup, noRestart); err != nil {
fmt.Println(err)
}
default:
log.Debug("Skipped another update already running.")
}
nextRuns := cron.Entries()
if len(nextRuns) > 0 {
log.Debug("Scheduled next run: " + nextRuns[0].Next.String())
}
})
if err != nil {
return err
}
}
func handleSignals() {
log.Info("First run: " + cron.Entries()[0].Schedule.Next(time.Now()).String())
cron.Start()
// Graceful shut-down on SIGINT/SIGTERM
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, syscall.SIGTERM)
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
signal.Notify(interrupt, syscall.SIGTERM)
go func() {
<-c
wg.Wait()
os.Exit(1)
}()
<-interrupt
cron.Stop()
log.Info("Waiting for running update to be finished...")
<-tryLockSem
os.Exit(1)
return nil
}
func setEnvOptStr(env string, opt string) error {