test-kitchen 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -7
  3. data/.github/ISSUE_TEMPLATE.md +56 -0
  4. data/.gitignore +28 -27
  5. data/.kitchen.ci.yml +23 -0
  6. data/.kitchen.proxy.yml +27 -0
  7. data/.rubocop.yml +3 -3
  8. data/.travis.yml +70 -53
  9. data/.yardopts +3 -3
  10. data/Berksfile +3 -0
  11. data/CHANGELOG.md +1083 -1051
  12. data/CONTRIBUTING.md +14 -14
  13. data/Gemfile +19 -14
  14. data/Gemfile.proxy_tests +4 -5
  15. data/Guardfile +42 -42
  16. data/LICENSE +15 -15
  17. data/MAINTAINERS.md +23 -24
  18. data/README.md +135 -135
  19. data/Rakefile +61 -76
  20. data/appveyor.yml +44 -34
  21. data/features/kitchen_action_commands.feature +164 -164
  22. data/features/kitchen_command.feature +16 -16
  23. data/features/kitchen_console_command.feature +34 -34
  24. data/features/kitchen_defaults.feature +38 -38
  25. data/features/kitchen_diagnose_command.feature +96 -96
  26. data/features/kitchen_driver_create_command.feature +64 -64
  27. data/features/kitchen_driver_discover_command.feature +25 -25
  28. data/features/kitchen_help_command.feature +16 -16
  29. data/features/kitchen_init_command.feature +274 -274
  30. data/features/kitchen_list_command.feature +104 -104
  31. data/features/kitchen_login_command.feature +62 -62
  32. data/features/kitchen_sink_command.feature +30 -30
  33. data/features/kitchen_test_command.feature +88 -88
  34. data/features/step_definitions/gem_steps.rb +36 -36
  35. data/features/step_definitions/git_steps.rb +5 -5
  36. data/features/step_definitions/output_steps.rb +5 -5
  37. data/features/support/env.rb +75 -75
  38. data/lib/kitchen.rb +150 -150
  39. data/lib/kitchen/base64_stream.rb +55 -55
  40. data/lib/kitchen/cli.rb +419 -419
  41. data/lib/kitchen/collection.rb +55 -55
  42. data/lib/kitchen/color.rb +65 -65
  43. data/lib/kitchen/command.rb +185 -185
  44. data/lib/kitchen/command/action.rb +45 -45
  45. data/lib/kitchen/command/console.rb +58 -58
  46. data/lib/kitchen/command/diagnose.rb +92 -92
  47. data/lib/kitchen/command/driver_discover.rb +105 -105
  48. data/lib/kitchen/command/exec.rb +41 -41
  49. data/lib/kitchen/command/list.rb +119 -119
  50. data/lib/kitchen/command/login.rb +43 -43
  51. data/lib/kitchen/command/sink.rb +54 -54
  52. data/lib/kitchen/command/test.rb +51 -51
  53. data/lib/kitchen/config.rb +322 -322
  54. data/lib/kitchen/configurable.rb +529 -529
  55. data/lib/kitchen/data_munger.rb +959 -960
  56. data/lib/kitchen/diagnostic.rb +141 -141
  57. data/lib/kitchen/driver.rb +56 -56
  58. data/lib/kitchen/driver/base.rb +134 -134
  59. data/lib/kitchen/driver/dummy.rb +108 -108
  60. data/lib/kitchen/driver/proxy.rb +72 -72
  61. data/lib/kitchen/driver/ssh_base.rb +357 -357
  62. data/lib/kitchen/errors.rb +229 -229
  63. data/lib/kitchen/generator/driver_create.rb +177 -177
  64. data/lib/kitchen/generator/init.rb +296 -296
  65. data/lib/kitchen/instance.rb +662 -662
  66. data/lib/kitchen/lazy_hash.rb +142 -142
  67. data/lib/kitchen/loader/yaml.rb +349 -349
  68. data/lib/kitchen/logger.rb +423 -423
  69. data/lib/kitchen/logging.rb +56 -56
  70. data/lib/kitchen/login_command.rb +52 -52
  71. data/lib/kitchen/metadata_chopper.rb +52 -52
  72. data/lib/kitchen/platform.rb +67 -67
  73. data/lib/kitchen/provisioner.rb +54 -54
  74. data/lib/kitchen/provisioner/base.rb +236 -236
  75. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  76. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  77. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  78. data/lib/kitchen/provisioner/chef_apply.rb +124 -125
  79. data/lib/kitchen/provisioner/chef_base.rb +341 -294
  80. data/lib/kitchen/provisioner/chef_solo.rb +88 -89
  81. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  82. data/lib/kitchen/provisioner/dummy.rb +79 -79
  83. data/lib/kitchen/provisioner/shell.rb +138 -138
  84. data/lib/kitchen/rake_tasks.rb +63 -63
  85. data/lib/kitchen/shell_out.rb +93 -93
  86. data/lib/kitchen/ssh.rb +276 -276
  87. data/lib/kitchen/state_file.rb +120 -120
  88. data/lib/kitchen/suite.rb +51 -51
  89. data/lib/kitchen/thor_tasks.rb +66 -66
  90. data/lib/kitchen/transport.rb +54 -54
  91. data/lib/kitchen/transport/base.rb +176 -176
  92. data/lib/kitchen/transport/dummy.rb +79 -79
  93. data/lib/kitchen/transport/ssh.rb +364 -364
  94. data/lib/kitchen/transport/winrm.rb +486 -486
  95. data/lib/kitchen/util.rb +147 -147
  96. data/lib/kitchen/verifier.rb +55 -55
  97. data/lib/kitchen/verifier/base.rb +235 -235
  98. data/lib/kitchen/verifier/busser.rb +277 -277
  99. data/lib/kitchen/verifier/dummy.rb +79 -79
  100. data/lib/kitchen/verifier/shell.rb +101 -101
  101. data/lib/kitchen/version.rb +21 -21
  102. data/lib/vendor/hash_recursive_merge.rb +82 -82
  103. data/spec/kitchen/base64_stream_spec.rb +77 -77
  104. data/spec/kitchen/cli_spec.rb +56 -56
  105. data/spec/kitchen/collection_spec.rb +80 -80
  106. data/spec/kitchen/color_spec.rb +54 -54
  107. data/spec/kitchen/config_spec.rb +408 -408
  108. data/spec/kitchen/configurable_spec.rb +1095 -1062
  109. data/spec/kitchen/data_munger_spec.rb +2694 -2383
  110. data/spec/kitchen/diagnostic_spec.rb +129 -129
  111. data/spec/kitchen/driver/base_spec.rb +121 -121
  112. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  113. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  114. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  115. data/spec/kitchen/driver_spec.rb +112 -112
  116. data/spec/kitchen/errors_spec.rb +309 -309
  117. data/spec/kitchen/instance_spec.rb +1419 -1419
  118. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  119. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  120. data/spec/kitchen/logger_spec.rb +429 -429
  121. data/spec/kitchen/logging_spec.rb +59 -59
  122. data/spec/kitchen/login_command_spec.rb +68 -68
  123. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  124. data/spec/kitchen/platform_spec.rb +89 -89
  125. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  126. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  127. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1067
  128. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  129. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  130. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  131. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  132. data/spec/kitchen/provisioner_spec.rb +107 -107
  133. data/spec/kitchen/shell_out_spec.rb +150 -150
  134. data/spec/kitchen/ssh_spec.rb +693 -693
  135. data/spec/kitchen/state_file_spec.rb +129 -129
  136. data/spec/kitchen/suite_spec.rb +62 -62
  137. data/spec/kitchen/transport/base_spec.rb +89 -89
  138. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  139. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  140. data/spec/kitchen/transport_spec.rb +112 -112
  141. data/spec/kitchen/util_spec.rb +165 -165
  142. data/spec/kitchen/verifier/base_spec.rb +362 -362
  143. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  144. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  145. data/spec/kitchen/verifier/shell_spec.rb +160 -158
  146. data/spec/kitchen/verifier_spec.rb +120 -120
  147. data/spec/kitchen_spec.rb +114 -114
  148. data/spec/spec_helper.rb +85 -85
  149. data/spec/support/powershell_max_size_spec.rb +40 -40
  150. data/support/busser_install_command.ps1 +14 -14
  151. data/support/busser_install_command.sh +14 -14
  152. data/support/chef-client-zero.rb +77 -77
  153. data/support/chef_base_init_command.ps1 +18 -18
  154. data/support/chef_base_init_command.sh +2 -2
  155. data/support/chef_base_install_command.ps1 +85 -85
  156. data/support/chef_base_install_command.sh +229 -229
  157. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  158. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  159. data/support/download_helpers.sh +109 -109
  160. data/support/dummy-validation.pem +27 -27
  161. data/templates/driver/CHANGELOG.md.erb +3 -3
  162. data/templates/driver/Gemfile.erb +3 -3
  163. data/templates/driver/README.md.erb +64 -64
  164. data/templates/driver/Rakefile.erb +21 -21
  165. data/templates/driver/driver.rb.erb +23 -23
  166. data/templates/driver/gemspec.erb +29 -29
  167. data/templates/driver/gitignore.erb +17 -17
  168. data/templates/driver/license_apachev2.erb +15 -15
  169. data/templates/driver/license_lgplv3.erb +16 -16
  170. data/templates/driver/license_mit.erb +22 -22
  171. data/templates/driver/license_reserved.erb +5 -5
  172. data/templates/driver/tailor.erb +4 -4
  173. data/templates/driver/travis.yml.erb +11 -11
  174. data/templates/driver/version.rb.erb +12 -12
  175. data/templates/init/chefignore.erb +1 -1
  176. data/templates/init/kitchen.yml.erb +18 -18
  177. data/test-kitchen.gemspec +62 -62
  178. data/test/integration/default/default_spec.rb +3 -0
  179. data/testing_windows.md +37 -37
  180. metadata +23 -11
@@ -1,55 +1,55 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2014, 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
- module Kitchen
20
-
21
- # Base64 encoder/decoder that operates on IO objects so as to minimize
22
- # memory allocations on large payloads.
23
- #
24
- # @author Fletcher Nichol <fnichol@nichol.ca>
25
- module Base64Stream
26
-
27
- # Encodes an input stream into a Base64 output stream. The input and ouput
28
- # objects must be opened IO resources. In other words, opening and closing
29
- # the resources are not the responsibilty of this method.
30
- #
31
- # @param io_in [#read] input stream
32
- # @param io_out [#write] output stream
33
- def self.strict_encode(io_in, io_out)
34
- buffer = ""
35
- while io_in.read(3 * 1000, buffer)
36
- io_out.write([buffer].pack("m0"))
37
- end
38
- buffer = nil # rubocop:disable Lint/UselessAssignment
39
- end
40
-
41
- # Decodes a Base64 input stream into an output stream. The input and ouput
42
- # objects must be opened IO resources. In other words, opening and closing
43
- # the resources are not the responsibilty of this method.
44
- #
45
- # @param io_in [#read] input stream
46
- # @param io_out [#write] output stream
47
- def self.strict_decode(io_in, io_out)
48
- buffer = ""
49
- while io_in.read(3 * 1000, buffer)
50
- io_out.write(buffer.unpack("m0").first)
51
- end
52
- buffer = nil # rubocop:disable Lint/UselessAssignment
53
- end
54
- end
55
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2014, 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
+ module Kitchen
20
+
21
+ # Base64 encoder/decoder that operates on IO objects so as to minimize
22
+ # memory allocations on large payloads.
23
+ #
24
+ # @author Fletcher Nichol <fnichol@nichol.ca>
25
+ module Base64Stream
26
+
27
+ # Encodes an input stream into a Base64 output stream. The input and ouput
28
+ # objects must be opened IO resources. In other words, opening and closing
29
+ # the resources are not the responsibilty of this method.
30
+ #
31
+ # @param io_in [#read] input stream
32
+ # @param io_out [#write] output stream
33
+ def self.strict_encode(io_in, io_out)
34
+ buffer = ""
35
+ while io_in.read(3 * 1000, buffer)
36
+ io_out.write([buffer].pack("m0"))
37
+ end
38
+ buffer = nil # rubocop:disable Lint/UselessAssignment
39
+ end
40
+
41
+ # Decodes a Base64 input stream into an output stream. The input and ouput
42
+ # objects must be opened IO resources. In other words, opening and closing
43
+ # the resources are not the responsibilty of this method.
44
+ #
45
+ # @param io_in [#read] input stream
46
+ # @param io_out [#write] output stream
47
+ def self.strict_decode(io_in, io_out)
48
+ buffer = ""
49
+ while io_in.read(3 * 1000, buffer)
50
+ io_out.write(buffer.unpack("m0").first)
51
+ end
52
+ buffer = nil # rubocop:disable Lint/UselessAssignment
53
+ end
54
+ end
55
+ end
data/lib/kitchen/cli.rb CHANGED
@@ -1,419 +1,419 @@
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 "thor"
20
-
21
- require "kitchen"
22
- require "kitchen/generator/driver_create"
23
- require "kitchen/generator/init"
24
-
25
- module Kitchen
26
-
27
- # The command line runner for Kitchen.
28
- #
29
- # @author Fletcher Nichol <fnichol@nichol.ca>
30
- class CLI < Thor
31
-
32
- # Common module to load and invoke a CLI-implementation agnostic command.
33
- module PerformCommand
34
-
35
- # Perform a CLI subcommand.
36
- #
37
- # @param task [String] action to take, usually corresponding to the
38
- # subcommand name
39
- # @param command [String] command class to create and invoke]
40
- # @param args [Array] remainder arguments from processed ARGV
41
- # (default: `nil`)
42
- # @param additional_options [Hash] additional configuration needed to
43
- # set up the command class (default: `{}`)
44
- def perform(task, command, args = nil, additional_options = {})
45
- require "kitchen/command/#{command}"
46
-
47
- command_options = {
48
- :action => task,
49
- :help => -> { help(task) },
50
- :config => @config,
51
- :shell => shell
52
- }.merge(additional_options)
53
-
54
- str_const = Thor::Util.camel_case(command)
55
- klass = ::Kitchen::Command.const_get(str_const)
56
- klass.new(args, options, command_options).call
57
- end
58
- end
59
-
60
- include Logging
61
- include PerformCommand
62
-
63
- # The maximum number of concurrent instances that can run--which is a bit
64
- # high
65
- MAX_CONCURRENCY = 9999
66
-
67
- attr_reader :config
68
-
69
- # Constructs a new instance.
70
- def initialize(*args)
71
- super
72
- $stdout.sync = true
73
- @loader = Kitchen::Loader::YAML.new(
74
- :project_config => ENV["KITCHEN_YAML"],
75
- :local_config => ENV["KITCHEN_LOCAL_YAML"],
76
- :global_config => ENV["KITCHEN_GLOBAL_YAML"]
77
- )
78
- @config = Kitchen::Config.new(
79
- :loader => @loader
80
- )
81
- @config.log_level = Kitchen.env_log unless Kitchen.env_log.nil?
82
- @config.log_overwrite = Kitchen.env_log_overwrite unless Kitchen.env_log_overwrite.nil?
83
- end
84
-
85
- # Sets the logging method_options
86
- # @api private
87
- def self.log_options
88
- method_option :log_level,
89
- :aliases => "-l",
90
- :desc => "Set the log level (debug, info, warn, error, fatal)"
91
- method_option :log_overwrite,
92
- :desc => "Set to false to prevent log overwriting each time Test Kitchen runs",
93
- :type => :boolean
94
- end
95
-
96
- # Sets the test_base_path method_options
97
- # @api private
98
- def self.test_base_path
99
- method_option :test_base_path,
100
- :aliases => "-t",
101
- :desc => "Set the base path of the tests"
102
- end
103
-
104
- desc "list [INSTANCE|REGEXP|all]", "Lists one or more instances"
105
- method_option :bare,
106
- :aliases => "-b",
107
- :type => :boolean,
108
- :desc => "List the name of each instance only, one per line"
109
- method_option :debug,
110
- :aliases => "-d",
111
- :type => :boolean,
112
- :desc => "[Deprecated] Please use `kitchen diagnose'"
113
- log_options
114
- def list(*args)
115
- update_config!
116
- perform("list", "list", args)
117
- end
118
-
119
- desc "diagnose [INSTANCE|REGEXP|all]", "Show computed diagnostic configuration"
120
- method_option :loader,
121
- :type => :boolean,
122
- :desc => "Include data loader diagnostics"
123
- method_option :plugins,
124
- :type => :boolean,
125
- :desc => "Include plugin diagnostics"
126
- method_option :instances,
127
- :type => :boolean,
128
- :default => true,
129
- :desc => "Include instances diagnostics"
130
- method_option :all,
131
- :type => :boolean,
132
- :desc => "Include all diagnostics"
133
- log_options
134
- def diagnose(*args)
135
- update_config!
136
- perform("diagnose", "diagnose", args, :loader => @loader)
137
- end
138
-
139
- {
140
- :create => "Change instance state to create. " \
141
- "Start one or more instances",
142
- :converge => "Change instance state to converge. " \
143
- "Use a provisioner to configure one or more instances",
144
- :setup => "Change instance state to setup. " \
145
- "Prepare to run automated tests. " \
146
- "Install busser and related gems on one or more instances",
147
- :verify => "Change instance state to verify. " \
148
- "Run automated tests on one or more instances",
149
- :destroy => "Change instance state to destroy. " \
150
- "Delete all information for one or more instances"
151
- }.each do |action, short_desc|
152
- desc(
153
- "#{action} [INSTANCE|REGEXP|all]",
154
- short_desc
155
- )
156
- long_desc <<-DESC
157
- The instance states are in order: destroy, create, converge, setup, verify, destroy.
158
- Change one or more instances from the current state to the #{action} state. Actions for all
159
- intermediate states will be executed. See http://kitchen.ci for further explanation.
160
- DESC
161
- method_option :concurrency,
162
- :aliases => "-c",
163
- :type => :numeric,
164
- :lazy_default => MAX_CONCURRENCY,
165
- :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
166
- Run a #{action} against all matching instances concurrently. Only N
167
- instances will run at the same time if a number is given.
168
- DESC
169
- method_option :parallel,
170
- :aliases => "-p",
171
- :type => :boolean,
172
- :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
173
- [Future DEPRECATION, use --concurrency]
174
- Run a #{action} against all matching instances concurrently.
175
- DESC
176
- test_base_path
177
- log_options
178
- define_method(action) do |*args|
179
- update_config!
180
- perform(action, "action", args)
181
- end
182
- end
183
-
184
- desc "test [INSTANCE|REGEXP|all]",
185
- "Test (destroy, create, converge, setup, verify and destroy) one or more instances"
186
- long_desc <<-DESC
187
- The instance states are in order: destroy, create, converge, setup, verify, destroy.
188
- Test changes the state of one or more instances to destroyed, then executes
189
- the actions for each state up to destroy. At any sign of failure, executing the
190
- actions stops and the instance is left in the last successful execution state.
191
-
192
- There are 3 post-verify modes for instance cleanup, triggered with
193
- the `--destroy' flag:
194
-
195
- * passing: instances passing verify will be destroyed afterwards.\n
196
- * always: instances will always be destroyed afterwards.\n
197
- * never: instances will never be destroyed afterwards.
198
- DESC
199
- method_option :concurrency,
200
- :aliases => "-c",
201
- :type => :numeric,
202
- :lazy_default => MAX_CONCURRENCY,
203
- :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
204
- Run a test against all matching instances concurrently. Only N
205
- instances will run at the same time if a number is given.
206
- DESC
207
- method_option :parallel,
208
- :aliases => "-p",
209
- :type => :boolean,
210
- :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
211
- [Future DEPRECATION, use --concurrency]
212
- Run a test against all matching instances concurrently.
213
- DESC
214
- method_option :destroy,
215
- :aliases => "-d",
216
- :default => "passing",
217
- :desc => "Destroy strategy to use after testing (passing, always, never)."
218
- method_option :auto_init,
219
- :type => :boolean,
220
- :default => false,
221
- :desc => "Invoke init command if .kitchen.yml is missing"
222
- test_base_path
223
- log_options
224
- def test(*args)
225
- update_config!
226
- ensure_initialized
227
- perform("test", "test", args)
228
- end
229
-
230
- desc "login INSTANCE|REGEXP", "Log in to one instance"
231
- log_options
232
- def login(*args)
233
- update_config!
234
- perform("login", "login", args)
235
- end
236
-
237
- desc "exec INSTANCE|REGEXP -c REMOTE_COMMAND",
238
- "Execute command on one or more instance"
239
- method_option :command,
240
- :aliases => "-c",
241
- :desc => "execute via ssh"
242
- log_options
243
- def exec(*args)
244
- update_config!
245
- perform("exec", "exec", args)
246
- end
247
-
248
- desc "version", "Print Kitchen's version information"
249
- def version
250
- puts "Test Kitchen version #{Kitchen::VERSION}"
251
- end
252
- map %w[-v --version] => :version
253
-
254
- desc "sink", "Show the Kitchen sink!", :hide => true
255
- def sink
256
- perform("sink", "sink")
257
- end
258
-
259
- desc "console", "Kitchen Console!"
260
- def console
261
- perform("console", "console")
262
- end
263
-
264
- register Kitchen::Generator::Init, "init",
265
- "init", "Adds some configuration to your cookbook so Kitchen can rock"
266
- long_desc <<-D, :for => "init"
267
- Init will add Test Kitchen support to an existing project for
268
- convergence integration testing. A default .kitchen.yml file (which is
269
- intended to be customized) is created in the project's root directory
270
- and one or more gems will be added to the project's Gemfile.
271
- D
272
- tasks["init"].options = Kitchen::Generator::Init.class_options
273
-
274
- # Thor class for kitchen driver commands.
275
- #
276
- # @author Fletcher Nichol <fnichol@nichol.ca>
277
- class Driver < Thor
278
-
279
- include PerformCommand
280
-
281
- register Kitchen::Generator::DriverCreate, "create",
282
- "create [NAME]", "Create a new Kitchen Driver gem project"
283
- long_desc <<-D, :for => "create"
284
- Create will generate a project scaffold for a brand new Test Kitchen
285
- Driver RubyGem. For example:
286
-
287
- > kitchen driver create foobar
288
-
289
- will create a project scaffold for a RubyGem called `kitchen-foobar'.
290
- D
291
- tasks["create"].options = Kitchen::Generator::DriverCreate.class_options
292
-
293
- desc "discover", "Discover Test Kitchen drivers published on RubyGems"
294
- long_desc <<-D
295
- Discover will perform a search aginst the RubyGems service for any
296
- published gems of the form: "kitchen-*". Note that it it cannot be
297
- guarenteed that every result is a driver, but chances are good most
298
- relevant drivers will be returned.
299
- D
300
- method_option :chef_config_path,
301
- :default => nil,
302
- :desc => "Path to chef config file containing proxy configuration to use"
303
- def discover
304
- perform("discover", "driver_discover", args)
305
- end
306
-
307
- # @return [String] basename
308
- def self.basename
309
- super + " driver"
310
- end
311
- end
312
-
313
- register Kitchen::CLI::Driver, "driver",
314
- "driver", "Driver subcommands"
315
-
316
- no_tasks do
317
- def invoke_task(command, *args)
318
- if command.name == "help" && args.first.first == "driver"
319
- Kitchen::CLI::Driver.task_help(shell, args.first.last)
320
- else
321
- super
322
- end
323
- end
324
- alias_method :invoke_command, :invoke_task
325
- end
326
-
327
- private
328
-
329
- # Ensure the any failing commands exit non-zero.
330
- #
331
- # @return [true] you die always on failure
332
- # @api private
333
- def self.exit_on_failure?
334
- true
335
- end
336
-
337
- # @return [Logger] the common logger
338
- # @api private
339
- def logger
340
- Kitchen.logger
341
- end
342
-
343
- # Update and finalize options for logging, concurrency, and other concerns.
344
- #
345
- # @api private
346
- def update_config!
347
- @config.log_level = log_level if log_level
348
-
349
- unless options[:log_overwrite].nil?
350
- @config.log_overwrite = options[:log_overwrite]
351
- end
352
-
353
- if options[:test_base_path]
354
- # ensure we have an absolute path
355
- @config.test_base_path = File.absolute_path(options[:test_base_path])
356
- end
357
-
358
- # Now that we have required configs, lets create our file logger
359
- Kitchen.logger = Kitchen.default_file_logger(
360
- log_level,
361
- options[:log_overwrite]
362
- )
363
-
364
- update_parallel!
365
- end
366
-
367
- # Validate the log level from the config / CLI options, defaulting
368
- # to :info if the supplied level is empty or invalid
369
- #
370
- # @api private
371
- def log_level
372
- return unless options[:log_level]
373
- return @log_level if @log_level
374
-
375
- level = options[:log_level].downcase.to_sym
376
- unless valid_log_level?(level)
377
- level = :info
378
- banner "WARNING - invalid log level specified: " \
379
- "\"#{options[:log_level]}\" - reverting to :info log level."
380
- end
381
-
382
- @log_level = level
383
- end
384
-
385
- # Check to whether a provided log level is valid
386
- #
387
- # @api private
388
- def valid_log_level?(level)
389
- !Util.to_logger_level(level).nil?
390
- end
391
-
392
- # Set parallel concurrency options for Thor
393
- #
394
- # @api private
395
- def update_parallel!
396
- if options[:parallel]
397
- # warn here in a future release when option is used
398
- @options = Thor::CoreExt::HashWithIndifferentAccess.new(options.to_hash)
399
- if options[:parallel] && !options[:concurrency]
400
- options[:concurrency] = MAX_CONCURRENCY
401
- end
402
- options.delete(:parallel)
403
- options.freeze
404
- end
405
- end
406
-
407
- # If auto_init option is active, invoke the init generator.
408
- #
409
- # @api private
410
- def ensure_initialized
411
- yaml = ENV["KITCHEN_YAML"] || ".kitchen.yml"
412
-
413
- if options[:auto_init] && !File.exist?(yaml)
414
- banner "Invoking init as '#{yaml}' file is missing"
415
- invoke "init"
416
- end
417
- end
418
- end
419
- end
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 "thor"
20
+
21
+ require "kitchen"
22
+ require "kitchen/generator/driver_create"
23
+ require "kitchen/generator/init"
24
+
25
+ module Kitchen
26
+
27
+ # The command line runner for Kitchen.
28
+ #
29
+ # @author Fletcher Nichol <fnichol@nichol.ca>
30
+ class CLI < Thor
31
+
32
+ # Common module to load and invoke a CLI-implementation agnostic command.
33
+ module PerformCommand
34
+
35
+ # Perform a CLI subcommand.
36
+ #
37
+ # @param task [String] action to take, usually corresponding to the
38
+ # subcommand name
39
+ # @param command [String] command class to create and invoke]
40
+ # @param args [Array] remainder arguments from processed ARGV
41
+ # (default: `nil`)
42
+ # @param additional_options [Hash] additional configuration needed to
43
+ # set up the command class (default: `{}`)
44
+ def perform(task, command, args = nil, additional_options = {})
45
+ require "kitchen/command/#{command}"
46
+
47
+ command_options = {
48
+ :action => task,
49
+ :help => -> { help(task) },
50
+ :config => @config,
51
+ :shell => shell
52
+ }.merge(additional_options)
53
+
54
+ str_const = Thor::Util.camel_case(command)
55
+ klass = ::Kitchen::Command.const_get(str_const)
56
+ klass.new(args, options, command_options).call
57
+ end
58
+ end
59
+
60
+ include Logging
61
+ include PerformCommand
62
+
63
+ # The maximum number of concurrent instances that can run--which is a bit
64
+ # high
65
+ MAX_CONCURRENCY = 9999
66
+
67
+ attr_reader :config
68
+
69
+ # Constructs a new instance.
70
+ def initialize(*args)
71
+ super
72
+ $stdout.sync = true
73
+ @loader = Kitchen::Loader::YAML.new(
74
+ :project_config => ENV["KITCHEN_YAML"],
75
+ :local_config => ENV["KITCHEN_LOCAL_YAML"],
76
+ :global_config => ENV["KITCHEN_GLOBAL_YAML"]
77
+ )
78
+ @config = Kitchen::Config.new(
79
+ :loader => @loader
80
+ )
81
+ @config.log_level = Kitchen.env_log unless Kitchen.env_log.nil?
82
+ @config.log_overwrite = Kitchen.env_log_overwrite unless Kitchen.env_log_overwrite.nil?
83
+ end
84
+
85
+ # Sets the logging method_options
86
+ # @api private
87
+ def self.log_options
88
+ method_option :log_level,
89
+ :aliases => "-l",
90
+ :desc => "Set the log level (debug, info, warn, error, fatal)"
91
+ method_option :log_overwrite,
92
+ :desc => "Set to false to prevent log overwriting each time Test Kitchen runs",
93
+ :type => :boolean
94
+ end
95
+
96
+ # Sets the test_base_path method_options
97
+ # @api private
98
+ def self.test_base_path
99
+ method_option :test_base_path,
100
+ :aliases => "-t",
101
+ :desc => "Set the base path of the tests"
102
+ end
103
+
104
+ desc "list [INSTANCE|REGEXP|all]", "Lists one or more instances"
105
+ method_option :bare,
106
+ :aliases => "-b",
107
+ :type => :boolean,
108
+ :desc => "List the name of each instance only, one per line"
109
+ method_option :debug,
110
+ :aliases => "-d",
111
+ :type => :boolean,
112
+ :desc => "[Deprecated] Please use `kitchen diagnose'"
113
+ log_options
114
+ def list(*args)
115
+ update_config!
116
+ perform("list", "list", args)
117
+ end
118
+
119
+ desc "diagnose [INSTANCE|REGEXP|all]", "Show computed diagnostic configuration"
120
+ method_option :loader,
121
+ :type => :boolean,
122
+ :desc => "Include data loader diagnostics"
123
+ method_option :plugins,
124
+ :type => :boolean,
125
+ :desc => "Include plugin diagnostics"
126
+ method_option :instances,
127
+ :type => :boolean,
128
+ :default => true,
129
+ :desc => "Include instances diagnostics"
130
+ method_option :all,
131
+ :type => :boolean,
132
+ :desc => "Include all diagnostics"
133
+ log_options
134
+ def diagnose(*args)
135
+ update_config!
136
+ perform("diagnose", "diagnose", args, :loader => @loader)
137
+ end
138
+
139
+ {
140
+ :create => "Change instance state to create. " \
141
+ "Start one or more instances",
142
+ :converge => "Change instance state to converge. " \
143
+ "Use a provisioner to configure one or more instances",
144
+ :setup => "Change instance state to setup. " \
145
+ "Prepare to run automated tests. " \
146
+ "Install busser and related gems on one or more instances",
147
+ :verify => "Change instance state to verify. " \
148
+ "Run automated tests on one or more instances",
149
+ :destroy => "Change instance state to destroy. " \
150
+ "Delete all information for one or more instances"
151
+ }.each do |action, short_desc|
152
+ desc(
153
+ "#{action} [INSTANCE|REGEXP|all]",
154
+ short_desc
155
+ )
156
+ long_desc <<-DESC
157
+ The instance states are in order: destroy, create, converge, setup, verify, destroy.
158
+ Change one or more instances from the current state to the #{action} state. Actions for all
159
+ intermediate states will be executed. See http://kitchen.ci for further explanation.
160
+ DESC
161
+ method_option :concurrency,
162
+ :aliases => "-c",
163
+ :type => :numeric,
164
+ :lazy_default => MAX_CONCURRENCY,
165
+ :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
166
+ Run a #{action} against all matching instances concurrently. Only N
167
+ instances will run at the same time if a number is given.
168
+ DESC
169
+ method_option :parallel,
170
+ :aliases => "-p",
171
+ :type => :boolean,
172
+ :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
173
+ [Future DEPRECATION, use --concurrency]
174
+ Run a #{action} against all matching instances concurrently.
175
+ DESC
176
+ test_base_path
177
+ log_options
178
+ define_method(action) do |*args|
179
+ update_config!
180
+ perform(action, "action", args)
181
+ end
182
+ end
183
+
184
+ desc "test [INSTANCE|REGEXP|all]",
185
+ "Test (destroy, create, converge, setup, verify and destroy) one or more instances"
186
+ long_desc <<-DESC
187
+ The instance states are in order: destroy, create, converge, setup, verify, destroy.
188
+ Test changes the state of one or more instances to destroyed, then executes
189
+ the actions for each state up to destroy. At any sign of failure, executing the
190
+ actions stops and the instance is left in the last successful execution state.
191
+
192
+ There are 3 post-verify modes for instance cleanup, triggered with
193
+ the `--destroy' flag:
194
+
195
+ * passing: instances passing verify will be destroyed afterwards.\n
196
+ * always: instances will always be destroyed afterwards.\n
197
+ * never: instances will never be destroyed afterwards.
198
+ DESC
199
+ method_option :concurrency,
200
+ :aliases => "-c",
201
+ :type => :numeric,
202
+ :lazy_default => MAX_CONCURRENCY,
203
+ :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
204
+ Run a test against all matching instances concurrently. Only N
205
+ instances will run at the same time if a number is given.
206
+ DESC
207
+ method_option :parallel,
208
+ :aliases => "-p",
209
+ :type => :boolean,
210
+ :desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
211
+ [Future DEPRECATION, use --concurrency]
212
+ Run a test against all matching instances concurrently.
213
+ DESC
214
+ method_option :destroy,
215
+ :aliases => "-d",
216
+ :default => "passing",
217
+ :desc => "Destroy strategy to use after testing (passing, always, never)."
218
+ method_option :auto_init,
219
+ :type => :boolean,
220
+ :default => false,
221
+ :desc => "Invoke init command if .kitchen.yml is missing"
222
+ test_base_path
223
+ log_options
224
+ def test(*args)
225
+ update_config!
226
+ ensure_initialized
227
+ perform("test", "test", args)
228
+ end
229
+
230
+ desc "login INSTANCE|REGEXP", "Log in to one instance"
231
+ log_options
232
+ def login(*args)
233
+ update_config!
234
+ perform("login", "login", args)
235
+ end
236
+
237
+ desc "exec INSTANCE|REGEXP -c REMOTE_COMMAND",
238
+ "Execute command on one or more instance"
239
+ method_option :command,
240
+ :aliases => "-c",
241
+ :desc => "execute via ssh"
242
+ log_options
243
+ def exec(*args)
244
+ update_config!
245
+ perform("exec", "exec", args)
246
+ end
247
+
248
+ desc "version", "Print Kitchen's version information"
249
+ def version
250
+ puts "Test Kitchen version #{Kitchen::VERSION}"
251
+ end
252
+ map %w[-v --version] => :version
253
+
254
+ desc "sink", "Show the Kitchen sink!", :hide => true
255
+ def sink
256
+ perform("sink", "sink")
257
+ end
258
+
259
+ desc "console", "Kitchen Console!"
260
+ def console
261
+ perform("console", "console")
262
+ end
263
+
264
+ register Kitchen::Generator::Init, "init",
265
+ "init", "Adds some configuration to your cookbook so Kitchen can rock"
266
+ long_desc <<-D, :for => "init"
267
+ Init will add Test Kitchen support to an existing project for
268
+ convergence integration testing. A default .kitchen.yml file (which is
269
+ intended to be customized) is created in the project's root directory
270
+ and one or more gems will be added to the project's Gemfile.
271
+ D
272
+ tasks["init"].options = Kitchen::Generator::Init.class_options
273
+
274
+ # Thor class for kitchen driver commands.
275
+ #
276
+ # @author Fletcher Nichol <fnichol@nichol.ca>
277
+ class Driver < Thor
278
+
279
+ include PerformCommand
280
+
281
+ register Kitchen::Generator::DriverCreate, "create",
282
+ "create [NAME]", "Create a new Kitchen Driver gem project"
283
+ long_desc <<-D, :for => "create"
284
+ Create will generate a project scaffold for a brand new Test Kitchen
285
+ Driver RubyGem. For example:
286
+
287
+ > kitchen driver create foobar
288
+
289
+ will create a project scaffold for a RubyGem called `kitchen-foobar'.
290
+ D
291
+ tasks["create"].options = Kitchen::Generator::DriverCreate.class_options
292
+
293
+ desc "discover", "Discover Test Kitchen drivers published on RubyGems"
294
+ long_desc <<-D
295
+ Discover will perform a search aginst the RubyGems service for any
296
+ published gems of the form: "kitchen-*". Note that it it cannot be
297
+ guarenteed that every result is a driver, but chances are good most
298
+ relevant drivers will be returned.
299
+ D
300
+ method_option :chef_config_path,
301
+ :default => nil,
302
+ :desc => "Path to chef config file containing proxy configuration to use"
303
+ def discover
304
+ perform("discover", "driver_discover", args)
305
+ end
306
+
307
+ # @return [String] basename
308
+ def self.basename
309
+ super + " driver"
310
+ end
311
+ end
312
+
313
+ register Kitchen::CLI::Driver, "driver",
314
+ "driver", "Driver subcommands"
315
+
316
+ no_tasks do
317
+ def invoke_task(command, *args)
318
+ if command.name == "help" && args.first.first == "driver"
319
+ Kitchen::CLI::Driver.task_help(shell, args.first.last)
320
+ else
321
+ super
322
+ end
323
+ end
324
+ alias_method :invoke_command, :invoke_task
325
+ end
326
+
327
+ private
328
+
329
+ # Ensure the any failing commands exit non-zero.
330
+ #
331
+ # @return [true] you die always on failure
332
+ # @api private
333
+ def self.exit_on_failure?
334
+ true
335
+ end
336
+
337
+ # @return [Logger] the common logger
338
+ # @api private
339
+ def logger
340
+ Kitchen.logger
341
+ end
342
+
343
+ # Update and finalize options for logging, concurrency, and other concerns.
344
+ #
345
+ # @api private
346
+ def update_config!
347
+ @config.log_level = log_level if log_level
348
+
349
+ unless options[:log_overwrite].nil?
350
+ @config.log_overwrite = options[:log_overwrite]
351
+ end
352
+
353
+ if options[:test_base_path]
354
+ # ensure we have an absolute path
355
+ @config.test_base_path = File.absolute_path(options[:test_base_path])
356
+ end
357
+
358
+ # Now that we have required configs, lets create our file logger
359
+ Kitchen.logger = Kitchen.default_file_logger(
360
+ log_level,
361
+ options[:log_overwrite]
362
+ )
363
+
364
+ update_parallel!
365
+ end
366
+
367
+ # Validate the log level from the config / CLI options, defaulting
368
+ # to :info if the supplied level is empty or invalid
369
+ #
370
+ # @api private
371
+ def log_level
372
+ return unless options[:log_level]
373
+ return @log_level if @log_level
374
+
375
+ level = options[:log_level].downcase.to_sym
376
+ unless valid_log_level?(level)
377
+ level = :info
378
+ banner "WARNING - invalid log level specified: " \
379
+ "\"#{options[:log_level]}\" - reverting to :info log level."
380
+ end
381
+
382
+ @log_level = level
383
+ end
384
+
385
+ # Check to whether a provided log level is valid
386
+ #
387
+ # @api private
388
+ def valid_log_level?(level)
389
+ !Util.to_logger_level(level).nil?
390
+ end
391
+
392
+ # Set parallel concurrency options for Thor
393
+ #
394
+ # @api private
395
+ def update_parallel!
396
+ if options[:parallel]
397
+ # warn here in a future release when option is used
398
+ @options = Thor::CoreExt::HashWithIndifferentAccess.new(options.to_hash)
399
+ if options[:parallel] && !options[:concurrency]
400
+ options[:concurrency] = MAX_CONCURRENCY
401
+ end
402
+ options.delete(:parallel)
403
+ options.freeze
404
+ end
405
+ end
406
+
407
+ # If auto_init option is active, invoke the init generator.
408
+ #
409
+ # @api private
410
+ def ensure_initialized
411
+ yaml = ENV["KITCHEN_YAML"] || ".kitchen.yml"
412
+
413
+ if options[:auto_init] && !File.exist?(yaml)
414
+ banner "Invoking init as '#{yaml}' file is missing"
415
+ invoke "init"
416
+ end
417
+ end
418
+ end
419
+ end