Sample code for 30+ languages & platforms
PureBasic

SSH Parallel Remote Commands on Multiple Servers

See more SSH Examples

Shows how to execute a command in parallel on multiple servers.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkSsh.pb"

Procedure ChilkatExample()

    success.i = 0

    ; This example requires the Chilkat API to have been previously unlocked.
    ; See Global Unlock Sample for sample code.

    ; Executing a command on multiple servers simultaneously is straightforward.
    ; It's just a matter of using one SSH object per server..
    ssh1.i = CkSsh::ckCreate()
    If ssh1.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ssh2.i = CkSsh::ckCreate()
    If ssh2.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ssh3.i = CkSsh::ckCreate()
    If ssh3.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    port.i = 22
    success = CkSsh::ckConnect(ssh1,"ssh-server1.com",port)
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh1)
        CkSsh::ckDispose(ssh1)
        CkSsh::ckDispose(ssh2)
        CkSsh::ckDispose(ssh3)
        ProcedureReturn
    EndIf

    ; Authenticate using login/password:
    success = CkSsh::ckAuthenticatePw(ssh1,"sshLogin1","sshPassword1")
    If success <> 1
        Debug CkSsh::ckLastErrorText(ssh1)
        CkSsh::ckDispose(ssh1)
        CkSsh::ckDispose(ssh2)
        CkSsh::ckDispose(ssh3)
        ProcedureReturn
    EndIf

    ; Connect and authenticate with 2 more servers.
    ; For brevity, the success/failure won't be checked...
    success = CkSsh::ckConnect(ssh2,"ssh-server2.com",port)
    success = CkSsh::ckAuthenticatePw(ssh2,"sshLogin2","sshPassword2")
    success = CkSsh::ckConnect(ssh3,"ssh-server3.com",port)
    success = CkSsh::ckAuthenticatePw(ssh3,"sshLogin3","sshPassword3")

    ; Note: If we wanted, we could've used ConnectAsync and AuthenticatePwAsync
    ; to do the connecting and authenticating in parallel...

    ; The command to be run on each SSH server will sleep for 5 seconds,
    ; and then show the current system date/time.
    cmd.s = "sleep 5; date"

    ; Start each command
    ssh1Channel.i = CkSsh::ckQuickCmdSend(ssh1,cmd)
    If ssh1Channel < 0
        Debug CkSsh::ckLastErrorText(ssh1)
        CkSsh::ckDispose(ssh1)
        CkSsh::ckDispose(ssh2)
        CkSsh::ckDispose(ssh3)
        ProcedureReturn
    EndIf

    ; For brevity, we're not checking the return values here:
    ssh2Channel.i = CkSsh::ckQuickCmdSend(ssh2,cmd)
    ssh3Channel.i = CkSsh::ckQuickCmdSend(ssh3,cmd)

    ; OK, at this point the command is running simultaneously on each server.

    ; Now collect the results of each command.
    pollTimeoutMs.i = 50
    numFinished.i = 0
    channel.i
    ; Note: You would rewrite this code to use arrays.
    ssh1Finished.i = 0
    ssh2Finished.i = 0
    ssh3Finished.i = 0
    While numFinished < 3
        ; Check to see if anything has finished.
        ; QuickCmdCheck returns -1 if there are no errors and nothing else finished
        ; QuickCmdCheck returns -2 if there was an error (such as a lost connection)
        ; QuickCmdCheck returns a channel number if a channel finished.
        If ssh1Finished <> 1
            channel = CkSsh::ckQuickCmdCheck(ssh1,pollTimeoutMs)
            If channel = -2
                Debug CkSsh::ckLastErrorText(ssh1)
                CkSsh::ckDispose(ssh1)
                CkSsh::ckDispose(ssh2)
                CkSsh::ckDispose(ssh3)
                ProcedureReturn
            EndIf

            If channel = ssh1Channel
                Debug "---- ssh1 channel " + Str(channel) + " finished ----"
                Debug CkSsh::ckGetReceivedText(ssh1,channel,"ansi")
                numFinished = numFinished + 1
                ssh1Finished = 1
            EndIf

        EndIf

        If ssh2Finished <> 1
            channel = CkSsh::ckQuickCmdCheck(ssh2,pollTimeoutMs)
            If channel = -2
                Debug CkSsh::ckLastErrorText(ssh2)
                CkSsh::ckDispose(ssh1)
                CkSsh::ckDispose(ssh2)
                CkSsh::ckDispose(ssh3)
                ProcedureReturn
            EndIf

            If channel = ssh2Channel
                Debug "---- ssh2 channel " + Str(channel) + " finished ----"
                Debug CkSsh::ckGetReceivedText(ssh2,channel,"ansi")
                numFinished = numFinished + 1
                ssh2Finished = 1
            EndIf

        EndIf

        If ssh3Finished <> 1
            channel = CkSsh::ckQuickCmdCheck(ssh3,pollTimeoutMs)
            If channel = -2
                Debug CkSsh::ckLastErrorText(ssh3)
                CkSsh::ckDispose(ssh1)
                CkSsh::ckDispose(ssh2)
                CkSsh::ckDispose(ssh3)
                ProcedureReturn
            EndIf

            If channel = ssh3Channel
                Debug "---- ssh3 channel " + Str(channel) + " finished ----"
                Debug CkSsh::ckGetReceivedText(ssh3,channel,"ansi")
                numFinished = numFinished + 1
                ssh3Finished = 1
            EndIf

        EndIf

    Wend

    ; --------------
    ; Sample output:

    ; 	---- ssh2 channel 101 finished ----
    ; 	Fri Dec 23 00:25:48 UTC 2016
    ; 
    ; 	---- ssh3 channel 102 finished ----
    ; 	Thu Dec 22 18:25:12 CST 2016
    ; 
    ; 	---- ssh1 channel 100 finished ----
    ; 	Thu Dec 22 18:25:48 CST 2016


    CkSsh::ckDispose(ssh1)
    CkSsh::ckDispose(ssh2)
    CkSsh::ckDispose(ssh3)


    ProcedureReturn
EndProcedure