jamie 0.1.0.beta3 → 0.1.0.beta4
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.
- data/Gemfile +0 -1
- data/Rakefile +12 -4
- data/jamie.gemspec +1 -0
- data/lib/jamie.rb +24 -22
- data/lib/jamie/cli.rb +15 -15
- data/lib/jamie/driver/dummy.rb +11 -3
- data/lib/jamie/thor_tasks.rb +1 -1
- data/lib/jamie/version.rb +1 -1
- data/spec/jamie/config/collection_spec.rb +77 -0
- data/spec/jamie/config_spec.rb +226 -0
- data/spec/jamie/instance_spec.rb +159 -0
- data/spec/jamie/platform_spec.rb +45 -0
- data/spec/jamie/suite_spec.rb +57 -0
- data/spec/spec_helper.rb +45 -0
- metadata +30 -4
- data/spec/jamie_spec.rb +0 -512
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -7,7 +7,7 @@ Rake::TestTask.new do |t|
|
|
7
7
|
t.verbose = true
|
8
8
|
end
|
9
9
|
|
10
|
-
task :default => [
|
10
|
+
task :default => [:test]
|
11
11
|
|
12
12
|
unless RUBY_ENGINE == 'jruby'
|
13
13
|
require 'cane/rake_task'
|
@@ -29,9 +29,17 @@ unless RUBY_ENGINE == 'jruby'
|
|
29
29
|
)
|
30
30
|
end
|
31
31
|
|
32
|
-
Tailor::RakeTask.new
|
32
|
+
Tailor::RakeTask.new do |task|
|
33
|
+
task.file_set('bin/*', 'binaries')
|
34
|
+
task.file_set('lib/**/*.rb', 'code') do |style|
|
35
|
+
# TODO: Tailor is confused thinking `module Jamie` is a class. Until
|
36
|
+
# the classes are split in seperate files, let's punt on this
|
37
|
+
style.max_code_lines_in_class 1550, level: :warn
|
38
|
+
end
|
39
|
+
task.file_set('spec/**/*.rb', 'tests')
|
40
|
+
end
|
33
41
|
|
34
|
-
Rake::Task[:default].enhance [
|
42
|
+
Rake::Task[:default].enhance [:cane, :tailor]
|
35
43
|
end
|
36
44
|
|
37
45
|
desc "Display LOC stats"
|
@@ -42,4 +50,4 @@ task :stats do
|
|
42
50
|
sh "countloc -r spec"
|
43
51
|
end
|
44
52
|
|
45
|
-
Rake::Task[:default].enhance [
|
53
|
+
Rake::Task[:default].enhance [:stats]
|
data/jamie.gemspec
CHANGED
data/lib/jamie.rb
CHANGED
@@ -164,7 +164,7 @@ module Jamie
|
|
164
164
|
def log_level
|
165
165
|
@log_level ||= begin
|
166
166
|
ENV['JAMIE_LOG'] && ENV['JAMIE_LOG'].downcase.to_sym ||
|
167
|
-
|
167
|
+
Jamie::DEFAULT_LOG_LEVEL
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
@@ -286,7 +286,7 @@ module Jamie
|
|
286
286
|
def platform_driver_hash(platform_name)
|
287
287
|
h = yaml[:platforms].find { |p| p[:name] == platform_name } || Hash.new
|
288
288
|
|
289
|
-
h.select { |key, value| [
|
289
|
+
h.select { |key, value| [:driver_plugin, :driver_config].include?(key) }
|
290
290
|
end
|
291
291
|
|
292
292
|
def new_instance_logger(index)
|
@@ -355,7 +355,7 @@ module Jamie
|
|
355
355
|
|
356
356
|
def common_driver_hash
|
357
357
|
yaml.select do |key, value|
|
358
|
-
[
|
358
|
+
[:driver_plugin, :driver_config].include?(key)
|
359
359
|
end
|
360
360
|
end
|
361
361
|
end
|
@@ -374,7 +374,7 @@ module Jamie
|
|
374
374
|
|
375
375
|
COLORS = %w(
|
376
376
|
cyan yellow green magenta red blue bright_cyan bright_yellow
|
377
|
-
bright_green bright_magenta bright_red
|
377
|
+
bright_green bright_magenta bright_red bright_blue
|
378
378
|
).freeze
|
379
379
|
|
380
380
|
def self.escape(name)
|
@@ -563,7 +563,7 @@ module Jamie
|
|
563
563
|
private
|
564
564
|
|
565
565
|
def validate_options(opts)
|
566
|
-
[
|
566
|
+
[:name, :run_list].each do |k|
|
567
567
|
raise ClientError, "Suite#new requires option :#{k}" if opts[k].nil?
|
568
568
|
end
|
569
569
|
end
|
@@ -604,7 +604,7 @@ module Jamie
|
|
604
604
|
private
|
605
605
|
|
606
606
|
def validate_options(opts)
|
607
|
-
[
|
607
|
+
[:name].each do |k|
|
608
608
|
raise ClientError, "Platform#new requires option :#{k}" if opts[k].nil?
|
609
609
|
end
|
610
610
|
end
|
@@ -792,7 +792,7 @@ module Jamie
|
|
792
792
|
private
|
793
793
|
|
794
794
|
def validate_options(opts)
|
795
|
-
[
|
795
|
+
[:suite, :platform, :driver, :jr, :logger].each do |k|
|
796
796
|
raise ClientError, "Instance#new requires option :#{k}" if opts[k].nil?
|
797
797
|
end
|
798
798
|
end
|
@@ -838,7 +838,7 @@ module Jamie
|
|
838
838
|
banner "#{output_verb} #{to_str}"
|
839
839
|
elapsed = action(verb) { |state| driver.public_send(verb, state) }
|
840
840
|
info("Finished #{output_verb.downcase} #{to_str}" +
|
841
|
-
|
841
|
+
" #{Util.duration(elapsed.real)}.")
|
842
842
|
yield if block_given?
|
843
843
|
Actor.current
|
844
844
|
end
|
@@ -927,7 +927,7 @@ module Jamie
|
|
927
927
|
|
928
928
|
private
|
929
929
|
|
930
|
-
TRANSITIONS = [
|
930
|
+
TRANSITIONS = [:destroy, :create, :converge, :setup, :verify]
|
931
931
|
|
932
932
|
def self.index(transition)
|
933
933
|
if transition.nil?
|
@@ -953,7 +953,7 @@ module Jamie
|
|
953
953
|
# @param [Hash] opts optional configuration
|
954
954
|
# @option opts [TrueClass, FalseClass] :use_sudo whether or not to invoke
|
955
955
|
# sudo before commands requiring root access (default: `true`)
|
956
|
-
def initialize(suite_name, opts = {:use_sudo => true})
|
956
|
+
def initialize(suite_name, opts = { :use_sudo => true })
|
957
957
|
validate_options(suite_name)
|
958
958
|
|
959
959
|
@suite_name = suite_name
|
@@ -972,7 +972,7 @@ module Jamie
|
|
972
972
|
@setup_cmd ||= if local_suite_files.empty?
|
973
973
|
nil
|
974
974
|
else
|
975
|
-
<<-INSTALL_CMD.gsub(
|
975
|
+
<<-INSTALL_CMD.gsub(/^ {10}/, '')
|
976
976
|
#{sudo}#{ruby_bin} -e "$(cat <<"EOF"
|
977
977
|
#{install_script}
|
978
978
|
EOF
|
@@ -994,7 +994,7 @@ module Jamie
|
|
994
994
|
@sync_cmd ||= if local_suite_files.empty?
|
995
995
|
nil
|
996
996
|
else
|
997
|
-
<<-INSTALL_CMD.gsub(
|
997
|
+
<<-INSTALL_CMD.gsub(/^ {10}/, '')
|
998
998
|
#{sudo}#{jr_bin} cleanup-suites
|
999
999
|
#{local_suite_files.map { |f| stream_file(f, remote_file(f)) }.join}
|
1000
1000
|
INSTALL_CMD
|
@@ -1053,7 +1053,7 @@ module Jamie
|
|
1053
1053
|
def stream_file(local_path, remote_path)
|
1054
1054
|
local_file = IO.read(local_path)
|
1055
1055
|
md5 = Digest::MD5.hexdigest(local_file)
|
1056
|
-
perms = sprintf("%o", File.stat(local_path).mode)[3,3]
|
1056
|
+
perms = sprintf("%o", File.stat(local_path).mode)[3, 3]
|
1057
1057
|
jr_stream_file = "#{jr_bin} stream-file #{remote_path} #{md5} #{perms}"
|
1058
1058
|
|
1059
1059
|
<<-STREAMFILE.gsub(/^ {8}/, '')
|
@@ -1115,7 +1115,7 @@ module Jamie
|
|
1115
1115
|
|
1116
1116
|
def self.symbolized_hash(obj)
|
1117
1117
|
if obj.is_a?(Hash)
|
1118
|
-
obj.inject({}) { |h, (k,v)| h[k.to_sym] = symbolized_hash(v) ; h }
|
1118
|
+
obj.inject({}) { |h, (k, v)| h[k.to_sym] = symbolized_hash(v) ; h }
|
1119
1119
|
elsif obj.is_a?(Array)
|
1120
1120
|
obj.inject([]) { |a, v| a << symbolized_hash(v) ; a }
|
1121
1121
|
else
|
@@ -1126,7 +1126,7 @@ module Jamie
|
|
1126
1126
|
def self.duration(total)
|
1127
1127
|
minutes = (total / 60).to_i
|
1128
1128
|
seconds = (total - (minutes * 60))
|
1129
|
-
"(%dm%.2fs)" % [
|
1129
|
+
"(%dm%.2fs)" % [minutes, seconds]
|
1130
1130
|
end
|
1131
1131
|
end
|
1132
1132
|
|
@@ -1316,7 +1316,7 @@ module Jamie
|
|
1316
1316
|
end
|
1317
1317
|
end
|
1318
1318
|
end
|
1319
|
-
@validations << [
|
1319
|
+
@validations << [attr, block]
|
1320
1320
|
end
|
1321
1321
|
|
1322
1322
|
def self.no_parallel_for(*methods)
|
@@ -1391,7 +1391,7 @@ module Jamie
|
|
1391
1391
|
opts[:password] = config[:password] if config[:password]
|
1392
1392
|
opts[:keys] = Array(config[:ssh_key]) if config[:ssh_key]
|
1393
1393
|
|
1394
|
-
[
|
1394
|
+
[state[:hostname], config[:username], opts]
|
1395
1395
|
end
|
1396
1396
|
|
1397
1397
|
def chef_home
|
@@ -1475,7 +1475,7 @@ module Jamie
|
|
1475
1475
|
socket = TCPSocket.new(hostname, config[:port])
|
1476
1476
|
IO.select([socket], nil, nil, 5)
|
1477
1477
|
rescue SocketError, Errno::ECONNREFUSED,
|
1478
|
-
|
1478
|
+
Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError
|
1479
1479
|
sleep 2
|
1480
1480
|
false
|
1481
1481
|
rescue Errno::EPERM, Errno::ETIMEDOUT
|
@@ -1546,8 +1546,9 @@ module Jamie
|
|
1546
1546
|
end
|
1547
1547
|
|
1548
1548
|
def upload_path(scp, path, dir = File.basename(path))
|
1549
|
-
|
1550
|
-
|
1549
|
+
dest = "#{chef_home}/#{dir}"
|
1550
|
+
|
1551
|
+
scp.upload!(path, dest, :recursive => true) do |ch, name, sent, total|
|
1551
1552
|
if sent == total
|
1552
1553
|
info("Uploaded #{name.sub(%r{^#{path}/}, '')} (#{total} bytes)")
|
1553
1554
|
end
|
@@ -1593,7 +1594,8 @@ module Jamie
|
|
1593
1594
|
fatal("#{name} must be installed, add it to your Gemfile.")
|
1594
1595
|
raise UserError, "#{bin} command not found"
|
1595
1596
|
end
|
1596
|
-
|
1597
|
+
|
1598
|
+
Jamie.mutex.synchronize { run_command "#{bin} install --path #{tmpdir}" }
|
1597
1599
|
end
|
1598
1600
|
|
1599
1601
|
def cp_cookbooks(tmpdir)
|
@@ -1628,7 +1630,7 @@ module Jamie
|
|
1628
1630
|
# attributes or nil values if they could not be determined
|
1629
1631
|
def self.extract(metadata_file)
|
1630
1632
|
mc = new(File.expand_path(metadata_file))
|
1631
|
-
[
|
1633
|
+
[mc[:name], mc[:version]]
|
1632
1634
|
end
|
1633
1635
|
|
1634
1636
|
# Creates a new instances and loads in the contents of the metdata.rb
|
data/lib/jamie/cli.rb
CHANGED
@@ -47,10 +47,10 @@ module Jamie
|
|
47
47
|
def list(*args)
|
48
48
|
result = parse_subcommand(args.first)
|
49
49
|
if options[:bare]
|
50
|
-
say Array(result).map{ |i| i.name }.join("\n")
|
50
|
+
say Array(result).map { |i| i.name }.join("\n")
|
51
51
|
else
|
52
52
|
table = [
|
53
|
-
[
|
53
|
+
[set_color("Instance", :green), set_color("Last Action", :green)]
|
54
54
|
]
|
55
55
|
table += Array(result).map { |i| display_instance(i) }
|
56
56
|
print_table(table)
|
@@ -107,7 +107,7 @@ module Jamie
|
|
107
107
|
results = get_filtered_instances(regexp)
|
108
108
|
if results.size > 1
|
109
109
|
die task, "Argument `#{regexp}' returned multiple results:\n" +
|
110
|
-
results.map{ |i| " * #{i.name}" }.join("\n")
|
110
|
+
results.map { |i| " * #{i.name}" }.join("\n")
|
111
111
|
end
|
112
112
|
instance = results.pop
|
113
113
|
|
@@ -210,7 +210,7 @@ module Jamie
|
|
210
210
|
when nil then set_color("<Not Created>", :red)
|
211
211
|
else set_color("<Unknown>", :white)
|
212
212
|
end
|
213
|
-
[
|
213
|
+
[set_color(instance.name, :white), action]
|
214
214
|
end
|
215
215
|
|
216
216
|
def die(task, msg)
|
@@ -220,18 +220,19 @@ module Jamie
|
|
220
220
|
end
|
221
221
|
|
222
222
|
def pry_prompts
|
223
|
-
[
|
224
|
-
|
223
|
+
[
|
224
|
+
proc { |target_self, nest_level, pry|
|
225
|
+
["[#{pry.input_array.size}] ",
|
225
226
|
"jc(#{Pry.view_clip(target_self.class)})",
|
226
227
|
"#{":#{nest_level}" unless nest_level.zero?}> "
|
227
228
|
].join
|
228
229
|
},
|
229
230
|
proc { |target_self, nest_level, pry|
|
230
|
-
[
|
231
|
+
["[#{pry.input_array.size}] ",
|
231
232
|
"jc(#{Pry.view_clip(target_self.class)})",
|
232
233
|
"#{":#{nest_level}" unless nest_level.zero?}* "
|
233
234
|
].join
|
234
|
-
}
|
235
|
+
},
|
235
236
|
]
|
236
237
|
end
|
237
238
|
end
|
@@ -265,7 +266,7 @@ module Jamie
|
|
265
266
|
puts ">>>>> Jamie gem not loaded, omitting tasks" unless ENV['CI']
|
266
267
|
end
|
267
268
|
THOR
|
268
|
-
empty_directory "test/integration/
|
269
|
+
empty_directory "test/integration/default" if init_test_dir?
|
269
270
|
append_to_gitignore(".jamie/")
|
270
271
|
append_to_gitignore(".jamie.local.yml")
|
271
272
|
add_plugins
|
@@ -277,7 +278,7 @@ module Jamie
|
|
277
278
|
url_base = "https://opscode-vm.s3.amazonaws.com/vagrant/boxes"
|
278
279
|
platforms = [
|
279
280
|
{ :n => 'ubuntu', :vers => %w(12.04 10.04), :rl => "recipe[apt]" },
|
280
|
-
{ :n => 'centos', :vers => %w(6.3 5.8), :rl => "recipe[yum::epel]" }
|
281
|
+
{ :n => 'centos', :vers => %w(6.3 5.8), :rl => "recipe[yum::epel]" },
|
281
282
|
]
|
282
283
|
platforms = platforms.map do |p|
|
283
284
|
p[:vers].map do |v|
|
@@ -296,15 +297,14 @@ module Jamie
|
|
296
297
|
nil
|
297
298
|
end
|
298
299
|
run_list = cookbook_name ? "recipe[#{cookbook_name}]" : nil
|
299
|
-
attributes = cookbook_name ? { cookbook_name => nil } : nil
|
300
300
|
|
301
301
|
{ 'driver_plugin' => 'vagrant',
|
302
302
|
'platforms' => platforms,
|
303
303
|
'suites' => [
|
304
|
-
{ 'name' => '
|
304
|
+
{ 'name' => 'default',
|
305
305
|
'run_list' => Array(run_list),
|
306
|
-
'attributes' =>
|
307
|
-
}
|
306
|
+
'attributes' => Hash.new
|
307
|
+
},
|
308
308
|
]
|
309
309
|
}.to_yaml
|
310
310
|
end
|
@@ -345,7 +345,7 @@ module Jamie
|
|
345
345
|
|
346
346
|
def list_plugins
|
347
347
|
specs = fetch_gem_specs.map { |t| t.first }.map { |t| t[0, 2] }.
|
348
|
-
sort { |x,y| x[0] <=> y[0] }
|
348
|
+
sort { |x, y| x[0] <=> y[0] }
|
349
349
|
specs = specs[0, 49].push(["...", "..."]) if specs.size > 49
|
350
350
|
specs = specs.unshift(["Gem Name", "Latest Stable Release"])
|
351
351
|
print_table(specs, :indent => 4)
|
data/lib/jamie/driver/dummy.rb
CHANGED
@@ -55,14 +55,22 @@ module Jamie
|
|
55
55
|
private
|
56
56
|
|
57
57
|
def report(action, state)
|
58
|
-
|
59
|
-
|
58
|
+
what = action.capitalize
|
59
|
+
info("[Dummy] #{what} on instance=#{instance} with state=#{state}")
|
60
|
+
sleep_if_set
|
61
|
+
random_failure_if_set
|
62
|
+
debug("[Dummy] #{what} completed (#{config[:sleep]}s).")
|
63
|
+
end
|
64
|
+
|
65
|
+
def sleep_if_set
|
60
66
|
sleep(config[:sleep].to_f) if config[:sleep].to_f > 0.0
|
67
|
+
end
|
68
|
+
|
69
|
+
def random_failure_if_set
|
61
70
|
if config[:random_failure] && [true, false].sample
|
62
71
|
debug("[Dummy] Random failure for action ##{action}.")
|
63
72
|
raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
|
64
73
|
end
|
65
|
-
debug("[Dummy] Action ##{action} completed (#{config[:sleep]}s).")
|
66
74
|
end
|
67
75
|
end
|
68
76
|
end
|
data/lib/jamie/thor_tasks.rb
CHANGED
data/lib/jamie/version.rb
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2012, Fletcher Nichol
|
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
|
+
require_relative '../../spec_helper'
|
20
|
+
|
21
|
+
describe Jamie::Config::Collection do
|
22
|
+
|
23
|
+
let(:collection) do
|
24
|
+
Jamie::Config::Collection.new([
|
25
|
+
obj('one'), obj('two', 'a'), obj('two', 'b'), obj('three')
|
26
|
+
])
|
27
|
+
end
|
28
|
+
|
29
|
+
it "transparently wraps an Array" do
|
30
|
+
collection.must_be_instance_of Array
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#get" do
|
34
|
+
|
35
|
+
it "returns a single object by its name" do
|
36
|
+
collection.get('three').must_equal obj('three')
|
37
|
+
end
|
38
|
+
|
39
|
+
it "returns the first occurance of an object by its name" do
|
40
|
+
collection.get('two').must_equal obj('two', 'a')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "returns nil if an object cannot be found by its name" do
|
44
|
+
collection.get('nope').must_be_nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#get_all" do
|
49
|
+
|
50
|
+
it "returns a Collection of objects whose name matches the regex" do
|
51
|
+
result = collection.get_all(/(one|three)/)
|
52
|
+
result.size.must_equal 2
|
53
|
+
result[0].must_equal obj('one')
|
54
|
+
result[1].must_equal obj('three')
|
55
|
+
result.get_all(/one/).size.must_equal 1
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns an empty Collection if on matches are found" do
|
59
|
+
result = collection.get_all(/noppa/)
|
60
|
+
result.must_equal []
|
61
|
+
result.get("nahuh").must_be_nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "#as_name" do
|
66
|
+
|
67
|
+
it "returns an Array of names as strings" do
|
68
|
+
collection.as_names.must_equal %w{one two two three}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def obj(name, extra = nil)
|
75
|
+
OpenStruct.new(:name => name, :extra => extra)
|
76
|
+
end
|
77
|
+
end
|