Add prompt check in action plugin for network platform (#32787)

* Add prompt check in action plugin for network platform

In case of ignore_errors for a wrong configuration
the prompt is left in configuration mode and moved to
next task, if the next taks requires prompt to be
in operational state it results in failure.
Hence add a check to ensure right prompt at start of
each task run.

* Add prompt check in action plugin for network platform

*  In case of ignore_errors for a wrong configuration
   the prompt is left in configuration mode and moved to
   next task, if the next taks requires prompt to be
   in operational state it results in failure.
*  Hence add a check to ensure right prompt at start of
   each task run.
*  Fix CI issue

* Fix CI issues
Fix review comment
Change iosxr exit command to abort as per review comment
pull/32899/head
Ganesh Nalawade 7 years ago committed by Kedar K
parent 414eaefcb5
commit 8472a53bea

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.aireos import aireos_provider_spec from ansible.module_utils.aireos import aireos_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -69,10 +71,11 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
if str(out).strip().endswith(')#'): out = conn.get_prompt()
if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.aruba import aruba_provider_spec from ansible.module_utils.aruba import aruba_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -69,10 +71,11 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
if str(out).strip().endswith(')#'): out = conn.get_prompt()
if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.module_utils.f5_utils import F5_COMMON_ARGS from ansible.module_utils.f5_utils import F5_COMMON_ARGS
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
@ -64,12 +66,13 @@ class ActionModule(_ActionModule):
'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config mode # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
while '(config' in str(out): out = conn.get_prompt()
while '(config' in to_text(out, errors='surrogate_then_replace').strip():
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
rc, out, err = connection.exec_command('prompt()') out = conn.get_prompt()
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.ce import ce_provider_spec from ansible.module_utils.ce import ce_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -78,11 +80,12 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
while str(out).strip().endswith(']'): out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(']'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('return') conn.send_command('exit')
rc, out, err = connection.exec_command('prompt()') out = conn.get_prompt()
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -25,6 +25,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.dellos10 import dellos10_provider_spec from ansible.module_utils.dellos10 import dellos10_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -73,11 +75,12 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
while str(out).strip().endswith(')#'): out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
rc, out, err = connection.exec_command('prompt()') out = conn.get_prompt()
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -22,6 +22,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.dellos6 import dellos6_provider_spec from ansible.module_utils.dellos6 import dellos6_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -69,11 +71,12 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
while str(out).strip().endswith(')#'): out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
rc, out, err = connection.exec_command('prompt()') out = conn.get_prompt()
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -25,6 +25,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.dellos9 import dellos9_provider_spec from ansible.module_utils.dellos9 import dellos9_provider_spec
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -73,11 +75,12 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
while str(out).strip().endswith(')#'): out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
rc, out, err = connection.exec_command('prompt()') out = conn.get_prompt()
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.module_utils.eos import eos_provider_spec from ansible.module_utils.eos import eos_provider_spec
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -38,6 +40,7 @@ class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None): def run(self, tmp=None, task_vars=None):
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
provider = load_provider(eos_provider_spec, self._task.args) provider = load_provider(eos_provider_spec, self._task.args)
transport = provider['transport'] or 'cli' transport = provider['transport'] or 'cli'
@ -95,5 +98,18 @@ class ActionModule(_ActionModule):
self._task.args['provider'] = provider self._task.args['provider'] = provider
if (self._play_context.connection == 'local' and transport == 'cli') or self._play_context.connection == 'network_cli':
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
while '(config' in to_text(out, errors='surrogate_then_replace').strip():
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
out = conn.get_prompt()
result = super(ActionModule, self).run(tmp, task_vars) result = super(ActionModule, self).run(tmp, task_vars)
return result return result

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
from ansible.module_utils.ios import ios_provider_spec from ansible.module_utils.ios import ios_provider_spec
@ -38,6 +40,7 @@ class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None): def run(self, tmp=None, task_vars=None):
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
provider = load_provider(ios_provider_spec, self._task.args) provider = load_provider(ios_provider_spec, self._task.args)
@ -71,5 +74,18 @@ class ActionModule(_ActionModule):
self._play_context.become = False self._play_context.become = False
self._play_context.become_method = None self._play_context.become_method = None
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
out = conn.get_prompt()
result = super(ActionModule, self).run(tmp, task_vars) result = super(ActionModule, self).run(tmp, task_vars)
return result return result

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.module_utils.iosxr import iosxr_provider_spec from ansible.module_utils.iosxr import iosxr_provider_spec
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -38,6 +40,7 @@ class ActionModule(_ActionModule):
def run(self, tmp=None, task_vars=None): def run(self, tmp=None, task_vars=None):
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
provider = load_provider(iosxr_provider_spec, self._task.args) provider = load_provider(iosxr_provider_spec, self._task.args)
@ -62,5 +65,18 @@ class ActionModule(_ActionModule):
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('abort')
rc, out, err = conn.get_prompt()
result = super(ActionModule, self).run(tmp, task_vars) result = super(ActionModule, self).run(tmp, task_vars)
return result return result

@ -24,6 +24,8 @@ import copy
import json import json
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
from ansible.module_utils.ironware import ironware_provider_spec from ansible.module_utils.ironware import ironware_provider_spec
@ -73,10 +75,11 @@ class ActionModule(_ActionModule):
# make sure we are in the right cli context which should be # make sure we are in the right cli context which should be
# enable mode and not config module # enable mode and not config module
rc, out, err = connection.exec_command('prompt()') conn = Connection(socket_path)
if str(out).strip().endswith(')#'): out = conn.get_prompt()
if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit') conn.send_command('exit')
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path

@ -23,10 +23,13 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.module_utils.network_common import load_provider
from ansible.module_utils.junos import junos_provider_spec from ansible.module_utils.junos import junos_provider_spec
from ansible.plugins.loader import connection_loader, module_loader from ansible.plugins.loader import connection_loader, module_loader
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider
try: try:
from __main__ import display from __main__ import display
@ -53,7 +56,6 @@ class ActionModule(_ActionModule):
if self._task.action == 'junos_netconf' or (provider['transport'] == 'cli' and self._task.action == 'junos_command'): if self._task.action == 'junos_netconf' or (provider['transport'] == 'cli' and self._task.action == 'junos_command'):
pc.connection = 'network_cli' pc.connection = 'network_cli'
pc.port = int(provider['port'] or self._play_context.port or 22) pc.port = int(provider['port'] or self._play_context.port or 22)
else: else:
pc.connection = 'netconf' pc.connection = 'netconf'
pc.port = int(provider['port'] or self._play_context.port or 830) pc.port = int(provider['port'] or self._play_context.port or 830)
@ -64,7 +66,7 @@ class ActionModule(_ActionModule):
pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT)
display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr)
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin)
@ -75,16 +77,20 @@ class ActionModule(_ActionModule):
'msg': 'unable to open shell. Please see: ' + 'msg': 'unable to open shell. Please see: ' +
'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
if pc.connection == 'network_cli':
# 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.vvvv('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 task_vars['ansible_socket'] = socket_path
if pc.connection == 'network_cli':
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
out = conn.get_prompt()
result = super(ActionModule, self).run(tmp, task_vars) result = super(ActionModule, self).run(tmp, task_vars)
return result return result

@ -21,6 +21,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.errors import AnsibleError from ansible.errors import AnsibleError
from ansible.plugins.action import ActionBase from ansible.plugins.action import ActionBase
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
@ -67,10 +69,23 @@ class ActionModule(ActionBase):
play_context.become = self.provider['authorize'] or False play_context.become = self.provider['authorize'] or False
play_context.become_pass = self.provider['auth_pass'] play_context.become_pass = self.provider['auth_pass']
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
socket_path = self._start_connection(play_context) socket_path = self._start_connection(play_context)
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path
if play_context.connection == 'network_cli':
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
if 'fail_on_missing_module' not in self._task.args: if 'fail_on_missing_module' not in self._task.args:
self._task.args['fail_on_missing_module'] = False self._task.args['fail_on_missing_module'] = False
@ -119,13 +134,6 @@ class ActionModule(ActionBase):
'msg': 'unable to open shell. Please see: ' + 'msg': 'unable to open shell. Please see: ' +
'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'}
# 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()')
if str(out).strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
connection.exec_command('exit')
if self._play_context.become_method == 'enable': if self._play_context.become_method == 'enable':
self._play_context.become = False self._play_context.become = False
self._play_context.become_method = None self._play_context.become_method = None

@ -23,6 +23,8 @@ import sys
import copy import copy
from ansible import constants as C from ansible import constants as C
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import Connection
from ansible.plugins.action.normal import ActionModule as _ActionModule from ansible.plugins.action.normal import ActionModule as _ActionModule
from ansible.module_utils.network_common import load_provider from ansible.module_utils.network_common import load_provider
from ansible.module_utils.nxos import nxos_provider_spec from ansible.module_utils.nxos import nxos_provider_spec
@ -43,6 +45,7 @@ class ActionModule(_ActionModule):
display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr)
if transport == 'cli': if transport == 'cli':
socket_path = None
if self._play_context.connection == 'local': if self._play_context.connection == 'local':
pc = copy.deepcopy(self._play_context) pc = copy.deepcopy(self._play_context)
pc.connection = 'network_cli' pc.connection = 'network_cli'
@ -66,6 +69,17 @@ class ActionModule(_ActionModule):
task_vars['ansible_socket'] = socket_path task_vars['ansible_socket'] = socket_path
# make sure we are in the right cli context which should be
# enable mode and not config module
if socket_path is None:
socket_path = self._connection.socket_path
conn = Connection(socket_path)
out = conn.get_prompt()
while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'):
display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr)
conn.send_command('exit')
out = conn.get_prompt()
else: else:
provider['transport'] = 'nxapi' provider['transport'] = 'nxapi'
if provider.get('host') is None: if provider.get('host') is None:

Loading…
Cancel
Save