cloudflare/cloudflared

Public

mirrored from https://github.com/cloudflare/cloudflaredAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
2021.10.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

config/manager.go

112lines · modecode

1package config
2
3import (
4 "io"
5 "os"
6
7 "github.com/pkg/errors"
8 "github.com/rs/zerolog"
9 yaml "gopkg.in/yaml.v2"
10
11 "github.com/cloudflare/cloudflared/watcher"
12)
13
14// Notifier sends out config updates
15type Notifier interface {
16 ConfigDidUpdate(Root)
17}
18
19// Manager is the base functions of the config manager
20type Manager interface {
21 Start(Notifier) error
22 Shutdown()
23}
24
25// FileManager watches the yaml config for changes
26// sends updates to the service to reconfigure to match the updated config
27type FileManager struct {
28 watcher watcher.Notifier
29 notifier Notifier
30 configPath string
31 log *zerolog.Logger
32 ReadConfig func(string, *zerolog.Logger) (Root, error)
33}
34
35// NewFileManager creates a config manager
36func NewFileManager(watcher watcher.Notifier, configPath string, log *zerolog.Logger) (*FileManager, error) {
37 m := &FileManager{
38 watcher: watcher,
39 configPath: configPath,
40 log: log,
41 ReadConfig: readConfigFromPath,
42 }
43 err := watcher.Add(configPath)
44 return m, err
45}
46
47// Start starts the runloop to watch for config changes
48func (m *FileManager) Start(notifier Notifier) error {
49 m.notifier = notifier
50
51 // update the notifier with a fresh config on start
52 config, err := m.GetConfig()
53 if err != nil {
54 return err
55 }
56 notifier.ConfigDidUpdate(config)
57
58 m.watcher.Start(m)
59 return nil
60}
61
62// GetConfig reads the yaml file from the disk
63func (m *FileManager) GetConfig() (Root, error) {
64 return m.ReadConfig(m.configPath, m.log)
65}
66
67// Shutdown stops the watcher
68func (m *FileManager) Shutdown() {
69 m.watcher.Shutdown()
70}
71
72func readConfigFromPath(configPath string, log *zerolog.Logger) (Root, error) {
73 if configPath == "" {
74 return Root{}, errors.New("unable to find config file")
75 }
76
77 file, err := os.Open(configPath)
78 if err != nil {
79 return Root{}, err
80 }
81 defer file.Close()
82
83 var config Root
84 if err := yaml.NewDecoder(file).Decode(&config); err != nil {
85 if err == io.EOF {
86 log.Error().Msgf("Configuration file %s was empty", configPath)
87 return Root{}, nil
88 }
89 return Root{}, errors.Wrap(err, "error parsing YAML in config file at "+configPath)
90 }
91
92 return config, nil
93}
94
95// File change notifications from the watcher
96
97// WatcherItemDidChange triggers when the yaml config is updated
98// sends the updated config to the service to reload its state
99func (m *FileManager) WatcherItemDidChange(filepath string) {
100 config, err := m.GetConfig()
101 if err != nil {
102 m.log.Err(err).Msg("Failed to read new config")
103 return
104 }
105 m.log.Info().Msg("Config file has been updated")
106 m.notifier.ConfigDidUpdate(config)
107}
108
109// WatcherDidError notifies of errors with the file watcher
110func (m *FileManager) WatcherDidError(err error) {
111 m.log.Err(err).Msg("Config watcher encountered an error")
112}
113