From b198b1a17b2df0ba03d32e8d1ecefcc2ede1f577 Mon Sep 17 00:00:00 2001 From: "Matt K. Fu" Date: Wed, 24 Apr 2013 19:21:11 +0800 Subject: [PATCH] system preference --- app/controllers/admin/sites_controller.rb | 7 +++ app/jobs/backup_server.rb | 6 ++- app/jobs/dashboard_counter.rb | 36 ++++++++++++++ app/jobs/generate_system_summary.rb | 46 +++++++++++++++++ app/jobs/nccu_calendar.rb | 21 -------- app/jobs/sync_db.rb | 25 ---------- app/jobs/update_tag_cloud.rb | 1 + app/models/site.rb | 5 +- .../sites/show_system_preference.html.erb | 47 ++++++++++++++++++ config/environment.rb | 3 +- .../initializers/orbit_system_preference.rb | 13 +++++ config/locales/en.yml | 12 +++++ config/locales/zh_tw.yml | 12 +++++ config/resque.god | 33 ++++++------ config/resque_schedule.god | 22 +++----- config/resque_schedule.yml | 12 ++--- config/routes.rb | 1 + lib/NewBlog.zip | Bin 53345 -> 0 bytes lib/orbit_job_log.rb | 32 ++++++++++++ 19 files changed, 251 insertions(+), 83 deletions(-) create mode 100644 app/jobs/dashboard_counter.rb create mode 100644 app/jobs/generate_system_summary.rb delete mode 100644 app/jobs/nccu_calendar.rb delete mode 100644 app/jobs/sync_db.rb create mode 100644 app/views/admin/sites/show_system_preference.html.erb create mode 100644 config/initializers/orbit_system_preference.rb delete mode 100644 lib/NewBlog.zip create mode 100644 lib/orbit_job_log.rb diff --git a/app/controllers/admin/sites_controller.rb b/app/controllers/admin/sites_controller.rb index e9e581a9..0ac65669 100644 --- a/app/controllers/admin/sites_controller.rb +++ b/app/controllers/admin/sites_controller.rb @@ -14,6 +14,13 @@ class Admin::SitesController < OrbitBackendController # @site = Site.new # end + def show_system_preference + @git_commit_list_file = File.new(OrbitSystemPreference::GitCommitListPath, "r") rescue nil + @db_backup_list_file = File.new(OrbitSystemPreference::ArchiveDbListPath, "r") rescue nil + @resque_logs_file = File.new(OrbitSystemPreference::ResqueLogFile, "r") rescue nil + @site = Site.first + end + def update @site.update_attributes(params[:site]) site_restart diff --git a/app/jobs/backup_server.rb b/app/jobs/backup_server.rb index 3f0ae6b7..ae7128b1 100644 --- a/app/jobs/backup_server.rb +++ b/app/jobs/backup_server.rb @@ -5,9 +5,13 @@ class BackupServer #CronMail.time_check("Going to backup Orbit").deliver dbhost = Mongoid.config.database.connection.primary.join ':' dbname = Mongoid.config.database.name + archive_db_list_path = OrbitSystemPreference::ArchiveDbListPath dbdirectory = "#{Rails.root}/tmp/#{dbname}-"+Time.now.strftime("%Y-%m-%d-%H-%M") %x[mongodump -h #{dbhost} -d #{dbname} -o #{dbdirectory} ] - # %x[touch #{Rails.root}/tmp/restart] + %x[rm #{archive_db_list_path}] + %x[ls #{Rails.root}/tmp/#{dbname}* | du -h --max-depth=1 --block-size=1M |sort -h >> #{archive_db_list_path}] + OrbitJobLogger.info "DB backup done Path:#{dbdirectory}" + end end diff --git a/app/jobs/dashboard_counter.rb b/app/jobs/dashboard_counter.rb new file mode 100644 index 00000000..ce934aae --- /dev/null +++ b/app/jobs/dashboard_counter.rb @@ -0,0 +1,36 @@ +class DashboardCounter < Resque::Plugins::RestrictionJob + @queue = :high + + def self.perform(*args) + site = Site.first + obj = new(*args) + site.dashboard_counter[:visitors_this_week] = obj.display_visitors_this_week + site.dashboard_counter[:visitors_this_month] = obj.display_visitors_this_month + site.dashboard_counter[:visitors_this_year] = obj.display_visitors_this_year + site.save + OrbitJobLogger.info "DashboardCounter done #{site.dashboard_counter.to_s}" + end + + + def display_visitors(options={}) + impressions = Impression.where(options).and(:referrer.ne => nil) + impressions.map{|i| i[:session_hash]}.uniq.count + end + + def display_visitors_today + display_visitors(created_at: {'$gte' => Date.today.beginning_of_day, '$lte' => Date.today.end_of_day}) + end + + def display_visitors_this_week + display_visitors(created_at: {'$gte' => Date.today.beginning_of_week, '$lte' => Date.today.end_of_week}) + end + + def display_visitors_this_month + display_visitors(created_at: {'$gte' => Date.today.beginning_of_month, '$lte' => Date.today.end_of_month}) + end + + def display_visitors_this_year + display_visitors(created_at: {'$gte' => Date.today.beginning_of_year, '$lte' => Date.today.end_of_year}) + end + +end diff --git a/app/jobs/generate_system_summary.rb b/app/jobs/generate_system_summary.rb new file mode 100644 index 00000000..782c18ae --- /dev/null +++ b/app/jobs/generate_system_summary.rb @@ -0,0 +1,46 @@ +class GenerateSystemSummary + @queue = :high + + def self.perform() + @site = Site.first + get_disk_free + get_git_log_list + get_package_info + @site.save + end + + def self.get_package_info + @info = {} + get_nginx_version + get_MongoDB_version + get_Linux_version + @site.system_package_info = @info + end + + def self.get_git_log_list + git_commit_list_path = OrbitSystemPreference::GitCommitListPath + %x[rm #{git_commit_list_path}] + %x[cd #{Rails.root};#{OrbitSystemPreference::GitLogCommend} >>#{git_commit_list_path} ] + end + + def self.get_disk_free + @site.disk_space= %x[#{OrbitSystemPreference::DiskFree}] + end + + def self.get_nginx_version + @info[:nginx] = %x[#{OrbitSystemPreference::SystemPackage::NginxVersion} ] + end + + def self.get_MongoDB_version + @info[:mongodb] = %x[#{OrbitSystemPreference::SystemPackage::MongodbVersion} ] + end + + def self.get_Linux_version + @info[:linux] = %x[#{OrbitSystemPreference::SystemPackage::SystemVersion} ] + end + + def self.check_system_has_enough_space( limit =OrbitSystemPreference::DefaultDiskSpaceLimit ) + binding.pry + end + +end \ No newline at end of file diff --git a/app/jobs/nccu_calendar.rb b/app/jobs/nccu_calendar.rb deleted file mode 100644 index df60bdd2..00000000 --- a/app/jobs/nccu_calendar.rb +++ /dev/null @@ -1,21 +0,0 @@ -class NccuCalendar - require 'open-uri' - require 'tempfile' - - @queue = :high - - def self.perform() - # temp_file = Tempfile.new('new_cal') - # open('http://events.nccu.edu.tw/Month').read{|data| - # temp_file << data - # } - -open(File.join(Rails.root, 'public/static', 'nccu_calendar.xml'), 'wb') do |fo| - fo.print open('http://events.nccu.edu.tw/Month').read -end - - # FileUtils.mv(temp_file, File.join(Rails.root, 'public/static', 'nccu_calendar.xml')) - - puts "[#{ DateTime.now.strftime("%Y %D %H:%M")}]NccuCalendar Synced #{File.join(Rails.root, 'public/static', 'nccu_calendar.xml')}" - end -end diff --git a/app/jobs/sync_db.rb b/app/jobs/sync_db.rb deleted file mode 100644 index 9c92e816..00000000 --- a/app/jobs/sync_db.rb +++ /dev/null @@ -1,25 +0,0 @@ -class SyncDb - - @queue = :high - - def self.perform() - puts "[ #{DateTime.now.strftime("%Y %D %H:%M") }]\t SyncDb Starting" - self.start_sync - self.set_admin - end - - def self.start_sync - task = 'mid_site:sync' - args = [] - %x[rake #{task} --trace >> #{Rails.root}/log/rake.log] - User.all.each{|ur| ur.create_dept_cache} - puts "[#{ DateTime.now.strftime("%Y %D %H:%M")}]\tSyncDb Synced" - end - - def self.set_admin - task = 'mid_site:install_admin' - args = [] - %x[rake #{task} --trace >> #{Rails.root}/log/rake.log] - puts "[#{ DateTime.now.strftime("%Y %D %H:%M")}]\tAdmin done" - end -end diff --git a/app/jobs/update_tag_cloud.rb b/app/jobs/update_tag_cloud.rb index e0df88d4..08fd16ee 100644 --- a/app/jobs/update_tag_cloud.rb +++ b/app/jobs/update_tag_cloud.rb @@ -5,5 +5,6 @@ class UpdateTagCloud Tag.all.each do |tag| tag.update_attribute(:cloud_view_count, tag.impressionist_count(:created_at.gte => 14.days.ago, :created_at.lte => Time.now)) end + OrbitJobLogger.info "UpdateTagCloud Done" end end \ No newline at end of file diff --git a/app/models/site.rb b/app/models/site.rb index c4df3fc3..07facaa7 100644 --- a/app/models/site.rb +++ b/app/models/site.rb @@ -18,7 +18,10 @@ class Site field :title_always_on, :type => Boolean, :default => false field :dashbroad_allow_visitor, :type => Boolean, :default => false field :mail_settings, :type => Hash - + + field :disk_space, :type => String + field :system_package_info, :type => Hash,:default=>{} + field :school field :department diff --git a/app/views/admin/sites/show_system_preference.html.erb b/app/views/admin/sites/show_system_preference.html.erb new file mode 100644 index 00000000..19360afb --- /dev/null +++ b/app/views/admin/sites/show_system_preference.html.erb @@ -0,0 +1,47 @@ +

<%= I18n.t("site.system_preference") %>

+ + +
+
+

<%= I18n.t("site.system_preference_.summary.disk_space") %>:

+ <%= content_tag :p,@site.disk_space %> +

<%= I18n.t("site.system_preference_.summary.code_update_at") %>:

+ <% @site.system_package_info.each do |index,value| %> +

<%= index.titleize %> <%= I18n.t("site.system_preference_.summary.version") %>:

+ <%= content_tag :p,value %> + <% end %> +

<%= I18n.t("site.system_preference_.summary.weekness_report") %>:<%= '' %>

+
+
+ <% if @git_commit_list_file %> + <% @git_commit_list_file.lines do |line|%> + <%= (line + "
").html_safe %> + <% end%> + <% else %> +
<%= I18n.t("site.system_preference_.summary.no_data") %>
+ <% end %> +
+
+ <%if @db_backup_list_file %> + <% @db_backup_list_file.lines do |line|%> + <%=(line + "
").html_safe %> + <% end %> + <% else %> +
<%= I18n.t("site.system_preference_.summary.no_data") %>
+ <% end %> +
+
+ <%if @db_backup_list_file %> + <% @resque_logs_file.lines do |line|%> + <%=(line + "
").html_safe %> + <% end if @resque_logs_file%> + <%else %> +
<%= I18n.t("site.system_preference_.summary.no_data") %>
+ <% end %> +
+
\ No newline at end of file diff --git a/config/environment.rb b/config/environment.rb index bdc566b5..0d9f5fdb 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -5,4 +5,5 @@ YAML::ENGINE.yamler = 'syck' # Initialize the rails application Orbit::Application.initialize! -Me = Site.first \ No newline at end of file +Me = Site.first +OrbitJobLogger = OrbitJobLog.new \ No newline at end of file diff --git a/config/initializers/orbit_system_preference.rb b/config/initializers/orbit_system_preference.rb new file mode 100644 index 00000000..2f7e8cb6 --- /dev/null +++ b/config/initializers/orbit_system_preference.rb @@ -0,0 +1,13 @@ +module OrbitSystemPreference + ArchiveDbListPath = "#{Rails.root}/log/archive_db.list.log" + GitCommitListPath = "#{Rails.root}/log/git_commit.list.log" + ResqueLogFile ="#{Rails.root}/log/orbit_job.log" + GitLogCommend = 'git log --pretty=format:"%x09%ad%x09%s" --date=short' + DiskFree= 'df -h /' + DefaultDiskSpaceLimit = 3 #in GB + module SystemPackage + MongodbVersion = "mongod --version" + NginxVersion = "nginx -V" + SystemVersion = "uname -a" + end +end \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 102ef231..a2604c57 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -389,6 +389,18 @@ en: search_help: Please Enter the search argument for Google search. settings: Site setting sub_menu: Site sub-menu + system_preference: System Preference + system_preference_: + tab_backups: Backups + tab_commits: Commits + tab_summary: Summary + tab_logs: Logs + summary: + code_update_at: Code Update histroy + disk_space: Disk Free + no_data: No Data + version: Version + weekness_report: Weekness Report title: Site Title title_help: Site Title Guide site_: Site diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml index 94e8d43d..73db5dbc 100644 --- a/config/locales/zh_tw.yml +++ b/config/locales/zh_tw.yml @@ -389,6 +389,18 @@ zh_tw: search_help: 請輸入送交Google搜尋的參數 settings: 基本設定 sub_menu: 次選單 + system_preference: 系統狀態 + system_preference_: + tab_backups: 備份記錄 + tab_commits: 程式版本 + tab_summary: 總覽 + tab_logs: 登錄檔 + summary: + code_update_at: 程式更新紀錄 + disk_space: 硬碟空間 + no_data: 沒有資訊 + version: 版本 + weekness_report: 弱點掃瞄資訊 title: 網站標題 title_help: 網站標題說明 site_: 網站 diff --git a/config/resque.god b/config/resque.god index afd706c0..8a1b03ab 100644 --- a/config/resque.god +++ b/config/resque.god @@ -1,14 +1,9 @@ -#developer pls change here -rails_root = "/home/nccu/stage/NCCU" #keep this blank when development +rails_env = ENV['RAILS_ENV'] || "production" +rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/..' +user_home = ENV['HOME'] || File.dirname(__FILE__) + '/../..' +development_uid = '' +development_gid = '' -development_uid = 'kaito' #when dev -development_gid = 'staff' #when dev - -#rails_env = "developement" -rails_env = "production" - -development_rails_root = File.expand_path("..",File.dirname(__FILE__)) -#rails_root = (rails_env == 'production' )? production_rails_root : development_rails_root num_workers = rails_env == 'production' ? 5 : 2 num_workers.times do |num| @@ -16,16 +11,26 @@ num_workers.times do |num| w.dir = rails_root w.name = "resque-#{num}" - w.group = 'resque-stage' + w.group = 'nccu_production' w.interval = 30.seconds - w.env = {"QUEUE"=>"critical,high,low", "RAILS_ENV"=>rails_env} - w.start = "rake -f #{rails_root}/Rakefile resque:work QUEUE=* RAILS_ENV=#{rails_env}" + + queue = case num + when 0 + 'critical' + when 1..2 + 'high,low' + when 3..num_workers + 'low' + end + + w.env = {"QUEUE"=>queue, "RAILS_ENV"=>rails_env} + w.start = "HOME=#{user_home} rake -f #{rails_root}/Rakefile resque:work QUEUE=* RAILS_ENV=#{rails_env}" w.uid = (rails_env == 'production' )? "root" : development_uid w.gid = (rails_env == 'production' )? "root" : development_gid - w.log = (rails_env == 'production' )? "/var/log/#{w.name}-stage.log":"#{rails_root}/log/#{w.name}.log" + w.log = (rails_env == 'production' )? "/var/log/#{w.group}-#{w.name}":"#{rails_root}/log/dev_resque-#{w.name}.log" # restart if memory gets too high w.transition(:up, :restart) do |on| diff --git a/config/resque_schedule.god b/config/resque_schedule.god index 34a6dff8..5f136438 100644 --- a/config/resque_schedule.god +++ b/config/resque_schedule.god @@ -1,27 +1,21 @@ -#developer pls change here -rails_root = "/home/nccu/NCCU/" #keep this blank when development - -development_uid = 'kaito' #when dev -development_gid = 'staff' #when dev - -#rails_env = "developement" -rails_env = "production" - -development_rails_root = File.expand_path("..",File.dirname(__FILE__)) -#rails_root = (rails_env == 'production' )? production_rails_root : development_rails_root +rails_env = ENV['RAILS_ENV'] || "production" +rails_root = ENV['RAILS_ROOT'] || File.dirname(__FILE__) + '/..' +user_home = ENV['HOME'] || File.dirname(__FILE__) + '/../..' +development_uid = '' +development_gid = '' God.watch do |w| w.dir = rails_root w.name = "resque-scheduler" - w.group = 'resque' + w.group = 'nccu_production' w.interval = 30.seconds w.env = {"QUEUE"=>"critical,high,low", "RAILS_ENV"=>rails_env} - w.start = "rake -f #{rails_root}/Rakefile resque:scheduler RAILS_ENV=#{rails_env}" + w.start = "HOME= #{user_home} rake -f #{rails_root}/Rakefile resque:scheduler RAILS_ENV=#{rails_env}" w.uid = (rails_env == 'production' )? "root" : development_uid w.gid = (rails_env == 'production' )? "root" : development_gid - w.log = (rails_env == 'production' )? "/var/log/#{w.name}.log":"#{rails_root}/log/#{w.name}.log" + w.log = (rails_env == 'production' )? "/var/log/#{w.group}-#{w.name}.log":"#{rails_root}/log/dev_resque-#{w.name}.log" # restart if memory gets too high w.transition(:up, :restart) do |on| diff --git a/config/resque_schedule.yml b/config/resque_schedule.yml index 0fc798eb..e73f9642 100644 --- a/config/resque_schedule.yml +++ b/config/resque_schedule.yml @@ -1,11 +1,11 @@ -# do_mail_matt: -# every: 10s -# class: FetchTime -# args: -# description: Runs the perform method in FetchTime - update_tag_cloud: cron: 0 0 [0,12] * * * class: UpdateTagCloud args: description: UpdateTagCloud + +generate_system_summary: + cron: 0 0 12 * * * + class: GenerateSystemSummary + args: + description: Generate the system status such as disk free space,package version list for showing at site tab \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2e2dc8a5..b6612105 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,6 +17,7 @@ Orbit::Application.routes.draw do # routes for admin namespace :admin do + match 'system_preference' => "sites#show_system_preference",:as=>"system_preference" mount Resque::Server.new, :at => "/resque" resources :assets do collection do diff --git a/lib/NewBlog.zip b/lib/NewBlog.zip deleted file mode 100644 index 71f0e09101e32b59c1c13c6bc32357663d03d909..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53345 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 diff --git a/lib/orbit_job_log.rb b/lib/orbit_job_log.rb new file mode 100644 index 00000000..f8ba5488 --- /dev/null +++ b/lib/orbit_job_log.rb @@ -0,0 +1,32 @@ +class OrbitJobLog < Logger + FORMAT = "%m/%d/%Y %H:%M%p: " + def initialize + case Rails.env + when 'production' + # Logger::Syslog.new("orbit_routine", Syslog::LOG_LOCAL5) + super(Orbit::Application.config.root.to_s+'/log/orbit_job.log','daily') + when 'development' + super(Orbit::Application.config.root.to_s+'/log/orbit_job.dev.log','daily') + end + end + + def debug(msg) + super(Time.now.strftime()+msg) + end + + def info(msg) + super(Time.now.strftime(FORMAT)+msg) + end + + def warn(msg) + super(Time.now.strftime(FORMAT)+msg) + end + + def error(msg) + super(Time.now.strftime(FORMAT)+msg) + end + + def fatal(msg) + super(Time.now.strftime(FORMAT)+msg) + end +end \ No newline at end of file