test-kitchen 1.6.0 → 1.7.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.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/.cane +8 -7
  3. data/.github/ISSUE_TEMPLATE.md +56 -0
  4. data/.gitignore +28 -27
  5. data/.kitchen.ci.yml +23 -0
  6. data/.kitchen.proxy.yml +27 -0
  7. data/.rubocop.yml +3 -3
  8. data/.travis.yml +70 -53
  9. data/.yardopts +3 -3
  10. data/Berksfile +3 -0
  11. data/CHANGELOG.md +1083 -1051
  12. data/CONTRIBUTING.md +14 -14
  13. data/Gemfile +19 -14
  14. data/Gemfile.proxy_tests +4 -5
  15. data/Guardfile +42 -42
  16. data/LICENSE +15 -15
  17. data/MAINTAINERS.md +23 -24
  18. data/README.md +135 -135
  19. data/Rakefile +61 -76
  20. data/appveyor.yml +44 -34
  21. data/features/kitchen_action_commands.feature +164 -164
  22. data/features/kitchen_command.feature +16 -16
  23. data/features/kitchen_console_command.feature +34 -34
  24. data/features/kitchen_defaults.feature +38 -38
  25. data/features/kitchen_diagnose_command.feature +96 -96
  26. data/features/kitchen_driver_create_command.feature +64 -64
  27. data/features/kitchen_driver_discover_command.feature +25 -25
  28. data/features/kitchen_help_command.feature +16 -16
  29. data/features/kitchen_init_command.feature +274 -274
  30. data/features/kitchen_list_command.feature +104 -104
  31. data/features/kitchen_login_command.feature +62 -62
  32. data/features/kitchen_sink_command.feature +30 -30
  33. data/features/kitchen_test_command.feature +88 -88
  34. data/features/step_definitions/gem_steps.rb +36 -36
  35. data/features/step_definitions/git_steps.rb +5 -5
  36. data/features/step_definitions/output_steps.rb +5 -5
  37. data/features/support/env.rb +75 -75
  38. data/lib/kitchen.rb +150 -150
  39. data/lib/kitchen/base64_stream.rb +55 -55
  40. data/lib/kitchen/cli.rb +419 -419
  41. data/lib/kitchen/collection.rb +55 -55
  42. data/lib/kitchen/color.rb +65 -65
  43. data/lib/kitchen/command.rb +185 -185
  44. data/lib/kitchen/command/action.rb +45 -45
  45. data/lib/kitchen/command/console.rb +58 -58
  46. data/lib/kitchen/command/diagnose.rb +92 -92
  47. data/lib/kitchen/command/driver_discover.rb +105 -105
  48. data/lib/kitchen/command/exec.rb +41 -41
  49. data/lib/kitchen/command/list.rb +119 -119
  50. data/lib/kitchen/command/login.rb +43 -43
  51. data/lib/kitchen/command/sink.rb +54 -54
  52. data/lib/kitchen/command/test.rb +51 -51
  53. data/lib/kitchen/config.rb +322 -322
  54. data/lib/kitchen/configurable.rb +529 -529
  55. data/lib/kitchen/data_munger.rb +959 -960
  56. data/lib/kitchen/diagnostic.rb +141 -141
  57. data/lib/kitchen/driver.rb +56 -56
  58. data/lib/kitchen/driver/base.rb +134 -134
  59. data/lib/kitchen/driver/dummy.rb +108 -108
  60. data/lib/kitchen/driver/proxy.rb +72 -72
  61. data/lib/kitchen/driver/ssh_base.rb +357 -357
  62. data/lib/kitchen/errors.rb +229 -229
  63. data/lib/kitchen/generator/driver_create.rb +177 -177
  64. data/lib/kitchen/generator/init.rb +296 -296
  65. data/lib/kitchen/instance.rb +662 -662
  66. data/lib/kitchen/lazy_hash.rb +142 -142
  67. data/lib/kitchen/loader/yaml.rb +349 -349
  68. data/lib/kitchen/logger.rb +423 -423
  69. data/lib/kitchen/logging.rb +56 -56
  70. data/lib/kitchen/login_command.rb +52 -52
  71. data/lib/kitchen/metadata_chopper.rb +52 -52
  72. data/lib/kitchen/platform.rb +67 -67
  73. data/lib/kitchen/provisioner.rb +54 -54
  74. data/lib/kitchen/provisioner/base.rb +236 -236
  75. data/lib/kitchen/provisioner/chef/berkshelf.rb +114 -114
  76. data/lib/kitchen/provisioner/chef/common_sandbox.rb +322 -322
  77. data/lib/kitchen/provisioner/chef/librarian.rb +112 -112
  78. data/lib/kitchen/provisioner/chef_apply.rb +124 -125
  79. data/lib/kitchen/provisioner/chef_base.rb +341 -294
  80. data/lib/kitchen/provisioner/chef_solo.rb +88 -89
  81. data/lib/kitchen/provisioner/chef_zero.rb +245 -245
  82. data/lib/kitchen/provisioner/dummy.rb +79 -79
  83. data/lib/kitchen/provisioner/shell.rb +138 -138
  84. data/lib/kitchen/rake_tasks.rb +63 -63
  85. data/lib/kitchen/shell_out.rb +93 -93
  86. data/lib/kitchen/ssh.rb +276 -276
  87. data/lib/kitchen/state_file.rb +120 -120
  88. data/lib/kitchen/suite.rb +51 -51
  89. data/lib/kitchen/thor_tasks.rb +66 -66
  90. data/lib/kitchen/transport.rb +54 -54
  91. data/lib/kitchen/transport/base.rb +176 -176
  92. data/lib/kitchen/transport/dummy.rb +79 -79
  93. data/lib/kitchen/transport/ssh.rb +364 -364
  94. data/lib/kitchen/transport/winrm.rb +486 -486
  95. data/lib/kitchen/util.rb +147 -147
  96. data/lib/kitchen/verifier.rb +55 -55
  97. data/lib/kitchen/verifier/base.rb +235 -235
  98. data/lib/kitchen/verifier/busser.rb +277 -277
  99. data/lib/kitchen/verifier/dummy.rb +79 -79
  100. data/lib/kitchen/verifier/shell.rb +101 -101
  101. data/lib/kitchen/version.rb +21 -21
  102. data/lib/vendor/hash_recursive_merge.rb +82 -82
  103. data/spec/kitchen/base64_stream_spec.rb +77 -77
  104. data/spec/kitchen/cli_spec.rb +56 -56
  105. data/spec/kitchen/collection_spec.rb +80 -80
  106. data/spec/kitchen/color_spec.rb +54 -54
  107. data/spec/kitchen/config_spec.rb +408 -408
  108. data/spec/kitchen/configurable_spec.rb +1095 -1062
  109. data/spec/kitchen/data_munger_spec.rb +2694 -2383
  110. data/spec/kitchen/diagnostic_spec.rb +129 -129
  111. data/spec/kitchen/driver/base_spec.rb +121 -121
  112. data/spec/kitchen/driver/dummy_spec.rb +199 -199
  113. data/spec/kitchen/driver/proxy_spec.rb +138 -138
  114. data/spec/kitchen/driver/ssh_base_spec.rb +1115 -1115
  115. data/spec/kitchen/driver_spec.rb +112 -112
  116. data/spec/kitchen/errors_spec.rb +309 -309
  117. data/spec/kitchen/instance_spec.rb +1419 -1419
  118. data/spec/kitchen/lazy_hash_spec.rb +117 -117
  119. data/spec/kitchen/loader/yaml_spec.rb +774 -774
  120. data/spec/kitchen/logger_spec.rb +429 -429
  121. data/spec/kitchen/logging_spec.rb +59 -59
  122. data/spec/kitchen/login_command_spec.rb +68 -68
  123. data/spec/kitchen/metadata_chopper_spec.rb +82 -82
  124. data/spec/kitchen/platform_spec.rb +89 -89
  125. data/spec/kitchen/provisioner/base_spec.rb +386 -386
  126. data/spec/kitchen/provisioner/chef_apply_spec.rb +136 -136
  127. data/spec/kitchen/provisioner/chef_base_spec.rb +1161 -1067
  128. data/spec/kitchen/provisioner/chef_solo_spec.rb +557 -557
  129. data/spec/kitchen/provisioner/chef_zero_spec.rb +1001 -1001
  130. data/spec/kitchen/provisioner/dummy_spec.rb +99 -99
  131. data/spec/kitchen/provisioner/shell_spec.rb +566 -566
  132. data/spec/kitchen/provisioner_spec.rb +107 -107
  133. data/spec/kitchen/shell_out_spec.rb +150 -150
  134. data/spec/kitchen/ssh_spec.rb +693 -693
  135. data/spec/kitchen/state_file_spec.rb +129 -129
  136. data/spec/kitchen/suite_spec.rb +62 -62
  137. data/spec/kitchen/transport/base_spec.rb +89 -89
  138. data/spec/kitchen/transport/ssh_spec.rb +1255 -1255
  139. data/spec/kitchen/transport/winrm_spec.rb +1143 -1143
  140. data/spec/kitchen/transport_spec.rb +112 -112
  141. data/spec/kitchen/util_spec.rb +165 -165
  142. data/spec/kitchen/verifier/base_spec.rb +362 -362
  143. data/spec/kitchen/verifier/busser_spec.rb +610 -610
  144. data/spec/kitchen/verifier/dummy_spec.rb +99 -99
  145. data/spec/kitchen/verifier/shell_spec.rb +160 -158
  146. data/spec/kitchen/verifier_spec.rb +120 -120
  147. data/spec/kitchen_spec.rb +114 -114
  148. data/spec/spec_helper.rb +85 -85
  149. data/spec/support/powershell_max_size_spec.rb +40 -40
  150. data/support/busser_install_command.ps1 +14 -14
  151. data/support/busser_install_command.sh +14 -14
  152. data/support/chef-client-zero.rb +77 -77
  153. data/support/chef_base_init_command.ps1 +18 -18
  154. data/support/chef_base_init_command.sh +2 -2
  155. data/support/chef_base_install_command.ps1 +85 -85
  156. data/support/chef_base_install_command.sh +229 -229
  157. data/support/chef_zero_prepare_command_legacy.ps1 +9 -9
  158. data/support/chef_zero_prepare_command_legacy.sh +10 -10
  159. data/support/download_helpers.sh +109 -109
  160. data/support/dummy-validation.pem +27 -27
  161. data/templates/driver/CHANGELOG.md.erb +3 -3
  162. data/templates/driver/Gemfile.erb +3 -3
  163. data/templates/driver/README.md.erb +64 -64
  164. data/templates/driver/Rakefile.erb +21 -21
  165. data/templates/driver/driver.rb.erb +23 -23
  166. data/templates/driver/gemspec.erb +29 -29
  167. data/templates/driver/gitignore.erb +17 -17
  168. data/templates/driver/license_apachev2.erb +15 -15
  169. data/templates/driver/license_lgplv3.erb +16 -16
  170. data/templates/driver/license_mit.erb +22 -22
  171. data/templates/driver/license_reserved.erb +5 -5
  172. data/templates/driver/tailor.erb +4 -4
  173. data/templates/driver/travis.yml.erb +11 -11
  174. data/templates/driver/version.rb.erb +12 -12
  175. data/templates/init/chefignore.erb +1 -1
  176. data/templates/init/kitchen.yml.erb +18 -18
  177. data/test-kitchen.gemspec +62 -62
  178. data/test/integration/default/default_spec.rb +3 -0
  179. data/testing_windows.md +37 -37
  180. metadata +23 -11
@@ -1,108 +1,108 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
- #
5
- # Copyright (C) 2012, 2013, 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
- require "kitchen"
20
-
21
- module Kitchen
22
-
23
- module Driver
24
-
25
- # Dummy driver for Kitchen. This driver does nothing but report what would
26
- # happen if this driver did anything of consequence. As a result it may
27
- # be a useful driver to use when debugging or developing new features or
28
- # plugins.
29
- #
30
- # @author Fletcher Nichol <fnichol@nichol.ca>
31
- class Dummy < Kitchen::Driver::Base
32
-
33
- kitchen_driver_api_version 2
34
-
35
- plugin_version Kitchen::VERSION
36
-
37
- default_config :sleep, 0
38
- default_config :random_failure, false
39
-
40
- # (see Base#create)
41
- def create(state)
42
- state[:my_id] = "#{instance.name}-#{Time.now.to_i}"
43
- report(:create, state)
44
- end
45
-
46
- # (see Base#setup)
47
- def setup(state)
48
- report(:setup, state)
49
- end
50
-
51
- # (see Base#verify)
52
- def verify(state)
53
- report(:verify, state)
54
- end
55
-
56
- # (see Base#destroy)
57
- def destroy(state)
58
- report(:destroy, state)
59
- state.delete(:my_id)
60
- end
61
-
62
- private
63
-
64
- # Report what action is taking place, sleeping if so configured, and
65
- # possibly fail randomly.
66
- #
67
- # @param action [Symbol] the action currently taking place
68
- # @param state [Hash] the state hash
69
- # @api private
70
- def report(action, state)
71
- what = action.capitalize
72
- info("[Dummy] #{what} on instance=#{instance} with state=#{state}")
73
- sleep_if_set
74
- failure_if_set(action)
75
- debug("[Dummy] #{what} completed (#{config[:sleep]}s).")
76
- end
77
-
78
- # Sleep for a period of time, if a value is set in the config.
79
- #
80
- # @api private
81
- def sleep_if_set
82
- sleep(config[:sleep].to_f) if config[:sleep].to_f > 0.0
83
- end
84
-
85
- # Simulate a failure in an action, if set in the config.
86
- #
87
- # @param action [Symbol] the action currently taking place
88
- # @api private
89
- def failure_if_set(action)
90
- if config[:"fail_#{action}"]
91
- debug("[Dummy] Failure for action ##{action}.")
92
- raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
93
- elsif config[:random_failure] && randomly_fail?
94
- debug("[Dummy] Random failure for action ##{action}.")
95
- raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
96
- end
97
- end
98
-
99
- # Determine whether or not to randomly fail.
100
- #
101
- # @return [true, false]
102
- # @api private
103
- def randomly_fail?
104
- [true, false].sample
105
- end
106
- end
107
- end
108
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
4
+ #
5
+ # Copyright (C) 2012, 2013, 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
+ require "kitchen"
20
+
21
+ module Kitchen
22
+
23
+ module Driver
24
+
25
+ # Dummy driver for Kitchen. This driver does nothing but report what would
26
+ # happen if this driver did anything of consequence. As a result it may
27
+ # be a useful driver to use when debugging or developing new features or
28
+ # plugins.
29
+ #
30
+ # @author Fletcher Nichol <fnichol@nichol.ca>
31
+ class Dummy < Kitchen::Driver::Base
32
+
33
+ kitchen_driver_api_version 2
34
+
35
+ plugin_version Kitchen::VERSION
36
+
37
+ default_config :sleep, 0
38
+ default_config :random_failure, false
39
+
40
+ # (see Base#create)
41
+ def create(state)
42
+ state[:my_id] = "#{instance.name}-#{Time.now.to_i}"
43
+ report(:create, state)
44
+ end
45
+
46
+ # (see Base#setup)
47
+ def setup(state)
48
+ report(:setup, state)
49
+ end
50
+
51
+ # (see Base#verify)
52
+ def verify(state)
53
+ report(:verify, state)
54
+ end
55
+
56
+ # (see Base#destroy)
57
+ def destroy(state)
58
+ report(:destroy, state)
59
+ state.delete(:my_id)
60
+ end
61
+
62
+ private
63
+
64
+ # Report what action is taking place, sleeping if so configured, and
65
+ # possibly fail randomly.
66
+ #
67
+ # @param action [Symbol] the action currently taking place
68
+ # @param state [Hash] the state hash
69
+ # @api private
70
+ def report(action, state)
71
+ what = action.capitalize
72
+ info("[Dummy] #{what} on instance=#{instance} with state=#{state}")
73
+ sleep_if_set
74
+ failure_if_set(action)
75
+ debug("[Dummy] #{what} completed (#{config[:sleep]}s).")
76
+ end
77
+
78
+ # Sleep for a period of time, if a value is set in the config.
79
+ #
80
+ # @api private
81
+ def sleep_if_set
82
+ sleep(config[:sleep].to_f) if config[:sleep].to_f > 0.0
83
+ end
84
+
85
+ # Simulate a failure in an action, if set in the config.
86
+ #
87
+ # @param action [Symbol] the action currently taking place
88
+ # @api private
89
+ def failure_if_set(action)
90
+ if config[:"fail_#{action}"]
91
+ debug("[Dummy] Failure for action ##{action}.")
92
+ raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
93
+ elsif config[:random_failure] && randomly_fail?
94
+ debug("[Dummy] Random failure for action ##{action}.")
95
+ raise ActionFailed, "Action ##{action} failed for #{instance.to_str}."
96
+ end
97
+ end
98
+
99
+ # Determine whether or not to randomly fail.
100
+ #
101
+ # @return [true, false]
102
+ # @api private
103
+ def randomly_fail?
104
+ [true, false].sample
105
+ end
106
+ end
107
+ end
108
+ end
@@ -1,72 +1,72 @@
1
- # -*- encoding: utf-8 -*-
2
- #
3
- # Author:: Seth Chisamore <schisamo@opscode.com>
4
- #
5
- # Copyright:: Copyright (c) 2013 Opscode, Inc.
6
- # License:: Apache License, Version 2.0
7
- #
8
- # Licensed under the Apache License, Version 2.0 (the "License");
9
- # you may not use this file except in compliance with the License.
10
- # You may obtain a copy of the License at
11
- #
12
- # http://www.apache.org/licenses/LICENSE-2.0
13
- #
14
- # Unless required by applicable law or agreed to in writing, software
15
- # distributed under the License is distributed on an "AS IS" BASIS,
16
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
- # See the License for the specific language governing permissions and
18
- # limitations under the License.
19
- #
20
-
21
- require "kitchen"
22
- require "kitchen/version"
23
-
24
- module Kitchen
25
-
26
- module Driver
27
-
28
- # Simple driver that proxies commands through to a test instance whose
29
- # lifecycle is not managed by Test Kitchen. This driver is useful for long-
30
- # lived non-ephemeral test instances that are simply "reset" between test
31
- # runs. Think executing against devices like network switches--this is why
32
- # the driver was created.
33
- #
34
- # @author Seth Chisamore <schisamo@opscode.com>
35
- class Proxy < Kitchen::Driver::SSHBase
36
-
37
- plugin_version Kitchen::VERSION
38
-
39
- required_config :host
40
- required_config :reset_command
41
-
42
- no_parallel_for :create, :destroy
43
-
44
- # (see Base#create)
45
- def create(state)
46
- state[:hostname] = config[:host]
47
- reset_instance(state)
48
- end
49
-
50
- # (see Base#destroy)
51
- def destroy(state)
52
- return if state[:hostname].nil?
53
- reset_instance(state)
54
- state.delete(:hostname)
55
- end
56
-
57
- private
58
-
59
- # Resets the non-Kitchen managed instance using by issuing a command
60
- # over SSH.
61
- #
62
- # @param state [Hash] the state hash
63
- # @api private
64
- def reset_instance(state)
65
- if cmd = config[:reset_command]
66
- info("Resetting instance state with command: #{cmd}")
67
- ssh(build_ssh_args(state), cmd)
68
- end
69
- end
70
- end
71
- end
72
- end
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # Author:: Seth Chisamore <schisamo@opscode.com>
4
+ #
5
+ # Copyright:: Copyright (c) 2013 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require "kitchen"
22
+ require "kitchen/version"
23
+
24
+ module Kitchen
25
+
26
+ module Driver
27
+
28
+ # Simple driver that proxies commands through to a test instance whose
29
+ # lifecycle is not managed by Test Kitchen. This driver is useful for long-
30
+ # lived non-ephemeral test instances that are simply "reset" between test
31
+ # runs. Think executing against devices like network switches--this is why
32
+ # the driver was created.
33
+ #
34
+ # @author Seth Chisamore <schisamo@opscode.com>
35
+ class Proxy < Kitchen::Driver::SSHBase
36
+
37
+ plugin_version Kitchen::VERSION
38
+
39
+ required_config :host
40
+ required_config :reset_command
41
+
42
+ no_parallel_for :create, :destroy
43
+
44
+ # (see Base#create)
45
+ def create(state)
46
+ state[:hostname] = config[:host]
47
+ reset_instance(state)
48
+ end
49
+
50
+ # (see Base#destroy)
51
+ def destroy(state)
52
+ return if state[:hostname].nil?
53
+ reset_instance(state)
54
+ state.delete(:hostname)
55
+ end
56
+
57
+ private
58
+
59
+ # Resets the non-Kitchen managed instance using by issuing a command
60
+ # over SSH.
61
+ #
62
+ # @param state [Hash] the state hash
63
+ # @api private
64
+ def reset_instance(state)
65
+ if cmd = config[:reset_command]
66
+ info("Resetting instance state with command: #{cmd}")
67
+ ssh(build_ssh_args(state), cmd)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,357 +1,357 @@
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/util"
20
-
21
- require "kitchen/lazy_hash"
22
-
23
- module Kitchen
24
-
25
- module Driver
26
-
27
- # Legacy base class for a driver that uses SSH to communication with an
28
- # instance. This class has been updated to use the Instance's Transport to
29
- # issue commands and transfer files and no longer uses the `Kitchen:SSH`
30
- # class directly.
31
- #
32
- # **NOTE:** Authors of new Drivers are encouraged to inherit from
33
- # `Kitchen::Driver::Base` instead and existing Driver authors are
34
- # encouraged to update their Driver class to inherit from
35
- # `Kitchen::Driver::SSHBase`.
36
- #
37
- # A subclass must implement the following methods:
38
- # * #create(state)
39
- # * #destroy(state)
40
- #
41
- # @author Fletcher Nichol <fnichol@nichol.ca>
42
- # @deprecated While all possible effort has been made to preserve the
43
- # original behavior of this class, future improvements to the Driver,
44
- # Transport, and Verifier subsystems may not be picked up in these
45
- # Drivers. When legacy Driver::SSHBase support is removed, this class
46
- # will no longer be available.
47
- class SSHBase
48
-
49
- include ShellOut
50
- include Configurable
51
- include Logging
52
-
53
- default_config :sudo, true
54
- default_config :port, 22
55
-
56
- # Creates a new Driver object using the provided configuration data
57
- # which will be merged with any default configuration.
58
- #
59
- # @param config [Hash] provided driver configuration
60
- def initialize(config = {})
61
- init_config(config)
62
- end
63
-
64
- # (see Base#create)
65
- def create(state) # rubocop:disable Lint/UnusedMethodArgument
66
- raise ClientError, "#{self.class}#create must be implemented"
67
- end
68
-
69
- # (see Base#converge)
70
- def converge(state) # rubocop:disable Metrics/AbcSize
71
- provisioner = instance.provisioner
72
- provisioner.create_sandbox
73
- sandbox_dirs = Dir.glob("#{provisioner.sandbox_path}/*")
74
-
75
- instance.transport.connection(backcompat_merged_state(state)) do |conn|
76
- conn.execute(env_cmd(provisioner.install_command))
77
- conn.execute(env_cmd(provisioner.init_command))
78
- info("Transferring files to #{instance.to_str}")
79
- conn.upload(sandbox_dirs, provisioner[:root_path])
80
- debug("Transfer complete")
81
- conn.execute(env_cmd(provisioner.prepare_command))
82
- conn.execute(env_cmd(provisioner.run_command))
83
- end
84
- rescue Kitchen::Transport::TransportFailed => ex
85
- raise ActionFailed, ex.message
86
- ensure
87
- instance.provisioner.cleanup_sandbox
88
- end
89
-
90
- # (see Base#setup)
91
- def setup(state)
92
- verifier = instance.verifier
93
-
94
- instance.transport.connection(backcompat_merged_state(state)) do |conn|
95
- conn.execute(env_cmd(verifier.install_command))
96
- end
97
- rescue Kitchen::Transport::TransportFailed => ex
98
- raise ActionFailed, ex.message
99
- end
100
-
101
- # (see Base#verify)
102
- def verify(state) # rubocop:disable Metrics/AbcSize
103
- verifier = instance.verifier
104
- verifier.create_sandbox
105
- sandbox_dirs = Dir.glob(File.join(verifier.sandbox_path, "*"))
106
-
107
- instance.transport.connection(backcompat_merged_state(state)) do |conn|
108
- conn.execute(env_cmd(verifier.init_command))
109
- info("Transferring files to #{instance.to_str}")
110
- conn.upload(sandbox_dirs, verifier[:root_path])
111
- debug("Transfer complete")
112
- conn.execute(env_cmd(verifier.prepare_command))
113
- conn.execute(env_cmd(verifier.run_command))
114
- end
115
- rescue Kitchen::Transport::TransportFailed => ex
116
- raise ActionFailed, ex.message
117
- ensure
118
- instance.verifier.cleanup_sandbox
119
- end
120
-
121
- # (see Base#destroy)
122
- def destroy(state) # rubocop:disable Lint/UnusedMethodArgument
123
- raise ClientError, "#{self.class}#destroy must be implemented"
124
- end
125
-
126
- def legacy_state(state)
127
- backcompat_merged_state(state)
128
- end
129
-
130
- # (see Base#login_command)
131
- def login_command(state)
132
- instance.transport.connection(backcompat_merged_state(state)).
133
- login_command
134
- end
135
-
136
- # Executes an arbitrary command on an instance over an SSH connection.
137
- #
138
- # @param state [Hash] mutable instance and driver state
139
- # @param command [String] the command to be executed
140
- # @raise [ActionFailed] if the command could not be successfully completed
141
- def remote_command(state, command)
142
- instance.transport.connection(backcompat_merged_state(state)) do |conn|
143
- conn.execute(env_cmd(command))
144
- end
145
- end
146
-
147
- # **(Deprecated)** Executes a remote command over SSH.
148
- #
149
- # @param ssh_args [Array] ssh arguments
150
- # @param command [String] remote command to invoke
151
- # @deprecated This method should no longer be called directly and exists
152
- # to support very old drivers. This will be removed in the future.
153
- def ssh(ssh_args, command)
154
- pseudo_state = { :hostname => ssh_args[0], :username => ssh_args[1] }
155
- pseudo_state.merge!(ssh_args[2])
156
- connection_state = backcompat_merged_state(pseudo_state)
157
-
158
- instance.transport.connection(connection_state) do |conn|
159
- conn.execute(env_cmd(command))
160
- end
161
- end
162
-
163
- # Performs whatever tests that may be required to ensure that this driver
164
- # will be able to function in the current environment. This may involve
165
- # checking for the presence of certain directories, software installed,
166
- # etc.
167
- #
168
- # @raise [UserError] if the driver will not be able to perform or if a
169
- # documented dependency is missing from the system
170
- def verify_dependencies
171
- end
172
-
173
- class << self
174
- # @return [Array<Symbol>] an array of action method names that cannot
175
- # be run concurrently and must be run in serial via a shared mutex
176
- attr_reader :serial_actions
177
- end
178
-
179
- # Registers certain driver actions that cannot be safely run concurrently
180
- # in threads across multiple instances. Typically this might be used
181
- # for create or destroy actions that use an underlying resource that
182
- # cannot be used at the same time.
183
- #
184
- # A shared mutex for this driver object will be used to synchronize all
185
- # registered methods.
186
- #
187
- # @example a single action method that cannot be run concurrently
188
- #
189
- # no_parallel_for :create
190
- #
191
- # @example multiple action methods that cannot be run concurrently
192
- #
193
- # no_parallel_for :create, :destroy
194
- #
195
- # @param methods [Array<Symbol>] one or more actions as symbols
196
- # @raise [ClientError] if any method is not a valid action method name
197
- def self.no_parallel_for(*methods)
198
- action_methods = [:create, :converge, :setup, :verify, :destroy]
199
-
200
- Array(methods).each do |meth|
201
- next if action_methods.include?(meth)
202
-
203
- raise ClientError, "##{meth} is not a valid no_parallel_for method"
204
- end
205
-
206
- @serial_actions ||= []
207
- @serial_actions += methods
208
- end
209
-
210
- private
211
-
212
- def backcompat_merged_state(state)
213
- driver_ssh_keys = %w[
214
- forward_agent hostname password port ssh_key username
215
- ].map(&:to_sym)
216
- config.select { |key, _| driver_ssh_keys.include?(key) }.rmerge(state)
217
- end
218
-
219
- # Builds arguments for constructing a `Kitchen::SSH` instance.
220
- #
221
- # @param state [Hash] state hash
222
- # @return [Array] SSH constructor arguments
223
- # @api private
224
- def build_ssh_args(state)
225
- combined = config.to_hash.merge(state)
226
-
227
- opts = Hash.new
228
- opts[:user_known_hosts_file] = "/dev/null"
229
- opts[:paranoid] = false
230
- opts[:keys_only] = true if combined[:ssh_key]
231
- opts[:password] = combined[:password] if combined[:password]
232
- opts[:forward_agent] = combined[:forward_agent] if combined.key? :forward_agent
233
- opts[:port] = combined[:port] if combined[:port]
234
- opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
235
- opts[:logger] = logger
236
-
237
- [combined[:hostname], combined[:username], opts]
238
- end
239
-
240
- # Adds http, https and ftp proxy environment variables to a command, if
241
- # set in configuration data or on local workstation.
242
- #
243
- # @param cmd [String] command string
244
- # @return [String] command string
245
- # @api private
246
- # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
247
- def env_cmd(cmd)
248
- return if cmd.nil?
249
- env = "env"
250
- http_proxy = config[:http_proxy] || ENV["http_proxy"] ||
251
- ENV["HTTP_PROXY"]
252
- https_proxy = config[:https_proxy] || ENV["https_proxy"] ||
253
- ENV["HTTPS_PROXY"]
254
- ftp_proxy = config[:ftp_proxy] || ENV["ftp_proxy"] ||
255
- ENV["FTP_PROXY"]
256
- no_proxy = if (!config[:http_proxy] && http_proxy) ||
257
- (!config[:https_proxy] && https_proxy) ||
258
- (!config[:ftp_proxy] && ftp_proxy)
259
- ENV["no_proxy"] || ENV["NO_PROXY"]
260
- end
261
- env << " http_proxy=#{http_proxy}" if http_proxy
262
- env << " https_proxy=#{https_proxy}" if https_proxy
263
- env << " ftp_proxy=#{ftp_proxy}" if ftp_proxy
264
- env << " no_proxy=#{no_proxy}" if no_proxy
265
-
266
- env == "env" ? cmd : "#{env} #{cmd}"
267
- end
268
-
269
- # Executes a remote command over SSH.
270
- #
271
- # @param command [String] remove command to run
272
- # @param connection [Kitchen::SSH] an SSH connection
273
- # @raise [ActionFailed] if an exception occurs
274
- # @api private
275
- def run_remote(command, connection)
276
- return if command.nil?
277
-
278
- connection.exec(env_cmd(command))
279
- rescue SSHFailed, Net::SSH::Exception => ex
280
- raise ActionFailed, ex.message
281
- end
282
-
283
- # Transfers one or more local paths over SSH.
284
- #
285
- # @param locals [Array<String>] array of local paths
286
- # @param remote [String] remote destination path
287
- # @param connection [Kitchen::SSH] an SSH connection
288
- # @raise [ActionFailed] if an exception occurs
289
- # @api private
290
- def transfer_path(locals, remote, connection)
291
- return if locals.nil? || Array(locals).empty?
292
-
293
- info("Transferring files to #{instance.to_str}")
294
- locals.each { |local| connection.upload_path!(local, remote) }
295
- debug("Transfer complete")
296
- rescue SSHFailed, Net::SSH::Exception => ex
297
- raise ActionFailed, ex.message
298
- end
299
-
300
- # Blocks until a TCP socket is available where a remote SSH server
301
- # should be listening.
302
- #
303
- # @param hostname [String] remote SSH server host
304
- # @param username [String] SSH username (default: `nil`)
305
- # @param options [Hash] configuration hash (default: `{}`)
306
- # @api private
307
- def wait_for_sshd(hostname, username = nil, options = {})
308
- pseudo_state = { :hostname => hostname }
309
- pseudo_state[:username] = username if username
310
- pseudo_state.merge!(options)
311
-
312
- instance.transport.connection(backcompat_merged_state(pseudo_state)).
313
- wait_until_ready
314
- end
315
-
316
- # Intercepts any bare #puts calls in subclasses and issues an INFO log
317
- # event instead.
318
- #
319
- # @param msg [String] message string
320
- def puts(msg)
321
- info(msg)
322
- end
323
-
324
- # Intercepts any bare #print calls in subclasses and issues an INFO log
325
- # event instead.
326
- #
327
- # @param msg [String] message string
328
- def print(msg)
329
- info(msg)
330
- end
331
-
332
- # Delegates to Kitchen::ShellOut.run_command, overriding some default
333
- # options:
334
- #
335
- # * `:use_sudo` defaults to the value of `config[:use_sudo]` in the
336
- # Driver object
337
- # * `:log_subject` defaults to a String representation of the Driver's
338
- # class name
339
- #
340
- # @see ShellOut#run_command
341
- def run_command(cmd, options = {})
342
- base_options = {
343
- :use_sudo => config[:use_sudo],
344
- :log_subject => Thor::Util.snake_case(self.class.to_s)
345
- }.merge(options)
346
- super(cmd, base_options)
347
- end
348
-
349
- # Returns the Busser object associated with the driver.
350
- #
351
- # @return [Busser] a busser
352
- def busser
353
- instance.verifier
354
- end
355
- end
356
- end
357
- 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/util"
20
+
21
+ require "kitchen/lazy_hash"
22
+
23
+ module Kitchen
24
+
25
+ module Driver
26
+
27
+ # Legacy base class for a driver that uses SSH to communication with an
28
+ # instance. This class has been updated to use the Instance's Transport to
29
+ # issue commands and transfer files and no longer uses the `Kitchen:SSH`
30
+ # class directly.
31
+ #
32
+ # **NOTE:** Authors of new Drivers are encouraged to inherit from
33
+ # `Kitchen::Driver::Base` instead and existing Driver authors are
34
+ # encouraged to update their Driver class to inherit from
35
+ # `Kitchen::Driver::SSHBase`.
36
+ #
37
+ # A subclass must implement the following methods:
38
+ # * #create(state)
39
+ # * #destroy(state)
40
+ #
41
+ # @author Fletcher Nichol <fnichol@nichol.ca>
42
+ # @deprecated While all possible effort has been made to preserve the
43
+ # original behavior of this class, future improvements to the Driver,
44
+ # Transport, and Verifier subsystems may not be picked up in these
45
+ # Drivers. When legacy Driver::SSHBase support is removed, this class
46
+ # will no longer be available.
47
+ class SSHBase
48
+
49
+ include ShellOut
50
+ include Configurable
51
+ include Logging
52
+
53
+ default_config :sudo, true
54
+ default_config :port, 22
55
+
56
+ # Creates a new Driver object using the provided configuration data
57
+ # which will be merged with any default configuration.
58
+ #
59
+ # @param config [Hash] provided driver configuration
60
+ def initialize(config = {})
61
+ init_config(config)
62
+ end
63
+
64
+ # (see Base#create)
65
+ def create(state) # rubocop:disable Lint/UnusedMethodArgument
66
+ raise ClientError, "#{self.class}#create must be implemented"
67
+ end
68
+
69
+ # (see Base#converge)
70
+ def converge(state) # rubocop:disable Metrics/AbcSize
71
+ provisioner = instance.provisioner
72
+ provisioner.create_sandbox
73
+ sandbox_dirs = Dir.glob("#{provisioner.sandbox_path}/*")
74
+
75
+ instance.transport.connection(backcompat_merged_state(state)) do |conn|
76
+ conn.execute(env_cmd(provisioner.install_command))
77
+ conn.execute(env_cmd(provisioner.init_command))
78
+ info("Transferring files to #{instance.to_str}")
79
+ conn.upload(sandbox_dirs, provisioner[:root_path])
80
+ debug("Transfer complete")
81
+ conn.execute(env_cmd(provisioner.prepare_command))
82
+ conn.execute(env_cmd(provisioner.run_command))
83
+ end
84
+ rescue Kitchen::Transport::TransportFailed => ex
85
+ raise ActionFailed, ex.message
86
+ ensure
87
+ instance.provisioner.cleanup_sandbox
88
+ end
89
+
90
+ # (see Base#setup)
91
+ def setup(state)
92
+ verifier = instance.verifier
93
+
94
+ instance.transport.connection(backcompat_merged_state(state)) do |conn|
95
+ conn.execute(env_cmd(verifier.install_command))
96
+ end
97
+ rescue Kitchen::Transport::TransportFailed => ex
98
+ raise ActionFailed, ex.message
99
+ end
100
+
101
+ # (see Base#verify)
102
+ def verify(state) # rubocop:disable Metrics/AbcSize
103
+ verifier = instance.verifier
104
+ verifier.create_sandbox
105
+ sandbox_dirs = Dir.glob(File.join(verifier.sandbox_path, "*"))
106
+
107
+ instance.transport.connection(backcompat_merged_state(state)) do |conn|
108
+ conn.execute(env_cmd(verifier.init_command))
109
+ info("Transferring files to #{instance.to_str}")
110
+ conn.upload(sandbox_dirs, verifier[:root_path])
111
+ debug("Transfer complete")
112
+ conn.execute(env_cmd(verifier.prepare_command))
113
+ conn.execute(env_cmd(verifier.run_command))
114
+ end
115
+ rescue Kitchen::Transport::TransportFailed => ex
116
+ raise ActionFailed, ex.message
117
+ ensure
118
+ instance.verifier.cleanup_sandbox
119
+ end
120
+
121
+ # (see Base#destroy)
122
+ def destroy(state) # rubocop:disable Lint/UnusedMethodArgument
123
+ raise ClientError, "#{self.class}#destroy must be implemented"
124
+ end
125
+
126
+ def legacy_state(state)
127
+ backcompat_merged_state(state)
128
+ end
129
+
130
+ # (see Base#login_command)
131
+ def login_command(state)
132
+ instance.transport.connection(backcompat_merged_state(state)).
133
+ login_command
134
+ end
135
+
136
+ # Executes an arbitrary command on an instance over an SSH connection.
137
+ #
138
+ # @param state [Hash] mutable instance and driver state
139
+ # @param command [String] the command to be executed
140
+ # @raise [ActionFailed] if the command could not be successfully completed
141
+ def remote_command(state, command)
142
+ instance.transport.connection(backcompat_merged_state(state)) do |conn|
143
+ conn.execute(env_cmd(command))
144
+ end
145
+ end
146
+
147
+ # **(Deprecated)** Executes a remote command over SSH.
148
+ #
149
+ # @param ssh_args [Array] ssh arguments
150
+ # @param command [String] remote command to invoke
151
+ # @deprecated This method should no longer be called directly and exists
152
+ # to support very old drivers. This will be removed in the future.
153
+ def ssh(ssh_args, command)
154
+ pseudo_state = { :hostname => ssh_args[0], :username => ssh_args[1] }
155
+ pseudo_state.merge!(ssh_args[2])
156
+ connection_state = backcompat_merged_state(pseudo_state)
157
+
158
+ instance.transport.connection(connection_state) do |conn|
159
+ conn.execute(env_cmd(command))
160
+ end
161
+ end
162
+
163
+ # Performs whatever tests that may be required to ensure that this driver
164
+ # will be able to function in the current environment. This may involve
165
+ # checking for the presence of certain directories, software installed,
166
+ # etc.
167
+ #
168
+ # @raise [UserError] if the driver will not be able to perform or if a
169
+ # documented dependency is missing from the system
170
+ def verify_dependencies
171
+ end
172
+
173
+ class << self
174
+ # @return [Array<Symbol>] an array of action method names that cannot
175
+ # be run concurrently and must be run in serial via a shared mutex
176
+ attr_reader :serial_actions
177
+ end
178
+
179
+ # Registers certain driver actions that cannot be safely run concurrently
180
+ # in threads across multiple instances. Typically this might be used
181
+ # for create or destroy actions that use an underlying resource that
182
+ # cannot be used at the same time.
183
+ #
184
+ # A shared mutex for this driver object will be used to synchronize all
185
+ # registered methods.
186
+ #
187
+ # @example a single action method that cannot be run concurrently
188
+ #
189
+ # no_parallel_for :create
190
+ #
191
+ # @example multiple action methods that cannot be run concurrently
192
+ #
193
+ # no_parallel_for :create, :destroy
194
+ #
195
+ # @param methods [Array<Symbol>] one or more actions as symbols
196
+ # @raise [ClientError] if any method is not a valid action method name
197
+ def self.no_parallel_for(*methods)
198
+ action_methods = [:create, :converge, :setup, :verify, :destroy]
199
+
200
+ Array(methods).each do |meth|
201
+ next if action_methods.include?(meth)
202
+
203
+ raise ClientError, "##{meth} is not a valid no_parallel_for method"
204
+ end
205
+
206
+ @serial_actions ||= []
207
+ @serial_actions += methods
208
+ end
209
+
210
+ private
211
+
212
+ def backcompat_merged_state(state)
213
+ driver_ssh_keys = %w[
214
+ forward_agent hostname password port ssh_key username
215
+ ].map(&:to_sym)
216
+ config.select { |key, _| driver_ssh_keys.include?(key) }.rmerge(state)
217
+ end
218
+
219
+ # Builds arguments for constructing a `Kitchen::SSH` instance.
220
+ #
221
+ # @param state [Hash] state hash
222
+ # @return [Array] SSH constructor arguments
223
+ # @api private
224
+ def build_ssh_args(state)
225
+ combined = config.to_hash.merge(state)
226
+
227
+ opts = Hash.new
228
+ opts[:user_known_hosts_file] = "/dev/null"
229
+ opts[:paranoid] = false
230
+ opts[:keys_only] = true if combined[:ssh_key]
231
+ opts[:password] = combined[:password] if combined[:password]
232
+ opts[:forward_agent] = combined[:forward_agent] if combined.key? :forward_agent
233
+ opts[:port] = combined[:port] if combined[:port]
234
+ opts[:keys] = Array(combined[:ssh_key]) if combined[:ssh_key]
235
+ opts[:logger] = logger
236
+
237
+ [combined[:hostname], combined[:username], opts]
238
+ end
239
+
240
+ # Adds http, https and ftp proxy environment variables to a command, if
241
+ # set in configuration data or on local workstation.
242
+ #
243
+ # @param cmd [String] command string
244
+ # @return [String] command string
245
+ # @api private
246
+ # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
247
+ def env_cmd(cmd)
248
+ return if cmd.nil?
249
+ env = "env"
250
+ http_proxy = config[:http_proxy] || ENV["http_proxy"] ||
251
+ ENV["HTTP_PROXY"]
252
+ https_proxy = config[:https_proxy] || ENV["https_proxy"] ||
253
+ ENV["HTTPS_PROXY"]
254
+ ftp_proxy = config[:ftp_proxy] || ENV["ftp_proxy"] ||
255
+ ENV["FTP_PROXY"]
256
+ no_proxy = if (!config[:http_proxy] && http_proxy) ||
257
+ (!config[:https_proxy] && https_proxy) ||
258
+ (!config[:ftp_proxy] && ftp_proxy)
259
+ ENV["no_proxy"] || ENV["NO_PROXY"]
260
+ end
261
+ env << " http_proxy=#{http_proxy}" if http_proxy
262
+ env << " https_proxy=#{https_proxy}" if https_proxy
263
+ env << " ftp_proxy=#{ftp_proxy}" if ftp_proxy
264
+ env << " no_proxy=#{no_proxy}" if no_proxy
265
+
266
+ env == "env" ? cmd : "#{env} #{cmd}"
267
+ end
268
+
269
+ # Executes a remote command over SSH.
270
+ #
271
+ # @param command [String] remove command to run
272
+ # @param connection [Kitchen::SSH] an SSH connection
273
+ # @raise [ActionFailed] if an exception occurs
274
+ # @api private
275
+ def run_remote(command, connection)
276
+ return if command.nil?
277
+
278
+ connection.exec(env_cmd(command))
279
+ rescue SSHFailed, Net::SSH::Exception => ex
280
+ raise ActionFailed, ex.message
281
+ end
282
+
283
+ # Transfers one or more local paths over SSH.
284
+ #
285
+ # @param locals [Array<String>] array of local paths
286
+ # @param remote [String] remote destination path
287
+ # @param connection [Kitchen::SSH] an SSH connection
288
+ # @raise [ActionFailed] if an exception occurs
289
+ # @api private
290
+ def transfer_path(locals, remote, connection)
291
+ return if locals.nil? || Array(locals).empty?
292
+
293
+ info("Transferring files to #{instance.to_str}")
294
+ locals.each { |local| connection.upload_path!(local, remote) }
295
+ debug("Transfer complete")
296
+ rescue SSHFailed, Net::SSH::Exception => ex
297
+ raise ActionFailed, ex.message
298
+ end
299
+
300
+ # Blocks until a TCP socket is available where a remote SSH server
301
+ # should be listening.
302
+ #
303
+ # @param hostname [String] remote SSH server host
304
+ # @param username [String] SSH username (default: `nil`)
305
+ # @param options [Hash] configuration hash (default: `{}`)
306
+ # @api private
307
+ def wait_for_sshd(hostname, username = nil, options = {})
308
+ pseudo_state = { :hostname => hostname }
309
+ pseudo_state[:username] = username if username
310
+ pseudo_state.merge!(options)
311
+
312
+ instance.transport.connection(backcompat_merged_state(pseudo_state)).
313
+ wait_until_ready
314
+ end
315
+
316
+ # Intercepts any bare #puts calls in subclasses and issues an INFO log
317
+ # event instead.
318
+ #
319
+ # @param msg [String] message string
320
+ def puts(msg)
321
+ info(msg)
322
+ end
323
+
324
+ # Intercepts any bare #print calls in subclasses and issues an INFO log
325
+ # event instead.
326
+ #
327
+ # @param msg [String] message string
328
+ def print(msg)
329
+ info(msg)
330
+ end
331
+
332
+ # Delegates to Kitchen::ShellOut.run_command, overriding some default
333
+ # options:
334
+ #
335
+ # * `:use_sudo` defaults to the value of `config[:use_sudo]` in the
336
+ # Driver object
337
+ # * `:log_subject` defaults to a String representation of the Driver's
338
+ # class name
339
+ #
340
+ # @see ShellOut#run_command
341
+ def run_command(cmd, options = {})
342
+ base_options = {
343
+ :use_sudo => config[:use_sudo],
344
+ :log_subject => Thor::Util.snake_case(self.class.to_s)
345
+ }.merge(options)
346
+ super(cmd, base_options)
347
+ end
348
+
349
+ # Returns the Busser object associated with the driver.
350
+ #
351
+ # @return [Busser] a busser
352
+ def busser
353
+ instance.verifier
354
+ end
355
+ end
356
+ end
357
+ end