test-kitchen 1.7.0 → 1.7.1.dev

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 (181) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -8
  3. data/.gitattributes +3 -0
  4. data/.github/ISSUE_TEMPLATE.md +55 -55
  5. data/.gitignore +28 -28
  6. data/.kitchen.ci.yml +23 -23
  7. data/.kitchen.proxy.yml +27 -27
  8. data/.rubocop.yml +3 -3
  9. data/.travis.yml +70 -70
  10. data/.yardopts +3 -3
  11. data/Berksfile +3 -3
  12. data/CHANGELOG.md +1090 -1083
  13. data/CONTRIBUTING.md +14 -14
  14. data/Gemfile +19 -19
  15. data/Gemfile.proxy_tests +4 -4
  16. data/Guardfile +42 -42
  17. data/LICENSE +15 -15
  18. data/MAINTAINERS.md +23 -23
  19. data/README.md +135 -135
  20. data/Rakefile +61 -61
  21. data/appveyor.yml +44 -44
  22. data/features/kitchen_action_commands.feature +164 -164
  23. data/features/kitchen_command.feature +16 -16
  24. data/features/kitchen_console_command.feature +34 -34
  25. data/features/kitchen_defaults.feature +38 -38
  26. data/features/kitchen_diagnose_command.feature +96 -96
  27. data/features/kitchen_driver_create_command.feature +64 -64
  28. data/features/kitchen_driver_discover_command.feature +25 -25
  29. data/features/kitchen_help_command.feature +16 -16
  30. data/features/kitchen_init_command.feature +274 -274
  31. data/features/kitchen_list_command.feature +104 -104
  32. data/features/kitchen_login_command.feature +62 -62
  33. data/features/kitchen_sink_command.feature +30 -30
  34. data/features/kitchen_test_command.feature +88 -88
  35. data/features/step_definitions/gem_steps.rb +36 -36
  36. data/features/step_definitions/git_steps.rb +5 -5
  37. data/features/step_definitions/output_steps.rb +5 -5
  38. data/features/support/env.rb +75 -75
  39. data/lib/kitchen.rb +150 -150
  40. data/lib/kitchen/base64_stream.rb +55 -55
  41. data/lib/kitchen/cli.rb +419 -419
  42. data/lib/kitchen/collection.rb +55 -55
  43. data/lib/kitchen/color.rb +65 -65
  44. data/lib/kitchen/command.rb +185 -185
  45. data/lib/kitchen/command/action.rb +45 -45
  46. data/lib/kitchen/command/console.rb +58 -58
  47. data/lib/kitchen/command/diagnose.rb +92 -92
  48. data/lib/kitchen/command/driver_discover.rb +105 -105
  49. data/lib/kitchen/command/exec.rb +41 -41
  50. data/lib/kitchen/command/list.rb +119 -119
  51. data/lib/kitchen/command/login.rb +43 -43
  52. data/lib/kitchen/command/sink.rb +54 -54
  53. data/lib/kitchen/command/test.rb +51 -51
  54. data/lib/kitchen/config.rb +322 -322
  55. data/lib/kitchen/configurable.rb +529 -529
  56. data/lib/kitchen/data_munger.rb +959 -959
  57. data/lib/kitchen/diagnostic.rb +141 -141
  58. data/lib/kitchen/driver.rb +56 -56
  59. data/lib/kitchen/driver/base.rb +134 -134
  60. data/lib/kitchen/driver/dummy.rb +108 -108
  61. data/lib/kitchen/driver/proxy.rb +72 -72
  62. data/lib/kitchen/driver/ssh_base.rb +357 -357
  63. data/lib/kitchen/errors.rb +229 -229
  64. data/lib/kitchen/generator/driver_create.rb +177 -177
  65. data/lib/kitchen/generator/init.rb +296 -296
  66. data/lib/kitchen/instance.rb +662 -662
  67. data/lib/kitchen/lazy_hash.rb +142 -142
  68. data/lib/kitchen/loader/yaml.rb +349 -349
  69. data/lib/kitchen/logger.rb +423 -423
  70. data/lib/kitchen/logging.rb +56 -56
  71. data/lib/kitchen/login_command.rb +52 -52
  72. data/lib/kitchen/metadata_chopper.rb +52 -52
  73. data/lib/kitchen/platform.rb +67 -67
  74. data/lib/kitchen/provisioner.rb +54 -54
  75. data/lib/kitchen/provisioner/base.rb +236 -236
  76. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  77. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  78. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  79. data/lib/kitchen/provisioner/chef_apply.rb +124 -124
  80. data/lib/kitchen/provisioner/chef_base.rb +341 -341
  81. data/lib/kitchen/provisioner/chef_solo.rb +88 -88
  82. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  83. data/lib/kitchen/provisioner/dummy.rb +79 -79
  84. data/lib/kitchen/provisioner/shell.rb +138 -138
  85. data/lib/kitchen/rake_tasks.rb +63 -63
  86. data/lib/kitchen/shell_out.rb +93 -93
  87. data/lib/kitchen/ssh.rb +276 -276
  88. data/lib/kitchen/state_file.rb +120 -120
  89. data/lib/kitchen/suite.rb +51 -51
  90. data/lib/kitchen/thor_tasks.rb +66 -66
  91. data/lib/kitchen/transport.rb +54 -54
  92. data/lib/kitchen/transport/base.rb +176 -176
  93. data/lib/kitchen/transport/dummy.rb +79 -79
  94. data/lib/kitchen/transport/ssh.rb +364 -364
  95. data/lib/kitchen/transport/winrm.rb +486 -486
  96. data/lib/kitchen/util.rb +147 -147
  97. data/lib/kitchen/verifier.rb +55 -55
  98. data/lib/kitchen/verifier/base.rb +235 -235
  99. data/lib/kitchen/verifier/busser.rb +277 -277
  100. data/lib/kitchen/verifier/dummy.rb +79 -79
  101. data/lib/kitchen/verifier/shell.rb +101 -101
  102. data/lib/kitchen/version.rb +21 -21
  103. data/lib/vendor/hash_recursive_merge.rb +82 -82
  104. data/spec/kitchen/base64_stream_spec.rb +77 -77
  105. data/spec/kitchen/cli_spec.rb +56 -56
  106. data/spec/kitchen/collection_spec.rb +80 -80
  107. data/spec/kitchen/color_spec.rb +54 -54
  108. data/spec/kitchen/config_spec.rb +408 -408
  109. data/spec/kitchen/configurable_spec.rb +1095 -1095
  110. data/spec/kitchen/data_munger_spec.rb +2694 -2694
  111. data/spec/kitchen/diagnostic_spec.rb +129 -129
  112. data/spec/kitchen/driver/base_spec.rb +121 -121
  113. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  114. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  115. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  116. data/spec/kitchen/driver_spec.rb +112 -112
  117. data/spec/kitchen/errors_spec.rb +309 -309
  118. data/spec/kitchen/instance_spec.rb +1419 -1419
  119. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  120. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  121. data/spec/kitchen/logger_spec.rb +429 -429
  122. data/spec/kitchen/logging_spec.rb +59 -59
  123. data/spec/kitchen/login_command_spec.rb +68 -68
  124. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  125. data/spec/kitchen/platform_spec.rb +89 -89
  126. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  127. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  128. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1161
  129. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  130. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  131. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  132. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  133. data/spec/kitchen/provisioner_spec.rb +107 -107
  134. data/spec/kitchen/shell_out_spec.rb +150 -150
  135. data/spec/kitchen/ssh_spec.rb +693 -693
  136. data/spec/kitchen/state_file_spec.rb +129 -129
  137. data/spec/kitchen/suite_spec.rb +62 -62
  138. data/spec/kitchen/transport/base_spec.rb +89 -89
  139. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  140. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  141. data/spec/kitchen/transport_spec.rb +112 -112
  142. data/spec/kitchen/util_spec.rb +165 -165
  143. data/spec/kitchen/verifier/base_spec.rb +362 -362
  144. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  145. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  146. data/spec/kitchen/verifier/shell_spec.rb +160 -160
  147. data/spec/kitchen/verifier_spec.rb +120 -120
  148. data/spec/kitchen_spec.rb +114 -114
  149. data/spec/spec_helper.rb +85 -85
  150. data/spec/support/powershell_max_size_spec.rb +40 -40
  151. data/support/busser_install_command.ps1 +14 -14
  152. data/support/busser_install_command.sh +14 -14
  153. data/support/chef-client-zero.rb +77 -77
  154. data/support/chef_base_init_command.ps1 +18 -18
  155. data/support/chef_base_init_command.sh +2 -2
  156. data/support/chef_base_install_command.ps1 +85 -85
  157. data/support/chef_base_install_command.sh +229 -229
  158. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  159. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  160. data/support/download_helpers.sh +109 -109
  161. data/support/dummy-validation.pem +27 -27
  162. data/templates/driver/CHANGELOG.md.erb +3 -3
  163. data/templates/driver/Gemfile.erb +3 -3
  164. data/templates/driver/README.md.erb +64 -64
  165. data/templates/driver/Rakefile.erb +21 -21
  166. data/templates/driver/driver.rb.erb +23 -23
  167. data/templates/driver/gemspec.erb +29 -29
  168. data/templates/driver/gitignore.erb +17 -17
  169. data/templates/driver/license_apachev2.erb +15 -15
  170. data/templates/driver/license_lgplv3.erb +16 -16
  171. data/templates/driver/license_mit.erb +22 -22
  172. data/templates/driver/license_reserved.erb +5 -5
  173. data/templates/driver/tailor.erb +4 -4
  174. data/templates/driver/travis.yml.erb +11 -11
  175. data/templates/driver/version.rb.erb +12 -12
  176. data/templates/init/chefignore.erb +1 -1
  177. data/templates/init/kitchen.yml.erb +18 -18
  178. data/test-kitchen.gemspec +62 -62
  179. data/test/integration/default/default_spec.rb +3 -3
  180. data/testing_windows.md +37 -37
  181. metadata +5 -4
@@ -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