\ 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 e3e880e..8b5b8ce 100644
--- a/app/views/admin/site_panel/_server_manager_index.html.erb
+++ b/app/views/admin/site_panel/_server_manager_index.html.erb
@@ -68,6 +68,7 @@
"><%=t(:edit)%>';}"><%=t(:remove)%>"><%= t('client_management.see_sites') %>
+ <%= t('client_management.backup_setting') %>Detect sites<%=t('client_management.super_manager_management')%>
diff --git a/app/views/admin/site_panel/backup_setting.html.erb b/app/views/admin/site_panel/backup_setting.html.erb
new file mode 100644
index 0000000..9f719fa
--- /dev/null
+++ b/app/views/admin/site_panel/backup_setting.html.erb
@@ -0,0 +1,145 @@
+<%= form_for @site_server, :url => {:action=>"update_backup_setting"}, :html => {:class => 'form-horizontal main-forms'} do |f| %>
+<% content_for :page_specific_css do %>
+ <%= stylesheet_link_tag "lib/main-forms" %>
+<% end %>
+<% content_for :page_specific_javascript do %>
+<% end %>
+
+<%#= f.error_messages %>
+
+
+
+<% end %>
\ No newline at end of file
diff --git a/config/locales/en.yml b/config/locales/en.yml
index f1d1ea1..1b9d8e1 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -15,6 +15,13 @@ en:
confirm_new_password: "Confirm new password"
super_manager_management: "Super Manager Management"
create_super_manager: Create Super Manager For Site
+ backup_setting: "Backup Setting"
+ add_backup_setting: "Add Backup Setting"
+ file_backup: "File Backup"
+ db_backup: "DB Backup"
+ backup_time: "Backup Time"
+ period: "Period"
+ retain_count: "Retain Count"
enable_api: Enable API
api_key: API Key
setting: Setting
diff --git a/config/locales/zh_tw.yml b/config/locales/zh_tw.yml
index dc886b4..6f15aae 100644
--- a/config/locales/zh_tw.yml
+++ b/config/locales/zh_tw.yml
@@ -15,6 +15,13 @@ zh_tw:
confirm_new_password: "確認新密碼"
super_manager_management: "管理網站超級管理者"
create_super_manager: 創建網站超級管理者
+ backup_setting: "備份設定"
+ add_backup_setting: "新增備份設定"
+ file_backup: "檔案備份"
+ db_backup: "資料庫備份"
+ backup_time: "備份時間"
+ period: "週期"
+ retain_count: "保留"
enable_api: 開啟API
api_key: API Key
setting: 設定
diff --git a/config/routes.rb b/config/routes.rb
index feb563b..e8a23cc 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -68,6 +68,9 @@ Rails.application.routes.draw do
patch 'create_cert'
end
member do
+ get 'backup_setting'
+ post 'update_backup_setting'
+ patch 'update_backup_setting'
get "super_manager_management"
patch "update_super_manager_management"
get "super_manager_management_for_site"
diff --git a/lib/tasks/change_backup_setting.rake b/lib/tasks/change_backup_setting.rake
new file mode 100644
index 0000000..38e9370
--- /dev/null
+++ b/lib/tasks/change_backup_setting.rake
@@ -0,0 +1,96 @@
+require 'net/ssh'
+require 'pathname'
+require 'json'
+require 'base64'
+namespace :exec_commands do
+ desc "Change Server Backup Setting Script"
+ task :change_backup_setting,[:site_server_id] => :environment do |task,args|
+ if args.site_server_id.present?
+ site_server = SiteServer.find(args.site_server_id)
+ else
+ raise StandardError.new('Please Specify Server ID!')
+ end
+ thread_key = "change_backup_setting_#{site_server.id}"
+ @thread = Multithread.where(:key=>thread_key).first
+ begin
+ if @thread.nil?
+ @thread = Multithread.create(:key=>thread_key,:status=>{"infos"=>[],"status"=>"execing"})
+ else
+ @thread.update(:status=>{"infos"=>[],"status"=>"execing"})
+ end
+ 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|
+ @no_stdout = true
+ crontab_lines_str = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' crontab -l", false, true)
+ if site_server.site_server_file_backups.count != 0
+ SiteServerFileBackup.init_class_variables(site_server)
+ rsnapshot_conf_default = SiteServerFileBackup::DefaultConf
+ rsnapshot_conf_exist = check_file_exist_for_ssh(ssh, rsnapshot_conf_default)
+ update_thread_infos_for_exec("Checking file backups config...")
+ if rsnapshot_conf_exist
+ rsnapshot_conf_contents = read_file_for_ssh(ssh, rsnapshot_conf_default)
+ else
+ rsnapshot_sample_conf = File.expand_path("../../../rsnapshot_sample.conf", __FILE__)
+ rsnapshot_conf_contents = File.read(rsnapshot_sample_conf)
+ write_file_for_ssh(ssh, rsnapshot_conf_default, rsnapshot_conf_contents)
+ end
+ site_server.site_server_file_backups.each do |file_backup|
+ rsnapshot_conf_path = file_backup.rsnapshot_conf_path
+ if check_file_exist_for_ssh(ssh, rsnapshot_conf_path)
+ tmp = read_file_for_ssh(ssh, rsnapshot_conf_path)
+ else
+ tmp = rsnapshot_conf_contents.clone
+ end
+ tmp = file_backup.gsub_rsnapshot_conf(tmp)
+ write_file_for_ssh(ssh, rsnapshot_conf_path, tmp)
+ mkdir_for_ssh(ssh, file_backup.path)
+ end
+ update_thread_infos_for_exec("Finish writing file backups config!")
+ end
+ site_server.site_server_db_backups do |db_backup|
+ mkdir_for_ssh(ssh, db_backup.path)
+ end
+ crontab_lines_str = SiteServerFileBackup.write_crontab_setting(site_server, crontab_lines_str)
+ crontab_lines_str = SiteServerDbBackup.write_crontab_setting(site_server, crontab_lines_str)
+ write_crontab_for_ssh(ssh, crontab_lines_str)
+ update_thread_infos_for_exec("Finish setting backups!")
+ end
+ site_server.site_server_file_backups.update_all(:need_rewrite=>false)
+ site_server.site_server_db_backups.update_all(:need_rewrite=>false)
+ site_server.update(:need_rewrite_backup_setting=>false)
+ @thread.update(:status=>@thread.status.merge({"status"=>"finish"}))
+ rescue => e
+ @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
+ end
+ def mkdir_for_ssh(ssh, dir)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' sh -c \"mkdir -p #{dir}\"", false)
+ end
+ def write_crontab_for_ssh(ssh, crontab_lines_str)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"x='#{crontab_lines_str.gsub("\n", '\n').gsub("'","'\"'\"'")}'; sudo -p 'sudo password:' sh -c \"echo '$x'| crontab -\"", false)
+ end
+ def read_file_for_ssh(ssh, file_name)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' sh -c \"cat #{file_name}\"", false, true)
+ end
+ def write_file_for_ssh(ssh, file_name, contents)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"x='#{contents.gsub("\n", '\n').gsub("'","'\"'\"'")}';sudo -p 'sudo password:' sh -c \"echo '$x' > #{file_name}\"", false)
+ end
+ def copy_file_for_ssh(ssh, src, dst)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' bash -l -c 'cp #{src} #{dst}'", 1)
+ end
+ def check_file_exist_for_ssh(ssh, file_name)
+ exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' bash -l -c 'if [ -e #{file_name} ]; then echo 1; else echo 0; fi'", false, true).include?('1')
+ end
+end
\ No newline at end of file
diff --git a/lib/tasks/detect_sites.rake b/lib/tasks/detect_sites.rake
index c736e5b..0dc25fb 100644
--- a/lib/tasks/detect_sites.rake
+++ b/lib/tasks/detect_sites.rake
@@ -164,6 +164,79 @@ namespace :create_site do
end
end
end
+ update_thread_infos("Detecting Backup Setting on #{site_server.server_name}...")
+ crontab_lines = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' crontab -l;crontab -l",false,false)
+ file_backups = crontab_lines.select{|s| s.match(/^\s*[^\s#]/) && s.include?('rsnapshot')}.map{|s| SiteServerFileBackup.read_from_crontab_line(s)}.compact
+ rsnapshot_confs_path = ([SiteServerFileBackup::DefaultConf] + file_backups.map{|time, rsnapshot_conf_path, period| rsnapshot_conf_path}).uniq
+ retain_settings = {}
+ backup_dir_info = {}
+ snapshot_root_info = {}
+ rsnapshot_confs_path.each do |rsnapshot_conf_path|
+ backup_retain_lines = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' grep -E '^\\s*retain\\s+' #{rsnapshot_conf_path}",false,false).map{|s| s.strip}.select{|s| s.present?}
+ backup_retain_lines = backup_retain_lines
+ next if backup_retain_lines.blank?
+ part_retain_settings = backup_retain_lines.map{|s| (s.strip.split(/\s+/)[1..2] rescue nil)}.compact.to_h
+ retain_settings[rsnapshot_conf_path] = part_retain_settings
+
+ backup_dir_subinfo = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' grep -E '^\s*backup' #{rsnapshot_conf_path}",false,false).map{|s| s.strip}.select{|s| s.present?} # ex: ["backup\t/home/rulingcom\tlocalhost/"]
+ backup_dir_info[rsnapshot_conf_path] = backup_dir_subinfo.map{|s| s.strip.split(/\s+/)[1..2]}
+
+ snapshot_root_subinfo = exec_ssh_command_by_sudo_and_see_output(ssh,"sudo -p 'sudo password:' grep -E '^\s*snapshot_root' #{rsnapshot_conf_path}",false,false).map{|s| s.strip}.select{|s| s.present?}.last # ex: "snapshot_root\t/home/backup/orbit"
+ snapshot_root_info[rsnapshot_conf_path] = snapshot_root_subinfo.strip.split(/\s+/)[1] rescue nil #only single snapshot_root in a conf
+ end
+ file_backups_group = file_backups.group_by{|time, rsnapshot_conf_path, period| rsnapshot_conf_path}
+ file_backup_ids = []
+ retain_settings.each do |rsnapshot_conf_path, part_retain_settings|
+ path = snapshot_root_info[rsnapshot_conf_path]
+ if path.nil?
+ path = '/home/backup/orbit'
+ end
+ backup_dir_subinfo = backup_dir_info[rsnapshot_conf_path]
+ tmp = file_backups_group[rsnapshot_conf_path]
+ unused_period = part_retain_settings.map{|period_text, retain_count| SiteServerFileBackup::PeriodsTypes.index(period_text).to_i} - tmp.map{|time, rsnapshot_conf_path, period| period}
+ unused_retain_settings = unused_period.map{|period| [period, part_retain_settings[SiteServerFileBackup::PeriodsTypes[period]]]}
+ backup_dir_subinfo.each do |backup_dir, backup_prefix|
+ unused_retain_settings.each do |period, retain_count|
+ file_backup_data = {:site_server=>@site_server, :disable=>true, :period=>period, :path=>path, :retain_count=>retain_count, :rsnapshot_conf_path=>rsnapshot_conf_path, :backup_dir=>backup_dir, :backup_prefix=>backup_prefix}
+ file_backup = SiteServerFileBackup.where(file_backup_data.except(:disable)).first
+ if file_backup.nil?
+ file_backup = SiteServerFileBackup.create(file_backup_data)
+ else
+ file_backup.update_attributes(file_backup_data)
+ end
+ file_backup_ids << file_backup.id
+ end
+ tmp.each do |time, rsnapshot_conf_path, period|
+ retain_count = part_retain_settings[SiteServerFileBackup::PeriodsTypes[period]]
+ if retain_count
+ file_backup_data = {:site_server=>@site_server, :disable=>false, :backup_time=>time, :path=>path, :period=>period, :retain_count=>retain_count, :rsnapshot_conf_path=>rsnapshot_conf_path, :backup_dir=>backup_dir, :backup_prefix=>backup_prefix}
+ file_backup = SiteServerFileBackup.where(file_backup_data.except(:disable)).first
+ if file_backup.nil?
+ file_backup = SiteServerFileBackup.create(file_backup_data)
+ else
+ file_backup.update_attributes(file_backup_data)
+ end
+ file_backup_ids << file_backup.id
+ end
+ end
+ end
+ end
+ SiteServerFileBackup.where(:id.in=>file_backup_ids).update_all(:need_rewrite=>false)
+ db_backup_ids = []
+ db_backup_infos = crontab_lines.select{|s| s.match(/^\s*[^\s#]/) && s.include?('mongodump')}.map{|s| SiteServerDbBackup.read_from_crontab_line(s, crontab_lines)}.compact
+ db_backup_infos.each do |backup_time, path, period, retain_count|
+ next if backup_time.nil?
+ db_backup_data = {:site_server=>@site_server, :disable=>false, :period=>period, :path=>path, :backup_time=>backup_time, :retain_count=>retain_count}
+ db_backup = SiteServerDbBackup.where(db_backup_data.except(:disable)).first
+ if db_backup.nil?
+ db_backup = SiteServerDbBackup.create(db_backup_data)
+ else
+ db_backup.update_attributes(db_backup_data)
+ end
+ db_backup_ids << db_backup.id
+ end
+ SiteServerDbBackup.where(:id.in=>db_backup_ids).update_all(:need_rewrite=>false)
+ update_thread_infos("Finish detecting Backup Setting on #{site_server.server_name}!")
end
end
end
diff --git a/rsnapshot_sample.conf b/rsnapshot_sample.conf
new file mode 100644
index 0000000..657eb23
--- /dev/null
+++ b/rsnapshot_sample.conf
@@ -0,0 +1,238 @@
+#################################################
+# rsnapshot.conf - rsnapshot configuration file #
+#################################################
+# #
+# PLEASE BE AWARE OF THE FOLLOWING RULE: #
+# #
+# This file requires tabs between elements #
+# #
+#################################################
+
+#######################
+# CONFIG FILE VERSION #
+#######################
+
+config_version 1.2
+
+###########################
+# SNAPSHOT ROOT DIRECTORY #
+###########################
+
+# All snapshots will be stored under this root directory.
+#
+#snapshot_root /var/cache/rsnapshot/
+snapshot_root /home/backup/orbit
+
+# If no_create_root is enabled, rsnapshot will not automatically create the
+# snapshot_root directory. This is particularly useful if you are backing
+# up to removable media, such as a FireWire or USB drive.
+#
+#no_create_root 1
+
+#################################
+# EXTERNAL PROGRAM DEPENDENCIES #
+#################################
+
+# LINUX USERS: Be sure to uncomment "cmd_cp". This gives you extra features.
+# EVERYONE ELSE: Leave "cmd_cp" commented out for compatibility.
+#
+# See the README file or the man page for more details.
+#
+cmd_cp /bin/cp
+
+# uncomment this to use the rm program instead of the built-in perl routine.
+#
+cmd_rm /bin/rm
+# rsync must be enabled for anything to work. This is the only command that
+# must be enabled.
+#
+cmd_rsync /usr/bin/rsync
+
+# Uncomment this to enable remote ssh backups over rsync.
+#
+#cmd_ssh /usr/bin/ssh
+
+# Comment this out to disable syslog support.
+#
+cmd_logger /usr/bin/logger
+
+# Uncomment this to specify the path to "du" for disk usage checks.
+# If you have an older version of "du", you may also want to check the
+# "du_args" parameter below.
+#
+#cmd_du /usr/bin/du
+
+# Uncomment this to specify the path to rsnapshot-diff.
+#
+#cmd_rsnapshot_diff /usr/bin/rsnapshot-diff
+
+# Specify the path to a script (and any optional arguments) to run right
+# before rsnapshot syncs files
+#
+#cmd_preexec /path/to/preexec/script
+
+# Specify the path to a script (and any optional arguments) to run right
+# after rsnapshot syncs files
+#
+#cmd_postexec /path/to/postexec/script
+
+# Paths to lvcreate, lvremove, mount and umount commands, for use with
+# Linux LVMs.
+#
+#linux_lvm_cmd_lvcreate /sbin/lvcreate
+#linux_lvm_cmd_lvremove /sbin/lvremove
+#linux_lvm_cmd_mount /bin/mount
+#linux_lvm_cmd_umount /bin/umount
+
+#########################################
+# BACKUP LEVELS / INTERVALS #
+# Must be unique and in ascending order #
+# e.g. alpha, beta, gamma, etc. #
+#########################################
+
+#retain alpha 6
+#retain beta 7
+#retain gamma 4
+#retain delta 3
+retain daily 7
+
+############################################
+# GLOBAL OPTIONS #
+# All are optional, with sensible defaults #
+############################################
+# Verbose level, 1 through 5.
+# 1 Quiet Print fatal errors only
+# 2 Default Print errors and warnings only
+# 3 Verbose Show equivalent shell commands being executed
+# 4 Extra Verbose Show extra verbose information
+# 5 Debug mode Everything
+#
+verbose 2
+# Same as "verbose" above, but controls the amount of data sent to the
+# logfile, if one is being used. The default is 3.
+# If you want the rsync output, you have to set it to 4
+#
+loglevel 3
+# If you enable this, data will be written to the file you specify. The
+# amount of data written is controlled by the "loglevel" parameter.
+#
+#logfile /var/log/rsnapshot.log
+
+# If enabled, rsnapshot will write a lockfile to prevent two instances
+# from running simultaneously (and messing up the snapshot_root).
+# If you enable this, make sure the lockfile directory is not world
+# writable. Otherwise anyone can prevent the program from running.
+#
+lockfile /var/run/rsnapshot.pid
+
+# By default, rsnapshot check lockfile, check if PID is running
+# and if not, consider lockfile as stale, then start
+# Enabling this stop rsnapshot if PID in lockfile is not running
+#
+#stop_on_stale_lockfile 0
+# Default rsync args. All rsync commands have at least these options set.
+#
+#rsync_short_args -a
+#rsync_long_args --delete --numeric-ids --relative --delete-excluded
+# ssh has no args passed by default, but you can specify some here.
+#
+#ssh_args -p 22
+
+# Default arguments for the "du" program (for disk space reporting).
+# The GNU version of "du" is preferred. See the man page for more details.
+# If your version of "du" doesnt support the -h flag, try -k flag instead.n#n#du_args -cshnn# If this is enabled, rsync wont span filesystem partitions within a
+# backup point. This essentially passes the -x option to rsync.
+# The default is 0 (off).
+#
+#one_fs 0
+
+# The include and exclude parameters, if enabled, simply get passed directly
+# to rsync. If you have multiple include/exclude patterns, put each one on a
+# separate line. Please look up the --include and --exclude options in the
+# rsync man page for more details on how to specify file name patterns.
+#
+#include ???
+#include ???
+#exclude ???
+#exclude ???
+
+# The include_file and exclude_file parameters, if enabled, simply get
+# passed directly to rsync. Please look up the --include-from and
+# --exclude-from options in the rsync man page for more details.
+#
+#include_file /path/to/include/file
+#exclude_file /path/to/exclude/file
+# If your version of rsync supports --link-dest, consider enabling this.
+# This is the best way to support special files (FIFOs, etc) cross-platform.
+# The default is 0 (off).
+#
+#link_dest 0
+
+# When sync_first is enabled, it changes the default behaviour of rsnapshot.
+# Normally, when rsnapshot is called with its lowest interval
+# (i.e.: "rsnapshot alpha"), it will sync files AND rotate the lowest
+# intervals. With sync_first enabled, "rsnapshot sync" handles the file sync,
+# and all interval calls simply rotate files. See the man page for more
+# details. The default is 0 (off).
+#
+#sync_first 0
+# If enabled, rsnapshot will move the oldest directory for each interval
+# to [interval_name].delete, then it will remove the lockfile and delete
+# that directory just before it exits. The default is 0 (off).
+#
+#use_lazy_deletes 0
+
+# Number of rsync re-tries. If you experience any network problems or
+# network card issues that tend to cause ssh to fail with errors like
+# "Corrupted MAC on input", for example, set this to a non-zero value
+# to have the rsync operation re-tried.
+#
+#rsync_numtries 0
+# LVM parameters. Used to backup with creating lvm snapshot before backup
+# and removing it after. This should ensure consistency of data in some special
+# cases
+#
+# LVM snapshot(s) size (lvcreate --size option).
+#
+#linux_lvm_snapshotsize 100M
+# Name to be used when creating the LVM logical volume snapshot(s).
+#
+#linux_lvm_snapshotname rsnapshot
+
+# Path to the LVM Volume Groups.
+#
+#linux_lvm_vgpath /dev
+# Mount point to use to temporarily mount the snapshot(s).
+#
+#linux_lvm_mountpath /path/to/mount/lvm/snapshot/during/backup
+
+###############################
+### BACKUP POINTS / SCRIPTS ###
+###############################
+
+# LOCALHOST
+backup /home/rulingcom/ localhost/
+#backup /home/ localhost/
+#backup /etc/ localhost/
+#backup /usr/local/ localhost/
+#backup /var/log/rsnapshot localhost/
+#backup /etc/passwd localhost/
+#backup /home/foo/My Documents/ localhost/
+#backup /foo/bar/ localhost/ one_fs=1,rsync_short_args=-urltvpog
+#backup_script /usr/local/bin/backup_pgsql.sh localhost/postgres/
+# You must set linux_lvm_* parameters below before using lvm snapshots
+#backup lvm://vg0/xen-home/ lvm-vg0/xen-home/
+# EXAMPLE.COM
+#backup_exec /bin/date "+ backup of example.com started at %c"
+#backup root@example.com:/home/ example.com/ +rsync_long_args=--bwlimit=16,exclude=core
+#backup root@example.com:/etc/ example.com/ exclude=mtab,exclude=core
+#backup_exec ssh root@example.com "mysqldump -A > /var/db/dump/mysql.sql"
+#backup root@example.com:/var/db/dump/ example.com/
+#backup_exec /bin/date "+ backup of example.com ended at %c"
+
+# CVS.SOURCEFORGE.NET
+#backup_script /usr/local/bin/backup_rsnapshot_cvsroot.sh rsnapshot.cvs.sourceforge.net/
+
+# RSYNC.SAMBA.ORG
+#backup rsync://rsync.samba.org/rsyncftp/ rsync.samba.org/rsyncftp/
+