require 'net/ssh' require 'pathname' require 'json' namespace :create_site do desc "Change Site Cert" task :change_site_cert,[:id,:is_certbot] => :environment do |task,args| begin @site_construct = SiteConstruct.find(args.id) @site_cert = @site_construct.site_cert site_server = @site_construct.site_server @site_construct.update(:infos=>[],:status=>"changing") is_certbot = (args.is_certbot == "true") || (@site_cert.is_certbot rescue false) if !site_server.nil? && (!@site_cert.nil? || is_certbot) @password = site_server.password Net::SSH.start(site_server.ip , site_server.account , password: site_server.password) do |ssh| if is_certbot domain_name = @site_construct.domain_name if domain_name.present? certbot_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which certbot certbot-auto'",false,true).strip.split("\n")[0] if certbot_path.present? if @site_cert update_infos("Using certbot to change cert setting...") else update_infos("Using certbot to generate cert for #{domain_name}...") end redirect_to_https = @site_construct.redirect_to_https exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' #{certbot_path} --nginx -d #{domain_name} -n --#{redirect_to_https ? 'redirect' : 'no-redirect'}",true,false) nginx_file = @site_construct.nginx_file nginx_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{nginx_file}",false,true) crt_file_path = nginx_file_content.match(/ssl_certificate\s+(.*)/)[1].split(';').first rescue '' private_key_path = nginx_file_content.match(/ssl_certificate_key\s+(.*)/)[1].split(';').first rescue '' site_cert = @site_construct.site_cert if crt_file_path.present? && private_key_path.present? if site_cert.nil? site_cert = SiteCert.where(:source_paths=>[crt_file_path,private_key_path]).first site_cert = SiteCert.new if site_cert.nil? end if true #site_cert.source_paths.count == 0 site_cert["cert_file"] = File.basename(crt_file_path) cert_file_store_path = site_cert.cert_file.file.file crt_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{crt_file_path}",false).select{|s| s.present?}.join("\n").strip.split(/(\r\n|\n)/).select{|s| s.present?}.join("\n") FileUtils.mkdir_p(File.dirname(cert_file_store_path)) unless Dir.exist?(File.dirname(cert_file_store_path)) File.open(site_cert.cert_file.file.file,'w+'){|f| f.write(crt_file_content)} site_cert["private_key"] = File.basename(private_key_path) private_key_store_path = site_cert.private_key.file.file private_key_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{private_key_path}",false).select{|s| s.present?}.join("\n").strip.split(/(\r\n|\n)/).select{|s| s.present?}.join("\n") FileUtils.mkdir_p(File.dirname(private_key_store_path)) unless Dir.exist?(File.dirname(private_key_path)) File.open(site_cert.private_key.file.file,'w+'){|f| f.write(private_key_content)} site_cert.source_paths = [crt_file_path,private_key_path] site_cert.is_certbot = private_key_path.include?("letsencrypt") site_cert.save @site_construct.update(:site_cert=>site_cert) end all_ports = (@site_construct.port + ["443"]).uniq @site_construct.update(:port=> all_ports ) update_infos("Finish installing cert with certbot!") else update_infos("Certbot generate cert failed!") update_infos("Please check your domain dns setting(A record)!") @site_construct.update(:status=>"error") end else update_infos("Please install certbot first!") end else update_infos("Please set domain name first!") end else update_infos("Copying Cert to #{@site_construct.server_type}...") cert_file_content = [(@site_cert.cert_file.file.read.strip rescue ""),(@site_cert.ca_bundle.file.read.strip rescue "")].join("\n").strip private_key_content = @site_cert.private_key.file.read cert_file_store_path = @site_construct.cert_file_remote_store_path exec_ssh_command_by_sudo(ssh,"mkdir -p #{File.dirname(cert_file_store_path)}") exec_command_by_user(ssh,"x='#{cert_file_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{cert_file_store_path}\"") private_key_store_path = @site_construct.private_key_remote_store_path exec_ssh_command_by_sudo(ssh,"mkdir -p #{File.dirname(private_key_store_path)}") exec_command_by_user(ssh,"x='#{private_key_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{private_key_store_path}\"") update_infos("Finish copy.") update_infos("Setting Cert...") nginx_file_content = exec_command_by_user(ssh,"cat #{@site_construct.nginx_file}") all_ports = (@site_construct.port + ["443"]).uniq @site_construct.update(:port=> all_ports ) nginx_file_content = @site_construct.generate_nginx_text(nginx_file_content) cmd = "x='#{nginx_file_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{@site_construct.nginx_file}\"" exec_command_by_user(ssh,cmd) end exec_ssh_command_by_sudo(ssh,"service nginx restart") update_infos("Finish!") @site_construct.update(:status=>"finish") end else update_infos("Cert not found!") @site_construct.update(:status=>"error") end rescue => e puts [e,e.backtrace] update_infos(e.to_s) @site_construct.update(:status=>"error") end end def exec_command_by_user(session,command) output = session.exec!(command) return output[0...-1].gsub(/^\n[\n]+/,'') end def exec_ssh_command_by_sudo(session,command) output = session.exec!("echo '#{@password}' | sudo -S #{command}") if output.include?("sudo:") && output.include?("command not found") output = session.exec!(command) end return output end end