backup-gundua 2.3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/CHANGELOG +77 -0
- data/LICENSE +9 -0
- data/README.textile +175 -0
- data/Rakefile +69 -0
- data/VERSION +1 -0
- data/backup.gemspec +123 -0
- data/bin/backup +124 -0
- data/generators/backup/backup_generator.rb +72 -0
- data/generators/backup/templates/config/backup.rb +202 -0
- data/generators/backup/templates/migrations/create_backup_tables.rb +18 -0
- data/generators/backup/templates/tasks/backup.rake +71 -0
- 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/adapters/archive.rb +34 -0
- data/lib/backup/adapters/base.rb +113 -0
- data/lib/backup/adapters/custom.rb +41 -0
- data/lib/backup/adapters/mysql.rb +54 -0
- data/lib/backup/adapters/postgresql.rb +56 -0
- data/lib/backup/adapters/sqlite.rb +25 -0
- data/lib/backup/command_helper.rb +11 -0
- data/lib/backup/configuration/adapter.rb +21 -0
- data/lib/backup/configuration/adapter_options.rb +8 -0
- data/lib/backup/configuration/attributes.rb +19 -0
- data/lib/backup/configuration/base.rb +55 -0
- data/lib/backup/configuration/helpers.rb +24 -0
- data/lib/backup/configuration/mail.rb +20 -0
- data/lib/backup/configuration/smtp.rb +8 -0
- data/lib/backup/configuration/storage.rb +8 -0
- data/lib/backup/connection/s3.rb +85 -0
- data/lib/backup/environment/base.rb +12 -0
- data/lib/backup/environment/rails.rb +17 -0
- data/lib/backup/environment/unix.rb +94 -0
- data/lib/backup/mail/base.rb +93 -0
- data/lib/backup/mail/mail.txt +7 -0
- data/lib/backup/record/base.rb +65 -0
- data/lib/backup/record/ftp.rb +37 -0
- data/lib/backup/record/local.rb +26 -0
- data/lib/backup/record/s3.rb +24 -0
- data/lib/backup/record/scp.rb +31 -0
- data/lib/backup/record/sftp.rb +36 -0
- data/lib/backup/storage/ftp.rb +36 -0
- data/lib/backup/storage/local.rb +24 -0
- data/lib/backup/storage/s3.rb +14 -0
- data/lib/backup/storage/scp.rb +28 -0
- data/lib/backup/storage/sftp.rb +29 -0
- data/lib/backup.rb +118 -0
- data/setup/backup.rb +202 -0
- data/setup/backup.sqlite3 +0 -0
- data/spec/configuration/attributes_spec.rb +35 -0
- metadata +185 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
# Backup Configuration File
|
2
|
+
#
|
3
|
+
# Use the "backup" block to add backup settings to the configuration file.
|
4
|
+
# The argument before the "do" in (backup "argument" do) is called a "trigger".
|
5
|
+
# This acts as the identifier for the configuration.
|
6
|
+
#
|
7
|
+
# In the example below we have a "mysql-backup-s3" trigger for the backup setting.
|
8
|
+
# All the configuration is done inside this block. To initialize the backup process for this block,
|
9
|
+
# you invoke it using the following rake task:
|
10
|
+
#
|
11
|
+
# rake backup:run trigger="mysql-backup-s3"
|
12
|
+
#
|
13
|
+
# You can add as many backup block settings as you want, just be sure every trigger is unique and you can run
|
14
|
+
# each of them separately.
|
15
|
+
#
|
16
|
+
# ADAPTERS
|
17
|
+
# - MySQL
|
18
|
+
# - PostgreSQL
|
19
|
+
# - SQLite
|
20
|
+
# - Archive
|
21
|
+
# - Custom
|
22
|
+
#
|
23
|
+
# STORAGE METHODS
|
24
|
+
# - S3 (Amazon)
|
25
|
+
# - SCP (Remote Server)
|
26
|
+
# - FTP (Remote Server)
|
27
|
+
# - SFTP (Remote Server)
|
28
|
+
# - LOCAL (Local Server)
|
29
|
+
#
|
30
|
+
# GLOBAL OPTIONS
|
31
|
+
# - Keep Backups (keep_backups)
|
32
|
+
# - Encrypt With Pasword (encrypt_with_password)
|
33
|
+
# - Notify (notify)
|
34
|
+
#
|
35
|
+
# This is the "decrypt" command for all encrypted backups:
|
36
|
+
# sudo backup --decrypt /path/to/encrypted/file
|
37
|
+
#
|
38
|
+
# Each Backup Setting can contain:
|
39
|
+
# - 1 Adapter
|
40
|
+
# - 1 Storage Method
|
41
|
+
# - Multiple Global Options
|
42
|
+
#
|
43
|
+
# The combination of these, however, do not matter! So experiment with it.
|
44
|
+
#
|
45
|
+
# You can also let Backup notify you by email on successfully created backups.
|
46
|
+
# - Just uncomment the block of code below (notifier_settings) and fill in your credentials.
|
47
|
+
# - Then for set "notify" to "true" in each (backup) block you wish to be notified of.
|
48
|
+
#
|
49
|
+
# For more information on "Backup", please refer to the wiki on github
|
50
|
+
# http://wiki.github.com/meskyanichi/backup/configuration-file
|
51
|
+
|
52
|
+
|
53
|
+
# Notifier
|
54
|
+
# Uncomment this if you want to enable notification by email on successful backup runs
|
55
|
+
# You will also have to set "notify true" inside each backup block below to enable it for that particular backup
|
56
|
+
# notifier_settings do
|
57
|
+
#
|
58
|
+
# to "example1@gmail.com"
|
59
|
+
# from "example2@gmail.com"
|
60
|
+
#
|
61
|
+
# smtp do
|
62
|
+
# host "smtp.gmail.com"
|
63
|
+
# port "587"
|
64
|
+
# username "example1@gmail.com"
|
65
|
+
# password "example1password"
|
66
|
+
# authentication "plain"
|
67
|
+
# domain "localhost.localdomain"
|
68
|
+
# tls true
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# end
|
72
|
+
|
73
|
+
|
74
|
+
# Initialize with:
|
75
|
+
# rake backup:run trigger='mysql-backup-s3'
|
76
|
+
backup 'mysql-backup-s3' do
|
77
|
+
|
78
|
+
adapter :mysql do
|
79
|
+
user 'user'
|
80
|
+
password 'password'
|
81
|
+
database 'database'
|
82
|
+
|
83
|
+
# skip_tables ['table1', 'table2', 'table3']
|
84
|
+
#
|
85
|
+
# options do
|
86
|
+
# host '123.45.678.90'
|
87
|
+
# port '80'
|
88
|
+
# socket '/tmp/socket.sock'
|
89
|
+
# end
|
90
|
+
# additional_options '--single-transaction --quick'
|
91
|
+
end
|
92
|
+
|
93
|
+
storage :s3 do
|
94
|
+
access_key_id 'access_key_id'
|
95
|
+
secret_access_key 'secret_access_key'
|
96
|
+
bucket '/bucket/backups/mysql/'
|
97
|
+
use_ssl true
|
98
|
+
end
|
99
|
+
|
100
|
+
keep_backups 25
|
101
|
+
encrypt_with_password 'password'
|
102
|
+
notify false
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Initialize with:
|
108
|
+
# rake backup:run trigger='postgresql-backup-s3'
|
109
|
+
backup 'postgresql-backup-scp' do
|
110
|
+
|
111
|
+
adapter :postgresql do
|
112
|
+
user 'user'
|
113
|
+
database 'database'
|
114
|
+
|
115
|
+
# skip_tables ['table1', 'table2', 'table3']
|
116
|
+
|
117
|
+
# options do
|
118
|
+
# host '123.45.678.90'
|
119
|
+
# port '80'
|
120
|
+
# socket '/tmp/socket.sock'
|
121
|
+
# end
|
122
|
+
# additional_options '--clean --blobs'
|
123
|
+
end
|
124
|
+
|
125
|
+
storage :scp do
|
126
|
+
ip 'example.com'
|
127
|
+
user 'user'
|
128
|
+
password 'password'
|
129
|
+
path '/var/backups/postgresql/'
|
130
|
+
end
|
131
|
+
|
132
|
+
keep_backups :all
|
133
|
+
encrypt_with_password false
|
134
|
+
notify false
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
|
139
|
+
# Initialize with:
|
140
|
+
# rake backup:run trigger='archive-backup-ftp'
|
141
|
+
backup 'archive-backup-ftp' do
|
142
|
+
|
143
|
+
adapter :archive do
|
144
|
+
files ["#{RAILS_ROOT}/log", "#{RAILS_ROOT}/db"]
|
145
|
+
end
|
146
|
+
|
147
|
+
storage :ftp do
|
148
|
+
ip 'example.com'
|
149
|
+
user 'user'
|
150
|
+
password 'password'
|
151
|
+
path '/var/backups/archive/'
|
152
|
+
end
|
153
|
+
|
154
|
+
keep_backups 10
|
155
|
+
encrypt_with_password false
|
156
|
+
notify false
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Initialize with:
|
162
|
+
# rake backup:run trigger='custom-backup-sftp'
|
163
|
+
backup 'custom-backup-sftp' do
|
164
|
+
|
165
|
+
adapter :custom do
|
166
|
+
commands \
|
167
|
+
[ "mysqldump [options] [database] > :tmp_path/my_mysql_dump.sql",
|
168
|
+
"pg_dump [options] [database] > :tmp_path/my_postgresql_dump.sql",
|
169
|
+
"any_other_db_format [options] [database] > :tmp_path/my_any_other_db_format.sql" ]
|
170
|
+
end
|
171
|
+
|
172
|
+
storage :sftp do
|
173
|
+
ip 'example.com'
|
174
|
+
user 'user'
|
175
|
+
password 'password'
|
176
|
+
path '/var/backups/custom/'
|
177
|
+
end
|
178
|
+
|
179
|
+
keep_backups :all
|
180
|
+
encrypt_with_password 'password'
|
181
|
+
notify false
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
# Initializ with:
|
187
|
+
# rake backup:run trigger='sqlite-backup-local'
|
188
|
+
backup 'sqlite-backup-local' do
|
189
|
+
|
190
|
+
adapter :sqlite do
|
191
|
+
database "#{RAILS_ROOT}/db/production.sqlite3"
|
192
|
+
end
|
193
|
+
|
194
|
+
storage :local do
|
195
|
+
path "/path/to/storage/location/"
|
196
|
+
end
|
197
|
+
|
198
|
+
keep_backups :all
|
199
|
+
encrypt_with_password false
|
200
|
+
notify false
|
201
|
+
|
202
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateBackupTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :backup do |t|
|
4
|
+
t.string :trigger
|
5
|
+
t.string :adapter
|
6
|
+
t.string :filename
|
7
|
+
t.string :md5sum
|
8
|
+
t.string :path
|
9
|
+
t.string :bucket
|
10
|
+
t.string :type
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.down
|
16
|
+
drop_table :backup
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
namespace :backup do
|
2
|
+
|
3
|
+
desc "Run Backup Procedure."
|
4
|
+
task :run => :environment do
|
5
|
+
puts "Running: #{ENV['trigger']}."
|
6
|
+
Backup::Setup.new(ENV['trigger'], @backup_procedures).initialize_adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Finds backup records by trigger"
|
10
|
+
task :find => :environment do
|
11
|
+
puts "Finding backup records with trigger: #{ENV['trigger']}."
|
12
|
+
backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
|
13
|
+
records = Array.new
|
14
|
+
case backup.procedure.storage_name.to_sym
|
15
|
+
when :s3 then records = Backup::Record::S3.all :conditions => {:trigger => ENV['trigger']}
|
16
|
+
when :scp then records = Backup::Record::SCP.all :conditions => {:trigger => ENV['trigger']}
|
17
|
+
when :ftp then records = Backup::Record::FTP.all :conditions => {:trigger => ENV['trigger']}
|
18
|
+
when :sftp then records = Backup::Record::SFTP.all :conditions => {:trigger => ENV['trigger']}
|
19
|
+
when :local then records = Backup::Record::Local.all :conditions => {:trigger => ENV['trigger']}
|
20
|
+
end
|
21
|
+
|
22
|
+
if ENV['table'].eql?("true")
|
23
|
+
puts Hirb::Helpers::AutoTable.render(records)
|
24
|
+
else
|
25
|
+
records.each do |record|
|
26
|
+
puts record.to_yaml
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Truncates all records for the specified \"trigger\", excluding the physical files on s3 or the remote server."
|
32
|
+
task :truncate => :environment do
|
33
|
+
puts "Truncating backup records with trigger: #{ENV['trigger']}."
|
34
|
+
Backup::Record::Base.destroy_all :trigger => ENV['trigger']
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Truncates everything."
|
38
|
+
task :truncate_all => :environment do
|
39
|
+
puts "Truncating all backup records."
|
40
|
+
Backup::Record::Base.destroy_all
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
|
44
|
+
task :destroy => :environment do
|
45
|
+
puts "Destroying backup records with trigger: #{ENV['trigger']}."
|
46
|
+
backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
|
47
|
+
case backup.procedure.storage_name.to_sym
|
48
|
+
when :s3 then Backup::Record::S3.destroy_all_backups backup.procedure, ENV['trigger']
|
49
|
+
when :scp then Backup::Record::SCP.destroy_all_backups backup.procedure, ENV['trigger']
|
50
|
+
when :ftp then Backup::Record::FTP.destroy_all_backups backup.procedure, ENV['trigger']
|
51
|
+
when :sftp then Backup::Record::SFTP.destroy_all_backups backup.procedure, ENV['trigger']
|
52
|
+
when :local then Backup::Record::Local.destroy_all_backups backup.procedure, ENV['trigger']
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
|
57
|
+
task :destroy_all => :environment do
|
58
|
+
puts "Destroying all backup records."
|
59
|
+
backup = Backup::Setup.new(false, @backup_procedures)
|
60
|
+
backup.procedures.each do |backup_procedure|
|
61
|
+
case backup_procedure.storage_name.to_sym
|
62
|
+
when :s3 then Backup::Record::S3.destroy_all_backups backup_procedure, backup_procedure.trigger
|
63
|
+
when :scp then Backup::Record::SCP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
64
|
+
when :ftp then Backup::Record::FTP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
65
|
+
when :sftp then Backup::Record::SFTP.destroy_all_backups backup_procedure, backup_procedure.trigger
|
66
|
+
when :local then Backup::Record::Local.destroy_all_backups backup_procedure, backup_procedure.trigger
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class BackupUpdateGenerator < Rails::Generator::Base
|
2
|
+
|
3
|
+
# This method gets initialized when the generator gets run.
|
4
|
+
# It will receive an array of arguments inside @args
|
5
|
+
def initialize(runtime_args, runtime_options = {})
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
# Processes the file generation/templating
|
10
|
+
# This will automatically be run after the initialize method
|
11
|
+
def manifest
|
12
|
+
record do |m|
|
13
|
+
|
14
|
+
# Generates the database update migration file
|
15
|
+
m.migration_template "migrations/update_backup_tables.rb",
|
16
|
+
"db/migrate",
|
17
|
+
:migration_file_name => "update_backup_tables"
|
18
|
+
|
19
|
+
# Outputs the generators message to the terminal
|
20
|
+
puts message
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def message
|
25
|
+
<<-MESSAGE
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
==============================================================
|
30
|
+
Backup's update files have been generated!
|
31
|
+
==============================================================
|
32
|
+
|
33
|
+
Please follow these instructions Backup:
|
34
|
+
|
35
|
+
1: Please migrate the database to finish the update!
|
36
|
+
|
37
|
+
rake db:migrate
|
38
|
+
|
39
|
+
|
40
|
+
For More Information:
|
41
|
+
http://github.com/meskyanichi/backup
|
42
|
+
|
43
|
+
==============================================================
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
MESSAGE
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
@@ -0,0 +1,34 @@
|
|
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
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Backup
|
2
|
+
module Adapters
|
3
|
+
class Base
|
4
|
+
|
5
|
+
include Backup::CommandHelper
|
6
|
+
|
7
|
+
attr_accessor :procedure, :timestamp, :options, :tmp_path, :encrypt_with_password, :keep_backups, :trigger
|
8
|
+
|
9
|
+
# IMPORTANT
|
10
|
+
# final_file must have the value of the final filename result
|
11
|
+
# so if a file gets compressed, then the file could look like this:
|
12
|
+
# myfile.gz
|
13
|
+
#
|
14
|
+
# and if a file afterwards gets encrypted, the file will look like:
|
15
|
+
# myfile.gz.enc
|
16
|
+
#
|
17
|
+
# It is important that, whatever the final filename of the file will be, that :final_file will contain it.
|
18
|
+
attr_accessor :performed_file, :compressed_file, :encrypted_file, :final_file
|
19
|
+
|
20
|
+
# Initializes the Backup Process
|
21
|
+
#
|
22
|
+
# This will first load in any prefixed settings from the Backup::Adapters::Base
|
23
|
+
# Then it will add it's own settings.
|
24
|
+
#
|
25
|
+
# First it will call the 'perform' method. This method is concerned with the backup, and must
|
26
|
+
# be implemented by derived classes!
|
27
|
+
# Then it will optionally encrypt the backed up file
|
28
|
+
# Then it will store it to the specified storage location
|
29
|
+
# Then it will record the data to the database
|
30
|
+
# Once this is all done, all the temporary files will be removed
|
31
|
+
#
|
32
|
+
# Wrapped inside of begin/ensure/end block to ensure the deletion of any files in the tmp directory
|
33
|
+
def initialize(trigger, procedure)
|
34
|
+
self.trigger = trigger
|
35
|
+
self.procedure = procedure
|
36
|
+
self.timestamp = Time.now.strftime("%Y%m%d%H%M%S")
|
37
|
+
self.tmp_path = File.join(BACKUP_PATH.gsub(' ', '\ '), 'tmp', 'backup', trigger)
|
38
|
+
self.encrypt_with_password = procedure.attributes['encrypt_with_password']
|
39
|
+
self.keep_backups = procedure.attributes['keep_backups']
|
40
|
+
|
41
|
+
self.performed_file = "#{timestamp}.#{trigger.gsub(' ', '-')}#{performed_file_extension}"
|
42
|
+
self.compressed_file = "#{performed_file}.gz"
|
43
|
+
self.encrypted_file = "#{compressed_file}.enc"
|
44
|
+
self.final_file = compressed_file
|
45
|
+
|
46
|
+
begin
|
47
|
+
create_tmp_folder
|
48
|
+
load_settings # if respond_to?(:load_settings)
|
49
|
+
perform
|
50
|
+
encrypt
|
51
|
+
store
|
52
|
+
record
|
53
|
+
notify
|
54
|
+
ensure
|
55
|
+
remove_tmp_files
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates the temporary folder for the specified adapter
|
60
|
+
def create_tmp_folder
|
61
|
+
run "mkdir -p #{tmp_path}"
|
62
|
+
end
|
63
|
+
|
64
|
+
# TODO make methods in derived classes public? respond_to cannot identify private methods
|
65
|
+
def load_settings
|
66
|
+
end
|
67
|
+
|
68
|
+
# Removes the files inside the temporary folder
|
69
|
+
def remove_tmp_files
|
70
|
+
run "rm #{File.join(tmp_path, '*')}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# Encrypts the archive file
|
74
|
+
def encrypt
|
75
|
+
if encrypt_with_password.is_a?(String)
|
76
|
+
log system_messages[:encrypting]
|
77
|
+
run "openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password}"
|
78
|
+
self.final_file = encrypted_file
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Initializes the storing process
|
83
|
+
def store
|
84
|
+
procedure.initialize_storage(self)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Records data on every individual file to the database
|
88
|
+
def record
|
89
|
+
record = procedure.initialize_record
|
90
|
+
record.load_adapter(self)
|
91
|
+
record.save
|
92
|
+
end
|
93
|
+
|
94
|
+
# Delivers a notification by email regarding the successfully stored backup
|
95
|
+
def notify
|
96
|
+
if Backup::Mail::Base.setup?
|
97
|
+
Backup::Mail::Base.notify!(self)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def system_messages
|
102
|
+
{ :compressing => "Compressing backup..",
|
103
|
+
:archiving => "Archiving backup..",
|
104
|
+
:encrypting => "Encrypting backup..",
|
105
|
+
:mysqldump => "Creating MySQL dump..",
|
106
|
+
:pgdump => "Creating PostgreSQL dump..",
|
107
|
+
:sqlite => "Copying and compressing SQLite database..",
|
108
|
+
:commands => "Executing commands.." }
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,41 @@
|
|
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
|
@@ -0,0 +1,54 @@
|
|
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
|
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_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 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
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Backup
|
2
|
+
module Adapters
|
3
|
+
class PostgreSQL < Backup::Adapters::Base
|
4
|
+
|
5
|
+
attr_accessor :user, :password, :database, :skip_tables, :host, :port, :socket, :additional_options
|
6
|
+
|
7
|
+
private
|
8
|
+
|
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
|
+
|
17
|
+
def pg_dump
|
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
|
22
|
+
end
|
23
|
+
|
24
|
+
def performed_file_extension
|
25
|
+
".sql"
|
26
|
+
end
|
27
|
+
|
28
|
+
# Loads the initial settings
|
29
|
+
def load_settings
|
30
|
+
%w(user password database skip_tables additional_options).each do |attribute|
|
31
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
|
32
|
+
end
|
33
|
+
|
34
|
+
%w(host port socket).each do |attribute|
|
35
|
+
send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns a list of options in PostgreSQL syntax
|
40
|
+
def options
|
41
|
+
options = String.new
|
42
|
+
options += " --port='#{port}' " unless port.blank?
|
43
|
+
options += " --host='#{host}' " unless host.blank?
|
44
|
+
options += " --host='#{socket}' " unless socket.blank? unless options.include?('--host=')
|
45
|
+
options
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns a list of tables to skip in PostgreSQL syntax
|
49
|
+
def tables_to_skip
|
50
|
+
return "" unless skip_tables
|
51
|
+
[*skip_tables].map {|table| " -T \"#{table}\" "}
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|