test-kitchen 1.6.0 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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