diff --git a/app/controllers/admin/site_panel_controller.rb b/app/controllers/admin/site_panel_controller.rb index 795392c..3351211 100644 --- a/app/controllers/admin/site_panel_controller.rb +++ b/app/controllers/admin/site_panel_controller.rb @@ -35,6 +35,32 @@ class Admin::SitePanelController < OrbitAdminController elsif params[:type] == 'delete' SiteServer.find(params[:id]).destroy redirect_to admin_site_panel_server_manager_path + elsif params[:type] == 'detect_sites' + Thread.new do + system("rake create_site:detect_sites") + end + render :json => {"success"=>true} + elsif params[:type] == 'see_infos' + if params["key"].blank? + thread = Multithread.where(:key=>'detect_sites').first + if thread.nil? + thread = Multithread.where(:key=>'execing_commands').first + else + if thread.status["status"] == "finish" || thread.status["status"] == "error" + exec_thread = Multithread.where(:key=>'execing_commands').first + thread = exec_thread if !exec_thread.nil? + end + end + else + thread = Multithread.where(:key=>params["key"]).first + end + if thread.nil? + render :json => {"infos"=>[],"status"=>"starting"} + else + render :json => thread.status + end + elsif params[:type] == 'get_server_names' + render :json => (SiteServer.all.map{|s| s.server_name rescue ""}.select{|n| !n.blank?} rescue []) else @site_server = SiteServer.find(params[:id]) end @@ -90,21 +116,40 @@ class Admin::SitePanelController < OrbitAdminController end elsif params[:type] == 'close' Thread.new do - system("rake create_site:exec_commands[#{params[:id]},,close_site]") + system("rake exec_commands:exec_commands[#{params[:id]},,close_site]") end elsif params[:type] == 'open' Thread.new do - system("rake create_site:exec_commands[#{params[:id]},,open_site]") + system("rake exec_commands:exec_commands[#{params[:id]},,open_site]") end + elsif params[:type] == 'detail' + @site = SiteConstruct.find(params[:id]) + render 'see_detail_for_created_site' and return + elsif params[:type] == 'delete_from_list' + SiteConstruct.find(params[:id]).destroy + redirect_to :back and return else Thread.new do - system("rake create_site:exec_commands[#{params[:id]},'#{params[:commands]}',open_site]") + if params[:id].blank? && !params[:server_names].blank? + system("rake exec_commands:exec_commands[,'#{params[:commands]}',exec_all,'#{params[:server_names].join('////')}']") + else + system("rake exec_commands:exec_commands[#{params[:id]},'#{params[:commands]}',exec_commands]") + end end end render :json =>{"success"=>true} end def sites_list - @sites = SiteConstruct.all.desc(:id).page(params[:page].to_i).per(10) + @module_app = ModuleApp.where(:title=>@app_title).first + @categories = @module_app.categories + @sites = SiteConstruct.any_in(:hidden=>[false,nil]).desc(:id) + @site_servers = SiteServer.all.with_categories(filters("category")) + @sites = (params[:server_name].blank? ? @sites : @sites.where(:server_type=>params[:server_name])) + @sites = @sites.any_in(:server_type => @site_servers.map{|s| s.server_name}) + @sites = search_data(@sites,[:domain_name,:site_name,:school_name,:status]).page(params[:page].to_i).per(10) + if request.xhr? + render :partial => "sites_list_table" + end end def site_infos site_construct = SiteConstruct.where(:id=>params[:id]).first diff --git a/app/models/site_construct.rb b/app/models/site_construct.rb index e66a0d4..d52f2bc 100644 --- a/app/models/site_construct.rb +++ b/app/models/site_construct.rb @@ -8,6 +8,7 @@ class SiteConstruct field :server_type field :site_name field :domain_name + field :nginx_file field :db_name field :port, type: String, :default => "80" field :path @@ -17,6 +18,7 @@ class SiteConstruct field :constructed, type: Boolean, :default => false field :status, type: String, :default => "" field :infos, type: Array, :default => [] + field :hidden, type: Boolean, :default => false after_initialize do |record| if record.status.nil? record.status = "" @@ -26,5 +28,13 @@ class SiteConstruct record.infos = [] record.save end + if record.nginx_file.nil? + record.nginx_file = "/etc/nginx/orbit_sites/"+record.site_name.to_s + record.save + end + if record.path.nil? + dir_path = ((record.site_type == "School" && !record.school_name.blank?) ? "school_sites/#{record.school_name}" : "orbit_sites") + record.path = "/home/rulingcom/#{dir_path}" + end end end \ No newline at end of file diff --git a/app/views/admin/site_panel/_form.html.erb b/app/views/admin/site_panel/_form.html.erb index 4a83a0d..d05e293 100644 --- a/app/views/admin/site_panel/_form.html.erb +++ b/app/views/admin/site_panel/_form.html.erb @@ -116,6 +116,7 @@ }) $('#site_construct_server_type').click(function(){ var domain_name = domain_name_relations[$(this).val()]; + $("#domain_name").val($("#site_name").val().replace("_","-") + "."+domain_name); $('#domain_name').siblings('.hint').html('schoolname-deptname.'+domain_name+' eg: nctu-eed.'+domain_name); }) $("#site_name").on("blur",function(){ @@ -134,7 +135,16 @@ } }) $("#site_construct_site_type").val("School"); - $("form#new_site_construct").on("submit",function(){ + $("form.main-forms").submit(function(){ $("#path").removeAttr("disabled"); + var type = $("#site_construct_site_type").val(); + type = (type == "School" ? "school_sites" : "orbit_sites" ); + var school = $("#school_name").val(); + if(school != ""){ + $("#path").val("/home/rulingcom/" + type + "/" + school); + }else{ + $("#path").val("/home/rulingcom/" + type); + } + console.log($("#path").val()); }) \ No newline at end of file diff --git a/app/views/admin/site_panel/_server_manager_index.html.erb b/app/views/admin/site_panel/_server_manager_index.html.erb index 56c9c1a..736a045 100644 --- a/app/views/admin/site_panel/_server_manager_index.html.erb +++ b/app/views/admin/site_panel/_server_manager_index.html.erb @@ -1,6 +1,7 @@ + @@ -9,11 +10,19 @@ <% @site_servers.each do |site_server|%> + <% end %> @@ -21,5 +30,113 @@
Sites amount Server name IP Action
+

+ Active: <%=SiteConstruct.where(:server_type => site_server.server_name,:status=>"finish").count %>
+ Closed: <%=SiteConstruct.where(:server_type => site_server.server_name,:status=>"closed").count %>
+ Not yet installed: <%=SiteConstruct.where(:server_type => site_server.server_name,:status=>"").count %>
+

+
<%=site_server.server_name%> <%=site_server.ip%> "><%=t(:edit)%> ';}"><%=t(:remove)%> + "><%= t('client_management.see_sites') %>
+ See infos "><%=t(:add)%> -
\ No newline at end of file + Detect sites + Exec commands + + \ No newline at end of file diff --git a/app/views/admin/site_panel/_sites_list_filter.html.erb b/app/views/admin/site_panel/_sites_list_filter.html.erb new file mode 100644 index 0000000..dd9d4f0 --- /dev/null +++ b/app/views/admin/site_panel/_sites_list_filter.html.erb @@ -0,0 +1,192 @@ +
+ +
+
+
+
+ +
+ +
+
+
+ <% @categories.each do |category|%> + <%=category.title%> + <% end %> +
+
+ 清除 +
+
+
+
+
+
+ 清除 +
+
+
+
+ \ No newline at end of file diff --git a/app/views/admin/site_panel/_sites_list_table.html.erb b/app/views/admin/site_panel/_sites_list_table.html.erb new file mode 100644 index 0000000..3b94737 --- /dev/null +++ b/app/views/admin/site_panel/_sites_list_table.html.erb @@ -0,0 +1,204 @@ + + + + + + + + + + + + <% status_relation = {"creating"=>"creating".html_safe,"error"=>"error".html_safe,"finish"=>"finish".html_safe,"closed"=>"closed".html_safe}%> + <% @sites.each do |site|%> + + + + + + + + <% end %> + +
Server nameDomain namePortStatusAction
<%=site.server_type%>://<%=site.domain_name%><%=((site.port.to_s != '80' && site.port.to_s != '443') ? ':'+site.port.to_s : '')%>" title="open <%=((site.port.to_s == "443") ? "https" : "http")%>://<%=site.domain_name%><%=((site.port.to_s != '80' && site.port.to_s != '443') ? ':'+site.port.to_s : '')%> to new window" target="_blank"><%=site.domain_name%><%=site.port%><%= (site.status.blank? ? "not yet create" : status_relation[site.status]) %> + See infos + <% if site.status.blank? %> + Create site + <% elsif site.status == "error" || site.status == "finish" %> + Recreate site + Delete site + Close site + Restart site + <% elsif site.status == "closed" %> + Start site + <% end%> + Exec commands + " title="See <%=site.domain_name%> detail" class="btn btn-primary see_detail" data-id="<%=site.id.to_s%>">Detail + " title="Delete <%=site.domain_name%> from list" class="btn btn-primary see_detail" data-id="<%=site.id.to_s%>">Delete from list +
+
+ + <%=t(:add)%> +
+ \ No newline at end of file diff --git a/app/views/admin/site_panel/see_detail_for_created_site.html.erb b/app/views/admin/site_panel/see_detail_for_created_site.html.erb new file mode 100644 index 0000000..981851c --- /dev/null +++ b/app/views/admin/site_panel/see_detail_for_created_site.html.erb @@ -0,0 +1,45 @@ +
+
+ +
<%=@site.server_type%>
+
+
+ +
<%=@site.domain_name%>
+
+
+ +
<%=@site.port%>
+
+
+ +
<%=@site.site_type%>
+
+ <% if @site.site_type == "School"%> +
+ +
<%=@site.school_name%>
+
+ <% end %> +
+ +
<%=@site.site_name%>
+
+
+ +
<%=@site.db_name%>
+
+
+ +
<%=@site.nginx_file%>
+
+
+ +
<%=@site.path%>
+
+
+ +
+
\ No newline at end of file diff --git a/app/views/admin/site_panel/server_manager.html.erb b/app/views/admin/site_panel/server_manager.html.erb index 564ac2f..a99d201 100644 --- a/app/views/admin/site_panel/server_manager.html.erb +++ b/app/views/admin/site_panel/server_manager.html.erb @@ -1,3 +1,5 @@ +<%= javascript_include_tag "lib/jquery-ui-1.12.1/jquery-ui" %> +<%= stylesheet_link_tag "lib/jquery-ui-1.12.1/jquery-ui" %> <% content_for :page_specific_javascript do %> <%= javascript_include_tag "lib/module-area" %> <% end %> diff --git a/app/views/admin/site_panel/sites_list.html.erb b/app/views/admin/site_panel/sites_list.html.erb index 49b5721..ddf7309 100644 --- a/app/views/admin/site_panel/sites_list.html.erb +++ b/app/views/admin/site_panel/sites_list.html.erb @@ -1,145 +1,20 @@ <%= javascript_include_tag "lib/jquery-ui-1.12.1/jquery-ui" %> <%= stylesheet_link_tag "lib/jquery-ui-1.12.1/jquery-ui" %> +<% content_for :page_specific_javascript do %> + <%= javascript_include_tag "lib/module-area" %> +<% end %> +<% content_for :page_specific_css do %> + <%= stylesheet_link_tag "lib/main-forms" %> + <%= stylesheet_link_tag "lib/main-list" %> + <%= stylesheet_link_tag "lib/pageslide" %> +<% end %> <% if !params[:id].blank? %>
<% end %> - - - - - - - - - - - - <% status_relation = {"creating"=>"creating".html_safe,"error"=>"error".html_safe,"finish"=>"finish".html_safe,"closed"=>"closed".html_safe}%> - <% @sites.each do |site|%> - - - - - - - - <% end %> - -
Server nameDomain namePortStatusAction
<%=site.server_type%><%=site.domain_name%><%=site.port%><%= (site.status.blank? ? "not yet create" : status_relation[site.status]) %> - See infos - <% if site.status.blank? %> - Create site - <% elsif site.status == "error" || site.status == "finish" %> - Recreate site - Delete site - Close site - <% elsif site.status == "closed" %> - Start site - <% end%> -
-
- - <%=t(:add)%> -
- \ No newline at end of file +<%= render :partial => "sites_list_filter" %> + + <%=render :partial=>'sites_list_table',:locals=>{:@sites=>@sites}%> + \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index f62b94c..4c47224 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,6 @@ en: client_management: + see_sites: See sites on the server client_management: Client Management my_sites: My Sites help_and_faq: Help and FAQ diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 8cd1229..59e304a 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -1,5 +1,6 @@ zh_tw: client_management: + see_sites: 查看主機上的網站 client_management: Client Management my_sites: My Sites help_and_faq: Help and FAQ diff --git a/config/routes.rb b/config/routes.rb index 2b926e5..eebedd1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -36,10 +36,13 @@ Rails.application.routes.draw do get "contracts" end end + get "site_panel/edit_site" => "site_panel#edit_site" post "site_panel/edit_site" => "site_panel#edit_site" get "site_panel/site_infos" => "site_panel#site_infos" post "site_panel/site_infos" => "site_panel#site_infos" post "site_panel/create_site" => "site_panel#create_site" + post "site_panel/create" => "site_panel#create" + patch "site_panel/create" => "site_panel#create" get "site_panel" => "site_panel#index" get "site_panel/sites_list" => "site_panel#sites_list" get "site_panel/server_manager" => "site_panel#server_manager" diff --git a/lib/tasks/create_site.rake b/lib/tasks/create_site.rake index 55e2aa9..72a7c78 100644 --- a/lib/tasks/create_site.rake +++ b/lib/tasks/create_site.rake @@ -22,6 +22,14 @@ namespace :create_site do begin @site_construct.update(:status=>"creating") @site_construct.update!(:infos=>[]) + begin + Net::SSH.start(args.ip , args.user , password: args.password) 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) do |ssh| update_infos("setting nginx for #{args.site_name}") nginx_setting_texts = ('upstream '+args.site_name+'_sock {\n'+ @@ -43,23 +51,23 @@ namespace :create_site do 'proxy_pass http://'+args.site_name+'_sock;\n'+ ' }\n'+ '}') - exec_ssh_command_by_sudo(ssh,"touch /etc/nginx/orbit_sites/#{args.site_name}") - exec_ssh_command_by_sudo(ssh,"sh -c \"echo '#{nginx_setting_texts}' > /etc/nginx/orbit_sites/#{args.site_name}\"") + exec_ssh_command_by_sudo_for_create(ssh,"touch /etc/nginx/orbit_sites/#{args.site_name}") + exec_ssh_command_by_sudo_for_create(ssh,"sh -c \"echo '#{nginx_setting_texts}' > /etc/nginx/orbit_sites/#{args.site_name}\"") update_infos("restarting nginx") - exec_ssh_command_by_sudo(ssh,"service nginx restart") + exec_ssh_command_by_sudo_for_create(ssh,"service nginx restart") update_infos("finish restarting nginx") dir = Pathname.new(args.path) while dir.to_s != '/' do - exec_ssh_command_by_sudo(ssh,"mkdir #{dir}") + exec_ssh_command_by_sudo_for_create(ssh,"mkdir #{dir}") dir = dir.dirname end update_infos("cloning orbit4-5 from #{args.git_url} to #{args.path}/#{args.site_name}") - exec_ssh_command_by_sudo(ssh,"git clone #{args.git_url.gsub("http://","http://#{args.git_user+':'+args.git_password+'@'}").gsub("https://","https://#{args.git_user+':'+args.git_password+'@'}")} #{args.path}/#{args.site_name}") - exec_ssh_command_by_sudo(ssh,"chown #{args.user}:#{args.user} -R #{args.path}/#{args.site_name}") - exec_ssh_command_by_sudo(ssh,"chmod 777 #{args.path}/#{args.site_name} -R") + exec_ssh_command_by_sudo_for_create(ssh,"git clone #{args.git_url.gsub("http://","http://#{args.git_user+':'+args.git_password+'@'}").gsub("https://","https://#{args.git_user+':'+args.git_password+'@'}")} #{args.path}/#{args.site_name}") + exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chown #{args.user}:#{args.user} #{args.path}/#{args.site_name} -R") + exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{args.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(ssh,"echo '#{db_setting_text.gsub("orbit_4_5",args.db_name)}' > #{args.path}/#{args.site_name}/config/mongoid.yml") + exec_ssh_command_by_sudo_for_create(ssh,"sh -c \"echo '#{db_setting_text.gsub("orbit_4_5",args.db_name)}' > #{args.path}/#{args.site_name}/config/mongoid.yml\"",true) gemdir = ssh.exec!("/home/rulingcom/.rvm/bin/rvm gemdir").to_s if gemdir.include?("No such file or directory") ls = ssh.exec!("echo `ls /home`").to_s.split @@ -74,12 +82,17 @@ namespace :create_site do else bundle_dir = gemdir.gsub("\n","") + '/bin/bundle' update_infos("execing bundle install...") - exec_ssh_command_by_sudo(ssh,"bash -l -c 'cd #{args.path}/#{args.site_name}\n#{bundle_dir} install'") - exec_ssh_command_by_sudo(ssh,"bash -l -c 'cd #{args.path}/#{args.site_name}\n#{bundle_dir} install'") + exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{args.site_name}\n#{bundle_dir} install'",true) + exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{args.site_name}\n#{bundle_dir} install'") update_infos("finish execing bundle install") update_infos("starting #{args.site_name} web server to development") - exec_ssh_command_by_sudo(ssh,"bash -l -c 'cd #{args.path}/#{args.site_name}\n#{bundle_dir} exec unicorn_rails -c config/unicorn.rb -D -E development\n'") + outputs = exec_ssh_command_by_sudo_for_create(ssh,"bash -l -c 'cd #{args.path}/#{args.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\n#{bundle_dir} 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}/#{args.site_name} -R") + exec_ssh_command_by_sudo_for_create(ssh,"sudo -p 'sudo password:' chmod 777 #{args.path}/#{args.site_name} -R") + end update_infos("finish creating #{args.site_name}") + exec_ssh_command_by_sudo_for_create(ssh,"chmod 777 #{args.path}/#{args.site_name} -R") @site_construct.update(:status =>"finish") puts "finish creating #{args.site_name} on #{args.ip}" end @@ -96,6 +109,57 @@ namespace :create_site do end return output 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=false) + outputs = [] + session.open_channel do |channel| + channel.request_pty do |channel, success| + channel.exec(command) do |ch, success| + abort "could not execute command: #{command}" unless success + channel.on_data do |ch, data| + outputs.push(data) + print "#{data}" + if update + if data.include? "\n" + update_infos_for_exec(data) + else + update_infos_for_exec(data,true) + end + end + if data.to_s.include?("sudo password:") || data.to_s.include?("Password:") + channel.send_data "#{@password}\n" + 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) + if outputs.join("\n").include?("Permission denied") || outputs.join("\n").include?("Operation not permitted") + outputs = exec_ssh_command_for_create(session,"sudo -p 'sudo password:' #{command}",update) + end + return outputs.join("\n") + end + def update_infos_for_exec(info,update_last=false) + if update_last && !@site_construct.infos.empty? + @site_construct.infos[-1] += info + else + @site_construct.infos = @site_construct.infos.push(info) + end + @site_construct.save! + return @site_construct.infos + end def update_infos(info) puts info @site_construct.infos = @site_construct.infos.push(info) diff --git a/lib/tasks/delete_dbs.rake b/lib/tasks/delete_dbs.rake new file mode 100644 index 0000000..3152aa9 --- /dev/null +++ b/lib/tasks/delete_dbs.rake @@ -0,0 +1,43 @@ +require 'net/ssh' +require 'pathname' +namespace :create_site do + desc "Delete databases Script" + task :delete_dbs,[:server_name,:dbs] => :environment do |task,args| + site_server = SiteServer.where(:server_name=>args.server_name).first + ip = site_server.ip + user = site_server.account + password = site_server.password + @password = password + dbs = args.dbs.split + begin + Net::SSH.start(ip , user , password: password) do |ssh| + end + rescue Net::SSH::HostKeyMismatch + system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{ip}") + rescue Errno::ENOTTY + system("ssh-add \"$HOME/.ssh/id_rsa\"") + end + Net::SSH.start(ip , user , password: password) do |ssh| + dbs.each do |db| + puts "deleting database #{db}" + exec_ssh_command_by_sudo(ssh,"bash -l -c 'echo \"db.dropDatabase()\" | mongo --shell \'#{db}\''") + puts "finish deleting database #{db}" + end + end + puts "finished deleting databases rake" + 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 + end + def update_infos(info) + puts info + @site_construct.infos = @site_construct.infos.push(info) + @site_construct.save! + return @site_construct.infos + end +end \ No newline at end of file diff --git a/lib/tasks/delete_site.rake b/lib/tasks/delete_site.rake index c554349..5132e33 100644 --- a/lib/tasks/delete_site.rake +++ b/lib/tasks/delete_site.rake @@ -1,7 +1,7 @@ require 'net/ssh' require 'pathname' namespace :create_site do - desc "Create Site Script" + desc "Delete Site Script" task :delete_site,[:site_construct_id] => :environment do |task,args| @site_construct = SiteConstruct.find(args.site_construct_id) site_server = SiteServer.where(:server_name=>@site_construct.server_type).first @@ -10,17 +10,25 @@ namespace :create_site do password = site_server.password @password = password begin + begin + Net::SSH.start(ip , user , password: password) do |ssh| + end + rescue Net::SSH::HostKeyMismatch + system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{ip}") + rescue Errno::ENOTTY + system("ssh-add \"$HOME/.ssh/id_rsa\"") + end Net::SSH.start(ip , user , password: password) do |ssh| @site_construct.update!(:infos=>[]) update_infos("deleting database for #{@site_construct.site_name}") db_name = exec_ssh_command_by_sudo(ssh,"echo `cat #{@site_construct.path}/#{@site_construct.site_name}/config/mongoid.yml | grep 'database'`").split("database:").last.strip - exec_ssh_command_by_sudo(ssh,"bash -l -c 'echo \'db.dropDatabase()\' | mongo --shell \'#{db_name}\''") + exec_ssh_command_by_sudo(ssh,"bash -l -c 'echo \"db.dropDatabase()\" | mongo --shell \'#{db_name}\''") update_infos("finish deleting database for #{@site_construct.site_name}") update_infos("deleting orbit4-5 at #{@site_construct.path}/#{@site_construct.site_name}") exec_ssh_command_by_sudo(ssh,"rm -rf #{@site_construct.path}/#{@site_construct.site_name}") update_infos("finish deleting #{@site_construct.site_name}") update_infos("deleting nginx for #{@site_construct.site_name}") - exec_ssh_command_by_sudo(ssh,"rm -f /etc/nginx/orbit_sites/#{@site_construct.site_name}") + exec_ssh_command_by_sudo(ssh,"rm -f #{@site_construct.nginx_file}") update_infos("finish deleting nginx setting for #{@site_construct.site_name}") update_infos("restarting nginx") exec_ssh_command_by_sudo(ssh,"service nginx restart") diff --git a/lib/tasks/detect_sites.rake b/lib/tasks/detect_sites.rake new file mode 100644 index 0000000..218dc30 --- /dev/null +++ b/lib/tasks/detect_sites.rake @@ -0,0 +1,108 @@ +require 'net/ssh' +require 'pathname' +namespace :create_site do + desc "Detect sites" + task :detect_sites,[:detect_name] => :environment do |task,args| + #Multithread.where(:key=>'detect_sites').destroy + Multithread.where(:key=>'detect_sites').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")} + @thread = Multithread.where(:key=>'detect_sites').first + if @thread.nil? + begin + @thread = Multithread.create(:key=>'detect_sites',:status=>{"infos"=>[],"status"=>"detecting"}) + if( args.detect_name.nil? rescue true) + site_servers = SiteServer.all.to_a + else + site_servers = SiteServer.where(:server_name=>args.detect_name).to_a + end + site_servers.each do |site_server| + @site_server = site_server + update_thread_infos(""+@site_server.server_name+"") + @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| + nginx_include_dirs = exec_ssh_command_by_sudo(ssh,'echo `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_dirs = nginx_include_dirs.split("\n").map{|t| t.gsub("include",'').gsub(';','').strip} + domain_name = @site_server.domain_name#'serv.rulingcom.com' + nginx_include_dirs.each do |nginx_include_dir| + server_names = exec_ssh_command_by_sudo(ssh,"grep 'server_name' -r #{nginx_include_dir}") + server_names_array = server_names.split("\n") + server_names_array = server_names_array.select{|t| !t.include?('No such file or directory')}.flat_map{|t| t.strip.split('server_name').last.split(";").first.strip.split} + server_names_array.each do |server_name| + if !server_name.include?(domain_name) + next if !`nslookup "#{server_name}"`.include?(@site_server.ip) + end + nginx_file = exec_ssh_command_by_sudo(ssh,"grep '#{server_name}' -r #{nginx_include_dir}").split("\n").select{|s| !s.include?("No such file or directory")}.first.split('server_name').first.strip.split(":").first + 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") + SiteConstruct.where(:server_type => @site_server.server_name , :domain_name=>server_name).destroy + next + end + path = Pathname.new(site_path).dirname.to_s + site_name = Pathname.new(site_path).basename.to_s + server_type = @site_server.server_name + port = exec_ssh_command_by_sudo(ssh,"echo `grep 'listen' #{nginx_file} | grep -v -e '#.*listen'`").split("\n").first.strip.split("listen").last.strip.split(";").first.split.select{|p| p.strip == p.strip.to_i.to_s}.first.strip rescue "80" + db_name = exec_ssh_command_by_sudo(ssh,"echo `cat #{site_path}/config/mongoid.yml | grep 'database'`").split("database:").last.strip + db_name = site_name.gsub("-","_") if db_name.include?("No such file or directory") + unicorn_sock_path = exec_ssh_command_by_sudo(ssh,"echo `grep 'server unix' #{nginx_file} | grep -v -e '#.*server unix'`").strip.split("server unix").last.strip.split(":").last.strip rescue (site_path+"/tmp/unicorn.sock") + if Pathname.new(path).basename.to_s == "orbit_sites" || Pathname.new(path).basename.to_s == "housing_sites" || Pathname.new(path).basename.to_s == "dev_sites" || Pathname.new(path).dirname.to_s == "/home" + school_name = nil + site_type = "Gravity" + else + school_name = Pathname.new(path).basename.to_s + site_type = "School" + end + pid_infos = exec_ssh_command_by_sudo(ssh,"fuser #{unicorn_sock_path}").to_s.strip.gsub("\n","") + if pid_infos.length != 0 && !pid_infos.include?("not exist") && !pid_infos.include?("No such file or directory") + status = "finish" + else + bundle_show_info = exec_ssh_command_by_sudo(ssh,"bash -l -c 'cd #{site_path};bundle show'") + if bundle_show_info.include?("is not yet checked out") || bundle_show_info.include?("No such file or directory") + status = "" + else + status = "closed" + end + end + site_construct = SiteConstruct.where(:server_type => server_type , :domain_name=>server_name).first + update_thread_infos("Detect #{server_name}".html_safe) + if site_construct.nil? + site_construct = SiteConstruct.create(:server_type=>server_type,:site_name=>site_name,:domain_name=>server_name,:nginx_file=>nginx_file,:db_name=>db_name,:port=>port,:path=>path,:site_type=>site_type,:school_name=>school_name,:user_id=>User.first.id,:status=>status) + else + site_construct.update(:server_type=>server_type,:site_name=>site_name,:domain_name=>server_name,:nginx_file=>nginx_file,:db_name=>db_name,:port=>port,:path=>path,:site_type=>site_type,:school_name=>school_name,:user_id=>User.first.id,:status=>status) + end + end + end + end + end + end + @thread.update(:status=>@thread.status.merge({"status"=>"finish"})) + rescue => e + @thread.update(:status=>{"infos"=>@thread.status["infos"].push(e.to_s),"status"=>"error"}) + end + 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 + end + def update_thread_infos(info) + puts info + @thread.status["infos"] = @thread.status["infos"].push(info) + @thread.save! + return @thread.status["infos"] + end +end \ No newline at end of file diff --git a/lib/tasks/exec_command.rake b/lib/tasks/exec_command.rake index 5598205..38db070 100644 --- a/lib/tasks/exec_command.rake +++ b/lib/tasks/exec_command.rake @@ -1,43 +1,108 @@ require 'net/ssh' require 'pathname' -namespace :create_site do - desc "Create Site Script" - task :exec_commands,[:site_construct_id,:commands,:type] => :environment do |task,args| - @site_construct = SiteConstruct.find(args.site_construct_id) - site_server = SiteServer.where(:server_name=>@site_construct.server_type).first - ip = site_server.ip - user = site_server.account - password = site_server.password - @password = password - #begin - Net::SSH.start(ip , user , password: password) do |ssh| - @site_construct.update!(:infos=>[]) - if args.type == 'close_site' - exec_ssh_command_by_sudo(ssh,"bash -l -c 'kill -s TERM `fuser #{@site_construct.path}/#{@site_construct.site_name}/tmp/unicorn.sock`'") - update_infos("finish closing #{@site_construct.site_name}") - @site_construct.update(:status =>"closed") - elsif args.type == 'open_site' - exec_ssh_command_by_sudo(ssh,"bash -l -c 'cd #{@site_construct.path}/#{@site_construct.site_name};kill -s TERM `fuser tmp/unicorn.sock`;bundle exec unicorn_rails -c config/unicorn.rb -D -E development'") - update_infos("finish starting #{@site_construct.site_name}") - @site_construct.update(:status =>"finish") - else - commands = YAML.load(args.commands) rescue args.commands - if(!commands.blank? rescue true) - if commands.class == Array - commands.each do |command| - update_infos("execing #{command}") - exec_ssh_command_by_sudo(ssh,"bash -l -c '#{command}'") +namespace :exec_commands do + desc "Exec commands Script" + task :exec_commands,[:site_construct_id,:commands,:type,:server_name] => :environment do |task,args| + @type = args.type + if !args.site_construct_id.blank? + @site_construct = SiteConstruct.find(args.site_construct_id) + site_server = SiteServer.where(:server_name=>@site_construct.server_type).first + site_servers = [site_server] + else + @site_construct = nil + site_servers = SiteServer.where(:server_name.in=>args.server_name.split("////")).to_a + end + if args.type == "exec_all" + Multithread.where(:key=>'execing_commands').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")} + @thread = Multithread.where(:key=>'execing_commands').first + else + @thread = nil + end + if @thread.nil? + begin + if @thread.nil? && args.type == "exec_all" + @thread = Multithread.create(:key=>'execing_commands',:status=>{"infos"=>[],"status"=>"execing"}) + end + site_servers.each do |site_server| + ip = site_server.ip + user = site_server.account + password = site_server.password + @password = password + begin + Net::SSH.start(ip , user , password: password) do |ssh| + end + rescue Net::SSH::HostKeyMismatch + system("ssh-keygen -f \"$HOME/.ssh/known_hosts\" -R #{ip}") + rescue Errno::ENOTTY + system("ssh-add \"$HOME/.ssh/id_rsa\"") + end + Net::SSH.start(ip , user , password: password) do |ssh| + @site_construct.update!(:infos=>[]) rescue nil + if args.type == 'close_site' + exec_ssh_command_by_sudo_and_see_output(ssh,"chmod 777 #{@site_construct.path}/#{@site_construct.site_name} -R",false) + exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'kill -s TERM `fuser #{@site_construct.path}/#{@site_construct.site_name}/tmp/unicorn.sock`'",false) + update_infos_for_exec("finish closing #{@site_construct.site_name}") + @site_construct.update(:status =>"closed") + elsif args.type == 'open_site' + default_rails_env = 'development' + enable_rails_env = ['development','production'] + rails_env = default_rails_env + log_files = exec_ssh_command_by_sudo_and_see_output(ssh,"ls -t '#{@site_construct.path}/#{@site_construct.site_name}/log'",false).flat_map{|output| output.split(/(\r\n|\t|\n|\s+)/)}.select{|output| output.present? && /(\r\n|\t|\n|\s+)/.match(output).nil?} rescue [] + log_files.each do |log_file| + if( enable_rails_env.include?(log_file.sub('.log','')) rescue false) + rails_env = log_file.sub('.log','') + break + end + end + update_infos_for_exec("starting site to #{rails_env}") + outputs = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' chmod 777 #{@site_construct.path}/#{@site_construct.site_name} -R",false) + output = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'cd #{@site_construct.path}/#{@site_construct.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 #{rails_env}\n'",false) + if output.include? "bundle install" + update_infos_for_exec("not yet bundle install") + outputs = exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'cd #{@site_construct.path}/#{@site_construct.site_name};bundle install'") + if outputs.join("\n").include? "Username for" + update_infos_for_exec("Cannot finish bundle install.") + update_infos_for_exec("This site include an private git project.") + @site_construct.update(:status =>"error") + break + end + end + update_infos_for_exec("finish starting #{@site_construct.site_name}") + @site_construct.update(:status =>"finish") + elsif args.type == 'exec_all' + sites = SiteConstruct.where(:server_type=>args.server_name).to_a + commands = args.commands.split("////").select{|c| c != ""} rescue [args.commands] + sites.each do |site_construct| + @site_construct = site_construct + @site_construct.update!(:infos=>[]) + exec_ssh_command_by_sudo(ssh,"chmod 777 #{@site_construct.path}/#{@site_construct.site_name} -R") + commands.each do |command| + exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'cd #{@site_construct.path}/#{@site_construct.site_name};#{command}'") + end end else - update_infos("execing #{commands}") - exec_ssh_command_by_sudo(ssh,"bash -l -c '#{commands}'") + exec_ssh_command_by_sudo(ssh,"chmod 777 #{@site_construct.path}/#{@site_construct.site_name} -R") + commands = args.commands.split("////").select{|c| c != ""} rescue [args.commands] + commands.each do |command| + exec_ssh_command_by_sudo_and_see_output(ssh,"bash -l -c 'cd #{@site_construct.path}/#{@site_construct.site_name};#{command}'") + end end end end + if !@thread.nil? + @thread.update(:status=>@thread.status.merge({"status"=>"finish"})) + end + rescue => e + if !@thread.nil? + @thread.update(:status=>{"infos"=>@thread.status["infos"].push(e.message),"status"=>"error"}) + @thread.update(:status=>{"infos"=>@thread.status["infos"].push(e.backtrace.join("\n")),"status"=>"error"}) + end + if !@site_construct.nil? + @site_construct.update(:status =>"error",:infos=>@site_construct.infos.push("#{e.message}")) + @site_construct.update(:status =>"error",:infos=>@site_construct.infos.push("#{e.backtrace.join("\n")}")) + end end - #rescue =>e - # @site_construct.update(:status =>"error",:infos=>@site_construct.infos.push("#{e}")) - # end + end end def exec_ssh_command_by_sudo(session,command) output = session.exec!("echo '#{@password}' | sudo -S #{command}") @@ -47,10 +112,71 @@ namespace :create_site do end return output end - def update_infos(info) - puts info - @site_construct.infos = @site_construct.infos.push(info) + def update_infos_for_exec(info,update_last=false) + if update_last && !@site_construct.infos.empty? + @site_construct.infos[-1] += info.to_s + else + @site_construct.infos = @site_construct.infos.push(info.to_s) + end @site_construct.save! return @site_construct.infos end + def update_thread_infos_for_exec(info,update_last=false) + if update_last && !@thread.status["infos"].empty? + @thread.status["infos"][-1] += info.to_s + else + @thread.status["infos"] = @thread.status["infos"].push(info.to_s) + end + @thread.save! + return @thread.status["infos"] + end + def exec_ssh_command_and_see_output(session,command,update=true) + outputs = [] + @flag = (@type == "exec_all") + if update + update_thread_infos_for_exec("execing #{command} on on #{@site_construct.domain_name}") if @flag + update_infos_for_exec("execing #{command}") + end + session.open_channel do |channel| + channel.request_pty do |channel, success| + channel.exec(command) do |ch, success| + abort "could not execute command: #{command}" unless success + channel.on_data do |ch, data| + print "#{data}" + if data.include? "\n" || outputs.empty? + outputs.push(data.to_s) + if update + update_thread_infos_for_exec(data) if @flag + update_infos_for_exec(data) + end + else + outputs[-1] += data.to_s rescue "" + if update + update_thread_infos_for_exec(data,true) if @flag + update_infos_for_exec(data,true) + end + end + if data.to_s.include?("sudo password:") || data.to_s.include?("Password:") + channel.send_data "#{@password}\n" + end + end + channel.on_close do |ch| + if update + update_thread_infos_for_exec("finish execing #{command} on #{@site_construct.domain_name}") if @flag + update_infos_for_exec("finish execing #{command}") + end + end + end + end + end + session.loop + return outputs + end + def exec_ssh_command_by_sudo_and_see_output(session,command,update=true) + outputs = exec_ssh_command_and_see_output(session,command,update) + 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) + end + return outputs + end end \ No newline at end of file diff --git a/lib/tasks/test_ssh.rake b/lib/tasks/test_ssh.rake new file mode 100644 index 0000000..3705276 --- /dev/null +++ b/lib/tasks/test_ssh.rake @@ -0,0 +1,47 @@ +require 'net/ssh' +require 'net/ssh/proxy/http' +require 'pathname' +namespace :create_site do + desc "Test ssh" + task :test_ssh,[] => :environment do |task,args| + @site_server = SiteServer.where(:server_name=>'dev').first + Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password) do |ssh| + exec_ssh_command_by_sudo_and_see_output_for_test(ssh,"bash -l -c 'cd orbit_sites/design3;bundle update'") + end + end + def exec_ssh_command_and_see_output_for_test(session,command) + outputs = [] + puts "execing #{command}" + session.open_channel do |channel| + channel.request_pty do |channel, success| + channel.exec(command) do |ch, success| + abort "could not execute command: #{command}" unless success + channel.on_data do |ch, data| + outputs.push(data) + print "#{data}" + if data.to_s.include? "sudo password:" + channel.send_data "#{@site_server.password}\n" + end + end + channel.on_close do |ch| + puts "finish execing #{command}" + end + end + end + end + session.loop + return outputs + end + def exec_ssh_command_by_sudo_and_see_output_for_test(session,command) + outputs = exec_ssh_command_and_see_output_for_test(session,command) + if outputs.join("\n").include?("Permission denied") + exec_ssh_command_and_see_output_for_test(session,"sudo -p 'sudo password:' #{command}") + end + end + def update_thread_infos(info) + puts info + @thread.status["infos"] = @thread.status["infos"].push(info) + @thread.save! + return @thread.status["infos"] + end +end \ No newline at end of file diff --git a/lib/tasks/test_vpn.rake b/lib/tasks/test_vpn.rake new file mode 100644 index 0000000..3ae8e74 --- /dev/null +++ b/lib/tasks/test_vpn.rake @@ -0,0 +1,48 @@ +require 'net/ssh' +require 'net/ssh/proxy/http' +require 'pathname' +namespace :create_site do + desc "Detect sites" + task :test_vpn,[:ip,:port,:username,:password] => :environment do |task,args| + # Multithread.where(:key=>'detect_sites').each{|thread| thread.destroy if (thread.status["status"] == "error" || thread.status["status"] == "finish")} + # @thread = Multithread.where(:key=>'detect_sites').first + #if @thread.nil? + # begin + # @thread = Multithread.create(:key=>'detect_sites',:status=>{"infos"=>[],"status"=>"detecting"}) + # SiteServer.all.to_a.each do |site_server| + # @site_server = site_server + # update_thread_infos(""+@site_server.server_name+"") + # @password = @site_server.password + #begin + @site_server = SiteServer.where(:server_name=>"rulingcom.com").first + proxy = Net::SSH::Proxy::HTTP.new(args.ip, args.port.to_i, + :user => args.username, :password => args.password) + Net::SSH.start(@site_server.ip , @site_server.account , password: @site_server.password, proxy: proxy) do |ssh| + exec_ssh_command_by_sudo("echo 'abc'") + end + #rescue Errno::ETIMEDOUT , Net::SSH::ConnectionTimeout => e + # update_thread_infos(e.to_s) + #end + # end + #@thread.update(:status=>@thread.status.merge({"status"=>"finish"})) + #rescue => e + # puts e + # @thread.update(:status=>{"infos"=>@thread.status["infos"].push(e.to_s),"status"=>"error"}) + #end + #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 + end + def update_thread_infos(info) + puts info + @thread.status["infos"] = @thread.status["infos"].push(info) + @thread.save! + return @thread.status["infos"] + end +end \ No newline at end of file