REXEC(3)

โœจ REXEC โœจ (the rexec man page, section 3, rexec 1.2 bestie ๐Ÿ’–)

๐Ÿ’ซ NAME ๐Ÿ’ซ

nfstest.rexec โ€” the Remote procedure module ๐Ÿซถ


๐ŸŒธ DESCRIPTION ๐ŸŒธ

Okay so picture this: you've got a whole lil toolbox for running a huge range of commands, statements, expressions or functions over on a remote host. How? By running a server process on that remote host that just... serves your requests without disconnecting. Iconic behavior honestly. โœจ

The way that matters is: it lets you do a whole sequence of operations remotely and not lose state. Like, you could open a file remotely, go do a bunch of other stuff, and then write to that same still-open file without opening it all over again. No re-opening, no drama. ๐Ÿ’…

The remote server can also run as a different user by using the sudo option and sending seteuid. And it can run locally too โ€” using fork when it's running as the same user, or using the shell when the sudo option is in play. Versatile queen. ๐Ÿ‘‘

โš ๏ธ Real talk though: to use this module, your user id has to be able to ssh to the remote host without needing a password. No password, no vibes. Periodt.

๐ŸŽ€ CLASSES ๐ŸŽ€

๐ŸŒˆ class RemoteServer(builtins.object)

โœจ Methods defined here:

  • __del__(self) โ€” the Destructor ๐Ÿชฆ
  • __init__(self, port, logfile=None) โ€” Remote procedure server
  • log(self, msg) โ€” write message to log file ๐Ÿ“
  • start(self)

๐Ÿฆ‹ class Rexec(baseobj.BaseObj)

Rexec object ๐Ÿซง

Rexec() -> New remote procedure object

Arguments:

  • servername โ€” name or IP address of remote server
  • logfile โ€” name of logfile to create on remote server
  • sudo โ€” run remote server as root

Usage:

from nfstest.rexec import Rexec

# Function to be defined at remote host
def add_one(n):
    return n + 1

# Function to be defined at remote host
def get_time(delay=0):
    time.sleep(delay)
    return time.time()

# Create remote procedure object
x = Rexec("192.168.0.85")

# Define function at remote host
x.rcode(add_one)

# Evaluate the expression calling add_one()
out = x.reval("add_one(67)")

# Run the function with the given argument
out = x.run("add_one", 7)

# Run built-in functions
import time
out = x.run(time.time)

# Import libraries and symbols
x.rimport("time", ["sleep"])
x.run("sleep", 2)

# Define function at remote host -- since function uses the
# time module, this module must be first imported
x.rimport("time")
x.rcode(get_time)

# Evaluate the expression calling get_time()
out = x.reval("get_time()")

# Run the function with the given argument
out = x.run("get_time", 10)

# Open file on remote host
fd = x.run(os.open, "/tmp/testfile", os.O_WRONLY|os.O_CREAT|os.O_TRUNC)
count = x.run(os.write, fd, "hello there
       ")
x.run(os.close, fd)

# Use of positional arguments
out = x.run("get_time", 2)

# Use of named arguments
out = x.run("get_time", delay=2)

# Use of NOWAIT option for long running functions so other things
# can be done while waiting
x.run("get_time", 2, NOWAIT=True)
while True:
    # Poll every 0.1 secs to see if function has finished
    if x.poll(0.1):
        # Get results
        out = x.results()
        break

# Create remote procedure object as a different user
# First, run the remote server as root
x = Rexec("192.168.0.85", sudo=True)
# Then set the effective user id
x.run(os.seteuid, 1000)

๐ŸŒŸ Methods defined here:

  • __del__(self) โ€” Destructor ๐Ÿชฆ
  • __init__(self, servername=None, logfile=None, sudo=False, timeout=30.0) โ€” Constructor

Initialize object's private data. ๐Ÿ’พ

  • servername โ€” host name or IP address of host where remote server will run [Default: None (run locally)]
  • logfile โ€” pathname of log file to be created on remote host [Default: None]
  • sudo โ€” run remote procedure server as root [Default: False]
  • timeout โ€” timeout for synchronous calls [Default: 30.0]
  • close(self) โ€” close connection to remote server ๐Ÿ‘‹
  • poll(self, timeout=0) โ€” return whether there is any data available to be read
    • timeout โ€” maximum time in seconds to block, if timeout is None then an infinite timeout is used โณ
  • rcode(self, code) โ€” define function on remote server
  • results(self, xid=None) โ€” return pending results
  • reval(self, expr) โ€” evaluate expression on remote server ๐Ÿงฎ
  • rexec(self, expr) โ€” execute statement on remote server
  • rimport(self, module, symbols=[]) โ€” import module on remote server ๐Ÿ“ฆ
    • module โ€” module to import in the remote server
    • symbols โ€” if given, import only these symbols from the module
  • run(self, *kwts, **kwds) โ€” run function on remote server ๐Ÿƒโ™€๏ธ

The first positional argument is the function to be executed. All other positional arguments and any named arguments are treated as arguments to the function.

  • wait(self, objlist=None, timeout=0) โ€” return a list of Rexec objects where data is available to be read
    • objlist โ€” list of Rexec objects to poll, if not given use current object
    • timeout โ€” maximum time in seconds to block, if timeout is None then an infinite timeout is used โณ

๐Ÿ‘€ SEE ALSO ๐Ÿ‘€

baseobj(3)


๐Ÿ’€ BUGS ๐Ÿ’€

No known bugs. (Not a single one, bestie โ€” we ate and left no crumbs. ๐Ÿ”ฅ)


๐Ÿ‘‘ AUTHOR ๐Ÿ‘‘

Jorge Mora (mora@netapp.com)


And that's the whole page, fr fr ๐Ÿซถ This was NFStest 3.2, dated 21 March 2023 โ€” go forth and remote-procedure slay ๐Ÿ’…โœจ

๐Ÿ“ฆ where this page comes from