Esempio n. 1
0
    def send_message(self, message):
        # TODO support kerberos/ntlm session with message encryption

        if not self.session:
            self.session = self.build_session()

        # urllib3 fails on SSL retries with unicode buffers- must send it a byte string
        # see https://github.com/shazow/urllib3/issues/717
        if isinstance(message, unicode_type):
            message = message.encode('utf-8')

        request = requests.Request('POST', self.endpoint, data=message)
        prepared_request = self.session.prepare_request(request)

        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response_text = response.text
            response.raise_for_status()
            return response_text
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = ex.response.content
            else:
                response_text = ''
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            raise WinRMTransportError('http', error_message)
Esempio n. 2
0
def fix_send_message(self, message):
    """Hacking from winrm.transport.Transport.send_message
    For adding detailed error message
    """
    if not self.session:
        self.session = self.build_session()

    # urllib3 fails on SSL retries with unicode buffers- must send it a byte string
    # see https://github.com/shazow/urllib3/issues/717
    if isinstance(message, type(u'')):
        message = message.encode('utf-8')

    request = requests.Request('POST', self.endpoint, data=message)
    prepared_request = self.session.prepare_request(request)

    try:
        response = self.session.send(prepared_request,
                                     timeout=self.read_timeout_sec)
        response_text = response.text
        response.raise_for_status()
        return response_text
    except requests.HTTPError as ex:
        if ex.response.status_code == 401:
            raise InvalidCredentialsError(
                "the specified credentials were rejected by the server")
        if ex.response.content:
            response_text = ex.response.content
        else:
            response_text = ''
        # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
        # should handle this 500 error and retry receiving command output.
        if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
            LOG.debug(
                'Receiving cmd result from %s but exceed operation timeout, keep retry',
                ex.request.url)
            raise WinRMOperationTimeoutError()

        # hack start
        # 2150858793 Operation timeout
        # 2147943418 Illegal operation attempted on a registry key that has been marked for deletion.
        # 2147746132 Class not registered
        LOG.error('Send message [%s] to [%s] get HTTP code [%s] [%s]', message,
                  self.endpoint, ex.response.status_code, response_text)
        err_code, err_msg = parse_error_response(response_text)
        if err_code == "2150858793":
            # raise EPASWinRMOperationTimeout(err_msg)
            raise OSCEWinRMOperationTimeout(err_msg)
        elif err_code == "2147943418":
            # raise EPASWinRMIllegalOperation(err_msg)
            raise OSCEWinRMIllegalOperation(err_msg)
        elif err_code == "2147746132":
            # raise EPASWinRMClassNotRegister(err_msg)
            raise OSCEWinRMClassNotRegister(err_msg)
        else:
            # raise EPASWinRMTransportException(ex.response.status_code, err_code, err_msg)
            raise OSCEWinRMTransportException(ex.response.status_code,
                                              err_code, err_msg)
Esempio n. 3
0
    def send_message(self, message):
        # TODO add message_id vs relates_to checking
        # TODO port error handling code
        try:
            resp = self.transport.send_message(message)
            return resp
        except WinRMTransportError as ex:
            try:
                # if response is XML-parseable, it's probably a SOAP fault; extract the details
                root = ET.fromstring(ex.response_text)
            except Exception:
                # assume some other transport error; raise the original exception
                raise ex

            fault = root.find('soapenv:Body/soapenv:Fault', xmlns)
            if fault is not None:
                fault_data = dict(transport_message=ex.message,
                                  http_status_code=ex.code)
                wsmanfault_code = fault.find(
                    'soapenv:Detail/wsmanfault:WSManFault[@Code]', xmlns)
                if wsmanfault_code is not None:
                    fault_data['wsmanfault_code'] = wsmanfault_code.get('Code')
                    # convert receive timeout code to WinRMOperationTimeoutError
                    if fault_data['wsmanfault_code'] == '2150858793':
                        # TODO: this fault code is specific to the Receive operation; convert all op timeouts?
                        raise WinRMOperationTimeoutError()

                fault_code = fault.find('soapenv:Code/soapenv:Value', xmlns)
                if fault_code is not None:
                    fault_data['fault_code'] = fault_code.text

                fault_subcode = fault.find(
                    'soapenv:Code/soapenv:Subcode/soapenv:Value', xmlns)
                if fault_subcode is not None:
                    fault_data['fault_subcode'] = fault_subcode.text

                error_message = fault.find('soapenv:Reason/soapenv:Text',
                                           xmlns)
                if error_message is not None:
                    error_message = error_message.text
                else:
                    error_message = "(no error message in fault)"

                raise WinRMError('{0} (extended fault data: {1})'.format(
                    error_message, fault_data))
Esempio n. 4
0
    def send_message(self, message):
        # TODO support kerberos/ntlm session with message encryption

        if not self.session:
            self.session = self.build_session()

        # urllib3 fails on SSL retries with unicode buffers- must send it a byte string
        # see https://github.com/shazow/urllib3/issues/717
        if isinstance(message, unicode_type):
            message = message.encode('utf-8')

        request = requests.Request('POST', self.endpoint, data=message)
        prepared_request = self.session.prepare_request(request)

        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response_text = response.text
            response.raise_for_status()
            return response_text
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = ex.response.content
            else:
                response_text = ''
            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            import xml.etree.ElementTree as ET

            if response_text:
                root = ET.fromstring(response_text)
                ns = {'s': "http://www.w3.org/2003/05/soap-envelope",
                      'a': "http://schemas.xmlsoap.org/ws/2004/08/addressing",
                      'w': "http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd"}

                for text in root.findall('s:Body/s:Fault/s:Reason/s:Text', ns):
                    error_message += "\n%s" % text.text

            raise WinRMTransportError('http', error_message)
Esempio n. 5
0
    def get_command_output(self, shell_id, command_id):
        """
        Get the Output of the given shell and command
        @param string shell_id: The shell id on the remote machine.
         See #open_shell
        @param string command_id: The command id on the remote machine.
         See #run_command
        #@return [Hash] Returns a Hash with a key :exitcode and :data.
         Data is an Array of Hashes where the cooresponding key
        #   is either :stdout or :stderr.  The reason it is in an Array so so
         we can get the output in the order it ocurrs on
        #   the console.
        """
        stdout_buffer, stderr_buffer = [], []
        command_done = False

        ############################################################################
        # 限时15*60s                                                                #
        #   程序反复查看相应,如果相应成功,且在超时时限内则命令成功,否则报超时异常。 #
        #   获取响应的时长较长。                                                    #
        ############################################################################
        return_code = -1
        limited_seconds = 15 * 60
        start_time = datetime.datetime.now()
        while not command_done:
            print('get the response from windows...')
            try:
                stdout, stderr, return_code, command_done = \
                    self._raw_get_command_output(shell_id, command_id)
                stdout_buffer.append(stdout)
                stderr_buffer.append(stderr)
            except WinRMOperationTimeoutError as e:
                # this is an expected error when waiting for a long-running process, just silently retry
                pass

            end_time = datetime.datetime.now()
            delta_time = end_time - start_time
            total_seconds = delta_time.total_seconds()
            if total_seconds > limited_seconds:
                raise WinRMOperationTimeoutError()
        return b''.join(stdout_buffer), b''.join(stderr_buffer), return_code
Esempio n. 6
0
    def _send_message_request(self, prepared_request, message):
        try:
            response = self.session.send(prepared_request, timeout=self.read_timeout_sec)
            response.raise_for_status()
            return response
        except requests.HTTPError as ex:
            if ex.response.status_code == 401:
                raise InvalidCredentialsError("the specified credentials were rejected by the server")
            if ex.response.content:
                response_text = self._get_message_response_text(ex.response)
            else:
                response_text = ''

            # Per http://msdn.microsoft.com/en-us/library/cc251676.aspx rule 3,
            # should handle this 500 error and retry receiving command output.
            if b'http://schemas.microsoft.com/wbem/wsman/1/windows/shell/Receive' in message and b'Code="2150858793"' in response_text:
                raise WinRMOperationTimeoutError()

            error_message = 'Bad HTTP response returned from server. Code {0}'.format(ex.response.status_code)

            raise WinRMTransportError('http', error_message)
Esempio n. 7
0
 def sleep_for_timeout_then_raise(*args, **kwargs):
     time.sleep(0.2)
     raise WinRMOperationTimeoutError()