test-kitchen 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cane +5 -0
- data/.travis.yml +8 -3
- data/CHANGELOG.md +66 -0
- data/Guardfile +3 -1
- data/README.md +3 -1
- data/Rakefile +1 -16
- data/features/kitchen_command.feature +1 -0
- data/features/kitchen_driver_create_command.feature +1 -0
- data/features/kitchen_driver_discover_command.feature +1 -0
- data/features/kitchen_help_command.feature +16 -0
- data/features/kitchen_init_command.feature +2 -0
- data/features/kitchen_list_command.feature +42 -0
- data/features/support/env.rb +25 -0
- data/lib/kitchen.rb +0 -1
- data/lib/kitchen/busser.rb +2 -2
- data/lib/kitchen/cli.rb +80 -233
- data/lib/kitchen/command.rb +117 -0
- data/lib/kitchen/command/action.rb +44 -0
- data/lib/kitchen/command/console.rb +51 -0
- data/lib/kitchen/command/diagnose.rb +51 -0
- data/lib/kitchen/command/driver_discover.rb +72 -0
- data/lib/kitchen/command/list.rb +86 -0
- data/lib/kitchen/command/login.rb +42 -0
- data/lib/kitchen/command/sink.rb +53 -0
- data/lib/kitchen/command/test.rb +50 -0
- data/lib/kitchen/driver/ssh_base.rb +2 -1
- data/lib/kitchen/loader/yaml.rb +67 -29
- data/lib/kitchen/provisioner/base.rb +67 -4
- data/lib/kitchen/provisioner/chef_base.rb +50 -65
- data/lib/kitchen/provisioner/chef_solo.rb +3 -2
- data/lib/kitchen/provisioner/chef_zero.rb +11 -9
- data/lib/kitchen/provisioner/shell.rb +88 -0
- data/lib/kitchen/state_file.rb +7 -2
- data/lib/kitchen/util.rb +1 -1
- data/lib/kitchen/version.rb +1 -1
- data/spec/kitchen/loader/yaml_spec.rb +327 -13
- data/spec/spec_helper.rb +2 -7
- data/support/chef-client-zero.rb +1 -0
- data/templates/driver/README.md.erb +1 -1
- data/test-kitchen.gemspec +2 -2
- metadata +59 -46
@@ -0,0 +1,117 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'thread'
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
|
23
|
+
module Command
|
24
|
+
|
25
|
+
# Base class for CLI commands.
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
class Base
|
29
|
+
|
30
|
+
include Logging
|
31
|
+
|
32
|
+
def initialize(cmd_args, cmd_options, options = {})
|
33
|
+
@args = cmd_args
|
34
|
+
@options = cmd_options
|
35
|
+
@action = options.fetch(:action, nil)
|
36
|
+
@help = options.fetch(:help, lambda { "No help provided" })
|
37
|
+
@config = options.fetch(:config, nil)
|
38
|
+
@loader = options.fetch(:loader, nil)
|
39
|
+
@shell = options.fetch(:shell)
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
attr_reader :args, :options, :help, :config, :shell, :action
|
45
|
+
|
46
|
+
def die(msg)
|
47
|
+
error "\n#{msg}\n\n"
|
48
|
+
help.call
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_all_instances
|
53
|
+
result = @config.instances
|
54
|
+
|
55
|
+
if result.empty?
|
56
|
+
die "No instances defined"
|
57
|
+
else
|
58
|
+
result
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_filtered_instances(regexp)
|
63
|
+
result = begin
|
64
|
+
@config.instances.get(regexp) ||
|
65
|
+
@config.instances.get_all(/#{regexp}/)
|
66
|
+
rescue RegexpError => e
|
67
|
+
die "Invalid Ruby regular expression, " +
|
68
|
+
"you may need to single quote the argument. " +
|
69
|
+
"Please try again or consult http://rubular.com/ (#{e.message})"
|
70
|
+
end
|
71
|
+
result = Array(result)
|
72
|
+
|
73
|
+
if result.empty?
|
74
|
+
die "No instances for regex `#{regexp}', try running `kitchen list'"
|
75
|
+
else
|
76
|
+
result
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def logger
|
81
|
+
Kitchen.logger
|
82
|
+
end
|
83
|
+
|
84
|
+
def parse_subcommand(arg = nil)
|
85
|
+
arg == "all" ? get_all_instances : get_filtered_instances(arg)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Common module to execute a Kitchen action such as create, converge, etc.
|
90
|
+
#
|
91
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
92
|
+
module RunAction
|
93
|
+
|
94
|
+
def run_action(action, instances, *args)
|
95
|
+
concurrency = 1
|
96
|
+
if options[:concurrency]
|
97
|
+
concurrency = options[:concurrency] || instances.size
|
98
|
+
concurrency = instances.size if concurrency > instances.size
|
99
|
+
end
|
100
|
+
|
101
|
+
queue = Queue.new
|
102
|
+
instances.each {|i| queue << i }
|
103
|
+
concurrency.times { queue << nil }
|
104
|
+
|
105
|
+
threads = []
|
106
|
+
concurrency.times do
|
107
|
+
threads << Thread.new do
|
108
|
+
while instance = queue.pop
|
109
|
+
instance.public_send(action, *args)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
threads.map { |i| i.join }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
|
21
|
+
require 'benchmark'
|
22
|
+
|
23
|
+
module Kitchen
|
24
|
+
|
25
|
+
module Command
|
26
|
+
|
27
|
+
# Command to run a single action one or more instances.
|
28
|
+
#
|
29
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
30
|
+
class Action < Kitchen::Command::Base
|
31
|
+
|
32
|
+
include RunAction
|
33
|
+
|
34
|
+
def call
|
35
|
+
banner "Starting Kitchen (v#{Kitchen::VERSION})"
|
36
|
+
elapsed = Benchmark.measure do
|
37
|
+
results = parse_subcommand(args.first)
|
38
|
+
run_action(action, results)
|
39
|
+
end
|
40
|
+
banner "Kitchen is finished. #{Util.duration(elapsed.real)}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
|
23
|
+
module Command
|
24
|
+
|
25
|
+
# Command to launch a Pry-based Kitchen console..
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
class Console < Kitchen::Command::Base
|
29
|
+
|
30
|
+
def call
|
31
|
+
require 'pry'
|
32
|
+
Pry.start(@config, :prompt => [prompt(">"), prompt("*")])
|
33
|
+
rescue LoadError => e
|
34
|
+
warn %{Make sure you have the pry gem installed. You can install it with:}
|
35
|
+
warn %{`gem install pry` or including 'gem "pry"' in your Gemfile.}
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def prompt(char)
|
42
|
+
proc { |target_self, nest_level, pry|
|
43
|
+
["[#{pry.input_array.size}] ",
|
44
|
+
"kc(#{Pry.view_clip(target_self.class)})",
|
45
|
+
"#{":#{nest_level}" unless nest_level.zero?}#{char} "
|
46
|
+
].join
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
require 'kitchen/diagnostic'
|
21
|
+
|
22
|
+
require 'yaml'
|
23
|
+
|
24
|
+
module Kitchen
|
25
|
+
|
26
|
+
module Command
|
27
|
+
|
28
|
+
# Command to log into to instance.
|
29
|
+
#
|
30
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
31
|
+
class Diagnose < Kitchen::Command::Base
|
32
|
+
|
33
|
+
def call
|
34
|
+
loader = if options[:all] || options[:loader]
|
35
|
+
@loader
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
instances = if options[:all] || options[:instances]
|
41
|
+
parse_subcommand(args.first)
|
42
|
+
else
|
43
|
+
[]
|
44
|
+
end
|
45
|
+
|
46
|
+
puts Kitchen::Diagnostic.new(
|
47
|
+
:loader => loader, :instances => instances).read.to_yaml
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
|
21
|
+
require 'rubygems/spec_fetcher'
|
22
|
+
require 'safe_yaml'
|
23
|
+
|
24
|
+
module Kitchen
|
25
|
+
|
26
|
+
module Command
|
27
|
+
|
28
|
+
# Command to discover drivers published on RubyGems.
|
29
|
+
#
|
30
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
31
|
+
class DriverDiscover < Kitchen::Command::Base
|
32
|
+
|
33
|
+
def call
|
34
|
+
specs = fetch_gem_specs.sort { |x, y| x[0] <=> y[0] }
|
35
|
+
specs = specs[0, 49].push(["...", "..."]) if specs.size > 49
|
36
|
+
specs = specs.unshift(["Gem Name", "Latest Stable Release"])
|
37
|
+
print_table(specs, :indent => 4)
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def fetch_gem_specs
|
43
|
+
SafeYAML::OPTIONS[:suppress_warnings] = true
|
44
|
+
req = Gem::Requirement.default
|
45
|
+
dep = Gem::Deprecate.skip_during do
|
46
|
+
Gem::Dependency.new(/kitchen-/i, req)
|
47
|
+
end
|
48
|
+
fetcher = Gem::SpecFetcher.fetcher
|
49
|
+
|
50
|
+
specs = if fetcher.respond_to?(:find_matching)
|
51
|
+
fetch_gem_specs_pre_rubygems_2(fetcher, dep)
|
52
|
+
else
|
53
|
+
fetch_gem_specs_post_rubygems_2(fetcher, dep)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def fetch_gem_specs_post_rubygems_2(fetcher, dep)
|
58
|
+
specs = fetcher.spec_for_dependency(dep, false)
|
59
|
+
specs.first.map { |t| [t.first.name, t.first.version] }
|
60
|
+
end
|
61
|
+
|
62
|
+
def fetch_gem_specs_pre_rubygems_2(fetcher, dep)
|
63
|
+
specs = fetcher.find_matching(dep, false, false, false)
|
64
|
+
specs.map { |t| t.first }.map { |t| t[0, 2] }
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_table(*args)
|
68
|
+
shell.print_table(*args)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
|
23
|
+
module Command
|
24
|
+
|
25
|
+
# Command to list one or more instances.
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
class List < Kitchen::Command::Base
|
29
|
+
|
30
|
+
def call
|
31
|
+
result = parse_subcommand(args.first)
|
32
|
+
if options[:debug]
|
33
|
+
die "The --debug flag on the list subcommand is deprecated, " +
|
34
|
+
"please use `kitchen diagnose'."
|
35
|
+
elsif options[:bare]
|
36
|
+
puts Array(result).map { |i| i.name }.join("\n")
|
37
|
+
else
|
38
|
+
list_table(result)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def color_pad(string)
|
45
|
+
string + set_color("", :white)
|
46
|
+
end
|
47
|
+
|
48
|
+
def display_instance(instance)
|
49
|
+
[
|
50
|
+
color_pad(instance.name),
|
51
|
+
color_pad(instance.driver.name),
|
52
|
+
color_pad(instance.provisioner.name),
|
53
|
+
format_last_action(instance.last_action)
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
def format_last_action(last_action)
|
58
|
+
case last_action
|
59
|
+
when 'create' then set_color("Created", :cyan)
|
60
|
+
when 'converge' then set_color("Converged", :magenta)
|
61
|
+
when 'setup' then set_color("Set Up", :blue)
|
62
|
+
when 'verify' then set_color("Verified", :yellow)
|
63
|
+
when nil then set_color("<Not Created>", :red)
|
64
|
+
else set_color("<Unknown>", :white)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def list_table(result)
|
69
|
+
table = [
|
70
|
+
[set_color("Instance", :green), set_color("Driver", :green),
|
71
|
+
set_color("Provisioner", :green), set_color("Last Action", :green)]
|
72
|
+
]
|
73
|
+
table += Array(result).map { |i| display_instance(i) }
|
74
|
+
print_table(table)
|
75
|
+
end
|
76
|
+
|
77
|
+
def print_table(*args)
|
78
|
+
shell.print_table(*args)
|
79
|
+
end
|
80
|
+
|
81
|
+
def set_color(*args)
|
82
|
+
shell.set_color(*args)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Author:: Fletcher Nichol (<fnichol@nichol.ca>)
|
4
|
+
#
|
5
|
+
# Copyright (C) 2013, 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 'kitchen/command'
|
20
|
+
|
21
|
+
module Kitchen
|
22
|
+
|
23
|
+
module Command
|
24
|
+
|
25
|
+
# Command to log into to instance.
|
26
|
+
#
|
27
|
+
# @author Fletcher Nichol <fnichol@nichol.ca>
|
28
|
+
class Login < Kitchen::Command::Base
|
29
|
+
|
30
|
+
def call
|
31
|
+
results = parse_subcommand(args.first)
|
32
|
+
if results.size > 1
|
33
|
+
die "Argument `#{args.first}' returned multiple results:\n" +
|
34
|
+
results.map { |i| " * #{i.name}" }.join("\n")
|
35
|
+
end
|
36
|
+
instance = results.pop
|
37
|
+
|
38
|
+
instance.login
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|