// 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) (exitCode int, exitMessage string) { // get numbers and units units := wrkutils.GetByteUnits(input) re := regexp.MustCompile(`\d+`) amountString := re.FindString(input) // report errors if amountString == "" { log.WithFields(log.Fields{ "input": input, "regexp": re.String(), }).Fatal("Configuration error: couldn't extract number from string") } else if units == "" { log.WithFields(log.Fields{ "input": input, }).Fatal("Configuration error: couldn't extract byte units from string") } amount := wrkutils.ParseMyInt(amountString) actualAmount := getSwapOrMemory("free", swapOrMem, units) if actualAmount > amount { return 0, "" } msg := "Free " + swapOrMem + " lower than defined threshold" actualString := fmt.Sprint(actualAmount) + units return wrkutils.GenericError(msg, input, []string{actualString}) }
// swapUsage checks to see whether or not the system has a swap usage // percentage below a certain threshold func swapUsage(parameters []string) (exitCode int, exitMessage string) { maxPercentUsed := wrkutils.ParseMyInt(parameters[0]) actualPercentUsed := getUsedPercent("swap") if actualPercentUsed < float32(maxPercentUsed) { return 0, "" } msg := "Swap usage above defined maximum" slc := []string{fmt.Sprint(actualPercentUsed)} return wrkutils.GenericError(msg, fmt.Sprint(maxPercentUsed), slc) }
// temp parses the output of lm_sensors and determines if Core 0 (all cores) are // over a certain threshold as specified in the JSON. func temp(parameters []string) (exitCode int, exitMessage string) { // TODO: check for negative, outrageously high temperatures // allCoreTemps returns the temperature of each core allCoreTemps := func() (temps []int) { cmd := exec.Command("sensors") out, err := cmd.CombinedOutput() outstr := string(out) wrkutils.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 := wrkutils.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() wrkutils.IndexError("No such core available", core, temps) return temps[core] } max := wrkutils.ParseMyInt(parameters[0]) temp := getCoreTemp(0) if temp < max { return 0, "" } msg := "Core temp exceeds defined maximum" return wrkutils.GenericError(msg, max, []string{fmt.Sprint(temp)}) }
// groupID checks to see if a group of a certain name has a given integer id func groupID(parameters []string) (exitCode int, exitMessage string) { name := parameters[0] id := wrkutils.ParseMyInt(parameters[1]) groups := getGroups() for _, g := range groups { if g.Name == name { if g.ID == id { return 0, "" } msg := "Group does not have expected ID" return wrkutils.GenericError(msg, fmt.Sprint(id), []string{fmt.Sprint(g.ID)}) } } return groupNotFound(name) }
// cpuUsage checks to see whether or not CPU usage is below a certain %. func cpuUsage(parameters []string) (exitCode int, exitMessage string) { // TODO check that parameters are in range 0 < x < 100 cpuPercentUsed := func(sampleTime time.Duration) float32 { idle0, total0 := getCPUSample() time.Sleep(sampleTime) idle1, total1 := getCPUSample() idleTicks := float32(idle1 - idle0) totalTicks := float32(total1 - total0) return (100 * (totalTicks - idleTicks) / totalTicks) } maxPercentUsed := wrkutils.ParseMyInt(parameters[0]) actualPercentUsed := cpuPercentUsed(3 * time.Second) if actualPercentUsed < float32(maxPercentUsed) { return 0, "" } msg := "CPU usage above defined maximum" slc := []string{fmt.Sprint(actualPercentUsed)} return wrkutils.GenericError(msg, fmt.Sprint(maxPercentUsed), slc) }
func diskUsage(parameters []string) (exitCode int, exitMessage string) { // percentFSUsed gets the percent of the filesystem that is occupied percentFSUsed := func(path string) int { // get FS info (*nix systems only!) var stat syscall.Statfs_t syscall.Statfs(path, &stat) // blocks * size of block = available size totalBytes := stat.Blocks * uint64(stat.Bsize) availableBytes := stat.Bavail * uint64(stat.Bsize) usedBytes := totalBytes - availableBytes percentUsed := int((float64(usedBytes) / float64(totalBytes)) * 100) return percentUsed } maxPercentUsed := wrkutils.ParseMyInt(parameters[1]) actualPercentUsed := percentFSUsed(parameters[0]) if actualPercentUsed < maxPercentUsed { return 0, "" } msg := "More disk space used than expected" slc := []string{fmt.Sprint(actualPercentUsed) + "%"} return wrkutils.GenericError(msg, fmt.Sprint(maxPercentUsed)+"%", slc) }
// port parses /proc/net/tcp to determine if a given port is in an open state // and returns an error if it is not. func port(parameters []string) (exitCode int, exitMessage string) { // getHexPorts gets all open ports as hex strings from /proc/net/tcp getHexPorts := func() (ports []string) { paths := [2]string{"/proc/net/tcp", "/proc/net/udp"} for _, path := range paths { data := wrkutils.FileToString(path) table := tabular.ProbabalisticSplit(data) // TODO by header isn't working //localAddresses := tabular.GetColumnByHeader("local_address", table) localAddresses := tabular.GetAllNoHeader(table) portRe := regexp.MustCompile(`([0-9A-F]{8}):([0-9A-F]{4})`) for _, address := range localAddresses { port := portRe.FindString(address) if port != "" { if len(port) < 10 { log.WithFields(log.Fields{ "port": port, "length": len(port), }).Fatal("Couldn't parse port number in " + path) } portString := string(port[9:]) ports = append(ports, portString) } } } return ports } // strHexToDecimal converts from string containing hex number to int strHexToDecimal := func(hex string) int { portInt, err := strconv.ParseInt(hex, 16, 64) if err != nil { log.WithFields(log.Fields{ "number": hex, "error": err.Error(), }).Fatal("Couldn't parse hex number") } return int(portInt) } // getOpenPorts gets a list of open/listening ports as integers getOpenPorts := func() (ports []int) { for _, port := range getHexPorts() { ports = append(ports, strHexToDecimal(port)) } return ports } // TODO check if it is in a valid range port := wrkutils.ParseMyInt(parameters[0]) open := getOpenPorts() for _, p := range open { if p == port { return 0, "" } } // convert ports to string to send to wrkutils.GenericError var strPorts []string for _, port := range open { strPorts = append(strPorts, fmt.Sprint(port)) } return wrkutils.GenericError("Port not open", fmt.Sprint(port), strPorts) }