test-kitchen 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.cane +1 -1
- data/.rubocop.yml +3 -0
- data/.travis.yml +20 -9
- data/CHANGELOG.md +219 -108
- data/Gemfile +10 -6
- data/Guardfile +38 -9
- data/README.md +11 -1
- data/Rakefile +21 -37
- data/bin/kitchen +4 -4
- data/features/kitchen_action_commands.feature +161 -0
- data/features/kitchen_console_command.feature +34 -0
- data/features/kitchen_diagnose_command.feature +64 -0
- data/features/kitchen_init_command.feature +29 -17
- data/features/kitchen_list_command.feature +2 -2
- data/features/kitchen_login_command.feature +56 -0
- data/features/{sink_command.feature → kitchen_sink_command.feature} +0 -0
- data/features/kitchen_test_command.feature +88 -0
- data/features/step_definitions/gem_steps.rb +8 -6
- data/features/step_definitions/git_steps.rb +4 -2
- data/features/step_definitions/output_steps.rb +5 -0
- data/features/support/env.rb +12 -9
- data/lib/kitchen.rb +60 -38
- data/lib/kitchen/base64_stream.rb +55 -0
- data/lib/kitchen/busser.rb +124 -58
- data/lib/kitchen/cli.rb +121 -38
- data/lib/kitchen/collection.rb +3 -3
- data/lib/kitchen/color.rb +4 -4
- data/lib/kitchen/command.rb +78 -11
- data/lib/kitchen/command/action.rb +3 -2
- data/lib/kitchen/command/console.rb +12 -5
- data/lib/kitchen/command/diagnose.rb +17 -3
- data/lib/kitchen/command/driver_discover.rb +26 -7
- data/lib/kitchen/command/exec.rb +41 -0
- data/lib/kitchen/command/list.rb +44 -14
- data/lib/kitchen/command/login.rb +2 -1
- data/lib/kitchen/command/sink.rb +2 -1
- data/lib/kitchen/command/test.rb +5 -4
- data/lib/kitchen/config.rb +146 -14
- data/lib/kitchen/configurable.rb +314 -0
- data/lib/kitchen/data_munger.rb +522 -18
- data/lib/kitchen/diagnostic.rb +43 -4
- data/lib/kitchen/driver.rb +4 -4
- data/lib/kitchen/driver/base.rb +80 -115
- data/lib/kitchen/driver/dummy.rb +34 -6
- data/lib/kitchen/driver/proxy.rb +14 -3
- data/lib/kitchen/driver/ssh_base.rb +61 -7
- data/lib/kitchen/errors.rb +109 -9
- data/lib/kitchen/generator/driver_create.rb +39 -5
- data/lib/kitchen/generator/init.rb +130 -45
- data/lib/kitchen/instance.rb +162 -28
- data/lib/kitchen/lazy_hash.rb +79 -7
- data/lib/kitchen/loader/yaml.rb +159 -27
- data/lib/kitchen/logger.rb +267 -21
- data/lib/kitchen/logging.rb +30 -3
- data/lib/kitchen/login_command.rb +11 -2
- data/lib/kitchen/metadata_chopper.rb +2 -2
- data/lib/kitchen/provisioner.rb +4 -4
- data/lib/kitchen/provisioner/base.rb +107 -103
- data/lib/kitchen/provisioner/chef/berkshelf.rb +36 -8
- data/lib/kitchen/provisioner/chef/librarian.rb +40 -11
- data/lib/kitchen/provisioner/chef_base.rb +206 -167
- data/lib/kitchen/provisioner/chef_solo.rb +25 -7
- data/lib/kitchen/provisioner/chef_zero.rb +105 -29
- data/lib/kitchen/provisioner/dummy.rb +1 -1
- data/lib/kitchen/provisioner/shell.rb +21 -6
- data/lib/kitchen/rake_tasks.rb +8 -3
- data/lib/kitchen/shell_out.rb +15 -18
- data/lib/kitchen/ssh.rb +122 -27
- data/lib/kitchen/state_file.rb +24 -7
- data/lib/kitchen/thor_tasks.rb +9 -4
- data/lib/kitchen/util.rb +43 -118
- data/lib/kitchen/version.rb +1 -1
- data/lib/vendor/hash_recursive_merge.rb +10 -2
- data/spec/kitchen/base64_stream_spec.rb +77 -0
- data/spec/kitchen/busser_spec.rb +490 -0
- data/spec/kitchen/collection_spec.rb +10 -10
- data/spec/kitchen/color_spec.rb +2 -2
- data/spec/kitchen/config_spec.rb +234 -62
- data/spec/kitchen/configurable_spec.rb +490 -0
- data/spec/kitchen/data_munger_spec.rb +1070 -862
- data/spec/kitchen/diagnostic_spec.rb +79 -0
- data/spec/kitchen/driver/base_spec.rb +80 -85
- data/spec/kitchen/driver/dummy_spec.rb +43 -14
- data/spec/kitchen/driver/proxy_spec.rb +134 -0
- data/spec/kitchen/driver/ssh_base_spec.rb +644 -0
- data/spec/kitchen/driver_spec.rb +15 -15
- data/spec/kitchen/errors_spec.rb +309 -0
- data/spec/kitchen/instance_spec.rb +143 -46
- data/spec/kitchen/lazy_hash_spec.rb +36 -9
- data/spec/kitchen/loader/yaml_spec.rb +237 -226
- data/spec/kitchen/logger_spec.rb +419 -0
- data/spec/kitchen/logging_spec.rb +59 -0
- data/spec/kitchen/login_command_spec.rb +49 -0
- data/spec/kitchen/metadata_chopper_spec.rb +82 -0
- data/spec/kitchen/platform_spec.rb +4 -4
- data/spec/kitchen/provisioner/base_spec.rb +65 -125
- data/spec/kitchen/provisioner/chef_base_spec.rb +798 -0
- data/spec/kitchen/provisioner/chef_solo_spec.rb +316 -0
- data/spec/kitchen/provisioner/chef_zero_spec.rb +624 -0
- data/spec/kitchen/provisioner/shell_spec.rb +269 -0
- data/spec/kitchen/provisioner_spec.rb +6 -6
- data/spec/kitchen/shell_out_spec.rb +143 -0
- data/spec/kitchen/ssh_spec.rb +683 -0
- data/spec/kitchen/state_file_spec.rb +28 -21
- data/spec/kitchen/suite_spec.rb +7 -7
- data/spec/kitchen/util_spec.rb +68 -10
- data/spec/kitchen_spec.rb +107 -0
- data/spec/spec_helper.rb +18 -13
- data/support/chef-client-zero.rb +10 -9
- data/support/chef_helpers.sh +16 -0
- data/support/download_helpers.sh +109 -0
- data/test-kitchen.gemspec +42 -33
- metadata +107 -33
@@ -0,0 +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 = "" # rubocop:disable Lint/UselessAssignment
|
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 = "" # rubocop:disable Lint/UselessAssignment
|
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/busser.rb
CHANGED
@@ -16,8 +16,8 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require
|
20
|
-
require
|
19
|
+
require "base64"
|
20
|
+
require "digest"
|
21
21
|
|
22
22
|
module Kitchen
|
23
23
|
|
@@ -95,21 +95,23 @@ module Kitchen
|
|
95
95
|
# @return [String] a command string to setup the test suite, or nil if no
|
96
96
|
# work needs to be performed
|
97
97
|
def setup_cmd
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
98
|
+
return if local_suite_files.empty?
|
99
|
+
|
100
|
+
ruby = "#{config[:ruby_bindir]}/ruby"
|
101
|
+
gem = sudo("#{config[:ruby_bindir]}/gem")
|
102
|
+
busser = sudo(config[:busser_bin])
|
103
|
+
|
104
|
+
cmd = <<-CMD.gsub(/^ {8}/, "")
|
105
|
+
#{busser_setup_env}
|
106
|
+
gem_bindir=`#{ruby} -rrubygems -e "puts Gem.bindir"`
|
107
|
+
|
108
|
+
if ! #{gem} list busser -i >/dev/null; then
|
109
|
+
#{gem} install #{gem_install_args}
|
110
|
+
fi
|
111
|
+
#{sudo("${gem_bindir}")}/busser setup
|
112
|
+
#{busser} plugin install #{plugins.join(" ")}
|
113
|
+
CMD
|
114
|
+
Util.wrap_command(cmd)
|
113
115
|
end
|
114
116
|
|
115
117
|
# Returns a command string which transfers all suite test files to the
|
@@ -121,18 +123,22 @@ module Kitchen
|
|
121
123
|
# @return [String] a command string to transfer all suite test files, or
|
122
124
|
# nil if no work needs to be performed.
|
123
125
|
def sync_cmd
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
126
|
+
return if local_suite_files.empty?
|
127
|
+
|
128
|
+
cmd = <<-CMD.gsub(/^ {8}/, "")
|
129
|
+
#{busser_setup_env}
|
130
|
+
|
131
|
+
#{sudo(config[:busser_bin])} suite cleanup
|
132
|
+
|
133
|
+
CMD
|
134
|
+
local_suite_files.each do |f|
|
135
|
+
cmd << stream_file(f, remote_file(f, config[:suite_name])).concat("\n")
|
136
|
+
end
|
137
|
+
helper_files.each do |f|
|
138
|
+
cmd << stream_file(f, remote_file(f, "helpers")).concat("\n")
|
135
139
|
end
|
140
|
+
|
141
|
+
Util.wrap_command(cmd)
|
136
142
|
end
|
137
143
|
|
138
144
|
# Returns a command string which runs all Busser suite tests for the suite.
|
@@ -143,16 +149,15 @@ module Kitchen
|
|
143
149
|
# @return [String] a command string to run the test suites, or nil if no
|
144
150
|
# work needs to be performed
|
145
151
|
def run_cmd
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
end
|
152
|
+
return if local_suite_files.empty?
|
153
|
+
|
154
|
+
cmd = <<-CMD.gsub(/^ {8}/, "")
|
155
|
+
#{busser_setup_env}
|
156
|
+
|
157
|
+
#{sudo(config[:busser_bin])} test
|
158
|
+
CMD
|
159
|
+
|
160
|
+
Util.wrap_command(cmd)
|
156
161
|
end
|
157
162
|
|
158
163
|
private
|
@@ -160,83 +165,144 @@ module Kitchen
|
|
160
165
|
DEFAULT_RUBY_BINDIR = "/opt/chef/embedded/bin".freeze
|
161
166
|
DEFAULT_ROOT_PATH = "/tmp/busser".freeze
|
162
167
|
|
168
|
+
# @return [Hash] a configuration hash
|
169
|
+
# @api private
|
163
170
|
attr_reader :config
|
164
171
|
|
172
|
+
# Ensures that the object is internally consistent and otherwise raising
|
173
|
+
# an exception.
|
174
|
+
#
|
175
|
+
# @param suite_name [String] the suite name
|
176
|
+
# @raise [ClientError] if a suite name is missing
|
177
|
+
# @raise [UserError] if the suite name is invalid
|
178
|
+
# @api private
|
165
179
|
def validate_options(suite_name)
|
166
180
|
if suite_name.nil?
|
167
181
|
raise ClientError, "Busser#new requires a suite_name"
|
168
182
|
end
|
169
183
|
|
170
|
-
if suite_name ==
|
184
|
+
if suite_name == "helper"
|
171
185
|
raise UserError,
|
172
186
|
"Suite name invalid: 'helper' is a reserved directory name."
|
173
187
|
end
|
174
188
|
end
|
175
189
|
|
190
|
+
# Returns a uniquely sorted Array of Busser plugin gems that need to
|
191
|
+
# be installed for the related suite.
|
192
|
+
#
|
193
|
+
# @return [Array<String>] a lexically sorted, unique item array of Busser
|
194
|
+
# plugin gem names
|
195
|
+
# @api private
|
176
196
|
def plugins
|
197
|
+
non_suite_dirs = %w[data data_bags environments nodes roles]
|
177
198
|
glob = File.join(config[:test_base_path], config[:suite_name], "*")
|
178
199
|
Dir.glob(glob).reject { |d|
|
179
|
-
!
|
200
|
+
!File.directory?(d) || non_suite_dirs.include?(File.basename(d))
|
180
201
|
}.map { |d| "busser-#{File.basename(d)}" }.sort.uniq
|
181
202
|
end
|
182
203
|
|
204
|
+
# Returns an Array of test suite filenames for the related suite currently
|
205
|
+
# residing on the local workstation. Any special provisioner-specific
|
206
|
+
# directories (such as a Chef roles/ directory) are excluded.
|
207
|
+
#
|
208
|
+
# @return [Array<String>] array of suite files
|
209
|
+
# @api private
|
183
210
|
def local_suite_files
|
184
211
|
base = File.join(config[:test_base_path], config[:suite_name])
|
185
212
|
glob = File.join(base, "*/**/*")
|
186
213
|
Dir.glob(glob).reject do |f|
|
187
|
-
|
214
|
+
chef_data_dir?(base, f) || File.directory?(f)
|
188
215
|
end
|
189
216
|
end
|
190
217
|
|
191
|
-
|
192
|
-
|
218
|
+
# Determines whether or not a local workstation file exists under a
|
219
|
+
# Chef-related directory.
|
220
|
+
#
|
221
|
+
# @return [truthy,falsey] whether or not a given file is some kind of
|
222
|
+
# Chef-related file
|
223
|
+
# @api private
|
224
|
+
def chef_data_dir?(base, file)
|
225
|
+
file =~ %r{^#{base}/(data|data_bags|environments|nodes|roles)/}
|
193
226
|
end
|
194
227
|
|
228
|
+
# Returns an Array of common helper filenames currently residing on the
|
229
|
+
# local workstation.
|
230
|
+
#
|
231
|
+
# @return [Array<String>] array of helper files
|
232
|
+
# @api private
|
195
233
|
def helper_files
|
196
|
-
|
234
|
+
glob = File.join(config[:test_base_path], "helpers", "*/**/*")
|
235
|
+
Dir.glob(glob).reject { |f| File.directory?(f) }
|
197
236
|
end
|
198
237
|
|
238
|
+
# Returns a command string that will, once evaluated, result in the
|
239
|
+
# fully qualified destination path of a file on an instance.
|
240
|
+
#
|
241
|
+
# @param file [String] absolute path to the local file
|
242
|
+
# @param dir [String] suite directory or helper directory name
|
243
|
+
# @return [String] command string
|
244
|
+
# @api private
|
199
245
|
def remote_file(file, dir)
|
200
246
|
local_prefix = File.join(config[:test_base_path], dir)
|
201
|
-
"
|
247
|
+
"`#{sudo(config[:busser_bin])} suite path`/".
|
248
|
+
concat(file.sub(%r{^#{local_prefix}/}, ""))
|
202
249
|
end
|
203
250
|
|
251
|
+
# Returns a command string that will, once evaluated, result in the copying
|
252
|
+
# of a local file to a remote instance.
|
253
|
+
#
|
254
|
+
# @param local_path [String] the path to a local source file for copying
|
255
|
+
# @param remote_path [String] the destrination path on the remote instance
|
256
|
+
# @return [String] command string
|
257
|
+
# @api private
|
204
258
|
def stream_file(local_path, remote_path)
|
205
259
|
local_file = IO.read(local_path)
|
260
|
+
encoded_file = Base64.encode64(local_file).gsub("\n", "")
|
206
261
|
md5 = Digest::MD5.hexdigest(local_file)
|
207
|
-
perms =
|
262
|
+
perms = format("%o", File.stat(local_path).mode)[2, 4]
|
208
263
|
stream_cmd = [
|
209
|
-
|
264
|
+
sudo(config[:busser_bin]),
|
210
265
|
"deserialize",
|
211
266
|
"--destination=#{remote_path}",
|
212
267
|
"--md5sum=#{md5}",
|
213
268
|
"--perms=#{perms}"
|
214
269
|
].join(" ")
|
215
270
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
end
|
221
|
-
|
222
|
-
def sudo
|
223
|
-
config[:sudo] ? "sudo -E " : ""
|
271
|
+
[
|
272
|
+
%{echo "Uploading #{remote_path} (mode=#{perms})"},
|
273
|
+
%{echo "#{encoded_file}" | #{stream_cmd}}
|
274
|
+
].join("\n").concat("\n")
|
224
275
|
end
|
225
276
|
|
226
|
-
|
227
|
-
|
277
|
+
# Conditionally prefixes a command with a sudo command.
|
278
|
+
#
|
279
|
+
# @param command [String] command to be prefixed
|
280
|
+
# @return [String] the command, conditionaly prefixed with sudo
|
281
|
+
# @api private
|
282
|
+
def sudo(command)
|
283
|
+
config[:sudo] ? "sudo -E #{command}" : command
|
228
284
|
end
|
229
285
|
|
286
|
+
# Returns a command string that sets appropriate environment variables for
|
287
|
+
# busser commands.
|
288
|
+
#
|
289
|
+
# @return [String] command string
|
290
|
+
# @api private
|
230
291
|
def busser_setup_env
|
231
292
|
[
|
232
293
|
%{BUSSER_ROOT="#{config[:root_path]}"},
|
233
294
|
%{GEM_HOME="#{config[:root_path]}/gems"},
|
234
295
|
%{GEM_PATH="#{config[:root_path]}/gems"},
|
235
296
|
%{GEM_CACHE="#{config[:root_path]}/gems/cache"},
|
236
|
-
%{
|
297
|
+
%{\nexport BUSSER_ROOT GEM_HOME GEM_PATH GEM_CACHE}
|
237
298
|
].join(" ")
|
238
299
|
end
|
239
300
|
|
301
|
+
# Returns arguments to a `gem install` command, suitable to install the
|
302
|
+
# Busser gem.
|
303
|
+
#
|
304
|
+
# @return [String] arguments string
|
305
|
+
# @api private
|
240
306
|
def gem_install_args
|
241
307
|
gem, version = config[:version].split("@")
|
242
308
|
gem, version = "busser", gem if gem =~ /^\d+\.\d+\.\d+/
|
data/lib/kitchen/cli.rb
CHANGED
@@ -16,11 +16,11 @@
|
|
16
16
|
# See the License for the specific language governing permissions and
|
17
17
|
# limitations under the License.
|
18
18
|
|
19
|
-
require
|
19
|
+
require "thor"
|
20
20
|
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
21
|
+
require "kitchen"
|
22
|
+
require "kitchen/generator/driver_create"
|
23
|
+
require "kitchen/generator/init"
|
24
24
|
|
25
25
|
module Kitchen
|
26
26
|
|
@@ -32,12 +32,21 @@ module Kitchen
|
|
32
32
|
# Common module to load and invoke a CLI-implementation agnostic command.
|
33
33
|
module PerformCommand
|
34
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: `{}`)
|
35
44
|
def perform(task, command, args = nil, additional_options = {})
|
36
45
|
require "kitchen/command/#{command}"
|
37
46
|
|
38
47
|
command_options = {
|
39
48
|
:action => task,
|
40
|
-
:help =>
|
49
|
+
:help => -> { help(task) },
|
41
50
|
:config => @config,
|
42
51
|
:shell => shell
|
43
52
|
}.merge(additional_options)
|
@@ -51,6 +60,8 @@ module Kitchen
|
|
51
60
|
include Logging
|
52
61
|
include PerformCommand
|
53
62
|
|
63
|
+
# The maximum number of concurrent instances that can run--which is a bit
|
64
|
+
# high
|
54
65
|
MAX_CONCURRENCY = 9999
|
55
66
|
|
56
67
|
# Constructs a new instance.
|
@@ -59,22 +70,27 @@ module Kitchen
|
|
59
70
|
$stdout.sync = true
|
60
71
|
Kitchen.logger = Kitchen.default_file_logger
|
61
72
|
@loader = Kitchen::Loader::YAML.new(
|
62
|
-
:project_config => ENV[
|
63
|
-
:local_config => ENV[
|
64
|
-
:global_config => ENV[
|
73
|
+
:project_config => ENV["KITCHEN_YAML"],
|
74
|
+
:local_config => ENV["KITCHEN_LOCAL_YAML"],
|
75
|
+
:global_config => ENV["KITCHEN_GLOBAL_YAML"]
|
65
76
|
)
|
66
77
|
@config = Kitchen::Config.new(
|
67
78
|
:loader => @loader,
|
68
|
-
:log_level => ENV.fetch(
|
79
|
+
:log_level => ENV.fetch("KITCHEN_LOG", "info").downcase.to_sym
|
69
80
|
)
|
70
81
|
end
|
71
82
|
|
72
83
|
desc "list [INSTANCE|REGEXP|all]", "Lists one or more instances"
|
73
|
-
method_option :bare,
|
84
|
+
method_option :bare,
|
85
|
+
:aliases => "-b",
|
86
|
+
:type => :boolean,
|
74
87
|
:desc => "List the name of each instance only, one per line"
|
75
|
-
method_option :debug,
|
88
|
+
method_option :debug,
|
89
|
+
:aliases => "-d",
|
90
|
+
:type => :boolean,
|
76
91
|
:desc => "[Deprecated] Please use `kitchen diagnose'"
|
77
|
-
method_option :log_level,
|
92
|
+
method_option :log_level,
|
93
|
+
:aliases => "-l",
|
78
94
|
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
79
95
|
def list(*args)
|
80
96
|
update_config!
|
@@ -82,36 +98,63 @@ module Kitchen
|
|
82
98
|
end
|
83
99
|
|
84
100
|
desc "diagnose [INSTANCE|REGEXP|all]", "Show computed diagnostic configuration"
|
85
|
-
method_option :log_level,
|
101
|
+
method_option :log_level,
|
102
|
+
:aliases => "-l",
|
86
103
|
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
87
|
-
method_option :loader,
|
104
|
+
method_option :loader,
|
105
|
+
:type => :boolean,
|
88
106
|
:desc => "Include data loader diagnostics"
|
89
|
-
method_option :instances,
|
107
|
+
method_option :instances,
|
108
|
+
:type => :boolean,
|
109
|
+
:default => true,
|
90
110
|
:desc => "Include instances diagnostics"
|
91
|
-
method_option :all,
|
111
|
+
method_option :all,
|
112
|
+
:type => :boolean,
|
92
113
|
:desc => "Include all diagnostics"
|
93
114
|
def diagnose(*args)
|
94
115
|
update_config!
|
95
116
|
perform("diagnose", "diagnose", args, :loader => @loader)
|
96
117
|
end
|
97
118
|
|
98
|
-
|
119
|
+
{
|
120
|
+
:create => "Change instance state to create. " \
|
121
|
+
"Start one or more instances",
|
122
|
+
:converge => "Change instance state to converge. " \
|
123
|
+
"Use a provisioner to configure one or more instances",
|
124
|
+
:setup => "Change instance state to setup. " \
|
125
|
+
"Prepare to run automated tests. " \
|
126
|
+
"Install busser and related gems on one or more instances",
|
127
|
+
:verify => "Change instance state to verify. " \
|
128
|
+
"Run automated tests on one or more instances",
|
129
|
+
:destroy => "Change instance state to destroy. " \
|
130
|
+
"Delete all information for one or more instances"
|
131
|
+
}.each do |action, short_desc|
|
99
132
|
desc(
|
100
133
|
"#{action} [INSTANCE|REGEXP|all]",
|
101
|
-
|
134
|
+
short_desc
|
102
135
|
)
|
103
|
-
|
104
|
-
|
105
|
-
|
136
|
+
long_desc <<-DESC
|
137
|
+
The instance states are in order: destroy, create, converge, setup, verify, destroy.
|
138
|
+
Change one or more instances from the current state to the #{action} state. Actions for all
|
139
|
+
intermediate states will be executed. See http://kitchen.ci for further explanation.
|
140
|
+
DESC
|
141
|
+
method_option :concurrency,
|
142
|
+
:aliases => "-c",
|
143
|
+
:type => :numeric,
|
144
|
+
:lazy_default => MAX_CONCURRENCY,
|
145
|
+
:desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
|
106
146
|
Run a #{action} against all matching instances concurrently. Only N
|
107
147
|
instances will run at the same time if a number is given.
|
108
148
|
DESC
|
109
|
-
method_option :parallel,
|
110
|
-
:
|
149
|
+
method_option :parallel,
|
150
|
+
:aliases => "-p",
|
151
|
+
:type => :boolean,
|
152
|
+
:desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
|
111
153
|
[Future DEPRECATION, use --concurrency]
|
112
154
|
Run a #{action} against all matching instances concurrently.
|
113
155
|
DESC
|
114
|
-
method_option :log_level,
|
156
|
+
method_option :log_level,
|
157
|
+
:aliases => "-l",
|
115
158
|
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
116
159
|
define_method(action) do |*args|
|
117
160
|
update_config!
|
@@ -119,9 +162,13 @@ module Kitchen
|
|
119
162
|
end
|
120
163
|
end
|
121
164
|
|
122
|
-
desc "test [INSTANCE|REGEXP|all]",
|
165
|
+
desc "test [INSTANCE|REGEXP|all]",
|
166
|
+
"Test (destroy, create, converge, setup, verify and destroy) one or more instances"
|
123
167
|
long_desc <<-DESC
|
124
|
-
|
168
|
+
The instance states are in order: destroy, create, converge, setup, verify, destroy.
|
169
|
+
Test changes the state of one or more instances to destroyed, then executes
|
170
|
+
the actions for each state up to destroy. At any sign of failure, executing the
|
171
|
+
actions stops and the instance is left in the last successful execution state.
|
125
172
|
|
126
173
|
There are 3 post-verify modes for instance cleanup, triggered with
|
127
174
|
the `--destroy' flag:
|
@@ -130,22 +177,31 @@ module Kitchen
|
|
130
177
|
* always: instances will always be destroyed afterwards.\n
|
131
178
|
* never: instances will never be destroyed afterwards.
|
132
179
|
DESC
|
133
|
-
method_option :concurrency,
|
134
|
-
:
|
135
|
-
:
|
180
|
+
method_option :concurrency,
|
181
|
+
:aliases => "-c",
|
182
|
+
:type => :numeric,
|
183
|
+
:lazy_default => MAX_CONCURRENCY,
|
184
|
+
:desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
|
136
185
|
Run a test against all matching instances concurrently. Only N
|
137
186
|
instances will run at the same time if a number is given.
|
138
187
|
DESC
|
139
|
-
method_option :parallel,
|
140
|
-
:
|
188
|
+
method_option :parallel,
|
189
|
+
:aliases => "-p",
|
190
|
+
:type => :boolean,
|
191
|
+
:desc => <<-DESC.gsub(/^\s+/, "").gsub(/\n/, " ")
|
141
192
|
[Future DEPRECATION, use --concurrency]
|
142
193
|
Run a test against all matching instances concurrently.
|
143
194
|
DESC
|
144
|
-
method_option :log_level,
|
195
|
+
method_option :log_level,
|
196
|
+
:aliases => "-l",
|
145
197
|
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
146
|
-
method_option :destroy,
|
198
|
+
method_option :destroy,
|
199
|
+
:aliases => "-d",
|
200
|
+
:default => "passing",
|
147
201
|
:desc => "Destroy strategy to use after testing (passing, always, never)."
|
148
|
-
method_option :auto_init,
|
202
|
+
method_option :auto_init,
|
203
|
+
:type => :boolean,
|
204
|
+
:default => false,
|
149
205
|
:desc => "Invoke init command if .kitchen.yml is missing"
|
150
206
|
def test(*args)
|
151
207
|
update_config!
|
@@ -154,18 +210,32 @@ module Kitchen
|
|
154
210
|
end
|
155
211
|
|
156
212
|
desc "login INSTANCE|REGEXP", "Log in to one instance"
|
157
|
-
method_option :log_level,
|
213
|
+
method_option :log_level,
|
214
|
+
:aliases => "-l",
|
158
215
|
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
159
216
|
def login(*args)
|
160
217
|
update_config!
|
161
218
|
perform("login", "login", args)
|
162
219
|
end
|
163
220
|
|
221
|
+
desc "exec INSTANCE|REGEXP -c REMOTE_COMMAND",
|
222
|
+
"Execute command on one or more instance"
|
223
|
+
method_option :log_level,
|
224
|
+
:aliases => "-l",
|
225
|
+
:desc => "Set the log level (debug, info, warn, error, fatal)"
|
226
|
+
method_option :command,
|
227
|
+
:aliases => "-c",
|
228
|
+
:desc => "execute via ssh"
|
229
|
+
def exec(*args)
|
230
|
+
update_config!
|
231
|
+
perform("exec", "exec", args)
|
232
|
+
end
|
233
|
+
|
164
234
|
desc "version", "Print Kitchen's version information"
|
165
235
|
def version
|
166
236
|
puts "Test Kitchen version #{Kitchen::VERSION}"
|
167
237
|
end
|
168
|
-
map %w
|
238
|
+
map %w[-v --version] => :version
|
169
239
|
|
170
240
|
desc "sink", "Show the Kitchen sink!", :hide => true
|
171
241
|
def sink
|
@@ -217,6 +287,7 @@ module Kitchen
|
|
217
287
|
perform("discover", "driver_discover", args)
|
218
288
|
end
|
219
289
|
|
290
|
+
# @return [String] basename
|
220
291
|
def self.basename
|
221
292
|
super + " driver"
|
222
293
|
end
|
@@ -238,14 +309,23 @@ module Kitchen
|
|
238
309
|
|
239
310
|
private
|
240
311
|
|
312
|
+
# Ensure the any failing commands exit non-zero.
|
313
|
+
#
|
314
|
+
# @return [true] you die always on failure
|
315
|
+
# @api private
|
241
316
|
def self.exit_on_failure?
|
242
317
|
true
|
243
318
|
end
|
244
319
|
|
320
|
+
# @return [Logger] the common logger
|
321
|
+
# @api private
|
245
322
|
def logger
|
246
323
|
Kitchen.logger
|
247
324
|
end
|
248
325
|
|
326
|
+
# Update and finalize options for logging, concurrency, and other concerns.
|
327
|
+
#
|
328
|
+
# @api private
|
249
329
|
def update_config!
|
250
330
|
if options[:log_level]
|
251
331
|
level = options[:log_level].downcase.to_sym
|
@@ -264,10 +344,13 @@ module Kitchen
|
|
264
344
|
end
|
265
345
|
end
|
266
346
|
|
347
|
+
# If auto_init option is active, invoke the init generator.
|
348
|
+
#
|
349
|
+
# @api private
|
267
350
|
def ensure_initialized
|
268
|
-
yaml = ENV[
|
351
|
+
yaml = ENV["KITCHEN_YAML"] || ".kitchen.yml"
|
269
352
|
|
270
|
-
if options[:auto_init] && !
|
353
|
+
if options[:auto_init] && !File.exist?(yaml)
|
271
354
|
banner "Invoking init as '#{yaml}' file is missing"
|
272
355
|
invoke "init"
|
273
356
|
end
|