test-kitchen 1.7.0 → 1.7.1.dev

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