dockerspec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +7 -0
  3. data/CHANGELOG.md +7 -0
  4. data/CONTRIBUTING.md +13 -0
  5. data/LICENSE +190 -0
  6. data/README.md +202 -0
  7. data/Rakefile +57 -0
  8. data/TESTING.md +30 -0
  9. data/TODO.md +6 -0
  10. data/lib/dockerspec.rb +21 -0
  11. data/lib/dockerspec/builder.rb +408 -0
  12. data/lib/dockerspec/builder/config_helpers.rb +425 -0
  13. data/lib/dockerspec/builder/image_gc.rb +71 -0
  14. data/lib/dockerspec/builder/logger.rb +56 -0
  15. data/lib/dockerspec/builder/logger/ci.rb +69 -0
  16. data/lib/dockerspec/builder/logger/debug.rb +47 -0
  17. data/lib/dockerspec/builder/logger/info.rb +111 -0
  18. data/lib/dockerspec/builder/logger/silent.rb +51 -0
  19. data/lib/dockerspec/builder/matchers.rb +134 -0
  20. data/lib/dockerspec/builder/matchers/helpers.rb +88 -0
  21. data/lib/dockerspec/docker_gem.rb +25 -0
  22. data/lib/dockerspec/exceptions.rb +26 -0
  23. data/lib/dockerspec/helper/ci.rb +61 -0
  24. data/lib/dockerspec/helper/docker.rb +44 -0
  25. data/lib/dockerspec/helper/multiple_sources_description.rb +142 -0
  26. data/lib/dockerspec/helper/rspec_example_helpers.rb +48 -0
  27. data/lib/dockerspec/rspec_assertions.rb +54 -0
  28. data/lib/dockerspec/rspec_resources.rb +198 -0
  29. data/lib/dockerspec/rspec_settings.rb +29 -0
  30. data/lib/dockerspec/runner.rb +374 -0
  31. data/lib/dockerspec/serverspec.rb +20 -0
  32. data/lib/dockerspec/serverspec/rspec_resources.rb +174 -0
  33. data/lib/dockerspec/serverspec/rspec_settings.rb +27 -0
  34. data/lib/dockerspec/serverspec/runner.rb +302 -0
  35. data/lib/dockerspec/serverspec/specinfra_backend.rb +128 -0
  36. data/lib/dockerspec/serverspec/specinfra_hack.rb +43 -0
  37. data/lib/dockerspec/version.rb +29 -0
  38. data/spec/spec_helper.rb +44 -0
  39. 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