Thursday, July 12, 2012

Parallel remote command ssh execution script

The following script executes the given commands on specified remote hosts in parallel. Notice that default actors corePoolSize parameter has been set to a higher value than the default one, as cpu usage for this script will remain low, actors will mostly wait for remote server results. (jassh.jar executable jar is available here - JASSH project page)
exec java -jar jassh.jar -deprecation -savecompiled -usejavacp -nocompdaemon "$0" "$@"

import fr.janalyse.ssh._
import util.Properties

if (args.size<2) {
  println("""usage : rexec.scala command [user[:password]@]host[:port] ...""")
  println("""  Of course prefer public key authentication, default behavior if no password is provided """)
  println("""  example : rexec.scala "hostname" toto@ toto@""")

// host | host:port | username@host |username:password@host | username@host:port | ... 
val serverRE="""(?:(\w+)(?:[:](.*))?@)?((?:(?:\d+[.]){3}\d+)|(?:\w+))(?:[:](\d+))?""".r

val cmd2exec=args.head
val servers = args.tail map {
  case serverRE(user, password, host, port) => 
      host     = host,
      username = Option(user).getOrElse(Properties.userName),
      password = SSHPassword(Option(password)),
      port     = Option(port).map(_.toInt).getOrElse(22)
  case notUnderstood => 
    throw new RuntimeException("Couln'd understand remote host description : "+notUnderstood)

def rexec(server:SSHOptions, cmd2exec:String):String = 
     .map("%8s@%-16s: %s".format(server.username,, _))
var sys=new scala.sys.SystemProperties()

import actors.Actor._
val caller=self
for(server <- servers) actor { caller ! rexec(server, cmd2exec) }
for(_ <- servers) receive {case msg => println(msg) }

usage example :

$ ./rexec.scala "uname -r" test@  test:testtest@ 
    test@       : 3.2.1-gentoo-r2
    test@   : 3.2.0-2-486

From what I've read, scala 2.10 will provide better solutions to tune threads pool, will update this post later.

No comments:

Post a Comment