Created
August 4, 2012 15:12
-
-
Save urfolomeus/3258292 to your computer and use it in GitHub Desktop.
Quick script to migrate heroku apps to the new free individual postgres DBs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## README | |
# This is a quick script I hacked out to migrate all my heroku apps | |
# to the new free individual postgres DBs. To use it: | |
# - install the heroku gem if you don't already have it | |
# - set the value of IGNORE_OTHERS_APPS to true if you only want to | |
# run the script against apps you've created yourself | |
# - add any apps you want to ignore because they don't use PostgreSQL | |
# (or for any other reason) to the IGNORE_LIST | |
## CAVEAT!! | |
# - USE AT YOUR OWN RISK!! This works for me, but it may not work for you! | |
# - I don't remove the SHARED_DATABASE at the end of the process in | |
# case you want to rollback, so you'll need to delete it yourself once | |
# you're happy everything worked | |
# heroku addons:remove shared-database | |
# - if everything goes south you can just try again, but you'll have to make | |
# sure that you set the shared database back to be primary by running | |
# heroku pg:promote SHARED_DATABASE --app <app_name> | |
## N.B. | |
# If you do this before Aug 9th then you get: | |
# - an extra 4000 lines for your DB if on the dev plan | |
# - $20 credit if on basic or production plan | |
# | |
# More info at: https://devcenter.heroku.com/articles/migrating-from-shared-database-to-heroku-postgres | |
## OPTIONS | |
IGNORE_OTHERS_APPS = true | |
IGNORE_LIST = [ ] | |
class HerokuDBMigrator | |
def initialize(app_name) | |
@app_name = app_name | |
end | |
def run | |
raise "No app_name set" if @app_name.nil? or @app_name == "" | |
maintenance :on | |
add_required_addons | |
transfer | |
rescue Exception => e | |
p e | |
ensure | |
maintenance :off | |
end | |
private | |
def maintenance(state) | |
heroku "maintenance:#{state}" | |
puts "maintenance #{state}" | |
end | |
def add_required_addons | |
add "heroku-postgresql:dev" | |
add "pgbackups" | |
end | |
def add(addon) | |
unless installed?(addon) | |
puts "adding #{addon}" | |
heroku "addons:add #{addon}" | |
end | |
end | |
def get_addons | |
heroku('addons').split(/\n/).map{|a| a.split(' => ').first}.compact | |
end | |
def installed?(addon) | |
@addons ||= get_addons | |
not @addons.select {|a| a.include?(addon)}.empty? | |
end | |
def transfer | |
backup_existing_db | |
setup_new_db | |
end | |
def backup_existing_db | |
puts "backing up existing DB" | |
heroku "pgbackups:capture --expire" | |
end | |
def setup_new_db | |
db_name = heroku("config").match(/(HEROKU_POSTGRESQL_.*)_URL/)[1] | |
puts "setting up #{db_name}" | |
heroku "pgbackups:restore #{db_name} --confirm #{@app_name}" | |
puts "making #{db_name} primary" | |
heroku "pg:promote #{db_name}" | |
end | |
def heroku(command) | |
`heroku #{command} --app #{@app_name}` | |
end | |
end | |
apps = `heroku apps`.split(/\n/) | |
apps.reject! {|app| app =~ /\s+/} if IGNORE_OTHERS_APPS | |
apps -= IGNORE_LIST | |
apps.each do |app| | |
puts "\nTransferring app: #{app}" | |
HerokuDBMigrator.new(app).run | |
puts | |
end |
Turns out that's exactly what it was. If there you do heroku addons --app
you get the usage message returned, which in turn generates an array with nils in it. I've left the compact in, but I've also changed the run method to raise an error before starting if no app_name is set.
Thanks for the heads up :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yeah I tested that one as it seemed most obvious culprit (although I'd have thought that no add-ons in heroku would just return an empty array which means the #include? in the select would never get called). I thought that what was happening was that the second split on ' => ' was returning an array with nil as the first element, but I couldn't get any output for 'heroku addons' to produce that result. I figured that by compacting the array (not uniq as I first did in my hungover state :D) would remove any nils and therefore remove errors so I just went with that.
What _was_quite interesting though (for a given vaue of interesting) was that the output you pasted showed that no app_name was being passed in to the HerokuDBMigrator. That would cause all calls to be made with --app at the end with no app. So I reckon I must be incorrectly parsing the error message returned from that. So if you can figure out how it managed to get a nil/blank app name, you'll be on the right path ;)