Migration for moving to a single shared container for all users
This commit is contained in:
		
							parent
							
								
									c79b86bff5
								
							
						
					
					
						commit
						22ce52d00c
					
				
							
								
								
									
										180
									
								
								migrate_to_single_container.rb
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										180
									
								
								migrate_to_single_container.rb
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,180 @@
 | 
			
		||||
#!/usr/bin/env ruby
 | 
			
		||||
 | 
			
		||||
require "rubygems"
 | 
			
		||||
require "bundler/setup"
 | 
			
		||||
require "rest_client"
 | 
			
		||||
require "redis"
 | 
			
		||||
require "yaml"
 | 
			
		||||
require "logger"
 | 
			
		||||
require "json"
 | 
			
		||||
require "active_support/core_ext/hash"
 | 
			
		||||
 | 
			
		||||
class Migrator
 | 
			
		||||
 | 
			
		||||
  attr_accessor :username, :base_url, :swift_host, :swift_token,
 | 
			
		||||
                :environment, :dry_run, :settings, :logger
 | 
			
		||||
 | 
			
		||||
  def initialize(username)
 | 
			
		||||
    @username = username
 | 
			
		||||
 | 
			
		||||
    @environment = ENV["ENVIRONMENT"] || "staging"
 | 
			
		||||
    @settings = YAML.load(File.read('config.yml'))[@environment]
 | 
			
		||||
 | 
			
		||||
    @swift_host = @settings["swift"]["host"]
 | 
			
		||||
    @swift_token = File.read("tmp/swift_token.txt").strip
 | 
			
		||||
 | 
			
		||||
    @dry_run = ENV["DRYRUN"] || false # disables writing anything when true
 | 
			
		||||
 | 
			
		||||
    @logger = Logger.new("log/migrate_to_single_container.log")
 | 
			
		||||
    log_level = ENV["LOGLEVEL"] || "INFO"
 | 
			
		||||
    logger.level = Kernel.const_get "Logger::#{log_level}"
 | 
			
		||||
    logger.progname = username
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def migrate
 | 
			
		||||
    logger.info "Starting migration for '#{username}'"
 | 
			
		||||
    set_container_migration_state("in_progress")
 | 
			
		||||
    begin
 | 
			
		||||
      work_on_dir("", "")
 | 
			
		||||
    rescue Exception => ex
 | 
			
		||||
      logger.error "Error migrating documents for '#{username}': #{ex}"
 | 
			
		||||
      set_container_migration_state("not_started")
 | 
			
		||||
      # write username to file for later reference
 | 
			
		||||
      File.open('log/failed_migration.log', 'a') { |f| f.puts username }
 | 
			
		||||
      exit 1
 | 
			
		||||
    end
 | 
			
		||||
    delete_container_migration_state
 | 
			
		||||
    File.open('log/finished_migration.log', 'a') { |f| f.puts username }
 | 
			
		||||
    logger.info "Finished migration for '#{username}'"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def is_dir?(name)
 | 
			
		||||
    name[-1] == "/"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_container_migration_state(type)
 | 
			
		||||
    redis.set("rs:container_migration:#{username}", type) unless dry_run
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def delete_container_migration_state
 | 
			
		||||
    redis.del("rs:container_migration:#{username}") unless dry_run
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def work_on_dir(directory, parent_directory)
 | 
			
		||||
    logger.debug "Retrieving listing for '#{parent_directory}#{directory}'"
 | 
			
		||||
 | 
			
		||||
    listing = get_directory_listing_from_swift("#{parent_directory}#{directory}")
 | 
			
		||||
 | 
			
		||||
    if listing
 | 
			
		||||
      listing.split("\n").each do |item|
 | 
			
		||||
        if is_dir? item
 | 
			
		||||
          # get dir listing and repeat
 | 
			
		||||
          work_on_dir(item, "#{parent_directory}")
 | 
			
		||||
        else
 | 
			
		||||
          copy_document("#{parent_directory}", item)
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def copy_document(directory, document)
 | 
			
		||||
    old_document_url = "#{url_for_directory(@username, directory)}/#{escape(document)}"
 | 
			
		||||
    new_document_url = "#{new_url_for_directory(@username, directory)}/#{escape(document)}"
 | 
			
		||||
 | 
			
		||||
    logger.debug "Copying document from #{old_document_url} to #{new_document_url}"
 | 
			
		||||
 | 
			
		||||
    response = do_get_request(old_document_url)
 | 
			
		||||
 | 
			
		||||
    unless dry_run
 | 
			
		||||
      do_put_request(new_document_url, response.body, response.headers[:content_type])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redis
 | 
			
		||||
    @redis ||= Redis.new(@settings["redis"].symbolize_keys)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def get_directory_listing_from_swift(directory)
 | 
			
		||||
    is_root_listing = directory.empty?
 | 
			
		||||
 | 
			
		||||
    get_response = nil
 | 
			
		||||
 | 
			
		||||
    do_head_request("#{url_for_directory(@username, directory)}") do |response|
 | 
			
		||||
      return "" if response.code == 404
 | 
			
		||||
 | 
			
		||||
      if is_root_listing
 | 
			
		||||
        get_response = do_get_request("#{container_url_for(@username)}/?path=")
 | 
			
		||||
      else
 | 
			
		||||
        get_response = do_get_request("#{container_url_for(@username)}/?path=#{escape(directory)}")
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    get_response.body
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_head_request(url, &block)
 | 
			
		||||
    RestClient.head(url, default_headers, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_get_request(url, &block)
 | 
			
		||||
    RestClient.get(url, default_headers, &block)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def do_put_request(url, data, content_type)
 | 
			
		||||
    RestClient.put(url, data, default_headers.merge({content_type: content_type}))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def default_headers
 | 
			
		||||
    {"x-auth-token" => @swift_token}
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def url_for_directory(user, directory)
 | 
			
		||||
    if directory.empty?
 | 
			
		||||
      container_url_for(user)
 | 
			
		||||
    else
 | 
			
		||||
      "#{container_url_for(user)}/#{escape(directory)}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def container_url_for(user)
 | 
			
		||||
    "#{base_url}/#{container_for(user)}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def new_container_url_for(user)
 | 
			
		||||
    "#{base_url}/rs:documents:#{environment.to_s.downcase}/#{user}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def new_url_for_directory(user, directory)
 | 
			
		||||
    if directory.empty?
 | 
			
		||||
      new_container_url_for(user)
 | 
			
		||||
    else
 | 
			
		||||
      "#{new_container_url_for(user)}/#{escape(directory)}"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def base_url
 | 
			
		||||
    @base_url ||= @swift_host
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def container_for(user)
 | 
			
		||||
    "rs:#{environment.to_s.chars.first}:#{user}"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def escape(url)
 | 
			
		||||
    # We want spaces to turn into %20 and slashes to stay slashes
 | 
			
		||||
    CGI::escape(url).gsub('+', '%20').gsub('%2F', '/')
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
username = ARGV[0]
 | 
			
		||||
 | 
			
		||||
unless username
 | 
			
		||||
  puts "No username given."
 | 
			
		||||
  puts "Usage:"
 | 
			
		||||
  puts "ENVIRONMENT=staging ./migrate_to_single_container.rb <username>"
 | 
			
		||||
  exit 1
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
migrator = Migrator.new username
 | 
			
		||||
migrator.migrate
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user