def do_check_nagiosconfig(): command = [ cmk.utils.paths.nagios_binary, "-vp", cmk.utils.paths.nagios_config_file ] cmk_base.console.verbose("Running '%s'\n" % subprocess.list2cmdline(command)) cmk_base.console.output("Validating Nagios configuration...") p = subprocess.Popen( command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding="utf-8", ) stdout, stderr = p.communicate() exit_status = p.returncode if not exit_status: cmk_base.console.output(tty.ok + "\n") return True cmk_base.console.output("ERROR:\n") cmk_base.console.output(stdout, stderr) return False
def walk(self, snmp_config, oid, check_plugin_name=None, table_base_oid=None, context_name=None): # type: (SNMPHostConfig, str, Optional[str], Optional[str], Optional[str]) -> SNMPRowInfo protospec = self._snmp_proto_spec(snmp_config) ipaddress = snmp_config.ipaddress if snmp_config.is_ipv6_primary: ipaddress = "[" + ipaddress + "]" portspec = self._snmp_port_spec(snmp_config) command = self._snmp_walk_command(snmp_config, context_name) command += [ "-OQ", "-OU", "-On", "-Ot", "%s%s%s" % (protospec, ipaddress, portspec), oid ] console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command)) snmp_process = None exitstatus = None rowinfo = [] # type: SNMPRowInfo try: snmp_process = subprocess.Popen(command, close_fds=True, stdin=open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8") rowinfo = self._get_rowinfo_from_snmp_process(snmp_process) except MKTimeout: # On timeout exception try to stop the process to prevent child process "leakage" if snmp_process: os.kill(snmp_process.pid, signal.SIGTERM) snmp_process.wait() raise finally: # The stdout and stderr pipe are not closed correctly on a MKTimeout # Normally these pipes getting closed after p.communicate finishes # Closing them a second time in a OK scenario won't hurt neither.. if snmp_process: exitstatus = snmp_process.wait() if snmp_process.stderr: error = snmp_process.stderr.read() snmp_process.stderr.close() if snmp_process.stdout: snmp_process.stdout.close() if exitstatus: console.verbose(tty.red + tty.bold + "ERROR: " + tty.normal + "SNMP error: %s\n" % six.ensure_str(error).strip()) raise MKSNMPError( "SNMP Error on %s: %s (Exit-Code: %d)" % (ipaddress, six.ensure_str(error).strip(), exitstatus)) return rowinfo
def get(self, snmp_config, oid, context_name=None): # type: (SNMPHostConfig, OID, Optional[ContextName]) -> Optional[RawValue] if oid.endswith(".*"): oid_prefix = oid[:-2] commandtype = "getnext" else: oid_prefix = oid commandtype = "get" protospec = self._snmp_proto_spec(snmp_config) ipaddress = snmp_config.ipaddress if snmp_config.is_ipv6_primary: ipaddress = "[" + ipaddress + "]" portspec = self._snmp_port_spec(snmp_config) command = ( self._snmp_base_command(commandtype, snmp_config, context_name) + [ "-On", "-OQ", "-Oe", "-Ot", "%s%s%s" % (protospec, ipaddress, portspec), oid_prefix ]) console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command)) snmp_process = subprocess.Popen( command, close_fds=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8", ) exitstatus = snmp_process.wait() if snmp_process.stderr is None or snmp_process.stdout is None: raise TypeError() if exitstatus: console.verbose(tty.red + tty.bold + "ERROR: " + tty.normal + "SNMP error\n") console.verbose(snmp_process.stderr.read() + "\n") return None line = snmp_process.stdout.readline().strip() if not line: console.verbose("Error in response to snmpget.\n") return None parts = line.split("=", 1) if len(parts) != 2: return None item = parts[0] value = parts[1].strip() console.vverbose("SNMP answer: ==> [%s]\n" % value) if value.startswith('No more variables') or \ value.startswith('End of MIB') or \ value.startswith('No Such Object available') or \ value.startswith('No Such Instance currently exists'): return None # In case of .*, check if prefix is the one we are looking for if commandtype == "getnext" and not item.startswith(oid_prefix + "."): return None return strip_snmp_value(value)
def _local_automation_failure(command, cmdline, code=None, out=None, err=None, exc=None): call = subprocess.list2cmdline(cmdline) if config.debug else command msg = "Error running automation call <tt>%s<tt>" % call if code: msg += " (exit code %d)" % code if out: msg += ", output: <pre>%s</pre>" % _hilite_errors(out) if err: msg += ", error: <pre>%s</pre>" % _hilite_errors(err) if exc: msg += ": %s" % exc return MKGeneralException(msg)
def _git_command(args): command = ["git"] + [six.ensure_str(a) for a in args] logger.debug("GIT: Execute in %s: %s", cmk.utils.paths.default_config_dir, subprocess.list2cmdline(command)) try: p = subprocess.Popen(command, cwd=cmk.utils.paths.default_config_dir, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding="utf-8") except OSError as e: if e.errno == errno.ENOENT: raise MKGeneralException( _("Error executing GIT command <tt>%s</tt>:<br><br>%s") % (subprocess.list2cmdline(command), e)) raise status = p.wait() if status != 0: out = u"" if p.stdout is None else six.ensure_text(p.stdout.read()) raise MKGeneralException( _("Error executing GIT command <tt>%s</tt>:<br><br>%s") % (subprocess.list2cmdline(command), out.replace("\n", "<br>\n")))
def main(sys_argv=None): if sys_argv is None: sys_argv = sys.argv[1:] short_options = 'u:p:l:D:k:' long_options = [ 'help', 'debug', 'ipmi-command=', 'quiet-cache', 'sdr-cache-recreate', 'interpret-oem-data', 'output-sensor-state', 'ignore-not-available-sensors', 'driver-type=', 'output-sensor-thresholds' ] opt_debug = False hostname = None username = None password = None privilege_lvl = None ipmi_cmd_type = None try: opts, args = getopt.getopt(sys_argv, short_options, long_options) except getopt.GetoptError as err: sys.stderr.write("%s\n" % err) return 1 additional_opts = [] for o, a in opts: if o in ['--help']: agent_ipmi_sensors_usage() return 1 if o in ['--debug']: opt_debug = True # Common options elif o in ['--ipmi-command']: ipmi_cmd_type = a elif o in ['-u']: username = a elif o in ['-p']: password = a elif o in ['-l']: privilege_lvl = a # FreeIPMI options elif o in ['-D']: additional_opts += ["%s" % o, "%s" % a] elif o in ['--driver-type']: additional_opts += ["%s=%s" % (o, a)] elif o in ['-k']: additional_opts += ["%s" % o, "%s" % a] elif o in ['--quiet-cache']: additional_opts.append(o) elif o in ['--sdr-cache-recreate']: additional_opts.append(o) elif o in ['--interpret-oem-data']: additional_opts.append(o) elif o in ['--output-sensor-state']: additional_opts.append(o) elif o in ['--ignore-not-available-sensors']: additional_opts.append(o) elif o in ['--output-sensor-thresholds']: additional_opts.append(o) if len(args) == 1: hostname = args[0] else: sys.stderr.write("ERROR: Please specify exactly one host.\n") return 1 if not (username and password and privilege_lvl): sys.stderr.write("ERROR: Credentials are missing.\n") return 1 os.environ[ "PATH"] = "/usr/local/sbin:/usr/sbin:/sbin:" + os.environ["PATH"] if ipmi_cmd_type in [None, 'freeipmi']: ipmi_cmd = [ "ipmi-sensors", "-h", hostname, "-u", username, "-p", password, "-l", privilege_lvl ] + \ additional_opts queries = { "_sensors": ([], []) } # type: Dict[str, Tuple[List[str], List[str]]] elif ipmi_cmd_type == 'ipmitool': ipmi_cmd = [ "ipmitool", "-H", hostname, "-U", username, "-P", password, "-L", privilege_lvl ] # As in check_mk_agent queries = { "": (["sensor", "list"], ['command failed', 'discrete']), "_discrete": (["sdr", "elist", "compact"], []) } else: sys.stderr.write("ERROR: Unknown IPMI command '%s'.\n" % ipmi_cmd_type) return 1 ipmi_cmd_str = subprocess.list2cmdline(ipmi_cmd) if opt_debug: sys.stderr.write("Executing: '%s'\n" % ipmi_cmd_str) errors = [] for section, (types, excludes) in queries.items(): sys.stdout.write("<<<ipmi%s:sep(124)>>>\n" % section) try: try: p = subprocess.Popen( ipmi_cmd + types, close_fds=True, stdin=open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8", ) except OSError as e: if e.errno == errno.ENOENT: # No such file or directory raise Exception("Could not find '%s' command (PATH: %s)" % (ipmi_cmd_type, os.environ.get("PATH"))) raise stdout, stderr = p.communicate() if stderr: errors.append(stderr) parse_data(stdout.splitlines(), excludes) except Exception as e: errors.append(str(e)) if errors: msg = "ERROR: '%s'.\n" % ", ".join(errors) sys.stderr.write(six.ensure_str(msg)) return 1 return 0
def check_mk_local_automation(command, args=None, indata="", stdin_data=None, timeout=None): # type: (str, Optional[Sequence[Union[str, Text]]], Any, Optional[str], Optional[int]) -> Any if args is None: args = [] new_args = [six.ensure_str(a) for a in args] if stdin_data is None: stdin_data = repr(indata) if timeout: new_args = ["--timeout", "%d" % timeout] + new_args cmd = ['check_mk', '--automation', command] + new_args if command in ['restart', 'reload']: call_hook_pre_activate_changes() cmd = [six.ensure_str(a) for a in cmd] try: # This debug output makes problems when doing bulk inventory, because # it garbles the non-HTML response output # if config.debug: # html.write("<div class=message>Running <tt>%s</tt></div>\n" % subprocess.list2cmdline(cmd)) auto_logger.info("RUN: %s" % subprocess.list2cmdline(cmd)) p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding="utf-8") except Exception as e: raise _local_automation_failure(command=command, cmdline=cmd, exc=e) assert p.stdin is not None assert p.stdout is not None assert p.stderr is not None auto_logger.info("STDIN: %r" % stdin_data) p.stdin.write(stdin_data) p.stdin.close() outdata = p.stdout.read() exitcode = p.wait() auto_logger.info("FINISHED: %d" % exitcode) auto_logger.debug("OUTPUT: %r" % outdata) errdata = p.stderr.read() if errdata: auto_logger.warning("'%s' returned '%s'" % (" ".join(cmd), errdata)) if exitcode != 0: auto_logger.error("Error running %r (exit code %d)" % (subprocess.list2cmdline(cmd), exitcode)) raise _local_automation_failure(command=command, cmdline=cmd, code=exitcode, out=outdata, err=errdata) # On successful "restart" command execute the activate changes hook if command in ['restart', 'reload']: call_hook_activate_changes() try: return ast.literal_eval(outdata) except SyntaxError as e: raise _local_automation_failure(command=command, cmdline=cmd, out=outdata, exc=e)
def scan_parents_of(config_cache, hosts, silent=False, settings=None): # type: (config.ConfigCache, List[HostName], bool, Optional[Dict[str, int]]) -> Gateways if settings is None: settings = {} if config.monitoring_host: nagios_ip = ip_lookup.lookup_ipv4_address(config.monitoring_host) else: nagios_ip = None os.putenv("LANG", "") os.putenv("LC_ALL", "") # Start processes in parallel procs = [] # type: List[Tuple[HostName, Optional[HostAddress], Union[str, subprocess.Popen]]] for host in hosts: console.verbose("%s " % host) try: ip = ip_lookup.lookup_ipv4_address(host) if ip is None: raise RuntimeError() command = [ "traceroute", "-w", "%d" % settings.get("timeout", 8), "-q", "%d" % settings.get("probes", 2), "-m", "%d" % settings.get("max_ttl", 10), "-n", ip ] console.vverbose("Running '%s'\n" % subprocess.list2cmdline(command)) procs.append((host, ip, subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True, encoding="utf-8"))) except Exception as e: if cmk.utils.debug.enabled(): raise procs.append((host, None, "ERROR: %s" % e)) # Output marks with status of each single scan def dot(color, dot='o'): # type: (str, str) -> None if not silent: console.output(tty.bold + color + dot + tty.normal) # Now all run and we begin to read the answers. For each host # we add a triple to gateways: the gateway, a scan state and a diagnostic output gateways = [] # type: Gateways for host, ip, proc_or_error in procs: if isinstance(proc_or_error, six.string_types): lines = [proc_or_error] exitstatus = 1 else: exitstatus = proc_or_error.wait() if proc_or_error.stdout is None: raise RuntimeError() lines = [l.strip() for l in proc_or_error.stdout.readlines()] if exitstatus: dot(tty.red, '*') gateways.append( (None, "failed", 0, "Traceroute failed with exit code %d" % (exitstatus & 255))) continue if len(lines) == 1 and lines[0].startswith("ERROR:"): message = lines[0][6:].strip() console.verbose("%s: %s\n", host, message, stream=sys.stderr) dot(tty.red, "D") gateways.append((None, "dnserror", 0, message)) continue if len(lines) == 0: if cmk.utils.debug.enabled(): raise MKGeneralException( "Cannot execute %s. Is traceroute installed? Are you root?" % command) dot(tty.red, '!') continue if len(lines) < 2: if not silent: console.error("%s: %s\n" % (host, ' '.join(lines))) gateways.append((None, "garbled", 0, "The output of traceroute seem truncated:\n%s" % ("".join(lines)))) dot(tty.blue) continue # Parse output of traceroute: # traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 40 byte packets # 1 * * * # 2 10.0.0.254 0.417 ms 0.459 ms 0.670 ms # 3 172.16.0.254 0.967 ms 1.031 ms 1.544 ms # 4 217.0.116.201 23.118 ms 25.153 ms 26.959 ms # 5 217.0.76.134 32.103 ms 32.491 ms 32.337 ms # 6 217.239.41.106 32.856 ms 35.279 ms 36.170 ms # 7 74.125.50.149 45.068 ms 44.991 ms * # 8 * 66.249.94.86 41.052 ms 66.249.94.88 40.795 ms # 9 209.85.248.59 43.739 ms 41.106 ms 216.239.46.240 43.208 ms # 10 216.239.48.53 45.608 ms 47.121 ms 64.233.174.29 43.126 ms # 11 209.85.255.245 49.265 ms 40.470 ms 39.870 ms # 12 8.8.8.8 28.339 ms 28.566 ms 28.791 ms routes = [] # type: List[Optional[str]] for line in lines[1:]: parts = line.split() route = parts[1] if route.count('.') == 3: routes.append(route) elif route == '*': routes.append(None) # No answer from this router else: if not silent: console.error("%s: invalid output line from traceroute: '%s'\n" % (host, line)) if len(routes) == 0: error = "incomplete output from traceroute. No routes found." console.error("%s: %s\n" % (host, error)) gateways.append((None, "garbled", 0, error)) dot(tty.red) continue # Only one entry -> host is directly reachable and gets nagios as parent - # if nagios is not the parent itself. Problem here: How can we determine # if the host in question is the monitoring host? The user must configure # this in monitoring_host. if len(routes) == 1: if ip == nagios_ip: gateways.append((None, "root", 0, "")) # We are the root-monitoring host dot(tty.white, 'N') elif config.monitoring_host: gateways.append(((config.monitoring_host, nagios_ip, None), "direct", 0, "")) dot(tty.cyan, 'L') else: gateways.append((None, "direct", 0, "")) continue # Try far most route which is not identical with host itself ping_probes = settings.get("ping_probes", 5) skipped_gateways = 0 this_route = None # type: Optional[HostAddress] for r in routes[::-1]: if not r or (r == ip): continue # Do (optional) PING check in order to determine if that # gateway can be monitored via the standard host check if ping_probes: if not gateway_reachable_via_ping(r, ping_probes): console.verbose("(not using %s, not reachable)\n", r, stream=sys.stderr) skipped_gateways += 1 continue this_route = r break if not this_route: error = "No usable routing information" if not silent: console.error("%s: %s\n" % (host, error)) gateways.append((None, "notfound", 0, error)) dot(tty.blue) continue # TTLs already have been filtered out) gateway_ip = this_route gateway = _ip_to_hostname(config_cache, this_route) if gateway: console.verbose("%s(%s) ", gateway, gateway_ip) else: console.verbose("%s ", gateway_ip) # Try to find DNS name of host via reverse DNS lookup dns_name = _ip_to_dnsname(gateway_ip) gateways.append(((gateway, gateway_ip, dns_name), "gateway", skipped_gateways, "")) dot(tty.green, 'G') return gateways