dockly 3.4.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
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