backup 2.1.2 → 2.2.0

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.
@@ -9,8 +9,10 @@ namespace :backup do
9
9
  task :truncate => :environment do
10
10
  backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
11
11
  case backup.procedure.storage_name.to_sym
12
- when :s3 then Backup::Record::S3.destroy_all(:trigger => ENV['trigger'], :storage => 's3')
13
- when :scp then Backup::Record::SCP.destroy_all(:trigger => ENV['trigger'], :storage => 'scp')
12
+ when :s3 then Backup::Record::S3.destroy_all :trigger => ENV['trigger'], :storage => 's3'
13
+ when :scp then Backup::Record::SCP.destroy_all :trigger => ENV['trigger'], :storage => 'scp'
14
+ when :ftp then Backup::Record::FTP.destroy_all :trigger => ENV['trigger'], :storage => 'ftp'
15
+ when :sftp then Backup::Record::SFTP.destroy_all :trigger => ENV['trigger'], :storage => 'sftp'
14
16
  end
15
17
  end
16
18
 
@@ -18,23 +20,30 @@ namespace :backup do
18
20
  task :truncate_all => :environment do
19
21
  Backup::Record::S3.destroy_all
20
22
  Backup::Record::SCP.destroy_all
23
+ Backup::Record::FTP.destroy_all
24
+ Backup::Record::SFTP.destroy_all
21
25
  end
22
26
 
23
27
  desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
24
28
  task :destroy => :environment do
25
29
  backup = Backup::Setup.new(ENV['trigger'], @backup_procedures)
26
30
  case backup.procedure.storage_name.to_sym
27
- when :s3 then Backup::Record::S3.destroy_all_backups(backup.procedure, ENV['trigger'])
28
- when :scp then Backup::Record::SCP.destroy_all_backups(backup.procedure, ENV['trigger'])
31
+ when :s3 then Backup::Record::S3.destroy_all_backups backup.procedure, ENV['trigger']
32
+ when :scp then Backup::Record::SCP.destroy_all_backups backup.procedure, ENV['trigger']
33
+ when :ftp then Backup::Record::FTP.destroy_all_backups backup.procedure, ENV['trigger']
34
+ when :sftp then Backup::Record::SFTP.destroy_all_backups backup.procedure, ENV['trigger']
29
35
  end
30
36
  end
31
37
 
32
38
  desc "Destroys all records for the specified \"trigger\", including the physical files on s3 or the remote server."
33
39
  task :destroy_all => :environment do
34
- @backup_procedures.each do |backup_procedure|
40
+ backup = Backup::Setup.new(false, @backup_procedures)
41
+ backup.procedures.each do |backup_procedure|
35
42
  case backup_procedure.storage_name.to_sym
36
- when :s3 then Backup::Record::S3.destroy_all_backups(backup_procedure, backup_procedure.trigger)
37
- when :scp then Backup::Record::SCP.destroy_all_backups(backup_procedure, backup_procedure.trigger)
43
+ when :s3 then Backup::Record::S3.destroy_all_backups backup_procedure, backup_procedure.trigger
44
+ when :scp then Backup::Record::SCP.destroy_all_backups backup_procedure, backup_procedure.trigger
45
+ when :ftp then Backup::Record::FTP.destroy_all_backups backup_procedure, backup_procedure.trigger
46
+ when :sftp then Backup::Record::SFTP.destroy_all_backups backup_procedure, backup_procedure.trigger
38
47
  end
39
48
  end
40
49
  end
data/lib/backup.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  # Load in Connectivity and Transfer Gems
2
2
  require 'net/ssh'
3
3
  require 'net/scp'
4
+ require 'net/ftp'
5
+ require 'net/sftp'
4
6
  require 'aws/s3'
5
7
 
6
8
  # Load in Adapters
7
9
  require 'backup/adapters/base'
8
10
  require 'backup/adapters/mysql'
11
+ require 'backup/adapters/postgresql'
9
12
  require 'backup/adapters/archive'
13
+ require 'backup/adapters/custom'
10
14
 
11
15
  # Load in Connectors
12
16
  require 'backup/connection/s3'
@@ -14,14 +18,19 @@ require 'backup/connection/s3'
14
18
  # Load in Storage
15
19
  require 'backup/storage/s3'
16
20
  require 'backup/storage/scp'
21
+ require 'backup/storage/ftp'
22
+ require 'backup/storage/sftp'
17
23
 
18
24
  # Load in Backup Recorders
19
25
  require 'backup/record/s3'
20
26
  require 'backup/record/scp'
27
+ require 'backup/record/ftp'
28
+ require 'backup/record/sftp'
21
29
 
22
30
  # Load in Configuration
23
31
  require 'backup/configuration/base'
24
32
  require 'backup/configuration/adapter'
33
+ require 'backup/configuration/adapter_options'
25
34
  require 'backup/configuration/storage'
26
35
  require 'backup/configuration/helpers'
27
36
 
@@ -38,21 +47,30 @@ module Backup
38
47
  class Setup
39
48
 
40
49
  attr_accessor :trigger, :procedures, :procedure
41
-
50
+
51
+ # Sets the Trigger and All Available Procedures.
52
+ # Will not find a specific procedure if the "trigger" argument is set to false.
42
53
  def initialize(trigger, procedures)
43
54
  self.trigger = trigger
44
55
  self.procedures = procedures
45
- self.procedure = find_triggered_procedure
56
+ self.procedure = find_triggered_procedure unless trigger.eql?(false)
46
57
  end
47
58
 
59
+ # Initializes one of the few adapters and start the backup process
48
60
  def initialize_adapter
49
61
  case procedure.adapter_name.to_sym
50
- when :mysql then Backup::Adapters::MySQL.new(trigger, procedure)
51
- when :archive then Backup::Adapters::Archive.new(trigger, procedure)
52
- else raise "Unknown Adapter: \"#{procedure.adapter_name}\""
62
+ when :mysql then Backup::Adapters::MySQL.new trigger, procedure
63
+ when :postgresql then Backup::Adapters::PostgreSQL.new trigger, procedure
64
+ when :archive then Backup::Adapters::Archive.new trigger, procedure
65
+ when :custom then Backup::Adapters::Custom.new trigger, procedure
66
+ else raise "Unknown Adapter: \"#{procedure.adapter_name}\"."
53
67
  end
54
68
  end
55
-
69
+
70
+ # Scans through all the backup settings and returns the backup setting
71
+ # that was specified in the "trigger" argument.
72
+ # If an non-existing trigger is specified, it will raise an error and display
73
+ # all the available triggers.
56
74
  def find_triggered_procedure
57
75
  procedures.each do |procedure|
58
76
  if procedure.trigger.eql?(trigger)
@@ -2,18 +2,32 @@ module Backup
2
2
  module Adapters
3
3
  class Archive < Backup::Adapters::Base
4
4
 
5
- attr_accessor :archived_file, :compressed_file, :encrypted_file, :user, :password, :database
5
+ attr_accessor :archived_file, :compressed_file, :encrypted_file
6
6
 
7
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 archive and compress every folder/file
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
8
19
  def initialize(trigger, procedure)
9
20
  super
10
21
  load_settings
11
22
 
12
- targz
13
- encrypt
14
- store
15
- record
16
- remove_tmp_files
23
+ begin
24
+ targz
25
+ encrypt
26
+ store
27
+ record
28
+ ensure
29
+ remove_tmp_files
30
+ end
17
31
  end
18
32
 
19
33
  private
@@ -38,11 +52,9 @@ module Backup
38
52
 
39
53
  # Loads the initial settings
40
54
  def load_settings
41
- self.user = procedure.get_adapter_configuration.attributes['user']
42
- self.password = procedure.get_adapter_configuration.attributes['password']
43
- self.database = procedure.get_adapter_configuration.attributes['database']
55
+ self.trigger = procedure.trigger
44
56
 
45
- self.archived_file = "#{timestamp}.archive.#{trigger.gsub(' ', '-')}.tar"
57
+ self.archived_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.tar"
46
58
  self.compressed_file = "#{archived_file}.gz"
47
59
  self.encrypted_file = "#{compressed_file}.enc"
48
60
  self.final_file = compressed_file
@@ -19,7 +19,7 @@ module Backup
19
19
  self.trigger = trigger
20
20
  self.procedure = procedure
21
21
  self.timestamp = Time.now.strftime("%Y%m%d%H%M%S")
22
- self.tmp_path = "#{RAILS_ROOT.gsub(' ', '\ ')}/tmp/backup/#{procedure.adapter_name}"
22
+ self.tmp_path = File.join(RAILS_ROOT.gsub(' ', '\ '), 'tmp', 'backup', trigger)
23
23
  self.encrypt_with_password = procedure.attributes['encrypt_with_password']
24
24
  self.keep_backups = procedure.attributes['keep_backups']
25
25
  create_tmp_folder
@@ -32,21 +32,25 @@ module Backup
32
32
 
33
33
  # Removes the files inside the temporary folder
34
34
  def remove_tmp_files
35
- %x{ rm #{tmp_path}/* }
35
+ %x{ rm #{File.join(tmp_path, '*')} }
36
36
  end
37
37
 
38
38
  # Initializes the storing process depending on the store settings
39
39
  # Options:
40
40
  # Amazon (S3)
41
41
  # Remote Server (SCP)
42
+ # Remote Server (FTP)
43
+ # Remote Server (SFTP)
42
44
  def store
43
45
  case procedure.storage_name.to_sym
44
46
  when :s3 then Backup::Storage::S3.new(self)
45
47
  when :scp then Backup::Storage::SCP.new(self)
48
+ when :ftp then Backup::Storage::FTP.new(self)
49
+ when :sftp then Backup::Storage::SFTP.new(self)
46
50
  end
47
51
  end
48
52
 
49
- # Records data on every individual file to the backup.sqlite3 local database
53
+ # Records data on every individual file to the database
50
54
  def record
51
55
  case procedure.storage_name.to_sym
52
56
  when :s3
@@ -57,6 +61,14 @@ module Backup
57
61
  record = Backup::Record::SCP.new
58
62
  record.load_adapter(self)
59
63
  record.save
64
+ when :ftp
65
+ record = Backup::Record::FTP.new
66
+ record.load_adapter(self)
67
+ record.save
68
+ when :sftp
69
+ record = Backup::Record::SFTP.new
70
+ record.load_adapter(self)
71
+ record.save
60
72
  end
61
73
  end
62
74
 
@@ -0,0 +1,74 @@
1
+ module Backup
2
+ module Adapters
3
+ class Custom < Backup::Adapters::Base
4
+
5
+ attr_accessor :archived_file, :compressed_file, :encrypted_file, :commands
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 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
25
+ execute_commands
26
+ targz
27
+ encrypt
28
+ store
29
+ record
30
+ ensure
31
+ remove_tmp_files
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Executes the commands
38
+ def execute_commands
39
+ if commands.is_a?(Array)
40
+ commands.each do |command|
41
+ %x{ #{command.gsub(':tmp_path', tmp_path)} }
42
+ end
43
+ elsif commands.is_a?(String)
44
+ %x{ #{commands.gsub(':tmp_path', tmp_path)} }
45
+ end
46
+ end
47
+
48
+ # Archives and Compresses
49
+ def targz
50
+ %x{ tar -czf #{File.join(tmp_path, compressed_file)} #{File.join(tmp_path, '*')} }
51
+ end
52
+
53
+ # Encrypts the archive file
54
+ def encrypt
55
+ if encrypt_with_password.is_a?(String)
56
+ %x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
57
+ self.final_file = encrypted_file
58
+ end
59
+ end
60
+
61
+ # Loads the initial settings
62
+ def load_settings
63
+ self.trigger = procedure.trigger
64
+ self.commands = procedure.get_adapter_configuration.attributes['commands']
65
+
66
+ self.archived_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.tar"
67
+ self.compressed_file = "#{archived_file}.gz"
68
+ self.encrypted_file = "#{compressed_file}.enc"
69
+ self.final_file = compressed_file
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -2,25 +2,39 @@ module Backup
2
2
  module Adapters
3
3
  class MySQL < Backup::Adapters::Base
4
4
 
5
- attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database
5
+ attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database, :skip_tables, :host, :port, :socket
6
6
 
7
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
8
19
  def initialize(trigger, procedure)
9
20
  super
10
21
  load_settings
11
22
 
12
- mysqldump
13
- encrypt
14
- store
15
- record
16
- remove_tmp_files
23
+ begin
24
+ mysqldump
25
+ encrypt
26
+ store
27
+ record
28
+ ensure
29
+ remove_tmp_files
30
+ end
17
31
  end
18
32
 
19
33
  private
20
34
 
21
35
  # Dumps and Compresses the MySQL file
22
36
  def mysqldump
23
- %x{ mysqldump -u #{user} --password='#{password}' #{database} | gzip -f --best > #{File.join(tmp_path, compressed_file)} }
37
+ %x{ mysqldump -u #{user} --password='#{password}' #{options} #{database} #{tables_to_skip} | gzip -f --best > #{File.join(tmp_path, compressed_file)} }
24
38
  end
25
39
 
26
40
  # Encrypts the MySQL file
@@ -33,16 +47,42 @@ module Backup
33
47
 
34
48
  # Loads the initial settings
35
49
  def load_settings
36
- self.user = procedure.get_adapter_configuration.attributes['user']
37
- self.password = procedure.get_adapter_configuration.attributes['password']
38
- self.database = procedure.get_adapter_configuration.attributes['database']
50
+ self.trigger = procedure.trigger
51
+
52
+ %w(user password database skip_tables).each do |attribute|
53
+ send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
54
+ end
55
+
56
+ %w(host port socket).each do |attribute|
57
+ send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
58
+ end
39
59
 
40
- self.dumped_file = "#{timestamp}.#{database}.sql"
60
+ self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
41
61
  self.compressed_file = "#{dumped_file}.gz"
42
62
  self.encrypted_file = "#{compressed_file}.enc"
43
63
  self.final_file = compressed_file
44
64
  end
45
65
 
66
+ # Returns a list of options in MySQL syntax
67
+ def options
68
+ options = String.new
69
+ options += " --host='#{host}' " unless host.blank?
70
+ options += " --port='#{port}' " unless port.blank?
71
+ options += " --socket='#{socket}' " unless socket.blank?
72
+ options
73
+ end
74
+
75
+ # Returns a list of tables to skip in MySQL syntax
76
+ def tables_to_skip
77
+ if skip_tables.is_a?(Array)
78
+ skip_tables.map {|table| " --ignore-table='#{database}.#{table}' "}
79
+ elsif skip_tables.is_a?(String)
80
+ " --ignore-table='#{database}.#{skip_tables}' "
81
+ else
82
+ ""
83
+ end
84
+ end
85
+
46
86
  end
47
87
  end
48
88
  end
@@ -0,0 +1,88 @@
1
+ module Backup
2
+ module Adapters
3
+ class PostgreSQL < Backup::Adapters::Base
4
+
5
+ attr_accessor :dumped_file, :compressed_file, :encrypted_file, :user, :password, :database, :skip_tables, :host, :port, :socket
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
+ ensure
29
+ remove_tmp_files
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # Dumps and Compresses the PostgreSQL file
36
+ def pg_dump
37
+ %x{ pg_dump -U #{user} #{options} #{tables_to_skip} #{database} | gzip -f --best > #{File.join(tmp_path, compressed_file)} }
38
+ end
39
+
40
+ # Encrypts the PostgreSQL file
41
+ def encrypt
42
+ if encrypt_with_password.is_a?(String)
43
+ %x{ openssl enc -des-cbc -in #{File.join(tmp_path, compressed_file)} -out #{File.join(tmp_path, encrypted_file)} -k #{encrypt_with_password} }
44
+ self.final_file = encrypted_file
45
+ end
46
+ end
47
+
48
+ # Loads the initial settings
49
+ def load_settings
50
+ self.trigger = procedure.trigger
51
+
52
+ %w(user password database skip_tables).each do |attribute|
53
+ send(:"#{attribute}=", procedure.get_adapter_configuration.attributes[attribute])
54
+ end
55
+
56
+ %w(host port socket).each do |attribute|
57
+ send(:"#{attribute}=", procedure.get_adapter_configuration.get_options.attributes[attribute])
58
+ end
59
+
60
+ self.dumped_file = "#{timestamp}.#{trigger.gsub(' ', '-')}.sql"
61
+ self.compressed_file = "#{dumped_file}.gz"
62
+ self.encrypted_file = "#{compressed_file}.enc"
63
+ self.final_file = compressed_file
64
+ end
65
+
66
+ # Returns a list of options in PostgreSQL syntax
67
+ def options
68
+ options = String.new
69
+ options += " --port='#{port}' " unless port.blank?
70
+ options += " --host='#{host}' " unless host.blank?
71
+ options += " --host='#{socket}' " unless socket.blank? unless options.include?('--host=')
72
+ options
73
+ end
74
+
75
+ # Returns a list of tables to skip in PostgreSQL syntax
76
+ def tables_to_skip
77
+ if skip_tables.is_a?(Array)
78
+ skip_tables.map {|table| " -T \"#{table}\" "}
79
+ elsif skip_tables.is_a?(String)
80
+ " -T \"#{skip_tables}\" "
81
+ else
82
+ ""
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end