diff --git a/lib/ansible/plugins/connection/httpapi.py b/lib/ansible/plugins/connection/httpapi.py index 7919964065..9d7ffdeb97 100644 --- a/lib/ansible/plugins/connection/httpapi.py +++ b/lib/ansible/plugins/connection/httpapi.py @@ -277,9 +277,9 @@ class Connection(NetworkConnectionBase): if is_handled is True: return self.send(path, data, **kwargs) elif is_handled is False: - raise AnsibleConnectionFailure('Could not connect to {0}: {1}'.format(self._url + path, exc.reason)) - else: raise + else: + response = is_handled except URLError as exc: raise AnsibleConnectionFailure('Could not connect to {0}: {1}'.format(self._url + path, exc.reason)) diff --git a/lib/ansible/plugins/httpapi/__init__.py b/lib/ansible/plugins/httpapi/__init__.py index 6801abc72e..8611a83b00 100644 --- a/lib/ansible/plugins/httpapi/__init__.py +++ b/lib/ansible/plugins/httpapi/__init__.py @@ -61,19 +61,20 @@ class HttpApiBase(AnsiblePlugin): :returns: * True if the code has been handled in a way that the request may be resent without changes. - * False if this code indicates a fatal or unknown error which - cannot be handled by the plugin. This will result in an - AnsibleConnectionFailure being raised. - * Any other response passes the HTTPError along to the caller to - deal with as appropriate. - """ + * False if the error cannot be handled or recovered from by the + plugin. This will result in the HTTPError being returned to the + caller to deal with as appropriate. + * Any other value returned is taken as a valid response from the + server without making another request. In many cases, this can just + be the original exception. + """ if exc.code == 401 and self.connection._auth: # Stored auth appears to be invalid, clear and retry self.connection._auth = None self.login(self.connection.get_option('remote_user'), self.connection.get_option('password')) return True - return False + return exc @abstractmethod def send_request(self, data, **message_kwargs): diff --git a/lib/ansible/plugins/httpapi/ftd.py b/lib/ansible/plugins/httpapi/ftd.py index ec4b5cec7a..560331186e 100644 --- a/lib/ansible/plugins/httpapi/ftd.py +++ b/lib/ansible/plugins/httpapi/ftd.py @@ -217,8 +217,8 @@ class HttpApi(HttpApiBase): self.connection._auth = None self.login(self.connection.get_option('remote_user'), self.connection.get_option('password')) return True - # None means that the exception will be passed further to the caller - return None + # False means that the exception will be passed further to the caller + return False def _display(self, http_method, title, msg=''): self.connection.queue_message('vvvv', 'REST:%s:%s:%s\n%s' % (http_method, self.connection._url, title, msg)) diff --git a/lib/ansible/plugins/httpapi/restconf.py b/lib/ansible/plugins/httpapi/restconf.py index 3a5def2c97..b883ccaf4b 100644 --- a/lib/ansible/plugins/httpapi/restconf.py +++ b/lib/ansible/plugins/httpapi/restconf.py @@ -62,30 +62,26 @@ class HttpApi(HttpApiBase): 'Content-Type': message_kwargs.get('content_type') or CONTENT_TYPE, 'Accept': message_kwargs.get('accept') or CONTENT_TYPE, } - try: - response, response_data = self.connection.send(path, data, headers=headers, method=message_kwargs.get('method')) - except HTTPError as exc: - response_data = exc + response, response_data = self.connection.send(path, data, headers=headers, method=message_kwargs.get('method')) - return handle_response(response_data) - - def handle_httperror(self, exc): - return None + return handle_response(response, response_data) -def handle_response(response): +def handle_response(response, response_data): try: - response_json = json.loads(response.read()) + response_data = json.loads(response_data.read()) except ValueError: - if isinstance(response, HTTPError): - raise ConnectionError(to_text(response), code=response.code) - return response.read() + response_data = response_data.read() - if 'errors' in response_json and 'jsonrpc' not in response_json: - errors = response_json['errors']['error'] + 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 - error_text = '\n'.join((error['error-message'] for error in errors)) + raise ConnectionError(error_text, code=response.code) + raise ConnectionError(to_text(response), code=response.code) - raise ConnectionError(error_text, code=response.code) - - return response_json + return response_data