require 'net/ssh' require 'pathname' namespace :create_site do desc "Create Site Script" task :create_site,[:git_template_url,:git_extension_url,:git_url,:ip, :server_port,:user,:password,:site_name,:domain_name,:port,:db_name,:path,:site_construct_id] => :environment do |task,args| @password = args.password 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 @site_construct.update(:status=>"creating") @site_construct.update!(:infos=>[]) begin Net::SSH.start(args.ip , args.user , { password: args.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: args.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_create(ssh,"touch /etc/nginx/orbit_sites/#{@site_construct.get_site_name}") exec_ssh_command_by_sudo_for_create(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_create(ssh,"sudo -p 'sudo password:' service nginx restart") update_infos("Finish restarting nginx") exec_ssh_command_by_sudo_for_create(ssh,"mkdir -p #{args.path}") update_infos("Cloning orbit4-5 from #{args.git_url} to #{args.path}/#{args.site_name}") exec_ssh_command_by_sudo_for_create(ssh,"git clone #{args.git_url} #{args.path}/#{@site_construct.get_site_name}") exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule add #{args.git_template_url} app/templates/default-theme'") exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule add #{args.git_extension_url} modules'") exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && git submodule update --init --recursive'") ssh.exec!("bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name} && ln -s modules/* .'") exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R") exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{@site_construct.get_site_name.gsub(" ","\\ ")} -R") db_setting_text = ssh.exec!("cat #{args.path}/#{@site_construct.get_site_name}/config/mongoid.yml") update_infos("Setting dbname to #{@site_construct.db_name}") exec_ssh_command_by_sudo_for_create(ssh,"sh -c \"echo '#{db_setting_text.gsub("orbit_4_5",@site_construct.db_name)}' > #{args.path}/#{@site_construct.get_site_name}/config/mongoid.yml\"",true) rvm_path = ssh.exec!("which rvm").to_s.strip if rvm_path.blank? rvm_path = "/home/#{args.user}/.rvm/bin/rvm" end gemdir = ssh.exec!("#{rvm_path} gemdir").to_s if gemdir.include?("No such file or directory") ls = ssh.exec!("echo `ls /home`").to_s.split ls.each do |d| rvm_path = "/home/#{d}/.rvm/bin/rvm" gemdir = ssh.exec!("#{rvm_path} gemdir").to_s break if !gemdir.to_s.include?("No such file or directory") end if gemdir.include?("No such file or directory") rvm_path = "/usr/share/rvm/bin/rvm" gemdir = ssh.exec!("#{rvm_path} gemdir").to_s end end if gemdir.include?("No such file or directory") update_infos("Please connect your admin to install rvm on #{args.ip}") @site_construct.update(:status =>"error") else bundle_dir = gemdir.gsub("\n","") + '/bin/bundle' update_infos("Execing bundle install...") exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\nbundle install'",true) exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{@site_construct.get_site_name}\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_create(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" exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{@site_construct.get_site_name} -R") exec_ssh_command_by_sudo_for_create(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_create(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 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 update_thread_infos_for_exec(info,update_last=false) if update_last @thread.status["infos"][-1] += info else @thread.status["infos"] = @thread.status["infos"].push(info) end @thread.save! return @thread.status["infos"] end def exec_ssh_command_for_create(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_create(session,command,update=false) outputs = exec_ssh_command_for_create(session,command,update) tmp = outputs.join("\n") if tmp.include?("Permission denied") || tmp.include?("Operation not permitted") outputs = exec_ssh_command_for_create(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