func (chk Installed) Status() (int, string, error) { name := getManager() options := managers[name] cmd := exec.Command(name, options, chk.pkg) out, err := cmd.CombinedOutput() outstr := string(out) var msg string switch { case err == nil && (name == "rpm" || name == "pacman"): return errutil.Success() // failures due to mising package case name == "dpkg" && strings.Contains(outstr, "not installed"): case name == "pacman" && strings.Contains(outstr, "not found"): case name == "rpm" && strings.Contains(outstr, "not installed"): msg := "Package was not found:" msg += "\n\tPackage name: " + chk.pkg msg += "\n\tPackage manager: " + name msg += "\n\tCommand output: " + outstr return 1, msg, nil // failures that were not due to packages not being installed case err != nil: errutil.ExecError(cmd, outstr, err) default: return errutil.Success() } return 1, msg, nil }
func (chk SystemctlUnitFileStatus) Status() (int, string, error) { units, statuses, err := systemdstatus.UnitFileStatuses() if err != nil { return 1, "", err } var actualStatus string found := false for _, unit := range units { if unit == chk.unit { found = true } } if !found { return 1, "Unit file could not be found: " + chk.unit, nil } for i, un := range units { if un == chk.unit { actualStatus = statuses[i] if actualStatus == chk.status { return errutil.Success() } } } msg := "Unit didn't have status" return errutil.GenericError(msg, chk.status, []string{actualStatus}) }
func (chk Command) Status() (int, string, error) { cmd := exec.Command("bash", "-c", chk.Command) err := cmd.Start() if err != nil && strings.Contains(err.Error(), "not found in $PATH") { return 1, "Executable not found: " + chk.Command, nil } else if err != nil { return 1, "", err } if err = cmd.Wait(); err != nil { var exitCode int // this is convoluted, but should work on Windows & Unix if exiterr, ok := err.(*exec.ExitError); ok { if status, ok := exiterr.Sys().(syscall.WaitStatus); ok { exitCode = status.ExitStatus() } } // dummy, in case the above failed. We know it's not zero! if exitCode == 0 { exitCode = 1 } out, _ := cmd.CombinedOutput() // don't care if this fails exitMessage := "Command exited with non-zero exit code:" exitMessage += "\n\tCommand: " + chk.Command exitMessage += "\n\tExit code: " + fmt.Sprint(exitCode) exitMessage += "\n\tOutput: " + string(out) return 1, exitMessage, nil } return errutil.Success() }
// freeMemOrSwap is an abstraction of FreeMemory and FreeSwap, which measures // if the desired resource has a quantity free above the amount specified func freeMemOrSwap(input string, swapOrMem string) (int, string, error) { amount, units, err := chkutil.SeparateByteUnits(input) if err != nil { log.WithFields(log.Fields{ "err": err.Error(), }).Fatal("Couldn't separate string into a scalar and units") } var actualAmount int switch strings.ToLower(swapOrMem) { case "memory": actualAmount, err = memstatus.FreeMemory(units) case "swap": actualAmount, err = memstatus.FreeSwap(units) default: log.Fatalf("Invalid option passed to freeMemoOrSwap: %s", swapOrMem) } if err != nil { return 1, "", err } else if actualAmount > amount { return errutil.Success() } msg := "Free " + swapOrMem + " lower than defined threshold" actualString := fmt.Sprint(actualAmount) + units return errutil.GenericError(msg, input, []string{actualString}) }
// RoutingTableMatch asks: Is this value in this column of the routing table? func RoutingTableMatch(col string, str string) (int, string, error) { column := RoutingTableColumn(col) if tabular.StrIn(str, column) { return errutil.Success() } return errutil.GenericError("Not found in routing table", str, column) }
func (chk PHPConfig) Status() (int, string, error) { // getPHPVariable returns the value of a PHP configuration value as a string // or just "" if it doesn't exist getPHPVariable := func(name string) (val string) { quote := func(str string) string { return "\"" + str + "\"" } // php -r 'echo get_cfg_var("default_mimetype"); echo := fmt.Sprintf("echo get_cfg_var(%s);", quote(name)) cmd := exec.Command("php", "-r", echo) out, err := cmd.CombinedOutput() if err != nil { errutil.ExecError(cmd, string(out), err) } return string(out) } actualValue := getPHPVariable(chk.variable) if actualValue == chk.value { return errutil.Success() } else if actualValue == "" { msg := "PHP configuration variable not set" return errutil.GenericError(msg, chk.value, []string{actualValue}) } msg := "PHP variable did not match expected value" return errutil.GenericError(msg, chk.value, []string{actualValue}) }
func (chk DockerRunningAPI) Status() (int, string, error) { running := getRunningContainersAPI(chk.path) if tabular.StrContainedIn(chk.name, running) { return errutil.Success() } msg := "Docker container not runnning" return errutil.GenericError(msg, chk.name, running) }
// ResponseMatchesGeneral is an abstraction of ResponseMatches and // ResponseMatchesInsecure that simply varies in the security of the connection func ResponseMatchesGeneral(urlstr string, re *regexp.Regexp, secure bool) (int, string, error) { body := chkutil.URLToBytes(urlstr, secure) if re.Match(body) { return errutil.Success() } msg := "Response didn't match regexp" return errutil.GenericError(msg, re.String(), []string{string(body)}) }
func (chk FileMatches) Status() (int, string, error) { if chk.re.Match(chkutil.FileToBytes(chk.path)) { return errutil.Success() } msg := "File does not match regexp:" msg += "\n\tFile: " + chk.path msg += "\n\tRegexp: " + chk.re.String() return 1, msg, nil }
func (chk UserInGroup) Status() (int, string, error) { boo, err := usrstatus.UserInGroup(chk.user, chk.group) if err != nil { return 1, "", err } else if boo { return errutil.Success() } return 1, "User not found in group", nil }
// timerCheck is pure DRY for SystemctlTimer and SystemctlTimerLoaded func timerCheck(unit string, all bool) (int, string, error) { timers, err := systemdstatus.Timers(all) if err != nil { return 1, "", err } else if tabular.StrIn(unit, timers) { return errutil.Success() } return errutil.GenericError("Timer not found", unit, timers) }
func (chk SystemctlLoaded) Status() (int, string, error) { boo, err := systemdstatus.ServiceLoaded(chk.service) if err != nil { return 1, "", err } else if boo { return errutil.Success() } return 1, "Service wasn't loaded: " + chk.service, nil }
// ipCheck(int, string, error) is an abstraction of IP4 and // IP6 func ipCheck(name string, address *net.IP, version int) (int, string, error) { ips := netstatus.InterfaceIPs(name) for _, ip := range ips { if ip.Equal(*address) { return errutil.Success() } } return errutil.GenericError("Interface does not have IP", address, ips) }
func (chk SystemctlActive) Status() (int, string, error) { boo, err := systemdstatus.ServiceActive(chk.service) if err != nil { return 1, "", err } else if boo { return errutil.Success() } return 1, "Service wasn't active: " + chk.service, nil }
func (chk SystemctlSockListening) Status() (int, string, error) { listening, err := systemdstatus.ListeningSockets() if err != nil { return 1, "", err } if tabular.StrIn(chk.path, listening) { return errutil.Success() } return errutil.GenericError("Socket wasn't listening", chk.path, listening) }
func (chk DockerImage) Status() (int, string, error) { images, err := dockerstatus.DockerImageRepositories() if err != nil { return 1, "", err } if tabular.StrIn(chk.name, images) { return errutil.Success() } return errutil.GenericError("Docker image was not found", chk.name, images) }
func (chk Permissions) Status() (int, string, error) { passed, err := fsstatus.FileHasPermissions(chk.expectedPerms, chk.path) if err != nil { return 1, "", err } if passed { return errutil.Success() } return 1, "File did not have permissions: " + chk.expectedPerms, nil }
func (chk PortTCP) Status() (int, string, error) { if netstatus.PortOpen("tcp", chk.port) { return errutil.Success() } // convert ports to string to send to errutil.GenericError var strPorts []string for _, port := range netstatus.OpenPorts("tcp") { strPorts = append(strPorts, fmt.Sprint(port)) } return errutil.GenericError("Port not open", fmt.Sprint(chk.port), strPorts) }
func (chk DockerImageRegexp) Status() (int, string, error) { images, err := dockerstatus.DockerImageRepositories() if err != nil { return 1, "", err } if tabular.ReIn(chk.re, images) { return errutil.Success() } msg := "Docker image was not found." return errutil.GenericError(msg, chk.re.String(), images) }
func (chk DockerRunningRegexp) Status() (int, string, error) { running, err := dockerstatus.RunningContainers() if err != nil { return 1, "", err } if tabular.ReIn(chk.re, running) { return errutil.Success() } msg := "Docker container not runnning" return errutil.GenericError(msg, chk.re.String(), running) }
// isType checks if the resource at path is of the type specified by name by // passing path to checker. Mostly used to abstract Directory, File, Symlink. func isType(name string, checker fileCondition, path string) (int, string, error) { boo, err := checker(path) if os.IsNotExist(err) { return 1, "No such file or directory: " + path, nil } else if os.IsPermission(err) { return 1, "", errors.New("Insufficient Permissions to read: " + path) } else if boo { return errutil.Success() } return 1, "Is not a " + name + ": " + path, nil }
func (chk CommandOutputMatches) Status() (int, string, error) { cmd := exec.Command("bash", "-c", chk.Command) out, err := cmd.CombinedOutput() if err != nil { errutil.ExecError(cmd, string(out), err) } if chk.re.Match(out) { return errutil.Success() } msg := "Command output did not match regexp" return errutil.GenericError(msg, chk.re.String(), []string{string(out)}) }
func (chk SwapUsage) Status() (int, string, error) { actualPercentUsed, err := memstatus.UsedSwap("percent") if err != nil { return 1, "", err } if actualPercentUsed < int(chk.maxPercentUsed) { return errutil.Success() } msg := "Swap usage above defined maximum" slc := []string{fmt.Sprint(actualPercentUsed)} return errutil.GenericError(msg, fmt.Sprint(chk.maxPercentUsed), slc) }
func (chk InodeUsage) Status() (int, string, error) { actualPercentUsed, err := fsstatus.PercentInodesUsed(chk.filesystem) if err != nil { return 1, "Unexpected error", err } if actualPercentUsed < chk.maxPercentUsed { return errutil.Success() } msg := "More disk space used than expected" slc := []string{fmt.Sprint(actualPercentUsed) + "%"} return errutil.GenericError(msg, fmt.Sprint(chk.maxPercentUsed)+"%", slc) }
// genericUserField constructs (int, string, error)s that check if a given field of a User // object found by lookupUser has a given value func genericUserField(usernameOrUID string, fieldName string, fieldValue string) (int, string, error) { boolean, err := userHasField(usernameOrUID, fieldName, fieldValue) if err != nil { return 1, "User does not exist: " + usernameOrUID, nil } else if boolean { return errutil.Success() } msg := "User does not have expected " + fieldName + ": " msg += "\nUser: "******"\nGiven: " + fieldValue return 1, msg, nil }
func (chk Module) Status() (int, string, error) { // kernelModules returns a list of all Modules that are currently loaded // TODO just read from /proc/Modules kernelModules := func() (Modules []string) { cmd := exec.Command("/sbin/lsmod") return chkutil.CommandColumnNoHeader(0, cmd) } Modules := kernelModules() if tabular.StrIn(chk.name, Modules) { return errutil.Success() } return errutil.GenericError("Module is not loaded", chk.name, Modules) }
func (chk GroupID) Status() (int, string, error) { groups, err := usrstatus.Groups() if err != nil { return 0, "", err } for _, g := range groups { if g.Name == chk.name { if g.ID == chk.id { return errutil.Success() } msg := "Group does not have expected ID" return errutil.GenericError(msg, chk.id, []int{g.ID}) } } return groupNotFound(chk.name) }
func (chk InterfaceExists) Status() (int, string, error) { // getInterfaceNames returns the names of all network interfaces getInterfaceNames := func() (interfaces []string) { for _, iface := range netstatus.GetInterfaces() { interfaces = append(interfaces, iface.Name) } return } interfaces := getInterfaceNames() for _, iface := range interfaces { if iface == chk.name { return errutil.Success() } } return errutil.GenericError("Interface does not exist", chk.name, interfaces) }
func (chk Temp) Status() (int, string, error) { // allCoreTemps returns the Temperature of each core allCoreTemps := func() (Temps []int) { cmd := exec.Command("sensors") out, err := cmd.CombinedOutput() outstr := string(out) errutil.ExecError(cmd, outstr, err) restr := `Core\s\d+:\s+[\+\-](?P<Temp>\d+)\.*\d*°C` re := regexp.MustCompile(restr) for _, line := range regexp.MustCompile(`\n+`).Split(outstr, -1) { if re.MatchString(line) { // submatch captures only the integer part of the Temperature matchDict := chkutil.SubmatchMap(re, line) if _, ok := matchDict["Temp"]; !ok { log.WithFields(log.Fields{ "regexp": re.String(), "matchDict": matchDict, "output": outstr, }).Fatal("Couldn't find any Temperatures in `sensors` output") } TempInt64, err := strconv.ParseInt(matchDict["Temp"], 10, 64) if err != nil { log.WithFields(log.Fields{ "regexp": re.String(), "matchDict": matchDict, "output": outstr, "error": err.Error(), }).Fatal("Couldn't parse integer from `sensors` output") } Temps = append(Temps, int(TempInt64)) } } return Temps } // getCoreTemp returns an integer Temperature for a certain core getCoreTemp := func(core int) (Temp int) { Temps := allCoreTemps() errutil.IndexError("No such core available", core, Temps) return Temps[core] } Temp := getCoreTemp(0) if Temp < int(chk.max) { return errutil.Success() } msg := "Core Temp exceeds defined maximum" return errutil.GenericError(msg, chk.max, []string{fmt.Sprint(Temp)}) }
func (chk PacmanIgnore) Status() (int, string, error) { path := "/etc/pacman.conf" data := chkutil.FileToString(path) re := regexp.MustCompile(`[^#]IgnorePkg\s+=\s+.+`) find := re.FindString(data) var packages []string if find != "" { spl := strings.Split(find, " ") errutil.IndexError("Not enough lines in "+path, 2, spl) packages = spl[2:] // first two are "IgnorePkg" and "=" if tabular.StrIn(chk.pkg, packages) { return errutil.Success() } } msg := "Couldn't find package in IgnorePkg" return errutil.GenericError(msg, chk.pkg, packages) }