mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
79e14027ee
Signed-off-by: Ramkumar Chinchani <rchincha@cisco.com> Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com> Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
121 lines
2.7 KiB
Go
121 lines
2.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"os/signal"
|
|
"syscall"
|
|
|
|
"github.com/fsnotify/fsnotify"
|
|
"github.com/rs/zerolog/log"
|
|
|
|
"zotregistry.io/zot/pkg/api"
|
|
"zotregistry.io/zot/pkg/api/config"
|
|
)
|
|
|
|
type HotReloader struct {
|
|
watcher *fsnotify.Watcher
|
|
filePath string
|
|
ctlr *api.Controller
|
|
}
|
|
|
|
func NewHotReloader(ctlr *api.Controller, filePath string) (*HotReloader, error) {
|
|
// creates a new file watcher
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hotReloader := &HotReloader{
|
|
watcher: watcher,
|
|
filePath: filePath,
|
|
ctlr: ctlr,
|
|
}
|
|
|
|
return hotReloader, nil
|
|
}
|
|
|
|
func signalHandler(ctlr *api.Controller, sigCh chan os.Signal, ctx context.Context, cancel context.CancelFunc) {
|
|
select {
|
|
// if signal then shutdown
|
|
case sig := <-sigCh:
|
|
defer cancel()
|
|
|
|
ctlr.Log.Info().Interface("signal", sig).Msg("received signal")
|
|
|
|
// gracefully shutdown http server
|
|
ctlr.Shutdown() //nolint: contextcheck
|
|
|
|
close(sigCh)
|
|
// if reload then return
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
}
|
|
|
|
func initShutDownRoutine(ctlr *api.Controller, ctx context.Context, cancel context.CancelFunc) {
|
|
sigCh := make(chan os.Signal, 1)
|
|
|
|
go signalHandler(ctlr, sigCh, ctx, cancel)
|
|
|
|
// block all async signals to this server
|
|
signal.Ignore()
|
|
|
|
// handle SIGINT and SIGHUP.
|
|
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP)
|
|
}
|
|
|
|
func (hr *HotReloader) Start() context.Context {
|
|
reloadCtx, cancelFunc := context.WithCancel(context.Background())
|
|
|
|
done := make(chan bool)
|
|
|
|
initShutDownRoutine(hr.ctlr, reloadCtx, cancelFunc)
|
|
|
|
// run watcher
|
|
go func() {
|
|
defer hr.watcher.Close()
|
|
|
|
go func() {
|
|
for {
|
|
select {
|
|
// watch for events
|
|
case event := <-hr.watcher.Events:
|
|
if event.Op == fsnotify.Write {
|
|
log.Info().Msg("config file changed, trying to reload config")
|
|
|
|
newConfig := config.New()
|
|
|
|
err := LoadConfiguration(newConfig, hr.filePath)
|
|
if err != nil {
|
|
log.Error().Err(err).Msg("failed to reload config, retry writing it.")
|
|
|
|
continue
|
|
}
|
|
// if valid config then reload
|
|
cancelFunc()
|
|
|
|
// create new context
|
|
reloadCtx, cancelFunc = context.WithCancel(context.Background())
|
|
|
|
// init shutdown routine
|
|
initShutDownRoutine(hr.ctlr, reloadCtx, cancelFunc)
|
|
|
|
hr.ctlr.LoadNewConfig(reloadCtx, newConfig)
|
|
}
|
|
// watch for errors
|
|
case err := <-hr.watcher.Errors:
|
|
log.Panic().Err(err).Str("config", hr.filePath).Msg("fsnotfy error while watching config")
|
|
}
|
|
}
|
|
}()
|
|
|
|
if err := hr.watcher.Add(hr.filePath); err != nil {
|
|
log.Panic().Err(err).Str("config", hr.filePath).Msg("failed to add config file to fsnotity watcher")
|
|
}
|
|
|
|
<-done
|
|
}()
|
|
|
|
return reloadCtx
|
|
}
|