Setting up Multiple Site Instances on Joyent Accelerators

By Scott Roth on May 14th, 2008

Tagged with: joyent, capistrano, rails, tutorial

I recently set up a new Rails site on a Joyent Accelerator for a client.  The accelerator size selected had more than enough capacity, so we decided to set up the staging instance of the site on the same box.  There is a great set of instructions on the Joyent wiki for how to properly set up a Rails site that will be deployed via Capistrano to an Accelerator, so start there if you've never set up a site on Joyent before.  There are actually very few tweaks to those instructions you need to follow to set up multiple site instances on one Accelerator - in my case a "staging" and a "production" environment for a single application.

mongrel_cluster.yml
The default place to store this file is under /config.  We are actually going to set up a separate mongrel file for each environment, so create a file called mongrel_cluster_[environment].yml  (e.g. mongrel_cluster_staging.yml) under /config/accelerator/environments in your Rails application.  Set the number of servers, the port, and the environment variables as you would normally.  We'll be moving this file back to its expected location during the deployment process.

Now copy over the three files mentioned on the wiki into the /accelerator folder and make the needed changes from the instructions.  We'll just be adding a few additional modifications.

accelerator_tasks.rb
Since we have moved the location of the mongrel configuration file we need to let the "create_vhost" task know where to read in the YAML file from as it uses variables from that file to properly configure apache.  So update this line:

1  cluster_info = 
YAML.load(File.read("config/accelerator/environments/mong
rel_cluster_#{application}.yml
"))

apache_vhost.erb
No changes needed.  W00t!

smf_template.erb
This file is the template used to set up all the dependant services that your Rails app will need.  The problem with the default version is that the mongrel service needs to have a distinct name for each application that is set up on the box otherwise bad conflicts happen.  (This is also mentioned on the Joyent wiki page.)  Update this line to make sure you have a distinct name for each environment:

1  <dependent name='mongrel_multi-user_<%= application %>' 
restart_on='none' grouping='optional_all'>

Now we move onto the final step.  We have moved the location of the mongrel configuration file so that we can support multiples of that file in our source control system.  However, the mongrel service on the deployed server is still looking for that file in the old location with the old name.  So, we are going to add a simple task to deploy.rb to fix this at deploy time.  At the bottom of your file add a new custom task:

1  namespace :custom do
2 task :movemongrelconfig, :roles => :app do
3 # Move the env specific file to the general location
4 run "mv
#{release_path}/config/accelerator/environments/mongr
el_cluster_#{application}.yml
#{release_path}/config/mongrel_cluster.yml
"
5 end
6 end

And call the new task at the end of the deployment process:

1  after :deploy, 'custom:movemongrelconfig'

I'm sure that there are other ways to get multiple site instances running, but this one was relatively simple and has been working well for us for some time now.

Making FTP Code Compatible With SFTP Servers

By Phil Matarese on April 30th, 2008

Tagged with: ruby, rails, plugin

Why?

We recently needed to toggle between support for SFTP and traditional FTP in one of our applications.  In a Rails app, this is more of an annoyance than necessary because of the interface differences between Net::FTP and Net::SFTP.  Not only are the transfer and navigation methods arbitrarily different, but the way the current directory on the server is dealt with is not consistent.  I suspect these differences grow from the underlying differences in the technologies, but it would still be nice to code just one branch of code that does file transfers for either type of server.  This is Ruby, right?

What?

This was the impetus for writing the sftp-compat plugin to extend Net::SFTP, giving it all the same interfaces as Net::FTP.  The plugin is very new, but it was extracted from a real, working project we developed.  It's functional, and it's being used in production right now as we speak (rather as I write and as you read - nobody is speaking right now - it's actually very quiet here - nice and tranquil - mmm.)

How?

All of the documentation can be found at http://sftp-compat.rubyforge.org/.  There may be some functionality missing from the interface depending on your use case.  The current version was designed for writing to remote FTP hosts, so there are a few methods for reading that I never needed to implement.  If you are interested in using sftp-compat, but need the missing functions or would like to commit extra functions, please drop me an email.

Cinema Redux Redux

By Phil Matarese on April 30th, 2008

Tagged with: ruby, rmagick, frivolity

After the Cinema Redux presentation at GoRuCo was posted at ConFreaks, I couldn't resist reduxing the redux.  I mean, this is totally meta.  And, meta goes with Ruby like analogies go with blog posts.  So, here it is... Cinema Redux Redux.

Redux ReduxCinema Redux at GoRuCo
Redux ReduxCinema Redux (Detail)
 

Create Your Own Cinema Redux Poster with Ruby and RMagick

By John Berry on April 25th, 2008

Tagged with: ruby, rmagick

A few years back, the talented Brendan Dawes created Cinema Redux, which lays out a film as a series of stills captured at 1 frame per second. The result is a matrix of images resembling a DNA print of the film. By arranging these stills into rows of 1 minute, you get an interesting overview of how a film flows from start to finish.

While there are still some prints available for sale - 2001: A Space Odyssey is available through Coudal Partners - I wanted to do my own. Here are a few:

2001: A Space Odyssey2001: A Space Odyssey
There Will Be BloodThere Will Be Blood
Dr. StrangeloveDr. Strangelove

 

Helvetica Helvetica
by Gary Hustwit
Super Mario 1, 2, 3, World & 64 speed runs Super Mario 1, 2, 3,
World & 64 speed runs
The Incredibles The Incredibles
 

 

Detail view of 2001: A Space Odyssey
Detail view of 2001: A Space Odyssey

What the Script Does

montage.rb has 2 major processes.  First, it reads each of the rendered stills and resizes them to computed size (based on configuration options), and writes them to a subdirectory.  Next, it reads in these scaled images into an RMagick ImageList - using the montage method - then writes the resulting file.  The montage method would handle resizing for you, but the memory required to handle all frames from the movie at full resolution is prohibitively high.  Manually scaling the images allows for more efficient memory management.

Step 0

Before you get started, you'll of course need RMagick 2 (and thus ImageMagick).  While I'm sure you could hack the script to run with RMagick 1.x, I strongly advise you don't.  RMagick 2 does a much better job of memory management, and supports the .destroy! method, allowing the script to free memory in the image resize loop.  RMagick 1.x caused all sorts of problems for me early on.

Step 1: Download montage.rb

That's it, just download montage.rb.  Well, then unzip it.

Step 2: Export The Movie as a Series of Stills

Create a new directory and place in it your movie and montage.rb. This next export step will create thousands of still images, so you might want to get a little organized.

If you don't have QuickTime Pro:
You'll need FFmpeg. The command you'll use will be similar to:

ffmpeg -i YOUR_MOVIE.avi -r 1 -f image2 movie_%4d.png 

Once this is done, you can skip to Step 3. 

If you do have QuickTime Pro:
Select "File -> Export..."

From the Export select menu, chose "Movie to Image Sequence"

 

Click the Options button, and use the following settings

(For these options, I chose Best Depth and Medium Quality)

Choose your target directory and save.  This step will create those few thousand still images, so make sure you're putting them in the newly created directory.

Step 3: Choose montage.rb options 

Run montage.rb without any arguments to get a listing of the usage options.  The only required argument is the file pattern that will match against the movie stills.

What Now?

I went with QOOP as a printing service, and chose a 20" x 30" format.  Some jpeg compression was in order to get the filesize below their threshold, but not much. The print is high quality and I'm quite pleased.

Note that if you're into Processing, you can find a sketch that appears to do similar work here.

Rspec Without db:test:prepare

By Phil Matarese on April 23rd, 2008

Tagged with: rails, rspec, rake

First Things First

At the Hotel MatareseOnce upon a time, after deploying an Rspec'd app for the first time, we wanted to run all the specs on our staging server to see that everything was running as expected.  Only, there was a problem with dependencies.

At the time we had a pretty gross, gem-dependency soup cooking up in our app.  We had rspec as a frozen gem and rspec_on_rails as a plugin, and this was causing (unconfirmed) load-order problems for rake.  After checking the rspec documentation again, we changed rspec from a gem to a plugin, which straightened everything out (I think).

The Basics

Basically, our current setup is to have piston (essential for plugin management), rcov (keep the coverage above 50% or the bus blows up), and ZenTest (because autotest is fun) installed locally as gems on all development machines - there is no reason for us to use these on our production or staging servers.  Within the app we have rspec_on_rails, rspec_autotest, and rails_rcov (which uses magic) installed in the plugins directory (under the watchful eye of piston.)  These are part of the app, not only because the rspec docs like it that way, but because we'd like to ensure all the tests pass after a deployment.  Everything is all nice and neat now.  Shouldn't have anymore problems.  Nope.  No sir.  No way.  Uh-uh.

The Problem

Gimmelwald, Population 130When running rake spec, the database can't be found.  But... we installed it... right? Of course, it's right there.  And... the permissions? They're good, too.  Uhh... Hey, did that say the "development" database can't be found?  What the...

Unbeknownst to us, the spec task had as a prerequisite db:test:prepare, which takes a schema_dump from the development database and uses it to create a test database.  This is something we don't need.  Unfortunately, there's no option or flag that you can use to disable this prerequisite.

The Solution

So this one got a little hairy.  The load order for rake tasks is rails, custom code in lib/tasks/*, and then rspec.  So, I couldn't drop the spec prerequisites with my custom code, because they didn't exist yet.  My first attempt to solve this involved wiping out db:test:prepare completely, no matter what.  I was a bit hesitant to do this, because it had nothing to do with what I was really trying to accomplish – I've got nothing against db:test:prepare, I just want it decoupled from rspec.  Here is our current solution which only wipes out db:test:prepare when the spec task is invoked.  Not only does this solve the problem of testing on a staging server, but it also speeds up testing in our local development environments.  Enjoy.

 1  # bock_db_test_prepare.rb
2
3 # without this, you could never
4 # remove elements of a task
5 class Rake::Task
6 def clear_it
7 @actions.clear
8 @prerequisites.clear
9 end
10 end
11
12 # set up the blocking as a rake task,
13 # so we can add it as a prereq to spec
14 namespace :ap do
15 namespace :spec do
16 task :skip_db_test_prepare do
17 Rake::Task['db:test:prepare'].clear_it
18 end
19 end
20 end
21
22 # block it!
23 task :spec => 'ap:spec:skip_db_test_prepare'

The final line works even though the spec task doesn't exist yet. Essentially, our custom code creates an empty spec task with our single prerequisite. When rspec loads, the real task and prerequisites will be appended after ours. Success.