298298from typing import Optional
299299from typing import NoReturn
300300from typing import Tuple
301+ from typing import ByteString
301302
302303try :
303304 import boto3
@@ -339,7 +340,7 @@ def wrapped(self, *args, **kwargs):
339340 for attempt in range (remaining_tries ):
340341 try :
341342 return_tuple = func (self , * args , ** kwargs )
342- self ._vvvv (f"ssm_retry: (success ) { to_text (return_tuple )} " )
343+ self ._vvvv (f"ssm_retry: (end of process ) { to_text (return_tuple )} " )
343344 break
344345
345346 except (AnsibleConnectionFailure , Exception ) as e :
@@ -662,7 +663,33 @@ def poll(self, label: str, cmd: str) -> NoReturn:
662663 raise AnsibleConnectionFailure (f"{ label } command '{ cmd } ' timeout on host: { self .instance_id } " )
663664 yield self .poll_stdout ()
664665
665- def exec_communicate (self , cmd : str , mark_start : str , mark_begin : str , mark_end : str ) -> Tuple [int , str , str ]:
666+ def _check_become_success (self , cmd : str ) -> ByteString :
667+ become_output = b''
668+ for result in self .poll ("ENSURE_BECOME" , cmd ):
669+ if not result :
670+ continue
671+ become_output += self ._stdout .readline ()
672+ if not self .become .check_success (become_output ) and not self .become .check_password_prompt (become_output ):
673+ return ByteString
674+
675+ def ensure_become (self , cmd : str , sudoable : bool ) -> ByteString :
676+ """When become is activated we ensure that the become step has succeed and if not the process may be waiting for
677+ the password to be provided. In this case we will send it to the stdin
678+ """
679+ become_output = b''
680+ if self .become and self .become .expect_prompt () and sudoable :
681+ try :
682+ become_output = self ._check_become_success (cmd )
683+ except AnsibleConnectionFailure :
684+ # Inject password into command
685+ if not self .become .check_success (become_output ):
686+ become_pass = self .become .get_option ('become_pass' , playcontext = self ._play_context )
687+ self ._session .stdin .write (to_bytes (become_pass , errors = 'surrogate_or_strict' ) + b'\n ' )
688+ become_output = self ._check_become_success (cmd )
689+ return become_output
690+
691+
692+ def exec_communicate (self , cmd : str , mark_start : str , mark_begin : str , mark_end : str , sudoable : bool ) -> Tuple [int , str , str ]:
666693 """Interact with session.
667694 Read stdout between the markers until 'mark_end' is reached.
668695
@@ -673,7 +700,7 @@ def exec_communicate(self, cmd: str, mark_start: str, mark_begin: str, mark_end:
673700 :returns: A tuple with the return code, the stdout and the stderr content.
674701 """
675702 # Read stdout between the markers
676- stdout = ""
703+ stdout = to_text ( self . ensure_become ( cmd , sudoable ))
677704 win_line = ""
678705 begin = False
679706 returncode = None
@@ -708,6 +735,7 @@ def exec_communicate(self, cmd: str, mark_start: str, mark_begin: str, mark_end:
708735 def exec_command (self , cmd : str , in_data : bool = None , sudoable : bool = True ) -> Tuple [int , str , str ]:
709736 """run a command on the ssm host"""
710737
738+ self ._v (f"[_exec_command] => { cmd } - sudoable = { sudoable } " )
711739 super ().exec_command (cmd , in_data = in_data , sudoable = sudoable )
712740
713741 self ._vvv (f"EXEC: { to_text (cmd )} " )
@@ -727,7 +755,7 @@ def exec_command(self, cmd: str, in_data: bool = None, sudoable: bool = True) ->
727755 for chunk in chunks (cmd , 1024 ):
728756 self ._session .stdin .write (to_bytes (chunk , errors = "surrogate_or_strict" ))
729757
730- return self .exec_communicate (cmd , mark_start , mark_begin , mark_end )
758+ return self .exec_communicate (cmd , mark_start , mark_begin , mark_end , sudoable )
731759
732760 def _prepare_terminal (self ):
733761 """perform any one-time terminal settings"""
@@ -1016,6 +1044,7 @@ def _file_transport_command(self, in_path, out_path, ssm_action):
10161044 def put_file (self , in_path , out_path ):
10171045 """transfer a file from local to remote"""
10181046
1047+ self ._v ("put_file" )
10191048 super ().put_file (in_path , out_path )
10201049
10211050 self ._vvv (f"PUT { in_path } TO { out_path } " )
@@ -1027,13 +1056,15 @@ def put_file(self, in_path, out_path):
10271056 def fetch_file (self , in_path , out_path ):
10281057 """fetch a file from remote to local"""
10291058
1059+ self ._v ("fetch_file" )
10301060 super ().fetch_file (in_path , out_path )
10311061
10321062 self ._vvv (f"FETCH { in_path } TO { out_path } " )
10331063 return self ._file_transport_command (in_path , out_path , "get" )
10341064
10351065 def close (self ):
10361066 """terminate the connection"""
1067+ self ._v ("close" )
10371068 if self ._session_id :
10381069 self ._vvv (f"CLOSING SSM CONNECTION TO: { self .instance_id } " )
10391070 if self ._has_timeout :
0 commit comments