Reference
REPL syntax
RemoteREPL syntax is just normal Julia REPL syntax, the only minor difference is that ?expr
produces help for expr
, but we don't have a separate help mode for this.
Security considerations
Note that any logged-in users on the client or server machines can execute arbitrary commands in the serve_repl() process. For this reason, you should avoid using RemoteREPL on shared infrastructure like compute clusters if you don't trust other users on the system. (In the future perhaps we can avoid this by forwarding between socket files?)
This package uses an SSH tunnel by default to forward traffic when host != Sockets.localhost
, so it should be quite secure to use over an open network. If both client and server are on a secure network, it's possible to skip the tunnel to avoid setting up SSH. However, if anyone breaks into your network you'll be left with no security whatsoever.
TLDR; this package aims to provide safe defaults for single-user machines. However, do not expose the RemoteREPL port to an open network. Abitrary remote code execution is the main feature provided by this package!
Interrupting remote evaluation
When the RemoteREPL client is waiting on a response, it will catch InterruptException
and forward it to the server as an interruption message. This allows blocking operations such as IO to be interrupted safely.
However, this doesn't work for non-yielding operations such as tight computational loops. For these cases, pressing Control-C three times will disconnect from the server, leaving the remote operation still running.
API reference
RemoteREPL.connect_repl
— Functionconnect_repl([host=localhost,] port::Integer=27754;
tunnel = (host != localhost) ? :ssh : :none,
ssh_opts = ``, region=nothing, namespace=nothing,
repl=Base.active_repl, session_id = nothing)
Connect client REPL to a remote host
on port
. This is then accessible as a remote sub-repl of the current Julia session.
For security, connect_repl()
uses an ssh tunnel for remote hosts. This means that host
needs to be running an ssh server and you need ssh credentials set up for use on that host. For secure networks this can be disabled by setting tunnel=:none
.
To provide extra options to SSH, you may pass a Cmd
object in the ssh_opts
keyword, for example an identity file may be set with ssh_opts = `-i /path/to/identity.pem`
. For a more permanent solution, add a Host
section to your ssh config file.
You can also use the following technologies for tunneling in place of SSH:
- AWS Session Manager: set
tunnel=:aws
. The optionalregion
keyword argument can be used to specify the AWS Region of your server. - kubectl: set
tunnel=:k8s
. The optionalnamespace
keyword argument can be used to specify the namespace of your Kubernetes resource.
See README.md for more information.
RemoteREPL.serve_repl
— Functionserve_repl([address=Sockets.localhost,] port=27754; [on_client_connect=nothing])
serve_repl(server)
Start a REPL server listening on interface address
and port
. In normal operation serve_repl()
serves REPL clients indefinitely (ie., it does not return), so you will generally want to launch it using @async serve_repl()
to do other useful work at the same time.
The hook on_client_connect
may be supplied to modify the ServerSideSession
for a client after each client connects. This can be used to define the default module in which the client evaluates commands.
If you want to be able to stop the server you can pass an already-listening server
object (the result of Sockets.listen()
). The server can then be cancelled from another task using close(server)
as necessary to control the server lifetime.
Security
serve_repl()
uses an unauthenticated, unecrypted protocol so it should not be used on open networks or multi-user machines where other users aren't trusted. For open networks, use the default address=Sockets.localhost
and the automatic ssh tunnel support provided by the client-side connect_repl()
.
RemoteREPL.connect_remote
— Functionconnect_remote([host=localhost,] port::Integer=27754;
tunnel = (host != localhost) ? :ssh : :none,
ssh_opts = ``, session_id = nothing)
Connect to remote server without any REPL integrations. This will allow you to use @remote
, but not the REPL mode. Useful in circumstances where no REPL is available, but interactivity is desired like Jupyter or Pluto notebooks. Otherwise, see connect_repl
.
RemoteREPL.@remote
— Macro@remote ex
Execute expression ex
on the other side of the current RemoteREPL connection and return the value.
This can be used in both directions:
- From the normal
julia>
prompt, executeex
on the remote server and return the value to the client. - From a remote prompt, execute
ex
on the client and push the resulting value to the remote server.
Examples
Push a value from the client to the server:
julia> client_val = 1:100;
julia@localhost> server_val = @remote client_val
1:100
Fetch a pair of variables (x,y)
from the server, and plot them on the client with a single line:
# In two lines
julia> x,y = @remote (x, y)
plot(x, y)
# Or as a single expression
julia> plot(@remote((x, y))...)
RemoteREPL.remote_eval
— Functionremote_eval(cmdstr)
remote_eval(host, port, cmdstr)
Parse a string cmdstr
, evaluate it in the remote REPL server's Main
module or the session with session_id
, then close the connection. Returns the result which the REPL would normally pass to show()
(likely a Text
object).
For example, to cause the remote Julia instance to exit, you could use
using RemoteREPL
RemoteREPL.remote_eval("exit()")
RemoteREPL.remotecmd
— Functionremotecmd(conn::Connection, out_stream::IO, cmdstr::String)
Evaluate cmdstr
in the remote session of connection conn
and write result into out_stream
. Also supports the magic RemoteREPL
commands like %module
and %include
.
remotecmd(cmdstr::String)
Evaluate cmdstr
in the last opened RemoteREPL connection and print result to Base.stdout
remotecmd(conn::Connection, cmdstr::String)
Evaluate cmdstr
in the connection conn
and print result to Base.stdout
.
RemoteREPL.remote_module!
— Functionremote_module!(conn::Connection = _repl_client_connection, mod::Module)
Change future remote commands in the session of connection conn
to be evaluated into module mod
. The default connection _repl_client_connection
is the last established RemoteREPL connection. If the module cannot be evaluated locally pass the name as a string. Equivalent to using the %module
magic.
remote_module!(conn::Connection = _repl_client_connection, modstr::String)
Change future remote commands in the session of connection conn
to be evaluated into module identified by modstr
. The default connection _repl_client_connection
is the last established RemoteREPL connection. Equivalent to using the %module
magic.