示例#1
0
    def parse_rpc_error(self, rpc_error):
        if self.check_rc:
            try:
                error_root = fromstring(rpc_error)
                root = Element('root')
                root.append(error_root)

                error_list = root.findall('.//nc:rpc-error', NS_MAP)
                if not error_list:
                    raise ConnectionError(
                        to_text(rpc_error, errors='surrogate_then_replace'))

                warnings = []
                for error in error_list:
                    message_ele = error.find('./nc:error-message', NS_MAP)

                    if message_ele is None:
                        message_ele = error.find('./nc:error-info', NS_MAP)

                    message = message_ele.text if message_ele is not None else None

                    severity = error.find('./nc:error-severity', NS_MAP).text

                    if severity == 'warning' and self.ignore_warning and message is not None:
                        warnings.append(message)
                    else:
                        raise ConnectionError(
                            to_text(rpc_error,
                                    errors='surrogate_then_replace'))
                return warnings
            except XMLSyntaxError:
                raise ConnectionError(rpc_error)
示例#2
0
    def _run_queue(self, queue, output):
        if self._become:
            self.connection.queue_message('vvvv', 'firing event: on_become')
            queue.insert(0, 'enable')

        request = request_builder(queue, output)
        headers = {'Content-Type': 'application/json'}

        response, response_data = self.connection.send('/ins',
                                                       request,
                                                       headers=headers,
                                                       method='POST')

        try:
            response_data = json.loads(to_text(response_data.getvalue()))
        except ValueError:
            raise ConnectionError(
                'Response was not valid JSON, got {0}'.format(
                    to_text(response_data.getvalue())))

        results = handle_response(response_data)

        if self._become:
            results = results[1:]
        return results
示例#3
0
    def login(self, username, password):
        def request_token_payload(username, password):
            return {
                'grant_type': 'password',
                'username': username,
                'password': password
            }

        def refresh_token_payload(refresh_token):
            return {
                'grant_type': 'refresh_token',
                'refresh_token': refresh_token
            }

        if self.refresh_token:
            payload = refresh_token_payload(self.refresh_token)
        elif username and password:
            payload = request_token_payload(username, password)
        else:
            raise AnsibleConnectionFailure(
                'Username and password are required for login in absence of refresh token'
            )

        response = self._lookup_login_url(payload)

        try:
            self.refresh_token = response['refresh_token']
            self.access_token = response['access_token']
            self.connection._auth = {
                'Authorization': 'Bearer %s' % self.access_token
            }
        except KeyError:
            raise ConnectionError(
                'Server returned response without token info during connection authentication: %s'
                % response)
示例#4
0
    def _lookup_login_url(self, payload):
        """ Try to find correct login URL and get api token using this URL.

        :param payload: Token request payload
        :type payload: dict
        :return: token generation response
        """
        preconfigured_token_path = self._get_api_token_path()
        if preconfigured_token_path:
            token_paths = [preconfigured_token_path]
        else:
            token_paths = self._get_known_token_paths()

        for url in token_paths:
            try:
                response = self._send_login_request(payload, url)

            except ConnectionError as e:
                self.connection.queue_message(
                    'vvvv',
                    'REST:request to %s failed because of connection error: %s '
                    % (url, e))
                # In the case of ConnectionError caused by HTTPError we should check response code.
                # Response code 400 returned in case of invalid credentials so we should stop attempts to log in and
                # inform the user.
                if hasattr(e, 'http_code') and e.http_code == 400:
                    raise
            else:
                if not preconfigured_token_path:
                    self._set_api_token_path(url)
                return response

        raise ConnectionError(
            INVALID_API_TOKEN_PATH_MSG
            if preconfigured_token_path else MISSING_API_TOKEN_PATH_MSG)
示例#5
0
    def send_request(self, data, **message_kwargs):
        data = to_list(data)
        become = self._become
        if become:
            self.connection.queue_message('vvvv', 'firing event: on_become')
            data.insert(0, {"cmd": "enable", "input": self._become_pass})

        output = message_kwargs.get('output', 'text')
        request = request_builder(data, output)
        headers = {'Content-Type': 'application/json-rpc'}

        response, response_data = self.connection.send('/command-api',
                                                       request,
                                                       headers=headers,
                                                       method='POST')

        try:
            response_data = json.loads(to_text(response_data.getvalue()))
        except ValueError:
            raise ConnectionError(
                'Response was not valid JSON, got {0}'.format(
                    to_text(response_data.getvalue())))

        results = handle_response(response_data)

        if become:
            results = results[1:]
        if len(results) == 1:
            results = results[0]

        return results
示例#6
0
 def test_get_known_token_paths_with_failed_api_call(
         self, get_list_of_supported_api_versions_mock):
     get_list_of_supported_api_versions_mock.side_effect = ConnectionError(
         'test error message')
     result = self.ftd_plugin._get_known_token_paths()
     assert result == [
         TOKEN_PATH_TEMPLATE.format(version)
         for version in DEFAULT_API_VERSIONS
     ]
示例#7
0
    def run_commands(self, commands, check_rc=True):
        if commands is None:
            raise ValueError("'commands' value is required")

        headers = {'Content-Type': 'application/json'}
        responses = list()
        for cmd in to_list(commands):
            if not isinstance(cmd, Mapping):
                cmd = {'command': cmd}

            cmd['command'] = strip_run_script_cli2json(cmd['command'])

            output = cmd.pop('output', None)
            if output and output not in self.get_option_values().get('output'):
                raise ValueError("'output' value is %s is invalid. Valid values are %s" % (output, ','.join(self.get_option_values().get('output'))))

            data = request_builder(cmd['command'])

            response, response_data = self.connection.send('/jsonrpc', data, cookies=self._auth_token, headers=headers, method='POST')
            try:
                response_data = json.loads(to_text(response_data.getvalue()))
            except ValueError:
                raise ConnectionError('Response was not valid JSON, got {0}'.format(
                    to_text(response_data.getvalue())
                ))

            if response_data.get('error', None):
                raise ConnectionError("Request Error, got {0}".format(response_data['error']))
            if not response_data.get('result', None):
                raise ConnectionError("Request Error, got {0}".format(response_data))

            response_data = response_data['result']

            if output and output == 'text':
                statusOut = getKeyInResponse(response_data, 'status')
                cliOut = getKeyInResponse(response_data, 'CLIoutput')
                if statusOut == "ERROR":
                    raise ConnectionError("Command error({1}) for request {0}".format(cmd['command'], cliOut))
                if cliOut is None:
                    raise ValueError("Response for request {0} doesn't have the CLIoutput field, got {1}".format(cmd['command'], response_data))
                response_data = cliOut

            responses.append(response_data)
        return responses
示例#8
0
def handle_response(response, response_data):
    try:
        response_data = json.loads(response_data.read())
    except ValueError:
        response_data = response_data.read()

    if isinstance(response, HTTPError):
        if response_data:
            if 'errors' in response_data:
                errors = response_data['errors']['error']
                error_text = '\n'.join(
                    (error['error-message'] for error in errors))
            else:
                error_text = response_data

            raise ConnectionError(error_text, code=response.code)
        raise ConnectionError(to_text(response), code=response.code)

    return response_data
示例#9
0
 def test_lookup_login_url_with_failed_request(self, api_request_mock,
                                               get_known_token_paths_mock):
     payload = mock.MagicMock()
     url = mock.MagicMock()
     get_known_token_paths_mock.return_value = [url]
     api_request_mock.side_effect = ConnectionError('Error message')
     with mock.patch.object(self.ftd_plugin.connection,
                            'queue_message') as display_mock:
         self.assertRaises(ConnectionError,
                           self.ftd_plugin._lookup_login_url, payload)
         assert display_mock.called
示例#10
0
    def login(self, username, password):
        if username and password:
            payload = {}
            url = '/rest/com/vmware/cis/session'
            response, response_data = self.send_request(url, payload)
        else:
            raise AnsibleConnectionFailure(
                'Username and password are required for login')

        if response == 404:
            raise ConnectionError(response_data)

        if not response_data.get('value'):
            raise ConnectionError(
                'Server returned response without token info during connection authentication: %s'
                % response)

        self.connection._session_uid = "vmware-api-session-id:%s" % response_data[
            'value']
        self.connection._token = response_data['value']
示例#11
0
 def send_request(self, path, data=None, method='GET', **message_kwargs):
     headers = {'Content-Type': 'application/json'}
     response, response_data = self.connection.send(path, data, method=method, cookies=self._auth_token, headers=headers, **message_kwargs)
     try:
         if response.status == 204:
             response_data = {}
         else:
             response_data = json.loads(to_text(response_data.getvalue()))
     except ValueError:
         raise ConnectionError('Response was not valid JSON, got {0}'.format(
             to_text(response_data.getvalue())
         ))
     return response_data
示例#12
0
 def api_spec(self):
     if self._api_spec is None:
         spec_path_url = self._get_api_spec_path()
         response = self.send_request(url_path=spec_path_url,
                                      http_method=HTTPMethod.GET)
         if response[ResponseParams.SUCCESS]:
             self._api_spec = FdmSwaggerParser().parse_spec(
                 response[ResponseParams.RESPONSE])
         else:
             raise ConnectionError(
                 'Failed to download API specification. Status code: %s. Response: %s'
                 % (response[ResponseParams.STATUS_CODE],
                    response[ResponseParams.RESPONSE]))
     return self._api_spec
示例#13
0
    def run_commands(self, commands=None, check_rc=True):
        if commands is None:
            raise ValueError("'commands' value is required")

        responses = list()
        for cmd in to_list(commands):
            if not isinstance(cmd, Mapping):
                cmd = {'command': cmd}

            output = cmd.pop('output', None)
            if output:
                cmd['command'] = self._get_command_with_output(cmd['command'], output)

            try:
                out = self.send_command(**cmd)
            except AnsibleConnectionFailure as e:
                if check_rc is True:
                    raise
                out = getattr(e, 'err', e)

            if out is not None:
                try:
                    out = to_text(out, errors='surrogate_or_strict').strip()
                except UnicodeError:
                    raise ConnectionError(message=u'Failed to decode output from %s: %s' % (cmd, to_text(out)))

                if output and output == 'json':
                    try:
                        out = json.loads(out)
                    except ValueError:
                        raise ConnectionError('Response was not valid JSON, got {0}'.format(
                            to_text(out)
                        ))
                responses.append(out)

        return responses
示例#14
0
 def _send_service_request(self,
                           path,
                           error_msg_prefix,
                           data=None,
                           **kwargs):
     try:
         self._ignore_http_errors = True
         return self.connection.send(path, data, **kwargs)
     except HTTPError as e:
         # HttpApi connection does not read the error response from HTTPError, so we do it here and wrap it up in
         # ConnectionError, so the actual error message is displayed to the user.
         error_msg = self._response_to_json(to_text(e.read()))
         raise ConnectionError('%s: %s' % (error_msg_prefix, error_msg),
                               http_code=e.code)
     finally:
         self._ignore_http_errors = False
示例#15
0
def handle_response(response):
    results = []

    if response['ins_api'].get('outputs'):
        for output in to_list(response['ins_api']['outputs']['output']):
            if output['code'] != '200':
                # Best effort messages: some API output keys may not exist on some platforms
                input_data = output.get('input', '')
                msg = output.get('msg', '')
                clierror = output.get('clierror', '')
                raise ConnectionError('%s: %s: %s' %
                                      (input_data, msg, clierror),
                                      code=output['code'])
            elif 'body' in output:
                result = output['body']
                if isinstance(result, dict):
                    result = json.dumps(result)

                results.append(result.strip())

    return results
示例#16
0
def handle_response(response):
    if 'error' in response:
        error = response['error']

        error_text = []
        for data in error['data']:
            error_text.extend(data.get('errors', []))
        error_text = '\n'.join(error_text) or error['message']

        raise ConnectionError(error_text, code=error['code'])

    results = []

    for result in response['result']:
        if 'messages' in result:
            results.append(result['messages'][0])
        elif 'output' in result:
            results.append(result['output'].strip())
        else:
            results.append(json.dumps(result))

    return results
示例#17
0
    def edit_config(self,
                    candidate=None,
                    commit=True,
                    replace=None,
                    comment=None):
        resp = {}
        operations = self.get_device_operations()
        self.check_edit_config_capability(operations, candidate, commit,
                                          replace, comment)
        results = []
        requests = []

        if replace:
            device_info = self.get_device_info()
            if '9K' not in device_info.get('network_os_platform', ''):
                raise ConnectionError(
                    message=u'replace is supported only on Nexus 9K devices')
            candidate = 'config replace {0}'.format(replace)

        if commit:
            self.send_command('configure terminal')

            for line in to_list(candidate):
                if not isinstance(line, Mapping):
                    line = {'command': line}

                cmd = line['command']
                if cmd != 'end':
                    results.append(self.send_command(**line))
                    requests.append(cmd)

            self.send_command('end')
        else:
            raise ValueError('check mode is not supported')

        resp['request'] = requests
        resp['response'] = results
        return resp
示例#18
0
def request_builder(commands, output, version='1.0', chunk='0', sid=None):
    """Encodes a NXAPI JSON request message
    """
    output_to_command_type = {
        'text': 'cli_show_ascii',
        'json': 'cli_show',
        'bash': 'bash',
        'config': 'cli_conf'
    }

    maybe_output = commands[0].split('|')[-1].strip()
    if maybe_output in output_to_command_type:
        command_type = output_to_command_type[maybe_output]
        commands = [command.split('|')[0].strip() for command in commands]
    else:
        try:
            command_type = output_to_command_type[output]
        except KeyError:
            msg = 'invalid format, received %s, expected one of %s' % \
                (output, ','.join(output_to_command_type.keys()))
            raise ConnectionError(msg)

    if isinstance(commands, (list, set, tuple)):
        commands = ' ;'.join(commands)

    # Order should not matter but some versions of NX-OS software fail
    # to process the payload properly if 'input' gets serialized before
    # 'type' and the payload of 'input' contains the word 'type'.
    msg = collections.OrderedDict()
    msg['version'] = version
    msg['type'] = command_type
    msg['chunk'] = chunk
    msg['sid'] = sid
    msg['input'] = commands
    msg['output_format'] = 'json'

    return json.dumps(dict(ins_api=msg))
    def login(self, username, password):
        if username and password:
            cp_domain = self.get_option('domain')
            if cp_domain:
                payload = {
                    'user': username,
                    'password': password,
                    'domain': cp_domain
                }
            else:
                payload = {'user': username, 'password': password}
            url = '/web_api/login'
            response, response_data = self.send_request(url, payload)
        else:
            raise AnsibleConnectionFailure(
                'Username and password are required for login')

        try:
            self.connection._auth = {'X-chkp-sid': response_data['sid']}
            self.connection._session_uid = response_data['uid']
        except KeyError:
            raise ConnectionError(
                'Server returned response without token info during connection authentication: %s'
                % response)
示例#20
0
    def run_commands(self, commands=None, check_rc=True):
        if commands is None:
            raise ValueError("'commands' value is required")
        responses = list()
        for cmd in to_list(commands):
            if not isinstance(cmd, Mapping):
                cmd = {'command': cmd}

            output = cmd.pop('output', None)
            if output:
                raise ValueError(
                    "'output' value %s is not supported for run_commands" %
                    output)

            try:
                out = self.send_command(**cmd)
            except AnsibleConnectionFailure as e:
                if check_rc:
                    raise
                out = getattr(e, 'err', e)

            if out is not None:
                try:
                    out = to_text(out, errors='surrogate_or_strict').strip()
                except UnicodeError:
                    raise ConnectionError(
                        message=u'Failed to decode output from %s: %s' %
                        (cmd, to_text(out)))

                try:
                    out = json.loads(out)
                except ValueError:
                    pass

                responses.append(out)
        return responses
示例#21
0
 def _response_to_json(self, response_text):
     try:
         return json.loads(response_text) if response_text else {}
     # JSONDecodeError only available on Python 3.5+
     except ValueError:
         raise ConnectionError('Invalid JSON response: %s' % response_text)
示例#22
0
 def _response_to_json(response_text):
     try:
         return json.loads(response_text) if response_text else {}
     # JSONDecodeError only available on Python 3.5+
     except getattr(json.decoder, 'JSONDecodeError', ValueError):
         raise ConnectionError('Invalid JSON response: %s' % response_text)