-
-
Notifications
You must be signed in to change notification settings - Fork 179
/
config.go
304 lines (229 loc) · 8.07 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
package serv
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/dosco/graphjin/core"
"github.com/dosco/graphjin/serv/internal/auth"
"github.com/spf13/viper"
)
type Core = core.Config
type Auth = auth.Auth
type JWTConfig = auth.JWTConfig
// Config struct holds the GraphJin service config values
type Config struct {
// Core holds config values for the GraphJin compiler
Core `mapstructure:",squash"`
// Serv holds config values for the GraphJin Service
Serv `mapstructure:",squash"`
closeFn func()
hostPort string
vi *viper.Viper
}
// Serv struct contains config values used by the GraphJin service
type Serv struct {
// AppName is the name of your application used in log and debug messages
AppName string `mapstructure:"app_name"`
// Production when set to true runs the service with production level
// security and other defaults. For example allow lists are enforced.
Production bool
// ConfigPath is the default path to find all configuration
// files and scripts under
ConfigPath string `mapstructure:"config_path"`
// LogLevel can be debug, error, warn, info
LogLevel string `mapstructure:"log_level"`
// LogFormat can be json or simple
LogFormat string `mapstructure:"log_format"`
// HostPost to run the service on. Example localhost:8080
HostPort string `mapstructure:"host_port"`
// Host to run the service on
Host string
// Port to run the service on
Port string
// HTTPGZip enables HTTP compresssion
HTTPGZip bool `mapstructure:"http_compress"`
// Enable the web UI. Disabled in production
WebUI bool `mapstructure:"web_ui"`
// EnableTracing enables OpenTrace request tracing
EnableTracing bool `mapstructure:"enable_tracing"`
// WatchAndReload enables reloading the service on config changes
WatchAndReload bool `mapstructure:"reload_on_config_change"`
// AuthFailBlock when enabled blocks requests with a 401 on auth failure
AuthFailBlock bool `mapstructure:"auth_fail_block"`
// SeedFile is the path to the database seeding script
SeedFile string `mapstructure:"seed_file"`
// MigrationsPath is the path to the database migration files
MigrationsPath string `mapstructure:"migrations_path"`
// AllowedOrigins sets the HTTP CORS Access-Control-Allow-Origin header
AllowedOrigins []string `mapstructure:"cors_allowed_origins"`
// AllowedHeaders sets the HTTP CORS Access-Control-Allow-Headers header
AllowedHeaders []string `mapstructure:"cors_allowed_headers"`
// DebugCORS enables debug logs for cors
DebugCORS bool `mapstructure:"cors_debug"`
// APIPath change the suffix of the api path. Defaults to /v1/graphql
APIPath string `mapstructure:"api_path"`
// CacheControl sets the HTTP Cache-Control header
CacheControl string `mapstructure:"cache_control"`
// Telemetry struct contains OpenCensus metrics and tracing related config
Telemetry Telemetry
// Auth set the default auth used by the service
Auth Auth
// Auths sets multiple auths to be used by actions
Auths []Auth
// DB struct contains db config
DB Database `mapstructure:"database"`
Actions []Action
// RateLimiter sets the API rate limits
RateLimiter RateLimiter `mapstructure:"rate_limiter"`
}
// Database config
type Database struct {
Type string
Host string
Port uint16
DBName string
User string
Password string
Schema string
PoolSize int32 `mapstructure:"pool_size"`
MaxRetries int `mapstructure:"max_retries"`
PingTimeout time.Duration `mapstructure:"ping_timeout"`
EnableTLS bool `mapstructure:"enable_tls"`
ServerName string `mapstructure:"server_name"`
ServerCert string `mapstructure:"server_cert"`
ClientCert string `mapstructure:"client_cert"`
ClientKey string `mapstructure:"client_key"`
}
// RateLimiter sets the API rate limits
type RateLimiter struct {
Rate float64
Bucket int
IPHeader string `mapstructure:"ip_header"`
}
// Telemetry struct contains OpenCensus metrics and tracing related config
type Telemetry struct {
// Debug enables debug logging for metrics and tracing data.
Debug bool
// Interval to send out metrics and tracing data
Interval *time.Duration
Metrics struct {
// Exporter is the name of the metrics exporter to use. Example: prometheus
Exporter string
// Endpoint to send the data to.
Endpoint string
// Namespace is set based on your exporter configration
Namespace string
// Key is set based on your exporter configuration
Key string
}
Tracing struct {
// Exporter is the name of the tracing exporter to use. Example: zipkin
Exporter string
// Endpoint to send the data to. Example: http://zipkin:9411/api/v2/spans
Endpoint string
// Sample sets how many requests to sample for tracing: Example: 0.6
Sample string
// IncludeQuery when set the GraphQL query is included in the tracing data
IncludeQuery bool `mapstructure:"include_query"`
// IncludeParams when set variables used with the query are included in the
// tracing data
IncludeParams bool `mapstructure:"include_params"`
// ExcludeHealthCheck when set health check tracing is excluded from the
// tracing data
ExcludeHealthCheck bool `mapstructure:"exclude_health_check"`
}
}
// Action struct contains config values for a GraphJin service action
type Action struct {
Name string
SQL string
AuthName string `mapstructure:"auth_name"`
}
// ReadInConfig function reads in the config file for the environment specified in the GO_ENV
// environment variable. This is the best way to create a new GraphJin config.
func ReadInConfig(configFile string) (*Config, error) {
// migrate old sg var prefixes to new gj prefixes
for _, e := range os.Environ() {
if !strings.HasPrefix(e, "SG_") {
continue
}
v := strings.SplitN(e, "=", 2)
os.Setenv(("GJ_" + v[0][3:]), v[1])
}
cpath := path.Dir(configFile)
cfile := path.Base(configFile)
vi := newViper(cpath, cfile)
if err := vi.ReadInConfig(); err != nil {
return nil, err
}
inherits := vi.GetString("inherits")
if inherits != "" {
vi = newViper(cpath, inherits)
if err := vi.ReadInConfig(); err != nil {
return nil, err
}
if vi.IsSet("inherits") {
return nil, fmt.Errorf("inherited config (%s) cannot itself inherit (%s)",
inherits,
vi.GetString("inherits"))
}
vi.SetConfigName(cfile)
if err := vi.MergeInConfig(); err != nil {
return nil, err
}
}
c := &Config{vi: vi}
c.Serv.ConfigPath = cpath
c.Core.ConfigPath = cpath
if err := vi.Unmarshal(&c); err != nil {
return nil, fmt.Errorf("failed to decode config, %v", err)
}
return c, nil
}
func newViper(configPath, configFile string) *viper.Viper {
vi := viper.New()
vi.SetEnvPrefix("GJ")
vi.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
vi.AutomaticEnv()
vi.AddConfigPath(configPath)
vi.SetConfigName(configFile)
vi.AddConfigPath("./config")
vi.SetDefault("host_port", "0.0.0.0:8080")
vi.SetDefault("web_ui", false)
vi.SetDefault("enable_tracing", false)
vi.SetDefault("auth_fail_block", false)
vi.SetDefault("seed_file", "seed.js")
vi.SetDefault("log_level", "info")
vi.SetDefault("log_format", "json")
vi.SetDefault("default_block", true)
vi.SetDefault("database.type", "postgres")
vi.SetDefault("database.host", "localhost")
vi.SetDefault("database.port", 5432)
vi.SetDefault("database.user", "postgres")
vi.SetDefault("database.password", "")
vi.SetDefault("database.schema", "public")
vi.SetDefault("env", "development")
vi.BindEnv("env", "GO_ENV") //nolint: errcheck
vi.BindEnv("host", "HOST") //nolint: errcheck
vi.BindEnv("port", "PORT") //nolint: errcheck
vi.SetDefault("auth.rails.max_idle", 80)
vi.SetDefault("auth.rails.max_active", 12000)
vi.SetDefault("auth.creds_in_header", false)
vi.SetDefault("auth.subs_creds_in_vars", false)
return vi
}
func (c *Config) telemetryEnabled() bool {
return c.Telemetry.Debug || c.Telemetry.Metrics.Exporter != "" || c.Telemetry.Tracing.Exporter != ""
}
func (c *Config) RelPath(p string) string {
if filepath.IsAbs(p) {
return p
}
return path.Join(c.Serv.ConfigPath, p)
}
func (c *Config) rateLimiterEnable() bool {
return c.RateLimiter.Rate > 0 && c.RateLimiter.Bucket > 0
}