backup-wakiki 2.4.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.
Files changed (54) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/CHANGELOG +77 -0
  4. data/LICENSE +9 -0
  5. data/README.textile +175 -0
  6. data/Rakefile +65 -0
  7. data/VERSION +1 -0
  8. data/backup-2.3.1.gem +0 -0
  9. data/backup-wakiki.gemspec +113 -0
  10. data/backup.gemspec +111 -0
  11. data/bin/backup +124 -0
  12. data/generators/backup/backup_generator.rb +72 -0
  13. data/generators/backup/templates/config/backup.rb +202 -0
  14. data/generators/backup/templates/migrations/create_backup_tables.rb +18 -0
  15. data/generators/backup/templates/tasks/backup.rake +71 -0
  16. data/generators/backup_update/backup_update_generator.rb +50 -0
  17. data/generators/backup_update/templates/migrations/update_backup_tables.rb +27 -0
  18. data/lib/backup.rb +112 -0
  19. data/lib/backup/adapters/archive.rb +34 -0
  20. data/lib/backup/adapters/base.rb +113 -0
  21. data/lib/backup/adapters/custom.rb +41 -0
  22. data/lib/backup/adapters/mysql.rb +60 -0
  23. data/lib/backup/adapters/postgresql.rb +56 -0
  24. data/lib/backup/adapters/sqlite.rb +25 -0
  25. data/lib/backup/command_helper.rb +11 -0
  26. data/lib/backup/configuration/adapter.rb +21 -0
  27. data/lib/backup/configuration/adapter_options.rb +8 -0
  28. data/lib/backup/configuration/attributes.rb +19 -0
  29. data/lib/backup/configuration/base.rb +55 -0
  30. data/lib/backup/configuration/helpers.rb +24 -0
  31. data/lib/backup/configuration/mail.rb +20 -0
  32. data/lib/backup/configuration/smtp.rb +8 -0
  33. data/lib/backup/configuration/storage.rb +8 -0
  34. data/lib/backup/connection/s3.rb +87 -0
  35. data/lib/backup/environment/base.rb +12 -0
  36. data/lib/backup/environment/rails.rb +17 -0
  37. data/lib/backup/environment/unix.rb +94 -0
  38. data/lib/backup/mail/base.rb +96 -0
  39. data/lib/backup/mail/mail.txt +7 -0
  40. data/lib/backup/record/base.rb +65 -0
  41. data/lib/backup/record/ftp.rb +39 -0
  42. data/lib/backup/record/local.rb +26 -0
  43. data/lib/backup/record/s3.rb +26 -0
  44. data/lib/backup/record/scp.rb +33 -0
  45. data/lib/backup/record/sftp.rb +38 -0
  46. data/lib/backup/storage/ftp.rb +38 -0
  47. data/lib/backup/storage/local.rb +24 -0
  48. data/lib/backup/storage/s3.rb +16 -0
  49. data/lib/backup/storage/scp.rb +30 -0
  50. data/lib/backup/storage/sftp.rb +31 -0
  51. data/setup/backup.rb +202 -0
  52. data/setup/backup.sqlite3 +0 -0
  53. data/spec/configuration/attributes_spec.rb +35 -0
  54. metadata +183 -0
@@ -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,112 @@
1
+ # Load Gems
2
+ require 'hirb'
3
+
4
+ # Load Environments
5
+ require 'backup/environment/base'
6
+ require 'backup/environment/unix'
7
+ require 'backup/environment/rails'
8
+
9
+ # Load Configuration
10
+ require 'backup/configuration/attributes'
11
+ require 'backup/configuration/base'
12
+ require 'backup/configuration/adapter'
13
+ require 'backup/configuration/adapter_options'
14
+ require 'backup/configuration/storage'
15
+ require 'backup/configuration/mail'
16
+ require 'backup/configuration/smtp'
17
+ require 'backup/configuration/helpers'
18
+
19
+ require 'backup/command_helper'
20
+
21
+ # Include the Configuration and Environment Helpers
22
+ include Backup::Configuration::Helpers
23
+ include Backup::Environment::Base
24
+
25
+ # Load either UNIX or RAILS environment configuration
26
+ case current_environment
27
+ when :unix then include Backup::Environment::Unix
28
+ when :rails then include Backup::Environment::Rails
29
+ end
30
+
31
+ # Load configuration
32
+ if File.exist?(File.join(BACKUP_PATH, 'config', 'backup.rb'))
33
+ require File.join(BACKUP_PATH, 'config', 'backup.rb')
34
+ end
35
+
36
+ # Load Mail Notifier
37
+ require 'backup/mail/base'
38
+
39
+ # Set Mail Configuration (extracted from the backup.rb configuration file) inside the Mail Class
40
+ Backup::Mail::Base.setup(@mail_configuration)
41
+
42
+ # Backup Module
43
+ module Backup
44
+ module Adapters
45
+ autoload :Base, 'backup/adapters/base'
46
+ autoload :MySQL, 'backup/adapters/mysql'
47
+ autoload :SQLite, 'backup/adapters/sqlite'
48
+ autoload :PostgreSQL, 'backup/adapters/postgresql'
49
+ autoload :Archive, 'backup/adapters/archive'
50
+ autoload :Custom, 'backup/adapters/custom'
51
+ end
52
+
53
+ module Storage
54
+ autoload :S3, 'backup/storage/s3'
55
+ autoload :SCP, 'backup/storage/scp'
56
+ autoload :FTP, 'backup/storage/ftp'
57
+ autoload :SFTP, 'backup/storage/sftp'
58
+ autoload :Local, 'backup/storage/local'
59
+ end
60
+
61
+ module Record
62
+ autoload :Base, 'backup/record/base'
63
+ autoload :S3, 'backup/record/s3'
64
+ autoload :SCP, 'backup/record/scp'
65
+ autoload :FTP, 'backup/record/ftp'
66
+ autoload :SFTP, 'backup/record/sftp'
67
+ autoload :Local, 'backup/record/local'
68
+ end
69
+
70
+ class Setup
71
+
72
+ attr_accessor :trigger, :procedures, :procedure
73
+
74
+ # Sets the Trigger and All Available Procedures.
75
+ # Will not find a specific procedure if the "trigger" argument is set to false.
76
+ def initialize(trigger, procedures)
77
+ self.trigger = trigger
78
+ self.procedures = procedures
79
+ self.procedure = find_triggered_procedure unless trigger.eql?(false)
80
+ end
81
+
82
+ # Initializes one of the few adapters and start the backup process
83
+ def initialize_adapter
84
+ case procedure.adapter_name.to_sym
85
+ when :mysql then Backup::Adapters::MySQL.new trigger, procedure
86
+ when :sqlite then Backup::Adapters::SQLite.new trigger, procedure
87
+ when :postgresql then Backup::Adapters::PostgreSQL.new trigger, procedure
88
+ when :archive then Backup::Adapters::Archive.new trigger, procedure
89
+ when :custom then Backup::Adapters::Custom.new trigger, procedure
90
+ else
91
+ puts "Unknown Adapter: \"#{procedure.adapter_name}\"."
92
+ exit
93
+ end
94
+ end
95
+
96
+ # Scans through all the backup settings and returns the backup setting
97
+ # that was specified in the "trigger" argument.
98
+ # If an non-existing trigger is specified, it will raise an error and display
99
+ # all the available triggers.
100
+ def find_triggered_procedure
101
+ procedures.each do |procedure|
102
+ if procedure.trigger.eql?(trigger)
103
+ return procedure
104
+ end
105
+ end
106
+ available_triggers = procedures.map {|procedure| "- #{procedure.trigger}\n" }
107
+ puts "Could not find a backup procedure with the trigger \"#{trigger}\". \nHere's a list of available triggers:\n#{available_triggers}"
108
+ exit
109
+ end
110
+
111
+ end
112
+ 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