RVM, Passenger and symlinks

Première publication : 2010-08-25

Here is some kind of follow up after my previous lengthy description on how we use RVM, Passenger and Rails at work.

One of my co-workers has updated RVM this morning (to get the brand new 1.0.0) and all his local Rails web apps broke down.

We’ve spent about an hour checking with Bundler (also updated from rc5 to rc6 before the breakdown), reinstalling Passenger, completely nuking RVM and reinstalling everything from scratch (rubies, Gemsets, gems…). Nothing good came out of this :-(

We had very few information ; nothing in the browser, no Rails logs and no Apache logs either. But when when we stopped Apache, it spit a few lines before stopping, showing a Passenger error stating that a method is missing in the RVM setup for the particular Rails app (cf. the setup_load_paths.rb file).

The same setup on my own laptop was working great.

RVM is updated with Git, so it’s quite easy to install a specific tag and see if it’s working. I’ve tracked down the changes to the point where the latest tag (1.0.0) was breaking my friend’s apps.

The wonderful RVM guys (wayneeseguin and Sutto) told me (in the IRC channel) that the major thing that has changed in 1.0.0 is the security feature about .rvmrc files. They have to be manually trusted the first time RVM meets them.

We were sure that we did this for the .rvmrc file in each of the Rails apps, but Passenger was still hanging, as if it was waiting for something

Sutto explained to me that RVM is making a md5 checksum of the path of each trusted (or not) .rvmrc file. We have verified that there was indeed a line for our .rvmrc files.

With RVM 1.0.0 you can choose to disable this security feature globally. When we did this, everything started to work fine again. As soon as we activated this again, every app stopped working. It became clear that it had to do with the .rvmrc files.

Sutto asked me to show him the VHosts for the Ruby apps and then I understood !

Usually, on Mac OS X, you put your web stuff in /Users/_my_login/Sites and point your VHosts to some subdirectories of that. It’s like /home/_my_login/www in the Linux/Unix world. I don’t know why, but my co-worker (from this point, I no longer considered him as my friend) (I’m kidding) has has created a symlink to point /Users/_his_login/www to /Users/_his_login/Sites. You’d tell me that there is nothing wrong here, and you’d be right.

In his terminal, when he wants to go to his web app directory to work, he’s doing something like cd ~/www/_project. Then, the first time, RVM asks him about the .rvmrc it finds just here. The .rvmrc file is trusted and RVM is working fine. It seems.

In his VHosts, the RootDirectory is like /Users/_his_login/Sites/_project(notice the Sites part instead of www), and Passenger executes the config script that reads the .rvmrc file to use the right things. At this very moment, the .rvmrc file’s path is /Users/_his_login/Sites/_project/.rvmrc and its md5 checksum is obviously different than the one for the trusted /Users/_his_login/www/_project/.rvmrc file.

For the moment Passenger doesn’t know what to do. It waits for RVM to give him some environment variables, RVM doesn’t give it anything because it waits for the file to be trusted (or not).

With Sutto, we agreed that the best thing to do is to document this and make Passenger aware of this, to let him show some error in the browser and/or in the web server’s log file.

That’s how we’ve lost nearly 3 hours today, because of a symlink. But once again, I learned a lot. I’d rather read this kind stuff in a blog post, in just a few minutes (that’s why I’m writing this), than spending some hours, but I don’t really regret it.

Update : Sutto has just told my that the current HEAD for RVM is showing an exception when RVM asks to trust (or not) the newly found .rvmrc file. You just have to do $ rvm update --head && rvm reload.