test-kitchen 2.5.4 → 2.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba11941e2fb1db16f6bdb83f86c9822ad222f18f0e26e37a94683fb6fda29042
4
- data.tar.gz: 57b12bd55f5b39b0be4fd482dc22666fb62eeb7182a44199b7aadcd90857330f
3
+ metadata.gz: b776d094e27dc25c3f569ad96100866c9015d60593d9d99b54e30b8b6b0e4b03
4
+ data.tar.gz: 598635116f83455b7852cee81a77efc907f6ea2a9c52f8312526b9a7e6ca0922
5
5
  SHA512:
6
- metadata.gz: '095582d89c5645bbace34075c30b95170f9c0d5a5a06067c58e7b348bf4d711d5a068101940b0b035ad371f213eaebef70a695d620aa230fafc4ca86828005f4'
7
- data.tar.gz: 7b2c76fcea81d87b976745081682122ed7dec1d63ffba2d99180913871c595c7e17adc511223a996a0e25b277f8e782ec8cd1623479a93d79092eda0ce5a3d03
6
+ metadata.gz: ae5d8636e834c68d3565a73b9cb5a3af46246fb9b2427a80166716366cd254947049667a80a23c569f1f9eda26eb28bac4bc50fbb8eceaf55fa54cf5548a6554
7
+ data.tar.gz: d91650528d01dcac17ad882cfd260d41b2d7c1ce3118aa0a8ddecfafd935ed1b237cf5507067a512ef5fe7dc003e23d57983f5f5f5cde994e5766a02385ea8af
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ desc "Run all quality tasks"
42
42
  task quality: %i{style stats}
43
43
 
44
44
  begin
45
- require "yard"
45
+ require "yard" unless defined?(YARD)
46
46
  YARD::Rake::YardocTask.new
47
47
  rescue LoadError
48
48
  puts "yard is not available. (sudo) gem install yard to generate yard documentation."
@@ -4,7 +4,7 @@
4
4
  Signal.trap("INT") { exit 1 }
5
5
 
6
6
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), %w{.. lib})
7
- require "rubygems"
7
+ require "rubygems" unless defined?(Gem)
8
8
  require "kitchen/cli"
9
9
  require "kitchen/errors"
10
10
 
@@ -15,9 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "pathname"
19
- require "thread"
20
-
18
+ require "pathname" unless defined?(Pathname)
21
19
  require_relative "kitchen/errors"
22
20
  require_relative "kitchen/logger"
23
21
  require_relative "kitchen/logging"
@@ -67,7 +65,7 @@ module Kitchen
67
65
  #
68
66
  # @return [Pathname] root path of gem
69
67
  def source_root
70
- @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
68
+ @source_root ||= Pathname.new(File.expand_path("..", __dir__))
71
69
  end
72
70
 
73
71
  # Returns a default logger which emits on standard output.
@@ -15,7 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thor"
18
+ # CI tests fail without an explicit unconditional require of Thor
19
+ require "thor" # rubocop:disable ChefRuby/UnlessDefinedRequire
19
20
 
20
21
  require_relative "../kitchen"
21
22
  require_relative "generator/init"
@@ -15,8 +15,6 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thread"
19
-
20
18
  module Kitchen
21
19
  module Command
22
20
  # Base class for CLI commands.
@@ -17,7 +17,7 @@
17
17
 
18
18
  require_relative "../command"
19
19
 
20
- require "benchmark"
20
+ require "benchmark" unless defined?(Benchmark)
21
21
 
22
22
  module Kitchen
23
23
  module Command
@@ -18,7 +18,7 @@
18
18
  require_relative "../command"
19
19
  require_relative "../diagnostic"
20
20
 
21
- require "yaml"
21
+ autoload :YAML, "yaml"
22
22
 
23
23
  module Kitchen
24
24
  module Command
@@ -32,9 +32,9 @@ module Kitchen
32
32
 
33
33
  loader = record_failure { load_loader }
34
34
 
35
- puts Kitchen::Diagnostic.new(
35
+ puts YAML.dump(Kitchen::Diagnostic.new(
36
36
  loader: loader, instances: instances, plugins: plugins?
37
- ).read.to_yaml
37
+ ).read)
38
38
  end
39
39
 
40
40
  private
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require_relative "../command"
19
- require "json"
19
+ require "json" unless defined?(JSON)
20
20
 
21
21
  module Kitchen
22
22
  module Command
@@ -17,7 +17,7 @@
17
17
 
18
18
  require_relative "../command"
19
19
 
20
- require "benchmark"
20
+ require "benchmark" unless defined?(Benchmark)
21
21
 
22
22
  module Kitchen
23
23
  module Command
@@ -213,7 +213,7 @@ module Kitchen
213
213
  provisioner: Provisioner::DEFAULT_PLUGIN,
214
214
  verifier: Verifier::DEFAULT_PLUGIN,
215
215
  transport: lambda do |_suite, platform|
216
- platform =~ /^win/i ? "winrm" : Transport::DEFAULT_PLUGIN
216
+ /^win/i.match?(platform) ? "winrm" : Transport::DEFAULT_PLUGIN
217
217
  end,
218
218
  },
219
219
  kitchen_root: kitchen_root,
@@ -19,6 +19,7 @@ require_relative "../configurable"
19
19
  require_relative "../errors"
20
20
  require_relative "../lazy_hash"
21
21
  require_relative "../logging"
22
+ require_relative "../plugin_base"
22
23
  require_relative "../shell_out"
23
24
 
24
25
  module Kitchen
@@ -26,7 +27,7 @@ module Kitchen
26
27
  # Base class for a driver.
27
28
  #
28
29
  # @author Fletcher Nichol <fnichol@nichol.ca>
29
- class Base
30
+ class Base < Kitchen::Plugin::Base
30
31
  include Configurable
31
32
  include Logging
32
33
  include ShellOut
@@ -69,43 +70,6 @@ module Kitchen
69
70
  false
70
71
  end
71
72
 
72
- class << self
73
- # @return [Array<Symbol>] an array of action method names that cannot
74
- # be run concurrently and must be run in serial via a shared mutex
75
- attr_reader :serial_actions
76
- end
77
-
78
- # Registers certain driver actions that cannot be safely run concurrently
79
- # in threads across multiple instances. Typically this might be used
80
- # for create or destroy actions that use an underlying resource that
81
- # cannot be used at the same time.
82
- #
83
- # A shared mutex for this driver object will be used to synchronize all
84
- # registered methods.
85
- #
86
- # @example a single action method that cannot be run concurrently
87
- #
88
- # no_parallel_for :create
89
- #
90
- # @example multiple action methods that cannot be run concurrently
91
- #
92
- # no_parallel_for :create, :destroy
93
- #
94
- # @param methods [Array<Symbol>] one or more actions as symbols
95
- # @raise [ClientError] if any method is not a valid action method name
96
- def self.no_parallel_for(*methods)
97
- action_methods = %i{create setup converge verify destroy}
98
-
99
- Array(methods).each do |meth|
100
- next if action_methods.include?(meth)
101
-
102
- raise ClientError, "##{meth} is not a valid no_parallel_for method"
103
- end
104
-
105
- @serial_actions ||= []
106
- @serial_actions += methods
107
- end
108
-
109
73
  # Sets the API version for this driver. If the driver does not set this
110
74
  # value, then `nil` will be used and reported.
111
75
  #
@@ -18,7 +18,8 @@
18
18
  require "thor/util"
19
19
 
20
20
  require_relative "../lazy_hash"
21
- require "benchmark"
21
+ require_relative "../plugin_base"
22
+ require "benchmark" unless defined?(Benchmark)
22
23
 
23
24
  module Kitchen
24
25
  module Driver
@@ -42,7 +43,7 @@ module Kitchen
42
43
  # Transport, and Verifier subsystems may not be picked up in these
43
44
  # Drivers. When legacy Driver::SSHBase support is removed, this class
44
45
  # will no longer be available.
45
- class SSHBase
46
+ class SSHBase < Kitchen::Plugin::Base
46
47
  include ShellOut
47
48
  include Configurable
48
49
  include Logging
@@ -179,43 +180,6 @@ module Kitchen
179
180
  # documented dependency is missing from the system
180
181
  def verify_dependencies; end
181
182
 
182
- class << self
183
- # @return [Array<Symbol>] an array of action method names that cannot
184
- # be run concurrently and must be run in serial via a shared mutex
185
- attr_reader :serial_actions
186
- end
187
-
188
- # Registers certain driver actions that cannot be safely run concurrently
189
- # in threads across multiple instances. Typically this might be used
190
- # for create or destroy actions that use an underlying resource that
191
- # cannot be used at the same time.
192
- #
193
- # A shared mutex for this driver object will be used to synchronize all
194
- # registered methods.
195
- #
196
- # @example a single action method that cannot be run concurrently
197
- #
198
- # no_parallel_for :create
199
- #
200
- # @example multiple action methods that cannot be run concurrently
201
- #
202
- # no_parallel_for :create, :destroy
203
- #
204
- # @param methods [Array<Symbol>] one or more actions as symbols
205
- # @raise [ClientError] if any method is not a valid action method name
206
- def self.no_parallel_for(*methods)
207
- action_methods = %i{create converge setup verify destroy}
208
-
209
- Array(methods).each do |meth|
210
- next if action_methods.include?(meth)
211
-
212
- raise ClientError, "##{meth} is not a valid no_parallel_for method"
213
- end
214
-
215
- @serial_actions ||= []
216
- @serial_actions += methods
217
- end
218
-
219
183
  # Cache directory that a driver could implement to inform the provisioner
220
184
  # that it can leverage it internally
221
185
  #
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "benchmark"
19
- require "fileutils"
18
+ require "benchmark" unless defined?(Benchmark)
19
+ require "fileutils" unless defined?(FileUtils)
20
20
 
21
21
  module Kitchen
22
22
  # An instance of a suite running on a platform. A created instance may be a
@@ -28,7 +28,7 @@ module Kitchen
28
28
  include Logging
29
29
 
30
30
  class << self
31
- # @return [Hash] a hash of mutxes, arranged by Driver class names
31
+ # @return [Hash] a hash of mutexes, arranged by Plugin class names
32
32
  # @api private
33
33
  attr_accessor :mutexes
34
34
 
@@ -322,21 +322,29 @@ module Kitchen
322
322
  end
323
323
  end
324
324
 
325
- # Perform any final configuration or preparation needed for the driver
326
- # object carry out its duties.
325
+ # If a plugin has declared via .no_parallel_for that it is not
326
+ # thread-safe for certain actions, create a mutex to track it.
327
327
  #
328
+ # @param plugin_class[Class] Kitchen::Plugin::Base
328
329
  # @api private
329
- def setup_driver
330
- @driver.finalize_config!(self)
331
-
332
- if driver.class.serial_actions
330
+ def setup_plugin_mutexes(plugin_class)
331
+ if plugin_class.serial_actions
333
332
  Kitchen.mutex.synchronize do
334
333
  self.class.mutexes ||= {}
335
- self.class.mutexes[driver.class] = Mutex.new
334
+ self.class.mutexes[plugin_class] = Mutex.new
336
335
  end
337
336
  end
338
337
  end
339
338
 
339
+ # Perform any final configuration or preparation needed for the driver
340
+ # object carry out its duties.
341
+ #
342
+ # @api private
343
+ def setup_driver
344
+ @driver.finalize_config!(self)
345
+ setup_plugin_mutexes(driver.class)
346
+ end
347
+
340
348
  # Perform any final configuration or preparation needed for the lifecycle hooks
341
349
  # object carry out its duties.
342
350
  #
@@ -351,6 +359,7 @@ module Kitchen
351
359
  # @api private
352
360
  def setup_provisioner
353
361
  @provisioner.finalize_config!(self)
362
+ setup_plugin_mutexes(provisioner.class)
354
363
  end
355
364
 
356
365
  # Perform any final configuration or preparation needed for the transport
@@ -359,6 +368,7 @@ module Kitchen
359
368
  # @api private
360
369
  def setup_transport
361
370
  transport.finalize_config!(self)
371
+ setup_plugin_mutexes(transport.class)
362
372
  end
363
373
 
364
374
  # Perform any final configuration or preparation needed for the verifier
@@ -367,6 +377,7 @@ module Kitchen
367
377
  # @api private
368
378
  def setup_verifier
369
379
  verifier.finalize_config!(self)
380
+ setup_plugin_mutexes(verifier.class)
370
381
  end
371
382
 
372
383
  # Perform all actions in order from last state to desired state.
@@ -541,10 +552,11 @@ module Kitchen
541
552
  # @param block [Proc] a block to be called
542
553
  # @api private
543
554
  def synchronize_or_call(what, state)
544
- if Array(driver.class.serial_actions).include?(what)
545
- debug("#{to_str} is synchronizing on #{driver.class}##{what}")
546
- self.class.mutexes[driver.class].synchronize do
547
- debug("#{to_str} is messaging #{driver.class}##{what}")
555
+ plugin_class = plugin_class_for_action(what)
556
+ if Array(plugin_class.serial_actions).include?(what)
557
+ debug("#{to_str} is synchronizing on #{plugin_class}##{what}")
558
+ self.class.mutexes[plugin_class].synchronize do
559
+ debug("#{to_str} is messaging #{plugin_class}##{what}")
548
560
  yield(state)
549
561
  end
550
562
  else
@@ -552,6 +564,21 @@ module Kitchen
552
564
  end
553
565
  end
554
566
 
567
+ # Maps the given action to the plugin class associated with the action
568
+ #
569
+ # @param what[Symbol] action
570
+ # @return [Class] Kitchen::Plugin::Base
571
+ # @api private
572
+ def plugin_class_for_action(what)
573
+ {
574
+ create: driver,
575
+ setup: transport,
576
+ converge: provisioner,
577
+ verify: verifier,
578
+ destroy: driver,
579
+ }[what].class
580
+ end
581
+
555
582
  # Writes a high level message for logging and/or output.
556
583
  #
557
584
  # In this case, all instance banner messages will be written to the common
@@ -15,9 +15,9 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "erb"
18
+ require "erb" unless defined?(Erb)
19
19
  require_relative "../../vendor/hash_recursive_merge"
20
- require "yaml"
20
+ require "yaml" unless defined?(YAML)
21
21
 
22
22
  module Kitchen
23
23
  module Loader
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "fileutils"
18
+ require "fileutils" unless defined?(FileUtils)
19
19
  require "logger"
20
20
 
21
21
  module Kitchen
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
+ #
4
+ # Copyright (C) 2014, Fletcher Nichol
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ module Kitchen
19
+ module Plugin
20
+ class Base
21
+ class << self
22
+ # @return [Array<Symbol>] an array of action method names that cannot
23
+ # be run concurrently and must be run in serial via a shared mutex
24
+ attr_reader :serial_actions
25
+ end
26
+
27
+ # Registers certain driver actions that cannot be safely run concurrently
28
+ # in threads across multiple instances. Typically this might be used
29
+ # for create or destroy actions that use an underlying resource that
30
+ # cannot be used at the same time.
31
+ #
32
+ # A shared mutex for this driver object will be used to synchronize all
33
+ # registered methods.
34
+ #
35
+ # @example a single action method that cannot be run concurrently
36
+ #
37
+ # no_parallel_for :create
38
+ #
39
+ # @example multiple action methods that cannot be run concurrently
40
+ #
41
+ # no_parallel_for :create, :destroy
42
+ #
43
+ # @param methods [Array<Symbol>] one or more actions as symbols
44
+ # @raise [ClientError] if any method is not a valid action method name
45
+ def self.no_parallel_for(*methods)
46
+ action_methods = %i{create setup converge verify destroy}
47
+
48
+ Array(methods).each do |meth|
49
+ next if action_methods.include?(meth)
50
+
51
+ raise ClientError, "##{meth} is not a valid no_parallel_for method"
52
+ end
53
+
54
+ @serial_actions ||= []
55
+ @serial_actions += methods
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -18,13 +18,14 @@
18
18
  require_relative "../configurable"
19
19
  require_relative "../errors"
20
20
  require_relative "../logging"
21
+ require_relative "../plugin_base"
21
22
 
22
23
  module Kitchen
23
24
  module Provisioner
24
25
  # Base class for a provisioner.
25
26
  #
26
27
  # @author Fletcher Nichol <fnichol@nichol.ca>
27
- class Base
28
+ class Base < Kitchen::Plugin::Base
28
29
  include Configurable
29
30
  include Logging
30
31
 
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "json"
18
+ require "json" unless defined?(JSON)
19
19
 
20
20
  module Kitchen
21
21
  module Provisioner
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "shellwords"
19
- require "rbconfig"
18
+ require "shellwords" unless defined?(Shellwords)
19
+ require "rbconfig" unless defined?(RbConfig)
20
20
 
21
21
  require_relative "../../errors"
22
22
  require_relative "../../logging"
@@ -110,13 +110,13 @@ module Kitchen
110
110
  # @return [String]
111
111
  # @api private
112
112
  def escape_path(path)
113
- if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
113
+ if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"])
114
114
  # I know what you're thinking: "just use Shellwords.escape". That
115
115
  # method produces incorrect results on Windows with certain input
116
116
  # which would be a metacharacter in Sh but is not for one or more of
117
117
  # Windows command line parsing libraries. This covers the 99% case of
118
118
  # spaces in the path without breaking other stuff.
119
- if path =~ /[ \t\n\v"]/
119
+ if /[ \t\n\v"]/.match?(path)
120
120
  "\"#{path.gsub(/[ \t\n\v\"\\]/) { |m| '\\' + m[0] }}\""
121
121
  else
122
122
  path
@@ -136,7 +136,7 @@ module Kitchen
136
136
  # @api private
137
137
  def detect_chef_command!(logger)
138
138
  unless ENV["PATH"].split(File::PATH_SEPARATOR).any? do |path|
139
- if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
139
+ if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"])
140
140
  # Windows could have different extentions: BAT, EXE or NONE
141
141
  %w{chef chef.exe chef.bat}.each do |bin|
142
142
  File.exist?(File.join(path, bin))
@@ -15,18 +15,18 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "fileutils"
19
- require "pathname"
20
- require "json"
21
- require "cgi"
18
+ require "fileutils" unless defined?(FileUtils)
19
+ require "pathname" unless defined?(Pathname)
20
+ require "json" unless defined?(JSON)
21
+ require "cgi" unless defined?(CGI)
22
22
 
23
23
  require_relative "chef/policyfile"
24
24
  require_relative "chef/berkshelf"
25
25
  require_relative "chef/common_sandbox"
26
26
  require_relative "../util"
27
- require "mixlib/install"
28
- require "mixlib/install/script_generator"
29
- require "license_acceptance/acceptor"
27
+ module LicenseAcceptance
28
+ autoload :Acceptor, "license_acceptance/acceptor"
29
+ end
30
30
 
31
31
  begin
32
32
  require "chef-config/config"
@@ -156,7 +156,7 @@ module Kitchen
156
156
  product_name: <chef or chef-workstation>
157
157
  install_strategy: skip
158
158
  MSG
159
- when provisioner[:require_chef_omnibus].to_s.match(/\d/)
159
+ when provisioner[:require_chef_omnibus].to_s.match?(/\d/)
160
160
  Util.outdent!(<<-MSG)
161
161
  The 'require_chef_omnibus' attribute with version values will change
162
162
  to use the new 'product_version' attribute.
@@ -328,7 +328,7 @@ module Kitchen
328
328
  return unless config[:require_chef_omnibus] || config[:product_name]
329
329
  return if config[:product_name] && config[:install_strategy] == "skip"
330
330
 
331
- prefix_command(sudo(install_script_contents))
331
+ prefix_command(install_script_contents)
332
332
  end
333
333
 
334
334
  private
@@ -503,6 +503,7 @@ module Kitchen
503
503
  # @return [String] contents of product based install script
504
504
  # @api private
505
505
  def script_for_product
506
+ require "mixlib/install"
506
507
  installer = Mixlib::Install.new({
507
508
  product_name: config[:product_name],
508
509
  product_version: config[:product_version],
@@ -516,6 +517,12 @@ module Kitchen
516
517
  opts[key] = config[key] if config[key]
517
518
  end
518
519
 
520
+ unless windows_os?
521
+ # omnitruck installer does not currently support a tmp dir option on windows
522
+ opts[:install_command_options][:tmp_dir] = config[:root_path]
523
+ opts[:install_command_options]["TMPDIR"] = config[:root_path]
524
+ end
525
+
519
526
  if config[:download_url]
520
527
  opts[:install_command_options][:download_url_override] = config[:download_url]
521
528
  opts[:install_command_options][:checksum] = config[:checksum] if config[:checksum]
@@ -534,7 +541,6 @@ module Kitchen
534
541
  # install.ps1 only supports http_proxy
535
542
  prox.delete_if { |p| %i{https_proxy ftp_proxy no_proxy}.include?(p) } if powershell_shell?
536
543
  end
537
-
538
544
  opts[:install_command_options].merge!(proxies)
539
545
  end)
540
546
  config[:chef_omnibus_root] = installer.root
@@ -553,8 +559,14 @@ module Kitchen
553
559
  end
554
560
 
555
561
  def install_from_file(command)
556
- install_file = "/tmp/chef-installer.sh"
557
- script = ["cat > #{install_file} <<\"EOL\""]
562
+ install_file = "#{config[:root_path]}/chef-installer.sh"
563
+ script = []
564
+ script << "mkdir -p #{config[:root_path]}"
565
+ script << "if [ $? -ne 0 ]; then"
566
+ script << " echo Kitchen config setting root_path: '#{config[:root_path]}' not creatable by regular user "
567
+ script << " exit 1"
568
+ script << "fi"
569
+ script << "cat > #{install_file} <<\"EOL\""
558
570
  script << command
559
571
  script << "EOL"
560
572
  script << "chmod +x #{install_file}"
@@ -565,11 +577,12 @@ module Kitchen
565
577
  # @return [String] contents of version based install script
566
578
  # @api private
567
579
  def script_for_omnibus_version
580
+ require "mixlib/install/script_generator"
568
581
  installer = Mixlib::Install::ScriptGenerator.new(
569
582
  config[:require_chef_omnibus], powershell_shell?, install_options
570
583
  )
571
584
  config[:chef_omnibus_root] = installer.root
572
- installer.install_command
585
+ sudo(installer.install_command)
573
586
  end
574
587
 
575
588
  # Hook used in subclasses to indicate support for policyfiles.
@@ -27,6 +27,10 @@ module Kitchen
27
27
 
28
28
  plugin_version Kitchen::VERSION
29
29
 
30
+ # ChefSolo is dependent on Berkshelf, which is not thread-safe.
31
+ # See discussion on https://github.com/test-kitchen/test-kitchen/issues/1307
32
+ no_parallel_for :converge
33
+
30
34
  default_config :solo_rb, {}
31
35
 
32
36
  default_config :chef_solo_path do |provisioner|
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "shellwords"
18
+ require "shellwords" unless defined?(Shellwords)
19
19
 
20
20
  require_relative "base"
21
21
  require_relative "../version"
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "mixlib/shellout"
18
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
19
19
 
20
20
  module Kitchen
21
21
  # Mixin that wraps a command shell out invocation, providing a #run_command
@@ -16,9 +16,10 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require "logger"
19
- require "net/ssh"
20
- require "net/scp"
21
- require "socket"
19
+ module Net
20
+ autoload :SSH, "net/ssh"
21
+ end
22
+ require "socket" unless defined?(Socket)
22
23
 
23
24
  require_relative "errors"
24
25
  require_relative "login_command"
@@ -90,6 +91,7 @@ module Kitchen
90
91
  # `Net::SCP.upload`
91
92
  # @see http://net-ssh.github.io/net-scp/classes/Net/SCP.html#method-i-upload
92
93
  def upload!(local, remote, options = {}, &progress)
94
+ require "net/scp" unless defined?(Net::SCP)
93
95
  if progress.nil?
94
96
  progress = lambda do |_ch, name, sent, total|
95
97
  logger.debug("Uploaded #{name} (#{total} bytes)") if sent == total
@@ -100,6 +102,7 @@ module Kitchen
100
102
  end
101
103
 
102
104
  def upload(local, remote, options = {}, &progress)
105
+ require "net/scp" unless defined?(Net::SCP)
103
106
  if progress.nil?
104
107
  progress = lambda do |_ch, name, sent, total|
105
108
  if sent == total
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "yaml"
18
+ autoload :YAML, "yaml"
19
19
 
20
20
  module Kitchen
21
21
  # Exception class for any exceptions raised when reading and parsing a state
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thor"
18
+ require "thor" unless defined?(Thor)
19
19
 
20
20
  require_relative "../kitchen"
21
21
 
@@ -21,6 +21,7 @@ require_relative "../errors"
21
21
  require_relative "../lazy_hash"
22
22
  require_relative "../logging"
23
23
  require_relative "../login_command"
24
+ require_relative "../plugin_base"
24
25
 
25
26
  module Kitchen
26
27
  module Transport
@@ -40,7 +41,7 @@ module Kitchen
40
41
  #
41
42
  # @author Salim Afiune <salim@afiunemaya.com.mx>
42
43
  # @author Fletcher Nichol <fnichol@nichol.ca>
43
- class Base
44
+ class Base < Kitchen::Plugin::Base
44
45
  include Configurable
45
46
  include Logging
46
47
 
@@ -11,7 +11,7 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
 
14
- require "fileutils"
14
+ require "fileutils" unless defined?(FileUtils)
15
15
 
16
16
  require_relative "../shell_out"
17
17
  require_relative "base"
@@ -28,7 +28,7 @@ module Kitchen
28
28
  plugin_version Kitchen::VERSION
29
29
 
30
30
  def connection(state, &block)
31
- options = config.to_hash.merge(state)
31
+ options = connection_options(config.to_hash.merge(state))
32
32
  Kitchen::Transport::Exec::Connection.new(options, &block)
33
33
  end
34
34
 
@@ -40,19 +40,105 @@ module Kitchen
40
40
  def execute(command)
41
41
  return if command.nil?
42
42
 
43
- run_command(command)
43
+ if host_os_windows?
44
+ run_command(run_from_file_command(command))
45
+ close
46
+ else
47
+ run_command(command)
48
+ end
49
+ end
50
+
51
+ def close
52
+ if host_os_windows?
53
+ FileUtils.remove(exec_script_file)
54
+ end
44
55
  end
45
56
 
46
57
  # "Upload" the files by copying them locally.
47
58
  #
48
59
  # @see Base#upload
49
60
  def upload(locals, remote)
50
- FileUtils.mkdir_p(remote)
61
+ # evaluate $env:temp on Windows
62
+ real_remote = remote.to_s == "\$env:TEMP\\kitchen" ? kitchen_temp : remote
63
+ FileUtils.mkdir_p(real_remote)
51
64
  Array(locals).each do |local|
52
- FileUtils.cp_r(local, remote)
65
+ FileUtils.cp_r(local, real_remote)
66
+ end
67
+ end
68
+
69
+ # (see Base#init_options)
70
+ def init_options(options)
71
+ super
72
+ @instance_name = @options.delete(:instance_name)
73
+ @kitchen_root = @options.delete(:kitchen_root)
74
+ end
75
+
76
+ private
77
+
78
+ # @return [String] display name for the associated instance
79
+ # @api private
80
+ attr_reader :instance_name
81
+
82
+ # @return [String] local path to the root of the project
83
+ # @api private
84
+ attr_reader :kitchen_root
85
+
86
+ # Takes a long command and saves it to a file and uploads it to
87
+ # the test instance. Windows has cli character limits.
88
+ #
89
+ # @param command [String] a long command to be saved and uploaded
90
+ # @return [String] a command that executes the uploaded script
91
+ # @api private
92
+ def run_from_file_command(command)
93
+ if logger.debug?
94
+ debug("Creating exec script for #{instance_name} (#{exec_script_file})")
95
+ debug("Executing #{exec_script_file}")
96
+ end
97
+ File.open(exec_script_file, "wb") { |file| file.write(command) }
98
+ %{powershell -file "#{exec_script_file}"}
99
+ end
100
+
101
+ # @return [String] evaluated $env:temp variable
102
+ # @api private
103
+ def kitchen_temp
104
+ "#{ENV["temp"]}/kitchen"
105
+ end
106
+
107
+ # @return [String] name of script using instance name
108
+ # @api private
109
+ def exec_script_name
110
+ "#{instance_name}-exec-script.ps1"
111
+ end
112
+
113
+ # @return [String] file path for exec script to be run
114
+ # @api private
115
+ def exec_script_file
116
+ File.join(kitchen_root, ".kitchen", exec_script_name)
117
+ end
118
+
119
+ def host_os_windows?
120
+ case RbConfig::CONFIG["host_os"]
121
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
122
+ true
123
+ else
124
+ false
53
125
  end
54
126
  end
127
+ end
128
+
129
+ private
55
130
 
131
+ # Builds the hash of options needed by the Connection object on construction.
132
+ #
133
+ # @param data [Hash] merged configuration and mutable state data
134
+ # @return [Hash] hash of connection options
135
+ # @api private
136
+ def connection_options(data)
137
+ opts = {
138
+ instance_name: instance.name,
139
+ kitchen_root: Dir.pwd,
140
+ }
141
+ opts
56
142
  end
57
143
  end
58
144
  end
@@ -17,13 +17,13 @@
17
17
 
18
18
  require_relative "../../kitchen"
19
19
 
20
- require "fileutils"
21
- require "net/ssh"
20
+ require "fileutils" unless defined?(FileUtils)
21
+ require "net/ssh" unless defined?(Net::SSH)
22
22
  require "net/ssh/gateway"
23
23
  require "net/ssh/proxy/http"
24
24
  require "net/scp"
25
- require "timeout"
26
- require "benchmark"
25
+ require "timeout" unless defined?(Timeout)
26
+ require "benchmark" unless defined?(Benchmark)
27
27
 
28
28
  module Kitchen
29
29
  module Transport
@@ -17,10 +17,10 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
 
20
- require "rbconfig"
21
- require "uri"
20
+ require "rbconfig" unless defined?(RbConfig)
21
+ require "uri" unless defined?(URI)
22
22
  require_relative "../../kitchen"
23
- require "winrm"
23
+ require "winrm" unless defined?(WinRM::Connection)
24
24
 
25
25
  module Kitchen
26
26
  module Transport
@@ -110,7 +110,7 @@ module Kitchen
110
110
  def self.wrap_command(cmd)
111
111
  cmd = "false" if cmd.nil?
112
112
  cmd = "true" if cmd.to_s.empty?
113
- cmd = cmd.sub(/\n\Z/, "") if cmd =~ /\n\Z/
113
+ cmd = cmd.sub(/\n\Z/, "") if /\n\Z/.match?(cmd)
114
114
 
115
115
  "sh -c '\n#{cmd}\n'"
116
116
  end
@@ -18,13 +18,14 @@
18
18
  require_relative "../errors"
19
19
  require_relative "../configurable"
20
20
  require_relative "../logging"
21
+ require_relative "../plugin_base"
21
22
 
22
23
  module Kitchen
23
24
  module Verifier
24
25
  # Base class for a verifier.
25
26
  #
26
27
  # @author Fletcher Nichol <fnichol@nichol.ca>
27
- class Base
28
+ class Base < Kitchen::Plugin::Base
28
29
  include Configurable
29
30
  include Logging
30
31
 
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "base64"
19
- require "digest"
18
+ require "base64" unless defined?(Base64)
19
+ require "digest" unless defined?(Digest)
20
20
 
21
21
  require_relative "base"
22
22
 
@@ -168,7 +168,7 @@ module Kitchen
168
168
  # @api private
169
169
  def gem_install_args
170
170
  gem, version = config[:version].split("@")
171
- if gem =~ /^\d+\.\d+\.\d+/
171
+ if /^\d+\.\d+\.\d+/.match?(gem)
172
172
  version = gem
173
173
  gem = "busser"
174
174
  end
@@ -23,7 +23,7 @@ module Kitchen
23
23
  #
24
24
  # @author SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
25
25
  class Shell < Kitchen::Verifier::Base
26
- require "mixlib/shellout"
26
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
27
27
 
28
28
  kitchen_verifier_api_version 1
29
29
 
@@ -16,5 +16,5 @@
16
16
  # limitations under the License.
17
17
 
18
18
  module Kitchen
19
- VERSION = "2.5.4".freeze
19
+ VERSION = "2.8.0".freeze
20
20
  end
@@ -1,4 +1,4 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "kitchen/version"
4
4
  require "English"
@@ -15,12 +15,12 @@ Gem::Specification.new do |gem|
15
15
  gem.summary = gem.description
16
16
  gem.homepage = "https://kitchen.ci/"
17
17
 
18
- # The gemfile and gemspec are necessary for appbundler in Chef-DK / Workstation
18
+ # The gemfile and gemspec are necessary for appbundler in ChefDK / Workstation
19
19
  gem.files = %w{LICENSE test-kitchen.gemspec Gemfile Rakefile} + Dir.glob("{bin,lib,templates,support}/**/*")
20
20
  gem.executables = %w{kitchen}
21
21
  gem.require_paths = ["lib"]
22
22
 
23
- gem.required_ruby_version = ">= 2.3"
23
+ gem.required_ruby_version = ">= 2.4"
24
24
 
25
25
  gem.add_dependency "mixlib-shellout", ">= 1.2", "< 4.0"
26
26
  gem.add_dependency "net-scp", ">= 1.1", "< 4.0" # pinning until we can confirm 4+ works
@@ -35,7 +35,7 @@ Gem::Specification.new do |gem|
35
35
  gem.add_dependency "winrm-fs", "~> 1.1"
36
36
  # Required to run the Chef provisioner local license check for remote systems
37
37
  # TK is not under Chef EULA
38
- gem.add_dependency "license-acceptance", "~> 1.0", ">= 1.0.11"
38
+ gem.add_dependency "license-acceptance", ">= 1.0.11", "< 3.0" # pinning until we can confirm 3+ works
39
39
 
40
40
  gem.add_development_dependency "rb-readline"
41
41
  gem.add_development_dependency "bundler"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-kitchen
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.4
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Nichol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-29 00:00:00.000000000 Z
11
+ date: 2020-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -198,22 +198,22 @@ dependencies:
198
198
  name: license-acceptance
199
199
  requirement: !ruby/object:Gem::Requirement
200
200
  requirements:
201
- - - "~>"
202
- - !ruby/object:Gem::Version
203
- version: '1.0'
204
201
  - - ">="
205
202
  - !ruby/object:Gem::Version
206
203
  version: 1.0.11
204
+ - - "<"
205
+ - !ruby/object:Gem::Version
206
+ version: '3.0'
207
207
  type: :runtime
208
208
  prerelease: false
209
209
  version_requirements: !ruby/object:Gem::Requirement
210
210
  requirements:
211
- - - "~>"
212
- - !ruby/object:Gem::Version
213
- version: '1.0'
214
211
  - - ">="
215
212
  - !ruby/object:Gem::Version
216
213
  version: 1.0.11
214
+ - - "<"
215
+ - !ruby/object:Gem::Version
216
+ version: '3.0'
217
217
  - !ruby/object:Gem::Dependency
218
218
  name: rb-readline
219
219
  requirement: !ruby/object:Gem::Requirement
@@ -423,6 +423,7 @@ files:
423
423
  - lib/kitchen/metadata_chopper.rb
424
424
  - lib/kitchen/platform.rb
425
425
  - lib/kitchen/plugin.rb
426
+ - lib/kitchen/plugin_base.rb
426
427
  - lib/kitchen/provisioner.rb
427
428
  - lib/kitchen/provisioner/base.rb
428
429
  - lib/kitchen/provisioner/chef/berkshelf.rb
@@ -492,14 +493,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
492
493
  requirements:
493
494
  - - ">="
494
495
  - !ruby/object:Gem::Version
495
- version: '2.3'
496
+ version: '2.4'
496
497
  required_rubygems_version: !ruby/object:Gem::Requirement
497
498
  requirements:
498
499
  - - ">="
499
500
  - !ruby/object:Gem::Version
500
501
  version: '0'
501
502
  requirements: []
502
- rubygems_version: 3.1.2
503
+ rubygems_version: 3.1.4
503
504
  signing_key:
504
505
  specification_version: 4
505
506
  summary: Test Kitchen is an integration tool for developing and testing infrastructure