dockly 3.2.0.pre.1 → 4.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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- N2MzMTNlNjU1OGM5MDJmY2M5MDYxNzk2YjA0OGIyMTVhZmNlNTBkYQ==
5
- data.tar.gz: !binary |-
6
- MzRhMzcwZTNjYTRmYjFjODk3NTNjNWZjZDJiMGE3YmE2OGE4NjU2Mw==
2
+ SHA1:
3
+ metadata.gz: 0eb949e588205c02f1c15dbc3b609b7d14e3fd24
4
+ data.tar.gz: 52ab9c8916b071f0035400ced4c4fd73cf407885
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NzNmMjE0ZWE2NmI1OTcxOTNhZTY1MzU0NzhlNGRmYTQwMzc2NWNhOGYwZWRm
10
- ZDljZGI3ODZiYjdkZjI3MzM2NzAwODM1ZDEwYjU1MjIzOGQ5YzQ2OWRlMjg0
11
- MWNjNjBlMGI0M2NkYTBjNmI4ZmI1ZjZlYTcxZjBlY2I0MmViMDU=
12
- data.tar.gz: !binary |-
13
- NDQwYWNkOWViYWFmZDg3NzljNGMyM2VmNjc0NGZhOTUyMDQ0Yjc4MTlmMDRj
14
- NDQzNzVjMjEyMjBjODllMmJkOWY4ZDE4NGQ1NjIxZWMyZjQzZTUzZjg3NDU1
15
- NWVhMTRlYjg1NWVjMmQ1MDMzNDNhOTA2NDQ5MjNiZGQzYTlmNGQ=
6
+ metadata.gz: e5ec4ce34a0bc5b270451dbd717988038a4ad3344e1a2f1d497a089cf287f3da1d8d3b940291575b8d69f75a9d00df685e36a1ec2cd9134e3d651d190f32dd75
7
+ data.tar.gz: 3400f1bf912778501d3b360d75a17d22e959ad68d1a5dee63bbfe9785d73bbb9a42fac4465486f8445469dbd6fd9f99b67c38be066edfd2f2dbd860d808d4ca9
@@ -1 +1 @@
1
- 1.9.3-p547
1
+ 2.3.1
@@ -1,14 +1,13 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9
4
- - 2.0
5
- - 2.1
6
- - 2.2
3
+ - 2.0
4
+ - 2.1
5
+ - 2.2
6
+ - 2.3
7
7
  script:
8
8
  - git fetch --tags
9
9
  - CI=true bundle exec rake
10
10
  before_install:
11
11
  - sudo apt-get update -qq
12
12
  - sudo apt-get install -qq rpm
13
- - gem install bundler
14
-
13
+ - gem install bundler -v 1.17.3
data/README.md CHANGED
@@ -174,6 +174,11 @@ In addition to the above attributes, `docker` has the following references:
174
174
  - allows one
175
175
  - class: `Dockly::Docker::Registry`
176
176
  - description: a registry to push to in lieu of exporting as a tar -- the registry will be automatically pulled upon installing the package
177
+ - `ecr`
178
+ - required: `false`
179
+ - allows one
180
+ - class: `Dockly::Docker::ECR`
181
+ - description: an AWS ECR Docker registry to push to in lieu of exporting as a tar -- the registry will be automatically pulled upon installing the package
177
182
 
178
183
  Need finer control of Docker packages? We also wrote [docker-api](https://github.com/swipely/docker-api).
179
184
 
@@ -200,6 +205,23 @@ The `registry` DSL is used to define Docker Registries. It has the following att
200
205
  - default: `https://index.docker.io/v1`
201
206
  - description: the server where the registry lives
202
207
 
208
+ `ecr`
209
+ --------
210
+
211
+ The `ecr` DSL is used to define AWS ECR Docker registries. It has the following attributes:
212
+
213
+ - `server_address`
214
+ - required: `true`
215
+ - description: the server where the registry lives without the repo name, eg `accountid.dkr.ecr.region.amazonaws.com`
216
+ - `username`
217
+ - required: `false`
218
+ - default: pulled from auth data obtained using assumed role's credentials
219
+ - description: the username to authenticate
220
+ - `password`
221
+ - required: `false`
222
+ - default: pulled from auth data obtained using assumed role's credentials
223
+ - description: the password to authenticate
224
+
203
225
  `foreman`
204
226
  ---------
205
227
 
@@ -24,8 +24,9 @@ Gem::Specification.new do |gem|
24
24
  gem.add_dependency 'minigit', '~> 0.0.4'
25
25
  gem.add_development_dependency 'cane'
26
26
  gem.add_development_dependency 'pry'
27
- gem.add_development_dependency 'rake'
27
+ gem.add_development_dependency 'rake', '< 11.0'
28
28
  gem.add_development_dependency 'rspec', '~> 2.14.1'
29
29
  gem.add_development_dependency 'vcr'
30
- gem.add_development_dependency 'webmock'
30
+ gem.add_development_dependency 'webmock', '<= 1.18.0'
31
+ gem.add_development_dependency 'addressable', '<= 2.3.6'
31
32
  end
@@ -24,7 +24,8 @@ module Dockly
24
24
  generate_snippet_for :s3_docker_import, [:s3_url, :repo, :tag]
25
25
  generate_snippet_for :s3_diff_docker_import, [:base_image, :diff_image, :repo, :tag]
26
26
  generate_snippet_for :registry_import, [:repo, :tag], { :tag => "latest" }
27
+ generate_snippet_for :auth_ecr, [:server_address]
27
28
 
28
- generate_snippet_for :docker_tag_latest, [:repo, :tag]
29
+ generate_snippet_for :docker_tag_latest, [:repo, :tag, :new_name]
29
30
  end
30
31
  end
@@ -89,11 +89,17 @@ class Dockly::BuildCache::Base
89
89
 
90
90
  def push_to_s3(file)
91
91
  ensure_present! :s3_bucket, :s3_object_prefix
92
- connection.put_object(bucket: s3_bucket, key: s3_object(hash_output), body: file)
92
+ connection.put_object(
93
+ bucket: s3_bucket,
94
+ key: s3_object(hash_output),
95
+ body: file,
96
+ acl: 'bucket-owner-full-control',
97
+ )
93
98
  connection.copy_object(
94
99
  copy_source: [s3_bucket, s3_object(hash_output)].join('/'),
95
100
  bucket: s3_bucket,
96
- key: s3_object('latest')
101
+ key: s3_object('latest'),
102
+ acl: 'bucket-owner-full-control',
97
103
  )
98
104
  end
99
105
 
@@ -77,7 +77,7 @@ class Dockly::BuildCache::Docker < Dockly::BuildCache::Base
77
77
  debug 'Restarting the container to copy the cache\'s output'
78
78
  # Restart the container so we can copy its output
79
79
  container = container.commit.run('sleep 3600')
80
- container.copy(output_directory) { |chunk| file.write(chunk.to_s) }
80
+ container.archive_out(output_directory) { |chunk| file.write(chunk.to_s) }
81
81
  container.kill
82
82
  file.tap(&:rewind)
83
83
  end
@@ -55,7 +55,8 @@ class Dockly::Deb
55
55
  Dockly.s3.copy_object(
56
56
  copy_source: File.join(s3_bucket, object),
57
57
  bucket: s3_bucket,
58
- key: s3_object_name
58
+ key: s3_object_name,
59
+ acl: 'bucket-owner-full-control',
59
60
  )
60
61
  info "Successfully copied s3://#{s3_bucket}/#{object} to s3://#{s3_bucket}/#{s3_object_name}"
61
62
  end
@@ -76,12 +77,16 @@ class Dockly::Deb
76
77
  end
77
78
 
78
79
  def upload_to_s3
79
- info "uploading to s3"
80
80
  return if s3_bucket.nil?
81
81
  raise "Package wasn't created!" unless File.exist?(build_path)
82
82
  info "uploading package to s3"
83
83
  File.open(build_path, 'rb') do |file|
84
- Dockly.s3.put_object(bucket: s3_bucket, key: s3_object_name, body: file)
84
+ Dockly.s3.put_object(
85
+ bucket: s3_bucket,
86
+ key: s3_object_name,
87
+ body: file,
88
+ acl: 'bucket-owner-full-control',
89
+ )
85
90
  end
86
91
  end
87
92
 
@@ -120,7 +125,14 @@ private
120
125
  add_files(@dir_package)
121
126
  add_docker_auth_config(@dir_package)
122
127
  add_docker(@dir_package)
123
- add_startup_script(@dir_package) if package_startup_script
128
+
129
+ if package_startup_script.is_a?(String)
130
+ raise ArgumentError,
131
+ 'package_startup_script filename must not be empty if specified' if package_startup_script.empty?
132
+ add_startup_script(@dir_package, package_startup_script)
133
+ elsif package_startup_script
134
+ add_startup_script(@dir_package)
135
+ end
124
136
 
125
137
  convert_package
126
138
 
@@ -168,7 +180,7 @@ private
168
180
  end
169
181
 
170
182
  def add_docker_auth_config(package)
171
- return if (registry = get_registry).nil? || !registry.authentication_required?
183
+ return if (registry = get_registry).nil? || !should_auth?(registry)
172
184
  info "adding docker config file"
173
185
  registry.generate_config_file!
174
186
 
@@ -179,11 +191,18 @@ private
179
191
  package.attributes[:prefix] = nil
180
192
  end
181
193
 
194
+ def should_auth?(registry)
195
+ registry.is_a?(Dockly::Docker::Registry) &&
196
+ registry.authentication_required?
197
+ end
198
+
182
199
  def add_docker(package)
183
200
  return if docker.nil? || docker.s3_bucket
184
201
  info "adding docker image"
185
202
  docker.generate!
186
- return unless docker.registry.nil?
203
+
204
+ return if get_registry
205
+
187
206
  package.attributes[:prefix] = docker.package_dir
188
207
  Dir.chdir(File.dirname(docker.tar_path)) do
189
208
  package.input(File.basename(docker.tar_path))
@@ -192,7 +211,7 @@ private
192
211
  end
193
212
 
194
213
  def get_registry
195
- if docker && registry = docker.registry
214
+ if docker && (registry = docker.registry)
196
215
  registry
197
216
  end
198
217
  end
@@ -201,38 +220,53 @@ private
201
220
  scripts = ["#!/bin/bash"]
202
221
  bb = Dockly::BashBuilder.new
203
222
  scripts << bb.normalize_for_dockly
204
- if get_registry
205
- scripts << bb.registry_import(docker.repo, docker.tag)
206
- elsif docker
207
- if docker.s3_bucket.nil?
208
- docker_output = File.join(docker.package_dir, docker.export_filename)
209
- if docker.tar_diff
210
- scripts << bb.file_diff_docker_import(docker.import, docker_output, docker.name, docker.tag)
211
- else
212
- scripts << bb.file_docker_import(docker_output, docker.name, docker.tag)
223
+
224
+ if docker
225
+ if (registry = docker.registry)
226
+ if registry.is_a?(Dockly::Docker::ECR)
227
+ scripts << bb.auth_ecr(registry.server_address)
213
228
  end
229
+
230
+ scripts << bb.registry_import(docker.repo, docker.tag)
231
+ scripts << bb.docker_tag_latest(docker.repo, docker.tag, docker.name)
214
232
  else
215
- if docker.tar_diff
216
- scripts << bb.s3_diff_docker_import(docker.import, docker.s3_url, docker.name, docker.tag)
217
- else
218
- scripts << bb.s3_docker_import(docker.s3_url, docker.name, docker.tag)
219
- end
233
+ scripts += collect_non_registry_scripts(bb)
220
234
  end
221
- scripts << bb.docker_tag_latest(docker.repo, docker.tag)
222
235
  end
223
236
  scripts.join("\n")
224
237
  end
225
238
 
226
- def add_startup_script(package)
239
+ def collect_non_registry_scripts(bb)
240
+ scripts = []
241
+
242
+ if docker.s3_bucket.nil?
243
+ docker_output = File.join(docker.package_dir, docker.export_filename)
244
+ if docker.tar_diff
245
+ scripts << bb.file_diff_docker_import(docker.import, docker_output, docker.name, docker.tag)
246
+ else
247
+ scripts << bb.file_docker_import(docker_output, docker.name, docker.tag)
248
+ end
249
+ else
250
+ if docker.tar_diff
251
+ scripts << bb.s3_diff_docker_import(docker.import, docker.s3_url, docker.name, docker.tag)
252
+ else
253
+ scripts << bb.s3_docker_import(docker.s3_url, docker.name, docker.tag)
254
+ end
255
+ end
256
+
257
+ scripts << bb.docker_tag_latest(docker.repo, docker.tag, docker.repo)
258
+ end
259
+
260
+ def add_startup_script(package, startup_script = "dockly-startup.sh")
227
261
  ensure_present! :build_dir
228
- startup_script_path = File.join(build_dir, "dockly-startup.sh")
262
+ startup_script_path = File.join(build_dir, startup_script)
229
263
  File.open(startup_script_path, 'w+') do |f|
230
264
  f.write(post_startup_script)
231
265
  f.chmod(0755)
232
266
  end
233
267
  package.attributes[:prefix] = "/opt/dockly"
234
268
  Dir.chdir(build_dir) do
235
- package.input("dockly-startup.sh")
269
+ package.input(startup_script)
236
270
  end
237
271
  package.attributes[:prefix] = nil
238
272
  end
@@ -10,11 +10,13 @@ class Dockly::Docker
10
10
  include Dockly::Util::Logger::Mixin
11
11
 
12
12
  autoload :Registry, 'dockly/docker/registry'
13
+ autoload :ECR, 'dockly/docker/ecr'
13
14
 
14
15
  logger_prefix '[dockly docker]'
15
16
 
16
17
  dsl_class_attribute :build_cache, Dockly::BuildCache.model, type: Array
17
- dsl_class_attribute :registry, Dockly::Docker::Registry
18
+ dsl_class_attribute :docker_registry, Dockly::Docker::Registry
19
+ dsl_class_attribute :ecr, Dockly::Docker::ECR
18
20
 
19
21
  dsl_attribute :name, :import, :git_archive, :build, :tag, :build_dir, :package_dir,
20
22
  :timeout, :cleanup_images, :tar_diff, :s3_bucket, :s3_object_prefix
@@ -32,6 +34,10 @@ class Dockly::Docker
32
34
  (@build_env ||= {}).tap { |env| env.merge!(hash) if hash.is_a?(Hash) }
33
35
  end
34
36
 
37
+ def registry
38
+ ecr || docker_registry
39
+ end
40
+
35
41
  def copy_from_s3(sha)
36
42
  return if s3_bucket.nil?
37
43
  object = s3_object_for(sha)
@@ -39,7 +45,8 @@ class Dockly::Docker
39
45
  Dockly.s3.copy_object(
40
46
  copy_source: File.join(s3_bucket, object),
41
47
  bucket: s3_bucket,
42
- key: s3_object
48
+ key: s3_object,
49
+ acl: 'bucket-owner-full-control',
43
50
  )
44
51
  info "Successfully copied s3://#{s3_bucket}/#{object} to s3://#{s3_bucket}/#{s3_object}"
45
52
  end
@@ -176,7 +183,9 @@ class Dockly::Docker
176
183
  repo = "#{name}-base"
177
184
  tag = "dockly-#{Dockly::VERSION}-#{File.basename(import).split('.').first}"
178
185
  info "looking for imported base image with tag: #{tag}"
179
- image = Docker::Image.all.find { |img| img.info['RepoTags'].include?("#{repo}:#{tag}") }
186
+ image = Docker::Image.all.find do |img|
187
+ img.info['RepoTags'] && img.info['RepoTags'].include?("#{repo}:#{tag}")
188
+ end
180
189
  if image
181
190
  info "found imported base image: #{image.id}"
182
191
  image
@@ -315,14 +324,26 @@ class Dockly::Docker
315
324
  end
316
325
 
317
326
  def push_to_registry(image)
318
- ensure_present! :registry
327
+ raise "No registry to push to" if registry.nil?
328
+
319
329
  info "Exporting #{image.id} to Docker registry at #{registry.server_address}"
330
+
320
331
  registry.authenticate!
321
- image = Docker::Image.all(:all => true).find { |img|
322
- img.id.start_with?(image.id) || image.id.start_with?(img.id)
323
- }
332
+
333
+ image =
334
+ Docker::Image
335
+ .all(:all => true)
336
+ .find do |img|
337
+ img.id.include?(image.id) || image.id.include?(img.id)
338
+ end
339
+
324
340
  raise "Could not find image after authentication" if image.nil?
325
- image.push(registry.to_h, :registry => registry.server_address)
341
+
342
+ image.push(registry.to_h, :registry => registry.server_address) do |resp|
343
+ if resp.include?('errorDetail')
344
+ raise "Error pushing to registry: #{resp}"
345
+ end
346
+ end
326
347
  end
327
348
 
328
349
  def fetch_import
@@ -0,0 +1,60 @@
1
+ class Dockly::Docker::ECR
2
+ include Dockly::Util::DSL
3
+ include Dockly::Util::Logger::Mixin
4
+
5
+ logger_prefix '[dockly docker ecr]'
6
+
7
+ dsl_attribute :name, :server_address, :password, :username
8
+
9
+ def authenticate!
10
+ @username ||= login_from_aws[0]
11
+ @password ||= login_from_aws[1]
12
+
13
+ ensure_present! :password, :server_address, :username
14
+
15
+ debug "Attempting to authenticate at #{server_address}"
16
+
17
+ ::Docker.authenticate!(self.to_h)
18
+
19
+ info "Successfully authenticated at #{server_address}"
20
+ rescue ::Docker::Error::AuthenticationError
21
+ raise "Could not authenticate at #{server_address}"
22
+ end
23
+
24
+ def authentication_required?
25
+ true
26
+ end
27
+
28
+ def default_server_address?
29
+ false
30
+ end
31
+
32
+ def login_from_aws
33
+ @login_from_aws ||=
34
+ Base64
35
+ .decode64(auth_data.authorization_token)
36
+ .split(':')
37
+ end
38
+
39
+ def auth_data
40
+ @auth_data ||=
41
+ client
42
+ .get_authorization_token
43
+ .authorization_data
44
+ .first
45
+ end
46
+
47
+ def client
48
+ @client ||= Aws::ECR::Client.new(region: 'us-east-1')
49
+ end
50
+
51
+ def to_h
52
+ ensure_present! :username, :password, :server_address
53
+
54
+ {
55
+ 'serveraddress' => "https://#{server_address}",
56
+ 'username' => username,
57
+ 'password' => password
58
+ }
59
+ end
60
+ end
@@ -72,8 +72,11 @@ module Dockly
72
72
  end
73
73
 
74
74
  def multipart_upload
75
- @multipart_upload ||=
76
- connection.create_multipart_upload(bucket: s3_bucket, key: s3_object)
75
+ @multipart_upload ||= connection.create_multipart_upload(
76
+ bucket: s3_bucket,
77
+ key: s3_object,
78
+ acl: 'bucket-owner-full-control',
79
+ )
77
80
  end
78
81
  end
79
82
  end
@@ -1,8 +1,8 @@
1
1
  module Dockly
2
- MAJOR = 3
3
- MINOR = 2
2
+ MAJOR = 4
3
+ MINOR = 1
4
4
  PATCH = 0
5
- RELEASE = 'pre.1'
5
+ RELEASE = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, PATCH, RELEASE].compact.join('.')
8
8
  end
@@ -0,0 +1,11 @@
1
+ auth_ecr() {
2
+ $(aws ecr get-login --region us-east-1 --no-include-email)
3
+ }
4
+
5
+ worked=1
6
+ for attempt in {1..10}; do
7
+ [[ $worked != 0 ]] || break
8
+ auth_ecr && worked=0 || (log "ecr auth: attempt $attempt failed, sleeping 30"; sleep 30)
9
+ done
10
+ [[ $worked != 0 ]] && fatal "failed to auth to ecr"
11
+ log "ecr auth: successfully authenticated"
@@ -1,3 +1,3 @@
1
1
  <% if data[:tag] %>
2
- docker tag <%= data[:repo] %>:<%= data[:tag] %> <%= data[:repo] %>:latest
2
+ docker tag <%= data[:repo] %>:<%= data[:tag] %> <%= data[:new_name] %>:latest
3
3
  <% end %>
@@ -32,8 +32,8 @@ describe Dockly::BashBuilder do
32
32
 
33
33
  context "when there is a tag" do
34
34
  it "tags the repo:tag as repo:latest" do
35
- output = subject.docker_tag_latest("test_repo", "a_tag")
36
- expect(output).to include("docker tag test_repo:a_tag test_repo:latest")
35
+ output = subject.docker_tag_latest("registry/test_repo", "a_tag", "test_repo")
36
+ expect(output).to include("docker tag registry/test_repo:a_tag test_repo:latest")
37
37
  end
38
38
  end
39
39
  end
@@ -156,7 +156,7 @@ describe Dockly::BuildCache::Docker, :docker do
156
156
  context "when parameter command returns successfully" do
157
157
  let(:command) { "uname -r" }
158
158
  it 'returns the output of the parameter_command' do
159
- expect(build_cache.parameter_output(command)).to match(/\A3\.\d{2}\.\d-\d{1,2}-\w+\Z/)
159
+ expect(build_cache.parameter_output(command)).to match(/\A\d.\d.\d+-\w+-\w+\z/)
160
160
  end
161
161
  end
162
162
 
@@ -175,6 +175,25 @@ describe Dockly::Deb do
175
175
  expect(`dpkg --contents #{filename}`).to_not include("dockly-startup.sh")
176
176
  end
177
177
  end
178
+
179
+ context 'when package_startup_script is a string' do
180
+ context 'when the string is empty' do
181
+ before { subject.package_startup_script('') }
182
+
183
+ it 'does not place a startup script with the provided name in the package' do
184
+ expect{subject.create_package!}.to raise_error(ArgumentError)
185
+ end
186
+ end
187
+
188
+ context 'when the string is not empty' do
189
+ before { subject.package_startup_script('special-startup.sh') }
190
+
191
+ it 'places a startup script with the provided name in the package' do
192
+ subject.create_package!
193
+ expect(`dpkg --contents #{filename}`).to include("special-startup.sh")
194
+ end
195
+ end
196
+ end
178
197
  end
179
198
 
180
199
  describe '#exists?' do
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dockly::Docker::ECR do
4
+ subject do
5
+ described_class.new(name: 'ecr', server_address: registry)
6
+ end
7
+
8
+ let(:username) { 'AWS' }
9
+ let(:password) { 'password' }
10
+ let(:registry) { 'accountid.dkr.ecr.region.amazonaws.com' }
11
+ let(:endpoint) { "https://#{registry}" }
12
+ let(:ecr_client) { Aws::ECR::Client.new(stub_responses: true) }
13
+
14
+ after do
15
+ Aws.config[:ecr] = { stub_responses: {} }
16
+ end
17
+
18
+ describe '#authenticate!' do
19
+ context 'when AWS provides a username and password for ECR' do
20
+ before do
21
+ Aws.config[:ecr] = {
22
+ stub_responses: {
23
+ get_authorization_token: {
24
+ authorization_data: [
25
+ {
26
+ authorization_token: Base64.encode64("#{username}:#{password}"),
27
+ proxy_endpoint: endpoint
28
+ }
29
+ ]
30
+ }
31
+ }
32
+ }
33
+ end
34
+
35
+ context 'and docker auth succeeds' do
36
+ before do
37
+ allow(::Docker)
38
+ .to receive(:authenticate!)
39
+ .with({
40
+ 'serveraddress' => endpoint,
41
+ 'username' => username,
42
+ 'password' => password
43
+ })
44
+ end
45
+
46
+ it 'does not error' do
47
+ expect { subject.authenticate! }.to_not raise_error
48
+ end
49
+ end
50
+
51
+ context 'and docker auth raises and error' do
52
+ before do
53
+ allow(::Docker)
54
+ .to receive(:authenticate!)
55
+ .and_raise(::Docker::Error::AuthenticationError)
56
+ end
57
+
58
+ it 'raises' do
59
+ expect { subject.authenticate! }
60
+ .to raise_error(/Could not authenticate/)
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'when it is unable to get auth from AWS' do
67
+ before do
68
+ Aws.config[:ecr] = {
69
+ stub_responses: {
70
+ get_authorization_token: ->(_context) { raise 'Unable to get token' }
71
+ }
72
+ }
73
+ end
74
+
75
+ it 'raises' do
76
+ expect(::Docker).not_to receive(:authenticate!)
77
+ expect { subject.authenticate! }.to raise_error
78
+ end
79
+ end
80
+ end
@@ -3,6 +3,76 @@ require 'spec_helper'
3
3
  describe Dockly::Docker do
4
4
  subject { described_class.new(:name => :test_docker) }
5
5
 
6
+ describe '#registry' do
7
+ context 'when there is no registry' do
8
+ it 'returns nil' do
9
+ expect(subject.registry).to eq(nil)
10
+ end
11
+ end
12
+
13
+ context 'when there is only an ecr registry' do
14
+ subject do
15
+ Dockly::Docker.new do
16
+ ecr { server_address 'accountid.dkr.ecr.region.amazonaws.com' }
17
+ end
18
+ end
19
+
20
+ it 'returns an ecr registry' do
21
+ registry = subject.registry
22
+
23
+ expect(registry).not_to eq(nil)
24
+ expect(registry).to be_a(Dockly::Docker::ECR)
25
+ expect(registry.server_address)
26
+ .to eq('accountid.dkr.ecr.region.amazonaws.com')
27
+ end
28
+ end
29
+
30
+ context 'when there is a docker registry' do
31
+ context 'and an ecr registry' do
32
+ subject do
33
+ Dockly::Docker.new do
34
+ registry do
35
+ username ENV['DOCKER_USER']
36
+ email ENV['DOCKER_EMAIL']
37
+ password ENV['DOCKER_PASS']
38
+ end
39
+
40
+ ecr { server_address 'accountid.dkr.ecr.region.amazonaws.com' }
41
+ end
42
+ end
43
+
44
+ it 'prefers the ecr registry' do
45
+ registry = subject.registry
46
+
47
+ expect(registry).not_to eq(nil)
48
+ expect(registry).to be_a(Dockly::Docker::ECR)
49
+ expect(registry.server_address)
50
+ .to eq('accountid.dkr.ecr.region.amazonaws.com')
51
+ end
52
+ end
53
+
54
+ context 'and only a docker registry' do
55
+ subject do
56
+ Dockly::Docker.new do
57
+ registry do
58
+ username ENV['DOCKER_USER']
59
+ email ENV['DOCKER_EMAIL']
60
+ password ENV['DOCKER_PASS']
61
+ end
62
+ end
63
+
64
+ it 'returns the docker registry' do
65
+ registry = subject.registry
66
+
67
+ expect(registry).not_to eq(nil)
68
+ expect(registry).to be_a(Dockly::Docker::Registry)
69
+ expect(registry.username).to eq(ENV['DOCKER_USER'])
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+
6
76
  describe '#ensure_tar' do
7
77
  let(:action) { subject.ensure_tar(file) }
8
78
 
@@ -147,7 +217,7 @@ describe Dockly::Docker do
147
217
  end
148
218
 
149
219
  context 'and it points to a non-S3 url' do
150
- let(:url) { 'http://www.html5zombo.com' }
220
+ let(:url) { 'http://html5zombo.com' }
151
221
 
152
222
  before { subject.tag 'yolo' }
153
223
 
@@ -172,7 +242,7 @@ describe Dockly::Docker do
172
242
  context "with a registry export" do
173
243
  let(:registry) { double(:registry) }
174
244
  before do
175
- subject.instance_variable_set(:"@registry", registry)
245
+ subject.instance_variable_set(:"@docker_registry", registry)
176
246
  expect(subject).to receive(:push_to_registry)
177
247
  end
178
248
 
@@ -243,6 +313,107 @@ describe Dockly::Docker do
243
313
  end
244
314
  end
245
315
 
316
+ describe '#push_to_registry', :docker do
317
+ let(:image) { Docker::Image.create('fromImage' => 'ubuntu:14.04') }
318
+ let(:ecr) { double(:ecr) }
319
+
320
+ context 'when there is no registry' do
321
+ it 'raises' do
322
+ expect(subject.registry).to eq(nil)
323
+
324
+ expect { subject.push_to_registry(image) }.to raise_error(/No registry/)
325
+ end
326
+ end
327
+
328
+ context 'when there is a registry' do
329
+ before do
330
+ subject.instance_variable_set(:"@ecr", ecr)
331
+
332
+ allow(ecr)
333
+ .to receive(:server_address)
334
+ .and_return('server_address')
335
+
336
+ expect(subject.registry).to eq(ecr)
337
+ end
338
+
339
+ context "that can't be authenticated to" do
340
+ before do
341
+ allow(ecr)
342
+ .to receive(:authenticate!)
343
+ .and_raise
344
+ end
345
+
346
+ it 'raises' do
347
+ expect { subject.push_to_registry(image) }
348
+ .to raise_error(StandardError)
349
+ end
350
+ end
351
+
352
+ context 'that can be authenticated to' do
353
+ before do
354
+ allow(ecr).to receive(:authenticate!)
355
+
356
+ allow(Docker::Image)
357
+ .to receive(:all)
358
+ .with(all: true)
359
+ .and_return(available_images)
360
+ end
361
+
362
+ context "but the image isn't found" do
363
+ let(:available_images) { [] }
364
+
365
+ it 'raises' do
366
+ expect { subject.push_to_registry(image) }
367
+ .to raise_error(/Could not find image after authentication/)
368
+ end
369
+ end
370
+
371
+ context 'and the image is found' do
372
+ let(:available_images) { [image] }
373
+
374
+ before do
375
+ allow(ecr)
376
+ .to receive(:to_h)
377
+ .and_return({})
378
+ allow(image)
379
+ .to receive(:push)
380
+ .and_yield(push_message)
381
+ end
382
+
383
+ context 'but the push to the registry fails' do
384
+ let(:push_message) do
385
+ <<-EOF
386
+ {"errorDetail":{"message":"name unknown: The repository with name 'repository'
387
+ does not exist in the registry with id 'accoundid'"},"error":"name unknown:
388
+ The repository with name 'repository' does not exist in the registry with id 'accountid'"}
389
+ EOF
390
+ end
391
+
392
+ it 'raises' do
393
+ expect { subject.push_to_registry(image) }
394
+ .to raise_error(/Error pushing to registry/)
395
+ end
396
+ end
397
+
398
+ context 'and the push to the registry succeeds' do
399
+ let(:push_message) do
400
+ <<-EOF
401
+ {"status":"Pushed","progressDetail":{},"id":"id"}
402
+ {"status":"sha: digest: digest size: 2048"}
403
+ {"progressDetail":{},"aux":{"Tag":"sha","Digest":"digest","Size":2048}}
404
+ EOF
405
+ end
406
+
407
+ it 'passes' do
408
+ expect(subject.push_to_registry(image))
409
+ .not_to raise_error
410
+ end
411
+ end
412
+ end
413
+ end
414
+ end
415
+ end
416
+
246
417
  describe '#export_image_diff', :docker do
247
418
  let(:images) { [] }
248
419
  let(:output) { StringIO.new }
@@ -29,9 +29,9 @@ describe Dockly::Foreman do
29
29
  subject.create!
30
30
  File.exist?('build/foreman/foreman.target').should be_true
31
31
  File.exist?('build/foreman/foreman-web.target').should be_true
32
- File.exist?('build/foreman/foreman-web-1.service').should be_true
33
- File.read('build/foreman/foreman-web-1.service')
34
- .lines.grep(/^ExecStart=\/bin\/bash -lc '\/bin\/sh start_my_server'$/)
32
+ File.exist?('build/foreman/foreman-web@.service').should be_true
33
+ File.open('build/foreman/foreman-web@.service')
34
+ .grep(/^ExecStart=\/bin\/bash -lc 'exec \/bin\/sh start_my_server'$/)
35
35
  .length.should == 1
36
36
  end
37
37
  end
metadata CHANGED
@@ -1,217 +1,231 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockly
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.0.pre.1
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Swipely, Inc.
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-29 00:00:00.000000000 Z
11
+ date: 2021-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clamp
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: docker-api
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ! '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: 1.14.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ! '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: 1.14.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: dockly-util
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.0.9
48
- - - <
48
+ - - "<"
49
49
  - !ruby/object:Gem::Version
50
50
  version: '1.0'
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - ! '>='
55
+ - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: 0.0.9
58
- - - <
58
+ - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '1.0'
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: excon
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - ! '>='
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  type: :runtime
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ! '>='
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: aws-sdk
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ~>
79
+ - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '2.0'
82
82
  type: :runtime
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - ~>
86
+ - - "~>"
87
87
  - !ruby/object:Gem::Version
88
88
  version: '2.0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: foreman
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ! '>='
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  type: :runtime
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ! '>='
100
+ - - ">="
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: fpm
105
105
  requirement: !ruby/object:Gem::Requirement
106
106
  requirements:
107
- - - ~>
107
+ - - "~>"
108
108
  - !ruby/object:Gem::Version
109
109
  version: 1.2.0
110
110
  type: :runtime
111
111
  prerelease: false
112
112
  version_requirements: !ruby/object:Gem::Requirement
113
113
  requirements:
114
- - - ~>
114
+ - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: 1.2.0
117
117
  - !ruby/object:Gem::Dependency
118
118
  name: minigit
119
119
  requirement: !ruby/object:Gem::Requirement
120
120
  requirements:
121
- - - ~>
121
+ - - "~>"
122
122
  - !ruby/object:Gem::Version
123
123
  version: 0.0.4
124
124
  type: :runtime
125
125
  prerelease: false
126
126
  version_requirements: !ruby/object:Gem::Requirement
127
127
  requirements:
128
- - - ~>
128
+ - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: 0.0.4
131
131
  - !ruby/object:Gem::Dependency
132
132
  name: cane
133
133
  requirement: !ruby/object:Gem::Requirement
134
134
  requirements:
135
- - - ! '>='
135
+ - - ">="
136
136
  - !ruby/object:Gem::Version
137
137
  version: '0'
138
138
  type: :development
139
139
  prerelease: false
140
140
  version_requirements: !ruby/object:Gem::Requirement
141
141
  requirements:
142
- - - ! '>='
142
+ - - ">="
143
143
  - !ruby/object:Gem::Version
144
144
  version: '0'
145
145
  - !ruby/object:Gem::Dependency
146
146
  name: pry
147
147
  requirement: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - ! '>='
149
+ - - ">="
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0'
152
152
  type: :development
153
153
  prerelease: false
154
154
  version_requirements: !ruby/object:Gem::Requirement
155
155
  requirements:
156
- - - ! '>='
156
+ - - ">="
157
157
  - !ruby/object:Gem::Version
158
158
  version: '0'
159
159
  - !ruby/object:Gem::Dependency
160
160
  name: rake
161
161
  requirement: !ruby/object:Gem::Requirement
162
162
  requirements:
163
- - - ! '>='
163
+ - - "<"
164
164
  - !ruby/object:Gem::Version
165
- version: '0'
165
+ version: '11.0'
166
166
  type: :development
167
167
  prerelease: false
168
168
  version_requirements: !ruby/object:Gem::Requirement
169
169
  requirements:
170
- - - ! '>='
170
+ - - "<"
171
171
  - !ruby/object:Gem::Version
172
- version: '0'
172
+ version: '11.0'
173
173
  - !ruby/object:Gem::Dependency
174
174
  name: rspec
175
175
  requirement: !ruby/object:Gem::Requirement
176
176
  requirements:
177
- - - ~>
177
+ - - "~>"
178
178
  - !ruby/object:Gem::Version
179
179
  version: 2.14.1
180
180
  type: :development
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
- - - ~>
184
+ - - "~>"
185
185
  - !ruby/object:Gem::Version
186
186
  version: 2.14.1
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: vcr
189
189
  requirement: !ruby/object:Gem::Requirement
190
190
  requirements:
191
- - - ! '>='
191
+ - - ">="
192
192
  - !ruby/object:Gem::Version
193
193
  version: '0'
194
194
  type: :development
195
195
  prerelease: false
196
196
  version_requirements: !ruby/object:Gem::Requirement
197
197
  requirements:
198
- - - ! '>='
198
+ - - ">="
199
199
  - !ruby/object:Gem::Version
200
200
  version: '0'
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: webmock
203
203
  requirement: !ruby/object:Gem::Requirement
204
204
  requirements:
205
- - - ! '>='
205
+ - - "<="
206
206
  - !ruby/object:Gem::Version
207
- version: '0'
207
+ version: 1.18.0
208
208
  type: :development
209
209
  prerelease: false
210
210
  version_requirements: !ruby/object:Gem::Requirement
211
211
  requirements:
212
- - - ! '>='
212
+ - - "<="
213
213
  - !ruby/object:Gem::Version
214
- version: '0'
214
+ version: 1.18.0
215
+ - !ruby/object:Gem::Dependency
216
+ name: addressable
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "<="
220
+ - !ruby/object:Gem::Version
221
+ version: 2.3.6
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "<="
227
+ - !ruby/object:Gem::Version
228
+ version: 2.3.6
215
229
  description: Packaging made easy
216
230
  email:
217
231
  - tomhulihan@swipely.com
@@ -222,11 +236,11 @@ executables:
222
236
  extensions: []
223
237
  extra_rdoc_files: []
224
238
  files:
225
- - .cane
226
- - .gitignore
227
- - .rspec
228
- - .ruby-version
229
- - .travis.yml
239
+ - ".cane"
240
+ - ".gitignore"
241
+ - ".rspec"
242
+ - ".ruby-version"
243
+ - ".travis.yml"
230
244
  - Gemfile
231
245
  - LICENSE.txt
232
246
  - README.md
@@ -243,6 +257,7 @@ files:
243
257
  - lib/dockly/cli.rb
244
258
  - lib/dockly/deb.rb
245
259
  - lib/dockly/docker.rb
260
+ - lib/dockly/docker/ecr.rb
246
261
  - lib/dockly/docker/registry.rb
247
262
  - lib/dockly/foreman.rb
248
263
  - lib/dockly/history.rb
@@ -255,6 +270,7 @@ files:
255
270
  - lib/dockly/version.rb
256
271
  - lib/foreman/cli_fix.rb
257
272
  - lib/foreman/export/base_fix.rb
273
+ - snippets/auth_ecr.erb
258
274
  - snippets/docker_tag_latest.erb
259
275
  - snippets/file_diff_docker_import.erb
260
276
  - snippets/file_docker_import.erb
@@ -272,6 +288,7 @@ files:
272
288
  - spec/dockly/build_cache/local_spec.rb
273
289
  - spec/dockly/cli_spec.rb
274
290
  - spec/dockly/deb_spec.rb
291
+ - spec/dockly/docker/ecr_spec.rb
275
292
  - spec/dockly/docker/registry_spec.rb
276
293
  - spec/dockly/docker_spec.rb
277
294
  - spec/dockly/foreman_spec.rb
@@ -294,24 +311,24 @@ homepage: https://github.com/swipely/dockly
294
311
  licenses:
295
312
  - MIT
296
313
  metadata: {}
297
- post_install_message:
314
+ post_install_message:
298
315
  rdoc_options: []
299
316
  require_paths:
300
317
  - lib
301
318
  required_ruby_version: !ruby/object:Gem::Requirement
302
319
  requirements:
303
- - - ! '>='
320
+ - - ">="
304
321
  - !ruby/object:Gem::Version
305
322
  version: '0'
306
323
  required_rubygems_version: !ruby/object:Gem::Requirement
307
324
  requirements:
308
- - - ! '>'
325
+ - - ">="
309
326
  - !ruby/object:Gem::Version
310
- version: 1.3.1
327
+ version: '0'
311
328
  requirements: []
312
- rubyforge_project:
313
- rubygems_version: 2.6.2
314
- signing_key:
329
+ rubyforge_project:
330
+ rubygems_version: 2.5.1
331
+ signing_key:
315
332
  specification_version: 4
316
333
  summary: Packaging made easy
317
334
  test_files:
@@ -321,6 +338,7 @@ test_files:
321
338
  - spec/dockly/build_cache/local_spec.rb
322
339
  - spec/dockly/cli_spec.rb
323
340
  - spec/dockly/deb_spec.rb
341
+ - spec/dockly/docker/ecr_spec.rb
324
342
  - spec/dockly/docker/registry_spec.rb
325
343
  - spec/dockly/docker_spec.rb
326
344
  - spec/dockly/foreman_spec.rb
@@ -339,3 +357,4 @@ test_files:
339
357
  - spec/fixtures/test-2.tar.gz
340
358
  - spec/fixtures/test-3.tar
341
359
  - spec/spec_helper.rb
360
+ has_rdoc: