dmitryv-backup 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/CHANGELOG +125 -0
  2. data/LICENSE +20 -0
  3. data/README.md +180 -0
  4. data/VERSION +1 -0
  5. data/bin/backup +108 -0
  6. data/generators/backup/backup_generator.rb +69 -0
  7. data/generators/backup/templates/backup.rake +56 -0
  8. data/generators/backup/templates/backup.rb +229 -0
  9. data/generators/backup/templates/create_backup_tables.rb +18 -0
  10. data/generators/backup_update/backup_update_generator.rb +50 -0
  11. data/generators/backup_update/templates/migrations/update_backup_tables.rb +27 -0
  12. data/lib/backup.rb +131 -0
  13. data/lib/backup/adapters/archive.rb +34 -0
  14. data/lib/backup/adapters/base.rb +138 -0
  15. data/lib/backup/adapters/custom.rb +41 -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 +11 -0
  20. data/lib/backup/compressors/base.rb +7 -0
  21. data/lib/backup/compressors/gzip.rb +9 -0
  22. data/lib/backup/compressors/seven_zip.rb +9 -0
  23. data/lib/backup/configuration/adapter.rb +21 -0
  24. data/lib/backup/configuration/adapter_options.rb +8 -0
  25. data/lib/backup/configuration/attributes.rb +19 -0
  26. data/lib/backup/configuration/base.rb +77 -0
  27. data/lib/backup/configuration/helpers.rb +24 -0
  28. data/lib/backup/configuration/mail.rb +20 -0
  29. data/lib/backup/configuration/smtp.rb +8 -0
  30. data/lib/backup/configuration/storage.rb +8 -0
  31. data/lib/backup/connection/cloudfiles.rb +75 -0
  32. data/lib/backup/connection/s3.rb +85 -0
  33. data/lib/backup/environment/base.rb +12 -0
  34. data/lib/backup/environment/rails_configuration.rb +15 -0
  35. data/lib/backup/environment/unix_configuration.rb +109 -0
  36. data/lib/backup/mail/base.rb +97 -0
  37. data/lib/backup/mail/mail.txt +7 -0
  38. data/lib/backup/record/base.rb +65 -0
  39. data/lib/backup/record/cloudfiles.rb +28 -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 +26 -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/ftp.rb +38 -0
  48. data/lib/backup/storage/local.rb +22 -0
  49. data/lib/backup/storage/s3.rb +17 -0
  50. data/lib/backup/storage/scp.rb +30 -0
  51. data/lib/backup/storage/sftp.rb +31 -0
  52. data/lib/generators/backup/USAGE +10 -0
  53. data/lib/generators/backup/backup_generator.rb +47 -0
  54. data/lib/generators/backup/templates/backup.rake +56 -0
  55. data/lib/generators/backup/templates/backup.rb +229 -0
  56. data/lib/generators/backup/templates/create_backup_tables.rb +18 -0
  57. data/setup/backup.rb +231 -0
  58. data/setup/backup.sqlite3 +0 -0
  59. metadata +271 -0
@@ -0,0 +1,77 @@
1
+ module Backup
2
+ module Configuration
3
+ class Base
4
+ extend Backup::Configuration::Attributes
5
+ generate_attributes %w(encrypt_with_password encrypt_with_gpg_public_key keep_backups notify)
6
+
7
+ attr_accessor :trigger, :storage_name, :adapter_name
8
+
9
+ def initialize(trigger)
10
+ @trigger = trigger
11
+ @adapter_configuration = Backup::Configuration::Adapter.new
12
+ @storage_configuration = Backup::Configuration::Storage.new
13
+ @compressor = :gzip
14
+ end
15
+
16
+ def adapter(adapter, &block)
17
+ @adapter_name = adapter
18
+ @adapter_configuration.instance_eval &block
19
+ end
20
+
21
+ def storage(storage, &block)
22
+ @storage_name = storage
23
+ @storage_configuration.instance_eval &block
24
+ end
25
+
26
+ def compressor(compressor)
27
+ @compressor = compressor
28
+ end
29
+
30
+ def storage_class
31
+ case @storage_name.to_sym
32
+ when :cloudfiles then Backup::Storage::CloudFiles
33
+ when :s3 then Backup::Storage::S3
34
+ when :scp then Backup::Storage::SCP
35
+ when :ftp then Backup::Storage::FTP
36
+ when :sftp then Backup::Storage::SFTP
37
+ when :local then Backup::Storage::Local
38
+ end
39
+ end
40
+
41
+ def record_class
42
+ case @storage_name.to_sym
43
+ when :cloudfiles then Backup::Record::CloudFiles
44
+ when :s3 then Backup::Record::S3
45
+ when :scp then Backup::Record::SCP
46
+ when :ftp then Backup::Record::FTP
47
+ when :sftp then Backup::Record::SFTP
48
+ when :local then Backup::Record::Local
49
+ end
50
+ end
51
+
52
+ def compressor_class
53
+ case @compressor.to_sym
54
+ when :gzip then Backup::Compressors::Gzip
55
+ when :seven_zip then Backup::Compressors::SevenZip
56
+ end
57
+ end
58
+
59
+ # Initializes the storing process depending on the store settings
60
+ def initialize_storage(adapter)
61
+ storage_class.new(adapter)
62
+ end
63
+
64
+ def initialize_record
65
+ record_class.new
66
+ end
67
+
68
+ def get_adapter_configuration
69
+ @adapter_configuration
70
+ end
71
+
72
+ def get_storage_configuration
73
+ @storage_configuration
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,24 @@
1
+ module Backup
2
+ module Configuration
3
+ module Helpers
4
+
5
+ # A helper method for the config/backup.rb configuration file
6
+ # Expects a trigger in argument one (STRING)
7
+ # Expects a block of settings
8
+ def backup(trigger, &block)
9
+ backup = Backup::Configuration::Base.new(trigger)
10
+ backup.instance_eval &block
11
+ @backup_procedures ||= Array.new
12
+ @backup_procedures << backup
13
+ end
14
+
15
+ # A helper method for the config/mail.rb configuration file
16
+ # Takes a block containing the mail options
17
+ def notifier_settings(&block)
18
+ @mail_configuration = Backup::Configuration::Mail.new
19
+ @mail_configuration.instance_eval &block
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module Backup
2
+ module Configuration
3
+ class Mail
4
+ extend Backup::Configuration::Attributes
5
+ generate_attributes %w(from to smtp)
6
+
7
+ def initialize
8
+ @smtp_configuration = Backup::Configuration::SMTP.new
9
+ end
10
+
11
+ def smtp(&block)
12
+ @smtp_configuration.instance_eval &block
13
+ end
14
+
15
+ def get_smtp_configuration
16
+ @smtp_configuration
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ module Backup
2
+ module Configuration
3
+ class SMTP
4
+ extend Backup::Configuration::Attributes
5
+ generate_attributes %w(host port username password authentication domain tls)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module Backup
2
+ module Configuration
3
+ class Storage
4
+ extend Backup::Configuration::Attributes
5
+ generate_attributes %w(ip user password path access_key_id secret_access_key use_ssl bucket username api_key container)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,75 @@
1
+ require 'cloudfiles'
2
+
3
+ module Backup
4
+ module Connection
5
+ class CloudFiles
6
+
7
+ attr_accessor :adapter, :procedure, :api_key, :username, :cf_container, :final_file, :tmp_path
8
+
9
+ # Initializes the Cloud Files connection, setting the values using the
10
+ # Cloud Files adapter
11
+ def initialize(adapter = false)
12
+ if adapter
13
+ self.adapter = adapter
14
+ self.procedure = adapter.procedure
15
+ self.final_file = adapter.final_file
16
+ self.tmp_path = adapter.tmp_path.gsub('\ ', ' ')
17
+ load_storage_configuration_attributes
18
+ end
19
+ end
20
+
21
+ # Sets values from a procedure, rather than from the adapter object
22
+ def static_initialize(procedure)
23
+ self.procedure = procedure
24
+ load_storage_configuration_attributes(true)
25
+ end
26
+
27
+ # Establishes a connection with Rackspace Cloud Files using the
28
+ # credentials provided by the user
29
+ def connect
30
+ connection
31
+ end
32
+
33
+ # Wrapper for the Connection object
34
+ def connection
35
+ ::CloudFiles::Connection.new(username, api_key)
36
+ end
37
+
38
+ # Wrapper for the Container object
39
+ def container
40
+ connection.container(cf_container)
41
+ end
42
+
43
+ # Initializes the file transfer to Rackspace Cloud Files
44
+ # This can only run after a connection has been made using the #connect method
45
+ def store
46
+ object = container.create_object(final_file)
47
+ object.write(open(File.join(tmp_path, final_file)))
48
+ end
49
+
50
+ # Destroys file from a bucket on Amazon S3
51
+ def destroy(file, c)
52
+ c = connection.container(c)
53
+ c.delete_object(file)
54
+ end
55
+
56
+ private
57
+
58
+ def load_storage_configuration_attributes(static = false)
59
+ %w(api_key username).each do |attribute|
60
+ if static
61
+ send("#{attribute}=", procedure.get_storage_configuration.attributes[attribute])
62
+ else
63
+ send("#{attribute}=", adapter.procedure.get_storage_configuration.attributes[attribute])
64
+ end
65
+ end
66
+
67
+ if static
68
+ self.cf_container = procedure.get_storage_configuration.attributes['container']
69
+ else
70
+ self.cf_container = adapter.procedure.get_storage_configuration.attributes['container']
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,85 @@
1
+ require 's3'
2
+
3
+ module Backup
4
+ module Connection
5
+ class S3
6
+
7
+ attr_accessor :adapter, :procedure, :access_key_id, :secret_access_key, :s3_bucket, :use_ssl, :final_file, :tmp_path
8
+
9
+ # Initializes the S3 connection, setting the values using the S3 adapter
10
+ def initialize(adapter = false)
11
+ if adapter
12
+ self.adapter = adapter
13
+ self.procedure = adapter.procedure
14
+ self.final_file = adapter.final_file
15
+ self.tmp_path = adapter.tmp_path.gsub('\ ', ' ')
16
+ load_storage_configuration_attributes
17
+ end
18
+ end
19
+
20
+ # Sets values from a procedure, rather than from the adapter object
21
+ def static_initialize(procedure)
22
+ self.procedure = procedure
23
+ load_storage_configuration_attributes(true)
24
+ end
25
+
26
+ # Establishes a connection with Amazon S3 using the credentials provided by the user
27
+ def connect
28
+ service
29
+ end
30
+
31
+ # Wrapper for the Service object
32
+ def service
33
+ ::S3::Service.new(:access_key_id => access_key_id,
34
+ :secret_access_key => secret_access_key,
35
+ :use_ssl => use_ssl)
36
+ end
37
+
38
+ # Wrapper for the Bucket object
39
+ def bucket
40
+ begin
41
+ # Find existing bucket:
42
+ bucket = service.buckets.find(s3_bucket)
43
+ rescue ::S3::Error::NoSuchBucket => e
44
+ # Apparently the bucket doesn't exist yet, so create a new one:
45
+ bucket = service.buckets.build(s3_bucket)
46
+ bucket.save
47
+ end
48
+ bucket.retrieve
49
+ end
50
+
51
+ # Initializes the file transfer to Amazon S3
52
+ # This can only run after a connection has been made using the #connect method
53
+ def store
54
+ object = bucket.objects.build(final_file)
55
+ object.content = open(File.join(tmp_path, final_file))
56
+ object.save
57
+ end
58
+
59
+ # Destroys file from a bucket on Amazon S3
60
+ def destroy(file, bucket_as_string)
61
+ object = bucket.objects.find(file)
62
+ object.destroy
63
+ end
64
+
65
+ private
66
+
67
+ def load_storage_configuration_attributes(static = false)
68
+ %w(access_key_id secret_access_key use_ssl).each do |attribute|
69
+ if static
70
+ send("#{attribute}=", procedure.get_storage_configuration.attributes[attribute])
71
+ else
72
+ send("#{attribute}=", adapter.procedure.get_storage_configuration.attributes[attribute])
73
+ end
74
+ end
75
+
76
+ if static
77
+ self.s3_bucket = procedure.get_storage_configuration.attributes['bucket']
78
+ else
79
+ self.s3_bucket = adapter.procedure.get_storage_configuration.attributes['bucket']
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ 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