Monday, April 13, 2009

Moved

This blog has moved to honoluluhacker.com

Friday, July 25, 2008

Passenger on CentOS, problems with passenger-memory-stats

I was having difficult running passenger-memory-stats, I was getting:

/usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.2/bin/passenger-memory-stats:145:in `list_processes': Invalid options. (ArgumentError)
from /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.2/bin/passenger-memory-stats:107:in `start'
from /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.2/bin/passenger-memory-stats:214
from /usr/bin/passenger-memory-stats:19:in `load'
from /usr/bin/passenger-memory-stats:19


After googling around, I found a post that said:

For those on CentOS/RHEL change line 107 in /usr/local/lib/ruby/gems/1.8/gems/passenger-2.0.2/bin/passenger-memory-stats from:

apache_processes = list_processes(:exe => PlatformInfo::HTTPD)

to

apache_processes = list_processes(:exe => 'httpd.worker')

This worked like a charm!

Thursday, July 24, 2008

Passenger Rocks

I set up Phusion Passenger which makes obsolete all the work I did for different Mongrel setups on my Capistrano scripts. It's amazing how much work I have done in my career that has now been made obsolute by something cooler. I still think FoxPro was the best.

Some notes to anyone setting up passenger. For CentOS, we had to install the package httpd-devel. The passenger setup script does the rest, you copy a few lines into your main http configuration file and it's good to go.

Here's my new configuration with SSL (names have been changed to protect my employer.) Note, my rails directory is /var/www/myrails/current:

<virtualhost>

ServerAdmin kevin@kenglish77.com
ServerName myrails.kenglish77.com
ErrorLog logs/myrails.kenglish77.com-error_log
CustomLog logs/myrails.kenglish77.com-access_log common

RewriteEngine On
RewriteCond %{SERVER_PORT} !443
RewriteRule ^(.*)$ https://myrails.kenglish77.com$1 [R=301,L]

</virtualhost>

<virtualhost>

ServerAdmin kevin@kenglish77.com
ServerName myrails.kenglish77.com

DocumentRoot "/var/www/myrails/current/public"
RailsEnv "id"

ErrorLog logs/myrails.kenglish77.com-ssl-error_log
CustomLog logs/myrails.kenglish77.com-ssl-access_log common

ExpiresActive On
ExpiresByType image/png "access plus 1 day"
ExpiresByType image/gif "access plus 1 day"
ExpiresByType image/jpeg "access plus 1 day"
ExpiresByType application/x-javascript "access plus 1 day"
ExpiresByType text/css "access plus 1 day"

RequestHeader set X_FORWARDED_PROTO 'https'
RewriteEngine On

# Force SSL
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,NE]

# Deflate
AddOutputFilterByType DEFLATE text/html text/plain text/xml application/xml application/xhtml+xml text/javascript text/css application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch bMSIE !no-gzip !gzip-only-text/html

SSLEngine on
SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
SSLCertificateFile /etc/pki/tls/certs/wildcard-kenglish77.crt
SSLCertificateKeyFile /etc/pki/tls/private/wildcard-kenglish77.key
SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire

</virtualhost>

Friday, February 15, 2008

Mongrel/Apache Setup on Ubuntu Server

This has been written up other places and most of what I know comes from Apache Best Practice Deployment By Charles Brian Quinn. I'm using Ubuntu Server 7.10 (Gusty Gibbons). I followed the "The Perfect Server - Ubuntu Gutsy Gibbon (Ubuntu 7.10)" guide, which is pretty good. I skipped the sections that didn't apply to my environment like Quotas and DNS.

After installing apache, I found out the version. Fortunately, it's 2.2:

$ apache2 -version
Server version: Apache/2.2.4 (Ubuntu)
Server built: Feb 4 2008 20:30:42

I had to manually link the apache logs directory to my /etc/apache2 directory.

$ cd /etc/apache2
$ sudo ln -s /var/log/apache2 logs/

Next, I needed to link all in the apache modules that I would be using from mods-available to mods-enabled . This is a nice feature of Apache 2.2. It sure beats copying a bunch of apache configuration commands into the http.conf.

$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/rewrite.load
$ sudo ln -s ../mods-available/proxy.load
$ sudo ln -s ../mods-available/proxy.conf
$ sudo ln -s ../mods-available/proxy_balancer.load
$ sudo ln -s ../mods-available/proxy_http.load
$ sudo ln -s ../mods-available/proxy_connect.load

(I found out the hard way that I needed the proxy_http.load module.)

Next I did my capistrano deploy to /var/www/myapp. I always make sure my mongrels are working by using lynx on the server box:

$ lynx http://127.0.0.1:3000
$ lynx http://127.0.0.1:3001
$ lynx http://127.0.0.1:3002
$ lynx http://127.0.0.1:3003
$ lynx http://127.0.0.1:3004

As long as the home page loads up, I'm good.

Finally, I created my myapp.conf in /etc/apache2/conf.d

$ cd /etc/apache2/conf.d
$ sudo vi myapp.conf

Here's what my apache config document looks like. It's very similar to Quinn's only I don't use seperate files:


ServerAdmin webmaster@localhost

# use my rails app as the document root.
DocumentRoot /var/www/myapp/current/public/

Options FollowSymLinks
AllowOverride None


Options Indexes FollowSymLinks MultiViews
AllowOverride None
Order allow,deny
allow from all


RewriteEngine On
# Uncomment for rewrite debugging, this can come in handy
# RewriteLog logs/myapp_rewrite_log
# RewriteLogLevel 9

# Check for maintenance file and redirect all requests
# ( this is for use with Capistrano's disable_web task )

RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /system/maintenance.html [L]

# Rewrite index to check for static
RewriteRule ^/$ /index.html [QSA]

# Rewrite to check for Rails cached page
RewriteRule ^([^.]+)$ $1.html [QSA]

# Redirect all non-static requests to cluster
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]

# My balancer proxy


# You need these for Ubuntu
Order deny,allow
Deny from all
Allow from all
BalancerMember http://127.0.0.1:3000
BalancerMember http://127.0.0.1:3001
BalancerMember http://127.0.0.1:3002
BalancerMember http://127.0.0.1:3003
BalancerMember http://127.0.0.1:3004

# Loggin options
# Possible values include: debug, info, notice, warn, error, crit,
# alert, emerg.

LogLevel warn
ServerSignature On
ErrorLog logs/myapp_errors_log
CustomLog logs/myapp_log combined



I know this post isn't very novel but I'm going to try to blog once a week now.

Friday, December 14, 2007

Generator replacement for plugin_migration

I struggled last Friday trying to make loaded_plugins and plugin_migrations work in Rails 2.0. I was deep in the Rails source code when Seth suggest I simply create a generator. This is pretty easy. Here's what I came up with:


class MyPluginGenerator < Rails::Generator::NamedBase

def initialize(runtime_args, runtime_options = {})
super
@argument = runtime_args.shift
end

def manifest
relative_migration_path = "../../../db/migrate/"
recorded_session = record do |m|
get_migrations.each do | mf |
new_migration_file_name = mf.sub(/^(\d{3})_/,'')
new_migration_file_name.sub!(/\.rb$/,'')
unless migration_exists(new_migration_file_name)
m.migration_template "#{relative_migration_path}/#{mf}", 'db/migrate',
:assigns => { :migration_name => new_migration_file_name.camelize},
:migration_file_name => new_migration_file_name
puts " CREATING #{new_migration_file_name}."
else
puts " exists #{new_migration_file_name}, skipping."
end
end
end
end

protected
# Override with your own usage banner.
def banner
"Usage: #{$0} my_plugin migration"
end

def migration_exists(file_name)
migration_directory = File.dirname(__FILE__) + "/../../../../../db/migrate"
not Dir.glob("#{migration_directory}/[0-9]*_*.rb").grep(/[0-9]+_#{file_name}.rb$/).blank?
end

def get_migrations
migration_files = []
my_plugin_migration_path = File.dirname(__FILE__) + '/../../db/migrate'
Dir.entries(my_plugin_migration_path).sort.each do | migration_file |
if migration_file =~ /^(\d{3})/
migration_files << migration_file
end
end
migration_files
end


end

I place this in the file:
vendor/plugins/my_plugin/generators/my_plugin/my_plugin_generator.rb

To run it, I do:

ruby script/generate my_plugin migration


The generator will copy migrations from vendor/plugins/my_plugindb/migrate to db/migrate. It uses Rails functionality to ensure that the migration files are numbered sequentially starting with my application's next available migration number. If the migration is already in db/migrate, it will be skipped but it will not abort. This means I can add migrations to the plugin and run the generator again without worrying about it overwriting the old migrations.

Most of the work is done in the manifest method. By default, the Rails method migration_template looks for the template in a directory called template. In this case it would be looking for the migration file in vendor/plugins/my_plugin/generators/my_plugin/template which is what my relative_migration_path is relative to. My migration_exists method is basically a cut-and-paste from the Rails source code. I don't know why but they these methods are protected in Rails.

I hope this helps, it's a temporary fix. I'm sure the guys at plugin a week will have plugin_migrations fixed in no time :)

Thursday, December 6, 2007

Namespace Hell

I was writing a Rails plugin when I entered namespace hell. I had 2 classes with the same name and they were conflicting. I'm not sure if this was Rails problem or a simple ruby issue. Here is the scenario, the directory layout was as follows:

lib/query.rb
lib/warehouse/query.rb
lib/warehouse/table_report_query.rb

in query.rb I had:

class Query < ActiveRecord::Base
some_code_here
end


in lib/warehouse/query.rb I had:

module Warehouse
class Query
some_code_here
end

end


in lib/warehouse/table_report_query.rb I had:

module Warehouse
class TableReportQuery < Query
some_code_here
end
end

So, in the controller, when I did:

table_query = Warehouse::TableReportQuery.new()

You would think that TableReportQuery would inherit from Warehouse::Query. WRONG! It was inheriting from the first Query and throwing the classic activerecord "method not found" error.

So what's the solution. Well, I give credit to this blog article about Ruby Namespace Conflicts for inspiring my solution. I changed lib/warehouse/table_report_query.rb to be:

class Warehouse::TableReportQuery < Warehouse::Query
some_code_here
end

and it worked! Is that ruby Voodoo or what?

Tuesday, December 4, 2007

Plugin Development

Developing a Plugin for Rails can be a lot of fun. You can find a good guide here with the complete guide to rails plugins.

Piston

Be sure to read Managing Rails Plugins with Piston.

The best way to produce a good plugin is to create a separate application which can be used to test the plugin and use piston to import changes into you main application using 'piston update'.

Avoid Restarting Mongrel

I have learned one helpful trick. By default, you will have to restart your Mongrel server every time you make a change to your plugin. You can avoid this by placing the following code at the top of your plugin's init.rb file:

  Dependencies.load_once_paths.delete(lib_path)