// 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 } else if diagnostics = sets.NewString(requested...).Intersection(sets.NewString(available...)).List(); len(diagnostics) == 0 { 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 }
func discoverSystemdUnit(logger *log.Logger, name string) types.SystemdUnit { unit := types.SystemdUnit{Name: name, Exists: false} if output, err := exec.Command("systemctl", "show", name).Output(); err != nil { logger.Error("DS1004", fmt.Sprintf("Error running `systemctl show %s`: %s\nCannot analyze systemd units.", name, err.Error())) } else { attr := make(map[string]string) for _, line := range strings.Split(string(output), "\n") { elements := strings.SplitN(line, "=", 2) // Looking for "Foo=Bar" settings if len(elements) == 2 { // found that, record it... attr[elements[0]] = elements[1] } } if val := attr["LoadState"]; val != "loaded" { logger.Debug("DS1005", fmt.Sprintf("systemd unit '%s' does not exist. LoadState is '%s'", name, val)) return unit // doesn't exist - leave everything blank } else { unit.Exists = true } if val := attr["UnitFileState"]; val == "enabled" { logger.Debug("DS1006", fmt.Sprintf("systemd unit '%s' is enabled - it will start automatically at boot.", name)) unit.Enabled = true } else { logger.Debug("DS1007", fmt.Sprintf("systemd unit '%s' is not enabled - it does not start automatically at boot. UnitFileState is '%s'", name, val)) } if val := attr["ActiveState"]; val == "active" { logger.Debug("DS1008", fmt.Sprintf("systemd unit '%s' is currently running", name)) unit.Active = true } else { logger.Debug("DS1009", fmt.Sprintf("systemd unit '%s' is not currently running. ActiveState is '%s'; exit code was %d.", name, val, unit.ExitStatus)) } fmt.Sscanf(attr["StatusErrno"], "%d", &unit.ExitStatus) // ignore errors... } return unit }