Latest Posts

Preserving my old Drupal links 2013-01-08

About a year ago, I built a wine rack out of an Ikea bed and blogged about it. I sent it in to Hack a Day and they promptly posted it. Then Lifehacker featured it, and this has become the most frequently visited blog post I've ever composed. Now that I've gone "minimalist" on my blog (all static HTML with RuhOh), I didn't want these old links to go dead on Hack a Day and LifeHacker. They are linking to a Drupal URL that refers to index.php and a query string with the Drupal node number. Not exactly easy to make static.

When I converted my old Drupal posts to static HTML using Jekyll, it conveniently arranged them all into permalink style folders based on date (year/month/day). Jekyll also created markdown files in folders by node number with meta data at the top that tells Jekyll (or RuhOh) how to find them by permalink. So I got the idea to make a static HTML file but name it index.php and put a little javascript in it that reads the query string then redirects the browser to the relevant node folder. So I came up with this:

    uri = new miuri(location.href);
    window.location = uri.query('q');

MiURI is a simple URI parser in Javascript that I included in the index.php. That's all it took, so now all my old index.php links out there in the internets still work.

I dumped Drupal 2013-01-05

Recently I was checking over my Amazon EC2 bill and noticed that it was twice as much as normal. The extra charges were for Disk I/O. I hadn't thought about this much but Amazon charges 10 cents per million I/O requests on it's Elastic Block Store. My EC2 instance never came near a million I/O requests so it was off my radar. Until now. My EC2 instance was running about a million I/O requests per hour! After some investigation I figured out that MySQL and Drupal were responsible. After more investigation I discovered that Russian bots were registering users on my Drupal blog at the rate of 2 per minute. I had over 50,000 users registered on my blog! All but 3 of them were Russian bots wanting to post spam comments. All the user registrations had caused MySQL to thrash. I shutdown Drupal and the disk I/O ops dropped to a normal rate.

This made me think, why do I use a SQL backed CMS for my blog? I hardly ever post, nobody ever posts comments. I only have a blog in hopes that something I've done and blogged about can be useful to someone. Also, for that potential employer that wants to see what I tinker with. So why the heavy CMS and SQL when a static HTML blog would work fine? I could even host it on Amazon S3 and forget about maintaining an EC2 instance.

I thought about writing some quick Ruby to grab all my Drupal posts out of SQL and then build static HTML pages out of them. Then I thought, surely someone's done this, and I did some Googling. I discovered Jekyll. It's the static site generator behind GitHub and it had a plug-in that ran perfectly on my Drupal MySQL tables and turned all my old posts into Markdown pages. Brilliant! This led me to then discover the author's next project: Ruhoh

Ruhoh is a static blog generator, has Markdown baked in, as well as a templating engine, is open source, and my favorite part: it's written in Ruby. You compose your blog posts, run a compile command and then deploy it. I love it! It's minimalistic yet has some cool features like tagging and categories built in.

IKEA bed re-purposed into a wine rack 2011-11-07

My neighbor had a pile of stuff at the curb that he was giving away or throwing away, whichever occurred first. I noticed a 5 gallon paint bucket full of some very nice looking wood. So I stopped to pick it up. He said it was an IKEA bed that was broken. It even had the hardware in a zip bag.

A couple days later I was looking at it and trying to figure out what I could make out of it. We have been saving our spent wine bottles to fill with a future batch of homemade wine. We've saved about 60 bottles and they were stashed in several places around the house due to not having a good place for them.

So I thought, could it be a wine rack? I laid it out on the garage floor and realized that the mattress slats were the exact length of 12 wine bottles comfortably lined up side by side. I had enough slats for 5 tiers. 5 x 12 = 60 bottles. Eureka!

From 20111101_wine_rack

I cut the bed posts up to form the 4 posts and the cross beams. Then I drilled some holes to make use of the bed's hardware to attach the shelves.

From 20111101_wine_rack

I didn't want the bottles rolling around so I picked up some "screen bead" at the home improvement store. My middle daughter Nena really got into the project at this point. We had to cut, sand, and glue 176 pieces of screen bead for the bottle bumpers.

From 20111101_wine_rack

The result? A 60 bottle wine rack! I started a 6 gallon batch of Argentine Malbec yesterday. That will be the first home batch on the rack, and will only fill half the rack. (30 bottles)

From 20111101_wine_rack
From 20111101_wine_rack

Setting Content-Disposition on PDF files in Nginx 2011-10-08

Adobe and Internet Explorer team up to cause PDF's to automatically open up in your current browser window. I personally find this rather convenient, but your typical web user probably doesn't. In fact, while working on a client website, this "non-technical" client requested that PDFs linked on the website open in a new window. Blech! I don't like doing that. So I go to Jakob Nielsen's website to arm myself with a good explanation on why this is a bad idea. Instead, I run across this interesting piece by Nielsen: http://www.useit.com/alertbox/open_new_windows.html

Nielsen says: "When using PC-native file formats such as PDF or spreadsheets, users feel like they're interacting with a PC application. Because users are no longer browsing a website, they shouldn't be given a browser UI."

I like his thoughts on the matter, so I set out to implement his solution.

The client's site is a Radiant CMS site, and I'm trying to keep the content management as simple as possible so that non-technical people can update the site's content. I really didn't want to go messing about with this within Radiant or Rails. Then I struck me, this really isn't a problem for the framework, it's static content, it's a problem for the webserver to handle. In my case, Nginx was going to handle it.

Here's what I came up with. Note this goes within your server block: {% highlight %} location ~* .pdf$ {
# determine the PDF filename
if ($uri ~ "^/upload/(.+.pdf)$") {
set $filename $1;
}
add_header Content-Disposition"attachment;filename=$filename";
}

Then a reload of nginx, and a quick wget -S to check if my Content-Disposition header was there (yay it was!). Also, I had to close then reopen IE before it seemed to notice (probably caching). And done!

I like Nginx.

Internet Explorer now pops up a dialog box asking if I want to Open or Save the PDF. I like that! But, clicking open still causes the PDF to be opened in a browser window, albeit a new browser window with Adobe PDF controls at the bottom. I decide this is a good compromise.

Simple S3 backup for my EC2 instance 2011-05-06

For disaster recovery, I have my HairForecast.com EC2 instance rsync'ing dumps of the SQL db to my home server nightly. Between that, my own EC2 AMI, and SVN, I can have HairForecast up and running in a matter of minutes if something were to happen to it's primary EC2 instance.

This is good, until this week while away from home, my homeserver went down for unknown reasons. I'm getting nightly emails from my instance that it can't rsync to home. So I thought, now is a good time to just have it back up the files to S3.

I grabbed the Ruby S3 gem, and literally 5 minutes later I had this script locked and loaded to run tonight:

#!/usr/bin/ruby
require 'aws/s3'
AWS::S3::Base.establish_connection!(
    :access_key_id     => 'ABCD',
    :secret_access_key => '1234'  )

AWS::S3::S3Object.store(ARGV[1], open(ARGV[2]), ARGV[0])

Note that it takes 3 arguments, bucket name, filename, path to file. I like to use absolute paths when running crons, since they never run where you expect them to. If you specify a path as a bucket key, then S3 will make folders in your bucket, which is cool I think. But in this case I just wanted my backup files in the root of the bucket.

I'm delighted with the fact that it took longer to blog about this then it did to implement.

A Riak backed password vault 2011-03-30

Document databases have been quite the buzz lately. They are schema-less, no SQL databases that mainly just store keys and values. One particular system called Riak has grabbed my attention recently. I discovered Riak through Sean Cribbs, with whom I'm familiar because of his work on Radiant.

From the Riak website: "Riak is a Dynamo-inspired database that is being used in production by companies like Mozilla and Comcast. Riak scales predictably and easily and simplifies development by giving users the ability to quickly prototype, test, and deploy their applications." (http://wiki.basho.com/)

I learn by doing, so I decided to build a quick and simple password vault to help me learn Riak. Since Riak uses REST and HTTP as it's interface, I thought it would be cool to build it in Javascript, and have the files served by Riak itself.

To my delight, it was quite easy! Gentoo doesn't have a package for Riak yet, so I cloned the github and compiled it from source. The only dependency I needed was Erlang. In a matter of minutes I had a running Riak node

I used Basho's Javascript client, Jquery, and the GibberishAES library for encryption.

If you'd like a closer look, it's on my Githib here: http://github.com/jeremyfsu/Riak-Backed-Password-Vault

Keeping php-cgi running under nginx 2011-03-24

I just moved this blog to Amazon EC2, I really like the pricing model, and the flexibility. On the new gentoo instance, I decided to give Nginx a whirl for running hairforecast.com and jeremywalworth.com and other sites I host. So far it's working well, except for fastcgi for PHP (for Drupal which is what jeremywalworth.com is on).

The problem is php-cgi just mysteriously dies. Poking around on the internets reveals several people with the problem, but no solid solutions other than supervisord or some other watch dog to restart php-cgi when it dies. I'd like to eventually move my blog to Radiant, so I wasn't ambitious about finding a solid solution. I'm also not excited about installing yet another package (supervisord). So I whipped up this humble little Ruby script and put it in root's cron to run every minute.

!/usr/bin/ruby

a = netstat -l | grep phpcgi.socket unless a.size > 0 exec 'php-cgi -b /tmp/phpcgi.socket &' end

It uses netstat to determine if php-cgi has a listening socket, if not, it tries to start it.

It's simple and solves the problem, at least for now!

Random Photo Radiant Extension 2011-03-24

I just released my first contribution to the Radiant CMS extension library. My extension adds a "random photo" tag that can be used inside any Radiant page. It selects a random photo from a specified directory and renders the appropriate IMG tag.

Here it is at Radiant's extension library: http://ext.radiantcms.org/extensions/272-random-photo

Here's the git hub: https://github.com/jeremyfsu/Radiant-CMS-Random-Photo-Extension

Winter Harvest! 2011-01-27

I'm finally harvesting some of the produce from my fall garden. We have some beautiful fat carrots! The other night, Darcy and I had the first salads from the garden. This is Red Romaine, Arugula, and Carrots, all fresh from the garden. The broccoli has started to form heads! Everything else is slow going. I think the squirrels are stealing the peas, I keep seeing baby pods form and then disappear. The Swiss Chard isn't growing well at all, I think I'll try it again in the warmer weather. The Cauliflower looks great, but hasn't formed heads yet. The Spinach looks good, but is growing very slow.

Starcraft II and how I learned that fdisk doesn't affect the data on your drive 2010-12-08

So I bought StarCraft II to join in the fun with my geek friends who are all playing it. However, it just so happens that I'm in bad position in terms of hardware. My main Windows rig is a company issued laptop with tight controls on the antivirus and other settings, and getting SC2 to run on it is proving impossible. My main desktop rig is Linux, with an XP VM that runs in VirtualBox. Well, VirtualBox has direct to hardware 3d acceleration support. I gave it a whirl, but alas, my GeForce 8400 looks like a GeForce 6600 to XP within the VBox VM. SC2 doesn't like that.

So my next idea was to boot my XP VM directly. It's on it's own partition, so why not? So I edited my grub.conf and tried it. No dice, grub doesn't find the partition. I played with some settings, including hiding partitions with grub, then suddenly grub starts throwing Error 17. I can't even boot my Linux install now.

After booting a linux USB thumb drive I have, and poking around, I find that the Partition System ID's are all changed to Amoeba. WTH!?

So I fix them, luckily I follow the same pattern on all my linux installs. Linux boots, but /usr and /home are missing, ah crap, those are on LVM. LVM was using some extended partitions. Back into fdisk I go and I see that my extended partitions are gone! BP goes up. This is my main dev rig for work.

After more poking around, I discover that I can see the dimensions of my extended partitions when I fdisk /dev/sda4, which was the originally the extended partition. I notice that it's ID is Linux, and I think, oh that should be Linux Extended. I change it, and fdisk says nope, can't do that, delete it first and create a new one. BP goes up again. I'm thinking I've lost my /home and /usr forever.

So I do some reading, after googling for "recovering extended partitions". After reading a few blog posts, I realize that fdisk just alters the partition table, not the data on the drive, so you can, theoretically, delete partitions. Then go back and create them, exactly as they were before, and it will be like nothing ever happened. Really? So I write down the dimensions from fdisk /dev/sda4. Then I fdisk /dev/sda and very nervously delete partition 4, then recreate it as an extended. Then I create my extended partitions within 4. I hit 'w' to write the table, take a deep breath, and reboot.

Linux stops and does an fsck on vg1 because it's last mount date is in the future. NICE! Who cares about that, it knows vg1 exists! Which was my main LVM volume group.

After fsck runs, I'm back in action. My XP VM was an extended partition too, so I fire up VirtualBox and boot XP, and there it was, just like nothing ever happened.

So, the moral of this story? Even when it looks like you just bought the farm, try all your options, it may not be as dire as it seems!