.\" Automatically generated by Pod::Man 2.27 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Net::OpenSSH::Parallel 3pm" .TH Net::OpenSSH::Parallel 3pm "2012-05-04" "perl v5.18.2" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Net::OpenSSH::Parallel \- Run SSH jobs in parallel .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Net::OpenSSH::Parallel; \& \& my $pssh = Net::OpenSSH::Parallel\->new(); \& $pssh\->add_host($_) for @hosts; \& \& $pssh\->push(\*(Aq*\*(Aq, scp_put => \*(Aq/local/file/path\*(Aq, \*(Aq/remote/file/path\*(Aq); \& $pssh\->push(\*(Aq*\*(Aq, command => \*(Aqgurummm\*(Aq, \& \*(Aq/remote/file/path\*(Aq, \*(Aq/tmp/output\*(Aq); \& $pssh\->push($special_host, command => \*(Aqprumprum\*(Aq, \*(Aq/tmp/output\*(Aq); \& $pssh\->push(\*(Aq*\*(Aq, scp_get => \*(Aq/tmp/output\*(Aq, \*(Aqlogs/%HOST%/output\*(Aq); \& \& $pssh\->run; .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" Run this here, that there, etc. .PP \&\f(CW\*(C`Net::OpenSSH::Parallel\*(C'\fR is an scheduler that can run commands in parallel in a set of hosts through \s-1SSH.\s0 It tries to find a compromise between being simple to use, efficient and covering a good part of the problem space of parallel process execution via \s-1SSH.\s0 .PP Obviously, it is build on top of Net::OpenSSH! .PP Common usage of the module is as follows: .IP "\(bu" 4 create a \f(CW\*(C`Net::OpenSSH::Parallel\*(C'\fR object .IP "\(bu" 4 register the hosts where you want to run commands with the \&\*(L"add_host\*(R" method .IP "\(bu" 4 queue the actions you want to run (commands, file copy operations, etc.) using the \*(L"push\*(R" method. .IP "\(bu" 4 call the \*(L"run\*(R" method and let the parallel scheduler take care of everything! .SS "Labelling hosts" .IX Subsection "Labelling hosts" Every host is identified by an unique label that is given when the host is registered into the parallel scheduler. Usually, the host name is used also as the label, but this is not required by the module. .PP The rationale behind using labels is that a hostname does not necessarily identify unique \*(L"remote processors\*(R" (for instance, sometimes your logical \*(L"remote processors\*(R" may be user accounts distributed over a set of hosts: \f(CW\*(C`foo1@bar1\*(C'\fR, \f(CW\*(C`foo2@bar1\*(C'\fR, \&\f(CW\*(C`foo3@bar2\*(C'\fR, ...; a set of hosts that are accesible behind an unique \&\s-1IP,\s0 listening in different ports; etc.) .SS "Selecting hosts" .IX Subsection "Selecting hosts" Several of the methods of this module (well, currently, just \f(CW\*(C`push\*(C'\fR) accept a selector string to determine which of the registered hosts should be affected by the operation. .PP For instance, in... .PP .Vb 1 \& $pssh\->push(\*(Aq*\*(Aq, command => \*(Aqls\*(Aq) .Ve .PP the first argument is the selector. The one used here, \f(CW\*(C`*\*(C'\fR, selects all the registered hosts. .PP Other possible selectors are: .PP .Vb 4 \& \*(Aqbar*\*(Aq # selects everything beginning by \*(Aqbar\*(Aq \& \*(Aqfoo1,foo3,foo6\*(Aq # selects the hosts of the given names \& \*(Aqbar*,foo1,foo3,foo6\*(Aq # both \& \*(Aq*doz*\*(Aq # everything containing \*(Aqdoz\*(Aq .Ve .PP \&\fINote: I am still considering how the selector mini-language should be, don't hesitate to send your suggestions!\fR .SS "Local resource usage" .IX Subsection "Local resource usage" When the number of hosts managed by the scheduler is too high, the local node can become overloaded. .PP Roughly, every \s-1SSH\s0 connection requires two local \f(CW\*(C`ssh\*(C'\fR processes (one to run the \s-1SSH\s0 connection and another one to launch the remote command) that results in around 5MB of \s-1RAM\s0 usage per host. .PP \&\s-1CPU\s0 usage varies greatly depending on the tasks carried out. The most expensive are short remote tasks (because of the local process creation and destruction overhead) and tasks that transfer big ammounts of data through \s-1SSH \s0(because of the encryption going on). .PP In practice, \s-1CPU\s0 usage doesn't matter too much (mostly because the \s-1OS\s0 would be able to manage it but also because there is not too many things we can do to reduce it) and usually it is \s-1RAM\s0 about what we should be more concerned. .PP The module accepts two parameters to limit resource usage: .IP "\(bu" 4 \&\f(CW\*(C`workers\*(C'\fR .Sp is the maximun number of remote commands that can be running concurrently. .IP "\(bu" 4 \&\f(CW\*(C`connections\*(C'\fR .Sp is the maximum number of \s-1SSH\s0 connections that can be active concurrently. .PP In practice, limiting the maximum number of connections indirectly limits \s-1RAM\s0 usage and limiting the the maximum number of workers indirectly limits \s-1CPU\s0 usage. .PP The module requires the maximum number of connections to be at least equal or bigger than the maximun number of workers, and it is recomended that \f(CW\*(C`maximum_connections >= 2 * maximum_workers\*(C'\fR (otherwise the scheduler will not be able to reuse connections efficiently). .PP You will have to experiment to find out which combinations give the best results in your particular scenarios. .PP Also, for small sets of hosts you can just let these parameters unlimited. .SS "Variable expansion" .IX Subsection "Variable expansion" This module activates Net::OpenSSH variable expansion by default. That way, it is possible to easily customize the actions executed on every host in base to some of its properties. .PP For instance: .PP .Vb 1 \& $pssh\->push(\*(Aq*\*(Aq, scp_get => "/var/log/messages", "messages.%HOST%"); .Ve .PP copies the log files appending the name of the remote hosts to the local file names. .PP The variables \f(CW\*(C`HOST\*(C'\fR, \f(CW\*(C`USER\*(C'\fR, \f(CW\*(C`PORT\*(C'\fR and \f(CW\*(C`LABEL\*(C'\fR are predefined. .SS "Error handling" .IX Subsection "Error handling" When something goes wrong (for instance, some host is unreachable, some connection dies, some command fails, etc.) the module can handle the error in several predefined ways as follows: .PP \fIError policies\fR .IX Subsection "Error policies" .PP To set the error handling police, \*(L"new\*(R", \*(L"add_host\*(R" and \*(L"push\*(R" methods support and optional \f(CW\*(C`on_error\*(C'\fR argument that can take the following values (these constants are available from Net::OpenSSH::Parallel::Constants): .IP "\s-1OSSH_ON_ERROR_IGNORE\s0" 4 .IX Item "OSSH_ON_ERROR_IGNORE" Ignores the error and continues executing tasks in the host queue as it had never happened. .IP "\s-1OSSH_ON_ERROR_ABORT\s0" 4 .IX Item "OSSH_ON_ERROR_ABORT" Aborts the processing on the corresponding host. The error will be propagated to other hosts joining it at any later point once the join is reached. .Sp In other words, this police aborts the queued jobs for this host and any other that has a dependency on it. .IP "\s-1OSSH_ON_ERROR_DONE\s0" 4 .IX Item "OSSH_ON_ERROR_DONE" Similar to \f(CW\*(C`OSSH_ON_ERROR_ABORT\*(C'\fR but will not propagate errors to other hosts via joins. .IP "\s-1OSSH_ON_ERROR_ABORT_ALL\s0" 4 .IX Item "OSSH_ON_ERROR_ABORT_ALL" Causes all the host queues to be aborted as soon as possible (and that usually means after currently running actions end). .IP "\s-1OSSH_ON_ERROR_REPEAT\s0" 4 .IX Item "OSSH_ON_ERROR_REPEAT" The module will try to perform the current task again and again until it succeeds. This police can lead to an infinite loop and so its direct usage is discouraged (but see the following point about setting the policy dynamically). .PP The default policy is \f(CW\*(C`OSSH_ON_ERROR_ABORT\*(C'\fR. .PP \fISetting the policy dynamically\fR .IX Subsection "Setting the policy dynamically" .PP When a subroutine reference is used as the policy instead of the any of the constants previously described, the given subroutine will be called on error conditions as follows: .PP .Vb 1 \& $on_error\->($pssh, $label, $error, $task) .Ve .PP \&\f(CW$pssh\fR is a reference to the \f(CW\*(C`Net::OpenSSH::Parallel\*(C'\fR object, \&\f(CW$label\fR is the label associated to the host where the error happened. \f(CW$error\fR is the error type as defined in Net::OpenSSH::Parallel::Constants and \f(CW$task\fR is a reference to the task that was being carried out. .PP The return value of the subroutine must be one of the described constants and the corresponding policy will be applied. .PP \fIRetrying connection errors\fR .IX Subsection "Retrying connection errors" .PP If the module fails when trying to stablish a new \s-1SSH\s0 connection or when an existing connection dies unexpectedly, the option \&\f(CW\*(C`reconnections\*(C'\fR can be used to instruct the module to retry the connection until it succeds or the given maximun is reached. .PP \&\f(CW\*(C`reconnections\*(C'\fR is accepted by both the \*(L"new\*(R" and \*(L"add_host\*(R" methods. .PP Example: .PP .Vb 1 \& $pssh\->add_host(\*(Aqfoo\*(Aq, reconnections => 3); .Ve .PP Note that the reconnections maximum is not per host but per queued task. .SS "\s-1API\s0" .IX Subsection "API" These are the available methods: .ie n .IP "$pssh = Net::OpenSSH::Parallel\->new(%opts)" 4 .el .IP "\f(CW$pssh\fR = Net::OpenSSH::Parallel\->new(%opts)" 4 .IX Item "$pssh = Net::OpenSSH::Parallel->new(%opts)" creates a new object. .Sp The accepted options are: .RS 4 .ie n .IP "workers => $maximum_workers" 4 .el .IP "workers => \f(CW$maximum_workers\fR" 4 .IX Item "workers => $maximum_workers" sets the maximum number of operations that can be carried out in parallel (see \*(L"Local resource usage\*(R"). .ie n .IP "connections => $maximum_connections" 4 .el .IP "connections => \f(CW$maximum_connections\fR" 4 .IX Item "connections => $maximum_connections" sets the maximum number of \s-1SSH\s0 connections that can be stablished simultaneously (see \*(L"Local resource usage\*(R"). .Sp \&\f(CW$maximum_connections\fR must be equal or bigger than \f(CW$maximum_workers\fR .ie n .IP "reconnections => $maximum_reconnections" 4 .el .IP "reconnections => \f(CW$maximum_reconnections\fR" 4 .IX Item "reconnections => $maximum_reconnections" when connecting to some host fails, this argument tells the module the maximum number of additional connection atemps that it should perform before giving up. The default value is zero. .Sp See also \*(L"Retrying connection errors\*(R". .ie n .IP "on_error => $policy" 4 .el .IP "on_error => \f(CW$policy\fR" 4 .IX Item "on_error => $policy" Sets the error handling policy (see \*(L"Error handling\*(R"). .RE .RS 4 .RE .ie n .IP "$pssh\->add_host($label, %opts)" 4 .el .IP "\f(CW$pssh\fR\->add_host($label, \f(CW%opts\fR)" 4 .IX Item "$pssh->add_host($label, %opts)" .PD 0 .ie n .IP "$pssh\->add_host($label, $host, %opts)" 4 .el .IP "\f(CW$pssh\fR\->add_host($label, \f(CW$host\fR, \f(CW%opts\fR)" 4 .IX Item "$pssh->add_host($label, $host, %opts)" .PD registers a new host into the \f(CW$pssh\fR object. .IX Xref "add_host" .Sp \&\f(CW$label\fR is the name used to refer to the registered host afterwards. .Sp When the hostname argument is ommited, the label is used also as the hostname. .Sp The accepted options are: .RS 4 .ie n .IP "on_error => $policy" 4 .el .IP "on_error => \f(CW$policy\fR" 4 .IX Item "on_error => $policy" Sets the error handling policy (see \*(L"Error handling\*(R"). .ie n .IP "reconnections => $maximum_reconnections" 4 .el .IP "reconnections => \f(CW$maximum_reconnections\fR" 4 .IX Item "reconnections => $maximum_reconnections" See \*(L"Retrying connection errors\*(R". .RE .RS 4 .Sp Any additional option will be passed verbatim to the Net::OpenSSH constructor later. For instance: .Sp .Vb 1 \& $pssh\->add_host($host, user => $user, password => $password); .Ve .RE .ie n .IP "$pssh\->push($selector, $action, \e%opts, @action_args)" 4 .el .IP "\f(CW$pssh\fR\->push($selector, \f(CW$action\fR, \e%opts, \f(CW@action_args\fR)" 4 .IX Item "$pssh->push($selector, $action, %opts, @action_args)" .PD 0 .ie n .IP "$pssh\->push($selector, $action, @action_args)" 4 .el .IP "\f(CW$pssh\fR\->push($selector, \f(CW$action\fR, \f(CW@action_args\fR)" 4 .IX Item "$pssh->push($selector, $action, @action_args)" .PD pushes a new action into the queues selected by \f(CW$selector\fR. .Sp The supported actions are: .RS 4 .ie n .IP "command => @cmd" 4 .el .IP "command => \f(CW@cmd\fR" 4 .IX Item "command => @cmd" queue the given shell command on the selected hosts. .Sp Example: .Sp .Vb 3 \& $self\->push(\*(Aq*\*(Aq, \*(Aqcommand\*(Aq \& { stdout_fh => $find_fh, stderr_to_stdout => 1 }, \& \*(Aqfind\*(Aq, \*(Aq/my/dir\*(Aq); .Ve .ie n .IP "scp_get => @remote, $local" 4 .el .IP "scp_get => \f(CW@remote\fR, \f(CW$local\fR" 4 .IX Item "scp_get => @remote, $local" .PD 0 .ie n .IP "scp_put => @local, $remote" 4 .el .IP "scp_put => \f(CW@local\fR, \f(CW$remote\fR" 4 .IX Item "scp_put => @local, $remote" .PD These methods queue an \s-1SCP\s0 remote file copy operation in the selected hosts. .ie n .IP "rsync_get => @remote, $local" 4 .el .IP "rsync_get => \f(CW@remote\fR, \f(CW$local\fR" 4 .IX Item "rsync_get => @remote, $local" .PD 0 .ie n .IP "rsync_put => @local, $remote" 4 .el .IP "rsync_put => \f(CW@local\fR, \f(CW$remote\fR" 4 .IX Item "rsync_put => @local, $remote" .PD These methods queue an rsync remote file copy operation in the selected hosts. .ie n .IP "sub => sub { ... }, @extra_args" 4 .el .IP "sub => sub { ... }, \f(CW@extra_args\fR" 4 .IX Item "sub => sub { ... }, @extra_args" .PD 0 .ie n .IP "sub { ... }, @extra_args" 4 .el .IP "sub { ... }, \f(CW@extra_args\fR" 4 .IX Item "sub { ... }, @extra_args" .PD Queues a call to a perl subroutine that will be executed locally. .Sp Note that subroutines are executed synchronously in the same process, so no other task will be scheduled while they are running. .Sp The sub is called as .Sp .Vb 1 \& $sub\->($pssh, $label, @extra_args) .Ve .Sp where \f(CW$pssh\fR is the current Net::OpenSSH::Parallel object. .ie n .IP "parsub => sub { ... }, @extra_args" 4 .el .IP "parsub => sub { ... }, \f(CW@extra_args\fR" 4 .IX Item "parsub => sub { ... }, @extra_args" Queues a call to a perl subroutine that will be executed locally on a forked process. .Sp The sub is called as .Sp .Vb 1 \& $sub\->($label, $ssh, @extra_args) .Ve .Sp Where \f(CW$ssh\fR is an Net::OpenSSH object that can be used to interact with the remote machine. .Sp Note that the interface is different to that of the \f(CW\*(C`sub\*(C'\fR action. .Sp An example of usage: .Sp .Vb 12 \& sub sudo_install { \& my ($label, $ssh, @pkgs) = @_; \& my ($pty) = $ssh\->open2pty(\*(Aqsudo\*(Aq, \*(Aqapt\-get\*(Aq, \*(Aqinstall\*(Aq, @pkgs); \& my $expect = Expect\->init($pty); \& $expect\->raw_pty(1); \& $expect\->expect($timeout, ":"); \& $expect\->send("$passwd\en"); \& $expect\->expect($timeout, "\en"); \& $expect\->raw_pty(0); \& while(<$expect>) { print }; \& close $expect; \& } \& \& $pssh\->push(\*(Aq*\*(Aq, parsub => \e&sudo_install, \*(Aqscummvm\*(Aq); .Ve .Sp If the subroutine dies or calls \f(CW\*(C`_exit\*(C'\fR with a non zero return code, the error handling code will be triggered (see \*(L"Error handling\*(R"). .Sp The \f(CW\*(C`parsub\*(C'\fR action accepts the additional option \f(CW\*(C`no_ssh\*(C'\fR indicating that the \f(CW$ssh\fR object is not going to be used. For instance: .Sp .Vb 6 \& $pssh\->push(\*(Aq*\*(Aq, parsub => { no_ssh => 1 }, \& sub { \& my $label = shift; \& { exec "gzip", "/tmp/file\-$label" }; \& die "exec failed: $!"; \& }); .Ve .Sp That can make the script faster when the maximum number of simultaneous connections is limited. See \*(L"Local resource usage\*(R". .ie n .IP "join => $selector" 4 .el .IP "join => \f(CW$selector\fR" 4 .IX Item "join => $selector" Joins allow to synchronize jobs between different servers. .Sp For instance: .Sp .Vb 3 \& $ssh\->push(\*(Aqserver_B\*(Aq, scp_get => \*(Aq/tmp/foo\*(Aq, \*(Aqfoo\*(Aq); \& $ssh\->push(\*(Aqserver_A\*(Aq, join => \*(Aqserver_B\*(Aq); \& $ssh\->push(\*(Aqserver_A\*(Aq, scp_put => \*(Aqfoo\*(Aq, \*(Aq/tmp/foo\*(Aq); .Ve .Sp The join makes server_A to wait for the \f(CW\*(C`scp_get\*(C'\fR operation queued in server_B to finish before proceeding with the \f(CW\*(C`scp_put\*(C'\fR. .Sp In general the join will make the selected servers wait for any task queued on the servers matched by \f(CW$selector\fR to finish before proceeding with the next queued tasks. .Sp One common usage is to synchronize all servers at some point: .Sp .Vb 1 \& $ssh\->push(\*(Aq*\*(Aq, join => \*(Aq*\*(Aq); .Ve .Sp By default, errors are propagated at joins. For instance, in the example above, if the scp_get operation queued on server_B failed, it would abort any further operation queued on server_B and any further operation queued after the join in server_A. See also \*(L"Error handling\*(R". .ie n .IP "here => $tag" 4 .el .IP "here => \f(CW$tag\fR" 4 .IX Item "here => $tag" Push a tag in the stack that can be used as a target for goto operations. .ie n .IP "goto => $target" 4 .el .IP "goto => \f(CW$target\fR" 4 .IX Item "goto => $target" Jumps forward until the given \f(CW\*(C`here\*(C'\fR tag is reached. .Sp Joins to other hosts queues will be ignored, and joins from other queues to this one will be succesfully fulfilled. For instance: .Sp .Vb 9 \& $pssh\->add_host(A => ...); \& $pssh\->add_host(B => ...); \& $pssh\->push(\*(Aq*\*(Aq, cmd => \*(Aqecho "hello from %HOST"\*(Aq); \& $pssh\->push(\*(AqA\*(Aq, goto => \*(Aqthere\*(Aq); \& $pssh\->push(\*(AqA\*(Aq, join => \*(AqB\*(Aq); # ignored by A on goto \& $pssh\->push(\*(AqB\*(Aq, join => \*(AqA\*(Aq); # fulfilled by A on goto \& $pssh\->push(\*(Aq*\*(Aq, cmd => \*(Aqecho "hello from %HOST% again"\*(Aq); \& $pssh\->push(\*(Aq*\*(Aq, here => \*(Aqthere\*(Aq); \& $pssh\->push(\*(Aq*\*(Aq, cmd => \*(Aqecho "bye bye from %HOST%"); .Ve .Sp Note that it is not possible to jump backguards. .Sp There is an special target \f(CW\*(C`END\*(C'\fR that can be used to jump to the end of the queue. .IP "stop" 4 .IX Item "stop" Discards any additional operations queued. Any pending joins will be successfully fulfilled. .Sp It is equivalent to .Sp .Vb 1 \& $pssh\->push(\*(Aq*\*(Aq, goto => \*(AqEND\*(Aq); .Ve .RE .RS 4 .Sp When given, \f(CW%opts\fR can contain the following options: .ie n .IP "on_error => $fail_mode" 4 .el .IP "on_error => \f(CW$fail_mode\fR" 4 .IX Item "on_error => $fail_mode" .PD 0 .IP "on_error => sub { ... }" 4 .IX Item "on_error => sub { ... }" .PD See \*(L"Error handling\*(R". .ie n .IP "or_goto => $tag" 4 .el .IP "or_goto => \f(CW$tag\fR" 4 .IX Item "or_goto => $tag" Supported for \f(CW\*(C`command\*(C'\fR, \f(CW\*(C`scp_get\*(C'\fR, \f(CW\*(C`scp_put\*(C'\fR, \f(CW\*(C`rsync_get\*(C'\fR and \&\f(CW\*(C`rsync_put\*(C'\fR, when the command, scp or rsync operation fails a goto to the given target is performed. .Sp For instance: .Sp .Vb 4 \& $pssh\->all(command => { or_goto => \*(Aqno_file\*(Aq }, \& "test \-f /etc/foo"); \& $pssh\->all(scp_get => "/etc/foo", "/tmp/foo\-%LABEL%"); \& $pssh\->all(here => "no_file"); .Ve .Sp Failures related to \s-1SSH\s0 errors do not trigger the goto but the error handling code. .ie n .IP "timeout => $seconds" 4 .el .IP "timeout => \f(CW$seconds\fR" 4 .IX Item "timeout => $seconds" not implemented yet! .IP "on_done => sub { ... }" 4 .IX Item "on_done => sub { ... }" not implemented yet! .RE .RS 4 .Sp Any other option will be passed to the corresponding Net::OpenSSH method (spawn, scp_put, etc.). .RE .ie n .IP "$pssh\->all($action => @args)" 4 .el .IP "\f(CW$pssh\fR\->all($action => \f(CW@args\fR)" 4 .IX Item "$pssh->all($action => @args)" .PD 0 .ie n .IP "$pssh\->all($action => \e%opts, @args)" 4 .el .IP "\f(CW$pssh\fR\->all($action => \e%opts, \f(CW@args\fR)" 4 .IX Item "$pssh->all($action => %opts, @args)" .PD Shortcut for... .Sp .Vb 1 \& $pssh\->push(\*(Aq*\*(Aq, $action, \e%opts, @args); .Ve .ie n .IP "$pssh\->run" 4 .el .IP "\f(CW$pssh\fR\->run" 4 .IX Item "$pssh->run" Runs the queued operations. .Sp It returns a true value on success and false otherwise. .ie n .IP "$pssh\->get_error($label)" 4 .el .IP "\f(CW$pssh\fR\->get_error($label)" 4 .IX Item "$pssh->get_error($label)" Returns the last error associated to the host of the given label. .ie n .IP "$pssh\->get_errors" 4 .el .IP "\f(CW$pssh\fR\->get_errors" 4 .IX Item "$pssh->get_errors" In list context returns a list of pairs \f(CW\*(C`$label => $error\*(C'\fR for the failed queues. .Sp In scalar context returns the number of failed queues. .SH "FAQ \- Frequently Asked Questions" .IX Header "FAQ - Frequently Asked Questions" .IP "Running remote commands with sudo" 4 .IX Item "Running remote commands with sudo" \&\fBQ\fR: I need to run the remote commands with sudo that asks for a password. How can I do it? .Sp \&\fBA\fR: First read the answer given to a similar question on Net::OpenSSH \s-1FAQ.\s0 .Sp The problem is that Net::OpenSSH::Parallel methods do not support the option, so you will have to use an external file. .Sp .Vb 2 \& $pssh\->push(\*(Aq*\*(Aq, cmd => { stdin_file => $passwd_file }, \& \*(Aqsudo\*(Aq, \*(Aq\-Skp\*(Aq, \*(Aq\*(Aq, \*(Aq\-\-\*(Aq, @cmd); .Ve .Sp One trick you can use if you only have one password is to use the \&\f(CW\*(C`DATA\*(C'\fR file handle: .Sp .Vb 6 \& $pssh\->push(\*(Aq*\*(Aq, cmd => { stdin_fh => \e*DATA}, \& \*(Aqsudo\*(Aq, \*(Aq\-Skp\*(Aq, \*(Aq\*(Aq, \*(Aq\-\-\*(Aq, @cmd); \& ... \& # and at the end of your script \& _\|_DATA_\|_ \& this\-is\-my\-remote\-password\-for\-sudo .Ve .Sp Or you can also use the \f(CW\*(C`parsub\*(C'\fR action: .Sp .Vb 1 \& my %sudo_passwords = (host1 => "foo", ...); \& \& sub sudo { \& my ($label, $ssh, @cmd) = @_; \& $ssh\->system({stdin_data => "$sudo_passwords{$label}\en"}, \& \*(Aqsudo\*(Aq, \*(Aq\-Skp\*(Aq, \*(Aq\*(Aq, \*(Aq\-\-\*(Aq, @cmd); \& } \& \& $pssh\->push(\*(Aq*\*(Aq, parsub => \e&sudo, @cmd); .Ve .SH "TODO" .IX Header "TODO" .IP "\(bu" 4 run N processes per host concurrently .Sp allow running more than one process per remote server concurrently .IP "\(bu" 4 delay before reconnect .Sp when connecting fails, do not try to reconnect inmediately but after some predefined period .IP "\(bu" 4 rationalize debugging .Sp currently it is a mess .IP "\(bu" 4 add loggin support .Sp log the operations performed in a given file .IP "\(bu" 4 stdio redirection .Sp add support for better handling of the Net::OpenSSH stdio redirection facilities .IP "\(bu" 4 configurable valid return codes .Sp Non zero exit code is not always an error. .SH "BUGS AND SUPPORT" .IX Header "BUGS AND SUPPORT" This module should be considered beta quality, everything seems to work but it may yet contain critical bugs. .PP If you find any, report it via or by email (to sfandino@yahoo.com), please. .PP Feedback and comments are also welcome! .PP The 'sub' and 'parsub' features should be considered experimental and its \s-1API\s0 or behaviour could be changed in future versions of the module. .SS "Reporting bugs" .IX Subsection "Reporting bugs" In order to report a bug, write a minimal program that triggers it and place the following line at the beggining: .PP .Vb 1 \& $Net::OpenSSH::Parallel::debug = \-1; .Ve .PP Then, send me (via rt or email) the debugging output you get when you run it. Include also the source code of the script, a description of what is going wrong and the details of your \s-1OS\s0 and the versions of Perl, \f(CW\*(C`Net::OpenSSH\*(C'\fR and \f(CW\*(C`Net::OpenSSH::Parallel\*(C'\fR you are using. .SS "Development version" .IX Subsection "Development version" The source code for this module is hosted at GitHub: . .SS "Commercial support" .IX Subsection "Commercial support" Commercial support, professional services and custom software development around this module are available through my current company. Drop me an email with a rough description of your requirements and we will get back to you \s-1ASAP.\s0 .SS "My wishlist" .IX Subsection "My wishlist" If you like this module and you're feeling generous, take a look at my Amazon Wish List: .PP Also consider contributing to the OpenSSH project this module builds upon: . .SH "SEE ALSO" .IX Header "SEE ALSO" Net::OpenSSH is used to manage the \s-1SSH\s0 connections to the remote hosts. .PP SSH::Batch has a similar focus as this module. In my opinion it is simpler to use but rather more limited. .PP GRID::Machine allows to run perl code distributed in a cluster via \&\s-1SSH.\s0 .PP If your application requires orchestating workflows more complex than those supported by Net::OpenSSH::Parallel, you should probably consider some \s-1POE\s0 or AnyEvent based solution (check POE::Component::OpenSSH). .PP App::MrShell is another module allowing to run the same command in several host in parallel. .PP Some people find easier to use Net::OpenSSH combined with Parallel::ForkManager, threads or Coro. .PP Net::SSH::Mechanize is another framework written on top of AnyEvent that allows to run remote commands through \s-1SSH\s0 in parallel. .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" Copyright X 2009\-2012 by Salvador Fandin\*~o (sfandino@yahoo.com). .PP This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.10.0 or, at your option, any later version of Perl 5 you may have available.