248 lines
15 KiB
Ruby
248 lines
15 KiB
Ruby
require 'net/ssh'
|
|
require 'pathname'
|
|
namespace :create_site do
|
|
desc "Copy Site from another site"
|
|
task :copy_site,[:ip, :server_port,:user,:password,:site_name,:domain_name,:port,:db_name,:path,:site_construct_id,:template_site_construct_id,:only_copy_installed_module] => :environment do |task,args|
|
|
@password = args.password
|
|
template_site = SiteConstruct.find(args.template_site_construct_id)
|
|
if args.site_construct_id.blank?
|
|
@site_construct = SiteConstruct.new
|
|
@site_construct.server_type = (SiteServer.where(:ip=>args.ip).first.server_name rescue args.ip)
|
|
@site_construct.site_name = args.site_name
|
|
@site_construct.domain_name = args.domain_name
|
|
@site_construct.db_name = args.db_name.gsub(" ","")
|
|
@site_construct.port = args.port
|
|
@site_construct.path = args.path
|
|
@site_construct.school_name = args.site_name.split(/[-_]/)
|
|
@site_construct.user_id = User.first.id.to_s
|
|
@site_construct.save
|
|
else
|
|
@site_construct = SiteConstruct.find(args.site_construct_id)
|
|
end
|
|
begin
|
|
org_creating = (@site_construct.status == "creating")
|
|
@site_construct.update(:status=>"creating")
|
|
@site_construct.update!(:infos=>[])
|
|
begin
|
|
Net::SSH.start(args.ip , args.user , { password: @password, port: args.server_port}) do |ssh|
|
|
end
|
|
rescue Net::SSH::HostKeyMismatch
|
|
system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{args.ip}")
|
|
rescue Errno::ENOTTY
|
|
system("ssh-add \"$HOME/.ssh/id_rsa\"")
|
|
end
|
|
Net::SSH.start(args.ip , args.user , { password: @password, port: args.server_port}) do |ssh|
|
|
update_infos("Setting nginx for #{args.site_name}")
|
|
nginx_setting_texts = @site_construct.generate_nginx_text
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"touch /etc/nginx/orbit_sites/#{@site_construct.get_site_name}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"x='#{nginx_setting_texts.gsub(/'{1,3}/,"\"\'\"")}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > /etc/nginx/orbit_sites/#{@site_construct.get_site_name}\"")
|
|
update_infos("Restarting nginx")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sudo -p 'sudo password:' service nginx restart")
|
|
update_infos("Finish restarting nginx")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"mkdir -p #{args.path}")
|
|
update_infos("Copying site's files for #{args.site_name}")
|
|
exec_ssh_command_for_copy(ssh,"sudo -p 'sudo password:' apt-get install -y rsync")
|
|
extra_exclude_path = ""
|
|
if args.only_copy_installed_module == true || args.only_copy_installed_module == "true"
|
|
extra_exclude_path = ",public/uploads/"
|
|
end
|
|
server = SiteServer.where(:server_name => template_site.server_type).first
|
|
ls_out = exec_ssh_command_for_copy(ssh, "if [ ! -d \"#{@site_construct.full_site_path}/app\" ]; then echo 'No such file or directory: #{@site_construct.full_site_path}/app'; fi", false).join("\n")
|
|
if ls_out.include?("No such file or directory") || org_creating
|
|
if @site_construct.server_type == template_site.server_type
|
|
exec_ssh_command_for_copy(ssh,"rsync -ar -e 'ssh -o \"StrictHostKeyChecking=no\" -p 22' --info=progress2 --no-inc-recursive --delete --exclude={tmp/cache/,tmp/unicorn.sock,tmp/pids/*#{extra_exclude_path}} #{template_site.path}/#{template_site.get_site_name}/ #{args.path}/#{@site_construct.get_site_name}/",true)
|
|
else
|
|
exec_ssh_command_for_copy(ssh,"sudo -p 'sudo password:' apt-get install -y sshpass")
|
|
outputs = exec_ssh_command_for_copy(ssh,"sshpass -p \"#{server.password}\" rsync -ar -e 'ssh -o \"StrictHostKeyChecking=no\" -p 22' --info=progress2 --no-inc-recursive --delete --exclude={tmp/cache/,tmp/unicorn.sock,tmp/pids/*#{extra_exclude_path}} #{server.account}@#{server.ip}:#{template_site.path}/#{template_site.get_site_name}/ #{args.path}/#{@site_construct.get_site_name}/",true)
|
|
if outputs.join("\n").include?("Host key verification failed")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{server.ip}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"ssh-keyscan -H #{server.ip} >> ~/.ssh/known_hosts")
|
|
exec_ssh_command_for_copy(ssh,"sshpass -p \"#{server.password}\" rsync -ar --info=progress2 --no-inc-recursive --delete --exclude={tmp/cache/,tmp/unicorn.sock,tmp/pids/*#{extra_exclude_path}} #{server.account}@#{server.ip}:#{template_site.path}/#{template_site.get_site_name}/ #{args.path}/#{@site_construct.get_site_name}/",true)
|
|
end
|
|
end
|
|
end
|
|
update_infos("Finish copying site's files for #{args.site_name}!")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{@site_construct.get_site_name} -R")
|
|
db_setting_text = ssh.exec!("cat #{args.path}/#{args.site_name}/config/mongoid.yml")
|
|
update_infos("Setting dbname to #{args.db_name}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sh -c \"echo '#{db_setting_text.gsub(/database: .+/,"database: "+args.db_name)}' > #{args.path}/#{@site_construct.get_site_name}/config/mongoid.yml\"",true)
|
|
unless args.only_copy_installed_module == true || args.only_copy_installed_module == "true"
|
|
update_infos("Copying db from #{template_site.db_name} to #{args.db_name}")
|
|
if @site_construct.server_type == template_site.server_type
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"mongodump -d #{template_site.db_name} -o #{args.path}/#{@site_construct.get_site_name}/dump_xxxx")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"mongorestore --drop -d #{args.db_name} #{args.path}/#{@site_construct.get_site_name}/dump_xxxx/#{template_site.db_name}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"rm -rf #{args.path}/#{@site_construct.get_site_name}/dump_xxxx")
|
|
else
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sshpass -p '#{server.password}' ssh #{server.account}@#{server.ip} 'mongodump -d #{template_site.db_name} -o #{template_site.path}/#{template_site.site_name}/dump_xxxx'")
|
|
exec_ssh_command_for_copy(ssh,"sshpass -p \"#{server.password}\" rsync -ar --info=progress2 --no-inc-recursive --delete #{server.account}@#{server.ip}:#{template_site.path}/#{template_site.get_site_name}/dump_xxxx/ #{args.path}/#{args.site_name}/dump_xxxx/")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"mongorestore --drop -d #{args.db_name} #{args.path}/#{@site_construct.get_site_name}/dump_xxxx/#{template_site.db_name}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"rm -rf #{args.path}/#{@site_construct.get_site_name}/dump_xxxx")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sshpass -p '#{server.password}' ssh #{server.account}@#{server.ip} 'rm -rf #{template_site.path}/#{template_site.get_site_name}/dump_xxxx'")
|
|
end
|
|
update_infos("Finish copying database!")
|
|
end
|
|
update_infos("Checking extensions!")
|
|
extensions = ["downloaded_extensions.rb","built_in_extensions.rb"]
|
|
extensions.each do |extension_file|
|
|
outputs = exec_ssh_command_by_sudo_for_copy(ssh,"cat #{args.path}/#{@site_construct.get_site_name}/#{extension_file}")
|
|
next if outputs.blank?
|
|
if !outputs.include?("No such file or directory")
|
|
read_lines = outputs.split("\n").map{|l| l.split('#').first}
|
|
include_path_lines = read_lines.select{|l| (l.include?("path") rescue false)}
|
|
include_path_lines.each do |line|
|
|
path = line.split(/[:>]/).last.gsub(/[\'\"]/,"").strip
|
|
absolute_path = (path[0] == "/") ? path : ("#{template_site.path}/#{template_site.get_site_name}/#{path}")
|
|
absolute_path = (absolute_path[-1] == "/") ? absolute_path : (absolute_path + "/")
|
|
if @site_construct.server_type == template_site.server_type
|
|
exec_ssh_command_for_copy(ssh,"rsync -ar --info=progress2 --no-inc-recursive --delete #{absolute_path} #{args.path}/#{args.site_name}/#{Pathname.new(absolute_path).basename}/")
|
|
else
|
|
server = SiteServer.where(:server_name => template_site.server_type).first
|
|
exec_ssh_command_for_copy(ssh,"sshpass -p \"#{server.password}\" rsync -ar --info=progress2 --no-inc-recursive --delete #{server.account}@#{server.ip}:#{absolute_path} #{args.path}/#{args.site_name}/#{Pathname.new(absolute_path).basename}/")
|
|
end
|
|
outputs = outputs.gsub(path,"#{args.path}/#{args.site_name}/#{Pathname.new(absolute_path).basename}/")
|
|
end
|
|
if include_path_lines.count != 0
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sh -c \"echo '#{outputs.gsub("\"","\\\"").gsub("'","\\\"")}' > #{args.path}/#{@site_construct.get_site_name}/#{extension_file}\"")
|
|
end
|
|
end
|
|
end
|
|
update_infos("Finish checking extensions!")
|
|
|
|
update_infos("Execing bundle install...")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nrm -f Gemfile.lock tmp/unicorn_rails.sock tmp/unicorn_roda.sock tmp/unicorn.sock\nbundle install'",true)
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nrm -f Gemfile.lock tmp/unicorn_rails.sock tmp/unicorn_roda.sock tmp/unicorn.sock\nbundle install'")
|
|
update_infos("Finish execing bundle install")
|
|
update_infos("Starting #{args.site_name} web server to development")
|
|
outputs = exec_ssh_command_by_sudo_for_copy(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nkill -s TERM `fuser tmp/unicorn.sock`\nsudo -p \"sudo password:\" kill -s TERM `sudo -p \"sudo password:\" fuser tmp/unicorn.sock`\nsudo -p \"sudo password:\" rm -f tmp/pids/unicorn.pid\nbundle exec unicorn_rails -c config/unicorn.rb -D -E development\n'")
|
|
if (outputs.include? "not writable" rescue false)
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{@site_construct.get_site_name} -R")
|
|
end
|
|
update_infos("Finish creating #{args.site_name}")
|
|
exec_ssh_command_by_sudo_for_copy(ssh,"chmod 777 #{args.path}/#{@site_construct.get_site_name} -R")
|
|
@site_construct.update(:status =>"finish")
|
|
puts "finish creating #{args.site_name} on #{args.ip}"
|
|
end
|
|
rescue =>e
|
|
@site_construct.update(:status =>"error",:infos=>@site_construct.infos.push("#{e}"))
|
|
end
|
|
end
|
|
def exec_ssh_command_by_sudo(session,command)
|
|
output = session.exec!("echo '#{@password}' | sudo -S #{command}")
|
|
# output = session.exec!("echo '#{@password}' | sudo -S -s #{command}")
|
|
if output.include?("sudo:") && output.include?("command not found")
|
|
output = session.exec!(command)
|
|
end
|
|
return output.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
|
|
end
|
|
def exec_ssh_command_for_copy(session,command,update_outputs=false)
|
|
outputs = []
|
|
if update_outputs
|
|
update_infos_for_exec("")
|
|
end
|
|
session.open_channel do |channel|
|
|
channel.request_pty do |channel, success|
|
|
channel.exec("LANG=en.UTF8 && #{command}") do |ch, success|
|
|
abort "could not execute command: #{command}" unless success
|
|
channel.on_data do |ch, data|
|
|
data_str = data.to_s
|
|
data_str.encode!("UTF-8", :invalid => :replace, :undef => :replace, :replace => '')
|
|
if data_str.include?("sudo password:") || data_str.include?("Password:")
|
|
channel.send_data "#{@password}\n"
|
|
else
|
|
print data_str unless @no_stdout
|
|
data_str.gsub!("\r\n", "\n")
|
|
rm_idx = data_str.index("\r")
|
|
if rm_idx.nil?
|
|
@remove_last_line = false
|
|
else
|
|
@remove_last_line = (outputs.count > 0 && data_str[0...rm_idx].exclude?("\n"))
|
|
end
|
|
data_str.gsub!(/.*\r/, '')
|
|
next if data_str.length == 0
|
|
if data_str.include?("\n") || outputs.empty?
|
|
output_lines = data_str.split("\n")
|
|
first_output = output_lines[0]
|
|
if first_output
|
|
if @remove_last_line
|
|
outputs = outputs[1..-1]
|
|
outputs = [] if outputs.nil?
|
|
end
|
|
if outputs.count != 0
|
|
outputs[-1] += first_output
|
|
else
|
|
outputs << first_output
|
|
end
|
|
end
|
|
new_arr = output_lines[1..-1]
|
|
new_arr = [] if new_arr.nil?
|
|
if data_str[-1] == "\n"
|
|
new_arr << ""
|
|
end
|
|
outputs += new_arr
|
|
if update_outputs
|
|
if first_output
|
|
update_infos_for_exec(first_output,true)
|
|
end
|
|
update_infos_for_exec(new_arr,false,true)
|
|
end
|
|
else
|
|
if @remove_last_line
|
|
outputs = outputs[1..-1]
|
|
outputs = [] if outputs.nil?
|
|
end
|
|
if outputs.count == 0
|
|
outputs.push(data_str)
|
|
else
|
|
outputs[-1] += (data_str rescue "")
|
|
end
|
|
if update_outputs
|
|
update_infos_for_exec(data_str,true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
session.loop
|
|
return outputs
|
|
end
|
|
def exec_ssh_command_by_sudo_for_copy(session,command,update=false)
|
|
outputs = exec_ssh_command_for_copy(session,command,update)
|
|
tmp = outputs.join("\n")
|
|
if outputs.join("\n").include?("Permission denied") || outputs.join("\n").include?("Operation not permitted")
|
|
outputs = exec_ssh_command_for_copy(session,"sudo -p 'sudo password:' #{command}",update)
|
|
tmp = outputs.join("\n")
|
|
end
|
|
return tmp
|
|
end
|
|
def update_infos_for_exec(info,update_last=false,update_array=false)
|
|
return if @site_construct.nil?
|
|
if update_last && !@site_construct.infos.empty?
|
|
if @remove_last_line
|
|
@site_construct.infos[-1] = info.to_s
|
|
else
|
|
@site_construct.infos[-1] += info.to_s
|
|
end
|
|
else
|
|
if @remove_last_line
|
|
@site_construct.infos = @site_construct.infos[0...-1]
|
|
end
|
|
if update_array
|
|
@site_construct.infos += info
|
|
else
|
|
@site_construct.infos.push(info.to_s)
|
|
end
|
|
end
|
|
@site_construct.save!
|
|
return @site_construct.infos
|
|
end
|
|
def update_infos(info)
|
|
puts info
|
|
@site_construct.infos = @site_construct.infos.push(info)
|
|
@site_construct.save!
|
|
return @site_construct.infos
|
|
end
|
|
end |