Skip to content

Instantly share code, notes, and snippets.

@gosuri
Created May 5, 2011 20:58
Show Gist options
  • Save gosuri/957912 to your computer and use it in GitHub Desktop.
Save gosuri/957912 to your computer and use it in GitHub Desktop.
Backup script to take a snapshot of the database and upload to Rockspace Cloud Files
# Backup script to take a snapshot of the database and upload to Rockspace Cloud Files
# also manages the no of backups to keep.
#
# Note: You will require a Rackspace Cloud account, more details @ http://www.rackspace.com/cloud/
#
# -------------
# Configuration
# -------------
# The script uses the database.yml for configuration. Backup database details should be
# provided for the appropriate environment.
#
# ---------------------
# Sample Configuration
# ---------------------
# production:
# adapter: mysql
# host: db_host
# database: database_name
# username: db_user
# backup:
# adapter: mysql
# host: db_host
# database: db_name
# username: root
# cloud_user: rackspace_cloud_user_id
# cloud_key: api_key_provided_by_rackspace
# cloud_container: container_to_store
# keep_backups: no_of_backups_to_keep_in_the_container
#
# -----------------
# Gem Dependencies
# -----------------
# rails 2.3.8
# cloudfiles
namespace :db do
desc "Creates a snapshot of the database under tmp/backups/db and uploads to Rackspace Cloud"
task :backup, :needs => :environment do
BACKUP_DIR_PATH = File.expand_path(File.join(RAILS_ROOT,"tmp","backups","db"))
# Create Directories if they don't exist
FileUtils.mkpath BACKUP_DIR_PATH unless File.directory?(BACKUP_DIR_PATH)
# Check for lock file to ensure just one backup is being taken at a time
lock_file = File.expand_path(File.join(BACKUP_DIR_PATH,".lock"))
raise "There is a backup process being run or did not finish properly, check #{BACKUP_DIR_PATH}" if File.exists? lock_file
# Create the lock file and write the process id, should delete this once the backup is done
File.open(lock_file, 'w') {|f| f.write(Process.pid) }
# Check if mysqldump exists in the path
mysqldump_path = nil
ENV['PATH'].split(':').each {|folder| mysqldump_path = folder + "/mysqldump" if File.exists?(folder+'/mysqldump')}
raise "mysqldump executable not found in path" if mysqldump_path.blank?
# Fetch Database details from database.yml
db_config = Rails::Configuration.new.database_configuration[RAILS_ENV]["backup"]
raise "backup DB is not defined in database config" if db_config.blank?
# Consutrcting the mysqldump command
command = "#{mysqldump_path} --opt "
command += "-h #{db_config['host']} " unless db_config['host'].blank?
command += "-P #{db_config['port']} " unless db_config['port'].blank?
command += "-u #{db_config['username']} " unless db_config['username'].blank?
command += "-p#{db_config['password']} " unless db_config['password'].blank?
command += "#{db_config['database']} "
file_name = Time.now.strftime("#{db_config['database']}-%d-%B-%YT%H%M.sql")
file_path = File.expand_path(File.join(BACKUP_DIR_PATH,file_name))
command += "> #{file_path}"
puts "starting backup, writing to #{file_path}"
system command # Run the command
puts "backup complete, wrote to #{file_path}"
# Upload to the cloud
puts "starting upload"
cloud_files = CloudFiles::Connection.new(:username => db_config['cloud_user'], :api_key => db_config['cloud_key'])
container = cloud_files.container(db_config['cloud_container'])
obj = container.create_object(file_name)
obj.write File.open(file_path,'rb')
puts "upload complete"
# Cleanup
File.delete(file_path)
File.delete(lock_file)
# Number of files should not exceed the number specified @ keep_backups
if container.objects.count > db_config['keep_backups']
objects = container.objects_detail # => Fetches all the object details
no_objs_to_delete = objects.size - db_config['keep_backups'] - 1
sorted_objects = objects.sort_by {|obj| obj[1][:last_modified]}
sorted_objects[0..no_objs_to_delete].each {|obj| container.delete_object obj[0]}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment