namxam-backup 2.4.5

Sign up to get free protection for your applications and to get access to all the features.
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