-
Notifications
You must be signed in to change notification settings - Fork 23
Expand file tree
/
Copy pathconfig.go
More file actions
391 lines (326 loc) · 14.5 KB
/
Copy pathconfig.go
File metadata and controls
391 lines (326 loc) · 14.5 KB
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
package config
import (
"encoding/json"
"flag"
"os"
"path/filepath"
"strings"
)
// Verbosity is the current log level
type Verbosity int
const (
//Info indicates normal logging level
Info Verbosity = iota
//Verbose indicates additional logging (for troubleshooting the app)
Verbose
)
type Region string
const (
USRegion Region = "us"
EURegion Region = "eu"
NoRegion Region = "none"
)
// userFlags is a struct containing the commandline arguments passed in at runtime
type userFlags struct {
Verbose bool
Interactive bool
Quiet bool
VeryQuiet bool
Help bool
Version bool
SkipVersionCheck bool
YesToAll bool
ShowOverrideHelp bool
AutoAttach bool
UsageOptOut bool
Run bool
ListScripts bool
Proxy string
ProxyUser string
ProxyPassword string
Tasks string
ConfigFile string
Override string
OutputPath string
Filter string
BrowserURL string
AttachmentEndpoint string
Suites string
Include string
APIKey string
Region string
Script string
ScriptFlags string
K8sNamespace string
ACAgentsNamespace string
InNewRelicCLI bool
}
type ConfigFlag struct {
Name string `json:"name"`
Value interface{} `json:"value"`
}
// MarshalJSON - custom JSON marshaling for this task, we'll strip out the passphrase to keep it only in memory, not on disk
func (f userFlags) MarshalJSON() ([]byte, error) {
proxySpecified := false
if f.Proxy != "" || f.ProxyPassword != "" || f.ProxyUser != "" {
proxySpecified = true
}
return json.Marshal(&struct {
Verbose bool
Quiet bool
VeryQuiet bool
YesToAll bool
ShowOverrideHelp bool
AutoAttach bool
ProxySpecified bool
SkipVersionCheck bool
Run bool
ListScripts bool
Tasks string
ConfigFile string
Override string
OutputPath string
Filter string
BrowserURL string
Suites string
APIKey string
Include string
Region string
Script string
ScriptFlags string
K8sNamespace string
ACAgentsNamespace string
}{
Verbose: f.Verbose,
Quiet: f.Quiet,
VeryQuiet: f.VeryQuiet,
YesToAll: f.YesToAll,
ShowOverrideHelp: f.ShowOverrideHelp,
AutoAttach: f.AutoAttach,
ProxySpecified: proxySpecified,
SkipVersionCheck: f.SkipVersionCheck,
Run: f.Run,
ListScripts: f.ListScripts,
Tasks: f.Tasks,
ConfigFile: f.ConfigFile,
Override: f.Override,
OutputPath: f.OutputPath,
Filter: f.Filter,
BrowserURL: f.BrowserURL,
Suites: f.Suites,
Include: f.Include,
APIKey: obfuscateAPIKey(f.APIKey),
Region: f.Region,
Script: f.Script,
ScriptFlags: f.ScriptFlags,
K8sNamespace: f.K8sNamespace,
ACAgentsNamespace: f.ACAgentsNamespace,
})
}
// LogLevel is the current log level for output to the screen
var LogLevel Verbosity
// Flags story configuration information
var Flags = userFlags{}
// Version of the application
var Version string
// USUsageEndpoint is the haberdasher endpoint to which usage statistics are sent for US accounts
var USUsageEndpoint string
// EUUsageEndpoint is the haberdasher endpoint to which usage statistics are sent for EU accounts
var EUUsageEndpoint string
// EUUsageEndpoint is the haberdasher endpoint to which usage statistics are sent
var UsageEndpoint string
// USAttachmentEndpoint is the haberdasher endpoint to which attachments are sent for US accounts
var USAttachmentEndpoint string
// EUAttachmentEndpoint is the haberdasher endpoint to which attachments are sent for EU accounts
var EUAttachmentEndpoint string
// AttachmentEndpoint is the haberdasher endpoint to which attachments are sent
var AttachmentEndpoint string
// USHaberdasherURL is the base url for the Haberdasher service in the US
var USHaberdasherURL string
// EUHaberdasherURL is the base url for the Haberdasher service in the EU
var EUHaberdasherURL string
// HaberdasherURL is the base url for the Haberdasher service
var HaberdasherURL string
// BuildTimestamp stores when the build was done
var BuildTimestamp string
func ParseFlags() {
// declaring the cmd arg Flags
//
// Define short option with no description, then long option with description
// FOR EXAMPLE:
// "v", false, ""
// "verbose", false, "Display verbose logging during check execution. Off by default"
defaultString := ""
flag.BoolVar(&Flags.Verbose, "v", false, "alias for -verbose")
flag.BoolVar(&Flags.Verbose, "verbose", false, "Display verbose logging during check execution. Off by default")
flag.BoolVar(&Flags.Version, "version", false, "Display current program version. Take precedence over -skip-version-check")
flag.BoolVar(&Flags.SkipVersionCheck, "skip-version-check", false, "Skips the automatic check for a newer version of the application.")
flag.StringVar(&Flags.Tasks, "t", defaultString, "alias for -tasks")
flag.StringVar(&Flags.Tasks, "tasks", defaultString, "Specific {name of task} - could be comma separated list and/or contain a wildcard (*)")
flag.StringVar(&Flags.Suites, "s", defaultString, "alias for -suites")
flag.StringVar(&Flags.Suites, "suites", defaultString, "Specific {name of task suite} - could be comma separated list. If you do '-h suites' it will list all diagnostic task suites that can be run.")
flag.BoolVar(&Flags.AutoAttach, "a", false, "alias for -attach")
flag.BoolVar(&Flags.AutoAttach, "attach", false, "Attach for automatic upload to New Relic account")
flag.StringVar(&Flags.APIKey, "api-key", defaultString, "API Key from New Relic for upload to New Relic account")
flag.BoolVar(&Flags.Help, "h", false, "alias for -help")
flag.BoolVar(&Flags.Help, "help", false, "Displays full list of command line options. If you do '-h tasks' it will list all tasks that can be run.")
flag.StringVar(&Flags.ConfigFile, "c", defaultString, "alias for -config-file")
flag.StringVar(&Flags.ConfigFile, "config-file", defaultString, "Override default config file location. Can be used to specify either a folder to search in addition to the default folders or a specific config file")
flag.StringVar(&Flags.Proxy, "p", defaultString, "alias for -proxy")
flag.StringVar(&Flags.Proxy, "proxy", defaultString, "Proxy should be in the format http(s)://proxyIp:proxyPort Not necessary in most cases… will override config file if used)")
flag.StringVar(&Flags.ProxyUser, "proxy-user", defaultString, "Proxy username, if necessary")
flag.StringVar(&Flags.ProxyPassword, "proxy-pw", defaultString, "Proxy password, if necessary")
flag.StringVar(&Flags.Override, "o", defaultString, "alias for -override")
flag.StringVar(&Flags.Override, "override", defaultString, "Specify overrides for detected values. Format <Identifier>.<property>=<value> - example '-o Base/Config/Validate.agentLanguage=PHP'")
flag.StringVar(&Flags.OutputPath, "output-path", filepath.FromSlash("./"), "Output directory for results. Files will be named 'nrdiag-output.json and nrdiag-output.zip.")
flag.BoolVar(&Flags.YesToAll, "y", false, "alias for -yes")
flag.BoolVar(&Flags.YesToAll, "yes", false, "Say 'yes' to any prompt that comes up while running.")
flag.StringVar(&Flags.Filter, "filter", "success,warning,failure,error,info", "Filter results based on status. Accepted values: Success, Warning, Failure, Error, None or Info. Multiple values can be provided in comma separated list. e.g: \"Success,Warning,Failure\"")
flag.BoolVar(&Flags.Quiet, "q", false, "Quiet output; only prints the high level results and not the explanatory output. Suppresses file addition warnings if '-y' is also used. Does not contradict '-v'")
flag.BoolVar(&Flags.VeryQuiet, "qq", false, "Very quiet output; only prints a single summary line for output (implies '-q'). Suppresses file addition warnings if '-y' is also used. Does not contradict '-v'. Inclusion filters are ignored.")
flag.StringVar(&Flags.BrowserURL, "browser-url", defaultString, "Specify a URL to check for the presence of a New Relic Browser agent")
flag.StringVar(&Flags.K8sNamespace, "k8s-namespace", defaultString, "Specify the namespace from where to scrape the New Relic resources. If you are using Agent-control, you can also set the '-ac-agents-namespace' flag to specify the namespace where Agent-control Agents are running.")
flag.StringVar(&Flags.ACAgentsNamespace, "ac-agents-namespace", defaultString, "Specify the namespace from where to scrape the Agent-control running agents.")
flag.BoolVar(&Flags.UsageOptOut, "usage-opt-out", false, "Decline to send anonymous New Relic Diagnostic tool usage data to New Relic for this run")
flag.StringVar(&Flags.Include, "include", defaultString, "Include a file or directory (including subdirectories) in the nrdiag-output.zip. Limit 4GB. To upload the results to New Relic also use the '-a' flag.")
flag.StringVar(&Flags.Region, "r", defaultString, "alias for -region")
flag.StringVar(&Flags.Region, "region", defaultString, "The region your New Relic account is in. Accepted values: EU or US. Case insensitive. (Default: US)")
flag.BoolVar(&Flags.ListScripts, "list-scripts", false, "List available scripts")
flag.StringVar(&Flags.Script, "script", defaultString, "View or run a script")
flag.StringVar(&Flags.ScriptFlags, "script-flags", defaultString, "Use with -run -script to pass command line flags to the script")
flag.BoolVar(&Flags.Run, "run", false, "Use with -script to run the script")
//if first arg looks like it was build with `go build`, then we are testing against Haberdasher staging or localhost endpoint
if strings.Contains(os.Args[0], "newrelic-diagnostics-cli") {
flag.StringVar(&Flags.AttachmentEndpoint, "attachment-endpoint", defaultString, "The endpoint to send attachments to. (NR ONLY)")
}
flag.Parse()
if Flags.VeryQuiet {
Flags.Quiet = true
//pseudo-filter to force everything to display
Flags.Filter = ""
}
// This has to be in the config init otherwise you don't get logs as expected
if Flags.Verbose {
LogLevel = Verbose
} else {
LogLevel = Info
}
if Flags.BrowserURL != "" {
Flags.Override = "Browser/Agent/GetSource.url=" + Flags.BrowserURL + "," + Flags.Override
Flags.Tasks = "Browser/Agent/Detect," + Flags.Tasks
}
// Set the endpoints based on region
switch parseRegionFlagAndEnv(Flags.Region, os.Getenv("NEW_RELIC_REGION")) {
case EURegion:
UsageEndpoint = EUUsageEndpoint
// Only set AttachmentEndpoint if the `-attachment-endpoint` flag was not used
if Flags.AttachmentEndpoint == "" {
AttachmentEndpoint = EUAttachmentEndpoint
}
HaberdasherURL = EUHaberdasherURL
default:
UsageEndpoint = USUsageEndpoint
if Flags.AttachmentEndpoint == "" {
AttachmentEndpoint = USAttachmentEndpoint
}
HaberdasherURL = USHaberdasherURL
}
Flags.InNewRelicCLI = (os.Getenv("NEWRELIC_CLI_SUBPROCESS") != "")
}
// UsagePayload gathers and sanitizes user command line input
// A map with string keys and interface values is returned
// The interface values will contain either a boolean or a string
func (f userFlags) UsagePayload() []ConfigFlag {
return []ConfigFlag{
{Name: "verbose", Value: f.Verbose},
{Name: "interactive", Value: f.Interactive},
{Name: "quiet", Value: f.Quiet},
{Name: "veryQuiet", Value: f.VeryQuiet},
{Name: "help", Value: f.Help},
{Name: "version", Value: f.Version},
{Name: "yesToAll", Value: f.YesToAll},
{Name: "showOverrideHelp", Value: f.ShowOverrideHelp},
{Name: "autoAttach", Value: f.AutoAttach},
{Name: "proxy", Value: boolifyFlag(f.Proxy)},
{Name: "proxyUser", Value: boolifyFlag(f.ProxyUser)},
{Name: "proxyPassword", Value: boolifyFlag(f.ProxyPassword)},
{Name: "tasks", Value: f.Tasks},
{Name: "configFile", Value: boolifyFlag(f.ConfigFile)},
{Name: "override", Value: boolifyFlag(f.Override)},
{Name: "outputPath", Value: boolifyFlag(f.OutputPath)},
{Name: "filter", Value: f.Filter},
{Name: "browserURL", Value: boolifyFlag(f.BrowserURL)},
{Name: "attachmentEndpoint", Value: boolifyFlag(f.AttachmentEndpoint)},
{Name: "suites", Value: f.Suites},
{Name: "include", Value: f.Include},
{Name: "region", Value: f.Region},
{Name: "script", Value: f.Script},
{Name: "k8sNamespace", Value: f.K8sNamespace},
{Name: "aCAgentsNamespace", Value: f.ACAgentsNamespace},
}
}
// boolifyFlag is a helper function for falsey/truthy conversion of UserFlag strings
func boolifyFlag(inputFlag string) bool {
return inputFlag != ""
}
// IsForcedTask returns true if the supplied task (identifier) was supplied in the
// -t command line argument.
func (f userFlags) IsForcedTask(identifier string) bool {
identifiers := strings.Split(f.Tasks, ",")
for _, ident := range identifiers {
trimmedIdentifier := strings.TrimSpace(ident)
if strings.EqualFold(identifier, trimmedIdentifier) {
return true
}
}
return false
}
// parseRegionFlagAndEnv - Parse region flag and region env variable, determine which to use.
// Prioritize in this order:
// - Use the command line flag if that is provided
// - If flag is not provided, use env variable NEW_RELIC_REGION, if present
// - If neither the flag or env variable are present, default to US
func parseRegionFlagAndEnv(regionFromFlag string, regionFromEnv string) Region {
regionFlag := stringToRegion(regionFromFlag)
regionEnv := stringToRegion(regionFromEnv)
// No region provided, use default US
if regionFlag == NoRegion && regionEnv == NoRegion {
return USRegion
}
// Both the command line flag and the env variable were provided, priority is flag
if regionFlag != NoRegion && regionEnv != NoRegion {
return regionFlag
}
// Region was provided via env
if regionFlag == NoRegion && regionEnv != NoRegion {
return regionEnv
}
// Region was provided via flag
if regionFlag != NoRegion && regionEnv == NoRegion {
return regionFlag
}
// if we somehow got here, go with default US
return USRegion
}
// stringToRegion - converts region string to Region type
func stringToRegion(region string) Region {
r := strings.TrimSpace(strings.ToLower(region))
if r == "eu" {
return EURegion
}
if r == "us" {
return USRegion
}
return NoRegion
}
// obfuscateAPIKey - returns an obfuscated version of an API key showing only the first 6 characters
func obfuscateAPIKey(apiKey string) string {
if apiKey == "" {
return ""
}
keyLen := len(apiKey)
if keyLen <= 6 {
return strings.Repeat("*", keyLen)
}
return apiKey[:6] + strings.Repeat("*", keyLen-6)
}