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.
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