backupgem 0.0.2

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.
data/CHANGELOG ADDED
@@ -0,0 +1,6 @@
1
+ = Backup Changelog
2
+
3
+ == Version 0.0.2
4
+
5
+ * First stable code in place.
6
+ * Packaged in an gem format
data/README ADDED
@@ -0,0 +1,387 @@
1
+ ===What is Backup?===
2
+ <tt>Backup</tt> is the easiest and most flexible backup, archive and rotate
3
+ tool. It's a beginning-to-end solution for scheduled backups in a clean ruby
4
+ package that is simple use and powerful when customized.
5
+
6
+ Backup allows you to specify each of the following options:
7
+ * what is being archived (files, folders, arbitrary scripts)
8
+ * how it's being archived (tar gzip, bz2)
9
+ * where the archive is going (multiple backup servers? easy)
10
+ * how the archive is going to get there (scp, ftp, mv)
11
+ * where is will be stored when it gets there
12
+ * how it's going to be rotated when it gets there (grandfather-father-son, etc)
13
+ * how often will this process happen (customizable cycles)
14
+ * what happens to the working copy after the process (recreate files, folders etc. restart daemons)
15
+
16
+ Backup is a collection of scripts that is complete enough to save you
17
+ time, but flexible enough to work with any situation.
18
+
19
+ ===Getting Backup===
20
+ ====Prerequisites====
21
+ Backup makes the following assumptions about your machines:
22
+ * server and client understand POSIX commmands
23
+ * passwords and paths are the same on each server
24
+
25
+ Backup depends on the following libraries:
26
+ * [[Runt]] for describing [[temporal ranges]]
27
+ * [[Net::SSH]] for SSH backups
28
+ * [[Net::FTP]] for FTP backups
29
+
30
+ These are listed as dependencies in the gem file so you should be prompted to
31
+ install them when you install Backup.
32
+
33
+ ====Using RubyGems====
34
+ If you have [[http://rubygems.rubyforge.org RubyGems]] installed, installing
35
+ Backup is simple:
36
+
37
+ sudo gem install backupgem
38
+
39
+ ====Using svn====
40
+ If you prefer, you can checkout backupgem from the [[RubyForge Repository]].
41
+ Feel free to browse the releases or trunk [[here]].
42
+
43
+ svn+ssh://blar blar blar
44
+
45
+ ===License Information===
46
+ Backup is made available under either the BSD license, or the same license Ruby
47
+ (which, by extension, also allows the GPL as a permissable license as well).
48
+ You can view the full text of any of these licenses in the <tt>doc</tt> subdirectory
49
+ of the Backup distrubtion. The texts of the BSD and GPL licenses are also
50
+ available online: "BSD":http://www.opensource.org/licenses/bsd-license.php and
51
+ "GPL":http://www.opensource.org/licenses/gpl-license.php.
52
+
53
+ If you desire permission to use either Backup in a manner incompatible with
54
+ these licenses, please contact the copyright holder
55
+ ([[mailto:nate@natemurray.com Nate Murray]] in order to negotiate a more
56
+ compatible license.
57
+
58
+ ===Support===
59
+ Mailing lists, bug trackers, feature requests, and public forums are all
60
+ available courtesty of [[http://rubyforge.org RubyForge]] at the
61
+ [[http://rubyforge.org/projects/backupgem BackupGem project page]].
62
+
63
+ ====Mailing Lists====
64
+ {|class="wikitable"
65
+ ! List Name
66
+ !
67
+ ! Desc.
68
+ |---
69
+ | [[http://rubyforge.org/pipermail/backupgem-users backupgem-users]]
70
+ | [[http://rubyforge.org/mailman/listinfo/backupgem-users subscribe / unsubscribe]]
71
+ | The BackupGem users list is devoted to the discussion of and questions about the usage of Backup. If you can't quite figure out how to get a feature of Backup to work, this is the list you would go to in order to ask your questions.
72
+ |---
73
+ | [[http://rubyforge.org/pipermail/backupgem-devel backupgem-devel]]
74
+ | [[http://rubyforge.org/mailman/listinfo/backupgem-devel subscribe / unsubscribe]]
75
+ | The Backup developers list is devoted to the discussion of Backup's implementation. If you have created a patch that you would like to discuss, or if you would like to discuss a new feature, this is the list for you.
76
+ |}
77
+
78
+ ===About the Author===
79
+ Backup was written by [[mailto:nate@natemurray.com Nate Murray].
80
+ Nate currently works at an internet retailer in Southern California.
81
+ Feel free to send him compliments, candy, money, praise, or new feature patches--he likes
82
+ all those things. You can send him questions and suggestions, too, if you
83
+ really want to. However, for bug reports and general feature requests,
84
+ please use the trackers on the [[http://rubyforge.org/projects/backupgem BackupGem project page]].
85
+
86
+ ===Special Thanks===
87
+ * Matt Pulver for help with various technical problems and ideas.
88
+
89
+ * Jamis Buck for writing [http://weblog.rubyonrails.com/2006/8/30/capistrano-1-1-9-beta Capistrano]. Capistrano provided the inspiration and some code for this work. Additionally, the Net::SSH manual provided the inspiration for this manual. Thanks for the top-notch work Jamis!
90
+
91
+ * [[mailto:info@digitalclash.com Matthew Lipper]] for writing the Runt Ruby Temporal Expressions Library
92
+
93
+ ==How Backup Works==
94
+ ===Intro===
95
+ A basic backup has the following sequence:
96
+ * content
97
+ * compress
98
+ * encrypt
99
+ * deliver
100
+ * rotate
101
+ * cleanup
102
+
103
+ This order is the default, however, like most things it is customizable.
104
+ Think of it like a pipline: the input of each step is the output of the last
105
+ step.
106
+
107
+ Each of these things are specified in a <tt>recipe</tt> file which is describe below.
108
+
109
+ ===CLI===
110
+
111
+ Usage: ./backup [options]
112
+ Recipe Options -----------------------
113
+ -r, --recipe RECIPE A recipe file to load. Multiple recipes
114
+ may be specified, and are loaded in the
115
+ given order.
116
+ -g, --global FILE Specify the global recipe file to work
117
+ with. Defaults to the file <tt>global.rb</tt>
118
+ in the directory of <tt>recipe</tt>
119
+ -s, --set NAME=VALUE Specify a variable and it's value to
120
+ set. This will be set after loading all
121
+ recipe files.
122
+
123
+ ==Backup Recipe File Format==
124
+ ===Introduction===
125
+ * The Backup Recipe format is pure ruby code. Anything that is valid ruby is valid in the recipe file. There are a number of shortcuts that will make your life easier.
126
+
127
+ * Each of the steps are specified as an <tt>action</tt>. (An action is really nothing more than a method that becomes defined in the Actor instance. See API docs if you're interestd.)
128
+
129
+ * You may create "hook" actions for any of the actions. So if you define a method <tt>before_content</tt> it will be called just before <tt>content</tt> is called. A method named <tt>after_rotation</tt> would be called after rotation. This may not always be needed as you can customize the rotation order to be whatever you want. See [[#XXX]] below.
130
+
131
+ * Each action has the variable <tt>last_result</tt> available to it. This is the return value of the method that was called previously. Note that this includes the output of the "hook" methods.
132
+
133
+ * All configuration variables are available to actions via the hash c[]. For example, the backup path is available to your actions as c[:backup_path].
134
+
135
+ ===Variables===
136
+ Intro on how to set variables. How this works.
137
+
138
+ Required variables for all configurations.
139
+ {|class="wikitable"
140
+ ! Name
141
+ ! Desc.
142
+ ! Example
143
+ |---
144
+ | :action_order
145
+ | short desc. TODO
146
+ | set :action_order, %w{ content compress encrypt deliver rotate cleanup }
147
+ |---
148
+ | :tmp_dir
149
+ | Specify a directory that backup can use as a temporary directory. Default <tt>/tmp</tt>.
150
+ | set :tmp_dir, File.dirname(__FILE__) + "/../tmp"
151
+ |---
152
+ | :backup_path
153
+ | The path to backup on. TODO - if its local the local server if its foreign the foreign server
154
+ | set :backup_path, "/var/local/backups/mediawiki"
155
+ |}
156
+
157
+ ===Content===
158
+ The first step in any backup is the content that is to be backed up. Backup
159
+ provides a couple of shortcuts for common ways to locate content and allows you
160
+ to arbitrarily define your own.
161
+
162
+ Some typical types of content are:
163
+ * a particular file
164
+ * a particular folder
165
+ * the contents of a particular folder
166
+
167
+ These could be specified like so:
168
+
169
+ action :content, :is_file => "/path/to/file" # content is a single file
170
+ action :content, :is_file => "/path/to/error_log", :recreate => true
171
+ action :content, :is_folder => "/path/to/folder" # content is the folder itself
172
+ action :content, :is_contents_of => "/path/to/other/folder" # content is folder/* , recursive option
173
+
174
+ If you want :content to be a series of shell commands just pass "action" a block:
175
+
176
+ action(:content) do
177
+ sh "echo \"hello $HOSTNAME\""
178
+ sh "mysqldump -uroot database > /path/to/db.sql"
179
+ "/path/to/db.sql" # make sure you return the full path to the folder/file you wish to be the content
180
+ end
181
+
182
+ ===Compress===
183
+ Next you may want to compress your content. Again, there are a few one-liners for common cases and you can create your own.
184
+
185
+ action :compress, :method => :tar_bz2 # actually calls a method named tar_bz2 with output of ":content" ( or ":after_content" )
186
+ # or
187
+ action :compress, :method => :tar_gzip
188
+
189
+ Again, you can create your own.
190
+
191
+ action(:compress)
192
+ sh "my_tar #{last_result} #{last_result}.tar"
193
+ sh "my_bzip #{last_result}.tar #{last_result}.tar.bz2"
194
+ last_result + ".tar.bz2"
195
+ end
196
+
197
+ ===Encrypt===
198
+ If you wish to use encryption this is available to you. I would recommend that
199
+ you think seriously about how you wish to manage your keys for this backup
200
+ process. If you are backing up encrypted data then you need to backup your keys
201
+ or else you risk losing access to your data. Secure key management is beyond
202
+ the scope of this document, but I recommend the following links:
203
+ * link 1
204
+ * link 2
205
+
206
+ set :encrypt, true # default is <tt>false</tt>
207
+ set :gpg_encrypt_options, "--default-recipient" # default is an empty string
208
+ action :encrypt, :method => :gpg # default, none
209
+
210
+ or your own:
211
+
212
+ action(:encrypt)
213
+ sh "gpg #{c[:gpg_encrypt_options]} --encrypt #{last_result}"
214
+ last_result + ".gpg" # ?
215
+ end
216
+
217
+ ===Delivery===
218
+ ====Action====
219
+ Delivery is supported via <tt>scp</tt>, <tt>ftp</tt>, and <tt>mv</tt>
220
+
221
+ action :delivery, :method => :scp
222
+ action :delivery, :method => :ftp
223
+ action :delivery, :method => :mv
224
+
225
+ The <tt>:mv</tt> action is defined like any user-defined action:
226
+
227
+ action(:mv) do
228
+ sh "mv #{last_result} #{c[:backup_path]}/"
229
+ c[:backup_path] <tt> "/" </tt> File.basename(last_result)
230
+ end
231
+
232
+ ====Variables====
233
+ {|class="wikitable"
234
+ ! Name
235
+ ! Desc.
236
+ ! Example
237
+ |---
238
+ | :servers
239
+ | An array of host names to deliver the data to. TODO this currently only supports 1 server.
240
+ | set :servers, %w{ localhost }
241
+ |---
242
+ | :ssh_user
243
+ | The name of the ssh user on the foreign server. Default ENV['USER'].
244
+ | set :ssh_user, ENV['USER']
245
+ |---
246
+ | :identity_key
247
+ | The path to the key to use when ssh'ing into a foreign server.
248
+ | set :identity_key, ENV['HOME'] + "/.ssh/id_rsa"
249
+ |}
250
+
251
+ ==Rotate==
252
+ Rotation of your backups is a way to keep snapshot copies of your backups in time while not keeping every single backup for every single day.
253
+ Currently the only form of rotation Backup supports is [[grandfather-father-son]] See Appendix A if you are unfamiliar with how this works.
254
+
255
+ set :rotation_method, :gfs # this is the default. you don't need to set it, but this is how you could
256
+
257
+ By deafult, a <tt>son</tt> is created daily, unless it is a day to create a father or
258
+ grandfather. It is assumed that every time you run Backup you want to create a
259
+ backup. Therefore, if you do not want to a son etc, do not run the program.
260
+ You can specify when the son is promoted to a father by the following variable.
261
+
262
+ set :son_promoted_on, :fri
263
+
264
+ You specify when fathers are promoted to grandfathers by something like the following
265
+
266
+ set :father_promoted_on, :last_fri_of_the_month
267
+
268
+ Valid argumetns for specifying these promotions are as follows:
269
+ * :mon-:sun - A symbol of the abbreviation of any day of the week
270
+ * :last_*_of_the_month - A symbol, replacing the * with the abbreviation for the day of the weeks. Such as :last_fri_of_the_month.
271
+ * Any valid Runt object.
272
+
273
+ Representing these [[temporal ranges]] is done internally by using Runt. You are, therefore, allowed to pass in your own arbitrarily complex runt object.
274
+ Say for instance that I wanted to promote to fathers on monday, wednesday and friday. I could do something like the following:
275
+
276
+ mon_wed_fri = Runt::DIWeek.new(Runt::Mon) |
277
+ Runt::DIWeek.new(Runt::Wed) |
278
+ Runt::DIWeek.new(Runt::Fri)
279
+ set :son_promoted_on, mon_wed_fri
280
+
281
+ See the [[Runt documentation]] for more information on this.
282
+
283
+ You can set how many of each rank to keep:
284
+
285
+ set :sons_to_keep, 14
286
+ set :fathers_to_keep, 6
287
+ set :grandfathers_to_keep, 6
288
+
289
+ ==Examples==
290
+
291
+ Here we will cover three examples.
292
+ # a super-simple backup to a local directory, show how easy it is
293
+ # a more complex implementation, show the variables you can set show the customizability and use of foreign server
294
+ # every more complex. define your own method, use a global file to share in the configuration.
295
+
296
+ ===Example One: Backup folder of Logs===
297
+ Our first example will be backing up a folder of logs. Say we have a folder
298
+ '/var/my_logs/' and it is full of log files. It's full. Seriously, it's getting
299
+ stuffy in there.
300
+ Anyway, what we want is to:
301
+ * move out all the old log files
302
+ * compress them and store them in a local folder
303
+ * store 2 weeks of daily backups (sons)
304
+ * store a weekly backup (father) going back 6 weeks
305
+ * and create a monthly backup on the last friday of every month (grandfather) for 6 months
306
+
307
+ Thankfully, this is incredibly simple:
308
+
309
+ set :backup_path, "/var/local/backups/my_old_logs"
310
+ set :tmp_dir, "/tmp" # this is the default so you actually dont have to specify it
311
+ action :content, :is_contents_of => "/var/my_logs"
312
+
313
+ ''In this case, make sure that <tt>:backup_path</tt> and <tt>:tmp_dir</tt> are writable by the user
314
+ that is running the backup script.''
315
+
316
+ And thats it!
317
+
318
+ Note a few things here.
319
+ # Each time we <tt>set</tt> a variable that becomes available to the actions as <tt>c[:var]</tt>
320
+
321
+ ===Example Two: SQL Backup===
322
+ Our second example will be backing up a MediaWiki installation.
323
+ Say we have a MySQL database named 'mediawiki'.
324
+ What we want is to:
325
+ * create a dump of the database every day
326
+ * compress this backup and store it in a local folder
327
+ * store 2 weeks of daily backups (son) [same as last time]
328
+ * store "father" backups every monday,wednesday and friday going back 6 weeks
329
+ * and create a monthly backup on the last friday of every month (grandfather) for 6 months
330
+
331
+ Thankfully, this is incredibly simple:
332
+
333
+ set :backup_path, "/var/local/backups/mediawiki"
334
+
335
+ action(:content) do
336
+ dump = c[:tmp_dir] + "/mediawiki.sql"
337
+ sh "mysqldump -uroot mediawiki > #{dump}"
338
+ dump # make sure you return the name of the file
339
+ end
340
+
341
+ action :delivery, :method => :scp
342
+ action :rotate, :method => :via_ssh
343
+
344
+ set :servers, %w{ my.server.com }
345
+
346
+ set :son_promoted_on, :sun
347
+ set :father_promoted_on, :last_sun_of_the_month
348
+
349
+ set :sons_to_keep, 21
350
+ set :fathers_to_keep, 12
351
+ set :grandfathers_to_keep, 12
352
+
353
+ ===Example Three: Something more complex===
354
+
355
+ action :content, :is_file => "/path/to/file.abc"
356
+ action :compress, :method => :my_tar_gzip
357
+
358
+ action(:my_tar_gzip) do
359
+ name = c[:tmp_dir] + "/" + File.basename(last_result) + ".tar.gzip"
360
+ sh "tar -czv --exclude .DS* --exclude CVS #{last_result} > #{name}"
361
+ name # make sure you return the name of the
362
+ end
363
+
364
+ set :encrypt, true
365
+
366
+ action :deliver, :method => :scp
367
+ action :rotate, :method => :via_ssh
368
+
369
+ set :ssh_user, "backup_user"
370
+ set :identity_key, ENV['HOME'] + "/.ssh/backup_key"
371
+
372
+ * how to setup the cron job
373
+
374
+ ==TODO==
375
+
376
+ what is left to do:
377
+ * start testing it
378
+ * work on the styles
379
+ * lookup setup.rb files
380
+
381
+ ==TODO==
382
+ * Add in better logging
383
+
384
+ ==BUGS==
385
+ * You can't <tt>return</tt> in the user-defined actions for some reason. I think this
386
+ has to do with the <tt>instance_eval</tt>. But still, I wouldn't think it would
387
+ matter. I'd be interested in any suggestions on how to fix this.
data/bin/backup ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.dirname(__FILE__) + "/../lib"
3
+
4
+ begin
5
+ require 'rubygems'
6
+ rescue LoadError
7
+ # no rubygems to load, so we fail silently
8
+ end
9
+
10
+ require 'backup/cli'
11
+
12
+ Backup::CLI.execute!
data/bin/commands.sh ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/bash
2
+ ./bin/backup --recipe examples/mediawiki.rb