namxam-backup 2.4.5

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 (61) hide show
  1. data/CHANGELOG +131 -0
  2. data/LICENSE +20 -0
  3. data/README.md +122 -0
  4. data/bin/backup +108 -0
  5. data/generators/backup/backup_generator.rb +69 -0
  6. data/generators/backup/templates/backup.rake +56 -0
  7. data/generators/backup/templates/backup.rb +253 -0
  8. data/generators/backup/templates/create_backup_tables.rb +18 -0
  9. data/generators/backup_update/backup_update_generator.rb +50 -0
  10. data/generators/backup_update/templates/migrations/update_backup_tables.rb +27 -0
  11. data/lib/backup.rb +132 -0
  12. data/lib/backup/adapters/archive.rb +34 -0
  13. data/lib/backup/adapters/base.rb +167 -0
  14. data/lib/backup/adapters/custom.rb +41 -0
  15. data/lib/backup/adapters/mongo_db.rb +139 -0
  16. data/lib/backup/adapters/mysql.rb +60 -0
  17. data/lib/backup/adapters/postgresql.rb +56 -0
  18. data/lib/backup/adapters/sqlite.rb +25 -0
  19. data/lib/backup/command_helper.rb +14 -0
  20. data/lib/backup/configuration/adapter.rb +21 -0
  21. data/lib/backup/configuration/adapter_options.rb +8 -0
  22. data/lib/backup/configuration/attributes.rb +19 -0
  23. data/lib/backup/configuration/base.rb +75 -0
  24. data/lib/backup/configuration/helpers.rb +24 -0
  25. data/lib/backup/configuration/mail.rb +20 -0
  26. data/lib/backup/configuration/smtp.rb +8 -0
  27. data/lib/backup/configuration/storage.rb +8 -0
  28. data/lib/backup/connection/cloudfiles.rb +75 -0
  29. data/lib/backup/connection/dropbox.rb +62 -0
  30. data/lib/backup/connection/s3.rb +88 -0
  31. data/lib/backup/core_ext/object.rb +5 -0
  32. data/lib/backup/environment/base.rb +12 -0
  33. data/lib/backup/environment/rails_configuration.rb +15 -0
  34. data/lib/backup/environment/unix_configuration.rb +109 -0
  35. data/lib/backup/mail/base.rb +97 -0
  36. data/lib/backup/mail/mail.txt +7 -0
  37. data/lib/backup/record/base.rb +65 -0
  38. data/lib/backup/record/cloudfiles.rb +28 -0
  39. data/lib/backup/record/dropbox.rb +27 -0
  40. data/lib/backup/record/ftp.rb +39 -0
  41. data/lib/backup/record/local.rb +26 -0
  42. data/lib/backup/record/s3.rb +25 -0
  43. data/lib/backup/record/scp.rb +33 -0
  44. data/lib/backup/record/sftp.rb +38 -0
  45. data/lib/backup/storage/base.rb +10 -0
  46. data/lib/backup/storage/cloudfiles.rb +16 -0
  47. data/lib/backup/storage/dropbox.rb +12 -0
  48. data/lib/backup/storage/ftp.rb +38 -0
  49. data/lib/backup/storage/local.rb +22 -0
  50. data/lib/backup/storage/s3.rb +15 -0
  51. data/lib/backup/storage/scp.rb +30 -0
  52. data/lib/backup/storage/sftp.rb +31 -0
  53. data/lib/backup/version.rb +3 -0
  54. data/lib/generators/backup/USAGE +10 -0
  55. data/lib/generators/backup/backup_generator.rb +47 -0
  56. data/lib/generators/backup/templates/backup.rake +56 -0
  57. data/lib/generators/backup/templates/backup.rb +236 -0
  58. data/lib/generators/backup/templates/create_backup_tables.rb +18 -0
  59. data/setup/backup.rb +255 -0
  60. data/setup/backup.sqlite3 +0 -0
  61. metadata +278 -0
@@ -0,0 +1,5 @@
1
+ class Object
2
+ def blank?
3
+ respond_to?(:empty?) ? empty? : !self
4
+ end unless method_defined? :blank?
5
+ end
@@ -0,0 +1,12 @@
1
+ module Backup
2
+ module Environment
3
+ module Base
4
+
5
+ def current_environment
6
+ return :rails if defined?(Rails.root)
7
+ return :unix
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module Backup
2
+ module Environment
3
+ module RailsConfiguration
4
+
5
+ if defined?(Rails.root)
6
+ # Sets BACKUP_PATH equal to Rails.root
7
+ BACKUP_PATH = Rails.root.to_s
8
+
9
+ # Sets DB_CONNECTION_SETTINGS to false
10
+ DB_CONNECTION_SETTINGS = false
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,109 @@
1
+ module Backup
2
+ module Environment
3
+ module UnixConfiguration
4
+
5
+ require 'active_record'
6
+
7
+ # Sets BACKUP_PATH
8
+ BACKUP_PATH = ENV['BACKUP_PATH'] || "/opt/backup"
9
+
10
+ # Sets DB_CONNECTION_SETTINGS
11
+ DB_CONNECTION_SETTINGS = {
12
+ :adapter => "sqlite3",
13
+ :database => "#{BACKUP_PATH}/backup.sqlite3",
14
+ :pool => 5,
15
+ :timeout => 5000
16
+ }
17
+
18
+ module Commands
19
+
20
+ def setup
21
+ unless File.directory?(BACKUP_PATH)
22
+ puts "Installing Backup in #{BACKUP_PATH}.."
23
+ %x{ #{sudo} mkdir -p #{File.join(BACKUP_PATH, 'config')} }
24
+ %x{ #{sudo} cp #{File.join(File.dirname(__FILE__), '..', '..', '..', 'setup', 'backup.sqlite3')} #{BACKUP_PATH} }
25
+ %x{ #{sudo} cp #{File.join(File.dirname(__FILE__), '..', '..', '..', 'setup', 'backup.rb')} #{File.join(BACKUP_PATH, 'config')} }
26
+ puts <<-MESSAGE
27
+
28
+ ==============================================================
29
+ Backup has been set up!
30
+ ==============================================================
31
+
32
+ 1: Set up some "Backup Settings" inside the configuration file!
33
+
34
+ #{BACKUP_PATH}/config/backup.rb
35
+
36
+
37
+ 2: Run the backups!
38
+
39
+ sudo backup --run [trigger]
40
+
41
+
42
+ For a list of Backup commands:
43
+
44
+ sudo backup --help
45
+
46
+
47
+ For More Information:
48
+
49
+ http://github.com/meskyanichi/backup
50
+
51
+ ==============================================================
52
+
53
+ MESSAGE
54
+ else
55
+ puts "\nBackup is already installed in #{BACKUP_PATH}..\n"
56
+ puts "If you want to reset it, run:\n\nbackup --reset\n\n"
57
+ puts "This will reinstall it."
58
+ puts "Warning: All configuration will be lost!\n\n"
59
+ end
60
+ end
61
+
62
+ def reset
63
+ if File.directory?(BACKUP_PATH)
64
+ remove
65
+ setup
66
+ else
67
+ puts "Backup is not installed.\n"
68
+ puts "Run the following command to install it:\n\nbackup --setup"
69
+ end
70
+ end
71
+
72
+ def remove
73
+ puts "Removing Backup..\n"
74
+ %x{ #{sudo} rm -rf #{BACKUP_PATH} }
75
+ end
76
+ end
77
+
78
+ module Helpers
79
+
80
+ def confirm_configuration_file_existence
81
+ unless File.exist?(File.join(BACKUP_PATH, 'config', 'backup.rb'))
82
+ puts "\nBackup could not find the Backup Configuration File."
83
+ puts "Did you set up Backup? Do so if you haven't yet:"
84
+ puts "\nbackup --setup\n "
85
+ exit
86
+ end
87
+ end
88
+
89
+ def sudo
90
+ if writable?(BACKUP_PATH)
91
+ ""
92
+ else
93
+ "sudo"
94
+ end
95
+ end
96
+
97
+ private
98
+ def writable?(f)
99
+ unless File.exists?(f)
100
+ writable?(File.dirname(f))
101
+ else
102
+ File.writable?(f)
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,97 @@
1
+ module Backup
2
+ module Mail
3
+ class Base
4
+
5
+ # Sets up the Mail Configuration for the Backup::Mail::Base class.
6
+ # This must be set in order to send emails
7
+ # It will dynamically add class methods (configuration) for each email that will be sent
8
+ def self.setup(config)
9
+ if config
10
+ (class << self; self; end).instance_eval do
11
+ config.attributes.each do |method, value|
12
+ define_method method do
13
+ value
14
+ end
15
+ end
16
+ config.get_smtp_configuration.attributes.each do |method, value|
17
+ define_method method do
18
+ value
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # Returns true if the "to" and "from" attributes are set
26
+ def self.setup?
27
+ return true if defined?(from) and defined?(to)
28
+ false
29
+ end
30
+
31
+ # Delivers the backup details by email to the recipient
32
+ # Requires the Backup Object
33
+ def self.notify!(backup)
34
+ if self.setup? and backup.procedure.attributes['notify'].eql?(true)
35
+ require 'pony'
36
+
37
+ @backup = backup
38
+ self.parse_body
39
+ Pony.mail({
40
+ :subject => "Backup for \"#{@backup.trigger}\" was successfully created!",
41
+ :body => @content
42
+ }.merge(self.smtp_configuration))
43
+ puts "Sending notification to #{self.to}."
44
+ end
45
+ end
46
+
47
+ # Retrieves SMTP configuration
48
+ def self.smtp_configuration
49
+ { :to => self.to,
50
+ :from => self.from,
51
+ :via => :smtp,
52
+ :smtp => {
53
+ :host => self.host,
54
+ :port => self.port,
55
+ :user => self.username,
56
+ :password => self.password,
57
+ :auth => self.authentication,
58
+ :domain => self.domain,
59
+ :tls => self.tls
60
+ }}
61
+ end
62
+
63
+ def self.parse_body
64
+ File.open(File.join(File.dirname(__FILE__), 'mail.txt'), 'r') do |file|
65
+ self.gsub_content(file.readlines)
66
+ end
67
+ end
68
+
69
+ def self.gsub_content(lines)
70
+ container = @backup.procedure.get_storage_configuration.attributes['container']
71
+ bucket = @backup.procedure.get_storage_configuration.attributes['bucket']
72
+ path = @backup.procedure.get_storage_configuration.attributes['path']
73
+ ip = @backup.procedure.get_storage_configuration.attributes['ip']
74
+
75
+ lines.each do |line|
76
+ line.gsub!(':trigger', @backup.trigger)
77
+ line.gsub!(':day', Time.now.strftime("%A (%d)"))
78
+ line.gsub!(':month', Time.now.strftime("%B"))
79
+ line.gsub!(':year', Time.now.strftime("%Y"))
80
+ line.gsub!(':time', Time.now.strftime("%r"))
81
+ line.gsub!(':adapter', @backup.procedure.adapter_name.to_s)
82
+ line.gsub!(':location', container || bucket || path)
83
+ line.gsub!(':backup', @backup.final_file)
84
+ case @backup.procedure.storage_name.to_sym
85
+ when :cloudfiles then line.gsub!(':remote', "on Rackspace Cloudfiles")
86
+ when :s3 then line.gsub!(':remote', "on Amazon S3")
87
+ when :local then line.gsub!(':remote', "on the local server")
88
+ when :scp, :sftp, :ftp then line.gsub!(':remote', "on the remote server (#{ip})")
89
+ end
90
+ @content ||= String.new
91
+ @content << line
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,7 @@
1
+ A backup was successfully created for the trigger: ":trigger"!
2
+
3
+ The backup was created on ":day of :month :year at :time", using the ":adapter" adapter.
4
+
5
+ The Backup was stored in ":location" :remote.
6
+
7
+ The following backup was stored: ":backup"
@@ -0,0 +1,65 @@
1
+ module Backup
2
+ module Record
3
+ class Base < ActiveRecord::Base
4
+
5
+ if DB_CONNECTION_SETTINGS
6
+ establish_connection(DB_CONNECTION_SETTINGS)
7
+ end
8
+
9
+ set_table_name 'backup'
10
+
11
+ default_scope :order => 'created_at desc'
12
+
13
+ # Callbacks
14
+ after_save :clean_backups
15
+
16
+ # Attributes
17
+ attr_accessor :adapter_config, :keep_backups
18
+
19
+ # Receives the options hash and stores it
20
+ def load_adapter(adapter)
21
+ self.adapter_config = adapter
22
+ self.trigger = adapter.procedure.trigger
23
+ self.adapter = adapter.procedure.adapter_name.to_s
24
+ self.filename = adapter.final_file
25
+ self.keep_backups = adapter.procedure.attributes['keep_backups']
26
+
27
+ # TODO calculate md5sum of file
28
+ load_specific_settings(adapter) if respond_to?(:load_specific_settings)
29
+ end
30
+
31
+ # Destroys all backups for the specified trigger from Remote Server (FTP)
32
+ def self.destroy_all_backups(procedure, trigger)
33
+ backups = self.all(:conditions => {:trigger => trigger})
34
+ unless backups.empty?
35
+ # Derived classes must implement this method!
36
+ self.destroy_backups(procedure, backups)
37
+
38
+ puts "\nAll \"#{procedure.trigger}\" backups destroyed.\n\n"
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ # Maintains the backup file amount on the remote server
45
+ # This is invoked after a successful record save
46
+ # This deletes the oldest files when the backup limit has been exceeded
47
+ def clean_backups
48
+ if keep_backups.is_a?(Integer)
49
+ backups = self.class.all(:conditions => {:trigger => trigger})
50
+ backups_to_destroy = backups[keep_backups, backups.size] || []
51
+
52
+ unless backups_to_destroy.empty?
53
+ # Derived classes must implement this method!
54
+ self.class.destroy_backups(adapter_config.procedure, backups_to_destroy)
55
+
56
+ puts "\nBackup storage for \"#{trigger}\" is limited to #{keep_backups} backups."
57
+ puts "\nThe #{keep_backups} most recent backups are now stored on the remote server.\n\n"
58
+ end
59
+ end
60
+ end
61
+
62
+ end
63
+ end
64
+ end
65
+
@@ -0,0 +1,28 @@
1
+ require 'backup/connection/cloudfiles'
2
+
3
+ module Backup
4
+ module Record
5
+ class CloudFiles < Backup::Record::Base
6
+
7
+ alias_attribute :container, :bucket
8
+
9
+ def load_specific_settings(adapter)
10
+ self.container = adapter.procedure.get_storage_configuration.attributes['container']
11
+ end
12
+
13
+ private
14
+
15
+ def self.destroy_backups(procedure, backups)
16
+ cf = Backup::Connection::CloudFiles.new
17
+ cf.static_initialize(procedure)
18
+ cf.connect
19
+ backups.each do |backup|
20
+ puts "\nDestroying backup \"#{backup.filename}\" from container \"#{backup.container}\"."
21
+ cf.destroy(backup.filename, backup.container)
22
+ backup.destroy
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ require 'backup/connection/dropbox'
2
+
3
+ module Backup
4
+ module Record
5
+ class Dropbox < Backup::Record::Base
6
+ def load_specific_settings(adapter)
7
+ end
8
+
9
+ private
10
+
11
+ def self.destroy_backups(procedure, backups)
12
+ dropbox = Backup::Connection::Dropbox.new
13
+ dropbox.static_initialize(procedure)
14
+ session = dropbox.session
15
+ backups.each do |backup|
16
+ puts "\nDestroying backup \"#{backup.filename}\"."
17
+ path_to_file = File.join(dropbox.path, backup.filename)
18
+ begin
19
+ session.delete(path_to_file, :mode => :dropbox)
20
+ rescue ::Dropbox::FileNotFoundError => e
21
+ puts "\n Backup with name '#{backup.filename}' was not found in '#{dropbox.path}'"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,39 @@
1
+ require 'net/ftp'
2
+
3
+ module Backup
4
+ module Record
5
+ class FTP < Backup::Record::Base
6
+
7
+ attr_accessor :ip, :user, :password
8
+
9
+ def load_specific_settings(adapter)
10
+ %w(ip user password path).each do |method|
11
+ send(:"#{method}=", adapter.procedure.get_storage_configuration.attributes[method])
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def self.destroy_backups(procedure, backups)
18
+ ip = procedure.get_storage_configuration.attributes['ip']
19
+ user = procedure.get_storage_configuration.attributes['user']
20
+ password = procedure.get_storage_configuration.attributes['password']
21
+
22
+ Net::FTP.open(ip, user, password) do |ftp|
23
+ backups.each do |backup|
24
+ puts "\nDestroying backup \"#{backup.filename}\" from path \"#{backup.path}\"."
25
+ begin
26
+ ftp.chdir(backup.path)
27
+ ftp.delete(backup.filename)
28
+ backup.destroy
29
+ rescue
30
+ puts "Could not find backup #{backup.path}/#{backup.filename}."
31
+ backup.destroy
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Backup
2
+ module Record
3
+ class Local < Backup::Record::Base
4
+
5
+ def load_specific_settings(adapter)
6
+ self.path = adapter.procedure.get_storage_configuration.attributes['path']
7
+ end
8
+
9
+ private
10
+
11
+ class << self
12
+ include Backup::CommandHelper
13
+
14
+ def destroy_backups(procedure, backups)
15
+ backups.each do |backup|
16
+ puts "\nDestroying backup \"#{backup.filename}\" from path \"#{backup.path}\"."
17
+ run "rm #{File.join(backup.path, backup.filename)}"
18
+ backup.destroy
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,25 @@
1
+ require 'backup/connection/s3'
2
+
3
+ module Backup
4
+ module Record
5
+ class S3 < Backup::Record::Base
6
+
7
+ def load_specific_settings(adapter)
8
+ self.bucket = adapter.procedure.get_storage_configuration.attributes['bucket']
9
+ end
10
+
11
+ private
12
+
13
+ def self.destroy_backups(procedure, backups)
14
+ s3 = Backup::Connection::S3.new
15
+ s3.static_initialize(procedure)
16
+ backups.each do |backup|
17
+ puts "\nDestroying backup \"#{backup.filename}\" from bucket \"#{backup.bucket}\"."
18
+ s3.destroy(backup.filename, backup.bucket)
19
+ backup.destroy
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end