capistrano-mongo-sync 0.1.4 → 0.1.6
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 +5 -5
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +13 -8
- data/README.md +6 -0
- data/RELEASE.md +6 -0
- data/capistrano-mongo-sync.gemspec +4 -4
- data/lib/capistrano/mongo_sync/mongo_sync.rb +29 -3
- data/lib/capistrano/tasks/mongo-sync.cap +2 -0
- data/test/test_mongo_sync.rb +15 -4
- metadata +6 -5
- data/lib/capistrano/mongo-sync/mongo-sync.cap +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 0f8dd6e66c59528341b95db1601e6d5ed1e9003628ab675d0ed8a19f39b00b20
|
4
|
+
data.tar.gz: bced25f1f251ab2aa23897cc0cb1571e61b1897f105e67565bbdd95b68ca1304
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6d7c9bca76a43f706947f585d407210080f68dff2d4c3dc7122832b7bd51c382cd6cda73768f97f3d2cca30b8481dbc3301805a7eedc3968428bbc23f7970a2
|
7
|
+
data.tar.gz: a45416c9fd270069861d19c339b0ec5cd8815d0822da5aca48a32d60e8c114f3ff1925a95e1b83c37cdf5126d5cda4b4dc359110f66f64bb5256cce32a0e2264
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,27 +1,32 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
capistrano-mongo-sync (0.1.
|
4
|
+
capistrano-mongo-sync (0.1.6)
|
5
5
|
capistrano (~> 3.1)
|
6
6
|
sshkit (~> 1.2)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
|
11
|
+
airbrussh (1.3.0)
|
12
|
+
sshkit (>= 1.6.1, != 1.7.0)
|
13
|
+
capistrano (3.10.1)
|
14
|
+
airbrussh (>= 1.0.0)
|
12
15
|
i18n
|
13
16
|
rake (>= 10.0.0)
|
14
|
-
sshkit (
|
15
|
-
|
17
|
+
sshkit (>= 1.9.0)
|
18
|
+
concurrent-ruby (1.0.5)
|
19
|
+
i18n (0.9.1)
|
20
|
+
concurrent-ruby (~> 1.0)
|
16
21
|
metaclass (0.0.4)
|
17
22
|
minitest (5.8.4)
|
18
23
|
mocha (1.1.0)
|
19
24
|
metaclass (~> 0.0.1)
|
20
25
|
net-scp (1.2.1)
|
21
26
|
net-ssh (>= 2.6.5)
|
22
|
-
net-ssh (
|
23
|
-
rake (
|
24
|
-
sshkit (1.
|
27
|
+
net-ssh (4.2.0)
|
28
|
+
rake (12.3.0)
|
29
|
+
sshkit (1.15.1)
|
25
30
|
net-scp (>= 1.1.2)
|
26
31
|
net-ssh (>= 2.8.0)
|
27
32
|
|
@@ -34,4 +39,4 @@ DEPENDENCIES
|
|
34
39
|
mocha (~> 1.1)
|
35
40
|
|
36
41
|
BUNDLED WITH
|
37
|
-
1.
|
42
|
+
1.16.1
|
data/README.md
CHANGED
@@ -13,6 +13,12 @@ Or sync just one collection from the database:
|
|
13
13
|
COLLECTION=users cap production mongo:pull
|
14
14
|
```
|
15
15
|
|
16
|
+
Or sync some records (comma separated list of mongo id's) from one collection from the database:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
COLLECTION=users IDS=1,2,3,4 cap production mongo:pull
|
20
|
+
```
|
21
|
+
|
16
22
|
Or sync your staging database from your production database.
|
17
23
|
|
18
24
|
```ruby
|
data/RELEASE.md
ADDED
@@ -1,11 +1,11 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'capistrano-mongo-sync'
|
3
|
-
gem.version = '0.1.
|
4
|
-
gem.date = '
|
3
|
+
gem.version = '0.1.6'
|
4
|
+
gem.date = '2018-01-18'
|
5
5
|
gem.summary = "A tool for keeping local mongo in sync with remote"
|
6
6
|
gem.description = "A tool for keeping local mongo in sync with remote"
|
7
|
-
gem.authors = ["Open Listings Engineering"]
|
8
|
-
gem.email = 'engineering@
|
7
|
+
gem.authors = ["Open Listings Engineering", "We're hiring!"]
|
8
|
+
gem.email = 'engineering@openlistings.com'
|
9
9
|
gem.homepage = 'https://github.com/openlistings/capistrano-mongo-sync'
|
10
10
|
gem.license = 'MIT'
|
11
11
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
1
3
|
class MongoSync
|
2
4
|
def initialize(connection)
|
3
5
|
@connection = connection
|
@@ -8,6 +10,7 @@ class MongoSync
|
|
8
10
|
@staging_db = fetch(:staging_db)
|
9
11
|
@from_db = fetch(:from_db)
|
10
12
|
@collection = fetch(:collection) || 'full'
|
13
|
+
@collection_ids = fetch(:collection_ids)
|
11
14
|
@hipchat_client = fetch(:hipchat_client)
|
12
15
|
|
13
16
|
fail "Incomplete configuration: missing remote_dump_base" unless @remote_dump_base
|
@@ -15,11 +18,18 @@ class MongoSync
|
|
15
18
|
fail "Incomplete configuration: missing production_db" unless @production_db
|
16
19
|
fail "Incomplete configuration: missing development_db" unless @development_db
|
17
20
|
fail "Incomplete configuration: missing from_db" unless @from_db
|
21
|
+
fail "Incomplete configuration: missing collection" if @collection_ids && @collection.nil?
|
18
22
|
end
|
19
23
|
|
20
24
|
# the first part of the dump dir, without the timestamp... for example "mydatabase-full"
|
21
25
|
def dump_dir_part
|
22
|
-
[@from_db, @collection].join('-')
|
26
|
+
str = [@from_db, @collection].join('-')
|
27
|
+
|
28
|
+
if @collection_ids
|
29
|
+
str = [str, Digest::MD5.hexdigest(@collection_ids)].join('-')
|
30
|
+
end
|
31
|
+
|
32
|
+
str
|
23
33
|
end
|
24
34
|
|
25
35
|
## Remote
|
@@ -40,12 +50,17 @@ class MongoSync
|
|
40
50
|
|
41
51
|
args = ['-d', @from_db, '-o', File.join(@remote_dump_base, dump_dir)]
|
42
52
|
args += ['-c', @collection] unless 'full' == @collection
|
53
|
+
args += ['-q', collection_ids_arg] if @collection_ids
|
43
54
|
|
44
55
|
@connection.execute :mongodump, *args
|
45
56
|
|
46
57
|
dump_dir
|
47
58
|
end
|
48
59
|
|
60
|
+
def collection_ids_arg
|
61
|
+
'{_id: {$in: [%s]}}' % @collection_ids.split(',').map{|id| 'ObjectId("%s")' % id}.join(',')
|
62
|
+
end
|
63
|
+
|
49
64
|
def staging_mongorestore!( remote_dump_dir )
|
50
65
|
full_path_to_remote_dump_dir = if remote_dump_dir == File.basename(remote_dump_dir)
|
51
66
|
File.join(@remote_dump_base, remote_dump_dir, @production_db)
|
@@ -53,7 +68,10 @@ class MongoSync
|
|
53
68
|
remote_dump_dir
|
54
69
|
end
|
55
70
|
|
56
|
-
|
71
|
+
args = []
|
72
|
+
args << '--drop' if drop_collection?
|
73
|
+
args += ['-d', @staging_db, full_path_to_remote_dump_dir]
|
74
|
+
@connection.execute :mongorestore, *args
|
57
75
|
end
|
58
76
|
|
59
77
|
def last_remote_dump
|
@@ -144,10 +162,18 @@ class MongoSync
|
|
144
162
|
def local_mongorestore!(local_dump_dir)
|
145
163
|
db_dump_path = File.join local_dump_dir, @from_db
|
146
164
|
@connection.within( @local_dump_base ) do
|
147
|
-
|
165
|
+
args = []
|
166
|
+
args << '--drop' if drop_collection?
|
167
|
+
args += ['-d', @development_db, db_dump_path]
|
168
|
+
@connection.execute :mongorestore, *args
|
148
169
|
end
|
149
170
|
end
|
150
171
|
|
172
|
+
# don't drop the collection if it's importing partially
|
173
|
+
def drop_collection?
|
174
|
+
@collection_ids.nil?
|
175
|
+
end
|
176
|
+
|
151
177
|
## Hipchat
|
152
178
|
def hipchat_notify!( room, user, msg, opts = {} )
|
153
179
|
return unless @hipchat_client
|
@@ -2,12 +2,14 @@
|
|
2
2
|
# Usage:
|
3
3
|
# ./bin/cap production mongo:pull
|
4
4
|
# COLLECTION=agents ./bin/cap production mongo:pull
|
5
|
+
# COLLECTION=agents IDS=1,2,3 ./bin/cap production mongo:pull
|
5
6
|
# ./bin/cap production mongo:sync_prod_to_staging
|
6
7
|
|
7
8
|
namespace :mongo do
|
8
9
|
set :remote_dump_base, '/tmp/dumps'
|
9
10
|
set :local_dump_base, '/tmp/dumps'
|
10
11
|
set :collection, ENV['COLLECTION'] || 'full'
|
12
|
+
set :collection_ids, ENV['IDS']
|
11
13
|
|
12
14
|
task :sync_prod_to_staging do
|
13
15
|
set :from_db, fetch(:production_db)
|
data/test/test_mongo_sync.rb
CHANGED
@@ -13,6 +13,7 @@ class MongoSync
|
|
13
13
|
@from_db = 'mydb'.freeze
|
14
14
|
@hipchat_client = nil
|
15
15
|
@collection = 'full'
|
16
|
+
@collection_ids = nil
|
16
17
|
|
17
18
|
instance_variable_get("@#{x}")
|
18
19
|
end
|
@@ -62,6 +63,16 @@ class MongoSyncTest < Minitest::Test
|
|
62
63
|
assert_equal 'mydb-agents-2015-01-01-01-01', output_dir
|
63
64
|
end
|
64
65
|
|
66
|
+
def test_remote_mongodump_agents_collection_with_collection_ids
|
67
|
+
@mongo_sync.instance_variable_set("@collection", 'agents')
|
68
|
+
@mongo_sync.instance_variable_set("@collection_ids", '1,2,3')
|
69
|
+
@connection.expects(:execute).once().with(:mongodump, '-d', 'mydb', '-o', '/mnt/tmp/dumps/mydb-agents-55b84a9d317184fe61224bfb4a060fb0-2015-01-01-01-01', '-c', 'agents', '-q', '{_id: {$in: [ObjectId("1"),ObjectId("2"),ObjectId("3")]}}')
|
70
|
+
output_dir = @mongo_sync.remote_mongodump!
|
71
|
+
|
72
|
+
# path includes hexdigest of IDS string
|
73
|
+
assert_equal 'mydb-agents-55b84a9d317184fe61224bfb4a060fb0-2015-01-01-01-01', output_dir
|
74
|
+
end
|
75
|
+
|
65
76
|
def test_dump_prompt_message
|
66
77
|
path_to_tgz = '/tmp/dumps/mydb-full-2015-01-01-01-00.tgz'
|
67
78
|
expected_msg = "Use local dump from today at 01:00 AM? \"%s\"? (y/n)" % path_to_tgz
|
@@ -104,7 +115,7 @@ class MongoSyncTest < Minitest::Test
|
|
104
115
|
def test_last_remote_dump_no_dumps
|
105
116
|
@connection.expects(:test, 'ls -td /mnt/tmp/dumps/*/mydb').returns(false)
|
106
117
|
lrd = @mongo_sync.last_remote_dump
|
107
|
-
|
118
|
+
assert_nil lrd
|
108
119
|
end
|
109
120
|
|
110
121
|
def test_last_remote_dump_dumps_y
|
@@ -126,19 +137,19 @@ class MongoSyncTest < Minitest::Test
|
|
126
137
|
@mongo_sync.instance_variable_set '@use_remote_dump_dir', 'n'
|
127
138
|
|
128
139
|
lrd = @mongo_sync.last_remote_dump
|
129
|
-
|
140
|
+
assert_nil lrd
|
130
141
|
end
|
131
142
|
|
132
143
|
def test_last_local_dump_no_dumps
|
133
144
|
@connection.expects(:test, 'ls -td /mnt/tmp/dumps/mydb-full*/mydb').returns(false)
|
134
145
|
lrd = @mongo_sync.last_remote_dump
|
135
|
-
|
146
|
+
assert_nil lrd
|
136
147
|
end
|
137
148
|
|
138
149
|
def test_last_remote_dump_tgz
|
139
150
|
@connection.expects(:test, 'ls -td /mnt/tmp/dumps/mydb-full*/mydb').returns(false)
|
140
151
|
lrd = @mongo_sync.last_remote_dump
|
141
|
-
|
152
|
+
assert_nil lrd
|
142
153
|
end
|
143
154
|
|
144
155
|
def test_local_mongorestore
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: capistrano-mongo-sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Open Listings Engineering
|
8
|
+
- We're hiring!
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2018-01-18 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: capistrano
|
@@ -67,7 +68,7 @@ dependencies:
|
|
67
68
|
- !ruby/object:Gem::Version
|
68
69
|
version: '1.1'
|
69
70
|
description: A tool for keeping local mongo in sync with remote
|
70
|
-
email: engineering@
|
71
|
+
email: engineering@openlistings.com
|
71
72
|
executables: []
|
72
73
|
extensions: []
|
73
74
|
extra_rdoc_files: []
|
@@ -78,10 +79,10 @@ files:
|
|
78
79
|
- Gemfile.lock
|
79
80
|
- LICENSE
|
80
81
|
- README.md
|
82
|
+
- RELEASE.md
|
81
83
|
- Rakefile
|
82
84
|
- capistrano-mongo-sync.gemspec
|
83
85
|
- lib/capistrano/mongo-sync.rb
|
84
|
-
- lib/capistrano/mongo-sync/mongo-sync.cap
|
85
86
|
- lib/capistrano/mongo_sync/mongo_sync.rb
|
86
87
|
- lib/capistrano/tasks/mongo-sync.cap
|
87
88
|
- test/test_mongo_sync.rb
|
@@ -105,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
105
106
|
version: '0'
|
106
107
|
requirements: []
|
107
108
|
rubyforge_project:
|
108
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.7.3
|
109
110
|
signing_key:
|
110
111
|
specification_version: 4
|
111
112
|
summary: A tool for keeping local mongo in sync with remote
|
@@ -1,75 +0,0 @@
|
|
1
|
-
##
|
2
|
-
# Usage:
|
3
|
-
# ./bin/cap production mongo:pull
|
4
|
-
# COLLECTION=agents ./bin/cap production mongo:pull
|
5
|
-
# ./bin/cap production mongo:sync_prod_to_staging
|
6
|
-
|
7
|
-
namespace :mongo do
|
8
|
-
set :remote_dump_base, '/tmp/dumps'
|
9
|
-
set :local_dump_base, '/tmp/dumps'
|
10
|
-
set :collection, ENV['COLLECTION'] || 'full'
|
11
|
-
|
12
|
-
task :sync_prod_to_staging do
|
13
|
-
set :from_db, fetch(:production_db)
|
14
|
-
|
15
|
-
on roles(:db) do
|
16
|
-
ms_remote = MongoSync.new(self)
|
17
|
-
ms_remote.hipchat_notify! 'Engineering', 'capistrano', 'Started syncing prod to staging...', color: 'yellow'
|
18
|
-
ms_remote.remote_setup!
|
19
|
-
ms_remote.remote_cleanup!
|
20
|
-
|
21
|
-
remote_dump_dir = ms_remote.last_remote_dump
|
22
|
-
remote_dump_dir ||= ms_remote.remote_mongodump!
|
23
|
-
|
24
|
-
ms_remote.staging_mongorestore! remote_dump_dir
|
25
|
-
ms_remote.hipchat_notify! 'Engineering', 'capistrano', 'Finished syncing prod to staging...', color: 'green'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
task :pull do
|
30
|
-
set :from_db, :production == fetch(:stage) ? fetch(:production_db) : fetch(:staging_db)
|
31
|
-
|
32
|
-
run_locally do
|
33
|
-
ms_local = MongoSync.new(self)
|
34
|
-
ms_local.local_setup!
|
35
|
-
ms_local.local_cleanup!
|
36
|
-
|
37
|
-
# variable scope
|
38
|
-
remote_tgz = nil
|
39
|
-
local_tgz = nil
|
40
|
-
|
41
|
-
if local_tgz = ms_local.last_local_dump
|
42
|
-
# use local tgz
|
43
|
-
ms_local.local_unarchive! local_tgz
|
44
|
-
|
45
|
-
local_dump_dir = File.join fetch(:local_dump_base), File.basename(local_tgz, '.tgz')
|
46
|
-
ms_local.local_mongorestore!(local_dump_dir)
|
47
|
-
else
|
48
|
-
# get dump from remote
|
49
|
-
on roles(:db) do
|
50
|
-
ms_remote = MongoSync.new(self)
|
51
|
-
ms_remote.remote_setup!
|
52
|
-
ms_remote.remote_cleanup!
|
53
|
-
|
54
|
-
# find & choose tarfile or dump & archive
|
55
|
-
remote_tgz = ms_remote.last_remote_dump_tgz
|
56
|
-
unless remote_tgz
|
57
|
-
dump_dir = ms_remote.remote_mongodump!
|
58
|
-
remote_tgz = ms_remote.remote_archive! dump_dir
|
59
|
-
end
|
60
|
-
|
61
|
-
# download!
|
62
|
-
local_tgz = File.join fetch(:local_dump_base), File.basename(remote_tgz)
|
63
|
-
download! remote_tgz, local_tgz, method: :scp
|
64
|
-
end
|
65
|
-
|
66
|
-
# unarchive!
|
67
|
-
ms_local.local_unarchive!(local_tgz)
|
68
|
-
|
69
|
-
# restore!
|
70
|
-
local_dump_dir = File.join fetch(:local_dump_base), File.basename(remote_tgz, '.tgz')
|
71
|
-
ms_local.local_mongorestore!(local_dump_dir)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|