mbailey-chef 0.9.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +172 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +25 -0
  5. data/bin/knife +26 -0
  6. data/bin/shef +34 -0
  7. data/distro/README +2 -0
  8. data/distro/common/man/man1/chef-indexer.1 +42 -0
  9. data/distro/common/man/man1/chef-server-webui.1 +106 -0
  10. data/distro/common/man/man1/chef-server.1 +107 -0
  11. data/distro/common/man/man1/chef-solr-indexer.1 +55 -0
  12. data/distro/common/man/man1/chef-solr.1 +55 -0
  13. data/distro/common/man/man8/chef-client.8 +63 -0
  14. data/distro/common/man/man8/chef-solo.8 +57 -0
  15. data/distro/common/man/man8/chef-solr-rebuild.8 +37 -0
  16. data/distro/common/man/man8/knife.8 +1349 -0
  17. data/distro/common/man/man8/shef.8 +45 -0
  18. data/distro/common/markdown/README +3 -0
  19. data/distro/common/markdown/knife.mkd +832 -0
  20. data/distro/debian/etc/default/chef-client +4 -0
  21. data/distro/debian/etc/default/chef-server +9 -0
  22. data/distro/debian/etc/default/chef-server-webui +9 -0
  23. data/distro/debian/etc/default/chef-solr +7 -0
  24. data/distro/debian/etc/default/chef-solr-indexer +7 -0
  25. data/distro/debian/etc/init/chef-client.conf +17 -0
  26. data/distro/debian/etc/init/chef-server-webui.conf +17 -0
  27. data/distro/debian/etc/init/chef-server.conf +17 -0
  28. data/distro/debian/etc/init/chef-solr-indexer.conf +17 -0
  29. data/distro/debian/etc/init/chef-solr.conf +17 -0
  30. data/distro/debian/etc/init.d/chef-client +175 -0
  31. data/distro/debian/etc/init.d/chef-server +122 -0
  32. data/distro/debian/etc/init.d/chef-server-webui +123 -0
  33. data/distro/debian/etc/init.d/chef-solr +177 -0
  34. data/distro/debian/etc/init.d/chef-solr-indexer +176 -0
  35. data/distro/redhat/etc/init.d/chef-client +106 -0
  36. data/distro/redhat/etc/init.d/chef-server +112 -0
  37. data/distro/redhat/etc/init.d/chef-server-webui +112 -0
  38. data/distro/redhat/etc/init.d/chef-solr +104 -0
  39. data/distro/redhat/etc/init.d/chef-solr-indexer +104 -0
  40. data/distro/redhat/etc/logrotate.d/chef-client +8 -0
  41. data/distro/redhat/etc/logrotate.d/chef-server +8 -0
  42. data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
  43. data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
  44. data/distro/redhat/etc/logrotate.d/chef-solr-indexer +8 -0
  45. data/distro/redhat/etc/sysconfig/chef-client +15 -0
  46. data/distro/redhat/etc/sysconfig/chef-server +14 -0
  47. data/distro/redhat/etc/sysconfig/chef-server-webui +14 -0
  48. data/distro/redhat/etc/sysconfig/chef-solr +8 -0
  49. data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
  50. data/lib/chef/api_client.rb +264 -0
  51. data/lib/chef/application/agent.rb +18 -0
  52. data/lib/chef/application/client.rb +246 -0
  53. data/lib/chef/application/knife.rb +171 -0
  54. data/lib/chef/application/solo.rb +215 -0
  55. data/lib/chef/application.rb +127 -0
  56. data/lib/chef/applications.rb +4 -0
  57. data/lib/chef/certificate.rb +194 -0
  58. data/lib/chef/checksum.rb +182 -0
  59. data/lib/chef/checksum_cache.rb +173 -0
  60. data/lib/chef/client.rb +304 -0
  61. data/lib/chef/config.rb +240 -0
  62. data/lib/chef/cookbook/cookbook_collection.rb +44 -0
  63. data/lib/chef/cookbook/file_system_file_vendor.rb +54 -0
  64. data/lib/chef/cookbook/file_vendor.rb +48 -0
  65. data/lib/chef/cookbook/metadata/version.rb +87 -0
  66. data/lib/chef/cookbook/metadata.rb +500 -0
  67. data/lib/chef/cookbook/remote_file_vendor.rb +87 -0
  68. data/lib/chef/cookbook/syntax_check.rb +136 -0
  69. data/lib/chef/cookbook_loader.rb +227 -0
  70. data/lib/chef/cookbook_site_streaming_uploader.rb +244 -0
  71. data/lib/chef/cookbook_uploader.rb +103 -0
  72. data/lib/chef/cookbook_version.rb +930 -0
  73. data/lib/chef/couchdb.rb +239 -0
  74. data/lib/chef/daemon.rb +172 -0
  75. data/lib/chef/data_bag.rb +215 -0
  76. data/lib/chef/data_bag_item.rb +228 -0
  77. data/lib/chef/exceptions.rb +66 -0
  78. data/lib/chef/file_access_control.rb +140 -0
  79. data/lib/chef/file_cache.rb +218 -0
  80. data/lib/chef/handler/json_file.rb +58 -0
  81. data/lib/chef/handler.rb +206 -0
  82. data/lib/chef/index_queue/amqp_client.rb +113 -0
  83. data/lib/chef/index_queue/consumer.rb +76 -0
  84. data/lib/chef/index_queue/indexable.rb +76 -0
  85. data/lib/chef/index_queue.rb +29 -0
  86. data/lib/chef/knife/bootstrap/archlinux-gems.erb +44 -0
  87. data/lib/chef/knife/bootstrap/centos5-gems.erb +41 -0
  88. data/lib/chef/knife/bootstrap/client-install.vbs +80 -0
  89. data/lib/chef/knife/bootstrap/fedora13-gems.erb +38 -0
  90. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +32 -0
  91. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +43 -0
  92. data/lib/chef/knife/bootstrap/windows-gems.erb +34 -0
  93. data/lib/chef/knife/bootstrap.rb +181 -0
  94. data/lib/chef/knife/client_bulk_delete.rb +40 -0
  95. data/lib/chef/knife/client_create.rb +70 -0
  96. data/lib/chef/knife/client_delete.rb +45 -0
  97. data/lib/chef/knife/client_edit.rb +45 -0
  98. data/lib/chef/knife/client_list.rb +40 -0
  99. data/lib/chef/knife/client_reregister.rb +56 -0
  100. data/lib/chef/knife/client_show.rb +50 -0
  101. data/lib/chef/knife/configure.rb +140 -0
  102. data/lib/chef/knife/configure_client.rb +52 -0
  103. data/lib/chef/knife/cookbook_bulk_delete.rb +58 -0
  104. data/lib/chef/knife/cookbook_create.rb +209 -0
  105. data/lib/chef/knife/cookbook_delete.rb +143 -0
  106. data/lib/chef/knife/cookbook_download.rb +130 -0
  107. data/lib/chef/knife/cookbook_list.rb +41 -0
  108. data/lib/chef/knife/cookbook_metadata.rb +82 -0
  109. data/lib/chef/knife/cookbook_metadata_from_file.rb +40 -0
  110. data/lib/chef/knife/cookbook_show.rb +98 -0
  111. data/lib/chef/knife/cookbook_site_download.rb +58 -0
  112. data/lib/chef/knife/cookbook_site_list.rb +56 -0
  113. data/lib/chef/knife/cookbook_site_search.rb +51 -0
  114. data/lib/chef/knife/cookbook_site_share.rb +109 -0
  115. data/lib/chef/knife/cookbook_site_show.rb +57 -0
  116. data/lib/chef/knife/cookbook_site_unshare.rb +52 -0
  117. data/lib/chef/knife/cookbook_site_vendor.rb +133 -0
  118. data/lib/chef/knife/cookbook_test.rb +82 -0
  119. data/lib/chef/knife/cookbook_upload.rb +95 -0
  120. data/lib/chef/knife/data_bag_create.rb +59 -0
  121. data/lib/chef/knife/data_bag_delete.rb +48 -0
  122. data/lib/chef/knife/data_bag_edit.rb +50 -0
  123. data/lib/chef/knife/data_bag_from_file.rb +44 -0
  124. data/lib/chef/knife/data_bag_list.rb +43 -0
  125. data/lib/chef/knife/data_bag_show.rb +41 -0
  126. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  127. data/lib/chef/knife/ec2_server_create.rb +216 -0
  128. data/lib/chef/knife/ec2_server_delete.rb +90 -0
  129. data/lib/chef/knife/ec2_server_list.rb +88 -0
  130. data/lib/chef/knife/exec.rb +52 -0
  131. data/lib/chef/knife/index_rebuild.rb +51 -0
  132. data/lib/chef/knife/node_bulk_delete.rb +43 -0
  133. data/lib/chef/knife/node_create.rb +47 -0
  134. data/lib/chef/knife/node_delete.rb +44 -0
  135. data/lib/chef/knife/node_edit.rb +44 -0
  136. data/lib/chef/knife/node_from_file.rb +42 -0
  137. data/lib/chef/knife/node_list.rb +41 -0
  138. data/lib/chef/knife/node_run_list_add.rb +64 -0
  139. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  140. data/lib/chef/knife/node_show.rb +54 -0
  141. data/lib/chef/knife/rackspace_server_create.rb +156 -0
  142. data/lib/chef/knife/rackspace_server_delete.rb +57 -0
  143. data/lib/chef/knife/rackspace_server_list.rb +59 -0
  144. data/lib/chef/knife/recipe_list.rb +32 -0
  145. data/lib/chef/knife/role_bulk_delete.rb +44 -0
  146. data/lib/chef/knife/role_create.rb +52 -0
  147. data/lib/chef/knife/role_delete.rb +44 -0
  148. data/lib/chef/knife/role_edit.rb +45 -0
  149. data/lib/chef/knife/role_from_file.rb +46 -0
  150. data/lib/chef/knife/role_list.rb +40 -0
  151. data/lib/chef/knife/role_show.rb +51 -0
  152. data/lib/chef/knife/search.rb +94 -0
  153. data/lib/chef/knife/slicehost_images_list.rb +53 -0
  154. data/lib/chef/knife/slicehost_server_create.rb +103 -0
  155. data/lib/chef/knife/slicehost_server_delete.rb +61 -0
  156. data/lib/chef/knife/slicehost_server_list.rb +64 -0
  157. data/lib/chef/knife/ssh.rb +328 -0
  158. data/lib/chef/knife/status.rb +87 -0
  159. data/lib/chef/knife/terremark_server_create.rb +152 -0
  160. data/lib/chef/knife/terremark_server_delete.rb +87 -0
  161. data/lib/chef/knife/terremark_server_list.rb +77 -0
  162. data/lib/chef/knife/windows_bootstrap.rb +154 -0
  163. data/lib/chef/knife.rb +522 -0
  164. data/lib/chef/log.rb +61 -0
  165. data/lib/chef/mixin/check_helper.rb +31 -0
  166. data/lib/chef/mixin/checksum.rb +32 -0
  167. data/lib/chef/mixin/command/unix.rb +215 -0
  168. data/lib/chef/mixin/command/windows.rb +72 -0
  169. data/lib/chef/mixin/command.rb +220 -0
  170. data/lib/chef/mixin/convert_to_class_name.rb +63 -0
  171. data/lib/chef/mixin/create_path.rb +56 -0
  172. data/lib/chef/mixin/deep_merge.rb +225 -0
  173. data/lib/chef/mixin/deprecation.rb +65 -0
  174. data/lib/chef/mixin/find_preferred_file.rb +92 -0
  175. data/lib/chef/mixin/from_file.rb +50 -0
  176. data/lib/chef/mixin/language.rb +156 -0
  177. data/lib/chef/mixin/language_include_attribute.rb +61 -0
  178. data/lib/chef/mixin/language_include_recipe.rb +52 -0
  179. data/lib/chef/mixin/params_validate.rb +225 -0
  180. data/lib/chef/mixin/recipe_definition_dsl_core.rb +81 -0
  181. data/lib/chef/mixin/shell_out.rb +38 -0
  182. data/lib/chef/mixin/template.rb +95 -0
  183. data/lib/chef/mixin/xml_escape.rb +140 -0
  184. data/lib/chef/mixins.rb +16 -0
  185. data/lib/chef/monkey_patches/dir.rb +36 -0
  186. data/lib/chef/monkey_patches/string.rb +28 -0
  187. data/lib/chef/monkey_patches/tempfile.rb +64 -0
  188. data/lib/chef/node/attribute.rb +465 -0
  189. data/lib/chef/node.rb +601 -0
  190. data/lib/chef/openid_registration.rb +187 -0
  191. data/lib/chef/platform.rb +371 -0
  192. data/lib/chef/provider/breakpoint.rb +36 -0
  193. data/lib/chef/provider/cookbook_file.rb +100 -0
  194. data/lib/chef/provider/cron/solaris.rb +195 -0
  195. data/lib/chef/provider/cron.rb +186 -0
  196. data/lib/chef/provider/deploy/revision.rb +73 -0
  197. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  198. data/lib/chef/provider/deploy.rb +319 -0
  199. data/lib/chef/provider/directory.rb +72 -0
  200. data/lib/chef/provider/env/windows.rb +75 -0
  201. data/lib/chef/provider/env.rb +152 -0
  202. data/lib/chef/provider/erl_call.rb +72 -0
  203. data/lib/chef/provider/execute.rb +58 -0
  204. data/lib/chef/provider/file.rb +213 -0
  205. data/lib/chef/provider/git.rb +211 -0
  206. data/lib/chef/provider/group/dscl.rb +121 -0
  207. data/lib/chef/provider/group/gpasswd.rb +53 -0
  208. data/lib/chef/provider/group/groupadd.rb +78 -0
  209. data/lib/chef/provider/group/pw.rb +84 -0
  210. data/lib/chef/provider/group/usermod.rb +57 -0
  211. data/lib/chef/provider/group/windows.rb +79 -0
  212. data/lib/chef/provider/group.rb +133 -0
  213. data/lib/chef/provider/http_request.rb +122 -0
  214. data/lib/chef/provider/ifconfig.rb +132 -0
  215. data/lib/chef/provider/link.rb +161 -0
  216. data/lib/chef/provider/log.rb +54 -0
  217. data/lib/chef/provider/mdadm.rb +91 -0
  218. data/lib/chef/provider/mount/mount.rb +232 -0
  219. data/lib/chef/provider/mount/windows.rb +80 -0
  220. data/lib/chef/provider/mount.rb +117 -0
  221. data/lib/chef/provider/ohai.rb +41 -0
  222. data/lib/chef/provider/package/apt.rb +110 -0
  223. data/lib/chef/provider/package/dpkg.rb +112 -0
  224. data/lib/chef/provider/package/easy_install.rb +114 -0
  225. data/lib/chef/provider/package/freebsd.rb +123 -0
  226. data/lib/chef/provider/package/macports.rb +105 -0
  227. data/lib/chef/provider/package/pacman.rb +101 -0
  228. data/lib/chef/provider/package/portage.rb +124 -0
  229. data/lib/chef/provider/package/rpm.rb +101 -0
  230. data/lib/chef/provider/package/rubygems.rb +462 -0
  231. data/lib/chef/provider/package/solaris.rb +127 -0
  232. data/lib/chef/provider/package/yum-dump.py +128 -0
  233. data/lib/chef/provider/package/yum.rb +222 -0
  234. data/lib/chef/provider/package/zypper.rb +133 -0
  235. data/lib/chef/provider/package.rb +160 -0
  236. data/lib/chef/provider/remote_directory.rb +140 -0
  237. data/lib/chef/provider/remote_file.rb +120 -0
  238. data/lib/chef/provider/route.rb +195 -0
  239. data/lib/chef/provider/ruby_block.rb +33 -0
  240. data/lib/chef/provider/script.rb +55 -0
  241. data/lib/chef/provider/service/arch.rb +109 -0
  242. data/lib/chef/provider/service/debian.rb +105 -0
  243. data/lib/chef/provider/service/freebsd.rb +156 -0
  244. data/lib/chef/provider/service/gentoo.rb +54 -0
  245. data/lib/chef/provider/service/init.rb +71 -0
  246. data/lib/chef/provider/service/redhat.rb +60 -0
  247. data/lib/chef/provider/service/simple.rb +118 -0
  248. data/lib/chef/provider/service/solaris.rb +85 -0
  249. data/lib/chef/provider/service/upstart.rb +192 -0
  250. data/lib/chef/provider/service/windows.rb +129 -0
  251. data/lib/chef/provider/service.rb +128 -0
  252. data/lib/chef/provider/subversion.rb +159 -0
  253. data/lib/chef/provider/template.rb +105 -0
  254. data/lib/chef/provider/user/dscl.rb +280 -0
  255. data/lib/chef/provider/user/pw.rb +113 -0
  256. data/lib/chef/provider/user/useradd.rb +137 -0
  257. data/lib/chef/provider/user/windows.rb +124 -0
  258. data/lib/chef/provider/user.rb +187 -0
  259. data/lib/chef/provider.rb +124 -0
  260. data/lib/chef/providers.rb +91 -0
  261. data/lib/chef/recipe.rb +130 -0
  262. data/lib/chef/resource/apt_package.rb +34 -0
  263. data/lib/chef/resource/bash.rb +33 -0
  264. data/lib/chef/resource/breakpoint.rb +35 -0
  265. data/lib/chef/resource/cookbook_file.rb +45 -0
  266. data/lib/chef/resource/cron.rb +188 -0
  267. data/lib/chef/resource/csh.rb +33 -0
  268. data/lib/chef/resource/deploy.rb +371 -0
  269. data/lib/chef/resource/deploy_revision.rb +35 -0
  270. data/lib/chef/resource/directory.rb +76 -0
  271. data/lib/chef/resource/dpkg_package.rb +34 -0
  272. data/lib/chef/resource/easy_install_package.rb +41 -0
  273. data/lib/chef/resource/env.rb +58 -0
  274. data/lib/chef/resource/erl_call.rb +83 -0
  275. data/lib/chef/resource/execute.rb +127 -0
  276. data/lib/chef/resource/file.rb +92 -0
  277. data/lib/chef/resource/freebsd_package.rb +35 -0
  278. data/lib/chef/resource/gem_package.rb +49 -0
  279. data/lib/chef/resource/git.rb +36 -0
  280. data/lib/chef/resource/group.rb +70 -0
  281. data/lib/chef/resource/http_request.rb +61 -0
  282. data/lib/chef/resource/ifconfig.rb +134 -0
  283. data/lib/chef/resource/link.rb +78 -0
  284. data/lib/chef/resource/log.rb +62 -0
  285. data/lib/chef/resource/macports_package.rb +29 -0
  286. data/lib/chef/resource/mdadm.rb +82 -0
  287. data/lib/chef/resource/mount.rb +135 -0
  288. data/lib/chef/resource/ohai.rb +40 -0
  289. data/lib/chef/resource/package.rb +80 -0
  290. data/lib/chef/resource/pacman_package.rb +33 -0
  291. data/lib/chef/resource/perl.rb +33 -0
  292. data/lib/chef/resource/portage_package.rb +33 -0
  293. data/lib/chef/resource/python.rb +33 -0
  294. data/lib/chef/resource/remote_directory.rb +109 -0
  295. data/lib/chef/resource/remote_file.rb +83 -0
  296. data/lib/chef/resource/route.rb +135 -0
  297. data/lib/chef/resource/rpm_package.rb +34 -0
  298. data/lib/chef/resource/ruby.rb +33 -0
  299. data/lib/chef/resource/ruby_block.rb +40 -0
  300. data/lib/chef/resource/scm.rb +146 -0
  301. data/lib/chef/resource/script.rb +60 -0
  302. data/lib/chef/resource/service.rb +160 -0
  303. data/lib/chef/resource/solaris_package.rb +36 -0
  304. data/lib/chef/resource/subversion.rb +36 -0
  305. data/lib/chef/resource/template.rb +69 -0
  306. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  307. data/lib/chef/resource/user.rb +130 -0
  308. data/lib/chef/resource/yum_package.rb +43 -0
  309. data/lib/chef/resource.rb +523 -0
  310. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  311. data/lib/chef/resource_collection.rb +217 -0
  312. data/lib/chef/resource_definition.rb +67 -0
  313. data/lib/chef/resource_definition_list.rb +38 -0
  314. data/lib/chef/resources.rb +64 -0
  315. data/lib/chef/rest/auth_credentials.rb +78 -0
  316. data/lib/chef/rest/cookie_jar.rb +31 -0
  317. data/lib/chef/rest/rest_request.rb +188 -0
  318. data/lib/chef/rest.rb +394 -0
  319. data/lib/chef/role.rb +287 -0
  320. data/lib/chef/run_context.rb +110 -0
  321. data/lib/chef/run_list/run_list_expansion.rb +172 -0
  322. data/lib/chef/run_list/run_list_item.rb +78 -0
  323. data/lib/chef/run_list.rb +150 -0
  324. data/lib/chef/run_status.rb +121 -0
  325. data/lib/chef/runner.rb +107 -0
  326. data/lib/chef/sandbox.rb +153 -0
  327. data/lib/chef/search/query.rb +60 -0
  328. data/lib/chef/shef/ext.rb +568 -0
  329. data/lib/chef/shef/model_wrapper.rb +120 -0
  330. data/lib/chef/shef/shef_rest.rb +28 -0
  331. data/lib/chef/shef/shef_session.rb +271 -0
  332. data/lib/chef/shef.rb +325 -0
  333. data/lib/chef/shell_out.rb +413 -0
  334. data/lib/chef/streaming_cookbook_uploader.rb +201 -0
  335. data/lib/chef/tasks/chef_repo.rake +256 -0
  336. data/lib/chef/util/file_edit.rb +122 -0
  337. data/lib/chef/util/windows/net_group.rb +101 -0
  338. data/lib/chef/util/windows/net_use.rb +121 -0
  339. data/lib/chef/util/windows/net_user.rb +198 -0
  340. data/lib/chef/util/windows/volume.rb +59 -0
  341. data/lib/chef/util/windows.rb +56 -0
  342. data/lib/chef/version.rb +21 -0
  343. data/lib/chef/webui_user.rb +231 -0
  344. data/lib/chef.rb +39 -0
  345. metadata +533 -0
@@ -0,0 +1,413 @@
1
+ #--
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Copyright:: Copyright (c) 2010 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'etc'
20
+ require 'tmpdir'
21
+ require 'chef/log'
22
+ require 'fcntl'
23
+ require 'chef/exceptions'
24
+
25
+ class Chef
26
+
27
+ # == Chef::ShellOut
28
+ # Provides a simplified interface to shelling out yet still collecting both
29
+ # standard out and standard error and providing full control over environment,
30
+ # working directory, uid, gid, etc.
31
+ #
32
+ # No means for passing input to the subprocess is provided, nor is there any
33
+ # way to inspect the output of the command as it is being read. If you need
34
+ # to do that, you have to use popen4 (in Chef::Mixin::Command)
35
+ #
36
+ # === Platform Support
37
+ # Chef::ShellOut uses Kernel.fork() and is therefore unsuitable for Windows
38
+ # or jruby.
39
+ class ShellOut
40
+ READ_WAIT_TIME = 0.01
41
+ READ_SIZE = 4096
42
+ DEFAULT_READ_TIMEOUT = 60
43
+ DEFAULT_ENVIRONMENT = {'LC_ALL' => 'C'}
44
+
45
+ attr_accessor :user, :group, :cwd, :valid_exit_codes
46
+ attr_reader :command, :umask, :environment
47
+ attr_writer :timeout
48
+ attr_reader :execution_time
49
+
50
+ attr_reader :stdout, :stderr, :status
51
+
52
+ attr_reader :stdin_pipe, :stdout_pipe, :stderr_pipe, :process_status_pipe
53
+
54
+ # === Arguments:
55
+ # Takes a single command, or a list of command fragments. These are used
56
+ # as arguments to Kernel.exec. See the Kernel.exec documentation for more
57
+ # explanation of how arguments are evaluated. The last argument can be an
58
+ # options Hash.
59
+ # === Options:
60
+ # If the last argument is a Hash, it is removed from the list of args passed
61
+ # to exec and used as an options hash. The following options are available:
62
+ # * +user+: the user the commmand should run as. if an integer is given, it is
63
+ # used as a uid. A string is treated as a username and resolved to a uid
64
+ # with Etc.getpwnam
65
+ # * +group+: the group the command should run as. works similarly to +user+
66
+ # * +cwd+: the directory to chdir to before running the command
67
+ # * +umask+: a umask to set before running the command. If given as an Integer,
68
+ # be sure to use two leading zeros so it's parsed as Octal. A string will
69
+ # be treated as an octal integer
70
+ # * +returns+: one or more Integer values to use as valid exit codes for the
71
+ # subprocess. This only has an effect if you call +error!+ after
72
+ # +run_command+.
73
+ # * +environment+: a Hash of environment variables to set before the command
74
+ # is run. By default, the environment will *always* be set to 'LC_ALL' => 'C'
75
+ # to prevent issues with multibyte characters in Ruby 1.8. To avoid this,
76
+ # use :environment => nil for *no* extra environment settings, or
77
+ # :environment => {'LC_ALL'=>nil, ...} to set other environment settings
78
+ # without changing the locale.
79
+ # * +timeout+: a Numeric value for the number of seconds to wait on the
80
+ # child process before raising an Exception. This is calculated as the
81
+ # total amount of time that ShellOut waited on the child process without
82
+ # receiving any output (i.e., IO.select returned nil). Default is 60
83
+ # seconds. Note: the stdlib Timeout library is not used.
84
+ # === Examples:
85
+ # Invoke find(1) to search for .rb files:
86
+ # find = Chef::ShellOut.new("find . -name '*.rb'")
87
+ # find.run_command
88
+ # # If all went well, the results are on +stdout+
89
+ # puts find.stdout
90
+ # # find(1) prints diagnostic info to STDERR:
91
+ # puts "error messages" + find.stderr
92
+ # # Raise an exception if it didn't exit with 0
93
+ # find.error!
94
+ # Run a command as the +www+ user with no extra ENV settings from +/tmp+
95
+ # cmd = Chef::ShellOut.new("apachectl", "start", :user => 'www', :env => nil, :cwd => '/tmp')
96
+ # cmd.run_command # etc.
97
+ def initialize(*command_args)
98
+ @stdout, @stderr = '', ''
99
+ @environment = DEFAULT_ENVIRONMENT
100
+ @cwd = Dir.tmpdir
101
+ @valid_exit_codes = [0]
102
+
103
+ if command_args.last.is_a?(Hash)
104
+ parse_options(command_args.pop)
105
+ end
106
+
107
+ @command = command_args.size == 1 ? command_args.first : command_args
108
+ end
109
+
110
+ def umask=(new_umask)
111
+ @umask = (new_umask.respond_to?(:oct) ? new_umask.oct : new_umask.to_i) & 007777
112
+ end
113
+
114
+ def uid
115
+ return nil unless user
116
+ user.kind_of?(Integer) ? user : Etc.getpwnam(user.to_s).uid
117
+ end
118
+
119
+ def gid
120
+ return nil unless group
121
+ group.kind_of?(Integer) ? group : Etc.getgrnam(group.to_s).gid
122
+ end
123
+
124
+ def timeout
125
+ @timeout || DEFAULT_READ_TIMEOUT
126
+ end
127
+
128
+ # Creates a String showing the output of the command, including a banner
129
+ # showing the exact command executed. Used by +invalid!+ to show command
130
+ # results when the command exited with an unexpected status.
131
+ def format_for_exception
132
+ msg = ""
133
+ msg << "---- Begin output of #{command} ----\n"
134
+ msg << "STDOUT: #{stdout.strip}\n"
135
+ msg << "STDERR: #{stderr.strip}\n"
136
+ msg << "---- End output of #{command} ----\n"
137
+ msg << "Ran #{command} returned #{status.exitstatus}" if status
138
+ msg
139
+ end
140
+
141
+ def exitstatus
142
+ @status && @status.exitstatus
143
+ end
144
+
145
+ # Run the command, writing the command's standard out and standard error
146
+ # to +stdout+ and +stderr+, and saving its exit status object to +status+
147
+ # === Returns
148
+ # returns +self+; +stdout+, +stderr+, +status+, and +exitstatus+ will be
149
+ # populated with results of the command
150
+ # === Raises
151
+ # * Errno::EACCES when you are not privileged to execute the command
152
+ # * Errno::ENOENT when the command is not available on the system (or not
153
+ # in the current $PATH)
154
+ # * Chef::Exceptions::CommandTimeout when the command does not complete
155
+ # within +timeout+ seconds (default: 60s)
156
+ def run_command
157
+ Chef::Log.debug("sh(#{@command})")
158
+ @child_pid = fork_subprocess
159
+
160
+ configure_parent_process_file_descriptors
161
+ propagate_pre_exec_failure
162
+
163
+ @result = nil
164
+ @execution_time = 0
165
+
166
+ # Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
167
+ # when calling IO.select and IO#read. Some OS Vendors are not interested
168
+ # in updating their ruby packages (Apple, *cough*) and we *have to*
169
+ # make it work. So I give you this epic hack:
170
+ GC.disable
171
+ until @status
172
+ ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
173
+ unless ready
174
+ @execution_time += READ_WAIT_TIME
175
+ if @execution_time >= timeout && !@result
176
+ raise Chef::Exceptions::CommandTimeout, "command timed out:\n#{format_for_exception}"
177
+ end
178
+ end
179
+
180
+ if ready && ready.first.include?(child_stdout)
181
+ read_stdout_to_buffer
182
+ end
183
+ if ready && ready.first.include?(child_stderr)
184
+ read_stderr_to_buffer
185
+ end
186
+
187
+ unless @status
188
+ # make one more pass to get the last of the output after the
189
+ # child process dies
190
+ if results = Process.waitpid2(@child_pid, Process::WNOHANG)
191
+ @status = results.last
192
+ redo
193
+ end
194
+ end
195
+ end
196
+ self
197
+ rescue Exception
198
+ # do our best to kill zombies
199
+ Process.waitpid2(@child_pid, Process::WNOHANG) rescue nil
200
+ raise
201
+ ensure
202
+ # no matter what happens, turn the GC back on, and hope whatever busted
203
+ # version of ruby we're on doesn't allocate some objects during the next
204
+ # GC run.
205
+ GC.enable
206
+ close_all_pipes
207
+ end
208
+
209
+ # Checks the +exitstatus+ against the set of +valid_exit_codes+. If
210
+ # +exitstatus+ is not in the list of +valid_exit_codes+, calls +invalid!+,
211
+ # which raises an Exception.
212
+ # === Returns
213
+ # nil::: always returns nil when it does not raise
214
+ # === Raises
215
+ # Chef::Exceptions::ShellCommandFailed::: via +invalid!+
216
+ def error!
217
+ unless Array(valid_exit_codes).include?(exitstatus)
218
+ invalid!("Expected process to exit 0, but it exited with #{exitstatus}")
219
+ end
220
+ end
221
+
222
+ # Raises a Chef::Exceptions::ShellCommandFailed exception, appending the
223
+ # command's stdout, stderr, and exitstatus to the exception message.
224
+ # === Arguments
225
+ # +msg+: A String to use as the basis of the exception message. The
226
+ # default explanation is very generic, providing a more informative message
227
+ # is highly encouraged.
228
+ # === Raises
229
+ # Chef::Exceptions::ShellCommandFailed always
230
+ def invalid!(msg=nil)
231
+ msg ||= "Command produced unexpected results"
232
+ raise Chef::Exceptions::ShellCommandFailed, msg + "\n" + format_for_exception
233
+ end
234
+
235
+ def inspect
236
+ "<#{self.class.name}##{object_id}: command: '#@command' process_status: #{@status.inspect} " +
237
+ "stdout: '#{stdout.strip}' stderr: '#{stderr.strip}' child_pid: #{@child_pid.inspect} " +
238
+ "environment: #{@environment.inspect} timeout: #{timeout} user: #@user group: #@group working_dir: #@cwd >"
239
+ end
240
+
241
+ private
242
+
243
+ def parse_options(opts)
244
+ opts.each do |option, setting|
245
+ case option.to_s
246
+ when 'cwd'
247
+ self.cwd = setting
248
+ when 'user'
249
+ self.user = setting
250
+ when 'group'
251
+ self.group = setting
252
+ when 'umask'
253
+ self.umask = setting
254
+ when 'timeout'
255
+ self.timeout = setting
256
+ when 'returns'
257
+ self.valid_exit_codes = Array(setting)
258
+ when 'environment', 'env'
259
+ # passing :environment => nil means don't set any new ENV vars
260
+ setting.nil? ? @environment = {} : @environment.merge!(setting)
261
+ else
262
+ raise Chef::Exceptions::InvalidCommandOption, "option '#{option.inspect}' is not a valid option for #{self.class.name}"
263
+ end
264
+ end
265
+ end
266
+
267
+ def set_user
268
+ if user
269
+ Process.euid = uid
270
+ Process.uid = uid
271
+ end
272
+ end
273
+
274
+ def set_group
275
+ if group
276
+ Process.egid = gid
277
+ Process.gid = gid
278
+ end
279
+ end
280
+
281
+ def set_environment
282
+ environment.each do |env_var,value|
283
+ ENV[env_var] = value
284
+ end
285
+ end
286
+
287
+ def set_umask
288
+ File.umask(umask) if umask
289
+ end
290
+
291
+ def initialize_ipc
292
+ @stdout_pipe, @stderr_pipe, @process_status_pipe = IO.pipe, IO.pipe, IO.pipe
293
+ @process_status_pipe.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
294
+ end
295
+
296
+ def child_stdout
297
+ @stdout_pipe[0]
298
+ end
299
+
300
+ def child_stderr
301
+ @stderr_pipe[0]
302
+ end
303
+
304
+ def child_process_status
305
+ @process_status_pipe[0]
306
+ end
307
+
308
+ def close_all_pipes
309
+ child_stdout.close unless child_stdout.closed?
310
+ child_stderr.close unless child_stderr.closed?
311
+ child_process_status.close unless child_process_status.closed?
312
+ end
313
+
314
+ # replace stdout, and stderr with pipes to the parent, and close the
315
+ # reader side of the error marshaling side channel. Close STDIN so when we
316
+ # exec, the new program will know it's never getting input ever.
317
+ def configure_subprocess_file_descriptors
318
+ process_status_pipe.first.close
319
+
320
+ # HACK: for some reason, just STDIN.close isn't good enough when running
321
+ # under ruby 1.9.2, so make it good enough:
322
+ stdin_reader, stdin_writer = IO.pipe
323
+ stdin_writer.close
324
+ STDIN.reopen stdin_reader
325
+ stdin_reader.close
326
+
327
+ stdout_pipe.first.close
328
+ STDOUT.reopen stdout_pipe.last
329
+ stdout_pipe.last.close
330
+
331
+ stderr_pipe.first.close
332
+ STDERR.reopen stderr_pipe.last
333
+ stderr_pipe.last.close
334
+
335
+ STDOUT.sync = STDERR.sync = true
336
+ end
337
+
338
+ def configure_parent_process_file_descriptors
339
+ # Close the sides of the pipes we don't care about
340
+ stdout_pipe.last.close
341
+ stderr_pipe.last.close
342
+ process_status_pipe.last.close
343
+ # Get output as it happens rather than buffered
344
+ child_stdout.sync = true
345
+ child_stderr.sync = true
346
+
347
+ true
348
+ end
349
+
350
+ # Some patch levels of ruby in wide use (in particular the ruby 1.8.6 on OSX)
351
+ # segfault when you IO.select a pipe that's reached eof. Weak sauce.
352
+ def open_pipes
353
+ @open_pipes ||= [child_stdout, child_stderr]
354
+ end
355
+
356
+ def read_stdout_to_buffer
357
+ while chunk = child_stdout.read_nonblock(READ_SIZE)
358
+ @stdout << chunk
359
+ end
360
+ rescue Errno::EAGAIN
361
+ rescue EOFError
362
+ open_pipes.delete_at(0)
363
+ end
364
+
365
+ def read_stderr_to_buffer
366
+ while chunk = child_stderr.read_nonblock(READ_SIZE)
367
+ @stderr << chunk
368
+ end
369
+ rescue Errno::EAGAIN
370
+ rescue EOFError
371
+ open_pipes.delete_at(1)
372
+ end
373
+
374
+ def fork_subprocess
375
+ initialize_ipc
376
+
377
+ fork do
378
+ configure_subprocess_file_descriptors
379
+
380
+ set_user
381
+ set_group
382
+ set_environment
383
+ set_umask
384
+
385
+ begin
386
+ command.kind_of?(Array) ? exec(*command) : exec(command)
387
+
388
+ raise 'forty-two' # Should never get here
389
+ rescue Exception => e
390
+ Marshal.dump(e, process_status_pipe.last)
391
+ process_status_pipe.last.flush
392
+ end
393
+ process_status_pipe.last.close unless (process_status_pipe.last.closed?)
394
+ exit!
395
+ end
396
+ end
397
+
398
+ # Attempt to get a Marshaled error from the side-channel.
399
+ # If it's there, un-marshal it and raise. If it's not there,
400
+ # assume everything went well.
401
+ def propagate_pre_exec_failure
402
+ begin
403
+ e = Marshal.load child_process_status
404
+ raise(Exception === e ? e : "unknown failure: #{e.inspect}")
405
+ rescue EOFError # If we get an EOF error, then the exec was successful
406
+ true
407
+ ensure
408
+ child_process_status.close
409
+ end
410
+ end
411
+
412
+ end
413
+ end
@@ -0,0 +1,201 @@
1
+ # inspired by/cargo-culted from http://stanislavvitvitskiy.blogspot.com/2008/12/multipart-post-in-ruby.html
2
+ # On Apr 6, 2010, at 3:00 PM, Stanislav Vitvitskiy wrote:
3
+ #
4
+ # It's free to use / modify / distribute. No need to mention anything. Just copy/paste and use.
5
+ #
6
+ # Regards,
7
+ # Stan
8
+
9
+ require 'net/http'
10
+ require 'mixlib/authentication/signedheaderauth'
11
+ require 'openssl'
12
+ require 'chef/version'
13
+
14
+ class Chef
15
+ class StreamingCookbookUploader
16
+
17
+ DefaultHeaders = { 'accept' => 'application/json', 'x-chef-version' => ::Chef::VERSION }
18
+
19
+ class << self
20
+
21
+ def post(to_url, user_id, secret_key_filename, params = {}, headers = {})
22
+ make_request(:post, to_url, user_id, secret_key_filename, params, headers)
23
+ end
24
+
25
+ def put(to_url, user_id, secret_key_filename, params = {}, headers = {})
26
+ make_request(:put, to_url, user_id, secret_key_filename, params, headers)
27
+ end
28
+
29
+ def make_request(http_verb, to_url, user_id, secret_key_filename, params = {}, headers = {})
30
+ boundary = '----RubyMultipartClient' + rand(1000000).to_s + 'ZZZZZ'
31
+ parts = []
32
+ content_file = nil
33
+
34
+ timestamp = Time.now.utc.iso8601
35
+ secret_key = OpenSSL::PKey::RSA.new(File.read(secret_key_filename))
36
+
37
+ unless params.nil? || params.empty?
38
+ params.each do |key, value|
39
+ if value.kind_of?(File)
40
+ content_file = value
41
+ filepath = value.path
42
+ filename = File.basename(filepath)
43
+ parts << StringPart.new( "--" + boundary + "\r\n" +
44
+ "Content-Disposition: form-data; name=\"" + key.to_s + "\"; filename=\"" + filename + "\"\r\n" +
45
+ "Content-Type: application/octet-stream\r\n\r\n")
46
+ parts << StreamPart.new(value, File.size(filepath))
47
+ parts << StringPart.new("\r\n")
48
+ else
49
+ parts << StringPart.new( "--" + boundary + "\r\n" +
50
+ "Content-Disposition: form-data; name=\"" + key.to_s + "\"\r\n\r\n")
51
+ parts << StringPart.new(value.to_s + "\r\n")
52
+ end
53
+ end
54
+ parts << StringPart.new("--" + boundary + "--\r\n")
55
+ end
56
+
57
+ body_stream = MultipartStream.new(parts)
58
+
59
+ timestamp = Time.now.utc.iso8601
60
+
61
+ url = URI.parse(to_url)
62
+
63
+ Chef::Log.logger.debug("Signing: method: #{http_verb}, path: #{url.path}, file: #{content_file}, User-id: #{user_id}, Timestamp: #{timestamp}")
64
+
65
+ # We use the body for signing the request if the file parameter
66
+ # wasn't a valid file or wasn't included. Extract the body (with
67
+ # multi-part delimiters intact) to sign the request.
68
+ # TODO: tim: 2009-12-28: It'd be nice to remove this special case, and
69
+ # always hash the entire request body. In the file case it would just be
70
+ # expanded multipart text - the entire body of the POST.
71
+ content_body = parts.inject("") { |result,part| result + part.read(0, part.size) }
72
+ content_file.rewind if content_file # we consumed the file for the above operation, so rewind it.
73
+
74
+ signing_options = {
75
+ :http_method=>http_verb,
76
+ :path=>url.path,
77
+ :user_id=>user_id,
78
+ :timestamp=>timestamp}
79
+ (content_file && signing_options[:file] = content_file) || (signing_options[:body] = (content_body || ""))
80
+
81
+ headers.merge!(Mixlib::Authentication::SignedHeaderAuth.signing_object(signing_options).sign(secret_key))
82
+
83
+ content_file.rewind if content_file
84
+
85
+ # net/http doesn't like symbols for header keys, so we'll to_s each one just in case
86
+ headers = DefaultHeaders.merge(Hash[*headers.map{ |k,v| [k.to_s, v] }.flatten])
87
+
88
+ req = case http_verb
89
+ when :put
90
+ Net::HTTP::Put.new(url.path, headers)
91
+ when :post
92
+ Net::HTTP::Post.new(url.path, headers)
93
+ end
94
+ req.content_length = body_stream.size
95
+ req.content_type = 'multipart/form-data; boundary=' + boundary unless parts.empty?
96
+ req.body_stream = body_stream
97
+
98
+ http = Net::HTTP.new(url.host, url.port)
99
+ if url.scheme == "https"
100
+ http.use_ssl = true
101
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
102
+ end
103
+ res = http.request(req)
104
+ #res = http.start {|http_proc| http_proc.request(req) }
105
+
106
+ # alias status to code and to_s to body for test purposes
107
+ # TODO: stop the following madness!
108
+ class << res
109
+ alias :to_s :body
110
+
111
+ # BUGBUG this makes the response compatible with what respsonse_steps expects to test headers (response.headers[] -> response[])
112
+ def headers
113
+ self
114
+ end
115
+
116
+ def status
117
+ code.to_i
118
+ end
119
+ end
120
+ res
121
+ end
122
+
123
+ end
124
+
125
+ class StreamPart
126
+ def initialize(stream, size)
127
+ @stream, @size = stream, size
128
+ end
129
+
130
+ def size
131
+ @size
132
+ end
133
+
134
+ # read the specified amount from the stream
135
+ def read(offset, how_much)
136
+ @stream.read(how_much)
137
+ end
138
+ end
139
+
140
+ class StringPart
141
+ def initialize(str)
142
+ @str = str
143
+ end
144
+
145
+ def size
146
+ @str.length
147
+ end
148
+
149
+ # read the specified amount from the string startiung at the offset
150
+ def read(offset, how_much)
151
+ @str[offset, how_much]
152
+ end
153
+ end
154
+
155
+ class MultipartStream
156
+ def initialize(parts)
157
+ @parts = parts
158
+ @part_no = 0
159
+ @part_offset = 0
160
+ end
161
+
162
+ def size
163
+ @parts.inject(0) {|size, part| size + part.size}
164
+ end
165
+
166
+ def read(how_much)
167
+ return nil if @part_no >= @parts.size
168
+
169
+ how_much_current_part = @parts[@part_no].size - @part_offset
170
+
171
+ how_much_current_part = if how_much_current_part > how_much
172
+ how_much
173
+ else
174
+ how_much_current_part
175
+ end
176
+
177
+ how_much_next_part = how_much - how_much_current_part
178
+
179
+ current_part = @parts[@part_no].read(@part_offset, how_much_current_part)
180
+
181
+ # recurse into the next part if the current one was not large enough
182
+ if how_much_next_part > 0
183
+ @part_no += 1
184
+ @part_offset = 0
185
+ next_part = read(how_much_next_part)
186
+ current_part + if next_part
187
+ next_part
188
+ else
189
+ ''
190
+ end
191
+ else
192
+ @part_offset += how_much_current_part
193
+ current_part
194
+ end
195
+ end
196
+ end
197
+
198
+ end
199
+
200
+
201
+ end