7
A new view on distributed execution
8
-----------------------------------
10
``py.execnet`` supports ad-hoc distribution of parts of
11
a program across process and network barriers. *Ad-hoc*
12
means that the client side may completely control
14
* which parts of a program execute remotely and
16
* which data protocols are used between them
18
without requiring any prior manual installation
19
of user program code on the remote side. In fact,
20
not even a prior installation of any server code
21
is required, provided there is a way to get
22
an input/output connection to a python interpreter
23
(for example via "ssh" and a "python" executable).
25
By comparison, traditional Remote Method Based (RMI)
26
require prior installation and manual rather
27
heavy processes of setup, distribution and
28
communication between program parts.
31
What about Security? Are you completely nuts?
32
---------------------------------------------
34
We'll talk about that later :-)
39
With ''py.execnet'' you get the means
41
- to navigate through the network with Process, Thread, SSH
42
and Socket- gateways that allow you ...
44
- to distribute your program across a network and define
45
communication protocols from the client side, making
46
server maintenance superflous. In fact, there is no such
47
thing as a server. It's just another computer ... if it
48
doesn't run in a kernel-level jail [#]_ in which case
49
even that is virtualized.
52
Available Gateways/Connection methods
53
-----------------------------------------
55
You may use one of the following connection methods:
57
* :api:`py.execnet.PopenGateway` a subprocess on the local
58
machine. Useful for jailing certain parts of a program
59
or for making use of multiple processors.
61
* :api:`py.execnet.SshGateway` a way to connect to
62
a remote ssh server and distribute execution to it.
64
* :api:`py.execnet.SocketGateway` a way to connect to
65
a remote Socket based server. *Note* that this method
66
requires a manually started
67
:source:py/execnet/script/socketserver.py
68
script. You can run this "server script" without
69
having the py lib installed on that remote system.
71
Remote execution approach
72
-------------------------------------
74
All gateways offer one main high level function:
76
def remote_exec(source):
77
"""return channel object for communicating with the asynchronously
78
executing 'source' code which will have a corresponding 'channel'
79
object in its executing namespace."""
81
With `remote_exec` you send source code to the other
82
side and get both a local and a remote Channel_ object,
83
which you can use to have the local and remote site
84
communicate data in a structured way. Here is
88
>>> gw = py.execnet.PopenGateway()
89
>>> channel = gw.remote_exec("""
91
... channel.send(os.getpid())
93
>>> remote_pid = channel.receive()
94
>>> remote_pid != py.std.os.getpid()
97
`remote_exec` implements the idea to ``determine
98
protocol and remote code from the client/local side``.
99
This makes distributing a program run in an ad-hoc
100
manner (using e.g. :api:`py.execnet.SshGateway`) very easy.
102
You should not need to maintain software on the other sides
103
you are running your code at, other than the Python
110
The **Channel** interface for exchanging data across gateways
111
-------------------------------------------------------------
113
While executing custom strings on "the other side" is simple enough
114
it is often tricky to deal with. Therefore we want a way
115
to send data items to and fro between the distributedly running
116
program. The idea is to inject a Channel object for each
117
execution of source code. This Channel object allows two
118
program parts to send data to each other.
119
Here is the current interface::
122
# API for sending and receiving anonymous values
125
sends the given item to the other side of the channel,
126
possibly blocking if the sender queue is full.
127
Note that items need to be marshallable (all basic
131
receives an item that was sent from the other side,
132
possibly blocking if there is none.
133
Note that exceptions from the other side will be
134
reraised as gateway.RemoteError exceptions containing
135
a textual representation of the remote traceback.
137
channel.waitclose(timeout=None):
138
wait until this channel is closed. Note that a closed
139
channel may still hold items that will be received or
140
send. Note that exceptions from the other side will be
141
reraised as gateway.RemoteError exceptions containing
142
a textual representation of the remote traceback.
145
close this channel on both the local and the remote side.
146
A remote side blocking on receive() on this channel
147
will get woken up and see an EOFError exception.
150
The complete Fileserver example
151
........................................
153
problem: retrieving contents of remote files::
156
contentserverbootstrap = py.code.Source(
161
channel.send(f.read())
165
# open a gateway to a fresh child process
166
contentgateway = py.execnet.SshGateway('codespeak.net')
167
channel = contentgateway.remote_exec(contentserverbootstrap)
169
for fn in somefilelist:
171
content = channel.receive()
174
# later you can exit / close down the gateway
175
contentgateway.exit()
178
A more complicated "nested" Gateway Example
179
...........................................
181
The following example opens a PopenGateway, i.e. a python
182
child process, starts a socket server within that process and
183
then opens a SocketGateway to the freshly started
184
socketserver. Thus it forms a "triangle"::
187
CLIENT < ... > PopenGateway()
194
The below "socketserver" mentioned script is a small script that
195
basically listens and accepts socket connections, receives one
196
liners and executes them.
198
Here are 20 lines of code making the above triangle happen::
202
socketserverbootstrap = py.code.Source(
203
mypath.dirpath().dirpath('bin', 'socketserver.py').read(),
206
sock = bind_and_listen(("localhost", %r))
210
# open a gateway to a fresh child process
211
proxygw = py.execnet.PopenGateway()
213
# execute asynchronously the above socketserverbootstrap on the other
214
channel = proxygw.remote_exec(socketserverbootstrap)
216
# the other side should start the socket server now
217
assert channel.receive() == "ok"
218
gw = py.execnet.SocketGateway('localhost', cls.port)
219
print "initialized socket gateway to port", cls.port
221
.. [#] There is an interesting emerging `Jail`_ linux technology
222
as well as a host of others, of course.
224
.. _`Jail`: http://books.rsbac.org/unstable/x2223.html