A collection of computer systems and programming tips that you may find useful.
Brought to you by Craic Computing LLC, a bioinformatics consulting company.

Wednesday, August 19, 2009

Capistrano and Environment Variables

When it works well, Capistrano is a great way to deploy Rails applications and take care of any remote server operations that are needed for that app.

But if you run into problems it can be a bear to troubleshoot. And the documentation is not great.

One issue that can catch you (or me!) unawares is the 'run' command that runs a Unix command on the remote host. I use these to symlink various files and to start up a daemon on the new deployment once that is complete.

You run into a problem if any of your remote commands require access to your Unix Environment Variables. The 'run' command is executed in a minimal environment without any of these.

The solution is to specify the variables that you need, such as PATH, as key/value pairs in the 'default_environment' hash in your cap deploy.rb file.

For example, here are two variables defined near the top of my file:
default_environment['AMAZON_ACCESS_KEY_ID'] = "YourAwsKeyHere"
default_environment['AMAZON_SECRET_ACCESS_KEY'] = "YourSecretAccessKeyHere"

Easy enough, once you know... not at all easy if you don't know!


Lightbox2 in a Rails App

Lightbox2, by Lokesh Dhakar, is an excellent JavaScript script for displaying images and slide shows as overlays on a web page, triggered by clicking on a thumbnail.

I wanted something like this to display screenshots in the online help for a Rails application. Overall it was pretty simple to set up, but here are some of the tweaks I needed to make.

1: Lightbox2 uses prototype.js and Scriptaculous. I had those in my Rails app but I found I had to upgrade those scripts to the latest versions in order to get Lightbox2 to work.

2: I had included the prototype and scriptaculous libraries using the Rails helper 'javascript_include_tag :defaults', but that alone is not sufficient. Lightbox2 needs the builder and effects scripts loaded. Lightbox2 says to use this line:
<script type="text/javascript" src="/javascripts/scriptaculous.js?load=effects,builder"></script>
And I put that right after the javascript_include_tag. This is undoubtedly duplication... I should probably just include the supporting scripts directly and leave out the Rails helper.

3: As the Lightbox2 docs point out, make sure you have the four default gif image files in the right places and that they are defined correctly in lightbox.js and lightbox.css.

4: Add the calls to lightbox.js and lightbox.css in your Rails layout file. Note that you have to change the paths from the example to suit Rails:
<script type="text/javascript" src="/javascripts/lightbox.js"></script>
<link rel="stylesheet" href="/stylesheets/lightbox.css" type="text/css" media="screen" />

5: Now you're ready to add images and links that use Lightbox2. The idea is very simple. Take a thumbnail image img tag and place within a 'a' tag pair. Make the href of the 'a' tag point to the full size image. Importantly, in the 'a' tag add the attribute 'rel="lightbox"'. For example:
<a href="/images/fullsize.jpg" rel="lightbox" title="Picture of a cat"><img src="/images/thumbnail.jpg" style="border: 1px solid #808080;"></a>
The title attribute of the 'a' tag becomes the caption of the overlay image. In this example I have included a border on the thumbnail image. That should do it for basic operation.

6: To fine tune the script you can edit lightbox.js and lightbox.css. For me the animation is too slow. You can disable the animation entirely but I preferred to just speed it up with a maximum setting of 10. I also messed with the CSS for the 'imageData' set of CSS IDs to change the font and specified a different image for the 'close' icon in the .js file.

Lightbox2 is pretty slick. You can do slide shows with it as well. Hope this helps you get it integrated with Rails.


Monday, August 17, 2009

Configuring SSL on an AWS EC2 instance - Security Groups

If you are trying to set up SSL with Apache (or any other server) on an AWS EC2 instance then before you do anything else, add port 443 to your Security Group.

Until you do that absolutely NOTHING will work!

You typically set up a Security Group when you create your EC2 account and then forget about them - I know I did...

You can see what ports you have open with this command:
$ ec2-describe-group
And you open up Port 443 with this command ('default' is the name of my security group):
$ ec2-authorize -p 443 default

I hope to write more on troubleshooting SSL set ups shortly.


Wednesday, August 12, 2009

AWS EBS Volumes and Snapshots

AWS Elastic Block Store Volumes are invaluable for setting up EC2 nodes.

You can clone and/or backup Volumes into static Snapshots, also extremely useful. But be aware that the process of creating a Snapshot can be extremely slow and this can be a major problem if you are not expecting the delay.

For example, creating a snapshot from a 50GB volume took almost 2 hours for me today. Now, times will vary for all sorts of reasons. Most importantly, the first time you create a snapshot off a given volume will take the longest. Subsequent snapshots are just recording the changes since the previous one.

Being prevented from using your Volume for an extended period of time can be a huge problem, so plan ahead and make your snapshots overnight, for example.

Having said that, if your Volume contains Static or Read-Only data, then you have more flexibility:
- You can create a Snapshot from a mounted Volume, without having unmount or detach
- You can mount an unmounted Volume that is in the process of Snapshot creation.

This is convenient and does not appear to be explicit in the AWS docs, as far as I can see.
But this is limited to Volumes that will not change during snapshot creation.

WARNING: DO NOT try this with a Volume that is being written to, such as one holding a database.


Tuesday, August 11, 2009

UNIX screen command

I have a mental block when it comes to the UNIX command 'screen' so this is a short reminder for me.

In a UNIX shell run 'screen' to create a new session. In this you might want to run a long job.

To exit from a screen session, destroying that session in the process, type 'exit'.

To detach from the session, leaving it running, type 'Ctrl-a d'

To return to a running 'screen' session from a top level shell, type 'screen -x'. This will list all running sessions and identify each with a PID number.

To return to a specific session, when you only have one running, type 'screen -r'.

To return to a session when more than one are running add the PID to the command, e.g. 'screen -r 123'.


Creating and Attaching AWS EBS Volumes to an EC2 node

AWS Elastic Block Store (EBS) Volumes are arbitrary blocks of storage that can be mounted on EC2 nodes and used like regular filesystems. Here are the basic steps needed to set them up (and the associated gotchas to avoid).

1. Create a new EBS Volume using the AWS Management Console.
Know what size in GiB you want in advance and make sure you create it in the same Availability Zone as the EC2 node you want to attach it to.

2. Attach it to your EC2 instance
Do this from the Management Console. If you have more than one EC2 node running make sure you know the Instance ID, PLUS know which device you want to attach the Volume to. Your options are typically /dev/sdf, /dev/sdg, etc. Not sure what happens if you try to attach to a device that is already in use. It probably won't let you but I would rather just not go there...

Wait until the Console tells you the Volume is 'attached'. You might want to refresh the console to see this.

Now go to the EC2 node...

3. Create a Filesystem on the Volume
If (and ONLY if) this is a NEW Volume then you need to create a filesystem on it before you can do anything. Skip this step if the Volume has previously been mounted.

You can create different types of filesystem on the Volume. On linux the current recommended type is ext3. Here I am using /dev/sdh. Note that it asks if I want to use the entire device - Yes I do!
# mkfs -t ext3 /dev/sdh
mke2fs 1.40.4 (31-Dec-2007)
/dev/sdh is entire device, not just one partition!
Proceed anyway? (y,n) y
4. Create a mount point for the filesystem
Again, you may not need to do this if the EC2 node has previously mounted this Volume, but for a new setup you want to create a mount point under /mnt for the volume. For example:
# mkdir /mnt/myvolume
And then proceed to mount the Volume:
# mount /dev/sdh /mnt/myvolume
There should be no output from this command. Check that it is mounted with 'df' and then just 'cd' to it and start using the space.

5: To detach your Volume
First you need to un-mount it from your EC2 node while the node is running.
# umount /mnt/myvolume
Then you can detach it using the Management Console (and remember to Detach, not Delete!)
Only then should you shutdown your EC2 node, if you choose to do that.

6: Creating Snapshots of Volumes
You can create Snapshots of your Volume as backups or as a copy from which to clone other Volumes to attach to other nodes. (A given Volume can only be attached to one node at a time).
You can do this from the Management Console. You should do this on Volumes that are not attached to EC2 nodes so as to avoid anything being written to the Volume during Snapshot creation. You should do that but you can create a snapshot from a mounted Volume if you want to. How risky this is depends on what you are doing - never do this if it the Volume carries a live database, but it is OK if the Volume has a read-only dataset on it. Caveat emptor.

In their web pages, AWS talks about an EBS volume having higher performance than local disk. The impression I get from other blogs is that this is very variable and depends on what you use the disk for. I have not formed an opinion for my applications as yet.


Sinatra and Passenger

It is easy to run a Sinatra application under the Phusion Passenger and Apache web server, but the configuration is not especially explicit.

I am assuming that you have Passenger already installed.

1: Set up your Sinatra application and test it on localhost - try something very simple for the purposes of getting it running under Passenger.

2: Create a file called config.ru in the same directory as the Sinatra app containing something like this, where 'yourapp' refers to your application in 'yourapp.rb'
require 'yourapp'
set :environment, :production
run Sinatra::Application
I find the choice of the file name config.ru confusing, but there you go.

3: Create a 'public' directory in the directory with your app, as well as 'tmp' and 'log' directories. They can be empty for a simple application - but you need 'public'
# mkdir public
# mkdir tmp
# mkdir log

4: Edit your apache2.conf (or httpd.conf) file

You may need to add a PassengerDefaultUser line right after your other Passenger lines.
PassengerDefaultUser root
And then you want a Virtual host block for the Sinatra service that looks something like this:
<VirtualHost *:80>
DocumentRoot /yourdir/public
ErrorLog /yourdir/log/sinatra_error_log
CustomLog /yourdir/log/sinatra_access_log common
<Directory /yourdir/public>
Options FollowSymLinks
AllowOverride None
Order allow,deny
Allow from all

You might want to 'touch' the two log files in your app log directory so they exist before apache wants to use them. In the past, at least, not having the log files in place would cause Apache to complain.

5. Restart Apache
This is a full restart
# /etc/init.d/apache2 restart
For changes to your application just use the standard Passenger reload by touching the file restart.txt in your tmp directory
# touch /yourdir/tmp/restsrt.txt

It is the presence of the empty public directory below your Sinatra app directory that tells Passenger that you have an app there. Notice that you are not telling it explicitly that you have a Sinatra app in the Apache conf file. Passenger looks one level up from this directory, sees the config.ru file and executes that.

Rather cryptic for my taste - but admittedly simple once you know how - and now you do...


Friday, August 7, 2009

Rename a MySQL database used in a Rails Application

The safe and simple way to rename an existing database is to dump it out as SQL, create a new database with the new name and then load it back in.
$ mysqldump -u root -p -v old_db > old_db.sql
$ mysqladmin -u root -p create new_db
$ mysql -u root -p new_db < old_db.sql
If the database is the back end to a Rails app then you also need to update your config/database.yml file to use the new name and restart the web server, or nudge Passenger.

Test out the new DB, test it again, and then some more before destroying the old database.
$ mysqladmin -u root -p drop old_db


Tuesday, August 4, 2009

RedCloth 4.2.2 and textilize in Rails 2.2

I found incorrect instructions on how to set up the RedCloth Textile rendering code in several places when I was trying to set it up.

Here is what needed to get it working (I am using Rails 2.2 on Mac OS X)

1: Install the gem
Just get it from a default gem repository and make sure you use 'RedCloth' and not 'redcloth'.
$ sudo gem install RedCloth
2: In your Rails app environment.rb file add two lines.
First specify this dependency with any others in the Rails::Initializer.run block. Don't worry about specifying a version.
  config.gem "RedCloth"
Second, add this require line at the end of the file:
require 'RedCloth'
3: Get rid of any earlier versions of RedCloth.
You may not need this but I ran into issues with Rails picking up v4.0.1 even though the newer 4.2.2 was present.
$ sudo gem uninstall RedCloth --version <your older version>
4: Restart your web server.
I run Apache2 and Passenger and simply doing 'touch tmp/restart.txt' did not solve my earlier version problem. Probably overkill but restart the server anyway.

5: That's it...


Archive of Tips