~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to py/doc/execnet.txt

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
The py.execnet library 
 
2
======================
 
3
 
 
4
.. contents::
 
5
.. sectnum::
 
6
 
 
7
A new view on distributed execution
 
8
----------------------------------- 
 
9
 
 
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 
 
13
 
 
14
* which parts of a program execute remotely and 
 
15
 
 
16
* which data protocols are used between them 
 
17
 
 
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). 
 
24
 
 
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.  
 
29
 
 
30
 
 
31
What about Security? Are you completely nuts? 
 
32
---------------------------------------------
 
33
 
 
34
We'll talk about that later :-) 
 
35
 
 
36
Basic Features
 
37
==============
 
38
 
 
39
With ''py.execnet'' you get the means 
 
40
 
 
41
- to navigate through the network with Process, Thread, SSH
 
42
  and Socket- gateways that allow you ... 
 
43
 
 
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. 
 
50
 
 
51
 
 
52
Available Gateways/Connection methods
 
53
-----------------------------------------
 
54
 
 
55
You may use one of the following connection methods:
 
56
 
 
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. 
 
60
 
 
61
* :api:`py.execnet.SshGateway` a way to connect to 
 
62
  a remote ssh server and distribute execution to it. 
 
63
 
 
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. 
 
70
 
 
71
Remote execution approach 
 
72
-------------------------------------
 
73
 
 
74
All gateways offer one main high level function: 
 
75
 
 
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."""
 
80
 
 
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 
 
85
an example: 
 
86
 
 
87
  >>> import py 
 
88
  >>> gw = py.execnet.PopenGateway()
 
89
  >>> channel = gw.remote_exec("""
 
90
  ...     import os
 
91
  ...     channel.send(os.getpid())
 
92
  ... """)
 
93
  >>> remote_pid = channel.receive()
 
94
  >>> remote_pid != py.std.os.getpid()
 
95
  True
 
96
 
 
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. 
 
101
 
 
102
You should not need to maintain software on the other sides 
 
103
you are running your code at, other than the Python 
 
104
executable itself. 
 
105
 
 
106
.. _`Channel`: 
 
107
.. _`channel-api`: 
 
108
.. _`exchange data`: 
 
109
 
 
110
The **Channel** interface for exchanging data across gateways
 
111
-------------------------------------------------------------
 
112
 
 
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:: 
 
120
 
 
121
    #
 
122
    # API for sending and receiving anonymous values
 
123
    #
 
124
    channel.send(item): 
 
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 
 
128
        python types are):
 
129
 
 
130
    channel.receive():
 
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. 
 
136
 
 
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. 
 
143
 
 
144
    channel.close(): 
 
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. 
 
148
 
 
149
 
 
150
The complete Fileserver example 
 
151
........................................ 
 
152
 
 
153
problem: retrieving contents of remote files::
 
154
 
 
155
    import py
 
156
    contentserverbootstrap = py.code.Source( 
 
157
            """
 
158
            for fn in channel:
 
159
                f = open(fn, 'rb')
 
160
                try:
 
161
                    channel.send(f.read())
 
162
                finally:
 
163
                    f.close()
 
164
            """) 
 
165
    # open a gateway to a fresh child process 
 
166
    contentgateway = py.execnet.SshGateway('codespeak.net') 
 
167
    channel = contentgateway.remote_exec(contentserverbootstrap)
 
168
 
 
169
    for fn in somefilelist: 
 
170
        channel.send(fn) 
 
171
        content = channel.receive()
 
172
        # process content 
 
173
     
 
174
    # later you can exit / close down the gateway
 
175
    contentgateway.exit()
 
176
 
 
177
 
 
178
A more complicated "nested" Gateway Example 
 
179
........................................... 
 
180
 
 
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":: 
 
185
 
 
186
 
 
187
    CLIENT < ... >  PopenGateway() 
 
188
        <             .
 
189
         .            .
 
190
          .          .
 
191
           .        .
 
192
            > SocketGateway() 
 
193
            
 
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. 
 
197
 
 
198
Here are 20 lines of code making the above triangle happen::
 
199
 
 
200
    import py 
 
201
    port = 7770
 
202
    socketserverbootstrap = py.code.Source(
 
203
        mypath.dirpath().dirpath('bin', 'socketserver.py').read(),
 
204
        """
 
205
        import socket
 
206
        sock = bind_and_listen(("localhost", %r)) 
 
207
        channel.send("ok") 
 
208
        startserver(sock)
 
209
    """ % port) 
 
210
    # open a gateway to a fresh child process
 
211
    proxygw = py.execnet.PopenGateway()
 
212
 
 
213
    # execute asynchronously the above socketserverbootstrap on the other
 
214
    channel = proxygw.remote_exec(socketserverbootstrap)
 
215
 
 
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
 
220
 
 
221
.. [#] There is an interesting emerging `Jail`_ linux technology 
 
222
       as well as a host of others, of course. 
 
223
 
 
224
.. _`Jail`: http://books.rsbac.org/unstable/x2223.html