Merge lp:~jml/launchpad/codehosting-to-services into lp:launchpad
- codehosting-to-services
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~jml/launchpad/codehosting-to-services |
Merge into: | lp:launchpad |
Prerequisite: | lp:~jml/launchpad/extract-ssh-server-auth |
Diff against target: |
594 lines (+191/-134) (has conflicts) 18 files modified
daemons/sftp.tac (+1/-1) lib/lp/codehosting/sftp.py (+1/-23) lib/lp/codehosting/sshserver/daemon.py (+3/-3) lib/lp/codehosting/sshserver/session.py (+19/-75) lib/lp/codehosting/sshserver/tests/test_daemon.py (+2/-2) lib/lp/services/sshserver/__init__.py (+8/-0) lib/lp/services/sshserver/accesslog.py (+1/-1) lib/lp/services/sshserver/auth.py (+6/-5) lib/lp/services/sshserver/events.py (+2/-13) lib/lp/services/sshserver/service.py (+3/-3) lib/lp/services/sshserver/session.py (+79/-0) lib/lp/services/sshserver/sftp.py (+35/-0) lib/lp/services/sshserver/tests/__init__.py (+8/-0) lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa (+15/-0) lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa.pub (+1/-0) lib/lp/services/sshserver/tests/test_accesslog.py (+4/-4) lib/lp/services/sshserver/tests/test_auth.py (+2/-3) lib/lp/services/sshserver/tests/test_events.py (+1/-1) Text conflict in daemons/sftp.tac Text conflict in lib/lp/services/sshserver/accesslog.py Text conflict in lib/lp/services/sshserver/service.py Text conflict in lib/lp/services/sshserver/tests/test_auth.py |
To merge this branch: | bzr merge lp:~jml/launchpad/codehosting-to-services |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paul Hummer (community) | code | Approve | |
Review via email: mp+23491@code.launchpad.net |
Commit message
Create a new generic Launchpad SSH server in lp.services.
Description of the change
As best as I can tell, this branch completes the work done in the mega lp:~jml/launchpad/ssh-key-auth branch. It moves all of the generic code out of lp.codehosting.
Most of the changes are simple module moves. There are some exceptions though.
* PatchedSSHSession is extracted from lp.codehosting.
* Likewise, FileTransferServer is moved out of lp.codehosting.sftp and into lp.services. It is modified slightly so that the SFTPStarted event is generated from it. Behaviour should be equivalent to current behaviour.
* BazaarSSHStarted and BazaarSSHClosed events are moved to the lp.codehosting session module. Relevant docstrings are updated.
* I had to copy some keys over for testing.
* Some tests and docstrings were tweaked to refer to Launchpad SSH server, rather than codehosting.
I look forward to your review.
jml
Preview Diff
1 | === modified file 'daemons/sftp.tac' |
2 | --- daemons/sftp.tac 2010-04-16 19:01:12 +0000 |
3 | +++ daemons/sftp.tac 2010-04-16 19:01:18 +0000 |
4 | @@ -21,7 +21,7 @@ |
5 | from lp.codehosting.sshserver.daemon import ( |
6 | ACCESS_LOG_NAME, get_key_path, LOG_NAME, make_portal, OOPS_CONFIG_SECTION, |
7 | PRIVATE_KEY_FILE, PUBLIC_KEY_FILE) |
8 | -from lp.codehosting.sshserver.service import SSHService |
9 | +from lp.services.sshserver.service import SSHService |
10 | |
11 | |
12 | # Construct an Application that has the codehosting SSH server. |
13 | |
14 | === modified file 'lib/lp/codehosting/sftp.py' |
15 | --- lib/lp/codehosting/sftp.py 2010-04-16 19:01:12 +0000 |
16 | +++ lib/lp/codehosting/sftp.py 2010-04-16 19:01:18 +0000 |
17 | @@ -15,7 +15,6 @@ |
18 | __metaclass__ = type |
19 | __all__ = [ |
20 | 'avatar_to_sftp_server', |
21 | - 'FileTransferServer', |
22 | 'TransportSFTPServer', |
23 | ] |
24 | |
25 | @@ -34,12 +33,10 @@ |
26 | from twisted.internet import defer |
27 | from twisted.python import util |
28 | |
29 | -from zope.event import notify |
30 | from zope.interface import implements |
31 | |
32 | +from canonical.config import config |
33 | from lp.codehosting.vfs import AsyncLaunchpadTransport, LaunchpadServer |
34 | -from lp.codehosting.sshserver import events |
35 | -from canonical.config import config |
36 | from lp.services.twistedsupport import gatherResults |
37 | |
38 | |
39 | @@ -253,28 +250,9 @@ |
40 | avatar.branchfs_proxy, user_id, hosted_transport, mirror_transport) |
41 | server.start_server() |
42 | transport = AsyncLaunchpadTransport(server, server.get_url()) |
43 | - notify(events.SFTPStarted(avatar)) |
44 | return TransportSFTPServer(transport) |
45 | |
46 | |
47 | -class FileTransferServer(filetransfer.FileTransferServer): |
48 | - |
49 | - def __init__(self, data=None, avatar=None): |
50 | - filetransfer.FileTransferServer.__init__(self, data, avatar) |
51 | - self.avatar = avatar |
52 | - |
53 | - def connectionLost(self, reason): |
54 | - # This method gets called twice: once from `SSHChannel.closeReceived` |
55 | - # when the client closes the channel and once from `SSHSession.closed` |
56 | - # when the server closes the session. We change the avatar attribute |
57 | - # to avoid logging the `SFTPClosed` event twice. |
58 | - filetransfer.FileTransferServer.connectionLost(self, reason) |
59 | - if self.avatar is not None: |
60 | - avatar = self.avatar |
61 | - self.avatar = None |
62 | - notify(events.SFTPClosed(avatar)) |
63 | - |
64 | - |
65 | class TransportSFTPServer: |
66 | """An implementation of `ISFTPServer` that backs onto a Bazaar transport. |
67 | |
68 | |
69 | === modified file 'lib/lp/codehosting/sshserver/daemon.py' |
70 | --- lib/lp/codehosting/sshserver/daemon.py 2010-04-16 19:01:12 +0000 |
71 | +++ lib/lp/codehosting/sshserver/daemon.py 2010-04-16 19:01:18 +0000 |
72 | @@ -27,9 +27,9 @@ |
73 | |
74 | from canonical.config import config |
75 | from lp.codehosting import sftp |
76 | -from lp.codehosting.sshserver.auth import ( |
77 | +from lp.codehosting.sshserver.session import launch_smart_server |
78 | +from lp.services.sshserver.auth import ( |
79 | LaunchpadAvatar, PublicKeyFromLaunchpadChecker) |
80 | -from lp.codehosting.sshserver.session import launch_smart_server |
81 | |
82 | |
83 | # The names of the key files of the server itself. The directory itself is |
84 | @@ -97,7 +97,7 @@ |
85 | """Create and return a `Portal` for the SSH service. |
86 | |
87 | This portal accepts SSH credentials and returns our customized SSH |
88 | - avatars (see `lp.codehosting.sshserver.auth.CodehostingAvatar`). |
89 | + avatars (see `CodehostingAvatar`). |
90 | """ |
91 | authentication_proxy = Proxy( |
92 | config.codehosting.authentication_endpoint) |
93 | |
94 | === modified file 'lib/lp/codehosting/sshserver/session.py' |
95 | --- lib/lp/codehosting/sshserver/session.py 2010-04-16 19:01:12 +0000 |
96 | +++ lib/lp/codehosting/sshserver/session.py 2010-04-16 19:01:18 +0000 |
97 | @@ -6,7 +6,6 @@ |
98 | __metaclass__ = type |
99 | __all__ = [ |
100 | 'launch_smart_server', |
101 | - 'PatchedSSHSession', |
102 | ] |
103 | |
104 | import os |
105 | @@ -16,81 +15,23 @@ |
106 | from zope.interface import implements |
107 | |
108 | from twisted.conch.interfaces import ISession |
109 | -from twisted.conch.ssh import channel, connection, session |
110 | +from twisted.conch.ssh import connection |
111 | from twisted.internet.process import ProcessExitedAlready |
112 | from twisted.python import log |
113 | |
114 | from canonical.config import config |
115 | from lp.codehosting import get_bzr_path |
116 | -from lp.codehosting.sshserver import events |
117 | - |
118 | - |
119 | -class PatchedSSHSession(session.SSHSession, object): |
120 | - """Session adapter that corrects bugs in Conch. |
121 | - |
122 | - This object provides no custom logic for Launchpad, it just addresses some |
123 | - simple bugs in the base `session.SSHSession` class that are not yet fixed |
124 | - upstream. |
125 | - """ |
126 | - |
127 | - def closeReceived(self): |
128 | - # Without this, the client hangs when it's finished transferring. |
129 | - # XXX: JonathanLange 2009-01-05: This does not appear to have a |
130 | - # corresponding bug in Twisted. We should test that the above comment |
131 | - # is indeed correct and then file a bug upstream. |
132 | - self.loseConnection() |
133 | - |
134 | - def loseConnection(self): |
135 | - # XXX: JonathanLange 2008-03-31: This deliberately replaces the |
136 | - # implementation of session.SSHSession.loseConnection. The default |
137 | - # implementation will try to call loseConnection on the client |
138 | - # transport even if it's None. I don't know *why* it is None, so this |
139 | - # doesn't necessarily address the root cause. |
140 | - # See http://twistedmatrix.com/trac/ticket/2754. |
141 | - transport = getattr(self.client, 'transport', None) |
142 | - if transport is not None: |
143 | - transport.loseConnection() |
144 | - # This is called by session.SSHSession.loseConnection. SSHChannel is |
145 | - # the base class of SSHSession. |
146 | - channel.SSHChannel.loseConnection(self) |
147 | - |
148 | - def stopWriting(self): |
149 | - """See `session.SSHSession.stopWriting`. |
150 | - |
151 | - When the client can't keep up with us, we ask the child process to |
152 | - stop giving us data. |
153 | - """ |
154 | - # XXX: MichaelHudson 2008-06-27: Being cagey about whether |
155 | - # self.client.transport is entirely paranoia inspired by the comment |
156 | - # in `loseConnection` above. It would be good to know if and why it is |
157 | - # necessary. See http://twistedmatrix.com/trac/ticket/2754. |
158 | - transport = getattr(self.client, 'transport', None) |
159 | - if transport is not None: |
160 | - # For SFTP connections, 'transport' is actually a _DummyTransport |
161 | - # instance. Neither _DummyTransport nor the protocol it wraps |
162 | - # (filetransfer.FileTransferServer) support pausing. |
163 | - pauseProducing = getattr(transport, 'pauseProducing', None) |
164 | - if pauseProducing is not None: |
165 | - pauseProducing() |
166 | - |
167 | - def startWriting(self): |
168 | - """See `session.SSHSession.startWriting`. |
169 | - |
170 | - The client is ready for data again, so ask the child to start |
171 | - producing data again. |
172 | - """ |
173 | - # XXX: MichaelHudson 2008-06-27: Being cagey about whether |
174 | - # self.client.transport is entirely paranoia inspired by the comment |
175 | - # in `loseConnection` above. It would be good to know if and why it is |
176 | - # necessary. See http://twistedmatrix.com/trac/ticket/2754. |
177 | - transport = getattr(self.client, 'transport', None) |
178 | - if transport is not None: |
179 | - # For SFTP connections, 'transport' is actually a _DummyTransport |
180 | - # instance. Neither _DummyTransport nor the protocol it wraps |
181 | - # (filetransfer.FileTransferServer) support pausing. |
182 | - resumeProducing = getattr(transport, 'resumeProducing', None) |
183 | - if resumeProducing is not None: |
184 | - resumeProducing() |
185 | +from lp.services.sshserver.events import AvatarEvent |
186 | + |
187 | + |
188 | +class BazaarSSHStarted(AvatarEvent): |
189 | + |
190 | + template = '[%(session_id)s] %(username)s started bzr+ssh session.' |
191 | + |
192 | + |
193 | +class BazaarSSHClosed(AvatarEvent): |
194 | + |
195 | + template = '[%(session_id)s] %(username)s closed bzr+ssh session.' |
196 | |
197 | |
198 | class ForbiddenCommand(Exception): |
199 | @@ -116,7 +57,10 @@ |
200 | def closed(self): |
201 | """See ISession.""" |
202 | if self._transport is not None: |
203 | - notify(events.BazaarSSHClosed(self.avatar)) |
204 | + # XXX: JonathanLange 2010-04-15: This is something of an |
205 | + # abstraction violation. Apart from this line and its twin, this |
206 | + # class knows nothing about Bazaar. |
207 | + notify(BazaarSSHClosed(self.avatar)) |
208 | try: |
209 | self._transport.signalProcess('HUP') |
210 | except (OSError, ProcessExitedAlready): |
211 | @@ -154,9 +98,9 @@ |
212 | "ERROR: %r already running a command on transport %r" |
213 | % (self, self._transport)) |
214 | # XXX: JonathanLange 2008-12-23: This is something of an abstraction |
215 | - # violation. Apart from this line, this class knows nothing about |
216 | - # Bazaar. |
217 | - notify(events.BazaarSSHStarted(self.avatar)) |
218 | + # violation. Apart from this line and its twin, this class knows |
219 | + # nothing about Bazaar. |
220 | + notify(BazaarSSHStarted(self.avatar)) |
221 | self._transport = self.reactor.spawnProcess( |
222 | protocol, executable, arguments, env=self.environment) |
223 | |
224 | |
225 | === modified file 'lib/lp/codehosting/sshserver/tests/test_daemon.py' |
226 | --- lib/lp/codehosting/sshserver/tests/test_daemon.py 2010-04-16 19:01:12 +0000 |
227 | +++ lib/lp/codehosting/sshserver/tests/test_daemon.py 2010-04-16 19:01:18 +0000 |
228 | @@ -14,10 +14,10 @@ |
229 | |
230 | from canonical.testing.layers import TwistedLayer |
231 | |
232 | -from lp.codehosting.sshserver.auth import SSHUserAuthServer |
233 | from lp.codehosting.sshserver.daemon import ( |
234 | get_key_path, get_portal, PRIVATE_KEY_FILE, PUBLIC_KEY_FILE) |
235 | -from lp.codehosting.sshserver.service import Factory |
236 | +from lp.services.sshserver.auth import SSHUserAuthServer |
237 | +from lp.services.sshserver.service import Factory |
238 | |
239 | |
240 | class StringTransportWith_setTcpKeepAlive(StringTransport): |
241 | |
242 | === added directory 'lib/lp/services/sshserver' |
243 | === added file 'lib/lp/services/sshserver/__init__.py' |
244 | --- lib/lp/services/sshserver/__init__.py 1970-01-01 00:00:00 +0000 |
245 | +++ lib/lp/services/sshserver/__init__.py 2010-04-16 19:01:18 +0000 |
246 | @@ -0,0 +1,8 @@ |
247 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
248 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
249 | + |
250 | +"""The Launchpad SSH server.""" |
251 | + |
252 | +__metaclass__ = type |
253 | +__all__ = [] |
254 | + |
255 | |
256 | === renamed file 'lib/lp/codehosting/sshserver/accesslog.py' => 'lib/lp/services/sshserver/accesslog.py' |
257 | --- lib/lp/codehosting/sshserver/accesslog.py 2010-04-16 19:01:12 +0000 |
258 | +++ lib/lp/services/sshserver/accesslog.py 2010-04-16 19:01:18 +0000 |
259 | @@ -17,7 +17,7 @@ |
260 | import zope.component.event |
261 | |
262 | from canonical.launchpad.scripts import WatchedFileHandler |
263 | -from lp.codehosting.sshserver.events import ILoggingEvent |
264 | +from lp.services.sshserver.events import ILoggingEvent |
265 | from lp.services.utils import synchronize |
266 | |
267 | |
268 | |
269 | === renamed file 'lib/lp/codehosting/sshserver/auth.py' => 'lib/lp/services/sshserver/auth.py' |
270 | --- lib/lp/codehosting/sshserver/auth.py 2010-04-16 19:01:12 +0000 |
271 | +++ lib/lp/services/sshserver/auth.py 2010-04-16 19:01:18 +0000 |
272 | @@ -38,11 +38,12 @@ |
273 | from zope.event import notify |
274 | from zope.interface import implements |
275 | |
276 | -from lp.codehosting import sftp |
277 | -from lp.codehosting.sshserver import events |
278 | -from lp.codehosting.sshserver.session import PatchedSSHSession |
279 | +from canonical.launchpad.xmlrpc import faults |
280 | + |
281 | +from lp.services.sshserver import events |
282 | +from lp.services.sshserver.sftp import FileTransferServer |
283 | +from lp.services.sshserver.session import PatchedSSHSession |
284 | from lp.services.twistedsupport.xmlrpc import trap_fault |
285 | -from canonical.launchpad.xmlrpc import faults |
286 | |
287 | |
288 | class LaunchpadAvatar(avatar.ConchUser): |
289 | @@ -68,7 +69,7 @@ |
290 | # fixes). |
291 | self.channelLookup = {'session': PatchedSSHSession} |
292 | # ...and set the only subsystem to be SFTP. |
293 | - self.subsystemLookup = {'sftp': sftp.FileTransferServer} |
294 | + self.subsystemLookup = {'sftp': FileTransferServer} |
295 | |
296 | def logout(self): |
297 | notify(events.UserLoggedOut(self)) |
298 | |
299 | === renamed file 'lib/lp/codehosting/sshserver/events.py' => 'lib/lp/services/sshserver/events.py' |
300 | --- lib/lp/codehosting/sshserver/events.py 2010-04-16 19:01:12 +0000 |
301 | +++ lib/lp/services/sshserver/events.py 2010-04-16 19:01:18 +0000 |
302 | @@ -6,8 +6,7 @@ |
303 | __metaclass__ = type |
304 | __all__ = [ |
305 | 'AuthenticationFailed', |
306 | - 'BazaarSSHClosed', |
307 | - 'BazaarSSHStarted', |
308 | + 'AvatarEvent', |
309 | 'ILoggingEvent', |
310 | 'LoggingEvent', |
311 | 'ServerStarting', |
312 | @@ -28,7 +27,7 @@ |
313 | class ILoggingEvent(Interface): |
314 | """An event is a logging event if it has a message and a severity level. |
315 | |
316 | - Events that provide this interface will be logged in codehosting access |
317 | + Events that provide this interface will be logged in the SSH server access |
318 | log. |
319 | """ |
320 | |
321 | @@ -143,13 +142,3 @@ |
322 | class SFTPClosed(AvatarEvent): |
323 | |
324 | template = '[%(session_id)s] %(username)s closed SFTP session.' |
325 | - |
326 | - |
327 | -class BazaarSSHStarted(AvatarEvent): |
328 | - |
329 | - template = '[%(session_id)s] %(username)s started bzr+ssh session.' |
330 | - |
331 | - |
332 | -class BazaarSSHClosed(AvatarEvent): |
333 | - |
334 | - template = '[%(session_id)s] %(username)s closed bzr+ssh session.' |
335 | |
336 | === renamed file 'lib/lp/codehosting/sshserver/service.py' => 'lib/lp/services/sshserver/service.py' |
337 | --- lib/lp/codehosting/sshserver/service.py 2010-04-16 19:01:12 +0000 |
338 | +++ lib/lp/services/sshserver/service.py 2010-04-16 19:01:18 +0000 |
339 | @@ -1,7 +1,7 @@ |
340 | # Copyright 2009 Canonical Ltd. This software is licensed under the |
341 | # GNU Affero General Public License version 3 (see the file LICENSE). |
342 | |
343 | -"""Twisted `service.Service` class for the codehosting SSH server. |
344 | +"""Twisted `service.Service` class for the Launchpad SSH server. |
345 | |
346 | An `SSHService` object can be used to launch the SSH server. |
347 | """ |
348 | @@ -24,8 +24,8 @@ |
349 | |
350 | from zope.event import notify |
351 | |
352 | -from lp.codehosting.sshserver import accesslog, events |
353 | -from lp.codehosting.sshserver.auth import SSHUserAuthServer |
354 | +from lp.services.sshserver import accesslog, events |
355 | +from lp.services.sshserver.auth import SSHUserAuthServer |
356 | from lp.services.twistedsupport import gatherResults |
357 | from lp.services.twistedsupport.loggingsupport import set_up_oops_reporting |
358 | |
359 | |
360 | === added file 'lib/lp/services/sshserver/session.py' |
361 | --- lib/lp/services/sshserver/session.py 1970-01-01 00:00:00 +0000 |
362 | +++ lib/lp/services/sshserver/session.py 2010-04-16 19:01:18 +0000 |
363 | @@ -0,0 +1,79 @@ |
364 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
365 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
366 | + |
367 | +"""Patched SSH session for the Launchpad server.""" |
368 | + |
369 | +__metaclass__ = type |
370 | +__all__ = [ |
371 | + 'PatchedSSHSession', |
372 | + ] |
373 | + |
374 | +from twisted.conch.ssh import channel, session |
375 | + |
376 | + |
377 | +class PatchedSSHSession(session.SSHSession, object): |
378 | + """Session adapter that corrects bugs in Conch. |
379 | + |
380 | + This object provides no custom logic for Launchpad, it just addresses some |
381 | + simple bugs in the base `session.SSHSession` class that are not yet fixed |
382 | + upstream. |
383 | + """ |
384 | + |
385 | + def closeReceived(self): |
386 | + # Without this, the client hangs when it's finished transferring. |
387 | + # XXX: JonathanLange 2009-01-05: This does not appear to have a |
388 | + # corresponding bug in Twisted. We should test that the above comment |
389 | + # is indeed correct and then file a bug upstream. |
390 | + self.loseConnection() |
391 | + |
392 | + def loseConnection(self): |
393 | + # XXX: JonathanLange 2008-03-31: This deliberately replaces the |
394 | + # implementation of session.SSHSession.loseConnection. The default |
395 | + # implementation will try to call loseConnection on the client |
396 | + # transport even if it's None. I don't know *why* it is None, so this |
397 | + # doesn't necessarily address the root cause. |
398 | + # See http://twistedmatrix.com/trac/ticket/2754. |
399 | + transport = getattr(self.client, 'transport', None) |
400 | + if transport is not None: |
401 | + transport.loseConnection() |
402 | + # This is called by session.SSHSession.loseConnection. SSHChannel is |
403 | + # the base class of SSHSession. |
404 | + channel.SSHChannel.loseConnection(self) |
405 | + |
406 | + def stopWriting(self): |
407 | + """See `session.SSHSession.stopWriting`. |
408 | + |
409 | + When the client can't keep up with us, we ask the child process to |
410 | + stop giving us data. |
411 | + """ |
412 | + # XXX: MichaelHudson 2008-06-27: Being cagey about whether |
413 | + # self.client.transport is entirely paranoia inspired by the comment |
414 | + # in `loseConnection` above. It would be good to know if and why it is |
415 | + # necessary. See http://twistedmatrix.com/trac/ticket/2754. |
416 | + transport = getattr(self.client, 'transport', None) |
417 | + if transport is not None: |
418 | + # For SFTP connections, 'transport' is actually a _DummyTransport |
419 | + # instance. Neither _DummyTransport nor the protocol it wraps |
420 | + # (filetransfer.FileTransferServer) support pausing. |
421 | + pauseProducing = getattr(transport, 'pauseProducing', None) |
422 | + if pauseProducing is not None: |
423 | + pauseProducing() |
424 | + |
425 | + def startWriting(self): |
426 | + """See `session.SSHSession.startWriting`. |
427 | + |
428 | + The client is ready for data again, so ask the child to start |
429 | + producing data again. |
430 | + """ |
431 | + # XXX: MichaelHudson 2008-06-27: Being cagey about whether |
432 | + # self.client.transport is entirely paranoia inspired by the comment |
433 | + # in `loseConnection` above. It would be good to know if and why it is |
434 | + # necessary. See http://twistedmatrix.com/trac/ticket/2754. |
435 | + transport = getattr(self.client, 'transport', None) |
436 | + if transport is not None: |
437 | + # For SFTP connections, 'transport' is actually a _DummyTransport |
438 | + # instance. Neither _DummyTransport nor the protocol it wraps |
439 | + # (filetransfer.FileTransferServer) support pausing. |
440 | + resumeProducing = getattr(transport, 'resumeProducing', None) |
441 | + if resumeProducing is not None: |
442 | + resumeProducing() |
443 | |
444 | === added file 'lib/lp/services/sshserver/sftp.py' |
445 | --- lib/lp/services/sshserver/sftp.py 1970-01-01 00:00:00 +0000 |
446 | +++ lib/lp/services/sshserver/sftp.py 2010-04-16 19:01:18 +0000 |
447 | @@ -0,0 +1,35 @@ |
448 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
449 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
450 | + |
451 | +"""Generic SFTP server functionality.""" |
452 | + |
453 | +__metaclass__ = type |
454 | +__all__ = [ |
455 | + 'FileTransferServer', |
456 | + ] |
457 | + |
458 | +from twisted.conch.ssh import filetransfer |
459 | + |
460 | +from zope.event import notify |
461 | + |
462 | +from lp.services.sshserver import events |
463 | + |
464 | + |
465 | +class FileTransferServer(filetransfer.FileTransferServer): |
466 | + """SFTP protocol implementation that logs key events.""" |
467 | + |
468 | + def __init__(self, data=None, avatar=None): |
469 | + filetransfer.FileTransferServer.__init__(self, data, avatar) |
470 | + notify(events.SFTPStarted(avatar)) |
471 | + self.avatar = avatar |
472 | + |
473 | + def connectionLost(self, reason): |
474 | + # This method gets called twice: once from `SSHChannel.closeReceived` |
475 | + # when the client closes the channel and once from `SSHSession.closed` |
476 | + # when the server closes the session. We change the avatar attribute |
477 | + # to avoid logging the `SFTPClosed` event twice. |
478 | + filetransfer.FileTransferServer.connectionLost(self, reason) |
479 | + if self.avatar is not None: |
480 | + avatar = self.avatar |
481 | + self.avatar = None |
482 | + notify(events.SFTPClosed(avatar)) |
483 | |
484 | === added directory 'lib/lp/services/sshserver/tests' |
485 | === added file 'lib/lp/services/sshserver/tests/__init__.py' |
486 | --- lib/lp/services/sshserver/tests/__init__.py 1970-01-01 00:00:00 +0000 |
487 | +++ lib/lp/services/sshserver/tests/__init__.py 2010-04-16 19:01:18 +0000 |
488 | @@ -0,0 +1,8 @@ |
489 | +# Copyright 2010 Canonical Ltd. This software is licensed under the |
490 | +# GNU Affero General Public License version 3 (see the file LICENSE). |
491 | + |
492 | +"""Tests for the Launchpad SSH server.""" |
493 | + |
494 | +__metaclass__ = type |
495 | +__all__ = [] |
496 | + |
497 | |
498 | === added directory 'lib/lp/services/sshserver/tests/keys' |
499 | === added file 'lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa' |
500 | --- lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa 1970-01-01 00:00:00 +0000 |
501 | +++ lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa 2010-04-16 19:01:18 +0000 |
502 | @@ -0,0 +1,15 @@ |
503 | +-----BEGIN RSA PRIVATE KEY----- |
504 | +MIICXAIBAAKBgQDSSpVRPhCiU9PPuZN7QyJdMOgTVwPyYpZGOHutR/9kxFvOLa39 |
505 | +nY0Eqo39OTumfZBMEEVqIPadQanO9LcdTnl9/Z4LcBGn09EFQ2y7VUkC6J2dSQtr |
506 | +YMY0tV+C5HGZ2oYBWKBl5PZ1RI4+qrJpAMMmINdnF0uEE/x8B1iMWGB3PwIBIwKB |
507 | +gQCcN2ebb+8ZgBmwQLazVnFMirsHDXClbc630i/9EOmbUAmvGp6B4sCHH5ytevkc |
508 | +l8pHIget7JnxKXbUQMKKzJTCpPwwEyL3ZVDxYXg37WQU74cVf93CjOjChs+hOeS1 |
509 | +sW5m9JFr9oomL5JWnGXr+TV/kYBCNVW++J1Bckn6kYpH+wJBAPUw0ZunXlBRuugA |
510 | +YTSmXUUX+ALu6maDD1t7gAk37waxNQMaH5DMk5R4IQtoxeQgCLqL2yEJUqK1lxOy |
511 | +wlp1k8UCQQDbj+Vr4poE9MpYNtPDiDqv2aXe6CJ3p1qQuNE0rSxk+0G9h3ASISRw |
512 | +DDLgcapg2xkOvG3pidfAJG9P827XiVszAkEA4CyiYm0jB5suivkIaqa7rOK23hxE |
513 | +BfQrTFOoQvFPkRcL5ZQ6Hfzes6EIRPIUA8WEUskC3GBLjXLTRTW5Aj+dCwJBAMi+ |
514 | +E5XWfjBqx6EcL1OvwKDG/g2hCZH4GEnNjBLneQveZ/29qEsW/L43CfHHAiyrD5hx |
515 | +w5OxOklF4h02VrZu9EsCQBEZcTAQOrWnkmp7uBrz1V8nFLAE6zFh/6Wj1Mn8k08j |
516 | +pcsLJAhm+qlV7EtV/5rk+v3WcXrKiRIiiC0Ron96Dx0= |
517 | +-----END RSA PRIVATE KEY----- |
518 | |
519 | === added file 'lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa.pub' |
520 | --- lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa.pub 1970-01-01 00:00:00 +0000 |
521 | +++ lib/lp/services/sshserver/tests/keys/ssh_host_key_rsa.pub 2010-04-16 19:01:18 +0000 |
522 | @@ -0,0 +1,1 @@ |
523 | +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA0kqVUT4QolPTz7mTe0MiXTDoE1cD8mKWRjh7rUf/ZMRbzi2t/Z2NBKqN/Tk7pn2QTBBFaiD2nUGpzvS3HU55ff2eC3ARp9PRBUNsu1VJAuidnUkLa2DGNLVfguRxmdqGAVigZeT2dUSOPqqyaQDDJiDXZxdLhBP8fAdYjFhgdz8= andrew@frobozz |
524 | |
525 | === renamed file 'lib/lp/codehosting/sshserver/tests/test_logging.py' => 'lib/lp/services/sshserver/tests/test_accesslog.py' |
526 | --- lib/lp/codehosting/sshserver/tests/test_logging.py 2010-04-16 19:01:12 +0000 |
527 | +++ lib/lp/services/sshserver/tests/test_accesslog.py 2010-04-16 19:01:18 +0000 |
528 | @@ -18,7 +18,7 @@ |
529 | import zope.component.event |
530 | |
531 | from canonical.launchpad.scripts import WatchedFileHandler |
532 | -from lp.codehosting.sshserver.accesslog import LoggingManager |
533 | +from lp.services.sshserver.accesslog import LoggingManager |
534 | from lp.testing import TestCase |
535 | |
536 | |
537 | @@ -71,9 +71,9 @@ |
538 | self.assertEqual(root_handlers, logging.getLogger('').handlers) |
539 | self.assertEqual(bzr_handlers, logging.getLogger('bzr').handlers) |
540 | |
541 | - def test_codehosting_log_doesnt_go_to_stderr(self): |
542 | + def test_log_doesnt_go_to_stderr(self): |
543 | # Once logging setup is called, any messages logged to the |
544 | - # codehosting logger should *not* be logged to stderr. If they are, |
545 | + # SSH server logger should *not* be logged to stderr. If they are, |
546 | # they will appear on the user's terminal. |
547 | log = self.makeLogger() |
548 | self.installLoggingManager(log) |
549 | @@ -136,7 +136,7 @@ |
550 | |
551 | def test_access_handlers(self): |
552 | # The logging setup installs a rotatable log handler that logs output |
553 | - # to config.codehosting.access_log. |
554 | + # to the SSH server access log. |
555 | directory = self.makeTemporaryDirectory() |
556 | access_log = self.makeLogger() |
557 | access_log_path = os.path.join(directory, 'access.log') |
558 | |
559 | === renamed file 'lib/lp/codehosting/sshserver/tests/test_auth.py' => 'lib/lp/services/sshserver/tests/test_auth.py' |
560 | --- lib/lp/codehosting/sshserver/tests/test_auth.py 2010-04-16 19:01:12 +0000 |
561 | +++ lib/lp/services/sshserver/tests/test_auth.py 2010-04-16 19:01:18 +0000 |
562 | @@ -21,10 +21,9 @@ |
563 | |
564 | from twisted.trial.unittest import TestCase as TrialTestCase |
565 | |
566 | -from canonical.config import config |
567 | from canonical.launchpad.xmlrpc import faults |
568 | from canonical.testing.layers import TwistedLayer |
569 | -from lp.codehosting.sshserver import auth |
570 | +from lp.services.sshserver import auth |
571 | from lp.services.twistedsupport import suppress_stderr |
572 | |
573 | |
574 | @@ -224,7 +223,7 @@ |
575 | |
576 | def test_bannerNotSentOnSuccess(self): |
577 | # No banner is printed when the user authenticates successfully. |
578 | - self.assertEqual(None, config.codehosting.banner) |
579 | + self.user_auth._banner = None |
580 | |
581 | d = self.requestSuccessfulAuthentication() |
582 | def check(ignored): |
583 | |
584 | === renamed file 'lib/lp/codehosting/sshserver/tests/test_events.py' => 'lib/lp/services/sshserver/tests/test_events.py' |
585 | --- lib/lp/codehosting/sshserver/tests/test_events.py 2010-04-16 19:01:12 +0000 |
586 | +++ lib/lp/services/sshserver/tests/test_events.py 2010-04-16 19:01:18 +0000 |
587 | @@ -13,7 +13,7 @@ |
588 | import zope.component.event |
589 | from zope.event import notify |
590 | |
591 | -from lp.codehosting.sshserver.events import ILoggingEvent, LoggingEvent |
592 | +from lp.services.sshserver.events import ILoggingEvent, LoggingEvent |
593 | |
594 | from lp.testing import TestCase |
595 |
<rockstar> jml, all of the codehosting- to-services branch is moves right? No real changes? sshkeygen. com/
<jml> rockstar, pretty much. except for what I mention in my comment.
<rockstar> jml, okay, so basically just docstrings and test comments got changed (outside of imports)
<jml> rockstar, that sounds right.
<rockstar> jml, okay. Looking now.
<rockstar> jml, your comment says you had to copy keys over. Why couldn't you move them?
<jml> rockstar, they are also used by the codehosting acceptance tests.
<rockstar> jml, hm. Do you really think it's wise to duplicate those keys?
<jml> rockstar, why would it be unwise?
<rockstar> jml, duplication. It's not code, this I know. But duplication in general can become unfun.
<jml> rockstar, you want me to generate a new RSA SSH key pair?
<jml> rockstar, it's pretty easy. there's even a cool website that'll do it for you!
<rockstar> jml, no, we can use the same one, but I'm wondering if we could symlink or something.
<rockstar> jml, that sounds like a very silly website. :)
<jml> rockstar, it is – http://
* rockstar groans
<jml> rockstar, anyway, I can make them symlinks if you want. it doesn't matter much either way to me
<rockstar> jml, actually, it doesn't matter much to me either. The question was more or less one of Kiko's "exploratory" questions. If you're okay with it, I am.
<jml> rockstar, cool.