dockerspec 0.2.0 → 0.3.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/CHANGELOG.md +34 -0
- data/LICENSE +1 -1
- data/README.md +190 -24
- data/Rakefile +60 -6
- data/TODO.md +3 -2
- data/lib/dockerspec.rb +1 -2
- data/lib/dockerspec/builder.rb +13 -6
- data/lib/dockerspec/builder/config_helpers.rb +8 -3
- data/lib/dockerspec/builder/logger/ci.rb +2 -2
- data/lib/dockerspec/builder/matchers.rb +32 -51
- data/lib/dockerspec/configuration.rb +188 -0
- data/lib/dockerspec/docker_exception_parser.rb +2 -2
- data/lib/dockerspec/engine/base.rb +156 -0
- data/lib/dockerspec/engine/infrataster.rb +87 -0
- data/lib/dockerspec/engine/specinfra.rb +130 -0
- data/lib/dockerspec/engine/specinfra/backend.rb +163 -0
- data/lib/dockerspec/{serverspec/specinfra_hack.rb → engine/specinfra/backend_hack.rb} +17 -3
- data/lib/dockerspec/engine_list.rb +150 -0
- data/lib/dockerspec/exceptions.rb +13 -0
- data/lib/dockerspec/helper/multiple_sources_description.rb +3 -3
- data/lib/dockerspec/helper/rspec_example_helpers.rb +86 -6
- data/lib/dockerspec/infrataster.rb +26 -0
- data/lib/dockerspec/rspec.rb +21 -0
- data/lib/dockerspec/{rspec_configuration.rb → rspec/configuration.rb} +1 -1
- data/lib/dockerspec/rspec/resources.rb +602 -0
- data/lib/dockerspec/rspec/resources/its_container.rb +110 -0
- data/lib/dockerspec/{rspec_settings.rb → rspec/settings.rb} +5 -1
- data/lib/dockerspec/runner.rb +2 -357
- data/lib/dockerspec/runner/base.rb +367 -0
- data/lib/dockerspec/runner/compose.rb +322 -0
- data/lib/dockerspec/runner/docker.rb +302 -0
- data/lib/dockerspec/runner/serverspec.rb +21 -0
- data/lib/dockerspec/runner/serverspec/base.rb +185 -0
- data/lib/dockerspec/runner/serverspec/compose.rb +106 -0
- data/lib/dockerspec/runner/serverspec/docker.rb +116 -0
- data/lib/dockerspec/runner/serverspec/rspec.rb +20 -0
- data/lib/dockerspec/{serverspec/rspec_settings.rb → runner/serverspec/rspec/settings.rb} +1 -1
- data/lib/dockerspec/serverspec.rb +12 -2
- data/lib/dockerspec/version.rb +1 -1
- data/spec/spec_helper.rb +6 -2
- metadata +84 -15
- data/lib/dockerspec/rspec_assertions.rb +0 -54
- data/lib/dockerspec/rspec_resources.rb +0 -203
- data/lib/dockerspec/serverspec/rspec_resources.rb +0 -179
- data/lib/dockerspec/serverspec/runner.rb +0 -305
- data/lib/dockerspec/serverspec/specinfra_backend.rb +0 -128
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
#
|
3
|
+
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
+
# Copyright:: Copyright (c) 2016 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 'dockerspec/runner/compose'
|
21
|
+
require 'dockerspec/helper/rspec_example_helpers'
|
22
|
+
require 'dockerspec/exceptions'
|
23
|
+
|
24
|
+
module Dockerspec
|
25
|
+
module RSpec
|
26
|
+
module Resources
|
27
|
+
#
|
28
|
+
# This generates the object to use within `its_container` calls.
|
29
|
+
#
|
30
|
+
class ItsContainer
|
31
|
+
#
|
32
|
+
# A message with description on how to avoid the error when you forget
|
33
|
+
# specifying the docker container you want to test with Docker Compose.
|
34
|
+
#
|
35
|
+
NO_DOCKER_COMPOSE_MESSAGE = <<-EOE
|
36
|
+
|
37
|
+
`its_container` can only be used within a `docker_compose` resource.
|
38
|
+
|
39
|
+
For example:
|
40
|
+
|
41
|
+
describe docker_compose('docker-compose.yml', wait: 30) do
|
42
|
+
its_container(:mysql) do
|
43
|
+
# [...]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
EOE
|
48
|
+
.freeze
|
49
|
+
|
50
|
+
#
|
51
|
+
# Constructs a `its_container` object.
|
52
|
+
#
|
53
|
+
# @param container [String] The name of the container.
|
54
|
+
#
|
55
|
+
# @return [Dockerspec::RSpec::Resource::ItsContainer] The
|
56
|
+
# `its_container` object.
|
57
|
+
#
|
58
|
+
# @api public
|
59
|
+
#
|
60
|
+
def initialize(container)
|
61
|
+
@container = container
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Restores the testing context from the RSpec metadata.
|
66
|
+
#
|
67
|
+
# Searches for {Dockerspec::Runner::Compose} objects in the RSpec
|
68
|
+
# metadata and restores their context to run the tests.
|
69
|
+
#
|
70
|
+
# This is called from the `before` block in the
|
71
|
+
# *lib/dockerspec/runner/base.rb* file:
|
72
|
+
#
|
73
|
+
# ```ruby
|
74
|
+
# RSpec.configure do |c|
|
75
|
+
# c.before(:each) do
|
76
|
+
# metadata = RSpec.current_example.metadata
|
77
|
+
# Dockerspec::Helper::RSpecExampleHelpers
|
78
|
+
# .restore_rspec_context(metadata)
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# ```
|
82
|
+
#
|
83
|
+
# @return void
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
#
|
87
|
+
def restore_rspec_context
|
88
|
+
metadata = ::RSpec.current_example.metadata
|
89
|
+
compose =
|
90
|
+
Helper::RSpecExampleHelpers
|
91
|
+
.search_object(metadata, Dockerspec::Runner::Compose)
|
92
|
+
raise ItsContainerError, NO_DOCKER_COMPOSE_MESSAGE if compose.nil?
|
93
|
+
compose.restore_rspec_context
|
94
|
+
compose.select_container(@container)
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Gets the description for the `its_container` resource.
|
99
|
+
#
|
100
|
+
# @return [String] The description.
|
101
|
+
#
|
102
|
+
# @api public
|
103
|
+
#
|
104
|
+
def to_s
|
105
|
+
"\"#{@container}\" container"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
#
|
3
3
|
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
-
# Copyright:: Copyright (c) 2015 Xabier de Zuazo
|
4
|
+
# Copyright:: Copyright (c) 2015-2016 Xabier de Zuazo
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -26,4 +26,8 @@ RSpec.configure do |c|
|
|
26
26
|
c.add_setting :dockerfile_path
|
27
27
|
c.add_setting :rm_build
|
28
28
|
c.add_setting :log_level
|
29
|
+
|
30
|
+
# Docker Compose settings:
|
31
|
+
c.add_setting :docker_wait
|
32
|
+
c.add_setting :container_name
|
29
33
|
end
|
data/lib/dockerspec/runner.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
#
|
3
3
|
# Author:: Xabier de Zuazo (<xabier@zuazo.org>)
|
4
|
-
# Copyright:: Copyright (c) 2015 Xabier de Zuazo
|
4
|
+
# Copyright:: Copyright (c) 2015-2016 Xabier de Zuazo
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,359 +17,4 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require 'docker'
|
21
|
-
require 'dockerspec/docker_gem'
|
22
|
-
require 'dockerspec/exceptions'
|
23
|
-
require 'dockerspec/helper/multiple_sources_description'
|
24
|
-
require 'dockerspec/docker_exception_parser'
|
25
|
-
|
26
|
-
module Dockerspec
|
27
|
-
#
|
28
|
-
# This class runs a docker image (without using Serverspec for that).
|
29
|
-
#
|
30
|
-
# This class is not used much, only inherited by
|
31
|
-
# {Dockerspec::Serverspec::Runner}, which uses Serverspec to run the images.
|
32
|
-
# Some of the methods here are used there, others not.
|
33
|
-
#
|
34
|
-
class Runner
|
35
|
-
include Dockerspec::Helper::MultipleSourcesDescription
|
36
|
-
|
37
|
-
#
|
38
|
-
# Constructs a Docker runner class to run Docker images.
|
39
|
-
#
|
40
|
-
# @example From a Running Docker Image
|
41
|
-
# Dockerspec::Runner.new('debian:8') #=> #<Dockerspec::Runner:0x0124>
|
42
|
-
#
|
43
|
-
# @example From a Running Docker Container ID
|
44
|
-
# # This does not start any new container
|
45
|
-
# Dockerspec::Runner.new(id: 'c51f86c28340')
|
46
|
-
# #=> #<Dockerspec::Runner:0x0124>
|
47
|
-
#
|
48
|
-
# @example From a Running Docker Container Image Name
|
49
|
-
# Dockerspec::Runner.new('my-debian') #=> #<Dockerspec::Runner:0x0125>
|
50
|
-
#
|
51
|
-
# @param opts [String, Hash] The `:tag` or a list of options.
|
52
|
-
#
|
53
|
-
# @option opts [String] :tag The Docker image tag name to run.
|
54
|
-
# @option opts [String] :id The Docker container ID to use instead of
|
55
|
-
# starting a new container.
|
56
|
-
# @option opts [Boolean] :rm (calculated) Whether to remove the Docker
|
57
|
-
# container afterwards.
|
58
|
-
# @option opts [String] :path The environment `PATH` value of the
|
59
|
-
# container.
|
60
|
-
# @option opts [Hash, Array] :env Some `ENV` instructions to add to the
|
61
|
-
# container.
|
62
|
-
#
|
63
|
-
# @return [Dockerspec::Runner] Runner object.
|
64
|
-
#
|
65
|
-
# @api public
|
66
|
-
#
|
67
|
-
def initialize(*opts)
|
68
|
-
@options = parse_options(opts)
|
69
|
-
send("setup_from_#{source}", @options[source])
|
70
|
-
ObjectSpace.define_finalizer(self, proc { finalize })
|
71
|
-
end
|
72
|
-
|
73
|
-
#
|
74
|
-
# Runs the Docker Container.
|
75
|
-
#
|
76
|
-
# @example
|
77
|
-
# builder = Dockerspec::Builder.new('.')
|
78
|
-
# builder.build
|
79
|
-
# runner = Dockerspec::Runner.new(builder)
|
80
|
-
# runner.run #=> #<Dockerspec::Runner:0x0123>
|
81
|
-
#
|
82
|
-
# @return [Dockerspec::Runner] Runner object.
|
83
|
-
#
|
84
|
-
# @api public
|
85
|
-
#
|
86
|
-
def run
|
87
|
-
create_container
|
88
|
-
run_container
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
#
|
93
|
-
# Gets the Docker container ID.
|
94
|
-
#
|
95
|
-
# @example
|
96
|
-
# builder = Dockerspec::Builder.new('.').build
|
97
|
-
# runner = Dockerspec::Runner.new(builder).run
|
98
|
-
# runner.id #=> "b8ba0befc716[...]"
|
99
|
-
#
|
100
|
-
# @return [String] Container ID.
|
101
|
-
#
|
102
|
-
# @api public
|
103
|
-
#
|
104
|
-
def id
|
105
|
-
return nil unless @container.respond_to?(:id)
|
106
|
-
@container.id
|
107
|
-
end
|
108
|
-
|
109
|
-
#
|
110
|
-
# Gets the Docker image ID.
|
111
|
-
#
|
112
|
-
# @example
|
113
|
-
# builder = Dockerspec::Builder.new('.').build
|
114
|
-
# runner = Dockerspec::Runner.new(builder)
|
115
|
-
# runner.image_id #=> "c51f86c28340[...]"
|
116
|
-
#
|
117
|
-
# @return [String] Image ID.
|
118
|
-
#
|
119
|
-
# @api public
|
120
|
-
#
|
121
|
-
def image_id
|
122
|
-
return @build.id unless @build.nil?
|
123
|
-
@container.json['Image']
|
124
|
-
end
|
125
|
-
|
126
|
-
#
|
127
|
-
# Stops and deletes the Docker Container.
|
128
|
-
#
|
129
|
-
# Automatically called when `:rm` option is enabled.
|
130
|
-
#
|
131
|
-
# @return void
|
132
|
-
#
|
133
|
-
# @api public
|
134
|
-
#
|
135
|
-
def finalize
|
136
|
-
return unless @options[:rm] && !@container.nil?
|
137
|
-
@container.stop
|
138
|
-
@container.delete
|
139
|
-
end
|
140
|
-
|
141
|
-
#
|
142
|
-
# Gets a descriptions of the object.
|
143
|
-
#
|
144
|
-
# @example Running from a Container Image ID
|
145
|
-
# r = Dockerspec::Runner.new('debian')
|
146
|
-
# r.to_s #=> "Docker Run from tag: \"debian\""
|
147
|
-
#
|
148
|
-
# @example Attaching to a Running Container ID
|
149
|
-
# r = Dockerspec::Runner.new(id: '92cc98ab560a')
|
150
|
-
# r.to_s #=> "Docker Run from id: \"92cc98ab560a\""
|
151
|
-
#
|
152
|
-
# @return [String] The object description.
|
153
|
-
#
|
154
|
-
# @api public
|
155
|
-
#
|
156
|
-
def to_s
|
157
|
-
description('Docker Run from')
|
158
|
-
end
|
159
|
-
|
160
|
-
protected
|
161
|
-
|
162
|
-
#
|
163
|
-
# Gets the source to start the container from.
|
164
|
-
#
|
165
|
-
# Possible values: `:tag`, `:id`.
|
166
|
-
#
|
167
|
-
# @example Start the Container from an Image Tag
|
168
|
-
# self.source #=> :tag
|
169
|
-
#
|
170
|
-
# @example Attach to a Running Container ID
|
171
|
-
# self.source #=> :id
|
172
|
-
#
|
173
|
-
# @return [Symbol] The source.
|
174
|
-
#
|
175
|
-
# @api private
|
176
|
-
#
|
177
|
-
def source
|
178
|
-
return @source unless @source.nil?
|
179
|
-
@source = %i(tag id).find { |from| @options.key?(from) }
|
180
|
-
end
|
181
|
-
|
182
|
-
#
|
183
|
-
# Generates a description from Docker tag name.
|
184
|
-
#
|
185
|
-
# @example
|
186
|
-
# self.description_from_tag('debian') #=> "debian"
|
187
|
-
# self.description_from_tag('92cc98ab560a92cc98ab560[...]')
|
188
|
-
# #=> "92cc98ab560a"
|
189
|
-
#
|
190
|
-
# @return [String] The description, shortened if necessary.
|
191
|
-
#
|
192
|
-
# @see Dockerspec::Helper::MultipleSourceDescription#description_from_docker
|
193
|
-
#
|
194
|
-
# @api private
|
195
|
-
#
|
196
|
-
alias_method :description_from_tag, :description_from_docker
|
197
|
-
|
198
|
-
#
|
199
|
-
# Gets the default options configured using `RSpec.configuration`.
|
200
|
-
#
|
201
|
-
# @example
|
202
|
-
# self.rspec_options #=> {}
|
203
|
-
#
|
204
|
-
# @return [Hash] The configuration options.
|
205
|
-
#
|
206
|
-
# @api private
|
207
|
-
#
|
208
|
-
def rspec_options
|
209
|
-
{}
|
210
|
-
end
|
211
|
-
|
212
|
-
#
|
213
|
-
# Gets the default configuration options after merging them with RSpec
|
214
|
-
# configuration options.
|
215
|
-
#
|
216
|
-
# @example
|
217
|
-
# self.default_options #=> {}
|
218
|
-
#
|
219
|
-
# @return [Hash] The configuration options.
|
220
|
-
#
|
221
|
-
# @api private
|
222
|
-
#
|
223
|
-
def default_options
|
224
|
-
{}.merge(rspec_options)
|
225
|
-
end
|
226
|
-
|
227
|
-
#
|
228
|
-
# Ensures that the passed options are correct.
|
229
|
-
#
|
230
|
-
# Currently this only checks that you passed the `:tag` or the `:id`
|
231
|
-
# argument.
|
232
|
-
#
|
233
|
-
# @return void
|
234
|
-
#
|
235
|
-
# @raise [Dockerspec::DockerRunArgumentError] Raises this exception when
|
236
|
-
# the required fields are missing.
|
237
|
-
#
|
238
|
-
# @api private
|
239
|
-
#
|
240
|
-
def assert_options!(opts)
|
241
|
-
return if opts[:tag].is_a?(String) || opts[:id].is_a?(String)
|
242
|
-
fail DockerRunArgumentError, 'You need to pass the `:tag` or the `:id` '\
|
243
|
-
'option to the #docker_run method.'
|
244
|
-
end
|
245
|
-
|
246
|
-
#
|
247
|
-
# Parses the configuration options passed to the constructor.
|
248
|
-
#
|
249
|
-
# @example
|
250
|
-
# self.parse_options #=> {:rm=>true}
|
251
|
-
#
|
252
|
-
# @param opts [Array<String, Hash>] The list of options. The strings will
|
253
|
-
# be interpreted as `:tag`, others will be merged.
|
254
|
-
#
|
255
|
-
# @return [Hash] The configuration options.
|
256
|
-
#
|
257
|
-
# @raise [Dockerspec::DockerRunArgumentError] Raises this exception when
|
258
|
-
# some required fields are missing.
|
259
|
-
#
|
260
|
-
# @see #initialize
|
261
|
-
#
|
262
|
-
# @api private
|
263
|
-
#
|
264
|
-
def parse_options(opts)
|
265
|
-
opts_hs_ary = opts.map { |x| x.is_a?(Hash) ? x : { tag: x } }
|
266
|
-
result = opts_hs_ary.reduce(default_options) { |a, e| a.merge(e) }
|
267
|
-
assert_options!(result)
|
268
|
-
result
|
269
|
-
end
|
270
|
-
|
271
|
-
#
|
272
|
-
# Generates the build object from the Docker image tag.
|
273
|
-
#
|
274
|
-
# Saves the build internally.
|
275
|
-
#
|
276
|
-
# @param tag [String] The image name or ID.
|
277
|
-
#
|
278
|
-
# @return void
|
279
|
-
#
|
280
|
-
# @api private
|
281
|
-
#
|
282
|
-
def setup_from_tag(tag)
|
283
|
-
@build = Builder.new(id: tag).build
|
284
|
-
end
|
285
|
-
|
286
|
-
#
|
287
|
-
# Generates the container object from a running Docker container.
|
288
|
-
#
|
289
|
-
# Saves the container internally.
|
290
|
-
#
|
291
|
-
# @param id [String] The container ID or name.
|
292
|
-
#
|
293
|
-
# @return void
|
294
|
-
#
|
295
|
-
# @api private
|
296
|
-
#
|
297
|
-
def setup_from_id(id)
|
298
|
-
@container = ::Docker::Container.get(id)
|
299
|
-
rescue ::Docker::Error::DockerError => e
|
300
|
-
DockerExceptionParser.new(e)
|
301
|
-
end
|
302
|
-
|
303
|
-
#
|
304
|
-
# Ensures that the Docker container has a correct `CMD`.
|
305
|
-
#
|
306
|
-
# @param opts [Hash] {Docker::Container} options.
|
307
|
-
#
|
308
|
-
# @return [Hash] {Docker::Container} options.
|
309
|
-
#
|
310
|
-
# @api private
|
311
|
-
#
|
312
|
-
def add_container_cmd_option(opts)
|
313
|
-
opts['Cmd'] = %w(/bin/sh) if @build.cmd.nil?
|
314
|
-
opts
|
315
|
-
end
|
316
|
-
|
317
|
-
#
|
318
|
-
# Adds some `ENV` options to the Docker container.
|
319
|
-
#
|
320
|
-
# @param opts [Hash] {Docker::Container} options.
|
321
|
-
#
|
322
|
-
# @return [Hash] {Docker::Container} options.
|
323
|
-
#
|
324
|
-
# @api private
|
325
|
-
#
|
326
|
-
def add_container_env_options(opts)
|
327
|
-
opts['Env'] = opts['Env'].to_a << "PATH=#{path}" if @options.key?(:path)
|
328
|
-
env = @options[:env].to_a.map { |v| v.join('=') }
|
329
|
-
opts['Env'] = opts['Env'].to_a.concat(env)
|
330
|
-
opts
|
331
|
-
end
|
332
|
-
|
333
|
-
#
|
334
|
-
# Generates the Docker container options for {Docker::Container}.
|
335
|
-
#
|
336
|
-
# @return [Hash] The container options.
|
337
|
-
#
|
338
|
-
# @api private
|
339
|
-
#
|
340
|
-
def container_options
|
341
|
-
opts = { 'Image' => image_id, 'OpenStdin' => true }
|
342
|
-
|
343
|
-
add_container_cmd_option(opts)
|
344
|
-
add_container_env_options(opts)
|
345
|
-
opts
|
346
|
-
end
|
347
|
-
|
348
|
-
#
|
349
|
-
# Creates the Docker container.
|
350
|
-
#
|
351
|
-
# *Note: Based on Specinfra `:docker` backend code.*
|
352
|
-
#
|
353
|
-
# @return void
|
354
|
-
#
|
355
|
-
# @api private
|
356
|
-
#
|
357
|
-
def create_container
|
358
|
-
return @container unless @container.nil?
|
359
|
-
@container = ::Docker::Container.create(container_options)
|
360
|
-
rescue ::Docker::Error::DockerError => e
|
361
|
-
DockerExceptionParser.new(e)
|
362
|
-
end
|
363
|
-
|
364
|
-
#
|
365
|
-
# Runs the Docker container.
|
366
|
-
#
|
367
|
-
# @return void
|
368
|
-
#
|
369
|
-
# @api private
|
370
|
-
#
|
371
|
-
def run_container
|
372
|
-
@container.start
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
20
|
+
require 'dockerspec/runner/docker'
|