Sean’s Obsessions

Sean Walberg’s blog

EPEL Nginx Rpm and Upgrade From 0.6.x to 0.8.x

I just upgraded my nginx rpm and my site refused to start. /var/log/nginx/error.log reported the following:

2010/11/19 09:30:08 [emerg] 27885#0: eventfd() failed (38: Function not implemented)
2010/11/19 09:30:08 [alert] 27884#0: worker process 27885 exited with fatal code 2 and can not be respawn

It turns out the new nginx rpm was compiled with –with-file-aio which uses the eventfd() call:

1
2
3
4
5
[root@smallpayroll ~]# nginx -V
nginx version: nginx/0.8.53
built by gcc 4.1.2 20080704 (Red Hat 4.1.2-48)
TLS SNI support disabled
configure arguments: --user=nginx --group=nginx --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_perl_module --with-mail --with-file-aio --with-mail_ssl_module --with-ipv6 --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables' --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i386 -mtune=generic -fasynchronous-unwind-tables'

eventfd() wasn’t available until Kernel 2.6.22. I was running 2.6.18 because that’s what my VPS offered when I started. Fortunately it was a quick option in the Linode panel, a reboot, and now I’m running 2.6.32.

Fun With Git

I’ve started using Git instead of svn. Like many other people, I tried it out to get easier branching, but found it’s just a pleasure to use in general.

One great feature is that git can work with an SVN repository. You use git to check out some SVN code into a local git repository, you work with the repo as if it were git, then you commit your changes back to svn.

The lowdown on this is:

1
2
3
4
5
6
7
8
9
# Check out the svn repo
# It may take a while because it's copying all the changes, not just a checkout
git svn init http://myrepo/myproject/trunk myproject
cd myproject
# do some work
# commit to git
git commit -a -m "did some work"
# send updates to svn
git svn dcommit

But wait, someone else has done some work and you want to pull the latest changes from svn to your git repo

1
git svn rebase

Nice eh? So let’s say you’re working in your git repo, and want to branch

1
2
git branch somefeature
git checkout somefeature

You’re working along, and you want to pull changes from svn into master and your branch.

1
2
3
4
5
6
git checkout master
git svn rebase
# master is up to date
# so merge master into the branch
git checkout somefeature
git merge master

This is so easy to use! Previously, with SVN, I’d branch, work on the feature, and then merge back to trunk. Given how painful merges were, there was no hope that I’d be merging trunk changes into my feature branch.

I’m sure my tune will change the first time I blow up my repository though :)

Load Testing a Rails App With JMeter and the Authenticity_token

I have been slowly learning how to use JMeter to load test the Small Payroll application. One of the problems has been getting around the CSRF protection that Rails puts in with the authenticity_token parameter.

Each form has a hidden form element:

1
2
3
<div style="margin:0;padding:0;display:inline">
<input name="authenticity_token" type="hidden"
value="16iUP1J2tdSKyvHKgYR/I/og6K7NgPPmTHCZ+idQP4k=" />

The token is also encrypted in the session so that the response to the form has to match. This value changes every time the form is loaded and can’t be set to a known value, otherwise it would be easy to defeat the CSRF protection. This means that JMeter has to figure out the token and put it into the POST.

Googling around, I found some people that said they did it, and a lot of people who couldn’t get it to work, but no solid walkthroughs.

Here’s my solution:

There are three elements. The first is the HTTP request sampler that gets the login page. Under that is a regular expression extractor post processor that gets the authenticity token. The extractor uses a simple regexp to pull out the value parameter and saves it to the LOGIN_AUTH_TOKEN variable. The login is then done by making reference to the variable - ${LOGIN_AUTH_TOKEN}. Make sure you have the Encode? button checked, as the authenticity_token is not always base-64 friendly!

The final step, not pictured, is that you have an HTTP Cookie Manager in your thread group to take care of cookies. You probably already have one, though.

Sean

Piping With the Find Command and Dealing With Spaces

I often use the find command as such:

1
grep foo `find . -name \*.php`

which looks for foo in all the PHP files. If the list of files gets too long for the shell, then xargs is the better option:

1
find . -name \*.php | xargs grep foo /dev/null

This breaks up the command into manageable chunks. The /dev/null is there in case xargs only passes one file name to the command, this ensures there will be two file names to trigger the printing of the matching file (there’s probably an option, but I like this way better)

The problem with find -print |xargs is that a file or directory with spaces causes problems. For instance “xxx yyy/blah.php” will run

1
grep foo /dev/null xxx yyy/blah.php

neither of which exist.

My first hack at it was to revert to programmer mode and do a loop:

1
find . -name \*.php | while read A; do grep foo "$A" /dev/null; done

The best solution I found so far is to use -printf to force find to quote the file when it spits out the file name and get back into the xargs/stream mode of thinking:

1
find . -name \*.php -printf '"%h/%f"\n' | xargs grep foo /dev/null

Maybe there’s an easier way? (besides shooting people that use spaces in directory or file names)

Command Line Geolocation

A comment in a Slashdot article lead me to iploc.org, specifically Country names zone which lets you get the country for a given IP address over DNS.

I wrapped it in a bash function… throw this at the end of your .bashrc:

1
2
geo() { dig +short TXT `echo $1 | \
 awk -F. '{print $4"."$3"."$2"."$1".cc.iploc.org"}'`;}

and you can get geo information from the command line:

1
2
$ geo 204.187.154.1
"CA"

A Shameless Plug for SaaS

In 2008 and 2009, my wife and I hired a nanny a few days a week to take care of our three children. Nothing exciting there. Part of hiring a nanny is that you have to deduct and remit taxes, CPP, and EI. All easy stuff; I’ve taken a payroll course before and the calculators were available online.

I wrote some scripts to help me out, which I eventually improved to the point where I had a fully functional payroll system. I put it online at SmallPayroll.ca thinking I’d be able to charge a few bucks for people to use it. Even though our nanny moved on in the summer and we found a day care, I’ve kept on improving the site. I may be biased, but I think it’s a pretty good system for helping people in a similar situation do their payroll.

On Friday I got a piece of mail from the Canada Revenue Agency, saying there was a problem with the T4 I submitted for my nanny in 2008 (2008! It’s almost 2010!). We only started in November so this was before I had written the first script and everything was manual. Of course I couldn’t find any of my paperwork from back then, and with a recent basement flood it could be anywhere.

Fortunately the problem ended up being on CRA’s end, but this incident highlighted how helpful a SaaS such as my own small payroll system would have been. All the data is there online and I would have known the calculations were correct because software was doing them.

Top 1 Best Database Management Tool - and How to Use It

I’m noticing that more and more of the items that pop up in my feed reader are of the “Top N” variety. Some are decent, where the author breaks the topic down into subgroups and then shows one or two tools for each purpose. However some of them are just silly, such as the “top 100 photoshop tutorials”, which is really “the last 50 Photoshop tutorials I bookmarked, and 50 that I just Googled”.

So when I read Top Five Best Database Management Tools, I wondered what the heck the value was. Some of the tools were for Microsoft SQL server, some were for MySQL, and there was no criteria for the list other than “reader favourites”.

So, in an effort to answer the “how do I manage my database” question, here’s the top 1 database management tool, and how to use it.

But first, a disclaimer. It’s only the top tool if:

  • You use mySQL
  • Your web server can serve PHP
  • You’re me

The tool is phpMyAdmin. That should come as no surprise, because it’s on everyone else’s top N list. There may be better, but it’s easy to install and probably handles anything you can throw at it. If you’re not using MySQL, or you have something better, then go ahead and use it!

So go to the homepage and download the software. If you’re in Windows grab the .zip version, if you’re in Linux, grab the .gz version.

First, uncompress the software to somewhere outside your document root. Doing it this way makes management a bit easier in the future, but slightly complicates the installation. On my machine, I’d go

1
2
3
cd /var/www
tar -xzf tar -xzf /tmp/phpMyAdmin-3.2.3-all-languages.tar.gz
ln -s phpMyAdmin-3.2.3-all-languages phpMyAdmin

Line 1 gets you to the parent directory of the web stuff (at least in RedHat/CentOS). Line 2 uncompresses the software. Line 3 creates a symbolic link to the current version.

Next we’ll create an Apache configuration file to handle access to the software. You can do this in the main httpd.conf file, but most distributions have a directory where extra configurations are loaded.

/etc/httpd/conf.d/phpmyadmin.conf:

1
2
3
4
5
6
7
Alias /phpMyAdmin/ /var/www/phpMyAdmin/

    Order deny,allow
    Deny from all
    Allow from 127.0.0.1
    Allow from 192.168.1.0/24
    Allow from 1.2.3.4

Line 1 maps anything under /phpMyAdmin/ (note the trailing /) to /var/www/phpMyAdmin/. The latter is a symlink to the current version, so if you want to upgrade you can have both versions uncompressed and use the symlink to change the active version. You can also choose a more friendly name, if you’d like.

The rest of the code restricts access to the localhost (127.0.0.1), the local network, and a certain outside address. If you want everyone to access it, delete the Location stanza and everything inside it (leaving only the Alias)

If you go to the URL, you’ll be able to log in using your username and password.

An interesting thing about phpMyAdmin is that it can manage several servers from one web page. In this case, the login screen will allow you to choose the server. This is great if you have multiple mySQL servers, or if your web server and SQL server are on separate devices.

The easiest way to do this is to use the web based configuration:

1
2
mkdir /var/www/phpMyAdmin/config
chmod 777 /var/www/phpMyAdmin/config

Then hop over to http://127.0.0.1/phpMyAdmin/setup/ (or whatever your server is) and follow the instructions to create several servers. Unless you have a specific reason to, you can choose the defaults (except for the server name!)

Once you’re done, protect the directory from writing and copy the generated file to the root:

1
2
chmod 755 /var/www/phpMyAdmin/config
cp /var/www/phpMyAdmin/config/config.inc.php /var/www/phpMyAdmin

If you’d rather not use the web interface, copy the config.sample.inc.php to config.inc.php and go from there.

Moving From Github to Gemcutter for Your Rails App’s Gems

Much hoopla has been made over Github stopping their gem building service, and for people to use Gemcutter.

All the stuff I’ve read has been that gemcutter is much better for publishing Gems, and that it’s easier to find the canonical gem (instead of deciding whether fred-mygem is better than barney-mygem)

Fair enough, but what about slobs like me that haven’t had to modify gems, and just want to start using the new source for gems and to update existing apps accordingly?

Turns out, it’s pretty easy.

1
2
3
4
5
6
# Update gem to at least 1.3.5
gem update --sytem
# install gemcutter
gem install gemcutter
# update gem sources
gem tumble

If you look at ~/.gemrc, you’ll see that github has been pushed to the end:

1
2
3
4
5
6
7
8
9
10
11
---
:benchmark: false
:verbose: true
gem: --no-ri --no-rdoc
:update_sources: true
:sources:
- http://gemcutter.org
- http://gems.rubyforge.org/
- http://gems.github.com
:bulk_threshold: 1000
:backtrace: false

The last thing to do is to reinstall the old github gems using their new names. In environment.rb and environments/*.rb, look for your config.gem lines:

1
2
3
config.gem "thoughtbot-factory_girl",
       :lib     => 'factory_girl',
       :source  => 'http://gems.github.com'

Becomes:

1
config.gem "factory_girl"

Note that all you’re doing is taking off the owner of the gem, and then getting rid of the extra parameters.

It would be wise to first make sure that the gem is available on gemcutter. Browse to http://gemcutter.org/gems/GEMNAME, (eg http://gemcutter.org/gems/factory_girl) to see if you get an error.

Finally, run

rake gems:install
from within your app’s directory to install the new gems.

Presto! It’s easier than I thought.

Shoulda, Nested Contexts, and Should_change_by

I love some of shoulda’s macros, partially because it forces me to think about my tests and put them in setup blocks, which ends up making things cleaner.

So I ran into a case where I do an action and use should_change to make sure that a certain number of rows were added to a table, then I do it again and make sure they don’t change. So I used a nested set of contexts to handle this:

1
2
3
4
5
6
7
8
9
10
11
12
13
context "do it once" do
  setup do
    post :method, :foo => {...}
  end
  should_change("something", :by => 6) {Something.count}
  #... other tests ...
  context "do it a second time" do
     setup do
       post :method, :foo => {...}
     end
     # should it change by 6 or 0?
  end
end

I wasn’t sure if the should_change applied to both the setup blocks or only the second. Turns out it’s only the second, so it should not change in the second test. Here’s proof:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'test_helper'
class SomethingControllerTest
  context "outer" do
    setup do
      @user = Factory.create(:valid_user)
    end
    should_change("number of users", :by => 1) { User.count }
    context "inner" do
      setup do
      end
      should_change("number of users", :by => 0) { User.count }
    end
  end
end

Since I didn’t write my tests before I wrote the code I wasn’t sure if my code was bad or my test was. Now I know how the test could be structured and I could test properly.

Svn Merge

(this is one of those “so I remember it” posts that might help others)
Edit: See below for a more accurate way to merge the trunk back into HEAD

I’ve got some code that I’m storing in SVN. In traditional SVN form, I’ve got my repo set up as

/trunk
/branches

So my work is done out of trunk, ie

1
svn co http://home.ertw.com/svn/repos/payroll/trunk/ payroll

I then had some major rework I wanted to do. Rather than continuing to develop out of trunk, I wanted to keep these changes separate so that I could continue working on other things in the code base at the same time as the rework. In svn, that’s done as a branch. From the root of the checked out code:

1
2
svn copy http://home.ertw.com/svn/repos/payroll/trunk http://home.ertw.com/svn/repos/payroll/branches/engine_mark_2
svn switch http://home.ertw.com/svn/repos/payroll/branches/engine_mark_2

The first command copies all the files from the trunk to a branch called “branches/engine_mark_2”. Note that the “trunk” and “branches” are just directories, they have no meaning themselves. I could develop out of /, or even out of /fred and branch to /wilma.

The second command switches the current repository from /trunk to /branches/engine_mark_2. I had just checked in all the code, so nothing had to change, it was just a pointer to where I was storing changes.

So, I could continue working on this branch, and also check out /trunk to somewhere else to make changes.

After all the work in the branch is done and checked in, take a look at the current branch:

1
2
3
4
5
6
7
8
9
10
11
[sean@sergeant payroll]$ svn info
Path: .
URL: http://home.ertw.com/svn/repos/payroll/branches/engine_mark_2
Repository Root: http://home.ertw.com/svn/repos/payroll
Repository UUID: 116013b7-0df0-436d-95c2-deac7dca3705
Revision: 92
Node Kind: directory
Schedule: normal
Last Changed Author: sean
Last Changed Rev: 92
Last Changed Date: 2009-08-24 20:57:22 -0500 (Mon, 24 Aug 2009)

The revision the branch started at is 92.

I checked out a copy of /trunk to another directory:

1
svn co http://home.ertw.com/svn/repos/payroll/trunk payrolltrunk; cd payrolltrunk

Then merge version 92 to the head, giving the url to the branch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
svn merge -r 92:HEAD http://home.ertw.com/svn/repos/payroll/branches/engine_mark_2
--- Merging r93 through r95 into '.':
U    test/unit/accrual_test.rb
U    test/unit/employer_test.rb
U    test/factories.rb
U    test/lib/tax_calc_test.rb
U    test/lib/cpp_ei_test.rb
--- Merging r93 through r95 into 'test/lib/finalize_test.rb':
U    test/lib/finalize_test.rb
--- Merging r93 through r95 into '.':
U    test/lib/pre_flight_test.rb
A    test/lib/payroll_procedure_test.rb
U    app/models/employee.rb
U    app/models/accrual.rb
U    app/models/employer.rb
U    app/controllers/payroll_controller.rb
U    db/schema.rb
A    db/migrate/20090827031532_add_payroll_run_to_accrual.rb
A    db/migrate/20090827032200_add_status_to_employee.rb
U    lib/payroll_engine.rb

At this point you’re sitting in a copy of HEAD with the branches changes merged it. Thankfully I had no conflicts, otherwise I’d have to resolve those before continuing by looking at the files with a status of “C” and fixing the conflicts that are marked by SVN inside the file.

Finally, commit the changes to HEAD:

1
svn commit

Then, either wipe out all your checked out copies and check out HEAD again, or switch your working copy of the branch back to head:

1
 svn switch http://home.ertw.com/svn/repos/payroll/trunk

The branch can stay as is.

Edit
After doing this again I found a problem trying this again when I had added files to the repository in the branch, and was getting “Skipped missing target” errors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
svn log --verbose --stop-on-copy $BRANCH
...
------------------------------------------------------------------------
r106 | sean | 2009-09-04 07:56:23 -0500 (Fri, 04 Sep 2009) | 2 lines
Changed paths:
   A /branches/reporting (from /trunk:105)
Branching to integrate reports
# now in a checked out version of trunk
[sean@sergeant payroll]$ svn merge -r 106:HEAD $BRANCH
--- Merging r107 through r117 into '.':
A    test/unit/helpers/payroll_history_helper_test.rb
U    test/unit/accrual_test.rb
U    test/functional/payroll_controller_test.rb
A    test/functional/payroll_history_controller_test.rb
A    app/helpers/payroll_history_helper.rb
U    app/models/employee.rb
U    app/models/payroll_run.rb
U    app/models/accrual.rb
U    app/models/employer.rb
U    app/controllers/payroll_controller.rb
A    app/controllers/payroll_history_controller.rb
U    app/views/layouts/application.html.erb
U    app/views/payroll/run_final.html.erb
A    app/views/payroll_history
A    app/views/payroll_history/index.html.erb
A    app/views/payroll_history/get.html.erb
A    app/reports
A    app/reports/pay_stub_aggregator.rb
A    app/reports/pay_stub_controller.rb
U    config/environment.rb
U    db/schema.rb
U    lib/payroll_engine.rb

Second edit

So I was working in a branch (copied at revision 147) and had made some updates to HEAD that I wanted to sync up.

From my working copy of the branch:

1
2
3
$ svn merge --dry-run -r 147:149 http://home.ertw.com/svn/repos/payroll/trunk .
U    test/lib/cpp_ei_test.rb
U    lib/payroll_engine.rb

The –dry-run tells me which files will be updated. That was good, so I re-ran without the –dry-run.