Allow persistent connection plugins to queue messages back to ansible-connection (#49977)

* Connections can queue messages to be returned from ansible-connection

* Provide fallback for invalid display level

* Strip display from plugins

* Route messages through helper method to try to avoid improper appends
This commit is contained in:
Nathaniel Case 2018-12-19 10:54:42 -05:00 committed by GitHub
parent 49993a55e5
commit 1829a72885
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 75 additions and 83 deletions

View file

@ -192,9 +192,6 @@ from ansible.module_utils._text import to_bytes, to_text
from ansible.playbook.play_context import PlayContext
from ansible.plugins.connection import NetworkConnectionBase
from ansible.plugins.loader import cliconf_loader, terminal_loader, connection_loader
from ansible.utils.display import Display
display = Display()
class AnsibleCmdRespRecv(Exception):
@ -230,16 +227,16 @@ class Connection(NetworkConnectionBase):
self.cliconf = cliconf_loader.get(self._network_os, self)
if self.cliconf:
display.vvvv('loaded cliconf plugin for network_os %s' % self._network_os)
self.queue_message('vvvv', 'loaded cliconf plugin for network_os %s' % self._network_os)
self._sub_plugin = {'type': 'cliconf', 'name': self._network_os, 'obj': self.cliconf}
else:
display.vvvv('unable to load cliconf for network_os %s' % self._network_os)
self.queue_message('vvvv', 'unable to load cliconf for network_os %s' % self._network_os)
else:
raise AnsibleConnectionFailure(
'Unable to automatically determine host network os. Please '
'manually configure ansible_network_os value for this host'
)
display.display('network_os is set to %s' % self._network_os, log_only=True)
self.queue_message('log', 'network_os is set to %s' % self._network_os)
def _get_log_channel(self):
name = "p=%s u=%s | " % (os.getpid(), getpass.getuser())
@ -282,15 +279,15 @@ class Connection(NetworkConnectionBase):
play_context = PlayContext()
play_context.deserialize(pc_data)
messages = ['updating play_context for connection']
self.queue_message('vvvv', 'updating play_context for connection')
if self._play_context.become ^ play_context.become:
if play_context.become is True:
auth_pass = play_context.become_pass
self._terminal.on_become(passwd=auth_pass)
messages.append('authorizing connection')
self.queue_message('vvvv', 'authorizing connection')
else:
self._terminal.on_unbecome()
messages.append('deauthorizing connection')
self.queue_message('vvvv', 'deauthorizing connection')
self._play_context = play_context
@ -299,8 +296,6 @@ class Connection(NetworkConnectionBase):
if hasattr(self, 'disable_response_logging'):
self.disable_response_logging()
return messages
def _connect(self):
'''
Connects to the remote device and starts the terminal
@ -313,7 +308,7 @@ class Connection(NetworkConnectionBase):
ssh = self.paramiko_conn._connect()
host = self.get_option('host')
display.vvvv('ssh connection done, setting terminal', host=host)
self.queue_message('vvvv', 'ssh connection done, setting terminal')
self._ssh_shell = ssh.ssh.invoke_shell()
self._ssh_shell.settimeout(self.get_option('persistent_command_timeout'))
@ -322,20 +317,20 @@ class Connection(NetworkConnectionBase):
if not self._terminal:
raise AnsibleConnectionFailure('network os %s is not supported' % self._network_os)
display.vvvv('loaded terminal plugin for network_os %s' % self._network_os, host=host)
self.queue_message('vvvv', 'loaded terminal plugin for network_os %s' % self._network_os)
self.receive(prompts=self._terminal.terminal_initial_prompt, answer=self._terminal.terminal_initial_answer,
newline=self._terminal.terminal_inital_prompt_newline)
display.vvvv('firing event: on_open_shell()', host=host)
self.queue_message('vvvv', 'firing event: on_open_shell()')
self._terminal.on_open_shell()
if self._play_context.become and self._play_context.become_method == 'enable':
display.vvvv('firing event: on_become', host=host)
self.queue_message('vvvv', 'firing event: on_become')
auth_pass = self._play_context.become_pass
self._terminal.on_become(passwd=auth_pass)
display.vvvv('ssh connection has completed successfully', host=host)
self.queue_message('vvvv', 'ssh connection has completed successfully')
self._connected = True
return self
@ -346,17 +341,17 @@ class Connection(NetworkConnectionBase):
'''
# only close the connection if its connected.
if self._connected:
display.debug("closing ssh connection to device", host=self._play_context.remote_addr)
self.queue_message('debug', "closing ssh connection to device")
if self._ssh_shell:
display.debug("firing event: on_close_shell()")
self.queue_message('debug', "firing event: on_close_shell()")
self._terminal.on_close_shell()
self._ssh_shell.close()
self._ssh_shell = None
display.debug("cli session is now closed")
self.queue_message('debug', "cli session is now closed")
self.paramiko_conn.close()
self.paramiko_conn = None
display.debug("ssh connection has been closed successfully")
self.queue_message('debug', "ssh connection has been closed successfully")
super(Connection, self).close()
def receive(self, command=None, prompts=None, answer=None, newline=True, prompt_retry_check=False, check_all=False):
@ -451,19 +446,19 @@ class Connection(NetworkConnectionBase):
response = self.receive(command, prompt, answer, newline, prompt_retry_check, check_all)
return to_text(response, errors='surrogate_or_strict')
except (socket.timeout, AttributeError):
display.vvvv(traceback.format_exc(), host=self._play_context.remote_addr)
self.queue_message('error', traceback.format_exc())
raise AnsibleConnectionFailure("timeout value %s seconds reached while trying to send command: %s"
% (self._ssh_shell.gettimeout(), command.strip()))
def _handle_buffer_read_timeout(self, signum, frame):
display.vvvv("Response received, triggered 'persistent_buffer_read_timeout' timer of %s seconds"
% self.get_option('persistent_buffer_read_timeout'), host=self._play_context.remote_addr)
self.queue_message('vvvv', "Response received, triggered 'persistent_buffer_read_timeout' timer of %s seconds" %
self.get_option('persistent_buffer_read_timeout'))
raise AnsibleCmdRespRecv()
def _handle_command_timeout(self, signum, frame):
msg = 'command timeout triggered, timeout value is %s secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide.'\
% self.get_option('persistent_command_timeout')
display.display(msg, log_only=True)
self.queue_message('log', msg)
raise AnsibleConnectionFailure(msg)
def _strip(self, data):