backup 2.3.1 → 2.3.2.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +16 -1
- data/README.textile +42 -177
- data/bin/backup +14 -17
- data/generators/backup/templates/config/backup.rb +26 -6
- data/generators/backup/templates/migrations/create_backup_tables.rb +3 -2
- data/generators/backup/templates/tasks/backup.rake +14 -17
- data/generators/backup_update/backup_update_generator.rb +50 -0
- data/generators/backup_update/templates/migrations/update_backup_tables.rb +27 -0
- data/lib/backup.rb +31 -30
- data/lib/backup/adapters/archive.rb +19 -54
- data/lib/backup/adapters/base.rb +55 -35
- data/lib/backup/adapters/custom.rb +15 -53
- data/lib/backup/adapters/mysql.rb +24 -55
- data/lib/backup/adapters/postgresql.rb +19 -54
- data/lib/backup/adapters/sqlite.rb +25 -0
- data/lib/backup/command_helper.rb +11 -0
- data/lib/backup/configuration/adapter.rb +4 -11
- data/lib/backup/configuration/adapter_options.rb +3 -14
- data/lib/backup/configuration/attributes.rb +19 -0
- data/lib/backup/configuration/base.rb +26 -9
- data/lib/backup/configuration/mail.rb +3 -9
- data/lib/backup/configuration/smtp.rb +3 -14
- data/lib/backup/configuration/storage.rb +3 -12
- data/lib/backup/connection/s3.rb +3 -1
- data/lib/backup/environment/unix.rb +4 -4
- data/lib/backup/mail/base.rb +8 -2
- data/lib/backup/mail/mail.txt +3 -3
- data/lib/backup/record/base.rb +65 -0
- data/lib/backup/record/ftp.rb +10 -69
- data/lib/backup/record/local.rb +26 -0
- data/lib/backup/record/s3.rb +9 -63
- data/lib/backup/record/scp.rb +9 -64
- data/lib/backup/record/sftp.rb +10 -68
- data/lib/backup/storage/ftp.rb +3 -1
- data/lib/backup/storage/local.rb +24 -0
- data/lib/backup/storage/s3.rb +3 -1
- data/lib/backup/storage/scp.rb +3 -1
- data/lib/backup/storage/sftp.rb +3 -1
- data/setup/backup.rb +27 -6
- data/setup/backup.sqlite3 +0 -0
- metadata +130 -60
- data/.document +0 -5
- data/.gitignore +0 -5
- data/Rakefile +0 -70
- data/backup.gemspec +0 -111
@@ -2,78 +2,40 @@ module Backup
|
|
2
2
|
module Adapters
|
3
3
|
class Custom < Backup::Adapters::Base
|
4
4
|
|
5
|
-
attr_accessor :
|
5
|
+
attr_accessor :commands
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
# First it will execute any given commands
|
13
|
-
# Then it will archive and compress every folder/file
|
14
|
-
# Then it will optionally encrypt the backed up file
|
15
|
-
# Then it will store it to the specified storage location
|
16
|
-
# Then it will record the data to the database
|
17
|
-
# Once this is all done, all the temporary files will be removed
|
18
|
-
#
|
19
|
-
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
20
|
-
def initialize(trigger, procedure)
|
21
|
-
super
|
22
|
-
load_settings
|
23
|
-
|
24
|
-
begin
|
7
|
+
private
|
8
|
+
|
9
|
+
# Execute any given commands, then archive and compress every folder/file
|
10
|
+
def perform
|
25
11
|
execute_commands
|
26
12
|
targz
|
27
|
-
encrypt
|
28
|
-
store
|
29
|
-
record
|
30
|
-
notify
|
31
|
-
ensure
|
32
|
-
remove_tmp_files
|
33
13
|
end
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
14
|
|
38
15
|
# Executes the commands
|
39
16
|
def execute_commands
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
elsif commands.is_a?(String)
|
46
|
-
puts system_messages[:commands]
|
47
|
-
%x{ #{commands.gsub(':tmp_path', tmp_path)} }
|
17
|
+
return unless commands
|
18
|
+
log system_messages[:commands]
|
19
|
+
[*commands].each do |command|
|
20
|
+
run "#{command.gsub(':tmp_path', tmp_path)}"
|
48
21
|
end
|
49
22
|
end
|
50
23
|
|
51
24
|
# Archives and Compresses
|
52
25
|
def targz
|
53
|
-
|
54
|
-
|
26
|
+
log system_messages[:archiving]; log system_messages[:compressing]
|
27
|
+
run "tar -czf #{File.join(tmp_path, compressed_file)} #{File.join(tmp_path, '*')}"
|
55
28
|
end
|
56
29
|
|
57
|
-
|
58
|
-
|
59
|
-
if encrypt_with_password.is_a?(String)
|
60
|
-
puts system_messages[:encrypting]
|
61
|
-
%x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
|
62
|
-
self.final_file = encrypted_file
|
63
|
-
end
|
30
|
+
def performed_file_extension
|
31
|
+
".tar"
|
64
32
|
end
|
65
|
-
|
33
|
+
|
66
34
|
# Loads the initial settings
|
67
35
|
def load_settings
|
68
|
-
self.trigger = procedure.trigger
|
69
36
|
self.commands = procedure.get_adapter_configuration.attributes['commands']
|
70
|
-
|
71
|
-
self.archived_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.tar"
|
72
|
-
self.compressed_file = "#{archived_file}.gz"
|
73
|
-
self.encrypted_file = "#{compressed_file}.enc"
|
74
|
-
self.final_file = compressed_file
|
75
37
|
end
|
76
38
|
|
77
39
|
end
|
78
40
|
end
|
79
|
-
end
|
41
|
+
end
|
@@ -2,68 +2,36 @@ module Backup
|
|
2
2
|
module Adapters
|
3
3
|
class MySQL < Backup::Adapters::Base
|
4
4
|
|
5
|
-
attr_accessor :
|
6
|
-
|
7
|
-
# Initializes the Backup Process
|
8
|
-
#
|
9
|
-
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
-
# Then it will add it's own settings.
|
11
|
-
#
|
12
|
-
# First it will create a compressed MySQL dump
|
13
|
-
# Then it will optionally encrypt the backed up file
|
14
|
-
# Then it will store it to the specified storage location
|
15
|
-
# Then it will record the data to the database
|
16
|
-
# Once this is all done, all the temporary files will be removed
|
17
|
-
#
|
18
|
-
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
19
|
-
def initialize(trigger, procedure)
|
20
|
-
super
|
21
|
-
load_settings
|
22
|
-
|
23
|
-
begin
|
24
|
-
mysqldump
|
25
|
-
encrypt
|
26
|
-
store
|
27
|
-
record
|
28
|
-
notify
|
29
|
-
ensure
|
30
|
-
remove_tmp_files
|
31
|
-
end
|
32
|
-
end
|
5
|
+
attr_accessor :user, :password, :database, :skip_tables, :host, :port, :socket, :additional_options, :tables
|
33
6
|
|
34
7
|
private
|
35
|
-
|
8
|
+
|
36
9
|
# Dumps and Compresses the MySQL file
|
10
|
+
def perform
|
11
|
+
log system_messages[:mysqldump]; log system_messages[:compressing]
|
12
|
+
run "#{mysqldump} -u #{user} --password='#{password}' #{options} #{additional_options} #{database} #{tables_to_include} #{tables_to_skip} | gzip -f --best > #{File.join(tmp_path, compressed_file)}"
|
13
|
+
end
|
14
|
+
|
37
15
|
def mysqldump
|
38
|
-
|
39
|
-
|
16
|
+
# try to determine the full path, and fall back to myqsldump if not found
|
17
|
+
cmd = `which mysqldump`.chomp
|
18
|
+
cmd = 'mysqldump' if cmd.empty?
|
19
|
+
cmd
|
40
20
|
end
|
41
21
|
|
42
|
-
|
43
|
-
|
44
|
-
if encrypt_with_password.is_a?(String)
|
45
|
-
puts system_messages[:encrypting]
|
46
|
-
%x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
|
47
|
-
self.final_file = encrypted_file
|
48
|
-
end
|
22
|
+
def performed_file_extension
|
23
|
+
".sql"
|
49
24
|
end
|
50
|
-
|
25
|
+
|
51
26
|
# Loads the initial settings
|
52
27
|
def load_settings
|
53
|
-
|
54
|
-
|
55
|
-
%w(user password database skip_tables additional_options).each do |attribute|
|
28
|
+
%w(user password database tables skip_tables additional_options).each do |attribute|
|
56
29
|
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
57
30
|
end
|
58
31
|
|
59
32
|
%w(host port socket).each do |attribute|
|
60
33
|
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
61
34
|
end
|
62
|
-
|
63
|
-
self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
|
64
|
-
self.compressed_file = "#{dumped_file}.gz"
|
65
|
-
self.encrypted_file = "#{compressed_file}.enc"
|
66
|
-
self.final_file = compressed_file
|
67
35
|
end
|
68
36
|
|
69
37
|
# Returns a list of options in MySQL syntax
|
@@ -77,15 +45,16 @@ module Backup
|
|
77
45
|
|
78
46
|
# Returns a list of tables to skip in MySQL syntax
|
79
47
|
def tables_to_skip
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
48
|
+
return "" unless skip_tables
|
49
|
+
[*skip_tables].map {|table| " --ignore-table='#{database}.#{table}' "}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns a list of tables to include in MySQL syntax
|
53
|
+
def tables_to_include
|
54
|
+
return "" unless tables
|
55
|
+
[*tables].join(" ")
|
87
56
|
end
|
88
57
|
|
89
58
|
end
|
90
59
|
end
|
91
|
-
end
|
60
|
+
end
|
@@ -2,56 +2,31 @@ module Backup
|
|
2
2
|
module Adapters
|
3
3
|
class PostgreSQL < Backup::Adapters::Base
|
4
4
|
|
5
|
-
attr_accessor :
|
6
|
-
|
7
|
-
# Initializes the Backup Process
|
8
|
-
#
|
9
|
-
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
10
|
-
# Then it will add it's own settings.
|
11
|
-
#
|
12
|
-
# First it will create a compressed PostgreSQL dump
|
13
|
-
# Then it will optionally encrypt the backed up file
|
14
|
-
# Then it will store it to the specified storage location
|
15
|
-
# Then it will record the data to the database
|
16
|
-
# Once this is all done, all the temporary files will be removed
|
17
|
-
#
|
18
|
-
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
19
|
-
def initialize(trigger, procedure)
|
20
|
-
super
|
21
|
-
load_settings
|
22
|
-
|
23
|
-
begin
|
24
|
-
pg_dump
|
25
|
-
encrypt
|
26
|
-
store
|
27
|
-
record
|
28
|
-
notify
|
29
|
-
ensure
|
30
|
-
remove_tmp_files
|
31
|
-
end
|
32
|
-
end
|
5
|
+
attr_accessor :user, :password, :database, :skip_tables, :host, :port, :socket, :additional_options
|
33
6
|
|
34
7
|
private
|
35
|
-
|
8
|
+
|
36
9
|
# Dumps and Compresses the PostgreSQL file
|
10
|
+
def perform
|
11
|
+
log system_messages[:pgdump]; log system_messages[:compressing]
|
12
|
+
ENV['PGPASSWORD'] = password
|
13
|
+
run "#{pg_dump} -U #{user} #{options} #{additional_options} #{tables_to_skip} #{database} | gzip -f --best > #{File.join(tmp_path, compressed_file)}"
|
14
|
+
ENV['PGPASSWORD'] = nil
|
15
|
+
end
|
16
|
+
|
37
17
|
def pg_dump
|
38
|
-
|
39
|
-
|
18
|
+
# try to determine the full path, and fall back to pg_dump if not found
|
19
|
+
cmd = `which pg_dump`.chomp
|
20
|
+
cmd = 'pg_dump' if cmd.empty?
|
21
|
+
cmd
|
40
22
|
end
|
41
23
|
|
42
|
-
|
43
|
-
|
44
|
-
if encrypt_with_password.is_a?(String)
|
45
|
-
puts system_messages[:encrypting]
|
46
|
-
%x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
|
47
|
-
self.final_file = encrypted_file
|
48
|
-
end
|
24
|
+
def performed_file_extension
|
25
|
+
".sql"
|
49
26
|
end
|
50
|
-
|
27
|
+
|
51
28
|
# Loads the initial settings
|
52
29
|
def load_settings
|
53
|
-
self.trigger = procedure.trigger
|
54
|
-
|
55
30
|
%w(user password database skip_tables additional_options).each do |attribute|
|
56
31
|
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
57
32
|
end
|
@@ -59,11 +34,6 @@ module Backup
|
|
59
34
|
%w(host port socket).each do |attribute|
|
60
35
|
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
61
36
|
end
|
62
|
-
|
63
|
-
self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
|
64
|
-
self.compressed_file = "#{dumped_file}.gz"
|
65
|
-
self.encrypted_file = "#{compressed_file}.enc"
|
66
|
-
self.final_file = compressed_file
|
67
37
|
end
|
68
38
|
|
69
39
|
# Returns a list of options in PostgreSQL syntax
|
@@ -77,15 +47,10 @@ module Backup
|
|
77
47
|
|
78
48
|
# Returns a list of tables to skip in PostgreSQL syntax
|
79
49
|
def tables_to_skip
|
80
|
-
|
81
|
-
|
82
|
-
elsif skip_tables.is_a?(String)
|
83
|
-
" -T \"#{skip_tables}\" "
|
84
|
-
else
|
85
|
-
""
|
86
|
-
end
|
50
|
+
return "" unless skip_tables
|
51
|
+
[*skip_tables].map {|table| " -T \"#{table}\" "}
|
87
52
|
end
|
88
53
|
|
89
54
|
end
|
90
55
|
end
|
91
|
-
end
|
56
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Backup
|
2
|
+
module Adapters
|
3
|
+
class SQLite < Base
|
4
|
+
|
5
|
+
attr_accessor :database
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
# Compress the sqlite file
|
10
|
+
def perform
|
11
|
+
log system_messages[:sqlite]
|
12
|
+
run "gzip -c --best #{database} > #{File.join(tmp_path, compressed_file)}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_settings
|
16
|
+
self.database = procedure.get_adapter_configuration.attributes['database']
|
17
|
+
end
|
18
|
+
|
19
|
+
def performed_file_extension
|
20
|
+
""
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,18 +1,11 @@
|
|
1
1
|
module Backup
|
2
2
|
module Configuration
|
3
3
|
class Adapter
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
%w(files user password database skip_tables commands additional_options).each do |method|
|
8
|
-
define_method method do |value|
|
9
|
-
attributes[method] = value
|
10
|
-
end
|
11
|
-
end
|
4
|
+
extend Backup::Configuration::Attributes
|
5
|
+
generate_attributes %w(files exclude user password database tables skip_tables commands additional_options)
|
12
6
|
|
13
7
|
def initialize
|
14
|
-
@
|
15
|
-
@options = Backup::Configuration::AdapterOptions.new
|
8
|
+
@options = Backup::Configuration::AdapterOptions.new
|
16
9
|
end
|
17
10
|
|
18
11
|
def options(&block)
|
@@ -25,4 +18,4 @@ module Backup
|
|
25
18
|
|
26
19
|
end
|
27
20
|
end
|
28
|
-
end
|
21
|
+
end
|
@@ -1,19 +1,8 @@
|
|
1
1
|
module Backup
|
2
2
|
module Configuration
|
3
3
|
class AdapterOptions
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
%w(host port socket).each do |method|
|
8
|
-
define_method method do |value|
|
9
|
-
attributes[method] = value
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
@attributes = {}
|
15
|
-
end
|
16
|
-
|
4
|
+
extend Backup::Configuration::Attributes
|
5
|
+
generate_attributes %w(host port socket)
|
17
6
|
end
|
18
7
|
end
|
19
|
-
end
|
8
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Backup
|
2
|
+
module Configuration
|
3
|
+
module Attributes
|
4
|
+
|
5
|
+
def generate_attributes(*attrs)
|
6
|
+
define_method :attributes do
|
7
|
+
@attributes ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
attrs.flatten.each do |att|
|
11
|
+
define_method att do |value|
|
12
|
+
self.attributes[att.to_s] = value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -1,16 +1,12 @@
|
|
1
1
|
module Backup
|
2
2
|
module Configuration
|
3
3
|
class Base
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
attributes[method] = value
|
9
|
-
end
|
10
|
-
end
|
4
|
+
extend Backup::Configuration::Attributes
|
5
|
+
generate_attributes %w(encrypt_with_password keep_backups notify)
|
6
|
+
|
7
|
+
attr_accessor :trigger, :storage_name, :adapter_name
|
11
8
|
|
12
9
|
def initialize(trigger)
|
13
|
-
@attributes = {}
|
14
10
|
@trigger = trigger
|
15
11
|
@adapter_configuration = Backup::Configuration::Adapter.new
|
16
12
|
@storage_configuration = Backup::Configuration::Storage.new
|
@@ -25,6 +21,27 @@ module Backup
|
|
25
21
|
@storage_name = storage
|
26
22
|
@storage_configuration.instance_eval &block
|
27
23
|
end
|
24
|
+
|
25
|
+
# Initializes the storing process depending on the store settings
|
26
|
+
def initialize_storage(adapter)
|
27
|
+
case @storage_name.to_sym
|
28
|
+
when :s3 then Backup::Storage::S3.new(adapter)
|
29
|
+
when :scp then Backup::Storage::SCP.new(adapter)
|
30
|
+
when :ftp then Backup::Storage::FTP.new(adapter)
|
31
|
+
when :sftp then Backup::Storage::SFTP.new(adapter)
|
32
|
+
when :local then Backup::Storage::Local.new(adapter)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize_record
|
37
|
+
case @storage_name.to_sym
|
38
|
+
when :s3 then Backup::Record::S3.new
|
39
|
+
when :scp then Backup::Record::SCP.new
|
40
|
+
when :ftp then Backup::Record::FTP.new
|
41
|
+
when :sftp then Backup::Record::SFTP.new
|
42
|
+
when :local then Backup::Record::Local.new
|
43
|
+
end
|
44
|
+
end
|
28
45
|
|
29
46
|
def get_adapter_configuration
|
30
47
|
@adapter_configuration
|
@@ -35,4 +52,4 @@ module Backup
|
|
35
52
|
end
|
36
53
|
end
|
37
54
|
end
|
38
|
-
end
|
55
|
+
end
|