backup 3.0.3 → 3.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +22 -2
- data/README.md +51 -16
- data/backup.gemspec +3 -2
- data/lib/backup.rb +8 -6
- data/lib/backup/configuration/notifier/twitter.rb +21 -0
- data/lib/backup/configuration/syncer/rsync.rb +4 -4
- data/lib/backup/notifier/twitter.rb +87 -0
- data/lib/backup/syncer/rsync.rb +14 -14
- data/lib/backup/version.rb +7 -36
- data/lib/templates/notifier/twitter +9 -0
- data/lib/templates/syncer/rsync +3 -3
- data/spec/notifier/twitter_spec.rb +86 -0
- data/spec/syncer/rsync_spec.rb +11 -11
- data/spec/version_spec.rb +5 -16
- metadata +18 -3
data/Gemfile.lock
CHANGED
@@ -1,18 +1,20 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
backup (3.0.
|
4
|
+
backup (3.0.4)
|
5
5
|
dropbox (~> 1.2.3)
|
6
6
|
fog (~> 0.5.3)
|
7
7
|
mail (~> 2.2.15)
|
8
8
|
net-scp (~> 1.0.4)
|
9
9
|
net-sftp (~> 2.0.5)
|
10
10
|
thor (~> 0.14.6)
|
11
|
+
twitter (~> 1.1.2)
|
11
12
|
|
12
13
|
GEM
|
13
14
|
remote: http://rubygems.org/
|
14
15
|
specs:
|
15
16
|
activesupport (3.0.5)
|
17
|
+
addressable (2.2.4)
|
16
18
|
builder (3.0.0)
|
17
19
|
diff-lcs (1.1.2)
|
18
20
|
dropbox (1.2.3)
|
@@ -21,6 +23,12 @@ GEM
|
|
21
23
|
multipart-post (>= 1.0)
|
22
24
|
oauth (>= 0.3.6)
|
23
25
|
excon (0.5.6)
|
26
|
+
faraday (0.5.7)
|
27
|
+
addressable (~> 2.2.4)
|
28
|
+
multipart-post (~> 1.1.0)
|
29
|
+
rack (< 2, >= 1.1.0)
|
30
|
+
faraday_middleware (0.3.2)
|
31
|
+
faraday (~> 0.5.4)
|
24
32
|
fog (0.5.3)
|
25
33
|
builder
|
26
34
|
excon (>= 0.5.2)
|
@@ -30,11 +38,12 @@ GEM
|
|
30
38
|
net-ssh (>= 2.0.23)
|
31
39
|
nokogiri (>= 1.4.4)
|
32
40
|
ruby-hmac
|
33
|
-
formatador (0.
|
41
|
+
formatador (0.1.1)
|
34
42
|
fuubar (0.0.3)
|
35
43
|
rspec (~> 2.0)
|
36
44
|
rspec-instafail (~> 0.1.4)
|
37
45
|
ruby-progressbar (~> 0.0.9)
|
46
|
+
hashie (1.0.0)
|
38
47
|
i18n (0.5.0)
|
39
48
|
infinity_test (1.0.2)
|
40
49
|
notifiers (>= 1.1.0)
|
@@ -49,6 +58,8 @@ GEM
|
|
49
58
|
nokogiri (>= 1.2.1)
|
50
59
|
mime-types (1.16)
|
51
60
|
mocha (0.9.12)
|
61
|
+
multi_json (0.0.5)
|
62
|
+
multi_xml (0.2.1)
|
52
63
|
multipart-post (1.1.0)
|
53
64
|
net-scp (1.0.4)
|
54
65
|
net-ssh (>= 1.99.1)
|
@@ -59,6 +70,7 @@ GEM
|
|
59
70
|
notifiers (1.1.0)
|
60
71
|
oauth (0.4.4)
|
61
72
|
polyglot (0.3.1)
|
73
|
+
rack (1.2.1)
|
62
74
|
rspec (2.5.0)
|
63
75
|
rspec-core (~> 2.5.0)
|
64
76
|
rspec-expectations (~> 2.5.0)
|
@@ -70,10 +82,18 @@ GEM
|
|
70
82
|
rspec-mocks (2.5.0)
|
71
83
|
ruby-hmac (0.4.0)
|
72
84
|
ruby-progressbar (0.0.9)
|
85
|
+
simple_oauth (0.1.4)
|
73
86
|
thor (0.14.6)
|
74
87
|
timecop (0.3.5)
|
75
88
|
treetop (1.4.9)
|
76
89
|
polyglot (>= 0.3.1)
|
90
|
+
twitter (1.1.2)
|
91
|
+
faraday (~> 0.5.4)
|
92
|
+
faraday_middleware (~> 0.3.1)
|
93
|
+
hashie (~> 1.0.0)
|
94
|
+
multi_json (~> 0.0.5)
|
95
|
+
multi_xml (~> 0.2.0)
|
96
|
+
simple_oauth (~> 0.1.3)
|
77
97
|
watchr (0.7)
|
78
98
|
|
79
99
|
PLATFORMS
|
data/README.md
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
Backup 3
|
2
2
|
========
|
3
3
|
|
4
|
-
Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX) that allows you to configure and perform backups in a simple manner using an elegant Ruby DSL. It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations (Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it can archive files and folders, it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG), it can notify you about successful and/or failed backups. It is very extensible and easy to add new functionality to. It's easy to use.
|
4
|
+
Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX) that allows you to configure and perform backups in a simple manner using an elegant Ruby DSL. It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations (Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it can archive files and folders, it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG), it can notify you about successful and/or failed backups (Email or Twitter). It is very extensible and easy to add new functionality to. It's easy to use.
|
5
5
|
|
6
6
|
Author
|
7
7
|
------
|
8
8
|
|
9
|
-
Michael van Rooijen ( [@meskyanichi](http://twitter.com/#!/meskyanichi) )
|
9
|
+
**Michael van Rooijen ( [@meskyanichi](http://twitter.com/#!/meskyanichi) )**
|
10
10
|
|
11
11
|
Drop me a message for any questions, suggestions, requests, bugs or submit them to the [issue log](https://github.com/meskyanichi/backup/issues).
|
12
12
|
|
@@ -17,14 +17,12 @@ To get the latest stable version
|
|
17
17
|
|
18
18
|
gem install backup
|
19
19
|
|
20
|
-
To get the latest *build* of the latest stable version
|
21
|
-
|
22
|
-
gem install backup --pre
|
23
|
-
|
24
|
-
Builds **aim** to be stable, but cannot guarantee it. Builds tend to be released a lot more frequent than the stable versions. So if you want to live on the edge and want the latest improvements, install the build gems.
|
25
|
-
|
26
20
|
You can view the list of released versions over at [RubyGems.org (Backup)](https://rubygems.org/gems/backup/versions)
|
27
21
|
|
22
|
+
Getting Started
|
23
|
+
---------------
|
24
|
+
|
25
|
+
I recommend you read this README first, and refer to the [Wiki pages](https://github.com/meskyanichi/backup/wiki) afterwards. There's also a [Getting Started wiki page](https://github.com/meskyanichi/backup/wiki/Getting-Started).
|
28
26
|
|
29
27
|
What Backup 3 currently supports
|
30
28
|
================================
|
@@ -72,6 +70,13 @@ Storage Features
|
|
72
70
|
|
73
71
|
[Storage Wiki Page](https://github.com/meskyanichi/backup/wiki/Storages)
|
74
72
|
|
73
|
+
Syncers
|
74
|
+
-------
|
75
|
+
|
76
|
+
- RSync
|
77
|
+
|
78
|
+
[Syncer Wiki Page](https://github.com/meskyanichi/backup/wiki/Syncers)
|
79
|
+
|
75
80
|
Compressors
|
76
81
|
-----------
|
77
82
|
|
@@ -91,6 +96,7 @@ Notifiers
|
|
91
96
|
---------
|
92
97
|
|
93
98
|
- Mail
|
99
|
+
- Twitter
|
94
100
|
|
95
101
|
[Notifiers Wiki Page](https://github.com/meskyanichi/backup/wiki/Notifiers)
|
96
102
|
|
@@ -158,34 +164,50 @@ Below you see a sample configuration file you could create for Backup 3. Just re
|
|
158
164
|
s3.keep = 20
|
159
165
|
end
|
160
166
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
167
|
+
sync_with RSync do |rsync|
|
168
|
+
rsync.ip = "123.45.678.90"
|
169
|
+
rsync.username = "my_username"
|
170
|
+
rsync.path = "~/backups/"
|
171
|
+
rsync.mirror = true
|
172
|
+
rsync.compress = true
|
173
|
+
|
174
|
+
rsync.directories do |directory|
|
175
|
+
directory.add "/var/apps/my_app/public/videos"
|
176
|
+
directory.add "/var/apps/my_app/public/music"
|
177
|
+
end
|
166
178
|
end
|
167
179
|
|
168
180
|
notify_by Mail do |mail|
|
169
181
|
mail.on_success = false
|
170
182
|
mail.on_failure = true
|
171
183
|
end
|
184
|
+
|
185
|
+
notify_by Twitter do |tweet|
|
186
|
+
tweet.on_success = true
|
187
|
+
tweet.on_failure = true
|
188
|
+
end
|
189
|
+
|
172
190
|
end
|
173
191
|
|
174
192
|
### Explanation for the above example
|
175
193
|
|
176
|
-
First it dumps all the tables inside the MySQL database "my_sample_mysql_db", except for the "logs" table. It also dumps the MongoDB database "my_sample_mongo_db", but only the collections "users", "events" and "posts". After that it'll create a "user_avatars.tar" archive with all the uploaded avatars of the users. After that it'll create a "logs.tar" archive with the "production.log", "newrelic_agent.log" and "other.log" logs. After that it'll compress the backup file using Gzip (with the mode set to "best", rather than "fast" for best compression). After that it'll encrypt the whole backup file (everything included: databases, archives) using "OpenSSL". Now the Backup can only be extracted when you know the password to decrypt it ("my_secret_password" in this case). Then it'll store the backup file to Amazon S3 in to 'my_bucket/backups'. Next
|
194
|
+
First it dumps all the tables inside the MySQL database "my_sample_mysql_db", except for the "logs" table. It also dumps the MongoDB database "my_sample_mongo_db", but only the collections "users", "events" and "posts". After that it'll create a "user_avatars.tar" archive with all the uploaded avatars of the users. After that it'll create a "logs.tar" archive with the "production.log", "newrelic_agent.log" and "other.log" logs. After that it'll compress the backup file using Gzip (with the mode set to "best", rather than "fast" for best compression). After that it'll encrypt the whole backup file (everything included: databases, archives) using "OpenSSL". Now the Backup can only be extracted when you know the password to decrypt it ("my_secret_password" in this case). Then it'll store the backup file to Amazon S3 in to 'my_bucket/backups'. Next, we're going to use the RSync Syncer to create a mirror of the `/var/apps/my_app/public/videos` and `/var/apps/my_app/public/music` folders on a remote server. (This will not package, compress, encrypt - but will directly sync these folders "as is" to the desired location). Finally, it'll notify me by email if the backup raises an error/exception during the process, indicating that something went wrong. However, it does not notify me by email when successful backups occur because I set `mail.on_success` to `false`. It'll also notify me by Twitter when failed backups occur, but also when successful ones occur because I set the `tweet.on_success` to `true`.
|
177
195
|
|
178
196
|
### Things to note
|
179
197
|
|
180
198
|
The __keep__ option I passed in to the S3 storage location enables "Backup Cycling". In this case, after the 21st backup file gets pushed, it'll exceed the 20 backup limit, and remove the oldest backup from the S3 bucket.
|
181
199
|
|
182
|
-
The __RSync__
|
200
|
+
The __RSync__ Syncer ( `sync_with` ) is a different kind of __Storage__ method. As mentioned above, it does not follow the same procedure as the __Storage__ ( `store_with` ) method. A Storage method stores the final result of a copied/organized/packaged/compressed/encrypted file to the desired remote location. A Syncer directly syncs the specified directories and **completely bypasses** the copied/organized/packaged/compressed/encrypted process. This is especially good for backing up directories containing gigabytes of data, such as images, music, videos, and similar large formats. Also, rather than transferring the whole directory every time, it'll only transfer files in all these directories that have been modified or new ones that have been added, and it only transfers the bytes of the modified files that changed, and **not** the full file, thus, saving huge amounts of bandwidth, cpu load, time and possibly money.
|
183
201
|
|
184
202
|
The __Mail__ notifier. I have not provided the SMTP options to use my Gmail account to notify myself when exceptions are raised during the process. So this won't work, check out the wiki on how to configure this. I left it out in this example.
|
185
203
|
|
204
|
+
The __Twitter__ notifier. You will require your consumer and oauth credentials, which I have also left out of this example.
|
205
|
+
|
206
|
+
Check out the Wiki for more information on all the above subjects.
|
207
|
+
|
186
208
|
### And that's it!
|
187
209
|
|
188
|
-
So as you can see the DSL is straightforward and should be simple to understand and extend to your needs. You can have as many databases, archives, storage locations, compressors, encryptors and notifiers inside the above example as you need and it'll bundle all of it up in a nice packaged archive and transfer it to every specified location (as redundant as you like).
|
210
|
+
So as you can see the DSL is straightforward and should be simple to understand and extend to your needs. You can have as many databases, archives, storage locations, syncers, compressors, encryptors and notifiers inside the above example as you need and it'll bundle all of it up in a nice packaged archive and transfer it to every specified location (as redundant as you like).
|
189
211
|
|
190
212
|
### Running the example
|
191
213
|
|
@@ -216,6 +238,19 @@ Suggestions, Bugs, Requests, Questions
|
|
216
238
|
|
217
239
|
View the [issue log](https://github.com/meskyanichi/backup/issues) and post them there.
|
218
240
|
|
241
|
+
Contributors
|
242
|
+
------------
|
243
|
+
|
244
|
+
<table>
|
245
|
+
<tr>
|
246
|
+
<th>Contributor</th>
|
247
|
+
<th>Contribution</th>
|
248
|
+
</tr>
|
249
|
+
<tr>
|
250
|
+
<td><a href="https://github.com/asanghi" target="_blank">Aditya Sanghi ( asanghi )</a></td>
|
251
|
+
<td>Twitter Notifier</td>
|
252
|
+
</tr>
|
253
|
+
</table>
|
219
254
|
|
220
255
|
Want to contribute?
|
221
256
|
-------------------
|
data/backup.gemspec
CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |gem|
|
|
7
7
|
##
|
8
8
|
# General configuration / information
|
9
9
|
gem.name = 'backup'
|
10
|
-
gem.version = Backup::Version.
|
10
|
+
gem.version = Backup::Version.current
|
11
11
|
gem.platform = Gem::Platform::RUBY
|
12
12
|
gem.authors = 'Michael van Rooijen'
|
13
13
|
gem.email = 'meskyanichi@gmail.com'
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
17
17
|
It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations
|
18
18
|
(Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it can archive files and folders,
|
19
19
|
it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG),
|
20
|
-
it can notify you about successful and/or failed backups. It is very extensible and easy to add new functionality to. It\'s easy to use.'
|
20
|
+
it can notify you about successful and/or failed backups (Email, Twitter). It is very extensible and easy to add new functionality to. It\'s easy to use.'
|
21
21
|
|
22
22
|
##
|
23
23
|
# Files and folder that need to be compiled in to the Ruby Gem
|
@@ -37,5 +37,6 @@ Gem::Specification.new do |gem|
|
|
37
37
|
gem.add_dependency 'mail', ['~> 2.2.15'] # Mail
|
38
38
|
gem.add_dependency 'net-sftp', ['~> 2.0.5' ] # SFTP Protocol
|
39
39
|
gem.add_dependency 'net-scp', ['~> 1.0.4' ] # SCP Protocol
|
40
|
+
gem.add_dependency 'twitter', ['~> 1.1.2' ] # Twitter
|
40
41
|
|
41
42
|
end
|
data/lib/backup.rb
CHANGED
@@ -20,8 +20,8 @@ module Backup
|
|
20
20
|
STORAGES = ['S3', 'CloudFiles', 'Dropbox', 'FTP', 'SFTP', 'SCP', 'RSync']
|
21
21
|
COMPRESSORS = ['Gzip']
|
22
22
|
ENCRYPTORS = ['OpenSSL', 'GPG']
|
23
|
-
NOTIFIERS = ['Mail']
|
24
23
|
SYNCERS = ['RSync']
|
24
|
+
NOTIFIERS = ['Mail', 'Twitter']
|
25
25
|
|
26
26
|
##
|
27
27
|
# Backup's internal paths
|
@@ -58,8 +58,9 @@ module Backup
|
|
58
58
|
autoload :Helpers, File.join(CONFIGURATION_PATH, 'helpers')
|
59
59
|
|
60
60
|
module Notifier
|
61
|
-
autoload :Base,
|
62
|
-
autoload :Mail,
|
61
|
+
autoload :Base, File.join(CONFIGURATION_PATH, 'notifier', 'base')
|
62
|
+
autoload :Mail, File.join(CONFIGURATION_PATH, 'notifier', 'mail')
|
63
|
+
autoload :Twitter, File.join(CONFIGURATION_PATH, 'notifier', 'twitter')
|
63
64
|
end
|
64
65
|
|
65
66
|
module Encryptor
|
@@ -145,9 +146,10 @@ module Backup
|
|
145
146
|
##
|
146
147
|
# Autoload notification files
|
147
148
|
module Notifier
|
148
|
-
autoload :Base,
|
149
|
-
autoload :Binder,
|
150
|
-
autoload :Mail,
|
149
|
+
autoload :Base, File.join(NOTIFIER_PATH, 'base')
|
150
|
+
autoload :Binder, File.join(NOTIFIER_PATH, 'binder')
|
151
|
+
autoload :Mail, File.join(NOTIFIER_PATH, 'mail')
|
152
|
+
autoload :Twitter, File.join(NOTIFIER_PATH, 'twitter')
|
151
153
|
end
|
152
154
|
|
153
155
|
##
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Backup
|
4
|
+
module Configuration
|
5
|
+
module Notifier
|
6
|
+
class Twitter < Base
|
7
|
+
class << self
|
8
|
+
|
9
|
+
##
|
10
|
+
# Twitter consumer key credentials
|
11
|
+
attr_accessor :consumer_key, :consumer_secret
|
12
|
+
|
13
|
+
##
|
14
|
+
# OAuth credentials
|
15
|
+
attr_accessor :oauth_token, :oauth_token_secret
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -19,15 +19,15 @@ module Backup
|
|
19
19
|
attr_accessor :port
|
20
20
|
|
21
21
|
##
|
22
|
-
#
|
23
|
-
attr_accessor :
|
22
|
+
# Directories to sync
|
23
|
+
attr_accessor :directories
|
24
24
|
|
25
25
|
##
|
26
|
-
# Path to store the synced files/
|
26
|
+
# Path to store the synced files/directories to
|
27
27
|
attr_accessor :path
|
28
28
|
|
29
29
|
##
|
30
|
-
# Flag for mirroring the files/
|
30
|
+
# Flag for mirroring the files/directories
|
31
31
|
attr_accessor :mirror
|
32
32
|
|
33
33
|
##
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
##
|
4
|
+
# Only load the Twitter gem when using Twitter notifications
|
5
|
+
require 'twitter'
|
6
|
+
|
7
|
+
module Backup
|
8
|
+
module Notifier
|
9
|
+
class Twitter < Base
|
10
|
+
|
11
|
+
##
|
12
|
+
# Container for the Twitter Client object
|
13
|
+
attr_accessor :twitter_client
|
14
|
+
|
15
|
+
##
|
16
|
+
# Container for the Model object
|
17
|
+
attr_accessor :model
|
18
|
+
|
19
|
+
##
|
20
|
+
# Twitter consumer key credentials
|
21
|
+
attr_accessor :consumer_key, :consumer_secret
|
22
|
+
|
23
|
+
##
|
24
|
+
# OAuth credentials
|
25
|
+
attr_accessor :oauth_token, :oauth_token_secret
|
26
|
+
|
27
|
+
##
|
28
|
+
# Instantiates a new Backup::Notifier::Twitter object
|
29
|
+
def initialize(&block)
|
30
|
+
load_defaults!
|
31
|
+
|
32
|
+
instance_eval(&block) if block_given?
|
33
|
+
|
34
|
+
set_defaults!
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Performs the notification
|
39
|
+
# Takes an exception object that might've been created if an exception occurred.
|
40
|
+
# If this is the case it'll invoke notify_failure!(exception), otherwise, if no
|
41
|
+
# error was raised, it'll go ahead and notify_success!
|
42
|
+
#
|
43
|
+
# If'll only perform these if on_success is true or on_failure is true
|
44
|
+
def perform!(model, exception = false)
|
45
|
+
@model = model
|
46
|
+
|
47
|
+
if notify_on_success? and exception.eql?(false)
|
48
|
+
log!
|
49
|
+
notify_success!
|
50
|
+
elsif notify_on_failure? and not exception.eql?(false)
|
51
|
+
log!
|
52
|
+
notify_failure!(exception)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
##
|
59
|
+
# Sends a tweet informing the user that the backup operation
|
60
|
+
# proceeded without any errors
|
61
|
+
def notify_success!
|
62
|
+
twitter_client.update("[Backup::Succeeded] #{model.label} (#{model.trigger})")
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Sends a tweet informing the user that the backup operation
|
67
|
+
# raised an exception and will send the user the error details
|
68
|
+
def notify_failure!(exception)
|
69
|
+
twitter_client.update("[Backup::Failed] #{model.label} (#{model.trigger})")
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# Configures the Twitter object by passing in the @consumer_key, @consumer_secret
|
74
|
+
# @oauth_token and @oauth_token_secret. Instantiates and sets the @twitter_client object
|
75
|
+
def set_defaults!
|
76
|
+
::Twitter.configure do |config|
|
77
|
+
config.consumer_key = @consumer_key
|
78
|
+
config.consumer_secret = @consumer_secret
|
79
|
+
config.oauth_token = @oauth_token
|
80
|
+
config.oauth_token_secret = @oauth_token_secret
|
81
|
+
end
|
82
|
+
@twitter_client = ::Twitter.client
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/backup/syncer/rsync.rb
CHANGED
@@ -19,15 +19,15 @@ module Backup
|
|
19
19
|
attr_writer :port
|
20
20
|
|
21
21
|
##
|
22
|
-
#
|
23
|
-
attr_writer :
|
22
|
+
# Directories to sync
|
23
|
+
attr_writer :directories
|
24
24
|
|
25
25
|
##
|
26
|
-
# Path to store the synced files/
|
26
|
+
# Path to store the synced files/directories to
|
27
27
|
attr_accessor :path
|
28
28
|
|
29
29
|
##
|
30
|
-
# Flag for mirroring the files/
|
30
|
+
# Flag for mirroring the files/directories
|
31
31
|
attr_writer :mirror
|
32
32
|
|
33
33
|
##
|
@@ -46,7 +46,7 @@ module Backup
|
|
46
46
|
def initialize(&block)
|
47
47
|
load_defaults!
|
48
48
|
|
49
|
-
@
|
49
|
+
@directories = Array.new
|
50
50
|
@additional_options ||= Array.new
|
51
51
|
@path ||= 'backups'
|
52
52
|
@port ||= 22
|
@@ -62,8 +62,8 @@ module Backup
|
|
62
62
|
# Performs the RSync operation
|
63
63
|
# debug options: -vhP
|
64
64
|
def perform!
|
65
|
-
Logger.message("#{ self.class } started syncing #{
|
66
|
-
Logger.silent( run("#{ utility(:rsync) } -vhP #{ options } #{
|
65
|
+
Logger.message("#{ self.class } started syncing #{ directories }.")
|
66
|
+
Logger.silent( run("#{ utility(:rsync) } -vhP #{ options } #{ directories } '#{ username }@#{ ip }:#{ path }'") )
|
67
67
|
end
|
68
68
|
|
69
69
|
##
|
@@ -97,21 +97,21 @@ module Backup
|
|
97
97
|
end
|
98
98
|
|
99
99
|
##
|
100
|
-
# If no block has been provided, it'll return the array of @
|
101
|
-
# If a block has been provided, it'll evaluate it and add the defined paths to the @
|
102
|
-
def
|
100
|
+
# If no block has been provided, it'll return the array of @directories.
|
101
|
+
# If a block has been provided, it'll evaluate it and add the defined paths to the @directories
|
102
|
+
def directories(&block)
|
103
103
|
unless block_given?
|
104
|
-
return @
|
105
|
-
"'#{
|
104
|
+
return @directories.map do |directory|
|
105
|
+
"'#{directory}'"
|
106
106
|
end.join("\s")
|
107
107
|
end
|
108
108
|
instance_eval(&block)
|
109
109
|
end
|
110
110
|
|
111
111
|
##
|
112
|
-
# Adds a path to the @
|
112
|
+
# Adds a path to the @directories array
|
113
113
|
def add(path)
|
114
|
-
@
|
114
|
+
@directories << path
|
115
115
|
end
|
116
116
|
|
117
117
|
end
|
data/lib/backup/version.rb
CHANGED
@@ -1,32 +1,19 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Backup
|
4
|
-
|
5
|
-
##
|
6
|
-
# Usage:
|
7
|
-
#
|
8
|
-
# # Returns the current backup version based on the defined constants
|
9
|
-
# Backup::Version.current
|
10
|
-
#
|
11
|
-
# # Returns a gemspec compatible version number based on the defined constants
|
12
|
-
# Backup::Version.gemspec
|
13
|
-
#
|
14
4
|
class Version
|
15
5
|
|
16
6
|
##
|
7
|
+
# Change the MAJOR, MINOR and PATCH constants below
|
8
|
+
# to adjust the version of the Backup gem
|
9
|
+
#
|
17
10
|
# MAJOR:
|
18
11
|
# Defines the major version
|
19
12
|
# MINOR:
|
20
13
|
# Defines the minor version
|
21
14
|
# PATCH:
|
22
15
|
# Defines the patch version
|
23
|
-
|
24
|
-
# Defines the build version ( use 'false' if no build )
|
25
|
-
MAJOR, MINOR, PATCH, BUILD = 3, 0, 3, false
|
26
|
-
|
27
|
-
# ========================================================= #
|
28
|
-
# ADJUST THE CONSTANTS ABOVE TO CHANGE THE BACKUP VERSION #
|
29
|
-
# ========================================================= #
|
16
|
+
MAJOR, MINOR, PATCH = 3, 0, 4
|
30
17
|
|
31
18
|
##
|
32
19
|
# Returns the major version ( big release based off of multiple minor releases )
|
@@ -41,31 +28,15 @@ module Backup
|
|
41
28
|
end
|
42
29
|
|
43
30
|
##
|
44
|
-
# Returns the patch version ( updates, features and (crucial) bug fixes
|
31
|
+
# Returns the patch version ( updates, features and (crucial) bug fixes )
|
45
32
|
def self.patch
|
46
33
|
PATCH
|
47
34
|
end
|
48
35
|
|
49
36
|
##
|
50
|
-
# Returns the
|
51
|
-
def self.build
|
52
|
-
BUILD
|
53
|
-
end
|
54
|
-
|
55
|
-
##
|
56
|
-
# Returns the current version ( not for gemspec / rubygems )
|
37
|
+
# Returns the current version of the Backup gem ( qualified for the gemspec )
|
57
38
|
def self.current
|
58
|
-
"#{major}.#{minor}.#{patch}
|
59
|
-
end
|
60
|
-
|
61
|
-
##
|
62
|
-
# Returns the (gemspec qualified) current version
|
63
|
-
def self.gemspec
|
64
|
-
if build.eql?(false)
|
65
|
-
"#{major}.#{minor}.#{patch}"
|
66
|
-
else
|
67
|
-
"#{major}.#{minor}.#{patch}.build.#{build}"
|
68
|
-
end
|
39
|
+
"#{major}.#{minor}.#{patch}"
|
69
40
|
end
|
70
41
|
|
71
42
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
notify_by Twitter do |tweet|
|
2
|
+
tweet.on_success = true
|
3
|
+
tweet.on_failure = true
|
4
|
+
|
5
|
+
tweet.consumer_key = 'my_consumer_key'
|
6
|
+
tweet.consumer_secret = 'my_consumer_secret'
|
7
|
+
tweet.oauth_token = 'my_oauth_token'
|
8
|
+
tweet.oauth_token_secret = 'my_oauth_token_secret'
|
9
|
+
end
|
data/lib/templates/syncer/rsync
CHANGED
@@ -7,8 +7,8 @@
|
|
7
7
|
rsync.mirror = true
|
8
8
|
rsync.compress = true
|
9
9
|
|
10
|
-
rsync.
|
11
|
-
|
12
|
-
|
10
|
+
rsync.directories do |directory|
|
11
|
+
directory.add "/var/apps/my_app/public/uploads"
|
12
|
+
directory.add "/var/apps/my_app/logs"
|
13
13
|
end
|
14
14
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
4
|
+
|
5
|
+
describe Backup::Notifier::Twitter do
|
6
|
+
let(:notifier) do
|
7
|
+
Backup::Notifier::Twitter.new do |twitter|
|
8
|
+
twitter.consumer_key = 'consumer_key'
|
9
|
+
twitter.consumer_secret = 'consumer_secret'
|
10
|
+
twitter.oauth_token = 'oauth_token'
|
11
|
+
twitter.oauth_token_secret = 'oauth_token_secret'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it do
|
16
|
+
notifier.consumer_key.should == 'consumer_key'
|
17
|
+
notifier.consumer_secret.should == 'consumer_secret'
|
18
|
+
notifier.oauth_token.should == 'oauth_token'
|
19
|
+
notifier.oauth_token_secret.should == 'oauth_token_secret'
|
20
|
+
|
21
|
+
notifier.on_success.should == true
|
22
|
+
notifier.on_failure.should == true
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'defaults' do
|
26
|
+
it do
|
27
|
+
Backup::Configuration::Notifier::Twitter.defaults do |twitter|
|
28
|
+
twitter.consumer_key = 'new_consumer_key'
|
29
|
+
twitter.on_success = false
|
30
|
+
twitter.on_failure = true
|
31
|
+
end
|
32
|
+
notifier = Backup::Notifier::Twitter.new do |twitter|
|
33
|
+
twitter.consumer_key = 'my_own_consumer_key'
|
34
|
+
end
|
35
|
+
|
36
|
+
notifier.consumer_key.should == 'my_own_consumer_key'
|
37
|
+
notifier.on_success.should == false
|
38
|
+
notifier.on_failure.should == true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#initialize' do
|
43
|
+
it do
|
44
|
+
Backup::Notifier::Twitter.any_instance.expects(:set_defaults!)
|
45
|
+
Backup::Notifier::Twitter.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#perform!' do
|
50
|
+
let(:model) { Backup::Model.new('blah', 'blah') {} }
|
51
|
+
before do
|
52
|
+
notifier.on_success = false
|
53
|
+
notifier.on_failure = false
|
54
|
+
end
|
55
|
+
|
56
|
+
context "when successful" do
|
57
|
+
it do
|
58
|
+
Backup::Logger.expects(:message).with("Backup::Notifier::Twitter started notifying about the process.")
|
59
|
+
notifier.expects("notify_success!")
|
60
|
+
notifier.on_success = true
|
61
|
+
notifier.perform!(model)
|
62
|
+
end
|
63
|
+
|
64
|
+
it do
|
65
|
+
notifier.expects("notify_success!").never
|
66
|
+
notifier.on_success = false
|
67
|
+
notifier.perform!(model)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "when failed" do
|
72
|
+
it do
|
73
|
+
Backup::Logger.expects(:message).with("Backup::Notifier::Twitter started notifying about the process.")
|
74
|
+
notifier.expects("notify_failure!")
|
75
|
+
notifier.on_failure = true
|
76
|
+
notifier.perform!(model, Exception.new)
|
77
|
+
end
|
78
|
+
|
79
|
+
it do
|
80
|
+
notifier.expects("notify_failure!").never
|
81
|
+
notifier.on_failure = false
|
82
|
+
notifier.perform!(model, Exception.new)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/spec/syncer/rsync_spec.rb
CHANGED
@@ -15,9 +15,9 @@ describe Backup::Syncer::RSync do
|
|
15
15
|
rsync.compress = true
|
16
16
|
rsync.additional_options = []
|
17
17
|
|
18
|
-
rsync.
|
19
|
-
|
20
|
-
|
18
|
+
rsync.directories do |directory|
|
19
|
+
directory.add "/some/random/directory"
|
20
|
+
directory.add "/another/random/directory"
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -64,7 +64,7 @@ describe Backup::Syncer::RSync do
|
|
64
64
|
rsync.path.should == 'backups'
|
65
65
|
rsync.compress.should == nil
|
66
66
|
rsync.mirror.should == nil
|
67
|
-
rsync.
|
67
|
+
rsync.directories.should == ''
|
68
68
|
rsync.additional_options.should == []
|
69
69
|
end
|
70
70
|
|
@@ -122,18 +122,18 @@ describe Backup::Syncer::RSync do
|
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
describe '#
|
125
|
+
describe '#directories' do
|
126
126
|
context 'when its empty' do
|
127
127
|
it do
|
128
|
-
rsync.
|
129
|
-
rsync.
|
128
|
+
rsync.directories = []
|
129
|
+
rsync.directories.should == ''
|
130
130
|
end
|
131
131
|
end
|
132
132
|
|
133
133
|
context 'when it has items' do
|
134
134
|
it do
|
135
|
-
rsync.
|
136
|
-
rsync.
|
135
|
+
rsync.directories = ['directory1', 'directory1/directory2', 'directory1/directory2/directory3']
|
136
|
+
rsync.directories.should == "'directory1' 'directory1/directory2' 'directory1/directory2/directory3'"
|
137
137
|
end
|
138
138
|
end
|
139
139
|
end
|
@@ -146,9 +146,9 @@ describe Backup::Syncer::RSync do
|
|
146
146
|
|
147
147
|
describe '#perform' do
|
148
148
|
it 'should invoke transfer!' do
|
149
|
-
Backup::Logger.expects(:message).with("Backup::Syncer::RSync started syncing '/some/random/
|
149
|
+
Backup::Logger.expects(:message).with("Backup::Syncer::RSync started syncing '/some/random/directory' '/another/random/directory'.")
|
150
150
|
rsync.expects(:utility).with(:rsync).returns(:rsync)
|
151
|
-
rsync.expects(:run).with("rsync -vhP --archive --delete -z --port='22' '/some/random/
|
151
|
+
rsync.expects(:run).with("rsync -vhP --archive --delete -z --port='22' '/some/random/directory' '/another/random/directory' 'my_username@123.45.678.90:backups/'")
|
152
152
|
rsync.perform!
|
153
153
|
end
|
154
154
|
end
|
data/spec/version_spec.rb
CHANGED
@@ -2,31 +2,20 @@
|
|
2
2
|
|
3
3
|
require File.dirname(__FILE__) + '/spec_helper'
|
4
4
|
|
5
|
-
def set_version(major, minor, patch
|
5
|
+
def set_version(major, minor, patch)
|
6
6
|
Backup::Version.stubs(:major).returns(major)
|
7
7
|
Backup::Version.stubs(:minor).returns(minor)
|
8
8
|
Backup::Version.stubs(:patch).returns(patch)
|
9
|
-
Backup::Version.stubs(:build).returns(build)
|
10
9
|
end
|
11
10
|
|
12
11
|
describe Backup::Version do
|
13
|
-
it 'should return a valid gemspec version' do
|
14
|
-
set_version(1,2,3,false)
|
15
|
-
Backup::Version.gemspec.should == '1.2.3'
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'should return a valid gemspec version with a build' do
|
19
|
-
set_version(4,5,6,615)
|
20
|
-
Backup::Version.gemspec.should == '4.5.6.build.615'
|
21
|
-
end
|
22
|
-
|
23
12
|
it 'should return a nicer gemspec output' do
|
24
|
-
set_version(1,2,3
|
25
|
-
Backup::Version.current.should == '1.2.3
|
13
|
+
set_version(1,2,3)
|
14
|
+
Backup::Version.current.should == '1.2.3'
|
26
15
|
end
|
27
16
|
|
28
17
|
it 'should return a nicer gemspec output with build' do
|
29
|
-
set_version(4,5,6
|
30
|
-
Backup::Version.current.should == '4.5.6
|
18
|
+
set_version(4,5,6)
|
19
|
+
Backup::Version.current.should == '4.5.6'
|
31
20
|
end
|
32
21
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 3.0.
|
5
|
+
version: 3.0.4
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Michael van Rooijen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-03-
|
13
|
+
date: 2011-03-13 00:00:00 +01:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -79,12 +79,23 @@ dependencies:
|
|
79
79
|
version: 1.0.4
|
80
80
|
type: :runtime
|
81
81
|
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: twitter
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ~>
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.1.2
|
91
|
+
type: :runtime
|
92
|
+
version_requirements: *id007
|
82
93
|
description: |-
|
83
94
|
Backup is a RubyGem (for UNIX-like operating systems: Linux, Mac OSX) that allows you to configure and perform backups in a simple manner using an elegant Ruby DSL.
|
84
95
|
It supports various databases (MySQL, PostgreSQL, MongoDB and Redis), it supports various storage locations
|
85
96
|
(Amazon S3, Rackspace Cloud Files, Dropbox, any remote server through FTP, SFTP, SCP and RSync), it can archive files and folders,
|
86
97
|
it can cycle backups, it can do incremental backups, it can compress backups, it can encrypt backups (OpenSSL or GPG),
|
87
|
-
it can notify you about successful and/or failed backups. It is very extensible and easy to add new functionality to. It's easy to use.
|
98
|
+
it can notify you about successful and/or failed backups (Email, Twitter). It is very extensible and easy to add new functionality to. It's easy to use.
|
88
99
|
email: meskyanichi@gmail.com
|
89
100
|
executables:
|
90
101
|
- backup
|
@@ -121,6 +132,7 @@ files:
|
|
121
132
|
- lib/backup/configuration/helpers.rb
|
122
133
|
- lib/backup/configuration/notifier/base.rb
|
123
134
|
- lib/backup/configuration/notifier/mail.rb
|
135
|
+
- lib/backup/configuration/notifier/twitter.rb
|
124
136
|
- lib/backup/configuration/storage/base.rb
|
125
137
|
- lib/backup/configuration/storage/cloudfiles.rb
|
126
138
|
- lib/backup/configuration/storage/dropbox.rb
|
@@ -146,6 +158,7 @@ files:
|
|
146
158
|
- lib/backup/notifier/mail.rb
|
147
159
|
- lib/backup/notifier/templates/notify_failure.erb
|
148
160
|
- lib/backup/notifier/templates/notify_success.erb
|
161
|
+
- lib/backup/notifier/twitter.rb
|
149
162
|
- lib/backup/storage/base.rb
|
150
163
|
- lib/backup/storage/cloudfiles.rb
|
151
164
|
- lib/backup/storage/dropbox.rb
|
@@ -166,6 +179,7 @@ files:
|
|
166
179
|
- lib/templates/encryptor/gpg
|
167
180
|
- lib/templates/encryptor/openssl
|
168
181
|
- lib/templates/notifier/mail
|
182
|
+
- lib/templates/notifier/twitter
|
169
183
|
- lib/templates/readme
|
170
184
|
- lib/templates/storage/cloudfiles
|
171
185
|
- lib/templates/storage/dropbox
|
@@ -206,6 +220,7 @@ files:
|
|
206
220
|
- spec/logger_spec.rb
|
207
221
|
- spec/model_spec.rb
|
208
222
|
- spec/notifier/mail_spec.rb
|
223
|
+
- spec/notifier/twitter_spec.rb
|
209
224
|
- spec/spec_helper.rb
|
210
225
|
- spec/storage/base_spec.rb
|
211
226
|
- spec/storage/cloudfiles_spec.rb
|