예제 #1
0
// phpConfig checks the value of a PHP configuration variable
func phpConfig(parameters []string) (exitCode int, exitMessage string) {
	// 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 {
			wrkutils.ExecError(cmd, string(out), err)
		}
		return string(out)
	}
	name := parameters[0]
	value := parameters[1]
	actualValue := getPHPVariable(name)
	if actualValue == value {
		return 0, ""
	} else if actualValue == "" {
		msg := "PHP configuration variable not set"
		return wrkutils.GenericError(msg, value, []string{actualValue})
	}
	msg := "PHP variable did not match expected value"
	return wrkutils.GenericError(msg, value, []string{actualValue})
}
예제 #2
0
// getIPWorker(exitCode int, exitMessage string) is an abstraction of Ip4 and Ip6
func getIPWorker(name string, address string, version int) (exitCode int, exitMessage string) {
	ips := getInterfaceIPs(name, version)
	if tabular.StrIn(address, ips) {
		return 0, ""
	}
	return wrkutils.GenericError("Interface does not have IP", address, ips)
}
예제 #3
0
// routingTableMatch(exitCode int, exitMessage string) constructs a Worker that returns whether or not the
// given string was found in the given column of the routing table. It is an
// astraction of routingTableDestination, routingTableInterface, and
// routingTableGateway
func routingTableMatch(col string, str string) (exitCode int, exitMessage string) {
	column := routingTableColumn(col)
	if tabular.StrIn(str, column) {
		return 0, ""
	}
	return wrkutils.GenericError("Not found in routing table", str, column)
}
예제 #4
0
// timers(exitCode int, exitMessage string) is pure DRY for systemctlTimer and systemctlTimerLoaded
func timersWorker(unit string, all bool) (exitCode int, exitMessage string) {
	timers := getTimers(all)
	if tabular.StrIn(unit, timers) {
		return 0, ""
	}
	return wrkutils.GenericError("Timer not found", unit, timers)
}
예제 #5
0
// systemctlUnitFileStatus checks whether or not the given unit file has the
// given status: static | enabled | disabled
func systemctlUnitFileStatus(parameters []string) (exitCode int, exitMessage string) {
	// getUnitFilesWithStatuses returns a pair of string slices that hold
	// the name of unit files with their current statuses.
	getUnitFilesWithStatuses := func() (units []string, statuses []string) {
		cmd := exec.Command("systemctl", "--no-pager", "list-unit-files")
		units = wrkutils.CommandColumnNoHeader(0, cmd)
		cmd = exec.Command("systemctl", "--no-pager", "list-unit-files")
		statuses = wrkutils.CommandColumnNoHeader(1, cmd)
		// last two are empty line and junk statistics we don't care about
		msg := fmt.Sprint(cmd.Args) + " didn't output enough lines"
		wrkutils.IndexError(msg, 2, units)
		wrkutils.IndexError(msg, 2, statuses)
		return units[:len(units)-2], statuses[:len(statuses)-2]
	}
	unit := parameters[0]
	status := parameters[1]
	units, statuses := getUnitFilesWithStatuses()
	var actualStatus string
	// TODO check if unit could be found at all
	for i, un := range units {
		if un == unit {
			actualStatus = statuses[i]
			if actualStatus == status {
				return 0, ""
			}
		}
	}
	msg := "Unit didn't have status"
	return wrkutils.GenericError(msg, status, []string{actualStatus})
}
예제 #6
0
// 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})

}
예제 #7
0
// groupNotFound creates generic error messages and exit codes for groupExits,
// userInGroup, and groupID
func groupNotFound(name string) (int, string) {
	// get a nicely formatted list of groups that do exist
	var existing []string
	for _, group := range getGroups() {
		existing = append(existing, group.Name)
	}
	return wrkutils.GenericError("Group not found", name, existing)
}
예제 #8
0
// responseMatchesGeneral is an abstraction of responseMatches and
// responseMatchesInsecure that simply varies in the security of the connection
func responseMatchesGeneral(parameters []string, secure bool) (exitCode int, exitMessage string) {
	urlstr := parameters[0]
	re := wrkutils.ParseUserRegex(parameters[1])
	body := wrkutils.URLToBytes(urlstr, secure)
	if re.Match(body) {
		return 0, ""
	}
	msg := "Response didn't match regexp"
	return wrkutils.GenericError(msg, re.String(), []string{string(body)})
}
예제 #9
0
// 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)
}
예제 #10
0
// systemctlSock is an abstraction of systemctlSockPath and systemctlSockUnit,
// it reads from `systemctl list-sockets` and sees if the value is in the
// appropriate column.
func systemctlSock(value string, column string) (exitCode int, exitMessage string) {
	outstr := wrkutils.CommandOutput(exec.Command("systemctl", "list-sockets"))
	lines := tabular.Lines(outstr)
	msg := "systemctl list-sockers didn't output enough rows"
	wrkutils.IndexError(msg, len(lines)-4, lines)
	unlines := tabular.Unlines(lines[:len(lines)-4])
	table := tabular.SeparateOnAlignment(unlines)
	values := tabular.GetColumnByHeader(column, table)
	if tabular.StrIn(value, values) {
		return 0, ""
	}
	return wrkutils.GenericError("Socket not found", value, values)
}
예제 #11
0
// userInGroup checks whether or not a given user is in a given group
func userInGroup(parameters []string) (exitCode int, exitMessage string) {
	user := parameters[0]
	group := parameters[0]
	groups := getGroups()
	for _, g := range groups {
		if g.Name == group {
			if tabular.StrIn(user, g.Users) {
				return 0, ""
			}
			return wrkutils.GenericError("User not found in group", user, g.Users)
		}
	}
	return groupNotFound(group)
}
예제 #12
0
// commandOutputMatches checks to see if a command's combined output matches a
// given regexp
func commandOutputMatches(parameters []string) (exitCode int, exitMessage string) {
	toExec := parameters[0]
	re := wrkutils.ParseUserRegex(parameters[1])
	cmd := exec.Command("bash", "-c", toExec)
	out, err := cmd.CombinedOutput()
	if err != nil {
		wrkutils.ExecError(cmd, string(out), err)
	}
	if re.Match(out) {
		return 0, ""
	}
	msg := "Command output did not match regexp"
	return wrkutils.GenericError(msg, re.String(), []string{string(out)})
}
예제 #13
0
// module checks to see if a kernel module is installed
func module(parameters []string) (exitCode int, exitMessage string) {
	// 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 wrkutils.CommandColumnNoHeader(0, cmd)
	}
	name := parameters[0]
	modules := kernelModules()
	if tabular.StrIn(name, modules) {
		return 0, ""
	}
	return wrkutils.GenericError("Module is not loaded", name, modules)
}
예제 #14
0
// permissions checks to see if a file's octal permissions match the given set
func permissions(parameters []string) (exitCode int, exitMessage string) {
	path := parameters[0]
	givenMode := parameters[1]
	finfo, err := os.Stat(path)
	if err != nil {
		wrkutils.CouldntReadError(path, err)
	}
	actualMode := fmt.Sprint(finfo.Mode().Perm()) // -rwxrw-r-- format
	if actualMode == givenMode {
		return 0, ""
	}
	msg := "File modes did not match"
	return wrkutils.GenericError(msg, givenMode, []string{actualMode})
}
예제 #15
0
// 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)})
}
예제 #16
0
// 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)
}
예제 #17
0
// systemctlService checks to see if a service has a givens status
// status: active | loaded
func systemctlService(service string, activeOrLoaded string) (exitCode int, exitMessage string) {
	// cmd depends on whether we're checking active or loaded
	cmd := exec.Command("systemctl", "show", "-p", "ActiveState", service)
	if activeOrLoaded == "loaded" {
		cmd = exec.Command("systemctl", "show", "-p", "LoadState", service)
	}
	outString := wrkutils.CommandOutput(cmd)
	contained := "ActiveState=active"
	if activeOrLoaded == "loaded" {
		contained = "LoadState=loaded"
	}
	if strings.Contains(outString, contained) {
		return 0, ""
	}
	msg := "Service not " + activeOrLoaded
	return wrkutils.GenericError(msg, service, []string{outString})
}
예제 #18
0
// interfaceExists detects if a network interface exists,
func interfaceExists(parameters []string) (exitCode int, exitMessage string) {
	// getInterfaceNames returns the names of all network interfaces
	getInterfaceNames := func() (interfaces []string) {
		for _, iface := range getInterfaces() {
			interfaces = append(interfaces, iface.Name)
		}
		return
	}
	name := parameters[0]
	interfaces := getInterfaceNames()
	for _, iface := range interfaces {
		if iface == name {
			return 0, ""
		}
	}
	return wrkutils.GenericError("Interface does not exist", name, interfaces)
}
예제 #19
0
// up determines if a network interface is up and running or not
func up(parameters []string) (exitCode int, exitMessage string) {
	// getUpInterfaces returns all the names of the interfaces that are up
	getUpInterfaces := func() (interfaceNames []string) {
		for _, iface := range getInterfaces() {
			if iface.Flags&net.FlagUp != 0 {
				interfaceNames = append(interfaceNames, iface.Name)
			}
		}
		return interfaceNames

	}
	name := parameters[0]
	upInterfaces := getUpInterfaces()
	if tabular.StrIn(name, upInterfaces) {
		return 0, ""
	}
	return wrkutils.GenericError("Interface is not up", name, upInterfaces)
}
예제 #20
0
// pacmanIgnore checks to see whether a given package is in /etc/pacman.conf's
// IgnorePkg setting
func pacmanIgnore(parameters []string) (exitCode int, exitMessage string) {
	pkg := parameters[0]
	path := "/etc/pacman.conf"
	data := wrkutils.FileToString(path)
	re := regexp.MustCompile(`[^#]IgnorePkg\s+=\s+.+`)
	find := re.FindString(data)
	var packages []string
	if find != "" {
		spl := strings.Split(find, " ")
		wrkutils.IndexError("Not enough lines in "+path, 2, spl)
		packages = spl[2:] // first two are "IgnorePkg" and "="
		if tabular.StrIn(pkg, packages) {
			return 0, ""
		}
	}
	msg := "Couldn't find package in IgnorePkg"
	return wrkutils.GenericError(msg, pkg, packages)
}
예제 #21
0
// 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)
}
예제 #22
0
// gateway checks to see that the default gateway has a certain IP
func gateway(parameters []string) (exitCode int, exitMessage string) {
	// getGatewayAddress filters all gateway IPs for a non-zero value
	getGatewayAddress := func() (addr string) {
		ips := routingTableColumn("Gateway")
		for _, ip := range ips {
			if ip != "0.0.0.0" {
				return ip
			}
		}
		return "0.0.0.0"
	}
	address := parameters[0]
	gatewayIP := getGatewayAddress()
	if address == gatewayIP {
		return 0, ""
	}
	msg := "Gateway does not have address"
	return wrkutils.GenericError(msg, address, []string{gatewayIP})
}
예제 #23
0
// running checks if a process is running using `ps aux`, and searching for the
// process name, excluding this process (in case the process name is in the JSON
// file name)
func running(parameters []string) (exitCode int, exitMessage string) {
	// getRunningCommands returns the entries in the "COMMAND" column of `ps aux`
	getRunningCommands := func() (commands []string) {
		cmd := exec.Command("ps", "aux")
		return wrkutils.CommandColumnNoHeader(10, cmd)
	}
	proc := parameters[0]
	// remove this process from consideration
	commands := getRunningCommands()
	var filtered []string
	for _, cmd := range commands {
		if !strings.Contains(cmd, "distributive") {
			filtered = append(filtered, cmd)
		}
	}
	if tabular.StrIn(proc, filtered) {
		return 0, ""
	}
	return wrkutils.GenericError("Process not running", proc, filtered)
}
예제 #24
0
// checksum checks the hash of a given file using the given algorithm
func checksum(parameters []string) (exitCode int, exitMessage string) {
	// getChecksum returns the checksum of some data, using a specified
	// algorithm
	getChecksum := func(algorithm string, data []byte) (checksum string) {
		algorithm = strings.ToUpper(algorithm)
		// default
		hasher := md5.New()
		switch algorithm {
		case "SHA1":
			hasher = sha1.New()
		case "SHA224":
			hasher = sha256.New224()
		case "SHA256":
			hasher = sha256.New()
		case "SHA384":
			hasher = sha512.New384()
		case "SHA512":
			hasher = sha512.New()
		}
		hasher.Write(data)
		str := hex.EncodeToString(hasher.Sum(nil))
		return str

	}
	// getFileChecksum is self-explanatory
	getFileChecksum := func(algorithm string, path string) (checksum string) {
		return getChecksum(algorithm, wrkutils.FileToBytes(path))
	}

	algorithm := parameters[0]
	checkAgainst := parameters[1]
	path := parameters[2]
	chksum := getFileChecksum(algorithm, path)
	// TODO warn on unequal lengths
	if chksum == checkAgainst {
		return 0, ""
	}
	msg := "Checksums do not match for file: " + path
	return wrkutils.GenericError(msg, checkAgainst, []string{chksum})
}
예제 #25
0
// existsRepoWithProperty is an abstraction of YumRepoExists and YumRepoURL.
// It takes a struct field name to check, and an expected value. If the expected
// value is found in the field of a repo, it returns 0, "" else an error message.
// Valid choices for prop: "URL" | "Name" | "Name"
func existsRepoWithProperty(prop string, val *regexp.Regexp, manager string) (int, string) {
	var properties []string
	for _, repo := range getRepos(manager) {
		switch prop {
		case "URL":
			properties = append(properties, repo.URL)
		case "Name":
			properties = append(properties, repo.Name)
		case "Status":
			properties = append(properties, repo.Status)
		case "ID":
			properties = append(properties, repo.ID)
		default:
			log.Fatal("Repos don't have the requested property: " + prop)
		}
	}
	if tabular.ReIn(val, properties) {
		return 0, ""
	}
	msg := "Repo with given " + prop + " not found"
	return wrkutils.GenericError(msg, val.String(), properties)
}
예제 #26
0
// gatewayInterface checks that the default gateway is using a specified interface
func gatewayInterface(parameters []string) (exitCode int, exitMessage string) {
	// getGatewayInterface returns the interface that the default gateway is
	// operating on
	getGatewayInterface := func() (iface string) {
		ips := routingTableColumn("Gateway")
		names := routingTableColumn("Iface")
		for i, ip := range ips {
			if ip != "0.0.0.0" {
				msg := "Fewer names in kernel routing table than IPs"
				wrkutils.IndexError(msg, i, names)
				return names[i] // interface name
			}
		}
		return ""
	}
	name := parameters[0]
	iface := getGatewayInterface()
	if name == iface {
		return 0, ""
	}
	msg := "Default gateway does not operate on interface"
	return wrkutils.GenericError(msg, name, []string{iface})
}
예제 #27
0
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)
}
예제 #28
0
// 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)
}