dockly 3.4.1 → 4.3.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,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 643369ac9e98df641a6b68eb246c6453bbd5f228
4
- data.tar.gz: 6539614f380fadd9867307fe2c0dfc3314f5dfb6
2
+ SHA256:
3
+ metadata.gz: f95076bb1a6669dfc79828fa8801aee570fd2a0aba323725ffdd475029ff9538
4
+ data.tar.gz: 0e7f27b46aa45f31c65cf13631ff856ce67d048812dbbc6e3db9250c1f6142c6
5
5
  SHA512:
6
- metadata.gz: c70fbeb01ec143d0d9c54fc9d66a38dcafc709a591e150cb6ae55201fe7ef895afd3e7a7105f66f2562f8b71514fba4a1c33cc0d30f06d49ead77559264a8ff5
7
- data.tar.gz: e89ca5f52ade24755fa7a96a0442484c209633817b70fa4ff024b51900a6878adc93fe6b691bb4a8c47ff4b188b356beccec5b602dc82ef97cb766468770b53f
6
+ metadata.gz: 0dd1127b2e8726e6e3d96999f5353c2a93e329ada97d730c2ed2a6da7f806b3045338fd72d63fb7a7432a1853a44d78c44ea6a87dee1c96a51bba228b1e65162
7
+ data.tar.gz: f0e739007e82215ec72881324f6e0130e14d0ec03910e329ce3a308954364dd1bb9532b42d11bb8c7f9450f3e8607b9d756c1e93b1c825cc78d78f82e4551131
@@ -0,0 +1,32 @@
1
+ name: Unit Tests
2
+ on: [push, pull_request]
3
+ jobs:
4
+ docker-rspec:
5
+ runs-on:
6
+ - ubuntu-18.04
7
+ strategy:
8
+ matrix:
9
+ ruby:
10
+ - 2.7
11
+ - 2.6
12
+ - 2.5
13
+ - 2.4
14
+ fail-fast: true
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ with:
18
+ fetch-depth: 0
19
+ - uses: ruby/setup-ruby@v1
20
+ with:
21
+ ruby-version: ${{ matrix.ruby }}
22
+ - name: install bundler
23
+ run: |
24
+ gem install bundler -v '~> 1.17.3'
25
+ bundle update
26
+ - name: install rpm
27
+ run: |
28
+ set -x
29
+ sudo apt-get update -y
30
+ sudo apt-get install -y rpm
31
+ - name: spec tests
32
+ run: CI=true bundle exec rake
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 1.9.3-p547
1
+ 2.3.1
data/.travis.yml CHANGED
@@ -1,9 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9
4
3
  - 2.0
5
4
  - 2.1
6
5
  - 2.2
6
+ - 2.3
7
7
  script:
8
8
  - git fetch --tags
9
9
  - CI=true bundle exec rake
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
 
data/dockly.gemspec CHANGED
@@ -18,9 +18,11 @@ Gem::Specification.new do |gem|
18
18
  gem.add_dependency 'docker-api', '>= 1.14.0'
19
19
  gem.add_dependency 'dockly-util', '>= 0.0.9', '< 1.0'
20
20
  gem.add_dependency 'excon'
21
- gem.add_dependency 'aws-sdk', '~> 2.0'
21
+ gem.add_dependency 'aws-sdk-core', '~> 3'
22
+ gem.add_dependency 'aws-sdk-s3', '~> 1'
23
+ gem.add_dependency 'aws-sdk-ecr', '~> 1'
22
24
  gem.add_dependency 'foreman'
23
- gem.add_dependency 'fpm', '~> 1.2.0'
25
+ gem.add_dependency 'fpm', '~> 1.2'
24
26
  gem.add_dependency 'minigit', '~> 0.0.4'
25
27
  gem.add_development_dependency 'cane'
26
28
  gem.add_development_dependency 'pry'
@@ -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
@@ -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
data/lib/dockly/deb.rb CHANGED
@@ -77,7 +77,6 @@ class Dockly::Deb
77
77
  end
78
78
 
79
79
  def upload_to_s3
80
- info "uploading to s3"
81
80
  return if s3_bucket.nil?
82
81
  raise "Package wasn't created!" unless File.exist?(build_path)
83
82
  info "uploading package to s3"
@@ -181,7 +180,7 @@ private
181
180
  end
182
181
 
183
182
  def add_docker_auth_config(package)
184
- return if (registry = get_registry).nil? || !registry.authentication_required?
183
+ return if (registry = get_registry).nil? || !should_auth?(registry)
185
184
  info "adding docker config file"
186
185
  registry.generate_config_file!
187
186
 
@@ -192,11 +191,18 @@ private
192
191
  package.attributes[:prefix] = nil
193
192
  end
194
193
 
194
+ def should_auth?(registry)
195
+ registry.is_a?(Dockly::Docker::Registry) &&
196
+ registry.authentication_required?
197
+ end
198
+
195
199
  def add_docker(package)
196
200
  return if docker.nil? || docker.s3_bucket
197
201
  info "adding docker image"
198
202
  docker.generate!
199
- return unless docker.registry.nil?
203
+
204
+ return if get_registry
205
+
200
206
  package.attributes[:prefix] = docker.package_dir
201
207
  Dir.chdir(File.dirname(docker.tar_path)) do
202
208
  package.input(File.basename(docker.tar_path))
@@ -205,7 +211,7 @@ private
205
211
  end
206
212
 
207
213
  def get_registry
208
- if docker && registry = docker.registry
214
+ if docker && (registry = docker.registry)
209
215
  registry
210
216
  end
211
217
  end
@@ -214,28 +220,43 @@ private
214
220
  scripts = ["#!/bin/bash"]
215
221
  bb = Dockly::BashBuilder.new
216
222
  scripts << bb.normalize_for_dockly
217
- if get_registry
218
- scripts << bb.registry_import(docker.repo, docker.tag)
219
- elsif docker
220
- if docker.s3_bucket.nil?
221
- docker_output = File.join(docker.package_dir, docker.export_filename)
222
- if docker.tar_diff
223
- scripts << bb.file_diff_docker_import(docker.import, docker_output, docker.name, docker.tag)
224
- else
225
- 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)
226
228
  end
229
+
230
+ scripts << bb.registry_import(docker.repo, docker.tag)
231
+ scripts << bb.docker_tag_latest(docker.repo, docker.tag, docker.name)
227
232
  else
228
- if docker.tar_diff
229
- scripts << bb.s3_diff_docker_import(docker.import, docker.s3_url, docker.name, docker.tag)
230
- else
231
- scripts << bb.s3_docker_import(docker.s3_url, docker.name, docker.tag)
232
- end
233
+ scripts += collect_non_registry_scripts(bb)
233
234
  end
234
- scripts << bb.docker_tag_latest(docker.repo, docker.tag)
235
235
  end
236
236
  scripts.join("\n")
237
237
  end
238
238
 
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
+
239
260
  def add_startup_script(package, startup_script = "dockly-startup.sh")
240
261
  ensure_present! :build_dir
241
262
  startup_script_path = File.join(build_dir, startup_script)
@@ -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
data/lib/dockly/docker.rb CHANGED
@@ -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)
@@ -318,14 +324,26 @@ class Dockly::Docker
318
324
  end
319
325
 
320
326
  def push_to_registry(image)
321
- ensure_present! :registry
327
+ raise "No registry to push to" if registry.nil?
328
+
322
329
  info "Exporting #{image.id} to Docker registry at #{registry.server_address}"
330
+
323
331
  registry.authenticate!
324
- image = Docker::Image.all(:all => true).find { |img|
325
- img.id.start_with?(image.id) || image.id.start_with?(img.id)
326
- }
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
+
327
340
  raise "Could not find image after authentication" if image.nil?
328
- 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
329
347
  end
330
348
 
331
349
  def fetch_import
data/lib/dockly/rpm.rb CHANGED
@@ -31,5 +31,6 @@ private
31
31
  @deb_package.attributes[:rpm_user] = "root"
32
32
  @deb_package.attributes[:rpm_group] = "root"
33
33
  @deb_package.attributes[:rpm_os] = os
34
+ @deb_package.attributes[:workdir] = ::Dir.tmpdir
34
35
  end
35
36
  end
@@ -1,7 +1,7 @@
1
1
  module Dockly
2
- MAJOR = 3
3
- MINOR = 4
4
- PATCH = 1
2
+ MAJOR = 4
3
+ MINOR = 3
4
+ PATCH = 0
5
5
  RELEASE = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, PATCH, RELEASE].compact.join('.')
data/lib/dockly.rb CHANGED
@@ -4,7 +4,9 @@ require 'dockly/util/git'
4
4
  require 'foreman/cli_fix'
5
5
  require 'foreman/export/base_fix'
6
6
  require 'minigit'
7
- require 'aws-sdk'
7
+ require 'aws-sdk-core'
8
+ require 'aws-sdk-s3'
9
+ require 'aws-sdk-ecr'
8
10
  require 'open3'
9
11
 
10
12
  module Dockly
@@ -0,0 +1,14 @@
1
+ auth_ecr() {
2
+ account_id=$(aws sts get-caller-identity --query Account --output text)
3
+ region="<%= ENV['AWS_REGION'] || 'us-east-1' %>"
4
+ aws ecr get-login-password --region $region | \
5
+ docker login --username AWS --password-stdin $account_id.dkr.ecr.$region.amazonaws.com
6
+ }
7
+
8
+ worked=1
9
+ for attempt in {1..10}; do
10
+ [[ $worked != 0 ]] || break
11
+ auth_ecr && worked=0 || (log "ecr auth: attempt $attempt failed, sleeping 30"; sleep 30)
12
+ done
13
+ [[ $worked != 0 ]] && fatal "failed to auth to ecr"
14
+ 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
@@ -14,8 +14,11 @@ describe Dockly::BuildCache::Base do
14
14
  describe '#up_to_date?' do
15
15
  context 'when the object exists in s3' do
16
16
  before do
17
- allow(subject.connection)
18
- .to receive(:head_object)
17
+ allow(Dockly)
18
+ .to receive(:s3)
19
+ .and_return(
20
+ Aws::S3::Client.new(stub_responses: true)
21
+ )
19
22
  end
20
23
 
21
24
  its(:up_to_date?) { should be_true }
@@ -23,9 +26,13 @@ describe Dockly::BuildCache::Base do
23
26
 
24
27
  context 'when the object does not exist in s3' do
25
28
  before do
26
- allow(subject.connection)
27
- .to receive(:head_object)
28
- .and_raise(Aws::S3::Errors::NoSuchKey.new('Some Error', 500))
29
+ allow(Dockly)
30
+ .to receive(:s3)
31
+ .and_return(
32
+ Aws::S3::Client.new(
33
+ stub_responses: { :head_object => 'NoSuchKey' }
34
+ )
35
+ )
29
36
  end
30
37
 
31
38
  its(:up_to_date?) { should be_false }
@@ -37,9 +44,12 @@ describe Dockly::BuildCache::Base do
37
44
  let(:object) { double(:object) }
38
45
 
39
46
  before do
40
- allow(subject.connection)
41
- .to receive(:get_object)
42
- .and_return(object)
47
+ allow(Dockly)
48
+ .to receive(:s3)
49
+ .and_return(Aws::S3::Client.new(
50
+ stub_responses: { :get_object => object }
51
+ ))
52
+
43
53
  allow(object)
44
54
  .to receive(:body)
45
55
  .and_return(StringIO.new('hey dad').tap(&:rewind))
@@ -205,14 +205,19 @@ describe Dockly::Deb do
205
205
  pre_install "ls"
206
206
  post_install "rd /s /q C:\*"
207
207
  build_dir 'build/deb/s3'
208
+ s3_bucket 'bucket'
208
209
  end
209
210
  end
210
211
 
211
212
  context 'when the object does exist' do
212
213
  before do
213
- allow(Dockly.s3)
214
- .to receive(:head_object)
215
- .and_return({})
214
+ allow(Dockly)
215
+ .to receive(:s3)
216
+ .and_return(
217
+ Aws::S3::Client.new(
218
+ stub_responses: { :head_object => {} }
219
+ )
220
+ )
216
221
  end
217
222
 
218
223
  it 'is true' do
@@ -222,12 +227,16 @@ describe Dockly::Deb do
222
227
 
223
228
  context 'when the object does not exist' do
224
229
  before do
225
- allow(Dockly.s3)
226
- .to receive(:head_object)
227
- .and_raise(StandardError.new('object does not exist'))
230
+ allow(Dockly)
231
+ .to receive(:s3)
232
+ .and_return(
233
+ Aws::S3::Client.new(
234
+ stub_responses: { :head_object => 'ObjectDoesNotExist' }
235
+ )
236
+ )
228
237
  end
229
238
 
230
- it 'is true' do
239
+ it 'is false' do
231
240
  expect(subject.exists?).to be_false
232
241
  end
233
242
  end
@@ -267,12 +276,24 @@ describe Dockly::Deb do
267
276
  context 'when the package has been created' do
268
277
  before { subject.create_package! }
269
278
 
279
+ let(:client) do
280
+ client = Aws::S3::Client.new(stub_responses: true)
281
+ client.stub_responses(
282
+ :put_object, ->(context) do
283
+ expect(context.params[:bucket]).to eq(bucket_name)
284
+ expect(context.params[:key]).to eq(subject.s3_object_name)
285
+ expect(context.params).to have_key(:body)
286
+
287
+ {}
288
+ end
289
+ )
290
+ client
291
+ end
292
+
270
293
  it 'inserts the deb package into that bucket' do
271
- expect(Dockly.s3).to receive(:put_object) do |hash|
272
- expect(hash[:bucket]).to eq(bucket_name)
273
- expect(hash[:key]).to eq(subject.s3_object_name)
274
- expect(hash).to have_key(:body)
275
- end
294
+ expect(Dockly)
295
+ .to receive(:s3)
296
+ .and_return(client)
276
297
 
277
298
  subject.upload_to_s3
278
299
  end
@@ -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
 
@@ -134,11 +204,15 @@ describe Dockly::Docker do
134
204
  let(:url) { 's3://bucket/object' }
135
205
  let(:data) { 'sweet, sweet data' }
136
206
 
207
+ let(:client) { double() }
208
+
137
209
  before do
138
- allow(Dockly.s3)
210
+ allow(client)
139
211
  .to receive(:get_object)
140
- .with(bucket: 'bucket', key: 'object')
212
+ .with(hash_including({ bucket: 'bucket', key: 'object' }))
141
213
  .and_yield(data)
214
+
215
+ allow(Dockly).to receive(:s3).and_return(client)
142
216
  end
143
217
 
144
218
  it 'pulls the file from S3' do
@@ -172,7 +246,7 @@ describe Dockly::Docker do
172
246
  context "with a registry export" do
173
247
  let(:registry) { double(:registry) }
174
248
  before do
175
- subject.instance_variable_set(:"@registry", registry)
249
+ subject.instance_variable_set(:"@docker_registry", registry)
176
250
  expect(subject).to receive(:push_to_registry)
177
251
  end
178
252
 
@@ -243,6 +317,107 @@ describe Dockly::Docker do
243
317
  end
244
318
  end
245
319
 
320
+ describe '#push_to_registry', :docker do
321
+ let(:image) { Docker::Image.create('fromImage' => 'ubuntu:14.04') }
322
+ let(:ecr) { double(:ecr) }
323
+
324
+ context 'when there is no registry' do
325
+ it 'raises' do
326
+ expect(subject.registry).to eq(nil)
327
+
328
+ expect { subject.push_to_registry(image) }.to raise_error(/No registry/)
329
+ end
330
+ end
331
+
332
+ context 'when there is a registry' do
333
+ before do
334
+ subject.instance_variable_set(:"@ecr", ecr)
335
+
336
+ allow(ecr)
337
+ .to receive(:server_address)
338
+ .and_return('server_address')
339
+
340
+ expect(subject.registry).to eq(ecr)
341
+ end
342
+
343
+ context "that can't be authenticated to" do
344
+ before do
345
+ allow(ecr)
346
+ .to receive(:authenticate!)
347
+ .and_raise
348
+ end
349
+
350
+ it 'raises' do
351
+ expect { subject.push_to_registry(image) }
352
+ .to raise_error(StandardError)
353
+ end
354
+ end
355
+
356
+ context 'that can be authenticated to' do
357
+ before do
358
+ allow(ecr).to receive(:authenticate!)
359
+
360
+ allow(Docker::Image)
361
+ .to receive(:all)
362
+ .with(all: true)
363
+ .and_return(available_images)
364
+ end
365
+
366
+ context "but the image isn't found" do
367
+ let(:available_images) { [] }
368
+
369
+ it 'raises' do
370
+ expect { subject.push_to_registry(image) }
371
+ .to raise_error(/Could not find image after authentication/)
372
+ end
373
+ end
374
+
375
+ context 'and the image is found' do
376
+ let(:available_images) { [image] }
377
+
378
+ before do
379
+ allow(ecr)
380
+ .to receive(:to_h)
381
+ .and_return({})
382
+ allow(image)
383
+ .to receive(:push)
384
+ .and_yield(push_message)
385
+ end
386
+
387
+ context 'but the push to the registry fails' do
388
+ let(:push_message) do
389
+ <<-EOF
390
+ {"errorDetail":{"message":"name unknown: The repository with name 'repository'
391
+ does not exist in the registry with id 'accoundid'"},"error":"name unknown:
392
+ The repository with name 'repository' does not exist in the registry with id 'accountid'"}
393
+ EOF
394
+ end
395
+
396
+ it 'raises' do
397
+ expect { subject.push_to_registry(image) }
398
+ .to raise_error(/Error pushing to registry/)
399
+ end
400
+ end
401
+
402
+ context 'and the push to the registry succeeds' do
403
+ let(:push_message) do
404
+ <<-EOF
405
+ {"status":"Pushed","progressDetail":{},"id":"id"}
406
+ {"status":"sha: digest: digest size: 2048"}
407
+ {"progressDetail":{},"aux":{"Tag":"sha","Digest":"digest","Size":2048}}
408
+ EOF
409
+ end
410
+
411
+ it 'passes' do
412
+ expect(subject.push_to_registry(image))
413
+ .not_to raise_error
414
+ end
415
+ end
416
+ end
417
+ end
418
+ end
419
+ end
420
+
246
421
  describe '#export_image_diff', :docker do
247
422
  let(:images) { [] }
248
423
  let(:output) { StringIO.new }
@@ -11,6 +11,7 @@ describe Dockly::Rpm do
11
11
  pre_install "ls"
12
12
  post_install "rd /s /q C:\*"
13
13
  build_dir 'build'
14
+ s3_bucket 'bucket'
14
15
  end
15
16
  end
16
17
  let(:filename) { "build/rpm/my-sweet-rpm_77.0.8_x86_64.rpm" }
@@ -173,14 +174,17 @@ describe Dockly::Rpm do
173
174
  pre_install "ls"
174
175
  post_install "rd /s /q C:\*"
175
176
  build_dir 'build/rpm/s3'
177
+ s3_bucket 'bucket'
176
178
  end
177
179
  end
178
180
 
179
181
  context 'when the object does exist' do
180
182
  before do
181
- allow(Dockly.s3)
182
- .to receive(:head_object)
183
- .and_return({})
183
+ allow(Dockly)
184
+ .to receive(:s3)
185
+ .and_return(
186
+ Aws::S3::Client.new(stub_responses: true)
187
+ )
184
188
  end
185
189
 
186
190
  it 'is true' do
@@ -190,9 +194,13 @@ describe Dockly::Rpm do
190
194
 
191
195
  context 'when the object does not exist' do
192
196
  before do
193
- allow(Dockly.s3)
194
- .to receive(:head_object)
195
- .and_raise(StandardError.new('object does not exist'))
197
+ allow(Dockly)
198
+ .to receive(:s3)
199
+ .and_return(
200
+ Aws::S3::Client.new(
201
+ stub_responses: { :head_object => 'NoSuchKey' }
202
+ )
203
+ )
196
204
  end
197
205
 
198
206
  it 'is true' do
@@ -235,12 +243,24 @@ describe Dockly::Rpm do
235
243
  context 'when the package has been created' do
236
244
  before { subject.create_package! }
237
245
 
246
+ let(:client) do
247
+ client = Aws::S3::Client.new(stub_responses: true)
248
+ client.stub_responses(
249
+ :put_object, ->(context) do
250
+ expect(context.params[:bucket]).to eq(bucket_name)
251
+ expect(context.params[:key]).to eq(subject.s3_object_name)
252
+ expect(context.params).to have_key(:body)
253
+
254
+ {}
255
+ end
256
+ )
257
+ client
258
+ end
259
+
238
260
  it 'inserts the rpm package into that bucket' do
239
- expect(Dockly.s3).to receive(:put_object) do |hash|
240
- expect(hash[:bucket]).to eq(bucket_name)
241
- expect(hash[:key]).to eq(subject.s3_object_name)
242
- expect(hash).to have_key(:body)
243
- end
261
+ expect(Dockly)
262
+ .to receive(:s3)
263
+ .and_return(client)
244
264
 
245
265
  subject.upload_to_s3
246
266
  end
metadata CHANGED
@@ -1,229 +1,257 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dockly
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 4.3.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: 2019-10-18 00:00:00.000000000 Z
11
+ date: 2021-12-16 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
- name: aws-sdk
76
+ name: aws-sdk-core
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ~>
79
+ - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '2.0'
81
+ version: '3'
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
- version: '2.0'
88
+ version: '3'
89
+ - !ruby/object:Gem::Dependency
90
+ name: aws-sdk-s3
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '1'
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '1'
103
+ - !ruby/object:Gem::Dependency
104
+ name: aws-sdk-ecr
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - "~>"
115
+ - !ruby/object:Gem::Version
116
+ version: '1'
89
117
  - !ruby/object:Gem::Dependency
90
118
  name: foreman
91
119
  requirement: !ruby/object:Gem::Requirement
92
120
  requirements:
93
- - - '>='
121
+ - - ">="
94
122
  - !ruby/object:Gem::Version
95
123
  version: '0'
96
124
  type: :runtime
97
125
  prerelease: false
98
126
  version_requirements: !ruby/object:Gem::Requirement
99
127
  requirements:
100
- - - '>='
128
+ - - ">="
101
129
  - !ruby/object:Gem::Version
102
130
  version: '0'
103
131
  - !ruby/object:Gem::Dependency
104
132
  name: fpm
105
133
  requirement: !ruby/object:Gem::Requirement
106
134
  requirements:
107
- - - ~>
135
+ - - "~>"
108
136
  - !ruby/object:Gem::Version
109
- version: 1.2.0
137
+ version: '1.2'
110
138
  type: :runtime
111
139
  prerelease: false
112
140
  version_requirements: !ruby/object:Gem::Requirement
113
141
  requirements:
114
- - - ~>
142
+ - - "~>"
115
143
  - !ruby/object:Gem::Version
116
- version: 1.2.0
144
+ version: '1.2'
117
145
  - !ruby/object:Gem::Dependency
118
146
  name: minigit
119
147
  requirement: !ruby/object:Gem::Requirement
120
148
  requirements:
121
- - - ~>
149
+ - - "~>"
122
150
  - !ruby/object:Gem::Version
123
151
  version: 0.0.4
124
152
  type: :runtime
125
153
  prerelease: false
126
154
  version_requirements: !ruby/object:Gem::Requirement
127
155
  requirements:
128
- - - ~>
156
+ - - "~>"
129
157
  - !ruby/object:Gem::Version
130
158
  version: 0.0.4
131
159
  - !ruby/object:Gem::Dependency
132
160
  name: cane
133
161
  requirement: !ruby/object:Gem::Requirement
134
162
  requirements:
135
- - - '>='
163
+ - - ">="
136
164
  - !ruby/object:Gem::Version
137
165
  version: '0'
138
166
  type: :development
139
167
  prerelease: false
140
168
  version_requirements: !ruby/object:Gem::Requirement
141
169
  requirements:
142
- - - '>='
170
+ - - ">="
143
171
  - !ruby/object:Gem::Version
144
172
  version: '0'
145
173
  - !ruby/object:Gem::Dependency
146
174
  name: pry
147
175
  requirement: !ruby/object:Gem::Requirement
148
176
  requirements:
149
- - - '>='
177
+ - - ">="
150
178
  - !ruby/object:Gem::Version
151
179
  version: '0'
152
180
  type: :development
153
181
  prerelease: false
154
182
  version_requirements: !ruby/object:Gem::Requirement
155
183
  requirements:
156
- - - '>='
184
+ - - ">="
157
185
  - !ruby/object:Gem::Version
158
186
  version: '0'
159
187
  - !ruby/object:Gem::Dependency
160
188
  name: rake
161
189
  requirement: !ruby/object:Gem::Requirement
162
190
  requirements:
163
- - - <
191
+ - - "<"
164
192
  - !ruby/object:Gem::Version
165
193
  version: '11.0'
166
194
  type: :development
167
195
  prerelease: false
168
196
  version_requirements: !ruby/object:Gem::Requirement
169
197
  requirements:
170
- - - <
198
+ - - "<"
171
199
  - !ruby/object:Gem::Version
172
200
  version: '11.0'
173
201
  - !ruby/object:Gem::Dependency
174
202
  name: rspec
175
203
  requirement: !ruby/object:Gem::Requirement
176
204
  requirements:
177
- - - ~>
205
+ - - "~>"
178
206
  - !ruby/object:Gem::Version
179
207
  version: 2.14.1
180
208
  type: :development
181
209
  prerelease: false
182
210
  version_requirements: !ruby/object:Gem::Requirement
183
211
  requirements:
184
- - - ~>
212
+ - - "~>"
185
213
  - !ruby/object:Gem::Version
186
214
  version: 2.14.1
187
215
  - !ruby/object:Gem::Dependency
188
216
  name: vcr
189
217
  requirement: !ruby/object:Gem::Requirement
190
218
  requirements:
191
- - - '>='
219
+ - - ">="
192
220
  - !ruby/object:Gem::Version
193
221
  version: '0'
194
222
  type: :development
195
223
  prerelease: false
196
224
  version_requirements: !ruby/object:Gem::Requirement
197
225
  requirements:
198
- - - '>='
226
+ - - ">="
199
227
  - !ruby/object:Gem::Version
200
228
  version: '0'
201
229
  - !ruby/object:Gem::Dependency
202
230
  name: webmock
203
231
  requirement: !ruby/object:Gem::Requirement
204
232
  requirements:
205
- - - <=
233
+ - - "<="
206
234
  - !ruby/object:Gem::Version
207
235
  version: 1.18.0
208
236
  type: :development
209
237
  prerelease: false
210
238
  version_requirements: !ruby/object:Gem::Requirement
211
239
  requirements:
212
- - - <=
240
+ - - "<="
213
241
  - !ruby/object:Gem::Version
214
242
  version: 1.18.0
215
243
  - !ruby/object:Gem::Dependency
216
244
  name: addressable
217
245
  requirement: !ruby/object:Gem::Requirement
218
246
  requirements:
219
- - - <=
247
+ - - "<="
220
248
  - !ruby/object:Gem::Version
221
249
  version: 2.3.6
222
250
  type: :development
223
251
  prerelease: false
224
252
  version_requirements: !ruby/object:Gem::Requirement
225
253
  requirements:
226
- - - <=
254
+ - - "<="
227
255
  - !ruby/object:Gem::Version
228
256
  version: 2.3.6
229
257
  description: Packaging made easy
@@ -236,11 +264,12 @@ executables:
236
264
  extensions: []
237
265
  extra_rdoc_files: []
238
266
  files:
239
- - .cane
240
- - .gitignore
241
- - .rspec
242
- - .ruby-version
243
- - .travis.yml
267
+ - ".cane"
268
+ - ".github/workflows/unit_test.yml"
269
+ - ".gitignore"
270
+ - ".rspec"
271
+ - ".ruby-version"
272
+ - ".travis.yml"
244
273
  - Gemfile
245
274
  - LICENSE.txt
246
275
  - README.md
@@ -257,6 +286,7 @@ files:
257
286
  - lib/dockly/cli.rb
258
287
  - lib/dockly/deb.rb
259
288
  - lib/dockly/docker.rb
289
+ - lib/dockly/docker/ecr.rb
260
290
  - lib/dockly/docker/registry.rb
261
291
  - lib/dockly/foreman.rb
262
292
  - lib/dockly/history.rb
@@ -269,6 +299,7 @@ files:
269
299
  - lib/dockly/version.rb
270
300
  - lib/foreman/cli_fix.rb
271
301
  - lib/foreman/export/base_fix.rb
302
+ - snippets/auth_ecr.erb
272
303
  - snippets/docker_tag_latest.erb
273
304
  - snippets/file_diff_docker_import.erb
274
305
  - snippets/file_docker_import.erb
@@ -286,6 +317,7 @@ files:
286
317
  - spec/dockly/build_cache/local_spec.rb
287
318
  - spec/dockly/cli_spec.rb
288
319
  - spec/dockly/deb_spec.rb
320
+ - spec/dockly/docker/ecr_spec.rb
289
321
  - spec/dockly/docker/registry_spec.rb
290
322
  - spec/dockly/docker_spec.rb
291
323
  - spec/dockly/foreman_spec.rb
@@ -308,24 +340,23 @@ homepage: https://github.com/swipely/dockly
308
340
  licenses:
309
341
  - MIT
310
342
  metadata: {}
311
- post_install_message:
343
+ post_install_message:
312
344
  rdoc_options: []
313
345
  require_paths:
314
346
  - lib
315
347
  required_ruby_version: !ruby/object:Gem::Requirement
316
348
  requirements:
317
- - - '>='
349
+ - - ">="
318
350
  - !ruby/object:Gem::Version
319
351
  version: '0'
320
352
  required_rubygems_version: !ruby/object:Gem::Requirement
321
353
  requirements:
322
- - - '>='
354
+ - - ">="
323
355
  - !ruby/object:Gem::Version
324
356
  version: '0'
325
357
  requirements: []
326
- rubyforge_project:
327
- rubygems_version: 2.0.14
328
- signing_key:
358
+ rubygems_version: 3.0.6
359
+ signing_key:
329
360
  specification_version: 4
330
361
  summary: Packaging made easy
331
362
  test_files:
@@ -335,6 +366,7 @@ test_files:
335
366
  - spec/dockly/build_cache/local_spec.rb
336
367
  - spec/dockly/cli_spec.rb
337
368
  - spec/dockly/deb_spec.rb
369
+ - spec/dockly/docker/ecr_spec.rb
338
370
  - spec/dockly/docker/registry_spec.rb
339
371
  - spec/dockly/docker_spec.rb
340
372
  - spec/dockly/foreman_spec.rb