-
-
Save urfolomeus/3258292 to your computer and use it in GitHub Desktop.
## 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 |
Thanks for the feedback. Will take a look tomorrow. That error will get thrown if 'heroku addins' returns nil I think. Will confirm ramorra though ;)
I can't figure out what output Heroku is returning to heroku addons
that's causing it to barf. My specs pass no matter what I chuck at it. I suspect it's returning an error though. Can you run heroku addons
from the command line and let me know what you get please?
In the meantime I've just uniq'd it so that at least the rest of the script will run.
Oh, just realised that the app name is blank. Perhaps that's the root of the issue?
The only #include? I can see is on line #71. Perhaps the problem is an app has no addons?
Unscientifically derived guess from the sofa!
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 ;)
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 :)
I see this error at the end of an otherwise successful run:
I may be running an old version of the Heroku CLI though. As I said earlier though, nice work.