Add certbot feature to install cert.

This commit is contained in:
BoHung Chiu 2021-08-11 16:16:14 +08:00
parent f44dbfa1a2
commit dbfd2e0677
13 changed files with 303 additions and 36 deletions

View File

@ -39,7 +39,7 @@ class Admin::SitePanelController < OrbitAdminController
domain_name_search_text = "" domain_name_search_text = ""
end end
@site_certs = SiteCert.all.where(:is_valid=>true,:domain_names=>/\A#{domain_name_search_text}/) @site_certs = SiteCert.all.where(:is_valid=>true,:domain_names=>/\A#{domain_name_search_text}/)
@site_certs = SiteCert.all # @site_certs = SiteCert.all
if site_construct if site_construct
@enable_cert_id = site_construct.site_cert_id @enable_cert_id = site_construct.site_cert_id
end end
@ -129,11 +129,21 @@ class Admin::SitePanelController < OrbitAdminController
render :json => thread.status render :json => thread.status
end end
elsif params[:type] == 'get_server_names' elsif params[:type] == 'get_server_names'
render :json => (SiteServer.all.map{|s| s.server_name rescue ""}.select{|n| !n.blank?} rescue []) render :json => (SiteServer.all.where(:active=>true).map{|s| s.server_name rescue ""}.select{|n| !n.blank?} rescue [])
else else
@site_server = SiteServer.find(params[:id]) @site_server = SiteServer.find(params[:id])
end end
end end
def install_certbot
extra_text = ""
if params[:server_name].present?
extra_text = "[#{params[:server_name].gsub(/[\(\)\[\]]/){|ff| "\\"+ff }}]"
end
Thread.new do
system("bundle exec rake create_site:install_certbot#{extra_text}")
end
render :json => {"success"=>true}
end
def create def create
server_ability = ServerAbility.first server_ability = ServerAbility.first
if server_ability.available if server_ability.available
@ -227,9 +237,13 @@ class Admin::SitePanelController < OrbitAdminController
elsif params[:type] == 'select_cert' elsif params[:type] == 'select_cert'
@site_construct = SiteConstruct.find(params[:id]) @site_construct = SiteConstruct.find(params[:id])
@site_construct.update(:redirect_to_https=>params[:redirect_to_https]) @site_construct.update(:redirect_to_https=>params[:redirect_to_https])
is_certbot = true
if params[:site_cert_id] != "certbot"
is_certbot = false
@site_construct.update(:site_cert_id=>BSON::ObjectId(params[:site_cert_id])) @site_construct.update(:site_cert_id=>BSON::ObjectId(params[:site_cert_id]))
end
Thread.new do Thread.new do
system("bundle exec rake create_site:change_site_cert[#{params[:id]}]") system("bundle exec rake create_site:change_site_cert[#{params[:id]},#{is_certbot}]")
end end
else else
Thread.new do Thread.new do

View File

@ -4,6 +4,7 @@ class SiteCert
mount_uploader :cert_file, AssetUploader #Public key mount_uploader :cert_file, AssetUploader #Public key
mount_uploader :ca_bundle, AssetUploader mount_uploader :ca_bundle, AssetUploader
mount_uploader :private_key, AssetUploader mount_uploader :private_key, AssetUploader
field :is_certbot, type: Boolean ,default: false
field :is_valid , type: Boolean ,default: false field :is_valid , type: Boolean ,default: false
field :domain_names , type: Array ,default: [] field :domain_names , type: Array ,default: []
field :source_paths , type: Array ,default: [] field :source_paths , type: Array ,default: []

View File

@ -11,6 +11,7 @@ class SiteServer
field :account , type: String ,default: '' field :account , type: String ,default: ''
field :password , type: String ,default: '' field :password , type: String ,default: ''
field :active , type: Boolean ,default: true field :active , type: Boolean ,default: true
field :has_certbot, type: Boolean , default: false
def domain_names def domain_names
if self.domain_name != '' if self.domain_name != ''
[self.domain_name] [self.domain_name]

View File

@ -1,9 +1,25 @@
<style>
.inactive-serv{
font-weight: bold;
color: red;
font-size: 1.5em;
vertical-align: middle;
padding-left: 0.2em;
}
.green_text{
color: green;
}
.red_text{
color: red;
}
</style>
<table class="table main-list default footable-loaded"> <table class="table main-list default footable-loaded">
<thead> <thead>
<tr> <tr>
<th>Sites amount</th> <th>Sites amount</th>
<th>Server name</th> <th>Server name</th>
<th>IP</th> <th>IP</th>
<th>Certbot</th>
<th>Action</th> <th>Action</th>
</tr> </tr>
</thead> </thead>
@ -19,8 +35,18 @@
Development: <%=SiteConstruct.where(:hidden.ne=> true,:server_type => site_server.server_name,:rails_env.in=>["development",nil],:status=>"finish").count %><br> Development: <%=SiteConstruct.where(:hidden.ne=> true,:server_type => site_server.server_name,:rails_env.in=>["development",nil],:status=>"finish").count %><br>
</p> </p>
</td> </td>
<td><%=site_server.server_name%></td> <td><%=site_server.server_name%><%= '<span class="inactive-serv" title="inactive">X</span>'.html_safe if !(site_server.active) %></td>
<td><%=site_server.ip%></td> <td><%=site_server.ip%></td>
<td>
<% if site_server.has_certbot%>
<span class="green_text"><%= t("client_management.alreay_install") %></span>
<% else %>
<span class="red_text"><%= t("client_management.not_install") %></span>
<% if site_server.active %>
<span><a class="btn btn-success install_certbot" title="Install certbot" data-name="<%=site_server.server_name%>">Install certbot</a></span>
<% end %>
<% end %>
</td>
<td> <td>
<a class="btn btn-primary" href = "<%= admin_site_panel_edit_server_info_path+"?id=#{site_server.id.to_s}" %>"><%=t(:edit)%></a> <a class="btn btn-primary" href = "<%= admin_site_panel_edit_server_info_path+"?id=#{site_server.id.to_s}" %>"><%=t(:edit)%></a>
<a class="btn btn-primary" href = "#" onclick="if(window.confirm('Do you really want to delete <%=site_server.server_name%>?')) { window.location.href = '<%= admin_site_panel_edit_server_info_path+"?id=#{site_server.id.to_s}&type=delete" %>';}"><%=t(:remove)%></a> <a class="btn btn-primary" href = "#" onclick="if(window.confirm('Do you really want to delete <%=site_server.server_name%>?')) { window.location.href = '<%= admin_site_panel_edit_server_info_path+"?id=#{site_server.id.to_s}&type=delete" %>';}"><%=t(:remove)%></a>
@ -95,6 +121,9 @@
var status_text = "not yet create"; var status_text = "not yet create";
else else
var status_text = status_relation[status]; var status_text = status_relation[status];
if(!status_text){
status_text = "<span style=\"color: skyblue;\">"+status+"</span>";
}
$("#info_texts").html(status_text+"<div style='clear:both;'></div>"+infos.join("<br>")); $("#info_texts").html(status_text+"<div style='clear:both;'></div>"+infos.join("<br>"));
msg_end.scrollIntoView(); msg_end.scrollIntoView();
timeout_id = window.setTimeout(see_infos(key),1000); timeout_id = window.setTimeout(see_infos(key),1000);
@ -156,5 +185,13 @@
show_infos_dialog(key); show_infos_dialog(key);
}) })
}); });
$(".install_certbot").off("click").on("click",function(){
var server_name = $(this).data("name");
if( server_name == undefined)
server_name = "";
$.post("<%=admin_site_panel_install_certbot_path%>",{"server_name":server_name}).done(function(){
show_infos_dialog("install_certbot");
})
})
}) })
</script> </script>

View File

@ -49,6 +49,14 @@
<label class="control-label muted"><%= t(:tags) %></label> <label class="control-label muted"><%= t(:tags) %></label>
<%= select_tags(f, @module_app) %> <%= select_tags(f, @module_app) %>
</div> </div>
<% unless @site_server.new_record? %>
<div class="control-group">
<label class="control-label muted"><%= t("client_management.active") %></label>
<div class="controls">
<%= f.check_box :active %>
</div>
</div>
<% end %>
<div class="control-group"> <div class="control-group">
<label class="control-label muted" for="server_name">Server name:</label> <label class="control-label muted" for="server_name">Server name:</label>
<div class="controls"> <div class="controls">

View File

@ -1,4 +1,32 @@
<% if @site_certs.count == 0 %> <% if @site_certs.count == 0 %>
<% site_server = @site_construct.site_server %>
<% if (site_server.has_certbot rescue false)%>
<div class="control-group">
<label style=" font-size: 1.2em; font-weight: bold; ">
<%= check_box_tag("redirect_to_https",1,(@site_construct.redirect_to_https rescue false)) %>
<%=t("client_management.redirect_to_https")%>
</label>
</div>
<table class="table table-bordered main-list default">
<thead>
<th></th>
<th><%=t('client_management.upload_date')%></th>
<th><%=t('client_management.start_date')%>/<%=t('client_management.end_date')%></th>
<th><%=t('client_management.domain_name')%></th>
</thead>
<tbody>
<tr>
<td><%=radio_button_tag("site_cert","certbot",false)%></td>
<td>Certbot</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<% else %>
<a href="<%=admin_site_panel_server_manager_path%>">Please install certbot first!</a>
<div style="clear: both;"></div>
<% end %>
<%= link_to t('client_management.upload_cert'),upload_cert_admin_site_panel_index_path, :target=>"_blank" %> <%= link_to t('client_management.upload_cert'),upload_cert_admin_site_panel_index_path, :target=>"_blank" %>
<% else %> <% else %>
<div class="control-group"> <div class="control-group">

View File

@ -7,6 +7,9 @@ en:
upload_cert: Upload Cert upload_cert: Upload Cert
cert_management: Cert Management cert_management: Cert Management
client_management: client_management:
alreay_install: Alreay install
not_install: Not install
active: Active
over_the_limit: Please Contact us (RulingCare) to add the limit of Site number. over_the_limit: Please Contact us (RulingCare) to add the limit of Site number.
redirect_to_https: Redirect to https redirect_to_https: Redirect to https
start_date: Start Date start_date: Start Date

View File

@ -7,6 +7,9 @@ zh_tw:
upload_cert: 上傳憑證 upload_cert: 上傳憑證
cert_management: 憑證管理 cert_management: 憑證管理
client_management: client_management:
alreay_install: 已安裝
not_install: 未安裝
active: 啟用
over_the_limit: 請您聯絡客服以增加可以新增的網站數量上限。 over_the_limit: 請您聯絡客服以增加可以新增的網站數量上限。
redirect_to_https: 跳轉到https redirect_to_https: 跳轉到https
start_date: 開始日期 start_date: 開始日期

View File

@ -48,6 +48,9 @@ Rails.application.routes.draw do
get "site_panel/server_manager" => "site_panel#server_manager" get "site_panel/server_manager" => "site_panel#server_manager"
get "site_panel/edit_server_info" => "site_panel#edit_server_info" get "site_panel/edit_server_info" => "site_panel#edit_server_info"
post "site_panel/edit_server_info" => "site_panel#edit_server_info" post "site_panel/edit_server_info" => "site_panel#edit_server_info"
get "site_panel/install_certbot" => "site_panel#install_certbot"
post "site_panel/install_certbot" => "site_panel#install_certbot"
post "site_panel/update_cert_setting" => "site_panel#update_cert_setting" post "site_panel/update_cert_setting" => "site_panel#update_cert_setting"
resources :site_panel do resources :site_panel do
delete 'destroy_cert' delete 'destroy_cert'

View File

@ -3,15 +3,69 @@ require 'pathname'
require 'json' require 'json'
namespace :create_site do namespace :create_site do
desc "Change Site Cert" desc "Change Site Cert"
task :change_site_cert,[:id] => :environment do |task,args| task :change_site_cert,[:id,:is_certbot] => :environment do |task,args|
begin begin
@site_construct = SiteConstruct.find(args.id) @site_construct = SiteConstruct.find(args.id)
@site_cert = @site_construct.site_cert @site_cert = @site_construct.site_cert
site_server = @site_construct.site_server site_server = @site_construct.site_server
@site_construct.update(:infos=>[],:status=>"changing") @site_construct.update(:infos=>[],:status=>"changing")
if !site_server.nil? && !@site_cert.nil? 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 @password = site_server.password
Net::SSH.start(site_server.ip , site_server.account , password: site_server.password) do |ssh| 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'",false,true).strip
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}...") 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 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 private_key_content = @site_cert.private_key.file.read
@ -29,7 +83,7 @@ namespace :create_site do
nginx_file_content = @site_construct.generate_nginx_text(nginx_file_content) 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}\"" cmd = "x='#{nginx_file_content}'; echo '#{@password}' | sudo -S sh -c \"echo '$x' > #{@site_construct.nginx_file}\""
exec_command_by_user(ssh,cmd) exec_command_by_user(ssh,cmd)
puts nginx_file_content end
exec_ssh_command_by_sudo(ssh,"service nginx restart") exec_ssh_command_by_sudo(ssh,"service nginx restart")
update_infos("Finish!") update_infos("Finish!")
@site_construct.update(:status=>"finish") @site_construct.update(:status=>"finish")

View File

@ -8,11 +8,12 @@ namespace :create_site do
Multithread.where(:key=>'detect_sites').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")} Multithread.where(:key=>'detect_sites').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")}
Multithread.where(:key=>'detect_sites').destroy Multithread.where(:key=>'detect_sites').destroy
@thread = Multithread.where(:key=>'detect_sites').first @thread = Multithread.where(:key=>'detect_sites').first
@type = "exec_all"
if @thread.nil? if @thread.nil?
begin begin
@thread = Multithread.create(:key=>'detect_sites',:status=>{"infos"=>[],"status"=>"detecting"}) @thread = Multithread.create(:key=>'detect_sites',:status=>{"infos"=>[],"status"=>"detecting"})
if( args.detect_name.nil? rescue true) if( args.detect_name.nil? rescue true)
site_servers = SiteServer.all.to_a site_servers = SiteServer.all.where(:active=>true).to_a
else else
site_servers = SiteServer.where(:server_name=>args.detect_name).to_a site_servers = SiteServer.where(:server_name=>args.detect_name).to_a
end end
@ -33,6 +34,20 @@ namespace :create_site do
next next
end end
Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password) do |ssh| Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password) do |ssh|
certbot_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which certbot'",false,true).strip
@site_server.has_certbot = certbot_path.present?
@site_server.save
if @site_server.has_certbot
update_thread_infos("Checking certbot renew cronjob...")
crontab_lines = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' crontab -l",false,false)
certbot_renew_command = crontab_lines.select{|l| l.include?("certbot") && l.include?("renew")}[0]
unless certbot_renew_command
update_thread_infos("Add certbot renew cronjob!")
certbot_renew_command = "30 2 * * 1 #{certbot_path} renew --no-self-upgrade --post-hook 'sudo service nginx restart' > /var/log/le-renew.log"
update_thread_infos(certbot_renew_command)
exec_ssh_command_by_sudo_and_see_output(ssh,"CRON=\"#{certbot_renew_command}\" && (sudo -p 'sudo password:' crontab -l; echo \"\$CRON\" ) | sudo -p 'sudo password:' crontab -",false)
end
end
nginx_include_dir = exec_command_by_user(ssh,'grep include /etc/nginx/nginx.conf | grep -v "\#\|include /etc/nginx/mime.types\|include /etc/nginx/conf.d/\*.conf\|/etc/nginx/sites-enabled/\*"') nginx_include_dir = exec_command_by_user(ssh,'grep include /etc/nginx/nginx.conf | grep -v "\#\|include /etc/nginx/mime.types\|include /etc/nginx/conf.d/\*.conf\|/etc/nginx/sites-enabled/\*"')
nginx_include_dir = nginx_include_dir.gsub(/include|;|\n/,'').strip nginx_include_dir = nginx_include_dir.gsub(/include|;|\n/,'').strip
domain_name = @site_server.domain_name#'serv.rulingcom.com' domain_name = @site_server.domain_name#'serv.rulingcom.com'
@ -49,8 +64,7 @@ namespace :create_site do
server_name_list << server_name_for_site server_name_list << server_name_for_site
end end
server_name = server_name_list.join(' ') server_name = server_name_list.join(' ')
nginx_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{nginx_file}",false) nginx_file_content = exec_ssh_command_by_sudo_and_see_output(ssh,"cat #{nginx_file}",false,true)
nginx_file_content = nginx_file_content.join('\n') if nginx_file_content.class == Array
site_path = Pathname.new(exec_ssh_command_by_sudo(ssh,"echo `grep root #{nginx_file} | grep -v -e '#.*root'`").to_s.split("\n").first.to_s.strip.split("root").last.to_s.gsub(";","").strip).dirname.to_s site_path = Pathname.new(exec_ssh_command_by_sudo(ssh,"echo `grep root #{nginx_file} | grep -v -e '#.*root'`").to_s.split("\n").first.to_s.strip.split("root").last.to_s.gsub(";","").strip).dirname.to_s
if site_path.present? && exec_ssh_command_by_sudo(ssh,"ls #{site_path}").split.length != 0 && exec_ssh_command_by_sudo(ssh,"ls #{site_path}/Gemfile").include?("No such file or directory") if site_path.present? && exec_ssh_command_by_sudo(ssh,"ls #{site_path}").split.length != 0 && exec_ssh_command_by_sudo(ssh,"ls #{site_path}/Gemfile").include?("No such file or directory")
SiteConstruct.where(:server_type => @site_server.server_name , :domain_name=>server_name).destroy SiteConstruct.where(:server_type => @site_server.server_name , :domain_name=>server_name).destroy
@ -128,6 +142,7 @@ namespace :create_site do
FileUtils.mkdir_p(File.dirname(private_key_store_path)) unless Dir.exist?(File.dirname(private_key_path)) 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)} 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.source_paths = [crt_file_path,private_key_path]
site_cert.is_certbot = private_key_path.include?("letsencrypt")
site_cert.save site_cert.save
site_construct.update(:site_cert=>site_cert) site_construct.update(:site_cert=>site_cert)
end end

View File

@ -120,6 +120,7 @@ namespace :exec_commands do
return output return output
end end
def update_infos_for_exec(info,update_last=false) def update_infos_for_exec(info,update_last=false)
return if @site_construct.nil?
if update_last && !@site_construct.infos.empty? if update_last && !@site_construct.infos.empty?
@site_construct.infos[-1] += info.to_s @site_construct.infos[-1] += info.to_s
else else
@ -137,12 +138,16 @@ namespace :exec_commands do
@thread.save! @thread.save!
return @thread.status["infos"] return @thread.status["infos"]
end end
def exec_ssh_command_and_see_output(session,command,update=true) def exec_ssh_command_and_see_output(session,command,update=true,output_string=false)
outputs = [] outputs = []
@flag = (@type == "exec_all") @flag = (@type == "exec_all")
if update if update
if @site_construct
update_thread_infos_for_exec("execing #{command} on on <a href='#{((@site_construct.get_port == "443") ? "https" : "http")}://#{@site_construct.domain_name}#{((@site_construct.get_port=="80" || @site_construct.get_port=="443" || @site_construct.get_port.blank?) ? "" : (':'+@site_construct.get_port))}'>#{@site_construct.domain_name}</a>") if @flag update_thread_infos_for_exec("execing #{command} on on <a href='#{((@site_construct.get_port == "443") ? "https" : "http")}://#{@site_construct.domain_name}#{((@site_construct.get_port=="80" || @site_construct.get_port=="443" || @site_construct.get_port.blank?) ? "" : (':'+@site_construct.get_port))}'>#{@site_construct.domain_name}</a>") if @flag
update_infos_for_exec("execing #{command}") update_infos_for_exec("execing #{command}")
elsif @thread
update_thread_infos_for_exec("execing #{command}...")
end
end end
session.open_channel do |channel| session.open_channel do |channel|
channel.request_pty do |channel, success| channel.request_pty do |channel, success|
@ -173,21 +178,33 @@ namespace :exec_commands do
end end
channel.on_close do |ch| channel.on_close do |ch|
if update if update
if @site_construct
update_thread_infos_for_exec("finish execing #{command} on <a href='#{((@site_construct.get_port == "443") ? "https" : "http")}://#{@site_construct.domain_name}#{((@site_construct.get_port=="80" || @site_construct.get_port=="443" || @site_construct.get_port.blank?) ? "" : (':'+@site_construct.get_port))}'>#{@site_construct.domain_name}</a>") if @flag update_thread_infos_for_exec("finish execing #{command} on <a href='#{((@site_construct.get_port == "443") ? "https" : "http")}://#{@site_construct.domain_name}#{((@site_construct.get_port=="80" || @site_construct.get_port=="443" || @site_construct.get_port.blank?) ? "" : (':'+@site_construct.get_port))}'>#{@site_construct.domain_name}</a>") if @flag
update_infos_for_exec("finish execing #{command}") update_infos_for_exec("finish execing #{command}")
elsif @thread
update_thread_infos_for_exec("finish execing #{command}")
end
end end
end end
end end
end end
end end
session.loop session.loop
if output_string
return outputs.join("\n")
else
return outputs return outputs
end end
def exec_ssh_command_by_sudo_and_see_output(session,command,update=true) end
def exec_ssh_command_by_sudo_and_see_output(session,command,update=true,output_string=false)
outputs = exec_ssh_command_and_see_output(session,command,update) outputs = exec_ssh_command_and_see_output(session,command,update)
if outputs.join("\n").include?("Permission denied") || outputs.join("\n").include?("Operation not permitted") if outputs.join("\n").include?("Permission denied") || outputs.join("\n").include?("Operation not permitted")
outputs = exec_ssh_command_and_see_output(session,"sudo -p 'sudo password:' #{command}",update) outputs = exec_ssh_command_and_see_output(session,"sudo -p 'sudo password:' #{command}",update)
end end
if output_string
return outputs.join("\n")
else
return outputs return outputs
end end
end
end end

View File

@ -0,0 +1,83 @@
require 'net/ssh'
require 'pathname'
require 'fileutils'
namespace :create_site do
desc "Install certbot"
task :install_certbot,[:server_name] => :environment do |task,args|
#Multithread.where(:key=>'detect_sites').destroy
Multithread.where(:key=>'install_certbot').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")}
Multithread.where(:key=>'install_certbot').destroy
@thread = Multithread.where(:key=>'install_certbot').first
@type = "exec_all"
if @thread.nil?
begin
@thread = Multithread.create(:key=>'install_certbot',:status=>{"infos"=>[],"status"=>"running"})
if( args.server_name.nil? rescue true)
site_servers = SiteServer.all.where(:active=>true).to_a
else
site_servers = SiteServer.where(:server_name=>args.server_name).to_a
end
site_servers.each do |site_server|
@site_server = site_server
update_thread_infos("<span style='color: skyblue;'>"+@site_server.server_name+"</span>")
@password = @site_server.password
begin
begin
Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password) do |ssh|
end
rescue Net::SSH::HostKeyMismatch
system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{@site_server.ip}")
rescue Errno::ENOTTY
system("ssh-add \"$HOME/.ssh/id_rsa\"")
rescue => e
update_thread_infos(e.to_s)
next
end
Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password) do |ssh|
certbot_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which certbot'",false,true).strip
snap_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which snap'",false,true).strip
if certbot_path.blank?
if snap_path.blank?
update_thread_infos("Installing snap...")
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' apt update",true,false)
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' apt install snapd -y",true,false)
snap_path = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'which snap'",false,true).strip
end
if snap_path.present?
update_thread_infos("Installing snap core...")
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' bash -l -c 'snap install core && snap refresh core'",true,false)
update_thread_infos("Installing certbot with snap...")
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' snap install --classic certbot",true,false)
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' ln -s /snap/bin/certbot /usr/bin/certbot",false,false)
exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' certbot register --email bohung@rulingcom.com --agree-tos -n",false,false)
update_thread_infos("Finish install certbot!")
certbot_path = "/usr/bin/certbot"
else
update_thread_infos("There was some error when installing snap!")
end
end
if certbot_path.present?
@site_server.has_certbot = true
@site_server.save
update_thread_infos("Setting certbot renew to cronjob...")
crontab_lines = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' crontab -l",false,false)
certbot_renew_command = crontab_lines.select{|l| l.include?("certbot") && l.include?("renew")}[0]
unless certbot_renew_command
update_thread_infos("Add certbot renew cronjob!")
certbot_renew_command = "30 2 * * 1 #{certbot_path} renew --no-self-upgrade --post-hook 'sudo service nginx restart' > /var/log/le-renew.log"
update_thread_infos(certbot_renew_command)
exec_ssh_command_by_sudo_and_see_output(ssh,"CRON=\"#{certbot_renew_command}\" && (sudo -p 'sudo password:' crontab -l; echo \"\$CRON\" ) | sudo -p 'sudo password:' crontab -",false)
end
update_thread_infos("Finish setting renew cronjob!")
end
end
end
end
@thread.update(:status=>@thread.status.merge({"status"=>"finish"}))
rescue => e
puts [e,e.backtrace]
@thread.update(:status=>{"infos"=>@thread.status["infos"].push(e.to_s),"status"=>"error"})
end
end
end
end