mbailey-chef 0.9.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (345) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +172 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +25 -0
  5. data/bin/knife +26 -0
  6. data/bin/shef +34 -0
  7. data/distro/README +2 -0
  8. data/distro/common/man/man1/chef-indexer.1 +42 -0
  9. data/distro/common/man/man1/chef-server-webui.1 +106 -0
  10. data/distro/common/man/man1/chef-server.1 +107 -0
  11. data/distro/common/man/man1/chef-solr-indexer.1 +55 -0
  12. data/distro/common/man/man1/chef-solr.1 +55 -0
  13. data/distro/common/man/man8/chef-client.8 +63 -0
  14. data/distro/common/man/man8/chef-solo.8 +57 -0
  15. data/distro/common/man/man8/chef-solr-rebuild.8 +37 -0
  16. data/distro/common/man/man8/knife.8 +1349 -0
  17. data/distro/common/man/man8/shef.8 +45 -0
  18. data/distro/common/markdown/README +3 -0
  19. data/distro/common/markdown/knife.mkd +832 -0
  20. data/distro/debian/etc/default/chef-client +4 -0
  21. data/distro/debian/etc/default/chef-server +9 -0
  22. data/distro/debian/etc/default/chef-server-webui +9 -0
  23. data/distro/debian/etc/default/chef-solr +7 -0
  24. data/distro/debian/etc/default/chef-solr-indexer +7 -0
  25. data/distro/debian/etc/init/chef-client.conf +17 -0
  26. data/distro/debian/etc/init/chef-server-webui.conf +17 -0
  27. data/distro/debian/etc/init/chef-server.conf +17 -0
  28. data/distro/debian/etc/init/chef-solr-indexer.conf +17 -0
  29. data/distro/debian/etc/init/chef-solr.conf +17 -0
  30. data/distro/debian/etc/init.d/chef-client +175 -0
  31. data/distro/debian/etc/init.d/chef-server +122 -0
  32. data/distro/debian/etc/init.d/chef-server-webui +123 -0
  33. data/distro/debian/etc/init.d/chef-solr +177 -0
  34. data/distro/debian/etc/init.d/chef-solr-indexer +176 -0
  35. data/distro/redhat/etc/init.d/chef-client +106 -0
  36. data/distro/redhat/etc/init.d/chef-server +112 -0
  37. data/distro/redhat/etc/init.d/chef-server-webui +112 -0
  38. data/distro/redhat/etc/init.d/chef-solr +104 -0
  39. data/distro/redhat/etc/init.d/chef-solr-indexer +104 -0
  40. data/distro/redhat/etc/logrotate.d/chef-client +8 -0
  41. data/distro/redhat/etc/logrotate.d/chef-server +8 -0
  42. data/distro/redhat/etc/logrotate.d/chef-server-webui +8 -0
  43. data/distro/redhat/etc/logrotate.d/chef-solr +8 -0
  44. data/distro/redhat/etc/logrotate.d/chef-solr-indexer +8 -0
  45. data/distro/redhat/etc/sysconfig/chef-client +15 -0
  46. data/distro/redhat/etc/sysconfig/chef-server +14 -0
  47. data/distro/redhat/etc/sysconfig/chef-server-webui +14 -0
  48. data/distro/redhat/etc/sysconfig/chef-solr +8 -0
  49. data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
  50. data/lib/chef/api_client.rb +264 -0
  51. data/lib/chef/application/agent.rb +18 -0
  52. data/lib/chef/application/client.rb +246 -0
  53. data/lib/chef/application/knife.rb +171 -0
  54. data/lib/chef/application/solo.rb +215 -0
  55. data/lib/chef/application.rb +127 -0
  56. data/lib/chef/applications.rb +4 -0
  57. data/lib/chef/certificate.rb +194 -0
  58. data/lib/chef/checksum.rb +182 -0
  59. data/lib/chef/checksum_cache.rb +173 -0
  60. data/lib/chef/client.rb +304 -0
  61. data/lib/chef/config.rb +240 -0
  62. data/lib/chef/cookbook/cookbook_collection.rb +44 -0
  63. data/lib/chef/cookbook/file_system_file_vendor.rb +54 -0
  64. data/lib/chef/cookbook/file_vendor.rb +48 -0
  65. data/lib/chef/cookbook/metadata/version.rb +87 -0
  66. data/lib/chef/cookbook/metadata.rb +500 -0
  67. data/lib/chef/cookbook/remote_file_vendor.rb +87 -0
  68. data/lib/chef/cookbook/syntax_check.rb +136 -0
  69. data/lib/chef/cookbook_loader.rb +227 -0
  70. data/lib/chef/cookbook_site_streaming_uploader.rb +244 -0
  71. data/lib/chef/cookbook_uploader.rb +103 -0
  72. data/lib/chef/cookbook_version.rb +930 -0
  73. data/lib/chef/couchdb.rb +239 -0
  74. data/lib/chef/daemon.rb +172 -0
  75. data/lib/chef/data_bag.rb +215 -0
  76. data/lib/chef/data_bag_item.rb +228 -0
  77. data/lib/chef/exceptions.rb +66 -0
  78. data/lib/chef/file_access_control.rb +140 -0
  79. data/lib/chef/file_cache.rb +218 -0
  80. data/lib/chef/handler/json_file.rb +58 -0
  81. data/lib/chef/handler.rb +206 -0
  82. data/lib/chef/index_queue/amqp_client.rb +113 -0
  83. data/lib/chef/index_queue/consumer.rb +76 -0
  84. data/lib/chef/index_queue/indexable.rb +76 -0
  85. data/lib/chef/index_queue.rb +29 -0
  86. data/lib/chef/knife/bootstrap/archlinux-gems.erb +44 -0
  87. data/lib/chef/knife/bootstrap/centos5-gems.erb +41 -0
  88. data/lib/chef/knife/bootstrap/client-install.vbs +80 -0
  89. data/lib/chef/knife/bootstrap/fedora13-gems.erb +38 -0
  90. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +32 -0
  91. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +43 -0
  92. data/lib/chef/knife/bootstrap/windows-gems.erb +34 -0
  93. data/lib/chef/knife/bootstrap.rb +181 -0
  94. data/lib/chef/knife/client_bulk_delete.rb +40 -0
  95. data/lib/chef/knife/client_create.rb +70 -0
  96. data/lib/chef/knife/client_delete.rb +45 -0
  97. data/lib/chef/knife/client_edit.rb +45 -0
  98. data/lib/chef/knife/client_list.rb +40 -0
  99. data/lib/chef/knife/client_reregister.rb +56 -0
  100. data/lib/chef/knife/client_show.rb +50 -0
  101. data/lib/chef/knife/configure.rb +140 -0
  102. data/lib/chef/knife/configure_client.rb +52 -0
  103. data/lib/chef/knife/cookbook_bulk_delete.rb +58 -0
  104. data/lib/chef/knife/cookbook_create.rb +209 -0
  105. data/lib/chef/knife/cookbook_delete.rb +143 -0
  106. data/lib/chef/knife/cookbook_download.rb +130 -0
  107. data/lib/chef/knife/cookbook_list.rb +41 -0
  108. data/lib/chef/knife/cookbook_metadata.rb +82 -0
  109. data/lib/chef/knife/cookbook_metadata_from_file.rb +40 -0
  110. data/lib/chef/knife/cookbook_show.rb +98 -0
  111. data/lib/chef/knife/cookbook_site_download.rb +58 -0
  112. data/lib/chef/knife/cookbook_site_list.rb +56 -0
  113. data/lib/chef/knife/cookbook_site_search.rb +51 -0
  114. data/lib/chef/knife/cookbook_site_share.rb +109 -0
  115. data/lib/chef/knife/cookbook_site_show.rb +57 -0
  116. data/lib/chef/knife/cookbook_site_unshare.rb +52 -0
  117. data/lib/chef/knife/cookbook_site_vendor.rb +133 -0
  118. data/lib/chef/knife/cookbook_test.rb +82 -0
  119. data/lib/chef/knife/cookbook_upload.rb +95 -0
  120. data/lib/chef/knife/data_bag_create.rb +59 -0
  121. data/lib/chef/knife/data_bag_delete.rb +48 -0
  122. data/lib/chef/knife/data_bag_edit.rb +50 -0
  123. data/lib/chef/knife/data_bag_from_file.rb +44 -0
  124. data/lib/chef/knife/data_bag_list.rb +43 -0
  125. data/lib/chef/knife/data_bag_show.rb +41 -0
  126. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  127. data/lib/chef/knife/ec2_server_create.rb +216 -0
  128. data/lib/chef/knife/ec2_server_delete.rb +90 -0
  129. data/lib/chef/knife/ec2_server_list.rb +88 -0
  130. data/lib/chef/knife/exec.rb +52 -0
  131. data/lib/chef/knife/index_rebuild.rb +51 -0
  132. data/lib/chef/knife/node_bulk_delete.rb +43 -0
  133. data/lib/chef/knife/node_create.rb +47 -0
  134. data/lib/chef/knife/node_delete.rb +44 -0
  135. data/lib/chef/knife/node_edit.rb +44 -0
  136. data/lib/chef/knife/node_from_file.rb +42 -0
  137. data/lib/chef/knife/node_list.rb +41 -0
  138. data/lib/chef/knife/node_run_list_add.rb +64 -0
  139. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  140. data/lib/chef/knife/node_show.rb +54 -0
  141. data/lib/chef/knife/rackspace_server_create.rb +156 -0
  142. data/lib/chef/knife/rackspace_server_delete.rb +57 -0
  143. data/lib/chef/knife/rackspace_server_list.rb +59 -0
  144. data/lib/chef/knife/recipe_list.rb +32 -0
  145. data/lib/chef/knife/role_bulk_delete.rb +44 -0
  146. data/lib/chef/knife/role_create.rb +52 -0
  147. data/lib/chef/knife/role_delete.rb +44 -0
  148. data/lib/chef/knife/role_edit.rb +45 -0
  149. data/lib/chef/knife/role_from_file.rb +46 -0
  150. data/lib/chef/knife/role_list.rb +40 -0
  151. data/lib/chef/knife/role_show.rb +51 -0
  152. data/lib/chef/knife/search.rb +94 -0
  153. data/lib/chef/knife/slicehost_images_list.rb +53 -0
  154. data/lib/chef/knife/slicehost_server_create.rb +103 -0
  155. data/lib/chef/knife/slicehost_server_delete.rb +61 -0
  156. data/lib/chef/knife/slicehost_server_list.rb +64 -0
  157. data/lib/chef/knife/ssh.rb +328 -0
  158. data/lib/chef/knife/status.rb +87 -0
  159. data/lib/chef/knife/terremark_server_create.rb +152 -0
  160. data/lib/chef/knife/terremark_server_delete.rb +87 -0
  161. data/lib/chef/knife/terremark_server_list.rb +77 -0
  162. data/lib/chef/knife/windows_bootstrap.rb +154 -0
  163. data/lib/chef/knife.rb +522 -0
  164. data/lib/chef/log.rb +61 -0
  165. data/lib/chef/mixin/check_helper.rb +31 -0
  166. data/lib/chef/mixin/checksum.rb +32 -0
  167. data/lib/chef/mixin/command/unix.rb +215 -0
  168. data/lib/chef/mixin/command/windows.rb +72 -0
  169. data/lib/chef/mixin/command.rb +220 -0
  170. data/lib/chef/mixin/convert_to_class_name.rb +63 -0
  171. data/lib/chef/mixin/create_path.rb +56 -0
  172. data/lib/chef/mixin/deep_merge.rb +225 -0
  173. data/lib/chef/mixin/deprecation.rb +65 -0
  174. data/lib/chef/mixin/find_preferred_file.rb +92 -0
  175. data/lib/chef/mixin/from_file.rb +50 -0
  176. data/lib/chef/mixin/language.rb +156 -0
  177. data/lib/chef/mixin/language_include_attribute.rb +61 -0
  178. data/lib/chef/mixin/language_include_recipe.rb +52 -0
  179. data/lib/chef/mixin/params_validate.rb +225 -0
  180. data/lib/chef/mixin/recipe_definition_dsl_core.rb +81 -0
  181. data/lib/chef/mixin/shell_out.rb +38 -0
  182. data/lib/chef/mixin/template.rb +95 -0
  183. data/lib/chef/mixin/xml_escape.rb +140 -0
  184. data/lib/chef/mixins.rb +16 -0
  185. data/lib/chef/monkey_patches/dir.rb +36 -0
  186. data/lib/chef/monkey_patches/string.rb +28 -0
  187. data/lib/chef/monkey_patches/tempfile.rb +64 -0
  188. data/lib/chef/node/attribute.rb +465 -0
  189. data/lib/chef/node.rb +601 -0
  190. data/lib/chef/openid_registration.rb +187 -0
  191. data/lib/chef/platform.rb +371 -0
  192. data/lib/chef/provider/breakpoint.rb +36 -0
  193. data/lib/chef/provider/cookbook_file.rb +100 -0
  194. data/lib/chef/provider/cron/solaris.rb +195 -0
  195. data/lib/chef/provider/cron.rb +186 -0
  196. data/lib/chef/provider/deploy/revision.rb +73 -0
  197. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  198. data/lib/chef/provider/deploy.rb +319 -0
  199. data/lib/chef/provider/directory.rb +72 -0
  200. data/lib/chef/provider/env/windows.rb +75 -0
  201. data/lib/chef/provider/env.rb +152 -0
  202. data/lib/chef/provider/erl_call.rb +72 -0
  203. data/lib/chef/provider/execute.rb +58 -0
  204. data/lib/chef/provider/file.rb +213 -0
  205. data/lib/chef/provider/git.rb +211 -0
  206. data/lib/chef/provider/group/dscl.rb +121 -0
  207. data/lib/chef/provider/group/gpasswd.rb +53 -0
  208. data/lib/chef/provider/group/groupadd.rb +78 -0
  209. data/lib/chef/provider/group/pw.rb +84 -0
  210. data/lib/chef/provider/group/usermod.rb +57 -0
  211. data/lib/chef/provider/group/windows.rb +79 -0
  212. data/lib/chef/provider/group.rb +133 -0
  213. data/lib/chef/provider/http_request.rb +122 -0
  214. data/lib/chef/provider/ifconfig.rb +132 -0
  215. data/lib/chef/provider/link.rb +161 -0
  216. data/lib/chef/provider/log.rb +54 -0
  217. data/lib/chef/provider/mdadm.rb +91 -0
  218. data/lib/chef/provider/mount/mount.rb +232 -0
  219. data/lib/chef/provider/mount/windows.rb +80 -0
  220. data/lib/chef/provider/mount.rb +117 -0
  221. data/lib/chef/provider/ohai.rb +41 -0
  222. data/lib/chef/provider/package/apt.rb +110 -0
  223. data/lib/chef/provider/package/dpkg.rb +112 -0
  224. data/lib/chef/provider/package/easy_install.rb +114 -0
  225. data/lib/chef/provider/package/freebsd.rb +123 -0
  226. data/lib/chef/provider/package/macports.rb +105 -0
  227. data/lib/chef/provider/package/pacman.rb +101 -0
  228. data/lib/chef/provider/package/portage.rb +124 -0
  229. data/lib/chef/provider/package/rpm.rb +101 -0
  230. data/lib/chef/provider/package/rubygems.rb +462 -0
  231. data/lib/chef/provider/package/solaris.rb +127 -0
  232. data/lib/chef/provider/package/yum-dump.py +128 -0
  233. data/lib/chef/provider/package/yum.rb +222 -0
  234. data/lib/chef/provider/package/zypper.rb +133 -0
  235. data/lib/chef/provider/package.rb +160 -0
  236. data/lib/chef/provider/remote_directory.rb +140 -0
  237. data/lib/chef/provider/remote_file.rb +120 -0
  238. data/lib/chef/provider/route.rb +195 -0
  239. data/lib/chef/provider/ruby_block.rb +33 -0
  240. data/lib/chef/provider/script.rb +55 -0
  241. data/lib/chef/provider/service/arch.rb +109 -0
  242. data/lib/chef/provider/service/debian.rb +105 -0
  243. data/lib/chef/provider/service/freebsd.rb +156 -0
  244. data/lib/chef/provider/service/gentoo.rb +54 -0
  245. data/lib/chef/provider/service/init.rb +71 -0
  246. data/lib/chef/provider/service/redhat.rb +60 -0
  247. data/lib/chef/provider/service/simple.rb +118 -0
  248. data/lib/chef/provider/service/solaris.rb +85 -0
  249. data/lib/chef/provider/service/upstart.rb +192 -0
  250. data/lib/chef/provider/service/windows.rb +129 -0
  251. data/lib/chef/provider/service.rb +128 -0
  252. data/lib/chef/provider/subversion.rb +159 -0
  253. data/lib/chef/provider/template.rb +105 -0
  254. data/lib/chef/provider/user/dscl.rb +280 -0
  255. data/lib/chef/provider/user/pw.rb +113 -0
  256. data/lib/chef/provider/user/useradd.rb +137 -0
  257. data/lib/chef/provider/user/windows.rb +124 -0
  258. data/lib/chef/provider/user.rb +187 -0
  259. data/lib/chef/provider.rb +124 -0
  260. data/lib/chef/providers.rb +91 -0
  261. data/lib/chef/recipe.rb +130 -0
  262. data/lib/chef/resource/apt_package.rb +34 -0
  263. data/lib/chef/resource/bash.rb +33 -0
  264. data/lib/chef/resource/breakpoint.rb +35 -0
  265. data/lib/chef/resource/cookbook_file.rb +45 -0
  266. data/lib/chef/resource/cron.rb +188 -0
  267. data/lib/chef/resource/csh.rb +33 -0
  268. data/lib/chef/resource/deploy.rb +371 -0
  269. data/lib/chef/resource/deploy_revision.rb +35 -0
  270. data/lib/chef/resource/directory.rb +76 -0
  271. data/lib/chef/resource/dpkg_package.rb +34 -0
  272. data/lib/chef/resource/easy_install_package.rb +41 -0
  273. data/lib/chef/resource/env.rb +58 -0
  274. data/lib/chef/resource/erl_call.rb +83 -0
  275. data/lib/chef/resource/execute.rb +127 -0
  276. data/lib/chef/resource/file.rb +92 -0
  277. data/lib/chef/resource/freebsd_package.rb +35 -0
  278. data/lib/chef/resource/gem_package.rb +49 -0
  279. data/lib/chef/resource/git.rb +36 -0
  280. data/lib/chef/resource/group.rb +70 -0
  281. data/lib/chef/resource/http_request.rb +61 -0
  282. data/lib/chef/resource/ifconfig.rb +134 -0
  283. data/lib/chef/resource/link.rb +78 -0
  284. data/lib/chef/resource/log.rb +62 -0
  285. data/lib/chef/resource/macports_package.rb +29 -0
  286. data/lib/chef/resource/mdadm.rb +82 -0
  287. data/lib/chef/resource/mount.rb +135 -0
  288. data/lib/chef/resource/ohai.rb +40 -0
  289. data/lib/chef/resource/package.rb +80 -0
  290. data/lib/chef/resource/pacman_package.rb +33 -0
  291. data/lib/chef/resource/perl.rb +33 -0
  292. data/lib/chef/resource/portage_package.rb +33 -0
  293. data/lib/chef/resource/python.rb +33 -0
  294. data/lib/chef/resource/remote_directory.rb +109 -0
  295. data/lib/chef/resource/remote_file.rb +83 -0
  296. data/lib/chef/resource/route.rb +135 -0
  297. data/lib/chef/resource/rpm_package.rb +34 -0
  298. data/lib/chef/resource/ruby.rb +33 -0
  299. data/lib/chef/resource/ruby_block.rb +40 -0
  300. data/lib/chef/resource/scm.rb +146 -0
  301. data/lib/chef/resource/script.rb +60 -0
  302. data/lib/chef/resource/service.rb +160 -0
  303. data/lib/chef/resource/solaris_package.rb +36 -0
  304. data/lib/chef/resource/subversion.rb +36 -0
  305. data/lib/chef/resource/template.rb +69 -0
  306. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  307. data/lib/chef/resource/user.rb +130 -0
  308. data/lib/chef/resource/yum_package.rb +43 -0
  309. data/lib/chef/resource.rb +523 -0
  310. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  311. data/lib/chef/resource_collection.rb +217 -0
  312. data/lib/chef/resource_definition.rb +67 -0
  313. data/lib/chef/resource_definition_list.rb +38 -0
  314. data/lib/chef/resources.rb +64 -0
  315. data/lib/chef/rest/auth_credentials.rb +78 -0
  316. data/lib/chef/rest/cookie_jar.rb +31 -0
  317. data/lib/chef/rest/rest_request.rb +188 -0
  318. data/lib/chef/rest.rb +394 -0
  319. data/lib/chef/role.rb +287 -0
  320. data/lib/chef/run_context.rb +110 -0
  321. data/lib/chef/run_list/run_list_expansion.rb +172 -0
  322. data/lib/chef/run_list/run_list_item.rb +78 -0
  323. data/lib/chef/run_list.rb +150 -0
  324. data/lib/chef/run_status.rb +121 -0
  325. data/lib/chef/runner.rb +107 -0
  326. data/lib/chef/sandbox.rb +153 -0
  327. data/lib/chef/search/query.rb +60 -0
  328. data/lib/chef/shef/ext.rb +568 -0
  329. data/lib/chef/shef/model_wrapper.rb +120 -0
  330. data/lib/chef/shef/shef_rest.rb +28 -0
  331. data/lib/chef/shef/shef_session.rb +271 -0
  332. data/lib/chef/shef.rb +325 -0
  333. data/lib/chef/shell_out.rb +413 -0
  334. data/lib/chef/streaming_cookbook_uploader.rb +201 -0
  335. data/lib/chef/tasks/chef_repo.rake +256 -0
  336. data/lib/chef/util/file_edit.rb +122 -0
  337. data/lib/chef/util/windows/net_group.rb +101 -0
  338. data/lib/chef/util/windows/net_use.rb +121 -0
  339. data/lib/chef/util/windows/net_user.rb +198 -0
  340. data/lib/chef/util/windows/volume.rb +59 -0
  341. data/lib/chef/util/windows.rb +56 -0
  342. data/lib/chef/version.rb +21 -0
  343. data/lib/chef/webui_user.rb +231 -0
  344. data/lib/chef.rb +39 -0
  345. metadata +533 -0
data/lib/chef/knife.rb ADDED
@@ -0,0 +1,522 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
4
+ # Copyright:: Copyright (c) 2009 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+
20
+ require 'chef/version'
21
+ require 'mixlib/cli'
22
+ require 'chef/mixin/convert_to_class_name'
23
+
24
+ require 'pp'
25
+
26
+ class Chef
27
+ class Knife
28
+ include Mixlib::CLI
29
+ extend Chef::Mixin::ConvertToClassName
30
+
31
+ # The "require paths" of the core knife subcommands bundled with chef
32
+ DEFAULT_SUBCOMMAND_FILES = Dir[File.expand_path(File.join(File.dirname(__FILE__), 'knife', '*.rb'))]
33
+ DEFAULT_SUBCOMMAND_FILES.map! { |knife_file| knife_file[/#{CHEF_ROOT}#{Regexp.escape(File::SEPARATOR)}(.*)\.rb/,1] }
34
+
35
+ attr_accessor :name_args
36
+
37
+ def self.msg(msg="")
38
+ puts msg
39
+ end
40
+
41
+ def self.inherited(subclass)
42
+ unless subclass.unnamed?
43
+ subcommands[subclass.snake_case_name] = subclass
44
+ end
45
+ end
46
+
47
+ # Explicitly set the category for the current command to +new_category+
48
+ # The category is normally determined from the first word of the command
49
+ # name, but some commands make more sense using two or more words
50
+ # ===Arguments
51
+ # new_category::: A String to set the category to (see examples)
52
+ # ===Examples:
53
+ # Data bag commands would be in the 'data' category by default. To put them
54
+ # in the 'data bag' category:
55
+ # category('data bag')
56
+ def self.category(new_category)
57
+ @category = new_category
58
+ end
59
+
60
+ def self.subcommand_category
61
+ @category || snake_case_name.split('_').first unless unnamed?
62
+ end
63
+
64
+ def self.snake_case_name
65
+ convert_to_snake_case(name.split('::').last) unless unnamed?
66
+ end
67
+
68
+ # Does this class have a name? (Classes created via Class.new don't)
69
+ def self.unnamed?
70
+ name.nil? || name.empty?
71
+ end
72
+
73
+ def self.subcommands
74
+ @@subcommands ||= {}
75
+ end
76
+
77
+ def self.subcommands_by_category
78
+ unless @subcommands_by_category
79
+ @subcommands_by_category = Hash.new { |hash, key| hash[key] = [] }
80
+ subcommands.each do |snake_cased, klass|
81
+ @subcommands_by_category[klass.subcommand_category] << snake_cased
82
+ end
83
+ end
84
+ @subcommands_by_category
85
+ end
86
+
87
+ # Load all the sub-commands
88
+ def self.load_commands
89
+ DEFAULT_SUBCOMMAND_FILES.each { |subcommand| require subcommand }
90
+ subcommands
91
+ end
92
+
93
+ # Print the list of subcommands knife knows about. If +preferred_category+
94
+ # is given, only subcommands in that category are shown
95
+ def self.list_commands(preferred_category=nil)
96
+ load_commands
97
+ category_desc = preferred_category ? preferred_category + " " : ''
98
+ msg "Available #{category_desc}subcommands: (for details, knife SUB-COMMAND --help)\n\n"
99
+
100
+ if preferred_category && subcommands_by_category.key?(preferred_category)
101
+ commands_to_show = {preferred_category => subcommands_by_category[preferred_category]}
102
+ else
103
+ commands_to_show = subcommands_by_category
104
+ end
105
+
106
+ commands_to_show.sort.each do |category, commands|
107
+ msg "** #{category.upcase} COMMANDS **"
108
+ commands.each do |command|
109
+ msg subcommands[command].banner if subcommands[command]
110
+ end
111
+ msg
112
+ end
113
+ end
114
+
115
+ # Run knife for the given +args+ (ARGV), adding +options+ to the list of
116
+ # CLI options that the subcommand knows how to handle.
117
+ # ===Arguments
118
+ # args::: usually ARGV
119
+ # options::: A Mixlib::CLI option parser hash. These +options+ are how
120
+ # subcommands know about global knife CLI options
121
+ def self.run(args, options={})
122
+ load_commands
123
+ subcommand_class = subcommand_class_from(args)
124
+ subcommand_class.options.merge!(options)
125
+ instance = subcommand_class.new(args)
126
+ instance.configure_chef
127
+ instance.run
128
+ end
129
+
130
+ def self.guess_category(args)
131
+ category_words = args.select {|arg| arg =~ /^([[:alnum:]]|_)+$/ }
132
+ matching_category = nil
133
+ while (!matching_category) && (!category_words.empty?)
134
+ candidate_category = category_words.join(' ')
135
+ matching_category = candidate_category if subcommands_by_category.key?(candidate_category)
136
+ matching_category || category_words.pop
137
+ end
138
+ matching_category
139
+ end
140
+
141
+ def self.subcommand_class_from(args)
142
+ command_words = args.select {|arg| arg =~ /^([[:alnum:]]|_)+$/ }
143
+ subcommand_class = nil
144
+
145
+ while ( !subcommand_class ) && ( !command_words.empty? )
146
+ snake_case_class_name = command_words.join("_")
147
+ unless subcommand_class = subcommands[snake_case_class_name]
148
+ command_words.pop
149
+ end
150
+ end
151
+ subcommand_class || subcommand_not_found!(args)
152
+ end
153
+
154
+ protected
155
+
156
+ def load_late_dependency(dep, gem_name = nil)
157
+ begin
158
+ require dep
159
+ rescue LoadError
160
+ gem_name ||= dep.gsub('/', '-')
161
+ Chef::Log.fatal "#{gem_name} is not installed. run \"gem install #{gem_name}\" to install it."
162
+ exit 1
163
+ end
164
+ end
165
+
166
+ private
167
+
168
+ # :nodoc:
169
+ # Error out and print usage. probably becuase the arguments given by the
170
+ # user could not be resolved to a subcommand.
171
+ def self.subcommand_not_found!(args)
172
+ unless want_help?(args)
173
+ Chef::Log.fatal("Cannot find sub command for: '#{args.join(' ')}'")
174
+ end
175
+ Chef::Knife.list_commands(guess_category(args))
176
+ exit 10
177
+ end
178
+
179
+ # :nodoc:
180
+ # TODO: duplicated with chef/application/knife
181
+ # all logic should be removed from that and Chef::Knife should own it.
182
+ def self.want_help?(args)
183
+ (args.any? { |arg| arg =~ /^(:?(:?\-\-)?help|\-h)$/})
184
+ end
185
+
186
+ public
187
+
188
+ # Create a new instance of the current class configured for the given
189
+ # arguments and options
190
+ def initialize(argv=[])
191
+ super() # having to call super in initialize is the most annoying anti-pattern :(
192
+
193
+ command_name_words = self.class.snake_case_name.split('_')
194
+
195
+ # Mixlib::CLI ignores the embedded name_args
196
+ @name_args = parse_options(argv)
197
+ @name_args.reject! { |name_arg| command_name_words.delete(name_arg) }
198
+
199
+ # knife node run_list add requires that we have extra logic to handle
200
+ # the case that command name words could be joined by an underscore :/
201
+ command_name_words = command_name_words.join('_')
202
+ @name_args.reject! { |name_arg| command_name_words == name_arg }
203
+
204
+ if config[:help]
205
+ msg opt_parser
206
+ exit 1
207
+ end
208
+ end
209
+
210
+ def parse_options(args)
211
+ super
212
+ rescue OptionParser::InvalidOption => e
213
+ puts "Error: " + e.to_s
214
+ show_usage
215
+ exit(1)
216
+ end
217
+
218
+ def ask_question(question, opts={})
219
+ question = question + "[#{opts[:default]}] " if opts[:default]
220
+
221
+ if opts[:default] and config[:defaults]
222
+
223
+ opts[:default]
224
+
225
+ else
226
+
227
+ stdout.print question
228
+ a = stdin.readline.strip
229
+
230
+ if opts[:default]
231
+ a.empty? ? opts[:default] : a
232
+ else
233
+ a
234
+ end
235
+
236
+ end
237
+
238
+ end
239
+
240
+ def configure_chef
241
+ unless config[:config_file]
242
+ full_path = Dir.pwd.split(File::SEPARATOR)
243
+ (full_path.length - 1).downto(0) do |i|
244
+ config_file_to_check = File.join([ full_path[0..i], ".chef", "knife.rb" ].flatten)
245
+ if File.exists?(config_file_to_check)
246
+ config[:config_file] = config_file_to_check
247
+ break
248
+ end
249
+ end
250
+ # If we haven't set a config yet and $HOME is set, and the home
251
+ # knife.rb exists, use it:
252
+ if (!config[:config_file]) && ENV['HOME'] && File.exist?(File.join(ENV['HOME'], '.chef', 'knife.rb'))
253
+ config[:config_file] = File.join(ENV['HOME'], '.chef', 'knife.rb')
254
+ end
255
+ end
256
+
257
+ # Don't try to load a knife.rb if it doesn't exist.
258
+ if config[:config_file]
259
+ Chef::Config.from_file(config[:config_file])
260
+ else
261
+ # ...but do log a message if no config was found.
262
+ self.msg("No knife configuration file found")
263
+ end
264
+
265
+ Chef::Config[:log_level] = config[:log_level] if config[:log_level]
266
+ Chef::Config[:log_location] = config[:log_location] if config[:log_location]
267
+ Chef::Config[:node_name] = config[:node_name] if config[:node_name]
268
+ Chef::Config[:client_key] = config[:client_key] if config[:client_key]
269
+ Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
270
+ Chef::Log.init(Chef::Config[:log_location])
271
+ Chef::Log.level(Chef::Config[:log_level])
272
+
273
+ Chef::Log.debug("Using configuration from #{config[:config_file]}")
274
+
275
+ if Chef::Config[:node_name].nil?
276
+ raise ArgumentError, "No user specified, pass via -u or specifiy 'node_name' in #{config[:config_file] ? config[:config_file] : "~/.chef/knife.rb"}"
277
+ end
278
+ end
279
+
280
+ def pretty_print(data)
281
+ puts data
282
+ end
283
+
284
+ def output(data)
285
+ case config[:format]
286
+ when "json", nil
287
+ stdout.puts JSON.pretty_generate(data)
288
+ when "yaml"
289
+ require 'yaml'
290
+ stdout.puts YAML::dump(data)
291
+ when "text"
292
+ # If you were looking for some attribute and there is only one match
293
+ # just dump the attribute value
294
+ if data.length == 1 and config[:attribute]
295
+ stdout.puts data.values[0]
296
+ else
297
+ PP.pp(data, stdout)
298
+ end
299
+ else
300
+ raise ArgumentError, "Unknown output format #{config[:format]}"
301
+ end
302
+ end
303
+
304
+ def format_list_for_display(list)
305
+ config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b }
306
+ end
307
+
308
+ def format_for_display(item)
309
+ data = item.kind_of?(Chef::DataBagItem) ? item.raw_data : item
310
+
311
+ if config[:attribute]
312
+ config[:attribute].split(".").each do |attr|
313
+ if data.respond_to?(:[])
314
+ data = data[attr]
315
+ elsif data.nil?
316
+ nil # don't get no method error on nil
317
+ else data.respond_to?(attr.to_sym)
318
+ data = data.send(attr.to_sym)
319
+ end
320
+ end
321
+ { config[:attribute] => data.kind_of?(Chef::Node::Attribute) ? data.to_hash : data }
322
+ elsif config[:run_list]
323
+ data = data.run_list.run_list
324
+ { "run_list" => data }
325
+ elsif config[:id_only]
326
+ data.respond_to?(:name) ? data.name : data["id"]
327
+ else
328
+ data
329
+ end
330
+ end
331
+
332
+ def edit_data(data, parse_output=true)
333
+ output = JSON.pretty_generate(data)
334
+
335
+ if (!config[:no_editor])
336
+ filename = "knife-edit-"
337
+ 0.upto(20) { filename += rand(9).to_s }
338
+ filename << ".js"
339
+ filename = File.join(Dir.tmpdir, filename)
340
+ tf = File.open(filename, "w")
341
+ tf.sync = true
342
+ tf.puts output
343
+ tf.close
344
+ raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")
345
+ tf = File.open(filename, "r")
346
+ output = tf.gets(nil)
347
+ tf.close
348
+ File.unlink(filename)
349
+ end
350
+
351
+ parse_output ? JSON.parse(output) : output
352
+ end
353
+
354
+ def confirm(question, append_instructions=true)
355
+ return true if config[:yes]
356
+
357
+ stdout.print question
358
+ stdout.print "? (Y/N) " if append_instructions
359
+ answer = stdin.readline
360
+ answer.chomp!
361
+ case answer
362
+ when "Y", "y"
363
+ true
364
+ when "N", "n"
365
+ self.msg("You said no, so I'm done here.")
366
+ exit 3
367
+ else
368
+ self.msg("I have no idea what to do with #{answer}")
369
+ self.msg("Just say Y or N, please.")
370
+ confirm(question)
371
+ end
372
+ end
373
+
374
+ def show_usage
375
+ stdout.puts("USAGE: " + self.opt_parser.to_s)
376
+ end
377
+
378
+ def load_from_file(klass, from_file, bag=nil)
379
+ relative_path = ""
380
+ if klass == Chef::Role
381
+ relative_path = "roles"
382
+ elsif klass == Chef::Node
383
+ relative_path = "nodes"
384
+ elsif klass == Chef::DataBagItem
385
+ relative_path = "data_bags/#{bag}"
386
+ end
387
+
388
+ relative_file = File.expand_path(File.join(Dir.pwd, relative_path, from_file))
389
+ filename = nil
390
+
391
+ if file_exists_and_is_readable?(from_file)
392
+ filename = from_file
393
+ elsif file_exists_and_is_readable?(relative_file)
394
+ filename = relative_file
395
+ else
396
+ Chef::Log.fatal("Cannot find file #{from_file}")
397
+ exit 30
398
+ end
399
+
400
+ case from_file
401
+ when /\.(js|json)$/
402
+ JSON.parse(IO.read(filename))
403
+ when /\.rb$/
404
+ r = klass.new
405
+ r.from_file(filename)
406
+ r
407
+ else
408
+ Chef::Log.fatal("File must end in .js, .json, or .rb")
409
+ exit 30
410
+ end
411
+ end
412
+
413
+ def file_exists_and_is_readable?(file)
414
+ File.exists?(file) && File.readable?(file)
415
+ end
416
+
417
+ def edit_object(klass, name)
418
+ object = klass.load(name)
419
+
420
+ output = edit_data(object)
421
+
422
+ # Only make the save if the user changed the object.
423
+ #
424
+ # Output JSON for the original (object) and edited (output), then parse
425
+ # them without reconstituting the objects into real classes
426
+ # (create_additions=false). Then, compare the resulting simple objects,
427
+ # which will be Array/Hash/String/etc.
428
+ #
429
+ # We wouldn't have to do these shenanigans if all the editable objects
430
+ # implemented to_hash, or if to_json against a hash returned a string
431
+ # with stable key order.
432
+ object_parsed_again = JSON.parse(object.to_json, :create_additions => false)
433
+ output_parsed_again = JSON.parse(output.to_json, :create_additions => false)
434
+ if object_parsed_again != output_parsed_again
435
+ output.save
436
+ self.msg("Saved #{output}")
437
+ else
438
+ self.msg("Object unchanged, not saving")
439
+ end
440
+
441
+ output(format_for_display(object)) if config[:print_after]
442
+ end
443
+
444
+ def create_object(object, pretty_name=nil, &block)
445
+ output = edit_data(object)
446
+
447
+ if Kernel.block_given?
448
+ output = block.call(output)
449
+ else
450
+ output.save
451
+ end
452
+
453
+ pretty_name ||= output
454
+
455
+ self.msg("Created (or updated) #{pretty_name}")
456
+
457
+ output(output) if config[:print_after]
458
+ end
459
+
460
+ def delete_object(klass, name, delete_name=nil, &block)
461
+ confirm("Do you really want to delete #{name}")
462
+
463
+ if Kernel.block_given?
464
+ object = block.call
465
+ else
466
+ object = klass.load(name)
467
+ object.destroy
468
+ end
469
+
470
+ output(format_for_display(object)) if config[:print_after]
471
+
472
+ obj_name = delete_name ? "#{delete_name}[#{name}]" : object
473
+ self.msg("Deleted #{obj_name}!")
474
+ end
475
+
476
+ def bulk_delete(klass, fancy_name, delete_name=nil, list=nil, regex=nil, &block)
477
+ object_list = list ? list : klass.list(true)
478
+
479
+ if regex
480
+ to_delete = Hash.new
481
+ object_list.each_key do |object|
482
+ next if regex && object !~ /#{regex}/
483
+ to_delete[object] = object_list[object]
484
+ end
485
+ else
486
+ to_delete = object_list
487
+ end
488
+
489
+ output(format_list_for_display(to_delete))
490
+
491
+ confirm("Do you really want to delete the above items")
492
+
493
+ to_delete.each do |name, object|
494
+ if Kernel.block_given?
495
+ block.call(name, object)
496
+ else
497
+ object.destroy
498
+ end
499
+ output(format_for_display(object)) if config[:print_after]
500
+ self.msg("Deleted #{fancy_name} #{name}")
501
+ end
502
+ end
503
+
504
+ def msg(message)
505
+ stdout.puts message
506
+ end
507
+
508
+ def stdout
509
+ STDOUT
510
+ end
511
+
512
+ def stdin
513
+ STDIN
514
+ end
515
+
516
+ def rest
517
+ @rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
518
+ end
519
+
520
+ end
521
+ end
522
+