From d5f7a0181b1334fe23d3e734c2f8a1c34be35590 Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Sun, 19 Feb 2017 08:46:14 -0500 Subject: [PATCH] roll up of eos fixes (#21629) * fixes error where eos would close the cli shell * fixes network_cli connection plugin to check before calling open_shell() * fixes json commands being sent over eapi --- lib/ansible/module_utils/eos.py | 15 ++++++------ lib/ansible/plugins/action/eos.py | 23 +++++++++++-------- lib/ansible/plugins/connection/network_cli.py | 2 +- .../plugins/connection/test_network_cli.py | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/ansible/module_utils/eos.py b/lib/ansible/module_utils/eos.py index dced385dc83..fa63548fae1 100644 --- a/lib/ansible/module_utils/eos.py +++ b/lib/ansible/module_utils/eos.py @@ -64,7 +64,7 @@ eos_argument_spec = { def check_args(module, warnings): provider = module.params['provider'] or {} for key in eos_argument_spec: - if key != ['provider', 'transport'] and module.params[key]: + if key not in ['provider', 'transport'] and module.params[key]: warnings.append('argument %s has been deprecated and will be ' 'removed in a future version' % key) @@ -157,6 +157,7 @@ class Cli: def send_config(self, commands): multiline = False + rc = 0 for command in to_list(commands): if command == 'end': pass @@ -170,8 +171,8 @@ class Cli: rc, out, err = self.exec_command(command) if rc != 0: return (rc, out, err) - return (rc, 'ok','') + return (rc, 'ok','') def configure(self, commands): """Sends configuration commands to the remote device @@ -322,13 +323,11 @@ class Eapi: return response['result'] for item in to_list(commands): - if item['output'] == 'json' and not is_json(item['command']): - item['command'] = '%s | json' % item['command'] - - if item['output'] == 'text' and is_json(item['command']): - item['command'] = str(item['command']).split('|')[0] + if is_json(item['command']): + item['command'] = str(item['command']).replace('| json', '') + item['output'] == 'json' - if all((output == 'json', is_text(item['command']))) or all((output =='text', is_json(item['command']))): + if output != item['output']: responses.extend(_send(queue, output)) queue = list() diff --git a/lib/ansible/plugins/action/eos.py b/lib/ansible/plugins/action/eos.py index 4ae90cfa850..79f05a9f1a0 100644 --- a/lib/ansible/plugins/action/eos.py +++ b/lib/ansible/plugins/action/eos.py @@ -50,7 +50,7 @@ class ActionModule(_ActionModule): provider = self.load_provider() transport = provider['transport'] or 'cli' - display.vvv('transport is %s' % transport, self._play_context.remote_addr) + display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) @@ -66,11 +66,22 @@ class ActionModule(_ActionModule): connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = self._get_socket_path(pc) + display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) + if not os.path.exists(socket_path): # start the connection if it isn't started + display.vvvv('calling open_shell()', pc.remote_addr) rc, out, err = connection.exec_command('open_shell()') if not rc == 0: - return {'failed': True, 'msg': 'unable to open shell', 'rc': rc} + return {'failed': True, 'msg': 'unable to open shell'} + else: + # make sure we are in the right cli context which should be + # enable mode and not config module + rc, out, err = connection.exec_command('prompt()') + while str(out).strip().endswith(')#'): + display.debug('wrong context, sending exit to device', self._play_context.remote_addr) + connection.exec_command('exit') + rc, out, err = connection.exec_command('prompt()') task_vars['ansible_socket'] = socket_path @@ -92,13 +103,7 @@ class ActionModule(_ActionModule): self._play_context.become = False self._play_context.become_method = None - result = super(ActionModule, self).run(tmp, task_vars) - - if transport == 'cli': - display.vvv('closing cli shell connection', self._play_context.remote_addr) - rc, out, err = connection.exec_command('close_shell()') - - return result + return super(ActionModule, self).run(tmp, task_vars) def _get_socket_path(self, play_context): ssh = connection_loader.get('ssh', class_only=True) diff --git a/lib/ansible/plugins/connection/network_cli.py b/lib/ansible/plugins/connection/network_cli.py index a6bbaf608d5..4a96cb74b9a 100644 --- a/lib/ansible/plugins/connection/network_cli.py +++ b/lib/ansible/plugins/connection/network_cli.py @@ -234,7 +234,7 @@ class Connection(_Connection): return (0, self._history, '') try: - if self._shell is None: + if not self._connected: self.open_shell() except AnsibleConnectionFailure as exc: return (1, '', str(exc)) diff --git a/test/units/plugins/connection/test_network_cli.py b/test/units/plugins/connection/test_network_cli.py index f6535f9ae3f..aa24069e7f0 100644 --- a/test/units/plugins/connection/test_network_cli.py +++ b/test/units/plugins/connection/test_network_cli.py @@ -45,7 +45,6 @@ class TestConnectionClass(unittest.TestCase): conn.ssh = None self.assertRaises(AnsibleConnectionFailure, conn._connect) - #mocked_terminal_loader.all.assert_called_with(class_only=True) mocked_terminal_loader.reset_mock() mocked_terminal_loader.get.return_value = None @@ -139,6 +138,7 @@ class TestConnectionClass(unittest.TestCase): conn._shell = MagicMock() # test _shell already open + conn._connected = MagicMock(return_value=True) rc, out, err = conn.exec_command('command') self.assertEqual(out, 'command response') self.assertFalse(mock_open_shell.called)