puppet_docker_tools 0.1.5 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -1
- data/bin/puppet-docker +5 -3
- data/lib/puppet_docker_tools/runner.rb +52 -32
- data/lib/puppet_docker_tools/spec_helper.rb +0 -6
- data/lib/puppet_docker_tools/utilities.rb +22 -42
- data/spec/lib/puppet_docker_tools/runner_spec.rb +16 -43
- data/spec/lib/puppet_docker_tools/utilities_spec.rb +19 -57
- data/spec/support/context/with_docker_container.rb +37 -4
- data/spec/support/context/with_docker_image.rb +14 -4
- data/spec/support/context/with_transient_docker_container.rb +9 -0
- data/spec/support/examples/running_container.rb +43 -9
- metadata +4 -34
- data/spec/support/context/using_alpine.rb +0 -5
- data/spec/support/context/using_centos.rb +0 -5
- data/spec/support/context/with_docker_container_dummy_cmd.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b6627e1ff33d2a5c6b9f302ad8268f3206f083b
|
4
|
+
data.tar.gz: 135420d71d73f036a552fa4619fbf0d7ac02b435
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 291b7624f5478dd96a4e29be0516202ae01f453c1af520db31331b020b4a26b130ac542aa4ed7971e8d503f4cc8365a56ef8297c474236ab5dcb93ee3351f0a9
|
7
|
+
data.tar.gz: ddc9c5af3e64adfd1a5cb2ddb48bb07c07fa9534beb18fb4a837557054a717cb3de3b3fef893531eb072aa96df1e840e5efe4c2d8e4860762936ba14d8d66ef3
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ Usage:
|
|
21
21
|
puppet-docker pull [IMAGE] [--repository=<repo>]
|
22
22
|
puppet-docker push [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>] [--version=<version>] [--no-latest]
|
23
23
|
puppet-docker rev-labels [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
|
24
|
-
puppet-docker spec [DIRECTORY]
|
24
|
+
puppet-docker spec [DIRECTORY] [--image=<image>]
|
25
25
|
puppet-docker test [DIRECTORY] [--dockerfile=<dockerfile>]
|
26
26
|
puppet-docker version [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
|
27
27
|
puppet-docker update-base-images [TAG]...
|
@@ -39,6 +39,7 @@ Options:
|
|
39
39
|
--dockerfile=<dockerfile> File name for your dockerfile [default: Dockerfile]
|
40
40
|
--version=<version> Version to build. This field will be used to determine the label and will be passed as the version build arg.
|
41
41
|
**NOTE** `--build-arg version='<version>'` overrides `--version <version>`
|
42
|
+
--image=<image> Docker image to use for spec testing
|
42
43
|
--build-arg=<buildarg> Build arg to pass to container build, can be passed multiple times.
|
43
44
|
--no-latest Do not include the 'latest' tag when building and shipping images. By default, the 'latest' tag is built and shipped with the versioned tag.
|
44
45
|
```
|
data/bin/puppet-docker
CHANGED
@@ -13,7 +13,7 @@ Usage:
|
|
13
13
|
puppet-docker pull [IMAGE] [--repository=<repo>]
|
14
14
|
puppet-docker push [DIRECTORY] [--dockerfile=<dockerfile>] [--repository=<repo>] [--namespace=<namespace>] [--version=<version>] [--no-latest]
|
15
15
|
puppet-docker rev-labels [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
|
16
|
-
puppet-docker spec [DIRECTORY]
|
16
|
+
puppet-docker spec [DIRECTORY] [--image=<image>]
|
17
17
|
puppet-docker test [DIRECTORY] [--dockerfile=<dockerfile>]
|
18
18
|
puppet-docker version [DIRECTORY] [--dockerfile=<dockerfile>] [--namespace=<namespace>]
|
19
19
|
puppet-docker update-base-images [TAG]...
|
@@ -31,6 +31,7 @@ Options:
|
|
31
31
|
--dockerfile=<dockerfile> File name for your dockerfile [default: Dockerfile]
|
32
32
|
--version=<version> Version to build. This field will be used to determine the label and will be passed as the version build arg.
|
33
33
|
**NOTE** `--build-arg version='<version>'` overrides `--version <version>`
|
34
|
+
--image=<image> Docker image to use for spec testing
|
34
35
|
--build-arg=<buildarg> Build arg to pass to container build, can be passed multiple times.
|
35
36
|
--no-latest Do not include the 'latest' tag when building and shipping images. By default, the 'latest' tag is built and shipped with the versioned tag.
|
36
37
|
DOC
|
@@ -39,7 +40,7 @@ begin
|
|
39
40
|
options = Docopt::docopt(doc)
|
40
41
|
rescue Docopt::Exit
|
41
42
|
puts doc
|
42
|
-
exit
|
43
|
+
exit 1
|
43
44
|
end
|
44
45
|
|
45
46
|
defaults = {
|
@@ -51,6 +52,7 @@ defaults = {
|
|
51
52
|
'--version' => nil,
|
52
53
|
'--build-arg' => [],
|
53
54
|
'--no-latest' => false,
|
55
|
+
'--image' => nil,
|
54
56
|
}
|
55
57
|
|
56
58
|
options.merge!(defaults) do |key, option, default|
|
@@ -91,7 +93,7 @@ begin
|
|
91
93
|
elsif options['rev-labels']
|
92
94
|
command_runner.rev_labels
|
93
95
|
elsif options['spec']
|
94
|
-
command_runner.spec
|
96
|
+
command_runner.spec(image: options['--image'])
|
95
97
|
elsif options['test']
|
96
98
|
command_runner.lint
|
97
99
|
command_runner.spec
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'date'
|
2
|
-
require 'docker'
|
3
2
|
require 'json'
|
4
3
|
require 'rspec/core'
|
5
4
|
require 'time'
|
@@ -16,7 +15,7 @@ class PuppetDockerTools
|
|
16
15
|
@namespace = namespace
|
17
16
|
@dockerfile = dockerfile
|
18
17
|
|
19
|
-
file =
|
18
|
+
file = File.join(directory, dockerfile)
|
20
19
|
fail "File #{file} doesn't exist!" unless File.exist? file
|
21
20
|
end
|
22
21
|
|
@@ -31,7 +30,7 @@ class PuppetDockerTools
|
|
31
30
|
# 'arg=value'.
|
32
31
|
# @param latest Whether or not to build the latest tag along with the
|
33
32
|
# versioned image build.
|
34
|
-
def build(no_cache: false, version: nil, build_args: [], latest: true)
|
33
|
+
def build(no_cache: false, version: nil, build_args: [], latest: true, stream_output: true)
|
35
34
|
image_name = File.basename(directory)
|
36
35
|
build_args_hash = {
|
37
36
|
'vcs_ref' => PuppetDockerTools::Utilities.current_git_sha(directory),
|
@@ -49,7 +48,7 @@ class PuppetDockerTools
|
|
49
48
|
build_args_hash.merge!(PuppetDockerTools::Utilities.parse_build_args(Array(build_args)))
|
50
49
|
end
|
51
50
|
|
52
|
-
build_args_hash = PuppetDockerTools::Utilities.filter_build_args(build_args: build_args_hash, dockerfile:
|
51
|
+
build_args_hash = PuppetDockerTools::Utilities.filter_build_args(build_args: build_args_hash, dockerfile: File.join(directory, dockerfile))
|
53
52
|
|
54
53
|
# This variable is meant to be used for building the non-latest tagged build
|
55
54
|
# If the version was set via `version` or `build_args`, use that. If not,
|
@@ -61,29 +60,47 @@ class PuppetDockerTools
|
|
61
60
|
# and versions passed in to the dockerfile with an `ARG`
|
62
61
|
version = build_args_hash['version'] || PuppetDockerTools::Utilities.get_value_from_env('version', namespace: namespace, directory: directory, dockerfile: dockerfile)
|
63
62
|
|
64
|
-
path =
|
65
|
-
|
66
|
-
build_options = {'dockerfile' => dockerfile, 'buildargs' => "#{build_args_hash.to_json}"}
|
63
|
+
path = File.join(repository, image_name)
|
67
64
|
|
65
|
+
build_options = []
|
68
66
|
if no_cache
|
69
67
|
puts "Ignoring cache for #{path}"
|
70
|
-
build_options
|
68
|
+
build_options << '--no-cache'
|
71
69
|
end
|
72
70
|
|
71
|
+
if dockerfile != "Dockerfile"
|
72
|
+
build_options << ['--file', dockerfile]
|
73
|
+
end
|
74
|
+
|
75
|
+
tags = []
|
73
76
|
if latest
|
74
|
-
|
77
|
+
tags << ['--tag', "#{path}:latest"]
|
78
|
+
end
|
75
79
|
|
76
|
-
|
77
|
-
|
80
|
+
if version
|
81
|
+
tags << ['--tag', "#{path}:#{version}"]
|
82
|
+
end
|
78
83
|
|
79
|
-
|
84
|
+
if tags.empty?
|
85
|
+
return nil
|
80
86
|
end
|
81
87
|
|
82
|
-
if version
|
83
|
-
puts "Building #{path}:#{version}"
|
84
88
|
|
85
|
-
|
86
|
-
|
89
|
+
build_args = []
|
90
|
+
build_args_hash.map{ |k,v| "#{k}=#{v}" }.each do |val|
|
91
|
+
build_args << ['--build-arg', val]
|
92
|
+
end
|
93
|
+
|
94
|
+
build_command = ['docker', 'build', build_args, build_options, tags, directory].flatten
|
95
|
+
|
96
|
+
Open3.popen2e(*build_command) do |stdin, output_stream, wait_thread|
|
97
|
+
output=''
|
98
|
+
output_stream.each_line do |line|
|
99
|
+
stream_output ? (puts line) : (output += line)
|
100
|
+
end
|
101
|
+
exit_status = wait_thread.value.exitstatus
|
102
|
+
puts output unless stream_output
|
103
|
+
fail unless exit_status == 0
|
87
104
|
end
|
88
105
|
end
|
89
106
|
|
@@ -96,21 +113,15 @@ class PuppetDockerTools
|
|
96
113
|
|
97
114
|
# make sure we have the container locally
|
98
115
|
PuppetDockerTools::Utilities.pull("#{hadolint_container}:latest")
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
# Wait for the run to finish
|
103
|
-
container.wait
|
104
|
-
exit_status = container.json['State']['ExitCode']
|
105
|
-
unless exit_status == 0
|
106
|
-
fail container.logs(stdout: true, stderr: true)
|
107
|
-
end
|
116
|
+
docker_run = ['docker', 'run', '--rm', '-v', "#{File.join(Dir.pwd, directory, dockerfile)}:/Dockerfile:ro", '-i', 'hadolint/hadolint', PuppetDockerTools::Utilities.get_hadolint_command('Dockerfile')].flatten
|
117
|
+
output, status = Open3.capture2e(*docker_run)
|
118
|
+
fail output unless status == 0
|
108
119
|
end
|
109
120
|
|
110
121
|
# Run hadolint Dockerfile linting using a local hadolint executable. Executable
|
111
122
|
# found based on your path.
|
112
123
|
def local_lint
|
113
|
-
output, status = Open3.capture2e(PuppetDockerTools::Utilities.get_hadolint_command(
|
124
|
+
output, status = Open3.capture2e(*PuppetDockerTools::Utilities.get_hadolint_command(File.join(directory,dockerfile)))
|
114
125
|
fail output unless status == 0
|
115
126
|
end
|
116
127
|
|
@@ -120,7 +131,7 @@ class PuppetDockerTools
|
|
120
131
|
# versioned image build.
|
121
132
|
def push(latest: true, version: nil)
|
122
133
|
image_name = File.basename(directory)
|
123
|
-
path =
|
134
|
+
path = File.join(repository, image_name)
|
124
135
|
|
125
136
|
# only check for version from the label if we didn't pass it in
|
126
137
|
if version.nil?
|
@@ -169,15 +180,20 @@ class PuppetDockerTools
|
|
169
180
|
|
170
181
|
# Run spec tests
|
171
182
|
#
|
172
|
-
def spec
|
173
|
-
|
183
|
+
def spec(image: nil)
|
184
|
+
if image
|
185
|
+
fail 'Oh no! You have PUPPET_TEST_DOCKER_IMAGE set! Please unset!' if ENV['PUPPET_TEST_DOCKER_IMAGE']
|
186
|
+
ENV['PUPPET_TEST_DOCKER_IMAGE'] = image
|
187
|
+
end
|
188
|
+
|
189
|
+
tests = Dir.glob(File.join(directory,'spec','*_spec.rb'))
|
174
190
|
test_files = tests.map { |test| File.basename(test, '.rb') }
|
175
191
|
|
176
|
-
puts "Running RSpec tests from #{File.expand_path(
|
192
|
+
puts "Running RSpec tests from #{File.expand_path(File.join(directory,'spec'))} (#{test_files.join ","}), this may take some time"
|
177
193
|
success = true
|
178
194
|
tests.each do |test|
|
179
|
-
Open3.popen2e(
|
180
|
-
|
195
|
+
Open3.popen2e('rspec', 'spec', test) do |stdin, output_stream, wait_thread|
|
196
|
+
output_stream.each_line do |line|
|
181
197
|
puts line
|
182
198
|
end
|
183
199
|
exit_status = wait_thread.value.exitstatus
|
@@ -185,6 +201,10 @@ class PuppetDockerTools
|
|
185
201
|
end
|
186
202
|
end
|
187
203
|
|
204
|
+
if image
|
205
|
+
ENV['PUPPET_TEST_DOCKER_IMAGE'] = nil
|
206
|
+
end
|
207
|
+
|
188
208
|
fail "Running RSpec tests for #{directory} failed!" unless success
|
189
209
|
end
|
190
210
|
|
@@ -1,8 +1,2 @@
|
|
1
|
-
require 'serverspec'
|
2
|
-
require 'docker'
|
3
|
-
|
4
|
-
# Travis builds can take time
|
5
|
-
Docker.options[:read_timeout] = 7200
|
6
|
-
|
7
1
|
# Load any shared examples or context helpers
|
8
2
|
Dir[File.join(File.dirname(__FILE__), '..', '..', 'spec', 'support', '**', '*.rb')].sort.each { |f| require f }
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'docker'
|
2
1
|
require 'open3'
|
2
|
+
require 'json'
|
3
3
|
|
4
4
|
class PuppetDockerTools
|
5
5
|
module Utilities
|
@@ -15,13 +15,10 @@ class PuppetDockerTools
|
|
15
15
|
# command and a string containing the combined stdout and stderr
|
16
16
|
# from the push
|
17
17
|
def push_to_docker_repo(image_name, stream_output=true)
|
18
|
-
Open3.popen2e(
|
18
|
+
Open3.popen2e('docker', 'push', "#{image_name}") do |stdin, output_stream, wait_thread|
|
19
19
|
output=''
|
20
|
-
|
21
|
-
|
22
|
-
puts line
|
23
|
-
end
|
24
|
-
output += line
|
20
|
+
output_stream.each_line do |line|
|
21
|
+
stream_output ? (puts line) : (output += line)
|
25
22
|
end
|
26
23
|
exit_status = wait_thread.value.exitstatus
|
27
24
|
return exit_status, output
|
@@ -79,7 +76,8 @@ class PuppetDockerTools
|
|
79
76
|
# @param value The value you want to get from the labels, e.g. 'version'
|
80
77
|
# @param namespace The namespace for the value, e.g. 'org.label-schema'
|
81
78
|
def get_value_from_label(image, value: , namespace: )
|
82
|
-
|
79
|
+
output, _ = Open3.capture2('docker', 'inspect', '-f', '"{{json .Config.Labels }}"', "#{image}")
|
80
|
+
labels = JSON.parse(output)
|
83
81
|
labels["#{namespace}.#{value.tr('_', '-')}"]
|
84
82
|
rescue
|
85
83
|
nil
|
@@ -142,40 +140,19 @@ class PuppetDockerTools
|
|
142
140
|
# Pull a docker image
|
143
141
|
#
|
144
142
|
# @param image The image to pull. If the image does not include the tag to
|
145
|
-
# pull, it will pull
|
146
|
-
def pull(image)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
# Pull all tags for a docker image
|
157
|
-
#
|
158
|
-
# @param image The image to pull, e.g. puppet/puppetserver
|
159
|
-
def pull_all_tags(image)
|
160
|
-
Docker::Image.create('fromImage' => image)
|
161
|
-
|
162
|
-
# Filter through existing tags of that image so we can output what we pulled
|
163
|
-
images = Docker::Image.all('filter' => image)
|
164
|
-
images.each do |img|
|
165
|
-
timestamp = PuppetDockerTools::Utilities.format_timestamp(img.info["Created"])
|
166
|
-
puts "Pulled #{img.info["RepoTags"].join(', ')}, last updated #{timestamp}"
|
143
|
+
# pull, it will pull the 'latest' tag for that image
|
144
|
+
def pull(image, stream_output = true)
|
145
|
+
Open3.popen2e('docker', 'pull', "#{image}") do |stdin, output_stream, wait_thread|
|
146
|
+
output=''
|
147
|
+
output_stream.each_line do |line|
|
148
|
+
stream_output ? (puts line) : (output += line)
|
149
|
+
end
|
150
|
+
exit_status = wait_thread.value.exitstatus
|
151
|
+
puts output unless stream_output
|
152
|
+
fail unless exit_status == 0
|
167
153
|
end
|
168
154
|
end
|
169
155
|
|
170
|
-
# Pull a single tag of a docker image
|
171
|
-
#
|
172
|
-
# @param tag The image/tag to pull, e.g. puppet/puppetserver:latest
|
173
|
-
def pull_single_tag(tag)
|
174
|
-
image = Docker::Image.create('fromImage' => tag)
|
175
|
-
timestamp = PuppetDockerTools::Utilities.format_timestamp(image.info["Created"])
|
176
|
-
puts "Pulled #{image.info["RepoTags"].first}, last updated #{timestamp}"
|
177
|
-
end
|
178
|
-
|
179
156
|
# Pull the specified tags
|
180
157
|
#
|
181
158
|
# @param tags [Array] A list of tags to pull, e.g. ['centos:7', 'ubuntu:16.04']
|
@@ -197,9 +174,12 @@ class PuppetDockerTools
|
|
197
174
|
'DL4000',
|
198
175
|
'DL4001',
|
199
176
|
]
|
200
|
-
|
201
|
-
|
202
|
-
|
177
|
+
hadolint_command = ['hadolint']
|
178
|
+
ignore_rules.each do |rule|
|
179
|
+
hadolint_command << ['--ignore', rule]
|
180
|
+
end
|
181
|
+
hadolint_command << file
|
182
|
+
hadolint_command.flatten
|
203
183
|
end
|
204
184
|
|
205
185
|
# Get a value from a Dockerfile
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'puppet_docker_tools'
|
2
2
|
require 'puppet_docker_tools/runner'
|
3
|
-
require '
|
3
|
+
require 'tmpdir'
|
4
4
|
|
5
5
|
describe PuppetDockerTools::Runner do
|
6
6
|
def create_runner(directory:, repository:, namespace:, dockerfile:)
|
@@ -32,55 +32,50 @@ describe PuppetDockerTools::Runner do
|
|
32
32
|
end
|
33
33
|
|
34
34
|
describe '#build' do
|
35
|
-
let(:image) { double(Docker::Image) }
|
36
|
-
|
37
35
|
it 'builds a latest and version tag if version is found' do
|
38
36
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile)
|
39
37
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return('1.2.3')
|
40
|
-
expect(
|
41
|
-
expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:latest', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs }).and_return(image)
|
38
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--tag', 'test/test-image:latest', '--tag', 'test/test-image:1.2.3', runner.directory)
|
42
39
|
runner.build
|
43
40
|
end
|
44
41
|
|
45
42
|
it 'builds just a latest tag if no version is found' do
|
46
43
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile)
|
47
44
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return(nil)
|
48
|
-
expect(
|
45
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--tag', 'test/test-image:latest', runner.directory)
|
49
46
|
runner.build
|
50
47
|
end
|
51
48
|
|
52
49
|
it 'does not build a latest tag if latest is set to false' do
|
53
50
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile)
|
54
51
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return('1.2.3')
|
55
|
-
expect(
|
52
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--tag', 'test/test-image:1.2.3', runner.directory)
|
56
53
|
runner.build(latest: false)
|
57
54
|
end
|
58
55
|
|
59
56
|
it 'ignores the cache when that parameter is set' do
|
60
57
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile)
|
61
58
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return(nil)
|
62
|
-
expect(
|
59
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--no-cache', '--tag', 'test/test-image:latest', runner.directory)
|
63
60
|
runner.build(no_cache: true)
|
64
61
|
end
|
65
62
|
|
66
63
|
it 'passes the version when that parameter is set' do
|
67
64
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile_with_version)
|
68
|
-
expect(
|
69
|
-
expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:1.2.3', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs_with_version }).and_return(image)
|
65
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--build-arg', 'version=1.2.3', '--tag', 'test/test-image:latest', '--tag', 'test/test-image:1.2.3', runner.directory)
|
70
66
|
runner.build(version: '1.2.3')
|
71
67
|
end
|
72
68
|
|
73
69
|
it 'passes arbitrary build args' do
|
74
70
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile_with_arbitrary_args)
|
75
71
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: runner.namespace, directory: runner.directory, dockerfile: runner.dockerfile).and_return(nil)
|
76
|
-
expect(
|
72
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--build-arg', 'foo=bar', '--build-arg', 'baz=test=with=equals', '--tag', 'test/test-image:latest', runner.directory)
|
77
73
|
runner.build(build_args: ['foo=bar', 'baz=test=with=equals'])
|
78
74
|
end
|
79
75
|
|
80
76
|
it 'prioritizes version as a build arg over regular version' do
|
81
77
|
expect(File).to receive(:read).with("#{runner.directory}/#{runner.dockerfile}").and_return(read_dockerfile_with_version)
|
82
|
-
expect(
|
83
|
-
expect(Docker::Image).to receive(:build_from_dir).with(runner.directory, { 't' => 'test/test-image:1.2.3', 'dockerfile' => runner.dockerfile, 'buildargs' => buildargs_with_version }).and_return(image)
|
78
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--build-arg', 'version=1.2.3', '--tag', 'test/test-image:latest', '--tag', 'test/test-image:1.2.3', runner.directory)
|
84
79
|
runner.build(version: '1.2.4', build_args: ['version=1.2.3'])
|
85
80
|
end
|
86
81
|
|
@@ -88,53 +83,31 @@ describe PuppetDockerTools::Runner do
|
|
88
83
|
allow(File).to receive(:exist?).with('/tmp/test-image/Dockerfile.test').and_return(true)
|
89
84
|
expect(File).to receive(:read).with('/tmp/test-image/Dockerfile.test').and_return(read_dockerfile)
|
90
85
|
expect(PuppetDockerTools::Utilities).to receive(:get_value_from_env).with('version', namespace: 'org.label-schema', directory: '/tmp/test-image', dockerfile: 'Dockerfile.test').and_return(nil)
|
91
|
-
expect(
|
86
|
+
expect(Open3).to receive(:popen2e).with('docker', 'build', '--build-arg', 'vcs_ref=b0c5ead01b6cabdb3f01871bce699be165c3288f', '--build-arg', 'build_date=2018-06-08T17:18:13Z', '--no-cache', '--file', 'Dockerfile.test', '--tag', 'test/test-image:latest', runner.directory)
|
92
87
|
local_runner = create_runner(directory: '/tmp/test-image', repository: 'test', namespace: 'org.label-schema', dockerfile: 'Dockerfile.test')
|
93
|
-
local_runner.build
|
88
|
+
local_runner.build(no_cache: true)
|
94
89
|
end
|
95
90
|
end
|
96
91
|
|
97
92
|
describe '#lint' do
|
98
|
-
let(:passing_exit) {
|
99
|
-
{
|
100
|
-
'State' => {
|
101
|
-
'ExitCode' => 0
|
102
|
-
}
|
103
|
-
}
|
104
|
-
}
|
105
|
-
let(:failing_exit) {
|
106
|
-
{
|
107
|
-
'State' => {
|
108
|
-
'ExitCode' => 1
|
109
|
-
}
|
110
|
-
}
|
111
|
-
}
|
112
|
-
|
113
|
-
let(:container) { double(Docker::Container).as_null_object }
|
114
|
-
|
115
93
|
before do
|
116
|
-
allow(PuppetDockerTools::Utilities).to receive(:pull)
|
117
|
-
allow(Docker::Container).to receive(:create).and_return(container)
|
118
|
-
allow(container).to receive(:tap).and_return(container)
|
119
|
-
allow(container).to receive(:attach)
|
120
|
-
allow(container).to receive(:wait)
|
121
|
-
allow(container).to receive(:logs).and_return('container logs')
|
94
|
+
allow(PuppetDockerTools::Utilities).to receive(:pull)
|
122
95
|
end
|
123
96
|
|
124
97
|
it "should lint the container" do
|
125
|
-
allow(
|
98
|
+
allow(Open3).to receive(:capture2e).and_return(['', 0])
|
126
99
|
runner.lint
|
127
100
|
end
|
128
101
|
|
129
102
|
it "should exit with exit status if something went wrong" do
|
130
|
-
allow(
|
103
|
+
allow(Open3).to receive(:capture2e).and_return(['container logs', 1])
|
131
104
|
expect { runner.lint }.to raise_error(RuntimeError, /container logs/)
|
132
105
|
end
|
133
106
|
end
|
134
107
|
|
135
108
|
describe '#local_lint' do
|
136
109
|
it "should fail with logs if linting fails" do
|
137
|
-
allow(Open3).to receive(:capture2e).with(PuppetDockerTools::Utilities.get_hadolint_command('/tmp/test-image/Dockerfile')).and_return('container logs', 1)
|
110
|
+
allow(Open3).to receive(:capture2e).with(*PuppetDockerTools::Utilities.get_hadolint_command('/tmp/test-image/Dockerfile')).and_return('container logs', 1)
|
138
111
|
expect { runner.local_lint }.to raise_error(RuntimeError, /container logs/)
|
139
112
|
end
|
140
113
|
end
|
@@ -223,8 +196,8 @@ HERE
|
|
223
196
|
it "runs tests under the 'spec' directory" do
|
224
197
|
tests=["/tmp/test-image/spec/test1_spec.rb", "/tmp/test-image/spec/test2_spec.rb"]
|
225
198
|
expect(Dir).to receive(:glob).with("/tmp/test-image/spec/*_spec.rb").and_return(tests)
|
226
|
-
expect(Open3).to receive(:popen2e).with('rspec spec /tmp/test-image/spec/test1_spec.rb')
|
227
|
-
expect(Open3).to receive(:popen2e).with('rspec spec /tmp/test-image/spec/test2_spec.rb')
|
199
|
+
expect(Open3).to receive(:popen2e).with('rspec', 'spec', '/tmp/test-image/spec/test1_spec.rb')
|
200
|
+
expect(Open3).to receive(:popen2e).with('rspec', 'spec', '/tmp/test-image/spec/test2_spec.rb')
|
228
201
|
runner.spec
|
229
202
|
end
|
230
203
|
end
|
@@ -81,15 +81,20 @@ HERE
|
|
81
81
|
}
|
82
82
|
}
|
83
83
|
|
84
|
-
let(:
|
85
|
-
'
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
84
|
+
let(:labels) {
|
85
|
+
'{
|
86
|
+
"org.label-schema.build-date":"2018-08-24T21:31:54Z",
|
87
|
+
"org.label-schema.dockerfile":"/Dockerfile",
|
88
|
+
"org.label-schema.license":"Apache-2.0",
|
89
|
+
"org.label-schema.maintainer":"Puppet Release Team <release@puppet.com>",
|
90
|
+
"org.label-schema.name":"Puppet Server",
|
91
|
+
"org.label-schema.schema-version":"1.0",
|
92
|
+
"org.label-schema.url":"https://github.com/puppetlabs/puppetserver",
|
93
|
+
"org.label-schema.vcs-ref":"5296a6a86b141c9c1aeab63258205ae664d4108d",
|
94
|
+
"org.label-schema.vcs-url":"https://github.com/puppetlabs/puppetserver",
|
95
|
+
"org.label-schema.vendor":"Puppet",
|
96
|
+
"org.label-schema.version":"5.3.5"
|
97
|
+
}'
|
93
98
|
}
|
94
99
|
|
95
100
|
describe "#filter_build_args" do
|
@@ -107,11 +112,8 @@ HERE
|
|
107
112
|
end
|
108
113
|
|
109
114
|
describe "#get_value_from_label" do
|
110
|
-
let(:image) { double(Docker::Image).as_null_object }
|
111
|
-
|
112
115
|
before do
|
113
|
-
allow(
|
114
|
-
allow(image).to receive(:json).and_return(config_labels)
|
116
|
+
allow(Open3).to receive(:capture2).and_return(labels)
|
115
117
|
end
|
116
118
|
|
117
119
|
it "returns the value of a label" do
|
@@ -119,7 +121,7 @@ HERE
|
|
119
121
|
end
|
120
122
|
|
121
123
|
it "replaces '_' with '-' in the label name" do
|
122
|
-
expect(PuppetDockerTools::Utilities.get_value_from_label('puppet/puppetserver-test', value: 'vcs_ref', namespace: 'org.label-schema')).to eq('
|
124
|
+
expect(PuppetDockerTools::Utilities.get_value_from_label('puppet/puppetserver-test', value: 'vcs_ref', namespace: 'org.label-schema')).to eq('5296a6a86b141c9c1aeab63258205ae664d4108d')
|
123
125
|
end
|
124
126
|
|
125
127
|
it "returns nil if you ask for a value that isn't there" do
|
@@ -213,58 +215,18 @@ HERE
|
|
213
215
|
|
214
216
|
describe '#pull' do
|
215
217
|
it 'will pull a single image if the image has a tag' do
|
216
|
-
expect(
|
218
|
+
expect(Open3).to receive(:popen2e).with('docker', 'pull', 'test/test-dir:latest')
|
217
219
|
PuppetDockerTools::Utilities.pull('test/test-dir:latest')
|
218
220
|
end
|
219
|
-
|
220
|
-
it 'will pull all the images if no tag is passed' do
|
221
|
-
expect(PuppetDockerTools::Utilities).to receive(:pull_all_tags).with('test/test-dir')
|
222
|
-
PuppetDockerTools::Utilities.pull('test/test-dir')
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
describe '#pull_all_tags' do
|
227
|
-
let(:image_info) {
|
228
|
-
{
|
229
|
-
'Created' => '2018-05-11T20:09:32Z',
|
230
|
-
'RepoTags' => ['latest', '1.2.3'],
|
231
|
-
}
|
232
|
-
}
|
233
|
-
|
234
|
-
let(:image) { double(Docker::Image) }
|
235
|
-
let(:images) { [image] }
|
236
|
-
|
237
|
-
it 'pulls the tags' do
|
238
|
-
expect(Docker::Image).to receive(:create).with('fromImage' => 'test/test-dir')
|
239
|
-
expect(Docker::Image).to receive(:all).and_return(images)
|
240
|
-
expect(image).to receive(:info).and_return(image_info).twice
|
241
|
-
PuppetDockerTools::Utilities.pull_all_tags('test/test-dir')
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
describe '#pull_single_tag' do
|
246
|
-
let(:image_info) {
|
247
|
-
{
|
248
|
-
'Created' => '2018-05-11T20:09:32Z',
|
249
|
-
'RepoTags' => ['1.2.3'],
|
250
|
-
}
|
251
|
-
}
|
252
|
-
let(:image) { double(Docker::Image) }
|
253
|
-
|
254
|
-
it 'pulls the single tag' do
|
255
|
-
expect(Docker::Image).to receive(:create).with('fromImage' => 'test/test-dir:1.2.3').and_return(image)
|
256
|
-
expect(image).to receive(:info).and_return(image_info).twice
|
257
|
-
PuppetDockerTools::Utilities.pull_single_tag('test/test-dir:1.2.3')
|
258
|
-
end
|
259
221
|
end
|
260
222
|
|
261
223
|
describe '#get_hadolint_command' do
|
262
224
|
it 'generates a commmand with a dockerfile' do
|
263
|
-
expect(PuppetDockerTools::Utilities.get_hadolint_command('test/Dockerfile')).to eq('hadolint --ignore DL3008 --ignore DL3018 --ignore DL4000 --ignore DL4001 test/Dockerfile')
|
225
|
+
expect(PuppetDockerTools::Utilities.get_hadolint_command('test/Dockerfile')).to eq(['hadolint', '--ignore', 'DL3008', '--ignore', 'DL3018', '--ignore', 'DL4000', '--ignore', 'DL4001', 'test/Dockerfile'])
|
264
226
|
end
|
265
227
|
|
266
228
|
it 'defaults to generating a command that reads from stdin' do
|
267
|
-
expect(PuppetDockerTools::Utilities.get_hadolint_command).to eq('hadolint --ignore DL3008 --ignore DL3018 --ignore DL4000 --ignore DL4001 -')
|
229
|
+
expect(PuppetDockerTools::Utilities.get_hadolint_command).to eq(['hadolint', '--ignore', 'DL3008', '--ignore', 'DL3018', '--ignore', 'DL4000', '--ignore', 'DL4001', '-'])
|
268
230
|
end
|
269
231
|
end
|
270
232
|
|
@@ -1,11 +1,44 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
1
3
|
shared_context 'with a docker container' do
|
4
|
+
def is_running?(container)
|
5
|
+
is_running = false
|
6
|
+
output, _ = Open3.capture2e('docker', 'inspect', '--format', "'{{ .Config.Healthcheck }}'", "#{container}")
|
7
|
+
output.chomp!
|
8
|
+
output.gsub!(/'/, '')
|
9
|
+
|
10
|
+
# no configured healthcheck
|
11
|
+
if output.chomp == "<nil>"
|
12
|
+
command = ['docker', 'inspect', '-f', "'{{.State.Status}}'", "#{container}"]
|
13
|
+
else
|
14
|
+
command = ['docker', 'inspect', '-f', "'{{.State.Health.Status}}'", "#{container}"]
|
15
|
+
end
|
16
|
+
|
17
|
+
while ! is_running
|
18
|
+
output, _ = Open3.capture2e(*command)
|
19
|
+
output.chomp!
|
20
|
+
output.gsub!(/'/, '')
|
21
|
+
|
22
|
+
case output
|
23
|
+
when 'healthy', 'running'
|
24
|
+
return true
|
25
|
+
when 'unhealthy', 'removing', 'paused', 'exited', 'dead'
|
26
|
+
return false
|
27
|
+
end
|
28
|
+
|
29
|
+
puts "Container is not running yet, will try again in 5 seconds..."
|
30
|
+
sleep(5)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
2
34
|
before(:all) do
|
3
|
-
@container =
|
4
|
-
@container
|
35
|
+
@container = %x(docker run --detach --rm -i #{@image}).chomp
|
36
|
+
unless is_running?(@container)
|
37
|
+
fail "something went wrong with container startup!"
|
38
|
+
end
|
5
39
|
end
|
6
40
|
|
7
41
|
after(:all) do
|
8
|
-
@container
|
9
|
-
@container.delete(force: true)
|
42
|
+
%x(docker container kill #{@container})
|
10
43
|
end
|
11
44
|
end
|
@@ -1,9 +1,19 @@
|
|
1
|
+
require 'json'
|
1
2
|
shared_context 'with a docker image' do
|
2
3
|
before(:all) do
|
3
|
-
|
4
|
+
if ENV['PUPPET_TEST_DOCKER_IMAGE'] && !ENV['PUPPET_TEST_DOCKER_IMAGE'].empty?
|
5
|
+
@image=ENV['PUPPET_TEST_DOCKER_IMAGE']
|
6
|
+
else
|
7
|
+
@image = "test/#{File.basename(CURRENT_DIRECTORY)}:#{Random.rand(1000)}"
|
8
|
+
%x(docker image build --tag #{@image} #{CURRENT_DIRECTORY})
|
9
|
+
end
|
10
|
+
puts "Running tests on #{@image}..."
|
11
|
+
@image_json = JSON.parse(%x(docker inspect #{@image}))
|
12
|
+
end
|
4
13
|
|
5
|
-
|
6
|
-
|
7
|
-
|
14
|
+
after(:all) do
|
15
|
+
if !ENV['PUPPET_TEST_DOCKER_IMAGE'] || ENV['PUPPET_TEST_DOCKER_IMAGE'].empty?
|
16
|
+
%x(docker image rm --force #{@image})
|
17
|
+
end
|
8
18
|
end
|
9
19
|
end
|
@@ -1,11 +1,45 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
shared_examples "a running container" do |command, exit_code, expected_output|
|
4
|
+
unless command.is_a? Array
|
5
|
+
command = command.split(' ')
|
6
|
+
end
|
7
|
+
|
8
|
+
if expected_output && exit_code
|
9
|
+
it "should run #{command} with output matching #{expected_output} and exit code #{exit_code}" do
|
10
|
+
output, status = Open3.capture2e('docker', 'exec', @container, *command)
|
11
|
+
expect(output).to match(/#{expected_output}/)
|
12
|
+
expect(status.exitstatus).to eq(exit_code)
|
13
|
+
end
|
14
|
+
elsif expected_output
|
15
|
+
it "should run #{command} with output matching #{expected_output}" do
|
16
|
+
output, _ = Open3.capture2e('docker', 'exec', @container, *command)
|
17
|
+
expect(output).to match(/#{expected_output}/)
|
18
|
+
end
|
19
|
+
elsif exit_code
|
20
|
+
it "should run #{command} with exit code #{exit_code}" do
|
21
|
+
_, status = Open3.capture2e('docker', 'exec', @container, *command)
|
22
|
+
expect(status.exitstatus).to eq(exit_code)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
shared_examples "a service in a container" do |service, user, arg, pid|
|
29
|
+
if service && user
|
30
|
+
it "should run #{service} as #{user}" do
|
31
|
+
if pid
|
32
|
+
output, status = Open3.capture2e('docker', 'exec', @container, 'ps', '-f', '--quick-pid', pid)
|
33
|
+
else
|
34
|
+
output, status = Open3.capture2e('docker', 'exec', @container, 'ps', '-f', '-u', user)
|
35
|
+
output = output.split("\n").select { |proc| proc[/#{service}/] }.join('')
|
36
|
+
end
|
37
|
+
expect(status.exitstatus).to eq(0)
|
38
|
+
expect(output).to match(/#{service}/)
|
39
|
+
expect(output).to match(/#{user}/)
|
40
|
+
if arg
|
41
|
+
expect(output).to match(/#{arg}/)
|
42
|
+
end
|
43
|
+
end
|
10
44
|
end
|
11
45
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet_docker_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: docker-api
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '1.34'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '1.34'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rspec
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +24,6 @@ dependencies:
|
|
38
24
|
- - "~>"
|
39
25
|
- !ruby/object:Gem::Version
|
40
26
|
version: '3.0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: serverspec
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '2.41'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '2.41'
|
55
27
|
- !ruby/object:Gem::Dependency
|
56
28
|
name: docopt
|
57
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,11 +54,9 @@ files:
|
|
82
54
|
- lib/puppet_docker_tools/utilities.rb
|
83
55
|
- spec/lib/puppet_docker_tools/runner_spec.rb
|
84
56
|
- spec/lib/puppet_docker_tools/utilities_spec.rb
|
85
|
-
- spec/support/context/using_alpine.rb
|
86
|
-
- spec/support/context/using_centos.rb
|
87
57
|
- spec/support/context/with_docker_container.rb
|
88
|
-
- spec/support/context/with_docker_container_dummy_cmd.rb
|
89
58
|
- spec/support/context/with_docker_image.rb
|
59
|
+
- spec/support/context/with_transient_docker_container.rb
|
90
60
|
- spec/support/examples/running_container.rb
|
91
61
|
homepage: https://github.com/puppetlabs/puppet_docker_tools
|
92
62
|
licenses:
|
@@ -108,7 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
78
|
version: '0'
|
109
79
|
requirements: []
|
110
80
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
81
|
+
rubygems_version: 2.6.14
|
112
82
|
signing_key:
|
113
83
|
specification_version: 3
|
114
84
|
summary: Puppet tools for building docker images
|
@@ -1,18 +0,0 @@
|
|
1
|
-
shared_context 'with a docker container with a dummy cmd' do
|
2
|
-
before(:all) do
|
3
|
-
@image = Docker::Image.build_from_dir(CURRENT_DIRECTORY)
|
4
|
-
@container = Docker::Container.create(
|
5
|
-
'Image' => @image.id,
|
6
|
-
'Cmd' => ['sh', '-c', 'while true; do sleep 1; done']
|
7
|
-
)
|
8
|
-
@container.start
|
9
|
-
|
10
|
-
set :backend, :docker
|
11
|
-
set :docker_container, @container.id
|
12
|
-
end
|
13
|
-
|
14
|
-
after(:all) do
|
15
|
-
@container.kill
|
16
|
-
@container.delete(force: true)
|
17
|
-
end
|
18
|
-
end
|