83e958c3 |
return nil
}
// BuildAndRunDiagnostics builds diagnostics based on the options and executes them, returning a summary.
func (o PodDiagnosticsOptions) BuildAndRunDiagnostics() (bool, error, int, int) {
failed := false
errors := []error{}
diagnostics := []types.Diagnostic{}
func() { // don't trust discovery/build of diagnostics; wrap panic nicely in case of developer error
defer func() {
if r := recover(); r != nil {
failed = true
stack := debug.Stack()
errors = append(errors, fmt.Errorf("While building the diagnostics, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%v\n%s", r, stack))
}
}() // deferred panic handler
podDiags, ok, err := o.buildPodDiagnostics()
failed = failed || !ok
if ok {
diagnostics = append(diagnostics, podDiags...)
}
if err != nil {
errors = append(errors, err...)
}
}()
if failed {
return failed, kutilerrors.NewAggregate(errors), 0, len(errors)
}
failed, err, numWarnings, numErrors := runDiagnostics(o.Logger, diagnostics, 0, len(errors))
return failed, err, numWarnings, numErrors
}
var (
// availablePodDiagnostics contains the names of host diagnostics that can be executed
// during a single run of diagnostics. Add more diagnostics to the list as they are defined.
availablePodDiagnostics = sets.NewString(poddiag.PodCheckDnsName, poddiag.PodCheckAuthName)
)
// buildPodDiagnostics builds host Diagnostic objects based on the host environment.
// Returns the Diagnostics built, "ok" bool for whether to proceed or abort, and an error if any was encountered during the building of diagnostics.
func (o PodDiagnosticsOptions) buildPodDiagnostics() ([]types.Diagnostic, bool, []error) {
diagnostics := []types.Diagnostic{}
err, requestedDiagnostics := determineRequestedDiagnostics(availablePodDiagnostics.List(), o.RequestedDiagnostics, o.Logger)
if err != nil {
return diagnostics, false, []error{err} // don't waste time on discovery
}
// TODO: check we're actually in a container
for _, diagnosticName := range requestedDiagnostics {
switch diagnosticName {
case poddiag.PodCheckDnsName:
diagnostics = append(diagnostics, poddiag.PodCheckDns{})
case poddiag.PodCheckAuthName:
diagnostics = append(diagnostics, poddiag.PodCheckAuth{
MasterCaPath: StandardMasterCaPath,
TokenPath: StandardTokenPath,
MasterUrl: StandardMasterUrl,
})
default:
return diagnostics, false, []error{fmt.Errorf("unknown diagnostic: %v", diagnosticName)}
}
}
return diagnostics, true, nil
}
// runDiagnostics performs the actual execution of diagnostics once they're built.
func runDiagnostics(logger *log.Logger, diagnostics []types.Diagnostic, warnCount int, errorCount int) (bool, error, int, int) {
for _, diagnostic := range diagnostics {
func() { // wrap diagnostic panic nicely in case of developer error
defer func() {
if r := recover(); r != nil {
errorCount += 1
stack := debug.Stack()
logger.Error("CED5001",
fmt.Sprintf("While running the %s diagnostic, a panic was encountered.\nThis is a bug in diagnostics. Error and stack trace follow: \n%s\n%s",
diagnostic.Name(), fmt.Sprintf("%v", r), stack))
}
}()
if canRun, reason := diagnostic.CanRun(); !canRun {
if reason == nil {
logger.Notice("CED5002", fmt.Sprintf("Skipping diagnostic: %s\nDescription: %s", diagnostic.Name(), diagnostic.Description()))
} else {
logger.Notice("CED5003", fmt.Sprintf("Skipping diagnostic: %s\nDescription: %s\nBecause: %s", diagnostic.Name(), diagnostic.Description(), reason.Error()))
}
return
}
logger.Notice("CED5004", fmt.Sprintf("Running diagnostic: %s\nDescription: %s", diagnostic.Name(), diagnostic.Description()))
r := diagnostic.Check()
for _, entry := range r.Logs() {
logger.LogEntry(entry)
}
warnCount += len(r.Warnings())
errorCount += len(r.Errors())
}()
}
return errorCount > 0, nil, warnCount, errorCount
}
// determineRequestedDiagnostics determines which diagnostic the user wants to run
// based on the -d list and the available diagnostics.
// returns error or diagnostic names
func determineRequestedDiagnostics(available []string, requested []string, logger *log.Logger) (error, []string) {
diagnostics := []string{}
if len(requested) == 0 { // not specified, use the available list
diagnostics = available |
83e958c3 |
logger.Error("CED6001", log.EvalTemplate("CED6001", "None of the requested diagnostics are available:\n {{.requested}}\nPlease try from the following:\n {{.available}}",
log.Hash{"requested": requested, "available": available}))
return fmt.Errorf("No requested diagnostics available"), diagnostics
} else if len(diagnostics) < len(requested) {
logger.Error("CED6002", log.EvalTemplate("CED6002", "Of the requested diagnostics:\n {{.requested}}\nonly these are available:\n {{.diagnostics}}\nThe list of all possible is:\n {{.available}}",
log.Hash{"requested": requested, "diagnostics": diagnostics, "available": available}))
return fmt.Errorf("Not all requested diagnostics are available"), diagnostics
} // else it's a valid list.
return nil, diagnostics
} |