require 'insxsync' require 'find' require 'highline/import' require 'tempfile' class SyncPointRestore < ErrorHandlingIface def self.ask_missing_db_action answer = '' options = '[I/e/d]' d = 'i' until %w[i e d].include? answer answer = ask("[I]gnore the error, [e]dit the file, or [d]elete it? #{options} ") { |q| q.limit = 1; q.case = :downcase } answer = d if answer.length == 0 end case answer when 'i' return :ignore when 'e' return :edit when 'd' return :delete end end def self.update_configs(config_dir) FileUtils.rm_rf("#{config_dir}.bak") if File.exists?("#{config_dir}.bak") FileUtils.move(config_dir, "#{config_dir}.bak") Dir.mkdir(config_dir) FileUtils.cp_r(Dir[File.join("#{config_dir}.bak", '*')], config_dir) abbrvs = {'ian' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'mai' => 5, 'iunie' => 6, 'iulie' => 7, 'aug' => 8, 'sept' => 9, 'oct' => 10, 'noem' => 11, 'dec' => 12} reverse_abbrvs = abbrvs.invert dbs = {} temp = `mysql -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") temp.each do |db| next unless db =~ /(.*?)(3[01]|[012]\d)(ian|feb|mar|apr|mai|iunie|iulie|aug|sept|oct|noem|dec)/ results = db.scan(/(.*?)(3[01]|[012]\d)(ian|feb|mar|apr|mai|iunie|iulie|aug|sept|oct|noem|dec)/).flatten name = results[0] day = results[1] month = results[2].downcase dbs[name] = {} if not dbs.has_key?(name) dbs[name][abbrvs[month]] = [] if not dbs[name].has_key?(abbrvs[month]) dbs[name][abbrvs[month]].push(Integer(day)) end Find.find(config_dir) do |file| next if File.directory?(file) filename = file.scan(/#{config_dir}\/?(.*)/).flatten[0] next if filename == 'config.ini' text = File.read(file).gsub("\"", "'") text.gsub!(/database.params.hostname(\s*)=(\s*)'[^']*'/m, "database.params.hostname\\1=\\2'85.204.164.82'") text.gsub!(/database.params.username(\s*)=(\s*)'[^']*'/m, "database.params.username\\1=\\2'root'") text.gsub!(/database.params.password(\s*)=(\s*)'[^']*'/m, "database.params.password\\1=\\2'3dba6b67837565f146698075d5cd077fc805668c42defbf4e9b13db2eb2163ffWQXcbdGa5kLk4Kte70T66SAR7n7A13WuDsTV8VZuxwE='") text.gsub!(/BucketName(\s*)=(\s*)'[^']*'/m, "BucketName\\1=\\2'my1outsourcing2-bucket'") db_name, db_suffix = text.scan(/database.params.database\s*=\s*'([^']*?)(db|3[01][^']*|[0-2]\d[^']*)?'/).flatten if dbs.has_key?(db_name) latest_month = reverse_abbrvs[dbs[db_name].keys.max] latest_day = dbs[db_name][dbs[db_name].keys.max].max text.gsub!(/database.params.database(\s*)=(\s*)'[^']*'/m, "database.params.database\\1=\\2'#{db_name}#{latest_day}#{latest_month}'") else puts "Error updating subdomain config file: #{file}" puts "Subdomain config file uses the database '#{db_name}#{db_suffix}' but no equivalent database exists on MySQL host." case ask_missing_db_action() when :edit tmpfile = Tempfile.new('insxsync') begin tmpfile.write(text) editor = which("nano", "vi", "emacs") if editor.not_nil? system("#{editor} #{tmpfile.path}") tmpfile.rewind temp_text = tmpfile.read if temp_text == text $stderr.puts "File not edited. Ignoring error and continuing update..." next end tmpfile.rewind text = temp_text else $stderr.puts "Unable to find a valid editor (checked for vi, nano, emacs). Ignoring error and continuing update..." next end ensure tmpfile.close tmpfile.unlink end when :delete File.delete(file) next end end File.write(file, text) end end def self.restore_configs(sync_point_dir, dest_dir) failValidation if (!sync_point_dir.is_a?(String)) or (!dest_dir.is_a?(String)) FileUtils.rm_rf("#{dest_dir}.bak") if File.exists?("#{dest_dir}.bak") FileUtils.move(dest_dir, "#{dest_dir}.bak") Dir.mkdir(dest_dir) if File.exists?(File.join("#{dest_dir}.bak", 'config.ini')) FileUtils.copy(File.join("#{dest_dir}.bak", 'config.ini'), File.join(dest_dir, 'config.ini')) end FileUtils.cp_r(Dir[File.join(sync_point_dir, 'configs', '*')], dest_dir) abbrvs = {'ian' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'mai' => 5, 'iunie' => 6, 'iulie' => 7, 'aug' => 8, 'sept' => 9, 'oct' => 10, 'noem' => 11, 'dec' => 12} reverse_abbrvs = abbrvs.invert dbs = {} temp = `mysql -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") temp.each do |db| next unless db =~ /(.*?)(3[01]|[012]\d)(ian|feb|mar|apr|mai|iunie|iulie|aug|sept|oct|noem|dec)/ results = db.scan(/(.*?)(3[01]|[012]\d)(ian|feb|mar|apr|mai|iunie|iulie|aug|sept|oct|noem|dec)/).flatten name = results[0] day = results[1] month = results[2].downcase dbs[name] = {} if not dbs.has_key?(name) dbs[name][abbrvs[month]] = [] if not dbs[name].has_key?(abbrvs[month]) dbs[name][abbrvs[month]].push(Integer(day)) end Find.find(dest_dir) do |file| next unless File.file?(file) filename = file.scan(/#{dest_dir}\/?(.*)/).flatten[0] next if filename == 'config.ini' text = File.read(file).gsub("\"", "'") text.gsub!(/database.params.hostname(\s*)=(\s*)''/m, "database.params.hostname\\1=\\2'85.204.164.82'") text.gsub!(/database.params.username(\s*)=(\s*)''/m, "database.params.username\\1=\\2'root'") text.gsub!(/database.params.password(\s*)=(\s*)''/m, "database.params.password\\1=\\2'3dba6b67837565f146698075d5cd077fc805668c42defbf4e9b13db2eb2163ffWQXcbdGa5kLk4Kte70T66SAR7n7A13WuDsTV8VZuxwE='") text.gsub!(/BucketName(\s*)=(\s*)''/m, "BucketName\\1=\\2'my1outsourcing2-bucket'") db_name, db_suffix = text.scan(/database.params.database\s*=\s*'([^']*?)(db)?'/).flatten if dbs.has_key?(db_name) latest_month = reverse_abbrvs[dbs[db_name].keys.max] latest_day = dbs[db_name][dbs[db_name].keys.max].max text.gsub!(/database.params.database(\s*)=(\s*)'[^']*'/m, "database.params.database\\1=\\2'#{db_name}#{latest_day}#{latest_month}'") else puts "Error Synchronizing subdomain config file: #{file}" puts "Subdomain config file uses the database '#{db_name}#{db_suffix}' but no equivalent database exists on MySQL host." case ask_missing_db_action() when :edit tmpfile = Tempfile.new('insxsync') begin tmpfile.write(text) editor = which("nano", "vi", "emacs") if editor.not_nil? system("#{editor} #{tmpfile.path}") tmpfile.rewind temp_text = tmpfile.read if temp_text == text $stderr.puts "File not edited. Ignoring error and continuing synchronization..." next end tmpfile.rewind text = temp_text else $stderr.puts "Unable to find a valid editor (checked for vi, nano, emacs). Ignoring error and continuing synchronization..." next end ensure tmpfile.close tmpfile.unlink end when :delete File.delete(file) next end end File.write(file, text) end end def self.restore_data(sync_point_dir, time) abbrvs = {'ian' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4, 'mai' => 5, 'iunie' => 6, 'iulie' => 7, 'aug' => 8, 'sept' => 9, 'oct' => 10, 'noem' => 11, 'dec' => 12} reverse_abbrvs = abbrvs.invert day = Time.at(time.to_i).strftime('%d') month = reverse_abbrvs[Time.at(time.to_i).strftime('%m').to_i] Find.find(File.join(sync_point_dir, 'database')) do |file| next if File.directory?(file) old_name = File.basename(file, '.sql') new_name = old_name.scan(/\A(.*?)(db)?\z/).flatten[0] + day + month tmpfile = File.open("#{file}.tmp", 'w') tmppath = tmpfile.path File.open(file, 'r').each_line do |line| line.gsub!(/ndbcluster/i, "innodb") line.gsub!(/#{old_name}/i, new_name) tmpfile.write(line) end tmpfile.close FileUtils.mv(tmpfile.path, file) end Find.find(File.join(sync_point_dir, 'database')) do |file| next if File.directory?(file) mysql = which("mysql") raise if mysql.nil? `#{mysql} -u #{$db_user} --password='#{$db_pass}' -h #{$db_host} -P#{$db_port} < #{file}` if $?.exitstatus != 0 puts "Error: Unknown error importing #{file}." if yesno("Would you like to revert the import of this file?", false) dump = File.open(file, 'r') db_name = nil until db_name.not_nil? line = dump.readline if line =~ /use\s*`([^']*?)`/i db_name = line.scan(/use\s*`([^']*)`/i).flatten[0] end end `mysql -u #{$db_user} --password='#{$db_pass}' -e 'drop schema \`#{db_name}\`' -h #{$db_host} -P#{$db_port}` if $?.exitstatus == 0 puts "Import reverted successfully. Continuing..." else puts "Unknown error reverting import. Continuing..." end end end dump = File.open(file, 'r') db_name = nil until db_name.not_nil? line = dump.readline if line =~ /use\s*`([^']*?)`/i db_name = line.scan(/use\s*`([^']*)`/i).flatten[0] end end begin dbh = Mysql.real_connect($db_host, $db_user, $db_pass, db_name, $db_port) password_update = dbh.real_query("UPDATE `User` SET `Password`='92a891f888e79d1c2e8b82663c0f37cc6d61466c508ec62b8132588afe354712b20bb75429aa20aa3ab7cfcc58836c734306b43efd368080a2250831bf7f363f'") email_update = dbh.real_query("UPDATE `ContactDetail` set `Email`='test@my1outsourcing.com'") rescue Mysql::Error => e if e.error =~ /Can't connect to MySQL server/ $stderr.puts "MySQL host at #{$db_host}:#{$db_port} did not respond. No actions performed. Exiting..." exit -1 elsif e.error =~ /Access denied for user/ $stderr.puts "MySQL access denied for user '#{$db_user}' (using password: #{$db_pass.nil? ? "NO" : "YES"}). No actions performed. Exiting..." exit -1 end puts e $stderr.puts "Some other mysql error during import." exit -1 ensure dbh.close if dbh end #`mysql -u #{$db_user} --password='#{$db_pass}' -b '#{db_name}' -e -h #{$db_host} -P#{$db_port}` #`mysql -u #{$db_user} --password='#{$db_pass}' -b '#{db_name}' -e "UPDATE \`ContactDetail\` set \`Email\`='test@my1outsourcing.com'" -h #{$db_host} -P#{$db_port}` end end def self.restore_data_uat(dir) Find.find(File.join(dir, 'database')) do |file| next if File.directory?(file) old_name = File.basename(file, '.sql') new_name = 'dev' + old_name tmpfile = File.open("#{file}.tmp", 'w') File.open(file, 'r').each_line do |line| line.gsub!(/#{old_name}/i, new_name) tmpfile.write(line) end tmpfile.close FileUtils.mv(tmpfile.path, file) end dbs = `#{which('mysql')} -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") dbs.select! do |db| case db when 'mysql' false when 'information_schema' false when 'performance_schema' false when 'ndbinfo' false when 'test' false else true end end recovery_dumps = [] failed = false Find.find(File.join(dir, 'database')) do |file| next if File.directory?(file) mysql = which("mysql") raise if mysql.nil? old_name = File.basename(file, '.sql') new_name = 'dev' + old_name has_backup = false temp_dump = nil if dbs.include?(new_name) temp_dump = Dir::Tmpname.create([new_name, '.sql'], nil) {} print "Taking recovery dump for '#{new_name}'...\t\t" `#{which('mysqldump')} -u #{$db_user} --password='#{$db_pass}' -h #{$db_host} -P#{$db_port} --add-drop-database --databases #{new_name} > #{temp_dump}` if $?.exitstatus == 0 puts "Done." has_backup = true recovery_dumps.push([temp_dump, new_name]) else puts "ERROR!\nUnknown error occured during dump. No recover dump for '#{new_name}'. Continuing..." File.delete(temp_dump) if File.exists?(temp_dump) temp_dump = nil end if has_backup print "Dropping existing schema for '#{new_name}'...\t\t" `mysql -u #{$db_user} --password='#{$db_pass}' -e 'DROP SCHEMA \`#{new_name}\`' -h #{$db_host} -P#{$db_port}` puts "Done." else if yesno("WARNING: No recovery dump created for '#{new_name}'. In the event of an error, '#{new_name}' cannot be reverted and will be dropped. Do you wish to abort the synchronization?", false) failed = true break end next if yesno("Synchronization continuing. Do you wish to skip the synchronization of '#{new_name}'?", true) print "Dropping existing schema for '#{new_name}'...\t\t" `mysql -u #{$db_user} --password='#{$db_pass}' -e 'DROP SCHEMA \`#{new_name}\`' -h #{$db_host} -P#{$db_port}` puts "Done." end end print "Importing schema for '#{new_name}'...\t\t" `#{mysql} -u #{$db_user} --password='#{$db_pass}' -h #{$db_host} -P#{$db_port} < #{file}` puts "Done." if $?.exitstatus != 0 if has_backup puts "Error: Unknown error importing #{new_name}." if yesno("Would you like to revert the import of this databse?", false) new_dbs = `#{which('mysql')} -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") if new_dbs.include?(new_name) print "Dropping schema for incomplete import of '#{new_name}'...\t\t" `mysql -u #{$db_user} --password='#{$db_pass}' -e 'DROP SCHEMA \`#{new_name}\`' -h #{$db_host} -P#{$db_port}` puts "Done." end print "Imporitng recovery dump for '#{new_name}'...\t\t" `#{mysql} -u #{$db_user} --password='#{$db_pass}' -h #{$db_host} -P#{$db_port} < #{temp_dump}` `mysql -u #{$db_user} --password='#{$db_pass}' -e "UPDATE \`#{new_name}\`.\`User\` SET \`Password\` = '92a891f888e79d1c2e8b82663c0f37cc6d61466c508ec62b8132588afe354712b20bb75429aa20aa3ab7cfcc58836c734306b43efd368080a2250831bf7f363f'" -h #{$db_host} -P#{$db_port}` `mysql -u #{$db_user} --password='#{$db_pass}' -e "UPDATE \`#{new_name}\`.\`ContactDetail\` set \`Email\` = 'test@my1outsourcing.com'" -h #{$db_host} -P#{$db_port}` puts "Done." end unless yesno("Would you like to abort the synchronization?", false) failed = true break end else puts "Error: Unknown error importing #{new_name}." new_dbs = `#{which('mysql')} -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") if new_dbs.include?(new_name) print "Dropping schema for incomplete import of '#{new_name}'...\t\t" `mysql -u #{$db_user} --password='#{$db_pass}' -e 'DROP SCHEMA \`#{new_name}\`' -h #{$db_host} -P#{$db_port}` puts "Done." end unless yesno("Would you like to abort the synchronization?", false) failed = true break end end end end if failed and yesno("Synchronization aborted! Would you like to revert all changes (all recovery dumps will be restored)?") new_dbs = `#{which('mysql')} -u #{$db_user} --password='#{$db_pass}' -B -N -e 'show databases' -h #{$db_host} -P#{$db_port}`.split("\n") recovery_dumps.each do |dump| if new_dbs.include?(dump[1]) print "Dropping schema for import imported database '#{dump[1]}'...\t\t" `mysql -u #{$db_user} --password='#{$db_pass}' -e 'DROP SCHEMA \`#{dump[1]}\`' -h #{$db_host} -P#{$db_port}` puts "Done." end print "Imporitng recovery dump for '#{dump[1]}'...\t\t" `#{mysql} -u #{$db_user} --password='#{$db_pass}' -h #{$db_host} -P#{$db_port} < #{dump[0]}` puts "Done." end end print "Deleting recovery dumps...\t\t" recovery_dumps.each do |dump| File.delete(dump[0]) end done "Done." end end