forked from evergreen-ci/evergreen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
config.go
379 lines (330 loc) · 10.8 KB
/
config.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
package evergreen
import (
"flag"
"fmt"
"io/ioutil"
"os"
"github.com/pkg/errors"
"gopkg.in/yaml.v2"
)
var (
// Should be specified with -ldflags at build time
BuildRevision = ""
// Commandline Version String; used to control auto-updating.
// in the future this should probably be a date, but this is the legacy value
ClientVersion = "da802240058e2b8bc99546c5195b38273a7bd5b0"
)
const (
// DefaultConfFile is the default config file path for Evergreen.
DefaultConfFile = "/etc/mci_settings.yml"
)
// AuthUser configures a user for our Naive authentication setup.
type AuthUser struct {
Username string `yaml:"username"`
DisplayName string `yaml:"display_name"`
Password string `yaml:"password"`
Email string `yaml:"email"`
}
// NaiveAuthConfig contains a list of AuthUsers from the settings file.
type NaiveAuthConfig struct {
Users []*AuthUser
}
// CrowdConfig holds settings for interacting with Atlassian Crowd.
type CrowdConfig struct {
Username string
Password string
Urlroot string
}
// GithubAuthConfig holds settings for interacting with Github Authentication including the
// ClientID, ClientSecret and CallbackUri which are given when registering the application
// Furthermore,
type GithubAuthConfig struct {
ClientId string `yaml:"client_id"`
ClientSecret string `yaml:"client_secret"`
Users []string `yaml:"users"`
Organization string `yaml:"organization"`
}
// AuthConfig has a pointer to either a CrowConfig or a NaiveAuthConfig.
type AuthConfig struct {
Crowd *CrowdConfig `yaml:"crowd"`
Naive *NaiveAuthConfig `yaml:"naive"`
Github *GithubAuthConfig `yaml:"github"`
}
// RepoTrackerConfig holds settings for polling project repositories.
type RepoTrackerConfig struct {
NumNewRepoRevisionsToFetch int
MaxRepoRevisionsToSearch int
LogFile string
}
type ClientBinary struct {
Arch string `yaml:"arch" json:"arch"`
OS string `yaml:"os" json:"os"`
URL string `yaml:"url" json:"url"`
}
type ClientConfig struct {
ClientBinaries []ClientBinary `yaml:"client_binaries"`
LatestRevision string `yaml:"latest_revision"`
}
// APIConfig holds relevant encryption and log settings for the API server.
type APIConfig struct {
LogFile string
HttpListenAddr string
HttpsListenAddr string
HttpsKey string
HttpsCert string
}
// UIConfig holds relevant settings for the UI server.
type UIConfig struct {
Url string
HelpUrl string
HttpListenAddr string
// Secret to encrypt session storage
Secret string
LogFile string
// Default project to assume when none specified, e.g. when using
// the /waterfall route use this project, while /waterfall/other-project
// then use `other-project`
DefaultProject string
// Cache results of template compilation, so you don't have to re-read files
// on every request. Note that if this is true, changes to HTML templates
// won't take effect until server restart.
CacheTemplates bool
// SecureCookies sets the "secure" flag on user tokens. Evergreen
// does not yet natively support SSL UI connections, but this option
// is available, for example, for deployments behind HTTPS load balancers.
SecureCookies bool
}
// MonitorConfig holds logging settings for the monitor process.
type MonitorConfig struct {
LogFile string
}
// RunnerConfig holds logging and timing settings for the runner process.
type RunnerConfig struct {
LogFile string
IntervalSeconds int64
}
// HostInitConfig holds logging settings for the hostinit process.
type HostInitConfig struct {
LogFile string
SSHTimeoutSeconds int64
}
// NotifyConfig hold logging and email settings for the notify package.
type NotifyConfig struct {
LogFile string
SMTP *SMTPConfig `yaml:"smtp"`
}
// SMTPConfig holds SMTP email settings.
type SMTPConfig struct {
Server string `yaml:"server"`
Port int `yaml:"port"`
UseSSL bool `yaml:"use_ssl"`
Username string `yaml:"username"`
Password string `yaml:"password"`
From string `yaml:"from"`
AdminEmail []string `yaml:"admin_email"`
}
// SchedulerConfig holds relevant settings for the scheduler process.
type SchedulerConfig struct {
LogFile string
MergeToggle int
}
// TaskRunnerConfig holds logging settings for the scheduler process.
type TaskRunnerConfig struct {
LogFile string
}
// CloudProviders stores configuration settings for the supported cloud host providers.
type CloudProviders struct {
AWS AWSConfig `yaml:"aws"`
DigitalOcean DigitalOceanConfig `yaml:"digitalocean"`
}
// AWSConfig stores auth info for Amazon Web Services.
type AWSConfig struct {
Secret string `yaml:"aws_secret"`
Id string `yaml:"aws_id"`
}
// DigitalOceanConfig stores auth info for Digital Ocean.
type DigitalOceanConfig struct {
ClientId string `yaml:"client_id"`
Key string `yaml:"key"`
}
// JiraConfig stores auth info for interacting with Atlassian Jira.
type JiraConfig struct {
Host string
Username string
Password string
}
// PluginConfig holds plugin-specific settings, which are handled.
// manually by their respective plugins
type PluginConfig map[string]map[string]interface{}
type AlertsConfig struct {
LogFile string
SMTP *SMTPConfig `yaml:"smtp"`
}
type WriteConcern struct {
W int `yaml:"w"`
WMode string `yaml:"wmode"`
WTimeout int `yaml:"wtimeout"`
FSync bool `yaml:"fsync"`
J bool `yaml:"j"`
}
type DBSettings struct {
Url string `yaml:"url"`
SSL bool `yaml:"ssl"`
DB string `yaml:"db"`
WriteConcernSettings WriteConcern `yaml:"write_concern"`
}
// Settings contains all configuration settings for running Evergreen.
type Settings struct {
Database DBSettings `yaml:"database"`
WriteConcern WriteConcern `yaml:"write_concern"`
ConfigDir string `yaml:"configdir"`
ApiUrl string `yaml:"api_url"`
AgentExecutablesDir string `yaml:"agentexecutablesdir"`
ClientBinariesDir string `yaml:"client_binaries_dir"`
SuperUsers []string `yaml:"superusers"`
Jira JiraConfig `yaml:"jira"`
Providers CloudProviders `yaml:"providers"`
Keys map[string]string `yaml:"keys"`
Credentials map[string]string `yaml:"credentials"`
AuthConfig AuthConfig `yaml:"auth"`
RepoTracker RepoTrackerConfig `yaml:"repotracker"`
Monitor MonitorConfig `yaml:"monitor"`
Api APIConfig `yaml:"api"`
Alerts AlertsConfig `yaml:"alerts"`
Ui UIConfig `yaml:"ui"`
HostInit HostInitConfig `yaml:"hostinit"`
Notify NotifyConfig `yaml:"notify"`
Runner RunnerConfig `yaml:"runner"`
Scheduler SchedulerConfig `yaml:"scheduler"`
TaskRunner TaskRunnerConfig `yaml:"taskrunner"`
Expansions map[string]string `yaml:"expansions"`
Plugins PluginConfig `yaml:"plugins"`
IsProd bool `yaml:"isprod"`
}
// NewSettings builds an in-memory representation of the given settings file.
func NewSettings(filename string) (*Settings, error) {
configData, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
settings := &Settings{}
err = yaml.Unmarshal(configData, settings)
if err != nil {
return nil, err
}
return settings, nil
}
// Validate checks the settings and returns nil if the config is valid,
// or an error with a message explaining why otherwise.
func (settings *Settings) Validate(validators []ConfigValidator) error {
for _, validator := range validators {
err := validator(settings)
if err != nil {
return err
}
}
return nil
}
// GetSettingsOrExit loads the evergreen settings file,
// or exits with a non-0 code if any errors occur.
func GetSettingsOrExit() *Settings {
settings, err := GetSettings()
if err != nil {
// don't use the logger here, since it needs settings to initialize
fmt.Fprintf(os.Stderr, "Error reading config file: %v", err)
os.Exit(1)
}
return settings
}
// GetSettings returns Evergreen Settings or an error.
func GetSettings() (*Settings, error) {
var settingsPath = flag.String("conf", DefaultConfFile, "path to config file")
flag.Parse()
settings, err := NewSettings(*settingsPath)
if err != nil {
return nil, err
}
err = settings.Validate(ConfigValidationRules)
if err != nil {
return nil, err
}
return settings, nil
}
// ConfigValidator is a type of function that checks the settings
// struct for any errors or missing required fields.
type ConfigValidator func(settings *Settings) error
// ConfigValidationRules is the set of all ConfigValidator functions.
var ConfigValidationRules = []ConfigValidator{
func(settings *Settings) error {
if settings.Database.Url == "" || settings.Database.DB == "" {
return errors.New("DBUrl and DB must not be empty")
}
return nil
},
func(settings *Settings) error {
if settings.ApiUrl == "" {
return errors.New("API hostname must not be empty")
}
return nil
},
func(settings *Settings) error {
if settings.Ui.Secret == "" {
return errors.New("UI Secret must not be empty")
}
return nil
},
func(settings *Settings) error {
if settings.ConfigDir == "" {
return errors.New("Config directory must not be empty")
}
return nil
},
func(settings *Settings) error {
if settings.Ui.DefaultProject == "" {
return errors.New("You must specify a default project in UI")
}
return nil
},
func(settings *Settings) error {
if settings.Ui.Url == "" {
return errors.New("You must specify a default UI url")
}
return nil
},
func(settings *Settings) error {
notifyConfig := settings.Notify.SMTP
if notifyConfig == nil {
return nil
}
if notifyConfig.Server == "" || notifyConfig.Port == 0 {
return errors.New("You must specify a SMTP server and port")
}
if len(notifyConfig.AdminEmail) == 0 {
return errors.New("You must specify at least one admin_email")
}
if notifyConfig.From == "" {
return errors.New("You must specify a from address")
}
return nil
},
func(settings *Settings) error {
if settings.AuthConfig.Crowd == nil && settings.AuthConfig.Naive == nil && settings.AuthConfig.Github == nil {
return errors.New("You must specify one form of authentication")
}
if settings.AuthConfig.Naive != nil {
used := map[string]bool{}
for _, x := range settings.AuthConfig.Naive.Users {
if used[x.Username] {
return errors.New("Duplicate user in list")
}
used[x.Username] = true
}
}
if settings.AuthConfig.Github != nil {
if settings.AuthConfig.Github.Users == nil && settings.AuthConfig.Github.Organization == "" {
return errors.New("Must specify either a set of users or an organization for Github Authentication")
}
}
return nil
},
}