dockerspec 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +13 -0
- data/LICENSE +190 -0
- data/README.md +202 -0
- data/Rakefile +57 -0
- data/TESTING.md +30 -0
- data/TODO.md +6 -0
- data/lib/dockerspec.rb +21 -0
- data/lib/dockerspec/builder.rb +408 -0
- data/lib/dockerspec/builder/config_helpers.rb +425 -0
- data/lib/dockerspec/builder/image_gc.rb +71 -0
- data/lib/dockerspec/builder/logger.rb +56 -0
- data/lib/dockerspec/builder/logger/ci.rb +69 -0
- data/lib/dockerspec/builder/logger/debug.rb +47 -0
- data/lib/dockerspec/builder/logger/info.rb +111 -0
- data/lib/dockerspec/builder/logger/silent.rb +51 -0
- data/lib/dockerspec/builder/matchers.rb +134 -0
- data/lib/dockerspec/builder/matchers/helpers.rb +88 -0
- data/lib/dockerspec/docker_gem.rb +25 -0
- data/lib/dockerspec/exceptions.rb +26 -0
- data/lib/dockerspec/helper/ci.rb +61 -0
- data/lib/dockerspec/helper/docker.rb +44 -0
- data/lib/dockerspec/helper/multiple_sources_description.rb +142 -0
- data/lib/dockerspec/helper/rspec_example_helpers.rb +48 -0
- data/lib/dockerspec/rspec_assertions.rb +54 -0
- data/lib/dockerspec/rspec_resources.rb +198 -0
- data/lib/dockerspec/rspec_settings.rb +29 -0
- data/lib/dockerspec/runner.rb +374 -0
- data/lib/dockerspec/serverspec.rb +20 -0
- data/lib/dockerspec/serverspec/rspec_resources.rb +174 -0
- data/lib/dockerspec/serverspec/rspec_settings.rb +27 -0
- data/lib/dockerspec/serverspec/runner.rb +302 -0
- data/lib/dockerspec/serverspec/specinfra_backend.rb +128 -0
- data/lib/dockerspec/serverspec/specinfra_hack.rb +43 -0
- data/lib/dockerspec/version.rb +29 -0
- data/spec/spec_helper.rb +44 -0
- metadata +293 -0
@@ -0,0 +1,425 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
+
# Copyright:: Copyright (c) 2015 Xabier de Zuazo
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
module Dockerspec
|
21
|
+
class Builder
|
22
|
+
#
|
23
|
+
# Some helpers to get container image information from its JSON data.
|
24
|
+
#
|
25
|
+
# **Note:** Keep in mind that not all the available Dockerfile instructions
|
26
|
+
# can be checked in the docker image. You should use
|
27
|
+
# {Dockerspec::Serverspec::RSpecResources#docker_run} to check some
|
28
|
+
# instructions like `FROM`, `RUN`, `ADD` and `COPY` (see the examples
|
29
|
+
# there).
|
30
|
+
#
|
31
|
+
module ConfigHelpers
|
32
|
+
#
|
33
|
+
# Returns the image configuration.
|
34
|
+
#
|
35
|
+
# @return [Hash] The image configuration.
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
#
|
39
|
+
def image_config
|
40
|
+
@image.json['Config']
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Returns the image size in bytes.
|
45
|
+
#
|
46
|
+
# @example RSpec Example
|
47
|
+
# describe docker_build(path: '.') do
|
48
|
+
# its(:size) { should be < 20 * 2**20 } # 20M
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# @return [Fixnum] The image size in bytes.
|
52
|
+
#
|
53
|
+
# @api public
|
54
|
+
#
|
55
|
+
def size
|
56
|
+
@image.json['VirtualSize']
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Returns the image architecture.
|
61
|
+
#
|
62
|
+
# @example RSpec Example
|
63
|
+
# describe docker_build(path: '.') do
|
64
|
+
# its(:arch) { should eq 'amd64' }
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# @return [String] The architecture name.
|
68
|
+
#
|
69
|
+
# @api public
|
70
|
+
#
|
71
|
+
def architecture
|
72
|
+
@image.json['Architecture']
|
73
|
+
end
|
74
|
+
|
75
|
+
alias_method :arch, :architecture
|
76
|
+
|
77
|
+
#
|
78
|
+
# Returns the image Operating System.
|
79
|
+
#
|
80
|
+
# @example RSpec Example
|
81
|
+
# describe docker_build(path: '.') do
|
82
|
+
# its(:os) { should eq 'linux' }
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# @return [String] The OS name.
|
86
|
+
#
|
87
|
+
# @api public
|
88
|
+
#
|
89
|
+
def os
|
90
|
+
@image.json['Os']
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Returns the image maintainer or author (`MAINTAINER`).
|
95
|
+
#
|
96
|
+
# @example Basic RSpec Example
|
97
|
+
# describe docker_build(path: '.') do
|
98
|
+
# its(:maintainer) { should eq 'John Doe "john.doe@example.com"' }
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# @example RSpec Example Using *Have* Matchers
|
102
|
+
# describe docker_build(path: '.') do
|
103
|
+
# it { should have_maintainer 'John Doe "john.doe@example.com"' }
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# @example RSpec Example Using a Regular Expression
|
107
|
+
# describe docker_build(path: '.') do
|
108
|
+
# it { should have_maintainer(/John Doe/) }
|
109
|
+
# end
|
110
|
+
#
|
111
|
+
# @return [String] The maintainer.
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
#
|
115
|
+
def maintainer
|
116
|
+
@image.json['Author']
|
117
|
+
end
|
118
|
+
|
119
|
+
#
|
120
|
+
# Returns the image command (`CMD`).
|
121
|
+
#
|
122
|
+
# @example Basic RSpec Example
|
123
|
+
# describe docker_build(path: '.') do
|
124
|
+
# its(:cmd) { should eq ['/usr/bin/supervisord'] }
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# @example RSpec Example Using *Have* Matchers
|
128
|
+
# describe docker_build(path: '.') do
|
129
|
+
# it { should have_cmd ['/usr/bin/supervisord'] }
|
130
|
+
# end
|
131
|
+
#
|
132
|
+
# @return [Array] The image command.
|
133
|
+
#
|
134
|
+
# @api public
|
135
|
+
#
|
136
|
+
def cmd
|
137
|
+
image_config['Cmd']
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Returns the image labels (`LABEL`).
|
142
|
+
#
|
143
|
+
# @example Basic RSpec Example
|
144
|
+
# describe docker_build(path: '.') do
|
145
|
+
# its(:labels) { should include 'description' => 'My Container' }
|
146
|
+
# end
|
147
|
+
#
|
148
|
+
# @example RSpec Example Using *Have* Matchers
|
149
|
+
# describe docker_build(path: '.') do
|
150
|
+
# it { should have_label 'description' => 'My Container' }
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# @example RSpec Example Checking Only the Existence of the label
|
154
|
+
# describe docker_build(path: '.') do
|
155
|
+
# it { should have_label 'description' }
|
156
|
+
# end
|
157
|
+
#
|
158
|
+
# @return [Hash] The labels list.
|
159
|
+
#
|
160
|
+
# @api public
|
161
|
+
#
|
162
|
+
def labels
|
163
|
+
image_config['Labels']
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Returns **the first** label as a string (`LABEL`).
|
168
|
+
#
|
169
|
+
# @example Basic RSpec Example
|
170
|
+
# describe docker_build(path: '.') do
|
171
|
+
# its(:label) { should eq 'description=My Container' }
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# @return [String] The first label.
|
175
|
+
#
|
176
|
+
# @api public
|
177
|
+
#
|
178
|
+
def label
|
179
|
+
labels.first.join('=')
|
180
|
+
end
|
181
|
+
|
182
|
+
#
|
183
|
+
# Returns the image exposed ports (`EXPOSE`).
|
184
|
+
#
|
185
|
+
# @example Basic RSpec Example
|
186
|
+
# describe docker_build(path: '.') do
|
187
|
+
# its(:exposes) { should include '80' }
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# @example RSpec Example Using *Have* Matchers
|
191
|
+
# describe docker_build(path: '.') do
|
192
|
+
# it { should have_expose '80' }
|
193
|
+
# end
|
194
|
+
#
|
195
|
+
# @example RSpec Example Using Regular Expressions
|
196
|
+
# describe docker_build(path: '.') do
|
197
|
+
# it { should have_expose(/80$/) }
|
198
|
+
# end
|
199
|
+
#
|
200
|
+
# @return [Array] The exposed ports list.
|
201
|
+
#
|
202
|
+
# @api public
|
203
|
+
#
|
204
|
+
def exposes
|
205
|
+
image_config['ExposedPorts'].keys.map { |x| x.delete('/tcp') }
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Returns **the first** exposed port (`EXPOSE`).
|
210
|
+
#
|
211
|
+
# @example Basic RSpec Example
|
212
|
+
# describe docker_build(path: '.') do
|
213
|
+
# its(:expose) { should eq '80' }
|
214
|
+
# end
|
215
|
+
#
|
216
|
+
# @return [String] The exposed port.
|
217
|
+
#
|
218
|
+
# @api public
|
219
|
+
#
|
220
|
+
def expose
|
221
|
+
exposes.first
|
222
|
+
end
|
223
|
+
|
224
|
+
#
|
225
|
+
# Returns the image environment (`ENV`).
|
226
|
+
#
|
227
|
+
# @example Basic RSpec Example
|
228
|
+
# describe docker_build(path: '.') do
|
229
|
+
# its(:env) { should include 'container' => 'docker' }
|
230
|
+
# end
|
231
|
+
#
|
232
|
+
# @example RSpec Example Using *Have* Matchers
|
233
|
+
# describe docker_build(path: '.') do
|
234
|
+
# it { should have_env 'container' => 'docker' }
|
235
|
+
# end
|
236
|
+
#
|
237
|
+
# @example RSpec Example Checking Only the Existence of the Env Variable
|
238
|
+
# describe docker_build(path: '.') do
|
239
|
+
# it { should have_env 'container' }
|
240
|
+
# end
|
241
|
+
#
|
242
|
+
# @return [Hash] The environment.
|
243
|
+
#
|
244
|
+
# @api public
|
245
|
+
#
|
246
|
+
def envs
|
247
|
+
@env ||=
|
248
|
+
image_config['Env'].each_with_object({}) do |var, memo|
|
249
|
+
key, value = var.split('=', 2)
|
250
|
+
memo[key] = value
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
alias_method :env, :envs
|
255
|
+
|
256
|
+
#
|
257
|
+
# Returns the image entrypoint (`ENTRYPOINT`).
|
258
|
+
#
|
259
|
+
# @example Basic RSpec Example
|
260
|
+
# describe docker_build(path: '.') do
|
261
|
+
# its(:entrypoint) { should eq ['/entrypoint.sh'] }
|
262
|
+
# end
|
263
|
+
#
|
264
|
+
# @example RSpec Example Using *Have* Matchers
|
265
|
+
# describe docker_build(path: '.') do
|
266
|
+
# it { should have_entrypoint ['/entrypoint.sh'] }
|
267
|
+
# end
|
268
|
+
#
|
269
|
+
# @return [Array] The image entrypoint.
|
270
|
+
#
|
271
|
+
# @api public
|
272
|
+
#
|
273
|
+
def entrypoint
|
274
|
+
image_config['Entrypoint']
|
275
|
+
end
|
276
|
+
|
277
|
+
#
|
278
|
+
# Returns the image volumes (`VOLUME`).
|
279
|
+
#
|
280
|
+
# @example Basic RSpec Example
|
281
|
+
# describe docker_build(path: '.') do
|
282
|
+
# its(:volumes) { should include '/data1' }
|
283
|
+
# end
|
284
|
+
#
|
285
|
+
# @example RSpec Example Using *Have* Matchers
|
286
|
+
# describe docker_build(path: '.') do
|
287
|
+
# it { should have_volume '/data1' }
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# @example RSpec Example Using Regular Expressions
|
291
|
+
# describe docker_build(path: '.') do
|
292
|
+
# it { should have_volume %r{^/data[0-9]+$} }
|
293
|
+
# end
|
294
|
+
#
|
295
|
+
# @return [Array] The image volume list.
|
296
|
+
#
|
297
|
+
# @api public
|
298
|
+
#
|
299
|
+
def volumes
|
300
|
+
image_config['Volumes'].keys
|
301
|
+
end
|
302
|
+
|
303
|
+
#
|
304
|
+
# Returns **the first** volume (`VOLUME`).
|
305
|
+
#
|
306
|
+
# @example Basic RSpec Example
|
307
|
+
# describe docker_build(path: '.') do
|
308
|
+
# its(:volume) { should eq '/data1' }
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
# @return [String] The first volume.
|
312
|
+
#
|
313
|
+
# @api public
|
314
|
+
#
|
315
|
+
def volume
|
316
|
+
volumes.first
|
317
|
+
end
|
318
|
+
|
319
|
+
#
|
320
|
+
# Returns the image user (`USER`).
|
321
|
+
#
|
322
|
+
# @example Basic RSpec Example
|
323
|
+
# describe docker_build(path: '.') do
|
324
|
+
# its(:user) { should eq 'nobody' }
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# @example RSpec Example Using *Have* Matchers
|
328
|
+
# describe docker_build(path: '.') do
|
329
|
+
# it { should have_user 'nobody' }
|
330
|
+
# end
|
331
|
+
#
|
332
|
+
# @return [String] The username.
|
333
|
+
#
|
334
|
+
# @api public
|
335
|
+
#
|
336
|
+
def user
|
337
|
+
image_config['User']
|
338
|
+
end
|
339
|
+
|
340
|
+
#
|
341
|
+
# Returns the image workdir (`WORKDIR`).
|
342
|
+
#
|
343
|
+
# @example Basic RSpec Example
|
344
|
+
# describe docker_build(path: '.') do
|
345
|
+
# its(:workdir) { should eq '/opt/myapp' }
|
346
|
+
# end
|
347
|
+
#
|
348
|
+
# @example RSpec Example Using *Have* Matchers
|
349
|
+
# describe docker_build(path: '.') do
|
350
|
+
# it { should have_workdir '/opt/myapp' }
|
351
|
+
# end
|
352
|
+
#
|
353
|
+
# @example RSpec Example Using Regular Expressions
|
354
|
+
# describe docker_build(path: '.') do
|
355
|
+
# it { should have_workdir %r{^/opt/myapp} }
|
356
|
+
# end
|
357
|
+
#
|
358
|
+
# @return [String] The workdir.
|
359
|
+
#
|
360
|
+
# @api public
|
361
|
+
#
|
362
|
+
def workdir
|
363
|
+
image_config['WorkingDir']
|
364
|
+
end
|
365
|
+
|
366
|
+
#
|
367
|
+
# Returns the onbuild instructions (`ONBUILD`).
|
368
|
+
#
|
369
|
+
# @example Basic RSpec Example
|
370
|
+
# describe docker_build(path: '.') do
|
371
|
+
# its(:onbuilds) { should include 'RUN echo onbuild' }
|
372
|
+
# end
|
373
|
+
#
|
374
|
+
# @example RSpec Example Using *Have* Matchers
|
375
|
+
# describe docker_build(path: '.') do
|
376
|
+
# it { should have_onbuild 'RUN echo onbuild' }
|
377
|
+
# end
|
378
|
+
#
|
379
|
+
# @return [Array] The onbuild instructions.
|
380
|
+
#
|
381
|
+
# @api public
|
382
|
+
#
|
383
|
+
def onbuilds
|
384
|
+
image_config['OnBuild']
|
385
|
+
end
|
386
|
+
|
387
|
+
#
|
388
|
+
# Returns **the first** onbuild instruction (`ONBUILD`).
|
389
|
+
#
|
390
|
+
# @example Basic RSpec Example
|
391
|
+
# describe docker_build(path: '.') do
|
392
|
+
# its(:onbuild) { should eq 'RUN echo onbuild' }
|
393
|
+
# end
|
394
|
+
#
|
395
|
+
# @return [String] The onbuild instruction.
|
396
|
+
#
|
397
|
+
# @api public
|
398
|
+
#
|
399
|
+
def onbuild
|
400
|
+
onbuilds.first
|
401
|
+
end
|
402
|
+
|
403
|
+
#
|
404
|
+
# Returns the stop signal (`STOPSIGNAL`).
|
405
|
+
#
|
406
|
+
# @example Basic RSpec Example
|
407
|
+
# describe docker_build(path: '.') do
|
408
|
+
# its(:stopsignal) { should eq 'SIGTERM' }
|
409
|
+
# end
|
410
|
+
#
|
411
|
+
# @example RSpec Example Using *Have* Matchers
|
412
|
+
# describe docker_build(path: '.') do
|
413
|
+
# it { should have_stopsignal 'SIGTERM' }
|
414
|
+
# end
|
415
|
+
#
|
416
|
+
# @return [String] The stop signal name.
|
417
|
+
#
|
418
|
+
# @api public
|
419
|
+
#
|
420
|
+
def stopsignal
|
421
|
+
image_config['StopSignal']
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
+
# Copyright:: Copyright (c) 2015 Xabier de Zuazo
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'singleton'
|
21
|
+
require 'dockerspec/docker_gem'
|
22
|
+
|
23
|
+
module Dockerspec
|
24
|
+
class Builder
|
25
|
+
#
|
26
|
+
# A class to manage docker image deletion. The class stores the images
|
27
|
+
# created by {Dockerspec::Builder} objects and deletes them at the end of
|
28
|
+
# the Ruby/RSpec run.
|
29
|
+
#
|
30
|
+
class ImageGC
|
31
|
+
include Singleton
|
32
|
+
|
33
|
+
#
|
34
|
+
# The Image Garbage Collector constructor.
|
35
|
+
#
|
36
|
+
# @api public
|
37
|
+
#
|
38
|
+
def initialize
|
39
|
+
@images = []
|
40
|
+
ObjectSpace.define_finalizer(self, proc { finalize })
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Adds a Docker image to be garbage deleted at the end.
|
45
|
+
#
|
46
|
+
# @param image [String] Docker image ID.
|
47
|
+
#
|
48
|
+
# @return void
|
49
|
+
#
|
50
|
+
# @api public
|
51
|
+
#
|
52
|
+
def add(image)
|
53
|
+
@images << image
|
54
|
+
end
|
55
|
+
|
56
|
+
#
|
57
|
+
# Removes all the Docker images.
|
58
|
+
#
|
59
|
+
# Automatically called at the end of the RSpec/Ruby run.
|
60
|
+
#
|
61
|
+
# @return void
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
#
|
65
|
+
def finalize
|
66
|
+
@images.each { |i| ::Docker::Image.remove(i, force: true) }
|
67
|
+
@images = []
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|