diff options
author | Mike Wiebe <mwiebe@cisco.com> | 2019-09-18 07:37:50 -0400 |
---|---|---|
committer | Toshio Kuratomi <a.badger@gmail.com> | 2019-09-18 07:22:46 -0700 |
commit | ff9873beaad77ce7bbdf683981d401e72740bbba (patch) | |
tree | cd3859983c47d5dc88cf16a0354401df288cae4e /lib/ansible/plugins/action | |
parent | 6c3911b30473e28677153b13af3dc926dd5e8aa9 (diff) | |
download | ansible-ff9873beaad77ce7bbdf683981d401e72740bbba.tar.gz |
[stable-2.9] Stabilize nxos initiated copy for nxos_file_copy plugin (#62355)
* Retry spawn connection on failure
* Add debug logs
* Additional debug logs
* Close session before respawn attempt
* More debug info and increase loops
* Remove debug info and reset error dict on reconnect
* Add epdb debuger
* Add epdb debuger
* Add epdb debuger
* Wait before sending password and close pexpect session
* Fix comment typo
* Scrub error logs
* Scrub error logs
* Add more specific initial connect pattern
* Fix shippable errors
* Dont make remote_scp_server_password a hard requirement
* Add saftey check
(cherry picked from commit 97b15e9f0c4ddf419ca597e1b6769c29053bc06f)
Diffstat (limited to 'lib/ansible/plugins/action')
-rw-r--r-- | lib/ansible/plugins/action/nxos_file_copy.py | 58 |
1 files changed, 42 insertions, 16 deletions
diff --git a/lib/ansible/plugins/action/nxos_file_copy.py b/lib/ansible/plugins/action/nxos_file_copy.py index 43388fe468..c9cdcaa21d 100644 --- a/lib/ansible/plugins/action/nxos_file_copy.py +++ b/lib/ansible/plugins/action/nxos_file_copy.py @@ -21,10 +21,7 @@ import copy import hashlib import os import re -import sys import time -import traceback -import uuid from ansible.errors import AnsibleError from ansible.module_utils._text import to_text, to_bytes @@ -106,14 +103,12 @@ class ActionModule(ActionBase): raise AnsibleError('Playbook parameter <remote_scp_server> required when <file_pull> is True') if playvals['remote_scp_server'] or \ - playvals['remote_scp_server_user'] or \ - playvals['remote_scp_server_password']: + playvals['remote_scp_server_user']: if None in (playvals['remote_scp_server'], - playvals['remote_scp_server_user'], - playvals['remote_scp_server_password']): - params = '<remote_scp_server>, <remote_scp_server_user>, ,remote_scp_server_password>' - raise AnsibleError('Playbook parameters {0} must all be set together'.format(params)) + playvals['remote_scp_server_user']): + params = '<remote_scp_server>, <remote_scp_server_user>' + raise AnsibleError('Playbook parameters {0} must be set together'.format(params)) return playvals @@ -294,8 +289,8 @@ class ActionModule(ActionBase): # 14) - Copy completed without issues # 15) - nxos_router_prompt# # 16) - pexpect timeout - possible_outcomes = ['yes', - '(?i)Password', + possible_outcomes = [r'sure you want to continue connecting \(yes/no\)\? ', + '(?i)Password: ', 'file existing with this name', 'timed out', '(?i)No space.*#', @@ -350,27 +345,41 @@ class ActionModule(ActionBase): # Spawn pexpect connection to NX-OS device. nxos_session = pexpect.spawn('ssh ' + nxos_username + '@' + nxos_hostname + ' -p' + str(port)) # There might be multiple user_response_required prompts or intermittent timeouts - # spawning the expect session so loop up to 5 times during the spwan process. - for connect_attempt in range(6): + # spawning the expect session so loop up to 24 times during the spawn process. + max_attempts = 24 + for connect_attempt in range(max_attempts): outcome = process_outcomes(nxos_session) if outcome['user_response_required']: nxos_session.sendline('yes') continue if outcome['password_prompt_detected']: + time.sleep(3) nxos_session.sendline(nxos_password) continue if outcome['final_prompt_detected']: break if outcome['error'] or outcome['expect_timeout']: + # Error encountered, try to spawn expect session n more times up to max_attempts - 1 + if connect_attempt < max_attempts: + outcome['error'] = False + outcome['expect_timeout'] = False + nxos_session.close() + nxos_session = pexpect.spawn('ssh ' + nxos_username + '@' + nxos_hostname + ' -p' + str(port)) + continue self.results['failed'] = True + outcome['error_data'] = re.sub(nxos_password, '', outcome['error_data']) self.results['error_data'] = 'Failed to spawn expect session! ' + outcome['error_data'] + nxos_session.close() return else: # The before property will contain all text up to the expected string pattern. # The after string will contain the text that was matched by the expected pattern. msg = 'After {0} attempts, failed to spawn pexpect session to {1}' msg += 'BEFORE: {2}, AFTER: {3}' - raise AnsibleError(msg.format(connect_attempt, nxos_hostname, nxos_session.before, nxos_session.before)) + error_msg = msg.format(connect_attempt, nxos_hostname, nxos_session.before, nxos_session.after) + re.sub(nxos_password, '', error_msg) + nxos_session.close() + raise AnsibleError(error_msg) # Create local file directory under NX-OS filesystem if # local_file_directory playbook parameter is set. @@ -384,6 +393,7 @@ class ActionModule(ActionBase): if outcome['error'] or outcome['expect_timeout']: self.results['mkdir_cmd'] = mkdir_cmd self.results['failed'] = True + outcome['error_data'] = re.sub(nxos_password, '', outcome['error_data']) self.results['error_data'] = outcome['error_data'] return local_dir_root += each + '/' @@ -398,7 +408,12 @@ class ActionModule(ActionBase): nxos_session.sendline('yes') continue if outcome['password_prompt_detected']: - nxos_session.sendline(self.playvals['remote_scp_server_password']) + if self.playvals.get('remote_scp_server_password'): + nxos_session.sendline(self.playvals['remote_scp_server_password']) + else: + err_msg = 'Remote scp server {0} requires a password.'.format(rserver) + err_msg += ' Set the <remote_scp_server_password> playbook parameter or configure nxos device for passwordless scp' + raise AnsibleError(err_msg) continue if outcome['existing_file_with_same_name']: nxos_session.sendline('y') @@ -408,14 +423,25 @@ class ActionModule(ActionBase): break if outcome['error'] or outcome['expect_timeout']: self.results['failed'] = True + outcome['error_data'] = re.sub(nxos_password, '', outcome['error_data']) + if self.playvals.get('remote_scp_server_password'): + outcome['error_data'] = re.sub(self.playvals['remote_scp_server_password'], '', outcome['error_data']) self.results['error_data'] = outcome['error_data'] + nxos_session.close() return else: # The before property will contain all text up to the expected string pattern. # The after string will contain the text that was matched by the expected pattern. msg = 'After {0} attempts, failed to copy file to {1}' msg += 'BEFORE: {2}, AFTER: {3}, CMD: {4}' - raise AnsibleError(msg.format(copy_attempt, nxos_hostname, nxos_session.before, nxos_session.before, copy_cmd)) + error_msg = msg.format(copy_attempt, nxos_hostname, nxos_session.before, nxos_session.before, copy_cmd) + re.sub(nxos_password, '', error_msg) + if self.playvals.get('remote_scp_server_password'): + re.sub(self.playvals['remote_scp_server_password'], '', error_msg) + nxos_session.close() + raise AnsibleError(error_msg) + + nxos_session.close() def file_pull(self): local_file = self.playvals['local_file'] |