docker-registry-sync 0.2.11 → 0.2.12
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 +8 -8
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/lib/docker/registry/sync/cmd.rb +14 -3
- data/lib/docker/registry/sync/s3.rb +6 -12
- data/lib/docker/registry/sync/version.rb +1 -1
- data/spec/s3_spec.rb +148 -0
- data/spec/spec_helper.rb +66 -0
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MzRkMjE5NGZlODE5MTMxM2ZmMWFmNzBiMGNiZDE3OWVlNmZmMDQ4Mw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MDI5MDVmM2Q4MzM5Y2Q2M2ZlNDQyYzU1Y2M5OWMyMGFhNDEyNzcyNg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OWRmZTdhNTNlMmY1ZTIzNmIyOGIzNGJhOTE5ZDAwMzI3YTlhYWU2ZmMyMzU5
|
10
|
+
NDhlMzk5Zjc1MGFlM2VmNTdhMzk0NjEzYWQ0MWQwNGY4MTY4MjkyYzEyMDdk
|
11
|
+
ZGI4OGU5NzBhZjVlNzI0NzVmN2EzMWIzNjZmZjViMWU3ZTliZGI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MGNmMmExZjBiODk1MzI0ZWY1NjUxZGNkYzZiOGQyMGUwZTY1YjA2ZjNjYmNk
|
14
|
+
MTBmYzhmOTAzYjU5Y2E5ZWQ4NTM0NWU0ZmIyOTNhZGNkYmI4OWRjZTkyOGFj
|
15
|
+
MGVjYzM5MDk1OTIyYzdjNGM4ZDU2MDI5ZjFhZjYwZDQxMDE5ODU=
|
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -11,7 +11,9 @@ module Docker
|
|
11
11
|
include Docker::Registry::Sync
|
12
12
|
|
13
13
|
class << self
|
14
|
-
|
14
|
+
attr_accessor :config, :producer_finished, :work_queue, :status_queue, :threads
|
15
|
+
|
16
|
+
def configure(source_bucket, target_buckets, sqs_queue, use_sse, source_uses_sse, pool, log_level = :debug)
|
15
17
|
unless source_bucket.nil?
|
16
18
|
source_region, source_bucket = source_bucket.split(':')
|
17
19
|
else
|
@@ -41,6 +43,7 @@ module Docker
|
|
41
43
|
config.sqs_region = sqs_region
|
42
44
|
config.pool_size = pool
|
43
45
|
config.sqs_url = "https://#{sqs_uri}"
|
46
|
+
config.log_level = log_level
|
44
47
|
end
|
45
48
|
@config = Docker::Registry::Sync.config
|
46
49
|
end
|
@@ -66,7 +69,7 @@ module Docker
|
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
69
|
-
def
|
72
|
+
def configure_workers
|
70
73
|
@threads = Array.new(@config.pool_size)
|
71
74
|
@work_queue = Queue.new
|
72
75
|
@status_queue = Queue.new
|
@@ -75,6 +78,9 @@ module Docker
|
|
75
78
|
@threads_available = @threads.new_cond
|
76
79
|
|
77
80
|
@producer_finished = false
|
81
|
+
end
|
82
|
+
|
83
|
+
def start_workers
|
78
84
|
@consumer_thread = Thread.new do
|
79
85
|
sync_key_consumer
|
80
86
|
end
|
@@ -85,6 +91,7 @@ module Docker
|
|
85
91
|
@producer_finished = true
|
86
92
|
end
|
87
93
|
@consumer_thread.join
|
94
|
+
@consumer_thread = nil
|
88
95
|
@threads.each { |t| t.join unless t.nil? }
|
89
96
|
@config.logger.info "Processing job results..."
|
90
97
|
|
@@ -103,6 +110,7 @@ module Docker
|
|
103
110
|
|
104
111
|
def sync(image, tag)
|
105
112
|
configure_signal_handlers
|
113
|
+
configure_workers
|
106
114
|
start_workers
|
107
115
|
success = false
|
108
116
|
@config.target_buckets.each do |region, bucket, sse|
|
@@ -153,6 +161,7 @@ module Docker
|
|
153
161
|
@config.logger.info "Image sync data: #{data}"
|
154
162
|
|
155
163
|
if image_exists?(data['image'], data['target']['bucket'], data['target']['region'])
|
164
|
+
configure_workers
|
156
165
|
start_workers
|
157
166
|
@config.logger.info("Syncing tag: #{data['image']}:#{data['tag']} to #{data['target']['region']}:#{data['target']['bucket']}")
|
158
167
|
success = sync_tag(data['image'], data['tag'], data['target']['bucket'], data['target']['region'], data['target']['sse'], data['source']['bucket'], data['source']['region'])
|
@@ -165,6 +174,7 @@ module Docker
|
|
165
174
|
@config.logger.info("Falied to sync tag, leaving on queue: #{data['image']}:#{data['tag']} to #{data['target']['region']}:#{data['target']['bucket']}")
|
166
175
|
end
|
167
176
|
else
|
177
|
+
configure_workers
|
168
178
|
start_workers
|
169
179
|
success = sync_repo(data['image'], data['target']['bucket'], data['target']['region'], data['target']['sse'], data['source']['bucket'], data['source']['region'])
|
170
180
|
success &&= finalize_workers
|
@@ -179,12 +189,13 @@ module Docker
|
|
179
189
|
end
|
180
190
|
ec = 0
|
181
191
|
sleep @config.empty_queue_sleep_time unless @terminated
|
182
|
-
rescue => e
|
192
|
+
rescue StandardError => e
|
183
193
|
@config.logger.error "An unknown error occurred while monitoring queue: #{e}"
|
184
194
|
@config.logger.error e.traceback
|
185
195
|
@config.logger.error 'Exiting...'
|
186
196
|
@terminated = true
|
187
197
|
ec = 1
|
198
|
+
finalize_workers # make sure there are no hangers-on
|
188
199
|
end until @terminated
|
189
200
|
ec
|
190
201
|
end
|
@@ -34,7 +34,7 @@ module Docker
|
|
34
34
|
|
35
35
|
img_id = s3_source.get_object(bucket: source_bucket, key: "registry/repositories/#{image}/tag_#{tag}").body.read
|
36
36
|
sync_image(img_id, bucket, region, sse, source_bucket, source_region)
|
37
|
-
rescue => e
|
37
|
+
rescue StandardError => e
|
38
38
|
@config.logger.error "An unexpected error occoured while syncing tag #{image}:#{tag}: #{e}"
|
39
39
|
@config.logger.error e.backtrace
|
40
40
|
false
|
@@ -57,7 +57,7 @@ module Docker
|
|
57
57
|
JSON.load(img_index_resp.body.read).each do |image|
|
58
58
|
sync_image(image['id'], bucket, region, sse, source_bucket, source_region)
|
59
59
|
end
|
60
|
-
rescue => e
|
60
|
+
rescue StandardError => e
|
61
61
|
@config.logger.error "An unexpected error occoured while syncing repo #{repo}: #{e}"
|
62
62
|
@config.logger.error e.backtrace
|
63
63
|
false
|
@@ -114,9 +114,7 @@ module Docker
|
|
114
114
|
if @config.source_sse
|
115
115
|
opts[:copy_source_sse_customer_algorithm] = 'AES256'
|
116
116
|
end
|
117
|
-
@
|
118
|
-
@work_queue << opts
|
119
|
-
end
|
117
|
+
@work_queue << opts
|
120
118
|
sleep 0.1
|
121
119
|
end
|
122
120
|
end
|
@@ -134,9 +132,7 @@ module Docker
|
|
134
132
|
t_index = @threads.rindex { |t| t.nil? || t.status == false || t['finished'].nil? == false }
|
135
133
|
|
136
134
|
begin
|
137
|
-
opts = @
|
138
|
-
@work_queue.pop(true)
|
139
|
-
end
|
135
|
+
opts = @work_queue.pop(true)
|
140
136
|
rescue ThreadError
|
141
137
|
@config.logger.info "No work found on the queue, sleeping..."
|
142
138
|
sleep 1
|
@@ -152,14 +148,12 @@ module Docker
|
|
152
148
|
target_client.copy_object(opts)
|
153
149
|
success = true
|
154
150
|
@config.logger.info "Worker finished syncing key: #{opts[:key]}"
|
155
|
-
rescue => e
|
151
|
+
rescue StandardError => e
|
156
152
|
@config.logger.error "An unknown error occoured while copying object in s3: #{e}"
|
157
153
|
@config.logger.error e.backtrace
|
158
154
|
ensure
|
159
155
|
Thread.current['finished'] = true
|
160
|
-
@
|
161
|
-
@status_queue << success
|
162
|
-
end
|
156
|
+
@status_queue << success
|
163
157
|
end
|
164
158
|
end
|
165
159
|
else
|
data/spec/s3_spec.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'docker/registry/sync'
|
4
|
+
require 'aws-sdk'
|
5
|
+
|
6
|
+
def stub_s3_response(action, resp)
|
7
|
+
Aws.config[:s3] = { stub_responses: {} }
|
8
|
+
Aws.config[:s3][:stub_responses][action] = resp
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'Docker::Register::Sync::CMD' '#sync_tag' do
|
12
|
+
before do
|
13
|
+
Docker::Registry::Sync::CMD.configure(
|
14
|
+
'us-west-2:test-source-bucket',
|
15
|
+
'us-west-2:test-target-bucket',
|
16
|
+
'us-west-2:test-sqs-queue',
|
17
|
+
false,
|
18
|
+
false,
|
19
|
+
2,
|
20
|
+
:off
|
21
|
+
)
|
22
|
+
Docker::Registry::Sync::CMD.configure_workers
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'syncing tags' do
|
26
|
+
it 'successfully syncs' do
|
27
|
+
img_id = 'sync-successful'
|
28
|
+
stub_s3_response(:get_object, { body: img_id })
|
29
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_image).with(
|
30
|
+
img_id,
|
31
|
+
'test-target-bucket',
|
32
|
+
'us-west-2',
|
33
|
+
false,
|
34
|
+
'test-source-bucket',
|
35
|
+
'us-west-2'
|
36
|
+
)
|
37
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_keys)
|
38
|
+
res = Docker::Registry::Sync::CMD.sync_tag('sync-image', 'sync-tag', 'test-target-bucket', 'us-west-2', false)
|
39
|
+
expect(res).to be true
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'S3 API failure' do
|
43
|
+
img_id = 'sync-unsuccessful'
|
44
|
+
stub_s3_response(:get_object, RuntimeError.new('api failure'))
|
45
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_keys)
|
46
|
+
res = Docker::Registry::Sync::CMD.sync_tag('sync-image', 'sync-tag', 'test-target-bucket', 'us-west-2', false)
|
47
|
+
expect(res).to be false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'Docker::Register::Sync::CMD' '#sync_repo' do
|
53
|
+
before do
|
54
|
+
Docker::Registry::Sync::CMD.configure(
|
55
|
+
'us-west-2:test-source-bucket',
|
56
|
+
'us-west-2:test-target-bucket',
|
57
|
+
'us-west-2:test-sqs-queue',
|
58
|
+
false,
|
59
|
+
false,
|
60
|
+
2,
|
61
|
+
:off
|
62
|
+
)
|
63
|
+
Docker::Registry::Sync::CMD.configure_workers
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'syncing repositories' do
|
67
|
+
it 'successfully syncs' do
|
68
|
+
images = [{'id' => 'image-one'}, {'id' => 'image-two'}]
|
69
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_prefix)
|
70
|
+
images.each do |i|
|
71
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_image).with(i['id'],'test-target-bucket', 'us-west-2', false, 'test-source-bucket', 'us-west-2')
|
72
|
+
end
|
73
|
+
|
74
|
+
stub_s3_response(:get_object, { body: JSON.dump(images)})
|
75
|
+
res = Docker::Registry::Sync::CMD.sync_repo('sync-repo', 'test-target-bucket', 'us-west-2', false)
|
76
|
+
expect(res).to be true
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'S3 API failure' do
|
80
|
+
images = [{'id' => 'image-one'}, {'id' => 'image-two'}]
|
81
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_prefix)
|
82
|
+
images.each do |i|
|
83
|
+
allow(Docker::Registry::Sync::CMD).to receive(:sync_image).with(i['id'],'test-target-bucket', 'us-west-2', false, 'test-source-bucket', 'us-west-2')
|
84
|
+
end
|
85
|
+
|
86
|
+
stub_s3_response(:get_object, RuntimeError.new('api failure'))
|
87
|
+
res = Docker::Registry::Sync::CMD.sync_repo('sync-repo', 'test-target-bucket', 'us-west-2', false)
|
88
|
+
expect(res).to be false
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'Docker::Register::Sync::CMD' '#sync_key_consumer' do
|
94
|
+
before do
|
95
|
+
Docker::Registry::Sync::CMD.configure(
|
96
|
+
'us-west-2:test-source-bucket',
|
97
|
+
'us-west-2:test-target-bucket',
|
98
|
+
'us-west-2:test-sqs-queue',
|
99
|
+
false,
|
100
|
+
false,
|
101
|
+
1,
|
102
|
+
:off
|
103
|
+
)
|
104
|
+
Docker::Registry::Sync::CMD.configure_workers
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'runs' do
|
108
|
+
it 'successfully exits with no work and producer is finished' do
|
109
|
+
t = Thread.new do
|
110
|
+
Docker::Registry::Sync::CMD.sync_key_consumer
|
111
|
+
end
|
112
|
+
Docker::Registry::Sync::CMD.producer_finished = true
|
113
|
+
t.join
|
114
|
+
expect(Docker::Registry::Sync::CMD.work_queue.length).to be 0
|
115
|
+
expect(t.status).to be false
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'successfully exits when a child encounters an exception' do
|
119
|
+
Docker::Registry::Sync::CMD.work_queue << {
|
120
|
+
region: 'us-west-2',
|
121
|
+
key: 'exception-raiser',
|
122
|
+
bucket: 'exception-raiser',
|
123
|
+
copy_source: 'exception-raiser',
|
124
|
+
}
|
125
|
+
Docker::Registry::Sync::CMD.work_queue << {
|
126
|
+
region: 'us-west-2',
|
127
|
+
key: 'exception-raiser',
|
128
|
+
bucket: 'exception-raiser',
|
129
|
+
copy_source: 'exception-raiser',
|
130
|
+
}
|
131
|
+
Docker::Registry::Sync::CMD.producer_finished = true
|
132
|
+
stub_s3_response(:copy_object, RuntimeError.new('api failure'))
|
133
|
+
t = Thread.new do
|
134
|
+
Docker::Registry::Sync::CMD.sync_key_consumer
|
135
|
+
end
|
136
|
+
|
137
|
+
t.join
|
138
|
+
Docker::Registry::Sync::CMD.threads.each { |t| t.join }
|
139
|
+
expect(t.status).to be false
|
140
|
+
expect(Docker::Registry::Sync::CMD.threads[0].status).to be false
|
141
|
+
|
142
|
+
expect(Docker::Registry::Sync::CMD.work_queue.length).to be 0
|
143
|
+
expect(Docker::Registry::Sync::CMD.status_queue.length).to be 2
|
144
|
+
expect(Docker::Registry::Sync::CMD.status_queue.pop).to be false
|
145
|
+
expect(Docker::Registry::Sync::CMD.status_queue.pop).to be false
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause
|
4
|
+
# this file to always be loaded, without a need to explicitly require it in any
|
5
|
+
# files.
|
6
|
+
#
|
7
|
+
# Given that it is always loaded, you are encouraged to keep this file as
|
8
|
+
# light-weight as possible. Requiring heavyweight dependencies from this file
|
9
|
+
# will add to the boot time of your test suite on EVERY test run, even for an
|
10
|
+
# individual file that may not need all of that loaded. Instead, consider making
|
11
|
+
# a separate helper file that requires the additional dependencies and performs
|
12
|
+
# the additional setup, and require it from the spec files that actually need
|
13
|
+
# it.
|
14
|
+
#
|
15
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
16
|
+
# users commonly want.
|
17
|
+
#
|
18
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
19
|
+
require 'webmock/rspec'
|
20
|
+
require 'rack'
|
21
|
+
require 'simplecov'
|
22
|
+
require 'simplecov-console'
|
23
|
+
|
24
|
+
WebMock.disable_net_connect!(allow_localhost: false)
|
25
|
+
DIR = File.expand_path(File.dirname(__FILE__))
|
26
|
+
|
27
|
+
class S3ApiRack
|
28
|
+
def call(env)
|
29
|
+
code, ret = 500, 'The tests have changed, fix the rack'
|
30
|
+
[code, { 'Content-Type' => 'application/json' }, [ret]]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec.configure do |config|
|
35
|
+
config.expect_with :rspec do |expectations|
|
36
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
37
|
+
end
|
38
|
+
config.mock_with :rspec do |mocks|
|
39
|
+
mocks.verify_partial_doubles = true
|
40
|
+
end
|
41
|
+
#
|
42
|
+
config.before(:each) do
|
43
|
+
# Leaving in place to prevent accidental api calls
|
44
|
+
stub_request(:any, /127.0.0.1\//).
|
45
|
+
to_rack(S3ApiRack.new)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
51
|
+
SimpleCov::Formatter::HTMLFormatter,
|
52
|
+
SimpleCov::Formatter::Console
|
53
|
+
]
|
54
|
+
SimpleCov.minimum_coverage(80)
|
55
|
+
SimpleCov.start
|
56
|
+
|
57
|
+
def capture_stdout(&block)
|
58
|
+
original_stdout = $stdout
|
59
|
+
$stdout = fake = StringIO.new
|
60
|
+
begin
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
$stdout = original_stdout
|
64
|
+
end
|
65
|
+
#fake.string
|
66
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: docker-registry-sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Oldfield
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -132,6 +132,7 @@ extensions: []
|
|
132
132
|
extra_rdoc_files: []
|
133
133
|
files:
|
134
134
|
- .gitignore
|
135
|
+
- .rspec
|
135
136
|
- Gemfile
|
136
137
|
- README.md
|
137
138
|
- bin/docker-registry-sync
|
@@ -142,6 +143,8 @@ files:
|
|
142
143
|
- lib/docker/registry/sync/s3.rb
|
143
144
|
- lib/docker/registry/sync/sqs.rb
|
144
145
|
- lib/docker/registry/sync/version.rb
|
146
|
+
- spec/s3_spec.rb
|
147
|
+
- spec/spec_helper.rb
|
145
148
|
homepage: http://github.com/socrata-platform/docker-registry-sync
|
146
149
|
licenses:
|
147
150
|
- Apache
|
@@ -167,4 +170,6 @@ signing_key:
|
|
167
170
|
specification_version: 4
|
168
171
|
summary: Sync data between S3 two distinct docker registries using S3 data storage
|
169
172
|
and SNS as a messaging system.
|
170
|
-
test_files:
|
173
|
+
test_files:
|
174
|
+
- spec/s3_spec.rb
|
175
|
+
- spec/spec_helper.rb
|