def _get_agent_info_program(self, commandline, command_stdin): exepath = commandline.split()[0] # for error message, hide options! self._logger.debug("Calling external program %r" % (commandline)) p = None try: if config.monitoring_core == "cmc": p = subprocess.Popen( # nosec commandline, shell=True, stdin=subprocess.PIPE if command_stdin else open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid, close_fds=True, encoding="utf-8", ) else: # We can not create a separate process group when running Nagios # Upon reaching the service_check_timeout Nagios only kills the process # group of the active check. p = subprocess.Popen( # nosec commandline, shell=True, stdin=subprocess.PIPE if command_stdin else open(os.devnull), stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, encoding="utf-8", ) if command_stdin: stdout, stderr = p.communicate(input=ensure_unicode(command_stdin)) else: stdout, stderr = p.communicate() exitstatus = p.returncode except MKTimeout: # On timeout exception try to stop the process to prevent child process "leakage" if p: os.killpg(os.getpgid(p.pid), signal.SIGTERM) p.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 p: p.stdout.close() p.stderr.close() if exitstatus: if exitstatus == 127: raise MKAgentError("Program '%s' not found (exit code 127)" % exepath) else: raise MKAgentError("Agent exited with code %d: %s" % (exitstatus, stderr)) return stdout
def _execute(self): connection = None try: connection = self._create_ipmi_connection() output = "" output += self._fetch_ipmi_sensors_section(connection) output += self._fetch_ipmi_firmware_section(connection) return output except Exception as e: if cmk.utils.debug.enabled(): raise # Improve bad exceptions thrown by pyghmi e.g. in case of connection issues if isinstance(e, IpmiException) and "%s" % e == "None": raise MKAgentError("IPMI communication failed: %r" % e) else: raise finally: if connection: connection.ipmi_session.logout()
def _get_raw_data(self): """Returns the current raw data of this data source It either uses previously cached raw data of this data source or executes the data source to get new data. The "raw data" is the raw byte string returned by the source for CheckMKAgentDataSource sources. The SNMPDataSource source already return the final info data structure. """ raw_data = self._read_cache_file() if raw_data: self._logger.log(VERBOSE, "Use cached data") return raw_data, True elif raw_data is None and config.simulation_mode: raise MKAgentError("Got no data (Simulation mode enabled and no cachefile present)") self._logger.log(VERBOSE, "Execute data source") raw_data = self._execute() self._write_cache_file(raw_data) return raw_data, False
def _execute(self): if self._use_only_cache: raise MKAgentError("Got no data: No usable cache file present at %s" % self._cache_file_path()) self._verify_ipaddress() port = self._get_port() encryption_settings = self._host_config.agent_encryption socktype = (socket.AF_INET6 if self._host_config.is_ipv6_primary else socket.AF_INET) s = socket.socket(socktype, socket.SOCK_STREAM) timeout = self._get_timeout() output = [] self._logger.debug("Connecting via TCP to %s:%d (%ss timeout)" % (self._ipaddress, port, timeout)) try: s.settimeout(timeout) s.connect((self._ipaddress, port)) s.settimeout(None) self._logger.debug("Reading data from agent") while True: data = s.recv(4096, socket.MSG_WAITALL) if data and len(data) > 0: output.append(data) else: break except MKTerminate: raise except socket.error as e: if cmk.utils.debug.enabled(): raise raise MKAgentError("Communication failed: %s" % e) finally: s.close() output = ''.join(output) if len(output) == 0: # may be caused by xinetd not allowing our address raise MKEmptyAgentData("Empty output from agent at TCP port %d" % port) elif len(output) < 16: raise MKAgentError("Too short output from agent: %r" % output) output_is_plaintext = output.startswith("<<<") if encryption_settings["use_regular"] == "enforce" and output_is_plaintext: raise MKAgentError( "Agent output is plaintext but encryption is enforced by configuration") if not output_is_plaintext and encryption_settings["use_regular"] in ["enforce", "allow"]: try: # simply check if the protocol is an actual number protocol = int(output[0:2]) output = self._decrypt_package(output[2:], encryption_settings["passphrase"], protocol) except ValueError: raise MKAgentError("Unsupported protocol version: %s" % output[:2]) except Exception as e: if encryption_settings["use_regular"] == "enforce": raise MKAgentError("Failed to decrypt agent output: %s" % e) else: # of course the package might indeed have been encrypted but # in an incorrect format, but how would we find that out? # In this case processing the output will fail pass return output