I’m breaking the one post per week goal here with a project update.
I’ve released v0.1 of my remote command execution script, “fan”. This is still an early release, but things are coming together. I’ll be fixing a few bugs and adding some features for the v0.3 release (hopefully) before September. Here’s the current version’s features from the README:
v0.1 Features and Limitations
Download the latest version or fork the project via its Github page: http://github.com/hooobs/fan
I’ve run into a problem at my day job where I need to securely transfer some files between two discontiguous networks. Originally I place a server between the two networks to act as a staging area, but this seemed like a cumbersome method. More recently I’ve been working out a solution using EventMachine.
Using EventMachine::Connection@send_file_data, I’ve been able to stream a file to another machine and echo the contents of the file. The code below is pretty rough and simple, but it’s just a building block in a larger bit of code that perform all sorts of other tasks. Replace “YOUR_SERVER_HERE” with your the relevant listening server address.
fclient.rb (gist: 541251)
require 'rubygems'
require 'eventmachine'
module Client
def post_init
send_data "test_data.txt>"
EventMachine::send_file_data @signature, "test_data.txt"
end
def receive_data(data)
puts data
close_connection_after_writing
end
def unbind
puts "-- CONNECTION TERMINATED"
EventMachine::stop_event_loop
end
end
EventMachine::run {
EventMachine::connect 'YOUR_SERVER_HERE', 7799, Client
}
server (gist: 541250)
require 'rubygems'
require 'eventmachine'
module EchoServer
def post_init
puts "-- CONNECTION ESTABLISHED"
end
def receive_data data
send_data "-- DATA RECEIVED"
filename = data.split('>')[0]
filedata = data.split('>')[1]
puts "-- INCOMING DATA"
puts "-- FILENAME: #{filename}"
puts "-- DATA:\n\n #{filedata}"
puts "\n-- END DATA"
end
def unbind
puts "-- CONNECTION TERMINATED"
end
end
EventMachine::run {
EventMachine::start_server 'YOUR_SERVER_HERE', 7799, EchoServer
}
And that’s that. I’ve further modified the server to write the incoming data to a file and the client to actually pull the filename from the directory it monitors. The next step is to work in some sort of encryption as well.
Years ago, I used fanout for this purpose and thought that it’d be interesting to see a Ruby version of it. I haven’t had much time to work in a solid streak on the project, but lately I’ve been trying to work on a method to execute commands across several servers at once. I know this can be accomplished with applications like Capistrano, but I wanted to be able to execute the commands in parallel. I also wanted to learn a little bit about net-ssh and concurrency in Ruby along the way.
Currently I’m using Thread to execute commands in parallel, though I’m looking into other ways to achieve the same goal. Projects like the AMQP gem and Resque look like they’d be a handy way to have the bulk of the work queued up on a management machine to take some of the workload off the machine the tasks were issued from. I’m also looking into turning this into a sort of distributed cron and a message queue would make that transition a little smoother.
The only major issues I’m trying to work around right now is the ability to run administrative commands easily. I generally restrict root logins via ssh and having password-less sudo accounts defeats that purpose. I’m investigating the possibility of using AppArmor to secure an account to run specific commands, though it feels a little sketchy. Using a gem like Highline might be an option to allow for administrative commands to be issued somewhat interactively, though this would break the parallel goal I hoped to achieve.
Enough rambling, here’s the code in its infancy. I’ll be updating it as I have time away from paid projects. http://github.com/hooobs/fan