docker-registry-sync 0.1.0

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 ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ MTUwYjg1N2FmMjBmMzYyZjQ2OTJiNDZiY2ZjMWI2ZTFiOGRiNGVjYg==
5
+ data.tar.gz: !binary |-
6
+ MzhhYWY5OTkxMmNiMDczYTU3NjBhMjI3ZTg3MWVhZmMwZDYxNmFkMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NjNlYjg4OWYwNWM4MDM3ZmJkNjY3M2M3ZDk3OGUzOTZjMWZmYzQzYjUzNDQ1
10
+ ZWNkYTk1MzMwMGYxM2IzOGQzOTEwODFhYWRmYjhlNGExMDNmZDliOTNhM2Zj
11
+ ZWU5Y2YzZGQ2MTlkMGVmZGM2MzYzNjgyOTdmY2E3OWE0OTQ3ZTA=
12
+ data.tar.gz: !binary |-
13
+ ZmYxY2NjZTUyZjNjMGI0M2FmNDExZTU4MmM1NGM5MGZlMzczNTlmMmY0NjE3
14
+ YzM1MzA1Y2M5Y2ExNTJlMjk3YTg3YWVmZmEzOTU2MmE1ZjAxNTgzYmQ1ZmZh
15
+ NjYyNDk2N2IxMzNhMWRiYjk5MjNkMGM2ZDkxYWZiODUzYTcwZDk=
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ *.gem
2
+ *.swp
3
+ bin/*
4
+ !bin/docker-registry-sync
5
+ .bundle/
6
+ coverage/
7
+ install.sh
8
+ test.rb
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/README.md ADDED
File without changes
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'docker/registry/sync'
4
+
5
+ include Docker::Registry::Sync
6
+
7
+ def verify_opts(opts, command)
8
+ source_defined = !opts[:source_bucket].nil?
9
+ dest_defined = !opts[:target_buckets].nil?
10
+ queue_defined = !opts[:sqs_queue].nil?
11
+ if command == 'sync'
12
+ source_defined && dest_defined
13
+ elsif command == 'queue-sync'
14
+ source_defined && dest_defined && queue_defined
15
+ elsif command == 'run-sync'
16
+ queue_defined
17
+ else
18
+ false
19
+ end
20
+ end
21
+
22
+ options = {}
23
+ opt_parser = OptionParser.new do |opts|
24
+ opts.banner = <<EOC
25
+ docker-registry-sync [options] sync <image>:<tag>
26
+ docker-registry-sync [options] queue-sync <image>:<tag>
27
+ docker-registry-sync [options] run-sync
28
+
29
+ Available commands:
30
+ sync -- Sync docker image from one source registry S3 bucket to one or more S3 buckets.
31
+
32
+ Options:
33
+ EOC
34
+ options[:source_bucket] = nil
35
+ opts.on('-s SOUCE', '--source-bucket SOURCE', 'Primary docker registry S3 bucket. Pass as <region>:<bucket> [required]') do |b|
36
+ options[:source_bucket] = b
37
+ end
38
+
39
+ options[:target_buckets] = nil
40
+ opts.on('-t TARGETS', '--target-buckets TARGETS', 'S3 buckets to sync to, comma separated. Pass as <region>:<bucket>[,<region>:<bucket>] [required]') do |t|
41
+ options[:target_buckets] = t
42
+ end
43
+
44
+ options[:sqs_queue] = nil
45
+ opts.on('-q SQS_QUEUE', '--queue SQS_QUEUE', 'SQS queue url used to enqueue sync job. Pass as <region>:<uri> (do not include schema) [required if using queue-sync or run-sync]') do |b|
46
+ options[:sqs_queue] = b
47
+ end
48
+
49
+ options[:unset_proxy] = false
50
+ opts.on(nil, '--unset-proxy', "Use if 'http_proxy' is set in your environment, but you don't want to use it...") do |_u|
51
+ options[:unset_proxy] = true
52
+ end
53
+ end
54
+
55
+ opt_parser.version = VERSION
56
+ opt_parser.parse!
57
+
58
+ cmd = ARGV[0]
59
+ if cmd.nil?
60
+ puts "Command must be supplied!\n\n"
61
+ puts opt_parser
62
+ exit 1
63
+ end
64
+
65
+ image = ARGV[1]
66
+ if image.nil? && !['queue-sync', 'run-sync'].include?(cmd)
67
+ puts "Image and tag to sync must be supplied!\n\n"
68
+ puts opt_parser
69
+ exit 1
70
+ end
71
+
72
+ ENV['http_proxy'] = nil if options[:unset_proxy]
73
+
74
+ unless verify_opts(options, cmd)
75
+ puts "Both '--source-bucket' and '--target-buckets' must be defined for 'sync' and 'queue-sync' commands\n"
76
+ puts "'--queue' must be defined for 'queue-sync' and 'run-sync' commands\n\n"
77
+ puts opt_parser
78
+ exit 1
79
+ end
80
+
81
+ CMD.configure(
82
+ options[:source_bucket],
83
+ options[:target_buckets],
84
+ options[:sqs_queue]
85
+ )
86
+
87
+ ec = 1
88
+
89
+ case cmd
90
+ when 'sync'
91
+ image, tag = image.split(':')
92
+ ec = CMD.sync(image, tag)
93
+ when 'queue-sync'
94
+ image, tag = image.split(':')
95
+ ec = CMD.queue_sync(image, tag)
96
+ when 'run-sync'
97
+ ec = CMD.run_sync
98
+ else
99
+ puts "Unknown command: #{cmd}"
100
+ puts opt_parser
101
+ ec = 1
102
+ end
103
+
104
+ exit(ec)
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'docker/registry/sync'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'docker-registry-sync'
8
+ spec.version = Docker::Registry::Sync::VERSION
9
+ spec.authors = ['Brian Oldfield']
10
+ spec.email = ['brian.oldfield@socrata.com']
11
+ spec.summary = 'Sync data between S3 two distinct docker registries using S3 data storage and SNS as a messaging system.'
12
+ spec.description = 'Sync data between S3 two distinct docker registries using S3 data storage and SNS as a messaging system.'
13
+ spec.homepage = 'http://github.com/socrata-platform/docker-registry-sync'
14
+ spec.license = 'Apache'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/docker-registry-sync}) { |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.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec', '~> 3.3'
24
+ spec.add_development_dependency 'simplecov', '~> 0.10'
25
+ spec.add_development_dependency 'simplecov-console', '~> 0.2'
26
+ spec.add_development_dependency 'webmock', '~> 1.21'
27
+ spec.add_development_dependency 'rack', '~> 1.6'
28
+ spec.add_dependency 'aws-sdk', '~> 2.0'
29
+ end
@@ -0,0 +1,18 @@
1
+ require 'docker/registry/sync/cmd'
2
+ require 'docker/registry/sync/configuration'
3
+ require 'docker/registry/sync/version'
4
+
5
+ module Docker
6
+ module Registry
7
+ module Sync
8
+ class << self
9
+ attr_accessor :config
10
+
11
+ def configure
12
+ self.config ||= Docker::Registry::Sync::Configuration.new
13
+ yield self.config
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,118 @@
1
+ require 'json'
2
+ require 'docker/registry/sync/s3'
3
+ require 'docker/registry/sync/sqs'
4
+
5
+ module Docker
6
+ module Registry
7
+ module Sync
8
+ module CMD
9
+ include Docker::Registry::Sync
10
+
11
+ class << self
12
+ def configure(source_bucket, target_buckets, sqs_queue)
13
+ source_region, source_bucket = source_bucket.split(':')
14
+ target_buckets = target_buckets.split(',').collect { |bucket| bucket.split(':') }
15
+ sqs_region, sqs_uri = sqs_queue.split(':')
16
+ Docker::Registry::Sync.configure do |config|
17
+ config.source_bucket = source_bucket
18
+ config.source_region = source_region
19
+ config.target_buckets = target_buckets
20
+ config.sqs_region = sqs_region
21
+ config.sqs_url = "https://#{sqs_uri}"
22
+ end
23
+ @config = Docker::Registry::Sync.config
24
+ end
25
+
26
+ def configure_signal_handlers
27
+ @terminated = false
28
+
29
+ Signal.trap('INT') do
30
+ @config.logger.error 'Received INT signal...'
31
+ @terminated = true
32
+ end
33
+ Signal.trap('TERM') do
34
+ @config.logger.error 'Received TERM signal...'
35
+ @terminated = true
36
+ end
37
+ end
38
+
39
+ def sync(image, tag)
40
+ success = false
41
+ @config.target_buckets.each do |region, bucket|
42
+ if image_exists?(image, bucket, region)
43
+ success = sync_tag(image, tag, bucket, region)
44
+ else
45
+ success = sync_image(image, bucket, region)
46
+ end
47
+ end
48
+ success ? 0 : 1
49
+ end
50
+
51
+ def queue_sync(image, tag)
52
+ msgs = @config.target_buckets.map do |region, bucket|
53
+ JSON.dump(retries: 0,
54
+ image: image,
55
+ tag: tag,
56
+ source: {
57
+ bucket: @config.source_bucket,
58
+ region: @config.source_region
59
+ },
60
+ target: {
61
+ bucket: bucket,
62
+ region: region
63
+ })
64
+ end
65
+ send_message_batch(msgs) ? 0 : 1
66
+ end
67
+
68
+ def run_sync
69
+ ec = 1
70
+ configure_signal_handlers
71
+ begin
72
+ @config.logger.info 'Polling queue for images to sync...'
73
+ sqs = Aws::SQS::Client.new(region: @config.sqs_region)
74
+ resp = sqs.receive_message(
75
+ queue_url: @config.sqs_url,
76
+ max_number_of_messages: 1,
77
+ visibility_timeout: 900, # Give ourselves 15min to sync the image
78
+ wait_time_seconds: 10, # Wait a maximum of 10s for a new message
79
+ )
80
+ @config.logger.info "SQS returned #{resp.messages.length} new images to sync..."
81
+ if resp.messages.length == 1
82
+ message = resp.messages[0]
83
+ data = JSON.load(message.body)
84
+ @config.logger.info "Image sync data: #{data}"
85
+
86
+ if image_exists?(data['image'], data['target']['bucket'], data['target']['region'])
87
+ @config.logger.info("Syncing tag: #{data['image']}:#{data['tag']} to #{data['target']['region']}:#{data['target']['bucket']}")
88
+ if sync_tag(data['image'], data['tag'], data['target']['bucket'], data['target']['region'], data['source']['bucket'], data['source']['region'])
89
+ @config.logger.info("Finished syncing tag: #{data['image']}:#{data['tag']} to #{data['target']['region']}:#{data['target']['bucket']}")
90
+ finalize_message(message.receipt_handle)
91
+ else
92
+ @config.logger.info("Falied to sync tag, leaving on queue: #{data['image']}:#{data['tag']} to #{data['target']['region']}:#{data['target']['bucket']}")
93
+ end
94
+ else
95
+ @config.logger.info("Syncing image: #{data['image']} to #{data['target']['region']}:#{data['target']['bucket']}")
96
+ if sync_image(data['image'], data['target']['bucket'], data['target']['region'], data['source']['bucket'], data['source']['region'])
97
+ @config.logger.info("Finished syncing image: #{data['image']} to #{data['target']['region']}:#{data['target']['bucket']}")
98
+ finalize_message(message.receipt_handle)
99
+ else
100
+ @config.logger.error("Failed to sync image, leaving on queue: #{data['image']} to #{data['target']['region']}:#{data['target']['bucket']}")
101
+ end
102
+ end
103
+ end
104
+ ec = 0
105
+ sleep @config.empty_queue_sleep_time unless @terminated
106
+ rescue Exception => e
107
+ @config.logger.error "An unknown error occurred while monitoring queue: #{e}"
108
+ @config.logger.error 'Exiting...'
109
+ @terminated = true
110
+ ec = 1
111
+ end until @terminated
112
+ ec
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,73 @@
1
+ module Docker
2
+ module Registry
3
+ module Sync
4
+ module STDLogLvl
5
+ class << self
6
+ def debug
7
+ 1
8
+ end
9
+
10
+ def info
11
+ 2
12
+ end
13
+
14
+ def error
15
+ 3
16
+ end
17
+
18
+ def off
19
+ 4
20
+ end
21
+ end
22
+ end
23
+
24
+ module STDLogger
25
+ class << self
26
+ def do_log?(requested_lvl, curr_lvl)
27
+ curr_lvl = Docker::Registry::Sync::STDLogLvl.send(curr_lvl.to_sym)
28
+ requested_lvl = Docker::Registry::Sync::STDLogLvl.send(requested_lvl.to_sym)
29
+ requested_lvl >= curr_lvl
30
+ end
31
+
32
+ def debug(msg)
33
+ if do_log?(:debug, Docker::Registry::Sync.config.log_level)
34
+ STDOUT.puts "[DEBUG] #{msg}"
35
+ end
36
+ end
37
+
38
+ def info(msg)
39
+ if do_log?(:info, Docker::Registry::Sync.config.log_level)
40
+ STDOUT.puts "[INFO] #{msg}"
41
+ end
42
+ end
43
+
44
+ def error(msg)
45
+ if do_log?(:error, Docker::Registry::Sync.config.log_level)
46
+ STDERR.puts "[ERROR] #{msg}"
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ class Configuration
53
+ attr_accessor :source_bucket, :source_region, :target_buckets, :sqs_region, :sqs_url, :empty_queue_sleep_time
54
+ attr_accessor :log_level, :logger
55
+
56
+ def initialize
57
+ @source_bucket = nil
58
+ @source_region = nil
59
+
60
+ @target_buckets = nil
61
+
62
+ @sqs_region = nil
63
+ @sqs_url = nil
64
+
65
+ @empty_queue_sleep_time = 5
66
+
67
+ @log_level = :debug
68
+ @logger = Docker::Registry::Sync::STDLogger
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,100 @@
1
+ require 'aws-sdk'
2
+
3
+ module Docker
4
+ module Registry
5
+ module Sync
6
+ module CMD
7
+ include Docker::Registry::Sync
8
+
9
+ class << self
10
+ def image_exists?(image, bucket, region)
11
+ s3 = Aws::S3::Client.new(region: region)
12
+ begin
13
+ s3.head_object(bucket: bucket, key: "registry/repositories/#{image}/_index_images")
14
+ rescue Aws::S3::Errors::NotFound
15
+ false
16
+ else
17
+ true
18
+ end
19
+ end
20
+
21
+ def sync_prefix(source_client, target_client, target_bucket, prefix, source_bucket = nil)
22
+ source_bucket ||= @config.source_bucket
23
+ keys = []
24
+ img_resp = source_client.list_objects(bucket: source_bucket, prefix: prefix)
25
+
26
+ loop do
27
+ img_resp.contents.each do |item|
28
+ keys << item.key
29
+ end
30
+ if img_resp.last_page?
31
+ break
32
+ else
33
+ img_resp.next_page
34
+ end
35
+ end
36
+ sync_keys(target_client, target_bucket, keys)
37
+ end
38
+
39
+ def sync_keys(target_client, target_bucket, keys, source_bucket = nil)
40
+ source_bucket ||= @config.source_bucket
41
+ keys.each do |key|
42
+ @config.logger.info "Syncing key #{source_bucket}/#{key} to bucket #{target_bucket}"
43
+ target_client.copy_object(acl: 'bucket-owner-full-control',
44
+ bucket: target_bucket,
45
+ key: key,
46
+ copy_source: "#{source_bucket}/#{key}")
47
+ end
48
+ end
49
+
50
+ def sync_tag(image, tag, bucket, region, source_bucket = nil, source_region = nil)
51
+ source_region ||= @config.source_region
52
+ source_bucket ||= @config.source_bucket
53
+
54
+ s3_source = Aws::S3::Client.new(region: source_region)
55
+ s3_target = Aws::S3::Client.new(region: region)
56
+
57
+ begin
58
+ keys = ["tag#{tag}_json", "tag_#{tag}", '_index_images'].map do |key|
59
+ "registry/repositories/#{image}/#{key}"
60
+ end
61
+ sync_keys(s3_target, bucket, keys)
62
+
63
+ img_id_resp = s3_source.get_object(bucket: source_bucket, key: "registry/repositories/#{image}/tag_#{tag}")
64
+ img_prefix = "registry/images/#{img_id_resp.body.read}/"
65
+ sync_prefix(s3_source, s3_target, bucket, img_prefix)
66
+ rescue Exception => e
67
+ @config.logger.error "An unexpected error occoured while syncing tag #{image}:#{tag}: #{e}"
68
+ false
69
+ else
70
+ true
71
+ end
72
+ end
73
+
74
+ def sync_image(image, bucket, region, source_bucket = nil, source_region = nil)
75
+ source_region ||= @config.source_region
76
+ source_bucket ||= @config.source_bucket
77
+ s3_source = Aws::S3::Client.new(region: source_region)
78
+ s3_target = Aws::S3::Client.new(region: region)
79
+
80
+ begin
81
+ rep_prefix = "registry/repositories/#{image}/"
82
+ sync_prefix(s3_source, s3_target, bucket, rep_prefix)
83
+
84
+ img_index_resp = s3_source.get_object(bucket: source_bucket, key: "registry/repositories/#{image}/_index_images")
85
+ JSON.load(img_index_resp.body.read).each do |image|
86
+ image_prefix = "registry/images/#{image['id']}/"
87
+ sync_prefix(s3_source, s3_target, bucket, image_prefix)
88
+ end
89
+ rescue Exception => e
90
+ @config.logger.error "An unexpected error occoured while syncing image #{image}: #{e}"
91
+ false
92
+ else
93
+ true
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,48 @@
1
+ require 'digest'
2
+ require 'aws-sdk'
3
+
4
+ module Docker
5
+ module Registry
6
+ module Sync
7
+ module CMD
8
+ include Docker::Registry::Sync
9
+
10
+ class << self
11
+ def send_message_batch(messages, retries = 5)
12
+ if retries <= 0
13
+ success = false
14
+ messages.each do |msg|
15
+ @config.logger.Error "Failed to Enqueue message: #{msg}"
16
+ end
17
+ else
18
+ entries = messages.map do |msg|
19
+ @config.logger.info "Enqueuing message: #{msg}"
20
+ { id: Digest::MD5.hexdigest(msg), message_body: msg }
21
+ end
22
+ sqs = Aws::SQS::Client.new(region: @config.sqs_region)
23
+ resp = sqs.send_message_batch(queue_url: @config.sqs_url,
24
+ entries: entries)
25
+ if resp.failed.length > 0
26
+ rerun = resp.failed.map do |failed|
27
+ @config.logger.warn "Failed to Enqueue message, re-enqueuing: #{msg}"
28
+ messages.select { |m| Digest::MD5.hexdigest(m) == failed.id }[0]
29
+ end
30
+ sleep 1 # short sleep before trying again...
31
+ success = send_message_batch(rerun, retries - 1)
32
+ else
33
+ success = true
34
+ end
35
+ end
36
+ success
37
+ end
38
+
39
+ def finalize_message(receipt_handle)
40
+ sqs = Aws::SQS::Client.new(region: @config.sqs_region)
41
+ resp = sqs.delete_message(queue_url: @config.sqs_url,
42
+ receipt_handle: receipt_handle)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,7 @@
1
+ module Docker
2
+ module Registry
3
+ module Sync
4
+ VERSION = '0.1.0'
5
+ end
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,170 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: docker-registry-sync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Brian Oldfield
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '0.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '0.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov-console
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '0.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '0.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: webmock
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ version: '1.21'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ version: '1.21'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rack
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '1.6'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: aws-sdk
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ description: Sync data between S3 two distinct docker registries using S3 data storage
126
+ and SNS as a messaging system.
127
+ email:
128
+ - brian.oldfield@socrata.com
129
+ executables:
130
+ - docker-registry-sync
131
+ extensions: []
132
+ extra_rdoc_files: []
133
+ files:
134
+ - .gitignore
135
+ - Gemfile
136
+ - README.md
137
+ - bin/docker-registry-sync
138
+ - docker-registry-sync.gemspec
139
+ - lib/docker/registry/sync.rb
140
+ - lib/docker/registry/sync/cmd.rb
141
+ - lib/docker/registry/sync/configuration.rb
142
+ - lib/docker/registry/sync/s3.rb
143
+ - lib/docker/registry/sync/sqs.rb
144
+ - lib/docker/registry/sync/version.rb
145
+ homepage: http://github.com/socrata-platform/docker-registry-sync
146
+ licenses:
147
+ - Apache
148
+ metadata: {}
149
+ post_install_message:
150
+ rdoc_options: []
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ required_rubygems_version: !ruby/object:Gem::Requirement
159
+ requirements:
160
+ - - ! '>='
161
+ - !ruby/object:Gem::Version
162
+ version: '0'
163
+ requirements: []
164
+ rubyforge_project:
165
+ rubygems_version: 2.4.6
166
+ signing_key:
167
+ specification_version: 4
168
+ summary: Sync data between S3 two distinct docker registries using S3 data storage
169
+ and SNS as a messaging system.
170
+ test_files: []