DataFlex
DataFlex
SSH Parallel Remote Commands on Multiple Servers
See more SSH Examples
Demonstrates running the same command on several servers simultaneously. It is simply a matter of using one Ssh object per server, starting the command on each with QuickCmdSend, and then polling each connection with QuickCmdCheck until all have finished.
Background: This is the fan-out pattern behind configuration-management and monitoring tools: query or update a whole fleet in roughly the time the slowest single host takes, rather than the sum of all of them. Each server needs its own object because each has its own connection and authentication state. Note that results come back in whatever order the servers finish, which is why the example tracks completion per connection. Production code would keep the objects in arrays instead of repeating the logic per server.
Chilkat DataFlex Downloads
Use ChilkatAx-win32.pkg
Procedure Test
Boolean iSuccess
Handle hoSsh1
Handle hoSsh2
Handle hoSsh3
Integer iPort
String sPassword
String sCmd
Integer iChannel1
Integer iChannel2
Integer iChannel3
Integer iPollTimeoutMs
Integer iNumFinished
Boolean iFinished1
Boolean iFinished2
Boolean iFinished3
Integer iCh1
String sOut1
Integer iCh2
String sOut2
Integer iCh3
String sOut3
String sTemp1
Boolean bTemp1
Move False To iSuccess
// This example requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
// Demonstrates running the same command on several servers simultaneously. It is simply a
// matter of using one Ssh object per server.
Get Create (RefClass(cComChilkatSsh)) To hoSsh1
If (Not(IsComObjectCreated(hoSsh1))) Begin
Send CreateComObject of hoSsh1
End
Get Create (RefClass(cComChilkatSsh)) To hoSsh2
If (Not(IsComObjectCreated(hoSsh2))) Begin
Send CreateComObject of hoSsh2
End
Get Create (RefClass(cComChilkatSsh)) To hoSsh3
If (Not(IsComObjectCreated(hoSsh3))) Begin
Send CreateComObject of hoSsh3
End
Move 22 To iPort
// Normally you would not hard-code the password in source. You should instead obtain it
// from an interactive prompt, environment variable, or a secrets vault.
Move "mySshPassword" To sPassword
Get ComConnect Of hoSsh1 "ssh-server1.example.com" iPort To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh1 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAuthenticatePw Of hoSsh1 "mySshLogin" sPassword To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh1 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComConnect Of hoSsh2 "ssh-server2.example.com" iPort To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh2 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAuthenticatePw Of hoSsh2 "mySshLogin" sPassword To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh2 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComConnect Of hoSsh3 "ssh-server3.example.com" iPort To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh3 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComAuthenticatePw Of hoSsh3 "mySshLogin" sPassword To iSuccess
If (iSuccess = False) Begin
Get ComLastErrorText Of hoSsh3 To sTemp1
Showln sTemp1
Procedure_Return
End
// This command sleeps for 5 seconds and then prints the system date/time, making the parallel
// execution easy to observe.
Move "sleep 5; date" To sCmd
// Start the command on each server. QuickCmdSend returns immediately.
Get ComQuickCmdSend Of hoSsh1 sCmd To iChannel1
If (iChannel1 < 0) Begin
Get ComLastErrorText Of hoSsh1 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComQuickCmdSend Of hoSsh2 sCmd To iChannel2
If (iChannel2 < 0) Begin
Get ComLastErrorText Of hoSsh2 To sTemp1
Showln sTemp1
Procedure_Return
End
Get ComQuickCmdSend Of hoSsh3 sCmd To iChannel3
If (iChannel3 < 0) Begin
Get ComLastErrorText Of hoSsh3 To sTemp1
Showln sTemp1
Procedure_Return
End
// The command is now running on all three servers at once. Poll each connection until every
// command has finished. (Production code would keep the objects in arrays rather than
// repeating the logic.)
Move 50 To iPollTimeoutMs
Move 0 To iNumFinished
Move False To iFinished1
Move False To iFinished2
Move False To iFinished3
While (iNumFinished < 3)
If (Not iFinished1) Begin
Get ComQuickCmdCheck Of hoSsh1 iPollTimeoutMs To iCh1
If (iCh1 = -2) Begin
Get ComLastErrorText Of hoSsh1 To sTemp1
Showln sTemp1
Procedure_Return
End
If (iCh1 >= 0) Begin
Showln "---- ssh1 channel " iCh1 " finished ----"
Get ComGetReceivedText Of hoSsh1 iCh1 "utf-8" To sOut1
Get ComLastMethodSuccess Of hoSsh1 To bTemp1
If (bTemp1 = False) Begin
Get ComLastErrorText Of hoSsh1 To sTemp1
Showln sTemp1
Procedure_Return
End
Showln sOut1
Move True To iFinished1
Move (iNumFinished + 1) To iNumFinished
End
End
If (Not iFinished2) Begin
Get ComQuickCmdCheck Of hoSsh2 iPollTimeoutMs To iCh2
If (iCh2 = -2) Begin
Get ComLastErrorText Of hoSsh2 To sTemp1
Showln sTemp1
Procedure_Return
End
If (iCh2 >= 0) Begin
Showln "---- ssh2 channel " iCh2 " finished ----"
Get ComGetReceivedText Of hoSsh2 iCh2 "utf-8" To sOut2
Get ComLastMethodSuccess Of hoSsh2 To bTemp1
If (bTemp1 = False) Begin
Get ComLastErrorText Of hoSsh2 To sTemp1
Showln sTemp1
Procedure_Return
End
Showln sOut2
Move True To iFinished2
Move (iNumFinished + 1) To iNumFinished
End
End
If (Not iFinished3) Begin
Get ComQuickCmdCheck Of hoSsh3 iPollTimeoutMs To iCh3
If (iCh3 = -2) Begin
Get ComLastErrorText Of hoSsh3 To sTemp1
Showln sTemp1
Procedure_Return
End
If (iCh3 >= 0) Begin
Showln "---- ssh3 channel " iCh3 " finished ----"
Get ComGetReceivedText Of hoSsh3 iCh3 "utf-8" To sOut3
Get ComLastMethodSuccess Of hoSsh3 To bTemp1
If (bTemp1 = False) Begin
Get ComLastErrorText Of hoSsh3 To sTemp1
Showln sTemp1
Procedure_Return
End
Showln sOut3
Move True To iFinished3
Move (iNumFinished + 1) To iNumFinished
End
End
Loop
Send ComDisconnect To hoSsh1
Send ComDisconnect To hoSsh2
Send ComDisconnect To hoSsh3
End_Procedure