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,64 @@
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 'chef/resource/apt_package'
20
+ require 'chef/resource/bash'
21
+ require 'chef/resource/breakpoint'
22
+ require 'chef/resource/cookbook_file'
23
+ require 'chef/resource/cron'
24
+ require 'chef/resource/csh'
25
+ require 'chef/resource/deploy'
26
+ require 'chef/resource/deploy_revision'
27
+ require 'chef/resource/directory'
28
+ require 'chef/resource/dpkg_package'
29
+ require 'chef/resource/easy_install_package'
30
+ require 'chef/resource/env'
31
+ require 'chef/resource/erl_call'
32
+ require 'chef/resource/execute'
33
+ require 'chef/resource/file'
34
+ require 'chef/resource/freebsd_package'
35
+ require 'chef/resource/gem_package'
36
+ require 'chef/resource/git'
37
+ require 'chef/resource/group'
38
+ require 'chef/resource/http_request'
39
+ require 'chef/resource/ifconfig'
40
+ require 'chef/resource/link'
41
+ require 'chef/resource/log'
42
+ require 'chef/resource/macports_package'
43
+ require 'chef/resource/mdadm'
44
+ require 'chef/resource/mount'
45
+ require 'chef/resource/ohai'
46
+ require 'chef/resource/package'
47
+ require 'chef/resource/pacman_package'
48
+ require 'chef/resource/perl'
49
+ require 'chef/resource/portage_package'
50
+ require 'chef/resource/python'
51
+ require 'chef/resource/remote_directory'
52
+ require 'chef/resource/remote_file'
53
+ require 'chef/resource/rpm_package'
54
+ require 'chef/resource/route'
55
+ require 'chef/resource/ruby'
56
+ require 'chef/resource/ruby_block'
57
+ require 'chef/resource/scm'
58
+ require 'chef/resource/script'
59
+ require 'chef/resource/service'
60
+ require 'chef/resource/subversion'
61
+ require 'chef/resource/template'
62
+ require 'chef/resource/timestamped_deploy'
63
+ require 'chef/resource/user'
64
+ require 'chef/resource/yum_package'
@@ -0,0 +1,78 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Thom May (<thom@clearairturbulence.org>)
4
+ # Author:: Nuo Yan (<nuo@opscode.com>)
5
+ # Author:: Christopher Brown (<cb@opscode.com>)
6
+ # Author:: Christopher Walters (<cw@opscode.com>)
7
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
8
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
9
+ # License:: Apache License, Version 2.0
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing, software
18
+ # distributed under the License is distributed on an "AS IS" BASIS,
19
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ # See the License for the specific language governing permissions and
21
+ # limitations under the License.
22
+ #
23
+ require 'chef/exceptions'
24
+ require 'mixlib/authentication/signedheaderauth'
25
+
26
+ class Chef
27
+ class REST
28
+ class AuthCredentials
29
+ attr_reader :key_file, :client_name, :key, :raw_key
30
+
31
+ def initialize(client_name=nil, key_file=nil)
32
+ @client_name, @key_file = client_name, key_file
33
+ load_signing_key if sign_requests?
34
+ end
35
+
36
+ def sign_requests?
37
+ !!key_file
38
+ end
39
+
40
+ def signature_headers(request_params={})
41
+ raise ArgumentError, "Cannot sign the request without a client name, check that :node_name is assigned" if client_name.nil?
42
+ Chef::Log.debug("Signing the request as #{client_name}")
43
+
44
+ # params_in = {:http_method => :GET, :path => "/clients", :body => "", :host => "localhost"}
45
+ request_params = request_params.dup
46
+ request_params[:timestamp] = Time.now.utc.iso8601
47
+ request_params[:user_id] = client_name
48
+ host = request_params.delete(:host) || "localhost"
49
+
50
+ sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(request_params)
51
+ signed = sign_obj.sign(key).merge({:host => host})
52
+ signed.inject({}){|memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1];memo}
53
+ end
54
+
55
+ private
56
+
57
+ def load_signing_key
58
+ begin
59
+ @raw_key = IO.read(key_file).strip
60
+ rescue SystemCallError, IOError => e
61
+ Chef::Log.fatal "Failed to read the private key #{key_file}: #{e.inspect}, #{e.backtrace}"
62
+ raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key_file}, which you told me to use to sign requests!"
63
+ end
64
+ assert_valid_key_format!(@raw_key)
65
+ @key = OpenSSL::PKey::RSA.new(@raw_key)
66
+ end
67
+
68
+ def assert_valid_key_format!(raw_key)
69
+ unless (raw_key =~ /\A-----BEGIN RSA PRIVATE KEY-----$/) && (raw_key =~ /^-----END RSA PRIVATE KEY-----\Z/)
70
+ msg = "The file #{key_file} does not contain a correctly formatted private key.\n"
71
+ msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'"
72
+ raise Chef::Exceptions::InvalidPrivateKey, msg
73
+ end
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,31 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Thom May (<thom@clearairturbulence.org>)
4
+ # Author:: Nuo Yan (<nuo@opscode.com>)
5
+ # Author:: Christopher Brown (<cb@opscode.com>)
6
+ # Author:: Christopher Walters (<cw@opscode.com>)
7
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
8
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
9
+ # License:: Apache License, Version 2.0
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing, software
18
+ # distributed under the License is distributed on an "AS IS" BASIS,
19
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ # See the License for the specific language governing permissions and
21
+ # limitations under the License.
22
+ #
23
+ require 'singleton'
24
+
25
+ class Chef
26
+ class REST
27
+ class CookieJar < Hash
28
+ include Singleton
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,188 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Thom May (<thom@clearairturbulence.org>)
4
+ # Author:: Nuo Yan (<nuo@opscode.com>)
5
+ # Author:: Christopher Brown (<cb@opscode.com>)
6
+ # Author:: Christopher Walters (<cw@opscode.com>)
7
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
8
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
9
+ # License:: Apache License, Version 2.0
10
+ #
11
+ # Licensed under the Apache License, Version 2.0 (the "License");
12
+ # you may not use this file except in compliance with the License.
13
+ # You may obtain a copy of the License at
14
+ #
15
+ # http://www.apache.org/licenses/LICENSE-2.0
16
+ #
17
+ # Unless required by applicable law or agreed to in writing, software
18
+ # distributed under the License is distributed on an "AS IS" BASIS,
19
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ # See the License for the specific language governing permissions and
21
+ # limitations under the License.
22
+ #
23
+ require 'uri'
24
+ require 'net/http'
25
+ require 'chef/rest/cookie_jar'
26
+ require 'chef/version'
27
+
28
+ class Chef
29
+ class REST
30
+ class RESTRequest
31
+ attr_reader :method, :url, :headers, :http_client, :http_request
32
+
33
+ def initialize(method, url, req_body, base_headers={})
34
+ @method, @url = method, url
35
+ @request_body = nil
36
+ @cookies = CookieJar.instance
37
+ configure_http_client
38
+ build_headers(base_headers)
39
+ configure_http_request(req_body)
40
+ end
41
+
42
+ def host
43
+ @url.host
44
+ end
45
+
46
+ def port
47
+ @url.port
48
+ end
49
+
50
+ def query
51
+ @url.query
52
+ end
53
+
54
+ def path
55
+ @url.path.empty? ? "/" : @url.path
56
+ end
57
+
58
+ def call
59
+ hide_net_http_bug do
60
+ http_client.request(http_request) do |response|
61
+ store_cookie(response)
62
+ yield response if block_given?
63
+ response
64
+ end
65
+ end
66
+ end
67
+
68
+ def config
69
+ Chef::Config
70
+ end
71
+
72
+ private
73
+
74
+ def hide_net_http_bug
75
+ yield
76
+ rescue NoMethodError => e
77
+ # http://redmine.ruby-lang.org/issues/show/2708
78
+ # http://redmine.ruby-lang.org/issues/show/2758
79
+ if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/
80
+ Chef::Log.debug("rescued error in http connect, re-raising as Errno::ECONNREFUSED to hide bug in net/http")
81
+ Chef::Log.debug("#{e.class.name}: #{e.to_s}")
82
+ Chef::Log.debug(e.backtrace.join("\n"))
83
+ raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{url.scheme}://#{host}:#{port}"
84
+ else
85
+ raise
86
+ end
87
+ end
88
+
89
+ def store_cookie(response)
90
+ if response['set-cookie']
91
+ @cookies["#{host}:#{port}"] = response['set-cookie']
92
+ end
93
+ end
94
+
95
+ def build_headers(headers)
96
+ @headers = headers.dup
97
+ # TODO: need to set accept somewhere else
98
+ # headers.merge!('Accept' => "application/json") unless raw
99
+ @headers['X-Chef-Version'] = ::Chef::VERSION
100
+
101
+ if @cookies.has_key?("#{host}:#{port}")
102
+ @headers['Cookie'] = @cookies["#{host}:#{port}"]
103
+ end
104
+ end
105
+
106
+ #adapted from buildr/lib/buildr/core/transports.rb
107
+ def proxy_uri
108
+ proxy = Chef::Config["#{url.scheme}_proxy"]
109
+ proxy = URI.parse(proxy) if String === proxy
110
+ excludes = Chef::Config[:no_proxy].to_s.split(/\s*,\s*/).compact
111
+ excludes = excludes.map { |exclude| exclude =~ /:\d+$/ ? exclude : "#{exclude}:*" }
112
+ return proxy unless excludes.any? { |exclude| File.fnmatch(exclude, "#{host}:#{port}") }
113
+ end
114
+
115
+ def configure_http_client
116
+ http_proxy = proxy_uri
117
+ if http_proxy.nil?
118
+ @http_client = Net::HTTP.new(host, port)
119
+ else
120
+ Chef::Log.debug("using #{http_proxy.host}:#{http_proxy.port} for proxy")
121
+ user = Chef::Config["#{url.scheme}_proxy_user"]
122
+ pass = Chef::Config["#{url.scheme}_proxy_pass"]
123
+ @http_client = Net::HTTP.Proxy(http_proxy.host, http_proxy.port, user, pass).new(host, port)
124
+ end
125
+ if url.scheme == "https"
126
+ @http_client.use_ssl = true
127
+ if config[:ssl_verify_mode] == :verify_none
128
+ @http_client.verify_mode = OpenSSL::SSL::VERIFY_NONE
129
+ elsif config[:ssl_verify_mode] == :verify_peer
130
+ @http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
131
+ end
132
+ if config[:ssl_ca_path]
133
+ unless ::File.exist?(config[:ssl_ca_path])
134
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_path #{config[:ssl_ca_path]} does not exist"
135
+ end
136
+ @http_client.ca_path = config[:ssl_ca_path]
137
+ elsif config[:ssl_ca_file]
138
+ unless ::File.exist?(config[:ssl_ca_file])
139
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_ca_file #{config[:ssl_ca_file]} does not exist"
140
+ end
141
+ @http_client.ca_file = config[:ssl_ca_file]
142
+ end
143
+ if (config[:ssl_client_cert] || config[:ssl_client_key])
144
+ unless (config[:ssl_client_cert] && config[:ssl_client_key])
145
+ raise Chef::Exceptions::ConfigurationError, "You must configure ssl_client_cert and ssl_client_key together"
146
+ end
147
+ unless ::File.exists?(config[:ssl_client_cert])
148
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_cert #{config[:ssl_client_cert]} does not exist"
149
+ end
150
+ unless ::File.exists?(config[:ssl_client_key])
151
+ raise Chef::Exceptions::ConfigurationError, "The configured ssl_client_key #{config[:ssl_client_key]} does not exist"
152
+ end
153
+ @http_client.cert = OpenSSL::X509::Certificate.new(::File.read(config[:ssl_client_cert]))
154
+ @http_client.key = OpenSSL::PKey::RSA.new(::File.read(config[:ssl_client_key]))
155
+ end
156
+ end
157
+
158
+ @http_client.read_timeout = config[:rest_timeout]
159
+ end
160
+
161
+
162
+ def configure_http_request(request_body=nil)
163
+ req_path = "#{path}"
164
+ req_path << "?#{query}" if query
165
+
166
+ @http_request = case method.to_s.downcase
167
+ when "get"
168
+ Net::HTTP::Get.new(req_path, headers)
169
+ when "post"
170
+ Net::HTTP::Post.new(req_path, headers)
171
+ when "put"
172
+ Net::HTTP::Put.new(req_path, headers)
173
+ when "delete"
174
+ Net::HTTP::Delete.new(req_path, headers)
175
+ when "head"
176
+ Net::HTTP::Head.new(req_path, headers)
177
+ else
178
+ raise ArgumentError, "You must provide :GET, :PUT, :POST, :DELETE or :HEAD as the method"
179
+ end
180
+
181
+ @http_request.body = request_body if (request_body && @http_request.request_body_permitted?)
182
+ # Optionally handle HTTP Basic Authentication
183
+ @http_request.basic_auth(url.user, url.password) if url.user
184
+ end
185
+
186
+ end
187
+ end
188
+ end
data/lib/chef/rest.rb ADDED
@@ -0,0 +1,394 @@
1
+ #--
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Thom May (<thom@clearairturbulence.org>)
4
+ # Author:: Nuo Yan (<nuo@opscode.com>)
5
+ # Author:: Christopher Brown (<cb@opscode.com>)
6
+ # Author:: Christopher Walters (<cw@opscode.com>)
7
+ # Copyright:: Copyright (c) 2009, 2010 Opscode, Inc.
8
+ # License:: Apache License, Version 2.0
9
+ #
10
+ # Licensed under the Apache License, Version 2.0 (the "License");
11
+ # you may not use this file except in compliance with the License.
12
+ # You may obtain a copy of the License at
13
+ #
14
+ # http://www.apache.org/licenses/LICENSE-2.0
15
+ #
16
+ # Unless required by applicable law or agreed to in writing, software
17
+ # distributed under the License is distributed on an "AS IS" BASIS,
18
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
+ # See the License for the specific language governing permissions and
20
+ # limitations under the License.
21
+ #
22
+
23
+ require 'net/https'
24
+ require 'uri'
25
+ require 'json'
26
+ require 'tempfile'
27
+ require 'chef/api_client'
28
+ require 'chef/rest/auth_credentials'
29
+ require 'chef/rest/rest_request'
30
+ require 'chef/monkey_patches/string'
31
+
32
+ class Chef
33
+ # == Chef::REST
34
+ # Chef's custom REST client with built-in JSON support and RSA signed header
35
+ # authentication.
36
+ class REST
37
+ attr_reader :auth_credentials
38
+ attr_accessor :url, :cookies, :sign_on_redirect, :redirect_limit
39
+
40
+ # Create a REST client object. The supplied +url+ is used as the base for
41
+ # all subsequent requests. For example, when initialized with a base url
42
+ # http://localhost:4000, a call to +get_rest+ with 'nodes' will make an
43
+ # HTTP GET request to http://localhost:4000/nodes
44
+ def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={})
45
+ @url = url
46
+ @cookies = CookieJar.instance
47
+ @default_headers = options[:headers] || {}
48
+ @auth_credentials = AuthCredentials.new(client_name, signing_key_filename)
49
+ @sign_on_redirect, @sign_request = true, true
50
+ @redirects_followed = 0
51
+ @redirect_limit = 10
52
+ end
53
+
54
+ def signing_key_filename
55
+ @auth_credentials.key_file
56
+ end
57
+
58
+ def client_name
59
+ @auth_credentials.client_name
60
+ end
61
+
62
+ def signing_key
63
+ @auth_credentials.raw_key
64
+ end
65
+
66
+ # Register the client
67
+ def register(name=Chef::Config[:node_name], destination=Chef::Config[:client_key])
68
+ if (File.exists?(destination) && !File.writable?(destination))
69
+ raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination} - check permissions?"
70
+ end
71
+ nc = Chef::ApiClient.new
72
+ nc.name(name)
73
+
74
+ catch(:done) do
75
+ retries = config[:client_registration_retries] || 5
76
+ 0.upto(retries) do |n|
77
+ begin
78
+ response = nc.save(true, true)
79
+ Chef::Log.debug("Registration response: #{response.inspect}")
80
+ raise Chef::Exceptions::CannotWritePrivateKey, "The response from the server did not include a private key!" unless response.has_key?("private_key")
81
+ # Write out the private key
82
+ file = ::File.open(destination, File::WRONLY|File::EXCL|File::CREAT, 0600)
83
+ file.print(response["private_key"])
84
+ file.close
85
+ throw :done
86
+ rescue IOError
87
+ raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination}"
88
+ rescue Net::HTTPFatalError => e
89
+ Chef::Log.warn("Failed attempt #{n} of #{retries+1} on client creation")
90
+ raise unless e.response.code == "500"
91
+ end
92
+ end
93
+ end
94
+
95
+ true
96
+ end
97
+
98
+ # Send an HTTP GET request to the path
99
+ #
100
+ # Using this method to +fetch+ a file is considered deprecated.
101
+ #
102
+ # === Parameters
103
+ # path:: The path to GET
104
+ # raw:: Whether you want the raw body returned, or JSON inflated. Defaults
105
+ # to JSON inflated.
106
+ def get_rest(path, raw=false, headers={})
107
+ if raw
108
+ streaming_request(create_url(path), headers)
109
+ else
110
+ api_request(:GET, create_url(path), headers)
111
+ end
112
+ end
113
+
114
+ # Send an HTTP DELETE request to the path
115
+ def delete_rest(path, headers={})
116
+ api_request(:DELETE, create_url(path), headers)
117
+ end
118
+
119
+ # Send an HTTP POST request to the path
120
+ def post_rest(path, json, headers={})
121
+ api_request(:POST, create_url(path), headers, json)
122
+ end
123
+
124
+ # Send an HTTP PUT request to the path
125
+ def put_rest(path, json, headers={})
126
+ api_request(:PUT, create_url(path), headers, json)
127
+ end
128
+
129
+ # Streams a download to a tempfile, then yields the tempfile to a block.
130
+ # After the download, the tempfile will be closed and unlinked.
131
+ # If you rename the tempfile, it will not be deleted.
132
+ # Beware that if the server streams infinite content, this method will
133
+ # stream it until you run out of disk space.
134
+ def fetch(path, headers={})
135
+ streaming_request(create_url(path), headers) {|tmp_file| yield tmp_file }
136
+ end
137
+
138
+ def create_url(path)
139
+ if path =~ /^(http|https):\/\//
140
+ URI.parse(path)
141
+ else
142
+ URI.parse("#{@url}/#{path}")
143
+ end
144
+ end
145
+
146
+ def sign_requests?
147
+ auth_credentials.sign_requests? && @sign_request
148
+ end
149
+
150
+ # ==== DEPRECATED
151
+ # Use +api_request+ instead
152
+ #--
153
+ # Actually run an HTTP request. First argument is the HTTP method,
154
+ # which should be one of :GET, :PUT, :POST or :DELETE. Next is the
155
+ # URL, then an object to include in the body (which will be converted with
156
+ # .to_json). The limit argument is unused, it is present for backwards
157
+ # compatibility. Configure the redirect limit with #redirect_limit=
158
+ # instead.
159
+ #
160
+ # Typically, you won't use this method -- instead, you'll use one of
161
+ # the helper methods (get_rest, post_rest, etc.)
162
+ #
163
+ # Will return the body of the response on success.
164
+ def run_request(method, url, headers={}, data=false, limit=nil, raw=false)
165
+ json_body = data ? data.to_json : nil
166
+ headers = build_headers(method, url, headers, json_body, raw)
167
+
168
+ tf = nil
169
+
170
+ retriable_rest_request(method, url, json_body, headers) do |rest_request|
171
+
172
+ res = rest_request.call do |response|
173
+ if raw
174
+ tf = stream_to_tempfile(url, response)
175
+ else
176
+ response.read_body
177
+ end
178
+ end
179
+
180
+ if res.kind_of?(Net::HTTPSuccess)
181
+ if res['content-type'] =~ /json/
182
+ response_body = res.body.chomp
183
+ JSON.parse(response_body)
184
+ else
185
+ if method == :HEAD
186
+ true
187
+ elsif raw
188
+ tf
189
+ else
190
+ res.body
191
+ end
192
+ end
193
+ elsif res.kind_of?(Net::HTTPFound) or res.kind_of?(Net::HTTPMovedPermanently)
194
+ follow_redirect {run_request(:GET, create_url(res['location']), {}, false, nil, raw)}
195
+ elsif res.kind_of?(Net::HTTPNotModified)
196
+ false
197
+ else
198
+ if res['content-type'] =~ /json/
199
+ exception = JSON.parse(res.body)
200
+ msg = "HTTP Request Returned #{res.code} #{res.message}: "
201
+ msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
202
+ Chef::Log.warn(msg)
203
+ end
204
+ res.error!
205
+ end
206
+ end
207
+ end
208
+
209
+ # Runs an HTTP request to a JSON API. File Download not supported.
210
+ def api_request(method, url, headers={}, data=false)
211
+ json_body = data ? data.to_json : nil
212
+ headers = build_headers(method, url, headers, json_body)
213
+
214
+ retriable_rest_request(method, url, json_body, headers) do |rest_request|
215
+ response = rest_request.call {|r| r.read_body}
216
+
217
+ if response.kind_of?(Net::HTTPSuccess)
218
+ if response['content-type'] =~ /json/
219
+ JSON.parse(response.body.chomp)
220
+ else
221
+ Chef::Log.warn("Expected JSON response, but got content-type '#{response['content-type']}'")
222
+ response.body
223
+ end
224
+ elsif redirect_location = redirected_to(response)
225
+ follow_redirect {api_request(:GET, create_url(redirect_location))}
226
+ else
227
+ if response['content-type'] =~ /json/
228
+ exception = JSON.parse(response.body)
229
+ msg = "HTTP Request Returned #{response.code} #{response.message}: "
230
+ msg << (exception["error"].respond_to?(:join) ? exception["error"].join(", ") : exception["error"].to_s)
231
+ Chef::Log.warn(msg)
232
+ end
233
+ response.error!
234
+ end
235
+ end
236
+ end
237
+
238
+ # Makes a streaming download request. <b>Doesn't speak JSON.</b>
239
+ # Streams the response body to a tempfile. If a block is given, it's
240
+ # passed to Tempfile.open(), which means that the tempfile will automatically
241
+ # be unlinked after the block is executed.
242
+ #
243
+ # If no block is given, the tempfile is returned, which means it's up to
244
+ # you to unlink the tempfile when you're done with it.
245
+ def streaming_request(url, headers, &block)
246
+ headers = build_headers(:GET, url, headers, nil, true)
247
+ retriable_rest_request(:GET, url, nil, headers) do |rest_request|
248
+ tempfile = nil
249
+ response = rest_request.call do |r|
250
+ if block_given? && r.kind_of?(Net::HTTPSuccess)
251
+ begin
252
+ tempfile = stream_to_tempfile(url, r, &block)
253
+ yield tempfile
254
+ ensure
255
+ tempfile.close!
256
+ end
257
+ else
258
+ tempfile = stream_to_tempfile(url, r)
259
+ end
260
+ end
261
+ if response.kind_of?(Net::HTTPSuccess)
262
+ tempfile
263
+ elsif redirect_location = redirected_to(response)
264
+ # TODO: test tempfile unlinked when following redirects.
265
+ tempfile && tempfile.close!
266
+ follow_redirect {streaming_request(create_url(redirect_location), {}, &block)}
267
+ else
268
+ tempfile && tempfile.close!
269
+ response.error!
270
+ end
271
+ end
272
+ end
273
+
274
+ def retriable_rest_request(method, url, req_body, headers)
275
+ rest_request = Chef::REST::RESTRequest.new(method, url, req_body, headers)
276
+
277
+ Chef::Log.debug("Sending HTTP Request via #{method} to #{url.host}:#{url.port}#{rest_request.path}")
278
+
279
+ http_attempts = 0
280
+
281
+ begin
282
+ http_attempts += 1
283
+
284
+ res = yield rest_request
285
+
286
+ rescue Errno::ECONNREFUSED
287
+ if http_retry_count - http_attempts + 1 > 0
288
+ Chef::Log.error("Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
289
+ sleep(http_retry_delay)
290
+ retry
291
+ end
292
+ raise Errno::ECONNREFUSED, "Connection refused connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
293
+ rescue Timeout::Error
294
+ if http_retry_count - http_attempts + 1 > 0
295
+ Chef::Log.error("Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
296
+ sleep(http_retry_delay)
297
+ retry
298
+ end
299
+ raise Timeout::Error, "Timeout connecting to #{url.host}:#{url.port} for #{rest_request.path}, giving up"
300
+ rescue Net::HTTPServerException
301
+ if res.kind_of?(Net::HTTPForbidden)
302
+ if http_retry_count - http_attempts + 1 > 0
303
+ Chef::Log.error("Received 403 Forbidden against #{url.host}:#{url.port} for #{rest_request.path}, retry #{http_attempts}/#{http_retry_count}")
304
+ sleep(http_retry_delay)
305
+ retry
306
+ end
307
+ end
308
+ raise
309
+ end
310
+ end
311
+
312
+ def authentication_headers(method, url, json_body=nil)
313
+ request_params = {:http_method => method, :path => url.path, :body => json_body, :host => "#{url.host}:#{url.port}"}
314
+ request_params[:body] ||= ""
315
+ auth_credentials.signature_headers(request_params)
316
+ end
317
+
318
+ def http_retry_delay
319
+ config[:http_retry_delay]
320
+ end
321
+
322
+ def http_retry_count
323
+ config[:http_retry_count]
324
+ end
325
+
326
+ def config
327
+ Chef::Config
328
+ end
329
+
330
+ def follow_redirect
331
+ raise Chef::Exceptions::RedirectLimitExceeded if @redirects_followed >= redirect_limit
332
+ @redirects_followed += 1
333
+ Chef::Log.debug("Following redirect #{@redirects_followed}/#{redirect_limit}")
334
+ if @sign_on_redirect
335
+ yield
336
+ else
337
+ @sign_request = false
338
+ yield
339
+ end
340
+ ensure
341
+ @redirects_followed = 0
342
+ @sign_request = true
343
+ end
344
+
345
+ private
346
+
347
+ def redirected_to(response)
348
+ if response.kind_of?(Net::HTTPFound) || response.kind_of?(Net::HTTPMovedPermanently)
349
+ response['location']
350
+ else
351
+ nil
352
+ end
353
+ end
354
+
355
+ def build_headers(method, url, headers={}, json_body=false, raw=false)
356
+ headers = @default_headers.merge(headers)
357
+ headers['Accept'] = "application/json" unless raw
358
+ headers["Content-Type"] = 'application/json' if json_body
359
+ headers['Content-Length'] = json_body.bytesize.to_s if json_body
360
+ headers.merge!(authentication_headers(method, url, json_body)) if sign_requests?
361
+ headers
362
+ end
363
+
364
+ def stream_to_tempfile(url, response)
365
+ tf = Tempfile.open("chef-rest")
366
+ if RUBY_PLATFORM =~ /mswin|mingw32|windows/
367
+ tf.binmode #required for binary files on Windows platforms
368
+ end
369
+ Chef::Log.debug("Streaming download from #{url.to_s} to tempfile #{tf.path}")
370
+ # Stolen from http://www.ruby-forum.com/topic/166423
371
+ # Kudos to _why!
372
+ size, total = 0, response.header['Content-Length'].to_i
373
+ response.read_body do |chunk|
374
+ tf.write(chunk)
375
+ size += chunk.size
376
+ if Chef::Log.verbose
377
+ if size == 0
378
+ Chef::Log.debug("#{url.path} done (0 length file)")
379
+ elsif total == 0
380
+ Chef::Log.debug("#{url.path} (zero content length or no Content-Length header)")
381
+ else
382
+ Chef::Log.debug("#{url.path}" + " %d%% done (%d of %d)" % [(size * 100) / total, size, total])
383
+ end
384
+ end
385
+ end
386
+ tf.close
387
+ tf
388
+ rescue Exception
389
+ tf.close!
390
+ raise
391
+ end
392
+
393
+ end
394
+ end