TABLE OF CONTENTS


::pwtk::remote

SYNOPSIS

proc ::pwtk::remote {args} {

USAGE

   remote  ?OPTIONS?  USER@HOST  SCRIPT_CODE
 or    
   remote  ?OPTIONS?  USER@HOST  SCRIPT_FILE

 where OPTIONS are:
     -fg
     -rdir  DIRECTORY
     -rpwtk FILE

ARGUMENTS

PURPOSE

Run on the remote host either the script code contained in the 'SCRIPT_CODE' argument or the script file specified by the 'SCRIPT_FILE' argument. PWTK checks if the last argument is a file; if so, it consider it as a script-file, otherwise it considers the last arguments as a script-code.

The connection and file transfer to a remote host is managed via ssh and rsync. A user must be able to connect to the remote host without password (e.g., the ~/.ssh/id_rsa.pub key must be included in the ~/.ssh/authorized_keys file on the remote host).

The configuration of the PWTK remote execution is specified in the $PWTK/config/remote.tcl file and the user can tune it with the ~/.pwtk/remote.tcl file.

OPTIONS

BEWARE

::pwtk::remote is useful for Beowulf-type clusters without batch-queuing. On HPC supercomputers, consider using the PWTK batch-queuing instead (see section: 2.8 Batch Queuing Support).

EXAMPLE

    # run a script code on a remote host:

    remote -rpwtk ~/prog/q-e/pwtk/pwtk -rdir ~/calc/QE/myProject user@remotehost {
       import common.pwtk
       runPW relax.Cu111-1x1-4L.in
    }

    # run the script file 'calculate.pwtk' on a remote host:

    remote user@remotehost calculate.pwtk

DESCRIPTION

In the default "background" mode, PWTK submits the script to a remote host and returns immediately for further processing, i.e., the command is non-blocking. To wait for "background" remote process(es), use the ::pwtk::remote_wait command.

In the "foreground" mode (the -fg option), PWTK waits for the calculation to finish, i.e., the command is blocking.

By default, ::pwtk::remote runs the script on the remote host in the directory, which is a mirror of the current local directory. For example, if the current working directory on the local host is ~/path/to/project, then the calculation will be run on ~/path/to/project directory on the remote host (remote file-system); note that the value of $HOME on remote and local hosts can differ.

To request that the calculation on the remote host should run in an arbitary directory, use the "-rdir DIRECTORY" option.

BEWARE

The I/O files produced by remote calculations will not be copied to the current local directory (the only exception is the remote PWTK log file). It is the responsability of the user to copy the I/O files back to the local host.

RETURN VALUE

SOURCE

    variable remote_index
    variable remote

    # parse the options

    set options {
        {fg             "run the calculation in the foreground mode (default = background)"}
        {rdir.arg  {}   "directory on the remote host where calculation will be run (default = mirror of the current local directory but on the remote host)"}
        {rpwtk.arg pwtk "full pathname of the PWTK launcher on the remote host (default = pwtk)"}
        {id.arg    {}   "ID of this remote job, supplied by the caller"}
        {fid.arg   {}   "File-ID used for assembling the filename of the script"}
        {np             "do not use the propagate mechanism (default = use propagate)"}
        {direct         "use the script file is used directly (implies -np)"}
    }
    set narg 2
    set usage "?-f?  ?-fg?  ?-rdir DIRECTORY?  ?-rpwtk FILE?  ?-id ID?  ?-fid ID?  ?-np?  ?-direct?  user@host script"
    ::pwtk::parseOpt_
    
    # assign the last two arguments
    
    lassign $args user_at_host lastarg

    # get the hostname

    set host     [rhost_ $user_at_host]
    set hostonly [rhostonly_ $user_at_host]

    # get the remote directory
    
    #set rdir [::fileutil::relative $::env(HOME) [pwd]]
    set rdir [::fileutil::stripPath $::env(HOME) [pwd]]
    if { $opt(rdir) ne {} } {
        set rdir $opt(rdir)
    }
    set pdir [expr { [file pathtype $rdir] eq "relative" ? "~/$rdir" : $rdir }] ; # used for printing only

    # index

    if { $opt(id) ne {} } {
        set index $opt(id)
        set jobtxt " for job-$index"
    } else {
        set index [incr remote_index($hostonly)]
        set jobtxt ""
    }
    
    # findex

    if { $opt(fid) ne {} } {
        set findex $opt(fid)
    } else {
        set findex $index
    }    
    
    # lastarg (aka script)

    if { $opt(direct) } {
        fileMustExist $lastarg "PWTK script"       
        set scriptName $lastarg
        set scriptLog  [file rootname $lastarg].log
        set opt(np) 1
    } else {
        if { [file exists $lastarg] } {
            # the last argument is a file
            set scriptHead [file rootname $lastarg].
            set scriptCode [readFile $lastarg]
        } else {
            # the last argument is a script code
            set scriptCode $lastarg
            if { [set scriptHead [file tail [file rootname [info script]]]] ne {} } {
                append scriptHead .
            }
        }
        set scriptName $hostonly.${scriptHead}$findex.pwtk
        set scriptLog  $hostonly.${scriptHead}$findex.log
    }
    
    # make a script
    
    if { ! $opt(np) } {
        set scriptCode [::pwtk::propagate_dump]\n$scriptCode
    }
    if { ! $opt(direct) } {
        writeFile $scriptName $scriptCode
    }

    # printout
    
    print REMOTE "Running a script$jobtxt remotely on $user_at_host"
    print "
remote directory     :   $pdir
remote PWTK script   :   $scriptName
remote PWTK log file :   $scriptLog
"

    # check if the remote host is alive and user can connect to it

    #if { ! [host_is_up $user_at_host] } {
    #    ::pwtk::error "cannot communicate with '$host'\n\n$::errorInfo" 1
    #}
    if { ! [can_connect $user_at_host] } {
        ::pwtk::error "cannot connect to '$user_at_host'" 1
    }
            
    # create the remote directory and rsync the script there

    print "$remote(rsync)  $scriptName  $user_at_host:$rdir/\n"
    rmkdir $user_at_host $rdir
    rsync $scriptName $user_at_host:$rdir/$scriptName
    rsync_imports_ $user_at_host
    
    # check if $opt(rpwtk) is executable
    if { [rtclsh $user_at_host "puts \[auto_execok $opt(rpwtk)]"] eq {} } {
        ::pwtk::error "the specified PWTK executable '$opt(rpwtk)' either is not executable or does not exist" 1
    }
    
    # remote-exec the PWTK script

    print "Running remotely on $user_at_host:$rdir/
$opt(rpwtk) $scriptName > $scriptLog 2>&1\n"

    set pid [::pwtk::rexec_bg $user_at_host "cd $rdir; $remote(nohup) $opt(rpwtk) $scriptName > $scriptLog 2>&1 & echo \$!"]
    print "Remote PID = $pid ($scriptName)\n"; # N.B. do not use PID: as not to clash with the PWTK header PID: line

    # background or foreground ?
    
    if { $opt(fg) } {
        print "Waiting for the remote process $pid to finish...\n"
        remote_pidwait $user_at_host $pid
        
        print "\n$remote(rsync)  $user_at_host:$rdir/$scriptLog  .\n"
        rsync $user_at_host:$rdir/$scriptLog .
        return ""
    } else {
        # store the info about this background remote job

        set id [incr remote(ID)]
        
        array set remote [subst {
            ident,$id                      $hostonly,$index
            ID,$hostonly,$index            $id
            PID,$hostonly,$index           $pid
            user_at_host,$hostonly,$index  $user_at_host
            script,$hostonly,$index        $scriptName
            log,$hostonly,$index           $scriptLog
            rdir,$hostonly,$index          $rdir
            rpwtk,$hostonly,$index         $opt(rpwtk)
        }]
        return $id
    }
}