mongo 2.20.1 → 2.20.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 +4 -4
- data/Rakefile +9 -9
- data/lib/mongo/socket/ssl.rb +13 -4
- data/lib/mongo/version.rb +4 -15
- data/spec/integration/ocsp_verifier_spec.rb +30 -99
- data/spec/integration/reconnect_spec.rb +8 -2
- data/spec/integration/srv_monitoring_spec.rb +2 -3
- data/spec/integration/srv_spec.rb +0 -4
- data/spec/shared/CANDIDATE.md +28 -0
- data/spec/shared/LICENSE +20 -0
- data/spec/shared/bin/get-mongodb-download-url +17 -0
- data/spec/shared/bin/s3-copy +45 -0
- data/spec/shared/bin/s3-upload +69 -0
- data/spec/shared/lib/mrss/child_process_helper.rb +80 -0
- data/spec/shared/lib/mrss/cluster_config.rb +231 -0
- data/spec/shared/lib/mrss/constraints.rb +378 -0
- data/spec/shared/lib/mrss/docker_runner.rb +298 -0
- data/spec/shared/lib/mrss/eg_config_utils.rb +51 -0
- data/spec/shared/lib/mrss/event_subscriber.rb +210 -0
- data/spec/shared/lib/mrss/lite_constraints.rb +238 -0
- data/spec/shared/lib/mrss/release/candidate.rb +281 -0
- data/spec/shared/lib/mrss/release/product_data.rb +144 -0
- data/spec/shared/lib/mrss/server_version_registry.rb +113 -0
- data/spec/shared/lib/mrss/session_registry.rb +69 -0
- data/spec/shared/lib/mrss/session_registry_legacy.rb +60 -0
- data/spec/shared/lib/mrss/spec_organizer.rb +179 -0
- data/spec/shared/lib/mrss/utils.rb +37 -0
- data/spec/shared/lib/tasks/candidate.rake +64 -0
- data/spec/shared/share/Dockerfile.erb +251 -0
- data/spec/shared/share/haproxy-1.conf +16 -0
- data/spec/shared/share/haproxy-2.conf +17 -0
- data/spec/shared/shlib/config.sh +27 -0
- data/spec/shared/shlib/distro.sh +84 -0
- data/spec/shared/shlib/server.sh +423 -0
- data/spec/shared/shlib/set_env.sh +110 -0
- data/spec/support/common_shortcuts.rb +19 -37
- data/spec/support/constraints.rb +10 -0
- metadata +64 -15
- data/spec/support/dns.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8ccd08d09b5ee60c5da82105ce4bb165f1324e475e9f476f956d08a677a503b9
|
4
|
+
data.tar.gz: d055b854eb8f822e37ca7002bef5e3625c6ddf7052c06113c0568b0ca275eae6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 291abbb2324d615f2061a7f924e31c7020c7da0541ff5a5b115a9c3edb7b4a74a921ff3e226a50bb6c74fb9f8f79f8343f14ea17f701b6796fde2dc774f0c915
|
7
|
+
data.tar.gz: 792ed0dd04ed391c9b644fa13e65d4282182cac3e54af1f1a4830a20d6ed30c6f6eecef0c0e8d3cbab0c02bef907065a70568fa44b346bb8d947cc02a6a5abb6
|
data/Rakefile
CHANGED
@@ -4,6 +4,10 @@
|
|
4
4
|
require 'bundler'
|
5
5
|
require 'rspec/core/rake_task'
|
6
6
|
|
7
|
+
if File.exist?('./spec/shared/lib/tasks/candidate.rake')
|
8
|
+
load 'spec/shared/lib/tasks/candidate.rake'
|
9
|
+
end
|
10
|
+
|
7
11
|
ROOT = File.expand_path(File.join(File.dirname(__FILE__)))
|
8
12
|
|
9
13
|
$: << File.join(ROOT, 'spec/shared/lib')
|
@@ -34,16 +38,12 @@ end
|
|
34
38
|
|
35
39
|
task :default => ['spec:prepare', :spec]
|
36
40
|
|
37
|
-
|
38
|
-
# gem for this project. Our release process builds the gems in a
|
39
|
-
# particular way, in a GitHub action. This task is just to help remind
|
40
|
-
# developers of that fact.
|
41
|
+
desc 'Build the gem'
|
41
42
|
task :build do
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
WARNING
|
43
|
+
command = %w[ gem build ]
|
44
|
+
command << "--output=#{ENV['GEM_FILE_NAME']}" if ENV['GEM_FILE_NAME']
|
45
|
+
command << (ENV['GEMSPEC'] || 'mongo.gemspec')
|
46
|
+
system(*command)
|
47
47
|
end
|
48
48
|
|
49
49
|
# `rake version` is used by the deployment system so get the release version
|
data/lib/mongo/socket/ssl.rb
CHANGED
@@ -23,6 +23,7 @@ module Mongo
|
|
23
23
|
# @since 2.0.0
|
24
24
|
class SSL < Socket
|
25
25
|
include OpenSSL
|
26
|
+
include Loggable
|
26
27
|
|
27
28
|
# Initializes a new TLS socket.
|
28
29
|
#
|
@@ -363,12 +364,15 @@ module Mongo
|
|
363
364
|
end
|
364
365
|
|
365
366
|
def verify_ocsp_endpoint!(socket)
|
366
|
-
unless verify_ocsp_endpoint?
|
367
|
-
return
|
368
|
-
end
|
367
|
+
return unless verify_ocsp_endpoint?
|
369
368
|
|
370
369
|
cert = socket.peer_cert
|
371
|
-
ca_cert = socket.peer_cert_chain
|
370
|
+
ca_cert = find_issuer(cert, socket.peer_cert_chain)
|
371
|
+
|
372
|
+
unless ca_cert
|
373
|
+
log_warn("TLS certificate of '#{host_name}' could not be definitively verified via OCSP: issuer certificate not found in the chain.")
|
374
|
+
return
|
375
|
+
end
|
372
376
|
|
373
377
|
verifier = OcspVerifier.new(@host_name, cert, ca_cert, context.cert_store,
|
374
378
|
**Utils.shallow_symbolize_keys(options))
|
@@ -411,6 +415,11 @@ module Mongo
|
|
411
415
|
end
|
412
416
|
end
|
413
417
|
end
|
418
|
+
|
419
|
+
# Find the issuer certificate in the chain.
|
420
|
+
def find_issuer(cert, cert_chain)
|
421
|
+
cert_chain.find { |c| c.subject == cert.issuer }
|
422
|
+
end
|
414
423
|
end
|
415
424
|
end
|
416
425
|
end
|
data/lib/mongo/version.rb
CHANGED
@@ -1,20 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Copyright (C) 2014-2020 MongoDB Inc.
|
4
|
-
#
|
5
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
-
# you may not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing, software
|
12
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
-
# See the License for the specific language governing permissions and
|
15
|
-
# limitations under the License.
|
16
|
-
|
17
3
|
module Mongo
|
18
4
|
# The current version of the driver.
|
19
|
-
|
5
|
+
#
|
6
|
+
# Note that this file is automatically updated via `rake candidate:create`.
|
7
|
+
# Manual changes to this file will be overwritten by that rake task.
|
8
|
+
VERSION = '2.20.2'
|
20
9
|
end
|
@@ -9,6 +9,21 @@ describe Mongo::Socket::OcspVerifier do
|
|
9
9
|
with_openssl_debug
|
10
10
|
retry_test sleep: 5
|
11
11
|
|
12
|
+
def self.with_ocsp_responder(port = 8100, path = '/', &setup)
|
13
|
+
around do |example|
|
14
|
+
server = WEBrick::HTTPServer.new(Port: port)
|
15
|
+
server.mount_proc path, &setup
|
16
|
+
Thread.new { server.start }
|
17
|
+
begin
|
18
|
+
example.run
|
19
|
+
ensure
|
20
|
+
server.shutdown
|
21
|
+
end
|
22
|
+
|
23
|
+
::Utils.wait_for_port_free(port, 5)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
12
27
|
shared_examples 'verifies' do
|
13
28
|
context 'mri' do
|
14
29
|
fails_on_jruby
|
@@ -173,21 +188,10 @@ describe Mongo::Socket::OcspVerifier do
|
|
173
188
|
|
174
189
|
context 'one time' do
|
175
190
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
res['locAtion'] = "http://localhost:8101#{req.path}"
|
181
|
-
res.body = "See http://localhost:8101#{req.path}"
|
182
|
-
end
|
183
|
-
Thread.new { server.start }
|
184
|
-
begin
|
185
|
-
example.run
|
186
|
-
ensure
|
187
|
-
server.shutdown
|
188
|
-
end
|
189
|
-
|
190
|
-
::Utils.wait_for_port_free(8100, 5)
|
191
|
+
with_ocsp_responder do |req, res|
|
192
|
+
res.status = 303
|
193
|
+
res['locAtion'] = "http://localhost:8101#{req.path}"
|
194
|
+
res.body = "See http://localhost:8101#{req.path}"
|
191
195
|
end
|
192
196
|
|
193
197
|
include_context 'verifier', algorithm: algorithm
|
@@ -248,21 +252,10 @@ describe Mongo::Socket::OcspVerifier do
|
|
248
252
|
port: 8101,
|
249
253
|
)
|
250
254
|
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
res['locAtion'] = req.path
|
256
|
-
res.body = "See #{req.path} indefinitely"
|
257
|
-
end
|
258
|
-
Thread.new { server.start }
|
259
|
-
begin
|
260
|
-
example.run
|
261
|
-
ensure
|
262
|
-
server.shutdown
|
263
|
-
end
|
264
|
-
|
265
|
-
::Utils.wait_for_port_free(8100, 5)
|
255
|
+
with_ocsp_responder do |req, res|
|
256
|
+
res.status = 303
|
257
|
+
res['locAtion'] = req.path
|
258
|
+
res.body = "See #{req.path} indefinitely"
|
266
259
|
end
|
267
260
|
|
268
261
|
include_context 'verifier', algorithm: algorithm
|
@@ -274,85 +267,23 @@ describe Mongo::Socket::OcspVerifier do
|
|
274
267
|
|
275
268
|
include_context 'verifier', algorithm: 'rsa'
|
276
269
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
server.mount_proc '/' do |req, res|
|
270
|
+
[400, 404, 500, 503].each do |code|
|
271
|
+
context "code #{code}" do
|
272
|
+
with_ocsp_responder do |req, res|
|
281
273
|
res.status = code
|
282
274
|
res.body = "HTTP #{code}"
|
283
275
|
end
|
284
|
-
Thread.new { server.start }
|
285
|
-
begin
|
286
|
-
example.run
|
287
|
-
ensure
|
288
|
-
server.shutdown
|
289
|
-
end
|
290
|
-
|
291
|
-
::Utils.wait_for_port_free(8100, 5)
|
292
|
-
end
|
293
|
-
|
294
|
-
[400, 404, 500, 503].each do |_code|
|
295
|
-
context "code #{_code}" do
|
296
|
-
let(:code) { _code }
|
297
|
-
include_examples 'does not verify'
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
context '204' do
|
303
|
-
around do |example|
|
304
|
-
server = WEBrick::HTTPServer.new(Port: 8100)
|
305
|
-
server.mount_proc '/' do |req, res|
|
306
|
-
res.status = 204
|
307
|
-
end
|
308
|
-
Thread.new { server.start }
|
309
|
-
begin
|
310
|
-
example.run
|
311
|
-
ensure
|
312
|
-
server.shutdown
|
313
|
-
end
|
314
276
|
|
315
|
-
::Utils.wait_for_port_free(8100, 5)
|
316
|
-
end
|
317
|
-
|
318
|
-
context "code 204" do
|
319
|
-
let(:code) { 204 }
|
320
277
|
include_examples 'does not verify'
|
321
278
|
end
|
322
279
|
end
|
323
|
-
end
|
324
|
-
|
325
|
-
context 'responder URI has no path' do
|
326
|
-
require_external_connectivity
|
327
|
-
|
328
|
-
# https://github.com/jruby/jruby-openssl/issues/210
|
329
|
-
fails_on_jruby
|
330
280
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
# Use real certificates retrieved from Atlas for this test as they don't
|
335
|
-
# have a path in the OCSP URI (which the test also asserts).
|
336
|
-
# Note that these certificates expire in 3 months and need to be replaced
|
337
|
-
# with a more permanent solution.
|
338
|
-
# Use the spec/support/certificates/retrieve-atlas-cert script to retrieve
|
339
|
-
# current certificates from Atlas.
|
340
|
-
let(:cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp.crt') }
|
341
|
-
let(:ca_cert_path) { File.join(File.dirname(__FILE__), '../support/certificates/atlas-ocsp-ca.crt') }
|
342
|
-
let(:cert_store) do
|
343
|
-
OpenSSL::X509::Store.new.tap do |store|
|
344
|
-
store.set_default_paths
|
281
|
+
context 'code 204' do
|
282
|
+
with_ocsp_responder do |req, res|
|
283
|
+
res.status = 204
|
345
284
|
end
|
346
|
-
end
|
347
|
-
|
348
|
-
before do
|
349
|
-
verifier.ocsp_uris.length.should > 0
|
350
|
-
URI.parse(verifier.ocsp_uris.first).path.should == ''
|
351
|
-
end
|
352
285
|
|
353
|
-
|
354
|
-
# TODO This test will fail if the certificate expires
|
355
|
-
expect(verifier.verify).to be(true), "If atlas-ocsp certificates have expired, run spec/support/certificates/retrieve-atlas-cert to get a new ones"
|
286
|
+
include_examples 'does not verify'
|
356
287
|
end
|
357
288
|
end
|
358
289
|
end
|
@@ -111,6 +111,10 @@ describe 'Client after reconnect' do
|
|
111
111
|
# thread.kill should've similarly failed, but it doesn't.
|
112
112
|
fails_on_jruby
|
113
113
|
|
114
|
+
# odd failures related to async on ruby <= 3.1, I suspect something
|
115
|
+
# with how fibers worked in those versions.
|
116
|
+
minimum_mri_version '3.2.0'
|
117
|
+
|
114
118
|
it 'recreates SRV monitor' do
|
115
119
|
wait_for_discovery
|
116
120
|
|
@@ -151,6 +155,10 @@ describe 'Client after reconnect' do
|
|
151
155
|
# NotImplementedError: recvmsg_nonblock is not implemented
|
152
156
|
fails_on_jruby
|
153
157
|
|
158
|
+
# odd failures related to async on ruby <= 3.1, I suspect something
|
159
|
+
# with how fibers worked in those versions.
|
160
|
+
minimum_mri_version '3.2.0'
|
161
|
+
|
154
162
|
let(:uri) do
|
155
163
|
"mongodb+srv://test-fake.test.build.10gen.cc/"
|
156
164
|
end
|
@@ -181,8 +189,6 @@ describe 'Client after reconnect' do
|
|
181
189
|
end
|
182
190
|
|
183
191
|
around do |example|
|
184
|
-
require 'support/dns'
|
185
|
-
|
186
192
|
rules = [
|
187
193
|
['_mongodb._tcp.test-fake.test.build.10gen.cc', :srv,
|
188
194
|
[0, 0, 2799, 'localhost.test.build.10gen.cc'],
|
@@ -76,9 +76,8 @@ describe 'SRV Monitoring' do
|
|
76
76
|
# NotImplementedError: recvmsg_nonblock is not implemented
|
77
77
|
fails_on_jruby
|
78
78
|
|
79
|
-
|
80
|
-
|
81
|
-
end
|
79
|
+
# mock dns implementation doesn't play nice with 2.7, etc.
|
80
|
+
minimum_mri_version '3.0.0'
|
82
81
|
|
83
82
|
around do |example|
|
84
83
|
# Speed up the tests by listening on the fake ports we are using.
|
@@ -12,10 +12,6 @@ describe 'SRV lookup' do
|
|
12
12
|
# NotImplementedError: recvmsg_nonblock is not implemented
|
13
13
|
fails_on_jruby
|
14
14
|
|
15
|
-
before(:all) do
|
16
|
-
require 'support/dns'
|
17
|
-
end
|
18
|
-
|
19
15
|
let(:uri) do
|
20
16
|
"mongodb+srv://test-fake.test.build.10gen.cc/?tls=#{SpecConfig.instance.ssl?}&tlsInsecure=true"
|
21
17
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Candidate Tasks
|
2
|
+
|
3
|
+
When using the `candidate` rake tasks, you must make sure:
|
4
|
+
|
5
|
+
1. You are using at least `git` version 2.49.0.
|
6
|
+
2. You have the `gh` CLI tool installed.
|
7
|
+
3. You are logged into `gh` with an account that has collaborator access to the repository.
|
8
|
+
4. You have run `gh repo set-default` from the root of your local checkout to set the default repository to the canonical MongoDB repo.
|
9
|
+
5. The `origin` remote for your local checkout is set to your own fork.
|
10
|
+
6. The `upstream` remote for your local checkout is set to the canonical
|
11
|
+
MongoDB repo.
|
12
|
+
|
13
|
+
Once configured, you can use the following commands:
|
14
|
+
|
15
|
+
1. `rake candidate:prs` - This will list all pull requests that will be included in the next release. Any with `[?]` are unlabelled (or are not labelled with a recognized label). Otherwise, `[b]` means `bug`, `[f]` means `feature`, and `[x]` means `bcbreak`.
|
16
|
+
2. `rake candidate:preview` - This will generate and display the release notes for the next release, based on the associated pull requests.
|
17
|
+
3. `rake candidate:create` - This will create a new PR against the default repository, using the generated release notes as the description. The new PR will be given the `release-candidate` label.
|
18
|
+
|
19
|
+
Then, after the release candidate PR is approved and merged, the release process will automatically bundle, sign, and release the new version.
|
20
|
+
|
21
|
+
Once you've merged the PR, you can switch to the "Actions" tab for the repository on GitHub and look for the "Release" workflow (might be named differently), which should have triggered automatically. You can monitor the progress of the release there. If there are any problems, the workflow is generally safe to re-run after you've addressed them.
|
22
|
+
|
23
|
+
Things to do after the release succeeds:
|
24
|
+
|
25
|
+
1. Copy the release notes from the PR and create a new release announcement on the forums (https://www.mongodb.com/community/forums/c/announcements/driver-releases/110).
|
26
|
+
2. If the release was not automatically announced in #ruby, copy a link to the GitHub release or MongoDB forum post there.
|
27
|
+
3. Close the release in Jira.
|
28
|
+
|
data/spec/shared/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2020 MongoDB, Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
desired_version, arch = ARGV
|
4
|
+
if arch.nil?
|
5
|
+
STDERR.puts "Usage: get-mongodb-download-url desired-version arch"
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
$: << File.join(File.dirname(__FILE__), '../lib')
|
10
|
+
require 'mrss/server_version_registry'
|
11
|
+
|
12
|
+
begin
|
13
|
+
puts Mrss::ServerVersionRegistry.new(desired_version, arch).download_url
|
14
|
+
rescue Mrss::ServerVersionRegistry::Error => exc
|
15
|
+
STDERR.puts "Error: #{exc}"
|
16
|
+
exit 2
|
17
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'aws-sdk-s3'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: s3-copy options"
|
9
|
+
|
10
|
+
opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
|
11
|
+
options[:region] = v
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on("-p", "--param=KEY=VALUE", "Specify parameter for new files") do |v|
|
15
|
+
options[:params] ||= {}
|
16
|
+
k, v = v.split('=', 2)
|
17
|
+
options[:params][k.to_sym] = v
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-f", "--from=BUCKET:PATH", "Bucket name and key (or path) to copy from") do |v|
|
21
|
+
options[:from] = v
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-t", "--to=BUCKET:PATH", "Bucket name and key (or path) to write to (may be specified more than once)") do |v|
|
25
|
+
options[:to] ||= []
|
26
|
+
options[:to] << v
|
27
|
+
end
|
28
|
+
end.parse!
|
29
|
+
|
30
|
+
ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
|
31
|
+
|
32
|
+
bucket, key = options.fetch(:from).split(':', 2)
|
33
|
+
|
34
|
+
s3 = Aws::S3::Client.new
|
35
|
+
|
36
|
+
options.fetch(:to).each do |dest|
|
37
|
+
STDERR.puts "Copying to #{dest}"
|
38
|
+
dbucket, dkey = dest.split(':', 2)
|
39
|
+
s3.copy_object(
|
40
|
+
bucket: dbucket,
|
41
|
+
key: dkey,
|
42
|
+
copy_source: "/#{bucket}/#{key}",
|
43
|
+
**options[:params] || {},
|
44
|
+
)
|
45
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'aws-sdk-s3'
|
5
|
+
|
6
|
+
options = {}
|
7
|
+
OptionParser.new do |opts|
|
8
|
+
opts.banner = "Usage: s3-upload options"
|
9
|
+
|
10
|
+
opts.on("-r", "--region=REGION", "AWS region to use (default us-east-1)") do |v|
|
11
|
+
options[:region] = v
|
12
|
+
end
|
13
|
+
|
14
|
+
opts.on("-p", "--param=KEY=VALUE", "Specify parameter for S3 upload") do |v|
|
15
|
+
options[:params] ||= {}
|
16
|
+
k, v = v.split('=', 2)
|
17
|
+
options[:params][k.to_sym] = v
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-f", "--file=PATH", "Path to the file to upload, - to upload standard input") do |v|
|
21
|
+
options[:file] = v
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on("-w", "--write=BUCKET:PATH", "Bucket name and key (or path) to upload to") do |v|
|
25
|
+
options[:write] = v
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on("-c", "--copy=BUCKET:PATH", "Bucket name and key (or path) to copy to (may be specified more than once)") do |v|
|
29
|
+
options[:copy] ||= []
|
30
|
+
options[:copy] << v
|
31
|
+
end
|
32
|
+
end.parse!
|
33
|
+
|
34
|
+
ENV['AWS_REGION'] ||= options[:region] || 'us-east-1'
|
35
|
+
|
36
|
+
def upload(f, options)
|
37
|
+
s3 = Aws::S3::Client.new
|
38
|
+
write = options.fetch(:write)
|
39
|
+
STDERR.puts "Writing #{write}"
|
40
|
+
bucket, key = write.split(':', 2)
|
41
|
+
s3.put_object(
|
42
|
+
body: f.read,
|
43
|
+
bucket: bucket,
|
44
|
+
key: key,
|
45
|
+
**options[:params] || {},
|
46
|
+
)
|
47
|
+
if copy = options[:copy]
|
48
|
+
copy.each do |dest|
|
49
|
+
STDERR.puts "Copying to #{dest}"
|
50
|
+
dbucket, dkey = dest.split(':', 2)
|
51
|
+
s3.copy_object(
|
52
|
+
bucket: dbucket,
|
53
|
+
key: dkey,
|
54
|
+
copy_source: "/#{bucket}/#{key}",
|
55
|
+
**options[:params] || {},
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
if options[:file] == '-'
|
62
|
+
upload(STDIN, options)
|
63
|
+
elsif options[:file]
|
64
|
+
File.open(options[:file]) do |f|
|
65
|
+
upload(f, options)
|
66
|
+
end
|
67
|
+
else
|
68
|
+
upload(STDIN, options)
|
69
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
autoload :ChildProcess, 'childprocess'
|
5
|
+
autoload :Tempfile, 'tempfile'
|
6
|
+
|
7
|
+
module Mrss
|
8
|
+
module ChildProcessHelper
|
9
|
+
class SpawnError < StandardError; end
|
10
|
+
|
11
|
+
module_function def call(cmd, env: nil, cwd: nil)
|
12
|
+
process = ChildProcess.new(*cmd)
|
13
|
+
process.io.inherit!
|
14
|
+
if cwd
|
15
|
+
process.cwd = cwd
|
16
|
+
end
|
17
|
+
if env
|
18
|
+
env.each do |k, v|
|
19
|
+
process.environment[k.to_s] = v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
process.start
|
23
|
+
process.wait
|
24
|
+
process
|
25
|
+
end
|
26
|
+
|
27
|
+
module_function def check_call(cmd, env: nil, cwd: nil)
|
28
|
+
process = call(cmd, env: env, cwd: cwd)
|
29
|
+
unless process.exit_code == 0
|
30
|
+
raise SpawnError, "Failed to execute: #{cmd}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module_function def get_output(cmd, env: nil, cwd: nil)
|
35
|
+
process = ChildProcess.new(*cmd)
|
36
|
+
process.io.inherit!
|
37
|
+
if cwd
|
38
|
+
process.cwd = cwd
|
39
|
+
end
|
40
|
+
if env
|
41
|
+
env.each do |k, v|
|
42
|
+
process.environment[k.to_s] = v
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
output = ''
|
47
|
+
r, w = IO.pipe
|
48
|
+
|
49
|
+
begin
|
50
|
+
process.io.stdout = w
|
51
|
+
process.start
|
52
|
+
w.close
|
53
|
+
|
54
|
+
thread = Thread.new do
|
55
|
+
begin
|
56
|
+
loop do
|
57
|
+
output << r.readpartial(16384)
|
58
|
+
end
|
59
|
+
rescue EOFError
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
process.wait
|
64
|
+
thread.join
|
65
|
+
ensure
|
66
|
+
r.close
|
67
|
+
end
|
68
|
+
|
69
|
+
[process, output]
|
70
|
+
end
|
71
|
+
|
72
|
+
module_function def check_output(*args)
|
73
|
+
process, output = get_output(*args)
|
74
|
+
unless process.exit_code == 0
|
75
|
+
raise SpawnError,"Failed to execute: #{args}"
|
76
|
+
end
|
77
|
+
output
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|