mongo-oplog-backup 0.0.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3acf779f860fdb9a7fc941b68f7755c36f215ad6
4
- data.tar.gz: 5a1a19a402c4d337b90c81efc693aeb7d583e454
3
+ metadata.gz: 0683856bbe55049a12b2d1116dab286a2777ac0a
4
+ data.tar.gz: ec2de886b2be3a374fa7b19e5882dc0ba81d2235
5
5
  SHA512:
6
- metadata.gz: 5c01fe3144e8a2c891c363bac256082c17f836d71fa2b097d8f3e737afcaba51d41034b6c7dda7025ac5d0ee282a35908796441bbb9bf41cafc0aa89ac9e35af
7
- data.tar.gz: 94b42dac6b402b476c83ff6f1f131884d266d2b8bc545b389440574fc36f084bcbd7df9152d6149ee1d2f9a2c37e47864822d795c0d619109c93a3de2d1a17e1
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
- TODO: Write usage instructions here
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/<my-github-username>/mongo-oplog-backup/fork )
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`)
@@ -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
- state_file = config.state_file
96
- state = JSON.parse(File.read(state_file)) rescue nil
97
- state ||= {}
98
- have_position = (state['position'] && state['backup'])
99
-
100
- if mode == :auto
101
- if have_position
102
- mode = :oplog
103
- else
104
- mode = :full
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
- if mode == :oplog
109
- raise "Unknown backup position - cannot perform oplog backup." unless have_position
110
- MongoOplogBackup.log.info "Performing incremental oplog backup"
111
- position = BSON::Timestamp.from_json(state['position'])
112
- result = backup_oplog(start: position, backup: state['backup'])
113
- unless result[:empty]
114
- new_entries = result[:entries] - 1
115
- state['position'] = result[:position]
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 "Backed up #{new_entries} new entries to #{result[:file]}"
118
- else
119
- MongoOplogBackup.log.info "Nothing new to backup"
144
+ MongoOplogBackup.log.info "Performed full backup"
145
+
146
+ perform_oplog_afterwards = true
120
147
  end
121
- elsif mode == :full
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
- @options = options
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}`
@@ -1,3 +1,3 @@
1
1
  module MongoOplogBackup
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/sample-config.yml ADDED
@@ -0,0 +1,6 @@
1
+ # Any settings specified here are overridden by command line options.
2
+ host: localhost
3
+ port: 27017
4
+ username: backup-user
5
+ password: s3kr1t
6
+ ssl: true
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.1
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-15 00:00:00.000000000 Z
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