@ -27,11 +27,12 @@ import datetime
from ansible . errors import AnsibleConnectionFailure
from ansible . module_utils . six . moves import StringIO
from ansible . plugins import terminal_loader
from ansible . plugins . connection import ensure_connect
from ansible . plugins . connection . paramiko_ssh import Connection as _Connection
class Connection ( _Connection ) :
''' CLI SSH based connections on Paramiko '''
''' CLI (shell) SSH connections on Paramiko '''
transport = ' network_cli '
has_pipelining = False
@ -47,6 +48,7 @@ class Connection(_Connection):
self . _history = list ( )
def update_play_context ( self , play_context ) :
""" Updates the play context information for the connection """
if self . _play_context . become is False and play_context . become is True :
auth_pass = play_context . become_pass
self . _terminal . on_authorize ( passwd = auth_pass )
@ -57,6 +59,7 @@ class Connection(_Connection):
self . _play_context = play_context
def _connect ( self ) :
""" Connections to the device and sets the terminal type """
super ( Connection , self ) . _connect ( )
network_os = self . _play_context . network_os
@ -78,7 +81,9 @@ class Connection(_Connection):
return ( 0 , ' connected ' , ' ' )
def open_shell ( self , timeout = 10 ) :
@ensure_connect
def open_shell ( self ) :
""" Opens the vty shell on the connection """
self . _shell = self . ssh . invoke_shell ( )
self . _shell . settimeout ( self . _play_context . timeout )
@ -87,8 +92,7 @@ class Connection(_Connection):
if self . _shell :
self . _terminal . on_open_shell ( )
if hasattr ( self . _play_context , ' become ' ) :
if self . _play_context . become :
if getattr ( self . _play_context , ' become ' , None ) :
auth_pass = self . _play_context . become_pass
self . _terminal . on_authorize ( passwd = auth_pass )
@ -97,6 +101,7 @@ class Connection(_Connection):
super ( Connection , self ) . close ( )
def close_shell ( self ) :
""" Closes the vty shell if the device supports multiplexing """
if self . _shell :
self . _terminal . on_close_shell ( )
@ -107,6 +112,7 @@ class Connection(_Connection):
return ( 0 , ' shell closed ' , ' ' )
def receive ( self , obj = None ) :
""" Handles receiving of output from command """
recv = StringIO ( )
handled = False
@ -130,6 +136,7 @@ class Connection(_Connection):
return self . _sanitize ( resp , obj )
def send ( self , obj ) :
""" Sends the command to the device in the opened shell """
try :
command = obj [ ' command ' ]
self . _history . append ( command )
@ -139,11 +146,13 @@ class Connection(_Connection):
raise AnsibleConnectionFailure ( " timeout trying to send command: %s " % command . strip ( ) )
def _strip ( self , data ) :
""" Removes ANSI codes from device response """
for regex in self . _terminal . ansi_re :
data = regex . sub ( ' ' , data )
return data
def _handle_prompt ( self , resp , obj ) :
""" Matches the command prompt and responds """
prompt = re . compile ( obj [ ' prompt ' ] , re . I )
answer = obj [ ' answer ' ]
match = prompt . search ( resp )
@ -152,6 +161,7 @@ class Connection(_Connection):
return True
def _sanitize ( self , resp , obj = None ) :
""" Removes elements from the response before returning to the caller """
cleaned = [ ]
command = obj . get ( ' command ' ) if obj else None
for line in resp . splitlines ( ) :
@ -161,6 +171,7 @@ class Connection(_Connection):
return str ( " \n " . join ( cleaned ) ) . strip ( )
def _find_prompt ( self , response ) :
""" Searches the buffered response for a matching command prompt """
for regex in self . _terminal . terminal_errors_re :
if regex . search ( response ) :
raise AnsibleConnectionFailure ( response )
@ -173,10 +184,28 @@ class Connection(_Connection):
return True
def alarm_handler ( self , signum , frame ) :
""" Alarm handler raised in case of command timeout """
self . close_shell ( )
def exec_command ( self , cmd ) :
''' { ' command ' : <str>, ' prompt ' : <str>, ' answer ' : <str>} '''
""" Executes the cmd on in the shell and returns the output
The method accepts two forms of cmd . The first form is as a
string that represents the command to be executed in the shell . The
second form is as a JSON string with additional keyword .
Keywords supported for cmd :
* command - the command string to execute
* prompt - the expected prompt generated by executing command
* response - the string to respond to the prompt with
: arg cmd : the string that represents the command to be executed
which can be a single command or a json encoded string
: returns : a tuple of ( return code , stdout , stderr ) . The return
code is an integer and stdout and stderr are strings
"""
# TODO: add support for timeout to the cmd to handle non return
# commands such as a system restart
try :
obj = json . loads ( cmd )