puppet_docker_tools 0.1.5 → 0.2.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 +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
|