Refactoring Net::SSH: Part 6
In spite of appearances, progress has been happening (slowly) on Net::SSH. This next installment of the “Refactoring Net::SSH” series will give a brief look at what the latest changes have been, and what’s next on my “to do” list.
Tweaking the Transport Layer
As you may recall, the last article in this series was about the completion of the refactoring of the transport layer. Complete or not, I’ve continued tinkering on it. Originally, I had intended to allow a single Needle registry to contain multiple SSH sessions.
I’ve changed my mind.
The reasons for this are several, but the primary one is that it is just much easier if you only allow singletons in your registry. (Or, rather, it is easier if you require the primary dependencies in your app to be singletons. I still have many prototype services in the new Net::SSH.) If a service is known to be a singleton, you can just inject it as a dependency into any other service you want, and you’re guaranteed that the same instance of that service will be used throughout your application. By making the transport session service a prototype service, instead of singleton, I made alot more work for myself, because I now had to manually inject the correct instance of the session into each service that required it.
So, the transport session is now a singleton, and a registry may only contain a single instance of it. This isn’t a big deal—it just means that when I get around to finishing Net::SSH, the primary client interface will need to create a new registry (behind the scenes, of course) for each SSH connection that is requested.
It turned out to be surprisingly easy to make the change, although there are still a few places left to tweak for consistency’s sake. All I had to do was change the definition of the transport session service, and then change how other services that were dependent on the session referenced that service. Took about 15 minutes.
Last week I finished refactoring the user authentication service. This included the ssh-agent interface, the user key manager, and the three supported authentication mechanisms (password, public-key, and host-based). Before, all of this was implemented in three classes: Agent, UserKeyManager, and UserAuth. I split it up even further, making (among other things) each supported authentication mechanism its own class. It is now all unit tested, and although I haven’t done a formal integration test with the transport layer, I did write a simple test script that seemed to work as expected.
(Which brings me to a question, for any integration-testing gurus that happen to read this. What would be the best way to test the integration of the user authentication stuff with the transport layer? The only way I can think of is to add a new user to my machine and hard code that user’s password in the integration tests (to test the password authentication mechanism). I would also need to enable host-based authentication in my ssh server, and enable this test user to log into my machine based on the host they are on. I hesitate to do either of these things, for security reasons…)
The next piece to tackle is the connection layer, which manages the opening, closing, and processing of SSH channels. This will be a monstrous bit of work, made more so because I don’t particularly like how it is currently implemented. Plus, I’ve forgotten the details of how it works, so I’ll need to hit the SSH spec again to refresh my memory of the particulars. Because I’m not too excited at the prospect of this, things have ground almost to a halt on the Net::SSH refactoring, although I did spend some time yesterday reacquainting myself with the current implementation.
I’m afraid I won’t be able to reuse very much of the existing implementation…and it’s close to 1,000 lines of code. Ouch. :(
I really want to finish this. There are several other projects I’d rather be working on!