chef 0.9.18 → 0.10.0.beta.0

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 (177) hide show
  1. data/README.rdoc +0 -3
  2. data/distro/arch/etc/rc.d/chef-server +0 -4
  3. data/distro/arch/etc/rc.d/chef-server-webui +0 -4
  4. data/distro/arch/etc/rc.d/chef-solr +0 -4
  5. data/distro/arch/etc/rc.d/chef-solr-indexer +0 -4
  6. data/lib/chef.rb +3 -3
  7. data/lib/chef/api_client.rb +1 -1
  8. data/lib/chef/application.rb +11 -1
  9. data/lib/chef/application/client.rb +18 -22
  10. data/lib/chef/application/knife.rb +28 -29
  11. data/lib/chef/application/solo.rb +14 -12
  12. data/lib/chef/client.rb +112 -54
  13. data/lib/chef/config.rb +4 -0
  14. data/lib/chef/cookbook/chefignore.rb +66 -0
  15. data/lib/chef/cookbook/cookbook_collection.rb +6 -5
  16. data/lib/chef/cookbook/cookbook_version_loader.rb +151 -0
  17. data/lib/chef/cookbook/file_system_file_vendor.rb +10 -8
  18. data/lib/chef/cookbook/metadata.rb +200 -108
  19. data/lib/chef/cookbook_loader.rb +39 -163
  20. data/lib/chef/cookbook_uploader.rb +100 -78
  21. data/lib/chef/cookbook_version.rb +92 -47
  22. data/lib/chef/cookbook_version_selector.rb +163 -0
  23. data/lib/chef/couchdb.rb +9 -1
  24. data/lib/chef/data_bag.rb +1 -1
  25. data/lib/chef/data_bag_item.rb +1 -1
  26. data/lib/chef/encrypted_data_bag_item.rb +126 -0
  27. data/lib/chef/environment.rb +386 -0
  28. data/lib/chef/exceptions.rb +82 -1
  29. data/lib/chef/index_queue/amqp_client.rb +15 -12
  30. data/lib/chef/index_queue/indexable.rb +38 -4
  31. data/lib/chef/json_compat.rb +3 -3
  32. data/lib/chef/knife.rb +97 -202
  33. data/lib/chef/knife/bootstrap.rb +27 -61
  34. data/lib/chef/knife/bootstrap/archlinux-gems.erb +4 -2
  35. data/lib/chef/knife/bootstrap/centos5-gems.erb +6 -15
  36. data/lib/chef/knife/bootstrap/fedora13-gems.erb +3 -4
  37. data/lib/chef/knife/bootstrap/ubuntu10.04-apt.erb +2 -2
  38. data/lib/chef/knife/bootstrap/ubuntu10.04-gems.erb +6 -5
  39. data/lib/chef/knife/client_bulk_delete.rb +6 -3
  40. data/lib/chef/knife/client_create.rb +13 -10
  41. data/lib/chef/knife/client_delete.rb +10 -7
  42. data/lib/chef/knife/client_edit.rb +9 -6
  43. data/lib/chef/knife/client_list.rb +8 -5
  44. data/lib/chef/knife/client_reregister.rb +9 -6
  45. data/lib/chef/knife/client_show.rb +9 -6
  46. data/lib/chef/knife/configure.rb +15 -19
  47. data/lib/chef/knife/configure_client.rb +4 -4
  48. data/lib/chef/knife/cookbook_bulk_delete.rb +11 -8
  49. data/lib/chef/knife/cookbook_create.rb +120 -55
  50. data/lib/chef/knife/cookbook_delete.rb +18 -12
  51. data/lib/chef/knife/cookbook_download.rb +10 -6
  52. data/lib/chef/knife/cookbook_list.rb +15 -6
  53. data/lib/chef/knife/cookbook_metadata.rb +41 -21
  54. data/lib/chef/knife/cookbook_metadata_from_file.rb +4 -0
  55. data/lib/chef/knife/cookbook_show.rb +16 -5
  56. data/lib/chef/knife/cookbook_site_download.rb +2 -2
  57. data/lib/chef/knife/cookbook_site_share.rb +18 -13
  58. data/lib/chef/knife/cookbook_site_unshare.rb +7 -4
  59. data/lib/chef/knife/cookbook_site_vendor.rb +21 -18
  60. data/lib/chef/knife/cookbook_test.rb +14 -14
  61. data/lib/chef/knife/cookbook_upload.rb +91 -40
  62. data/lib/chef/knife/data_bag_create.rb +41 -6
  63. data/lib/chef/knife/data_bag_delete.rb +5 -3
  64. data/lib/chef/knife/data_bag_edit.rb +55 -11
  65. data/lib/chef/knife/data_bag_from_file.rb +47 -7
  66. data/lib/chef/knife/data_bag_list.rb +4 -1
  67. data/lib/chef/knife/data_bag_show.rb +44 -4
  68. data/lib/chef/knife/environment_create.rb +53 -0
  69. data/lib/chef/knife/environment_delete.rb +45 -0
  70. data/lib/chef/knife/environment_edit.rb +45 -0
  71. data/lib/chef/knife/environment_from_file.rb +39 -0
  72. data/lib/chef/knife/environment_list.rb +42 -0
  73. data/lib/chef/knife/environment_show.rb +46 -0
  74. data/lib/chef/knife/exec.rb +1 -1
  75. data/lib/chef/knife/index_rebuild.rb +8 -9
  76. data/lib/chef/knife/node_bulk_delete.rb +9 -6
  77. data/lib/chef/knife/node_create.rb +9 -6
  78. data/lib/chef/knife/node_delete.rb +10 -7
  79. data/lib/chef/knife/node_edit.rb +129 -10
  80. data/lib/chef/knife/node_from_file.rb +10 -7
  81. data/lib/chef/knife/node_list.rb +11 -6
  82. data/lib/chef/knife/node_run_list_add.rb +10 -7
  83. data/lib/chef/knife/node_run_list_remove.rb +9 -6
  84. data/lib/chef/knife/node_show.rb +15 -7
  85. data/lib/chef/knife/recipe_list.rb +4 -3
  86. data/lib/chef/knife/role_bulk_delete.rb +9 -6
  87. data/lib/chef/knife/role_create.rb +9 -6
  88. data/lib/chef/knife/role_delete.rb +10 -7
  89. data/lib/chef/knife/role_edit.rb +11 -8
  90. data/lib/chef/knife/role_from_file.rb +10 -7
  91. data/lib/chef/knife/role_list.rb +8 -5
  92. data/lib/chef/knife/role_show.rb +11 -8
  93. data/lib/chef/knife/search.rb +33 -10
  94. data/lib/chef/knife/ssh.rb +33 -61
  95. data/lib/chef/knife/status.rb +7 -4
  96. data/lib/chef/knife/subcommand_loader.rb +101 -0
  97. data/lib/chef/knife/tag_create.rb +31 -0
  98. data/lib/chef/knife/tag_delete.rb +31 -0
  99. data/lib/chef/knife/tag_list.rb +29 -0
  100. data/lib/chef/knife/ui.rb +229 -0
  101. data/lib/chef/knife/windows_bootstrap.rb +8 -5
  102. data/lib/chef/log.rb +5 -59
  103. data/lib/chef/mash.rb +211 -0
  104. data/lib/chef/mixins.rb +1 -2
  105. data/lib/chef/nil_argument.rb +3 -0
  106. data/lib/chef/node.rb +96 -34
  107. data/lib/chef/platform.rb +27 -0
  108. data/lib/chef/provider/cookbook_file.rb +21 -20
  109. data/lib/chef/provider/deploy/revision.rb +3 -0
  110. data/lib/chef/provider/file.rb +20 -11
  111. data/lib/chef/provider/git.rb +26 -26
  112. data/lib/chef/provider/group/aix.rb +70 -0
  113. data/lib/chef/provider/group/groupadd.rb +7 -4
  114. data/lib/chef/provider/group/usermod.rb +1 -1
  115. data/lib/chef/provider/package.rb +28 -28
  116. data/lib/chef/provider/package/dpkg.rb +1 -1
  117. data/lib/chef/provider/package/portage.rb +50 -39
  118. data/lib/chef/provider/package/rubygems.rb +1 -1
  119. data/lib/chef/provider/package/zypper.rb +3 -20
  120. data/lib/chef/provider/remote_directory.rb +0 -2
  121. data/lib/chef/provider/remote_file.rb +2 -3
  122. data/lib/chef/provider/service/arch.rb +28 -35
  123. data/lib/chef/provider/service/simple.rb +1 -1
  124. data/lib/chef/provider/subversion.rb +22 -22
  125. data/lib/chef/providers.rb +1 -0
  126. data/lib/chef/recipe.rb +10 -12
  127. data/lib/chef/resource.rb +49 -42
  128. data/lib/chef/resource/gem_package.rb +7 -3
  129. data/lib/chef/resource/git.rb +5 -5
  130. data/lib/chef/resource/package.rb +7 -7
  131. data/lib/chef/resource/scm.rb +2 -1
  132. data/lib/chef/resource/solaris_package.rb +0 -1
  133. data/lib/chef/resource/yum_package.rb +0 -1
  134. data/lib/chef/rest.rb +7 -16
  135. data/lib/chef/rest/rest_request.rb +0 -16
  136. data/lib/chef/role.rb +67 -13
  137. data/lib/chef/run_context.rb +37 -21
  138. data/lib/chef/run_list.rb +30 -15
  139. data/lib/chef/run_list/run_list_expansion.rb +41 -20
  140. data/lib/chef/run_list/run_list_item.rb +20 -6
  141. data/lib/chef/run_list/versioned_recipe_list.rb +68 -0
  142. data/lib/chef/runner.rb +7 -15
  143. data/lib/chef/search/query.rb +12 -7
  144. data/lib/chef/shef.rb +6 -7
  145. data/lib/chef/shef/shef_session.rb +40 -35
  146. data/lib/chef/shell_out.rb +22 -201
  147. data/lib/chef/shell_out/unix.rb +224 -0
  148. data/lib/chef/shell_out/windows.rb +95 -0
  149. data/lib/chef/solr_query.rb +187 -0
  150. data/lib/chef/solr_query/lucene.treetop +145 -0
  151. data/lib/chef/solr_query/lucene_nodes.rb +285 -0
  152. data/lib/chef/solr_query/query_transform.rb +65 -0
  153. data/lib/chef/solr_query/solr_http_request.rb +118 -0
  154. data/lib/chef/version.rb +4 -2
  155. data/lib/chef/version_class.rb +70 -0
  156. data/lib/chef/version_constraint.rb +116 -0
  157. metadata +68 -37
  158. data/lib/chef/cookbook/metadata/version.rb +0 -87
  159. data/lib/chef/knife/bluebox_images_list.rb +0 -54
  160. data/lib/chef/knife/bluebox_server_create.rb +0 -157
  161. data/lib/chef/knife/bluebox_server_delete.rb +0 -63
  162. data/lib/chef/knife/bluebox_server_list.rb +0 -59
  163. data/lib/chef/knife/ec2_instance_data.rb +0 -46
  164. data/lib/chef/knife/ec2_server_create.rb +0 -218
  165. data/lib/chef/knife/ec2_server_delete.rb +0 -87
  166. data/lib/chef/knife/ec2_server_list.rb +0 -89
  167. data/lib/chef/knife/rackspace_server_create.rb +0 -184
  168. data/lib/chef/knife/rackspace_server_delete.rb +0 -57
  169. data/lib/chef/knife/rackspace_server_list.rb +0 -59
  170. data/lib/chef/knife/slicehost_images_list.rb +0 -53
  171. data/lib/chef/knife/slicehost_server_create.rb +0 -103
  172. data/lib/chef/knife/slicehost_server_delete.rb +0 -61
  173. data/lib/chef/knife/slicehost_server_list.rb +0 -64
  174. data/lib/chef/knife/terremark_server_create.rb +0 -152
  175. data/lib/chef/knife/terremark_server_delete.rb +0 -87
  176. data/lib/chef/knife/terremark_server_list.rb +0 -77
  177. data/lib/chef/mixin/find_preferred_file.rb +0 -92
@@ -0,0 +1,224 @@
1
+ class Chef
2
+ class ShellOut
3
+ module Unix
4
+
5
+ # Run the command, writing the command's standard out and standard error
6
+ # to +stdout+ and +stderr+, and saving its exit status object to +status+
7
+ # === Returns
8
+ # returns +self+; +stdout+, +stderr+, +status+, and +exitstatus+ will be
9
+ # populated with results of the command
10
+ # === Raises
11
+ # * Errno::EACCES when you are not privileged to execute the command
12
+ # * Errno::ENOENT when the command is not available on the system (or not
13
+ # in the current $PATH)
14
+ # * Chef::Exceptions::CommandTimeout when the command does not complete
15
+ # within +timeout+ seconds (default: 60s)
16
+ def run_command
17
+ Chef::Log.debug("sh(#{@command})")
18
+ @child_pid = fork_subprocess
19
+
20
+ configure_parent_process_file_descriptors
21
+ propagate_pre_exec_failure
22
+
23
+ @result = nil
24
+ @execution_time = 0
25
+
26
+ # Ruby 1.8.7 and 1.8.6 from mid 2009 try to allocate objects during GC
27
+ # when calling IO.select and IO#read. Some OS Vendors are not interested
28
+ # in updating their ruby packages (Apple, *cough*) and we *have to*
29
+ # make it work. So I give you this epic hack:
30
+ GC.disable
31
+ until @status
32
+ ready = IO.select(open_pipes, nil, nil, READ_WAIT_TIME)
33
+ unless ready
34
+ @execution_time += READ_WAIT_TIME
35
+ if @execution_time >= timeout && !@result
36
+ raise Chef::Exceptions::CommandTimeout, "command timed out:\n#{format_for_exception}"
37
+ end
38
+ end
39
+
40
+ if ready && ready.first.include?(child_stdout)
41
+ read_stdout_to_buffer
42
+ end
43
+ if ready && ready.first.include?(child_stderr)
44
+ read_stderr_to_buffer
45
+ end
46
+
47
+ unless @status
48
+ # make one more pass to get the last of the output after the
49
+ # child process dies
50
+ if results = Process.waitpid2(@child_pid, Process::WNOHANG)
51
+ @status = results.last
52
+ redo
53
+ end
54
+ end
55
+ end
56
+ self
57
+ rescue Exception
58
+ # do our best to kill zombies
59
+ Process.waitpid2(@child_pid, Process::WNOHANG) rescue nil
60
+ raise
61
+ ensure
62
+ # no matter what happens, turn the GC back on, and hope whatever busted
63
+ # version of ruby we're on doesn't allocate some objects during the next
64
+ # GC run.
65
+ GC.enable
66
+ close_all_pipes
67
+ end
68
+
69
+ private
70
+
71
+ def set_user
72
+ if user
73
+ Process.euid = uid
74
+ Process.uid = uid
75
+ end
76
+ end
77
+
78
+ def set_group
79
+ if group
80
+ Process.egid = gid
81
+ Process.gid = gid
82
+ end
83
+ end
84
+
85
+ def set_environment
86
+ environment.each do |env_var,value|
87
+ ENV[env_var] = value
88
+ end
89
+ end
90
+
91
+ def set_umask
92
+ File.umask(umask) if umask
93
+ end
94
+
95
+ def set_cwd
96
+ Dir.chdir(cwd) if cwd
97
+ end
98
+
99
+ def initialize_ipc
100
+ @stdout_pipe, @stderr_pipe, @process_status_pipe = IO.pipe, IO.pipe, IO.pipe
101
+ @process_status_pipe.last.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
102
+ end
103
+
104
+ def child_stdout
105
+ @stdout_pipe[0]
106
+ end
107
+
108
+ def child_stderr
109
+ @stderr_pipe[0]
110
+ end
111
+
112
+ def child_process_status
113
+ @process_status_pipe[0]
114
+ end
115
+
116
+ def close_all_pipes
117
+ child_stdout.close unless child_stdout.closed?
118
+ child_stderr.close unless child_stderr.closed?
119
+ child_process_status.close unless child_process_status.closed?
120
+ end
121
+
122
+ # replace stdout, and stderr with pipes to the parent, and close the
123
+ # reader side of the error marshaling side channel. Close STDIN so when we
124
+ # exec, the new program will know it's never getting input ever.
125
+ def configure_subprocess_file_descriptors
126
+ process_status_pipe.first.close
127
+
128
+ # HACK: for some reason, just STDIN.close isn't good enough when running
129
+ # under ruby 1.9.2, so make it good enough:
130
+ stdin_reader, stdin_writer = IO.pipe
131
+ stdin_writer.close
132
+ STDIN.reopen stdin_reader
133
+ stdin_reader.close
134
+
135
+ stdout_pipe.first.close
136
+ STDOUT.reopen stdout_pipe.last
137
+ stdout_pipe.last.close
138
+
139
+ stderr_pipe.first.close
140
+ STDERR.reopen stderr_pipe.last
141
+ stderr_pipe.last.close
142
+
143
+ STDOUT.sync = STDERR.sync = true
144
+ end
145
+
146
+ def configure_parent_process_file_descriptors
147
+ # Close the sides of the pipes we don't care about
148
+ stdout_pipe.last.close
149
+ stderr_pipe.last.close
150
+ process_status_pipe.last.close
151
+ # Get output as it happens rather than buffered
152
+ child_stdout.sync = true
153
+ child_stderr.sync = true
154
+
155
+ true
156
+ end
157
+
158
+ # Some patch levels of ruby in wide use (in particular the ruby 1.8.6 on OSX)
159
+ # segfault when you IO.select a pipe that's reached eof. Weak sauce.
160
+ def open_pipes
161
+ @open_pipes ||= [child_stdout, child_stderr]
162
+ end
163
+
164
+ def read_stdout_to_buffer
165
+ while chunk = child_stdout.read_nonblock(READ_SIZE)
166
+ @stdout << chunk
167
+ @live_stream << chunk if @live_stream
168
+ end
169
+ rescue Errno::EAGAIN
170
+ rescue EOFError
171
+ open_pipes.delete_at(0)
172
+ end
173
+
174
+ def read_stderr_to_buffer
175
+ while chunk = child_stderr.read_nonblock(READ_SIZE)
176
+ @stderr << chunk
177
+ end
178
+ rescue Errno::EAGAIN
179
+ rescue EOFError
180
+ open_pipes.delete_at(1)
181
+ end
182
+
183
+ def fork_subprocess
184
+ initialize_ipc
185
+
186
+ fork do
187
+ configure_subprocess_file_descriptors
188
+
189
+ set_user
190
+ set_group
191
+ set_environment
192
+ set_umask
193
+ set_cwd
194
+
195
+ begin
196
+ command.kind_of?(Array) ? exec(*command) : exec(command)
197
+
198
+ raise 'forty-two' # Should never get here
199
+ rescue Exception => e
200
+ Marshal.dump(e, process_status_pipe.last)
201
+ process_status_pipe.last.flush
202
+ end
203
+ process_status_pipe.last.close unless (process_status_pipe.last.closed?)
204
+ exit!
205
+ end
206
+ end
207
+
208
+ # Attempt to get a Marshaled error from the side-channel.
209
+ # If it's there, un-marshal it and raise. If it's not there,
210
+ # assume everything went well.
211
+ def propagate_pre_exec_failure
212
+ begin
213
+ e = Marshal.load child_process_status
214
+ raise(Exception === e ? e : "unknown failure: #{e.inspect}")
215
+ rescue EOFError # If we get an EOF error, then the exec was successful
216
+ true
217
+ ensure
218
+ child_process_status.close
219
+ end
220
+ end
221
+
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,95 @@
1
+ #--
2
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
3
+ # Copyright:: Copyright (c) 2011 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 'timeout'
20
+ require 'win32/open3'
21
+
22
+ class Chef
23
+ class ShellOut
24
+ module Windows
25
+
26
+ #--
27
+ # Missing lots of features from the UNIX version, such as
28
+ # environment, cwd, etc.
29
+ def run_command
30
+ Chef::Log.debug("sh(#{@command})")
31
+ # win32 open4 is really just open3.
32
+ Open3.popen3(@command) do |stdin,stdout,stderr|
33
+ @finished_stdout = false
34
+ @finished_stderr = false
35
+ stdin.close
36
+ stdout.sync = true
37
+ stderr.sync = true
38
+
39
+ # TBH, I really don't know what this will do when it times out.
40
+ # However, I'm powerless to make windows have non-blocking IO, so
41
+ # thread party it is.
42
+ Timeout.timeout(timeout) do
43
+ out_reader = Thread.new do
44
+ loop do
45
+ read_stdout(stdout)
46
+ break if @finished_stdout
47
+ end
48
+ end
49
+ err_reader = Thread.new do
50
+ loop do
51
+ read_stderr(stderr)
52
+ break if @finished_stderr
53
+ end
54
+ end
55
+
56
+ out_reader.join
57
+ err_reader.join
58
+
59
+ @status = $?
60
+ end
61
+ end
62
+
63
+ self
64
+
65
+ rescue Timeout::Error
66
+ raise Chef::Exceptions::CommandTimeout, "command timed out:\n#{format_for_exception}"
67
+ end
68
+
69
+ def read_stdout(stdout)
70
+ return nil if @finished_stdout
71
+ if chunk = stdout.sysread(8096)
72
+ @stdout << chunk
73
+ else
74
+ @finished_stdout = true
75
+ end
76
+ rescue EOFError
77
+ @finished_stdout = true
78
+ rescue Errno::EAGAIN
79
+ end
80
+
81
+ def read_stderr(stderr)
82
+ return nil if @finished_stderr
83
+ if chunk = stderr.sysread(8096)
84
+ @stderr << chunk
85
+ else
86
+ @finished_stderr = true
87
+ end
88
+ rescue EOFError
89
+ @finished_stderr = true
90
+ rescue Errno::EAGAIN
91
+ end
92
+
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,187 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Daniel DeLeo (<dan@opscode.com>)
4
+ # Author:: Seth Falcon (<seth@opscode.com>)
5
+ # Copyright:: Copyright (c) 2009-2011 Opscode, Inc.
6
+ # License:: Apache License, Version 2.0
7
+ #
8
+ # Licensed under the Apache License, Version 2.0 (the "License");
9
+ # you may not use this file except in compliance with the License.
10
+ # You may obtain a copy of the License at
11
+ #
12
+ # http://www.apache.org/licenses/LICENSE-2.0
13
+ #
14
+ # Unless required by applicable law or agreed to in writing, software
15
+ # distributed under the License is distributed on an "AS IS" BASIS,
16
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
+ # See the License for the specific language governing permissions and
18
+ # limitations under the License.
19
+ #
20
+
21
+ require 'chef/mixin/xml_escape'
22
+ require 'chef/log'
23
+ require 'chef/config'
24
+ require 'chef/couchdb'
25
+ require 'chef/solr_query/solr_http_request'
26
+ require 'chef/solr_query/query_transform'
27
+
28
+ class Chef
29
+ class SolrQuery
30
+
31
+ ID_KEY = "X_CHEF_id_CHEF_X"
32
+ DEFAULT_PARAMS = Mash.new(:start => 0, :rows => 1000, :sort => "#{ID_KEY} asc", :wt => 'json', :indent => 'off').freeze
33
+ FILTER_PARAM_MAP = {:database => 'X_CHEF_database_CHEF_X', :type => "X_CHEF_type_CHEF_X", :data_bag => 'data_bag'}
34
+ VALID_PARAMS = [:start,:rows,:sort,:q,:type]
35
+ BUILTIN_SEARCH_TYPES = ["role","node","client","environment"]
36
+ DATA_BAG_ITEM = 'data_bag_item'
37
+
38
+ include Chef::Mixin::XMLEscape
39
+
40
+ attr_accessor :query
41
+ attr_accessor :params
42
+
43
+ # Create a new Query object - takes the solr_url and optional
44
+ # Chef::CouchDB object to inflate objects into.
45
+ def initialize(couchdb = nil)
46
+ @filter_query = {}
47
+ @params = {}
48
+
49
+ if couchdb.nil?
50
+ @database = Chef::Config[:couchdb_database]
51
+ @couchdb = Chef::CouchDB.new(nil, Chef::Config[:couchdb_database])
52
+ else
53
+ unless couchdb.kind_of?(Chef::CouchDB)
54
+ Chef::Log.warn("Passing the database name to Chef::Solr::Query initialization is deprecated. Please pass in the Chef::CouchDB object instead.")
55
+ @database = couchdb
56
+ @couchdb = Chef::CouchDB.new(nil, couchdb)
57
+ else
58
+ @database = couchdb.couchdb_database
59
+ @couchdb = couchdb
60
+ end
61
+ end
62
+ end
63
+
64
+ def self.from_params(params, couchdb=nil)
65
+ query = new(couchdb)
66
+ query.params = VALID_PARAMS.inject({}) do |p, param_name|
67
+ p[param_name] = params[param_name] if params.key?(param_name)
68
+ p
69
+ end
70
+ query.update_filter_query_from_params
71
+ query.update_query_from_params
72
+ query
73
+ end
74
+
75
+ def filter_by(filter_query_params)
76
+ filter_query_params.each do |key, value|
77
+ @filter_query[FILTER_PARAM_MAP[key]] = value
78
+ end
79
+ end
80
+
81
+ def filter_query
82
+ @filter_query.map { |param, value| "+#{param}:#{value}" }.join(' ')
83
+ end
84
+
85
+ def filter_by_type(type)
86
+ case type
87
+ when *BUILTIN_SEARCH_TYPES
88
+ filter_by(:type => type)
89
+ else
90
+ filter_by(:type => DATA_BAG_ITEM, :data_bag => type)
91
+ end
92
+ end
93
+
94
+ def update_filter_query_from_params
95
+ filter_by(:database => @database)
96
+ filter_by_type(params.delete(:type))
97
+ end
98
+
99
+ def update_query_from_params
100
+ original_query = URI.decode(params.delete(:q) || "*:*")
101
+ @query = Chef::SolrQuery::QueryTransform.transform(original_query)
102
+ end
103
+
104
+ def objects
105
+ if !object_ids.empty?
106
+ @bulk_objects ||= @couchdb.bulk_get(object_ids)
107
+ Chef::Log.debug { "bulk get of objects: #{@bulk_objects.inspect}" }
108
+ @bulk_objects
109
+ else
110
+ []
111
+ end
112
+ end
113
+
114
+ def object_ids
115
+ @object_ids ||= results["response"]["docs"].map { |d| d[ID_KEY] }
116
+ end
117
+
118
+ def results
119
+ @results ||= SolrHTTPRequest.select(self.to_hash)
120
+ end
121
+
122
+ # Search Solr for objects of a given type, for a given query.
123
+ def search
124
+ { "rows" => objects, "start" => results["response"]["start"],
125
+ "total" => results["response"]["numFound"] }
126
+ end
127
+
128
+ def to_hash
129
+ options = DEFAULT_PARAMS.merge(params)
130
+ options[:fq] = filter_query
131
+ options[:q] = @query
132
+ options
133
+ end
134
+
135
+ START_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".freeze
136
+ START_DELETE_BY_QUERY = "<delete><query>".freeze
137
+ END_DELETE_BY_QUERY = "</query></delete>\n".freeze
138
+ COMMIT = "<commit/>\n".freeze
139
+
140
+ def commit(opts={})
141
+ SolrHTTPRequest.update("#{START_XML}#{COMMIT}")
142
+ end
143
+
144
+ def delete_database(db)
145
+ query_data = xml_escape("X_CHEF_database_CHEF_X:#{db}")
146
+ xml = "#{START_XML}#{START_DELETE_BY_QUERY}#{query_data}#{END_DELETE_BY_QUERY}"
147
+ SolrHTTPRequest.update(xml)
148
+ commit
149
+ end
150
+
151
+ def rebuild_index(db=Chef::Config[:couchdb_database])
152
+ delete_database(db)
153
+
154
+ results = {}
155
+ [Chef::ApiClient, Chef::Node, Chef::Role].each do |klass|
156
+ results[klass.name] = reindex_all(klass) ? "success" : "failed"
157
+ end
158
+ databags = Chef::DataBag.cdb_list(true)
159
+ Chef::Log.info("Reloading #{databags.size.to_s} #{Chef::DataBag} objects into the indexer")
160
+ databags.each { |i| i.add_to_index; i.list(true).each { |x| x.add_to_index } }
161
+ results[Chef::DataBag.name] = "success"
162
+ results
163
+ end
164
+
165
+ def reindex_all(klass, metadata={})
166
+ begin
167
+ items = klass.cdb_list(true)
168
+ Chef::Log.info("Reloading #{items.size.to_s} #{klass.name} objects into the indexer")
169
+ items.each { |i| i.add_to_index }
170
+ rescue Net::HTTPServerException => e
171
+ # 404s are okay, there might not be any of that kind of object...
172
+ if e.message =~ /Not Found/
173
+ Chef::Log.warn("Could not load #{klass.name} objects from couch for re-indexing (this is ok if you don't have any of these)")
174
+ return false
175
+ else
176
+ raise e
177
+ end
178
+ rescue Exception => e
179
+ Chef::Log.fatal("Chef encountered an error while attempting to load #{klass.name} objects back into the index")
180
+ raise e
181
+ end
182
+ true
183
+ end
184
+
185
+
186
+ end
187
+ end