tylerrick-chef 0.10.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (450) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +171 -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/arch/etc/conf.d/chef-client.conf +5 -0
  9. data/distro/arch/etc/conf.d/chef-expander.conf +8 -0
  10. data/distro/arch/etc/conf.d/chef-server-webui.conf +10 -0
  11. data/distro/arch/etc/conf.d/chef-server.conf +10 -0
  12. data/distro/arch/etc/conf.d/chef-solr.conf +8 -0
  13. data/distro/arch/etc/rc.d/chef-client +76 -0
  14. data/distro/arch/etc/rc.d/chef-expander +78 -0
  15. data/distro/arch/etc/rc.d/chef-server +78 -0
  16. data/distro/arch/etc/rc.d/chef-server-webui +78 -0
  17. data/distro/arch/etc/rc.d/chef-solr +78 -0
  18. data/distro/common/html/chef-client.8.html +146 -0
  19. data/distro/common/html/chef-expander.8.html +164 -0
  20. data/distro/common/html/chef-expanderctl.8.html +146 -0
  21. data/distro/common/html/chef-server-webui.8.html +185 -0
  22. data/distro/common/html/chef-server.8.html +182 -0
  23. data/distro/common/html/chef-solo.8.html +191 -0
  24. data/distro/common/html/chef-solr.8.html +165 -0
  25. data/distro/common/html/knife-bootstrap.1.html +243 -0
  26. data/distro/common/html/knife-client.1.html +219 -0
  27. data/distro/common/html/knife-configure.1.html +170 -0
  28. data/distro/common/html/knife-cookbook-site.1.html +241 -0
  29. data/distro/common/html/knife-cookbook.1.html +384 -0
  30. data/distro/common/html/knife-data-bag.1.html +234 -0
  31. data/distro/common/html/knife-environment.1.html +267 -0
  32. data/distro/common/html/knife-exec.1.html +134 -0
  33. data/distro/common/html/knife-index.1.html +125 -0
  34. data/distro/common/html/knife-node.1.html +250 -0
  35. data/distro/common/html/knife-recipe.1.html +92 -0
  36. data/distro/common/html/knife-role.1.html +200 -0
  37. data/distro/common/html/knife-search.1.html +288 -0
  38. data/distro/common/html/knife-ssh.1.html +157 -0
  39. data/distro/common/html/knife-status.1.html +128 -0
  40. data/distro/common/html/knife-tag.1.html +137 -0
  41. data/distro/common/html/knife.1.html +321 -0
  42. data/distro/common/html/shef.1.html +283 -0
  43. data/distro/common/man/man1/knife-bootstrap.1 +197 -0
  44. data/distro/common/man/man1/knife-client.1 +99 -0
  45. data/distro/common/man/man1/knife-configure.1 +88 -0
  46. data/distro/common/man/man1/knife-cookbook-site.1 +145 -0
  47. data/distro/common/man/man1/knife-cookbook.1 +345 -0
  48. data/distro/common/man/man1/knife-data-bag.1 +130 -0
  49. data/distro/common/man/man1/knife-environment.1 +178 -0
  50. data/distro/common/man/man1/knife-exec.1 +46 -0
  51. data/distro/common/man/man1/knife-index.1 +29 -0
  52. data/distro/common/man/man1/knife-node.1 +134 -0
  53. data/distro/common/man/man1/knife-role.1 +88 -0
  54. data/distro/common/man/man1/knife-search.1 +280 -0
  55. data/distro/common/man/man1/knife-ssh.1 +83 -0
  56. data/distro/common/man/man1/knife-status.1 +29 -0
  57. data/distro/common/man/man1/knife-tag.1 +43 -0
  58. data/distro/common/man/man1/knife.1 +292 -0
  59. data/distro/common/man/man1/shef.1 +256 -0
  60. data/distro/common/man/man8/chef-client.8 +104 -0
  61. data/distro/common/man/man8/chef-expander.8 +97 -0
  62. data/distro/common/man/man8/chef-expanderctl.8 +62 -0
  63. data/distro/common/man/man8/chef-server-webui.8 +155 -0
  64. data/distro/common/man/man8/chef-server.8 +147 -0
  65. data/distro/common/man/man8/chef-solo.8 +158 -0
  66. data/distro/common/man/man8/chef-solr.8 +122 -0
  67. data/distro/common/markdown/README +3 -0
  68. data/distro/common/markdown/man1/knife-bootstrap.mkd +142 -0
  69. data/distro/common/markdown/man1/knife-client.mkd +103 -0
  70. data/distro/common/markdown/man1/knife-configure.mkd +70 -0
  71. data/distro/common/markdown/man1/knife-cookbook-site.mkd +123 -0
  72. data/distro/common/markdown/man1/knife-cookbook.mkd +263 -0
  73. data/distro/common/markdown/man1/knife-data-bag.mkd +117 -0
  74. data/distro/common/markdown/man1/knife-environment.mkd +151 -0
  75. data/distro/common/markdown/man1/knife-exec.mkd +37 -0
  76. data/distro/common/markdown/man1/knife-index.mkd +30 -0
  77. data/distro/common/markdown/man1/knife-node.mkd +130 -0
  78. data/distro/common/markdown/man1/knife-role.mkd +85 -0
  79. data/distro/common/markdown/man1/knife-search.mkd +180 -0
  80. data/distro/common/markdown/man1/knife-ssh.mkd +72 -0
  81. data/distro/common/markdown/man1/knife-status.mkd +36 -0
  82. data/distro/common/markdown/man1/knife-tag.mkd +39 -0
  83. data/distro/common/markdown/man1/knife.mkd +220 -0
  84. data/distro/common/markdown/man1/shef.mkd +189 -0
  85. data/distro/common/markdown/man8/chef-client.mkd +75 -0
  86. data/distro/common/markdown/man8/chef-expander.mkd +82 -0
  87. data/distro/common/markdown/man8/chef-expanderctl.mkd +58 -0
  88. data/distro/common/markdown/man8/chef-server-webui.mkd +121 -0
  89. data/distro/common/markdown/man8/chef-server.mkd +121 -0
  90. data/distro/common/markdown/man8/chef-solo.mkd +107 -0
  91. data/distro/common/markdown/man8/chef-solr.mkd +89 -0
  92. data/distro/debian/etc/default/chef-client +4 -0
  93. data/distro/debian/etc/default/chef-expander +8 -0
  94. data/distro/debian/etc/default/chef-server +9 -0
  95. data/distro/debian/etc/default/chef-server-webui +9 -0
  96. data/distro/debian/etc/default/chef-solr +8 -0
  97. data/distro/debian/etc/init.d/chef-client +185 -0
  98. data/distro/debian/etc/init.d/chef-expander +176 -0
  99. data/distro/debian/etc/init.d/chef-server +122 -0
  100. data/distro/debian/etc/init.d/chef-server-webui +123 -0
  101. data/distro/debian/etc/init.d/chef-solr +176 -0
  102. data/distro/debian/etc/init/chef-client.conf +17 -0
  103. data/distro/debian/etc/init/chef-expander.conf +17 -0
  104. data/distro/debian/etc/init/chef-server-webui.conf +17 -0
  105. data/distro/debian/etc/init/chef-server.conf +17 -0
  106. data/distro/debian/etc/init/chef-solr.conf +17 -0
  107. data/distro/redhat/etc/init.d/chef-client +110 -0
  108. data/distro/redhat/etc/init.d/chef-expander +104 -0
  109. data/distro/redhat/etc/init.d/chef-server +112 -0
  110. data/distro/redhat/etc/init.d/chef-server-webui +112 -0
  111. data/distro/redhat/etc/init.d/chef-solr +104 -0
  112. data/distro/redhat/etc/logrotate.d/chef-client +8 -0
  113. data/distro/redhat/etc/logrotate.d/chef-expander +8 -0
  114. data/distro/redhat/etc/logrotate.d/chef-server +8 -0
  115. data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
  116. data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
  117. data/distro/redhat/etc/sysconfig/chef-client +15 -0
  118. data/distro/redhat/etc/sysconfig/chef-expander +7 -0
  119. data/distro/redhat/etc/sysconfig/chef-server +14 -0
  120. data/distro/redhat/etc/sysconfig/chef-server-webui +14 -0
  121. data/distro/redhat/etc/sysconfig/chef-solr +8 -0
  122. data/lib/chef.rb +41 -0
  123. data/lib/chef/api_client.rb +271 -0
  124. data/lib/chef/application.rb +152 -0
  125. data/lib/chef/application/agent.rb +18 -0
  126. data/lib/chef/application/client.rb +285 -0
  127. data/lib/chef/application/knife.rb +188 -0
  128. data/lib/chef/application/solo.rb +218 -0
  129. data/lib/chef/applications.rb +4 -0
  130. data/lib/chef/certificate.rb +194 -0
  131. data/lib/chef/checksum.rb +167 -0
  132. data/lib/chef/checksum/storage.rb +18 -0
  133. data/lib/chef/checksum/storage/filesystem.rb +56 -0
  134. data/lib/chef/checksum_cache.rb +189 -0
  135. data/lib/chef/client.rb +366 -0
  136. data/lib/chef/config.rb +248 -0
  137. data/lib/chef/cookbook/chefignore.rb +66 -0
  138. data/lib/chef/cookbook/cookbook_collection.rb +45 -0
  139. data/lib/chef/cookbook/cookbook_version_loader.rb +173 -0
  140. data/lib/chef/cookbook/file_system_file_vendor.rb +56 -0
  141. data/lib/chef/cookbook/file_vendor.rb +48 -0
  142. data/lib/chef/cookbook/metadata.rb +629 -0
  143. data/lib/chef/cookbook/remote_file_vendor.rb +88 -0
  144. data/lib/chef/cookbook/syntax_check.rb +136 -0
  145. data/lib/chef/cookbook_loader.rb +121 -0
  146. data/lib/chef/cookbook_site_streaming_uploader.rb +244 -0
  147. data/lib/chef/cookbook_uploader.rb +154 -0
  148. data/lib/chef/cookbook_version.rb +1096 -0
  149. data/lib/chef/cookbook_version_selector.rb +168 -0
  150. data/lib/chef/couchdb.rb +246 -0
  151. data/lib/chef/daemon.rb +172 -0
  152. data/lib/chef/data_bag.rb +235 -0
  153. data/lib/chef/data_bag_item.rb +273 -0
  154. data/lib/chef/encrypted_data_bag_item.rb +139 -0
  155. data/lib/chef/environment.rb +455 -0
  156. data/lib/chef/exceptions.rb +154 -0
  157. data/lib/chef/file_access_control.rb +144 -0
  158. data/lib/chef/file_cache.rb +218 -0
  159. data/lib/chef/handler.rb +227 -0
  160. data/lib/chef/handler/error_report.rb +33 -0
  161. data/lib/chef/handler/json_file.rb +58 -0
  162. data/lib/chef/index_queue.rb +29 -0
  163. data/lib/chef/index_queue/amqp_client.rb +116 -0
  164. data/lib/chef/index_queue/consumer.rb +76 -0
  165. data/lib/chef/index_queue/indexable.rb +109 -0
  166. data/lib/chef/json_compat.rb +52 -0
  167. data/lib/chef/knife.rb +520 -0
  168. data/lib/chef/knife/bootstrap.rb +207 -0
  169. data/lib/chef/knife/bootstrap/archlinux-gems.erb +60 -0
  170. data/lib/chef/knife/bootstrap/centos5-gems.erb +56 -0
  171. data/lib/chef/knife/bootstrap/fedora13-gems.erb +43 -0
  172. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +49 -0
  173. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +50 -0
  174. data/lib/chef/knife/client_bulk_delete.rb +65 -0
  175. data/lib/chef/knife/client_create.rb +79 -0
  176. data/lib/chef/knife/client_delete.rb +46 -0
  177. data/lib/chef/knife/client_edit.rb +45 -0
  178. data/lib/chef/knife/client_list.rb +42 -0
  179. data/lib/chef/knife/client_reregister.rb +58 -0
  180. data/lib/chef/knife/client_show.rb +52 -0
  181. data/lib/chef/knife/configure.rb +149 -0
  182. data/lib/chef/knife/configure_client.rb +50 -0
  183. data/lib/chef/knife/cookbook_bulk_delete.rb +72 -0
  184. data/lib/chef/knife/cookbook_create.rb +274 -0
  185. data/lib/chef/knife/cookbook_delete.rb +151 -0
  186. data/lib/chef/knife/cookbook_download.rb +137 -0
  187. data/lib/chef/knife/cookbook_list.rb +47 -0
  188. data/lib/chef/knife/cookbook_metadata.rb +107 -0
  189. data/lib/chef/knife/cookbook_metadata_from_file.rb +44 -0
  190. data/lib/chef/knife/cookbook_show.rb +102 -0
  191. data/lib/chef/knife/cookbook_site_download.rb +70 -0
  192. data/lib/chef/knife/cookbook_site_install.rb +148 -0
  193. data/lib/chef/knife/cookbook_site_list.rb +62 -0
  194. data/lib/chef/knife/cookbook_site_search.rb +51 -0
  195. data/lib/chef/knife/cookbook_site_share.rb +114 -0
  196. data/lib/chef/knife/cookbook_site_show.rb +57 -0
  197. data/lib/chef/knife/cookbook_site_unshare.rb +56 -0
  198. data/lib/chef/knife/cookbook_site_vendor.rb +46 -0
  199. data/lib/chef/knife/cookbook_test.rb +93 -0
  200. data/lib/chef/knife/cookbook_upload.rb +240 -0
  201. data/lib/chef/knife/core/bootstrap_context.rb +100 -0
  202. data/lib/chef/knife/core/cookbook_scm_repo.rb +148 -0
  203. data/lib/chef/knife/core/generic_presenter.rb +191 -0
  204. data/lib/chef/knife/core/node_editor.rb +127 -0
  205. data/lib/chef/knife/core/node_presenter.rb +136 -0
  206. data/lib/chef/knife/core/object_loader.rb +75 -0
  207. data/lib/chef/knife/core/subcommand_loader.rb +112 -0
  208. data/lib/chef/knife/core/text_formatter.rb +100 -0
  209. data/lib/chef/knife/core/ui.rb +216 -0
  210. data/lib/chef/knife/data_bag_create.rb +93 -0
  211. data/lib/chef/knife/data_bag_delete.rb +51 -0
  212. data/lib/chef/knife/data_bag_edit.rb +94 -0
  213. data/lib/chef/knife/data_bag_from_file.rb +87 -0
  214. data/lib/chef/knife/data_bag_list.rb +46 -0
  215. data/lib/chef/knife/data_bag_show.rb +81 -0
  216. data/lib/chef/knife/environment_create.rb +53 -0
  217. data/lib/chef/knife/environment_delete.rb +45 -0
  218. data/lib/chef/knife/environment_edit.rb +45 -0
  219. data/lib/chef/knife/environment_from_file.rb +50 -0
  220. data/lib/chef/knife/environment_list.rb +42 -0
  221. data/lib/chef/knife/environment_show.rb +46 -0
  222. data/lib/chef/knife/exec.rb +51 -0
  223. data/lib/chef/knife/help.rb +103 -0
  224. data/lib/chef/knife/help_topics.rb +4 -0
  225. data/lib/chef/knife/index_rebuild.rb +50 -0
  226. data/lib/chef/knife/node_bulk_delete.rb +80 -0
  227. data/lib/chef/knife/node_create.rb +50 -0
  228. data/lib/chef/knife/node_delete.rb +47 -0
  229. data/lib/chef/knife/node_edit.rb +72 -0
  230. data/lib/chef/knife/node_from_file.rb +50 -0
  231. data/lib/chef/knife/node_list.rb +46 -0
  232. data/lib/chef/knife/node_run_list_add.rb +67 -0
  233. data/lib/chef/knife/node_run_list_remove.rb +48 -0
  234. data/lib/chef/knife/node_show.rb +73 -0
  235. data/lib/chef/knife/recipe_list.rb +32 -0
  236. data/lib/chef/knife/role_bulk_delete.rb +70 -0
  237. data/lib/chef/knife/role_create.rb +55 -0
  238. data/lib/chef/knife/role_delete.rb +47 -0
  239. data/lib/chef/knife/role_edit.rb +48 -0
  240. data/lib/chef/knife/role_from_file.rb +56 -0
  241. data/lib/chef/knife/role_list.rb +43 -0
  242. data/lib/chef/knife/role_show.rb +54 -0
  243. data/lib/chef/knife/search.rb +141 -0
  244. data/lib/chef/knife/ssh.rb +367 -0
  245. data/lib/chef/knife/status.rb +104 -0
  246. data/lib/chef/knife/tag_create.rb +52 -0
  247. data/lib/chef/knife/tag_delete.rb +60 -0
  248. data/lib/chef/knife/tag_list.rb +47 -0
  249. data/lib/chef/log.rb +39 -0
  250. data/lib/chef/mash.rb +211 -0
  251. data/lib/chef/mixin/check_helper.rb +31 -0
  252. data/lib/chef/mixin/checksum.rb +32 -0
  253. data/lib/chef/mixin/command.rb +163 -0
  254. data/lib/chef/mixin/command/unix.rb +215 -0
  255. data/lib/chef/mixin/command/windows.rb +76 -0
  256. data/lib/chef/mixin/convert_to_class_name.rb +63 -0
  257. data/lib/chef/mixin/create_path.rb +57 -0
  258. data/lib/chef/mixin/deep_merge.rb +225 -0
  259. data/lib/chef/mixin/deprecation.rb +65 -0
  260. data/lib/chef/mixin/from_file.rb +50 -0
  261. data/lib/chef/mixin/get_source_from_package.rb +42 -0
  262. data/lib/chef/mixin/language.rb +163 -0
  263. data/lib/chef/mixin/language_include_attribute.rb +61 -0
  264. data/lib/chef/mixin/language_include_recipe.rb +52 -0
  265. data/lib/chef/mixin/params_validate.rb +225 -0
  266. data/lib/chef/mixin/recipe_definition_dsl_core.rb +78 -0
  267. data/lib/chef/mixin/shell_out.rb +41 -0
  268. data/lib/chef/mixin/template.rb +95 -0
  269. data/lib/chef/mixin/xml_escape.rb +140 -0
  270. data/lib/chef/mixins.rb +15 -0
  271. data/lib/chef/monkey_patches/dir.rb +36 -0
  272. data/lib/chef/monkey_patches/numeric.rb +15 -0
  273. data/lib/chef/monkey_patches/object.rb +9 -0
  274. data/lib/chef/monkey_patches/regexp.rb +34 -0
  275. data/lib/chef/monkey_patches/string.rb +49 -0
  276. data/lib/chef/monkey_patches/tempfile.rb +64 -0
  277. data/lib/chef/nil_argument.rb +3 -0
  278. data/lib/chef/node.rb +677 -0
  279. data/lib/chef/node/attribute.rb +487 -0
  280. data/lib/chef/openid_registration.rb +187 -0
  281. data/lib/chef/platform.rb +434 -0
  282. data/lib/chef/provider.rb +124 -0
  283. data/lib/chef/provider/breakpoint.rb +36 -0
  284. data/lib/chef/provider/cookbook_file.rb +100 -0
  285. data/lib/chef/provider/cron.rb +186 -0
  286. data/lib/chef/provider/cron/solaris.rb +195 -0
  287. data/lib/chef/provider/deploy.rb +418 -0
  288. data/lib/chef/provider/deploy/revision.rb +80 -0
  289. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  290. data/lib/chef/provider/directory.rb +72 -0
  291. data/lib/chef/provider/env.rb +152 -0
  292. data/lib/chef/provider/env/windows.rb +75 -0
  293. data/lib/chef/provider/erl_call.rb +101 -0
  294. data/lib/chef/provider/execute.rb +65 -0
  295. data/lib/chef/provider/file.rb +226 -0
  296. data/lib/chef/provider/git.rb +243 -0
  297. data/lib/chef/provider/group.rb +133 -0
  298. data/lib/chef/provider/group/aix.rb +70 -0
  299. data/lib/chef/provider/group/dscl.rb +121 -0
  300. data/lib/chef/provider/group/gpasswd.rb +53 -0
  301. data/lib/chef/provider/group/groupadd.rb +91 -0
  302. data/lib/chef/provider/group/pw.rb +84 -0
  303. data/lib/chef/provider/group/suse.rb +53 -0
  304. data/lib/chef/provider/group/usermod.rb +57 -0
  305. data/lib/chef/provider/group/windows.rb +79 -0
  306. data/lib/chef/provider/http_request.rb +122 -0
  307. data/lib/chef/provider/ifconfig.rb +195 -0
  308. data/lib/chef/provider/link.rb +164 -0
  309. data/lib/chef/provider/log.rb +54 -0
  310. data/lib/chef/provider/mdadm.rb +91 -0
  311. data/lib/chef/provider/mount.rb +114 -0
  312. data/lib/chef/provider/mount/mount.rb +240 -0
  313. data/lib/chef/provider/mount/windows.rb +81 -0
  314. data/lib/chef/provider/ohai.rb +42 -0
  315. data/lib/chef/provider/package.rb +200 -0
  316. data/lib/chef/provider/package/apt.rb +145 -0
  317. data/lib/chef/provider/package/dpkg.rb +115 -0
  318. data/lib/chef/provider/package/easy_install.rb +136 -0
  319. data/lib/chef/provider/package/freebsd.rb +125 -0
  320. data/lib/chef/provider/package/macports.rb +105 -0
  321. data/lib/chef/provider/package/pacman.rb +101 -0
  322. data/lib/chef/provider/package/portage.rb +135 -0
  323. data/lib/chef/provider/package/rpm.rb +104 -0
  324. data/lib/chef/provider/package/rubygems.rb +465 -0
  325. data/lib/chef/provider/package/solaris.rb +130 -0
  326. data/lib/chef/provider/package/yum-dump.py +286 -0
  327. data/lib/chef/provider/package/yum.rb +1173 -0
  328. data/lib/chef/provider/package/zypper.rb +144 -0
  329. data/lib/chef/provider/remote_directory.rb +137 -0
  330. data/lib/chef/provider/remote_file.rb +118 -0
  331. data/lib/chef/provider/route.rb +193 -0
  332. data/lib/chef/provider/ruby_block.rb +34 -0
  333. data/lib/chef/provider/script.rb +55 -0
  334. data/lib/chef/provider/service.rb +122 -0
  335. data/lib/chef/provider/service/arch.rb +116 -0
  336. data/lib/chef/provider/service/debian.rb +130 -0
  337. data/lib/chef/provider/service/freebsd.rb +154 -0
  338. data/lib/chef/provider/service/gentoo.rb +53 -0
  339. data/lib/chef/provider/service/init.rb +71 -0
  340. data/lib/chef/provider/service/insserv.rb +52 -0
  341. data/lib/chef/provider/service/invokercd.rb +35 -0
  342. data/lib/chef/provider/service/redhat.rb +60 -0
  343. data/lib/chef/provider/service/simple.rb +120 -0
  344. data/lib/chef/provider/service/solaris.rb +85 -0
  345. data/lib/chef/provider/service/systemd.rb +102 -0
  346. data/lib/chef/provider/service/upstart.rb +198 -0
  347. data/lib/chef/provider/service/windows.rb +155 -0
  348. data/lib/chef/provider/subversion.rb +197 -0
  349. data/lib/chef/provider/template.rb +104 -0
  350. data/lib/chef/provider/user.rb +186 -0
  351. data/lib/chef/provider/user/dscl.rb +280 -0
  352. data/lib/chef/provider/user/pw.rb +113 -0
  353. data/lib/chef/provider/user/useradd.rb +137 -0
  354. data/lib/chef/provider/user/windows.rb +124 -0
  355. data/lib/chef/providers.rb +95 -0
  356. data/lib/chef/recipe.rb +129 -0
  357. data/lib/chef/resource.rb +609 -0
  358. data/lib/chef/resource/apt_package.rb +34 -0
  359. data/lib/chef/resource/bash.rb +33 -0
  360. data/lib/chef/resource/breakpoint.rb +35 -0
  361. data/lib/chef/resource/conditional.rb +90 -0
  362. data/lib/chef/resource/cookbook_file.rb +45 -0
  363. data/lib/chef/resource/cron.rb +188 -0
  364. data/lib/chef/resource/csh.rb +33 -0
  365. data/lib/chef/resource/deploy.rb +389 -0
  366. data/lib/chef/resource/deploy_revision.rb +40 -0
  367. data/lib/chef/resource/directory.rb +76 -0
  368. data/lib/chef/resource/dpkg_package.rb +34 -0
  369. data/lib/chef/resource/easy_install_package.rb +57 -0
  370. data/lib/chef/resource/env.rb +58 -0
  371. data/lib/chef/resource/erl_call.rb +83 -0
  372. data/lib/chef/resource/execute.rb +127 -0
  373. data/lib/chef/resource/file.rb +99 -0
  374. data/lib/chef/resource/freebsd_package.rb +35 -0
  375. data/lib/chef/resource/gem_package.rb +53 -0
  376. data/lib/chef/resource/git.rb +46 -0
  377. data/lib/chef/resource/group.rb +78 -0
  378. data/lib/chef/resource/http_request.rb +61 -0
  379. data/lib/chef/resource/ifconfig.rb +144 -0
  380. data/lib/chef/resource/link.rb +78 -0
  381. data/lib/chef/resource/log.rb +62 -0
  382. data/lib/chef/resource/macports_package.rb +29 -0
  383. data/lib/chef/resource/mdadm.rb +82 -0
  384. data/lib/chef/resource/mount.rb +134 -0
  385. data/lib/chef/resource/ohai.rb +40 -0
  386. data/lib/chef/resource/package.rb +80 -0
  387. data/lib/chef/resource/pacman_package.rb +33 -0
  388. data/lib/chef/resource/perl.rb +33 -0
  389. data/lib/chef/resource/portage_package.rb +33 -0
  390. data/lib/chef/resource/python.rb +33 -0
  391. data/lib/chef/resource/remote_directory.rb +109 -0
  392. data/lib/chef/resource/remote_file.rb +83 -0
  393. data/lib/chef/resource/route.rb +135 -0
  394. data/lib/chef/resource/rpm_package.rb +34 -0
  395. data/lib/chef/resource/ruby.rb +33 -0
  396. data/lib/chef/resource/ruby_block.rb +40 -0
  397. data/lib/chef/resource/scm.rb +147 -0
  398. data/lib/chef/resource/script.rb +60 -0
  399. data/lib/chef/resource/service.rb +151 -0
  400. data/lib/chef/resource/solaris_package.rb +36 -0
  401. data/lib/chef/resource/subversion.rb +36 -0
  402. data/lib/chef/resource/template.rb +69 -0
  403. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  404. data/lib/chef/resource/user.rb +130 -0
  405. data/lib/chef/resource/yum_package.rb +63 -0
  406. data/lib/chef/resource_collection.rb +217 -0
  407. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  408. data/lib/chef/resource_definition.rb +67 -0
  409. data/lib/chef/resource_definition_list.rb +38 -0
  410. data/lib/chef/resources.rb +64 -0
  411. data/lib/chef/rest.rb +400 -0
  412. data/lib/chef/rest/auth_credentials.rb +71 -0
  413. data/lib/chef/rest/cookie_jar.rb +31 -0
  414. data/lib/chef/rest/rest_request.rb +213 -0
  415. data/lib/chef/role.rb +343 -0
  416. data/lib/chef/run_context.rb +126 -0
  417. data/lib/chef/run_list.rb +165 -0
  418. data/lib/chef/run_list/run_list_expansion.rb +193 -0
  419. data/lib/chef/run_list/run_list_item.rb +92 -0
  420. data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
  421. data/lib/chef/run_status.rb +121 -0
  422. data/lib/chef/runner.rb +105 -0
  423. data/lib/chef/sandbox.rb +153 -0
  424. data/lib/chef/search/query.rb +65 -0
  425. data/lib/chef/shef.rb +327 -0
  426. data/lib/chef/shef/ext.rb +569 -0
  427. data/lib/chef/shef/model_wrapper.rb +120 -0
  428. data/lib/chef/shef/shef_rest.rb +28 -0
  429. data/lib/chef/shef/shef_session.rb +285 -0
  430. data/lib/chef/shell_out.rb +249 -0
  431. data/lib/chef/shell_out/unix.rb +223 -0
  432. data/lib/chef/shell_out/windows.rb +588 -0
  433. data/lib/chef/solr_query.rb +187 -0
  434. data/lib/chef/solr_query/lucene.treetop +150 -0
  435. data/lib/chef/solr_query/lucene_nodes.rb +285 -0
  436. data/lib/chef/solr_query/query_transform.rb +65 -0
  437. data/lib/chef/solr_query/solr_http_request.rb +132 -0
  438. data/lib/chef/streaming_cookbook_uploader.rb +201 -0
  439. data/lib/chef/tasks/chef_repo.rake +334 -0
  440. data/lib/chef/util/file_edit.rb +122 -0
  441. data/lib/chef/util/windows.rb +56 -0
  442. data/lib/chef/util/windows/net_group.rb +101 -0
  443. data/lib/chef/util/windows/net_use.rb +121 -0
  444. data/lib/chef/util/windows/net_user.rb +198 -0
  445. data/lib/chef/util/windows/volume.rb +59 -0
  446. data/lib/chef/version.rb +23 -0
  447. data/lib/chef/version_class.rb +70 -0
  448. data/lib/chef/version_constraint.rb +116 -0
  449. data/lib/chef/webui_user.rb +231 -0
  450. metadata +764 -0
@@ -0,0 +1,130 @@
1
+ #
2
+ # Author:: Toomas Pelberg (<toomasp@gmx.net>)
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
+ require 'chef/provider/package'
19
+ require 'chef/mixin/command'
20
+ require 'chef/resource/package'
21
+ require 'chef/mixin/get_source_from_package'
22
+
23
+ class Chef
24
+ class Provider
25
+ class Package
26
+ class Solaris < Chef::Provider::Package
27
+
28
+ include Chef::Mixin::GetSourceFromPackage
29
+
30
+ # def initialize(*args)
31
+ # super
32
+ # @current_resource = Chef::Resource::Package.new(@new_resource.name)
33
+ # end
34
+
35
+ def load_current_resource
36
+ @current_resource = Chef::Resource::Package.new(@new_resource.name)
37
+ @current_resource.package_name(@new_resource.package_name)
38
+ @new_resource.version(nil)
39
+
40
+ if @new_resource.source
41
+ unless ::File.exists?(@new_resource.source)
42
+ raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
43
+ end
44
+
45
+ Chef::Log.debug("#{@new_resource} checking pkg status")
46
+ status = popen4("pkginfo -l -d #{@new_resource.source} #{@new_resource.package_name}") do |pid, stdin, stdout, stderr|
47
+ stdout.each do |line|
48
+ case line
49
+ when /VERSION:\s+(.+)/
50
+ @new_resource.version($1)
51
+ end
52
+ end
53
+ end
54
+ elsif Array(@new_resource.action).include?(:install)
55
+ raise Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install"
56
+ end
57
+
58
+ Chef::Log.debug("#{@new_resource} checking install state")
59
+ status = popen4("pkginfo -l #{@current_resource.package_name}") do |pid, stdin, stdout, stderr|
60
+ stdout.each do |line|
61
+ case line
62
+ when /VERSION:\s+(.+)/
63
+ Chef::Log.debug("#{@new_resource} version #{$1} is already installed")
64
+ @current_resource.version($1)
65
+ end
66
+ end
67
+ end
68
+
69
+ unless status.exitstatus == 0 || status.exitstatus == 1
70
+ raise Chef::Exceptions::Package, "pkginfo failed - #{status.inspect}!"
71
+ end
72
+
73
+ unless @current_resource.version.nil?
74
+ @current_resource.version(nil)
75
+ end
76
+
77
+ @current_resource
78
+ end
79
+
80
+ def candidate_version
81
+ return @candidate_version if @candidate_version
82
+ status = popen4("pkginfo -l -d #{@new_resource.source} #{new_resource.package_name}") do |pid, stdin, stdout, stderr|
83
+ stdout.each_line do |line|
84
+ case line
85
+ when /VERSION:\s+(.+)/
86
+ @candidate_version = $1
87
+ @new_resource.version($1)
88
+ Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}")
89
+ end
90
+ end
91
+ end
92
+ unless status.exitstatus == 0
93
+ raise Chef::Exceptions::Package, "pkginfo -l -d #{@new_resource.source} - #{status.inspect}!"
94
+ end
95
+ @candidate_version
96
+ end
97
+
98
+ def install_package(name, version)
99
+ Chef::Log.debug("#{@new_resource} package install options: #{@new_resource.options}")
100
+ if @new_resource.options.nil?
101
+ run_command_with_systems_locale(
102
+ :command => "pkgadd -n -d #{@new_resource.source} all"
103
+ )
104
+ Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
105
+ else
106
+ run_command_with_systems_locale(
107
+ :command => "pkgadd -n#{expand_options(@new_resource.options)} -d #{@new_resource.source} all"
108
+ )
109
+ Chef::Log.debug("#{@new_resource} installed version #{@new_resource.version} from: #{@new_resource.source}")
110
+ end
111
+ end
112
+
113
+ def remove_package(name, version)
114
+ if @new_resource.options.nil?
115
+ run_command_with_systems_locale(
116
+ :command => "pkgrm -n #{name}"
117
+ )
118
+ Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
119
+ else
120
+ run_command_with_systems_locale(
121
+ :command => "pkgrm -n#{expand_options(@new_resource.options)} #{name}"
122
+ )
123
+ Chef::Log.debug("#{@new_resource} removed version #{@new_resource.version}")
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,286 @@
1
+ #
2
+ # Author:: Matthew Kent (<mkent@magoazul.com>)
3
+ # Copyright:: Copyright (c) 2009, 2011 Matthew Kent
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
+ # yum-dump.py
20
+ # Inspired by yumhelper.py by David Lutterkort
21
+ #
22
+ # Produce a list of installed, available and re-installable packages using yum
23
+ # and dump the results to stdout.
24
+ #
25
+ # yum-dump invokes yum similarly to the command line interface which makes it
26
+ # subject to most of the configuration paramaters in yum.conf. yum-dump will
27
+ # also load yum plugins in the same manor as yum - these can affect the output.
28
+ #
29
+ # Can be run as non root, but that won't update the cache.
30
+ #
31
+ # Intended to support yum 2.x and 3.x
32
+
33
+ import os
34
+ import sys
35
+ import time
36
+ import yum
37
+ import re
38
+ import errno
39
+
40
+ from yum import Errors
41
+ from optparse import OptionParser
42
+ from distutils import version
43
+
44
+ YUM_PID_FILE='/var/run/yum.pid'
45
+
46
+ # Seconds to wait for exclusive access to yum
47
+ LOCK_TIMEOUT = 10
48
+
49
+ YUM_VER = version.StrictVersion(yum.__version__)
50
+ YUM_MAJOR = YUM_VER.version[0]
51
+
52
+ if YUM_MAJOR > 3 or YUM_MAJOR < 2:
53
+ print >> sys.stderr, "yum-dump Error: Can't match supported yum version" \
54
+ " (%s)" % yum.__version__
55
+ sys.exit(1)
56
+
57
+ # Required for Provides output
58
+ if YUM_MAJOR == 2:
59
+ import rpm
60
+ import rpmUtils.miscutils
61
+
62
+ def setup(yb, options):
63
+ # Only want our output
64
+ #
65
+ if YUM_MAJOR == 3:
66
+ try:
67
+ if YUM_VER >= version.StrictVersion("3.2.22"):
68
+ yb.preconf.errorlevel=0
69
+ yb.preconf.debuglevel=0
70
+
71
+ # initialize the config
72
+ yb.conf
73
+ else:
74
+ yb.doConfigSetup(errorlevel=0, debuglevel=0)
75
+ except yum.Errors.ConfigError, e:
76
+ # supresses an ignored exception at exit
77
+ yb.preconf = None
78
+ print >> sys.stderr, "yum-dump Config Error: %s" % e
79
+ return 1
80
+ except ValueError, e:
81
+ yb.preconf = None
82
+ print >> sys.stderr, "yum-dump Options Error: %s" % e
83
+ return 1
84
+ elif YUM_MAJOR == 2:
85
+ yb.doConfigSetup()
86
+
87
+ def __log(a,b): pass
88
+
89
+ yb.log = __log
90
+ yb.errorlog = __log
91
+
92
+ # Give Chef every possible package version, it can decide what to do with them
93
+ if YUM_MAJOR == 3:
94
+ yb.conf.showdupesfromrepos = True
95
+ elif YUM_MAJOR == 2:
96
+ yb.conf.setConfigOption('showdupesfromrepos', True)
97
+
98
+ # Optionally run only on cached repositories, but non root must use the cache
99
+ if os.geteuid() != 0:
100
+ if YUM_MAJOR == 3:
101
+ yb.conf.cache = True
102
+ elif YUM_MAJOR == 2:
103
+ yb.conf.setConfigOption('cache', True)
104
+ else:
105
+ if YUM_MAJOR == 3:
106
+ yb.conf.cache = options.cache
107
+ elif YUM_MAJOR == 2:
108
+ yb.conf.setConfigOption('cache', options.cache)
109
+
110
+ return 0
111
+
112
+ def dump_packages(yb, list, output_provides):
113
+ packages = {}
114
+
115
+ if YUM_MAJOR == 2:
116
+ yb.doTsSetup()
117
+ yb.doRepoSetup()
118
+ yb.doSackSetup()
119
+
120
+ db = yb.doPackageLists(list)
121
+
122
+ for pkg in db.installed:
123
+ pkg.type = 'i'
124
+ packages[str(pkg)] = pkg
125
+
126
+ if YUM_VER >= version.StrictVersion("3.2.21"):
127
+ for pkg in db.available:
128
+ pkg.type = 'a'
129
+ packages[str(pkg)] = pkg
130
+
131
+ # These are both installed and available
132
+ for pkg in db.reinstall_available:
133
+ pkg.type = 'r'
134
+ packages[str(pkg)] = pkg
135
+ else:
136
+ # Old style method - no reinstall list
137
+ for pkg in yb.pkgSack.returnPackages():
138
+
139
+ if str(pkg) in packages:
140
+ if packages[str(pkg)].type == "i":
141
+ packages[str(pkg)].type = 'r'
142
+ continue
143
+
144
+ pkg.type = 'a'
145
+ packages[str(pkg)] = pkg
146
+
147
+ unique_packages = packages.values()
148
+
149
+ unique_packages.sort(lambda x, y: cmp(x.name, y.name))
150
+
151
+ for pkg in unique_packages:
152
+ if output_provides == "all" or \
153
+ (output_provides == "installed" and (pkg.type == "i" or pkg.type == "r")):
154
+
155
+ # yum 2 doesn't have provides_print, implement it ourselves using methods
156
+ # based on requires gathering in packages.py
157
+ if YUM_MAJOR == 2:
158
+ provlist = []
159
+
160
+ # Installed and available are gathered in different ways
161
+ if pkg.type == 'i' or pkg.type == 'r':
162
+ names = pkg.hdr[rpm.RPMTAG_PROVIDENAME]
163
+ flags = pkg.hdr[rpm.RPMTAG_PROVIDEFLAGS]
164
+ ver = pkg.hdr[rpm.RPMTAG_PROVIDEVERSION]
165
+ if names is not None:
166
+ tmplst = zip(names, flags, ver)
167
+
168
+ for (n, f, v) in tmplst:
169
+ prov = rpmUtils.miscutils.formatRequire(n, v, f)
170
+ provlist.append(prov)
171
+ # This is slow :(
172
+ elif pkg.type == 'a':
173
+ for prcoTuple in pkg.returnPrco('provides'):
174
+ prcostr = pkg.prcoPrintable(prcoTuple)
175
+ provlist.append(prcostr)
176
+
177
+ provides = provlist
178
+ else:
179
+ provides = pkg.provides_print
180
+ else:
181
+ provides = "[]"
182
+
183
+ print '%s %s %s %s %s %s %s' % (
184
+ pkg.name,
185
+ pkg.epoch,
186
+ pkg.version,
187
+ pkg.release,
188
+ pkg.arch,
189
+ provides,
190
+ pkg.type )
191
+
192
+ return 0
193
+
194
+ def yum_dump(options):
195
+ lock_obtained = False
196
+
197
+ yb = yum.YumBase()
198
+
199
+ status = setup(yb, options)
200
+ if status != 0:
201
+ return status
202
+
203
+ if options.output_options:
204
+ print "[option installonlypkgs] %s" % " ".join(yb.conf.installonlypkgs)
205
+
206
+ # Non root can't handle locking on rhel/centos 4
207
+ if os.geteuid() != 0:
208
+ return dump_packages(yb, options.package_list, options.output_provides)
209
+
210
+ # Wrap the collection and output of packages in yum's global lock to prevent
211
+ # any inconsistencies.
212
+ try:
213
+ # Spin up to LOCK_TIMEOUT
214
+ countdown = LOCK_TIMEOUT
215
+ while True:
216
+ try:
217
+ yb.doLock(YUM_PID_FILE)
218
+ lock_obtained = True
219
+ except Errors.LockError, e:
220
+ time.sleep(1)
221
+ countdown -= 1
222
+ if countdown == 0:
223
+ print >> sys.stderr, "yum-dump Locking Error! Couldn't obtain an " \
224
+ "exclusive yum lock in %d seconds. Giving up." % LOCK_TIMEOUT
225
+ return 200
226
+ else:
227
+ break
228
+
229
+ return dump_packages(yb, options.package_list, options.output_provides)
230
+
231
+ # Ensure we clear the lock and cleanup any resources
232
+ finally:
233
+ try:
234
+ yb.closeRpmDB()
235
+ if lock_obtained == True:
236
+ yb.doUnlock(YUM_PID_FILE)
237
+ except Errors.LockError, e:
238
+ print >> sys.stderr, "yum-dump Unlock Error: %s" % e
239
+ return 200
240
+
241
+ def main():
242
+ usage = "Usage: %prog [options]\n" + \
243
+ "Output a list of installed, available and re-installable packages via yum"
244
+ parser = OptionParser(usage=usage)
245
+ parser.add_option("-C", "--cache",
246
+ action="store_true", dest="cache", default=False,
247
+ help="run entirely from cache, don't update cache")
248
+ parser.add_option("-o", "--options",
249
+ action="store_true", dest="output_options", default=False,
250
+ help="output select yum options useful to Chef")
251
+ parser.add_option("-p", "--installed-provides",
252
+ action="store_const", const="installed", dest="output_provides", default="none",
253
+ help="output Provides for installed packages, big/wide output")
254
+ parser.add_option("-P", "--all-provides",
255
+ action="store_const", const="all", dest="output_provides", default="none",
256
+ help="output Provides for all package, slow, big/wide output")
257
+ parser.add_option("-i", "--installed",
258
+ action="store_const", const="installed", dest="package_list", default="all",
259
+ help="output only installed packages")
260
+ parser.add_option("-a", "--available",
261
+ action="store_const", const="available", dest="package_list", default="all",
262
+ help="output only available and re-installable packages")
263
+
264
+ (options, args) = parser.parse_args()
265
+
266
+ try:
267
+ return yum_dump(options)
268
+
269
+ except yum.Errors.RepoError, e:
270
+ print >> sys.stderr, "yum-dump Repository Error: %s" % e
271
+ return 1
272
+
273
+ except yum.Errors.YumBaseError, e:
274
+ print >> sys.stderr, "yum-dump General Error: %s" % e
275
+ return 1
276
+
277
+ try:
278
+ status = main()
279
+ # Suppress a nasty broken pipe error when output is piped to utilities like 'head'
280
+ except IOError, e:
281
+ if e.errno == errno.EPIPE:
282
+ sys.exit(1)
283
+ else:
284
+ raise
285
+
286
+ sys.exit(status)
@@ -0,0 +1,1173 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 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/provider/package'
20
+ require 'chef/mixin/command'
21
+ require 'chef/resource/package'
22
+ require 'singleton'
23
+ require 'chef/mixin/get_source_from_package'
24
+
25
+
26
+ class Chef
27
+ class Provider
28
+ class Package
29
+ class Yum < Chef::Provider::Package
30
+
31
+ class RPMUtils
32
+ class << self
33
+
34
+ # RPM::Version version_parse equivalent
35
+ def version_parse(evr)
36
+ return if evr.nil?
37
+
38
+ epoch = nil
39
+ # assume this is a version
40
+ version = evr
41
+ release = nil
42
+
43
+ lead = 0
44
+ tail = evr.size
45
+
46
+ if evr =~ %r{^([\d]+):}
47
+ epoch = $1.to_i
48
+ lead = $1.length + 1
49
+ elsif evr[0].ord == ":".ord
50
+ epoch = 0
51
+ lead = 1
52
+ end
53
+
54
+ if evr =~ %r{:?.*-(.*)$}
55
+ release = $1
56
+ tail = evr.length - release.length - lead - 1
57
+
58
+ if release.empty?
59
+ release = nil
60
+ end
61
+ end
62
+
63
+ version = evr[lead,tail]
64
+ if version.empty?
65
+ version = nil
66
+ end
67
+
68
+ [ epoch, version, release ]
69
+ end
70
+
71
+ # verify
72
+ def isalnum(x)
73
+ isalpha(x) or isdigit(x)
74
+ end
75
+
76
+ def isalpha(x)
77
+ v = x.ord
78
+ (v >= 65 and v <= 90) or (v >= 97 and v <= 122)
79
+ end
80
+
81
+ def isdigit(x)
82
+ v = x.ord
83
+ v >= 48 and v <= 57
84
+ end
85
+
86
+ # based on the reference spec in lib/rpmvercmp.c in rpm 4.9.0
87
+ def rpmvercmp(x, y)
88
+ # easy! :)
89
+ return 0 if x == y
90
+
91
+ if x.nil?
92
+ x = ""
93
+ end
94
+
95
+ if y.nil?
96
+ y = ""
97
+ end
98
+
99
+ # not so easy :(
100
+ #
101
+ # takes 2 strings like
102
+ #
103
+ # x = "1.20.b18.el5"
104
+ # y = "1.20.b17.el5"
105
+ #
106
+ # breaks into purely alpha and numeric segments and compares them using
107
+ # some rules
108
+ #
109
+ # * 10 > 1
110
+ # * 1 > a
111
+ # * z > a
112
+ # * Z > A
113
+ # * z > Z
114
+ # * leading zeros are ignored
115
+ # * separators (periods, commas) are ignored
116
+ # * "1.20.b18.el5.extrastuff" > "1.20.b18.el5"
117
+
118
+ x_pos = 0 # overall string element reference position
119
+ x_pos_max = x.length - 1 # number of elements in string, starting from 0
120
+ x_seg_pos = 0 # segment string element reference position
121
+ x_comp = nil # segment to compare
122
+
123
+ y_pos = 0
124
+ y_seg_pos = 0
125
+ y_pos_max = y.length - 1
126
+ y_comp = nil
127
+
128
+ while (x_pos <= x_pos_max and y_pos <= y_pos_max)
129
+ # first we skip over anything non alphanumeric
130
+ while (x_pos <= x_pos_max) and (isalnum(x[x_pos]) == false)
131
+ x_pos += 1 # +1 over pos_max if end of string
132
+ end
133
+ while (y_pos <= y_pos_max) and (isalnum(y[y_pos]) == false)
134
+ y_pos += 1
135
+ end
136
+
137
+ # if we hit the end of either we are done matching segments
138
+ if (x_pos == x_pos_max + 1) or (y_pos == y_pos_max + 1)
139
+ break
140
+ end
141
+
142
+ # we are now at the start of a alpha or numeric segment
143
+ x_seg_pos = x_pos
144
+ y_seg_pos = y_pos
145
+
146
+ # grab segment so we can compare them
147
+ if isdigit(x[x_seg_pos].ord)
148
+ x_seg_is_num = true
149
+
150
+ # already know it's a digit
151
+ x_seg_pos += 1
152
+
153
+ # gather up our digits
154
+ while (x_seg_pos <= x_pos_max) and isdigit(x[x_seg_pos])
155
+ x_seg_pos += 1
156
+ end
157
+ # copy the segment but not the unmatched character that x_seg_pos will
158
+ # refer to
159
+ x_comp = x[x_pos,x_seg_pos - x_pos]
160
+
161
+ while (y_seg_pos <= y_pos_max) and isdigit(y[y_seg_pos])
162
+ y_seg_pos += 1
163
+ end
164
+ y_comp = y[y_pos,y_seg_pos - y_pos]
165
+ else
166
+ # we are comparing strings
167
+ x_seg_is_num = false
168
+
169
+ while (x_seg_pos <= x_pos_max) and isalpha(x[x_seg_pos])
170
+ x_seg_pos += 1
171
+ end
172
+ x_comp = x[x_pos,x_seg_pos - x_pos]
173
+
174
+ while (y_seg_pos <= y_pos_max) and isalpha(y[y_seg_pos])
175
+ y_seg_pos += 1
176
+ end
177
+ y_comp = y[y_pos,y_seg_pos - y_pos]
178
+ end
179
+
180
+ # if y_seg_pos didn't advance in the above loop it means the segments are
181
+ # different types
182
+ if y_pos == y_seg_pos
183
+ # numbers always win over letters
184
+ return x_seg_is_num ? 1 : -1
185
+ end
186
+
187
+ # move the ball forward before we mess with the segments
188
+ x_pos += x_comp.length # +1 over pos_max if end of string
189
+ y_pos += y_comp.length
190
+
191
+ # we are comparing numbers - simply convert them
192
+ if x_seg_is_num
193
+ x_comp = x_comp.to_i
194
+ y_comp = y_comp.to_i
195
+ end
196
+
197
+ # compares ints or strings
198
+ # don't return if equal - try the next segment
199
+ if x_comp > y_comp
200
+ return 1
201
+ elsif x_comp < y_comp
202
+ return -1
203
+ end
204
+
205
+ # if we've reached here than the segments are the same - try again
206
+ end
207
+
208
+ # we must have reached the end of one or both of the strings and they
209
+ # matched up until this point
210
+
211
+ # segments matched completely but the segment separators were different -
212
+ # rpm reference code treats these as equal.
213
+ if (x_pos == x_pos_max + 1) and (y_pos == y_pos_max + 1)
214
+ return 0
215
+ end
216
+
217
+ # the most unprocessed characters left wins
218
+ if (x_pos_max - x_pos) > (y_pos_max - y_pos)
219
+ return 1
220
+ else
221
+ return -1
222
+ end
223
+ end
224
+
225
+ end # self
226
+ end # RPMUtils
227
+
228
+ class RPMVersion
229
+ include Comparable
230
+
231
+ def initialize(*args)
232
+ if args.size == 1
233
+ @e, @v, @r = RPMUtils.version_parse(args[0])
234
+ elsif args.size == 3
235
+ @e = args[0].to_i
236
+ @v = args[1]
237
+ @r = args[2]
238
+ else
239
+ raise ArgumentError, "Expecting either 'epoch-version-release' or 'epoch, " +
240
+ "version, release'"
241
+ end
242
+ end
243
+ attr_reader :e, :v, :r
244
+ alias :epoch :e
245
+ alias :version :v
246
+ alias :release :r
247
+
248
+ def self.parse(*args)
249
+ self.new(*args)
250
+ end
251
+
252
+ def <=>(y)
253
+ compare_versions(y)
254
+ end
255
+
256
+ def compare(y)
257
+ compare_versions(y, false)
258
+ end
259
+
260
+ def partial_compare(y)
261
+ compare_versions(y, true)
262
+ end
263
+
264
+ # RPM::Version rpm_version_to_s equivalent
265
+ def to_s
266
+ if @r.nil?
267
+ @v
268
+ else
269
+ "#{@v}-#{@r}"
270
+ end
271
+ end
272
+
273
+ def evr
274
+ "#{@e}:#{@v}-#{@r}"
275
+ end
276
+
277
+ private
278
+
279
+ # Rough RPM::Version rpm_version_cmp equivalent - except much slower :)
280
+ #
281
+ # partial lets epoch and version segment equality be good enough to return equal, eg:
282
+ #
283
+ # 2:1.2-1 == 2:1.2
284
+ # 2:1.2-1 == 2:
285
+ #
286
+ def compare_versions(y, partial=false)
287
+ x = self
288
+
289
+ # compare epoch
290
+ if (x.e.nil? == false and x.e > 0) and y.e.nil?
291
+ return 1
292
+ elsif x.e.nil? and (y.e.nil? == false and y.e > 0)
293
+ return -1
294
+ elsif x.e.nil? == false and y.e.nil? == false
295
+ if x.e < y.e
296
+ return -1
297
+ elsif x.e > y.e
298
+ return 1
299
+ end
300
+ end
301
+
302
+ # compare version
303
+ if partial and (x.v.nil? or y.v.nil?)
304
+ return 0
305
+ elsif x.v.nil? == false and y.v.nil?
306
+ return 1
307
+ elsif x.v.nil? and y.v.nil? == false
308
+ return -1
309
+ elsif x.v.nil? == false and y.v.nil? == false
310
+ cmp = RPMUtils.rpmvercmp(x.v, y.v)
311
+ return cmp if cmp != 0
312
+ end
313
+
314
+ # compare release
315
+ if partial and (x.r.nil? or y.r.nil?)
316
+ return 0
317
+ elsif x.r.nil? == false and y.r.nil?
318
+ return 1
319
+ elsif x.r.nil? and y.r.nil? == false
320
+ return -1
321
+ elsif x.r.nil? == false and y.r.nil? == false
322
+ cmp = RPMUtils.rpmvercmp(x.r, y.r)
323
+ return cmp
324
+ end
325
+
326
+ return 0
327
+ end
328
+ end
329
+
330
+ class RPMPackage
331
+ include Comparable
332
+
333
+ def initialize(*args)
334
+ if args.size == 4
335
+ @n = args[0]
336
+ @version = RPMVersion.new(args[1])
337
+ @a = args[2]
338
+ @provides = args[3]
339
+ elsif args.size == 6
340
+ @n = args[0]
341
+ e = args[1].to_i
342
+ v = args[2]
343
+ r = args[3]
344
+ @version = RPMVersion.new(e,v,r)
345
+ @a = args[4]
346
+ @provides = args[5]
347
+ else
348
+ raise ArgumentError, "Expecting either 'name, epoch-version-release, arch, provides' " +
349
+ "or 'name, epoch, version, release, arch, provides'"
350
+ end
351
+
352
+ # We always have one, ourselves!
353
+ if @provides.empty?
354
+ @provides = [ RPMProvide.new(@n, @version.evr, :==) ]
355
+ end
356
+ end
357
+ attr_reader :n, :a, :version, :provides
358
+ alias :name :n
359
+ alias :arch :a
360
+
361
+ def <=>(y)
362
+ compare(y)
363
+ end
364
+
365
+ def compare(y)
366
+ x = self
367
+
368
+ # easy! :)
369
+ return 0 if x.nevra == y.nevra
370
+
371
+ # compare name
372
+ if x.n.nil? == false and y.n.nil?
373
+ return 1
374
+ elsif x.n.nil? and y.n.nil? == false
375
+ return -1
376
+ elsif x.n.nil? == false and y.n.nil? == false
377
+ if x.n < y.n
378
+ return -1
379
+ elsif x.n > y.n
380
+ return 1
381
+ end
382
+ end
383
+
384
+ # compare version
385
+ if x.version > y.version
386
+ return 1
387
+ elsif x.version < y.version
388
+ return -1
389
+ end
390
+
391
+ # compare arch
392
+ if x.a.nil? == false and y.a.nil?
393
+ return 1
394
+ elsif x.a.nil? and y.a.nil? == false
395
+ return -1
396
+ elsif x.a.nil? == false and y.a.nil? == false
397
+ if x.a < y.a
398
+ return -1
399
+ elsif x.a > y.a
400
+ return 1
401
+ end
402
+ end
403
+
404
+ return 0
405
+ end
406
+
407
+ def to_s
408
+ nevra
409
+ end
410
+
411
+ def nevra
412
+ "#{@n}-#{@version.evr}.#{@a}"
413
+ end
414
+ end
415
+
416
+ # Simple implementation from rpm and ruby-rpm reference code
417
+ class RPMDependency
418
+ def initialize(*args)
419
+ if args.size == 3
420
+ @name = args[0]
421
+ @version = RPMVersion.new(args[1])
422
+ # Our requirement to other dependencies
423
+ @flag = args[2] || :==
424
+ elsif args.size == 5
425
+ @name = args[0]
426
+ e = args[1].to_i
427
+ v = args[2]
428
+ r = args[3]
429
+ @version = RPMVersion.new(e,v,r)
430
+ @flag = args[4] || :==
431
+ else
432
+ raise ArgumentError, "Expecting either 'name, epoch-version-release, flag' or " +
433
+ "'name, epoch, version, release, flag'"
434
+ end
435
+ end
436
+ attr_reader :name, :version, :flag
437
+
438
+ # Parses 2 forms:
439
+ #
440
+ # "mtr >= 2:0.71-3.0"
441
+ # "mta"
442
+ def self.parse(string)
443
+ if string =~ %r{^(\S+)\s+(>|>=|=|==|<=|<)\s+(\S+)$}
444
+ name = $1
445
+ if $2 == "="
446
+ flag = :==
447
+ else
448
+ flag = :"#{$2}"
449
+ end
450
+ version = $3
451
+
452
+ return self.new(name, version, flag)
453
+ else
454
+ name = string
455
+ return self.new(name, nil, nil)
456
+ end
457
+ end
458
+
459
+ # Test if another RPMDependency satisfies our requirements
460
+ def satisfy?(y)
461
+ unless y.kind_of?(RPMDependency)
462
+ raise ArgumentError, "Expecting an RPMDependency object"
463
+ end
464
+
465
+ x = self
466
+
467
+ # Easy!
468
+ if x.name != y.name
469
+ return false
470
+ end
471
+
472
+ # Partial compare
473
+ #
474
+ # eg: x.version 2.3 == y.version 2.3-1
475
+ sense = x.version.partial_compare(y.version)
476
+
477
+ # Thanks to rpmdsCompare() rpmds.c
478
+ if sense < 0 and (x.flag == :> || x.flag == :>=) || (y.flag == :<= || y.flag == :<)
479
+ return true
480
+ elsif sense > 0 and (x.flag == :< || x.flag == :<=) || (y.flag == :>= || y.flag == :>)
481
+ return true
482
+ elsif sense == 0 and (
483
+ ((x.flag == :== or x.flag == :<= or x.flag == :>=) and (y.flag == :== or y.flag == :<= or y.flag == :>=)) or
484
+ (x.flag == :< and y.flag == :<) or
485
+ (x.flag == :> and y.flag == :>)
486
+ )
487
+ return true
488
+ end
489
+
490
+ return false
491
+ end
492
+ end
493
+
494
+ class RPMProvide < RPMDependency; end
495
+ class RPMRequire < RPMDependency; end
496
+
497
+ class RPMDbPackage < RPMPackage
498
+ # <rpm parts>, installed, available
499
+ def initialize(*args)
500
+ # state
501
+ @available = args.pop
502
+ @installed = args.pop
503
+ super(*args)
504
+ end
505
+ attr_reader :available, :installed
506
+ end
507
+
508
+ # Simple storage for RPMPackage objects - keeps them unique and sorted
509
+ class RPMDb
510
+ def initialize
511
+ # package name => [ RPMPackage, RPMPackage ] of different versions
512
+ @rpms = Hash.new
513
+ # package nevra => RPMPackage for lookups
514
+ @index = Hash.new
515
+ # provide name (aka feature) => [RPMPackage, RPMPackage] each providing this feature
516
+ @provides = Hash.new
517
+ # RPMPackages listed as available
518
+ @available = Set.new
519
+ # RPMPackages listed as installed
520
+ @installed = Set.new
521
+ end
522
+
523
+ def [](package_name)
524
+ self.lookup(package_name)
525
+ end
526
+
527
+ # Lookup package_name and return a descending array of package objects
528
+ def lookup(package_name)
529
+ pkgs = @rpms[package_name]
530
+ if pkgs
531
+ return pkgs.sort.reverse
532
+ else
533
+ return nil
534
+ end
535
+ end
536
+
537
+ def lookup_provides(provide_name)
538
+ @provides[provide_name]
539
+ end
540
+
541
+ # Using the package name as a key, and nevra for an index, keep a unique list of packages.
542
+ # The available/installed state can be overwritten for existing packages.
543
+ def push(*args)
544
+ args.flatten.each do |new_rpm|
545
+ unless new_rpm.kind_of?(RPMDbPackage)
546
+ raise ArgumentError, "Expecting an RPMDbPackage object"
547
+ end
548
+
549
+ @rpms[new_rpm.n] ||= Array.new
550
+
551
+ # we may already have this one, like when the installed list is refreshed
552
+ idx = @index[new_rpm.nevra]
553
+ if idx
554
+ # grab the existing package if it's not
555
+ curr_rpm = idx
556
+ else
557
+ @rpms[new_rpm.n] << new_rpm
558
+
559
+ new_rpm.provides.each do |provide|
560
+ @provides[provide.name] ||= Array.new
561
+ @provides[provide.name] << new_rpm
562
+ end
563
+
564
+ curr_rpm = new_rpm
565
+ end
566
+
567
+ # Track the nevra -> RPMPackage association to avoid having to compare versions
568
+ # with @rpms[new_rpm.n] on the next round
569
+ @index[new_rpm.nevra] = curr_rpm
570
+
571
+ # these are overwritten for existing packages
572
+ if new_rpm.available
573
+ @available << curr_rpm
574
+ end
575
+ if new_rpm.installed
576
+ @installed << curr_rpm
577
+ end
578
+ end
579
+ end
580
+
581
+ def <<(*args)
582
+ self.push(args)
583
+ end
584
+
585
+ def clear
586
+ @rpms.clear
587
+ @index.clear
588
+ @provides.clear
589
+ clear_available
590
+ clear_installed
591
+ end
592
+
593
+ def clear_available
594
+ @available.clear
595
+ end
596
+
597
+ def clear_installed
598
+ @installed.clear
599
+ end
600
+
601
+ def size
602
+ @rpms.size
603
+ end
604
+ alias :length :size
605
+
606
+ def available_size
607
+ @available.size
608
+ end
609
+
610
+ def installed_size
611
+ @installed.size
612
+ end
613
+
614
+ def available?(package)
615
+ @available.include?(package)
616
+ end
617
+
618
+ def installed?(package)
619
+ @installed.include?(package)
620
+ end
621
+
622
+ def whatprovides(rpmdep)
623
+ unless rpmdep.kind_of?(RPMDependency)
624
+ raise ArgumentError, "Expecting an RPMDependency object"
625
+ end
626
+
627
+ what = []
628
+
629
+ packages = lookup_provides(rpmdep.name)
630
+ if packages
631
+ packages.each do |pkg|
632
+ pkg.provides.each do |provide|
633
+ if provide.satisfy?(rpmdep)
634
+ what << pkg
635
+ end
636
+ end
637
+ end
638
+ end
639
+
640
+ return what
641
+ end
642
+ end
643
+
644
+ # Cache for our installed and available packages, pulled in from yum-dump.py
645
+ class YumCache
646
+ include Chef::Mixin::Command
647
+ include Singleton
648
+
649
+ def initialize
650
+ @rpmdb = RPMDb.new
651
+
652
+ # Next time @rpmdb is accessed:
653
+ # :all - Trigger a run of "yum-dump.py --options --installed-provides", updates
654
+ # yum's cache and parses options from /etc/yum.conf. Pulls in Provides
655
+ # dependency data for installed packages only - this data is slow to
656
+ # gather.
657
+ # :provides - Same as :all but pulls in Provides data for available packages as well.
658
+ # Used as a last resort when we can't find a Provides match.
659
+ # :installed - Trigger a run of "yum-dump.py --installed", only reads the local rpm
660
+ # db. Used between client runs for a quick refresh.
661
+ # :none - Do nothing, a call to one of the reload methods is required.
662
+ @next_refresh = :all
663
+
664
+ @allow_multi_install = []
665
+
666
+ # these are for subsequent runs if we are on an interval
667
+ Chef::Client.when_run_starts do
668
+ YumCache.instance.reload
669
+ end
670
+ end
671
+
672
+ # Cache management
673
+ #
674
+
675
+ def refresh
676
+ case @next_refresh
677
+ when :none
678
+ return nil
679
+ when :installed
680
+ reset_installed
681
+ # fast
682
+ opts=" --installed"
683
+ when :all
684
+ reset
685
+ # medium
686
+ opts=" --options --installed-provides"
687
+ when :provides
688
+ reset
689
+ # slow!
690
+ opts=" --options --all-provides"
691
+ else
692
+ raise ArgumentError, "Unexpected value in next_refresh: #{@next_refresh}"
693
+ end
694
+
695
+ one_line = false
696
+ error = nil
697
+
698
+ helper = ::File.join(::File.dirname(__FILE__), 'yum-dump.py')
699
+
700
+ status = popen4("/usr/bin/python #{helper}#{opts}", :waitlast => true) do |pid, stdin, stdout, stderr|
701
+ stdout.each do |line|
702
+ one_line = true
703
+
704
+ line.chomp!
705
+
706
+ if line =~ %r{\[option (.*)\] (.*)}
707
+ if $1 == "installonlypkgs"
708
+ @allow_multi_install = $2.split
709
+ else
710
+ raise Chef::Exceptions::Package, "Strange, unknown option line '#{line}' from yum-dump.py"
711
+ end
712
+ next
713
+ end
714
+
715
+ if line =~ %r{^(\S+) ([0-9]+) (\S+) (\S+) (\S+) \[(.*)\] ([i,a,r])$}
716
+ name = $1
717
+ epoch = $2
718
+ version = $3
719
+ release = $4
720
+ arch = $5
721
+ provides = parse_provides($6)
722
+ type = $7
723
+ else
724
+ Chef::Log.warn("Problem parsing line '#{line}' from yum-dump.py! " +
725
+ "Please check your yum configuration.")
726
+ next
727
+ end
728
+
729
+ case type
730
+ when "i"
731
+ # if yum-dump was called with --installed this may not be true, but it's okay
732
+ # since we don't touch the @available Set in reload_installed
733
+ available = false
734
+ installed = true
735
+ when "a"
736
+ available = true
737
+ installed = false
738
+ when "r"
739
+ available = true
740
+ installed = true
741
+ end
742
+
743
+ pkg = RPMDbPackage.new(name, epoch, version, release, arch, provides, installed, available)
744
+ @rpmdb << pkg
745
+ end
746
+
747
+ error = stderr.readlines
748
+ end
749
+
750
+ if status.exitstatus != 0
751
+ raise Chef::Exceptions::Package, "Yum failed - #{status.inspect} - returns: #{error}"
752
+ else
753
+ unless one_line
754
+ Chef::Log.warn("Odd, no output from yum-dump.py. Please check " +
755
+ "your yum configuration.")
756
+ end
757
+ end
758
+
759
+ # A reload method must be called before the cache is altered
760
+ @next_refresh = :none
761
+ end
762
+
763
+ def reload
764
+ @next_refresh = :all
765
+ end
766
+
767
+ def reload_installed
768
+ @next_refresh = :installed
769
+ end
770
+
771
+ def reload_provides
772
+ @next_refresh = :provides
773
+ end
774
+
775
+ def reset
776
+ @rpmdb.clear
777
+ end
778
+
779
+ def reset_installed
780
+ @rpmdb.clear_installed
781
+ end
782
+
783
+ # Querying the cache
784
+ #
785
+
786
+ # Check for package by name or name+arch
787
+ def package_available?(package_name)
788
+ refresh
789
+
790
+ if @rpmdb.lookup(package_name)
791
+ return true
792
+ else
793
+ if package_name =~ %r{^(.*)\.(.*)$}
794
+ pkg_name = $1
795
+ pkg_arch = $2
796
+
797
+ if matches = @rpmdb.lookup(pkg_name)
798
+ matches.each do |m|
799
+ return true if m.arch == pkg_arch
800
+ end
801
+ end
802
+ end
803
+ end
804
+
805
+ return false
806
+ end
807
+
808
+ # Returns a array of packages satisfying an RPMDependency
809
+ def packages_from_require(rpmdep)
810
+ refresh
811
+ @rpmdb.whatprovides(rpmdep)
812
+ end
813
+
814
+ def version_available?(package_name, desired_version, arch=nil)
815
+ version(package_name, arch, true, false) do |v|
816
+ return true if desired_version == v
817
+ end
818
+
819
+ return false
820
+ end
821
+
822
+ def available_version(package_name, arch=nil)
823
+ version(package_name, arch, true, false)
824
+ end
825
+ alias :candidate_version :available_version
826
+
827
+ def installed_version(package_name, arch=nil)
828
+ version(package_name, arch, false, true)
829
+ end
830
+
831
+ def allow_multi_install
832
+ refresh
833
+ @allow_multi_install
834
+ end
835
+
836
+ private
837
+
838
+ def version(package_name, arch=nil, is_available=false, is_installed=false)
839
+ refresh
840
+ packages = @rpmdb[package_name]
841
+ if packages
842
+ packages.each do |pkg|
843
+ if is_available
844
+ next unless @rpmdb.available?(pkg)
845
+ end
846
+ if is_installed
847
+ next unless @rpmdb.installed?(pkg)
848
+ end
849
+ if arch
850
+ next unless pkg.arch == arch
851
+ end
852
+
853
+ if block_given?
854
+ yield pkg.version.to_s
855
+ else
856
+ # first match is latest version
857
+ return pkg.version.to_s
858
+ end
859
+ end
860
+ end
861
+
862
+ if block_given?
863
+ return self
864
+ else
865
+ return nil
866
+ end
867
+ end
868
+
869
+ # Parse provides from yum-dump.py output
870
+ def parse_provides(string)
871
+ ret = []
872
+ # ['atk = 1.12.2-1.fc6', 'libatk-1.0.so.0']
873
+ string.split(", ").each do |seg|
874
+ # 'atk = 1.12.2-1.fc6'
875
+ if seg =~ %r{^'(.*)'$}
876
+ ret << RPMProvide.parse($1)
877
+ end
878
+ end
879
+
880
+ return ret
881
+ end
882
+
883
+ end # YumCache
884
+
885
+ include Chef::Mixin::GetSourceFromPackage
886
+
887
+ def initialize(new_resource, run_context)
888
+ super
889
+
890
+ @yum = YumCache.instance
891
+ end
892
+
893
+ # Extra attributes
894
+ #
895
+
896
+ def arch
897
+ if @new_resource.respond_to?("arch")
898
+ @new_resource.arch
899
+ else
900
+ nil
901
+ end
902
+ end
903
+
904
+ def flush_cache
905
+ if @new_resource.respond_to?("flush_cache")
906
+ @new_resource.flush_cache
907
+ else
908
+ { :before => false, :after => false }
909
+ end
910
+ end
911
+
912
+ def allow_downgrade
913
+ if @new_resource.respond_to?("allow_downgrade")
914
+ @new_resource.allow_downgrade
915
+ else
916
+ false
917
+ end
918
+ end
919
+
920
+ # Helpers
921
+ #
922
+
923
+ def yum_arch
924
+ arch ? ".#{arch}" : nil
925
+ end
926
+
927
+ def yum_command(command)
928
+ status, stdout, stderr = output_of_command(command, {})
929
+
930
+ # This is fun: rpm can encounter errors in the %post/%postun scripts which aren't
931
+ # considered fatal - meaning the rpm is still successfully installed. These issue
932
+ # cause yum to emit a non fatal warning but still exit(1). As there's currently no
933
+ # way to suppress this behavior and an exit(1) will break a Chef run we make an
934
+ # effort to trap these and re-run the same install command - it will either fail a
935
+ # second time or succeed.
936
+ #
937
+ # A cleaner solution would have to be done in python and better hook into
938
+ # yum/rpm to handle exceptions as we see fit.
939
+ if status.exitstatus == 1
940
+ stdout.each_line do |l|
941
+ # rpm-4.4.2.3 lib/psm.c line 2182
942
+ if l =~ %r{^error: %(post|postun)\(.*\) scriptlet failed, exit status \d+$}
943
+ Chef::Log.warn("#{@new_resource} caught non-fatal scriptlet issue: \"#{l}\". Can't trust yum exit status " +
944
+ "so running install again to verify.")
945
+ status, stdout, stderr = output_of_command(command, {})
946
+ break
947
+ end
948
+ end
949
+ end
950
+
951
+ if status.exitstatus > 0
952
+ command_output = "STDOUT: #{stdout}"
953
+ command_output << "STDERR: #{stderr}"
954
+ handle_command_failures(status, command_output, {})
955
+ end
956
+ end
957
+
958
+ # Standard Provider methods for Parent
959
+ #
960
+
961
+ def load_current_resource
962
+ if flush_cache[:before]
963
+ @yum.reload
964
+ end
965
+
966
+ # At this point package_name could be:
967
+ #
968
+ # 1) a package name, eg: "foo"
969
+ # 2) a package name.arch, eg: "foo.i386"
970
+ # 3) or a dependency, eg: "foo >= 1.1"
971
+
972
+ # Check if we have name or name+arch which has a priority over a dependency
973
+ unless @yum.package_available?(@new_resource.package_name)
974
+ # If they aren't in the installed packages they could be a dependency
975
+ parse_dependency
976
+ end
977
+
978
+ # Don't overwrite an existing arch
979
+ unless arch
980
+ parse_arch
981
+ end
982
+
983
+ @current_resource = Chef::Resource::Package.new(@new_resource.name)
984
+ @current_resource.package_name(@new_resource.package_name)
985
+
986
+ if @new_resource.source
987
+ unless ::File.exists?(@new_resource.source)
988
+ raise Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}"
989
+ end
990
+
991
+ Chef::Log.debug("#{@new_resource} checking rpm status")
992
+ status = popen4("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}") do |pid, stdin, stdout, stderr|
993
+ stdout.each do |line|
994
+ case line
995
+ when /([\w\d_.-]+)\s([\w\d_.-]+)/
996
+ @current_resource.package_name($1)
997
+ @new_resource.version($2)
998
+ end
999
+ end
1000
+ end
1001
+ end
1002
+
1003
+ if @new_resource.version
1004
+ new_resource = "#{@new_resource.package_name}-#{@new_resource.version}#{yum_arch}"
1005
+ else
1006
+ new_resource = "#{@new_resource.package_name}#{yum_arch}"
1007
+ end
1008
+
1009
+ Chef::Log.debug("#{@new_resource} checking yum info for #{new_resource}")
1010
+
1011
+ installed_version = @yum.installed_version(@new_resource.package_name, arch)
1012
+ @current_resource.version(installed_version)
1013
+
1014
+ @candidate_version = @yum.candidate_version(@new_resource.package_name, arch)
1015
+
1016
+ Chef::Log.debug("#{@new_resource} installed version: #{installed_version || "(none)"} candidate version: " +
1017
+ "#{@candidate_version || "(none)"}")
1018
+
1019
+ @current_resource
1020
+ end
1021
+
1022
+ def install_package(name, version)
1023
+ if @new_resource.source
1024
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} localinstall #{@new_resource.source}")
1025
+ else
1026
+ # Work around yum not exiting with an error if a package doesn't exist for CHEF-2062
1027
+ if @yum.version_available?(name, version, arch)
1028
+ method = "install"
1029
+
1030
+ # More Yum fun:
1031
+ #
1032
+ # yum install of an old name+version will exit(1)
1033
+ # yum install of an old name+version+arch will exit(0) for some reason
1034
+ #
1035
+ # Some packages can be installed multiple times like the kernel
1036
+ unless @yum.allow_multi_install.include?(name)
1037
+ if RPMVersion.parse(@current_resource.version) > RPMVersion.parse(version)
1038
+ # Unless they want this...
1039
+ if allow_downgrade
1040
+ method = "downgrade"
1041
+ else
1042
+ # we bail like yum when the package is older
1043
+ raise Chef::Exceptions::Package, "Installed package #{name}-#{@current_resource.version} is newer " +
1044
+ "than candidate package #{name}-#{version}"
1045
+ end
1046
+ end
1047
+ end
1048
+
1049
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} #{method} #{name}-#{version}#{yum_arch}")
1050
+ else
1051
+ raise Chef::Exceptions::Package, "Version #{version} of #{name} not found. Did you specify both version " +
1052
+ "and release? (version-release, e.g. 1.84-10.fc6)"
1053
+ end
1054
+ end
1055
+ if flush_cache[:after]
1056
+ @yum.reload
1057
+ else
1058
+ @yum.reload_installed
1059
+ end
1060
+ end
1061
+
1062
+ # Keep upgrades from trying to install an older candidate version. Can happen when a new
1063
+ # version is installed then removed from a repository, now the older available version
1064
+ # shows up as a viable install candidate.
1065
+ #
1066
+ # Can be done in upgrade_package but an upgraded from->to log message slips out
1067
+ #
1068
+ # Hacky - better overall solution? Custom compare in Package provider?
1069
+ def action_upgrade
1070
+ # Ensure the candidate is newer
1071
+ if RPMVersion.parse(candidate_version) > RPMVersion.parse(@current_resource.version)
1072
+ super
1073
+ # Candidate is older
1074
+ else
1075
+ Chef::Log.debug("#{@new_resource} is at the latest version - nothing to do")
1076
+ end
1077
+ end
1078
+
1079
+ def upgrade_package(name, version)
1080
+ install_package(name, version)
1081
+ end
1082
+
1083
+ def remove_package(name, version)
1084
+ if version
1085
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}-#{version}#{yum_arch}")
1086
+ else
1087
+ yum_command("yum -d0 -e0 -y#{expand_options(@new_resource.options)} remove #{name}#{yum_arch}")
1088
+ end
1089
+ if flush_cache[:after]
1090
+ @yum.reload
1091
+ else
1092
+ @yum.reload_installed
1093
+ end
1094
+ end
1095
+
1096
+ def purge_package(name, version)
1097
+ remove_package(name, version)
1098
+ end
1099
+
1100
+ private
1101
+
1102
+ def parse_arch
1103
+ # Allow for foo.x86_64 style package_name like yum uses in it's output
1104
+ #
1105
+ if @new_resource.package_name =~ %r{^(.*)\.(.*)$}
1106
+ new_package_name = $1
1107
+ new_arch = $2
1108
+ # foo.i386 and foo.beta1 are both valid package names or expressions of an arch.
1109
+ # Ensure we don't have an existing package matching package_name, then ensure we at
1110
+ # least have a match for the new_package+new_arch before we overwrite. If neither
1111
+ # then fall through to standard package handling.
1112
+ if (@yum.installed_version(@new_resource.package_name).nil? and @yum.candidate_version(@new_resource.package_name).nil?) and
1113
+ (@yum.installed_version(new_package_name, new_arch) or @yum.candidate_version(new_package_name, new_arch))
1114
+ @new_resource.package_name(new_package_name)
1115
+ @new_resource.arch(new_arch)
1116
+ end
1117
+ end
1118
+ end
1119
+
1120
+ # If we don't have the package we could have been passed a 'whatprovides' feature
1121
+ #
1122
+ # eg: yum install "perl(Config)"
1123
+ # yum install "mtr = 2:0.71-3.1"
1124
+ # yum install "mtr > 2:0.71"
1125
+ #
1126
+ # We support resolving these out of the Provides data imported from yum-dump.py and
1127
+ # matching them up with an actual package so the standard resource handling can apply.
1128
+ #
1129
+ # There is currently no support for filename matching.
1130
+ def parse_dependency
1131
+ # Transform the package_name into a requirement
1132
+ yum_require = RPMRequire.parse(@new_resource.package_name)
1133
+ # and gather all the packages that have a Provides feature satisfying the requirement.
1134
+ # It could be multiple be we can only manage one
1135
+ packages = @yum.packages_from_require(yum_require)
1136
+
1137
+ if packages.empty?
1138
+ # Don't bother if we are just ensuring a package is removed - we don't need Provides data
1139
+ actions = Array(@new_resource.action)
1140
+ unless actions.size == 1 and (actions[0] == :remove || actions[0] == :purge)
1141
+ Chef::Log.debug("#{@new_resource} couldn't match #{@new_resource.package_name} in " +
1142
+ "installed Provides, loading available Provides - this may take a moment")
1143
+ @yum.reload_provides
1144
+ packages = @yum.packages_from_require(yum_require)
1145
+ end
1146
+ end
1147
+
1148
+ unless packages.empty?
1149
+ new_package_name = packages.first.name
1150
+ Chef::Log.debug("#{@new_resource} no package found for #{@new_resource.package_name} " +
1151
+ "but matched Provides for #{new_package_name}")
1152
+
1153
+ # Ensure it's not the same package under a different architecture
1154
+ unique_names = []
1155
+ packages.each do |pkg|
1156
+ unique_names << "#{pkg.name}-#{pkg.version.evr}"
1157
+ end
1158
+ unique_names.uniq!
1159
+
1160
+ if unique_names.size > 1
1161
+ Chef::Log.warn("#{@new_resource} matched multiple Provides for #{@new_resource.package_name} " +
1162
+ "but we can only use the first match: #{new_package_name}. Please use a more " +
1163
+ "specific version.")
1164
+ end
1165
+
1166
+ @new_resource.package_name(new_package_name)
1167
+ end
1168
+ end
1169
+
1170
+ end
1171
+ end
1172
+ end
1173
+ end