Example #1
0
 def _log_response_successful(self, response):
     url = response.request.url
     msg = (
         "Finished calling: {url}\nResponse Code: {code}" +
         "\n--Debug Response Start--\n{response}\n--Debug Response End--")
     self._logger.debug(
         msg.format(url=url,
                    code=response.response_code,
                    response=response.data))
     self._reporter.report(
         reports.node_communication_finished(url, response.response_code,
                                             response.data))
Example #2
0
 def _log_response_successful(self, response):
     url = response.request.url
     msg = (
         "Finished calling: {url}\nResponse Code: {code}"
         + "\n--Debug Response Start--\n{response}\n--Debug Response End--"
     )
     self._logger.debug(msg.format(
         url=url,
         code=response.response_code,
         response=response.data
     ))
     self._reporter.process(reports.node_communication_finished(
         url, response.response_code, response.data
     ))
Example #3
0
    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)
Example #4
0
    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:
            self.__handle_connection_error(host, request, e.reason)
        except HTTPException:
            self.__handle_connection_error(host, request, "Connection error")
Example #5
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))