knife 18.6.13 → 18.7.9

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 (673) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +23 -23
  3. data/LICENSE +201 -201
  4. data/Rakefile +33 -33
  5. data/bin/knife +24 -24
  6. data/knife.gemspec +65 -65
  7. data/lib/chef/application/knife.rb +237 -237
  8. data/lib/chef/chef_fs/knife.rb +162 -162
  9. data/lib/chef/knife/acl_add.rb +57 -57
  10. data/lib/chef/knife/acl_base.rb +183 -183
  11. data/lib/chef/knife/acl_bulk_add.rb +78 -78
  12. data/lib/chef/knife/acl_bulk_remove.rb +83 -83
  13. data/lib/chef/knife/acl_remove.rb +62 -62
  14. data/lib/chef/knife/acl_show.rb +56 -56
  15. data/lib/chef/knife/bootstrap/chef_vault_handler.rb +160 -160
  16. data/lib/chef/knife/bootstrap/client_builder.rb +212 -212
  17. data/lib/chef/knife/bootstrap/templates/README.md +11 -11
  18. data/lib/chef/knife/bootstrap/templates/chef-full.erb +249 -249
  19. data/lib/chef/knife/bootstrap/templates/windows-chef-client-msi.erb +278 -278
  20. data/lib/chef/knife/bootstrap/train_connector.rb +334 -334
  21. data/lib/chef/knife/bootstrap.rb +1229 -1224
  22. data/lib/chef/knife/client_bulk_delete.rb +104 -104
  23. data/lib/chef/knife/client_create.rb +140 -140
  24. data/lib/chef/knife/client_delete.rb +62 -62
  25. data/lib/chef/knife/client_edit.rb +52 -52
  26. data/lib/chef/knife/client_key_create.rb +73 -73
  27. data/lib/chef/knife/client_key_delete.rb +80 -80
  28. data/lib/chef/knife/client_key_edit.rb +83 -83
  29. data/lib/chef/knife/client_key_list.rb +73 -73
  30. data/lib/chef/knife/client_key_show.rb +80 -80
  31. data/lib/chef/knife/client_list.rb +41 -41
  32. data/lib/chef/knife/client_reregister.rb +58 -58
  33. data/lib/chef/knife/client_show.rb +48 -48
  34. data/lib/chef/knife/config_get.rb +39 -39
  35. data/lib/chef/knife/config_get_profile.rb +37 -37
  36. data/lib/chef/knife/config_list.rb +139 -139
  37. data/lib/chef/knife/config_list_profiles.rb +37 -37
  38. data/lib/chef/knife/config_show.rb +127 -127
  39. data/lib/chef/knife/config_use.rb +61 -61
  40. data/lib/chef/knife/config_use_profile.rb +47 -47
  41. data/lib/chef/knife/configure.rb +150 -150
  42. data/lib/chef/knife/configure_client.rb +48 -48
  43. data/lib/chef/knife/cookbook_bulk_delete.rb +71 -71
  44. data/lib/chef/knife/cookbook_delete.rb +151 -151
  45. data/lib/chef/knife/cookbook_download.rb +142 -142
  46. data/lib/chef/knife/cookbook_list.rb +47 -47
  47. data/lib/chef/knife/cookbook_metadata.rb +106 -106
  48. data/lib/chef/knife/cookbook_metadata_from_file.rb +49 -49
  49. data/lib/chef/knife/cookbook_show.rb +98 -98
  50. data/lib/chef/knife/cookbook_upload.rb +313 -313
  51. data/lib/chef/knife/core/bootstrap_context.rb +274 -274
  52. data/lib/chef/knife/core/cookbook_scm_repo.rb +159 -159
  53. data/lib/chef/knife/core/cookbook_site_streaming_uploader.rb +249 -249
  54. data/lib/chef/knife/core/formatting_options.rb +49 -49
  55. data/lib/chef/knife/core/gem_glob_loader.rb +134 -134
  56. data/lib/chef/knife/core/generic_presenter.rb +238 -238
  57. data/lib/chef/knife/core/hashed_command_loader.rb +100 -100
  58. data/lib/chef/knife/core/node_editor.rb +130 -130
  59. data/lib/chef/knife/core/node_presenter.rb +133 -133
  60. data/lib/chef/knife/core/object_loader.rb +115 -115
  61. data/lib/chef/knife/core/status_presenter.rb +147 -147
  62. data/lib/chef/knife/core/subcommand_loader.rb +208 -208
  63. data/lib/chef/knife/core/text_formatter.rb +85 -85
  64. data/lib/chef/knife/core/ui.rb +339 -339
  65. data/lib/chef/knife/core/windows_bootstrap_context.rb +441 -443
  66. data/lib/chef/knife/data_bag_create.rb +81 -81
  67. data/lib/chef/knife/data_bag_delete.rb +49 -49
  68. data/lib/chef/knife/data_bag_edit.rb +74 -74
  69. data/lib/chef/knife/data_bag_from_file.rb +113 -113
  70. data/lib/chef/knife/data_bag_list.rb +42 -42
  71. data/lib/chef/knife/data_bag_secret_options.rb +122 -122
  72. data/lib/chef/knife/data_bag_show.rb +69 -69
  73. data/lib/chef/knife/delete.rb +125 -125
  74. data/lib/chef/knife/deps.rb +156 -156
  75. data/lib/chef/knife/diff.rb +83 -83
  76. data/lib/chef/knife/download.rb +85 -85
  77. data/lib/chef/knife/edit.rb +88 -88
  78. data/lib/chef/knife/environment_compare.rb +128 -128
  79. data/lib/chef/knife/environment_create.rb +52 -52
  80. data/lib/chef/knife/environment_delete.rb +44 -44
  81. data/lib/chef/knife/environment_edit.rb +44 -44
  82. data/lib/chef/knife/environment_from_file.rb +84 -84
  83. data/lib/chef/knife/environment_list.rb +41 -41
  84. data/lib/chef/knife/environment_show.rb +47 -47
  85. data/lib/chef/knife/exec.rb +99 -99
  86. data/lib/chef/knife/group_add.rb +55 -55
  87. data/lib/chef/knife/group_create.rb +49 -49
  88. data/lib/chef/knife/group_destroy.rb +53 -53
  89. data/lib/chef/knife/group_list.rb +43 -43
  90. data/lib/chef/knife/group_remove.rb +56 -56
  91. data/lib/chef/knife/group_show.rb +49 -49
  92. data/lib/chef/knife/key_create.rb +112 -112
  93. data/lib/chef/knife/key_create_base.rb +50 -50
  94. data/lib/chef/knife/key_delete.rb +55 -55
  95. data/lib/chef/knife/key_edit.rb +118 -118
  96. data/lib/chef/knife/key_edit_base.rb +55 -55
  97. data/lib/chef/knife/key_list.rb +90 -90
  98. data/lib/chef/knife/key_list_base.rb +45 -45
  99. data/lib/chef/knife/key_show.rb +53 -53
  100. data/lib/chef/knife/license.rb +52 -52
  101. data/lib/chef/knife/list.rb +177 -177
  102. data/lib/chef/knife/node_bulk_delete.rb +75 -75
  103. data/lib/chef/knife/node_create.rb +47 -47
  104. data/lib/chef/knife/node_delete.rb +46 -46
  105. data/lib/chef/knife/node_edit.rb +70 -70
  106. data/lib/chef/knife/node_environment_set.rb +53 -53
  107. data/lib/chef/knife/node_from_file.rb +51 -51
  108. data/lib/chef/knife/node_list.rb +44 -44
  109. data/lib/chef/knife/node_policy_set.rb +79 -79
  110. data/lib/chef/knife/node_run_list_add.rb +104 -104
  111. data/lib/chef/knife/node_run_list_remove.rb +67 -67
  112. data/lib/chef/knife/node_run_list_set.rb +66 -66
  113. data/lib/chef/knife/node_show.rb +63 -63
  114. data/lib/chef/knife/null.rb +12 -12
  115. data/lib/chef/knife/org_create.rb +70 -70
  116. data/lib/chef/knife/org_delete.rb +32 -32
  117. data/lib/chef/knife/org_edit.rb +48 -48
  118. data/lib/chef/knife/org_list.rb +44 -44
  119. data/lib/chef/knife/org_show.rb +31 -31
  120. data/lib/chef/knife/org_user_add.rb +62 -62
  121. data/lib/chef/knife/org_user_remove.rb +103 -103
  122. data/lib/chef/knife/raw.rb +123 -123
  123. data/lib/chef/knife/recipe_list.rb +32 -32
  124. data/lib/chef/knife/rehash.rb +50 -50
  125. data/lib/chef/knife/role_bulk_delete.rb +66 -66
  126. data/lib/chef/knife/role_create.rb +53 -53
  127. data/lib/chef/knife/role_delete.rb +46 -46
  128. data/lib/chef/knife/role_edit.rb +45 -45
  129. data/lib/chef/knife/role_env_run_list_add.rb +87 -87
  130. data/lib/chef/knife/role_env_run_list_clear.rb +55 -55
  131. data/lib/chef/knife/role_env_run_list_remove.rb +57 -57
  132. data/lib/chef/knife/role_env_run_list_replace.rb +60 -60
  133. data/lib/chef/knife/role_env_run_list_set.rb +70 -70
  134. data/lib/chef/knife/role_from_file.rb +51 -51
  135. data/lib/chef/knife/role_list.rb +42 -42
  136. data/lib/chef/knife/role_run_list_add.rb +87 -87
  137. data/lib/chef/knife/role_run_list_clear.rb +55 -55
  138. data/lib/chef/knife/role_run_list_remove.rb +56 -56
  139. data/lib/chef/knife/role_run_list_replace.rb +60 -60
  140. data/lib/chef/knife/role_run_list_set.rb +69 -69
  141. data/lib/chef/knife/role_show.rb +48 -48
  142. data/lib/chef/knife/search.rb +194 -194
  143. data/lib/chef/knife/serve.rb +65 -65
  144. data/lib/chef/knife/show.rb +72 -72
  145. data/lib/chef/knife/ssh.rb +657 -657
  146. data/lib/chef/knife/ssl_check.rb +284 -284
  147. data/lib/chef/knife/ssl_fetch.rb +162 -162
  148. data/lib/chef/knife/status.rb +95 -95
  149. data/lib/chef/knife/supermarket_download.rb +119 -119
  150. data/lib/chef/knife/supermarket_install.rb +192 -192
  151. data/lib/chef/knife/supermarket_list.rb +76 -76
  152. data/lib/chef/knife/supermarket_search.rb +53 -53
  153. data/lib/chef/knife/supermarket_share.rb +166 -166
  154. data/lib/chef/knife/supermarket_show.rb +66 -66
  155. data/lib/chef/knife/supermarket_unshare.rb +62 -62
  156. data/lib/chef/knife/tag_create.rb +52 -52
  157. data/lib/chef/knife/tag_delete.rb +60 -60
  158. data/lib/chef/knife/tag_list.rb +47 -47
  159. data/lib/chef/knife/upload.rb +87 -87
  160. data/lib/chef/knife/user_create.rb +180 -180
  161. data/lib/chef/knife/user_delete.rb +151 -151
  162. data/lib/chef/knife/user_dissociate.rb +42 -42
  163. data/lib/chef/knife/user_edit.rb +94 -94
  164. data/lib/chef/knife/user_invite_add.rb +43 -43
  165. data/lib/chef/knife/user_invite_list.rb +34 -34
  166. data/lib/chef/knife/user_invite_rescind.rb +63 -63
  167. data/lib/chef/knife/user_key_create.rb +73 -73
  168. data/lib/chef/knife/user_key_delete.rb +80 -80
  169. data/lib/chef/knife/user_key_edit.rb +83 -83
  170. data/lib/chef/knife/user_key_list.rb +73 -73
  171. data/lib/chef/knife/user_key_show.rb +80 -80
  172. data/lib/chef/knife/user_list.rb +43 -43
  173. data/lib/chef/knife/user_password.rb +70 -70
  174. data/lib/chef/knife/user_reregister.rb +59 -59
  175. data/lib/chef/knife/user_show.rb +52 -52
  176. data/lib/chef/knife/version.rb +24 -24
  177. data/lib/chef/knife/xargs.rb +282 -282
  178. data/lib/chef/knife/yaml_convert.rb +91 -91
  179. data/lib/chef/knife.rb +677 -677
  180. data/lib/chef/utils/licensing_config.rb +9 -9
  181. data/lib/chef/utils/licensing_handler.rb +72 -53
  182. data/spec/data/apt/chef-integration-test-1.0/debian/changelog +5 -5
  183. data/spec/data/apt/chef-integration-test-1.0/debian/compat +1 -1
  184. data/spec/data/apt/chef-integration-test-1.0/debian/control +13 -13
  185. data/spec/data/apt/chef-integration-test-1.0/debian/copyright +34 -34
  186. data/spec/data/apt/chef-integration-test-1.0/debian/files +1 -1
  187. data/spec/data/apt/chef-integration-test-1.0/debian/rules +13 -13
  188. data/spec/data/apt/chef-integration-test-1.0/debian/source/format +1 -1
  189. data/spec/data/apt/chef-integration-test-1.1/debian/changelog +11 -11
  190. data/spec/data/apt/chef-integration-test-1.1/debian/compat +1 -1
  191. data/spec/data/apt/chef-integration-test-1.1/debian/control +13 -13
  192. data/spec/data/apt/chef-integration-test-1.1/debian/copyright +34 -34
  193. data/spec/data/apt/chef-integration-test-1.1/debian/files +1 -1
  194. data/spec/data/apt/chef-integration-test-1.1/debian/rules +13 -13
  195. data/spec/data/apt/chef-integration-test-1.1/debian/source/format +1 -1
  196. data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -5
  197. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -1
  198. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -10
  199. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -1
  200. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -45
  201. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -1
  202. data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -1
  203. data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -1
  204. data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -13
  205. data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -34
  206. data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -1
  207. data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -13
  208. data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -1
  209. data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -18
  210. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -91
  211. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -31
  212. data/spec/data/apt/chef-integration-test_1.0-1_amd64.changes +22 -22
  213. data/spec/data/apt/chef-integration-test_1.1-1_amd64.changes +22 -22
  214. data/spec/data/apt/var/www/apt/conf/distributions +7 -7
  215. data/spec/data/apt/var/www/apt/conf/incoming +4 -4
  216. data/spec/data/apt/var/www/apt/conf/pulls +3 -3
  217. data/spec/data/apt/var/www/apt/db/version +4 -4
  218. data/spec/data/apt/var/www/apt/dists/sid/Release +19 -19
  219. data/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages +16 -16
  220. data/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Release +5 -5
  221. data/spec/data/bootstrap/encrypted_data_bag_secret +1 -1
  222. data/spec/data/bootstrap/no_proxy.erb +2 -2
  223. data/spec/data/bootstrap/secret.erb +9 -9
  224. data/spec/data/bootstrap/test-hints.erb +12 -12
  225. data/spec/data/bootstrap/test.erb +1 -1
  226. data/spec/data/cb_version_cookbooks/tatft/README.rdoc +2 -2
  227. data/spec/data/cb_version_cookbooks/tatft/attributes/default.rb +1 -1
  228. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-600hhz-0 +1 -1
  229. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ahd2gq-0 +1 -1
  230. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-api8ux-0 +1 -1
  231. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-b0r1m1-0 +1 -1
  232. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-bfygsi-0 +1 -1
  233. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-el14l6-0 +1 -1
  234. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ivrl3y-0 +1 -1
  235. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-kkbs85-0 +1 -1
  236. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ory1ux-0 +1 -1
  237. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-pgsq76-0 +1 -1
  238. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ra8uim-0 +1 -1
  239. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t7k1g-0 +1 -1
  240. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t8g0sv-0 +1 -1
  241. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ufy6g3-0 +1 -1
  242. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-x2d6j9-0 +1 -1
  243. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-xi0l6h-0 +1 -1
  244. data/spec/data/client.d_00/00-foo.rb +2 -2
  245. data/spec/data/client.d_00/01-bar.rb +1 -1
  246. data/spec/data/client.d_00/02-strings.rb +2 -2
  247. data/spec/data/client.d_00/bar +1 -1
  248. data/spec/data/client.d_01/foo/bar.rb +1 -1
  249. data/spec/data/client.d_02/foo.rb/foo.txt +1 -1
  250. data/spec/data/config.rb +6 -6
  251. data/spec/data/cookbooks/angrybash/metadata.rb +2 -2
  252. data/spec/data/cookbooks/angrybash/recipes/default.rb +8 -8
  253. data/spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl +2 -2
  254. data/spec/data/cookbooks/apache2/metadata.json +33 -33
  255. data/spec/data/cookbooks/apache2/metadata.rb +2 -2
  256. data/spec/data/cookbooks/apache2/recipes/default.rb +2 -2
  257. data/spec/data/cookbooks/borken/metadata.rb +2 -2
  258. data/spec/data/cookbooks/borken/recipes/default.rb +1 -1
  259. data/spec/data/cookbooks/borken/templates/default/borken.erb +1 -1
  260. data/spec/data/cookbooks/chefignore +8 -8
  261. data/spec/data/cookbooks/ignorken/files/default/not_me.rb +2 -2
  262. data/spec/data/cookbooks/ignorken/metadata.rb +2 -2
  263. data/spec/data/cookbooks/ignorken/recipes/ignoreme.rb +1 -1
  264. data/spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb +2 -2
  265. data/spec/data/cookbooks/irssi/files/default/irssi.response +2 -2
  266. data/spec/data/cookbooks/java/files/default/java.response +1 -1
  267. data/spec/data/cookbooks/java/metadata.json +33 -33
  268. data/spec/data/cookbooks/java/metadata.rb +2 -2
  269. data/spec/data/cookbooks/name-mismatch-versionnumber/README.md +4 -4
  270. data/spec/data/cookbooks/name-mismatch-versionnumber/metadata.rb +8 -8
  271. data/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb +8 -8
  272. data/spec/data/cookbooks/openldap/attributes/default.rb +16 -16
  273. data/spec/data/cookbooks/openldap/attributes/smokey.rb +1 -1
  274. data/spec/data/cookbooks/openldap/definitions/client.rb +5 -5
  275. data/spec/data/cookbooks/openldap/definitions/server.rb +5 -5
  276. data/spec/data/cookbooks/openldap/files/default/.dotfile +1 -1
  277. data/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir +1 -1
  278. data/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb +2 -2
  279. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt +2 -2
  280. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt +2 -2
  281. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile +1 -1
  282. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt +2 -2
  283. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt +2 -2
  284. data/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt +3 -3
  285. data/spec/data/cookbooks/openldap/libraries/openldap/version.rb +3 -3
  286. data/spec/data/cookbooks/openldap/libraries/openldap.rb +4 -4
  287. data/spec/data/cookbooks/openldap/metadata.rb +8 -8
  288. data/spec/data/cookbooks/openldap/recipes/default.rb +4 -4
  289. data/spec/data/cookbooks/openldap/recipes/gigantor.rb +3 -3
  290. data/spec/data/cookbooks/openldap/recipes/one.rb +15 -15
  291. data/spec/data/cookbooks/openldap/recipes/return.rb +2 -2
  292. data/spec/data/cookbooks/openldap/templates/default/helper_test.erb +1 -1
  293. data/spec/data/cookbooks/openldap/templates/default/helpers.erb +14 -14
  294. data/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb +1 -1
  295. data/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb +1 -1
  296. data/spec/data/cookbooks/openldap/templates/default/nested_partial.erb +1 -1
  297. data/spec/data/cookbooks/openldap/templates/default/no_windows_line_endings.erb +4 -4
  298. data/spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb +1 -1
  299. data/spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb +1 -1
  300. data/spec/data/cookbooks/openldap/templates/default/test.erb +1 -1
  301. data/spec/data/cookbooks/preseed/files/default/preseed-file.seed +1 -1
  302. data/spec/data/cookbooks/preseed/files/default/preseed-template.seed +4 -4
  303. data/spec/data/cookbooks/preseed/metadata.rb +2 -2
  304. data/spec/data/cookbooks/preseed/templates/default/preseed-template-variables.seed +1 -1
  305. data/spec/data/cookbooks/preseed/templates/default/preseed-template.seed +1 -1
  306. data/spec/data/cookbooks/starter/chefignore +8 -8
  307. data/spec/data/cookbooks/starter/metadata.rb +2 -2
  308. data/spec/data/cookbooks/starter/recipes/default.rb +4 -4
  309. data/spec/data/cookbooks/supports-platform-constraints/metadata.rb +5 -5
  310. data/spec/data/cookbooks/wget/files/default/wget.response +2 -2
  311. data/spec/data/definitions/test.rb +4 -4
  312. data/spec/data/environment-config.rb +4 -4
  313. data/spec/data/file-providers-method-snapshot-chef-11-4.json +127 -127
  314. data/spec/data/fileedit/hosts +4 -4
  315. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/README.md +4 -4
  316. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/metadata.rb +13 -13
  317. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb +8 -8
  318. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/README.md +4 -4
  319. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb +9 -9
  320. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb +8 -8
  321. data/spec/data/kitchen/chefignore +6 -6
  322. data/spec/data/kitchen/openldap/attributes/default.rb +3 -3
  323. data/spec/data/kitchen/openldap/attributes/robinson.rb +2 -2
  324. data/spec/data/kitchen/openldap/definitions/client.rb +3 -3
  325. data/spec/data/kitchen/openldap/definitions/drewbarrymore.rb +2 -2
  326. data/spec/data/kitchen/openldap/recipes/gigantor.rb +2 -2
  327. data/spec/data/kitchen/openldap/recipes/ignoreme.rb +2 -2
  328. data/spec/data/kitchen/openldap/recipes/woot.rb +3 -3
  329. data/spec/data/knife_subcommand/test_explicit_category.rb +6 -6
  330. data/spec/data/knife_subcommand/test_name_mapping.rb +4 -4
  331. data/spec/data/knife_subcommand/test_yourself.rb +21 -21
  332. data/spec/data/lwrp/providers/buck_passer.rb +28 -28
  333. data/spec/data/lwrp/providers/buck_passer_2.rb +26 -26
  334. data/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb +28 -28
  335. data/spec/data/lwrp/providers/inline_compiler.rb +24 -24
  336. data/spec/data/lwrp/providers/monkey_name_printer.rb +5 -5
  337. data/spec/data/lwrp/providers/paint_drying_watcher.rb +7 -7
  338. data/spec/data/lwrp/providers/thumb_twiddler.rb +7 -7
  339. data/spec/data/lwrp/resources/bar.rb +4 -4
  340. data/spec/data/lwrp/resources/buck_passer.rb +6 -6
  341. data/spec/data/lwrp/resources/buck_passer_2.rb +4 -4
  342. data/spec/data/lwrp/resources/embedded_resource_accesses_providers_scope.rb +4 -4
  343. data/spec/data/lwrp/resources/foo.rb +6 -6
  344. data/spec/data/lwrp/resources/inline_compiler.rb +4 -4
  345. data/spec/data/lwrp/resources/monkey_name_printer.rb +6 -6
  346. data/spec/data/lwrp/resources/paint_drying_watcher.rb +4 -4
  347. data/spec/data/lwrp/resources/thumb_twiddler.rb +4 -4
  348. data/spec/data/lwrp/resources_with_default_attributes/nodeattr.rb +3 -3
  349. data/spec/data/lwrp_const_scoping/resources/conflict.rb +1 -1
  350. data/spec/data/lwrp_override/providers/buck_passer.rb +5 -5
  351. data/spec/data/lwrp_override/resources/foo.rb +11 -11
  352. data/spec/data/mac_users/10.9.plist.xml +560 -560
  353. data/spec/data/mac_users/10.9.shadow.xml +21 -21
  354. data/spec/data/metadata/quick_start/metadata.rb +14 -14
  355. data/spec/data/mixin/invalid_data.rb +3 -3
  356. data/spec/data/mixin/real_data.rb +2 -2
  357. data/spec/data/nested.json +2 -2
  358. data/spec/data/nodes/default.rb +15 -15
  359. data/spec/data/nodes/test.example.com.rb +17 -17
  360. data/spec/data/nodes/test.rb +15 -15
  361. data/spec/data/null_config.rb +1 -1
  362. data/spec/data/object_loader/environments/test.json +7 -7
  363. data/spec/data/object_loader/environments/test.rb +2 -2
  364. data/spec/data/object_loader/environments/test_json_class.json +8 -8
  365. data/spec/data/object_loader/nodes/test.json +7 -7
  366. data/spec/data/object_loader/nodes/test.rb +2 -2
  367. data/spec/data/object_loader/nodes/test_json_class.json +8 -8
  368. data/spec/data/object_loader/roles/test.json +7 -7
  369. data/spec/data/object_loader/roles/test.rb +2 -2
  370. data/spec/data/object_loader/roles/test_json_class.json +8 -8
  371. data/spec/data/partial_one.erb +1 -1
  372. data/spec/data/prefer_metadata_json/metadata.json +51 -51
  373. data/spec/data/prefer_metadata_json/metadata.rb +6 -6
  374. data/spec/data/recipes/test.rb +7 -7
  375. data/spec/data/root_alias_cookbooks/dup_attr/attributes/default.rb +1 -1
  376. data/spec/data/root_alias_cookbooks/dup_attr/attributes.rb +1 -1
  377. data/spec/data/root_alias_cookbooks/dup_attr/metadata.rb +2 -2
  378. data/spec/data/root_alias_cookbooks/dup_attr/recipe.rb +3 -3
  379. data/spec/data/root_alias_cookbooks/dup_recipe/attributes.rb +1 -1
  380. data/spec/data/root_alias_cookbooks/dup_recipe/metadata.rb +2 -2
  381. data/spec/data/root_alias_cookbooks/dup_recipe/recipe.rb +3 -3
  382. data/spec/data/root_alias_cookbooks/dup_recipe/recipes/default.rb +3 -3
  383. data/spec/data/root_alias_cookbooks/simple/attributes.rb +1 -1
  384. data/spec/data/root_alias_cookbooks/simple/metadata.rb +2 -2
  385. data/spec/data/root_alias_cookbooks/simple/recipe.rb +3 -3
  386. data/spec/data/rubygems.org/sexp_processor-info +49 -49
  387. data/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb +2 -2
  388. data/spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb +1 -1
  389. data/spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb +2 -2
  390. data/spec/data/run_context/cookbooks/circular-dep1/metadata.rb +2 -2
  391. data/spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb +1 -1
  392. data/spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb +2 -2
  393. data/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb +2 -2
  394. data/spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb +1 -1
  395. data/spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb +2 -2
  396. data/spec/data/run_context/cookbooks/circular-dep2/metadata.rb +2 -2
  397. data/spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb +1 -1
  398. data/spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb +2 -2
  399. data/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb +2 -2
  400. data/spec/data/run_context/cookbooks/dependency1/attributes/default.rb +2 -2
  401. data/spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file +1 -1
  402. data/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb +2 -2
  403. data/spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb +1 -1
  404. data/spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file +1 -1
  405. data/spec/data/run_context/cookbooks/dependency1/libraries/lib.rb +2 -2
  406. data/spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file +1 -1
  407. data/spec/data/run_context/cookbooks/dependency1/providers/provider.rb +1 -1
  408. data/spec/data/run_context/cookbooks/dependency1/providers/unparsed_file +1 -1
  409. data/spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file +1 -1
  410. data/spec/data/run_context/cookbooks/dependency1/resources/resource.rb +2 -2
  411. data/spec/data/run_context/cookbooks/dependency1/resources/unparsed_file +1 -1
  412. data/spec/data/run_context/cookbooks/dependency2/attributes/default.rb +2 -2
  413. data/spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb +1 -1
  414. data/spec/data/run_context/cookbooks/dependency2/libraries/lib.rb +2 -2
  415. data/spec/data/run_context/cookbooks/dependency2/providers/provider.rb +1 -1
  416. data/spec/data/run_context/cookbooks/dependency2/resources/resource.rb +2 -2
  417. data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -24
  418. data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -3
  419. data/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb +2 -2
  420. data/spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb +1 -1
  421. data/spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb +1 -1
  422. data/spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb +2 -2
  423. data/spec/data/run_context/cookbooks/test/attributes/george.rb +1 -1
  424. data/spec/data/run_context/cookbooks/test/definitions/new_animals.rb +9 -9
  425. data/spec/data/run_context/cookbooks/test/definitions/new_cat.rb +5 -5
  426. data/spec/data/run_context/cookbooks/test/definitions/test_res.rb +1 -1
  427. data/spec/data/run_context/cookbooks/test/providers/provider.rb +1 -1
  428. data/spec/data/run_context/cookbooks/test/recipes/default.rb +5 -5
  429. data/spec/data/run_context/cookbooks/test/recipes/one.rb +7 -7
  430. data/spec/data/run_context/cookbooks/test/recipes/two.rb +7 -7
  431. data/spec/data/run_context/cookbooks/test/resources/resource.rb +3 -3
  432. data/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb +2 -2
  433. data/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rb +1 -1
  434. data/spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb +2 -2
  435. data/spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb +2 -2
  436. data/spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb +1 -1
  437. data/spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb +3 -3
  438. data/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb +2 -2
  439. data/spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb +1 -1
  440. data/spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb +1 -1
  441. data/spec/data/run_context/cookbooks/test-with-deps/metadata.rb +3 -3
  442. data/spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb +1 -1
  443. data/spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb +2 -2
  444. data/spec/data/run_context/nodes/run_context.rb +5 -5
  445. data/spec/data/sample_msu1.xml +10 -10
  446. data/spec/data/sample_msu2.xml +14 -14
  447. data/spec/data/sample_msu3.xml +16 -16
  448. data/spec/data/search_queries_to_transform.txt +98 -98
  449. data/spec/data/shef-config.rb +11 -11
  450. data/spec/data/snap_package/async_result_success.json +6 -6
  451. data/spec/data/snap_package/change_id_result.json +175 -175
  452. data/spec/data/snap_package/find_result_failure.json +10 -10
  453. data/spec/data/snap_package/find_result_success.json +70 -70
  454. data/spec/data/snap_package/get_by_name_result_failure.json +10 -10
  455. data/spec/data/snap_package/get_by_name_result_success.json +38 -38
  456. data/spec/data/snap_package/get_conf_success.json +10 -10
  457. data/spec/data/snap_package/result_failure.json +9 -9
  458. data/spec/data/ssl/5e707473.0 +18 -18
  459. data/spec/data/ssl/chef-rspec.cert +27 -27
  460. data/spec/data/ssl/chef-rspec.key +27 -27
  461. data/spec/data/ssl/key.pem +15 -15
  462. data/spec/data/ssl/private_key.pem +27 -27
  463. data/spec/data/ssl/private_key_with_whitespace.pem +32 -32
  464. data/spec/data/standalone_cookbook/chefignore +9 -9
  465. data/spec/data/standalone_cookbook/recipes/default.rb +2 -2
  466. data/spec/data/templates/failed.erb +5 -5
  467. data/spec/data/trusted_certs/example.crt +22 -22
  468. data/spec/data/trusted_certs/example_no_cn.crt +36 -36
  469. data/spec/data/trusted_certs/intermediate.pem +27 -27
  470. data/spec/data/trusted_certs/opscode.pem +57 -57
  471. data/spec/data/trusted_certs/root.pem +22 -22
  472. data/spec/data/windows_certificates/base64_test.cer +20 -20
  473. data/spec/data/windows_certificates/othertest.cer +20 -20
  474. data/spec/data/windows_certificates/test.cer +20 -20
  475. data/spec/data/windows_certificates/test.pem +20 -20
  476. data/spec/functional/configure_spec.rb +33 -33
  477. data/spec/functional/cookbook_delete_spec.rb +157 -156
  478. data/spec/functional/exec_spec.rb +55 -55
  479. data/spec/functional/rehash_spec.rb +39 -39
  480. data/spec/functional/smoke_test.rb +42 -42
  481. data/spec/functional/ssh_spec.rb +352 -352
  482. data/spec/functional/version_spec.rb +26 -26
  483. data/spec/integration/chef_fs_data_store_spec.rb +557 -557
  484. data/spec/integration/chef_repo_path_spec.rb +962 -962
  485. data/spec/integration/chef_repository_file_system_spec.rb +200 -200
  486. data/spec/integration/chefignore_spec.rb +301 -301
  487. data/spec/integration/client_bulk_delete_spec.rb +131 -131
  488. data/spec/integration/client_create_spec.rb +70 -70
  489. data/spec/integration/client_delete_spec.rb +64 -64
  490. data/spec/integration/client_key_create_spec.rb +66 -66
  491. data/spec/integration/client_key_delete_spec.rb +43 -43
  492. data/spec/integration/client_key_list_spec.rb +61 -61
  493. data/spec/integration/client_key_show_spec.rb +45 -45
  494. data/spec/integration/client_list_spec.rb +49 -49
  495. data/spec/integration/client_show_spec.rb +37 -37
  496. data/spec/integration/commands_spec.rb +55 -55
  497. data/spec/integration/common_options_spec.rb +174 -174
  498. data/spec/integration/config_list_spec.rb +220 -220
  499. data/spec/integration/config_show_spec.rb +192 -192
  500. data/spec/integration/config_use_spec.rb +198 -198
  501. data/spec/integration/cookbook_api_ipv6_spec.rb +113 -113
  502. data/spec/integration/cookbook_bulk_delete_spec.rb +65 -65
  503. data/spec/integration/cookbook_download_spec.rb +72 -72
  504. data/spec/integration/cookbook_list_spec.rb +55 -55
  505. data/spec/integration/cookbook_show_spec.rb +149 -149
  506. data/spec/integration/cookbook_upload_spec.rb +128 -128
  507. data/spec/integration/data_bag_create_spec.rb +125 -125
  508. data/spec/integration/data_bag_delete_spec.rb +59 -59
  509. data/spec/integration/data_bag_edit_spec.rb +105 -105
  510. data/spec/integration/data_bag_from_file_spec.rb +116 -116
  511. data/spec/integration/data_bag_list_spec.rb +44 -44
  512. data/spec/integration/data_bag_show_spec.rb +95 -95
  513. data/spec/integration/delete_spec.rb +1018 -1018
  514. data/spec/integration/deps_spec.rb +703 -703
  515. data/spec/integration/diff_spec.rb +605 -605
  516. data/spec/integration/download_spec.rb +1336 -1336
  517. data/spec/integration/environment_compare_spec.rb +75 -75
  518. data/spec/integration/environment_create_spec.rb +41 -41
  519. data/spec/integration/environment_delete_spec.rb +37 -37
  520. data/spec/integration/environment_from_file_spec.rb +116 -116
  521. data/spec/integration/environment_list_spec.rb +42 -42
  522. data/spec/integration/environment_show_spec.rb +77 -77
  523. data/spec/integration/list_spec.rb +1060 -1060
  524. data/spec/integration/node_bulk_delete_spec.rb +52 -52
  525. data/spec/integration/node_create_spec.rb +47 -47
  526. data/spec/integration/node_delete_spec.rb +48 -48
  527. data/spec/integration/node_environment_set_spec.rb +46 -46
  528. data/spec/integration/node_from_file_spec.rb +59 -59
  529. data/spec/integration/node_list_spec.rb +45 -45
  530. data/spec/integration/node_run_list_add_spec.rb +54 -54
  531. data/spec/integration/node_run_list_remove_spec.rb +36 -36
  532. data/spec/integration/node_run_list_set_spec.rb +41 -41
  533. data/spec/integration/node_show_spec.rb +36 -36
  534. data/spec/integration/raw_spec.rb +297 -297
  535. data/spec/integration/redirection_spec.rb +64 -64
  536. data/spec/integration/role_bulk_delete_spec.rb +52 -52
  537. data/spec/integration/role_create_spec.rb +41 -41
  538. data/spec/integration/role_delete_spec.rb +48 -48
  539. data/spec/integration/role_from_file_spec.rb +96 -96
  540. data/spec/integration/role_list_spec.rb +45 -45
  541. data/spec/integration/role_show_spec.rb +51 -51
  542. data/spec/integration/search_node_spec.rb +40 -40
  543. data/spec/integration/serve_spec.rb +92 -92
  544. data/spec/integration/show_spec.rb +197 -197
  545. data/spec/integration/upload_spec.rb +1616 -1616
  546. data/spec/knife_spec_helper.rb +241 -241
  547. data/spec/support/chef_helpers.rb +79 -79
  548. data/spec/support/key_helpers.rb +102 -102
  549. data/spec/support/platform_helpers.rb +255 -255
  550. data/spec/support/platforms/prof/gc.rb +51 -51
  551. data/spec/support/platforms/prof/win32.rb +45 -45
  552. data/spec/support/platforms/win32/spec_service.rb +57 -57
  553. data/spec/support/recipe_dsl_helper.rb +83 -83
  554. data/spec/support/shared/context/config.rb +18 -18
  555. data/spec/support/shared/functional/knife.rb +37 -37
  556. data/spec/support/shared/integration/integration_helper.rb +122 -122
  557. data/spec/support/shared/integration/knife_support.rb +192 -192
  558. data/spec/support/shared/matchers/exit_with_code.rb +32 -32
  559. data/spec/support/shared/matchers/match_environment_variable.rb +17 -17
  560. data/spec/support/shared/unit/knife_shared.rb +39 -39
  561. data/spec/support/shared/unit/mock_shellout.rb +49 -49
  562. data/spec/tiny_server.rb +193 -190
  563. data/spec/unit/application/knife_spec.rb +241 -241
  564. data/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb +152 -152
  565. data/spec/unit/knife/bootstrap/client_builder_spec.rb +207 -207
  566. data/spec/unit/knife/bootstrap/train_connector_spec.rb +244 -244
  567. data/spec/unit/knife/bootstrap_spec.rb +2311 -2288
  568. data/spec/unit/knife/client_bulk_delete_spec.rb +166 -166
  569. data/spec/unit/knife/client_create_spec.rb +232 -232
  570. data/spec/unit/knife/client_delete_spec.rb +99 -99
  571. data/spec/unit/knife/client_edit_spec.rb +53 -53
  572. data/spec/unit/knife/client_list_spec.rb +34 -34
  573. data/spec/unit/knife/client_reregister_spec.rb +62 -62
  574. data/spec/unit/knife/client_show_spec.rb +52 -52
  575. data/spec/unit/knife/configure_client_spec.rb +81 -81
  576. data/spec/unit/knife/configure_spec.rb +190 -190
  577. data/spec/unit/knife/cookbook_bulk_delete_spec.rb +87 -87
  578. data/spec/unit/knife/cookbook_delete_spec.rb +239 -239
  579. data/spec/unit/knife/cookbook_download_spec.rb +255 -255
  580. data/spec/unit/knife/cookbook_list_spec.rb +88 -88
  581. data/spec/unit/knife/cookbook_metadata_from_file_spec.rb +72 -72
  582. data/spec/unit/knife/cookbook_metadata_spec.rb +182 -182
  583. data/spec/unit/knife/cookbook_show_spec.rb +253 -253
  584. data/spec/unit/knife/cookbook_upload_spec.rb +426 -426
  585. data/spec/unit/knife/core/bootstrap_context_spec.rb +287 -287
  586. data/spec/unit/knife/core/cookbook_scm_repo_spec.rb +187 -187
  587. data/spec/unit/knife/core/cookbook_site_streaming_uploader_spec.rb +198 -198
  588. data/spec/unit/knife/core/gem_glob_loader_spec.rb +242 -242
  589. data/spec/unit/knife/core/hashed_command_loader_spec.rb +112 -112
  590. data/spec/unit/knife/core/node_editor_spec.rb +211 -211
  591. data/spec/unit/knife/core/object_loader_spec.rb +81 -81
  592. data/spec/unit/knife/core/status_presenter_spec.rb +54 -54
  593. data/spec/unit/knife/core/subcommand_loader_spec.rb +64 -64
  594. data/spec/unit/knife/core/ui_spec.rb +656 -656
  595. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +282 -238
  596. data/spec/unit/knife/data_bag_create_spec.rb +175 -175
  597. data/spec/unit/knife/data_bag_edit_spec.rb +126 -126
  598. data/spec/unit/knife/data_bag_from_file_spec.rb +174 -174
  599. data/spec/unit/knife/data_bag_secret_options_spec.rb +173 -173
  600. data/spec/unit/knife/data_bag_show_spec.rb +139 -139
  601. data/spec/unit/knife/environment_compare_spec.rb +112 -112
  602. data/spec/unit/knife/environment_create_spec.rb +91 -91
  603. data/spec/unit/knife/environment_delete_spec.rb +71 -71
  604. data/spec/unit/knife/environment_edit_spec.rb +79 -79
  605. data/spec/unit/knife/environment_from_file_spec.rb +90 -90
  606. data/spec/unit/knife/environment_list_spec.rb +54 -54
  607. data/spec/unit/knife/environment_show_spec.rb +52 -52
  608. data/spec/unit/knife/key_create_spec.rb +223 -223
  609. data/spec/unit/knife/key_delete_spec.rb +133 -133
  610. data/spec/unit/knife/key_edit_spec.rb +264 -264
  611. data/spec/unit/knife/key_helper.rb +74 -74
  612. data/spec/unit/knife/key_list_spec.rb +216 -216
  613. data/spec/unit/knife/key_show_spec.rb +126 -126
  614. data/spec/unit/knife/license_spec.rb +89 -89
  615. data/spec/unit/knife/node_bulk_delete_spec.rb +94 -94
  616. data/spec/unit/knife/node_delete_spec.rb +77 -77
  617. data/spec/unit/knife/node_edit_spec.rb +116 -116
  618. data/spec/unit/knife/node_environment_set_spec.rb +61 -61
  619. data/spec/unit/knife/node_from_file_spec.rb +59 -59
  620. data/spec/unit/knife/node_list_spec.rb +62 -62
  621. data/spec/unit/knife/node_policy_set_spec.rb +122 -122
  622. data/spec/unit/knife/node_run_list_add_spec.rb +145 -145
  623. data/spec/unit/knife/node_run_list_remove_spec.rb +106 -106
  624. data/spec/unit/knife/node_run_list_set_spec.rb +115 -115
  625. data/spec/unit/knife/node_show_spec.rb +65 -65
  626. data/spec/unit/knife/org_create_spec.rb +76 -76
  627. data/spec/unit/knife/org_delete_spec.rb +41 -41
  628. data/spec/unit/knife/org_edit_spec.rb +49 -49
  629. data/spec/unit/knife/org_list_spec.rb +58 -58
  630. data/spec/unit/knife/org_show_spec.rb +45 -45
  631. data/spec/unit/knife/org_user_add_spec.rb +39 -39
  632. data/spec/unit/knife/raw_spec.rb +43 -43
  633. data/spec/unit/knife/role_bulk_delete_spec.rb +80 -80
  634. data/spec/unit/knife/role_create_spec.rb +80 -80
  635. data/spec/unit/knife/role_delete_spec.rb +67 -67
  636. data/spec/unit/knife/role_edit_spec.rb +77 -77
  637. data/spec/unit/knife/role_env_run_list_add_spec.rb +217 -217
  638. data/spec/unit/knife/role_env_run_list_clear_spec.rb +94 -94
  639. data/spec/unit/knife/role_env_run_list_remove_spec.rb +102 -102
  640. data/spec/unit/knife/role_env_run_list_replace_spec.rb +105 -105
  641. data/spec/unit/knife/role_env_run_list_set_spec.rb +99 -99
  642. data/spec/unit/knife/role_from_file_spec.rb +69 -69
  643. data/spec/unit/knife/role_list_spec.rb +54 -54
  644. data/spec/unit/knife/role_run_list_add_spec.rb +179 -179
  645. data/spec/unit/knife/role_run_list_clear_spec.rb +84 -84
  646. data/spec/unit/knife/role_run_list_remove_spec.rb +92 -92
  647. data/spec/unit/knife/role_run_list_replace_spec.rb +98 -98
  648. data/spec/unit/knife/role_run_list_set_spec.rb +89 -89
  649. data/spec/unit/knife/role_show_spec.rb +59 -59
  650. data/spec/unit/knife/search_spec.rb +147 -147
  651. data/spec/unit/knife/ssh_spec.rb +403 -403
  652. data/spec/unit/knife/ssl_check_spec.rb +256 -256
  653. data/spec/unit/knife/ssl_fetch_spec.rb +222 -222
  654. data/spec/unit/knife/status_spec.rb +112 -112
  655. data/spec/unit/knife/supermarket_download_spec.rb +152 -152
  656. data/spec/unit/knife/supermarket_install_spec.rb +203 -203
  657. data/spec/unit/knife/supermarket_list_spec.rb +70 -70
  658. data/spec/unit/knife/supermarket_search_spec.rb +85 -85
  659. data/spec/unit/knife/supermarket_share_spec.rb +208 -208
  660. data/spec/unit/knife/supermarket_unshare_spec.rb +78 -78
  661. data/spec/unit/knife/tag_create_spec.rb +23 -23
  662. data/spec/unit/knife/tag_delete_spec.rb +25 -25
  663. data/spec/unit/knife/tag_list_spec.rb +23 -23
  664. data/spec/unit/knife/user_create_spec.rb +282 -282
  665. data/spec/unit/knife/user_delete_spec.rb +171 -171
  666. data/spec/unit/knife/user_edit_spec.rb +54 -54
  667. data/spec/unit/knife/user_list_spec.rb +73 -73
  668. data/spec/unit/knife/user_password_spec.rb +64 -64
  669. data/spec/unit/knife/user_reregister_spec.rb +56 -56
  670. data/spec/unit/knife/user_show_spec.rb +91 -91
  671. data/spec/unit/knife_spec.rb +637 -637
  672. data/spec/unit/utils/licensing_handler_spec.rb +140 -0
  673. metadata +11 -7
@@ -1,657 +1,657 @@
1
- #
2
- # Author:: Adam Jacob (<adam@chef.io>)
3
- # Copyright:: Copyright (c) Chef Software Inc.
4
- # License:: Apache License, Version 2.0
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- #
18
-
19
- require_relative "../knife"
20
-
21
- class Chef
22
- class Knife
23
- class Ssh < Knife
24
-
25
- deps do
26
- require "chef/mixin/shell_out" unless defined?(Chef::Mixin::ShellOut)
27
- require "net/ssh" unless defined?(Net::SSH)
28
- require "net/ssh/multi"
29
- require "readline"
30
- require "chef/exceptions" unless defined?(Chef::Exceptions)
31
- require "chef/search/query" unless defined?(Chef::Search::Query)
32
- require "chef-config/path_helper" unless defined?(ChefConfig::PathHelper)
33
-
34
- include Chef::Mixin::ShellOut
35
- end
36
-
37
- attr_writer :password
38
-
39
- banner "knife ssh QUERY COMMAND (options)"
40
-
41
- option :concurrency,
42
- short: "-C NUM",
43
- long: "--concurrency NUM",
44
- description: "The number of concurrent connections.",
45
- default: nil,
46
- proc: lambda { |o| o.to_i }
47
-
48
- option :ssh_attribute,
49
- short: "-a ATTR",
50
- long: "--attribute ATTR",
51
- description: "The attribute to use for opening the connection - default depends on the context."
52
-
53
- option :manual,
54
- short: "-m",
55
- long: "--manual-list",
56
- boolean: true,
57
- description: "QUERY is a space separated list of servers.",
58
- default: false
59
-
60
- option :prefix_attribute,
61
- long: "--prefix-attribute ATTR",
62
- description: "The attribute to use for prefixing the output - default depends on the context."
63
-
64
- option :ssh_user,
65
- short: "-x USERNAME",
66
- long: "--ssh-user USERNAME",
67
- description: "The ssh username."
68
-
69
- option :ssh_password,
70
- short: "-P [PASSWORD]",
71
- long: "--ssh-password [PASSWORD]",
72
- description: "The ssh password - will prompt if flag is specified but no password is given.",
73
- # default to a value that can not be a password (boolean)
74
- # so we can effectively test if this parameter was specified
75
- # without a value
76
- default: false
77
-
78
- option :ssh_port,
79
- short: "-p PORT",
80
- long: "--ssh-port PORT",
81
- description: "The ssh port.",
82
- proc: Proc.new { |key| key.strip }
83
-
84
- option :ssh_timeout,
85
- short: "-t SECONDS",
86
- long: "--ssh-timeout SECONDS",
87
- description: "The ssh connection timeout.",
88
- proc: Proc.new { |key| key.strip.to_i },
89
- default: 120
90
-
91
- option :ssh_gateway,
92
- short: "-G GATEWAY",
93
- long: "--ssh-gateway GATEWAY",
94
- description: "The ssh gateway.",
95
- proc: Proc.new { |key| key.strip }
96
-
97
- option :ssh_gateway_identity,
98
- long: "--ssh-gateway-identity SSH_GATEWAY_IDENTITY",
99
- description: "The SSH identity file used for gateway authentication."
100
-
101
- option :forward_agent,
102
- short: "-A",
103
- long: "--forward-agent",
104
- description: "Enable SSH agent forwarding.",
105
- boolean: true
106
-
107
- option :ssh_identity_file,
108
- short: "-i IDENTITY_FILE",
109
- long: "--ssh-identity-file IDENTITY_FILE",
110
- description: "The SSH identity file used for authentication."
111
-
112
- option :host_key_verify,
113
- long: "--[no-]host-key-verify",
114
- description: "Verify host key, enabled by default.",
115
- boolean: true,
116
- default: true
117
-
118
- option :on_error,
119
- short: "-e",
120
- long: "--exit-on-error",
121
- description: "Immediately exit if an error is encountered.",
122
- boolean: true,
123
- default: false
124
-
125
- option :duplicated_fqdns,
126
- long: "--duplicated-fqdns",
127
- description: "Behavior if FQDNs are duplicated, ignored by default.",
128
- proc: Proc.new { |key| key.strip.to_sym },
129
- default: :ignore
130
-
131
- option :tmux_split,
132
- long: "--tmux-split",
133
- description: "Split tmux window.",
134
- boolean: true,
135
- default: false
136
-
137
- option :pty,
138
- long: "--[no-]pty",
139
- description: "Request a PTY, enabled by default.",
140
- boolean: true,
141
- default: true
142
-
143
- option :require_pty,
144
- long: "--[no-]require-pty",
145
- description: "Raise exception if a PTY cannot be acquired, disabled by default.",
146
- boolean: true,
147
- default: false
148
-
149
- def session
150
- ssh_error_handler = Proc.new do |server|
151
- if config[:on_error]
152
- # Net::SSH::Multi magic to force exception to be re-raised.
153
- throw :go, :raise
154
- else
155
- ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
156
- $!.backtrace.each { |l| Chef::Log.debug(l) }
157
- end
158
- end
159
-
160
- @session ||= Net::SSH::Multi.start(concurrent_connections: config[:concurrency], on_error: ssh_error_handler)
161
- end
162
-
163
- def configure_gateway
164
- if config[:ssh_gateway]
165
- gw_host, gw_user = config[:ssh_gateway].split("@").reverse
166
- gw_host, gw_port = gw_host.split(":")
167
- gw_opts = session_options(gw_host, gw_port, gw_user, gateway: true)
168
- user = gw_opts.delete(:user)
169
-
170
- begin
171
- # Try to connect with a key.
172
- session.via(gw_host, user, gw_opts)
173
- rescue Net::SSH::AuthenticationFailed
174
- prompt = "Enter the password for #{user}@#{gw_host}: "
175
- gw_opts[:password] = prompt_for_password(prompt)
176
- # Try again with a password.
177
- session.via(gw_host, user, gw_opts)
178
- end
179
- end
180
- end
181
-
182
- def configure_session
183
- list = config[:manual] ? @name_args[0].split(" ") : search_nodes
184
- if list.length == 0
185
- if @search_count == 0
186
- ui.fatal("No nodes returned from search")
187
- else
188
- ui.fatal("#{@search_count} #{@search_count > 1 ? "nodes" : "node"} found, " +
189
- "but does not have the required attribute to establish the connection. " +
190
- "Try setting another attribute to open the connection using --attribute.")
191
- end
192
- exit 10
193
- end
194
- if %i{warn fatal}.include?(config[:duplicated_fqdns])
195
- fqdns = list.map { |v| v[0] }
196
- if fqdns.count != fqdns.uniq.count
197
- duplicated_fqdns = fqdns.uniq
198
- ui.send(config[:duplicated_fqdns],
199
- "SSH #{duplicated_fqdns.count > 1 ? "nodes are" : "node is"} " +
200
- "duplicated: #{duplicated_fqdns.join(",")}")
201
- exit 10 if config[:duplicated_fqdns] == :fatal
202
- end
203
- end
204
- session_from_list(list)
205
- end
206
-
207
- def get_prefix_attribute(item)
208
- # Order of precedence for prefix
209
- # 1) config value (cli or knife config)
210
- # 2) nil
211
- msg = "Using node attribute '%s' as the prefix: %s"
212
- if item["prefix"]
213
- Chef::Log.debug(sprintf(msg, config[:prefix_attribute], item["prefix"]))
214
- item["prefix"]
215
- else
216
- nil
217
- end
218
- end
219
-
220
- def get_ssh_attribute(item)
221
- # Order of precedence for ssh target
222
- # 1) config value (cli or knife config)
223
- # 2) cloud attribute
224
- # 3) fqdn
225
- msg = "Using node attribute '%s' as the ssh target: %s"
226
- if item["target"]
227
- Chef::Log.debug(sprintf(msg, config[:ssh_attribute], item["target"]))
228
- item["target"]
229
- elsif !item.dig("cloud", "public_hostname").to_s.empty?
230
- Chef::Log.debug(sprintf(msg, "cloud.public_hostname", item["cloud"]["public_hostname"]))
231
- item["cloud"]["public_hostname"]
232
- else
233
- Chef::Log.debug(sprintf(msg, "fqdn", item["fqdn"]))
234
- item["fqdn"]
235
- end
236
- end
237
-
238
- def search_nodes
239
- list = []
240
- query = Chef::Search::Query.new
241
- required_attributes = { fqdn: ["fqdn"], cloud: ["cloud"] }
242
-
243
- separator = ui.presenter.attribute_field_separator
244
-
245
- if config[:prefix_attribute]
246
- required_attributes[:prefix] = config[:prefix_attribute].split(separator)
247
- end
248
-
249
- if config[:ssh_attribute]
250
- required_attributes[:target] = config[:ssh_attribute].split(separator)
251
- end
252
-
253
- @search_count = 0
254
- query.search(:node, @name_args[0], filter_result: required_attributes, fuzz: true) do |item|
255
- @search_count += 1
256
- # we should skip the loop to next iteration if the item
257
- # returned by the search is nil
258
- next if item.nil?
259
-
260
- # next if we couldn't find the specified attribute in the
261
- # returned node object
262
- host = get_ssh_attribute(item)
263
- next if host.nil?
264
-
265
- prefix = get_prefix_attribute(item)
266
- ssh_port = item.dig("cloud", "public_ssh_port")
267
- srv = [host, ssh_port, prefix]
268
- list.push(srv)
269
- end
270
-
271
- list
272
- end
273
-
274
- # Net::SSH session options hash for global options. These should be
275
- # options that will apply to the gateway connection in addition to the
276
- # main one.
277
- #
278
- # @since 12.5.0
279
- # @param host [String] Hostname for this session.
280
- # @param port [String] SSH port for this session.
281
- # @param user [String] Optional username for this session.
282
- # @param gateway [Boolean] Flag: host or gateway key
283
- # @return [Hash<Symbol, Object>]
284
- def session_options(host, port, user = nil, gateway: false)
285
- ssh_config = Net::SSH.configuration_for(host, true)
286
- {}.tap do |opts|
287
- opts[:user] = user || config[:ssh_user] || ssh_config[:user]
288
- if !gateway && config[:ssh_identity_file]
289
- opts[:keys] = File.expand_path(config[:ssh_identity_file])
290
- opts[:keys_only] = true
291
- elsif gateway && config[:ssh_gateway_identity]
292
- opts[:keys] = File.expand_path(config[:ssh_gateway_identity])
293
- opts[:keys_only] = true
294
- elsif config[:ssh_password]
295
- opts[:password] = config[:ssh_password]
296
- end
297
- # Don't set the keys to nil if we don't have them.
298
- forward_agent = config[:forward_agent] || ssh_config[:forward_agent]
299
- opts[:forward_agent] = forward_agent unless forward_agent.nil?
300
- port ||= ssh_config[:port]
301
- opts[:port] = port unless port.nil?
302
- opts[:logger] = Chef::Log.with_child(subsystem: "net/ssh") if Chef::Log.level == :trace
303
- unless config[:host_key_verify]
304
- opts[:verify_host_key] = :never
305
- opts[:user_known_hosts_file] = "/dev/null"
306
- end
307
- if ssh_config[:keepalive]
308
- opts[:keepalive] = true
309
- opts[:keepalive_interval] = ssh_config[:keepalive_interval]
310
- end
311
- # maintain support for legacy key types / ciphers / key exchange algorithms.
312
- # most importantly this adds back support for DSS host keys
313
- # See https://github.com/net-ssh/net-ssh/pull/709
314
- opts[:append_all_supported_algorithms] = true
315
- end
316
- end
317
-
318
- def session_from_list(list)
319
- list.each do |item|
320
- host, ssh_port, prefix = item
321
- prefix = host unless prefix
322
- Chef::Log.debug("Adding #{host}")
323
- session_opts = session_options(host, ssh_port, gateway: false)
324
- # Handle port overrides for the main connection.
325
- session_opts[:port] = config[:ssh_port] if config[:ssh_port]
326
- # Handle connection timeout
327
- session_opts[:timeout] = config[:ssh_timeout] if config[:ssh_timeout]
328
- # Handle session prefix
329
- session_opts[:properties] = { prefix: prefix }
330
- # Create the hostspec.
331
- hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host
332
- # Connect a new session on the multi.
333
- session.use(hostspec, session_opts)
334
-
335
- @longest = prefix.length if prefix.length > @longest
336
- end
337
-
338
- session
339
- end
340
-
341
- def fixup_sudo(command)
342
- command.sub(/^sudo/, "sudo -p 'knife sudo password: '")
343
- end
344
-
345
- def print_data(host, data)
346
- @buffers ||= {}
347
- if leftover = @buffers[host]
348
- @buffers[host] = nil
349
- print_data(host, leftover + data)
350
- else
351
- if newline_index = data.index("\n")
352
- line = data.slice!(0...newline_index)
353
- data.slice!(0)
354
- print_line(host, line)
355
- print_data(host, data)
356
- else
357
- @buffers[host] = data
358
- end
359
- end
360
- end
361
-
362
- def print_line(host, data)
363
- padding = @longest - host.length
364
- str = ui.color(host, :cyan) + (" " * (padding + 1)) + data
365
- ui.msg(str)
366
- end
367
-
368
- # @param command [String] the command to run
369
- # @param session_list [???] list of sessions, one per node
370
- #
371
- def ssh_command(command, session_list = session)
372
- stderr = ""
373
- exit_status = 0
374
- command = fixup_sudo(command)
375
- command.force_encoding("binary") if command.respond_to?(:force_encoding)
376
- session_list.open_channel do |chan|
377
- if config[:on_error] && exit_status != 0
378
- chan.close
379
- else
380
- if config[:pty]
381
- chan.request_pty do |ch, success|
382
- unless success
383
- ui.warn("Failed to obtain a PTY from #{ch.connection.host}")
384
- raise ArgumentError, "Request for PTY failed" if config[:require_pty]
385
- end
386
- end
387
- end
388
- chan.exec command do |ch, success|
389
- raise ArgumentError, "Cannot execute #{command}" unless success
390
-
391
- ch.on_data do |ichannel, data|
392
- print_data(ichannel.connection[:prefix], data)
393
- if /^knife sudo password: /.match?(data)
394
- print_data(ichannel.connection[:prefix], "\n")
395
- ichannel.send_data("#{get_password}\n")
396
- end
397
- end
398
- ch.on_extended_data do |_, _type, data|
399
- raise ArgumentError, "No PTY present. If a PTY is required use --require-pty" if data.eql?("sudo: no tty present and no askpass program specified\n")
400
-
401
- stderr += data
402
- end
403
- ch.on_request "exit-status" do |ichannel, data|
404
- exit_status = [exit_status, data.read_long].max
405
- end
406
- end
407
- end
408
- end
409
- session.loop
410
- exit_status
411
- ensure
412
- session_list.close
413
- end
414
-
415
- def get_password
416
- @password ||= prompt_for_password
417
- end
418
-
419
- def prompt_for_password(prompt = "Enter your password: ")
420
- ui.ask(prompt, echo: false)
421
- end
422
-
423
- # Present the prompt and read a single line from the console. It also
424
- # detects ^D and returns "exit" in that case. Adds the input to the
425
- # history, unless the input is empty. Loops repeatedly until a non-empty
426
- # line is input.
427
- def read_line
428
- loop do
429
- command = reader.readline("#{ui.color("knife-ssh>", :bold)} ", true)
430
-
431
- if command.nil?
432
- command = "exit"
433
- puts(command)
434
- else
435
- command.strip!
436
- end
437
-
438
- unless command.empty?
439
- return command
440
- end
441
- end
442
- end
443
-
444
- def reader
445
- Readline
446
- end
447
-
448
- def interactive
449
- puts "Connected to #{ui.list(session.servers_for.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
450
- puts
451
- puts "To run a command on a list of servers, do:"
452
- puts " on SERVER1 SERVER2 SERVER3; COMMAND"
453
- puts " Example: on latte foamy; echo foobar"
454
- puts
455
- puts "To exit interactive mode, use 'quit!'"
456
- puts
457
- loop do
458
- command = read_line
459
- case command
460
- when "quit!"
461
- puts "Bye!"
462
- break
463
- when /^on (.+?); (.+)$/
464
- raw_list = $1.split(" ")
465
- server_list = []
466
- session.servers.each do |session_server|
467
- server_list << session_server if raw_list.include?(session_server.host)
468
- end
469
- command = $2
470
- ssh_command(command, session.on(*server_list))
471
- else
472
- ssh_command(command)
473
- end
474
- end
475
- end
476
-
477
- def screen
478
- tf = Tempfile.new("knife-ssh-screen")
479
- ChefConfig::PathHelper.home(".screenrc") do |screenrc_path|
480
- if File.exist? screenrc_path
481
- tf.puts("source #{screenrc_path}")
482
- end
483
- end
484
- tf.puts("caption always '%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<'")
485
- tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'")
486
- window = 0
487
- session.servers_for.each do |server|
488
- tf.print("screen -t \"#{server.host}\" #{window} ssh ")
489
- tf.print("-i #{config[:ssh_identity_file]} ") if config[:ssh_identity_file]
490
- server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host)
491
- window += 1
492
- end
493
- tf.close
494
- exec("screen -c #{tf.path}")
495
- end
496
-
497
- def tmux
498
- ssh_dest = lambda do |server|
499
- identity = "-i #{config[:ssh_identity_file]} " if config[:ssh_identity_file]
500
- prefix = server.user ? "#{server.user}@" : ""
501
- "'ssh #{identity}#{prefix}#{server.host}'"
502
- end
503
-
504
- new_window_cmds = lambda do
505
- if session.servers_for.size > 1
506
- [""] + session.servers_for[1..].map do |server|
507
- if config[:tmux_split]
508
- "split-window #{ssh_dest.call(server)}; tmux select-layout tiled"
509
- else
510
- "new-window -a -n '#{server.host}' #{ssh_dest.call(server)}"
511
- end
512
- end
513
- else
514
- []
515
- end.join(" \\; ")
516
- end
517
-
518
- tmux_name = "'knife ssh #{@name_args[0].tr(":.", "=-")}'"
519
- begin
520
- server = session.servers_for.first
521
- cmd = ["tmux new-session -d -s #{tmux_name}",
522
- "-n '#{server.host}'", ssh_dest.call(server),
523
- new_window_cmds.call].join(" ")
524
- shell_out!(cmd)
525
- exec("tmux attach-session -t #{tmux_name}")
526
- rescue Chef::Exceptions::Exec
527
- end
528
- end
529
-
530
- def macterm
531
- begin
532
- require "appscript" unless defined?(Appscript)
533
- rescue LoadError
534
- STDERR.puts "You need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install"
535
- raise
536
- end
537
-
538
- Appscript.app("/Applications/Utilities/Terminal.app").windows.first.activate
539
- Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", using: :command_down)
540
- term = Appscript.app("Terminal")
541
- window = term.windows.first.get
542
-
543
- (session.servers_for.size - 1).times do |i|
544
- window.activate
545
- Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", using: :command_down)
546
- end
547
-
548
- session.servers_for.each_with_index do |server, tab_number|
549
- cmd = "unset PROMPT_COMMAND; echo -e \"\\033]0;#{server.host}\\007\"; ssh #{server.user ? "#{server.user}@#{server.host}" : server.host}"
550
- Appscript.app("Terminal").do_script(cmd, in: window.tabs[tab_number + 1].get)
551
- end
552
- end
553
-
554
- def cssh
555
- cssh_cmd = nil
556
- %w{csshX cssh}.each do |cmd|
557
-
558
- # Unix and Mac only
559
- cssh_cmd = shell_out!("which #{cmd}").stdout.strip
560
- break
561
- rescue Mixlib::ShellOut::ShellCommandFailed
562
-
563
- end
564
- raise Chef::Exceptions::Exec, "no command found for cssh" unless cssh_cmd
565
-
566
- # pass in the consolidated identity file option to cssh(X)
567
- if config[:ssh_identity_file]
568
- cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:ssh_identity_file])}'"
569
- end
570
-
571
- session.servers_for.each do |server|
572
- cssh_cmd << " #{server.user ? "#{server.user}@#{server.host}" : server.host}"
573
- end
574
- Chef::Log.debug("Starting cssh session with command: #{cssh_cmd}")
575
- exec(cssh_cmd)
576
- end
577
-
578
- def get_stripped_unfrozen_value(value)
579
- return nil unless value
580
-
581
- value.strip
582
- end
583
-
584
- def configure_user
585
- config[:ssh_user] = get_stripped_unfrozen_value(config[:ssh_user] ||
586
- Chef::Config[:knife][:ssh_user])
587
- end
588
-
589
- def configure_password
590
- if config.key?(:ssh_password) && config[:ssh_password].nil?
591
- # if we have an actual nil that means someone called "--ssh-password" with no value, so we prompt for a password
592
- config[:ssh_password] = get_password
593
- else
594
- # the false default of ssh_password results in a nil here
595
- config[:ssh_password] = get_stripped_unfrozen_value(config[:ssh_password])
596
- end
597
- end
598
-
599
- def configure_ssh_identity_file
600
- config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file])
601
- end
602
-
603
- def configure_ssh_gateway_identity
604
- config[:ssh_gateway_identity] = get_stripped_unfrozen_value(config[:ssh_gateway_identity])
605
- end
606
-
607
- def run
608
- @longest = 0
609
-
610
- if @name_args.length < 1
611
- show_usage
612
- ui.fatal("You must specify the SEARCH QUERY.")
613
- exit(1)
614
- end
615
-
616
- configure_user
617
- configure_password
618
- @password = config[:ssh_password] if config[:ssh_password]
619
-
620
- # If a password was not given, check for SSH identity file.
621
- unless @password
622
- configure_ssh_identity_file
623
- configure_ssh_gateway_identity
624
- end
625
-
626
- configure_gateway
627
- configure_session
628
-
629
- exit_status =
630
- case @name_args[1]
631
- when "interactive"
632
- interactive
633
- when "screen"
634
- screen
635
- when "tmux"
636
- tmux
637
- when "macterm"
638
- macterm
639
- when "cssh"
640
- cssh
641
- else
642
- ssh_command(@name_args[1..].join(" "))
643
- end
644
-
645
- session.close
646
- if exit_status && exit_status != 0
647
- exit exit_status
648
- else
649
- exit_status
650
- end
651
- end
652
-
653
- private :search_nodes
654
-
655
- end
656
- end
657
- end
1
+ #
2
+ # Author:: Adam Jacob (<adam@chef.io>)
3
+ # Copyright:: Copyright (c) Chef Software Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require_relative "../knife"
20
+
21
+ class Chef
22
+ class Knife
23
+ class Ssh < Knife
24
+
25
+ deps do
26
+ require "chef/mixin/shell_out" unless defined?(Chef::Mixin::ShellOut)
27
+ require "net/ssh" unless defined?(Net::SSH)
28
+ require "net/ssh/multi"
29
+ require "readline"
30
+ require "chef/exceptions" unless defined?(Chef::Exceptions)
31
+ require "chef/search/query" unless defined?(Chef::Search::Query)
32
+ require "chef-config/path_helper" unless defined?(ChefConfig::PathHelper)
33
+
34
+ include Chef::Mixin::ShellOut
35
+ end
36
+
37
+ attr_writer :password
38
+
39
+ banner "knife ssh QUERY COMMAND (options)"
40
+
41
+ option :concurrency,
42
+ short: "-C NUM",
43
+ long: "--concurrency NUM",
44
+ description: "The number of concurrent connections.",
45
+ default: nil,
46
+ proc: lambda { |o| o.to_i }
47
+
48
+ option :ssh_attribute,
49
+ short: "-a ATTR",
50
+ long: "--attribute ATTR",
51
+ description: "The attribute to use for opening the connection - default depends on the context."
52
+
53
+ option :manual,
54
+ short: "-m",
55
+ long: "--manual-list",
56
+ boolean: true,
57
+ description: "QUERY is a space separated list of servers.",
58
+ default: false
59
+
60
+ option :prefix_attribute,
61
+ long: "--prefix-attribute ATTR",
62
+ description: "The attribute to use for prefixing the output - default depends on the context."
63
+
64
+ option :ssh_user,
65
+ short: "-x USERNAME",
66
+ long: "--ssh-user USERNAME",
67
+ description: "The ssh username."
68
+
69
+ option :ssh_password,
70
+ short: "-P [PASSWORD]",
71
+ long: "--ssh-password [PASSWORD]",
72
+ description: "The ssh password - will prompt if flag is specified but no password is given.",
73
+ # default to a value that can not be a password (boolean)
74
+ # so we can effectively test if this parameter was specified
75
+ # without a value
76
+ default: false
77
+
78
+ option :ssh_port,
79
+ short: "-p PORT",
80
+ long: "--ssh-port PORT",
81
+ description: "The ssh port.",
82
+ proc: Proc.new { |key| key.strip }
83
+
84
+ option :ssh_timeout,
85
+ short: "-t SECONDS",
86
+ long: "--ssh-timeout SECONDS",
87
+ description: "The ssh connection timeout.",
88
+ proc: Proc.new { |key| key.strip.to_i },
89
+ default: 120
90
+
91
+ option :ssh_gateway,
92
+ short: "-G GATEWAY",
93
+ long: "--ssh-gateway GATEWAY",
94
+ description: "The ssh gateway.",
95
+ proc: Proc.new { |key| key.strip }
96
+
97
+ option :ssh_gateway_identity,
98
+ long: "--ssh-gateway-identity SSH_GATEWAY_IDENTITY",
99
+ description: "The SSH identity file used for gateway authentication."
100
+
101
+ option :forward_agent,
102
+ short: "-A",
103
+ long: "--forward-agent",
104
+ description: "Enable SSH agent forwarding.",
105
+ boolean: true
106
+
107
+ option :ssh_identity_file,
108
+ short: "-i IDENTITY_FILE",
109
+ long: "--ssh-identity-file IDENTITY_FILE",
110
+ description: "The SSH identity file used for authentication."
111
+
112
+ option :host_key_verify,
113
+ long: "--[no-]host-key-verify",
114
+ description: "Verify host key, enabled by default.",
115
+ boolean: true,
116
+ default: true
117
+
118
+ option :on_error,
119
+ short: "-e",
120
+ long: "--exit-on-error",
121
+ description: "Immediately exit if an error is encountered.",
122
+ boolean: true,
123
+ default: false
124
+
125
+ option :duplicated_fqdns,
126
+ long: "--duplicated-fqdns",
127
+ description: "Behavior if FQDNs are duplicated, ignored by default.",
128
+ proc: Proc.new { |key| key.strip.to_sym },
129
+ default: :ignore
130
+
131
+ option :tmux_split,
132
+ long: "--tmux-split",
133
+ description: "Split tmux window.",
134
+ boolean: true,
135
+ default: false
136
+
137
+ option :pty,
138
+ long: "--[no-]pty",
139
+ description: "Request a PTY, enabled by default.",
140
+ boolean: true,
141
+ default: true
142
+
143
+ option :require_pty,
144
+ long: "--[no-]require-pty",
145
+ description: "Raise exception if a PTY cannot be acquired, disabled by default.",
146
+ boolean: true,
147
+ default: false
148
+
149
+ def session
150
+ ssh_error_handler = Proc.new do |server|
151
+ if config[:on_error]
152
+ # Net::SSH::Multi magic to force exception to be re-raised.
153
+ throw :go, :raise
154
+ else
155
+ ui.warn "Failed to connect to #{server.host} -- #{$!.class.name}: #{$!.message}"
156
+ $!.backtrace.each { |l| Chef::Log.debug(l) }
157
+ end
158
+ end
159
+
160
+ @session ||= Net::SSH::Multi.start(concurrent_connections: config[:concurrency], on_error: ssh_error_handler)
161
+ end
162
+
163
+ def configure_gateway
164
+ if config[:ssh_gateway]
165
+ gw_host, gw_user = config[:ssh_gateway].split("@").reverse
166
+ gw_host, gw_port = gw_host.split(":")
167
+ gw_opts = session_options(gw_host, gw_port, gw_user, gateway: true)
168
+ user = gw_opts.delete(:user)
169
+
170
+ begin
171
+ # Try to connect with a key.
172
+ session.via(gw_host, user, gw_opts)
173
+ rescue Net::SSH::AuthenticationFailed
174
+ prompt = "Enter the password for #{user}@#{gw_host}: "
175
+ gw_opts[:password] = prompt_for_password(prompt)
176
+ # Try again with a password.
177
+ session.via(gw_host, user, gw_opts)
178
+ end
179
+ end
180
+ end
181
+
182
+ def configure_session
183
+ list = config[:manual] ? @name_args[0].split(" ") : search_nodes
184
+ if list.length == 0
185
+ if @search_count == 0
186
+ ui.fatal("No nodes returned from search")
187
+ else
188
+ ui.fatal("#{@search_count} #{@search_count > 1 ? "nodes" : "node"} found, " +
189
+ "but does not have the required attribute to establish the connection. " +
190
+ "Try setting another attribute to open the connection using --attribute.")
191
+ end
192
+ exit 10
193
+ end
194
+ if %i{warn fatal}.include?(config[:duplicated_fqdns])
195
+ fqdns = list.map { |v| v[0] }
196
+ if fqdns.count != fqdns.uniq.count
197
+ duplicated_fqdns = fqdns.uniq
198
+ ui.send(config[:duplicated_fqdns],
199
+ "SSH #{duplicated_fqdns.count > 1 ? "nodes are" : "node is"} " +
200
+ "duplicated: #{duplicated_fqdns.join(",")}")
201
+ exit 10 if config[:duplicated_fqdns] == :fatal
202
+ end
203
+ end
204
+ session_from_list(list)
205
+ end
206
+
207
+ def get_prefix_attribute(item)
208
+ # Order of precedence for prefix
209
+ # 1) config value (cli or knife config)
210
+ # 2) nil
211
+ msg = "Using node attribute '%s' as the prefix: %s"
212
+ if item["prefix"]
213
+ Chef::Log.debug(sprintf(msg, config[:prefix_attribute], item["prefix"]))
214
+ item["prefix"]
215
+ else
216
+ nil
217
+ end
218
+ end
219
+
220
+ def get_ssh_attribute(item)
221
+ # Order of precedence for ssh target
222
+ # 1) config value (cli or knife config)
223
+ # 2) cloud attribute
224
+ # 3) fqdn
225
+ msg = "Using node attribute '%s' as the ssh target: %s"
226
+ if item["target"]
227
+ Chef::Log.debug(sprintf(msg, config[:ssh_attribute], item["target"]))
228
+ item["target"]
229
+ elsif !item.dig("cloud", "public_hostname").to_s.empty?
230
+ Chef::Log.debug(sprintf(msg, "cloud.public_hostname", item["cloud"]["public_hostname"]))
231
+ item["cloud"]["public_hostname"]
232
+ else
233
+ Chef::Log.debug(sprintf(msg, "fqdn", item["fqdn"]))
234
+ item["fqdn"]
235
+ end
236
+ end
237
+
238
+ def search_nodes
239
+ list = []
240
+ query = Chef::Search::Query.new
241
+ required_attributes = { fqdn: ["fqdn"], cloud: ["cloud"] }
242
+
243
+ separator = ui.presenter.attribute_field_separator
244
+
245
+ if config[:prefix_attribute]
246
+ required_attributes[:prefix] = config[:prefix_attribute].split(separator)
247
+ end
248
+
249
+ if config[:ssh_attribute]
250
+ required_attributes[:target] = config[:ssh_attribute].split(separator)
251
+ end
252
+
253
+ @search_count = 0
254
+ query.search(:node, @name_args[0], filter_result: required_attributes, fuzz: true) do |item|
255
+ @search_count += 1
256
+ # we should skip the loop to next iteration if the item
257
+ # returned by the search is nil
258
+ next if item.nil?
259
+
260
+ # next if we couldn't find the specified attribute in the
261
+ # returned node object
262
+ host = get_ssh_attribute(item)
263
+ next if host.nil?
264
+
265
+ prefix = get_prefix_attribute(item)
266
+ ssh_port = item.dig("cloud", "public_ssh_port")
267
+ srv = [host, ssh_port, prefix]
268
+ list.push(srv)
269
+ end
270
+
271
+ list
272
+ end
273
+
274
+ # Net::SSH session options hash for global options. These should be
275
+ # options that will apply to the gateway connection in addition to the
276
+ # main one.
277
+ #
278
+ # @since 12.5.0
279
+ # @param host [String] Hostname for this session.
280
+ # @param port [String] SSH port for this session.
281
+ # @param user [String] Optional username for this session.
282
+ # @param gateway [Boolean] Flag: host or gateway key
283
+ # @return [Hash<Symbol, Object>]
284
+ def session_options(host, port, user = nil, gateway: false)
285
+ ssh_config = Net::SSH.configuration_for(host, true)
286
+ {}.tap do |opts|
287
+ opts[:user] = user || config[:ssh_user] || ssh_config[:user]
288
+ if !gateway && config[:ssh_identity_file]
289
+ opts[:keys] = File.expand_path(config[:ssh_identity_file])
290
+ opts[:keys_only] = true
291
+ elsif gateway && config[:ssh_gateway_identity]
292
+ opts[:keys] = File.expand_path(config[:ssh_gateway_identity])
293
+ opts[:keys_only] = true
294
+ elsif config[:ssh_password]
295
+ opts[:password] = config[:ssh_password]
296
+ end
297
+ # Don't set the keys to nil if we don't have them.
298
+ forward_agent = config[:forward_agent] || ssh_config[:forward_agent]
299
+ opts[:forward_agent] = forward_agent unless forward_agent.nil?
300
+ port ||= ssh_config[:port]
301
+ opts[:port] = port unless port.nil?
302
+ opts[:logger] = Chef::Log.with_child(subsystem: "net/ssh") if Chef::Log.level == :trace
303
+ unless config[:host_key_verify]
304
+ opts[:verify_host_key] = :never
305
+ opts[:user_known_hosts_file] = "/dev/null"
306
+ end
307
+ if ssh_config[:keepalive]
308
+ opts[:keepalive] = true
309
+ opts[:keepalive_interval] = ssh_config[:keepalive_interval]
310
+ end
311
+ # maintain support for legacy key types / ciphers / key exchange algorithms.
312
+ # most importantly this adds back support for DSS host keys
313
+ # See https://github.com/net-ssh/net-ssh/pull/709
314
+ opts[:append_all_supported_algorithms] = true
315
+ end
316
+ end
317
+
318
+ def session_from_list(list)
319
+ list.each do |item|
320
+ host, ssh_port, prefix = item
321
+ prefix = host unless prefix
322
+ Chef::Log.debug("Adding #{host}")
323
+ session_opts = session_options(host, ssh_port, gateway: false)
324
+ # Handle port overrides for the main connection.
325
+ session_opts[:port] = config[:ssh_port] if config[:ssh_port]
326
+ # Handle connection timeout
327
+ session_opts[:timeout] = config[:ssh_timeout] if config[:ssh_timeout]
328
+ # Handle session prefix
329
+ session_opts[:properties] = { prefix: prefix }
330
+ # Create the hostspec.
331
+ hostspec = session_opts[:user] ? "#{session_opts.delete(:user)}@#{host}" : host
332
+ # Connect a new session on the multi.
333
+ session.use(hostspec, session_opts)
334
+
335
+ @longest = prefix.length if prefix.length > @longest
336
+ end
337
+
338
+ session
339
+ end
340
+
341
+ def fixup_sudo(command)
342
+ command.sub(/^sudo/, "sudo -p 'knife sudo password: '")
343
+ end
344
+
345
+ def print_data(host, data)
346
+ @buffers ||= {}
347
+ if leftover = @buffers[host]
348
+ @buffers[host] = nil
349
+ print_data(host, leftover + data)
350
+ else
351
+ if newline_index = data.index("\n")
352
+ line = data.slice!(0...newline_index)
353
+ data.slice!(0)
354
+ print_line(host, line)
355
+ print_data(host, data)
356
+ else
357
+ @buffers[host] = data
358
+ end
359
+ end
360
+ end
361
+
362
+ def print_line(host, data)
363
+ padding = @longest - host.length
364
+ str = ui.color(host, :cyan) + (" " * (padding + 1)) + data
365
+ ui.msg(str)
366
+ end
367
+
368
+ # @param command [String] the command to run
369
+ # @param session_list [???] list of sessions, one per node
370
+ #
371
+ def ssh_command(command, session_list = session)
372
+ stderr = ""
373
+ exit_status = 0
374
+ command = fixup_sudo(command)
375
+ command.force_encoding("binary") if command.respond_to?(:force_encoding)
376
+ session_list.open_channel do |chan|
377
+ if config[:on_error] && exit_status != 0
378
+ chan.close
379
+ else
380
+ if config[:pty]
381
+ chan.request_pty do |ch, success|
382
+ unless success
383
+ ui.warn("Failed to obtain a PTY from #{ch.connection.host}")
384
+ raise ArgumentError, "Request for PTY failed" if config[:require_pty]
385
+ end
386
+ end
387
+ end
388
+ chan.exec command do |ch, success|
389
+ raise ArgumentError, "Cannot execute #{command}" unless success
390
+
391
+ ch.on_data do |ichannel, data|
392
+ print_data(ichannel.connection[:prefix], data)
393
+ if /^knife sudo password: /.match?(data)
394
+ print_data(ichannel.connection[:prefix], "\n")
395
+ ichannel.send_data("#{get_password}\n")
396
+ end
397
+ end
398
+ ch.on_extended_data do |_, _type, data|
399
+ raise ArgumentError, "No PTY present. If a PTY is required use --require-pty" if data.eql?("sudo: no tty present and no askpass program specified\n")
400
+
401
+ stderr += data
402
+ end
403
+ ch.on_request "exit-status" do |ichannel, data|
404
+ exit_status = [exit_status, data.read_long].max
405
+ end
406
+ end
407
+ end
408
+ end
409
+ session.loop
410
+ exit_status
411
+ ensure
412
+ session_list.close
413
+ end
414
+
415
+ def get_password
416
+ @password ||= prompt_for_password
417
+ end
418
+
419
+ def prompt_for_password(prompt = "Enter your password: ")
420
+ ui.ask(prompt, echo: false)
421
+ end
422
+
423
+ # Present the prompt and read a single line from the console. It also
424
+ # detects ^D and returns "exit" in that case. Adds the input to the
425
+ # history, unless the input is empty. Loops repeatedly until a non-empty
426
+ # line is input.
427
+ def read_line
428
+ loop do
429
+ command = reader.readline("#{ui.color("knife-ssh>", :bold)} ", true)
430
+
431
+ if command.nil?
432
+ command = "exit"
433
+ puts(command)
434
+ else
435
+ command.strip!
436
+ end
437
+
438
+ unless command.empty?
439
+ return command
440
+ end
441
+ end
442
+ end
443
+
444
+ def reader
445
+ Readline
446
+ end
447
+
448
+ def interactive
449
+ puts "Connected to #{ui.list(session.servers_for.collect { |s| ui.color(s.host, :cyan) }, :inline, " and ")}"
450
+ puts
451
+ puts "To run a command on a list of servers, do:"
452
+ puts " on SERVER1 SERVER2 SERVER3; COMMAND"
453
+ puts " Example: on latte foamy; echo foobar"
454
+ puts
455
+ puts "To exit interactive mode, use 'quit!'"
456
+ puts
457
+ loop do
458
+ command = read_line
459
+ case command
460
+ when "quit!"
461
+ puts "Bye!"
462
+ break
463
+ when /^on (.+?); (.+)$/
464
+ raw_list = $1.split(" ")
465
+ server_list = []
466
+ session.servers.each do |session_server|
467
+ server_list << session_server if raw_list.include?(session_server.host)
468
+ end
469
+ command = $2
470
+ ssh_command(command, session.on(*server_list))
471
+ else
472
+ ssh_command(command)
473
+ end
474
+ end
475
+ end
476
+
477
+ def screen
478
+ tf = Tempfile.new("knife-ssh-screen")
479
+ ChefConfig::PathHelper.home(".screenrc") do |screenrc_path|
480
+ if File.exist? screenrc_path
481
+ tf.puts("source #{screenrc_path}")
482
+ end
483
+ end
484
+ tf.puts("caption always '%-Lw%{= BW}%50>%n%f* %t%{-}%+Lw%<'")
485
+ tf.puts("hardstatus alwayslastline 'knife ssh #{@name_args[0]}'")
486
+ window = 0
487
+ session.servers_for.each do |server|
488
+ tf.print("screen -t \"#{server.host}\" #{window} ssh ")
489
+ tf.print("-i #{config[:ssh_identity_file]} ") if config[:ssh_identity_file]
490
+ server.user ? tf.puts("#{server.user}@#{server.host}") : tf.puts(server.host)
491
+ window += 1
492
+ end
493
+ tf.close
494
+ exec("screen -c #{tf.path}")
495
+ end
496
+
497
+ def tmux
498
+ ssh_dest = lambda do |server|
499
+ identity = "-i #{config[:ssh_identity_file]} " if config[:ssh_identity_file]
500
+ prefix = server.user ? "#{server.user}@" : ""
501
+ "'ssh #{identity}#{prefix}#{server.host}'"
502
+ end
503
+
504
+ new_window_cmds = lambda do
505
+ if session.servers_for.size > 1
506
+ [""] + session.servers_for[1..].map do |server|
507
+ if config[:tmux_split]
508
+ "split-window #{ssh_dest.call(server)}; tmux select-layout tiled"
509
+ else
510
+ "new-window -a -n '#{server.host}' #{ssh_dest.call(server)}"
511
+ end
512
+ end
513
+ else
514
+ []
515
+ end.join(" \\; ")
516
+ end
517
+
518
+ tmux_name = "'knife ssh #{@name_args[0].tr(":.", "=-")}'"
519
+ begin
520
+ server = session.servers_for.first
521
+ cmd = ["tmux new-session -d -s #{tmux_name}",
522
+ "-n '#{server.host}'", ssh_dest.call(server),
523
+ new_window_cmds.call].join(" ")
524
+ shell_out!(cmd)
525
+ exec("tmux attach-session -t #{tmux_name}")
526
+ rescue Chef::Exceptions::Exec
527
+ end
528
+ end
529
+
530
+ def macterm
531
+ begin
532
+ require "appscript" unless defined?(Appscript)
533
+ rescue LoadError
534
+ STDERR.puts "You need the rb-appscript gem to use knife ssh macterm. `(sudo) gem install rb-appscript` to install"
535
+ raise
536
+ end
537
+
538
+ Appscript.app("/Applications/Utilities/Terminal.app").windows.first.activate
539
+ Appscript.app("System Events").application_processes["Terminal.app"].keystroke("n", using: :command_down)
540
+ term = Appscript.app("Terminal")
541
+ window = term.windows.first.get
542
+
543
+ (session.servers_for.size - 1).times do |i|
544
+ window.activate
545
+ Appscript.app("System Events").application_processes["Terminal.app"].keystroke("t", using: :command_down)
546
+ end
547
+
548
+ session.servers_for.each_with_index do |server, tab_number|
549
+ cmd = "unset PROMPT_COMMAND; echo -e \"\\033]0;#{server.host}\\007\"; ssh #{server.user ? "#{server.user}@#{server.host}" : server.host}"
550
+ Appscript.app("Terminal").do_script(cmd, in: window.tabs[tab_number + 1].get)
551
+ end
552
+ end
553
+
554
+ def cssh
555
+ cssh_cmd = nil
556
+ %w{csshX cssh}.each do |cmd|
557
+
558
+ # Unix and Mac only
559
+ cssh_cmd = shell_out!("which #{cmd}").stdout.strip
560
+ break
561
+ rescue Mixlib::ShellOut::ShellCommandFailed
562
+
563
+ end
564
+ raise Chef::Exceptions::Exec, "no command found for cssh" unless cssh_cmd
565
+
566
+ # pass in the consolidated identity file option to cssh(X)
567
+ if config[:ssh_identity_file]
568
+ cssh_cmd << " --ssh_args '-i #{File.expand_path(config[:ssh_identity_file])}'"
569
+ end
570
+
571
+ session.servers_for.each do |server|
572
+ cssh_cmd << " #{server.user ? "#{server.user}@#{server.host}" : server.host}"
573
+ end
574
+ Chef::Log.debug("Starting cssh session with command: #{cssh_cmd}")
575
+ exec(cssh_cmd)
576
+ end
577
+
578
+ def get_stripped_unfrozen_value(value)
579
+ return nil unless value
580
+
581
+ value.strip
582
+ end
583
+
584
+ def configure_user
585
+ config[:ssh_user] = get_stripped_unfrozen_value(config[:ssh_user] ||
586
+ Chef::Config[:knife][:ssh_user])
587
+ end
588
+
589
+ def configure_password
590
+ if config.key?(:ssh_password) && config[:ssh_password].nil?
591
+ # if we have an actual nil that means someone called "--ssh-password" with no value, so we prompt for a password
592
+ config[:ssh_password] = get_password
593
+ else
594
+ # the false default of ssh_password results in a nil here
595
+ config[:ssh_password] = get_stripped_unfrozen_value(config[:ssh_password])
596
+ end
597
+ end
598
+
599
+ def configure_ssh_identity_file
600
+ config[:ssh_identity_file] = get_stripped_unfrozen_value(config[:ssh_identity_file])
601
+ end
602
+
603
+ def configure_ssh_gateway_identity
604
+ config[:ssh_gateway_identity] = get_stripped_unfrozen_value(config[:ssh_gateway_identity])
605
+ end
606
+
607
+ def run
608
+ @longest = 0
609
+
610
+ if @name_args.length < 1
611
+ show_usage
612
+ ui.fatal("You must specify the SEARCH QUERY.")
613
+ exit(1)
614
+ end
615
+
616
+ configure_user
617
+ configure_password
618
+ @password = config[:ssh_password] if config[:ssh_password]
619
+
620
+ # If a password was not given, check for SSH identity file.
621
+ unless @password
622
+ configure_ssh_identity_file
623
+ configure_ssh_gateway_identity
624
+ end
625
+
626
+ configure_gateway
627
+ configure_session
628
+
629
+ exit_status =
630
+ case @name_args[1]
631
+ when "interactive"
632
+ interactive
633
+ when "screen"
634
+ screen
635
+ when "tmux"
636
+ tmux
637
+ when "macterm"
638
+ macterm
639
+ when "cssh"
640
+ cssh
641
+ else
642
+ ssh_command(@name_args[1..].join(" "))
643
+ end
644
+
645
+ session.close
646
+ if exit_status && exit_status != 0
647
+ exit exit_status
648
+ else
649
+ exit_status
650
+ end
651
+ end
652
+
653
+ private :search_nodes
654
+
655
+ end
656
+ end
657
+ end