redis-backup 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,6 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in svn-backup.gemspec
4
3
  gemspec
5
- gem 'aws-sdk'
6
- gem 'redis'
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  redis-backup
2
2
  ============
3
3
 
4
- a small ruby gem that allows automated redis-backups
4
+ a small ruby gem that allows automated redis RDB-file backups with support for compression and S3 uploading.
5
5
 
6
6
  Installation
7
7
  ============
@@ -12,15 +12,21 @@ Usage
12
12
  =====
13
13
 
14
14
  redis-backup [options]
15
- -h, --help Usage information
16
- -b, --backup-dir BACKUP_DIR Directory to write backups to
17
- -s, --redis-source REDIS_SOURCE Full path to redis dump.rdb file
18
- -m REDIS_SAVE_METHOD, The method to call on redis for saving (save or bgsave or none)
19
- --redis-save-method
20
- -H, --redis-host REDIS_HOST Host for local redis
21
- -p, --redis-port REDIS_PORT Port for local redis
22
- -B, --s3-bucket S3_BUCKET Name of bucket to use on S3
23
- -A S3_ACCESS_KEY_ID, Your access_key_id for AWS S3
24
- --s3-access-key-id
25
- -S S3_SECRET_ACCESS_KEY, Your secret_access_key for AWS S3
26
- --s3-secret-access-key
15
+ Specific options:
16
+ -b, --backup-dir BACKUP_DIR Directory to write backups to
17
+ -c, --compress Compress backup as a zip file
18
+ -s, --redis-source REDIS_SOURCE Full path to redis dump.rdb file
19
+ -m REDIS_SAVE_METHOD, The method to call on redis for saving (save or bgsave or none)
20
+ --redis-save-method
21
+ -H, --redis-host REDIS_HOST Host for local redis
22
+ -p, --redis-port REDIS_PORT Port for local redis
23
+ -A S3_ACCESS_KEY_ID, Your access_key_id for AWS S3
24
+ --s3-access-key-id
25
+ -B, --s3-bucket S3_BUCKET Name of bucket to use on S3
26
+ -C, --s3-clean Cleanup intermediate backup files
27
+ -S S3_SECRET_ACCESS_KEY, Your secret_access_key for AWS S3
28
+ --s3-secret-access-key
29
+
30
+ Common options:
31
+ -h, --help Show this message
32
+ --version Show version
@@ -3,125 +3,63 @@
3
3
 
4
4
  #
5
5
  # redis-backup
6
- #
7
- # Uses environment variables for running:
8
- #
9
- # - BACKUP_DIR: Directory to write backups to
10
- # - REDIS_SAVE: 0 or 1. If "1", then perform, and wait for, a bgsave before copying backup
11
- # - REDIS_SAVE_METHOD: If calling a save, the method to call on redis for saving (save or bgsave)
12
- # - REDIS_HOST: Host for local redis
13
- # - REDIS_PORT: Port to local redis
14
- # - REDIS_SOURCE: Full path to redis dump.rdb file
15
- # - S3_SAVE: 0 or 1. If "1", then use S3 to backup the file
16
- # - S3_BUCKET: Name of bucket to use on S3
17
- # - S3_ACCESS_KEY_ID: Your access_key_id for AWS S3
18
- # - S3_SECRET_ACCESS_KEY: Your secret_access_key for AWS S3
19
- #
20
6
 
21
7
  require 'aws-sdk'
22
8
  require 'date'
23
9
  require 'fileutils'
24
- require 'optparse'
25
10
  require 'redis'
11
+ require 'zip/zip'
26
12
 
27
- require File.expand_path('../../lib/redis-backup/version', __FILE__)
28
- version = RedisBackup::VERSION
29
-
30
- backup_dir = "/data/backup/redis"
31
- redis_host = "localhost"
32
- redis_port = 6379
33
- redis_save_method = false
34
- redis_source = "/var/lib/redis/dump.rdb"
35
- s3_save = !!ENV.fetch("S3_SAVE", false)
36
- s3_bucket = false
37
- s3_access_key_id = false
38
- s3_secret_access_key = false
39
-
40
- optparse = OptionParser.new do |opts|
41
- opts.version = version
42
- opts.banner = "Usage: redis-backup [options]"
43
- opts.on('-h', '--help', 'Usage information') do
44
- puts opts
45
- exit
46
- end
47
- opts.on('-b', '--backup-dir BACKUP_DIR', 'Directory to write backups to') { |dir| backup_dir = dir }
48
- opts.on('-s', '--redis-source REDIS_SOURCE', 'Full path to redis dump.rdb file') { |source| redis_source = source }
49
- opts.on('-m', '--redis-save-method REDIS_SAVE_METHOD', 'The method to call on redis for saving (save or bgsave or none)') { |method| redis_save_method = method }
50
- opts.on('-H', '--redis-host REDIS_HOST', 'Host for local redis') { |host| redis_host = host }
51
- opts.on('-p', '--redis-port REDIS_PORT', 'Port for local redis') { |port| redis_port = port.to_i }
52
- opts.on('-B', '--s3-bucket S3_BUCKET', 'Name of bucket to use on S3') { |bucket| s3_bucket = bucket }
53
- opts.on('-A', '--s3-access-key-id S3_ACCESS_KEY_ID', 'Your access_key_id for AWS S3') { |key| s3_access_key_id = key }
54
- opts.on('-S', '--s3-secret-access-key S3_SECRET_ACCESS_KEY', 'Your secret_access_key for AWS S3') { |secret| s3_secret_access_key = secret }
55
- end
56
- optparse.parse!
57
-
58
- BACKUP_DIR = backup_dir
59
- REDIS_SAVE_METHOD = redis_save_method
60
- REDIS_HOST = redis_host
61
- REDIS_SOURCE = redis_source
62
- REDIS_PORT = redis_port
63
- S3_SAVE = !!s3_bucket && !!s3_access_key_id && !!s3_secret_access_key
64
- S3_BUCKET = s3_bucket
65
- S3_ACCESS_KEY_ID = s3_access_key_id
66
- S3_SECRET_ACCESS_KEY = s3_secret_access_key
67
-
68
-
69
- def colorize(text, color_code); RUBY_PLATFORM =~ /win32/ ? text : "#{color_code}#{text}\e[0m"; end
70
- def red(text); colorize(text, "\e[31m"); end
71
- def green(text); colorize(text, "\e[32m"); end
72
- def yellow(text); colorize(text, "\e[33m"); end
73
- def blue(text); colorize(text, "\e[34m"); end
74
- def magenta(text); colorize(text, "\e[35m"); end
75
- def cyan(text); colorize(text, "\e[36m"); end
76
- def white(text); colorize(text, "\e[37m"); end
77
- def bold(text); colorize(text, "\e[1m"); end
78
- def grey(text); colorize(text, "\e[90m"); end
79
-
80
- abort("Redis .rdb file does not exist: " + REDIS_SOURCE) unless File.exists? REDIS_SOURCE
81
-
82
- FileUtils.mkdir_p BACKUP_DIR unless File.directory? BACKUP_DIR
83
-
84
- abort("Backup directory does not exist: " + BACKUP_DIR) unless File.directory? BACKUP_DIR
85
- abort("Backup directory is not writable: " + BACKUP_DIR) unless File.writable? BACKUP_DIR
86
-
87
- if S3_SAVE
88
- abort("No bucket specified") unless S3_BUCKET
89
- abort("No access key specified in S3_ACCESS_KEY_ID environment variable") unless S3_ACCESS_KEY_ID
90
- abort("No secret access key specified in S3_SECRET_ACCESS_KEY environment variable") unless S3_SECRET_ACCESS_KEY
13
+ require File.expand_path('../../lib/redis-backup/options', __FILE__)
14
+ require File.expand_path('../../lib/redis-backup/utils', __FILE__)
15
+
16
+ options = RedisBackup::Options.parse(ARGV)
17
+
18
+ abort("Redis .rdb file does not exist: " + options.redis_source) unless File.exists? options.redis_source
19
+
20
+ FileUtils.mkdir_p options.backup_dir unless File.directory? options.backup_dir
21
+
22
+ abort("Backup directory does not exist: " + options.backup_dir) unless File.directory? options.backup_dir
23
+ abort("Backup directory is not writable: " + options.backup_dir) unless File.writable? options.backup_dir
24
+
25
+ if options.s3_save
26
+ abort("No bucket specified") unless options.s3_bucket
27
+ abort("No access key specified in S3_ACCESS_KEY_ID environment variable") unless options.s3_access_key_id
28
+ abort("No secret access key specified in S3_SECRET_ACCESS_KEY environment variable") unless options.s3_secret_access_key
91
29
  AWS.config({
92
- access_key_id: S3_ACCESS_KEY_ID,
93
- secret_access_key: S3_SECRET_ACCESS_KEY
30
+ access_key_id: options.s3_access_key_id,
31
+ secret_access_key: options.s3_secret_access_key
94
32
  })
95
33
  s3 = AWS::S3.new
96
- bucket = s3.buckets[S3_BUCKET]
97
- abort("Bucket does not exist: " + S3_BUCKET) unless bucket.exists?
34
+ bucket = s3.buckets[options.s3_bucket]
35
+ abort("Bucket does not exist: " + options.s3_bucket) unless bucket.exists?
98
36
  begin
99
37
  owner = bucket.owner
100
38
  rescue AWS::S3::Errors::AccessDenied => e
101
- abort("Access to the bucket is denied: " + S3_BUCKET)
39
+ abort("Access to the bucket is denied: " + options.s3_bucket)
102
40
  end
103
41
  end
104
42
 
105
43
 
106
- puts blue(cyan('Starting save'))
44
+ puts RedisBackup::Utils.cyan('Starting save')
107
45
  backup_start = Time.now
108
46
 
109
- puts "--> Saving from %s to %s" % [ REDIS_SOURCE, BACKUP_DIR ]
47
+ puts "--> Saving from %s to %s" % [ options.redis_source, options.backup_dir ]
110
48
 
111
- if REDIS_SAVE_METHOD
112
- puts "--> Performing background save " + bold(cyan('↴'))
49
+ if options.redis_save_method
50
+ puts "--> Performing background save " + RedisBackup::Utils.bold(RedisBackup::Utils.cyan('↴'))
113
51
  bgsave_start = Time.now
114
52
 
115
- mtime = File.mtime(REDIS_SOURCE).strftime("%Y-%m-%d-%H-%M-%S")
53
+ mtime = File.mtime(options.redis_source).strftime("%Y-%m-%d-%H-%M-%S")
116
54
  puts " - Current backup.rdb mtime: " + mtime
117
55
 
118
- puts " - Sending '%s' command" % (REDIS_SAVE_METHOD)
56
+ puts " - Sending '%s' command" % (options.redis_save_method)
119
57
  redis = Redis.new(
120
- :host => REDIS_HOST,
121
- :port => REDIS_PORT
58
+ :host => options.redis_host,
59
+ :port => options.redis_port
122
60
  )
123
61
 
124
- if REDIS_SAVE_METHOD == "bgsave"
62
+ if options.redis_save_method == "bgsave"
125
63
  redis.bgsave
126
64
  else
127
65
  redis.save
@@ -129,36 +67,66 @@ if REDIS_SAVE_METHOD
129
67
 
130
68
  puts " - Command sent, waiting"
131
69
 
132
- while File.mtime(REDIS_SOURCE).strftime("%Y-%m-%d-%H-%M-%S") == mtime
70
+ while File.mtime(options.redis_source).strftime("%Y-%m-%d-%H-%M-%S") == mtime
133
71
  sleep 0.0001
134
72
  end
135
73
 
136
- puts " - Save performed successfully, took %.2f seconds" % (Time.now - backup_start)
74
+ puts " - Save performed successfully, took %.2f seconds" % (Time.now - bgsave_start)
137
75
  end
138
76
 
139
- DATETIME = DateTime.parse(`date`).strftime("%Y-%m-%d-%H-%M-%S")
140
- REDIS_DEST = "%s/%s-dump.rdb" % [ BACKUP_DIR, DATETIME ]
77
+ backup_filename = "%s-dump.rdb" % [ DateTime.parse(`date`).strftime("%Y-%m-%d-%H-%M-%S") ]
78
+ backup_rdb_file = "%s/%s" % [ options.backup_dir, backup_filename ]
79
+ backup_file = backup_rdb_file
80
+
81
+ puts "--> Copying backup from %s to %s" % [ options.redis_source, backup_rdb_file ]
82
+ copy_start = Time.now
83
+ FileUtils.cp(options.redis_source, backup_rdb_file)
84
+ puts " - Copying completed, took %.2f" % (Time.now - copy_start)
85
+ puts " - RDB filesize is %s" % (RedisBackup::Utils.filesize(backup_rdb_file))
141
86
 
142
- puts "--> Copying backup from %s to %s" % [ REDIS_SOURCE, REDIS_DEST ]
143
- FileUtils.cp(REDIS_SOURCE, REDIS_DEST)
87
+ if options.compress
88
+ puts "--> Performing compression " + RedisBackup::Utils.bold(RedisBackup::Utils.cyan('↴'))
89
+ compress_start = Time.now
144
90
 
145
- if S3_SAVE
146
- puts "--> Pushing file to S3 " + bold(cyan('↴'))
91
+ puts " - Compressing to %s.zip" % [ backup_rdb_file ]
92
+
93
+ Zip::ZipFile.open(backup_rdb_file + ".zip", Zip::ZipFile::CREATE) do |zipfile|
94
+ zipfile.add(backup_filename, backup_rdb_file)
95
+ end
96
+
97
+ if options.clean
98
+ puts " - Removing temporary rdb file"
99
+ File.delete(backup_rdb_file)
100
+ end
101
+
102
+ puts " - Compression performed successfully, took %.2f seconds" % (Time.now - compress_start)
103
+
104
+ backup_file = backup_rdb_file + ".zip"
105
+ puts " - Compression filesize is %s" % (RedisBackup::Utils.filesize(backup_file))
106
+ end
107
+
108
+ if options.s3_save
109
+ puts "--> Pushing file to S3 " + RedisBackup::Utils.bold(RedisBackup::Utils.cyan('↴'))
147
110
  s3_start = Time.now
148
111
 
149
112
  puts " - Connecting to S3"
150
113
  s3 = AWS::S3.new
151
- bucket = s3.buckets[S3_BUCKET]
114
+ bucket = s3.buckets[options.s3_bucket]
152
115
 
153
116
  puts " - Uploading the file, please wait..."
154
- basename = File.basename(REDIS_DEST)
117
+ basename = File.basename(backup_file)
155
118
  object = bucket.objects[basename]
156
- object.write(:file => REDIS_DEST)
157
- request_uri = object.url_for(:read).request_uri.gsub(S3_ACCESS_KEY_ID, "YOUR_S3_ACCESS_KEY_ID")
119
+ object.write(:file => backup_file)
120
+ request_uri = object.url_for(:read).request_uri.gsub(options.s3_access_key_id, "YOUR_S3_ACCESS_KEY_ID")
121
+
122
+ if options.clean
123
+ puts " - Removing temporary backup file"
124
+ File.delete(backup_file)
125
+ end
158
126
 
159
127
  puts " - Uploaded to: " + object.public_url.request_uri
160
- puts " - Use this URL to download the file: https://s3.amazonaws.com/" + S3_BUCKET + request_uri
128
+ puts " - Use this URL to download the file: https://s3.amazonaws.com/" + options.s3_bucket + request_uri
161
129
  puts " - S3 sync performed successfully, took %.2f seconds" % (Time.now - s3_start)
162
130
  end
163
131
 
164
- puts '🚀 ' + green('Backup took %.2f seconds' % (Time.now - backup_start))
132
+ puts '🚀 ' + RedisBackup::Utils.green('Backup took %.2f seconds' % (Time.now - backup_start))
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding : utf-8 -*-
3
+
4
+ require 'optparse'
5
+ require 'ostruct'
6
+
7
+ require File.expand_path('../version', __FILE__)
8
+
9
+ module RedisBackup
10
+ class Options
11
+ def self.parse(args)
12
+ options = OpenStruct.new
13
+
14
+ options.backup_dir = "/data/backup/redis"
15
+ options.redis_host = "localhost"
16
+ options.redis_port = 6379
17
+ options.redis_save_method = false
18
+ options.redis_source = "/var/lib/redis/dump.rdb"
19
+ options.s3_save = !!ENV.fetch("S3_SAVE", false)
20
+ options.s3_bucket = false
21
+ options.s3_access_key_id = false
22
+ options.s3_secret_access_key = false
23
+
24
+ optparse = OptionParser.new do |opts|
25
+ opts.version = "redis-backup " + RedisBackup::VERSION
26
+
27
+ opts.banner = "Usage: redis-backup [options]"
28
+ opts.separator ""
29
+ opts.separator "Specific options:"
30
+
31
+ opts.on('-b', '--backup-dir BACKUP_DIR', 'Directory to write backups to') { |dir| options.backup_dir = dir }
32
+ opts.on('-c', '--compress', 'Compress backup as a zip file') { |dir| options.compress = true }
33
+ opts.on('-s', '--redis-source REDIS_SOURCE', 'Full path to redis dump.rdb file') { |source| options.redis_source = source }
34
+ opts.on('-m', '--redis-save-method REDIS_SAVE_METHOD', 'The method to call on redis for saving (save or bgsave or none)') { |method| options.redis_save_method = method }
35
+ opts.on('-H', '--redis-host REDIS_HOST', 'Host for local redis') { |host| options.redis_host = host }
36
+ opts.on('-p', '--redis-port REDIS_PORT', 'Port for local redis') { |port| options.redis_port = port.to_i }
37
+ opts.on('-A', '--s3-access-key-id S3_ACCESS_KEY_ID', 'Your access_key_id for AWS S3') { |key| options.s3_access_key_id = key }
38
+ opts.on('-B', '--s3-bucket S3_BUCKET', 'Name of bucket to use on S3') { |bucket| options.s3_bucket = bucket }
39
+ opts.on('-C', '--s3-clean', 'Cleanup intermediate backup files') { |dir| options.clean = true }
40
+ opts.on('-S', '--s3-secret-access-key S3_SECRET_ACCESS_KEY', 'Your secret_access_key for AWS S3') { |secret| options.s3_secret_access_key = secret }
41
+
42
+ opts.separator ""
43
+ opts.separator "Common options:"
44
+
45
+ opts.on_tail('-h', '--help', 'Show this message') do
46
+ puts opts
47
+ exit
48
+ end
49
+
50
+ # Another typical switch to print the version.
51
+ opts.on_tail("--version", "Show version") do
52
+ puts "redis-backup " + RedisBackup::VERSION
53
+ exit
54
+ end
55
+ end
56
+ optparse.parse!(args)
57
+
58
+ options.s3_save = !!options.s3_bucket && !!options.s3_access_key_id && !!options.s3_secret_access_key
59
+ options
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding : utf-8 -*-
3
+
4
+ module RedisBackup
5
+ class Utils
6
+ def self.filesize(filename)
7
+ compressed_file_size = File.size(filename).to_f / 2**20
8
+ '%.2f MB' % compressed_file_size
9
+ end
10
+
11
+ def self.colorize(text, color_code)
12
+ RUBY_PLATFORM =~ /win32/ ? text : "#{color_code}#{text}\e[0m";
13
+ end
14
+
15
+ def self.red(text)
16
+ colorize(text, "\e[31m")
17
+ end
18
+
19
+ def self.green(text)
20
+ colorize(text, "\e[32m")
21
+ end
22
+
23
+ def self.yellow(text)
24
+ colorize(text, "\e[33m")
25
+ end
26
+
27
+ def self.blue(text)
28
+ colorize(text, "\e[34m")
29
+ end
30
+
31
+ def self.magenta(text)
32
+ colorize(text, "\e[35m")
33
+ end
34
+
35
+ def self.cyan(text)
36
+ colorize(text, "\e[36m")
37
+ end
38
+
39
+ def self.white(text)
40
+ colorize(text, "\e[37m")
41
+ end
42
+
43
+ def self.bold(text)
44
+ colorize(text, "\e[1m")
45
+ end
46
+
47
+ def self.grey(text)
48
+ colorize(text, "\e[90m")
49
+ end
50
+
51
+ end
52
+ end
@@ -1,3 +1,3 @@
1
1
  module RedisBackup
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -16,4 +16,5 @@ Gem::Specification.new do |gem|
16
16
  gem.version = RedisBackup::VERSION
17
17
  gem.add_dependency(%q<aws-sdk>, [">= 0"])
18
18
  gem.add_dependency(%q<redis>, [">= 0"])
19
+ gem.add_dependency(%q<rubyzip>, [">= 0"])
19
20
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis-backup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-19 00:00:00.000000000 Z
12
+ date: 2013-05-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: aws-sdk
@@ -43,6 +43,22 @@ dependencies:
43
43
  - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rubyzip
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
46
62
  description: redis-backup is a simple backup script to automate the creation and storage
47
63
  or redis dump.rdb files.
48
64
  email:
@@ -59,6 +75,8 @@ files:
59
75
  - Rakefile
60
76
  - bin/redis-backup
61
77
  - lib/redis-backup.rb
78
+ - lib/redis-backup/options.rb
79
+ - lib/redis-backup/utils.rb
62
80
  - lib/redis-backup/version.rb
63
81
  - redis-backup.gemspec
64
82
  homepage: https://github.com/josegonzalez/redis-backup