#!/usr/bin/env oo-ruby

def migrate(type)
  puts "Starting #{type} migrations."
  migrations = self.class.constants.grep(/Migrate_/).
                sort.
                map {|m| self.class.send(:const_get, m)}.
                select {|m| m::VERSIONS[type]}
  migrations.each do |m|
    puts "Running migration #{m::name}..."
    m::migrate(type)
    puts "Migration #{m::name} finished."
  end
  puts '', 'Migrations complete.'
end

###############################################################################
# The 2.0.37 migration code is taken from li repo, stage branch (will be 
# stage-2.0.37),
# rhc-broker/script/rhc-admin-migrate-datastore;
#
# * Wrapped the script in a module.

module Migrate_2_0_37
  VERSIONS = {
    :compatible => false,                                                                                      
    :"non-compatible" => true,                                                                                 
    :prerelease => false,                                                                                      
    :postrelease => false,                                                                                     
    :run_parallel => [:"non-compatible"]
  }

  def self.migrate(type)
    case type
    when :prerelease
    when :postrelease
    when :"non-compatible"
      flatten_gears
    when :compatible
    end
  end

  def self.flatten_gears
    #puts "Running parallel migration : #{$parallel_index} of #{$num_processes}.."
    if $parallel_index.nil? or ($parallel_index == 0)
      db["applications"].drop_index("group_instances.gears.uuid_1") rescue nil 
    end
    filter = {}
    selection = {:fields => ["group_instances", "gears"], :timeout => false, :read => :primary}
    OpenShift::DataStore.find(:applications, filter, selection) do |app|
      begin
        #next if app["_id"].to_s.sum.modulo($num_processes)!=$parallel_index
        next if app["gears"].is_a?(Array) and app["gears"].length>0
        new_gears = []
        updates = { "$set" => {}, "$unset" => {} }
        gi_index = -1
        app['group_instances'].each do |gi|
          gi_index += 1
          gi['gears'].each do |gear|
            new_gear = gear.deep_dup
            new_gear["group_instance_id"] = BSON::ObjectId(gi["_id"].to_s)
            new_gears << new_gear
          end if gi['gears'].present?
          updates["$unset"]["group_instances.#{gi_index}.gears"] = ""
        end if app['group_instances'].present?
        updates["$set"]["gears"] = new_gears
        db['applications'].update({"_id" => BSON::ObjectId(app["_id"].to_s) }, updates)
      rescue Exception => e
        puts "Failed to migrate app_id: #{app['_id'].to_s}, Error: #{e.message}"
        puts e.backtrace.inspect
      end
    end
    #puts "Completed #{$parallel_index} of #{$num_processes} parallel tasks."
    puts "Completed flatten_gear migration."
  end
end

###############################################################################
# The 2.0.39 migration code is taken from li repo, stage branch (will be 
# stage-2.0.39),
# rhc-broker/script/rhc-admin-migrate-datastore;
#
# * Wrapped the script in a module.

module Migrate_2_0_39
  VERSIONS = {
    :compatible => true,
    :"non-compatible" => false,
    :prerelease => true,
    :postrelease => true,
    :run_parallel => []
  }

  def self.migrate(type)
    case type
    when :prerelease
      ensure_app_name_domain_unique_index
    when :postrelease
      ensure_app_name_domain_unique_index
      drop_app_domain_index
      drop_group_instances_gears_uuid_index
      remove_component_start_stop_configure_orders
    when :"non-compatible"
    when :compatible
      update_sshkeys
    end
  end

  def self.ensure_app_name_domain_unique_index
    print "Ensure new domain_id / canonical_name index on applications ... "
    db.collection('applications').ensure_index([["domain_id", Mongo::ASCENDING], ["canonical_name", Mongo::ASCENDING]], :unique => true) and puts "done"
    0
  end

  def self.drop_app_domain_index
    print "Drop old domain_id index on applications ... "
    db.collection('applications').drop_index("domain_id_1") and puts "done" rescue puts "not found"
    0
  end

  def self.drop_group_instances_gears_uuid_index
    print "Drop old group_instances_gears_uuid_1 index on applications ... "
    db.collection('applications').drop_index("group_instances.gears.uuid_1") and puts "done" rescue puts "not found"
    0
  end

  def self.remove_component_start_stop_configure_orders
    ['component_configure_order', 'component_start_order', 'component_stop_order'].each do |s|
      print "Remove empty or nil '#{s}' from all applications ... "
      (r = db['applications'].update(
        {'$and' => [
          {s => {'$exists' => true}},
          {"$or" => [
            {s => {"$size" => 0}},
            {s => {"$type" => 10}}, # null
          ]}
        ]},
        {"$unset" => {s => true}},
        {:multi => true, :w => 1} # force w = 1 to receive update count
      )) and puts "#{r['n']} updated" rescue puts "failed #{$!} #{$!.backtrace.join("\n")}"
    end
  end

  def self.update_sshkeys
    start_time = Time.now.to_i

    # updating application ssh keys
    print "Setting _type for application ssh keys... "
    set_app_sshkeys_type()
    puts "Done."

    print "Setting _id for application ssh keys... "
    key_count, app_count = set_app_sshkeys_id()
    puts "Done."
    puts "Updated #{key_count} sshkeys across #{app_count} applications"
    puts ""

    # updating domain ssh keys
    print "Setting _type for domain ssh keys... "
    set_domain_sshkeys_type()
    puts "Done."

    print "Setting _id for domain ssh keys... "
    key_count, domain_count = set_domain_sshkeys_id()
    puts "Done."
    puts "Updated #{key_count} sshkeys across #{domain_count} domains"
    puts ""

    # updating user ssh keys
    print "Setting _type for user ssh keys... "
    set_user_sshkeys_type()
    puts "Done."

    print "Setting _id for user ssh keys... "
    key_count, user_count = set_user_sshkeys_id()
    puts "Done."
    puts "Updated #{key_count} sshkeys across #{user_count} users"
    puts ""

    puts "Time taken: #{Time.now.to_i - start_time} seconds"
    puts ""

    # verifying sshkey updates
    print "Verifying updates for application ssh keys... "
    missed_update_count = verify_app_sshkeys()
    puts missed_update_count == 0 ? "Successful." : "Failed."

    print "Verifying updates for domain ssh keys... "
    missed_update_count = verify_domain_sshkeys()
    puts missed_update_count == 0 ? "Successful." : "Failed."

    print "Verifying updates for user ssh keys... "
    missed_update_count = verify_user_sshkeys()
    puts missed_update_count == 0 ? "Successful." : "Failed."
    puts ""
  end

  def self.set_app_sshkeys_type()
    index = 0
    search_count = 1
    while search_count > 0 do
      filter = {"$or" => [{"app_ssh_keys.#{index}._type" => {"$exists" => false}},
                          {"app_ssh_keys.#{index}._type" => nil}],
                "app_ssh_keys.#{index}.content" => {"$exists" => true}}

      update_query = {"$set" => {"app_ssh_keys.#{index}._type" => ApplicationSshKey.to_s}}
      db["applications"].update(filter, update_query, { :multi => true })

      index += 1
      search_count = db["applications"].find({"app_ssh_keys.#{index}" => {"$exists" => true}}).count
    end
  end

  def self.set_app_sshkeys_id()
    app_count = 0
    key_count = 0
    filter = {"app_ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}],
                                                "content" => {"$exists" => true}}}}
    db["applications"].find(filter, {fields: ["app_ssh_keys._id", "app_ssh_keys.name"]}).each do |app|
      app_count += 1
      index = -1
      app["app_ssh_keys"].each do |sshkey|
        index += 1
        next if sshkey.has_key?("_id") and sshkey["_id"].present?
        key_count += 1
        sshkey_id = Moped::BSON::ObjectId.new.to_s
        update_query = {"$set" => {"app_ssh_keys.#{index}._id" => BSON::ObjectId(sshkey_id)}}
        db["applications"].update({"_id" => BSON::ObjectId(app["_id"].to_s)}, update_query)
      end
    end
    return key_count, app_count
  end

  def self.verify_app_sshkeys
    missed_update_count = 0

    filter = {"app_ssh_keys" => {"$elemMatch" => {"$or" => [{"_type" => {"$exists" => false}}, {"_type" => nil}]}}}
    missed_update_count += db["applications"].find(filter).count

    filter = {"app_ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}]}}}
    missed_update_count += db["applications"].find(filter).count

    missed_update_count
  end

  def self.set_domain_sshkeys_type()
    index = 0
    search_count = 1
    while search_count > 0 do
      filter = {"$or" => [{"system_ssh_keys.#{index}._type" => {"$exists" => false}},
                          {"system_ssh_keys.#{index}._type" => nil}],
                "system_ssh_keys.#{index}.content" => {"$exists" => true}}

      update_query = {"$set" => {"system_ssh_keys.#{index}._type" => SystemSshKey.to_s}}
      db["domains"].update(filter, update_query, { :multi => true })

      index += 1
      search_count = db["domains"].find({"system_ssh_keys.#{index}" => {"$exists" => true}}).count
    end
  end

  def self.set_domain_sshkeys_id()
    domain_count = 0
    key_count = 0
    filter = {"system_ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}],
                                                   "content" => {"$exists" => true}}}}
    db["domains"].find(filter, {fields: ["system_ssh_keys._id", "system_ssh_keys.name"]}).each do |domain|
      domain_count += 1
      index = -1
      domain["system_ssh_keys"].each do |sshkey|
        index += 1
        next if sshkey.has_key?("_id") and sshkey["_id"].present?
        key_count += 1
        sshkey_id = Moped::BSON::ObjectId.new.to_s
        update_query = {"$set" => {"system_ssh_keys.#{index}._id" => BSON::ObjectId(sshkey_id)}}
        db["domains"].update({"_id" => BSON::ObjectId(domain["_id"].to_s)}, update_query)
      end
    end
    return key_count, domain_count
  end

  def self.verify_domain_sshkeys
    missed_update_count = 0

    filter = {"system_ssh_keys" => {"$elemMatch" => {"$or" => [{"_type" => {"$exists" => false}}, {"_type" => nil}]}}}
    missed_update_count += db["domains"].find(filter).count

    filter = {"system_ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}]}}}
    missed_update_count += db["domains"].find(filter).count

    missed_update_count
  end

  def self.set_user_sshkeys_type()
    index = 0
    search_count = 1
    while search_count > 0 do
      filter = {"$or" => [{"ssh_keys.#{index}._type" => {"$exists" => false}},
                          {"ssh_keys.#{index}._type" => nil}],
                "ssh_keys.#{index}.content" => {"$exists" => true}}

      update_query = {"$set" => {"ssh_keys.#{index}._type" => UserSshKey.to_s}}
      db["cloud_users"].update(filter, update_query, { :multi => true })

      index += 1
      search_count = db["cloud_users"].find({"ssh_keys.#{index}" => {"$exists" => true}}).count
    end
  end

  def self.set_user_sshkeys_id()
    user_count = 0
    key_count = 0
    filter = {"ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}],
                                            "content" => {"$exists" => true}}}}
    db["cloud_users"].find(filter, {fields: ["ssh_keys._id", "ssh_keys.name"]}).each do |user|
      user_count += 1
      index = -1
      user["ssh_keys"].each do |sshkey|
        index += 1
        next if sshkey.has_key?("_id") and sshkey["_id"].present?
        key_count += 1
        sshkey_id = Moped::BSON::ObjectId.new.to_s
        update_query = {"$set" => {"ssh_keys.#{index}._id" => BSON::ObjectId(sshkey_id)}}
        db["cloud_users"].update({"_id" => BSON::ObjectId(user["_id"].to_s)}, update_query)
      end
    end
    return key_count, user_count
  end

  def self.verify_user_sshkeys
    missed_update_count = 0

    filter = {"ssh_keys" => {"$elemMatch" => {"$or" => [{"_type" => {"$exists" => false}}, {"_type" => nil}]}}}
    missed_update_count += db["cloud_users"].find(filter).count

    filter = {"ssh_keys" => {"$elemMatch" => {"$or" => [{"_id" => {"$exists" => false}}, {"_id" => nil}]}}}
    missed_update_count += db["cloud_users"].find(filter).count

    missed_update_count
  end
end

###############################################################################
# The 2.0.40 migration code is taken from li repo, stage branch (will be 
# stage-2.0.40),
# rhc-broker/script/rhc-admin-migrate-datastore;
#
# * Wrapped the script in a module.

module Migrate_2_0_40
  VERSIONS = {
    :compatible => false,
    :"non-compatible" => true,
    :prerelease => false,
    :postrelease => true,
    :run_parallel => []
  }

  def self.migrate(type)
    case type
    when :prerelease
    when :postrelease
      set_aliases_for_ha_apps
      alter_downloaded_cart_map
      set_cartridge_id_on_component_instances
    when :"non-compatible"
      # not needed because we don't ship the mongodb cartridge yet
      #adjust_cartridge_versions
      migrate_districts
    when :compatible
    end
  end

  def self.alter_downloaded_cart_map(depth=1)
    puts "Removing downloaded_cart_map for all applications (attempt ##{depth}) ..."
    warn = 0
    migrated = 0

    db["applications"].find(
      {
        "$where" => 'for (i in this.downloaded_cart_map) return true; return false;'
      },
      :fields => ['_id', 'downloaded_cart_map', 'component_instances', 'pending_op_groups']
    ).each do |app|
      if app['pending_op_groups'].present?
        warn += 1
        puts "SKIP: Application #{app['_id']} has pending ops #{name} and can't be migrated."
        next
      end
      next unless app['downloaded_cart_map'].present?
      all = true
      app['downloaded_cart_map'].each_pair do |_, data|
        name = data['versioned_name']
        if instance = app['component_instances'].detect{ |i| i['cartridge_name'] == name }
          yaml = YAML.load(data["original_manifest"], safe: true)
          yaml['Id'] = instance['_id'].to_s
          text = OpenShift::Cartridge.new(yaml).to_descriptor.to_json

          result = db["applications"].update(
            {"_id" => app['_id'], "component_instances._id" => instance['_id'], "pending_op_groups" => {"$size" => 0}},
            {
              "$set" => {
                # matches what component_instance generates
                "component_instances.$.manifest_text" => text,
                "component_instances.$.manifest_url" => data['url'],
                "component_instances.$.cartridge_id" => instance['_id'],
              },
            },
            :w => 1) # w1 for update count
          if result['n'] != 1
            puts "WARNING: Application #{app['_id']} could not be updated."
            all = false
          end
        else
          puts "WARNING: Application #{app['_id']} has downloaded cart #{name} which does not have a corresponding component_instance.  May be corrupted."
          all = false
        end
      end
      if all
        result = db["applications"].update({"_id" => app['_id'], "pending_op_groups" => {"$size" => 0}}, {"$unset" => {"downloaded_cart_map" => ""}}, :w => 1)
        if result['n'] != 1
          puts "WARNING: Could not remove downloaded_cart_map from application #{app['_id']}."
          warn += 1
        else
          migrated += 1
        end
      else
        warn += 1
      end
    end

    if warn > 0
      if depth <= 3
        puts "  Migrated #{migrated} applications with downloadable cartridges"
        puts "  Some applications had pending ops, retrying"
        sleep 2
        alter_downloaded_cart_map(depth+1)
        return
      else
        puts "ERROR: Not all applications migrated after #{depth} tries, pending ops queue prevented changes."
      end
    else
      # remove all downloaded_cart_map from all applications if everything succeeded
      db["applications"].update({"pending_op_groups" => {"$size" => 0}}, {"$unset" => {"downloaded_cart_map" => ""}}, multi: true)
    end
    puts "  Migrated #{migrated} applications with downloadable cartridges"
  end

  def self.set_cartridge_id_on_component_instances(depth=1)
    puts "Ensuring all component instances have a cartridge_id (attempt ##{depth}) ..."
    ids = {}
    db['cartridge_types'].find({'priority' => {'$exists' => true}}, :fields => ['name']).each do |type|
      ids[type['name']] = type['_id']
    end
    if ids.blank?
      puts "ERROR: No active cartridges, cannot migrate"
      return
    end

    warn = 0
    migrated = 0
    db["applications"].find({'component_instances' => {'$elemMatch' => {'cartridge_id' => {'$not' => {'$exists' => true}}}}},
                            :fields => ['_id', 'component_instances', 'pending_op_groups']).each do |app|
      if app['pending_op_groups'].present?
        warn += 1
        puts "SKIP: Application #{app['_id']} has pending ops #{name} and can't be migrated."
        next
      end
      all = true
      app['component_instances'].each do |instance|
        next if instance['cartridge_id'].present?
        id = ids[instance['cartridge_name']]
        if id.blank?
          puts "WARNING: Application #{app['_id']} has component instance with name #{instance['cartridge_name']} that isn't an active cartridge."
          all = false
          next
        end
        result = db["applications"].update(
          {"_id" => app['_id'], "component_instances._id" => instance['_id'], "pending_op_groups" => {"$size" => 0}},
          {"$set" => {"component_instances.$.cartridge_id" => id}},
          :w => 1) # w1 for update count
        if result['n'] != 1
          puts "WARNING: Application #{app['_id']} could not be updated."
          all = false
        end
      end
      if all
        migrated += 1
      else
        warn += 1
      end
    end
    if warn > 0
      if depth <= 3
        puts "  Migrated #{migrated} applications"
        puts "  Some applications had pending ops, retrying"
        sleep 2
        set_cartridge_id_on_component_instances(depth+1)
        return
      else
        puts "ERROR: Not all applications migrated after #{depth} tries, pending ops queue prevented changes."
      end
    end
    puts "  Migrated #{migrated} applications"
  end

  def self.migrate_districts
    old_districts_count = db["districts"].find({"server_identities" => {"$exists" => true}}).count
 
    current_time = Time.now.utc
    db["districts"].find({}, {:fields => ["_id", "active_server_identities_size", "server_identities"], :timeout => false}) do |mcursor| 
      mcursor.each do |district|
        # skip if district is already migrated, this will make district migration re-entrant.
        next if district.has_key?("active_servers_size")
 
        updates = {}
        updates["$set"] = {"active_servers_size" => district["active_server_identities_size"]}
        updates["$unset"] = {"active_server_identities_size" => ""}
        new_servers = []
 
        district["server_identities"].each do |server|
          puts "Migrating: District (#{district['_id']}), Server (#{server['name']}), Active (#{server['active']}), Unresponsive (#{server['unresponsive']})"
          si = {}
          si['_id'] = BSON::ObjectId.new
          si['name'] = server['name']
          if server['active']
            si['active'] = true
          else
            si['active'] = false
          end
          if server['unresponsive']
            si['unresponsive'] = true
          else
            si['unresponsive'] = false
          end
          si['created_at'] = current_time
          si['updated_at'] = current_time
          new_servers << si
        end if district["server_identities"].present?
 
        updates["$set"]["servers"] = new_servers
        updates["$unset"]["server_identities"] = ""
        db["districts"].update({'_id' => district['_id']}, updates)
      end
    end if old_districts_count > 0
  
    new_districts_count = db["districts"].find({"servers" => {"$exists" => true}}).count
    if old_districts_count != new_districts_count
      puts "Error: District migration Failed!, #Old districts: #{old_districts_count}, #New districts: #{new_districts_count}"
      exit 1
    else
      puts "District migration Successful!"
    end
  end

  #
  # set the alias and SSL certificates in the secondary haproxy gears for HA applications 
  #
  def self.set_aliases_for_ha_apps
    print "Sending alias and SSL cert info to secondary proxy gears for all HA apps...\t"
    app_count = 0

    # fetch the list of HA applications
    Application.where({"scalable" => true, "ha" => true}).each do |app|
      # check if the application has any aliases
      if app.aliases.present?
        # get the list of gears that have the haproxy cartridge
        haproxy_gears = app.gears.select { |g| g.component_instances.select { |ci| ci.get_cartridge.is_web_proxy? }.present? }
        if haproxy_gears.length > 1
          app_count += 1
          fqdns = app.aliases.map {|app_alias| app_alias.fqdn}
          Application.run_in_application_lock(app) do
            haproxy_gears.each do |ha_gear|
              # the app_dns gear already has the alias information, so skip it
              ha_gear.add_aliases(fqdns) unless ha_gear.app_dns
              # also add the app-dns in the frontend map
              ha_gear.frontend_reconnect(true) unless ha_gear.app_dns
            end
          end
   
          # check to see if any of the app aliases have SSL certificates
          if app.aliases.select {|app_alias| app_alias.has_private_ssl_certificate}.present?
            # get the app_dns gear
            dns_haproxy_gear = haproxy_gears.select {|g| g.app_dns}.first
            # fetch the cert information for all aliases for this app from the HAProxy gear
            ssl_certs = dns_haproxy_gear.get_all_ssl_certs()
            Application.run_in_application_lock(app) do
              ssl_certs.each do |cert_info|
                haproxy_gears.each do |ha_gear|
                  # the app_dns gear already has the ssl cert information, so skip it
                  ha_gear.add_ssl_cert(cert_info[0], cert_info[1], cert_info[2]) unless ha_gear.app_dns
                end
              end
            end
          end
        end
      end
    end
    puts "Done."
    puts "Sent alias and SSL cert info for #{app_count} applications."
  end
end

###############################################################################
# The 2.0.41 migration code is taken from li repo, stage branch (will be 
# stage-2.0.41),
# rhc-broker/script/rhc-admin-migrate-datastore;
#
# * Wrapped the script in a module.

module Migrate_2_0_41
  VERSIONS = {
    :compatible => false,
    :"non-compatible" => false,
    :prerelease => false,
    :postrelease => true,
    :run_parallel => []
  }

  def self.migrate(type)
    case type
    when :prerelease
    when :postrelease
      update_ld_library_paths
    when :"non-compatible"
    when :compatible
    end
  end

  def self.update_ld_library_paths
    cart_filter = {
      "component_instances.component_name" => ['mysql-5.5', 'postgresql-9.2']
    }
    app_ids = Application.where({"scalable" => true}).in(cart_filter).only('_id').map { |a|
      a._id
    }
    puts "Executing execution hooks for #{app_ids.size} applications..."
    app_count = 0
    app_ids.each { |app_id|
      begin
        Application.find(app_id).execute_connections
        app_count += 1
      rescue => e
        puts "Failed to execute_connections for #{app_id} (ERR: #{e.message})"
      end
    }
    puts "Done."
    puts "Updated LD_LIBRARY_PATH for #{app_count} applications."
  end
end

###############################################################################
# The 2.0.42 migration code is taken from li repo, stage branch (will be 
# stage-2.0.42),
# rhc-broker/script/rhc-admin-migrate-datastore;
#
# * Wrapped the script in a module.

module Migrate_2_0_42
  VERSIONS = {
    :compatible => false,
    :"non-compatible" => true,
    :prerelease => false,
    :postrelease => true,
    :run_parallel => []
  }

  def self.migrate(type)
    puts "Starting migration: #{type}"
    case type
    when :prerelease
    when :postrelease
    when :"non-compatible"
      migrate_cloud_users
    when :compatible
    end
    puts "\nMigration complete"
  end

  def self.migrate_cloud_users
    # Drop existing index on 'pending_ops' field
    db["cloud_users"].drop_index("pending_ops.created_at_1") rescue nil

    # Remove 'pending_ops' and add 'pending_op_groups' to cloud_users records
    query = { "pending_ops.0" => { "$exists" => false }, "pending_op_groups" => { "$exists" => false } }
    updates = {"$unset" => {"pending_ops" => ""}, "$set" => {"pending_op_groups" => []}}
    db["cloud_users"].update(query, updates, { :multi => true })

    # Migration validation
    num_users_with_pending_ops = db["cloud_users"].find({"pending_ops.0" => { "$exists" => true }}).count
    if num_users_with_pending_ops != 0
      puts "Found #{num_users_with_pending_ops} users with pending ops. Please run 'oo-admin-clear-pending-ops -t 0' and retry the operation."
      exit 1
    end

    num_users_without_pending_op_groups = db["cloud_users"].find({"pending_op_groups" => { "$exists" => false }}).count
    if num_users_without_pending_op_groups != 0
      puts "Found #{num_users_without_pending_op_groups} users with-out 'pending_op_groups' field."
      puts "Migration failed, retry the operation and if the error persists then investigate the issue."
      exit 2
    end
    puts "Cloud users migration done!"
  end
end

###############################################################################
# Migration core code
#

require 'getoptlong'

def db
  $db ||= OpenShift::DataStore.db(:primary)
end

def p_usage
  puts <<USAGE

Usage: #{$0}

  --compatible                         Run the backwards-compatible portion of the migration (can be run after the system is upgraded with the brokers running)
  --prerelease                         Run the pre-release portion of the migration (can be run at any time and is re-entrant)
  --non-compatible                     Run the non-backwards compatible portion of the migration (must be run with the brokers shut down)
  --postrelease                        Run the post-release portion of the migration (can be run with brokers online, but node migration should have completed successfully)
  --help                               Show usage info
USAGE
  exit 255
end

begin
  opts = GetoptLong.new(
    ["--compatible", "-c", GetoptLong::NO_ARGUMENT],
    ["--non-compatible", "-n", GetoptLong::NO_ARGUMENT],
    ["--prerelease", "-p", GetoptLong::NO_ARGUMENT],
    ["--postrelease", "-o", GetoptLong::NO_ARGUMENT],
    ["--verbose", "-V", GetoptLong::NO_ARGUMENT],
    ["--help", "-h", GetoptLong::NO_ARGUMENT]
  )
  opt = {}
  opts.each do |o, a|
    opt[o[2..-1]] = a.to_s
  end
rescue Exception => e
  p_usage
end

if opt['help']
  p_usage
end

unless opt['compatible'] || opt['non-compatible'] || opt['prerelease'] || opt['postrelease']
  puts "compatible or non-compatible or prerelease or postrelease is required!"
  p_usage
end

if [opt['compatible'],opt['non-compatible'],opt['prerelease'],opt['postrelease']].compact.count > 2
  puts "compatible, non-compatible, prerelease and postrelease are mutually exclusive."
  p_usage
end

type = ((opt['compatible'] and :compatible) or (opt['non-compatible'] and :"non-compatible") or (opt['prerelease'] and :prerelease) or (opt['postrelease'] and :postrelease))

$:.unshift('/var/www/openshift/broker')
require 'config/environment'

migrate(type)

puts "Done!"
