mongo-oplog-backup 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +19 -3
- data/bin/mongo-oplog-backup +4 -1
- data/lib/mongo_oplog_backup/backup.rb +62 -30
- data/lib/mongo_oplog_backup/config.rb +21 -1
- data/lib/mongo_oplog_backup/version.rb +1 -1
- data/sample-config.yml +6 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0683856bbe55049a12b2d1116dab286a2777ac0a
|
4
|
+
data.tar.gz: ec2de886b2be3a374fa7b19e5882dc0ba81d2235
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9afd48be80dc546dfd14c6486eb4a324f5cb4c42deb7eda7d95c5f51e10827f2afb7f2cd19876d7bde06af8feac632c211e2e21da3c8b40305f7291b359f0cab
|
7
|
+
data.tar.gz: fe30271a6df011ebe714408f4311020c6c9d339e8bfb94ed7a27ef941c933437c46de2212a8562afd272675040d18708b59869d062bd635cf33bcc21a3350691
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
**Experimental** incremental backup system for MongoDB based on the oplog.
|
4
4
|
|
5
|
-
Not ready for any important data yet.
|
5
|
+
**Not ready for any important data yet. Use at your own risk.**
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -12,9 +12,24 @@ Not ready for any important data yet.
|
|
12
12
|
|
13
13
|
## Usage
|
14
14
|
|
15
|
+
To backup from localhost to the `mybackup` directory.
|
16
|
+
|
15
17
|
mongo-oplog-backup backup --dir mybackup
|
16
18
|
|
17
|
-
|
19
|
+
The first run will perform a full backup. Subsequent runs will backup any new entries from the oplog.
|
20
|
+
A full backup can be forced with the `--full` option.
|
21
|
+
|
22
|
+
For connection options, see `mongo-oplog-backup backup --help`.
|
23
|
+
|
24
|
+
## To restore
|
25
|
+
|
26
|
+
mongo-oplog-backup merge --dir mybackup/backup-<timestamp>
|
27
|
+
|
28
|
+
The above command merges the individual oplog backups into `mybackup/backup-<timestamp>/dump/oplog.bson`.
|
29
|
+
This allows you to restore the backup with the `mongorestore` command:
|
30
|
+
|
31
|
+
mongorestore --drop --oplogReplay backup/backup-<timestamp>/dump
|
32
|
+
|
18
33
|
|
19
34
|
## Backup structure
|
20
35
|
|
@@ -25,9 +40,10 @@ TODO: Write usage instructions here
|
|
25
40
|
* `oplog-<start>-<end>.bson` - The oplog from the start timestamp until the end timestamp (inclusive).
|
26
41
|
|
27
42
|
Each time a full backup is performed, a new backup folder is created.
|
43
|
+
|
28
44
|
## Contributing
|
29
45
|
|
30
|
-
1. Fork it ( http://github.com
|
46
|
+
1. Fork it ( http://github.com/journeyapps/mongo-oplog-backup/fork )
|
31
47
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
32
48
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
33
49
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/bin/mongo-oplog-backup
CHANGED
@@ -12,7 +12,9 @@ opts = Slop.parse(help: true, strict: true) do
|
|
12
12
|
on :d, :dir, "Directory to store backup files. Defaults to 'backup'.", argument: :required
|
13
13
|
on :full, 'Force full backup'
|
14
14
|
on :oplog, 'Force oplog backup'
|
15
|
+
on :'if-not-busy', 'Do nothing when another backup is busy running.'
|
15
16
|
|
17
|
+
on :f, :file, 'Configuration file for common defaults', argument: :required
|
16
18
|
on :ssl, "Connect to a mongod instance over an SSL connection"
|
17
19
|
on :host, "Specifies a resolvable hostname for the mongod that you wish to backup.", default: 'localhost', argument: :required
|
18
20
|
on :port, "Specifies the port that mongod is running on", default: '27017', argument: :required
|
@@ -25,6 +27,7 @@ opts = Slop.parse(help: true, strict: true) do
|
|
25
27
|
dir: dir,
|
26
28
|
ssl: opts.ssl?
|
27
29
|
}
|
30
|
+
config_opts[:file] = opts[:file]
|
28
31
|
config_opts[:host] = opts[:host]
|
29
32
|
config_opts[:port] = opts[:port]
|
30
33
|
config_opts[:username] = opts[:username]
|
@@ -38,7 +41,7 @@ opts = Slop.parse(help: true, strict: true) do
|
|
38
41
|
end
|
39
42
|
config = MongoOplogBackup::Config.new(config_opts)
|
40
43
|
backup = MongoOplogBackup::Backup.new(config)
|
41
|
-
backup.perform(mode)
|
44
|
+
backup.perform(mode, if_not_busy: opts.if_not_busy?)
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
@@ -2,6 +2,9 @@ require 'json'
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'mongo_oplog_backup/oplog'
|
4
4
|
|
5
|
+
class LockError < StandardError
|
6
|
+
end
|
7
|
+
|
5
8
|
module MongoOplogBackup
|
6
9
|
class Backup
|
7
10
|
attr_reader :config
|
@@ -10,6 +13,16 @@ module MongoOplogBackup
|
|
10
13
|
@config = config
|
11
14
|
end
|
12
15
|
|
16
|
+
def lock(lockname, &block)
|
17
|
+
File.open(lockname, File::RDWR|File::CREAT, 0644) do |file|
|
18
|
+
got_lock = file.flock(File::LOCK_EX|File::LOCK_NB)
|
19
|
+
if got_lock == false
|
20
|
+
raise LockError, "Failed to acquire lock - another backup may be busy"
|
21
|
+
end
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
13
26
|
def backup_oplog(options={})
|
14
27
|
start_at = options[:start]
|
15
28
|
backup = options[:backup]
|
@@ -91,42 +104,61 @@ module MongoOplogBackup
|
|
91
104
|
}
|
92
105
|
end
|
93
106
|
|
94
|
-
def perform(mode=:auto)
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
107
|
+
def perform(mode=:auto, options={})
|
108
|
+
if_not_busy = options[:if_not_busy] || false
|
109
|
+
|
110
|
+
perform_oplog_afterwards = false
|
111
|
+
|
112
|
+
lock(config.lock_file) do
|
113
|
+
state_file = config.state_file
|
114
|
+
state = JSON.parse(File.read(state_file)) rescue nil
|
115
|
+
state ||= {}
|
116
|
+
have_position = (state['position'] && state['backup'])
|
117
|
+
|
118
|
+
if mode == :auto
|
119
|
+
if have_position
|
120
|
+
mode = :oplog
|
121
|
+
else
|
122
|
+
mode = :full
|
123
|
+
end
|
105
124
|
end
|
106
|
-
end
|
107
125
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
126
|
+
if mode == :oplog
|
127
|
+
raise "Unknown backup position - cannot perform oplog backup." unless have_position
|
128
|
+
MongoOplogBackup.log.info "Performing incremental oplog backup"
|
129
|
+
position = BSON::Timestamp.from_json(state['position'])
|
130
|
+
result = backup_oplog(start: position, backup: state['backup'])
|
131
|
+
unless result[:empty]
|
132
|
+
new_entries = result[:entries] - 1
|
133
|
+
state['position'] = result[:position]
|
134
|
+
File.write(state_file, state.to_json)
|
135
|
+
MongoOplogBackup.log.info "Backed up #{new_entries} new entries to #{result[:file]}"
|
136
|
+
else
|
137
|
+
MongoOplogBackup.log.info "Nothing new to backup"
|
138
|
+
end
|
139
|
+
elsif mode == :full
|
140
|
+
MongoOplogBackup.log.info "Performing full backup"
|
141
|
+
result = backup_full
|
142
|
+
state = result
|
116
143
|
File.write(state_file, state.to_json)
|
117
|
-
MongoOplogBackup.log.info "
|
118
|
-
|
119
|
-
|
144
|
+
MongoOplogBackup.log.info "Performed full backup"
|
145
|
+
|
146
|
+
perform_oplog_afterwards = true
|
120
147
|
end
|
121
|
-
|
122
|
-
MongoOplogBackup.log.info "Performing full backup"
|
123
|
-
result = backup_full
|
124
|
-
state = result
|
125
|
-
File.write(state_file, state.to_json)
|
126
|
-
MongoOplogBackup.log.info "Performed full backup"
|
148
|
+
end
|
127
149
|
|
150
|
+
# Has to be outside the lock
|
151
|
+
if perform_oplog_afterwards
|
128
152
|
# Oplog backup
|
129
|
-
perform(:oplog)
|
153
|
+
perform(:oplog, options)
|
154
|
+
end
|
155
|
+
|
156
|
+
rescue LockError => e
|
157
|
+
if if_not_busy
|
158
|
+
MongoOplogBackup.log.info e.message
|
159
|
+
MongoOplogBackup.log.info 'Not performing backup'
|
160
|
+
else
|
161
|
+
raise
|
130
162
|
end
|
131
163
|
end
|
132
164
|
|
@@ -3,7 +3,23 @@ module MongoOplogBackup
|
|
3
3
|
attr_reader :options
|
4
4
|
|
5
5
|
def initialize(options)
|
6
|
-
|
6
|
+
config_file = options.delete(:file)
|
7
|
+
# Command line options take precedence
|
8
|
+
@options = from_file(config_file).merge(options)
|
9
|
+
end
|
10
|
+
|
11
|
+
def from_file file
|
12
|
+
options = {}
|
13
|
+
unless file.nil?
|
14
|
+
conf = YAML.load_file(file)
|
15
|
+
options[:ssl] = conf["ssl"] unless conf["ssl"].nil?
|
16
|
+
options[:host] = conf["host"] unless conf["host"].nil?
|
17
|
+
options[:port] = conf["port"].to_s unless conf["port"].nil?
|
18
|
+
options[:username] = conf["username"] unless conf["username"].nil?
|
19
|
+
options[:password] = conf["password"] unless conf["password"].nil?
|
20
|
+
end
|
21
|
+
|
22
|
+
options
|
7
23
|
end
|
8
24
|
|
9
25
|
def backup_dir
|
@@ -31,6 +47,10 @@ module MongoOplogBackup
|
|
31
47
|
File.join(backup_dir, 'backup.json')
|
32
48
|
end
|
33
49
|
|
50
|
+
def lock_file
|
51
|
+
File.join(backup_dir, 'backup.lock')
|
52
|
+
end
|
53
|
+
|
34
54
|
def exec(cmd)
|
35
55
|
MongoOplogBackup.log.debug ">>> #{cmd}"
|
36
56
|
`#{cmd}`
|
data/sample-config.yml
ADDED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongo-oplog-backup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ralf Kistner
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bson
|
@@ -120,6 +120,7 @@ files:
|
|
120
120
|
- lib/mongo_oplog_backup/version.rb
|
121
121
|
- mongo-oplog-backup.gemspec
|
122
122
|
- oplog-last-timestamp.js
|
123
|
+
- sample-config.yml
|
123
124
|
- spec/backup_spec.rb
|
124
125
|
- spec/enumerable_spec.rb
|
125
126
|
- spec/fixtures/oplog-1408088734:1-1408088740:1.bson
|