Handle ConnectionError exception in network modules (#43353)

* Handle ConnectionError exception in network modules

* Catch ConnectionError expection and fail module in case
  expection is raised.

* Fix CI failure
This commit is contained in:
Ganesh Nalawade 2018-07-30 10:24:58 +05:30 committed by GitHub
parent a44adc1dc9
commit 21dcaa4349
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 241 additions and 117 deletions

View file

@ -135,7 +135,11 @@ class Cli:
return self._device_configs[cmd]
except KeyError:
conn = self._get_connection()
try:
out = conn.get_config(filter=flags)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
cfg = to_text(out, errors='surrogate_then_replace').strip()
self._device_configs[cmd] = cfg
return cfg
@ -144,7 +148,11 @@ class Cli:
"""Run list of commands on remote device and return results
"""
connection = self._get_connection()
return connection.run_commands(commands=commands, check_rc=check_rc)
try:
response = connection.run_commands(commands=commands, check_rc=check_rc)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def load_config(self, commands, commit=False, replace=False):
"""Loads the config commands onto the remote device
@ -164,8 +172,12 @@ class Cli:
def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
conn = self._get_connection()
return conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path,
try:
diff = conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=diff_replace)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return diff
class Eapi:

View file

@ -26,6 +26,7 @@
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import json
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import env_fallback, return_values
from ansible.module_utils.network.common.utils import to_list, ComplexList
@ -81,8 +82,10 @@ def get_connection(module):
def get_capabilities(module):
if hasattr(module, '_ios_capabilities'):
return module._ios_capabilities
try:
capabilities = Connection(module._socket_path).get_capabilities()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
module._ios_capabilities = json.loads(capabilities)
return module._ios_capabilities
@ -93,7 +96,10 @@ def check_args(module, warnings):
def get_defaults_flag(module):
connection = get_connection(module)
try:
out = connection.get_defaults_flag()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return to_text(out, errors='surrogate_then_replace').strip()
@ -104,7 +110,10 @@ def get_config(module, flags=None):
return _DEVICE_CONFIGS[flag_str]
except KeyError:
connection = get_connection(module)
try:
out = connection.get_config(filter=flags)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
cfg = to_text(out, errors='surrogate_then_replace').strip()
_DEVICE_CONFIGS[flag_str] = cfg
return cfg

View file

@ -30,12 +30,11 @@ import json
import re
from difflib import Differ
from copy import deepcopy
from time import sleep
from ansible.module_utils._text import to_text, to_bytes
from ansible.module_utils.basic import env_fallback
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.connection import Connection
from ansible.module_utils.connection import Connection, ConnectionError
from ansible.module_utils.network.common.netconf import NetconfConnection
try:
@ -126,8 +125,10 @@ def get_connection(module):
def get_device_capabilities(module):
if hasattr(module, 'capabilities'):
return module.capabilities
try:
capabilities = Connection(module._socket_path).get_capabilities()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
module.capabilities = json.loads(capabilities)
return module.capabilities
@ -317,7 +318,11 @@ def get_config_diff(module, running=None, candidate=None):
conn = get_connection(module)
if is_cliconf(module):
return conn.get('show commit changes diff')
try:
response = conn.get('show commit changes diff')
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
elif is_netconf(module):
if running and candidate:
running_data = running.split("\n", 1)[1].rsplit("\n", 1)[0]
@ -332,14 +337,17 @@ def get_config_diff(module, running=None, candidate=None):
def discard_config(module):
conn = get_connection(module)
try:
conn.discard_changes()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
def commit_config(module, comment=None, confirmed=False, confirm_timeout=None,
persist=False, check=False, label=None):
conn = get_connection(module)
reply = None
try:
if check:
reply = conn.validate()
else:
@ -347,6 +355,8 @@ def commit_config(module, comment=None, confirmed=False, confirm_timeout=None,
reply = conn.commit(confirmed=confirmed, timeout=confirm_timeout, persist=persist)
elif is_cliconf(module):
reply = conn.commit(comment=comment, label=label)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return reply
@ -355,7 +365,10 @@ def get_oper(module, filter=None):
conn = get_connection(module)
if filter is not None:
try:
response = conn.get(filter)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
else:
return None
@ -366,12 +379,14 @@ def get_config(module, config_filter=None, source='running'):
conn = get_connection(module)
# Note: Does not cache config in favour of latest config on every get operation.
try:
out = conn.get_config(source=source, filter=config_filter)
if is_netconf(module):
out = to_xml(conn.get_config(source=source, filter=config_filter))
cfg = out.strip()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return cfg
@ -408,7 +423,7 @@ def load_config(module, command_filter, commit=False, replace=False,
else:
discard_config(module)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc))
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
finally:
# conn.unlock(target = 'candidate')
pass
@ -418,6 +433,7 @@ def load_config(module, command_filter, commit=False, replace=False,
cmd_filter = deepcopy(command_filter)
# If label is present check if label already exist before entering
# config mode
try:
if label:
old_label = check_existing_commit_labels(conn, label)
if old_label:
@ -430,11 +446,7 @@ def load_config(module, command_filter, commit=False, replace=False,
if admin:
cmd_filter.insert(0, 'admin')
try:
conn.edit_config(cmd_filter)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc))
if module._diff:
diff = get_config_diff(module)
@ -452,6 +464,8 @@ def load_config(module, command_filter, commit=False, replace=False,
conn.edit_config('exit')
else:
conn.discard_changes()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return diff
@ -493,9 +507,15 @@ def run_command(module, commands):
def copy_file(module, src, dst, proto='scp'):
conn = get_connection(module)
try:
conn.copy_file(source=src, destination=dst, proto=proto)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
def get_file(module, src, dst, proto='scp'):
conn = get_connection(module)
try:
conn.get_file(source=src, destination=dst, proto=proto)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

View file

@ -22,7 +22,7 @@ from contextlib import contextmanager
from copy import deepcopy
from ansible.module_utils.basic import env_fallback, return_values
from ansible.module_utils.connection import Connection
from ansible.module_utils.connection import Connection, ConnectionError
from ansible.module_utils.network.common.netconf import NetconfConnection
from ansible.module_utils._text import to_text
@ -93,7 +93,10 @@ def get_capabilities(module):
if hasattr(module, '_junos_capabilities'):
return module._junos_capabilities
try:
capabilities = Connection(module._socket_path).get_capabilities()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
module._junos_capabilities = json.loads(capabilities)
return module._junos_capabilities
@ -125,12 +128,15 @@ def load_configuration(module, candidate=None, action='merge', rollback=None, fo
module.fail_json(msg='format must be text when action is set')
conn = get_connection(module)
try:
if rollback is not None:
_validate_rollback_id(module, rollback)
obj = Element('load-configuration', {'rollback': str(rollback)})
conn.execute_rpc(tostring(obj))
else:
return conn.load_configuration(config=candidate, action=action, format=format)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
def get_configuration(module, compare=False, format='xml', rollback='0', filter=None):
@ -138,6 +144,7 @@ def get_configuration(module, compare=False, format='xml', rollback='0', filter=
module.fail_json(msg='invalid config format specified')
conn = get_connection(module)
try:
if compare:
xattrs = {'format': format}
_validate_rollback_id(module, rollback)
@ -146,18 +153,21 @@ def get_configuration(module, compare=False, format='xml', rollback='0', filter=
reply = conn.execute_rpc(tostring(Element('get-configuration', xattrs)))
else:
reply = conn.get_configuration(format=format, filter=filter)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return reply
def commit_configuration(module, confirm=False, check=False, comment=None, confirm_timeout=None, synchronize=False,
at_time=None, exit=False):
conn = get_connection(module)
try:
if check:
reply = conn.validate()
else:
reply = conn.commit(confirmed=confirm, timeout=confirm_timeout, comment=comment, synchronize=synchronize, at_time=at_time)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return reply
@ -165,17 +175,29 @@ def command(module, cmd, format='text', rpc_only=False):
conn = get_connection(module)
if rpc_only:
cmd += ' | display xml rpc'
return conn.command(command=cmd, format=format)
try:
response = conn.command(command=cmd, format=format)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def lock_configuration(x):
conn = get_connection(x)
return conn.lock()
def lock_configuration(module):
conn = get_connection(module)
try:
response = conn.lock()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def unlock_configuration(x):
conn = get_connection(x)
return conn.unlock()
def unlock_configuration(module):
conn = get_connection(module)
try:
response = conn.unlock()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
@contextmanager
@ -189,7 +211,11 @@ def locked_config(module):
def discard_changes(module):
conn = get_connection(module)
return conn.discard_changes()
try:
response = conn.discard_changes()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def get_diff(module, rollback='0'):

View file

@ -139,7 +139,11 @@ class Cli:
return self._device_configs[cmd]
except KeyError:
connection = self._get_connection()
try:
out = connection.get_config(filter=flags)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
cfg = to_text(out, errors='surrogate_then_replace').strip()
self._device_configs[cmd] = cfg
return cfg
@ -188,8 +192,12 @@ class Cli:
def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'):
conn = self._get_connection()
return conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path,
try:
response = conn.get_diff(candidate=candidate, running=running, diff_match=diff_match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=diff_replace)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def get_capabilities(self):
"""Returns platform info of the remove device
@ -198,7 +206,10 @@ class Cli:
return self._module._capabilities
connection = self._get_connection()
try:
capabilities = connection.get_capabilities()
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
self._module._capabilities = json.loads(capabilities)
return self._module._capabilities

View file

@ -81,7 +81,11 @@ def get_capabilities(module):
if hasattr(module, '_vyos_capabilities'):
return module._vyos_capabilities
try:
capabilities = Connection(module._socket_path).get_capabilities()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
module._vyos_capabilities = json.loads(capabilities)
return module._vyos_capabilities
@ -93,7 +97,10 @@ def get_config(module):
return _DEVICE_CONFIGS
else:
connection = get_connection(module)
try:
out = connection.get_config()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
cfg = to_text(out, errors='surrogate_then_replace').strip()
_DEVICE_CONFIGS = cfg
return cfg
@ -101,15 +108,19 @@ def get_config(module):
def run_commands(module, commands, check_rc=True):
connection = get_connection(module)
return connection.run_commands(commands=commands, check_rc=check_rc)
try:
response = connection.run_commands(commands=commands, check_rc=check_rc)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return response
def load_config(module, commands, commit=False, comment=None):
connection = get_connection(module)
try:
resp = connection.edit_config(candidate=commands, commit=commit, comment=comment)
response = connection.edit_config(candidate=commands, commit=commit, comment=comment)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc))
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
return resp.get('diff')
return response.get('diff')

View file

@ -264,7 +264,9 @@ backup_path:
type: string
sample: /playbooks/ansible/backup/eos_config.2016-07-16@22:28:34
"""
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.config import NetworkConfig, dumps
from ansible.module_utils.network.eos.eos import get_config, load_config, get_connection
from ansible.module_utils.network.eos.eos import run_commands
@ -382,8 +384,12 @@ def main():
candidate = get_candidate(module)
running = get_running_config(module, contents, flags=flags)
try:
response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=replace)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
config_diff = response['config_diff']
if config_diff:

View file

@ -293,6 +293,8 @@ backup_path:
"""
import json
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.ios.ios import run_commands, get_config
from ansible.module_utils.network.ios.ios import get_defaults_flag, get_connection
from ansible.module_utils.network.ios.ios import ios_argument_spec
@ -419,9 +421,12 @@ def main():
candidate = get_candidate_config(module)
running = get_running_config(module, contents, flags=flags)
try:
response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=replace)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
config_diff = response['config_diff']
banner_diff = response['banner_diff']

View file

@ -164,6 +164,7 @@ import shlex
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.netconf import exec_rpc
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_configuration, get_connection, get_capabilities, tostring
from ansible.module_utils.network.common.parsing import Conditional, FailedConditionalError
@ -373,7 +374,10 @@ def main():
if ('display json' not in cmd) and ('display xml' not in cmd):
if display and display != 'text':
cmd += ' | display {0}'.format(display)
try:
output.append(conn.get(command=cmd))
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
lines = [out.split('\n') for out in output]
result = {'changed': False, 'stdout': output, 'stdout_lines': lines}

View file

@ -77,6 +77,8 @@ commands:
"""
import re
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes
@ -146,9 +148,12 @@ def map_params_to_obj(module):
def load_config(module, config, commit=False):
conn = get_connection(module)
try:
conn.edit_config(to_list(config) + ['top'])
diff = conn.compare_configuration()
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
if diff:
if commit:
commit_configuration(module)
@ -156,7 +161,7 @@ def load_config(module, config, commit=False):
else:
discard_changes(module)
return str(diff).strip()
return to_text(diff, errors='surrogate_then_replace').strip()
def main():

View file

@ -138,7 +138,9 @@ from functools import partial
from copy import deepcopy
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.utils import remove_default_spec
from ansible.module_utils.network.junos.junos import junos_argument_spec, get_connection, tostring
from ansible.module_utils.network.junos.junos import commit_configuration, discard_changes
@ -160,7 +162,11 @@ def handle_purge(module, want):
login = SubElement(element, 'login')
conn = get_connection(module)
try:
reply = conn.execute_rpc(tostring(Element('get-configuration')), ignore_warning=False)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
users = reply.xpath('configuration/system/login/user/name')
if users:
for item in users:

View file

@ -276,8 +276,7 @@ backup_path:
type: string
sample: /playbooks/ansible/backup/nxos_config.2016-07-16@22:28:34
"""
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.config import NetworkConfig, dumps
@ -436,8 +435,12 @@ def main():
result['changed'] = True
else:
try:
response = connection.get_diff(candidate=candidate, running=running, diff_match=match, diff_ignore_lines=diff_ignore_lines, path=path,
diff_replace=replace)
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
config_diff = response['config_diff']
if config_diff:
commands = config_diff.split('\n')

View file

@ -131,7 +131,9 @@ backup_path:
"""
import re
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.vyos.vyos import load_config, get_config, run_commands
from ansible.module_utils.network.vyos.vyos import vyos_argument_spec, get_connection
@ -208,7 +210,11 @@ def run(module, result):
# create loadable config that includes only the configuration updates
connection = get_connection(module)
try:
response = connection.get_diff(candidate=candidate, running=config, diff_match=module.params['match'])
except ConnectionError as exc:
module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))
commands = response.get('config_diff')
sanitize_config(commands, result)