backup 2.4.5.1 → 3.0.0.build.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.infinity_test +7 -0
- data/.rspec +3 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +88 -0
- data/LICENSE.md +24 -0
- data/README.md +189 -75
- data/backup.gemspec +41 -0
- data/bin/backup +161 -90
- data/lib/backup.rb +133 -117
- data/lib/backup/archive.rb +54 -0
- data/lib/backup/cli.rb +50 -0
- data/lib/backup/compressor/base.rb +17 -0
- data/lib/backup/compressor/gzip.rb +61 -0
- data/lib/backup/configuration/base.rb +7 -67
- data/lib/backup/configuration/compressor/base.rb +10 -0
- data/lib/backup/configuration/compressor/gzip.rb +23 -0
- data/lib/backup/configuration/database/base.rb +18 -0
- data/lib/backup/configuration/database/mongodb.rb +37 -0
- data/lib/backup/configuration/database/mysql.rb +37 -0
- data/lib/backup/configuration/database/postgresql.rb +37 -0
- data/lib/backup/configuration/database/redis.rb +35 -0
- data/lib/backup/configuration/encryptor/base.rb +10 -0
- data/lib/backup/configuration/encryptor/gpg.rb +17 -0
- data/lib/backup/configuration/encryptor/open_ssl.rb +26 -0
- data/lib/backup/configuration/helpers.rb +47 -17
- data/lib/backup/configuration/notifier/base.rb +39 -0
- data/lib/backup/configuration/notifier/mail.rb +52 -0
- data/lib/backup/configuration/storage/base.rb +18 -0
- data/lib/backup/configuration/storage/cloudfiles.rb +21 -0
- data/lib/backup/configuration/storage/dropbox.rb +25 -0
- data/lib/backup/configuration/storage/ftp.rb +25 -0
- data/lib/backup/configuration/storage/rsync.rb +25 -0
- data/lib/backup/configuration/storage/s3.rb +25 -0
- data/lib/backup/configuration/storage/scp.rb +25 -0
- data/lib/backup/configuration/storage/sftp.rb +25 -0
- data/lib/backup/database/base.rb +33 -0
- data/lib/backup/database/mongodb.rb +137 -0
- data/lib/backup/database/mysql.rb +104 -0
- data/lib/backup/database/postgresql.rb +111 -0
- data/lib/backup/database/redis.rb +105 -0
- data/lib/backup/encryptor/base.rb +17 -0
- data/lib/backup/encryptor/gpg.rb +78 -0
- data/lib/backup/encryptor/open_ssl.rb +67 -0
- data/lib/backup/finder.rb +39 -0
- data/lib/backup/logger.rb +80 -0
- data/lib/backup/model.rb +249 -0
- data/lib/backup/notifier/base.rb +29 -0
- data/lib/backup/notifier/binder.rb +32 -0
- data/lib/backup/notifier/mail.rb +141 -0
- data/lib/backup/notifier/templates/notify_failure.erb +31 -0
- data/lib/backup/notifier/templates/notify_success.erb +16 -0
- data/lib/backup/storage/base.rb +60 -3
- data/lib/backup/storage/cloudfiles.rb +85 -6
- data/lib/backup/storage/dropbox.rb +74 -4
- data/lib/backup/storage/ftp.rb +103 -27
- data/lib/backup/storage/object.rb +45 -0
- data/lib/backup/storage/rsync.rb +100 -0
- data/lib/backup/storage/s3.rb +100 -7
- data/lib/backup/storage/scp.rb +94 -19
- data/lib/backup/storage/sftp.rb +94 -19
- data/lib/backup/version.rb +70 -1
- data/lib/templates/archive +4 -0
- data/lib/templates/compressor/gzip +4 -0
- data/lib/templates/database/mongodb +10 -0
- data/lib/templates/database/mysql +11 -0
- data/lib/templates/database/postgresql +11 -0
- data/lib/templates/database/redis +10 -0
- data/lib/templates/encryptor/gpg +9 -0
- data/lib/templates/encryptor/openssl +5 -0
- data/lib/templates/notifier/mail +14 -0
- data/lib/templates/readme +15 -0
- data/lib/templates/storage/cloudfiles +7 -0
- data/lib/templates/storage/dropbox +8 -0
- data/lib/templates/storage/ftp +8 -0
- data/lib/templates/storage/rsync +7 -0
- data/lib/templates/storage/s3 +8 -0
- data/lib/templates/storage/scp +8 -0
- data/lib/templates/storage/sftp +8 -0
- data/spec/archive_spec.rb +53 -0
- data/spec/backup_spec.rb +11 -0
- data/spec/compressor/gzip_spec.rb +59 -0
- data/spec/configuration/base_spec.rb +35 -0
- data/spec/configuration/compressor/gzip_spec.rb +28 -0
- data/spec/configuration/database/base_spec.rb +16 -0
- data/spec/configuration/database/mongodb_spec.rb +30 -0
- data/spec/configuration/database/mysql_spec.rb +32 -0
- data/spec/configuration/database/postgresql_spec.rb +32 -0
- data/spec/configuration/database/redis_spec.rb +30 -0
- data/spec/configuration/encryptor/gpg_spec.rb +25 -0
- data/spec/configuration/encryptor/open_ssl_spec.rb +31 -0
- data/spec/configuration/notifier/mail_spec.rb +32 -0
- data/spec/configuration/storage/cloudfiles_spec.rb +34 -0
- data/spec/configuration/storage/dropbox_spec.rb +40 -0
- data/spec/configuration/storage/ftp_spec.rb +40 -0
- data/spec/configuration/storage/rsync_spec.rb +37 -0
- data/spec/configuration/storage/s3_spec.rb +37 -0
- data/spec/configuration/storage/scp_spec.rb +40 -0
- data/spec/configuration/storage/sftp_spec.rb +40 -0
- data/spec/database/base_spec.rb +30 -0
- data/spec/database/mongodb_spec.rb +144 -0
- data/spec/database/mysql_spec.rb +150 -0
- data/spec/database/postgresql_spec.rb +164 -0
- data/spec/database/redis_spec.rb +122 -0
- data/spec/encryptor/gpg_spec.rb +57 -0
- data/spec/encryptor/open_ssl_spec.rb +102 -0
- data/spec/logger_spec.rb +37 -0
- data/spec/model_spec.rb +236 -0
- data/spec/notifier/mail_spec.rb +97 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/storage/base_spec.rb +33 -0
- data/spec/storage/cloudfiles_spec.rb +102 -0
- data/spec/storage/dropbox_spec.rb +89 -0
- data/spec/storage/ftp_spec.rb +133 -0
- data/spec/storage/object_spec.rb +74 -0
- data/spec/storage/rsync_spec.rb +115 -0
- data/spec/storage/s3_spec.rb +110 -0
- data/spec/storage/scp_spec.rb +129 -0
- data/spec/storage/sftp_spec.rb +125 -0
- data/spec/version_spec.rb +32 -0
- metadata +139 -123
- data/CHANGELOG +0 -131
- data/LICENSE +0 -20
- data/generators/backup/backup_generator.rb +0 -69
- data/generators/backup/templates/backup.rake +0 -56
- data/generators/backup/templates/backup.rb +0 -253
- data/generators/backup/templates/create_backup_tables.rb +0 -18
- data/generators/backup_update/backup_update_generator.rb +0 -50
- data/generators/backup_update/templates/migrations/update_backup_tables.rb +0 -27
- data/lib/backup/adapters/archive.rb +0 -34
- data/lib/backup/adapters/base.rb +0 -167
- data/lib/backup/adapters/custom.rb +0 -41
- data/lib/backup/adapters/mongo_db.rb +0 -139
- data/lib/backup/adapters/mysql.rb +0 -60
- data/lib/backup/adapters/postgresql.rb +0 -60
- data/lib/backup/adapters/sqlite.rb +0 -25
- data/lib/backup/command_helper.rb +0 -14
- data/lib/backup/configuration/adapter.rb +0 -21
- data/lib/backup/configuration/adapter_options.rb +0 -8
- data/lib/backup/configuration/attributes.rb +0 -19
- data/lib/backup/configuration/mail.rb +0 -20
- data/lib/backup/configuration/smtp.rb +0 -8
- data/lib/backup/configuration/storage.rb +0 -8
- data/lib/backup/connection/cloudfiles.rb +0 -75
- data/lib/backup/connection/dropbox.rb +0 -63
- data/lib/backup/connection/s3.rb +0 -88
- data/lib/backup/core_ext/object.rb +0 -5
- data/lib/backup/environment/base.rb +0 -12
- data/lib/backup/environment/rails_configuration.rb +0 -15
- data/lib/backup/environment/unix_configuration.rb +0 -109
- data/lib/backup/mail/base.rb +0 -97
- data/lib/backup/mail/mail.txt +0 -7
- data/lib/backup/record/base.rb +0 -65
- data/lib/backup/record/cloudfiles.rb +0 -28
- data/lib/backup/record/dropbox.rb +0 -27
- data/lib/backup/record/ftp.rb +0 -39
- data/lib/backup/record/local.rb +0 -26
- data/lib/backup/record/s3.rb +0 -25
- data/lib/backup/record/scp.rb +0 -33
- data/lib/backup/record/sftp.rb +0 -38
- data/lib/backup/storage/local.rb +0 -22
- data/lib/generators/backup/USAGE +0 -10
- data/lib/generators/backup/backup_generator.rb +0 -47
- data/lib/generators/backup/templates/backup.rake +0 -56
- data/lib/generators/backup/templates/backup.rb +0 -236
- data/lib/generators/backup/templates/create_backup_tables.rb +0 -18
- data/setup/backup.rb +0 -257
- data/setup/backup.sqlite3 +0 -0
@@ -1,27 +0,0 @@
|
|
1
|
-
class UpdateBackupTables < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
change_table :backup do |t|
|
4
|
-
t.rename :storage, :type # will use STI from now
|
5
|
-
t.string :md5sum
|
6
|
-
end
|
7
|
-
|
8
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='Backup::Record::FTP' WHERE type='ftp'"
|
9
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='Backup::Record::Local' WHERE type='local'"
|
10
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='Backup::Record::S3' WHERE type='s3'"
|
11
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='Backup::Record::SCP' WHERE type='scp'"
|
12
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='Backup::Record::SFTP' WHERE type='sftp'"
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.down
|
16
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='ftp' WHERE type='Backup::Record::FTP'"
|
17
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='local' WHERE type='Backup::Record::Local'"
|
18
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='s3' WHERE type='Backup::Record::S3'"
|
19
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='scp' WHERE type='Backup::Record::SCP'"
|
20
|
-
ActiveRecord::Base.connection.execute "UPDATE backup SET type='sftp' WHERE type='Backup::Record::SFTP'"
|
21
|
-
|
22
|
-
change_table :backup do |t|
|
23
|
-
t.rename :type, :storage
|
24
|
-
t.remove :md5sum
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Backup
|
2
|
-
module Adapters
|
3
|
-
class Archive < Backup::Adapters::Base
|
4
|
-
|
5
|
-
attr_accessor :files, :exclude
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
# Archives and Compresses all files
|
10
|
-
def perform
|
11
|
-
log system_messages[:archiving]; log system_messages[:compressing]
|
12
|
-
run "tar -czf #{File.join(tmp_path, compressed_file)} #{exclude_files} #{tar_files}"
|
13
|
-
end
|
14
|
-
|
15
|
-
def load_settings
|
16
|
-
self.files = procedure.get_adapter_configuration.attributes['files']
|
17
|
-
self.exclude = procedure.get_adapter_configuration.attributes['exclude']
|
18
|
-
end
|
19
|
-
|
20
|
-
def performed_file_extension
|
21
|
-
".tar"
|
22
|
-
end
|
23
|
-
|
24
|
-
def tar_files
|
25
|
-
[*files].map{|f| f.gsub(' ', '\ ')}.join(' ')
|
26
|
-
end
|
27
|
-
|
28
|
-
def exclude_files
|
29
|
-
[*exclude].compact.map{|x| "--exclude=#{x}"}.join(' ')
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/backup/adapters/base.rb
DELETED
@@ -1,167 +0,0 @@
|
|
1
|
-
require 'tempfile'
|
2
|
-
|
3
|
-
module Backup
|
4
|
-
module Adapters
|
5
|
-
class Base
|
6
|
-
|
7
|
-
include Backup::CommandHelper
|
8
|
-
|
9
|
-
attr_accessor :procedure, :timestamp, :options, :tmp_path, :encrypt_with_password, :encrypt_with_gpg_public_key, :keep_backups, :trigger
|
10
|
-
|
11
|
-
# IMPORTANT
|
12
|
-
# final_file must have the value of the final filename result
|
13
|
-
# so if a file gets compressed, then the file could look like this:
|
14
|
-
# myfile.gz
|
15
|
-
#
|
16
|
-
# and if a file afterwards gets encrypted, the file will look like:
|
17
|
-
# myfile.gz.enc (with a password)
|
18
|
-
# myfile.gz.gpg (with a gpg public key)
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# It is important that, whatever the final filename of the file will be, that :final_file will contain it.
|
22
|
-
attr_accessor :performed_file, :compressed_file, :encrypted_file, :final_file
|
23
|
-
|
24
|
-
# Initializes the Backup Process
|
25
|
-
#
|
26
|
-
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
27
|
-
# Then it will add it's own settings.
|
28
|
-
#
|
29
|
-
# First it will call the 'perform' method. This method is concerned with the backup, and must
|
30
|
-
# be implemented by derived classes!
|
31
|
-
# Then it will optionally encrypt the backed up file
|
32
|
-
# Then it will store it to the specified storage location
|
33
|
-
# Then it will record the data to the database
|
34
|
-
# Once this is all done, all the temporary files will be removed
|
35
|
-
#
|
36
|
-
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
37
|
-
def initialize(trigger, procedure)
|
38
|
-
self.trigger = trigger
|
39
|
-
self.procedure = procedure
|
40
|
-
self.timestamp = Time.now.strftime("%Y%m%d%H%M%S")
|
41
|
-
self.tmp_path = File.join(BACKUP_PATH.gsub(' ', '\ '), 'tmp', 'backup', trigger)
|
42
|
-
self.encrypt_with_password = procedure.attributes['encrypt_with_password']
|
43
|
-
self.encrypt_with_gpg_public_key = procedure.attributes['encrypt_with_gpg_public_key']
|
44
|
-
self.keep_backups = procedure.attributes['keep_backups']
|
45
|
-
|
46
|
-
self.performed_file = "#{timestamp}.#{trigger.gsub(' ', '-')}#{performed_file_extension}"
|
47
|
-
self.compressed_file = "#{performed_file}.gz"
|
48
|
-
self.final_file = compressed_file
|
49
|
-
|
50
|
-
begin
|
51
|
-
create_tmp_folder
|
52
|
-
load_settings # if respond_to?(:load_settings)
|
53
|
-
handle_before_backup
|
54
|
-
perform
|
55
|
-
encrypt
|
56
|
-
store
|
57
|
-
handle_after_backup
|
58
|
-
record
|
59
|
-
notify
|
60
|
-
ensure
|
61
|
-
remove_tmp_files
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
# Creates the temporary folder for the specified adapter
|
66
|
-
def create_tmp_folder
|
67
|
-
#need to create with universal privlages as some backup tasks might create this path under sudo
|
68
|
-
run "mkdir -m 0777 -p #{tmp_path.sub(/\/[^\/]+$/, '')}" #this is the parent to the tmp_path
|
69
|
-
run "mkdir -m 0777 -p #{tmp_path}" #the temp path dir
|
70
|
-
end
|
71
|
-
|
72
|
-
# TODO make methods in derived classes public? respond_to cannot identify private methods
|
73
|
-
def load_settings
|
74
|
-
end
|
75
|
-
|
76
|
-
def skip_backup(msg)
|
77
|
-
log "Terminating backup early because: #{msg}"
|
78
|
-
exit 1
|
79
|
-
end
|
80
|
-
|
81
|
-
# Removes the files inside the temporary folder
|
82
|
-
def remove_tmp_files
|
83
|
-
run "rm -r #{File.join(tmp_path)}" if File.exists?(tmp_path) #just in case there isn't one because the process was skipped
|
84
|
-
end
|
85
|
-
|
86
|
-
def handle_before_backup
|
87
|
-
return unless self.procedure.before_backup_block
|
88
|
-
log system_messages[:before_backup_hook]
|
89
|
-
#run it through this instance so the block is run as a part of this adapter...which means it has access to all sorts of sutff
|
90
|
-
self.instance_eval &self.procedure.before_backup_block
|
91
|
-
end
|
92
|
-
|
93
|
-
def handle_after_backup
|
94
|
-
return unless self.procedure.after_backup_block
|
95
|
-
log system_messages[:after_backup_hook]
|
96
|
-
#run it through this instance so the block is run as a part of this adapter...which means it has access to all sorts of sutff
|
97
|
-
self.instance_eval &self.procedure.after_backup_block
|
98
|
-
end
|
99
|
-
|
100
|
-
# Encrypts the archive file
|
101
|
-
def encrypt
|
102
|
-
if encrypt_with_gpg_public_key.is_a?(String) && encrypt_with_password.is_a?(String)
|
103
|
-
puts "both 'encrypt_with_gpg_public_key' and 'encrypt_with_password' are set. Please choose one or the other. Exiting."
|
104
|
-
exit 1
|
105
|
-
end
|
106
|
-
|
107
|
-
if encrypt_with_gpg_public_key.is_a?(String)
|
108
|
-
if `which gpg` == ''
|
109
|
-
puts "Encrypting with a GPG public key requires that gpg be in your public path. gpg was not found. Exiting"
|
110
|
-
exit 1
|
111
|
-
end
|
112
|
-
log system_messages[:encrypting_w_key]
|
113
|
-
self.encrypted_file = "#{self.final_file}.gpg"
|
114
|
-
|
115
|
-
# tmp_file = Tempfile.new('backup.pub'){ |tmp_file| tmp_file << encrypt_with_gpg_public_key }
|
116
|
-
tmp_file = Tempfile.new('backup.pub')
|
117
|
-
tmp_file << encrypt_with_gpg_public_key
|
118
|
-
tmp_file.close
|
119
|
-
# that will either say the key was added OR that it wasn't needed, but either way we need to parse for the uid
|
120
|
-
# which will be wrapped in '<' and '>' like <someone_famous@me.com>
|
121
|
-
encryptionKeyId = `gpg --import #{tmp_file.path} 2>&1`.match(/<(.+)>/)[1]
|
122
|
-
run "gpg -e --trust-model always -o #{File.join(tmp_path, encrypted_file)} -r '#{encryptionKeyId}' #{File.join(tmp_path, compressed_file)}"
|
123
|
-
elsif encrypt_with_password.is_a?(String)
|
124
|
-
log system_messages[:encrypting_w_pass]
|
125
|
-
self.encrypted_file = "#{self.final_file}.enc"
|
126
|
-
run "openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password}"
|
127
|
-
end
|
128
|
-
self.final_file = encrypted_file if encrypted_file
|
129
|
-
end
|
130
|
-
|
131
|
-
# Initializes the storing process
|
132
|
-
def store
|
133
|
-
procedure.initialize_storage(self)
|
134
|
-
end
|
135
|
-
|
136
|
-
# Records data on every individual file to the database
|
137
|
-
def record
|
138
|
-
record = procedure.initialize_record
|
139
|
-
record.load_adapter(self)
|
140
|
-
record.save
|
141
|
-
end
|
142
|
-
|
143
|
-
# Delivers a notification by email regarding the successfully stored backup
|
144
|
-
def notify
|
145
|
-
if Backup::Mail::Base.setup?
|
146
|
-
Backup::Mail::Base.notify!(self)
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
def system_messages
|
151
|
-
{ :compressing => "Compressing backup..",
|
152
|
-
:archiving => "Archiving backup..",
|
153
|
-
:encrypting_w_pass => "Encrypting backup with password..",
|
154
|
-
:encrypting_w_key => "Encrypting backup with gpg public key..",
|
155
|
-
:mysqldump => "Creating MySQL dump..",
|
156
|
-
:mongo_dump => "Creating MongoDB dump..",
|
157
|
-
:mongo_copy => "Creating MongoDB disk level copy..",
|
158
|
-
:before_backup_hook => "Running before backup hook..",
|
159
|
-
:after_backup_hook => "Running after backup hook..",
|
160
|
-
:pgdump => "Creating PostgreSQL dump..",
|
161
|
-
:sqlite => "Copying and compressing SQLite database..",
|
162
|
-
:commands => "Executing commands.." }
|
163
|
-
end
|
164
|
-
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
module Backup
|
2
|
-
module Adapters
|
3
|
-
class Custom < Backup::Adapters::Base
|
4
|
-
|
5
|
-
attr_accessor :commands
|
6
|
-
|
7
|
-
private
|
8
|
-
|
9
|
-
# Execute any given commands, then archive and compress every folder/file
|
10
|
-
def perform
|
11
|
-
execute_commands
|
12
|
-
targz
|
13
|
-
end
|
14
|
-
|
15
|
-
# Executes the commands
|
16
|
-
def execute_commands
|
17
|
-
return unless commands
|
18
|
-
log system_messages[:commands]
|
19
|
-
[*commands].each do |command|
|
20
|
-
run "#{command.gsub(':tmp_path', tmp_path)}"
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Archives and Compresses
|
25
|
-
def targz
|
26
|
-
log system_messages[:archiving]; log system_messages[:compressing]
|
27
|
-
run "tar -czf #{File.join(tmp_path, compressed_file)} #{File.join(tmp_path, '*')}"
|
28
|
-
end
|
29
|
-
|
30
|
-
def performed_file_extension
|
31
|
-
".tar"
|
32
|
-
end
|
33
|
-
|
34
|
-
# Loads the initial settings
|
35
|
-
def load_settings
|
36
|
-
self.commands = procedure.get_adapter_configuration.attributes['commands']
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
module Backup
|
2
|
-
module Adapters
|
3
|
-
class MongoDB < Backup::Adapters::Base
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
attr_accessor :user, :password, :database, :collections, :host, :port, :additional_options, :backup_method
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
BACKUP_METHOD_OPTIONS = [:mongodump, :disk_copy]
|
11
|
-
|
12
|
-
# Dumps and Compresses the Mongodump file
|
13
|
-
def perform
|
14
|
-
tmp_mongo_dir = "mongodump-#{Time.now.strftime("%Y%m%d%H%M%S")}"
|
15
|
-
tmp_dump_dir = File.join(tmp_path, tmp_mongo_dir)
|
16
|
-
|
17
|
-
case self.backup_method.to_sym
|
18
|
-
when :mongodump
|
19
|
-
#this is the default options
|
20
|
-
# PROS:
|
21
|
-
# * non-locking
|
22
|
-
# * much smaller archive sizes
|
23
|
-
# * can specifically target different databases or collections to dump
|
24
|
-
# * de-fragements the datastore
|
25
|
-
# * don't need to run under sudo
|
26
|
-
# * simple logic
|
27
|
-
# CONS:
|
28
|
-
# * a bit longer to restore as you have to do an import
|
29
|
-
# * does not include indexes or other meta data
|
30
|
-
log system_messages[:mongo_dump]
|
31
|
-
exit 1 unless run "#{mongodump} #{mongodump_options} #{collections_to_include} -o #{tmp_dump_dir} #{additional_options} > /dev/null 2>&1"
|
32
|
-
when :disk_copy
|
33
|
-
#this is a bit more complicated AND potentially a lot riskier:
|
34
|
-
# PROS:
|
35
|
-
# * byte level copy, so it includes all the indexes, meta data, etc
|
36
|
-
# * fast recovery; you just copy the files into place and startup mongo
|
37
|
-
# CONS:
|
38
|
-
# * locks the database, so ONLY use against a slave instance
|
39
|
-
# * copies everything; cannot specify a collection or a database
|
40
|
-
# * will probably need to run under sudo as the mongodb db_path file is probably under a different owner.
|
41
|
-
# If you do run under sudo, you will probably need to run rake RAILS_ENV=... if you aren't already
|
42
|
-
# * the logic is a bit brittle...
|
43
|
-
log system_messages[:mongo_copy]
|
44
|
-
|
45
|
-
cmd = "#{mongo} #{mongo_disk_copy_options} --quiet --eval 'printjson(db.isMaster());' admin"
|
46
|
-
output = JSON.parse(run(cmd, :exit_on_failure => true))
|
47
|
-
if output['ismaster']
|
48
|
-
puts "You cannot run in disk_copy mode against a master instance. This mode will lock the database. Please use :mongodump instead."
|
49
|
-
exit 1
|
50
|
-
end
|
51
|
-
|
52
|
-
begin
|
53
|
-
cmd = "#{mongo} #{mongo_disk_copy_options} --quiet --eval 'db.runCommand({fsync : 1, lock : 1}); printjson(db.runCommand({getCmdLineOpts:1}));' admin"
|
54
|
-
output = JSON.parse(run(cmd, :exit_on_failure => true))
|
55
|
-
|
56
|
-
#lets go find the dbpath. it is either going to be in the argv just returned OR we are going to have to parse through the mongo config file
|
57
|
-
cmd = "mongo --quiet --eval 'printjson(db.runCommand({getCmdLineOpts:1}));' admin"
|
58
|
-
output = JSON.parse(run(cmd, :exit_on_failure => true))
|
59
|
-
#see if --dbpath was passed in
|
60
|
-
db_path = output['argv'][output['argv'].index('--dbpath') + 1] if output['argv'].index('--dbpath')
|
61
|
-
#see if --config is passed in, and if so, lets parse it
|
62
|
-
db_path ||= $1 if output['argv'].index('--config') && File.read(output['argv'][output['argv'].index('--config') + 1]) =~ /dbpath\s*=\s*([^\s]*)/
|
63
|
-
db_path ||= "/data/db/" #mongo's default path
|
64
|
-
run "cp -rp #{db_path} #{tmp_dump_dir}"
|
65
|
-
ensure
|
66
|
-
#attempting to unlock
|
67
|
-
cmd = "#{mongo} #{mongo_disk_copy_options} --quiet --eval 'printjson(db.currentOp());' admin"
|
68
|
-
output = JSON.parse(run(cmd, :exit_on_failure => true))
|
69
|
-
(output['fsyncLock'] || 1).to_i.times do
|
70
|
-
run "#{mongo} #{mongo_disk_copy_options} --quiet --eval 'db.$cmd.sys.unlock.findOne();' admin"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
else
|
74
|
-
puts "you did not enter a valid backup_method option. Your choices are: #{BACKUP_METHOD_OPTIONS.join(', ')}"
|
75
|
-
exit 1
|
76
|
-
end
|
77
|
-
|
78
|
-
log system_messages[:compressing]
|
79
|
-
run "tar -cz -C #{tmp_path} -f #{File.join(tmp_path, compressed_file)} #{tmp_mongo_dir}"
|
80
|
-
end
|
81
|
-
|
82
|
-
def mongodump
|
83
|
-
cmd = run("which mongodump").chomp
|
84
|
-
cmd = 'mongodump' if cmd.empty?
|
85
|
-
cmd
|
86
|
-
end
|
87
|
-
|
88
|
-
def mongo
|
89
|
-
cmd = run("which mongo").chomp
|
90
|
-
cmd = 'mongo' if cmd.empty?
|
91
|
-
cmd
|
92
|
-
end
|
93
|
-
|
94
|
-
def performed_file_extension
|
95
|
-
".tar"
|
96
|
-
end
|
97
|
-
|
98
|
-
# Loads the initial settings
|
99
|
-
def load_settings
|
100
|
-
%w(user password database collections additional_options backup_method).each do |attribute|
|
101
|
-
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
102
|
-
end
|
103
|
-
|
104
|
-
%w(host port).each do |attribute|
|
105
|
-
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
106
|
-
end
|
107
|
-
|
108
|
-
self.backup_method ||= :mongodump
|
109
|
-
end
|
110
|
-
|
111
|
-
# Returns a list of options in Mongodump syntax
|
112
|
-
def mongodump_options
|
113
|
-
options = String.new
|
114
|
-
options += " --username='#{user}' " unless user.blank?
|
115
|
-
options += " --password='#{password}' " unless password.blank?
|
116
|
-
options += " --host='#{host}' " unless host.blank?
|
117
|
-
options += " --port='#{port}' " unless port.blank?
|
118
|
-
options += " --db='#{database}' " unless database.blank?
|
119
|
-
options
|
120
|
-
end
|
121
|
-
|
122
|
-
def mongo_disk_copy_options
|
123
|
-
options = String.new
|
124
|
-
options += " --username='#{user}' " unless user.blank?
|
125
|
-
options += " --password='#{password}' " unless password.blank?
|
126
|
-
options += " --host='#{host}' " unless host.blank?
|
127
|
-
options += " --port='#{port}' " unless port.blank?
|
128
|
-
options
|
129
|
-
end
|
130
|
-
|
131
|
-
# Returns a list of collections to include in Mongodump syntax
|
132
|
-
def collections_to_include
|
133
|
-
return "" unless collections
|
134
|
-
"--collection #{[*collections].join(" ")}"
|
135
|
-
end
|
136
|
-
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module Backup
|
2
|
-
module Adapters
|
3
|
-
class MySQL < Backup::Adapters::Base
|
4
|
-
|
5
|
-
attr_accessor :user, :password, :database, :skip_tables, :host, :port, :socket, :additional_options, :tables
|
6
|
-
|
7
|
-
private
|
8
|
-
|
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
|
-
|
15
|
-
def mysqldump
|
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
|
20
|
-
end
|
21
|
-
|
22
|
-
def performed_file_extension
|
23
|
-
".sql"
|
24
|
-
end
|
25
|
-
|
26
|
-
# Loads the initial settings
|
27
|
-
def load_settings
|
28
|
-
%w(user password database tables skip_tables additional_options).each do |attribute|
|
29
|
-
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
30
|
-
end
|
31
|
-
|
32
|
-
%w(host port socket).each do |attribute|
|
33
|
-
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Returns a list of options in MySQL syntax
|
38
|
-
def options
|
39
|
-
options = String.new
|
40
|
-
options += " --host='#{host}' " unless host.blank?
|
41
|
-
options += " --port='#{port}' " unless port.blank?
|
42
|
-
options += " --socket='#{socket}' " unless socket.blank?
|
43
|
-
options
|
44
|
-
end
|
45
|
-
|
46
|
-
# Returns a list of tables to skip in MySQL syntax
|
47
|
-
def tables_to_skip
|
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(" ")
|
56
|
-
end
|
57
|
-
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|