Skip to content

Commit 80526a5

Browse files
[POA-2410] When apidump returns an error, do not exit. (#51)
This avoids causing a boot-loop when the POSTMAN_API_KEY environment variable is missing or incomplete, or a command-line parameter is bad. I don't think we can distinguish initialization from non-initialization errors entirely, but almost all errors that are returned will be config problems. --------- Co-authored-by: Mudit Joshi <116863733+mudit-postman@users.noreply.github.com>
1 parent 1b16e0f commit 80526a5

File tree

1 file changed

+130
-102
lines changed

1 file changed

+130
-102
lines changed

cmd/internal/apidump/apidump.go

Lines changed: 130 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -89,126 +89,154 @@ func applyRandomizedStart() {
8989
}
9090
}
9191

92-
var Cmd = &cobra.Command{
93-
Use: "apidump",
94-
Short: "Capture requests/responses from network traffic.",
95-
Long: "Capture and store a sequence of requests/responses to a service by observing network traffic.",
96-
SilenceUsage: true,
97-
Args: cobra.ExactArgs(0),
98-
RunE: func(cmd *cobra.Command, _ []string) error {
99-
applyRandomizedStart()
92+
// When run in a container or as a systemd service, we will automatically be restarted
93+
// on failure. But, this will not correct misconfiguration errors; we will just get stuck
94+
// in a boot loop, which can cause disruption to the services in the same pod.
95+
//
96+
// Instead, we will terminate normally when no error is returned, but loop indefinitely
97+
// on error, as if randomized start failed.
98+
//
99+
// FIXME: do we need custom SIGTERM or SIGINT handlers? I do not think we do. But, it
100+
// might be that apidump already installed one before returning error. Will that cause a problem?
101+
//
102+
// TODO: create a separate command for "run as a service" vs "run on command line"? I don't
103+
// think there is a reliable way to tell the context otherwise.
104+
func apidumpRunWithoutAbnormalExit(cmd *cobra.Command, args []string) error {
105+
err := apidumpRunInternal(cmd, args)
100106

101-
traceTags, err := util.ParseTagsAndWarn(tagsFlag)
102-
if err != nil {
103-
return err
104-
}
107+
if err == nil {
108+
return nil
109+
}
105110

106-
plugins, err := pluginloader.Load(pluginsFlag)
111+
// Log the error and wait forever.
112+
printer.Stderr.Errorf("Error during initiaization: %v\n", err)
113+
printer.Stdout.Infof("This process will not exit, to avoid boot loops. Please correct the command line flags or environment and retry.\n")
114+
115+
select {}
116+
}
117+
118+
func apidumpRunInternal(cmd *cobra.Command, _ []string) error {
119+
applyRandomizedStart()
120+
121+
traceTags, err := util.ParseTagsAndWarn(tagsFlag)
122+
if err != nil {
123+
return err
124+
}
125+
126+
plugins, err := pluginloader.Load(pluginsFlag)
127+
if err != nil {
128+
return errors.Wrap(err, "failed to load plugins")
129+
}
130+
131+
// Check that exactly one of --project or --collection is specified.
132+
if projectID == "" && postmanCollectionID == "" {
133+
return errors.New("exactly one of --project or --collection must be specified")
134+
}
135+
136+
// If --project was given, convert projectID to serviceID.
137+
var serviceID akid.ServiceID
138+
if projectID != "" {
139+
err := akid.ParseIDAs(projectID, &serviceID)
107140
if err != nil {
108-
return errors.Wrap(err, "failed to load plugins")
141+
return errors.Wrap(err, "failed to parse project ID")
109142
}
143+
}
110144

111-
// Check that exactly one of --project or --collection is specified.
112-
if projectID == "" && postmanCollectionID == "" {
113-
return errors.New("exactly one of --project or --collection must be specified")
145+
// Look up existing trace by tags
146+
if appendByTagFlag {
147+
if outFlag.AkitaURI == nil {
148+
return errors.New("\"append-by-tag\" can only be used with a cloud-based trace")
114149
}
115150

116-
// If --project was given, convert projectID to serviceID.
117-
var serviceID akid.ServiceID
118-
if projectID != "" {
119-
err := akid.ParseIDAs(projectID, &serviceID)
120-
if err != nil {
121-
return errors.Wrap(err, "failed to parse project ID")
122-
}
151+
if outFlag.AkitaURI.ObjectName != "" {
152+
return errors.New("Cannot specify a trace name together with \"append-by-tag\"")
123153
}
124154

125-
// Look up existing trace by tags
126-
if appendByTagFlag {
127-
if outFlag.AkitaURI == nil {
128-
return errors.New("\"append-by-tag\" can only be used with a cloud-based trace")
129-
}
130-
131-
if outFlag.AkitaURI.ObjectName != "" {
132-
return errors.New("Cannot specify a trace name together with \"append-by-tag\"")
133-
}
155+
destURI, err := util.GetTraceURIByTags(rest.Domain,
156+
telemetry.GetClientID(),
157+
outFlag.AkitaURI.ServiceName,
158+
traceTags,
159+
"append-by-tag",
160+
)
161+
if err != nil {
162+
return err
163+
}
164+
if destURI.ObjectName != "" {
165+
outFlag.AkitaURI = &destURI
166+
}
167+
}
134168

135-
destURI, err := util.GetTraceURIByTags(rest.Domain,
136-
telemetry.GetClientID(),
137-
outFlag.AkitaURI.ServiceName,
138-
traceTags,
139-
"append-by-tag",
140-
)
169+
// Allow specification of an alternate rotation time, default 1h.
170+
// We can rotate the trace if we're sending the output to a cloud-based trace.
171+
// But, if the trace name is explicitly given, or selected by tag,
172+
// or we're sending the output to a local file, then we cannot rotate.
173+
traceRotateInterval := time.Duration(0)
174+
if (outFlag.AkitaURI != nil && outFlag.AkitaURI.ObjectName == "") || projectID != "" || postmanCollectionID != "" {
175+
if traceRotateFlag != "" {
176+
traceRotateInterval, err = time.ParseDuration(traceRotateFlag)
141177
if err != nil {
142-
return err
143-
}
144-
if destURI.ObjectName != "" {
145-
outFlag.AkitaURI = &destURI
178+
return errors.Wrap(err, "Failed to parse trace rotation interval.")
146179
}
180+
} else {
181+
traceRotateInterval = apispec.DefaultTraceRotateInterval
147182
}
183+
}
148184

149-
// Allow specification of an alternate rotation time, default 1h.
150-
// We can rotate the trace if we're sending the output to a cloud-based trace.
151-
// But, if the trace name is explicitly given, or selected by tag,
152-
// or we're sending the output to a local file, then we cannot rotate.
153-
traceRotateInterval := time.Duration(0)
154-
if (outFlag.AkitaURI != nil && outFlag.AkitaURI.ObjectName == "") || projectID != "" || postmanCollectionID != "" {
155-
if traceRotateFlag != "" {
156-
traceRotateInterval, err = time.ParseDuration(traceRotateFlag)
157-
if err != nil {
158-
return errors.Wrap(err, "Failed to parse trace rotation interval.")
159-
}
160-
} else {
161-
traceRotateInterval = apispec.DefaultTraceRotateInterval
162-
}
163-
}
185+
// Rate limit must be greater than zero.
186+
if rateLimitFlag <= 0.0 {
187+
rateLimitFlag = 1000.0
188+
}
164189

165-
// Rate limit must be greater than zero.
166-
if rateLimitFlag <= 0.0 {
167-
rateLimitFlag = 1000.0
190+
// If we collect TLS information, we have to parse it
191+
if collectTCPAndTLSReports {
192+
if !parseTLSHandshakes {
193+
printer.Stderr.Warningf("Overriding parse-tls-handshakes=false because TLS report collection is enabled.\n")
194+
parseTLSHandshakes = true
168195
}
196+
}
169197

170-
// If we collect TLS information, we have to parse it
171-
if collectTCPAndTLSReports {
172-
if !parseTLSHandshakes {
173-
printer.Stderr.Warningf("Overriding parse-tls-handshakes=false because TLS report collection is enabled.\n")
174-
parseTLSHandshakes = true
175-
}
176-
}
198+
args := apidump.Args{
199+
ClientID: telemetry.GetClientID(),
200+
Domain: rest.Domain,
201+
Out: outFlag,
202+
PostmanCollectionID: postmanCollectionID,
203+
ServiceID: serviceID,
204+
Tags: traceTags,
205+
SampleRate: sampleRateFlag,
206+
WitnessesPerMinute: rateLimitFlag,
207+
Interfaces: interfacesFlag,
208+
Filter: filterFlag,
209+
PathExclusions: pathExclusionsFlag,
210+
HostExclusions: hostExclusionsFlag,
211+
PathAllowlist: pathAllowlistFlag,
212+
HostAllowlist: hostAllowlistFlag,
213+
ExecCommand: execCommandFlag,
214+
ExecCommandUser: execCommandUserFlag,
215+
Plugins: plugins,
216+
LearnSessionLifetime: traceRotateInterval,
217+
StatsLogDelay: statsLogDelay,
218+
TelemetryInterval: telemetryInterval,
219+
ProcFSPollingInterval: procFSPollingInterval,
220+
CollectTCPAndTLSReports: collectTCPAndTLSReports,
221+
ParseTLSHandshakes: parseTLSHandshakes,
222+
MaxWitnessSize_bytes: maxWitnessSize_bytes,
223+
DockerExtensionMode: dockerExtensionMode,
224+
HealthCheckPort: healthCheckPort,
225+
SendWitnessPayloads: sendWitnessPayloads,
226+
}
227+
if err := apidump.Run(args); err != nil {
228+
return cmderr.AkitaErr{Err: err}
229+
}
230+
return nil
231+
}
177232

178-
args := apidump.Args{
179-
ClientID: telemetry.GetClientID(),
180-
Domain: rest.Domain,
181-
Out: outFlag,
182-
PostmanCollectionID: postmanCollectionID,
183-
ServiceID: serviceID,
184-
Tags: traceTags,
185-
SampleRate: sampleRateFlag,
186-
WitnessesPerMinute: rateLimitFlag,
187-
Interfaces: interfacesFlag,
188-
Filter: filterFlag,
189-
PathExclusions: pathExclusionsFlag,
190-
HostExclusions: hostExclusionsFlag,
191-
PathAllowlist: pathAllowlistFlag,
192-
HostAllowlist: hostAllowlistFlag,
193-
ExecCommand: execCommandFlag,
194-
ExecCommandUser: execCommandUserFlag,
195-
Plugins: plugins,
196-
LearnSessionLifetime: traceRotateInterval,
197-
StatsLogDelay: statsLogDelay,
198-
TelemetryInterval: telemetryInterval,
199-
ProcFSPollingInterval: procFSPollingInterval,
200-
CollectTCPAndTLSReports: collectTCPAndTLSReports,
201-
ParseTLSHandshakes: parseTLSHandshakes,
202-
MaxWitnessSize_bytes: maxWitnessSize_bytes,
203-
DockerExtensionMode: dockerExtensionMode,
204-
HealthCheckPort: healthCheckPort,
205-
SendWitnessPayloads: sendWitnessPayloads,
206-
}
207-
if err := apidump.Run(args); err != nil {
208-
return cmderr.AkitaErr{Err: err}
209-
}
210-
return nil
211-
},
233+
var Cmd = &cobra.Command{
234+
Use: "apidump",
235+
Short: "Capture requests/responses from network traffic.",
236+
Long: "Capture and store a sequence of requests/responses to a service by observing network traffic.",
237+
SilenceUsage: true,
238+
Args: cobra.ExactArgs(0),
239+
RunE: apidumpRunWithoutAbnormalExit,
212240
}
213241

214242
func init() {

0 commit comments

Comments
 (0)