Archive for October, 2008

PostgreSQL Backup Tips for n00bz

Posted by Timothy O'Connell in Code on October 29, 2008

Full disclosure: I'm no postgres expert. In fact, I'm pretty much a total noob myself.

Which, ironically, makes me uniquely qualified to write the Postgres tutorial that follows. An old hand is exactly the guy who you don't want to write a guide about common newbie problems because, as the old writers' saw goes, you do your best writing when you write what you know.

And when I set out a few days ago to crank out a backup script for my postgres databases, I knew precious little.

When I began, I had two databases on two servers that were only getting backed up when the whole filesystem got backed up: MySQL is still my bread and butter--it powers most of the applications I support--and while I had a robust enough scheme for making, date-stamping and backing up dumps from my various MySQL databases, I had nothing of the sort in place to protect my Postgres data. And while this was acceptable (due, primarily, to the non-essential nature of the data contained within those databases), it was far from optimal.

I ended up writing my program in python, but what follows will be language-neutral: I plan to mostly talk about things that happen between you (the sysadmin) and your filesystem. I will stop to make some remarks at the end that will be python-specific, but the main points I have to make are more widely applicable in that all you need to know to make use of them is a little bit of bash.

  1. Selecting all Databases
  2. Right off the bat, if you're going to be backing up multiple databases on multiple servers, you're going to need a way to automate the query by which you determine which databases you're going to need to dump: every whole-database backup starts with a list of databases.

    In MySQL, this is drop-dead easy: a quick "show databases" will get you all the information you need. In Postgres, the pg_database table is going to be your friend. Connect as the postgres user (or someone with equivalent access) and take a look at it: it's chock full of the Good Stuff That Kids Go For.

    When you're writing your automated backup, you can retrieve a list of all of your postgres databases thus:

    select datname from pg_database;


  3. Database "root" user
  4. It is probably an incredibly bad habit that I should not spread to others (but hey: that's what newbies do!), but I like to create a "root" user in my postgres databases. It's an old habit, one of those ones that dies hard, from my MySQL days and, even though I know it's wrong, it makes administering my postgres databases a little bit easier: rather than doing # su postgres -c psql and acting as the built-in postgres user whenever I need to shuffle things around in my database, I just keep a .pgpass (more on that in a second) in my UNIX root's homedir and do a quick # psql whenever I need to get into my database.

    It also comes in handy to have "root" user in your database when you're automating backups: you can execute your backup script as UNIX root, execute the necessary database functions without switching users and so on.

    In order to create this guy and give him the appropriate permissions, you can toss off the following easy-peasy bash, enter a password and be done with it:

    # su postgres -c "createuser -daP root"


  5. .pgpass
  6. The final thing that will save you some time when you're whipping up an automated database dumping scheme from scratch is know how to work a .pgpass file. You can (and probably should) read the full documentation here, but what it boils down to is summarized in the following bullet points:

    1. The file belongs in the home directory of the UNIX user who will be doing the backup.
    2. The file must not be world- or group-readable.
    3. The basic syntax is dbhostname:port:database:dbusername:password
    4. You can substitute an asterisk (i.e. wildcard) for any of those values except "dbusername" and "password".

    So basically, since your automatic backup will probably be executed by your (UNIX) root user, you're going to want to whip up a .pgpass in his homedir with a little bash like this:

    # echo "localhost:5432:*:root:xxxxxxxxxx" > .pgpass

    Then you're going to modify the permissions on that file like this:

    # chmod 0600 ~/.pgpass

    And that's that. Your access and permissions are good to go and you're ready to use the scripting language of your choice to set up an automatic backup.



And when you do get around to scripting that backup, you're probably going to want to gzip or bzip your dumps: as most backups end up traveling across some kind of network, it helps to have them be as compressed as possible. The simplest bash one-liner for gzipping up your SQL dumps is probably the one where you throw them all into one big archive like the man page recommends:

cat database1.sql database2.sql | gzip -9 > databaseDump.gz 

But when I wrote my program (in python), I did the actual dump commands with subprocess and created individual archives for my dumps. Here's a snippet:

outputFile = open(dbName+todaysDate+".sql.gz", "wb")
command1 = ["/usr/bin/pg_dump",dbName]
command2 = ["gzip","-9"]
p1 = subprocess.Popen(command1, stdout=subprocess.PIPE)
p2 = subprocess.Popen(command2, stdin=p1.stdout, stdout=outputFile)
p1.wait()
p2.wait()
outputFile.close()

This, as I mentioned, leaves you with a collection of individual archives that you can then stash in some place safe until some programmer's hasty application deploy nukes yesterday's production data and you get to play hero.

Click That Button

Posted by Trevor in General on October 28, 2008

CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON… CLICK THAT BUTTON….

Update: For 2 days only... CLICK for Obama! click that button »

How to sync Google Calendar with your iPhone

Posted by Trevor in General on October 27, 2008

I recently bit the bullet and picked up an iPhone, and it's been great... except that it can't sync up with my Google Calendar. I had figured out a trick that allowed me to subscribe to a private RSS feed of my calendar in iCal, but that's only a one-way deal.

I just came across some good news, though. Google has enabled CalDAV, which means you can easily have two-way syncing between your Google Calendar and iPhone.

Just follow these simple instructions from their support site, and your Google Calendar will appear in iCal's list of calendars, and iCal will sync any changes to and from Google Calendar. If you've enabled syncing between iCal and your iPhone, you're good to go.

There's also instructions for getting this working with Mozilla's Sunbird.

(via swissmiss)

Sweet.

Update: Sorry to get your hopes up - this doesn't work as expected because adding events on the iPhone are not synced back to your Google Calendar, just iCal. See the comments for details.

Easy Upload via URL with attachment_fu

Posted by Trevor in Ruby/Rails on October 24, 2008

Allowing file uploads with attachment_fu is super easy, but I've found that users sometimes want to be able to "upload" a file directly from a URL. This saves them the steps of downloading the file, finding it on their computer, uploading it into your app, etc.

I did a bit of digging around before I came across this handy trick that makes it pretty painless to add uploading via a URL to your app. I've wrapped up the code a bit and added in a few niceties that I found necessary to avoid raising exceptions unnecessarily.

The best part is that you don't need to change anything about your controller in order to get this to work. All you need is to add the uri attribute to your model and views, and you're good to go.

 
# app/models/upload.rb
 
class Upload < ActiveRecord::Base
 
  # ...normal attachment_fu code (has_attachment, etc)...
 
  # allow uploads via URL
  require 'open-uri'
  attr_reader :url
  def url=(uri)
    return nil if uri.blank?
    io = (open(URI.parse(uri)) rescue return nil)
    (class << io; self; end;).class_eval do
      define_method(:original_filename) { base_uri.path.split('/').last }
    end
    self.uploaded_data = io
  end
end
 
# app/controllers/uploads_controller.rb
 
class UploadsController < ApplicationController
 
  # avoid raising exceptions for common errors (e.g. file not found)
  rescue_from Errno::ENOENT, :with => :url_upload_not_found
  rescue_from Errno::ETIMEDOUT, :with => :url_upload_not_found
  rescue_from OpenURI::HTTPError, :with => :url_upload_not_found
  rescue_from Timeout::Error, :with => :url_upload_not_found
 
  def new
    @upload = Upload.new
  end
 
  def create
    @upload = current_user.uploads.build(params[:upload])
    if @upload.save
      redirect_to files_path
    else
      render :action => "new"
    end
  end
 
  def url_upload_not_found
    flash[:notice] = "Sorry, the URL you provided was not valid."
    redirect_to new_upload_path
  end
end
 
# app/views/uploads/new.html.erb
 
<%= error_messages_for :upload %>
<% form_for @upload, :html => { :multipart => true } do |f| -%>
  <%= f.file_field :uploaded_data # normal upload, or... %>
  <%= f.text_field :url # upload via url %>
  <%= submit_tag "Upload", :disable_with => "Upload" %>
<% end %>
 

You can see a working example of all this in El Dorado. I was bored, so I decided to try my hand at making a screencast. Check it out - it's got an awesome soundtrack at the very least :)

If you'd like to use this for multiple models, consider refactoring it into a module that you can include elsewhere.

Hope this helps - and suggestions/improvements are always welcome!

Stupid Linux Tricks: debug your website like a sysadmin

Posted by Timothy O'Connell in Code on October 21, 2008

I recently had a conversation with a certain programmer friend who, having foolishly overwritten his Firefox 3.0x with an installation of the 3.1 beta, was unable to use any of his plugins. This wasn't a huge problem for him--i.e. he figured he could live without his plugins for a week or two--until he realized that he wasn't going to be able to use LiveHTTPHeaders (http://livehttpheaders.mozdev.org/).

The plugin, which can greatly expedite client-side testing, is not the only way to do that sort of testing. In a pinch, you can view HTTP headers on the command line simply by firing up a terminal session and using wget:

$ wget -S almosteffortless.com -O /dev/null

The majuscule "S" gets you the headers and the "-O /dev/null" dumps the file you're about to retrieve in the bit bucket (rather than into your home directory or where ever). The output you get looks something like this:

toconnell@lana:~/tmp$ wget -S almosteffortless.com
--2008-10-21 13:43:24--  http://tyrannybelle.com/
Resolving tyrannybelle.com... 208.78.99.165
Connecting to tyrannybelle.com|208.78.99.165|:80... connected.
HTTP request sent, awaiting response...
  HTTP/1.1 200 OK
  Date: Tue, 21 Oct 2008 18:43:25 GMT
  Server: Apache/2.2.9 (Debian) PHP/5.2.6-5 with Suhosin-Patch mod_python/3.3.1 Python/2.5.2 mod_ssl/2.2.9 OpenSSL/0.9.8g
  X-Powered-By: PHP/5.2.6-5
  Set-Cookie: PHPSESSID=aefe500683f79ed067f91f76d3615d33; path=/
  Expires: Thu, 19 Nov 1981 08:52:00 GMT
  Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
  Pragma: no-cache
  Content-Length: 4932
  Keep-Alive: timeout=15, max=100
  Connection: Keep-Alive
  Content-Type: text/html
Length: 4932 (4.8K) [text/html]

You can see cookie info, cache and pragma values, Apache information and so on. Not too shabby.

I showed this to my pal and, though he was a little impressed, he wasn't entirely convinced that he was going to be able to do all of his client testing using only the CLI: "yes, that's all fine and good", he said, "but I usually need to right-click and 'View Page Source' in order to check on dynamically generated content."

"You're not going to want to hear this," I responded, "but telnet is your friend on this one."

toconnell@lana:~/tmp$ telnet tyrannybelle.com 80 

Will connect you to your website. All you've got to do at that point is manually GET your document. Let's say, for the example, that we just want our index. All you do, once you're connected, is

GET /

telnet will then proceed to make the request, dump the response onto your terminal as html and exit.

Granted, you don't get any syntax highlighting or fancy stuff, but if you're debugging from a mobile device, a computer without windowing software or in any other circumstance you can't use a proper browser, telnet is a great way to eyeball a website.

My friend admitted that this was, in fact, all right in a pinch, but it was plain from the look on his face that he still wasn't sold on ye olde command line as a testing/debugging tool. "What about layout?" he asked.

"Well yeah," I conceded, "there's really no good way to do that without a browser, but if you want to check on your tab order..."

And then, just as I was about to start in lynx, he said, "you know what? Forget it--I'm just going to go ahead and trash this beta install."

Stupid Linux Tricks: gpg plugin for vim

Posted by Timothy O'Connell in General on October 17, 2008

If you're like me, your favorite passtimes include cracking condescending jokes about how the mouse is just another passing fad, startling your coworkers by laughing out loud at anti-emacs rants on bash.org and encrypting every plaintext file in your home directory within an inch of its life.

If, however, you're like me in the above respects and you don't yet know about the gpg plugin for vim, then the quality of your life is currently being severely diminished.

But we can fix that.

Assuming you're running Debian (or some variation thereof) and you've already got vim installed and your keypair properly set up in your ~/.gnupg directory, here's the how-to on getting the plugin to work for your user:

# apt-get install vim-scripts
$ mkdir ~/.vim/plugin
$ ln -s /usr/share/vim-scripts/plugin/gnupg.vim ~/.vim/plugin/gnupg.vim

And that's it: three commands and you're in business.

(It is worth mentioning at this point that there is a whole slew of awesome vim plugins in the "vim-scripts" package. Enabling them is as easy as creating a symlink to them in the above manner.)

Once you've got your gpg plugin set up, creating encrypted files is as easy as:

$ vi newFile.gpg

A buffer opens up, you enter recipients' key numbers or aliases (i.e. 759991EC or toconnell will get the job done), quit the buffer and edit the file as usual. You'll obviously want to remember to at least enter your own ID in the buffer so that you can decrypt the file in the future.

Editing files is just as simple: the next time you attempt to open your file, you'll be prompted by vim for your private key password and, upon entering it, your file will be decrypted and you'll be able to make changes and save it.

Finally, depending on whether or not the recipients you've specified in the buffer are "trusted", you may be manually prompted to sign the document with their public keys when you save it. Other than that, you're pretty much golden: with the exception of the password prompt you'll get when you try to open the file, you've eliminated most of the hassle that goes into decrypting, editing and encrypting shared files on the command line.

Substantial labor and time savings = demonstrably improved quality of life.

Stupid Linux Tricks: cron task @reboot

Posted by Timothy O'Connell in Code on October 15, 2008

A little known fact of cron is that you can use it to execute commands as soon as your machine returns from a reboot. If, for example, I create a file in /etc/cron.d/ called "whatever" that looks like this:

@reboot    root    `which sshfs` user@remotemachine:/mnt/data  /mnt/data

The above command will be executed once the system is fully booted. This is ideal for cases in which depend on a number of services or in which manual intervention is required. One could, for example, create a file called "whatever" in /etc/cron.d/ to remind him that he needed to manually intervene once the boot process was finished and that he was now free to do just that:

@reboot    root    echo "Don't forget the sshfs mount!" | mail -s "[`hostname`] Reboot!" root

There are a handful of other, similarly useful shortcuts that Vixie built into cron but that aren't particularly well known:

    @yearly        Run once a year, "0 0 1 1 *".
    @annually      (same as @yearly)
    @monthly       Run once a month, "0 0 1 * *".
    @weekly        Run once a week, "0 0 * * 0".
    @daily         Run once a day, "0 0 * * *".
    @midnight      (same as @daily)
    @hourly        Run once an hour, "0 * * * *".

(Excerpted from the man page)