Archive for the ‘Linux’ Category

Sunday, September 16th, 2007

Recently we needed to run some tests against our application. However, the application shells out and uses a couple of Unix commands to do some of its work - commands that were not installed on my dev box at the time. Rather than ignoring failing tests (something, like ignoring warnings, I find really hard to do) I thought I should alter the tests to only run if the Unix command was present. After some discussion with Peter he came up with the following syntax:

using :some_command do   some_workend

Pretty nice - if some_command is available then the block is executed, otherwise nothing happens.

(By the way, the code below is (c) 2007 Rahoul Baruah and is available under the LGPL and is not the same as the code that actually made it into our application. [Legal stuff over])

require ‘open3′

module UnixTools

  def using command    raise “USING: you must supply a block when calling using” unless block_given? 

    installed = false    Open.popen3(”which #{command.to_s}”) do | stdin, stdout, stderr |      line = stdout.readline.chomp      expression = Regexp.new “(.)*no #{command.to_s} in(.)*”      installed = !expression.match line    end

    return (installed ? yield : false)  end

end

Stick this in a file called “unix_tools.rb” in your lib folder, make sure which is on your path and use!

One caveat - Peter started getting EOFs - because he was using the version of which that came with Fink. which on OSX returns “no COMMAND in $PATH”, which on CentOS returns “/usr/bin/which: no COMMAND in $PATH” but which in Fink returns EOF. As soon as he switched to /usr/bin/which it worked fine. YMMV, as ever.

Wednesday, April 4th, 2007

I’ve found out what the shared host problem was. I must have upgraded my local copy of Capistrano to the latest. Which changes the permissions used on deployment - instead of 755 they are 775. This causes problems on shared hosts because it effectively means you can execute scripts on other people’s accounts. So a patch has been submitted for Capistrano and you need to add the following to your deployment script.

task :set_permissions do donothing = trueend
Wednesday, April 4th, 2007

I’ve given up on shared hosting - too many variables. Instead I’ve invested in a VPS - meaning I have had to delve into the world of Linux (Fedora 6) administration.

First off, I had to set up my applications to run under mongrel (rather than the FCGI of your typical shared host). I followed the instructions in the “Agile Web Development” book - basically gem install mongrel and gem install mongrel_cluster on both your development box and the server. I also created a new user on the server that mongrel would run under - we wouldn’t want your application running as root would we? Add require ‘mongrel/recipes’ to your Capistrano script and include the line set :mongrel_conf, “#{current_path}/config/mongrel_cluster.yml”. If you are using my staging server instructions then you will probably need to change this - for example I have a mongrel_cluster_live.yml and a mongrel_cluster_test.yml. To create the mongrel_cluster configuration file go to your rails root folder and type mongrel_rails cluster::configure -e production -a 127.0.0.1 -N 3 -p 8000 -c /home/user/applications/current. This creates your mongrel_cluster.yml file - in this case with the production environment, listening to (the server’s) local address, with three processes starting on port 8000 (so 8000, 8001, 8002) deployed to /home/user/applications on the server (the current is the symlink that Capistrano creates).

Run through your normal Capistrano deployment procedure - you should see that the last stage is mongrel_rails cluster::start - in the example above it will attempt to start three mongrel processes on the server on ports 8000, 8001 and 8002. If all has gone well you should be able to point your browser at those three ports and see your application.

Next up is getting your front-end web-server to connect to these mongrel processes. I’m using Apache 2.2 with mod_load_balancer (again as described in the Agile Web Development book) - this is so that requests for myapp.com on port 80 get routed to one of the mongrel processes. This requires editing /etc/httpd/conf/httpd.conf (back this file up before touching it!). Firstly, tell Apache about your mongrel processes:

Proxy balancer://myapp_mongrel BalancerMember http://127.0.0.1:8000 BalancerMember http://127.0.0.1:8001 BalancerMember http://127.0.0.1:8002/Proxy

This attaches the name myapp_mongrel to the three mongrel processes we set up earlier. Then we create a virtual host with the following RewriteRule attached:

 RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f RewriteRule ^/(.*)$ balancer://myapp_mongrel{REQUEST_URI} [P,QSA,L]

This means that any request coming to Apache for myapp.com (or whatever your virtual host is called) is dealt with dynamically (Apache cannot find a static file to serve up in its place) is automatically passed to myapp_mongrel - which we have defined as http://127.0.0.1:8000..8002. So Apache forwards the request to one of your three mongrel processes which deals with it and returns the response back to Apache. Note that we could even set up the Mongrel processes to run on one or more different servers if we desired, spreading any really heavy loads across multiple machines.

This is all good, and nothing too unusual - as I say it’s mostly taken directly from the Agile Web Development book.

However, I also wanted my mongrel processes to start up automatically, should I need to restart the server. So I added some scripts to /etc/init.d. As I said before I had created a separate user for the mongrel processes - I don’t want any security issues compromising the entire server if I could help it. So my start up script (/etc/init.d/myapp - and don’t forget to chmod +x) was slightly different to most.

#!/bin/bash

case “$1″ in start) echo “starting myapp” su - user -c “mongrel_rails cluster::start -C /home/user/application/current/config/mongrel_cluster.yml” >> /var/log/messages ;; stop) echo “stopping myapp” su - user -c “mongrel_rails cluster::stop -C /home/user/application/current/config/mongrel_cluster.yml” >> /var/log/messages ;; restart) echo “restarting myapp” su - user -c “mongrel_rails cluster::restart -C /home/user/application/current/config/mongrel_cluster.yml” >> /var/log/messages ;;esac

Log in as root and try /etc/init.d/myapp restart - you should see mongrel stopping and then restarting. A quick ps aux should reveal your mongrel processes running under the correct user. Genius.

What is happening here is the use of su (switch user). By using su - username (the hypen is important) the script switches user to “username” and loads username’s environment. Then the mongrel_rails command is run - explicitly passing it the configuration file that it needs to use. All output is passed to /var/log/messages for analysis later.

Lastly, we need to tell Fedora to run our script on startup.

Edit /etc/rc.local

/etc/init.d/myapp start

And that is it - getting your application deployed on linux using mongrel and apache. My only other step was to firewall off all ports except SSH and Web - so that no-one could access the mongrel processes directly.