-
Notifications
You must be signed in to change notification settings - Fork 98
/
updater.go
127 lines (111 loc) · 3.75 KB
/
updater.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"context"
"fmt"
"net/http"
"os"
"time"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/kolide/kit/actor"
"github.com/kolide/launcher/pkg/autoupdate"
"github.com/kolide/updater/tuf"
)
// updaterConfig is a struct of update related options. It's used to
// simplify the call to `createUpdater` from launcher's main blocks.
type updaterConfig struct {
Logger log.Logger
RootDirectory string // launcher's root dir. use for holding tuf staging and updates
AutoupdateInterval time.Duration
UpdateChannel autoupdate.UpdateChannel
InitialDelay time.Duration // start delay, to avoid whomping critical early data
NotaryURL string
MirrorURL string
NotaryPrefix string
HTTPClient *http.Client
SigChannel chan os.Signal
}
// createUpdater returns an Actor suitable for an oklog/run group. It
// is a light wrapper around autoupdate.NewUpdater to simplify having
// multiple ones in launcher.
func createUpdater(
ctx context.Context,
binaryPath string,
finalizer autoupdate.UpdateFinalizer,
config *updaterConfig,
) (*actor.Actor, error) {
// create the updater
updater, err := autoupdate.NewUpdater(
binaryPath,
config.RootDirectory,
autoupdate.WithLogger(config.Logger),
autoupdate.WithHTTPClient(config.HTTPClient),
autoupdate.WithNotaryURL(config.NotaryURL),
autoupdate.WithMirrorURL(config.MirrorURL),
autoupdate.WithNotaryPrefix(config.NotaryPrefix),
autoupdate.WithFinalizer(finalizer),
autoupdate.WithUpdateChannel(config.UpdateChannel),
autoupdate.WithSigChannel(config.SigChannel),
)
if err != nil {
return nil, err
}
// create a variable to hold the stop function that the updater returns,
// so that we can pass it into the interrupt function
var stop func()
stopChan := make(chan bool)
return &actor.Actor{
Execute: func() error {
// When launcher first starts, we'd like the
// server to start receiving data
// immediately. But, if updater is trying to
// run, this creates an awkward pause for restart.
// So, delay starting updates by an hour or two.
if config.InitialDelay != 0 {
time.Sleep(config.InitialDelay)
}
// Failing to start the updater is not a fatal launcher
// error. If there's a problem, sleep and try
// again. Implementing this is a bit gnarly. In the event of a
// success, we get a nil error, and a stop function. But I don't
// see a simple way to ensure the updater is still running in
// the background.
for {
level.Info(config.Logger).Log("msg", "updater started")
// run the updater and set the stop function so that the interrupt has access to it
stop, err = updater.Run(tuf.WithFrequency(config.AutoupdateInterval), tuf.WithLogger(config.Logger))
if err == nil {
break
}
// err != nil, log it and loop again
level.Error(config.Logger).Log("msg", "Error running updater. Will retry", "err", err)
select {
case <-stopChan:
level.Debug(config.Logger).Log("msg", "stop requested. Breaking loop")
return nil
case <-time.After(30 * time.Minute):
break
}
}
// Don't exit unless there's a done signal TODO: remove when
// underlying libs are refactored, everything exits right now,
// so block this actor on the context finishing
level.Debug(config.Logger).Log("msg", "waiting")
<-ctx.Done()
return nil
},
Interrupt: func(err error) {
level.Info(config.Logger).Log("msg", "updater interrupted", "err", err)
level.Debug(config.Logger).Log("msg", "updater interrupted", "err", err, "stack", fmt.Sprintf("%+v", err))
// non-blocking channel send
select {
case stopChan <- true:
default:
level.Debug(config.Logger).Log("msg", "failed to send stop signal")
}
if stop != nil {
stop()
}
},
}, nil
}