test-kitchen 1.1.1 → 1.2.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +5 -0
  3. data/.travis.yml +8 -3
  4. data/CHANGELOG.md +66 -0
  5. data/Guardfile +3 -1
  6. data/README.md +3 -1
  7. data/Rakefile +1 -16
  8. data/features/kitchen_command.feature +1 -0
  9. data/features/kitchen_driver_create_command.feature +1 -0
  10. data/features/kitchen_driver_discover_command.feature +1 -0
  11. data/features/kitchen_help_command.feature +16 -0
  12. data/features/kitchen_init_command.feature +2 -0
  13. data/features/kitchen_list_command.feature +42 -0
  14. data/features/support/env.rb +25 -0
  15. data/lib/kitchen.rb +0 -1
  16. data/lib/kitchen/busser.rb +2 -2
  17. data/lib/kitchen/cli.rb +80 -233
  18. data/lib/kitchen/command.rb +117 -0
  19. data/lib/kitchen/command/action.rb +44 -0
  20. data/lib/kitchen/command/console.rb +51 -0
  21. data/lib/kitchen/command/diagnose.rb +51 -0
  22. data/lib/kitchen/command/driver_discover.rb +72 -0
  23. data/lib/kitchen/command/list.rb +86 -0
  24. data/lib/kitchen/command/login.rb +42 -0
  25. data/lib/kitchen/command/sink.rb +53 -0
  26. data/lib/kitchen/command/test.rb +50 -0
  27. data/lib/kitchen/driver/ssh_base.rb +2 -1
  28. data/lib/kitchen/loader/yaml.rb +67 -29
  29. data/lib/kitchen/provisioner/base.rb +67 -4
  30. data/lib/kitchen/provisioner/chef_base.rb +50 -65
  31. data/lib/kitchen/provisioner/chef_solo.rb +3 -2
  32. data/lib/kitchen/provisioner/chef_zero.rb +11 -9
  33. data/lib/kitchen/provisioner/shell.rb +88 -0
  34. data/lib/kitchen/state_file.rb +7 -2
  35. data/lib/kitchen/util.rb +1 -1
  36. data/lib/kitchen/version.rb +1 -1
  37. data/spec/kitchen/loader/yaml_spec.rb +327 -13
  38. data/spec/spec_helper.rb +2 -7
  39. data/support/chef-client-zero.rb +1 -0
  40. data/templates/driver/README.md.erb +1 -1
  41. data/test-kitchen.gemspec +2 -2
  42. 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