def _log_debug(self, response):
     url = response.request.url
     debug_data = response.debug
     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.report(
         reports.node_communication_debug_info(url, debug_data))
Exemple #2
0
 def _log_debug(self, response):
     url = response.request.url
     debug_data = response.debug
     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)
     )
Exemple #3
0
    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))