Imported Upstream version 12.1.0
[contrib/python-twisted.git] / doc / core / howto / tap.html
1 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE html  PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'  'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
2   <head>
3 <title>Twisted Documentation: Writing a twistd Plugin</title>
4 <link href="stylesheet.css" rel="stylesheet" type="text/css"/>
5   </head>
6
7   <body bgcolor="white">
8     <h1 class="title">Writing a twistd Plugin</h1>
9     <div class="toc"><ol><li><a href="#auto0">Goals</a></li><li><a href="#auto1">Alternatives to twistd plugins</a></li><li><a href="#auto2">Creating the plugin</a></li><li><a href="#auto3">Using cred with your TAP</a></li><li><a href="#auto4">Conclusion</a></li></ol></div>
10     <div class="content">
11 <span/>
12
13 <p>This document describes adding subcommands to
14 the <code>twistd</code> command, as a way to facilitate the deployment
15 of your applications. <em>(This feature was added in Twisted 2.5)</em></p>
16
17 <p>The target audience of this document are those that have developed
18 a Twisted application which needs a command line-based deployment
19 mechanism.</p>
20
21 <p>There are a few prerequisites to understanding this document:</p>
22 <ul>
23   <li>A basic understanding of the Twisted Plugin System (i.e.,
24       the <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.plugin.html" title="twisted.plugin">twisted.plugin</a></code> module) is
25       necessary, however, step-by-step instructions will be
26       given. Reading <a href="plugin.html" shape="rect">The Twisted Plugin
27       System</a> is recommended, in particular the <q>Extending an
28       Existing Program</q> section.</li>
29   <li>The <a href="application.html" shape="rect">Application</a> infrastructure
30     is used in <code>twistd</code> plugins; in particular, you should
31     know how to expose your program's functionality as a Service.</li>
32   <li>In order to parse command line arguments, the <code>twistd</code> plugin
33     mechanism relies
34     on <code>twisted.python.usage</code>, which is documented
35     in <a href="options.html" shape="rect">Using usage.Options</a>.</li>
36 </ul>
37
38 <h2>Goals<a name="auto0"/></h2>
39
40 <p>After reading this document, the reader should be able to expose
41 their Service-using application as a subcommand
42 of <code>twistd</code>, taking into consideration whatever was passed
43 on the command line.</p>
44
45 <h2>Alternatives to twistd plugins<a name="auto1"/></h2>
46 <p>The major alternative to the twistd plugin mechanism is the <code>.tac</code>
47 file, which is a simple script to be used with the
48 twistd <code>-y/--python</code> parameter. The twistd plugin mechanism
49 exists to offer a more extensible command-line-driven interface to
50 your application. For more information on <code>.tac</code> files, see
51 the document <a href="application.html" shape="rect">Using the Twisted Application
52 Framework</a>.</p>
53
54
55 <h2>Creating the plugin<a name="auto2"/></h2>
56
57 <p>The following directory structure is assumed of your project:</p>
58
59 <ul>
60   <li><strong>MyProject</strong> - Top level directory
61     <ul>
62       <li><strong>myproject</strong> - Python package
63         <ul><li><strong>__init__.py</strong></li></ul>
64       </li>
65     </ul>
66   </li>
67 </ul>
68
69 <p>
70   During development of your project, Twisted plugins can be loaded
71   from a special directory in your project, assuming your top level
72   directory ends up in sys.path. Create a directory
73   named <code>twisted</code> containing a directory
74   named <code>plugins</code>, and add a file
75   named <code>myproject_plugin.py</code> to it. This file will contain your
76   plugin. Note that you should <em>not</em> add any __init__.py files
77   to this directory structure, and the plugin file should <em>not</em>
78   be named <code>myproject.py</code> (because that would conflict with
79   your project's module name).
80 </p>
81
82 <p>
83   In this file, define an object which <em>provides</em> the interfaces
84   <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.plugin.IPlugin.html" title="twisted.plugin.IPlugin">twisted.plugin.IPlugin</a></code>
85   and <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.application.service.IServiceMaker.html" title="twisted.application.service.IServiceMaker">twisted.application.service.IServiceMaker</a></code>.
86 </p>
87
88 <p>The <code>tapname</code> attribute of your IServiceMaker provider
89 will be used as the subcommand name in a command
90 like <code class="shell">twistd [subcommand] [args...]</code>, and
91 the <code>options</code> attribute (which should be
92 a <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.python.usage.Options.html" title="twisted.python.usage.Options">usage.Options</a></code>
93 subclass) will be used to parse the given args.</p>
94
95 <pre class="python"><p class="py-linenumber"> 1
96  2
97  3
98  4
99  5
100  6
101  7
102  8
103  9
104 10
105 11
106 12
107 13
108 14
109 15
110 16
111 17
112 18
113 19
114 20
115 21
116 22
117 23
118 24
119 25
120 26
121 27
122 28
123 29
124 30
125 31
126 32
127 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
128
129 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">usage</span>
130 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IPlugin</span>
131 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span>.<span class="py-src-variable">service</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IServiceMaker</span>
132 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">internet</span>
133
134 <span class="py-src-keyword">from</span> <span class="py-src-variable">myproject</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">MyFactory</span>
135
136
137 <span class="py-src-keyword">class</span> <span class="py-src-identifier">Options</span>(<span class="py-src-parameter">usage</span>.<span class="py-src-parameter">Options</span>):
138     <span class="py-src-variable">optParameters</span> = [[<span class="py-src-string">&quot;port&quot;</span>, <span class="py-src-string">&quot;p&quot;</span>, <span class="py-src-number">1235</span>, <span class="py-src-string">&quot;The port number to listen on.&quot;</span>]]
139
140
141 <span class="py-src-keyword">class</span> <span class="py-src-identifier">MyServiceMaker</span>(<span class="py-src-parameter">object</span>):
142     <span class="py-src-variable">implements</span>(<span class="py-src-variable">IServiceMaker</span>, <span class="py-src-variable">IPlugin</span>)
143     <span class="py-src-variable">tapname</span> = <span class="py-src-string">&quot;myproject&quot;</span>
144     <span class="py-src-variable">description</span> = <span class="py-src-string">&quot;Run this! It'll make your dog happy.&quot;</span>
145     <span class="py-src-variable">options</span> = <span class="py-src-variable">Options</span>
146
147     <span class="py-src-keyword">def</span> <span class="py-src-identifier">makeService</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">options</span>):
148         <span class="py-src-string">&quot;&quot;&quot;
149         Construct a TCPServer from a factory defined in myproject.
150         &quot;&quot;&quot;</span>
151         <span class="py-src-keyword">return</span> <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">options</span>[<span class="py-src-string">&quot;port&quot;</span>]), <span class="py-src-variable">MyFactory</span>())
152
153
154 <span class="py-src-comment"># Now construct an object which *provides* the relevant interfaces</span>
155 <span class="py-src-comment"># The name of this variable is irrelevant, as long as there is *some*</span>
156 <span class="py-src-comment"># name bound to a provider of IPlugin and IServiceMaker.</span>
157
158 <span class="py-src-variable">serviceMaker</span> = <span class="py-src-variable">MyServiceMaker</span>()
159 </pre>
160
161 <p>
162   Now running <code class="shell">twistd --help</code> should
163   print <code>myproject</code> in the list of available subcommands,
164   followed by the description that we specified in the
165   plugin. <code class="shell">twistd -n myproject</code> would,
166   assuming we defined a <code>MyFactory</code> factory
167   inside <code>myproject</code>, start a listening server on port 1235
168   with that factory.
169 </p>
170
171 <h2>Using cred with your TAP<a name="auto3"/></h2>
172
173 <p>
174   Twisted ships with a robust authentication framework to use with
175   your application. If your server needs authentication functionality,
176   and you haven't read about <a href="cred.html" shape="rect">twisted.cred</a>
177   yet, read up on it first.
178 </p>
179
180 <p>
181   If you are building a twistd plugin and you want to support a wide
182   variety of authentication patterns, Twisted provides an easy-to-use
183   mixin for your Options subclass:
184   <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.cred.strcred.AuthOptionMixin.html" title="twisted.cred.strcred.AuthOptionMixin">strcred.AuthOptionMixin</a></code>.
185   The following code is an example of using this mixin:
186 </p>
187
188 <pre class="python"><p class="py-linenumber"> 1
189  2
190  3
191  4
192  5
193  6
194  7
195  8
196  9
197 10
198 11
199 12
200 13
201 14
202 15
203 16
204 17
205 18
206 19
207 20
208 21
209 22
210 23
211 24
212 25
213 26
214 27
215 28
216 29
217 30
218 31
219 32
220 33
221 34
222 35
223 36
224 37
225 38
226 39
227 40
228 41
229 42
230 43
231 44
232 45
233 46
234 47
235 48
236 </p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">cred</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">credentials</span>, <span class="py-src-variable">portal</span>, <span class="py-src-variable">strcred</span>
237 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">python</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">usage</span>
238 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">plugin</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IPlugin</span>
239 <span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">application</span>.<span class="py-src-variable">service</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IServiceMaker</span>
240 <span class="py-src-keyword">from</span> <span class="py-src-variable">myserver</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">myservice</span>
241
242 <span class="py-src-keyword">class</span> <span class="py-src-identifier">ServerOptions</span>(<span class="py-src-parameter">usage</span>.<span class="py-src-parameter">Options</span>, <span class="py-src-parameter">strcred</span>.<span class="py-src-parameter">AuthOptionMixin</span>):
243     <span class="py-src-comment"># This part is optional; it tells AuthOptionMixin what</span>
244     <span class="py-src-comment"># kinds of credential interfaces the user can give us.</span>
245     <span class="py-src-variable">supportedInterfaces</span> = (<span class="py-src-variable">credentials</span>.<span class="py-src-variable">IUsernamePassword</span>,)
246
247     <span class="py-src-variable">optParameters</span> = [
248         [<span class="py-src-string">&quot;port&quot;</span>, <span class="py-src-string">&quot;p&quot;</span>, <span class="py-src-number">1234</span>, <span class="py-src-string">&quot;Server port number&quot;</span>],
249         [<span class="py-src-string">&quot;host&quot;</span>, <span class="py-src-string">&quot;h&quot;</span>, <span class="py-src-string">&quot;localhost&quot;</span>, <span class="py-src-string">&quot;Server hostname&quot;</span>]]
250
251 <span class="py-src-keyword">class</span> <span class="py-src-identifier">MyServerServiceMaker</span>(<span class="py-src-parameter">object</span>):
252     <span class="py-src-variable">implements</span>(<span class="py-src-variable">IServiceMaker</span>, <span class="py-src-variable">IPlugin</span>)
253     <span class="py-src-variable">tapname</span> = <span class="py-src-string">&quot;myserver&quot;</span>
254     <span class="py-src-variable">description</span> = <span class="py-src-string">&quot;This server does nothing productive.&quot;</span>
255     <span class="py-src-variable">options</span> = <span class="py-src-variable">ServerOptions</span>
256
257     <span class="py-src-keyword">def</span> <span class="py-src-identifier">makeService</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">options</span>):
258         <span class="py-src-string">&quot;&quot;&quot;Construct a service object.&quot;&quot;&quot;</span>
259         <span class="py-src-comment"># The realm is a custom object that your server defines.</span>
260         <span class="py-src-variable">realm</span> = <span class="py-src-variable">myservice</span>.<span class="py-src-variable">MyServerRealm</span>(<span class="py-src-variable">options</span>[<span class="py-src-string">&quot;host&quot;</span>])
261
262         <span class="py-src-comment"># The portal is something Cred can provide, as long as</span>
263         <span class="py-src-comment"># you have a list of checkers that you'll support. This</span>
264         <span class="py-src-comment"># list is provided my AuthOptionMixin.</span>
265         <span class="py-src-variable">portal</span> = <span class="py-src-variable">portal</span>.<span class="py-src-variable">Portal</span>(<span class="py-src-variable">realm</span>, <span class="py-src-variable">options</span>[<span class="py-src-string">&quot;credCheckers&quot;</span>])
266
267         <span class="py-src-comment"># OR, if you know you might get multiple interfaces, and</span>
268         <span class="py-src-comment"># only want to give your application one of them, you</span>
269         <span class="py-src-comment"># also have that option with AuthOptionMixin:</span>
270         <span class="py-src-variable">interface</span> = <span class="py-src-variable">credentials</span>.<span class="py-src-variable">IUsernamePassword</span>
271         <span class="py-src-variable">portal</span> = <span class="py-src-variable">portal</span>.<span class="py-src-variable">Portal</span>(<span class="py-src-variable">realm</span>, <span class="py-src-variable">options</span>[<span class="py-src-string">&quot;credInterfaces&quot;</span>][<span class="py-src-variable">interface</span>])
272
273         <span class="py-src-comment"># The protocol factory is, like the realm, something you implement.</span>
274         <span class="py-src-variable">factory</span> = <span class="py-src-variable">myservice</span>.<span class="py-src-variable">ServerFactory</span>(<span class="py-src-variable">realm</span>, <span class="py-src-variable">portal</span>)
275
276         <span class="py-src-comment"># Finally, return a service that will listen for connections.</span>
277         <span class="py-src-keyword">return</span> <span class="py-src-variable">internet</span>.<span class="py-src-variable">TCPServer</span>(<span class="py-src-variable">int</span>(<span class="py-src-variable">options</span>[<span class="py-src-string">&quot;port&quot;</span>]), <span class="py-src-variable">factory</span>)
278
279
280 <span class="py-src-comment"># As in our example above, we have to construct an object that</span>
281 <span class="py-src-comment"># provides the IPlugin and IServiceMaker interfaces.</span>
282
283 <span class="py-src-variable">serviceMaker</span> = <span class="py-src-variable">MyServerServiceMaker</span>()
284 </pre>
285
286 <p>
287   Now that you have your TAP configured to support any authentication
288   we can throw at it, you're ready to use it. Here is an example of
289   starting your server using the /etc/passwd file for
290   authentication. (Clearly, this won't work on servers with shadow
291   passwords.)
292 </p>
293
294 <pre class="shell" xml:space="preserve">
295 $ twistd myserver --auth passwd:/etc/passwd
296 </pre>
297
298 <p>
299   For a full list of cred plugins supported, see <code class="API"><a href="http://twistedmatrix.com/documents/12.1.0/api/twisted.plugins.html" title="twisted.plugins">twisted.plugins</a></code>, or use the command-line help:
300 </p>
301
302 <pre class="shell" xml:space="preserve">
303 $ twistd myserver --help-auth
304 $ twistd myserver --help-auth-type passwd
305 </pre>
306
307 <h2>Conclusion<a name="auto4"/></h2>
308
309 <p>You should now be able to</p>
310 <ul>
311   <li>Create a twistd plugin</li>
312   <li>Incorporate authentication into your plugin</li>
313   <li>Use it from your development environment</li>
314   <li>Install it correctly and use it in deployment</li>
315 </ul>
316
317
318 </div>
319
320     <p><a href="index.html">Index</a></p>
321     <span class="version">Version: 12.1.0</span>
322   </body>
323 </html>