def translate(lines): # type: (List[bytes]) -> List[Tuple[bytes, bytes]] result_lines = [] try: oids_for_command = [] for line in lines: oids_for_command.append(line.split(" ")[0]) command = [ "snmptranslate", "-m", "ALL", "-M+%s" % cmk.utils.paths.local_mib_dir ] + oids_for_command p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=open(os.devnull, "w"), close_fds=True) p.wait() if p.stdout is None: raise RuntimeError() output = p.stdout.read() result = output.split("\n")[0::2] for idx, line in enumerate(result): result_lines.append((line.strip(), lines[idx].strip())) except Exception as e: console.error("%s\n" % e) return result_lines
def load_plugins(get_check_api_context, get_inventory_context): # type: (config.GetCheckApiContext, config.GetInventoryApiContext) -> None loaded_files = set() # type: Set[str] filelist = config.get_plugin_paths( str(cmk.utils.paths.local_inventory_dir), cmk.utils.paths.inventory_dir) for f in filelist: if f[0] == "." or f[-1] == "~": continue # ignore editor backup / temp files file_name = os.path.basename(f) if file_name in loaded_files: continue # skip already loaded files (e.g. from local) try: plugin_context = _new_inv_context(get_check_api_context, get_inventory_context) known_plugins = inv_info _load_plugin_includes(f, plugin_context) exec(open(f).read(), plugin_context) loaded_files.add(file_name) except Exception as e: console.error("Error in inventory plugin file %s: %s\n", f, e) if cmk.utils.debug.enabled(): raise continue # Now store the check context for all plugins found in this file for check_plugin_name in set(inv_info).difference(known_plugins): _plugin_contexts[check_plugin_name] = plugin_context
def _execute_walks_for_dump(snmp_config, oids): for oid in oids: try: console.verbose("Walk on \"%s\"..." % oid) yield walk_for_export(snmp_config, oid) except Exception as e: console.error("Error: %s\n" % e) if cmk.utils.debug.enabled(): raise
def _load_plugin_includes(check_file_path, plugin_context): for name in config.includes_of_plugin(check_file_path): path = _include_file_path(name) try: exec(open(path).read(), plugin_context) except Exception as e: console.error("Error in include file %s: %s\n", path, e) if cmk.utils.debug.enabled(): raise
def _execute_walks_for_dump(snmp_config, oids): # type: (SNMPHostConfig, List[OID]) -> Iterable[SNMPRowInfo] for oid in oids: try: console.verbose("Walk on \"%s\"..." % oid) yield walk_for_export(snmp_config, oid) except Exception as e: console.error("Error: %s\n" % e) if cmk.utils.debug.enabled(): raise
def do_update(core, with_precompile): try: do_create_config(core, with_agents=with_precompile) if with_precompile: core.precompile() except Exception as e: console.error("Configuration Error: %s\n" % e) if cmk.utils.debug.enabled(): raise sys.exit(1)
def precompile_hostchecks(): console.verbose("Creating precompiled host check config...\n") config.PackedConfig().save() if not os.path.exists(cmk.utils.paths.precompiled_hostchecks_dir): os.makedirs(cmk.utils.paths.precompiled_hostchecks_dir) config_cache = config.get_config_cache() console.verbose("Precompiling host checks...\n") for host in config_cache.all_active_hosts(): try: _precompile_hostcheck(config_cache, host) except Exception as e: if cmk.utils.debug.enabled(): raise console.error("Error precompiling checks for host %s: %s\n" % (host, e)) sys.exit(5)
def gather_snmp_check_plugin_names(host_config, on_error, do_snmp_scan, for_inventory=False, for_mgmt_board=False): check_plugin_names = set() try: check_plugin_names.update( _snmp_scan(host_config, on_error=on_error, do_snmp_scan=do_snmp_scan, for_inv=for_inventory, for_mgmt_board=for_mgmt_board)) except Exception as e: if on_error == "raise": raise elif on_error == "warn": console.error("SNMP scan failed: %s\n" % e) return list(check_plugin_names)
def execute(self, cmd, args): # type: (str, List[str]) -> Any self._handle_generic_arguments(args) try: try: automation = self._automations[cmd] except KeyError: raise MKAutomationError( "Automation command '%s' is not implemented." % cmd) if automation.needs_checks: config.load_all_checks(check_api.get_check_api_context) if automation.needs_config: config.load(validate_hosts=False) result = automation.execute(args) except (MKAutomationError, MKTimeout) as e: console.error("%s\n" % e) if cmk.utils.debug.enabled(): raise return 1 except Exception as e: if cmk.utils.debug.enabled(): raise console.error("%s\n" % e) return 2 finally: profiling.output_profile() if cmk.utils.debug.enabled(): console.output(pprint.pformat(result) + "\n") else: console.output("%r\n" % (result, )) return 0
def gather_snmp_check_plugin_names(host_config, on_error, do_snmp_scan, for_inventory=False, for_mgmt_board=False): # type: (SNMPHostConfig, str, bool, bool, bool) -> Set[CheckPluginName] check_plugin_names = set() # type: Set[CheckPluginName] try: check_plugin_names.update( _snmp_scan(host_config, on_error=on_error, do_snmp_scan=do_snmp_scan, for_inv=for_inventory, for_mgmt_board=for_mgmt_board)) except Exception as e: if on_error == "raise": raise if on_error == "warn": console.error("SNMP scan failed: %s\n" % e) return check_plugin_names
def do_snmptranslate(walk_filename): # type: (str) -> None if not walk_filename: raise MKGeneralException("Please provide the name of a SNMP walk file") walk_path = "%s/%s" % (cmk.utils.paths.snmpwalks_dir, walk_filename) if not os.path.exists(walk_path): raise MKGeneralException("The walk '%s' does not exist" % walk_path) def translate(lines): # type: (List[bytes]) -> List[Tuple[bytes, bytes]] result_lines = [] try: oids_for_command = [] for line in lines: oids_for_command.append(line.split(b" ")[0]) command = [ b"snmptranslate", b"-m", b"ALL", b"-M+%s" % cmk.utils.paths.local_mib_dir ] + oids_for_command p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=open(os.devnull, "w"), close_fds=True) p.wait() if p.stdout is None: raise RuntimeError() output = p.stdout.read() result = output.split(b"\n")[0::2] for idx, line in enumerate(result): result_lines.append((line.strip(), lines[idx].strip())) except Exception as e: console.error("%s\n" % e) return result_lines # Translate n-oid's per cycle entries_per_cycle = 500 translated_lines = [] # type: List[Tuple[bytes, bytes]] walk_lines = open(walk_path).readlines() console.error("Processing %d lines.\n" % len(walk_lines)) i = 0 while i < len(walk_lines): console.error("\r%d to go... " % (len(walk_lines) - i)) process_lines = walk_lines[i:i + entries_per_cycle] # FIXME: This encoding ping-pong os horrible... translated = translate([six.ensure_binary(pl) for pl in process_lines]) i += len(translated) translated_lines += translated console.error("\rfinished. \n") # Output formatted for translation, line in translated_lines: console.output("%s --> %s\n" % (six.ensure_str(line), six.ensure_str(translation)))
def do_snmpwalk(options, hostnames): # type: (SNMPWalkOptions, List[HostName]) -> None if "oids" in options and "extraoids" in options: raise MKGeneralException("You cannot specify --oid and --extraoid at the same time.") if not hostnames: raise MKBailOut("Please specify host names to walk on.") if not os.path.exists(cmk.utils.paths.snmpwalks_dir): os.makedirs(cmk.utils.paths.snmpwalks_dir) for hostname in hostnames: #TODO: What about SNMP management boards? snmp_config = create_snmp_host_config(hostname) try: _do_snmpwalk_on(snmp_config, options, cmk.utils.paths.snmpwalks_dir + "/" + hostname) except Exception as e: console.error("Error walking %s: %s\n" % (hostname, e)) if cmk.utils.debug.enabled(): raise cmk.base.cleanup.cleanup_globals()
def do_snmptranslate(walk_filename): if not walk_filename: raise MKGeneralException("Please provide the name of a SNMP walk file") walk_path = "%s/%s" % (cmk.utils.paths.snmpwalks_dir, walk_filename) if not os.path.exists(walk_path): raise MKGeneralException("The walk '%s' does not exist" % walk_path) def translate(lines): result_lines = [] try: oids_for_command = [] for line in lines: oids_for_command.append(line.split(" ")[0]) command = [ "snmptranslate", "-m", "ALL", "-M+%s" % cmk.utils.paths.local_mib_dir ] + oids_for_command p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=open(os.devnull, "w"), close_fds=True) p.wait() output = p.stdout.read() result = output.split("\n")[0::2] for idx, line in enumerate(result): result_lines.append((line.strip(), lines[idx].strip())) except Exception as e: console.error("%s\n" % e) return result_lines # Translate n-oid's per cycle entries_per_cycle = 500 translated_lines = [] walk_lines = open(walk_path).readlines() console.error("Processing %d lines.\n" % len(walk_lines)) i = 0 while i < len(walk_lines): console.error("\r%d to go... " % (len(walk_lines) - i)) process_lines = walk_lines[i:i + entries_per_cycle] translated = translate(process_lines) i += len(translated) translated_lines += translated console.error("\rfinished. \n") # Output formatted for translation, line in translated_lines: console.output("%s --> %s\n" % (line, translation))
def do_restart(core, only_reload=False): # type: (MonitoringCore, bool) -> None try: backup_path = None if try_get_activation_lock(): # TODO: Replace by MKBailOut()/MKTerminate()? console.error("Other restart currently in progress. Aborting.\n") sys.exit(1) # Save current configuration if os.path.exists(cmk.utils.paths.nagios_objects_file): backup_path = cmk.utils.paths.nagios_objects_file + ".save" console.verbose("Renaming %s to %s\n", cmk.utils.paths.nagios_objects_file, backup_path, stream=sys.stderr) os.rename(cmk.utils.paths.nagios_objects_file, backup_path) else: backup_path = None try: core_config.do_create_config(core, with_agents=True) except Exception as e: # TODO: Replace by MKBailOut()/MKTerminate()? console.error("Error creating configuration: %s\n" % e) if backup_path: os.rename(backup_path, cmk.utils.paths.nagios_objects_file) if cmk.utils.debug.enabled(): raise sys.exit(1) if config.monitoring_core == "cmc" or cmk.base.nagios_utils.do_check_nagiosconfig( ): if backup_path: os.remove(backup_path) core.precompile() do_core_action(only_reload and "reload" or "restart") else: # TODO: Replace by MKBailOut()/MKTerminate()? console.error( "Configuration for monitoring core is invalid. Rolling back.\n" ) broken_config_path = "%s/check_mk_objects.cfg.broken" % cmk.utils.paths.tmp_dir open(broken_config_path, "w").write(open(cmk.utils.paths.nagios_objects_file).read()) console.error( "The broken file has been copied to \"%s\" for analysis.\n" % broken_config_path) if backup_path: os.rename(backup_path, cmk.utils.paths.nagios_objects_file) else: os.remove(cmk.utils.paths.nagios_objects_file) sys.exit(1) except Exception as e: if backup_path: try: os.remove(backup_path) except OSError as oe: if oe.errno != errno.ENOENT: raise if cmk.utils.debug.enabled(): raise # TODO: Replace by MKBailOut()/MKTerminate()? console.error("An error occurred: %s\n" % e) sys.exit(1)
def scan_parents_of(config_cache, hosts, silent=False, settings=None): 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 = [] for host in hosts: console.verbose("%s " % host) try: ip = ip_lookup.lookup_ipv4_address(host) 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))) 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'): 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 = [] 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() 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 elif len(lines) == 0: if cmk.utils.debug.enabled(): raise MKGeneralException( "Cannot execute %s. Is traceroute installed? Are you root?" % command) else: dot(tty.red, '!') continue elif 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 = [] 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. elif 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 route = None 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 route = r break if not 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 = route gateway = _ip_to_hostname(config_cache, 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