runa-chef 0.8.0.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 (216) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +136 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +26 -0
  5. data/bin/knife +27 -0
  6. data/bin/shef +45 -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.1 +108 -0
  10. data/distro/common/man/man8/chef-client.8 +61 -0
  11. data/distro/common/man/man8/chef-solo.8 +58 -0
  12. data/distro/common/man/man8/knife.8 +359 -0
  13. data/distro/debian/etc/init.d/chef-client +175 -0
  14. data/distro/debian/etc/init.d/chef-indexer +175 -0
  15. data/distro/debian/etc/init.d/chef-server +120 -0
  16. data/distro/redhat/etc/init.d/chef-client +78 -0
  17. data/distro/redhat/etc/init.d/chef-indexer +76 -0
  18. data/distro/redhat/etc/init.d/chef-server +78 -0
  19. data/distro/redhat/etc/sysconfig/chef-client +10 -0
  20. data/distro/redhat/etc/sysconfig/chef-indexer +8 -0
  21. data/distro/redhat/etc/sysconfig/chef-server +10 -0
  22. data/distro/suse/etc/init.d/chef-client +121 -0
  23. data/lib/chef.rb +49 -0
  24. data/lib/chef/api_client.rb +269 -0
  25. data/lib/chef/application.rb +98 -0
  26. data/lib/chef/application/agent.rb +18 -0
  27. data/lib/chef/application/client.rb +214 -0
  28. data/lib/chef/application/knife.rb +138 -0
  29. data/lib/chef/application/server.rb +19 -0
  30. data/lib/chef/application/solo.rb +214 -0
  31. data/lib/chef/cache.rb +61 -0
  32. data/lib/chef/cache/checksum.rb +70 -0
  33. data/lib/chef/certificate.rb +154 -0
  34. data/lib/chef/client.rb +323 -0
  35. data/lib/chef/compile.rb +158 -0
  36. data/lib/chef/config.rb +195 -0
  37. data/lib/chef/cookbook.rb +198 -0
  38. data/lib/chef/cookbook/metadata.rb +487 -0
  39. data/lib/chef/cookbook/metadata/version.rb +87 -0
  40. data/lib/chef/cookbook_loader.rb +180 -0
  41. data/lib/chef/couchdb.rb +273 -0
  42. data/lib/chef/daemon.rb +170 -0
  43. data/lib/chef/data_bag.rb +216 -0
  44. data/lib/chef/data_bag_item.rb +227 -0
  45. data/lib/chef/exceptions.rb +39 -0
  46. data/lib/chef/file_cache.rb +205 -0
  47. data/lib/chef/knife.rb +300 -0
  48. data/lib/chef/knife/client_bulk_delete.rb +41 -0
  49. data/lib/chef/knife/client_create.rb +55 -0
  50. data/lib/chef/knife/client_delete.rb +37 -0
  51. data/lib/chef/knife/client_edit.rb +37 -0
  52. data/lib/chef/knife/client_list.rb +40 -0
  53. data/lib/chef/knife/client_reregister.rb +48 -0
  54. data/lib/chef/knife/client_show.rb +42 -0
  55. data/lib/chef/knife/configure.rb +84 -0
  56. data/lib/chef/knife/cookbook_bulk_delete.rb +47 -0
  57. data/lib/chef/knife/cookbook_delete.rb +41 -0
  58. data/lib/chef/knife/cookbook_download.rb +57 -0
  59. data/lib/chef/knife/cookbook_list.rb +41 -0
  60. data/lib/chef/knife/cookbook_metadata.rb +87 -0
  61. data/lib/chef/knife/cookbook_show.rb +75 -0
  62. data/lib/chef/knife/cookbook_upload.rb +173 -0
  63. data/lib/chef/knife/data_bag_create.rb +43 -0
  64. data/lib/chef/knife/data_bag_delete.rb +43 -0
  65. data/lib/chef/knife/data_bag_edit.rb +49 -0
  66. data/lib/chef/knife/data_bag_list.rb +42 -0
  67. data/lib/chef/knife/data_bag_show.rb +40 -0
  68. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  69. data/lib/chef/knife/node_bulk_delete.rb +44 -0
  70. data/lib/chef/knife/node_create.rb +39 -0
  71. data/lib/chef/knife/node_delete.rb +36 -0
  72. data/lib/chef/knife/node_edit.rb +36 -0
  73. data/lib/chef/knife/node_from_file.rb +42 -0
  74. data/lib/chef/knife/node_list.rb +41 -0
  75. data/lib/chef/knife/node_run_list_add.rb +64 -0
  76. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  77. data/lib/chef/knife/node_show.rb +46 -0
  78. data/lib/chef/knife/role_bulk_delete.rb +45 -0
  79. data/lib/chef/knife/role_create.rb +44 -0
  80. data/lib/chef/knife/role_delete.rb +36 -0
  81. data/lib/chef/knife/role_edit.rb +37 -0
  82. data/lib/chef/knife/role_from_file.rb +46 -0
  83. data/lib/chef/knife/role_list.rb +40 -0
  84. data/lib/chef/knife/role_show.rb +43 -0
  85. data/lib/chef/knife/search.rb +94 -0
  86. data/lib/chef/log.rb +39 -0
  87. data/lib/chef/mixin/check_helper.rb +31 -0
  88. data/lib/chef/mixin/checksum.rb +32 -0
  89. data/lib/chef/mixin/command.rb +390 -0
  90. data/lib/chef/mixin/convert_to_class_name.rb +57 -0
  91. data/lib/chef/mixin/create_path.rb +56 -0
  92. data/lib/chef/mixin/deep_merge.rb +33 -0
  93. data/lib/chef/mixin/find_preferred_file.rb +92 -0
  94. data/lib/chef/mixin/from_file.rb +50 -0
  95. data/lib/chef/mixin/generate_url.rb +58 -0
  96. data/lib/chef/mixin/language.rb +107 -0
  97. data/lib/chef/mixin/language_include_attribute.rb +56 -0
  98. data/lib/chef/mixin/language_include_recipe.rb +53 -0
  99. data/lib/chef/mixin/params_validate.rb +197 -0
  100. data/lib/chef/mixin/recipe_definition_dsl_core.rb +79 -0
  101. data/lib/chef/mixin/template.rb +94 -0
  102. data/lib/chef/nanite.rb +100 -0
  103. data/lib/chef/node.rb +463 -0
  104. data/lib/chef/node/attribute.rb +412 -0
  105. data/lib/chef/openid_registration.rb +181 -0
  106. data/lib/chef/platform.rb +268 -0
  107. data/lib/chef/provider.rb +101 -0
  108. data/lib/chef/provider/breakpoint.rb +36 -0
  109. data/lib/chef/provider/cron.rb +184 -0
  110. data/lib/chef/provider/deploy.rb +314 -0
  111. data/lib/chef/provider/deploy/revision.rb +70 -0
  112. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  113. data/lib/chef/provider/directory.rb +72 -0
  114. data/lib/chef/provider/erl_call.rb +72 -0
  115. data/lib/chef/provider/execute.rb +58 -0
  116. data/lib/chef/provider/file.rb +195 -0
  117. data/lib/chef/provider/git.rb +203 -0
  118. data/lib/chef/provider/group.rb +120 -0
  119. data/lib/chef/provider/group/dscl.rb +128 -0
  120. data/lib/chef/provider/group/gpasswd.rb +50 -0
  121. data/lib/chef/provider/group/groupadd.rb +78 -0
  122. data/lib/chef/provider/group/pw.rb +88 -0
  123. data/lib/chef/provider/group/usermod.rb +57 -0
  124. data/lib/chef/provider/http_request.rb +106 -0
  125. data/lib/chef/provider/ifconfig.rb +131 -0
  126. data/lib/chef/provider/link.rb +157 -0
  127. data/lib/chef/provider/mdadm.rb +88 -0
  128. data/lib/chef/provider/mount.rb +117 -0
  129. data/lib/chef/provider/mount/mount.rb +208 -0
  130. data/lib/chef/provider/package.rb +160 -0
  131. data/lib/chef/provider/package/apt.rb +110 -0
  132. data/lib/chef/provider/package/dpkg.rb +109 -0
  133. data/lib/chef/provider/package/easy_install.rb +106 -0
  134. data/lib/chef/provider/package/freebsd.rb +153 -0
  135. data/lib/chef/provider/package/macports.rb +105 -0
  136. data/lib/chef/provider/package/portage.rb +124 -0
  137. data/lib/chef/provider/package/rpm.rb +99 -0
  138. data/lib/chef/provider/package/rubygems.rb +136 -0
  139. data/lib/chef/provider/package/yum-dump.py +125 -0
  140. data/lib/chef/provider/package/yum.rb +175 -0
  141. data/lib/chef/provider/package/zypper.rb +132 -0
  142. data/lib/chef/provider/remote_directory.rb +126 -0
  143. data/lib/chef/provider/remote_file.rb +141 -0
  144. data/lib/chef/provider/route.rb +118 -0
  145. data/lib/chef/provider/ruby_block.rb +33 -0
  146. data/lib/chef/provider/script.rb +42 -0
  147. data/lib/chef/provider/service.rb +135 -0
  148. data/lib/chef/provider/service/debian.rb +64 -0
  149. data/lib/chef/provider/service/freebsd.rb +156 -0
  150. data/lib/chef/provider/service/gentoo.rb +54 -0
  151. data/lib/chef/provider/service/init.rb +71 -0
  152. data/lib/chef/provider/service/redhat.rb +62 -0
  153. data/lib/chef/provider/service/simple.rb +114 -0
  154. data/lib/chef/provider/subversion.rb +156 -0
  155. data/lib/chef/provider/template.rb +175 -0
  156. data/lib/chef/provider/user.rb +170 -0
  157. data/lib/chef/provider/user/dscl.rb +280 -0
  158. data/lib/chef/provider/user/pw.rb +113 -0
  159. data/lib/chef/provider/user/useradd.rb +108 -0
  160. data/lib/chef/recipe.rb +105 -0
  161. data/lib/chef/resource.rb +380 -0
  162. data/lib/chef/resource/apt_package.rb +34 -0
  163. data/lib/chef/resource/bash.rb +33 -0
  164. data/lib/chef/resource/breakpoint.rb +35 -0
  165. data/lib/chef/resource/cron.rb +179 -0
  166. data/lib/chef/resource/csh.rb +33 -0
  167. data/lib/chef/resource/deploy.rb +359 -0
  168. data/lib/chef/resource/deploy_revision.rb +35 -0
  169. data/lib/chef/resource/directory.rb +76 -0
  170. data/lib/chef/resource/dpkg_package.rb +34 -0
  171. data/lib/chef/resource/easy_install_package.rb +41 -0
  172. data/lib/chef/resource/erl_call.rb +83 -0
  173. data/lib/chef/resource/execute.rb +127 -0
  174. data/lib/chef/resource/file.rb +84 -0
  175. data/lib/chef/resource/gem_package.rb +41 -0
  176. data/lib/chef/resource/git.rb +36 -0
  177. data/lib/chef/resource/group.rb +70 -0
  178. data/lib/chef/resource/http_request.rb +52 -0
  179. data/lib/chef/resource/ifconfig.rb +134 -0
  180. data/lib/chef/resource/link.rb +78 -0
  181. data/lib/chef/resource/macports_package.rb +29 -0
  182. data/lib/chef/resource/mdadm.rb +82 -0
  183. data/lib/chef/resource/mount.rb +135 -0
  184. data/lib/chef/resource/package.rb +80 -0
  185. data/lib/chef/resource/perl.rb +33 -0
  186. data/lib/chef/resource/portage_package.rb +33 -0
  187. data/lib/chef/resource/python.rb +33 -0
  188. data/lib/chef/resource/remote_directory.rb +91 -0
  189. data/lib/chef/resource/remote_file.rb +60 -0
  190. data/lib/chef/resource/route.rb +135 -0
  191. data/lib/chef/resource/ruby.rb +33 -0
  192. data/lib/chef/resource/ruby_block.rb +39 -0
  193. data/lib/chef/resource/scm.rb +137 -0
  194. data/lib/chef/resource/script.rb +51 -0
  195. data/lib/chef/resource/service.rb +134 -0
  196. data/lib/chef/resource/subversion.rb +34 -0
  197. data/lib/chef/resource/template.rb +60 -0
  198. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  199. data/lib/chef/resource/user.rb +101 -0
  200. data/lib/chef/resource_collection.rb +212 -0
  201. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  202. data/lib/chef/resource_definition.rb +67 -0
  203. data/lib/chef/rest.rb +298 -0
  204. data/lib/chef/role.rb +301 -0
  205. data/lib/chef/run_list.rb +164 -0
  206. data/lib/chef/runner.rb +130 -0
  207. data/lib/chef/search/query.rb +71 -0
  208. data/lib/chef/shef.rb +220 -0
  209. data/lib/chef/shef/ext.rb +297 -0
  210. data/lib/chef/shef/shef_session.rb +175 -0
  211. data/lib/chef/streaming_cookbook_uploader.rb +185 -0
  212. data/lib/chef/tasks/chef_repo.rake +245 -0
  213. data/lib/chef/util/file_edit.rb +125 -0
  214. data/lib/chef/util/fileedit.rb +121 -0
  215. data/lib/chef/webui_user.rb +231 -0
  216. metadata +398 -0
@@ -0,0 +1,39 @@
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
+ class Chef
19
+ class Exceptions
20
+ class Application < RuntimeError; end
21
+ class Cron < RuntimeError; end
22
+ class Exec < RuntimeError; end
23
+ class FileNotFound < RuntimeError; end
24
+ class Package < RuntimeError; end
25
+ class Service < RuntimeError; end
26
+ class Route < RuntimeError; end
27
+ class SearchIndex < RuntimeError; end
28
+ class Override < RuntimeError; end
29
+ class UnsupportedAction < RuntimeError; end
30
+ class MissingLibrary < RuntimeError; end
31
+ class User < RuntimeError; end
32
+ class Group < RuntimeError; end
33
+ class Link < RuntimeError; end
34
+ class Mount < RuntimeError; end
35
+ class CouchDBNotFound < RuntimeError; end
36
+ class PrivateKeyMissing < RuntimeError; end
37
+ class CannotWritePrivateKey < RuntimeError; end
38
+ end
39
+ end
@@ -0,0 +1,205 @@
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
+ require 'chef/mixin/params_validate'
19
+ require 'chef/mixin/create_path'
20
+ require 'chef/exceptions'
21
+ require 'json'
22
+ require 'fileutils'
23
+
24
+ class Chef
25
+ class FileCache
26
+ class << self
27
+ include Chef::Mixin::ParamsValidate
28
+ include Chef::Mixin::CreatePath
29
+
30
+ # Write a file to the File Cache.
31
+ #
32
+ # === Parameters
33
+ # path<String>:: The path to the file you want to put in the cache - should
34
+ # be relative to Chef::Config[:file_cache_path]
35
+ # contents<String>:: A string with the contents you want written to the file
36
+ #
37
+ # === Returns
38
+ # true
39
+ def store(path, contents)
40
+ validate(
41
+ {
42
+ :path => path,
43
+ :contents => contents
44
+ },
45
+ {
46
+ :path => { :kind_of => String },
47
+ :contents => { :kind_of => String },
48
+ }
49
+ )
50
+
51
+ file_path_array = File.split(path)
52
+ file_name = file_path_array.pop
53
+ cache_path = create_cache_path(File.join(file_path_array))
54
+ io = File.open(File.join(cache_path, file_name), "w")
55
+ io.print(contents)
56
+ io.close
57
+ true
58
+ end
59
+
60
+ # Move a file in to the cache. Useful with the REST raw file output.
61
+ #
62
+ # === Parameteres
63
+ # file<String>:: The path to the file you want in the cache
64
+ # path<String>:: The relative name you want the new file to use
65
+ def move_to(file, path)
66
+ validate(
67
+ {
68
+ :file => file,
69
+ :path => path
70
+ },
71
+ {
72
+ :file => { :kind_of => String },
73
+ :path => { :kind_of => String },
74
+ }
75
+ )
76
+
77
+ file_path_array = File.split(path)
78
+ file_name = file_path_array.pop
79
+ if File.exists?(file) && File.writable?(file)
80
+ FileUtils.mv(
81
+ file,
82
+ File.join(create_cache_path(File.join(file_path_array), true), file_name)
83
+ )
84
+ else
85
+ raise RuntimeError, "Cannot move #{file} to #{path}!"
86
+ end
87
+ end
88
+
89
+ # Read a file from the File Cache
90
+ #
91
+ # === Parameters
92
+ # path<String>:: The path to the file you want to load - should
93
+ # be relative to Chef::Config[:file_cache_path]
94
+ # read<True/False>:: Whether to return the file contents, or the path.
95
+ # Defaults to true.
96
+ #
97
+ # === Returns
98
+ # String:: A string with the file contents, or the path to the file.
99
+ #
100
+ # === Raises
101
+ # Chef::Exceptions::FileNotFound:: If it cannot find the file in the cache
102
+ def load(path, read=true)
103
+ validate(
104
+ {
105
+ :path => path
106
+ },
107
+ {
108
+ :path => { :kind_of => String }
109
+ }
110
+ )
111
+ cache_path = create_cache_path(path, false)
112
+ raise Chef::Exceptions::FileNotFound, "Cannot find #{cache_path} for #{path}!" unless File.exists?(cache_path)
113
+ if read
114
+ File.read(cache_path)
115
+ else
116
+ cache_path
117
+ end
118
+ end
119
+
120
+ # Delete a file from the File Cache
121
+ #
122
+ # === Parameters
123
+ # path<String>:: The path to the file you want to delete - should
124
+ # be relative to Chef::Config[:file_cache_path]
125
+ #
126
+ # === Returns
127
+ # true
128
+ def delete(path)
129
+ validate(
130
+ {
131
+ :path => path
132
+ },
133
+ {
134
+ :path => { :kind_of => String },
135
+ }
136
+ )
137
+ cache_path = create_cache_path(path, false)
138
+ if File.exists?(cache_path)
139
+ File.unlink(cache_path)
140
+ end
141
+ true
142
+ end
143
+
144
+ # List all the files in the Cache
145
+ #
146
+ # === Returns
147
+ # Array:: An array of files in the cache, suitable for use with load, delete and store
148
+ def list()
149
+ keys = Array.new
150
+ Dir[File.join(Chef::Config[:file_cache_path], '**', '*')].each do |f|
151
+ if File.file?(f)
152
+ path = f.match("^#{Chef::Config[:file_cache_path]}\/(.+)")[1]
153
+ keys << path
154
+ end
155
+ end
156
+ keys
157
+ end
158
+
159
+ # Whether or not this file exists in the Cache
160
+ #
161
+ # === Parameters
162
+ # path:: The path to the file you want to check - is relative
163
+ # to Chef::Config[:file_cache_path]
164
+ #
165
+ # === Returns
166
+ # True:: If the file exists
167
+ # False:: If it does not
168
+ def has_key?(path)
169
+ validate(
170
+ {
171
+ :path => path
172
+ },
173
+ {
174
+ :path => { :kind_of => String },
175
+ }
176
+ )
177
+ full_path = create_cache_path(path, false)
178
+ if File.exists?(full_path)
179
+ true
180
+ else
181
+ false
182
+ end
183
+ end
184
+
185
+ # Create a full path to a given file in the cache. By default,
186
+ # also creates the path if it does not exist.
187
+ #
188
+ # === Parameters
189
+ # path:: The path to create, relative to Chef::Config[:file_cache_path]
190
+ # create_if_missing:: True by default - whether to create the path if it does not exist
191
+ #
192
+ # === Returns
193
+ # String:: The fully expanded path
194
+ def create_cache_path(path, create_if_missing=true)
195
+ cache_dir = File.expand_path(File.join(Chef::Config[:file_cache_path], path))
196
+ if create_if_missing
197
+ create_path(cache_dir)
198
+ else
199
+ cache_dir
200
+ end
201
+ end
202
+
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,300 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2009 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 'mixlib/cli'
20
+ require 'chef/mixin/convert_to_class_name'
21
+
22
+ class Chef
23
+ class Knife
24
+ include Mixlib::CLI
25
+ extend Chef::Mixin::ConvertToClassName
26
+
27
+ attr_accessor :name_args
28
+
29
+ # Load all the sub-commands
30
+ def self.load_commands
31
+ @sub_classes = Hash.new
32
+ Dir[
33
+ File.expand_path(File.join(File.dirname(__FILE__), 'knife', '*.rb'))
34
+ ].each do |knife_file|
35
+ require knife_file
36
+ snake_case_file_name = File.basename(knife_file).sub(/\.rb$/, '')
37
+ @sub_classes[snake_case_file_name] = convert_to_class_name(snake_case_file_name)
38
+ end
39
+ @sub_classes
40
+ end
41
+
42
+ def self.list_commands
43
+ load_commands
44
+ @sub_classes.keys.sort.each do |snake_case|
45
+ klass_instance = build_sub_class(snake_case)
46
+ klass_instance.parse_options
47
+ puts klass_instance.opt_parser
48
+ puts
49
+ end
50
+ end
51
+
52
+ def self.build_sub_class(snake_case, merge_opts=nil)
53
+ klass = Chef::Knife.const_get(@sub_classes[snake_case])
54
+ klass.options.merge!(merge_opts) if merge_opts
55
+ klass.new
56
+ end
57
+
58
+ def self.find_command(args=ARGV, merge_opts={})
59
+ load_commands
60
+
61
+ non_dash_args = Array.new
62
+ args.each do |arg|
63
+ non_dash_args << arg if arg =~ /^([[:alnum:]]|_)+$/
64
+ end
65
+
66
+ to_try = non_dash_args.length
67
+ klass_instance = nil
68
+ cli_bits = nil
69
+
70
+ while(to_try >= 0)
71
+ cli_bits = non_dash_args[0..to_try]
72
+ snake_case_class_name = cli_bits.join("_")
73
+
74
+ if @sub_classes.has_key?(snake_case_class_name)
75
+ klass_instance = build_sub_class(snake_case_class_name, merge_opts)
76
+ break
77
+ end
78
+
79
+ to_try = to_try - 1
80
+ end
81
+
82
+ unless klass_instance
83
+ Chef::Log.fatal("Cannot find sub command for: #{args.join(' ')}")
84
+ Chef::Knife.list_commands
85
+ exit 10
86
+ end
87
+
88
+ extra = klass_instance.parse_options(args)
89
+ if klass_instance.config[:help]
90
+ puts klass_instance.opt_parser
91
+ exit 1
92
+ end
93
+ klass_instance.name_args = (extra - cli_bits) || []
94
+ klass_instance.configure_chef
95
+ klass_instance
96
+ end
97
+
98
+ def ask_question(q)
99
+ print q
100
+ a = STDIN.readline
101
+ a.chomp!
102
+ a
103
+ end
104
+
105
+ def configure_chef
106
+ if !config[:config_file].nil? && File.exists?(config[:config_file]) && File.readable?(config[:config_file])
107
+ Chef::Config.from_file(config[:config_file])
108
+ end
109
+
110
+ Chef::Config[:log_level] = config[:log_level] if config[:log_level]
111
+ Chef::Config[:log_location] = config[:log_location] if config[:log_location]
112
+ Chef::Config[:node_name] = config[:node_name] if config[:node_name]
113
+ Chef::Config[:client_key] = config[:client_key] if config[:client_key]
114
+ Chef::Config[:chef_server_url] = config[:chef_server_url] if config[:chef_server_url]
115
+ Chef::Log::Formatter.show_time = false
116
+ Chef::Log.init(Chef::Config[:log_location])
117
+ Chef::Log.level(Chef::Config[:log_level])
118
+ end
119
+
120
+ def pretty_print(data)
121
+ puts data
122
+ end
123
+
124
+ def json_pretty_print(data)
125
+ puts JSON.pretty_generate(data)
126
+ end
127
+
128
+ def format_list_for_display(list)
129
+ config[:with_uri] ? list : list.keys.sort { |a,b| a <=> b }
130
+ end
131
+
132
+ def format_for_display(item)
133
+ data = item.kind_of?(Chef::DataBagItem) ? item.raw_data : item
134
+
135
+ if config[:attribute]
136
+ config[:attribute].split(".").each do |attr|
137
+ if data.respond_to?(:[])
138
+ data = data[attr]
139
+ else
140
+ data = data.send(attr.to_sym)
141
+ end
142
+ end
143
+ { config[:attribute] => data.kind_of?(Chef::Node::Attribute) ? data.to_hash: data }
144
+ elsif config[:run_list]
145
+ data = data.run_list.run_list
146
+ { "run_list" => data }
147
+ elsif config[:id_only]
148
+ data.respond_to?(:name) ? data.name : data["id"]
149
+ else
150
+ data
151
+ end
152
+ end
153
+
154
+ def edit_data(data, parse_output=true)
155
+ filename = "knife-edit-"
156
+ 0.upto(20) { filename += rand(9).to_s }
157
+ filename << ".js"
158
+ filename = File.join(Dir.tmpdir, filename)
159
+ tf = File.open(filename, "w")
160
+ tf.sync = true
161
+ tf.puts JSON.pretty_generate(data)
162
+ tf.close
163
+ raise "Please set EDITOR environment variable" unless system("#{config[:editor]} #{tf.path}")
164
+ tf = File.open(filename, "r")
165
+ output = tf.gets(nil)
166
+ tf.close
167
+ File.unlink(filename)
168
+
169
+ parse_output ? JSON.parse(output) : output
170
+ end
171
+
172
+ def confirm(question)
173
+ return true if config[:yes]
174
+
175
+ print "#{question}? (Y/N) "
176
+ answer = STDIN.readline
177
+ answer.chomp!
178
+ case answer
179
+ when "Y", "y"
180
+ true
181
+ when "N", "n"
182
+ Chef::Log.info("You said no, so I'm done here.")
183
+ exit 3
184
+ else
185
+ Chef::Log.error("I have no idea what to do with #{answer}")
186
+ Chef::Log.error("Just say Y or N, please.")
187
+ confirm(question)
188
+ end
189
+ end
190
+
191
+ def load_from_file(klass, from_file)
192
+ from_file = @name_args[0]
193
+ relative_file = File.expand_path(File.join(Dir.pwd, 'roles', from_file))
194
+ filename = nil
195
+
196
+ if file_exists_and_is_readable?(from_file)
197
+ filename = from_file
198
+ elsif file_exists_and_is_readable?(relative_file)
199
+ filename = relative_file
200
+ else
201
+ Chef::Log.fatal("Cannot find file #{from_file}")
202
+ exit 30
203
+ end
204
+
205
+ case from_file
206
+ when /\.(js|json)$/
207
+ JSON.parse(IO.read(filename))
208
+ when /\.rb$/
209
+ r = klass.new
210
+ r.from_file(filename)
211
+ r
212
+ else
213
+ Chef::Log.fatal("File must end in .js, .json, or .rb")
214
+ exit 30
215
+ end
216
+ end
217
+
218
+ def file_exists_and_is_readable?(file)
219
+ File.exists?(file) && File.readable?(file)
220
+ end
221
+
222
+ def edit_object(klass, name)
223
+ object = klass.load(name)
224
+
225
+ output = edit_data(object)
226
+
227
+ output.save
228
+
229
+ Chef::Log.info("Saved #{output}")
230
+
231
+ json_pretty_print(format_for_display(object)) if config[:print_after]
232
+ end
233
+
234
+ def create_object(object, pretty_name=nil, &block)
235
+ output = edit_data(object)
236
+
237
+ if Kernel.block_given?
238
+ output = block.call(output)
239
+ else
240
+ output.save
241
+ end
242
+
243
+ pretty_name ||= output
244
+
245
+ Chef::Log.info("Created (or updated) #{pretty_name}")
246
+
247
+ json_pretty_print(output) if config[:print_after]
248
+ end
249
+
250
+ def delete_object(klass, name, delete_name=nil, &block)
251
+ confirm("Do you really want to delete #{name}")
252
+
253
+ if Kernel.block_given?
254
+ object = block.call
255
+ else
256
+ object = klass.load(name)
257
+ object.destroy
258
+ end
259
+
260
+ json_pretty_print(format_for_display(object)) if config[:print_after]
261
+
262
+ obj_name = delete_name ? "#{delete_name}[#{name}]" : object
263
+ Chef::Log.warn("Deleted #{obj_name}!")
264
+ end
265
+
266
+ def bulk_delete(klass, fancy_name, delete_name=nil, list=nil, &block)
267
+ object_list = list ? list : klass.list(true)
268
+
269
+ if config[:regex]
270
+ to_delete = Hash.new
271
+ object_list.each_key do |object|
272
+ next if config[:regex] && object !~ /#{config[:regex]}/
273
+ to_delete[object] = object_list[object]
274
+ end
275
+ else
276
+ to_delete = object_list
277
+ end
278
+
279
+ json_pretty_print(format_list_for_display(to_delete))
280
+
281
+ confirm("Do you really want to delete the above items")
282
+
283
+ to_delete.each do |name, object|
284
+ if Kernel.block_given?
285
+ block.call(name, object)
286
+ else
287
+ object.destroy
288
+ end
289
+ json_pretty_print(format_for_display(object)) if config[:print_after]
290
+ Chef::Log.warn("Deleted #{fancy_name} #{name}")
291
+ end
292
+ end
293
+
294
+ def rest
295
+ @rest ||= Chef::REST.new(Chef::Config[:chef_server_url])
296
+ end
297
+
298
+ end
299
+ end
300
+