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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 933c334709a5c306b67c966dc4568e9b19d08985
4
- data.tar.gz: 587bbed62e4b4569e138c297b3b7425fe67e8d7a
2
+ SHA256:
3
+ metadata.gz: 0f8dd6e66c59528341b95db1601e6d5ed1e9003628ab675d0ed8a19f39b00b20
4
+ data.tar.gz: bced25f1f251ab2aa23897cc0cb1571e61b1897f105e67565bbdd95b68ca1304
5
5
  SHA512:
6
- metadata.gz: c48627b33a655b8921edc1874e2c9f48e92ce31cf5693b11ba5f1ca9552c5e3ca35c5c1d02566aef6669c8b870c8647acdaf3925da451e48eaac421d46a47a2a
7
- data.tar.gz: 720a51a7c10253eebaf6c000c61d9d043f186c5961c768929ceb5381c5b8e478d3477385a091d3f0495271f661a4bfd35a99dda5abf5f632a98937cc44c79ac9
6
+ metadata.gz: d6d7c9bca76a43f706947f585d407210080f68dff2d4c3dc7122832b7bd51c382cd6cda73768f97f3d2cca30b8481dbc3301805a7eedc3968428bbc23f7970a2
7
+ data.tar.gz: a45416c9fd270069861d19c339b0ec5cd8815d0822da5aca48a32d60e8c114f3ff1925a95e1b83c37cdf5126d5cda4b4dc359110f66f64bb5256cce32a0e2264
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.1.6
2
+
3
+ Add IDS feature used in conjunction with COLLECTION feature
4
+
1
5
  # 0.1.0
2
6
 
3
7
  Initial release
data/Gemfile.lock CHANGED
@@ -1,27 +1,32 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- capistrano-mongo-sync (0.1.0)
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
- capistrano (3.4.0)
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 (~> 1.3)
15
- i18n (0.7.0)
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 (3.0.2)
23
- rake (11.1.1)
24
- sshkit (1.9.0)
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.11.2
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
@@ -0,0 +1,6 @@
1
+ # Release a new version of this gem
2
+
3
+ http://guides.rubygems.org/make-your-own-gem/
4
+
5
+ `gem build capistrano-mongo-sync.gemspec`
6
+ `gem push capistrano-mongo-sync-<VERSION>.gem`
@@ -1,11 +1,11 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'capistrano-mongo-sync'
3
- gem.version = '0.1.4'
4
- gem.date = '2016-06-13'
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@openlistinggem.com'
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
- @connection.execute :mongorestore, '--drop', '-d', @staging_db, full_path_to_remote_dump_dir
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
- @connection.execute :mongorestore, '--drop', '-d', @development_db, db_dump_path
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)
@@ -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
- assert_equal nil, lrd
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
- assert_equal nil, lrd
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
- assert_equal nil, lrd
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
- assert_equal nil, lrd
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
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: 2016-06-13 00:00:00.000000000 Z
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@openlistinggem.com
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.5.1
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