def __handle_connection_error(self, host, request, reason): msg = "Unable to connect to {node} ({reason})" self._logger.debug(msg.format(node=host, reason=reason)) self._reporter.process( reports.node_communication_not_connected(host, reason) ) raise NodeConnectionException(host, request, reason)
def _log_response_failure(self, response): msg = "Unable to connect to {node} ({reason})" self._logger.debug( msg.format(node=response.request.host_label, reason=response.error_msg)) self._reporter.report( reports.node_communication_not_connected( response.request.host_label, response.error_msg)) if is_proxy_set(os.environ): self._logger.warning("Proxy is set") self._reporter.report( reports.node_communication_proxy_is_set( response.request.host_label, response.request.dest.addr, ))
def _log_response_failure(self, response): msg = "Unable to connect to {node} ({reason})" self._logger.debug(msg.format( node=response.request.host_label, reason=response.error_msg )) self._reporter.process( reports.node_communication_not_connected( response.request.host_label, response.error_msg ) ) if is_proxy_set(os.environ): self._logger.warning("Proxy is set") self._reporter.process(reports.node_communication_proxy_is_set( response.request.host_label, response.request.dest.addr, ))
def call_host(self, host, request, data): """ Send a request to a host host host address request command to be run on the host data command parameters, encoded by format_data_* method """ opener = self.__get_opener() url = "https://{host}:2224/{request}".format( host=("[{0}]".format(host) if ":" in host else host), request=request) cookies = self.__prepare_cookies(host) if cookies: opener.addheaders.append(("Cookie", ";".join(cookies))) msg = "Sending HTTP Request to: {url}" if data: msg += "\n--Debug Input Start--\n{data}\n--Debug Input End--" self._logger.debug(msg.format(url=url, data=data)) self._reporter.process(reports.node_communication_started(url, data)) result_msg = ( "Finished calling: {url}\nResponse Code: {code}" + "\n--Debug Response Start--\n{response}\n--Debug Response End--") try: # python3 requires data to be bytes not str if data: data = data.encode("utf-8") result = opener.open(url, data) # python3 returns bytes not str response_data = result.read().decode("utf-8") self._logger.debug( result_msg.format(url=url, code=result.getcode(), response=response_data)) self._reporter.process( reports.node_communication_finished(url, result.getcode(), response_data)) return response_data except urllib_HTTPError as e: # python3 returns bytes not str response_data = e.read().decode("utf-8") self._logger.debug( result_msg.format(url=url, code=e.code, response=response_data)) self._reporter.process( reports.node_communication_finished(url, e.code, response_data)) if e.code == 400: # old pcsd protocol: error messages are commonly passed in plain # text in response body with HTTP code 400 # we need to be backward compatible with that raise NodeCommandUnsuccessfulException(host, request, response_data.rstrip()) elif e.code == 401: raise NodeAuthenticationException( host, request, "HTTP error: {0}".format(e.code)) elif e.code == 403: raise NodePermissionDeniedException( host, request, "HTTP error: {0}".format(e.code)) elif e.code == 404: raise NodeUnsupportedCommandException( host, request, "HTTP error: {0}".format(e.code)) else: raise NodeCommunicationException( host, request, "HTTP error: {0}".format(e.code)) except urllib_URLError as e: msg = "Unable to connect to {node} ({reason})" self._logger.debug(msg.format(node=host, reason=e.reason)) self._reporter.process( reports.node_communication_not_connected(host, e.reason)) raise NodeConnectionException(host, request, e.reason)
def call_host(self, host, request, data, request_timeout=None): """ Send a request to a host host host address request command to be run on the host data command parameters, encoded by format_data_* method request timeout float timeout for request, if not set object property will be used """ def __debug_callback(data_type, debug_data): prefixes = { pycurl.DEBUG_TEXT: b"* ", pycurl.DEBUG_HEADER_IN: b"< ", pycurl.DEBUG_HEADER_OUT: b"> ", pycurl.DEBUG_DATA_IN: b"<< ", pycurl.DEBUG_DATA_OUT: b">> ", } if data_type in prefixes: debug_output.write(prefixes[data_type]) debug_output.write(debug_data) if not debug_data.endswith(b"\n"): debug_output.write(b"\n") output = io.BytesIO() debug_output = io.BytesIO() cookies = self.__prepare_cookies(host) timeout = (request_timeout if request_timeout is not None else self.request_timeout) url = "https://{host}:2224/{request}".format( host=("[{0}]".format(host) if ":" in host else host), request=request) handler = pycurl.Curl() handler.setopt(pycurl.PROTOCOLS, pycurl.PROTO_HTTPS) handler.setopt(pycurl.TIMEOUT_MS, int(timeout * 1000)) handler.setopt(pycurl.URL, url.encode("utf-8")) handler.setopt(pycurl.WRITEFUNCTION, output.write) handler.setopt(pycurl.VERBOSE, 1) handler.setopt(pycurl.DEBUGFUNCTION, __debug_callback) handler.setopt(pycurl.SSL_VERIFYHOST, 0) handler.setopt(pycurl.SSL_VERIFYPEER, 0) handler.setopt(pycurl.NOSIGNAL, 1) # required for multi-threading handler.setopt(pycurl.HTTPHEADER, ["Expect: "]) if cookies: handler.setopt(pycurl.COOKIE, ";".join(cookies).encode("utf-8")) if data: handler.setopt(pycurl.COPYPOSTFIELDS, data.encode("utf-8")) msg = "Sending HTTP Request to: {url}" if data: msg += "\n--Debug Input Start--\n{data}\n--Debug Input End--" self._logger.debug(msg.format(url=url, data=data)) self._reporter.process(reports.node_communication_started(url, data)) result_msg = ( "Finished calling: {url}\nResponse Code: {code}" + "\n--Debug Response Start--\n{response}\n--Debug Response End--") try: handler.perform() response_data = output.getvalue().decode("utf-8") response_code = handler.getinfo(pycurl.RESPONSE_CODE) self._logger.debug( result_msg.format(url=url, code=response_code, response=response_data)) self._reporter.process( reports.node_communication_finished(url, response_code, response_data)) if response_code == 400: # old pcsd protocol: error messages are commonly passed in plain # text in response body with HTTP code 400 # we need to be backward compatible with that raise NodeCommandUnsuccessfulException(host, request, response_data.rstrip()) elif response_code == 401: raise NodeAuthenticationException( host, request, "HTTP error: {0}".format(response_code)) elif response_code == 403: raise NodePermissionDeniedException( host, request, "HTTP error: {0}".format(response_code)) elif response_code == 404: raise NodeUnsupportedCommandException( host, request, "HTTP error: {0}".format(response_code)) elif response_code >= 400: raise NodeCommunicationException( host, request, "HTTP error: {0}".format(response_code)) return response_data except pycurl.error as e: # In pycurl versions lower then 7.19.3 it is not possible to set # NOPROXY option. Therefore for the proper support of proxy settings # we have to use environment variables. if is_proxy_set(os.environ): self._logger.warning("Proxy is set") self._reporter.process( reports.node_communication_proxy_is_set()) errno, reason = e.args msg = "Unable to connect to {node} ({reason})" self._logger.debug(msg.format(node=host, reason=reason)) self._reporter.process( reports.node_communication_not_connected(host, reason)) if errno == pycurl.E_OPERATION_TIMEDOUT: raise NodeConnectionTimedOutException(host, request, reason) else: raise NodeConnectionException(host, request, reason) finally: debug_data = debug_output.getvalue().decode("utf-8", "ignore") self._logger.debug( ("Communication debug info for calling: {url}\n" "--Debug Communication Info Start--\n" "{data}\n" "--Debug Communication Info End--").format(url=url, data=debug_data)) self._reporter.process( reports.node_communication_debug_info(url, debug_data))
def call_host(self, host, request, data): """ Send a request to a host host host address request command to be run on the host data command parameters, encoded by format_data_* method """ opener = self.__get_opener() url = "https://{host}:2224/{request}".format( host=("[{0}]".format(host) if ":" in host else host), request=request ) cookies = self.__prepare_cookies(host) if cookies: opener.addheaders.append(("Cookie", ";".join(cookies))) msg = "Sending HTTP Request to: {url}" if data: msg += "\n--Debug Input Start--\n{data}\n--Debug Input End--" self._logger.debug(msg.format(url=url, data=data)) self._reporter.process( reports.node_communication_started(url, data) ) result_msg = ( "Finished calling: {url}\nResponse Code: {code}" + "\n--Debug Response Start--\n{response}\n--Debug Response End--" ) try: # python3 requires data to be bytes not str if data: data = data.encode("utf-8") result = opener.open(url, data) # python3 returns bytes not str response_data = result.read().decode("utf-8") self._logger.debug(result_msg.format( url=url, code=result.getcode(), response=response_data )) self._reporter.process( reports.node_communication_finished( url, result.getcode(), response_data ) ) return response_data except urllib_HTTPError as e: # python3 returns bytes not str response_data = e.read().decode("utf-8") self._logger.debug(result_msg.format( url=url, code=e.code, response=response_data )) self._reporter.process( reports.node_communication_finished(url, e.code, response_data) ) if e.code == 400: # old pcsd protocol: error messages are commonly passed in plain # text in response body with HTTP code 400 # we need to be backward compatible with that raise NodeCommandUnsuccessfulException( host, request, response_data.rstrip() ) elif e.code == 401: raise NodeAuthenticationException( host, request, "HTTP error: {0}".format(e.code) ) elif e.code == 403: raise NodePermissionDeniedException( host, request, "HTTP error: {0}".format(e.code) ) elif e.code == 404: raise NodeUnsupportedCommandException( host, request, "HTTP error: {0}".format(e.code) ) else: raise NodeCommunicationException( host, request, "HTTP error: {0}".format(e.code) ) except urllib_URLError as e: msg = "Unable to connect to {node} ({reason})" self._logger.debug(msg.format(node=host, reason=e.reason)) self._reporter.process( reports.node_communication_not_connected(host, e.reason) ) raise NodeConnectionException(host, request, e.reason)