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">
3
<title>Twisted Documentation: Writing a twistd Plugin</title>
4
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
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">A note on .tap files</a></li><li><a href="#auto2">Alternatives to twistd plugins</a></li><li><a href="#auto3">Creating the plugin</a></li><li><a href="#auto4">Using cred with your TAP</a></li><li><a href="#auto5">Conclusion</a></li></ol></div>
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>
17
<p>The target audience of this document are those that have developed
18
a Twisted application which needs a command line-based deployment
21
<p>There are a few prerequisites to understanding this document:</p>
23
<li>A basic understanding of the Twisted Plugin System (i.e.,
24
the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.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
34
on <code>twisted.python.usage</code>, which is documented
35
in <a href="options.html" shape="rect">Using usage.Options</a>.</li>
38
<h2>Goals<a name="auto0"/></h2>
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>
45
<h2>A note on .tap files<a name="auto1"/></h2>
47
<p>Readers may be confused about a historical file type associated
48
with Twisted, the <code>.tap</code> file. This was a kind of file that
49
was generated by a program named <code>mktap</code> and
50
which <code>twistd</code> can read. <code>.tap</code> files are
51
deprecated; this document has nothing to do with them, although the
52
technology described herein is very closely related to the old
53
system. Existing plugins that were written for the mktap system are
54
compatible with this <code>twistd</code> plugin system; the following
58
<pre class="shell" xml:space="preserve">
59
$ mktap [foo] [options...]
60
$ twistd -n -f [foo].tap
64
are equivalent to the command:</p>
66
<pre class="shell" xml:space="preserve">$ twistd -n [foo] [options...]</pre>
68
<h2>Alternatives to twistd plugins<a name="auto2"/></h2>
69
<p>The major alternative to the twistd plugin mechanism is the <code>.tac</code>
70
file, which is a simple script to be used with the
71
twistd <code>-y/--python</code> parameter. The twistd plugin mechanism
72
exists to offer a more extensible command-line-driven interface to
73
your application. For more information on <code>.tac</code> files, see
74
the document <a href="application.html" shape="rect">Using the Twisted Application
78
<h2>Creating the plugin<a name="auto3"/></h2>
80
<p>The following directory structure is assumed of your project:</p>
83
<li><strong>MyProject</strong> - Top level directory
85
<li><strong>myproject</strong> - Python package
86
<ul><li><strong>__init__.py</strong></li></ul>
93
During development of your project, Twisted plugins can be loaded
94
from a special directory in your project, assuming your top level
95
directory ends up in sys.path. Create a directory
96
named <code>twisted</code> containing a directory
97
named <code>plugins</code>, and add a file
98
named <code>myproject_plugin.py</code> to it. This file will contain your
99
plugin. Note that you should <em>not</em> add any __init__.py files
100
to this directory structure, and the plugin file should <em>not</em>
101
be named <code>myproject.py</code> (because that would conflict with
102
your project's module name).
106
In this file, define an object which <em>provides</em> the interfaces
107
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.plugin.IPlugin.html" title="twisted.plugin.IPlugin">twisted.plugin.IPlugin</a></code>
108
and <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.application.service.IServiceMaker.html" title="twisted.application.service.IServiceMaker">twisted.application.service.IServiceMaker</a></code>.
111
<p>The <code>tapname</code> attribute of your IServiceMaker provider
112
will be used as the subcommand name in a command
113
like <code class="shell">twistd [subcommand] [args...]</code>, and
114
the <code>options</code> attribute (which should be
115
a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.python.usage.Options.html" title="twisted.python.usage.Options">usage.Options</a></code>
116
subclass) will be used to parse the given args.</p>
118
<pre class="python"><p class="py-linenumber"> 1
150
</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>
152
<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>
153
<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>
154
<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>
155
<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>
157
<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>
160
<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>):
161
<span class="py-src-variable">optParameters</span> = [[<span class="py-src-string">"port"</span>, <span class="py-src-string">"p"</span>, <span class="py-src-number">1235</span>, <span class="py-src-string">"The port number to listen on."</span>]]
164
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyServiceMaker</span>(<span class="py-src-parameter">object</span>):
165
<span class="py-src-variable">implements</span>(<span class="py-src-variable">IServiceMaker</span>, <span class="py-src-variable">IPlugin</span>)
166
<span class="py-src-variable">tapname</span> = <span class="py-src-string">"myproject"</span>
167
<span class="py-src-variable">description</span> = <span class="py-src-string">"Run this! It'll make your dog happy."</span>
168
<span class="py-src-variable">options</span> = <span class="py-src-variable">Options</span>
170
<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>):
171
<span class="py-src-string">"""
172
Construct a TCPServer from a factory defined in myproject.
173
"""</span>
174
<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">"port"</span>]), <span class="py-src-variable">MyFactory</span>())
177
<span class="py-src-comment"># Now construct an object which *provides* the relevant interfaces</span>
178
<span class="py-src-comment"># The name of this variable is irrelevant, as long as there is *some*</span>
179
<span class="py-src-comment"># name bound to a provider of IPlugin and IServiceMaker.</span>
181
<span class="py-src-variable">serviceMaker</span> = <span class="py-src-variable">MyServiceMaker</span>()
185
Now running <code class="shell">twistd --help</code> should
186
print <code>myproject</code> in the list of available subcommands,
187
followed by the description that we specified in the
188
plugin. <code class="shell">twistd -n myproject</code> would,
189
assuming we defined a <code>MyFactory</code> factory
190
inside <code>myproject</code>, start a listening server on port 1235
194
<h2>Using cred with your TAP<a name="auto4"/></h2>
197
Twisted ships with a robust authentication framework to use with
198
your application. If your server needs authentication functionality,
199
and you haven't read about <a href="cred.html" shape="rect">twisted.cred</a>
200
yet, read up on it first.
204
If you are building a twistd plugin and you want to support a wide
205
variety of authentication patterns, Twisted provides an easy-to-use
206
mixin for your Options subclass:
207
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.cred.strcred.AuthOptionMixin.html" title="twisted.cred.strcred.AuthOptionMixin">strcred.AuthOptionMixin</a></code>.
208
The following code is an example of using this mixin:
211
<pre class="python"><p class="py-linenumber"> 1
259
</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>
260
<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>
261
<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>
262
<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>
263
<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>
265
<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>):
266
<span class="py-src-comment"># This part is optional; it tells AuthOptionMixin what</span>
267
<span class="py-src-comment"># kinds of credential interfaces the user can give us.</span>
268
<span class="py-src-variable">supportedInterfaces</span> = (<span class="py-src-variable">credentials</span>.<span class="py-src-variable">IUsernamePassword</span>,)
270
<span class="py-src-variable">optParameters</span> = [
271
[<span class="py-src-string">"port"</span>, <span class="py-src-string">"p"</span>, <span class="py-src-number">1234</span>, <span class="py-src-string">"Server port number"</span>],
272
[<span class="py-src-string">"host"</span>, <span class="py-src-string">"h"</span>, <span class="py-src-string">"localhost"</span>, <span class="py-src-string">"Server hostname"</span>]]
274
<span class="py-src-keyword">class</span> <span class="py-src-identifier">MyServerServiceMaker</span>(<span class="py-src-parameter">object</span>):
275
<span class="py-src-variable">implements</span>(<span class="py-src-variable">IServiceMaker</span>, <span class="py-src-variable">IPlugin</span>)
276
<span class="py-src-variable">tapname</span> = <span class="py-src-string">"myserver"</span>
277
<span class="py-src-variable">description</span> = <span class="py-src-string">"This server does nothing productive."</span>
278
<span class="py-src-variable">options</span> = <span class="py-src-variable">ServerOptions</span>
280
<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>):
281
<span class="py-src-string">"""Construct a service object."""</span>
282
<span class="py-src-comment"># The realm is a custom object that your server defines.</span>
283
<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">"host"</span>])
285
<span class="py-src-comment"># The portal is something Cred can provide, as long as</span>
286
<span class="py-src-comment"># you have a list of checkers that you'll support. This</span>
287
<span class="py-src-comment"># list is provided my AuthOptionMixin.</span>
288
<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">"credCheckers"</span>])
290
<span class="py-src-comment"># OR, if you know you might get multiple interfaces, and</span>
291
<span class="py-src-comment"># only want to give your application one of them, you</span>
292
<span class="py-src-comment"># also have that option with AuthOptionMixin:</span>
293
<span class="py-src-variable">interface</span> = <span class="py-src-variable">credentials</span>.<span class="py-src-variable">IUsernamePassword</span>
294
<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">"credInterfaces"</span>][<span class="py-src-variable">interface</span>])
296
<span class="py-src-comment"># The protocol factory is, like the realm, something you implement.</span>
297
<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>)
299
<span class="py-src-comment"># Finally, return a service that will listen for connections.</span>
300
<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">"port"</span>]), <span class="py-src-variable">factory</span>)
303
<span class="py-src-comment"># As in our example above, we have to construct an object that</span>
304
<span class="py-src-comment"># provides the IPlugin and IServiceMaker interfaces.</span>
306
<span class="py-src-variable">serviceMaker</span> = <span class="py-src-variable">MyServerServiceMaker</span>()
310
Now that you have your TAP configured to support any authentication
311
we can throw at it, you're ready to use it. Here is an example of
312
starting your server using the /etc/passwd file for
313
authentication. (Clearly, this won't work on servers with shadow
317
<pre class="shell" xml:space="preserve">
318
$ twistd myserver --auth passwd:/etc/passwd
322
For a full list of cred plugins supported, see <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.plugins.html" title="twisted.plugins">twisted.plugins</a></code>, or use the command-line help:
325
<pre class="shell" xml:space="preserve">
326
$ twistd myserver --help-auth
327
$ twistd myserver --help-auth-type passwd
330
<h2>Conclusion<a name="auto5"/></h2>
332
<p>You should now be able to</p>
334
<li>Create a twistd plugin</li>
335
<li>Incorporate authentication into your plugin</li>
336
<li>Use it from your development environment</li>
337
<li>Install it correctly and use it in deployment</li>
343
<p><a href="index.html">Index</a></p>
344
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'