knife 17.0.244 → 17.2.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (572) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -5
  3. data/Rakefile +1 -6
  4. data/knife.gemspec +5 -5
  5. data/lib/chef/knife/configure.rb +1 -1
  6. data/lib/chef/knife/ssl_fetch.rb +1 -1
  7. data/lib/chef/knife/version.rb +1 -1
  8. data/spec/data/apt/chef-integration-test-1.0/debian/changelog +5 -0
  9. data/spec/data/apt/chef-integration-test-1.0/debian/compat +1 -0
  10. data/spec/data/apt/chef-integration-test-1.0/debian/control +13 -0
  11. data/spec/data/apt/chef-integration-test-1.0/debian/copyright +34 -0
  12. data/spec/data/apt/chef-integration-test-1.0/debian/files +1 -0
  13. data/spec/data/apt/chef-integration-test-1.0/debian/rules +13 -0
  14. data/spec/data/apt/chef-integration-test-1.0/debian/source/format +1 -0
  15. data/spec/data/apt/chef-integration-test-1.1/debian/changelog +11 -0
  16. data/spec/data/apt/chef-integration-test-1.1/debian/compat +1 -0
  17. data/spec/data/apt/chef-integration-test-1.1/debian/control +13 -0
  18. data/spec/data/apt/chef-integration-test-1.1/debian/copyright +34 -0
  19. data/spec/data/apt/chef-integration-test-1.1/debian/files +1 -0
  20. data/spec/data/apt/chef-integration-test-1.1/debian/rules +13 -0
  21. data/spec/data/apt/chef-integration-test-1.1/debian/source/format +1 -0
  22. data/spec/data/apt/chef-integration-test2-1.0/debian/changelog +5 -0
  23. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.debhelper.log +45 -0
  24. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2.substvars +1 -0
  25. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/conffiles +1 -0
  26. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/control +10 -0
  27. data/spec/data/apt/chef-integration-test2-1.0/debian/chef-integration-test2/DEBIAN/md5sums +1 -0
  28. data/spec/data/apt/chef-integration-test2-1.0/debian/compat +1 -0
  29. data/spec/data/apt/chef-integration-test2-1.0/debian/conffiles +1 -0
  30. data/spec/data/apt/chef-integration-test2-1.0/debian/control +13 -0
  31. data/spec/data/apt/chef-integration-test2-1.0/debian/copyright +34 -0
  32. data/spec/data/apt/chef-integration-test2-1.0/debian/files +1 -0
  33. data/spec/data/apt/chef-integration-test2-1.0/debian/rules +13 -0
  34. data/spec/data/apt/chef-integration-test2-1.0/debian/source/format +1 -0
  35. data/spec/data/apt/chef-integration-test2_1.0-1.debian.tar.gz +0 -0
  36. data/spec/data/apt/chef-integration-test2_1.0-1.dsc +18 -0
  37. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.build +91 -0
  38. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.changes +31 -0
  39. data/spec/data/apt/chef-integration-test2_1.0-1_amd64.deb +0 -0
  40. data/spec/data/apt/chef-integration-test2_1.0.orig.tar.gz +0 -0
  41. data/spec/data/apt/chef-integration-test_1.0-1_amd64.changes +22 -0
  42. data/spec/data/apt/chef-integration-test_1.0-1_amd64.deb +0 -0
  43. data/spec/data/apt/chef-integration-test_1.0.orig.tar.gz +0 -0
  44. data/spec/data/apt/chef-integration-test_1.1-1_amd64.changes +22 -0
  45. data/spec/data/apt/chef-integration-test_1.1-1_amd64.deb +0 -0
  46. data/spec/data/apt/chef-integration-test_1.1.orig.tar.gz +0 -0
  47. data/spec/data/apt/var/www/apt/conf/distributions +7 -0
  48. data/spec/data/apt/var/www/apt/conf/incoming +4 -0
  49. data/spec/data/apt/var/www/apt/conf/pulls +3 -0
  50. data/spec/data/apt/var/www/apt/db/checksums.db +0 -0
  51. data/spec/data/apt/var/www/apt/db/contents.cache.db +0 -0
  52. data/spec/data/apt/var/www/apt/db/packages.db +0 -0
  53. data/spec/data/apt/var/www/apt/db/references.db +0 -0
  54. data/spec/data/apt/var/www/apt/db/release.caches.db +0 -0
  55. data/spec/data/apt/var/www/apt/db/version +4 -0
  56. data/spec/data/apt/var/www/apt/dists/sid/Release +19 -0
  57. data/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages +16 -0
  58. data/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Packages.gz +0 -0
  59. data/spec/data/apt/var/www/apt/dists/sid/main/binary-amd64/Release +5 -0
  60. data/spec/data/apt/var/www/apt/dists/sid/main/binary-i386/Packages +0 -0
  61. data/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.0-1_amd64.deb +0 -0
  62. data/spec/data/apt/var/www/apt/pool/main/c/chef-integration-test/chef-integration-test_1.1-1_amd64.deb +0 -0
  63. data/spec/data/bad-config.rb +1 -0
  64. data/spec/data/bootstrap/encrypted_data_bag_secret +1 -0
  65. data/spec/data/bootstrap/no_proxy.erb +2 -0
  66. data/spec/data/bootstrap/secret.erb +9 -0
  67. data/spec/data/bootstrap/test-hints.erb +12 -0
  68. data/spec/data/bootstrap/test.erb +1 -0
  69. data/spec/data/cb_version_cookbooks/cookbook2/files/test.txt +0 -0
  70. data/spec/data/cb_version_cookbooks/cookbook2/templates/test.erb +0 -0
  71. data/spec/data/cb_version_cookbooks/tatft/README.rdoc +3 -0
  72. data/spec/data/cb_version_cookbooks/tatft/attributes/default.rb +1 -0
  73. data/spec/data/cb_version_cookbooks/tatft/definitions/runit_service.rb +1 -0
  74. data/spec/data/cb_version_cookbooks/tatft/files/default/giant_blob.tgz +1 -0
  75. data/spec/data/cb_version_cookbooks/tatft/libraries/ownage.rb +1 -0
  76. data/spec/data/cb_version_cookbooks/tatft/providers/lwp.rb +1 -0
  77. data/spec/data/cb_version_cookbooks/tatft/recipes/default.rb +1 -0
  78. data/spec/data/cb_version_cookbooks/tatft/resources/lwr.rb +1 -0
  79. data/spec/data/cb_version_cookbooks/tatft/templates/default/configuration.erb +0 -0
  80. data/spec/data/checksum/random.txt +1 -0
  81. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-600hhz-0 +1 -0
  82. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-6m8zdk-0 +0 -0
  83. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ahd2gq-0 +1 -0
  84. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-api8ux-0 +1 -0
  85. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-b0r1m1-0 +1 -0
  86. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-bfygsi-0 +1 -0
  87. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-el14l6-0 +1 -0
  88. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ivrl3y-0 +1 -0
  89. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-kkbs85-0 +1 -0
  90. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ory1ux-0 +1 -0
  91. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-pgsq76-0 +1 -0
  92. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ra8uim-0 +1 -0
  93. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t7k1g-0 +1 -0
  94. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-t8g0sv-0 +1 -0
  95. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-ufy6g3-0 +1 -0
  96. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-x2d6j9-0 +1 -0
  97. data/spec/data/checksum_cache/chef-file--tmp-chef-rendered-template20100929-10863-xi0l6h-0 +1 -0
  98. data/spec/data/client.d_00/00-foo.rb +2 -0
  99. data/spec/data/client.d_00/01-bar.rb +1 -0
  100. data/spec/data/client.d_00/02-strings.rb +2 -0
  101. data/spec/data/client.d_00/bar +1 -0
  102. data/spec/data/client.d_01/foo/bar.rb +1 -0
  103. data/spec/data/client.d_02/foo.rb/foo.txt +1 -0
  104. data/spec/data/config.rb +6 -0
  105. data/spec/data/cookbooks/angrybash/metadata.rb +2 -0
  106. data/spec/data/cookbooks/angrybash/recipes/default.rb +8 -0
  107. data/spec/data/cookbooks/apache2/files/default/apache2_module_conf_generate.pl +2 -0
  108. data/spec/data/cookbooks/apache2/metadata.json +33 -0
  109. data/spec/data/cookbooks/apache2/metadata.rb +2 -0
  110. data/spec/data/cookbooks/apache2/recipes/default.rb +3 -0
  111. data/spec/data/cookbooks/borken/metadata.rb +2 -0
  112. data/spec/data/cookbooks/borken/recipes/default.rb +2 -0
  113. data/spec/data/cookbooks/borken/templates/default/borken.erb +2 -0
  114. data/spec/data/cookbooks/chefignore +8 -0
  115. data/spec/data/cookbooks/ignorken/files/default/not_me.rb +2 -0
  116. data/spec/data/cookbooks/ignorken/metadata.rb +2 -0
  117. data/spec/data/cookbooks/ignorken/recipes/default.rb +1 -0
  118. data/spec/data/cookbooks/ignorken/recipes/ignoreme.rb +2 -0
  119. data/spec/data/cookbooks/ignorken/templates/ubuntu-12.10/not_me.rb +2 -0
  120. data/spec/data/cookbooks/irssi/files/default/irssi.response +2 -0
  121. data/spec/data/cookbooks/java/files/default/java.response +2 -0
  122. data/spec/data/cookbooks/java/metadata.json +33 -0
  123. data/spec/data/cookbooks/java/metadata.rb +2 -0
  124. data/spec/data/cookbooks/name-mismatch-versionnumber/README.md +4 -0
  125. data/spec/data/cookbooks/name-mismatch-versionnumber/metadata.rb +8 -0
  126. data/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb +8 -0
  127. data/spec/data/cookbooks/openldap/.root_dotfile +0 -0
  128. data/spec/data/cookbooks/openldap/attributes/default.rb +16 -0
  129. data/spec/data/cookbooks/openldap/attributes/smokey.rb +1 -0
  130. data/spec/data/cookbooks/openldap/definitions/client.rb +5 -0
  131. data/spec/data/cookbooks/openldap/definitions/server.rb +5 -0
  132. data/spec/data/cookbooks/openldap/files/default/.dotfile +1 -0
  133. data/spec/data/cookbooks/openldap/files/default/.ssh/id_rsa +1 -0
  134. data/spec/data/cookbooks/openldap/files/default/remotedir/.a_dotdir/.a_dotfile_in_a_dotdir +1 -0
  135. data/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb +2 -0
  136. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file1.txt +3 -0
  137. data/spec/data/cookbooks/openldap/files/default/remotedir/remote_dir_file2.txt +3 -0
  138. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/.a_dotfile +1 -0
  139. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file1.txt +3 -0
  140. data/spec/data/cookbooks/openldap/files/default/remotedir/remotesubdir/remote_subdir_file2.txt +3 -0
  141. data/spec/data/cookbooks/openldap/files/default/remotedir/subdir_with_no_file_just_a_subsubdir/the_subsubdir/some_file.txt +3 -0
  142. data/spec/data/cookbooks/openldap/libraries/openldap.rb +4 -0
  143. data/spec/data/cookbooks/openldap/libraries/openldap/version.rb +3 -0
  144. data/spec/data/cookbooks/openldap/metadata.rb +8 -0
  145. data/spec/data/cookbooks/openldap/recipes/default.rb +4 -0
  146. data/spec/data/cookbooks/openldap/recipes/gigantor.rb +3 -0
  147. data/spec/data/cookbooks/openldap/recipes/one.rb +15 -0
  148. data/spec/data/cookbooks/openldap/recipes/return.rb +2 -0
  149. data/spec/data/cookbooks/openldap/spec/spec_helper.rb +0 -0
  150. data/spec/data/cookbooks/openldap/templates/default/all_windows_line_endings.erb +4 -0
  151. data/spec/data/cookbooks/openldap/templates/default/helper_test.erb +1 -0
  152. data/spec/data/cookbooks/openldap/templates/default/helpers.erb +14 -0
  153. data/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb +1 -0
  154. data/spec/data/cookbooks/openldap/templates/default/nested_openldap_partials.erb +1 -0
  155. data/spec/data/cookbooks/openldap/templates/default/nested_partial.erb +1 -0
  156. data/spec/data/cookbooks/openldap/templates/default/no_windows_line_endings.erb +4 -0
  157. data/spec/data/cookbooks/openldap/templates/default/openldap_nested_variable_stuff.erb +1 -0
  158. data/spec/data/cookbooks/openldap/templates/default/openldap_stuff.conf.erb +1 -0
  159. data/spec/data/cookbooks/openldap/templates/default/openldap_variable_stuff.conf.erb +1 -0
  160. data/spec/data/cookbooks/openldap/templates/default/some_windows_line_endings.erb +4 -0
  161. data/spec/data/cookbooks/openldap/templates/default/test.erb +1 -0
  162. data/spec/data/cookbooks/preseed/files/default/preseed-file.seed +1 -0
  163. data/spec/data/cookbooks/preseed/files/default/preseed-template.seed +4 -0
  164. data/spec/data/cookbooks/preseed/metadata.rb +2 -0
  165. data/spec/data/cookbooks/preseed/templates/default/preseed-template-variables.seed +1 -0
  166. data/spec/data/cookbooks/preseed/templates/default/preseed-template.seed +1 -0
  167. data/spec/data/cookbooks/starter/chefignore +8 -0
  168. data/spec/data/cookbooks/starter/files/sample.txt +1 -0
  169. data/spec/data/cookbooks/starter/metadata.rb +2 -0
  170. data/spec/data/cookbooks/starter/recipes/default.rb +4 -0
  171. data/spec/data/cookbooks/supports-platform-constraints/metadata.rb +5 -0
  172. data/spec/data/cookbooks/wget/files/default/wget.response +2 -0
  173. data/spec/data/definitions/test.rb +5 -0
  174. data/spec/data/dsc_lcm.pfx +0 -0
  175. data/spec/data/environment-config.rb +5 -0
  176. data/spec/data/file-providers-method-snapshot-chef-11-4.json +127 -0
  177. data/spec/data/fileedit/blank +0 -0
  178. data/spec/data/fileedit/hosts +4 -0
  179. data/spec/data/gems/chef-integration-test-0.1.0.gem +0 -0
  180. data/spec/data/git_bundles/example-repo.gitbundle +0 -0
  181. data/spec/data/git_bundles/sinatra-test-app-with-callback-files.gitbundle +0 -0
  182. data/spec/data/git_bundles/sinatra-test-app-with-symlinks.gitbundle +0 -0
  183. data/spec/data/git_bundles/sinatra-test-app.gitbundle +0 -0
  184. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/README.md +4 -0
  185. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/metadata.rb +13 -0
  186. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb +8 -0
  187. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/README.md +4 -0
  188. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb +9 -0
  189. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb +8 -0
  190. data/spec/data/kitchen/chefignore +6 -0
  191. data/spec/data/kitchen/openldap/attributes/default.rb +3 -0
  192. data/spec/data/kitchen/openldap/attributes/robinson.rb +3 -0
  193. data/spec/data/kitchen/openldap/definitions/client.rb +3 -0
  194. data/spec/data/kitchen/openldap/definitions/drewbarrymore.rb +3 -0
  195. data/spec/data/kitchen/openldap/recipes/gigantor.rb +3 -0
  196. data/spec/data/kitchen/openldap/recipes/ignoreme.rb +3 -0
  197. data/spec/data/kitchen/openldap/recipes/woot.rb +3 -0
  198. data/spec/data/knife-home/.chef/plugins/knife/example_home_subcommand.rb +0 -0
  199. data/spec/data/knife-site-subcommands/plugins/knife/example_subcommand.rb +0 -0
  200. data/spec/data/knife_subcommand/test_explicit_category.rb +7 -0
  201. data/spec/data/knife_subcommand/test_name_mapping.rb +4 -0
  202. data/spec/data/knife_subcommand/test_yourself.rb +21 -0
  203. data/spec/data/lwrp/providers/buck_passer.rb +28 -0
  204. data/spec/data/lwrp/providers/buck_passer_2.rb +26 -0
  205. data/spec/data/lwrp/providers/embedded_resource_accesses_providers_scope.rb +28 -0
  206. data/spec/data/lwrp/providers/inline_compiler.rb +24 -0
  207. data/spec/data/lwrp/providers/monkey_name_printer.rb +5 -0
  208. data/spec/data/lwrp/providers/paint_drying_watcher.rb +7 -0
  209. data/spec/data/lwrp/providers/thumb_twiddler.rb +7 -0
  210. data/spec/data/lwrp/resources/bar.rb +4 -0
  211. data/spec/data/lwrp/resources/buck_passer.rb +6 -0
  212. data/spec/data/lwrp/resources/buck_passer_2.rb +4 -0
  213. data/spec/data/lwrp/resources/embedded_resource_accesses_providers_scope.rb +4 -0
  214. data/spec/data/lwrp/resources/foo.rb +6 -0
  215. data/spec/data/lwrp/resources/inline_compiler.rb +4 -0
  216. data/spec/data/lwrp/resources/monkey_name_printer.rb +6 -0
  217. data/spec/data/lwrp/resources/paint_drying_watcher.rb +4 -0
  218. data/spec/data/lwrp/resources/thumb_twiddler.rb +4 -0
  219. data/spec/data/lwrp/resources_with_default_attributes/nodeattr.rb +3 -0
  220. data/spec/data/lwrp_const_scoping/resources/conflict.rb +1 -0
  221. data/spec/data/lwrp_override/providers/buck_passer.rb +5 -0
  222. data/spec/data/lwrp_override/resources/foo.rb +11 -0
  223. data/spec/data/mac_users/10.9.plist.xml +560 -0
  224. data/spec/data/mac_users/10.9.shadow.xml +21 -0
  225. data/spec/data/metadata/quick_start/metadata.rb +14 -0
  226. data/spec/data/mixin/invalid_data.rb +3 -0
  227. data/spec/data/mixin/real_data.rb +2 -0
  228. data/spec/data/nested.json +2 -0
  229. data/spec/data/nodes/default.rb +15 -0
  230. data/spec/data/nodes/test.example.com.rb +17 -0
  231. data/spec/data/nodes/test.rb +15 -0
  232. data/spec/data/null_config.rb +1 -0
  233. data/spec/data/object_loader/environments/test.json +7 -0
  234. data/spec/data/object_loader/environments/test.rb +2 -0
  235. data/spec/data/object_loader/environments/test_json_class.json +8 -0
  236. data/spec/data/object_loader/nodes/test.json +7 -0
  237. data/spec/data/object_loader/nodes/test.rb +2 -0
  238. data/spec/data/object_loader/nodes/test_json_class.json +8 -0
  239. data/spec/data/object_loader/roles/test.json +7 -0
  240. data/spec/data/object_loader/roles/test.rb +2 -0
  241. data/spec/data/object_loader/roles/test_json_class.json +8 -0
  242. data/spec/data/old_home_dir/my-dot-emacs +0 -0
  243. data/spec/data/old_home_dir/my-dot-vim +0 -0
  244. data/spec/data/partial_one.erb +1 -0
  245. data/spec/data/prefer_metadata_json/metadata.json +51 -0
  246. data/spec/data/prefer_metadata_json/metadata.rb +6 -0
  247. data/spec/data/prefer_metadata_json/recipes/default.rb +0 -0
  248. data/spec/data/recipes.tgz +0 -0
  249. data/spec/data/recipes/test.rb +7 -0
  250. data/spec/data/remote_directory_data/remote_dir_file.txt +1 -0
  251. data/spec/data/remote_directory_data/remote_subdirectory/remote_subdir_file.txt +1 -0
  252. data/spec/data/remote_file/nyan_cat.png +0 -0
  253. data/spec/data/remote_file/nyan_cat.png.gz +0 -0
  254. data/spec/data/root_alias_cookbooks/dup_attr/attributes.rb +1 -0
  255. data/spec/data/root_alias_cookbooks/dup_attr/attributes/default.rb +1 -0
  256. data/spec/data/root_alias_cookbooks/dup_attr/metadata.rb +2 -0
  257. data/spec/data/root_alias_cookbooks/dup_attr/recipe.rb +3 -0
  258. data/spec/data/root_alias_cookbooks/dup_recipe/attributes.rb +1 -0
  259. data/spec/data/root_alias_cookbooks/dup_recipe/metadata.rb +2 -0
  260. data/spec/data/root_alias_cookbooks/dup_recipe/recipe.rb +3 -0
  261. data/spec/data/root_alias_cookbooks/dup_recipe/recipes/default.rb +3 -0
  262. data/spec/data/root_alias_cookbooks/simple/attributes.rb +1 -0
  263. data/spec/data/root_alias_cookbooks/simple/metadata.rb +2 -0
  264. data/spec/data/root_alias_cookbooks/simple/recipe.rb +3 -0
  265. data/spec/data/rubygems.org/latest_specs.4.8.gz +0 -0
  266. data/spec/data/rubygems.org/nonexistent_gem +0 -0
  267. data/spec/data/rubygems.org/nonexistent_gem-info +1 -0
  268. data/spec/data/rubygems.org/sexp_processor +0 -0
  269. data/spec/data/rubygems.org/sexp_processor-4.15.1.gemspec.rz +0 -0
  270. data/spec/data/rubygems.org/sexp_processor-info +49 -0
  271. data/spec/data/run_context/cookbooks/circular-dep1/attributes/default.rb +2 -0
  272. data/spec/data/run_context/cookbooks/circular-dep1/definitions/circular_dep1_res.rb +1 -0
  273. data/spec/data/run_context/cookbooks/circular-dep1/libraries/lib.rb +2 -0
  274. data/spec/data/run_context/cookbooks/circular-dep1/metadata.rb +2 -0
  275. data/spec/data/run_context/cookbooks/circular-dep1/providers/provider.rb +1 -0
  276. data/spec/data/run_context/cookbooks/circular-dep1/recipes/default.rb +0 -0
  277. data/spec/data/run_context/cookbooks/circular-dep1/resources/resource.rb +2 -0
  278. data/spec/data/run_context/cookbooks/circular-dep2/attributes/default.rb +2 -0
  279. data/spec/data/run_context/cookbooks/circular-dep2/definitions/circular_dep2_res.rb +1 -0
  280. data/spec/data/run_context/cookbooks/circular-dep2/libraries/lib.rb +2 -0
  281. data/spec/data/run_context/cookbooks/circular-dep2/metadata.rb +2 -0
  282. data/spec/data/run_context/cookbooks/circular-dep2/providers/provider.rb +1 -0
  283. data/spec/data/run_context/cookbooks/circular-dep2/recipes/default.rb +0 -0
  284. data/spec/data/run_context/cookbooks/circular-dep2/resources/resource.rb +2 -0
  285. data/spec/data/run_context/cookbooks/dependency1/attributes/aa_first.rb +2 -0
  286. data/spec/data/run_context/cookbooks/dependency1/attributes/default.rb +2 -0
  287. data/spec/data/run_context/cookbooks/dependency1/attributes/unparsed_file +1 -0
  288. data/spec/data/run_context/cookbooks/dependency1/attributes/zz_last.rb +2 -0
  289. data/spec/data/run_context/cookbooks/dependency1/definitions/dependency1_res.rb +1 -0
  290. data/spec/data/run_context/cookbooks/dependency1/definitions/unparsed_file +1 -0
  291. data/spec/data/run_context/cookbooks/dependency1/libraries/lib.rb +2 -0
  292. data/spec/data/run_context/cookbooks/dependency1/libraries/unparsed_file +1 -0
  293. data/spec/data/run_context/cookbooks/dependency1/providers/provider.rb +1 -0
  294. data/spec/data/run_context/cookbooks/dependency1/providers/unparsed_file +1 -0
  295. data/spec/data/run_context/cookbooks/dependency1/recipes/default.rb +0 -0
  296. data/spec/data/run_context/cookbooks/dependency1/recipes/unparsed_file +1 -0
  297. data/spec/data/run_context/cookbooks/dependency1/resources/resource.rb +2 -0
  298. data/spec/data/run_context/cookbooks/dependency1/resources/unparsed_file +1 -0
  299. data/spec/data/run_context/cookbooks/dependency2/attributes/default.rb +2 -0
  300. data/spec/data/run_context/cookbooks/dependency2/definitions/dependency2_res.rb +1 -0
  301. data/spec/data/run_context/cookbooks/dependency2/libraries/lib.rb +2 -0
  302. data/spec/data/run_context/cookbooks/dependency2/providers/provider.rb +1 -0
  303. data/spec/data/run_context/cookbooks/dependency2/recipes/default.rb +0 -0
  304. data/spec/data/run_context/cookbooks/dependency2/resources/resource.rb +2 -0
  305. data/spec/data/run_context/cookbooks/include/recipes/default.rb +24 -0
  306. data/spec/data/run_context/cookbooks/include/recipes/includee.rb +3 -0
  307. data/spec/data/run_context/cookbooks/no-default-attr/attributes/server.rb +2 -0
  308. data/spec/data/run_context/cookbooks/no-default-attr/definitions/no_default-attr_res.rb +1 -0
  309. data/spec/data/run_context/cookbooks/no-default-attr/providers/provider.rb +1 -0
  310. data/spec/data/run_context/cookbooks/no-default-attr/recipes/default.rb +0 -0
  311. data/spec/data/run_context/cookbooks/no-default-attr/resources/resource.rb +2 -0
  312. data/spec/data/run_context/cookbooks/test-with-circular-deps/attributes/default.rb +2 -0
  313. data/spec/data/run_context/cookbooks/test-with-circular-deps/definitions/test_with-circular-deps_res.rb +1 -0
  314. data/spec/data/run_context/cookbooks/test-with-circular-deps/libraries/lib.rb +2 -0
  315. data/spec/data/run_context/cookbooks/test-with-circular-deps/metadata.rb +2 -0
  316. data/spec/data/run_context/cookbooks/test-with-circular-deps/providers/provider.rb +1 -0
  317. data/spec/data/run_context/cookbooks/test-with-circular-deps/recipes/default.rb +0 -0
  318. data/spec/data/run_context/cookbooks/test-with-circular-deps/resources/resource.rb +3 -0
  319. data/spec/data/run_context/cookbooks/test-with-deps/attributes/default.rb +2 -0
  320. data/spec/data/run_context/cookbooks/test-with-deps/definitions/test_with-deps_res.rb +1 -0
  321. data/spec/data/run_context/cookbooks/test-with-deps/libraries/lib.rb +1 -0
  322. data/spec/data/run_context/cookbooks/test-with-deps/metadata.rb +3 -0
  323. data/spec/data/run_context/cookbooks/test-with-deps/providers/provider.rb +1 -0
  324. data/spec/data/run_context/cookbooks/test-with-deps/recipes/default.rb +0 -0
  325. data/spec/data/run_context/cookbooks/test-with-deps/recipes/server.rb +0 -0
  326. data/spec/data/run_context/cookbooks/test-with-deps/resources/resource.rb +2 -0
  327. data/spec/data/run_context/cookbooks/test/attributes/default.rb +0 -0
  328. data/spec/data/run_context/cookbooks/test/attributes/george.rb +1 -0
  329. data/spec/data/run_context/cookbooks/test/definitions/new_animals.rb +9 -0
  330. data/spec/data/run_context/cookbooks/test/definitions/new_cat.rb +5 -0
  331. data/spec/data/run_context/cookbooks/test/definitions/test_res.rb +1 -0
  332. data/spec/data/run_context/cookbooks/test/providers/provider.rb +1 -0
  333. data/spec/data/run_context/cookbooks/test/recipes/default.rb +5 -0
  334. data/spec/data/run_context/cookbooks/test/recipes/one.rb +7 -0
  335. data/spec/data/run_context/cookbooks/test/recipes/two.rb +7 -0
  336. data/spec/data/run_context/cookbooks/test/resources/resource.rb +3 -0
  337. data/spec/data/run_context/nodes/run_context.rb +5 -0
  338. data/spec/data/sample_msu1.xml +10 -0
  339. data/spec/data/sample_msu2.xml +14 -0
  340. data/spec/data/sample_msu3.xml +16 -0
  341. data/spec/data/search_queries_to_transform.txt +98 -0
  342. data/spec/data/shef-config.rb +11 -0
  343. data/spec/data/snap_package/async_result_success.json +6 -0
  344. data/spec/data/snap_package/change_id_result.json +175 -0
  345. data/spec/data/snap_package/find_result_failure.json +10 -0
  346. data/spec/data/snap_package/find_result_success.json +70 -0
  347. data/spec/data/snap_package/get_by_name_result_failure.json +10 -0
  348. data/spec/data/snap_package/get_by_name_result_success.json +38 -0
  349. data/spec/data/snap_package/get_conf_success.json +10 -0
  350. data/spec/data/snap_package/result_failure.json +9 -0
  351. data/spec/data/ssl/5e707473.0 +18 -0
  352. data/spec/data/ssl/binary/chef-rspec-der.cert +0 -0
  353. data/spec/data/ssl/binary/chef-rspec-der.key +0 -0
  354. data/spec/data/ssl/chef-rspec.cert +27 -0
  355. data/spec/data/ssl/chef-rspec.key +27 -0
  356. data/spec/data/ssl/key.pem +15 -0
  357. data/spec/data/ssl/private_key.pem +27 -0
  358. data/spec/data/ssl/private_key_with_whitespace.pem +32 -0
  359. data/spec/data/standalone_cookbook/Gemfile +1 -0
  360. data/spec/data/standalone_cookbook/chefignore +9 -0
  361. data/spec/data/standalone_cookbook/recipes/default.rb +3 -0
  362. data/spec/data/standalone_cookbook/vendor/bundle/ruby/2.0.0/gems/multi_json-1.9.0/lib/multi_json.rb +1 -0
  363. data/spec/data/templates/chef-seattle20160930-4388-1crv7ef.txt +1 -0
  364. data/spec/data/templates/chef-seattle20160930-4388-jjfoae.txt +1 -0
  365. data/spec/data/templates/chef-seattle20160930-4388-umeq2c.txt +1 -0
  366. data/spec/data/templates/failed.erb +5 -0
  367. data/spec/data/templates/seattle.txt +1 -0
  368. data/spec/data/trusted_certs/example.crt +22 -0
  369. data/spec/data/trusted_certs/example_no_cn.crt +36 -0
  370. data/spec/data/trusted_certs/intermediate.pem +27 -0
  371. data/spec/data/trusted_certs/opscode.pem +57 -0
  372. data/spec/data/trusted_certs/root.pem +22 -0
  373. data/spec/data/windows_certificates/base64_test.cer +20 -0
  374. data/spec/data/windows_certificates/othertest.cer +20 -0
  375. data/spec/data/windows_certificates/test.cer +20 -0
  376. data/spec/data/windows_certificates/test.p7b +0 -0
  377. data/spec/data/windows_certificates/test.pem +20 -0
  378. data/spec/data/windows_certificates/test.pfx +0 -0
  379. data/spec/functional/configure_spec.rb +33 -0
  380. data/spec/functional/cookbook_delete_spec.rb +156 -0
  381. data/spec/functional/exec_spec.rb +55 -0
  382. data/spec/functional/rehash_spec.rb +39 -0
  383. data/spec/functional/smoke_test.rb +42 -0
  384. data/spec/functional/ssh_spec.rb +352 -0
  385. data/spec/functional/version_spec.rb +26 -0
  386. data/spec/integration/chef_fs_data_store_spec.rb +557 -0
  387. data/spec/integration/chef_repo_path_spec.rb +962 -0
  388. data/spec/integration/chef_repository_file_system_spec.rb +200 -0
  389. data/spec/integration/chefignore_spec.rb +301 -0
  390. data/spec/integration/client_bulk_delete_spec.rb +131 -0
  391. data/spec/integration/client_create_spec.rb +70 -0
  392. data/spec/integration/client_delete_spec.rb +64 -0
  393. data/spec/integration/client_key_create_spec.rb +66 -0
  394. data/spec/integration/client_key_delete_spec.rb +43 -0
  395. data/spec/integration/client_key_list_spec.rb +61 -0
  396. data/spec/integration/client_key_show_spec.rb +45 -0
  397. data/spec/integration/client_list_spec.rb +49 -0
  398. data/spec/integration/client_show_spec.rb +37 -0
  399. data/spec/integration/common_options_spec.rb +174 -0
  400. data/spec/integration/config_list_spec.rb +220 -0
  401. data/spec/integration/config_show_spec.rb +192 -0
  402. data/spec/integration/config_use_spec.rb +198 -0
  403. data/spec/integration/cookbook_api_ipv6_spec.rb +113 -0
  404. data/spec/integration/cookbook_bulk_delete_spec.rb +65 -0
  405. data/spec/integration/cookbook_download_spec.rb +72 -0
  406. data/spec/integration/cookbook_list_spec.rb +55 -0
  407. data/spec/integration/cookbook_show_spec.rb +149 -0
  408. data/spec/integration/cookbook_upload_spec.rb +128 -0
  409. data/spec/integration/data_bag_create_spec.rb +125 -0
  410. data/spec/integration/data_bag_delete_spec.rb +59 -0
  411. data/spec/integration/data_bag_edit_spec.rb +105 -0
  412. data/spec/integration/data_bag_from_file_spec.rb +116 -0
  413. data/spec/integration/data_bag_list_spec.rb +44 -0
  414. data/spec/integration/data_bag_show_spec.rb +95 -0
  415. data/spec/integration/delete_spec.rb +1018 -0
  416. data/spec/integration/deps_spec.rb +703 -0
  417. data/spec/integration/diff_spec.rb +605 -0
  418. data/spec/integration/download_spec.rb +1336 -0
  419. data/spec/integration/environment_compare_spec.rb +75 -0
  420. data/spec/integration/environment_create_spec.rb +41 -0
  421. data/spec/integration/environment_delete_spec.rb +37 -0
  422. data/spec/integration/environment_from_file_spec.rb +116 -0
  423. data/spec/integration/environment_list_spec.rb +42 -0
  424. data/spec/integration/environment_show_spec.rb +77 -0
  425. data/spec/integration/list_spec.rb +1060 -0
  426. data/spec/integration/node_bulk_delete_spec.rb +52 -0
  427. data/spec/integration/node_create_spec.rb +47 -0
  428. data/spec/integration/node_delete_spec.rb +48 -0
  429. data/spec/integration/node_environment_set_spec.rb +46 -0
  430. data/spec/integration/node_from_file_spec.rb +59 -0
  431. data/spec/integration/node_list_spec.rb +45 -0
  432. data/spec/integration/node_run_list_add_spec.rb +54 -0
  433. data/spec/integration/node_run_list_remove_spec.rb +36 -0
  434. data/spec/integration/node_run_list_set_spec.rb +41 -0
  435. data/spec/integration/node_show_spec.rb +36 -0
  436. data/spec/integration/raw_spec.rb +297 -0
  437. data/spec/integration/redirection_spec.rb +64 -0
  438. data/spec/integration/role_bulk_delete_spec.rb +52 -0
  439. data/spec/integration/role_create_spec.rb +41 -0
  440. data/spec/integration/role_delete_spec.rb +48 -0
  441. data/spec/integration/role_from_file_spec.rb +96 -0
  442. data/spec/integration/role_list_spec.rb +45 -0
  443. data/spec/integration/role_show_spec.rb +51 -0
  444. data/spec/integration/search_node_spec.rb +40 -0
  445. data/spec/integration/serve_spec.rb +92 -0
  446. data/spec/integration/show_spec.rb +197 -0
  447. data/spec/integration/upload_spec.rb +1617 -0
  448. data/spec/knife_spec_helper.rb +241 -0
  449. data/spec/support/chef_helpers.rb +79 -0
  450. data/spec/support/key_helpers.rb +102 -0
  451. data/spec/support/platform_helpers.rb +251 -0
  452. data/spec/support/platforms/prof/gc.rb +51 -0
  453. data/spec/support/platforms/prof/win32.rb +45 -0
  454. data/spec/support/platforms/win32/spec_service.rb +57 -0
  455. data/spec/support/recipe_dsl_helper.rb +83 -0
  456. data/spec/support/shared/context/config.rb +18 -0
  457. data/spec/support/shared/functional/knife.rb +37 -0
  458. data/spec/support/shared/integration/integration_helper.rb +122 -0
  459. data/spec/support/shared/integration/knife_support.rb +192 -0
  460. data/spec/support/shared/matchers/exit_with_code.rb +32 -0
  461. data/spec/support/shared/matchers/match_environment_variable.rb +17 -0
  462. data/spec/support/shared/unit/knife_shared.rb +39 -0
  463. data/spec/support/shared/unit/mock_shellout.rb +49 -0
  464. data/spec/tiny_server.rb +190 -0
  465. data/spec/unit/application/knife_spec.rb +241 -0
  466. data/spec/unit/knife/bootstrap/chef_vault_handler_spec.rb +152 -0
  467. data/spec/unit/knife/bootstrap/client_builder_spec.rb +207 -0
  468. data/spec/unit/knife/bootstrap/train_connector_spec.rb +244 -0
  469. data/spec/unit/knife/bootstrap_spec.rb +2220 -0
  470. data/spec/unit/knife/client_bulk_delete_spec.rb +166 -0
  471. data/spec/unit/knife/client_create_spec.rb +169 -0
  472. data/spec/unit/knife/client_delete_spec.rb +99 -0
  473. data/spec/unit/knife/client_edit_spec.rb +53 -0
  474. data/spec/unit/knife/client_list_spec.rb +34 -0
  475. data/spec/unit/knife/client_reregister_spec.rb +62 -0
  476. data/spec/unit/knife/client_show_spec.rb +52 -0
  477. data/spec/unit/knife/configure_client_spec.rb +81 -0
  478. data/spec/unit/knife/configure_spec.rb +190 -0
  479. data/spec/unit/knife/cookbook_bulk_delete_spec.rb +87 -0
  480. data/spec/unit/knife/cookbook_delete_spec.rb +239 -0
  481. data/spec/unit/knife/cookbook_download_spec.rb +255 -0
  482. data/spec/unit/knife/cookbook_list_spec.rb +88 -0
  483. data/spec/unit/knife/cookbook_metadata_from_file_spec.rb +72 -0
  484. data/spec/unit/knife/cookbook_metadata_spec.rb +182 -0
  485. data/spec/unit/knife/cookbook_show_spec.rb +253 -0
  486. data/spec/unit/knife/cookbook_upload_spec.rb +364 -0
  487. data/spec/unit/knife/core/bootstrap_context_spec.rb +287 -0
  488. data/spec/unit/knife/core/cookbook_scm_repo_spec.rb +187 -0
  489. data/spec/unit/knife/core/cookbook_site_streaming_uploader_spec.rb +198 -0
  490. data/spec/unit/knife/core/gem_glob_loader_spec.rb +242 -0
  491. data/spec/unit/knife/core/hashed_command_loader_spec.rb +112 -0
  492. data/spec/unit/knife/core/node_editor_spec.rb +211 -0
  493. data/spec/unit/knife/core/object_loader_spec.rb +81 -0
  494. data/spec/unit/knife/core/status_presenter_spec.rb +54 -0
  495. data/spec/unit/knife/core/subcommand_loader_spec.rb +64 -0
  496. data/spec/unit/knife/core/ui_spec.rb +656 -0
  497. data/spec/unit/knife/core/windows_bootstrap_context_spec.rb +238 -0
  498. data/spec/unit/knife/data_bag_create_spec.rb +175 -0
  499. data/spec/unit/knife/data_bag_edit_spec.rb +126 -0
  500. data/spec/unit/knife/data_bag_from_file_spec.rb +174 -0
  501. data/spec/unit/knife/data_bag_secret_options_spec.rb +173 -0
  502. data/spec/unit/knife/data_bag_show_spec.rb +139 -0
  503. data/spec/unit/knife/environment_compare_spec.rb +112 -0
  504. data/spec/unit/knife/environment_create_spec.rb +91 -0
  505. data/spec/unit/knife/environment_delete_spec.rb +71 -0
  506. data/spec/unit/knife/environment_edit_spec.rb +79 -0
  507. data/spec/unit/knife/environment_from_file_spec.rb +90 -0
  508. data/spec/unit/knife/environment_list_spec.rb +54 -0
  509. data/spec/unit/knife/environment_show_spec.rb +52 -0
  510. data/spec/unit/knife/key_create_spec.rb +223 -0
  511. data/spec/unit/knife/key_delete_spec.rb +133 -0
  512. data/spec/unit/knife/key_edit_spec.rb +264 -0
  513. data/spec/unit/knife/key_helper.rb +74 -0
  514. data/spec/unit/knife/key_list_spec.rb +216 -0
  515. data/spec/unit/knife/key_show_spec.rb +126 -0
  516. data/spec/unit/knife/node_bulk_delete_spec.rb +94 -0
  517. data/spec/unit/knife/node_delete_spec.rb +77 -0
  518. data/spec/unit/knife/node_edit_spec.rb +116 -0
  519. data/spec/unit/knife/node_environment_set_spec.rb +61 -0
  520. data/spec/unit/knife/node_from_file_spec.rb +59 -0
  521. data/spec/unit/knife/node_list_spec.rb +62 -0
  522. data/spec/unit/knife/node_policy_set_spec.rb +122 -0
  523. data/spec/unit/knife/node_run_list_add_spec.rb +145 -0
  524. data/spec/unit/knife/node_run_list_remove_spec.rb +106 -0
  525. data/spec/unit/knife/node_run_list_set_spec.rb +115 -0
  526. data/spec/unit/knife/node_show_spec.rb +65 -0
  527. data/spec/unit/knife/org_create_spec.rb +76 -0
  528. data/spec/unit/knife/org_delete_spec.rb +41 -0
  529. data/spec/unit/knife/org_edit_spec.rb +49 -0
  530. data/spec/unit/knife/org_list_spec.rb +58 -0
  531. data/spec/unit/knife/org_show_spec.rb +45 -0
  532. data/spec/unit/knife/org_user_add_spec.rb +39 -0
  533. data/spec/unit/knife/raw_spec.rb +43 -0
  534. data/spec/unit/knife/role_bulk_delete_spec.rb +80 -0
  535. data/spec/unit/knife/role_create_spec.rb +80 -0
  536. data/spec/unit/knife/role_delete_spec.rb +67 -0
  537. data/spec/unit/knife/role_edit_spec.rb +77 -0
  538. data/spec/unit/knife/role_env_run_list_add_spec.rb +217 -0
  539. data/spec/unit/knife/role_env_run_list_clear_spec.rb +94 -0
  540. data/spec/unit/knife/role_env_run_list_remove_spec.rb +102 -0
  541. data/spec/unit/knife/role_env_run_list_replace_spec.rb +105 -0
  542. data/spec/unit/knife/role_env_run_list_set_spec.rb +99 -0
  543. data/spec/unit/knife/role_from_file_spec.rb +69 -0
  544. data/spec/unit/knife/role_list_spec.rb +54 -0
  545. data/spec/unit/knife/role_run_list_add_spec.rb +179 -0
  546. data/spec/unit/knife/role_run_list_clear_spec.rb +84 -0
  547. data/spec/unit/knife/role_run_list_remove_spec.rb +92 -0
  548. data/spec/unit/knife/role_run_list_replace_spec.rb +98 -0
  549. data/spec/unit/knife/role_run_list_set_spec.rb +89 -0
  550. data/spec/unit/knife/role_show_spec.rb +59 -0
  551. data/spec/unit/knife/ssh_spec.rb +403 -0
  552. data/spec/unit/knife/ssl_check_spec.rb +256 -0
  553. data/spec/unit/knife/ssl_fetch_spec.rb +222 -0
  554. data/spec/unit/knife/status_spec.rb +112 -0
  555. data/spec/unit/knife/supermarket_download_spec.rb +152 -0
  556. data/spec/unit/knife/supermarket_install_spec.rb +203 -0
  557. data/spec/unit/knife/supermarket_list_spec.rb +70 -0
  558. data/spec/unit/knife/supermarket_search_spec.rb +85 -0
  559. data/spec/unit/knife/supermarket_share_spec.rb +208 -0
  560. data/spec/unit/knife/supermarket_unshare_spec.rb +78 -0
  561. data/spec/unit/knife/tag_create_spec.rb +23 -0
  562. data/spec/unit/knife/tag_delete_spec.rb +25 -0
  563. data/spec/unit/knife/tag_list_spec.rb +23 -0
  564. data/spec/unit/knife/user_create_spec.rb +256 -0
  565. data/spec/unit/knife/user_delete_spec.rb +171 -0
  566. data/spec/unit/knife/user_edit_spec.rb +54 -0
  567. data/spec/unit/knife/user_list_spec.rb +73 -0
  568. data/spec/unit/knife/user_password_spec.rb +64 -0
  569. data/spec/unit/knife/user_reregister_spec.rb +56 -0
  570. data/spec/unit/knife/user_show_spec.rb +91 -0
  571. data/spec/unit/knife_spec.rb +634 -0
  572. metadata +580 -22
@@ -0,0 +1,2220 @@
1
+ #
2
+ # Author:: Ian Meyer (<ianmmeyer@gmail.com>)
3
+ # Copyright:: Copyright 2010-2016, Ian Meyer
4
+ # Copyright:: Copyright (c) Chef Software Inc.
5
+ # License:: Apache License, Version 2.0
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
+
20
+ require "knife_spec_helper"
21
+
22
+ Chef::Knife::Bootstrap.load_deps
23
+
24
+ describe Chef::Knife::Bootstrap do
25
+ let(:bootstrap_template) { nil }
26
+ let(:stderr) { StringIO.new }
27
+ let(:bootstrap_cli_options) { [ ] }
28
+ let(:linux_test) { true }
29
+ let(:windows_test) { false }
30
+ let(:linux_test) { false }
31
+ let(:unix_test) { false }
32
+ let(:ssh_test) { false }
33
+
34
+ let(:connection) do
35
+ double("TrainConnector",
36
+ windows?: windows_test,
37
+ linux?: linux_test,
38
+ unix?: unix_test)
39
+ end
40
+
41
+ let(:knife) do
42
+ Chef::Log.logger = Logger.new(StringIO.new)
43
+ Chef::Config[:knife][:bootstrap_template] = bootstrap_template unless bootstrap_template.nil?
44
+
45
+ k = Chef::Knife::Bootstrap.new(bootstrap_cli_options)
46
+ allow(k.ui).to receive(:stderr).and_return(stderr)
47
+ allow(k).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(false)
48
+ allow(k).to receive(:connection).and_return connection
49
+ k.merge_configs
50
+ k
51
+ end
52
+
53
+ context "#check_license" do
54
+ let(:acceptor) { instance_double(LicenseAcceptance::Acceptor) }
55
+
56
+ before do
57
+ expect(LicenseAcceptance::Acceptor).to receive(:new).and_return(acceptor)
58
+ end
59
+
60
+ describe "when a license is not required" do
61
+ it "does not set the chef_license" do
62
+ expect(acceptor).to receive(:license_required?).and_return(false)
63
+ knife.check_license
64
+ expect(Chef::Config[:chef_license]).to eq(nil)
65
+ end
66
+ end
67
+
68
+ describe "when a license is required" do
69
+ it "sets the chef_license" do
70
+ expect(acceptor).to receive(:license_required?).and_return(true)
71
+ expect(acceptor).to receive(:id_from_mixlib).and_return("id")
72
+ expect(acceptor).to receive(:check_and_persist)
73
+ expect(acceptor).to receive(:acceptance_value).and_return("accept-no-persist")
74
+ knife.check_license
75
+ expect(Chef::Config[:chef_license]).to eq("accept-no-persist")
76
+ end
77
+ end
78
+ end
79
+
80
+ context "#bootstrap_template" do
81
+ it "should default to chef-full" do
82
+ expect(knife.bootstrap_template).to be_a_kind_of(String)
83
+ expect(File.basename(knife.bootstrap_template)).to eq("chef-full")
84
+ end
85
+ end
86
+
87
+ context "#render_template - when using the chef-full default template" do
88
+ let(:rendered_template) do
89
+ knife.merge_configs
90
+ knife.render_template
91
+ end
92
+
93
+ it "should render client.rb" do
94
+ expect(rendered_template).to match("cat > /etc/chef/client.rb <<'EOP'")
95
+ expect(rendered_template).to match("chef_server_url \"https://localhost:443\"")
96
+ expect(rendered_template).to match("validation_client_name \"chef-validator\"")
97
+ expect(rendered_template).to match("log_location STDOUT")
98
+ end
99
+
100
+ it "should render first-boot.json" do
101
+ expect(rendered_template).to match("cat > /etc/chef/first-boot.json <<'EOP'")
102
+ expect(rendered_template).to match('{"run_list":\[\]}')
103
+ end
104
+
105
+ context "and encrypted_data_bag_secret was provided" do
106
+ it "should render encrypted_data_bag_secret file" do
107
+ expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true)
108
+ expect(knife).to receive(:read_secret).and_return("secrets")
109
+ expect(rendered_template).to match("cat > /etc/chef/encrypted_data_bag_secret <<'EOP'")
110
+ expect(rendered_template).to match('{"run_list":\[\]}')
111
+ expect(rendered_template).to match(/secrets/)
112
+ end
113
+ end
114
+ end
115
+
116
+ context "with --bootstrap-vault-item" do
117
+ let(:bootstrap_cli_options) { [ "--bootstrap-vault-item", "vault1:item1", "--bootstrap-vault-item", "vault1:item2", "--bootstrap-vault-item", "vault2:item1" ] }
118
+ it "sets the knife config cli option correctly" do
119
+ expect(knife.config[:bootstrap_vault_item]).to eq({ "vault1" => %w{item1 item2}, "vault2" => ["item1"] })
120
+ end
121
+ end
122
+
123
+ context "with --bootstrap-preinstall-command" do
124
+ command = "while sudo fuser /var/lib/dpkg/lock >/dev/null 2>&1; do\n echo 'waiting for dpkg lock';\n sleep 1;\n done;"
125
+ let(:bootstrap_cli_options) { [ "--bootstrap-preinstall-command", command ] }
126
+ let(:rendered_template) do
127
+ knife.merge_configs
128
+ knife.render_template
129
+ end
130
+ it "configures the preinstall command in the bootstrap template correctly" do
131
+ expect(rendered_template).to match(/command/)
132
+ end
133
+ end
134
+
135
+ context "with --bootstrap-proxy" do
136
+ let(:bootstrap_cli_options) { [ "--bootstrap-proxy", "1.1.1.1" ] }
137
+ let(:rendered_template) do
138
+ knife.merge_configs
139
+ knife.render_template
140
+ end
141
+ it "configures the https_proxy environment variable in the bootstrap template correctly" do
142
+ expect(rendered_template).to match(/https_proxy="1.1.1.1" export https_proxy/)
143
+ end
144
+ end
145
+
146
+ context "with --bootstrap-no-proxy" do
147
+ let(:bootstrap_cli_options) { [ "--bootstrap-no-proxy", "localserver" ] }
148
+ let(:rendered_template) do
149
+ knife.merge_configs
150
+ knife.render_template
151
+ end
152
+ it "configures the https_proxy environment variable in the bootstrap template correctly" do
153
+ expect(rendered_template).to match(/no_proxy="localserver" export no_proxy/)
154
+ end
155
+ end
156
+
157
+ context "with :bootstrap_template and :template_file cli options" do
158
+ let(:bootstrap_cli_options) { [ "--bootstrap-template", "my-template", "other-template" ] }
159
+
160
+ it "should select bootstrap template" do
161
+ expect(File.basename(knife.bootstrap_template)).to eq("my-template")
162
+ end
163
+ end
164
+
165
+ context "when finding templates" do
166
+ context "when :bootstrap_template config is set to a file" do
167
+ context "that doesn't exist" do
168
+ let(:bootstrap_template) { "/opt/blah/not/exists/template.erb" }
169
+
170
+ it "raises an error" do
171
+ expect { knife.find_template }.to raise_error(Errno::ENOENT)
172
+ end
173
+ end
174
+
175
+ context "that exists" do
176
+ let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) }
177
+
178
+ it "loads the given file as the template" do
179
+ expect(Chef::Log).to receive(:trace)
180
+ expect(knife.find_template).to eq(File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")))
181
+ end
182
+ end
183
+ end
184
+
185
+ context "when :bootstrap_template config is set to a template name" do
186
+ let(:bootstrap_template) { "example" }
187
+
188
+ let(:builtin_template_path) { File.expand_path(File.join(__dir__, "../../../lib/chef/knife/bootstrap/templates", "example.erb")) }
189
+
190
+ let(:chef_config_dir_template_path) { "/knife/chef/config/bootstrap/example.erb" }
191
+
192
+ let(:env_home_template_path) { "/env/home/.chef/bootstrap/example.erb" }
193
+
194
+ let(:gem_files_template_path) { "/Users/schisamo/.rvm/gems/ruby-1.9.2-p180@chef-0.10/gems/knife-windows-0.5.4/lib/chef/knife/bootstrap/fake-bootstrap-template.erb" }
195
+
196
+ def configure_chef_config_dir
197
+ allow(Chef::Knife).to receive(:chef_config_dir).and_return("/knife/chef/config")
198
+ end
199
+
200
+ def configure_env_home
201
+ allow(Chef::Util::PathHelper).to receive(:home).with(".chef", "bootstrap", "example.erb").and_yield(env_home_template_path)
202
+ end
203
+
204
+ def configure_gem_files
205
+ allow(Gem).to receive(:find_files).and_return([ gem_files_template_path ])
206
+ end
207
+
208
+ before(:each) do
209
+ expect(File).to receive(:exist?).with(bootstrap_template).and_return(false)
210
+ end
211
+
212
+ context "when file is available everywhere" do
213
+ before do
214
+ configure_chef_config_dir
215
+ configure_env_home
216
+ configure_gem_files
217
+
218
+ expect(File).to receive(:exist?).with(builtin_template_path).and_return(true)
219
+ end
220
+
221
+ it "should load the template from built-in templates" do
222
+ expect(knife.find_template).to eq(builtin_template_path)
223
+ end
224
+ end
225
+
226
+ context "when file is available in chef_config_dir" do
227
+ before do
228
+ configure_chef_config_dir
229
+ configure_env_home
230
+ configure_gem_files
231
+
232
+ expect(File).to receive(:exist?).with(builtin_template_path).and_return(false)
233
+ expect(File).to receive(:exist?).with(chef_config_dir_template_path).and_return(true)
234
+
235
+ it "should load the template from chef_config_dir" do
236
+ knife.find_template.should eq(chef_config_dir_template_path)
237
+ end
238
+ end
239
+ end
240
+
241
+ context "when file is available in home directory" do
242
+ before do
243
+ configure_chef_config_dir
244
+ configure_env_home
245
+ configure_gem_files
246
+
247
+ expect(File).to receive(:exist?).with(builtin_template_path).and_return(false)
248
+ expect(File).to receive(:exist?).with(chef_config_dir_template_path).and_return(false)
249
+ expect(File).to receive(:exist?).with(env_home_template_path).and_return(true)
250
+ end
251
+
252
+ it "should load the template from chef_config_dir" do
253
+ expect(knife.find_template).to eq(env_home_template_path)
254
+ end
255
+ end
256
+
257
+ context "when file is available in Gem files" do
258
+ before do
259
+ configure_chef_config_dir
260
+ configure_env_home
261
+ configure_gem_files
262
+
263
+ expect(File).to receive(:exist?).with(builtin_template_path).and_return(false)
264
+ expect(File).to receive(:exist?).with(chef_config_dir_template_path).and_return(false)
265
+ expect(File).to receive(:exist?).with(env_home_template_path).and_return(false)
266
+ expect(File).to receive(:exist?).with(gem_files_template_path).and_return(true)
267
+ end
268
+
269
+ it "should load the template from Gem files" do
270
+ expect(knife.find_template).to eq(gem_files_template_path)
271
+ end
272
+ end
273
+
274
+ context "when file is available in Gem files and home dir doesn't exist" do
275
+ before do
276
+ configure_chef_config_dir
277
+ configure_gem_files
278
+ allow(Chef::Util::PathHelper).to receive(:home).with(".chef", "bootstrap", "example.erb").and_return(nil)
279
+
280
+ expect(File).to receive(:exist?).with(builtin_template_path).and_return(false)
281
+ expect(File).to receive(:exist?).with(chef_config_dir_template_path).and_return(false)
282
+ expect(File).to receive(:exist?).with(gem_files_template_path).and_return(true)
283
+ end
284
+
285
+ it "should load the template from Gem files" do
286
+ expect(knife.find_template).to eq(gem_files_template_path)
287
+ end
288
+ end
289
+ end
290
+ end
291
+
292
+ ["-t", "--bootstrap-template"].each do |t|
293
+ context "when #{t} option is given in the command line" do
294
+ it "sets the knife :bootstrap_template config" do
295
+ knife.parse_options([t, "blahblah"])
296
+ knife.merge_configs
297
+ expect(knife.bootstrap_template).to eq("blahblah")
298
+ end
299
+ end
300
+ end
301
+
302
+ context "with run_list template" do
303
+ let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test.erb")) }
304
+
305
+ it "should return an empty run_list" do
306
+ expect(knife.render_template).to eq('{"run_list":[]}')
307
+ end
308
+
309
+ it "should have role[base] in the run_list" do
310
+ knife.parse_options(["-r", "role[base]"])
311
+ knife.merge_configs
312
+ expect(knife.render_template).to eq('{"run_list":["role[base]"]}')
313
+ end
314
+
315
+ it "should have role[base] and recipe[cupcakes] in the run_list" do
316
+ knife.parse_options(["-r", "role[base],recipe[cupcakes]"])
317
+ knife.merge_configs
318
+ expect(knife.render_template).to eq('{"run_list":["role[base]","recipe[cupcakes]"]}')
319
+ end
320
+
321
+ context "with bootstrap_attribute options" do
322
+ let(:jsonfile) do
323
+ file = Tempfile.new(["node", ".json"])
324
+ File.open(file.path, "w") { |f| f.puts '{"foo":{"bar":"baz"}}' }
325
+ file
326
+ end
327
+
328
+ it "should have foo => {bar => baz} in the first_boot from cli" do
329
+ knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
330
+ knife.merge_configs
331
+ expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}')
332
+ actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template)
333
+ expect(actual_hash).to eq(expected_hash)
334
+ end
335
+
336
+ it "should have foo => {bar => baz} in the first_boot from file" do
337
+ knife.parse_options(["--json-attribute-file", jsonfile.path])
338
+ knife.merge_configs
339
+ expected_hash = FFI_Yajl::Parser.new.parse('{"foo":{"bar":"baz"},"run_list":[]}')
340
+ actual_hash = FFI_Yajl::Parser.new.parse(knife.render_template)
341
+ expect(actual_hash).to eq(expected_hash)
342
+ jsonfile.close
343
+ end
344
+
345
+ it "raises a Chef::Exceptions::BootstrapCommandInputError with the proper error message" do
346
+ knife.parse_options(["-j", '{"foo":{"bar":"baz"}}'])
347
+ knife.parse_options(["--json-attribute-file", jsonfile.path])
348
+ knife.merge_configs
349
+ allow(knife).to receive(:validate_name_args!)
350
+ expect(knife).to receive(:check_license)
351
+
352
+ expect { knife.run }.to raise_error(Chef::Exceptions::BootstrapCommandInputError)
353
+ jsonfile.close
354
+ end
355
+ end
356
+ end
357
+
358
+ context "with hints template" do
359
+ let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "test-hints.erb")) }
360
+
361
+ it "should create a hint file when told to" do
362
+ knife.parse_options(["--hint", "openstack"])
363
+ knife.merge_configs
364
+ expect(knife.render_template).to match(%r{/etc/chef/ohai/hints/openstack.json})
365
+ end
366
+
367
+ it "should populate a hint file with JSON when given a file to read" do
368
+ allow(::File).to receive(:read).and_return('{ "foo" : "bar" }')
369
+ knife.parse_options(["--hint", "openstack=hints/openstack.json"])
370
+ knife.merge_configs
371
+ expect(knife.render_template).to match(/\{\"foo\":\"bar\"\}/)
372
+ end
373
+ end
374
+
375
+ describe "specifying no_proxy with various entries" do
376
+ subject(:knife) do
377
+ k = described_class.new
378
+ Chef::Config[:knife][:bootstrap_template] = template_file
379
+ allow(k).to receive(:connection).and_return connection
380
+ k.parse_options(options)
381
+ k.merge_configs
382
+ k
383
+ end
384
+
385
+ let(:options) { ["--bootstrap-no-proxy", setting] }
386
+
387
+ let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
388
+
389
+ let(:rendered_template) do
390
+ knife.render_template
391
+ end
392
+
393
+ context "via --bootstrap-no-proxy" do
394
+ let(:setting) { "api.opscode.com" }
395
+
396
+ it "renders the client.rb with a single FQDN no_proxy entry" do
397
+ expect(rendered_template).to match(/.*no_proxy\s*"api.opscode.com".*/)
398
+ end
399
+ end
400
+
401
+ context "via --bootstrap-no-proxy multiple" do
402
+ let(:setting) { "api.opscode.com,172.16.10.*" }
403
+
404
+ it "renders the client.rb with comma-separated FQDN and wildcard IP address no_proxy entries" do
405
+ expect(rendered_template).to match(/.*no_proxy\s*"api.opscode.com,172.16.10.\*".*/)
406
+ end
407
+ end
408
+
409
+ context "via --ssl-verify-mode none" do
410
+ let(:options) { ["--node-ssl-verify-mode", "none"] }
411
+
412
+ it "renders the client.rb with ssl_verify_mode set to :verify_none" do
413
+ expect(rendered_template).to match(/ssl_verify_mode :verify_none/)
414
+ end
415
+ end
416
+
417
+ context "via --node-ssl-verify-mode peer" do
418
+ let(:options) { ["--node-ssl-verify-mode", "peer"] }
419
+
420
+ it "renders the client.rb with ssl_verify_mode set to :verify_peer" do
421
+ expect(rendered_template).to match(/ssl_verify_mode :verify_peer/)
422
+ end
423
+ end
424
+
425
+ context "via --node-ssl-verify-mode all" do
426
+ let(:options) { ["--node-ssl-verify-mode", "all"] }
427
+
428
+ it "raises error" do
429
+ expect { rendered_template }.to raise_error(RuntimeError)
430
+ end
431
+ end
432
+
433
+ context "via --node-verify-api-cert" do
434
+ let(:options) { ["--node-verify-api-cert"] }
435
+
436
+ it "renders the client.rb with verify_api_cert set to true" do
437
+ expect(rendered_template).to match(/verify_api_cert true/)
438
+ end
439
+ end
440
+
441
+ context "via --no-node-verify-api-cert" do
442
+ let(:options) { ["--no-node-verify-api-cert"] }
443
+
444
+ it "renders the client.rb with verify_api_cert set to false" do
445
+ expect(rendered_template).to match(/verify_api_cert false/)
446
+ end
447
+ end
448
+ end
449
+
450
+ describe "specifying the encrypted data bag secret key" do
451
+ let(:secret) { "supersekret" }
452
+ let(:options) { [] }
453
+ let(:bootstrap_template) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "secret.erb")) }
454
+ let(:rendered_template) do
455
+ knife.parse_options(options)
456
+ knife.merge_configs
457
+ knife.render_template
458
+ end
459
+
460
+ it "creates a secret file" do
461
+ expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true)
462
+ expect(knife).to receive(:read_secret).and_return(secret)
463
+ expect(rendered_template).to match(/#{secret}/)
464
+ end
465
+
466
+ it "renders the client.rb with an encrypted_data_bag_secret entry" do
467
+ expect(knife).to receive(:encryption_secret_provided_ignore_encrypt_flag?).and_return(true)
468
+ expect(knife).to receive(:read_secret).and_return(secret)
469
+ expect(rendered_template).to match(%r{encrypted_data_bag_secret\s*"/etc/chef/encrypted_data_bag_secret"})
470
+ end
471
+
472
+ end
473
+
474
+ describe "when transferring trusted certificates" do
475
+ let(:rendered_template) do
476
+ knife.merge_configs
477
+ knife.render_template
478
+ end
479
+
480
+ before do
481
+ Chef::Config[:trusted_certs_dir] = Chef::Util::PathHelper.cleanpath(File.join(CHEF_SPEC_DATA, "trusted_certs"))
482
+ end
483
+
484
+ it "creates /etc/chef/trusted_certs" do
485
+ expect(rendered_template).to match(%r{mkdir -p /etc/chef/trusted_certs})
486
+ end
487
+
488
+ it "copies the certificates in the directory" do
489
+ certificates = Dir[File.join(Chef::Config[:trusted_certs_dir], "*.{crt,pem}")]
490
+
491
+ certificates.each do |cert|
492
+ expect(rendered_template).to match(%r{cat > /etc/chef/trusted_certs/#{File.basename(cert)} <<'EOP'})
493
+ end
494
+ end
495
+
496
+ it "doesn't create /etc/chef/trusted_certs if :trusted_certs_dir is empty" do
497
+ Dir.mktmpdir do |dir|
498
+ Chef::Config[:trusted_certs_dir] = dir
499
+ expect(rendered_template).not_to match(%r{mkdir -p /etc/chef/trusted_certs})
500
+ end
501
+ end
502
+ end
503
+
504
+ context "when doing fips things" do
505
+ let(:template_file) { File.expand_path(File.join(CHEF_SPEC_DATA, "bootstrap", "no_proxy.erb")) }
506
+
507
+ before do
508
+ Chef::Config[:knife][:bootstrap_template] = template_file
509
+ knife.merge_configs
510
+ end
511
+
512
+ let(:rendered_template) do
513
+ knife.render_template
514
+ end
515
+
516
+ context "when knife is in fips mode" do
517
+ before do
518
+ Chef::Config[:fips] = true
519
+ end
520
+
521
+ it "renders 'fips true'" do
522
+ expect(rendered_template).to match("fips")
523
+ end
524
+ end
525
+
526
+ context "when knife is not in fips mode" do
527
+ before do
528
+ # This is required because the chef-fips pipeline does
529
+ # has a default value of true for fips
530
+ Chef::Config[:fips] = false
531
+ end
532
+
533
+ it "does not render anything about fips" do
534
+ expect(rendered_template).not_to match("fips")
535
+ end
536
+ end
537
+ end
538
+
539
+ describe "when transferring client.d" do
540
+
541
+ let(:rendered_template) do
542
+ knife.merge_configs
543
+ knife.render_template
544
+ end
545
+
546
+ before do
547
+ Chef::Config[:client_d_dir] = client_d_dir
548
+ end
549
+
550
+ context "when client_d_dir is nil" do
551
+ let(:client_d_dir) { nil }
552
+
553
+ it "does not create /etc/chef/client.d" do
554
+ expect(rendered_template).not_to match(%r{mkdir -p /etc/chef/client\.d})
555
+ end
556
+ end
557
+
558
+ context "when client_d_dir is set" do
559
+ let(:client_d_dir) do
560
+ Chef::Util::PathHelper.cleanpath(
561
+ File.join(__dir__, "../../data/client.d_00")
562
+ )
563
+ end
564
+
565
+ it "creates /etc/chef/client.d" do
566
+ expect(rendered_template).to match("mkdir -p /etc/chef/client\.d")
567
+ end
568
+
569
+ context "a flat directory structure" do
570
+ it "escapes single-quotes" do
571
+ expect(rendered_template).to match("cat > /etc/chef/client.d/02-strings.rb <<'EOP'")
572
+ expect(rendered_template).to match("something '\\\\''/foo/bar'\\\\''")
573
+ end
574
+
575
+ it "creates a file 00-foo.rb" do
576
+ expect(rendered_template).to match("cat > /etc/chef/client.d/00-foo.rb <<'EOP'")
577
+ expect(rendered_template).to match("d6f9b976-289c-4149-baf7-81e6ffecf228")
578
+ end
579
+ it "creates a file bar" do
580
+ expect(rendered_template).to match("cat > /etc/chef/client.d/bar <<'EOP'")
581
+ expect(rendered_template).to match("1 / 0")
582
+ end
583
+ end
584
+
585
+ context "a nested directory structure" do
586
+ let(:client_d_dir) do
587
+ Chef::Util::PathHelper.cleanpath(
588
+ File.join(__dir__, "../../data/client.d_01")
589
+ )
590
+ end
591
+ it "creates a file foo/bar.rb" do
592
+ expect(rendered_template).to match("cat > /etc/chef/client.d/foo/bar.rb <<'EOP'")
593
+ expect(rendered_template).to match("1 / 0")
594
+ end
595
+ end
596
+ end
597
+ end
598
+
599
+ describe "#connection_protocol" do
600
+ let(:host_descriptor) { "example.com" }
601
+ let(:config) { {} }
602
+ let(:knife_connection_protocol) { nil }
603
+ before do
604
+ allow(knife).to receive(:config).and_return config
605
+ allow(knife).to receive(:host_descriptor).and_return host_descriptor
606
+ if knife_connection_protocol
607
+ Chef::Config[:knife][:connection_protocol] = knife_connection_protocol
608
+ knife.merge_configs
609
+ end
610
+ end
611
+
612
+ context "when protocol is part of the host argument" do
613
+ let(:host_descriptor) { "winrm://myhost" }
614
+
615
+ it "returns the value provided by the host argument" do
616
+ expect(knife.connection_protocol).to eq "winrm"
617
+ end
618
+ end
619
+
620
+ context "when protocol is provided via the CLI flag" do
621
+ let(:config) { { connection_protocol: "winrm" } }
622
+ it "returns that value" do
623
+ expect(knife.connection_protocol).to eq "winrm"
624
+ end
625
+
626
+ end
627
+ context "when protocol is provided via the host argument and the CLI flag" do
628
+ let(:host_descriptor) { "ssh://example.com" }
629
+ let(:config) { { connection_protocol: "winrm" } }
630
+
631
+ it "returns the value provided by the host argument" do
632
+ expect(knife.connection_protocol).to eq "ssh"
633
+ end
634
+ end
635
+
636
+ context "when no explicit protocol is provided" do
637
+ let(:config) { {} }
638
+ let(:host_descriptor) { "example.com" }
639
+ let(:knife_connection_protocol) { "winrm" }
640
+ it "falls back to knife config" do
641
+ expect(knife.connection_protocol).to eq "winrm"
642
+ end
643
+ context "and there is no knife bootstrap_protocol" do
644
+ let(:knife_connection_protocol) { nil }
645
+ it "falls back to 'ssh'" do
646
+ expect(knife.connection_protocol).to eq "ssh"
647
+ end
648
+ end
649
+ end
650
+
651
+ end
652
+
653
+ describe "#validate_protocol!" do
654
+ let(:host_descriptor) { "example.com" }
655
+ let(:config) { {} }
656
+ let(:connection_protocol) { "ssh" }
657
+ before do
658
+ allow(knife).to receive(:config).and_return config
659
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
660
+ allow(knife).to receive(:host_descriptor).and_return host_descriptor
661
+ end
662
+
663
+ context "when protocol is provided both in the URL and via --protocol" do
664
+
665
+ context "and they do not match" do
666
+ let(:connection_protocol) { "ssh" }
667
+ let(:config) { { connection_protocol: "winrm" } }
668
+ it "outputs an error and exits" do
669
+ expect(knife.ui).to receive(:error)
670
+ expect { knife.validate_protocol! }.to raise_error SystemExit
671
+ end
672
+ end
673
+
674
+ context "and they do match" do
675
+ let(:connection_protocol) { "winrm" }
676
+ let(:config) { { connection_protocol: "winrm" } }
677
+ it "returns true" do
678
+ expect(knife.validate_protocol!).to eq true
679
+ end
680
+ end
681
+ end
682
+
683
+ context "and the protocol is supported" do
684
+
685
+ Chef::Knife::Bootstrap::SUPPORTED_CONNECTION_PROTOCOLS.each do |proto|
686
+ let(:connection_protocol) { proto }
687
+ it "returns true for #{proto}" do
688
+ expect(knife.validate_protocol!).to eq true
689
+ end
690
+ end
691
+ end
692
+
693
+ context "and the protocol is not supported" do
694
+ let(:connection_protocol) { "invalid" }
695
+ it "outputs an error and exits" do
696
+ expect(knife.ui).to receive(:error).with(/Unsupported protocol '#{connection_protocol}'/)
697
+ expect { knife.validate_protocol! }.to raise_error SystemExit
698
+ end
699
+ end
700
+ end
701
+
702
+ describe "#validate_policy_options!" do
703
+
704
+ context "when only policy_name is given" do
705
+
706
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app-server } }
707
+
708
+ it "returns an error stating that policy_name and policy_group must be given together" do
709
+ expect { knife.validate_policy_options! }.to raise_error(SystemExit)
710
+ expect(stderr.string).to include("ERROR: --policy-name and --policy-group must be specified together")
711
+ end
712
+
713
+ end
714
+
715
+ context "when only policy_group is given" do
716
+
717
+ let(:bootstrap_cli_options) { %w{ --policy-group staging } }
718
+
719
+ it "returns an error stating that policy_name and policy_group must be given together" do
720
+ expect { knife.validate_policy_options! }.to raise_error(SystemExit)
721
+ expect(stderr.string).to include("ERROR: --policy-name and --policy-group must be specified together")
722
+ end
723
+
724
+ end
725
+
726
+ context "when both policy_name and policy_group are given, but run list is also given" do
727
+
728
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging --run-list cookbook } }
729
+
730
+ it "returns an error stating that policyfile and run_list are exclusive" do
731
+ expect { knife.validate_policy_options! }.to raise_error(SystemExit)
732
+ expect(stderr.string).to include("ERROR: Policyfile options and --run-list are exclusive")
733
+ end
734
+
735
+ end
736
+
737
+ context "when policy_name and policy_group are given with no conflicting options" do
738
+
739
+ let(:bootstrap_cli_options) { %w{ --policy-name my-app --policy-group staging } }
740
+
741
+ it "passes options validation" do
742
+ expect { knife.validate_policy_options! }.to_not raise_error
743
+ end
744
+
745
+ it "passes them into the bootstrap context" do
746
+ expect(knife.bootstrap_context.first_boot).to have_key(:policy_name)
747
+ expect(knife.bootstrap_context.first_boot).to have_key(:policy_group)
748
+ end
749
+
750
+ it "ensures that run_list is not set in the bootstrap context" do
751
+ expect(knife.bootstrap_context.first_boot).to_not have_key(:run_list)
752
+ end
753
+
754
+ end
755
+
756
+ # https://github.com/chef/chef/issues/4131
757
+ # Arguably a bug in the plugin: it shouldn't be setting this to nil, but it
758
+ # worked before, so make it work now.
759
+ context "when a plugin sets the run list option to nil" do
760
+ before do
761
+ knife.config[:run_list] = nil
762
+ end
763
+
764
+ it "passes options validation" do
765
+ expect { knife.validate_policy_options! }.to_not raise_error
766
+ end
767
+ end
768
+ end
769
+
770
+ # TODO - this is the only cli option we validate the _option_ itself -
771
+ # so we'll know if someone accidentally deletes or renames use_sudo_password
772
+ # Is this worht keeping? If so, then it seems we should expand it
773
+ # to cover all options.
774
+ context "validating use_sudo_password option" do
775
+ it "use_sudo_password contains description and long params for help" do
776
+ expect(knife.options).to(have_key(:use_sudo_password)) \
777
+ && expect(knife.options[:use_sudo_password][:description].to_s).not_to(eq(""))\
778
+ && expect(knife.options[:use_sudo_password][:long].to_s).not_to(eq(""))
779
+ end
780
+ end
781
+
782
+ context "#connection_opts" do
783
+ let(:connection_protocol) { "ssh" }
784
+ before do
785
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
786
+ end
787
+ context "behavioral test: " do
788
+ let(:expected_connection_opts) do
789
+ { base_opts: true,
790
+ ssh_identity_opts: true,
791
+ ssh_opts: true,
792
+ gateway_opts: true,
793
+ host_verify_opts: true,
794
+ sudo_opts: true,
795
+ winrm_opts: true }
796
+ end
797
+
798
+ it "queries and merges only expected configurations" do
799
+ expect(knife).to receive(:base_opts).and_return({ base_opts: true })
800
+ expect(knife).to receive(:host_verify_opts).and_return({ host_verify_opts: true })
801
+ expect(knife).to receive(:gateway_opts).and_return({ gateway_opts: true })
802
+ expect(knife).to receive(:sudo_opts).and_return({ sudo_opts: true })
803
+ expect(knife).to receive(:winrm_opts).and_return({ winrm_opts: true })
804
+ expect(knife).to receive(:ssh_opts).and_return({ ssh_opts: true })
805
+ expect(knife).to receive(:ssh_identity_opts).and_return({ ssh_identity_opts: true })
806
+ expect(knife.connection_opts).to match expected_connection_opts
807
+ end
808
+ end
809
+
810
+ context "functional test: " do
811
+ context "when protocol is winrm" do
812
+ let(:connection_protocol) { "winrm" }
813
+ # context "and neither CLI nor Chef::Config config entries have been provided"
814
+ # end
815
+ context "and all supported values are provided as Chef::Config entries" do
816
+ before do
817
+ # Set everything to easily identifiable and obviously fake values
818
+ # to verify that Chef::Config is being sourced instead of knife.config
819
+ knife.config = {}
820
+ Chef::Config[:knife][:max_wait] = 9999
821
+ Chef::Config[:knife][:winrm_user] = "winbob"
822
+ Chef::Config[:knife][:winrm_port] = 9999
823
+ Chef::Config[:knife][:ca_trust_file] = "trust.me"
824
+ Chef::Config[:knife][:kerberos_realm] = "realm"
825
+ Chef::Config[:knife][:kerberos_service] = "service"
826
+ Chef::Config[:knife][:winrm_auth_method] = "kerberos" # default is negotiate
827
+ Chef::Config[:knife][:winrm_basic_auth_only] = true
828
+ Chef::Config[:knife][:winrm_no_verify_cert] = true
829
+ Chef::Config[:knife][:session_timeout] = 9999
830
+ Chef::Config[:knife][:winrm_ssl] = true
831
+ Chef::Config[:knife][:winrm_ssl_peer_fingerprint] = "ABCDEF"
832
+ end
833
+
834
+ context "and no CLI options have been given" do
835
+ let(:expected_result) do
836
+ {
837
+ logger: Chef::Log, # not configurable
838
+ ca_trust_path: "trust.me",
839
+ max_wait_until_ready: 9999,
840
+ operation_timeout: 9999,
841
+ ssl_peer_fingerprint: "ABCDEF",
842
+ winrm_transport: "kerberos",
843
+ winrm_basic_auth_only: true,
844
+ user: "winbob",
845
+ port: 9999,
846
+ self_signed: true,
847
+ ssl: true,
848
+ kerberos_realm: "realm",
849
+ kerberos_service: "service",
850
+ }
851
+ end
852
+
853
+ it "generates a config hash using the Chef::Config values" do
854
+ knife.merge_configs
855
+ expect(knife.connection_opts).to match expected_result
856
+ end
857
+
858
+ end
859
+
860
+ context "and some CLI options have been given" do
861
+ let(:expected_result) do
862
+ {
863
+ logger: Chef::Log, # not configurable
864
+ ca_trust_path: "no trust",
865
+ max_wait_until_ready: 9999,
866
+ operation_timeout: 9999,
867
+ ssl_peer_fingerprint: "ABCDEF",
868
+ winrm_transport: "kerberos",
869
+ winrm_basic_auth_only: true,
870
+ user: "microsoftbob",
871
+ port: 12,
872
+ self_signed: true,
873
+ ssl: true,
874
+ kerberos_realm: "realm",
875
+ kerberos_service: "service",
876
+ password: "lobster",
877
+ }
878
+ end
879
+
880
+ before do
881
+ knife.config[:ca_trust_file] = "no trust"
882
+ knife.config[:connection_user] = "microsoftbob"
883
+ knife.config[:connection_port] = 12
884
+ knife.config[:winrm_port] = "13" # indirectly verify we're not looking for the wrong CLI flag
885
+ knife.config[:connection_password] = "lobster"
886
+ end
887
+
888
+ it "generates a config hash using the CLI options when available and falling back to Chef::Config values" do
889
+ knife.merge_configs
890
+ expect(knife.connection_opts).to match expected_result
891
+ end
892
+ end
893
+
894
+ context "and all CLI options have been given" do
895
+ before do
896
+ # We'll force kerberos vi knife.config because it
897
+ # causes additional options to populate - make sure
898
+ # Chef::Config is different so we can be sure that we didn't
899
+ # pull in the Chef::Config value
900
+ Chef::Config[:knife][:winrm_auth_method] = "negotiate"
901
+ knife.config[:connection_password] = "blue"
902
+ knife.config[:max_wait] = 1000
903
+ knife.config[:connection_user] = "clippy"
904
+ knife.config[:connection_port] = 1000
905
+ knife.config[:winrm_port] = 1001 # We should not see this value get used
906
+
907
+ knife.config[:ca_trust_file] = "trust.the.internet"
908
+ knife.config[:kerberos_realm] = "otherrealm"
909
+ knife.config[:kerberos_service] = "otherservice"
910
+ knife.config[:winrm_auth_method] = "kerberos" # default is negotiate
911
+ knife.config[:winrm_basic_auth_only] = false
912
+ knife.config[:winrm_no_verify_cert] = false
913
+ knife.config[:session_timeout] = 1000
914
+ knife.config[:winrm_ssl] = false
915
+ knife.config[:winrm_ssl_peer_fingerprint] = "FEDCBA"
916
+ end
917
+ let(:expected_result) do
918
+ {
919
+ logger: Chef::Log, # not configurable
920
+ ca_trust_path: "trust.the.internet",
921
+ max_wait_until_ready: 1000,
922
+ operation_timeout: 1000,
923
+ ssl_peer_fingerprint: "FEDCBA",
924
+ winrm_transport: "kerberos",
925
+ winrm_basic_auth_only: false,
926
+ user: "clippy",
927
+ port: 1000,
928
+ self_signed: false,
929
+ ssl: false,
930
+ kerberos_realm: "otherrealm",
931
+ kerberos_service: "otherservice",
932
+ password: "blue",
933
+ }
934
+ end
935
+ it "generates a config hash using the CLI options and pulling nothing from Chef::Config" do
936
+ knife.merge_configs
937
+ expect(knife.connection_opts).to match expected_result
938
+ end
939
+ end
940
+ end # with underlying Chef::Config values
941
+
942
+ context "and no values are provided from Chef::Config or CLI" do
943
+ before do
944
+ # We will use knife's actual config since these tests
945
+ # have assumptions based on CLI default values
946
+ end
947
+ let(:expected_result) do
948
+ {
949
+ logger: Chef::Log,
950
+ operation_timeout: 60,
951
+ self_signed: false,
952
+ ssl: false,
953
+ ssl_peer_fingerprint: nil,
954
+ winrm_basic_auth_only: false,
955
+ winrm_transport: "negotiate",
956
+ }
957
+ end
958
+ it "populates appropriate defaults" do
959
+ knife.merge_configs
960
+ expect(knife.connection_opts).to match expected_result
961
+ end
962
+ end
963
+ end # winrm
964
+
965
+ context "when protocol is ssh" do
966
+ let(:connection_protocol) { "ssh" }
967
+ # context "and neither CLI nor Chef::Config config entries have been provided"
968
+ # end
969
+ context "and all supported values are provided as Chef::Config entries" do
970
+ before do
971
+ # Set everything to easily identifiable and obviously fake values
972
+ # to verify that Chef::Config is being sourced instead of knife.config
973
+ knife.config = {}
974
+ Chef::Config[:knife][:max_wait] = 9999
975
+ Chef::Config[:knife][:session_timeout] = 9999
976
+ Chef::Config[:knife][:ssh_user] = "sshbob"
977
+ Chef::Config[:knife][:ssh_port] = 9999
978
+ Chef::Config[:knife][:host_key_verify] = false
979
+ Chef::Config[:knife][:ssh_gateway_identity] = "/gateway.pem"
980
+ Chef::Config[:knife][:ssh_gateway] = "admin@mygateway.local:1234"
981
+ Chef::Config[:knife][:ssh_identity_file] = "/identity.pem"
982
+ Chef::Config[:knife][:use_sudo_password] = false # We have no password.
983
+ end
984
+
985
+ context "and no CLI options have been given" do
986
+ let(:expected_result) do
987
+ {
988
+ logger: Chef::Log, # not configurable
989
+ max_wait_until_ready: 9999.0,
990
+ connection_timeout: 9999,
991
+ user: "sshbob",
992
+ bastion_host: "mygateway.local",
993
+ bastion_port: 1234,
994
+ bastion_user: "admin",
995
+ forward_agent: false,
996
+ keys_only: true,
997
+ key_files: ["/identity.pem", "/gateway.pem"],
998
+ sudo: false,
999
+ verify_host_key: "always",
1000
+ port: 9999,
1001
+ non_interactive: true,
1002
+ }
1003
+ end
1004
+
1005
+ it "generates a correct config hash using the Chef::Config values" do
1006
+ knife.merge_configs
1007
+ expect(knife.connection_opts).to match expected_result
1008
+ end
1009
+ end
1010
+
1011
+ context "and unsupported Chef::Config options are given in Chef::Config, not in CLI" do
1012
+ before do
1013
+ Chef::Config[:knife][:password] = "blah"
1014
+ Chef::Config[:knife][:ssh_password] = "blah"
1015
+ Chef::Config[:knife][:preserve_home] = true
1016
+ Chef::Config[:knife][:use_sudo] = true
1017
+ Chef::Config[:knife][:ssh_forward_agent] = "blah"
1018
+ end
1019
+ it "does not include the corresponding option in the connection options" do
1020
+ knife.merge_configs
1021
+ expect(knife.connection_opts.key?(:password)).to eq false
1022
+ expect(knife.connection_opts.key?(:ssh_forward_agent)).to eq false
1023
+ expect(knife.connection_opts.key?(:use_sudo)).to eq false
1024
+ expect(knife.connection_opts.key?(:preserve_home)).to eq false
1025
+ end
1026
+ end
1027
+
1028
+ context "and some CLI options have been given" do
1029
+ before do
1030
+ knife.config = {}
1031
+ knife.config[:connection_user] = "sshalice"
1032
+ knife.config[:connection_port] = 12
1033
+ knife.config[:ssh_port] = "13" # canary to indirectly verify we're not looking for the wrong CLI flag
1034
+ knife.config[:connection_password] = "feta cheese"
1035
+ knife.config[:max_wait] = 150
1036
+ knife.config[:session_timeout] = 120
1037
+ knife.config[:use_sudo] = true
1038
+ knife.config[:use_sudo_pasword] = true
1039
+ knife.config[:ssh_forward_agent] = true
1040
+ end
1041
+
1042
+ let(:expected_result) do
1043
+ {
1044
+ logger: Chef::Log, # not configurable
1045
+ max_wait_until_ready: 150.0, # cli
1046
+ connection_timeout: 120, # cli
1047
+ user: "sshalice", # cli
1048
+ password: "feta cheese", # cli
1049
+ bastion_host: "mygateway.local", # Config
1050
+ bastion_port: 1234, # Config
1051
+ bastion_user: "admin", # Config
1052
+ forward_agent: true, # cli
1053
+ keys_only: false, # implied false from config password present
1054
+ key_files: ["/identity.pem", "/gateway.pem"], # Config
1055
+ sudo: true, # ccli
1056
+ verify_host_key: "always", # Config
1057
+ port: 12, # cli
1058
+ non_interactive: true,
1059
+ }
1060
+ end
1061
+
1062
+ it "generates a config hash using the CLI options when available and falling back to Chef::Config values" do
1063
+ knife.merge_configs
1064
+ expect(knife.connection_opts).to match expected_result
1065
+ end
1066
+ end
1067
+
1068
+ context "and all CLI options have been given" do
1069
+ before do
1070
+ knife.config = {}
1071
+ knife.config[:max_wait] = 150
1072
+ knife.config[:session_timeout] = 120
1073
+ knife.config[:connection_user] = "sshroot"
1074
+ knife.config[:connection_port] = 1000
1075
+ knife.config[:connection_password] = "blah"
1076
+ knife.config[:forward_agent] = true
1077
+ knife.config[:use_sudo] = true
1078
+ knife.config[:use_sudo_password] = true
1079
+ knife.config[:preserve_home] = true
1080
+ knife.config[:use_sudo_pasword] = true
1081
+ knife.config[:ssh_forward_agent] = true
1082
+ knife.config[:ssh_verify_host_key] = true
1083
+ knife.config[:ssh_gateway_identity] = "/gateway-identity.pem"
1084
+ knife.config[:ssh_gateway] = "me@example.com:10"
1085
+ knife.config[:ssh_identity_file] = "/my-identity.pem"
1086
+
1087
+ # We'll set these as canaries - if one of these values shows up
1088
+ # in a failed test, then the behavior of not pulling from these keys
1089
+ # out of knife.config is broken:
1090
+ knife.config[:ssh_user] = "do not use"
1091
+ knife.config[:ssh_port] = 1001
1092
+ end
1093
+ let(:expected_result) do
1094
+ {
1095
+ logger: Chef::Log, # not configurable
1096
+ max_wait_until_ready: 150,
1097
+ connection_timeout: 120,
1098
+ user: "sshroot",
1099
+ password: "blah",
1100
+ port: 1000,
1101
+ bastion_host: "example.com",
1102
+ bastion_port: 10,
1103
+ bastion_user: "me",
1104
+ forward_agent: true,
1105
+ keys_only: false,
1106
+ key_files: ["/my-identity.pem", "/gateway-identity.pem"],
1107
+ sudo: true,
1108
+ sudo_options: "-H",
1109
+ sudo_password: "blah",
1110
+ verify_host_key: true,
1111
+ non_interactive: true,
1112
+ }
1113
+ end
1114
+ it "generates a config hash using the CLI options and pulling nothing from Chef::Config" do
1115
+ knife.merge_configs
1116
+ expect(knife.connection_opts).to match expected_result
1117
+ end
1118
+ end
1119
+ end
1120
+ context "and no values are provided from Chef::Config or CLI" do
1121
+ before do
1122
+ # We will use knife's actual config since these tests
1123
+ # have assumptions based on CLI default values
1124
+ config = {}
1125
+ end
1126
+
1127
+ let(:expected_result) do
1128
+ {
1129
+ forward_agent: false,
1130
+ key_files: [],
1131
+ logger: Chef::Log,
1132
+ keys_only: false,
1133
+ sudo: false,
1134
+ verify_host_key: "always",
1135
+ non_interactive: true,
1136
+ connection_timeout: 60,
1137
+ }
1138
+ end
1139
+ it "populates appropriate defaults" do
1140
+ knife.merge_configs
1141
+ expect(knife.connection_opts).to match expected_result
1142
+ end
1143
+ end
1144
+
1145
+ end # ssh
1146
+ end # functional tests
1147
+
1148
+ end # connection_opts
1149
+
1150
+ context "#base_opts" do
1151
+ let(:connection_protocol) { nil }
1152
+
1153
+ before do
1154
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1155
+ end
1156
+
1157
+ context "for all protocols" do
1158
+ context "when password is provided" do
1159
+ before do
1160
+ knife.config[:connection_port] = 250
1161
+ knife.config[:connection_user] = "test"
1162
+ knife.config[:connection_password] = "opscode"
1163
+ end
1164
+
1165
+ let(:expected_opts) do
1166
+ {
1167
+ port: 250,
1168
+ user: "test",
1169
+ logger: Chef::Log,
1170
+ password: "opscode",
1171
+ }
1172
+ end
1173
+ it "generates the correct options" do
1174
+ expect(knife.base_opts).to eq expected_opts
1175
+ end
1176
+
1177
+ end
1178
+
1179
+ context "when password is not provided" do
1180
+ before do
1181
+ knife.config[:connection_port] = 250
1182
+ knife.config[:connection_user] = "test"
1183
+ end
1184
+
1185
+ let(:expected_opts) do
1186
+ {
1187
+ port: 250,
1188
+ user: "test",
1189
+ logger: Chef::Log,
1190
+ }
1191
+ end
1192
+ it "generates the correct options" do
1193
+ expect(knife.base_opts).to eq expected_opts
1194
+ end
1195
+ end
1196
+ end
1197
+ end
1198
+
1199
+ context "#host_verify_opts" do
1200
+ let(:connection_protocol) { nil }
1201
+ before do
1202
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1203
+ end
1204
+
1205
+ context "for winrm" do
1206
+ let(:connection_protocol) { "winrm" }
1207
+ it "returns the expected configuration" do
1208
+ knife.config[:winrm_no_verify_cert] = true
1209
+ expect(knife.host_verify_opts).to eq( { self_signed: true } )
1210
+ end
1211
+ it "provides a correct default when no option given" do
1212
+ expect(knife.host_verify_opts).to eq( { self_signed: false } )
1213
+ end
1214
+ end
1215
+
1216
+ context "for ssh" do
1217
+ let(:connection_protocol) { "ssh" }
1218
+ it "returns the expected configuration" do
1219
+ knife.config[:ssh_verify_host_key] = false
1220
+ expect(knife.host_verify_opts).to eq( { verify_host_key: false } )
1221
+ end
1222
+ it "provides a correct default when no option given" do
1223
+ expect(knife.host_verify_opts).to eq( { verify_host_key: "always" } )
1224
+ end
1225
+ end
1226
+ end
1227
+
1228
+ # TODO - test keys_only, password, config source behavior
1229
+ context "#ssh_identity_opts" do
1230
+ let(:connection_protocol) { nil }
1231
+ before do
1232
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1233
+ end
1234
+
1235
+ context "for winrm" do
1236
+ let(:connection_protocol) { "winrm" }
1237
+ it "returns an empty hash" do
1238
+ expect(knife.ssh_identity_opts).to eq({})
1239
+ end
1240
+ end
1241
+
1242
+ context "for ssh" do
1243
+ let(:connection_protocol) { "ssh" }
1244
+ context "when an identity file is specified" do
1245
+ before do
1246
+ knife.config[:ssh_identity_file] = "/identity.pem"
1247
+ end
1248
+ it "generates the expected configuration" do
1249
+ expect(knife.ssh_identity_opts).to eq({
1250
+ key_files: [ "/identity.pem" ],
1251
+ keys_only: true,
1252
+ })
1253
+ end
1254
+ context "and a password is also specified" do
1255
+ before do
1256
+ knife.config[:connection_password] = "blah"
1257
+ end
1258
+ it "generates the expected configuration (key, keys_only false)" do
1259
+ expect(knife.ssh_identity_opts).to eq({
1260
+ key_files: [ "/identity.pem" ],
1261
+ keys_only: false,
1262
+ })
1263
+ end
1264
+ end
1265
+
1266
+ context "and a gateway is not specified" do
1267
+ context "but a gateway identity file is specified" do
1268
+ it "does not include the gateway identity file in keys" do
1269
+ expect(knife.ssh_identity_opts).to eq({
1270
+ key_files: ["/identity.pem"],
1271
+ keys_only: true,
1272
+ })
1273
+ end
1274
+
1275
+ end
1276
+
1277
+ end
1278
+
1279
+ context "and a gatway is specified" do
1280
+ before do
1281
+ knife.config[:ssh_gateway] = "example.com"
1282
+ end
1283
+ context "and a gateway identity file is not specified" do
1284
+ it "config includes only identity file and not gateway identity" do
1285
+ expect(knife.ssh_identity_opts).to eq({
1286
+ key_files: [ "/identity.pem" ],
1287
+ keys_only: true,
1288
+ })
1289
+ end
1290
+ end
1291
+
1292
+ context "and a gateway identity file is also specified" do
1293
+ before do
1294
+ knife.config[:ssh_gateway_identity] = "/gateway.pem"
1295
+ end
1296
+
1297
+ it "generates the expected configuration (both keys, keys_only true)" do
1298
+ expect(knife.ssh_identity_opts).to eq({
1299
+ key_files: [ "/identity.pem", "/gateway.pem" ],
1300
+ keys_only: true,
1301
+ })
1302
+ end
1303
+ end
1304
+ end
1305
+ end
1306
+
1307
+ context "when no identity file is specified" do
1308
+ it "generates the expected configuration (no keys, keys_only false)" do
1309
+ expect(knife.ssh_identity_opts).to eq( {
1310
+ key_files: [ ],
1311
+ keys_only: false,
1312
+ })
1313
+ end
1314
+ context "and a gateway with gateway identity file is specified" do
1315
+ before do
1316
+ knife.config[:ssh_gateway] = "host"
1317
+ knife.config[:ssh_gateway_identity] = "/gateway.pem"
1318
+ end
1319
+
1320
+ it "generates the expected configuration (gateway key, keys_only false)" do
1321
+ expect(knife.ssh_identity_opts).to eq({
1322
+ key_files: [ "/gateway.pem" ],
1323
+ keys_only: false,
1324
+ })
1325
+ end
1326
+ end
1327
+ end
1328
+ end
1329
+ end
1330
+
1331
+ context "#gateway_opts" do
1332
+ let(:connection_protocol) { nil }
1333
+ before do
1334
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1335
+ end
1336
+
1337
+ context "for winrm" do
1338
+ let(:connection_protocol) { "winrm" }
1339
+ it "returns an empty hash" do
1340
+ expect(knife.gateway_opts).to eq({})
1341
+ end
1342
+ end
1343
+
1344
+ context "for ssh" do
1345
+ let(:connection_protocol) { "ssh" }
1346
+ context "and ssh_gateway with hostname, user and port provided" do
1347
+ before do
1348
+ knife.config[:ssh_gateway] = "testuser@gateway:9021"
1349
+ end
1350
+ it "returns a proper bastion host config subset" do
1351
+ expect(knife.gateway_opts).to eq({
1352
+ bastion_user: "testuser",
1353
+ bastion_host: "gateway",
1354
+ bastion_port: 9021,
1355
+ })
1356
+ end
1357
+ end
1358
+ context "and ssh_gateway with only hostname is given" do
1359
+ before do
1360
+ knife.config[:ssh_gateway] = "gateway"
1361
+ end
1362
+ it "returns a proper bastion host config subset" do
1363
+ expect(knife.gateway_opts).to eq({
1364
+ bastion_user: nil,
1365
+ bastion_host: "gateway",
1366
+ bastion_port: nil,
1367
+ })
1368
+ end
1369
+ end
1370
+ context "and ssh_gateway with hostname and user is is given" do
1371
+ before do
1372
+ knife.config[:ssh_gateway] = "testuser@gateway"
1373
+ end
1374
+ it "returns a proper bastion host config subset" do
1375
+ expect(knife.gateway_opts).to eq({
1376
+ bastion_user: "testuser",
1377
+ bastion_host: "gateway",
1378
+ bastion_port: nil,
1379
+ })
1380
+ end
1381
+ end
1382
+
1383
+ context "and ssh_gateway with hostname and port is is given" do
1384
+ before do
1385
+ knife.config[:ssh_gateway] = "gateway:11234"
1386
+ end
1387
+ it "returns a proper bastion host config subset" do
1388
+ expect(knife.gateway_opts).to eq({
1389
+ bastion_user: nil,
1390
+ bastion_host: "gateway",
1391
+ bastion_port: 11234,
1392
+ })
1393
+ end
1394
+ end
1395
+
1396
+ context "and ssh_gateway is not provided" do
1397
+ it "returns an empty hash" do
1398
+ expect(knife.gateway_opts).to eq({})
1399
+ end
1400
+ end
1401
+ end
1402
+ end
1403
+
1404
+ context "#sudo_opts" do
1405
+ let(:connection_protocol) { nil }
1406
+ before do
1407
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1408
+ end
1409
+
1410
+ context "for winrm" do
1411
+ let(:connection_protocol) { "winrm" }
1412
+ it "returns an empty hash" do
1413
+ expect(knife.sudo_opts).to eq({})
1414
+ end
1415
+ end
1416
+
1417
+ context "for ssh" do
1418
+ let(:connection_protocol) { "ssh" }
1419
+ context "when use_sudo is set" do
1420
+ before do
1421
+ knife.config[:use_sudo] = true
1422
+ end
1423
+
1424
+ it "returns a config that enables sudo" do
1425
+ expect(knife.sudo_opts).to eq( { sudo: true } )
1426
+ end
1427
+
1428
+ context "when use_sudo_password is also set" do
1429
+ before do
1430
+ knife.config[:use_sudo_password] = true
1431
+ knife.config[:connection_password] = "opscode"
1432
+ end
1433
+ it "includes :connection_password value in a sudo-enabled configuration" do
1434
+ expect(knife.sudo_opts).to eq({
1435
+ sudo: true,
1436
+ sudo_password: "opscode",
1437
+ })
1438
+ end
1439
+ end
1440
+
1441
+ context "when preserve_home is set" do
1442
+ before do
1443
+ knife.config[:preserve_home] = true
1444
+ end
1445
+ it "enables sudo with sudo_option to preserve home" do
1446
+ expect(knife.sudo_opts).to eq({
1447
+ sudo_options: "-H",
1448
+ sudo: true,
1449
+ })
1450
+ end
1451
+ end
1452
+ end
1453
+
1454
+ context "when use_sudo is not set" do
1455
+ before do
1456
+ knife.config[:use_sudo_password] = true
1457
+ knife.config[:preserve_home] = true
1458
+ end
1459
+ it "returns configuration for sudo off, ignoring other related options" do
1460
+ expect(knife.sudo_opts).to eq( { sudo: false } )
1461
+ end
1462
+ end
1463
+ end
1464
+ end
1465
+
1466
+ context "#ssh_opts" do
1467
+ let(:connection_protocol) { nil }
1468
+ before do
1469
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1470
+ end
1471
+
1472
+ context "for ssh" do
1473
+ let(:connection_protocol) { "ssh" }
1474
+ let(:default_opts) do
1475
+ {
1476
+ non_interactive: true,
1477
+ forward_agent: false,
1478
+ connection_timeout: 60,
1479
+ }
1480
+ end
1481
+
1482
+ context "by default" do
1483
+ it "returns a configuration hash with appropriate defaults" do
1484
+ expect(knife.ssh_opts).to eq default_opts
1485
+ end
1486
+ end
1487
+
1488
+ context "when ssh_forward_agent has a value" do
1489
+ before do
1490
+ knife.config[:ssh_forward_agent] = true
1491
+ end
1492
+ it "returns a default configuration hash with forward_agent set to true" do
1493
+ expect(knife.ssh_opts).to eq(default_opts.merge(forward_agent: true))
1494
+ end
1495
+ end
1496
+ context "when session_timeout has a value" do
1497
+ before do
1498
+ knife.config[:session_timeout] = 120
1499
+ end
1500
+ it "returns a default configuration hash with updated timeout value." do
1501
+ expect(knife.ssh_opts).to eq(default_opts.merge(connection_timeout: 120))
1502
+ end
1503
+ end
1504
+
1505
+ end
1506
+
1507
+ context "for winrm" do
1508
+ let(:connection_protocol) { "winrm" }
1509
+ it "returns an empty has because ssh is not winrm" do
1510
+ expect(knife.ssh_opts).to eq({})
1511
+ end
1512
+ end
1513
+
1514
+ end
1515
+
1516
+ context "#winrm_opts" do
1517
+ let(:connection_protocol) { nil }
1518
+ before do
1519
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1520
+ end
1521
+
1522
+ context "for winrm" do
1523
+ let(:connection_protocol) { "winrm" }
1524
+ let(:expected) do
1525
+ {
1526
+ winrm_transport: "negotiate",
1527
+ winrm_basic_auth_only: false,
1528
+ ssl: false,
1529
+ ssl_peer_fingerprint: nil,
1530
+ operation_timeout: 60,
1531
+ }
1532
+ end
1533
+
1534
+ it "generates a correct configuration hash with expected defaults" do
1535
+ expect(knife.winrm_opts).to eq expected
1536
+ end
1537
+
1538
+ context "with ssl_peer_fingerprint" do
1539
+ let(:ssl_peer_fingerprint_expected) do
1540
+ expected.merge({ ssl_peer_fingerprint: "ABCD" })
1541
+ end
1542
+
1543
+ before do
1544
+ knife.config[:winrm_ssl_peer_fingerprint] = "ABCD"
1545
+ end
1546
+
1547
+ it "generates a correct options hash with ssl_peer_fingerprint from the config provided" do
1548
+ expect(knife.winrm_opts).to eq ssl_peer_fingerprint_expected
1549
+ end
1550
+ end
1551
+
1552
+ context "with winrm_ssl" do
1553
+ let(:ssl_expected) do
1554
+ expected.merge({ ssl: true })
1555
+ end
1556
+ before do
1557
+ knife.config[:winrm_ssl] = true
1558
+ end
1559
+
1560
+ it "generates a correct options hash with ssl from the config provided" do
1561
+ expect(knife.winrm_opts).to eq ssl_expected
1562
+ end
1563
+ end
1564
+
1565
+ context "with winrm_auth_method" do
1566
+ let(:winrm_auth_method_expected) do
1567
+ expected.merge({ winrm_transport: "freeaccess" })
1568
+ end
1569
+
1570
+ before do
1571
+ knife.config[:winrm_auth_method] = "freeaccess"
1572
+ end
1573
+
1574
+ it "generates a correct options hash with winrm_transport from the config provided" do
1575
+ expect(knife.winrm_opts).to eq winrm_auth_method_expected
1576
+ end
1577
+ end
1578
+
1579
+ context "with ca_trust_file" do
1580
+ let(:ca_trust_expected) do
1581
+ expected.merge({ ca_trust_path: "/trust.me" })
1582
+ end
1583
+ before do
1584
+ knife.config[:ca_trust_file] = "/trust.me"
1585
+ end
1586
+
1587
+ it "generates a correct options hash with ca_trust_file from the config provided" do
1588
+ expect(knife.winrm_opts).to eq ca_trust_expected
1589
+ end
1590
+ end
1591
+
1592
+ context "with kerberos auth" do
1593
+ let(:kerberos_expected) do
1594
+ expected.merge({
1595
+ kerberos_service: "testsvc",
1596
+ kerberos_realm: "TESTREALM",
1597
+ winrm_transport: "kerberos",
1598
+ })
1599
+ end
1600
+
1601
+ before do
1602
+ knife.config[:winrm_auth_method] = "kerberos"
1603
+ knife.config[:kerberos_service] = "testsvc"
1604
+ knife.config[:kerberos_realm] = "TESTREALM"
1605
+ end
1606
+
1607
+ it "generates a correct options hash containing kerberos auth configuration from the config provided" do
1608
+ expect(knife.winrm_opts).to eq kerberos_expected
1609
+ end
1610
+ end
1611
+
1612
+ context "with winrm_basic_auth_only" do
1613
+ before do
1614
+ knife.config[:winrm_basic_auth_only] = true
1615
+ end
1616
+ let(:basic_auth_expected) do
1617
+ expected.merge( { winrm_basic_auth_only: true } )
1618
+ end
1619
+ it "generates a correct options hash containing winrm_basic_auth_only from the config provided" do
1620
+ expect(knife.winrm_opts).to eq basic_auth_expected
1621
+ end
1622
+ end
1623
+ end
1624
+
1625
+ context "for ssh" do
1626
+ let(:connection_protocol) { "ssh" }
1627
+ it "returns an empty hash because ssh is not winrm" do
1628
+ expect(knife.winrm_opts).to eq({})
1629
+ end
1630
+ end
1631
+ end
1632
+ describe "#run" do
1633
+ it "performs the steps we expect to run a bootstrap" do
1634
+ expect(knife).to receive(:check_license)
1635
+ expect(knife).to receive(:validate_name_args!).ordered
1636
+ expect(knife).to receive(:validate_protocol!).ordered
1637
+ expect(knife).to receive(:validate_first_boot_attributes!).ordered
1638
+ expect(knife).to receive(:validate_winrm_transport_opts!).ordered
1639
+ expect(knife).to receive(:validate_policy_options!).ordered
1640
+ expect(knife).to receive(:winrm_warn_no_ssl_verification).ordered
1641
+ expect(knife).to receive(:warn_on_short_session_timeout).ordered
1642
+ expect(knife).to receive(:connect!).ordered
1643
+ expect(knife).to receive(:register_client).ordered
1644
+ expect(knife).to receive(:render_template).and_return "content"
1645
+ expect(knife).to receive(:upload_bootstrap).with("content").and_return "/remote/path.sh"
1646
+ expect(knife).to receive(:perform_bootstrap).with("/remote/path.sh")
1647
+ expect(connection).to receive(:del_file!) # Make sure cleanup happens
1648
+
1649
+ knife.run
1650
+
1651
+ # Post-run verify expected state changes (not many directly in #run)
1652
+ expect($stdout.sync).to eq true
1653
+ end
1654
+ end
1655
+
1656
+ describe "#register_client" do
1657
+ let(:vault_handler_mock) { double("ChefVaultHandler") }
1658
+ let(:client_builder_mock) { double("ClientBuilder") }
1659
+ let(:node_name) { nil }
1660
+ before do
1661
+ allow(knife).to receive(:chef_vault_handler).and_return vault_handler_mock
1662
+ allow(knife).to receive(:client_builder).and_return client_builder_mock
1663
+ knife.config[:chef_node_name] = node_name
1664
+ end
1665
+
1666
+ shared_examples_for "creating the client locally" do
1667
+ context "when a valid node name is present" do
1668
+ let(:node_name) { "test" }
1669
+ before do
1670
+ allow(client_builder_mock).to receive(:client).and_return "client"
1671
+ allow(client_builder_mock).to receive(:client_path).and_return "/key.pem"
1672
+ end
1673
+
1674
+ it "runs client_builder and vault_handler" do
1675
+ expect(client_builder_mock).to receive(:run)
1676
+ expect(vault_handler_mock).to receive(:run).with("client")
1677
+ knife.register_client
1678
+ end
1679
+
1680
+ it "sets the path to the client key in the bootstrap context" do
1681
+ allow(client_builder_mock).to receive(:run)
1682
+ allow(vault_handler_mock).to receive(:run).with("client")
1683
+ knife.register_client
1684
+ expect(knife.bootstrap_context.client_pem).to eq "/key.pem"
1685
+ end
1686
+ end
1687
+
1688
+ context "when no valid node name is present" do
1689
+ let(:node_name) { nil }
1690
+ it "shows an error and exits" do
1691
+ expect(knife.ui).to receive(:error)
1692
+ expect { knife.register_client }.to raise_error(SystemExit)
1693
+ end
1694
+ end
1695
+ end
1696
+ context "when chef_vault_handler says we're using vault" do
1697
+ let(:vault_handler_mock) { double("ChefVaultHandler") }
1698
+ before do
1699
+ allow(vault_handler_mock).to receive(:doing_chef_vault?).and_return true
1700
+ end
1701
+ it_behaves_like "creating the client locally"
1702
+ end
1703
+
1704
+ context "when an non-existant validation key is specified in chef config" do
1705
+ before do
1706
+ Chef::Config[:validation_key] = "/blah"
1707
+ allow(vault_handler_mock).to receive(:doing_chef_vault?).and_return false
1708
+ allow(File).to receive(:exist?).with(%r{/blah}).and_return false
1709
+ end
1710
+ it_behaves_like "creating the client locally"
1711
+ end
1712
+
1713
+ context "when a valid validation key is given and we're doing old-style client creation" do
1714
+ before do
1715
+ Chef::Config[:validation_key] = "/blah"
1716
+ allow(File).to receive(:exist?).with(%r{/blah}).and_return true
1717
+ allow(vault_handler_mock).to receive(:doing_chef_vault?).and_return false
1718
+ end
1719
+
1720
+ it "shows a warning message" do
1721
+ expect(knife.ui).to receive(:warn).twice
1722
+ knife.register_client
1723
+ end
1724
+ end
1725
+ end
1726
+
1727
+ describe "#perform_bootstrap" do
1728
+ let(:exit_status) { 0 }
1729
+ let(:stdout) { "" }
1730
+ let(:result_mock) { double("result", exit_status: exit_status, stderr: "A message", stdout: stdout) }
1731
+
1732
+ before do
1733
+ allow(connection).to receive(:hostname).and_return "testhost"
1734
+ end
1735
+ it "runs the remote script and logs the output" do
1736
+ expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
1737
+ expect(knife).to receive(:bootstrap_command)
1738
+ .with("/path.sh")
1739
+ .and_return("sh /path.sh")
1740
+ expect(connection)
1741
+ .to receive(:run_command)
1742
+ .with("sh /path.sh")
1743
+ .and_yield("output here", nil)
1744
+ .and_return result_mock
1745
+
1746
+ expect(knife.ui).to receive(:msg).with(/testhost/)
1747
+ knife.perform_bootstrap("/path.sh")
1748
+ end
1749
+
1750
+ context "when the remote command fails" do
1751
+ let(:exit_status) { 1 }
1752
+ it "shows an error and exits" do
1753
+ expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
1754
+ expect(knife).to receive(:bootstrap_command)
1755
+ .with("/path.sh")
1756
+ .and_return("sh /path.sh")
1757
+ expect(connection).to receive(:run_command).with("sh /path.sh").and_return result_mock
1758
+ expect { knife.perform_bootstrap("/path.sh") }.to raise_error(SystemExit)
1759
+ end
1760
+ end
1761
+
1762
+ context "when the remote command failed due to su auth error" do
1763
+ let(:exit_status) { 1 }
1764
+ let(:stdout) { "su: Authentication failure" }
1765
+ let(:connection_obj) { double("connection", transport_options: {}) }
1766
+ it "shows an error and exits" do
1767
+ allow(connection).to receive(:connection).and_return(connection_obj)
1768
+ expect(knife.ui).to receive(:info).with(/Bootstrapping.*/)
1769
+ expect(knife).to receive(:bootstrap_command)
1770
+ .with("/path.sh")
1771
+ .and_return("su - USER -c 'sh /path.sh'")
1772
+ expect(connection)
1773
+ .to receive(:run_command)
1774
+ .with("su - USER -c 'sh /path.sh'")
1775
+ .and_yield("output here", nil)
1776
+ .and_raise(Train::UserError)
1777
+ expect { knife.perform_bootstrap("/path.sh") }.to raise_error(Train::UserError)
1778
+ end
1779
+ end
1780
+ end
1781
+
1782
+ describe "#connect!" do
1783
+ before do
1784
+ # These are not required at run-time because train will handle its own
1785
+ # protocol loading. In this case, we're simulating train failures and have to load
1786
+ # them ourselves.
1787
+ require "net/ssh"
1788
+ require "train/transports/ssh"
1789
+ end
1790
+
1791
+ context "in the normal case" do
1792
+ it "connects using the connection_opts and notifies the operator of progress" do
1793
+ expect(knife.ui).to receive(:info).with(/Connecting to.*/)
1794
+ expect(knife).to receive(:connection_opts).and_return( { opts: "here" })
1795
+ expect(knife).to receive(:do_connect).with( { opts: "here" } )
1796
+ knife.connect!
1797
+ end
1798
+ end
1799
+
1800
+ context "when a general non-auth-failure occurs" do
1801
+ let(:expected_error) { RuntimeError.new }
1802
+ before do
1803
+ allow(knife).to receive(:do_connect).and_raise(expected_error)
1804
+ end
1805
+ it "re-raises the exception" do
1806
+ expect { knife.connect! }.to raise_error(expected_error)
1807
+ end
1808
+ end
1809
+
1810
+ context "when ssh fingerprint is invalid" do
1811
+ let(:expected_error) { Train::Error.new("fingerprint AA:BB is unknown for \"blah,127.0.0.1\"") }
1812
+ before do
1813
+ allow(knife).to receive(:do_connect).and_raise(expected_error)
1814
+ end
1815
+ it "warns, prompts to accept, then connects with verify_host_key of accept_new" do
1816
+ expect(knife).to receive(:do_connect).and_raise(expected_error)
1817
+ expect(knife.ui).to receive(:confirm)
1818
+ .with(/.*host 'blah \(127.0.0.1\)'.*AA:BB.*Are you sure you want to continue.*/m)
1819
+ .and_return(true)
1820
+ expect(knife).to receive(:do_connect) do |opts|
1821
+ expect(opts[:verify_host_key]).to eq :accept_new
1822
+ end
1823
+ knife.connect!
1824
+ end
1825
+ end
1826
+
1827
+ context "when an auth failure occurs" do
1828
+ let(:expected_error) do
1829
+ e = Train::Error.new
1830
+ actual = Net::SSH::AuthenticationFailed.new
1831
+ # Simulate train's nested error - they wrap
1832
+ # ssh/network errors in a TrainError.
1833
+ allow(e).to receive(:cause).and_return(actual)
1834
+ e
1835
+ end
1836
+
1837
+ let(:expected_error_password_prompt) do
1838
+ e = Train::ClientError.new
1839
+ reason = :no_ssh_password_or_key_available
1840
+ allow(e).to receive(:reason).and_return(reason)
1841
+ e
1842
+ end
1843
+
1844
+ let(:expected_error_password_prompt_winrm) do
1845
+ e = RuntimeError.new
1846
+ message = "password is a required option"
1847
+ allow(e).to receive(:message).and_return(message)
1848
+ e
1849
+ end
1850
+
1851
+ context "and password auth was used" do
1852
+ before do
1853
+ allow(connection).to receive(:password_auth?).and_return true
1854
+ end
1855
+
1856
+ it "re-raises the error so as not to resubmit the same failing password" do
1857
+ expect(knife).to receive(:do_connect).and_raise(expected_error)
1858
+ expect { knife.connect! }.to raise_error(expected_error)
1859
+ end
1860
+ end
1861
+
1862
+ context "and password auth was not used" do
1863
+ before do
1864
+ allow(connection).to receive(:password_auth?).and_return false
1865
+ allow(connection).to receive(:user).and_return "testuser"
1866
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
1867
+ end
1868
+
1869
+ context "when using ssh" do
1870
+ let(:connection_protocol) { "ssh" }
1871
+
1872
+ it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password" do
1873
+ expect(knife).to receive(:do_connect).and_raise(expected_error_password_prompt)
1874
+ expect(knife.ui).to receive(:warn).with(/Failed to auth.*/)
1875
+ expect(knife.ui).to receive(:ask).and_return("newpassword")
1876
+ # Ensure that we set echo off to prevent showing password on the screen
1877
+ expect(knife).to receive(:do_connect) do |opts|
1878
+ expect(opts[:password]).to eq "newpassword"
1879
+ end
1880
+ knife.connect!
1881
+ end
1882
+ end
1883
+
1884
+ context "when using winrm" do
1885
+ let(:connection_protocol) { "winrm" }
1886
+
1887
+ it "warns, prompts for password, then reconnects with a password-enabled configuration using the new password for" do
1888
+ expect(knife).to receive(:do_connect).and_raise(expected_error_password_prompt_winrm)
1889
+ expect(knife.ui).to receive(:warn).with(/Failed to auth.*/)
1890
+ expect(knife.ui).to receive(:ask).and_return("newpassword")
1891
+ # Ensure that we set echo off to prevent showing password on the screen
1892
+ expect(knife).to receive(:do_connect) do |opts|
1893
+ expect(opts[:password]).to eq "newpassword"
1894
+ end
1895
+ knife.connect!
1896
+ end
1897
+ end
1898
+ end
1899
+ end
1900
+ end
1901
+
1902
+ it "verifies that a server to bootstrap was given as a command line arg" do
1903
+ knife.name_args = nil
1904
+ expect(knife).to receive(:check_license)
1905
+ expect { knife.run }.to raise_error(SystemExit)
1906
+ expect(stderr.string).to match(/ERROR:.+FQDN or ip/)
1907
+ end
1908
+
1909
+ describe "#bootstrap_context" do
1910
+ context "under Windows" do
1911
+ let(:windows_test) { true }
1912
+ it "creates a WindowsBootstrapContext" do
1913
+ require "chef/knife/core/windows_bootstrap_context"
1914
+ expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::WindowsBootstrapContext
1915
+ end
1916
+ end
1917
+
1918
+ context "under linux" do
1919
+ let(:linux_test) { true }
1920
+ it "creates a BootstrapContext" do
1921
+ require "chef/knife/core/bootstrap_context"
1922
+ expect(knife.bootstrap_context.class).to eq Chef::Knife::Core::BootstrapContext
1923
+ end
1924
+ end
1925
+ end
1926
+
1927
+ describe "#config_value" do
1928
+ before do
1929
+ knife.config[:test_key_a] = "a from cli"
1930
+ knife.config[:test_key_b] = "b from cli"
1931
+ Chef::Config[:knife][:test_key_a] = "a from Chef::Config"
1932
+ Chef::Config[:knife][:test_key_c] = "c from Chef::Config"
1933
+ Chef::Config[:knife][:alt_test_key_c] = "alt c from Chef::Config"
1934
+ knife.merge_configs
1935
+ Chef::Config[:treat_deprecation_warnings_as_errors] = false
1936
+ end
1937
+
1938
+ it "returns the Chef::Config value from the cli when the CLI key is set" do
1939
+ expect(knife.config_value(:test_key_a, :alt_test_key_c)).to eq "a from cli"
1940
+ end
1941
+
1942
+ it "returns the Chef::Config value from the alternative key when the CLI key is not set" do
1943
+ expect(knife.config_value(:test_key_d, :alt_test_key_c)).to eq "alt c from Chef::Config"
1944
+ end
1945
+
1946
+ it "returns the default value when the key is not provided by CLI or Chef::Config" do
1947
+ expect(knife.config_value(:missing_key, :missing_key, "found")).to eq "found"
1948
+ end
1949
+ end
1950
+
1951
+ describe "#upload_bootstrap" do
1952
+ before do
1953
+ allow(connection).to receive(:temp_dir).and_return(temp_dir)
1954
+ allow(connection).to receive(:normalize_path) { |a| a }
1955
+ end
1956
+
1957
+ let(:content) { "bootstrap script content" }
1958
+ context "under Windows" do
1959
+ let(:windows_test) { true }
1960
+ let(:temp_dir) { "C:/Temp/bootstrap" }
1961
+ it "creates a bat file in the temp dir provided by connection, using given content" do
1962
+ expect(connection).to receive(:upload_file_content!).with(content, "C:/Temp/bootstrap/bootstrap.bat")
1963
+ expect(knife.upload_bootstrap(content)).to eq "C:/Temp/bootstrap/bootstrap.bat"
1964
+ end
1965
+ end
1966
+
1967
+ context "under Linux" do
1968
+ let(:linux_test) { true }
1969
+ let(:temp_dir) { "/tmp/bootstrap" }
1970
+ it "creates a 'sh file in the temp dir provided by connection, using given content" do
1971
+ expect(connection).to receive(:upload_file_content!).with(content, "/tmp/bootstrap/bootstrap.sh")
1972
+ expect(knife.upload_bootstrap(content)).to eq "/tmp/bootstrap/bootstrap.sh"
1973
+ end
1974
+ end
1975
+ end
1976
+
1977
+ describe "#bootstrap_command" do
1978
+ context "under Windows" do
1979
+ let(:windows_test) { true }
1980
+ it "prefixes the command to run under cmd.exe" do
1981
+ expect(knife.bootstrap_command("autoexec.bat")).to eq "cmd.exe /C autoexec.bat"
1982
+ end
1983
+
1984
+ end
1985
+ context "under Linux" do
1986
+ let(:linux_test) { true }
1987
+ it "prefixes the command to run under sh" do
1988
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "sh bootstrap.sh"
1989
+ end
1990
+
1991
+ context "with --su-user option" do
1992
+ let(:connection_obj) { double("connection", transport_options: {}) }
1993
+ before do
1994
+ knife.config[:su_user] = "root"
1995
+ allow(connection).to receive(:connection).and_return(connection_obj)
1996
+ end
1997
+ it "prefixes the command to run using su -USER -c" do
1998
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
1999
+ expect(connection_obj.transport_options.key?(:pty)).to eq true
2000
+ end
2001
+
2002
+ it "sudo appended if --sudo option enabled" do
2003
+ knife.config[:use_sudo] = true
2004
+ expect(knife.bootstrap_command("bootstrap.sh")).to eq "sudo su - #{knife.config[:su_user]} -c 'sh bootstrap.sh'"
2005
+ expect(connection_obj.transport_options.key?(:pty)).to eq true
2006
+ end
2007
+ end
2008
+ end
2009
+ end
2010
+
2011
+ describe "#default_bootstrap_template" do
2012
+ context "under Windows" do
2013
+ let(:windows_test) { true }
2014
+ it "is windows-chef-client-msi" do
2015
+ expect(knife.default_bootstrap_template).to eq "windows-chef-client-msi"
2016
+ end
2017
+
2018
+ end
2019
+ context "under Linux" do
2020
+ let(:linux_test) { true }
2021
+ it "is chef-full" do
2022
+ expect(knife.default_bootstrap_template).to eq "chef-full"
2023
+ end
2024
+ end
2025
+ end
2026
+
2027
+ describe "#do_connect" do
2028
+ let(:host_descriptor) { "example.com" }
2029
+ let(:connection) { double("TrainConnector") }
2030
+ let(:connector_mock) { double("TargetResolver", targets: [ connection ]) }
2031
+ before do
2032
+ allow(knife).to receive(:host_descriptor).and_return host_descriptor
2033
+ end
2034
+
2035
+ it "creates a TrainConnector and connects it" do
2036
+ expect(Chef::Knife::Bootstrap::TrainConnector).to receive(:new).and_return connection
2037
+ expect(connection).to receive(:connect!)
2038
+ knife.do_connect({})
2039
+ end
2040
+
2041
+ context "when sshd configured with requiretty" do
2042
+ let(:pty_err_msg) { "Sudo requires a TTY. Please see the README on how to configure sudo to allow for non-interactive usage." }
2043
+ let(:expected_error) { Train::UserError.new(pty_err_msg, :sudo_no_tty) }
2044
+ before do
2045
+ allow(connection).to receive(:connect!).and_raise(expected_error)
2046
+ end
2047
+ it "retry with pty true request option" do
2048
+ expect(Chef::Knife::Bootstrap::TrainConnector).to receive(:new).and_return(connection).exactly(2).times
2049
+ expect(knife.ui).to receive(:warn).with("#{pty_err_msg} - trying with pty request")
2050
+ expect { knife.do_connect({}) }.to raise_error(expected_error)
2051
+ end
2052
+ end
2053
+ end
2054
+
2055
+ describe "validate_winrm_transport_opts!" do
2056
+ before do
2057
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
2058
+ end
2059
+
2060
+ context "when using ssh" do
2061
+ let(:connection_protocol) { "ssh" }
2062
+ it "returns true" do
2063
+ expect(knife.validate_winrm_transport_opts!).to eq true
2064
+ end
2065
+ end
2066
+ context "when using winrm" do
2067
+ let(:connection_protocol) { "winrm" }
2068
+ context "with plaintext auth" do
2069
+ before do
2070
+ knife.config[:winrm_auth_method] = "plaintext"
2071
+ end
2072
+ context "with ssl" do
2073
+ before do
2074
+ knife.config[:winrm_ssl] = true
2075
+ end
2076
+ it "will not error because we won't send anything in plaintext regardless" do
2077
+ expect(knife.validate_winrm_transport_opts!).to eq true
2078
+ end
2079
+ end
2080
+ context "without ssl" do
2081
+ before do
2082
+ knife.config[:winrm_ssl] = false
2083
+ end
2084
+ context "and no validation key exists" do
2085
+ before do
2086
+ Chef::Config[:validation_key] = "validation_key.pem"
2087
+ allow(File).to receive(:exist?).with(/.*validation_key.pem/).and_return false
2088
+ end
2089
+
2090
+ it "will error because we will generate and send a client key over the wire in plaintext" do
2091
+ expect { knife.validate_winrm_transport_opts! }.to raise_error(SystemExit)
2092
+ end
2093
+
2094
+ end
2095
+ context "and a validation key exists" do
2096
+ before do
2097
+ Chef::Config[:validation_key] = "validation_key.pem"
2098
+ allow(File).to receive(:exist?).with(/.*validation_key.pem/).and_return true
2099
+ end
2100
+ # TODO - don't we still send validation key?
2101
+ it "will not error because we don not send client key over the wire" do
2102
+ expect(knife.validate_winrm_transport_opts!).to eq true
2103
+ end
2104
+ end
2105
+ end
2106
+ end
2107
+
2108
+ context "with other auth" do
2109
+ before do
2110
+ knife.config[:winrm_auth_method] = "kerberos"
2111
+ end
2112
+
2113
+ context "and no validation key exists" do
2114
+ before do
2115
+
2116
+ Chef::Config[:validation_key] = "validation_key.pem"
2117
+ allow(File).to receive(:exist?).with(/.*validation_key.pem/).and_return false
2118
+ end
2119
+
2120
+ it "will not error because we're not using plaintext auth" do
2121
+ expect(knife.validate_winrm_transport_opts!).to eq true
2122
+ end
2123
+ end
2124
+ context "and a validation key exists" do
2125
+ before do
2126
+ Chef::Config[:validation_key] = "validation_key.pem"
2127
+ allow(File).to receive(:exist?).with(/.*validation_key.pem/).and_return true
2128
+ end
2129
+
2130
+ it "will not error because a client key won't be sent over the wire in plaintext when a validation key is present" do
2131
+ expect(knife.validate_winrm_transport_opts!).to eq true
2132
+ end
2133
+ end
2134
+
2135
+ end
2136
+
2137
+ end
2138
+
2139
+ end
2140
+
2141
+ describe "#winrm_warn_no_ssl_verification" do
2142
+ before do
2143
+ allow(knife).to receive(:connection_protocol).and_return connection_protocol
2144
+ end
2145
+
2146
+ context "when using ssh" do
2147
+ let(:connection_protocol) { "ssh" }
2148
+ it "does not issue a warning" do
2149
+ expect(knife.ui).to_not receive(:warn)
2150
+ knife.winrm_warn_no_ssl_verification
2151
+ end
2152
+ end
2153
+ context "when using winrm" do
2154
+ let(:connection_protocol) { "winrm" }
2155
+ context "winrm_no_verify_cert is set" do
2156
+ before do
2157
+ knife.config[:winrm_no_verify_cert] = true
2158
+ end
2159
+
2160
+ context "and ca_trust_file is present" do
2161
+ before do
2162
+ knife.config[:ca_trust_file] = "file"
2163
+ end
2164
+
2165
+ it "does not issue a warning" do
2166
+ expect(knife.ui).to_not receive(:warn)
2167
+ knife.winrm_warn_no_ssl_verification
2168
+ end
2169
+ end
2170
+
2171
+ context "and winrm_ssl_peer_fingerprint is present" do
2172
+ before do
2173
+ knife.config[:winrm_ssl_peer_fingerprint] = "ABCD"
2174
+ end
2175
+ it "does not issue a warning" do
2176
+ expect(knife.ui).to_not receive(:warn)
2177
+ knife.winrm_warn_no_ssl_verification
2178
+ end
2179
+ end
2180
+ context "and neither ca_trust_file nor winrm_ssl_peer_fingerprint is present" do
2181
+ it "issues a warning" do
2182
+ expect(knife.ui).to receive(:warn)
2183
+ knife.winrm_warn_no_ssl_verification
2184
+ end
2185
+ end
2186
+ end
2187
+ end
2188
+ end
2189
+
2190
+ describe "#warn_on_short_session_timeout" do
2191
+ let(:session_timeout) { 60 }
2192
+
2193
+ before do
2194
+ allow(knife).to receive(:session_timeout).and_return(session_timeout)
2195
+ end
2196
+
2197
+ context "timeout is not set at all" do
2198
+ let(:session_timeout) { nil }
2199
+ it "does not issue a warning" do
2200
+ expect(knife.ui).to_not receive(:warn)
2201
+ knife.warn_on_short_session_timeout
2202
+ end
2203
+ end
2204
+
2205
+ context "timeout is more than 15" do
2206
+ let(:session_timeout) { 16 }
2207
+ it "does not issue a warning" do
2208
+ expect(knife.ui).to_not receive(:warn)
2209
+ knife.warn_on_short_session_timeout
2210
+ end
2211
+ end
2212
+ context "timeout is 15 or less" do
2213
+ let(:session_timeout) { 15 }
2214
+ it "issues a warning" do
2215
+ expect(knife.ui).to receive(:warn)
2216
+ knife.warn_on_short_session_timeout
2217
+ end
2218
+ end
2219
+ end
2220
+ end