From 7f90c9d1a74fdc3e9ee31bfe80229d4e4b8815e4 Mon Sep 17 00:00:00 2001 From: Nathaniel Case Date: Fri, 1 Dec 2017 12:22:54 -0500 Subject: [PATCH] Warn on `provider` with network_cli (#33355) * Warn on `provider` with network_cli also unify action plugins * Add to porting guide about connection warnings --- docs/docsite/rst/porting_guide_2.5.rst | 7 ++++ lib/ansible/plugins/action/eos.py | 8 +++-- lib/ansible/plugins/action/ios.py | 14 ++++---- lib/ansible/plugins/action/iosxr.py | 10 +++--- lib/ansible/plugins/action/junos.py | 45 +++++++++++++------------- lib/ansible/plugins/action/net_base.py | 45 ++++++++++++++------------ lib/ansible/plugins/action/nxos.py | 43 +++++++++++++----------- lib/ansible/plugins/action/vyos.py | 44 +++++++++++++++++-------- 8 files changed, 129 insertions(+), 87 deletions(-) diff --git a/docs/docsite/rst/porting_guide_2.5.rst b/docs/docsite/rst/porting_guide_2.5.rst index d526e054222..ec8d6ce43e5 100644 --- a/docs/docsite/rst/porting_guide_2.5.rst +++ b/docs/docsite/rst/porting_guide_2.5.rst @@ -139,3 +139,10 @@ Will result in: [DEPRECATION WARNING]: Param 'host' is deprecated. See the module docs for more information. This feature will be removed in version 2.9. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg. +Notice when using provider dictionary with new persistent connection types +-------------------------------------------------------------------------- + +Using a provider dictionary with one of the new persistent connection types for networking +(network_cli, netconf, etc.) will result in a warning. When using these connections +the standard Ansible infrastructure for controlling connections should be used. +(Link to basic inventory documentation?) diff --git a/lib/ansible/plugins/action/eos.py b/lib/ansible/plugins/action/eos.py index 13aedd03d98..7a8db31ca71 100644 --- a/lib/ansible/plugins/action/eos.py +++ b/lib/ansible/plugins/action/eos.py @@ -39,9 +39,13 @@ except ImportError: class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): - socket_path = None - if self._play_context.connection == 'local': + + if self._play_context.connection == 'network_cli': + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using network_cli and will be ignored') + elif self._play_context.connection == 'local': provider = load_provider(eos_provider_spec, self._task.args) transport = provider['transport'] or 'cli' diff --git a/lib/ansible/plugins/action/ios.py b/lib/ansible/plugins/action/ios.py index 34e03c23792..1ccf20628c9 100644 --- a/lib/ansible/plugins/action/ios.py +++ b/lib/ansible/plugins/action/ios.py @@ -39,11 +39,14 @@ except ImportError: class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): - socket_path = None - if self._play_context.connection == 'local': - provider = load_provider(ios_provider_spec, self._task.args) + if self._play_context.connection == 'network_cli': + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using network_cli and will be ignored') + elif self._play_context.connection == 'local': + provider = load_provider(ios_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ios' @@ -70,10 +73,6 @@ class ActionModule(_ActionModule): task_vars['ansible_socket'] = socket_path - if self._play_context.become_method == 'enable': - self._play_context.become = False - 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: @@ -87,5 +86,4 @@ class ActionModule(_ActionModule): out = conn.get_prompt() result = super(ActionModule, self).run(tmp, task_vars) - return result diff --git a/lib/ansible/plugins/action/iosxr.py b/lib/ansible/plugins/action/iosxr.py index e99cc456e33..bdd1919840b 100644 --- a/lib/ansible/plugins/action/iosxr.py +++ b/lib/ansible/plugins/action/iosxr.py @@ -39,11 +39,14 @@ except ImportError: class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): - socket_path = None - if self._play_context.connection == 'local': - provider = load_provider(iosxr_provider_spec, self._task.args) + if self._play_context.connection == 'network_cli': + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using network_cli and will be ignored') + elif self._play_context.connection == 'local': + provider = load_provider(iosxr_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'iosxr' @@ -78,5 +81,4 @@ class ActionModule(_ActionModule): out = conn.get_prompt() result = super(ActionModule, self).run(tmp, task_vars) - return result diff --git a/lib/ansible/plugins/action/junos.py b/lib/ansible/plugins/action/junos.py index da651b268f8..bfc667678ea 100644 --- a/lib/ansible/plugins/action/junos.py +++ b/lib/ansible/plugins/action/junos.py @@ -42,32 +42,29 @@ class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): module = module_loader._load_module_source(self._task.action, module_loader.find_plugin(self._task.action)) - if not getattr(module, 'USE_PERSISTENT_CONNECTION', False): return super(ActionModule, self).run(tmp, task_vars) - provider = load_provider(junos_provider_spec, self._task.args) - - pc = copy.deepcopy(self._play_context) - pc.network_os = 'junos' - - pc.remote_addr = provider['host'] or self._play_context.remote_addr - - if self._task.action == 'junos_netconf' or (provider['transport'] == 'cli' and self._task.action == 'junos_command'): - pc.connection = 'network_cli' - pc.port = int(provider['port'] or self._play_context.port or 22) - else: - pc.connection = 'netconf' - pc.port = int(provider['port'] or self._play_context.port or 830) - - pc.remote_user = provider['username'] or self._play_context.connection_user - pc.password = provider['password'] or self._play_context.password - pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file - pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) - - display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) socket_path = None + if self._play_context.connection == 'local': + provider = load_provider(junos_provider_spec, self._task.args) + pc = copy.deepcopy(self._play_context) + pc.network_os = 'junos' + pc.remote_addr = provider['host'] or self._play_context.remote_addr + if self._task.action == 'junos_netconf' or (provider['transport'] == 'cli' and self._task.action == 'junos_command'): + pc.connection = 'network_cli' + pc.port = int(provider['port'] or self._play_context.port or 22) + else: + pc.connection = 'netconf' + pc.port = int(provider['port'] or self._play_context.port or 830) + + pc.remote_user = provider['username'] or self._play_context.connection_user + pc.password = provider['password'] or self._play_context.password + pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file + pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) + + display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() @@ -78,8 +75,12 @@ class ActionModule(_ActionModule): 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path + else: + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using connection=%s and will be ignored' % self._play_context.connection) - if pc.connection == 'network_cli': + if (self._play_context.connection == 'local' and pc.connection == 'network_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: diff --git a/lib/ansible/plugins/action/net_base.py b/lib/ansible/plugins/action/net_base.py index 437e0898a69..270983407dc 100644 --- a/lib/ansible/plugins/action/net_base.py +++ b/lib/ansible/plugins/action/net_base.py @@ -39,6 +39,7 @@ except ImportError: class ActionModule(ActionBase): def run(self, tmp=None, task_vars=None): + socket_path = None play_context = copy.deepcopy(self._play_context) play_context.network_os = self._get_network_os(task_vars) @@ -51,28 +52,32 @@ class ActionModule(ActionBase): f3, p3, d3 = find_module(play_context.network_os, [p2]) module = load_module('ansible.module_utils.' + play_context.network_os, f3, p3, d3) - self.provider = load_provider(module.get_provider_argspec(), self._task.args) + if play_context.connection == 'local': - if play_context.network_os == 'junos': - play_context.connection = 'netconf' - play_context.port = int(self.provider['port'] or self._play_context.port or 830) + self.provider = load_provider(module.get_provider_argspec(), self._task.args) + if play_context.network_os == 'junos': + play_context.connection = 'netconf' + play_context.port = int(self.provider['port'] or self._play_context.port or 830) + else: + play_context.connection = 'network_cli' + play_context.port = int(self.provider['port'] or self._play_context.port or 22) + + play_context.remote_addr = self.provider['host'] or self._play_context.remote_addr + play_context.remote_user = self.provider['username'] or self._play_context.connection_user + play_context.password = self.provider['password'] or self._play_context.password + play_context.private_key_file = self.provider['ssh_keyfile'] or self._play_context.private_key_file + play_context.timeout = int(self.provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) + if 'authorize' in self.provider.keys(): + play_context.become = self.provider['authorize'] or False + play_context.become_pass = self.provider['auth_pass'] + + if self._play_context.connection == 'local': + socket_path = self._start_connection(play_context) + task_vars['ansible_socket'] = socket_path else: - play_context.connection = 'network_cli' - play_context.port = int(self.provider['port'] or self._play_context.port or 22) - - play_context.remote_addr = self.provider['host'] or self._play_context.remote_addr - play_context.remote_user = self.provider['username'] or self._play_context.connection_user - play_context.password = self.provider['password'] or self._play_context.password - play_context.private_key_file = self.provider['ssh_keyfile'] or self._play_context.private_key_file - play_context.timeout = int(self.provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) - if 'authorize' in self.provider.keys(): - play_context.become = self.provider['authorize'] or False - play_context.become_pass = self.provider['auth_pass'] - - socket_path = None - if self._play_context.connection == 'local': - socket_path = self._start_connection(play_context) - task_vars['ansible_socket'] = socket_path + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using connection=%s and will be ignored' % play_context.connection) if play_context.connection == 'network_cli': # make sure we are in the right cli context which should be diff --git a/lib/ansible/plugins/action/nxos.py b/lib/ansible/plugins/action/nxos.py index 188f480a5e2..bda32c66fc3 100644 --- a/lib/ansible/plugins/action/nxos.py +++ b/lib/ansible/plugins/action/nxos.py @@ -39,14 +39,19 @@ except ImportError: class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): - provider = load_provider(nxos_provider_spec, self._task.args) - transport = provider['transport'] or 'cli' + socket_path = None - display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) + if self._play_context.connection == 'network_cli': + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using network_cli and will be ignored') + elif self._play_context.connection == 'local': + provider = load_provider(nxos_provider_spec, self._task.args) + transport = provider['transport'] or 'cli' - if transport == 'cli': - socket_path = None - if self._play_context.connection == 'local': + display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) + + if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'nxos' @@ -56,8 +61,8 @@ class ActionModule(_ActionModule): pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file 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) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() @@ -69,17 +74,6 @@ class ActionModule(_ActionModule): 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: provider['transport'] = 'nxapi' if provider.get('host') is None: @@ -108,5 +102,18 @@ class ActionModule(_ActionModule): 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 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) return result diff --git a/lib/ansible/plugins/action/vyos.py b/lib/ansible/plugins/action/vyos.py index 330e89a1c3b..e14bc92e157 100644 --- a/lib/ansible/plugins/action/vyos.py +++ b/lib/ansible/plugins/action/vyos.py @@ -24,6 +24,8 @@ import copy from ansible import constants as C from ansible.plugins.action.normal import ActionModule as _ActionModule +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.vyos import vyos_provider_spec @@ -37,21 +39,25 @@ except ImportError: class ActionModule(_ActionModule): def run(self, tmp=None, task_vars=None): - provider = load_provider(vyos_provider_spec, self._task.args) + socket_path = None - pc = copy.deepcopy(self._play_context) - pc.connection = 'network_cli' - pc.network_os = 'vyos' - pc.remote_addr = provider['host'] or self._play_context.remote_addr - pc.port = int(provider['port'] or self._play_context.port or 22) - pc.remote_user = provider['username'] or self._play_context.connection_user - pc.password = provider['password'] or self._play_context.password - pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file - pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) + if self._play_context.connection == 'network_cli': + provider = self._task.args.get('provider', {}) + if any(provider.values()): + display.warning('provider is unnecessary when using network_cli and will be ignored') + elif self._play_context.connection == 'local': + provider = load_provider(vyos_provider_spec, self._task.args) + pc = copy.deepcopy(self._play_context) + pc.connection = 'network_cli' + pc.network_os = 'vyos' + pc.remote_addr = provider['host'] or self._play_context.remote_addr + pc.port = int(provider['port'] or self._play_context.port or 22) + pc.remote_user = provider['username'] or self._play_context.connection_user + pc.password = provider['password'] or self._play_context.password + pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file + pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) - display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) - - if self._play_context.connection == 'local': + display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() @@ -63,5 +69,17 @@ class ActionModule(_ActionModule): 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') + out = conn.get_prompt() + result = super(ActionModule, self).run(tmp, task_vars) return result