-
Notifications
You must be signed in to change notification settings - Fork 524
/
config.go
437 lines (381 loc) · 14.3 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
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package apmservertest
import (
"encoding/json"
"fmt"
"net"
"net/http"
"net/url"
"os"
"sort"
"time"
)
const (
defaultElasticsearchHost = "localhost"
defaultElasticsearchPort = "9200"
defaultElasticsearchUser = "apm_server_user"
defaultElasticsearchPass = "changeme"
defaultKibanaHost = "localhost"
defaultKibanaPort = "5601"
defaultKibanaUser = "apm_user_ro"
defaultKibanaPass = "changeme"
defaultKibanaBasePath = ""
)
// Config holds APM Server configuration.
type Config struct {
Kibana *KibanaConfig `json:"apm-server.kibana,omitempty"`
Sampling *SamplingConfig `json:"apm-server.sampling,omitempty"`
RUM *RUMConfig `json:"apm-server.rum,omitempty"`
DefaultServiceEnvironment string `json:"apm-server.default_service_environment,omitempty"`
AgentConfig *AgentConfig `json:"apm-server.agent.config,omitempty"`
TLS *TLSConfig `json:"apm-server.ssl,omitempty"`
// AgentAuth holds configuration for APM agent authorization.
AgentAuth AgentAuthConfig `json:"apm-server.auth"`
// ResponseHeaders holds headers to add to all APM Server HTTP responses.
ResponseHeaders http.Header `json:"apm-server.response_headers,omitempty"`
// Instrumentation holds configuration for libbeat and apm-server instrumentation.
Instrumentation *InstrumentationConfig `json:"instrumentation,omitempty"`
// Logging holds configuration for libbeat logging.
//
// We always enable JSON output, and log to stderr.
Logging *LoggingConfig `json:"logging,omitempty"`
// Monitoring holds configuration for stack monitoring.
Monitoring *MonitoringConfig `json:"monitoring,omitempty"`
// Output holds configuration for the libbeat output.
Output OutputConfig `json:"output"`
// AggregationConfig holds configuration related to aggregation.
Aggregation *AggregationConfig `json:"apm-server.aggregation,omitempty"`
}
// Args formats cfg as a list of arguments to pass to apm-server,
// in the form ["-E", "k=v", "-E", "k=v", ...]
func (cfg Config) Args() ([]string, error) {
return configArgs(cfg, nil)
}
// TLSConfig holds configuration to TLS encryption of agent/server communication.
type TLSConfig struct {
// ClientAuthentication controls whether TLS client authentication is
// enabled, and optional or required. If this is non-empty, then
// `apm-server.ssl.certificate_authorities` will be set to the server's
// self-signed certificate path.
ClientAuthentication string `json:"client_authentication,omitempty"`
CipherSuites []string `json:"cipher_suites,omitempty"`
SupportedProtocols []string `json:"supported_protocols,omitempty"`
}
// AgentConfig holds configuration related to the Kibana-based or
// Elasticsearch-based implementation of agent configuration.
type AgentConfig struct {
CacheExpiration time.Duration
ElasticsearchUsername string
ElasticsearchPassword string
ElasticsearchAPIKey string
}
func (c *AgentConfig) MarshalJSON() ([]byte, error) {
// time.Duration is encoded as int64.
// Convert time.Durations to durations, to encode as duration strings.
type config struct {
CacheExpiration string `json:"cache.expiration,omitempty"`
ElasticsearchUsername string `json:"elasticsearch.username,omitempty"`
ElasticsearchPassword string `json:"elasticsearch.password,omitempty"`
ElasticsearchAPIKey string `json:"elasticsearch.api_key,omitempty"`
}
return json.Marshal(config{
CacheExpiration: durationString(c.CacheExpiration),
ElasticsearchUsername: c.ElasticsearchUsername,
ElasticsearchPassword: c.ElasticsearchPassword,
ElasticsearchAPIKey: c.ElasticsearchAPIKey,
})
}
// LoggingConfig holds APM Server logging configuration.
type LoggingConfig struct {
Files FileLoggingConfig `json:"files"`
}
// FileLoggingConfig holds APM Server file logging configuration.
type FileLoggingConfig struct {
Path string `json:"path,omitempty"`
}
// KibanaConfig holds APM Server Kibana connection configuration.
type KibanaConfig struct {
Enabled bool `json:"enabled"`
Host string `json:"host,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
// SamplingConfig holds APM Server trace sampling configuration.
type SamplingConfig struct {
Tail *TailSamplingConfig `json:"tail,omitempty"`
}
// TailSamplingConfig holds APM Server tail-based sampling configuration.
type TailSamplingConfig struct {
Enabled bool
Interval time.Duration
Policies []TailSamplingPolicy
}
func (t *TailSamplingConfig) MarshalJSON() ([]byte, error) {
// time.Duration is encoded as int64.
// Convert time.Durations to durations, to encode as duration strings.
type config struct {
Enabled bool `json:"enabled"`
Interval string `json:"interval"`
Policies []TailSamplingPolicy `json:"policies,omitempty"`
}
return json.Marshal(config{
Enabled: t.Enabled,
Interval: durationString(t.Interval),
Policies: t.Policies,
})
}
// TailSamplingPolicy holds an APM Server tail-based sampling policy.
type TailSamplingPolicy struct {
ServiceName string `json:"service.name,omitempty"`
ServiceEnvironment string `json:"service.environment,omitempty"`
TraceName string `json:"trace.name,omitempty"`
TraceOutcome string `json:"trace.outcome,omitempty"`
SampleRate float64 `json:"sample_rate"`
}
// RUMConfig holds APM Server RUM configuration.
type RUMConfig struct {
Enabled bool `json:"enabled"`
// AllowOrigins holds a list of allowed origins for RUM.
AllowOrigins []string `json:"allow_origins,omitempty"`
// AllowHeaders holds a list of Access-Control-Allow-Headers for RUM.
AllowHeaders []string `json:"allow_headers,omitempty"`
// AllowServiceNames holds a list of exclusively allowed service names for
// RUM events.
AllowServiceNames []string `json:"allow_service_names,omitempty"`
// ResponseHeaders holds headers to add to all APM Server RUM HTTP responses.
ResponseHeaders http.Header `json:"response_headers,omitempty"`
Sourcemap *RUMSourcemapConfig `json:"source_mapping,omitempty"`
}
// RUMSourcemapConfig holds APM Server RUM sourcemap configuration.
type RUMSourcemapConfig struct {
Enabled bool `json:"enabled"`
ESConfig *ElasticsearchOutputConfig `json:"elasticsearch"`
}
// APIKeyConfig holds agent auth configuration.
type AgentAuthConfig struct {
SecretToken string `json:"secret_token,omitempty"`
APIKey *APIKeyAuthConfig `json:"api_key,omitempty"`
Anonymous *AnonymousAuthConfig `json:"anonymous,omitempty"`
}
// APIKeyAuthConfig holds API Key agent auth configuration.
type APIKeyAuthConfig struct {
Enabled bool `json:"enabled"`
}
// AnonymousAuthConfig holds anonymous agent auth configuration.
type AnonymousAuthConfig struct {
Enabled bool `json:"enabled"`
AllowAgent []string `json:"allow_agent,omitempty"`
AllowService []string `json:"allow_service,omitempty"`
RateLimit *RateLimitConfig `json:"rate_limit,omitempty"`
}
// RateLimitConfig holds event rate limit configuration.
type RateLimitConfig struct {
IPLimit int `json:"ip_limit,omitempty"`
EventLimit int `json:"event_limit,omitempty"`
}
// InstrumentationConfig holds APM Server instrumentation configuration.
type InstrumentationConfig struct {
Enabled bool `json:"enabled"`
Hosts []string `json:"hosts,omitempty"`
APIKey string `json:"api_key,omitempty"`
SecretToken string `json:"secret_token,omitempty"`
}
// OutputConfig holds APM Server libbeat output configuration.
type OutputConfig struct {
Console *ConsoleOutputConfig `json:"console,omitempty"`
Elasticsearch *ElasticsearchOutputConfig `json:"elasticsearch,omitempty"`
Logstash *LogstashOutputConfig `json:"logstash,omitempty"`
}
// ConsoleOutputConfig holds APM Server libbeat console output configuration.
type ConsoleOutputConfig struct {
Enabled bool `json:"enabled"`
}
// LogstashOutputConfig holds APM Server libbeat logstash output configuration.
type LogstashOutputConfig struct {
Enabled bool `json:"enabled"`
Hosts []string `json:"hosts,omitempty"`
BulkMaxSize int `json:"bulk_max_size,omitempty"`
}
// ElasticsearchOutputConfig holds APM Server libbeat Elasticsearch output configuration.
type ElasticsearchOutputConfig struct {
Enabled bool `json:"enabled"`
Hosts []string `json:"hosts,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
APIKey string `json:"api_key,omitempty"`
FlushBytes string `json:"flush_bytes,omitempty"`
FlushInterval time.Duration `json:"flush_interval,omitempty"`
}
func (c *ElasticsearchOutputConfig) MarshalJSON() ([]byte, error) {
return json.Marshal(struct {
Enabled bool `json:"enabled"`
Hosts []string `json:"hosts,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
APIKey string `json:"api_key,omitempty"`
FlushBytes string `json:"flush_bytes,omitempty"`
FlushInterval string `json:"flush_interval,omitempty"`
}{
Enabled: c.Enabled,
Hosts: c.Hosts,
Username: c.Username,
Password: c.Password,
APIKey: c.APIKey,
FlushBytes: c.FlushBytes,
FlushInterval: durationString(c.FlushInterval),
})
}
// MonitoringConfig holds APM Server stack monitoring configuration.
type MonitoringConfig struct {
Enabled bool
Elasticsearch *ElasticsearchOutputConfig
MetricsPeriod time.Duration
StatePeriod time.Duration
}
func (m *MonitoringConfig) MarshalJSON() ([]byte, error) {
// time.Duration is encoded as int64.
// Convert time.Durations to durations, to encode as duration strings.
type config struct {
Enabled bool `json:"enabled"`
Elasticsearch *ElasticsearchOutputConfig `json:"elasticsearch,omitempty"`
MetricsPeriod string `json:"elasticsearch.metrics.period,omitempty"`
StatePeriod string `json:"elasticsearch.state.period,omitempty"`
}
return json.Marshal(config{
Enabled: m.Enabled,
Elasticsearch: m.Elasticsearch,
MetricsPeriod: durationString(m.MetricsPeriod),
StatePeriod: durationString(m.StatePeriod),
})
}
func durationString(d time.Duration) string {
if d == 0 {
return ""
}
return d.String()
}
// AggregationConfig holds configuration related to aggregation.
type AggregationConfig struct {
MaxServices int `json:"max_services,omitempty"`
}
func configArgs(cfg Config, extra map[string]interface{}) ([]string, error) {
kv, err := flattenConfig(cfg, extra)
if err != nil {
return nil, err
}
out := make([]string, len(kv)*2)
for i, kv := range kv {
out[2*i] = "-E"
out[2*i+1] = kv
}
return out, nil
}
func flattenConfig(cfg Config, extra map[string]interface{}) ([]string, error) {
data, err := json.Marshal(cfg)
if err != nil {
return nil, err
}
m := make(map[string]interface{})
if err := json.Unmarshal(data, &m); err != nil {
return nil, err
}
for k, v := range extra {
m[k] = v
}
var kv []string
flattenMap(m, &kv, "")
sort.Strings(kv)
return kv, nil
}
func flattenMap(m map[string]interface{}, out *[]string, prefix string) {
for k, v := range m {
switch v := v.(type) {
case map[string]interface{}:
flattenMap(v, out, prefix+k+".")
default:
jsonv, err := json.Marshal(v)
if err != nil {
panic(err)
}
*out = append(*out, fmt.Sprintf("%s%s=%s", prefix, k, jsonv))
}
}
}
// DefaultConfig holds the default configuration.
func DefaultConfig() Config {
return Config{
Kibana: &KibanaConfig{
Enabled: true,
Host: (&url.URL{
Scheme: "http",
Host: net.JoinHostPort(
getenvDefault("KIBANA_HOST", defaultKibanaHost),
KibanaPort(),
),
Path: getenvDefault("KIBANA_BASE_PATH", defaultKibanaBasePath),
}).String(),
Username: getenvDefault("KIBANA_USER", defaultKibanaUser),
Password: getenvDefault("KIBANA_PASS", defaultKibanaPass),
},
Output: defaultOutputConfig(),
}
}
// defaultOutputConfig enables overriding the default output, and is used to
// default to console output in tests for apmservertest itself. This is needed
// to avoid interacting with Elasticsearch, which would cause systemtest tests
// to fail as they assume sole access to Elasticsearch.
func defaultOutputConfig() OutputConfig {
var outputConfig OutputConfig
switch v := os.Getenv("APMSERVERTEST_DEFAULT_OUTPUT"); v {
case "console":
outputConfig.Console = &ConsoleOutputConfig{Enabled: true}
case "":
outputConfig.Elasticsearch = &ElasticsearchOutputConfig{
Enabled: true,
Hosts: []string{net.JoinHostPort(
getenvDefault("ES_HOST", defaultElasticsearchHost),
ElasticsearchPort(),
)},
Username: getenvDefault("ES_USER", defaultElasticsearchUser),
Password: getenvDefault("ES_PASS", defaultElasticsearchPass),
// Lower the flush interval to 1ms to avoid delaying the tests.
FlushInterval: time.Millisecond,
}
default:
panic("APMSERVERTEST_DEFAULT_OUTPUT has unexpected value: " + v)
}
return outputConfig
}
// KibanaPort returns the Kibana port, configured using
// KIBANA_PORT, or otherwise returning the default of 5601.
func KibanaPort() string {
return getenvDefault("KIBANA_PORT", defaultKibanaPort)
}
// ElasticsearchPort returns the Elasticsearch REST API port,
// configured using ES_PORT, or otherwise returning the default
// of 9200.
func ElasticsearchPort() string {
return getenvDefault("ES_PORT", defaultElasticsearchPort)
}
func getenvDefault(k, defaultv string) string {
v := os.Getenv(k)
if v == "" {
return defaultv
}
return v
}