mbailey-chef 0.9.12.1

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