mongo-oplogreplayer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +1 -0
- data/bin/oplogreplayer +4 -0
- data/features/replayer.feature +9 -0
- data/features/support/setup.rb +1 -0
- data/lib/oplogreplayer/cli.rb +14 -0
- data/lib/oplogreplayer/log.rb +10 -0
- data/lib/oplogreplayer/mongobridge.rb +126 -0
- data/lib/oplogreplayer/replayer.rb +71 -0
- data/lib/oplogreplayer/version.rb +3 -0
- data/lib/oplogreplayer.rb +9 -0
- data/oplogreplayer.gemspec +30 -0
- data/spec/oplogreplayer_spec.rb +7 -0
- metadata +196 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 brettcave
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Oplogreplayer
|
2
|
+
|
3
|
+
Oplogreplayer connects to a replica set and monitors write operations by monitoring the oplog, replaying them
|
4
|
+
onto another replica set / mongo instance.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'oplogreplayer'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install oplogreplayer
|
19
|
+
|
20
|
+
## Configuration
|
21
|
+
|
22
|
+
Here is a sample configuration file that can be used.
|
23
|
+
|
24
|
+
resume: true
|
25
|
+
|
26
|
+
source:
|
27
|
+
replicaSet: rs_name
|
28
|
+
host: "rs_host_1:27017,rs_host_2:27017"
|
29
|
+
username: rsUser
|
30
|
+
password: rsPass
|
31
|
+
|
32
|
+
dest:
|
33
|
+
host: "localhost:27017"
|
34
|
+
onlyDbs: "foo,bar"
|
35
|
+
|
36
|
+
The example above shows how use a replicaset with authentication enabled as a source, and a single instance with no
|
37
|
+
authentication as a target.
|
38
|
+
|
39
|
+
`resume` - determines if the oplog replay is to be resumed from the last known point. A timestamp is stored at `dest` in local.oplog.status that is used for resumes.
|
40
|
+
|
41
|
+
`source` and `dest` are the "from" and "to" servers. The source should be a replicaset (for the oplog). The example above shows all the used keys. The following affects how the connection to mongo is made, in both source and dest
|
42
|
+
|
43
|
+
* If there is no username and password, then authentication is disabled
|
44
|
+
* the presence of `replicaSet` in the config is used to determine whether to use a regular client or replica set client. Removing `replicaSet` but leaving a comma-seperated list of hosts may produce unpredictable results.
|
45
|
+
|
46
|
+
`onlyDbs` will enable filtering on the replay, so that only the databases in the list will have operations executed on them.
|
47
|
+
|
48
|
+
## Usage
|
49
|
+
|
50
|
+
`oplogreplayer mongo2mongo -c path/to/oplogConf.yaml`
|
51
|
+
|
52
|
+
### Options
|
53
|
+
|
54
|
+
`-t / --timestamp` - Specifies a timestamp to resume from. Note that this resume, regardless of configuration file setting, and it will overwrite the persisted timestamp for future resumes.
|
55
|
+
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it ( http://github.com/brettcave/oplogreplayer/fork )
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/oplogreplayer
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
Feature: Replayer
|
2
|
+
In order to replay the oplog
|
3
|
+
As a CLI
|
4
|
+
I want to provide a mechanism to tail and replay the oplog
|
5
|
+
|
6
|
+
Scenario: Mongo to mongo replay
|
7
|
+
When I run `oplogreplayer mongo2mongo --test -c ../../sampleConf.yaml`
|
8
|
+
Then the output should contain "Test mode enabled"
|
9
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'aruba/cucumber'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'oplogreplayer'
|
3
|
+
|
4
|
+
module Oplogreplayer
|
5
|
+
class CLI < Thor
|
6
|
+
desc "mongo2mongo", "Replays the oplog from 1 mongo replica set to another instance or RS."
|
7
|
+
option :config, :type => :string, :required => true, :aliases => "-c", :desc => "The configuration for oplog source"
|
8
|
+
option :timestamp, :type => :numeric, :aliases => "-t"
|
9
|
+
def mongo2mongo()
|
10
|
+
Oplogreplayer::Replayer.m2m(options)
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'mongoriver'
|
2
|
+
|
3
|
+
module Oplogreplayer
|
4
|
+
class Mongobridge < Mongoriver::AbstractOutlet
|
5
|
+
|
6
|
+
@_mongoClient
|
7
|
+
@log
|
8
|
+
@filterDbs = nil
|
9
|
+
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
|
13
|
+
setupLogger
|
14
|
+
|
15
|
+
@log.info("Mongo bridge being configured")
|
16
|
+
|
17
|
+
connect_uri = "mongodb://"
|
18
|
+
connect_uri += "#{config["username"]}:#{config["password"]}@" if config["username"] and config["password"]
|
19
|
+
connect_uri += "#{config["host"]}"
|
20
|
+
connect_uri += "?replicaSet=#{config["replicaSet"]}" if config["replicaSet"]
|
21
|
+
|
22
|
+
if config["replicaSet"]
|
23
|
+
@_mongoClient = Mongo::MongoReplicaSetClient.from_uri(connect_uri)
|
24
|
+
@log.info("Target connection configured. Target is a replica set.")
|
25
|
+
else
|
26
|
+
@_mongoClient = Mongo::MongoClient.from_uri(connect_uri)
|
27
|
+
@log.info("Target connection configured. Target is a single instance.")
|
28
|
+
end
|
29
|
+
|
30
|
+
if config["onlyDbs"]
|
31
|
+
@filterDbs = config["onlyDbs"].split(",")
|
32
|
+
@log.info("Filter Dbs has been configured: #{@filterDbs.to_s}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def getOplogTimestamp()
|
37
|
+
findStamp = @_mongoClient.db("local").collection("oplog.tracker").find_one()
|
38
|
+
if findStamp
|
39
|
+
@log.debug("Stamp found: #{findStamp.inspect}")
|
40
|
+
# We return timestamp+1 as "timestamp" was already replayed before shutdown.
|
41
|
+
findStamp["timestamp"]+1
|
42
|
+
else
|
43
|
+
@log.debug("No stamp found. That should mean full replay.")
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# This is potentially bad - a find and update for every oplog....
|
49
|
+
def update_optime(timestamp)
|
50
|
+
# track what's been written with this - write optime to the fs, perhaps periodically.
|
51
|
+
@log.debug("Optime: #{timestamp}")
|
52
|
+
@_mongoClient.db("local").collection("oplog.tracker").update({}, {'timestamp' => timestamp}, {:upsert => true})
|
53
|
+
end
|
54
|
+
|
55
|
+
def insert(db_name, collection_name, document)
|
56
|
+
if @filterDbs and @filterDbs.include? db_name
|
57
|
+
@log.debug("insert #{db_name}.#{collection_name} : #{document.inspect}")
|
58
|
+
@_mongoClient.db(db_name).collection(collection_name).insert(document)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def remove(db_name,collection_name, document)
|
63
|
+
if @filterDbs and @filterDbs.include? db_name
|
64
|
+
@log.debug("remove #{db_name}.#{collection_name} : #{document.inspect}")
|
65
|
+
@_mongoClient.db(db_name).collection(collection_name).remove(document)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def update(db_name, collection_name,selector,update)
|
70
|
+
if @filterDbs and @filterDbs.include? db_name
|
71
|
+
@log.debug("update #{db_name}.#{collection_name} : #{selector} : #{update}")
|
72
|
+
@_mongoClient.db(db_name).collection(collection_name).update(selector,update)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def create_index(db_name, collection_name, index_key, options)
|
78
|
+
if @filterDbs and @filterDbs.include? db_name
|
79
|
+
@log.debug("create_index #{db_name}.#{collection_name} : #{index_key} : #{options}")
|
80
|
+
@_mongoClient.db(db_name).collection(collection_name).create_index(index_key,options)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def drop_index(db_name, collection_name, index_name)
|
85
|
+
if @filterDbs and @filterDbs.include? db_name
|
86
|
+
@log.debug("drop_index #{db_name}.#{collection_name} : #{index_name}")
|
87
|
+
@_mongoClient.db(db_name).collection(collection_name).drop_index(index_name)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_collection(db_name, collection_name, options)
|
92
|
+
if @filterDbs and @filterDbs.include? db_name
|
93
|
+
@log.debug("create_collection #{db_name} : #{collection_name} : #{options}")
|
94
|
+
@_mongoClient.db(db_name).create_collection(collection_name,options)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
def drop_collection(db_name, collection_name)
|
98
|
+
if @filterDbs and @filterDbs.include? db_name
|
99
|
+
@log.debug("drop_collection #{db_name} : #{collection_name}")
|
100
|
+
@_mongoClient.db(db_name).drop_collection(collection_name)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def rename_collection(db_name, old_collection_name, new_collection_name)
|
105
|
+
if @filterDbs and @filterDbs.include? db_name
|
106
|
+
@log.debug("rename_collection #{db_name} : from #{old_collection_name} to #{new_collection_name}")
|
107
|
+
@_mongoClient.db(db_name).rename_collection(old_collection_name,new_collection_name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def drop_database(db_name)
|
112
|
+
if @filterDbs and @filterDbs.include? db_name
|
113
|
+
@log.debug("drop_database #{db_name}")
|
114
|
+
@_mongoClient.drop_database(db_name)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def setupLogger()
|
121
|
+
@log = Log4r::Logger.new("Oplogreplay::Mongobridge")
|
122
|
+
@log.outputters = Log4r::StdoutOutputter.new(STDERR)
|
123
|
+
@log.level = Log4r::INFO
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'mongoriver'
|
2
|
+
require 'oplogreplayer/mongobridge'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Oplogreplayer
|
6
|
+
class Replayer
|
7
|
+
|
8
|
+
@_config = {}
|
9
|
+
|
10
|
+
def self.m2m(options)
|
11
|
+
|
12
|
+
config = options[:config]
|
13
|
+
timestamp = options[:timestamp]
|
14
|
+
|
15
|
+
log = Log4r::Logger.new('Oplogreplayer::Replayer')
|
16
|
+
log.outputters = Log4r::StdoutOutputter.new(STDERR)
|
17
|
+
log.level = Log4r::INFO
|
18
|
+
self.parseConfig(@_config, config)
|
19
|
+
|
20
|
+
sourceConfig = @_config["source"]
|
21
|
+
|
22
|
+
connect_uri = "mongodb://"
|
23
|
+
connect_uri += "#{sourceConfig["username"]}:#{sourceConfig["password"]}@" if sourceConfig["username"] and sourceConfig["password"]
|
24
|
+
connect_uri += "#{sourceConfig["host"]}"
|
25
|
+
connect_uri += "?replicaSet=#{sourceConfig["replicaSet"]}"
|
26
|
+
|
27
|
+
log.info("Setting up client for source")
|
28
|
+
rsClient = Mongo::MongoReplicaSetClient.from_uri(connect_uri)
|
29
|
+
|
30
|
+
log.info("Configuring tailer")
|
31
|
+
tailer = Mongoriver::Tailer.new([rsClient], :existing)
|
32
|
+
|
33
|
+
log.info("Creating mongo2mongo bridge")
|
34
|
+
bridge = Oplogreplayer::Mongobridge.new(@_config["dest"])
|
35
|
+
|
36
|
+
log.info("Creating a stream between tailer and bridge")
|
37
|
+
stream = Mongoriver::Stream.new(tailer, bridge)
|
38
|
+
|
39
|
+
# If a timestamp is supplied as an argument, override.
|
40
|
+
if timestamp
|
41
|
+
log.info("Replaying. Timestamp provided, overriding and starting at #{timestamp}")
|
42
|
+
stream.run_forever(timestamp)
|
43
|
+
elsif @_config["resume"]
|
44
|
+
log.info("Replaying. No timestamp provided but resume is enabled, will resume based on target's last timestamp")
|
45
|
+
# otherwise, try and resume.
|
46
|
+
# We need persistence of the oplog. Not sure whether to use local fs or destination mongo
|
47
|
+
# destination mongo seems better suited though. I'm going to use the local db for now.
|
48
|
+
stream.run_forever(bridge.getOplogTimestamp)
|
49
|
+
else
|
50
|
+
# No timestamp and no resume.... we're doing a full replay.
|
51
|
+
log.info("Replaying. No resume and no timestamp - full oplog replay.")
|
52
|
+
stream.run_forever()
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.parseConfig(target, configFile)
|
57
|
+
if ! ::File.exists?(configFile)
|
58
|
+
raise NoConfigFileError, "Config file not found: #{configFile}"
|
59
|
+
end
|
60
|
+
|
61
|
+
conf = YAML::load_file(configFile)
|
62
|
+
target.merge! conf
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.setupLogging()
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'oplogreplayer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mongo-oplogreplayer"
|
8
|
+
spec.version = Oplogreplayer::VERSION
|
9
|
+
spec.authors = ["brettcave"]
|
10
|
+
spec.email = ["brett@cave.za.net"]
|
11
|
+
spec.summary = %q{Replays the oplog from a mongo replica set}
|
12
|
+
spec.description = %q{Reads the oplog from a replica set and replays it to another mongo instance / rs.}
|
13
|
+
spec.homepage = "https://github.com/brettcave/mongo-oplogreplay"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.3"
|
23
|
+
spec.add_development_dependency "rspec", "~> 2.6"
|
24
|
+
spec.add_development_dependency "cucumber"
|
25
|
+
spec.add_development_dependency "aruba"
|
26
|
+
|
27
|
+
spec.add_dependency "mongoriver", "~> 0.3"
|
28
|
+
spec.add_dependency "mongo", "~> 1.10"
|
29
|
+
spec.add_dependency "thor", "~> 0.18"
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongo-oplogreplayer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- brettcave
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-07-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.5'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.5'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '10.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '10.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.6'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.6'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: cucumber
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: aruba
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: mongoriver
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0.3'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.3'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: mongo
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.10'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.10'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: thor
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0.18'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0.18'
|
142
|
+
description: Reads the oplog from a replica set and replays it to another mongo instance
|
143
|
+
/ rs.
|
144
|
+
email:
|
145
|
+
- brett@cave.za.net
|
146
|
+
executables:
|
147
|
+
- oplogreplayer
|
148
|
+
extensions: []
|
149
|
+
extra_rdoc_files: []
|
150
|
+
files:
|
151
|
+
- .gitignore
|
152
|
+
- Gemfile
|
153
|
+
- LICENSE.txt
|
154
|
+
- README.md
|
155
|
+
- Rakefile
|
156
|
+
- bin/oplogreplayer
|
157
|
+
- features/replayer.feature
|
158
|
+
- features/support/setup.rb
|
159
|
+
- lib/oplogreplayer.rb
|
160
|
+
- lib/oplogreplayer/cli.rb
|
161
|
+
- lib/oplogreplayer/log.rb
|
162
|
+
- lib/oplogreplayer/mongobridge.rb
|
163
|
+
- lib/oplogreplayer/replayer.rb
|
164
|
+
- lib/oplogreplayer/version.rb
|
165
|
+
- oplogreplayer.gemspec
|
166
|
+
- spec/oplogreplayer_spec.rb
|
167
|
+
homepage: https://github.com/brettcave/mongo-oplogreplay
|
168
|
+
licenses:
|
169
|
+
- MIT
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
require_paths:
|
173
|
+
- lib
|
174
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
176
|
+
requirements:
|
177
|
+
- - ! '>='
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
|
+
none: false
|
182
|
+
requirements:
|
183
|
+
- - ! '>='
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
requirements: []
|
187
|
+
rubyforge_project:
|
188
|
+
rubygems_version: 1.8.24
|
189
|
+
signing_key:
|
190
|
+
specification_version: 3
|
191
|
+
summary: Replays the oplog from a mongo replica set
|
192
|
+
test_files:
|
193
|
+
- features/replayer.feature
|
194
|
+
- features/support/setup.rb
|
195
|
+
- spec/oplogreplayer_spec.rb
|
196
|
+
has_rdoc:
|