client_management/lib/tasks/create_site.rake

235 lines
11 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

require 'net/ssh'
require 'pathname'
require 'base64'
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
# === 新增:關鍵欄位為空時直接中止,避免路徑塌陷後對 "/" 執行 git clone / chown / chmod 777 -R ===
if args.site_name.blank? || args.path.blank? || args.db_name.blank?
error_msg = "create_site 中止site_name(#{args.site_name.inspect}) / path(#{args.path.inspect}) / db_name(#{args.db_name.inspect}) 不可為空白"
puts error_msg
if args.site_construct_id.present?
sc = SiteConstruct.find(args.site_construct_id) rescue nil
sc.update(:status => "error", :infos => (sc.infos + [error_msg])) if sc
end
next
end
# === 新增結束 ===
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 = Array(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
base64_config = Base64.strict_encode64(nginx_setting_texts)
nginx_path = "/etc/nginx/orbit_sites/#{@site_construct.get_site_name}"
write_nginx_cmd = "sh -c \"echo '#{base64_config}' | base64 --decode > #{nginx_path}\""
exec_ssh_command_by_sudo_for_create(ssh, write_nginx_cmd)
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