A chroot environment seems to be rare these days. Everything is virtualized, load-balanced and what have you. I recently found myself trying to deploy into a chroot’ed Lighttpd environment with Capistrano and immediately ran over several pitfalls. The biggest problem is that Capistrano uses absolute links for directories like current and the links to the log directory.

A base directory for your app could be /var/www/rails and your Lighttpd runs in a chroot environment in /srv/lighty. In the application directory Capistrano creates the directories releases and shared. After a successful deployment it also creates a symbolic link named current pointing to the latest release, and several links to directories in system.

In this scenario the link current would point to the directory /srv/lighty/var/www/rails/releases/20070506135654. Now, since Lighttpd doesn’t know the directory structure above /srv/lighty that’s a bit of a problem and it won’t find the path when you point it to the dispatcher in the directory current. This is true if you launch your Rails application through FastCGI. In a Mongrel scenario it would pretty much result in the same problems. Additionally, your Rails application won’t find its log and other directories (if you’re up for it, these are public/system and tmp/pids).

Apparently not many people seem to use an environment like this. It’s pretty old-fashioned in this highly virtualized world, but you run across it from time to time. So what can you do?

Hacking the Symbolic Links

This isn’t going to be pretty. To get the thing to work somehow I created a filter for after_update_code and removed the links created by Capistrano to replace them with new ones, only this time they wouldn’t use absolute paths, but relative ones.

I’m not proud of this solution, but I had to come up with something pretty quickly, and it works for the moment, and was only supposed to do so. It will be replaced with a production-like deployment soon. I’ve replaced the task :symlink with my own which looks like this:

desc "Overwriting symlink task to 
task :symlink do
  on_rollback {
    run "cd #{deploy_to} && ln -nfs releases/#{File.basename previous_release} current"
  }

  run "cd #{deploy_to} && ln -nfs releases/#{File.basename current_release} current"

  run <<-CMD
    cd #{deploy_to} &&
    rm -f current/log current/public/system &&
    ln -nfs ../../shared/log current/log &&
    ln -nfs ../../../shared/system current/public/system
  CMD

  run <<-CMD
    test -d #{shared_path}/pids && 
    rm -rf #{release_path}/tmp/pids && 
    cd #{deploy_to} &&
    ln -nfs ../../../#{File.basename shared_path}/pids current/tmp/pids; true
  CMD
end

One remark: I remove some symlinks in the code, because Capistrano creates them in the update_code task.

As I said, it’s not pretty but it works. Here’s what it does: It removes the symbolic links created by Capistraon and replaces them with new ones using relative paths.

Putting the user in a cage

The better solution is to directly deploy into your chroot environment. Create a user that’s directly being send into it by SSH or by its login shell.

This scenario requires that all the tools needed for a deployment must be installed in the chroot environment, including Subversion. If that’s not a problem, this might be the ideal situation.

One thing you can’t do is restart your web server from here. A scenario like this would mean that you can only restart your FastCGI or Mongrel processes. This is a scenario I’ll use in the long run.

So is this hassle worth it? I’m not sure myself. It’s questionable, if the little added security is worth the effort you have to put in to get your applications working. In the end it depends on what your client's environment looks like, and if you have any control over it. If guidelines require chroot’ed services, then there’s not much you can do. Other than that I’d consider breaking the service out of the chroot and trying to find a better way of securing it. Xen and the like come to mind.

Tags: rails, ruby

At first I was rather disappointed by what Sun announced with JavaFX, the newest competitor in the RIA market. In my taste F3 looks rather ugly and has a way too expressive syntax, compared to, say SVG. The target's not the same between these two, I know that, but comparing what code you need to draw, SVG is a winner. Anyway, that's not really the point.

An announcement on RailsConf shed a new light on JavaFX. A new framework called RubyFX is on a quest to close the gap between the DLR supporting Ruby and Sun's rather desperate attempt to get into the RIA market. The code looks very expressive, and to say the least, is what I'm talking about. It's still early alpha, but it looks promising.

(Via Dion)

Tags: ruby

In an earlier post I wrote about namespacing your Rails model. There's an additional issue that must be thought of when doing so. Rails (of course) has conventions dealing with namespaces.

Normally, when you put classes in namespaces, like Admin::User, Rails normally expects this class to be in a folder admin in your app/models directory. Responsible for this is the method load_missing_constant in the module Dependencies, part of ActiveSupport. It also uses the namespace to build the table name. So Admin::User would result in admin_users. This isn't always a desirable outcome. Of course you could set a table name explicitly:

class Admin::User < ActiveRecord::Base
  set_table_name "users"
end

If you need to avoid namespace clashes, that's an acceptable option. But what if you only want to bring some order to your model directory? You want to create some subfolders to separate your model physically, if only to avoid having dozens of files in the model folder.

This is where load_missing_constant kicks in again. If you don't load the files in the subdirectories explicitly, it will assume that the files are in their according namespace. So having a class User in a file user.rb lying in the folder app/models/admin/ will lead it to assume User exists in the module Admin. To avoid that you'll have to add your model subfolders as load paths. To do that you can add the following line to your environment.rb:

config.load_paths += Dir["#{RAILS_ROOT}/app/models/[a-z]*"]

This will tell Rails to look for the the files in all subfolders of app/models on startup. This won't solve the issue yet, you'll still need to explicitly load the classes. So you put the following lines at the end of your environment.rb:

[ "app/models" ].each do |path|
  Dir["#{RAILS_ROOT}/#{path}/**/*.rb"].each do |file|
    load file
  end
end

That way you'll avoid the implicit call to load_missing_constant. You can add directories to the list, e.g. a subdirectory in lib. You could also explicitly require the classes you need, but who wants to do that, really?

Tags: rails, ruby