stemcell 0.8.0 → 0.8.1
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 +5 -13
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +14 -12
- data/examples/stemcellrc +0 -1
- data/lib/stemcell/errors.rb +16 -0
- data/lib/stemcell/launcher.rb +76 -26
- data/lib/stemcell/templates/bootstrap.sh.erb +7 -0
- data/lib/stemcell/version.rb +1 -1
- data/spec/lib/stemcell/launcher_spec.rb +58 -0
- metadata +9 -7
checksums.yaml
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
|
|
5
|
-
data.tar.gz: !binary |-
|
|
6
|
-
ZDVkYmQ1YzViMzJlNjhmZDBlNGM2YTVmYTZmNjFmM2U3N2VhYjdhZQ==
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 72fabe0d6ead6f78ac3e45619a500e6896e0c6c9
|
|
4
|
+
data.tar.gz: b53a9302344e97be08143b8ea814d5f2e5a3f092
|
|
7
5
|
SHA512:
|
|
8
|
-
metadata.gz:
|
|
9
|
-
|
|
10
|
-
YjdkYWIzNTBkMzY3N2E1ZjE1ZTVlY2U3MjJjODJmNjg1ZGQxMGMyOTYwOGRk
|
|
11
|
-
ZGQ1OWI2ZDI1ZGY4OTM1MjkwZTlkMDhkOWIyZTE3OTU4NGU4ZTc=
|
|
12
|
-
data.tar.gz: !binary |-
|
|
13
|
-
MDYwMzllODg3OTYxN2I5NGE1MWE3ZWE4ODliN2NiMmJkMGM4YjBlZGQ2ZDVm
|
|
14
|
-
MTU0ZjQwZGQ0NjNjNTNhMWRjN2Y1ZDM2M2IyNDdkNWU4NDdmYjJhOGZjNWI5
|
|
15
|
-
YTk1MDYyZjUyZjVkOWJhMDBjMGQ5ODA4MTBlYmQxYTgwMTJhNGI=
|
|
6
|
+
metadata.gz: 06803bd29174493c9127e88575c7847d5782ac2fd77c26687c92d5eaaf3254f882abfc1948fecaa07ccaa77837183b6872bbbef6b3ed2eeda10ebce279f508ad
|
|
7
|
+
data.tar.gz: cc936abe49a4c3690bb38700c6d70877a6e68bf632a55d4cce732cca48a707b7524db8a546f3279391d53d68e1c532107285a975eedb6e302917915595bec305
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
# next release
|
|
3
3
|
- ...
|
|
4
4
|
|
|
5
|
+
# 0.8.1
|
|
6
|
+
- Add retry mechanism for instances launch/termination
|
|
7
|
+
- Make `Launcher::launch!` transaction-like, which reclaims all partially launched instances in the event of non-intermittent error
|
|
8
|
+
- Display better error message with reason and failed instances
|
|
9
|
+
- Take converge lock during initial converge
|
|
10
|
+
|
|
5
11
|
# 0.8.0
|
|
6
12
|
- Support for VPC [Brenden](https://github.com/brndnmtthws)
|
|
7
13
|
- Support relative paths and home alias in `Launcher#try_file` [Patrick Viet](https://github.com/patrickviet)
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
stemcell (0.8.
|
|
4
|
+
stemcell (0.8.1)
|
|
5
5
|
aws-creds (~> 0.2.2)
|
|
6
6
|
aws-sdk (~> 1.9)
|
|
7
7
|
chef (>= 11.4.0)
|
|
@@ -15,7 +15,9 @@ GEM
|
|
|
15
15
|
specs:
|
|
16
16
|
aws-creds (0.2.3)
|
|
17
17
|
trollop (~> 2.0)
|
|
18
|
-
aws-sdk (1.
|
|
18
|
+
aws-sdk (1.62.0)
|
|
19
|
+
aws-sdk-v1 (= 1.62.0)
|
|
20
|
+
aws-sdk-v1 (1.62.0)
|
|
19
21
|
json (~> 1.4)
|
|
20
22
|
nokogiri (>= 1.4.4)
|
|
21
23
|
chef (11.14.6)
|
|
@@ -46,18 +48,18 @@ GEM
|
|
|
46
48
|
diff-lcs (1.2.5)
|
|
47
49
|
docile (1.1.5)
|
|
48
50
|
erubis (2.7.0)
|
|
49
|
-
ffi (1.9.
|
|
50
|
-
ffi-yajl (1.
|
|
51
|
+
ffi (1.9.6)
|
|
52
|
+
ffi-yajl (1.3.1)
|
|
51
53
|
ffi (~> 1.5)
|
|
52
|
-
libyajl2 (~> 1.
|
|
54
|
+
libyajl2 (~> 1.2)
|
|
53
55
|
hashie (2.1.2)
|
|
54
56
|
highline (1.6.21)
|
|
55
57
|
ipaddress (0.8.0)
|
|
56
58
|
json (1.7.7)
|
|
57
|
-
libyajl2 (1.0
|
|
59
|
+
libyajl2 (1.2.0)
|
|
58
60
|
method_source (0.8.2)
|
|
59
61
|
mime-types (1.25.1)
|
|
60
|
-
mini_portile (0.6.
|
|
62
|
+
mini_portile (0.6.2)
|
|
61
63
|
mixlib-authentication (1.3.0)
|
|
62
64
|
mixlib-log
|
|
63
65
|
mixlib-cli (1.5.0)
|
|
@@ -65,14 +67,14 @@ GEM
|
|
|
65
67
|
mixlib-log (1.6.0)
|
|
66
68
|
mixlib-shellout (1.4.0)
|
|
67
69
|
multi_json (1.10.1)
|
|
68
|
-
net-ssh (2.9.
|
|
70
|
+
net-ssh (2.9.2)
|
|
69
71
|
net-ssh-gateway (1.2.0)
|
|
70
72
|
net-ssh (>= 2.6.5)
|
|
71
73
|
net-ssh-multi (1.2.0)
|
|
72
74
|
net-ssh (>= 2.6.5)
|
|
73
75
|
net-ssh-gateway (>= 1.2.0)
|
|
74
|
-
nokogiri (1.6.
|
|
75
|
-
mini_portile (
|
|
76
|
+
nokogiri (1.6.6.2)
|
|
77
|
+
mini_portile (~> 0.6.0)
|
|
76
78
|
ohai (7.2.4)
|
|
77
79
|
ffi (~> 1.9)
|
|
78
80
|
ffi-yajl (~> 1.0)
|
|
@@ -89,7 +91,7 @@ GEM
|
|
|
89
91
|
coderay (~> 1.1.0)
|
|
90
92
|
method_source (~> 0.8.1)
|
|
91
93
|
slop (~> 3.4)
|
|
92
|
-
rack (1.
|
|
94
|
+
rack (1.6.0)
|
|
93
95
|
rake (10.3.2)
|
|
94
96
|
rest-client (1.6.7)
|
|
95
97
|
mime-types (>= 1.16)
|
|
@@ -110,7 +112,7 @@ GEM
|
|
|
110
112
|
simplecov-html (0.8.0)
|
|
111
113
|
slop (3.6.0)
|
|
112
114
|
systemu (2.6.4)
|
|
113
|
-
trollop (2.
|
|
115
|
+
trollop (2.1.1)
|
|
114
116
|
wmi-lite (1.0.0)
|
|
115
117
|
|
|
116
118
|
PLATFORMS
|
data/examples/stemcellrc
CHANGED
data/lib/stemcell/errors.rb
CHANGED
|
@@ -23,4 +23,20 @@ module Stemcell
|
|
|
23
23
|
@option = option
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
|
+
|
|
27
|
+
class IncompleteOperation < Error
|
|
28
|
+
attr_reader :operation, :all_instance_ids, :errors
|
|
29
|
+
def initialize(operation, all_instance_ids, errors)
|
|
30
|
+
super()
|
|
31
|
+
@operation = operation
|
|
32
|
+
@all_instance_ids = all_instance_ids
|
|
33
|
+
@errors = errors
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def message
|
|
37
|
+
"Incomplete operation '#{@operation}': " +
|
|
38
|
+
"all_instance_ids=#{@all_instance_ids.join('|')}; " +
|
|
39
|
+
"errors=" + (@errors.map { |k, v| "'#{k}' => '#{v}'"}.join('|'))
|
|
40
|
+
end
|
|
41
|
+
end
|
|
26
42
|
end
|
data/lib/stemcell/launcher.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
require 'aws-sdk'
|
|
2
2
|
require 'logger'
|
|
3
3
|
require 'erb'
|
|
4
|
+
require 'set'
|
|
4
5
|
|
|
5
6
|
require "stemcell/version"
|
|
6
7
|
require "stemcell/option_parser"
|
|
@@ -176,8 +177,6 @@ module Stemcell
|
|
|
176
177
|
end
|
|
177
178
|
end
|
|
178
179
|
|
|
179
|
-
#
|
|
180
|
-
|
|
181
180
|
# generate user data script to bootstrap instance, include in launch
|
|
182
181
|
# options UNLESS we have manually set the user-data (ie. for ec2admin)
|
|
183
182
|
launch_options[:user_data] = opts.fetch('user_data', render_template(opts))
|
|
@@ -186,14 +185,24 @@ module Stemcell
|
|
|
186
185
|
instances = do_launch(launch_options)
|
|
187
186
|
|
|
188
187
|
# set tags on all instances launched
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
wait
|
|
195
|
-
|
|
196
|
-
|
|
188
|
+
begin
|
|
189
|
+
set_tags(instances, tags)
|
|
190
|
+
@log.info "sent ec2 api requests successfully"
|
|
191
|
+
|
|
192
|
+
# wait for aws to report instance stats
|
|
193
|
+
if opts.fetch('wait', true)
|
|
194
|
+
wait(instances)
|
|
195
|
+
print_run_info(instances)
|
|
196
|
+
@log.info "launched instances successfully"
|
|
197
|
+
end
|
|
198
|
+
rescue => e
|
|
199
|
+
@log.info "launch failed, killing all launched instances"
|
|
200
|
+
begin
|
|
201
|
+
kill(instances, :ignore_not_found => true)
|
|
202
|
+
rescue => kill_error
|
|
203
|
+
@log.warn "encountered an error during cleanup: #{kill_error.message}"
|
|
204
|
+
end
|
|
205
|
+
raise e
|
|
197
206
|
end
|
|
198
207
|
|
|
199
208
|
return instances
|
|
@@ -203,17 +212,20 @@ module Stemcell
|
|
|
203
212
|
return @ec2.instances[id]
|
|
204
213
|
end
|
|
205
214
|
|
|
206
|
-
def kill(
|
|
207
|
-
return if
|
|
208
|
-
|
|
215
|
+
def kill(instance_ids, opts={})
|
|
216
|
+
return if instance_ids.nil?
|
|
217
|
+
|
|
218
|
+
errors = run_batch_operation(instance_ids) do |id|
|
|
209
219
|
begin
|
|
210
|
-
instance = find_instance(
|
|
220
|
+
instance = find_instance(id)
|
|
211
221
|
@log.warn "Terminating instance #{instance.instance_id}"
|
|
212
222
|
instance.terminate
|
|
223
|
+
nil # nil == success
|
|
213
224
|
rescue AWS::EC2::Errors::InvalidInstanceID::NotFound => e
|
|
214
|
-
|
|
225
|
+
opts[:ignore_not_found] ? nil : e
|
|
215
226
|
end
|
|
216
227
|
end
|
|
228
|
+
check_errors(:kill, instance_ids, errors)
|
|
217
229
|
end
|
|
218
230
|
|
|
219
231
|
# this is made public for ec2admin usage
|
|
@@ -243,15 +255,12 @@ module Stemcell
|
|
|
243
255
|
@log.info "Waiting up to #{@timeout} seconds for #{instances.count} " \
|
|
244
256
|
"instance(s) (#{instances.inspect}):"
|
|
245
257
|
|
|
246
|
-
while
|
|
247
|
-
|
|
248
|
-
if
|
|
249
|
-
kill(instances)
|
|
258
|
+
while !instances.all? { |i| i.status == :running }
|
|
259
|
+
elapsed = Time.now - @start_time
|
|
260
|
+
if elapsed >= @timeout
|
|
250
261
|
raise TimeoutError, "exceded timeout of #{@timeout}"
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
if instances.select{|i| i.status != :running }.empty?
|
|
254
|
-
break
|
|
262
|
+
else
|
|
263
|
+
sleep min(5, @timeout - elapsed)
|
|
255
264
|
end
|
|
256
265
|
end
|
|
257
266
|
|
|
@@ -279,11 +288,17 @@ module Stemcell
|
|
|
279
288
|
return instances
|
|
280
289
|
end
|
|
281
290
|
|
|
282
|
-
def set_tags(instances=[],tags)
|
|
291
|
+
def set_tags(instances=[], tags)
|
|
283
292
|
@log.info "setting tags on instance(s)"
|
|
284
|
-
instances
|
|
285
|
-
|
|
293
|
+
errors = run_batch_operation(instances) do |instance|
|
|
294
|
+
begin
|
|
295
|
+
instance.tags.set(tags)
|
|
296
|
+
nil # nil == success
|
|
297
|
+
rescue AWS::EC2::Errors::InvalidInstanceID::NotFound => e
|
|
298
|
+
e
|
|
299
|
+
end
|
|
286
300
|
end
|
|
301
|
+
check_errors(:set_tags, instances.map(&:id), errors)
|
|
287
302
|
end
|
|
288
303
|
|
|
289
304
|
# attempt to accept keys as file paths
|
|
@@ -291,5 +306,40 @@ module Stemcell
|
|
|
291
306
|
File.read(File.expand_path(opt)) rescue opt
|
|
292
307
|
end
|
|
293
308
|
|
|
309
|
+
MAX_ATTEMPTS = 3
|
|
310
|
+
INITIAL_RETRY_SEC = 1
|
|
311
|
+
|
|
312
|
+
# Return a Hash of instance => error. Empty hash indicates "no error"
|
|
313
|
+
# for code block:
|
|
314
|
+
# - if block returns nil, success
|
|
315
|
+
# - if block returns non-nil value (e.g., exception), retry 3 times w/ backoff
|
|
316
|
+
# - if block raises exception, fail
|
|
317
|
+
def run_batch_operation(instances)
|
|
318
|
+
instances.map do |instance|
|
|
319
|
+
begin
|
|
320
|
+
attempt = 0
|
|
321
|
+
result = nil
|
|
322
|
+
while attempt < MAX_ATTEMPTS
|
|
323
|
+
# sleep idempotently except for the first attempt
|
|
324
|
+
sleep(INITIAL_RETRY_SEC * 2 ** attempt) if attempt != 0
|
|
325
|
+
result = yield(instance)
|
|
326
|
+
break if result.nil? # nil indicates success
|
|
327
|
+
attempt += 1
|
|
328
|
+
end
|
|
329
|
+
result # result for this instance is nil or returned exception
|
|
330
|
+
rescue => e
|
|
331
|
+
e # result for this instance is caught exception
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def check_errors(operation, instance_ids, errors)
|
|
337
|
+
return if errors.all?(&:nil?)
|
|
338
|
+
raise IncompleteOperation.new(
|
|
339
|
+
operation,
|
|
340
|
+
instance_ids,
|
|
341
|
+
instance_ids.zip(errors).reject { |i, e| e.nil? }
|
|
342
|
+
)
|
|
343
|
+
end
|
|
294
344
|
end
|
|
295
345
|
end
|
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
# Martin Rhoads
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
(
|
|
12
|
+
echo 'Acquiring converge lock...'
|
|
13
|
+
/usr/bin/flock -e 200
|
|
14
|
+
echo 'Lock acquired!'
|
|
15
|
+
|
|
11
16
|
set -o pipefail
|
|
12
17
|
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
|
13
18
|
|
|
@@ -146,6 +151,7 @@ repo_dir = "${repo_dir}"
|
|
|
146
151
|
cookbook_path "#{repo_dir}/cookbooks"
|
|
147
152
|
role_path "#{repo_dir}/roles"
|
|
148
153
|
data_bag_path "#{repo_dir}/data_bags"
|
|
154
|
+
ssl_verify_mode :verify_peer
|
|
149
155
|
|
|
150
156
|
log_level :info
|
|
151
157
|
log_location STDOUT
|
|
@@ -252,3 +258,4 @@ configure_chef_daemon
|
|
|
252
258
|
|
|
253
259
|
|
|
254
260
|
echo "<%= last_bootstrap_line %>"
|
|
261
|
+
) 200> /var/run/converge.lock
|
data/lib/stemcell/version.rb
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
class MockInstance
|
|
4
|
+
def initialize(id)
|
|
5
|
+
@id = id
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def id
|
|
9
|
+
@id
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class MockException < StandardError
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe Stemcell::Launcher do
|
|
17
|
+
let(:launcher) {
|
|
18
|
+
opts = {}
|
|
19
|
+
Stemcell::Launcher::REQUIRED_OPTIONS.map { |k| opts[k] = "" }
|
|
20
|
+
launcher = Stemcell::Launcher.new(opts)
|
|
21
|
+
launcher
|
|
22
|
+
}
|
|
23
|
+
let(:operation) { 'op' }
|
|
24
|
+
let(:instances) { (1..4).map { |id| MockInstance.new(id) } }
|
|
25
|
+
let(:instance_ids) { instances.map(&:id) }
|
|
26
|
+
|
|
27
|
+
describe '#run_batch_operation' do
|
|
28
|
+
|
|
29
|
+
it "raises no exception when no internal error occur" do
|
|
30
|
+
errors = launcher.send(:run_batch_operation, instances) {}
|
|
31
|
+
errors.all?(&:nil?).should be_true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "runs full batch even when there are two error" do
|
|
35
|
+
errors = launcher.send(:run_batch_operation,
|
|
36
|
+
instances) do |instance, error|
|
|
37
|
+
raise "error-#{instance.id}" if instance.id % 2 == 0
|
|
38
|
+
end
|
|
39
|
+
errors.count(&:nil?).should be_eql(2)
|
|
40
|
+
errors.reject(&:nil?).map { |e| e.message }.should \
|
|
41
|
+
be_eql([2, 4].map { |id| "error-#{id}" })
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "retries after an intermittent error" do
|
|
45
|
+
count = 0
|
|
46
|
+
errors = launcher.send(:run_batch_operation,
|
|
47
|
+
instances) do |instance|
|
|
48
|
+
if instance.id == 3
|
|
49
|
+
count += 1
|
|
50
|
+
count < 3 ?
|
|
51
|
+
AWS::EC2::Errors::InvalidInstanceID::NotFound.new("error-#{instance.id}"):
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
errors.all?(&:nil?).should be_true
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: stemcell
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martin Rhoads
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2015-02-18 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: aws-sdk
|
|
@@ -45,14 +45,14 @@ dependencies:
|
|
|
45
45
|
name: chef
|
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
|
47
47
|
requirements:
|
|
48
|
-
- -
|
|
48
|
+
- - '>='
|
|
49
49
|
- !ruby/object:Gem::Version
|
|
50
50
|
version: 11.4.0
|
|
51
51
|
type: :runtime
|
|
52
52
|
prerelease: false
|
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
|
54
54
|
requirements:
|
|
55
|
-
- -
|
|
55
|
+
- - '>='
|
|
56
56
|
- !ruby/object:Gem::Version
|
|
57
57
|
version: 11.4.0
|
|
58
58
|
- !ruby/object:Gem::Dependency
|
|
@@ -166,6 +166,7 @@ files:
|
|
|
166
166
|
- spec/fixtures/chef_repo/stemcell-backing-store-missing.json
|
|
167
167
|
- spec/fixtures/chef_repo/stemcell-defaults-missing.json
|
|
168
168
|
- spec/fixtures/chef_repo/stemcell.json
|
|
169
|
+
- spec/lib/stemcell/launcher_spec.rb
|
|
169
170
|
- spec/lib/stemcell/metadata_source/chef_repository_spec.rb
|
|
170
171
|
- spec/lib/stemcell/metadata_source/configuration_spec.rb
|
|
171
172
|
- spec/lib/stemcell/metadata_source_spec.rb
|
|
@@ -182,17 +183,17 @@ require_paths:
|
|
|
182
183
|
- lib
|
|
183
184
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
185
|
requirements:
|
|
185
|
-
- -
|
|
186
|
+
- - '>='
|
|
186
187
|
- !ruby/object:Gem::Version
|
|
187
188
|
version: '0'
|
|
188
189
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
190
|
requirements:
|
|
190
|
-
- -
|
|
191
|
+
- - '>='
|
|
191
192
|
- !ruby/object:Gem::Version
|
|
192
193
|
version: '0'
|
|
193
194
|
requirements: []
|
|
194
195
|
rubyforge_project:
|
|
195
|
-
rubygems_version: 2.
|
|
196
|
+
rubygems_version: 2.0.14
|
|
196
197
|
signing_key:
|
|
197
198
|
specification_version: 4
|
|
198
199
|
summary: no summary
|
|
@@ -218,6 +219,7 @@ test_files:
|
|
|
218
219
|
- spec/fixtures/chef_repo/stemcell-backing-store-missing.json
|
|
219
220
|
- spec/fixtures/chef_repo/stemcell-defaults-missing.json
|
|
220
221
|
- spec/fixtures/chef_repo/stemcell.json
|
|
222
|
+
- spec/lib/stemcell/launcher_spec.rb
|
|
221
223
|
- spec/lib/stemcell/metadata_source/chef_repository_spec.rb
|
|
222
224
|
- spec/lib/stemcell/metadata_source/configuration_spec.rb
|
|
223
225
|
- spec/lib/stemcell/metadata_source_spec.rb
|