Objective-C
Objective-C
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 Objective-C Downloads
#import <CkoSsh.h>
#import <NSString.h>
BOOL success = NO;
// 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.
CkoSsh *ssh1 = [[CkoSsh alloc] init];
CkoSsh *ssh2 = [[CkoSsh alloc] init];
CkoSsh *ssh3 = [[CkoSsh alloc] init];
int port = 22;
// 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.
NSString *password = @"mySshPassword";
success = [ssh1 Connect: @"ssh-server1.example.com" port: [NSNumber numberWithInt: port]];
if (success == NO) {
NSLog(@"%@",ssh1.LastErrorText);
return;
}
success = [ssh1 AuthenticatePw: @"mySshLogin" password: password];
if (success == NO) {
NSLog(@"%@",ssh1.LastErrorText);
return;
}
success = [ssh2 Connect: @"ssh-server2.example.com" port: [NSNumber numberWithInt: port]];
if (success == NO) {
NSLog(@"%@",ssh2.LastErrorText);
return;
}
success = [ssh2 AuthenticatePw: @"mySshLogin" password: password];
if (success == NO) {
NSLog(@"%@",ssh2.LastErrorText);
return;
}
success = [ssh3 Connect: @"ssh-server3.example.com" port: [NSNumber numberWithInt: port]];
if (success == NO) {
NSLog(@"%@",ssh3.LastErrorText);
return;
}
success = [ssh3 AuthenticatePw: @"mySshLogin" password: password];
if (success == NO) {
NSLog(@"%@",ssh3.LastErrorText);
return;
}
// This command sleeps for 5 seconds and then prints the system date/time, making the parallel
// execution easy to observe.
NSString *cmd = @"sleep 5; date";
// Start the command on each server. QuickCmdSend returns immediately.
int channel1 = [[ssh1 QuickCmdSend: cmd] intValue];
if (channel1 < 0) {
NSLog(@"%@",ssh1.LastErrorText);
return;
}
int channel2 = [[ssh2 QuickCmdSend: cmd] intValue];
if (channel2 < 0) {
NSLog(@"%@",ssh2.LastErrorText);
return;
}
int channel3 = [[ssh3 QuickCmdSend: cmd] intValue];
if (channel3 < 0) {
NSLog(@"%@",ssh3.LastErrorText);
return;
}
// 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.)
int pollTimeoutMs = 50;
int numFinished = 0;
BOOL finished1 = NO;
BOOL finished2 = NO;
BOOL finished3 = NO;
while (numFinished < 3) {
if (!finished1) {
int ch1 = [[ssh1 QuickCmdCheck: [NSNumber numberWithInt: pollTimeoutMs]] intValue];
if (ch1 == -2) {
NSLog(@"%@",ssh1.LastErrorText);
return;
}
if (ch1 >= 0) {
NSLog(@"%@%d%@",@"---- ssh1 channel ",ch1,@" finished ----");
NSString *out1 = [ssh1 GetReceivedText: [NSNumber numberWithInt: ch1] charset: @"utf-8"];
if (ssh1.LastMethodSuccess == NO) {
NSLog(@"%@",ssh1.LastErrorText);
return;
}
NSLog(@"%@",out1);
finished1 = YES;
numFinished = numFinished + 1;
}
}
if (!finished2) {
int ch2 = [[ssh2 QuickCmdCheck: [NSNumber numberWithInt: pollTimeoutMs]] intValue];
if (ch2 == -2) {
NSLog(@"%@",ssh2.LastErrorText);
return;
}
if (ch2 >= 0) {
NSLog(@"%@%d%@",@"---- ssh2 channel ",ch2,@" finished ----");
NSString *out2 = [ssh2 GetReceivedText: [NSNumber numberWithInt: ch2] charset: @"utf-8"];
if (ssh2.LastMethodSuccess == NO) {
NSLog(@"%@",ssh2.LastErrorText);
return;
}
NSLog(@"%@",out2);
finished2 = YES;
numFinished = numFinished + 1;
}
}
if (!finished3) {
int ch3 = [[ssh3 QuickCmdCheck: [NSNumber numberWithInt: pollTimeoutMs]] intValue];
if (ch3 == -2) {
NSLog(@"%@",ssh3.LastErrorText);
return;
}
if (ch3 >= 0) {
NSLog(@"%@%d%@",@"---- ssh3 channel ",ch3,@" finished ----");
NSString *out3 = [ssh3 GetReceivedText: [NSNumber numberWithInt: ch3] charset: @"utf-8"];
if (ssh3.LastMethodSuccess == NO) {
NSLog(@"%@",ssh3.LastErrorText);
return;
}
NSLog(@"%@",out3);
finished3 = YES;
numFinished = numFinished + 1;
}
}
}
[ssh1 Disconnect];
[ssh2 Disconnect];
[ssh3 Disconnect];