Saturday, August 27, 2011

Buildin' a fence

Earlier this year Jericho, myself, and a bunch of friends and family planted a little orchard at the farm in Maine. This week I built a fence around it.

Happily mowing was mostly taken care of before I arrived:




So it was easy to work around the trees and along the eventual fence-line.

I started at the corners of the area and drove 8 foot steel t-posts:



Using a post driver:



This was actually a lot easier than I expected, perhaps because of the heavy rains on the preceding evenings. I strung 12 gauge monofilament wire between these to define a straight line:



I used the line to place intermediate t-posts:



After 15 t-posts were up and connected with monofilament, I hung deer netting from it:



This part seemed harder than driving the t-posts, maybe because I was already somewhat tired from that earlier activity, and maybe because this activity mostly involved holding my arms above my head for long periods of time doing more close-detail work.

I started by zip-tying the net to the monofilament to temporarily fight sag between posts:



Then I used inline tensioners to take up the slack:



The bottom of the net is held down with sod staples:




The netting quickly vanishes as you move away from it, so I also flagged each stretch:



Some loose ends still need to be wrapped up. I found some ferrules at the hardware store to secure the monofilament, but I haven't tried crimping them yet. The zip-ties need to be replaced with a more robust solution. And the deer net needs to be secured to each t-post to keep it from billowing so much.

Monday, August 22, 2011

Redhumped Caterpillar

At my mom's for the week (at least), house-sitting and putting up fence. I had some warning about these:



However seeing the almost stripped tree they were feeding on in person was still a shock:



I had tentatively identified them as codling moth larvae, which didn't quite make sense since these typically grow and feed inside fruit, not on leaves. My revised identification is redhumped caterpillar. I just sent an email to Maine Cooperative Extension to see what they think.

The bright side is that only one tree appears affected, and there seems to be a fair chance that it will recover.

Monday, August 1, 2011

Twisted Conch in 60 Seconds: Protocols

Welcome once more to Twisted Conch in 60 Seconds, the tutorial series about writing SSH applications with Twisted.

Over the past several articles, I've introduced the APIs for letting clients establish a new logical connection to your SSH server, generating output on those connections, accepting input on those connections, and detecting the end of those connections. Taken together, these four activities map almost exactly onto the standard Twisted protocol abstraction (represented and documented by the IProtocol interface). In this article, I'll show you how to use any IProtocol implementation from Twisted to interact with an SSH channel.

The previous example implemented an echo-ish type of server by customizing the session. I'll duplicate that functionality here, but in an IProtocol implementation:

class EchoProtocol(Protocol):
def connectionMade(self):
self.transport.write("Echo protocol connected\r\n")

def dataReceived(self, bytes):
self.transport.write("echo: " + repr(bytes) + "\r\n")

def connectionLost(self, reason):
print 'Connection lost', reason


Each of the three events a protocol might receive is handled here - connection made and data received are handled by writing something to the connection, and connection lost is handled by writing something to stdout (writing to the connection is no longer an option after it has been lost, of course). This is a simple, fairly typical Twisted-based protocol implementation; you'll find protocols like this all over the place.
The major part of the requirements for using this is having a transport to which to connect it. The SSHSession class you're now familiar with can serve in just that role. Only a little code to put it together with a protocol is required. Again I'll create a "session" channel which accepts but ignores pty requests:

class SimpleSession(SSHSession):
name = 'session'

def request_pty_req(self, data):
return True


And again I'll override request_shell so that the protocol is connected to the channel/transport as soon as the client requests a shell.

    def request_shell(self, data):
protocol = EchoProtocol()


All I've done so far here is make an instance of the protocol defined above. Next I'll create the transport object and hook it up to this protocol. This part uses a couple helpers from twisted.conch.ssh.session, SSHSessionProcessProtocol and wrapProtocol:

        transport = SSHSessionProcessProtocol(self)
protocol.makeConnection(transport)
transport.makeConnection(wrapProtocol(protocol))
self.client = transport
return True


Each step here is necessary, but the specifics aren't very interesting or important. Suffice it to say it hooks objects up as necessary so that bytes can be passed from the SSHSession to the protocol and vice versa.

The rest of the code for this version is the same as it has been in the previous versions (except for new imports). Here's the full code listing:

from twisted.internet.protocol import Protocol
from twisted.cred.portal import Portal
from twisted.cred.checkers import FilePasswordDB
from twisted.conch.ssh.factory import SSHFactory
from twisted.internet import reactor
from twisted.conch.ssh.keys import Key
from twisted.conch.interfaces import IConchUser
from twisted.conch.avatar import ConchUser
from twisted.conch.ssh.session import (
SSHSession, SSHSessionProcessProtocol, wrapProtocol)

with open('id_rsa') as privateBlobFile:
privateBlob = privateBlobFile.read()
privateKey = Key.fromString(data=privateBlob)

with open('id_rsa.pub') as publicBlobFile:
publicBlob = publicBlobFile.read()
publicKey = Key.fromString(data=publicBlob)

class EchoProtocol(Protocol):
def connectionMade(self):
self.transport.write("Echo protocol connected\r\n")

def dataReceived(self, bytes):
self.transport.write("echo: " + repr(bytes) + "\r\n")

def connectionLost(self, reason):
print 'Connection lost', reason

def nothing():
pass

class SimpleSession(SSHSession):
name = 'session'

def request_pty_req(self, data):
return True

def request_shell(self, data):
protocol = EchoProtocol()
transport = SSHSessionProcessProtocol(self)
protocol.makeConnection(transport)
transport.makeConnection(wrapProtocol(protocol))
self.client = transport
return True

class SimpleRealm(object):
def requestAvatar(self, avatarId, mind, *interfaces):
user = ConchUser()
user.channelLookup['session'] = SimpleSession
return IConchUser, user, nothing

factory = SSHFactory()
factory.privateKeys = {'ssh-rsa': privateKey}
factory.publicKeys = {'ssh-rsa': publicKey}
factory.portal = Portal(SimpleRealm())
factory.portal.registerChecker(FilePasswordDB("ssh-passwords"))

reactor.listenTCP(2022, factory)
reactor.run()


Connect to this server with an ssh client and type away, you should see something like this:


exarkun@boson:~$ ssh -p 2022 localhost
exarkun@localhost's password:
Echo protocol connected
echo: 'h'
echo: 'e'
echo: 'l'
echo: 'l'
echo: 'o'
echo: ','
echo: ' '
echo: 'w'
echo: 'o'
echo: 'r'
echo: 'l'
echo: 'd'
echo: '.'

Tune in next time for a surprise topic!