1313from jumpstarter .client .decorators import driver_click_command
1414
1515
16+ @dataclass
17+ class SSHCommandRunResult :
18+ """Result of executing an SSH command"""
19+ return_code : int
20+ stdout : str | bytes
21+ stderr : str | bytes
22+
23+ @staticmethod
24+ def from_completed_process (result : subprocess .CompletedProcess ) -> "SSHCommandRunResult" :
25+ return SSHCommandRunResult (
26+ return_code = result .returncode ,
27+ stdout = result .stdout or "" ,
28+ stderr = result .stderr or "" ,
29+ )
30+
31+
1632@dataclass (kw_only = True )
1733class SSHWrapperClient (CompositeClient ):
1834 """
@@ -31,10 +47,17 @@ def cli(self):
3147 @click .argument ("args" , nargs = - 1 )
3248 def ssh (direct , args ):
3349 result = self .run (direct , args )
34- self .logger .debug (f"SSH result: { result } " )
35- if result != 0 :
36- click .get_current_context ().exit (result )
37- return result
50+ self .logger .debug ("SSH exit code: %s" , result .return_code )
51+
52+ if result .stdout :
53+ click .echo (result .stdout , nl = False )
54+ if result .stderr :
55+ click .echo (result .stderr , nl = False , err = True )
56+
57+ if result .return_code != 0 :
58+ click .get_current_context ().exit (result .return_code )
59+
60+ return result .return_code
3861
3962 return ssh
4063
@@ -46,7 +69,7 @@ def stream(self, method="connect"):
4669 async def stream_async (self , method ):
4770 return await self .tcp .stream_async (method )
4871
49- def run (self , direct , args ):
72+ def run (self , direct , args ) -> SSHCommandRunResult :
5073 """Run SSH command with the given parameters and arguments"""
5174 # Get SSH command and default username from driver
5275 ssh_command = self .call ("get_ssh_command" )
@@ -73,8 +96,7 @@ def run(self, direct, args):
7396 with TcpPortforwardAdapter (
7497 client = self .tcp ,
7598 ) as addr :
76- host = addr [0 ]
77- port = addr [1 ]
99+ host , port = addr
78100 self .logger .debug (f"SSH port forward established - host: { host } , port: { port } " )
79101 return self ._run_ssh_local (host , port , ssh_command , default_username , ssh_identity , args )
80102
@@ -212,13 +234,17 @@ def _build_final_ssh_command(self, ssh_args, ssh_options, host, command_args):
212234 self .logger .debug (f"Running SSH command: { ssh_args } " )
213235 return ssh_args
214236
215- def _execute_ssh_command (self , ssh_args ):
237+ def _execute_ssh_command (self , ssh_args ) -> SSHCommandRunResult :
216238 """Execute the SSH command and return the result"""
217239 try :
218- result = subprocess .run (ssh_args )
219- return result . returncode
240+ result = subprocess .run (ssh_args , capture_output = True , text = True )
241+ return SSHCommandRunResult . from_completed_process ( result )
220242 except FileNotFoundError :
221243 self .logger .error (
222244 f"SSH command '{ ssh_args [0 ]} ' not found. Please ensure SSH is installed and available in PATH."
223245 )
224- return 127 # Standard exit code for "command not found"
246+ return SSHCommandRunResult (
247+ return_code = 127 , # Standard exit code for "command not found"
248+ stdout = "" ,
249+ stderr = f"SSH command '{ ssh_args [0 ]} ' not found" ,
250+ )
0 commit comments