chef 0.7.16 → 0.8.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of chef might be problematic. Click here for more details.

Files changed (180) hide show
  1. data/README.rdoc +11 -10
  2. data/bin/chef-client +2 -2
  3. data/bin/chef-solo +1 -1
  4. data/bin/knife +27 -0
  5. data/bin/shef +49 -0
  6. data/distro/README +2 -0
  7. data/distro/{debian → common}/man/man1/chef-indexer.1 +0 -0
  8. data/distro/{debian → common}/man/man1/chef-server.1 +0 -0
  9. data/distro/{debian → common}/man/man8/chef-client.8 +0 -0
  10. data/distro/{debian → common}/man/man8/chef-solo.8 +0 -0
  11. data/distro/common/man/man8/knife.8 +375 -0
  12. data/distro/redhat/etc/init.d/chef-client +8 -4
  13. data/distro/redhat/etc/init.d/chef-server +16 -15
  14. data/distro/redhat/etc/init.d/chef-server-webui +78 -0
  15. data/distro/redhat/etc/init.d/chef-solr +76 -0
  16. data/distro/redhat/etc/init.d/chef-solr-indexer +75 -0
  17. data/distro/redhat/etc/sysconfig/chef-client +10 -0
  18. data/distro/redhat/etc/sysconfig/chef-server +10 -0
  19. data/distro/redhat/etc/sysconfig/chef-server-webui +10 -0
  20. data/distro/redhat/etc/sysconfig/chef-solr +9 -0
  21. data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
  22. data/distro/suse/etc/init.d/chef-client +121 -0
  23. data/lib/chef.rb +1 -1
  24. data/lib/chef/api_client.rb +263 -0
  25. data/lib/chef/application.rb +1 -1
  26. data/lib/chef/application/client.rb +21 -3
  27. data/lib/chef/application/knife.rb +144 -0
  28. data/lib/chef/application/server.rb +2 -1
  29. data/lib/chef/application/solo.rb +9 -2
  30. data/lib/chef/cache.rb +61 -0
  31. data/lib/chef/cache/checksum.rb +70 -0
  32. data/lib/chef/certificate.rb +154 -0
  33. data/lib/chef/client.rb +123 -220
  34. data/lib/chef/compile.rb +9 -21
  35. data/lib/chef/config.rb +67 -10
  36. data/lib/chef/cookbook.rb +49 -22
  37. data/lib/chef/cookbook/metadata.rb +85 -5
  38. data/lib/chef/cookbook_loader.rb +4 -4
  39. data/lib/chef/couchdb.rb +99 -30
  40. data/lib/chef/daemon.rb +1 -1
  41. data/lib/chef/data_bag.rb +215 -0
  42. data/lib/chef/data_bag_item.rb +219 -0
  43. data/lib/chef/exceptions.rb +3 -0
  44. data/lib/chef/index_queue.rb +29 -0
  45. data/lib/chef/index_queue/amqp_client.rb +106 -0
  46. data/lib/chef/index_queue/consumer.rb +76 -0
  47. data/lib/chef/index_queue/indexable.rb +74 -0
  48. data/lib/chef/knife.rb +309 -0
  49. data/lib/chef/knife/client_bulk_delete.rb +40 -0
  50. data/lib/chef/knife/client_create.rb +62 -0
  51. data/lib/chef/knife/client_delete.rb +37 -0
  52. data/lib/chef/knife/client_edit.rb +37 -0
  53. data/lib/chef/knife/client_list.rb +40 -0
  54. data/lib/chef/knife/client_reregister.rb +48 -0
  55. data/lib/chef/knife/client_show.rb +42 -0
  56. data/lib/chef/knife/configure.rb +123 -0
  57. data/lib/chef/knife/cookbook_bulk_delete.rb +46 -0
  58. data/lib/chef/knife/cookbook_delete.rb +41 -0
  59. data/lib/chef/knife/cookbook_download.rb +57 -0
  60. data/lib/chef/knife/cookbook_list.rb +41 -0
  61. data/lib/chef/knife/cookbook_metadata.rb +87 -0
  62. data/lib/chef/knife/cookbook_show.rb +75 -0
  63. data/lib/chef/knife/cookbook_upload.rb +179 -0
  64. data/lib/chef/knife/data_bag_create.rb +43 -0
  65. data/lib/chef/knife/data_bag_delete.rb +43 -0
  66. data/lib/chef/knife/data_bag_edit.rb +49 -0
  67. data/lib/chef/knife/data_bag_list.rb +42 -0
  68. data/lib/chef/knife/data_bag_show.rb +40 -0
  69. data/lib/chef/knife/ec2_instance_data.rb +46 -0
  70. data/lib/chef/knife/index_rebuild.rb +51 -0
  71. data/lib/chef/knife/node_bulk_delete.rb +43 -0
  72. data/lib/chef/knife/node_create.rb +39 -0
  73. data/lib/chef/knife/node_delete.rb +36 -0
  74. data/lib/chef/knife/node_edit.rb +36 -0
  75. data/lib/chef/knife/node_from_file.rb +42 -0
  76. data/lib/chef/knife/node_list.rb +41 -0
  77. data/lib/chef/knife/node_run_list_add.rb +64 -0
  78. data/lib/chef/knife/node_run_list_remove.rb +45 -0
  79. data/lib/chef/knife/node_show.rb +46 -0
  80. data/lib/chef/knife/role_bulk_delete.rb +44 -0
  81. data/lib/chef/knife/role_create.rb +44 -0
  82. data/lib/chef/knife/role_delete.rb +36 -0
  83. data/lib/chef/knife/role_edit.rb +37 -0
  84. data/lib/chef/knife/role_from_file.rb +46 -0
  85. data/lib/chef/knife/role_list.rb +40 -0
  86. data/lib/chef/knife/role_show.rb +43 -0
  87. data/lib/chef/knife/search.rb +94 -0
  88. data/lib/chef/knife/ssh.rb +170 -0
  89. data/lib/chef/log.rb +30 -8
  90. data/lib/chef/mixin/checksum.rb +2 -7
  91. data/lib/chef/mixin/command.rb +32 -13
  92. data/lib/chef/mixin/convert_to_class_name.rb +15 -0
  93. data/lib/chef/mixin/deep_merge.rb +199 -11
  94. data/lib/chef/mixin/generate_url.rb +18 -9
  95. data/lib/chef/mixin/language.rb +29 -1
  96. data/lib/chef/mixin/language_include_attribute.rb +56 -0
  97. data/lib/chef/mixin/language_include_recipe.rb +53 -0
  98. data/lib/chef/mixin/params_validate.rb +25 -12
  99. data/lib/chef/mixin/recipe_definition_dsl_core.rb +2 -0
  100. data/lib/chef/mixin/template.rb +11 -1
  101. data/lib/chef/mixin/xml_escape.rb +87 -0
  102. data/lib/chef/node.rb +144 -122
  103. data/lib/chef/openid_registration.rb +12 -5
  104. data/lib/chef/platform.rb +89 -47
  105. data/lib/chef/provider/breakpoint.rb +36 -0
  106. data/lib/chef/provider/cron.rb +5 -6
  107. data/lib/chef/provider/deploy.rb +43 -10
  108. data/lib/chef/provider/deploy/revision.rb +2 -3
  109. data/lib/chef/provider/erl_call.rb +72 -0
  110. data/lib/chef/provider/file.rb +8 -4
  111. data/lib/chef/provider/git.rb +10 -5
  112. data/lib/chef/provider/group/dscl.rb +128 -0
  113. data/lib/chef/provider/http_request.rb +6 -2
  114. data/lib/chef/provider/ifconfig.rb +1 -0
  115. data/lib/chef/provider/link.rb +1 -1
  116. data/lib/chef/provider/log.rb +53 -0
  117. data/lib/chef/provider/mdadm.rb +88 -0
  118. data/lib/chef/provider/mount/mount.rb +1 -1
  119. data/lib/chef/provider/package.rb +1 -1
  120. data/lib/chef/provider/package/easy_install.rb +106 -0
  121. data/lib/chef/provider/package/pacman.rb +101 -0
  122. data/lib/chef/provider/package/portage.rb +1 -1
  123. data/lib/chef/provider/package/rpm.rb +10 -8
  124. data/lib/chef/provider/package/yum-dump.py +22 -3
  125. data/lib/chef/provider/package/yum.rb +32 -8
  126. data/lib/chef/provider/package/zypper.rb +132 -0
  127. data/lib/chef/provider/remote_directory.rb +58 -49
  128. data/lib/chef/provider/remote_file.rb +1 -1
  129. data/lib/chef/provider/route.rb +136 -80
  130. data/lib/chef/provider/ruby_block.rb +18 -1
  131. data/lib/chef/provider/service/arch.rb +109 -0
  132. data/lib/chef/provider/service/freebsd.rb +0 -1
  133. data/lib/chef/provider/service/simple.rb +2 -3
  134. data/lib/chef/provider/service/upstart.rb +191 -0
  135. data/lib/chef/provider/subversion.rb +12 -4
  136. data/lib/chef/provider/template.rb +85 -53
  137. data/lib/chef/provider/user.rb +1 -1
  138. data/lib/chef/provider/user/dscl.rb +277 -0
  139. data/lib/chef/provider/user/useradd.rb +1 -0
  140. data/lib/chef/recipe.rb +2 -41
  141. data/lib/chef/resource.rb +9 -3
  142. data/lib/chef/resource/breakpoint.rb +35 -0
  143. data/lib/chef/resource/deploy.rb +16 -2
  144. data/lib/chef/resource/easy_install_package.rb +41 -0
  145. data/lib/chef/resource/erl_call.rb +83 -0
  146. data/lib/chef/resource/freebsd_package.rb +35 -0
  147. data/lib/chef/resource/log.rb +62 -0
  148. data/lib/chef/resource/mdadm.rb +82 -0
  149. data/lib/chef/resource/pacman_package.rb +33 -0
  150. data/lib/chef/resource/ruby_block.rb +21 -2
  151. data/lib/chef/resource/scm.rb +8 -0
  152. data/lib/chef/resource/subversion.rb +1 -0
  153. data/lib/chef/resource/user.rb +5 -2
  154. data/lib/chef/resource/yum_package.rb +36 -0
  155. data/lib/chef/resource_collection.rb +17 -9
  156. data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
  157. data/lib/chef/rest.rb +166 -81
  158. data/lib/chef/role.rb +114 -38
  159. data/lib/chef/run_list.rb +15 -6
  160. data/lib/chef/runner.rb +13 -11
  161. data/lib/chef/search/query.rb +60 -0
  162. data/lib/chef/shef.rb +220 -0
  163. data/lib/chef/shef/ext.rb +297 -0
  164. data/lib/chef/shef/shef_session.rb +175 -0
  165. data/lib/chef/streaming_cookbook_uploader.rb +187 -0
  166. data/lib/chef/tasks/chef_repo.rake +53 -155
  167. data/lib/chef/util/file_edit.rb +94 -96
  168. data/lib/chef/webui_user.rb +233 -0
  169. metadata +219 -63
  170. data/distro/debian/etc/init.d/chef-indexer +0 -175
  171. data/distro/redhat/etc/chef/client.rb +0 -16
  172. data/distro/redhat/etc/chef/indexer.rb +0 -10
  173. data/distro/redhat/etc/chef/server.rb +0 -22
  174. data/distro/redhat/etc/init.d/chef-indexer +0 -76
  175. data/lib/chef/application/indexer.rb +0 -141
  176. data/lib/chef/queue.rb +0 -145
  177. data/lib/chef/search.rb +0 -88
  178. data/lib/chef/search/result.rb +0 -64
  179. data/lib/chef/search_index.rb +0 -77
  180. data/lib/chef/util/fileedit.rb +0 -121
@@ -38,7 +38,7 @@ class Chef
38
38
 
39
39
  def load_cookbooks
40
40
  cookbook_settings = Hash.new
41
- [Chef::Config.cookbook_path].flatten.reverse.each do |cb_path|
41
+ [Chef::Config.cookbook_path].flatten.each do |cb_path|
42
42
  Dir[File.join(cb_path, "*")].each do |cookbook|
43
43
  next unless File.directory?(cookbook)
44
44
  cookbook_name = File.basename(cookbook).to_sym
@@ -128,11 +128,11 @@ class Chef
128
128
  end
129
129
 
130
130
  def each
131
- @cookbook.each_value do |cobject|
132
- yield cobject
131
+ @cookbook.keys.sort { |a,b| a.to_s <=> b.to_s }.each do |cname|
132
+ yield @cookbook[cname]
133
133
  end
134
134
  end
135
-
135
+
136
136
  private
137
137
 
138
138
  def load_ignore_file(ignore_file)
@@ -1,5 +1,6 @@
1
1
  #
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Brown (<cb@opscode.com>)
3
4
  # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
5
  # License:: Apache License, Version 2.0
5
6
  #
@@ -22,39 +23,76 @@ require 'chef/log'
22
23
  require 'digest/sha2'
23
24
  require 'json'
24
25
 
26
+ # We want to fail on create if uuidtools isn't installed
27
+ begin
28
+ require 'uuidtools'
29
+ rescue LoadError
30
+ end
31
+
25
32
  class Chef
26
33
  class CouchDB
27
34
  include Chef::Mixin::ParamsValidate
28
35
 
29
- def initialize(url=nil)
36
+ def initialize(url=nil, db=Chef::Config[:couchdb_database])
30
37
  url ||= Chef::Config[:couchdb_url]
31
- @rest = Chef::REST.new(url)
38
+ @db = db
39
+ @rest = Chef::REST.new(url, nil, nil)
32
40
  end
33
-
41
+
42
+ def couchdb_database(args=nil)
43
+ @db = args || @db
44
+ end
45
+
46
+ def create_id_map
47
+ create_design_document(
48
+ "id_map",
49
+ {
50
+ "version" => 1,
51
+ "language" => "javascript",
52
+ "views" => {
53
+ "name_to_id" => {
54
+ "map" => <<-EOJS
55
+ function(doc) {
56
+ emit([ doc.chef_type, doc.name], doc._id);
57
+ }
58
+ EOJS
59
+ },
60
+ "id_to_name" => {
61
+ "map" => <<-EOJS
62
+ function(doc) {
63
+ emit(doc._id, [ doc.chef_type, doc.name ]);
64
+ }
65
+ EOJS
66
+ }
67
+ }
68
+ }
69
+ )
70
+ end
71
+
34
72
  def create_db
35
73
  @database_list = @rest.get_rest("_all_dbs")
36
- unless @database_list.detect { |db| db == Chef::Config[:couchdb_database] }
37
- response = @rest.put_rest(Chef::Config[:couchdb_database], Hash.new)
74
+ unless @database_list.detect { |db| db == couchdb_database }
75
+ response = @rest.put_rest(couchdb_database, Hash.new)
38
76
  end
39
- Chef::Config[:couchdb_database]
77
+ couchdb_database
40
78
  end
41
79
 
42
80
  def create_design_document(name, data)
43
81
  create_db
44
82
  to_update = true
45
83
  begin
46
- old_doc = @rest.get_rest("#{Chef::Config[:couchdb_database]}/_design%2F#{name}")
84
+ old_doc = @rest.get_rest("#{couchdb_database}/_design/#{name}")
47
85
  if data["version"] != old_doc["version"]
48
86
  data["_rev"] = old_doc["_rev"]
49
87
  Chef::Log.debug("Updating #{name} views")
50
88
  else
51
89
  to_update = false
52
90
  end
53
- rescue
54
- Chef::Log.debug("Creating #{name} views for the first time")
91
+ rescue
92
+ Chef::Log.debug("Creating #{name} views for the first time because: #{$!}")
55
93
  end
56
94
  if to_update
57
- @rest.put_rest("#{Chef::Config[:couchdb_database]}/_design%2F#{name}", data)
95
+ @rest.put_rest("#{couchdb_database}/_design%2F#{name}", data)
58
96
  end
59
97
  true
60
98
  end
@@ -70,7 +108,15 @@ class Chef
70
108
  :object => { :respond_to => :to_json },
71
109
  }
72
110
  )
73
- @rest.put_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}", object)
111
+ rows = get_view("id_map", "name_to_id", :key => [ obj_type, name ])["rows"]
112
+ uuid = rows.empty? ? UUIDTools::UUID.random_create.to_s : rows.first.fetch("id")
113
+
114
+ db_put_response = @rest.put_rest("#{couchdb_database}/#{uuid}", object)
115
+
116
+ Chef::Log.info("Sending #{obj_type}(#{uuid}) to the index queue for addition.")
117
+ object.add_to_index(:database => couchdb_database, :id => uuid, :type => obj_type)
118
+
119
+ db_put_response
74
120
  end
75
121
 
76
122
  def load(obj_type, name)
@@ -83,8 +129,10 @@ class Chef
83
129
  :obj_type => { :kind_of => String },
84
130
  :name => { :kind_of => String },
85
131
  }
86
- )
87
- @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
132
+ )
133
+ doc = find_by_name(obj_type, name)
134
+ doc.couchdb = self if doc.respond_to?(:couchdb)
135
+ doc
88
136
  end
89
137
 
90
138
  def delete(obj_type, name, rev=nil)
@@ -98,15 +146,22 @@ class Chef
98
146
  :name => { :kind_of => String },
99
147
  }
100
148
  )
149
+ del_id = nil
150
+ object, uuid = find_by_name(obj_type, name, true)
101
151
  unless rev
102
- last_obj = @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
103
- if last_obj.respond_to?(:couchdb_rev)
104
- rev = last_obj.couchdb_rev
152
+ if object.respond_to?(:couchdb_rev)
153
+ rev = object.couchdb_rev
105
154
  else
106
- rev = last_obj['_rev']
155
+ rev = object['_rev']
107
156
  end
108
157
  end
109
- @rest.delete_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}?rev=#{rev}")
158
+ response = @rest.delete_rest("#{couchdb_database}/#{uuid}?rev=#{rev}")
159
+ response.couchdb = self if response.respond_to?(:couchdb=)
160
+ Chef::Log.info("Sending #{obj_type}(#{uuid}) to the index queue for deletion..")
161
+
162
+ object.delete_from_index(:database => couchdb_database, :id => uuid, :type => obj_type)
163
+
164
+ response
110
165
  end
111
166
 
112
167
  def list(view, inflate=false)
@@ -119,10 +174,13 @@ class Chef
119
174
  }
120
175
  )
121
176
  if inflate
122
- @rest.get_rest(view_uri(view, "all"))
177
+ r = @rest.get_rest(view_uri(view, "all"))
178
+ r["rows"].each { |i| i["value"].couchdb = self if i["value"].respond_to?(:couchdb=) }
179
+ r
123
180
  else
124
- @rest.get_rest(view_uri(view, "all_id"))
181
+ r = @rest.get_rest(view_uri(view, "all_id"))
125
182
  end
183
+ r
126
184
  end
127
185
 
128
186
  def has_key?(obj_type, name)
@@ -137,13 +195,25 @@ class Chef
137
195
  }
138
196
  )
139
197
  begin
140
- @rest.get_rest("#{Chef::Config[:couchdb_database]}/#{obj_type}_#{safe_name(name)}")
198
+ find_by_name(obj_type, name)
141
199
  true
142
200
  rescue
143
201
  false
144
202
  end
145
203
  end
146
204
 
205
+ def find_by_name(obj_type, name, with_id=false)
206
+ r = get_view("id_map", "name_to_id", :key => [ obj_type, name ], :include_docs => true)
207
+ if r["rows"].length == 0
208
+ raise Chef::Exceptions::CouchDBNotFound, "Cannot find #{obj_type} #{name} in CouchDB!"
209
+ end
210
+ if with_id
211
+ [ r["rows"][0]["doc"], r["rows"][0]["id"] ]
212
+ else
213
+ r["rows"][0]["doc"]
214
+ end
215
+ end
216
+
147
217
  def get_view(design, view, options={})
148
218
  view_string = view_uri(design, view)
149
219
  view_string << "?" if options.length != 0
@@ -151,26 +221,25 @@ class Chef
151
221
  options.each { |k,v| view_string << "#{first ? '' : '&'}#{k}=#{URI.escape(v.to_json)}"; first = false }
152
222
  @rest.get_rest(view_string)
153
223
  end
224
+
225
+ def bulk_get(*to_fetch)
226
+ response = @rest.post_rest("#{couchdb_database}/_all_docs?include_docs=true", { "keys" => to_fetch.flatten })
227
+ response["rows"].collect { |r| r["doc"] }
228
+ end
154
229
 
155
230
  def view_uri(design, view)
156
231
  Chef::Config[:couchdb_version] ||= @rest.run_request(:GET,
157
232
  URI.parse(@rest.url + "/"),
158
- false,
233
+ {},
159
234
  10,
160
235
  false)["version"].gsub(/-.+/,"").to_f
161
236
  case Chef::Config[:couchdb_version]
162
237
  when 0.8
163
- "#{Chef::Config[:couchdb_database]}/_view/#{design}/#{view}"
238
+ "#{couchdb_database}/_view/#{design}/#{view}"
164
239
  else
165
- "#{Chef::Config[:couchdb_database]}/_design/#{design}/_view/#{view}"
240
+ "#{couchdb_database}/_design/#{design}/_view/#{view}"
166
241
  end
167
242
  end
168
243
 
169
- private
170
-
171
- def safe_name(name)
172
- name.gsub(/\./, "_")
173
- end
174
-
175
244
  end
176
245
  end
@@ -44,7 +44,7 @@ class Chef
44
44
  File.umask Chef::Config[:umask]
45
45
  $stdin.reopen("/dev/null")
46
46
  $stdout.reopen("/dev/null", "a")
47
- $stdout.reopen($stdout)
47
+ $stderr.reopen($stdout)
48
48
  save_pid_file
49
49
  at_exit { remove_pid_file }
50
50
  rescue NotImplementedError => e
@@ -0,0 +1,215 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Nuo Yan (<nuo@opscode.com>)
4
+ # Author:: Christopher Brown (<cb@opscode.com>)
5
+ # Copyright:: Copyright (c) 2009 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/config'
22
+ require 'chef/mixin/params_validate'
23
+ require 'chef/mixin/from_file'
24
+ require 'chef/couchdb'
25
+ require 'chef/data_bag_item'
26
+ require 'chef/index_queue'
27
+ require 'extlib'
28
+ require 'json'
29
+
30
+ class Chef
31
+ class DataBag
32
+
33
+ include Chef::Mixin::FromFile
34
+ include Chef::Mixin::ParamsValidate
35
+ include Chef::IndexQueue::Indexable
36
+
37
+ DESIGN_DOCUMENT = {
38
+ "version" => 2,
39
+ "language" => "javascript",
40
+ "views" => {
41
+ "all" => {
42
+ "map" => <<-EOJS
43
+ function(doc) {
44
+ if (doc.chef_type == "data_bag") {
45
+ emit(doc.name, doc);
46
+ }
47
+ }
48
+ EOJS
49
+ },
50
+ "all_id" => {
51
+ "map" => <<-EOJS
52
+ function(doc) {
53
+ if (doc.chef_type == "data_bag") {
54
+ emit(doc.name, doc.name);
55
+ }
56
+ }
57
+ EOJS
58
+ },
59
+ "entries" => {
60
+ "map" => <<-EOJS
61
+ function(doc) {
62
+ if (doc.chef_type == "data_bag_item") {
63
+ emit(doc.data_bag, doc.raw_data.id);
64
+ }
65
+ }
66
+ EOJS
67
+ }
68
+ }
69
+ }
70
+
71
+ attr_accessor :couchdb_rev, :couchdb_id, :couchdb
72
+
73
+ # Create a new Chef::DataBag
74
+ def initialize(couchdb=nil)
75
+ @name = ''
76
+ @couchdb_rev = nil
77
+ @couchdb_id = nil
78
+ @couchdb = (couchdb || Chef::CouchDB.new)
79
+ end
80
+
81
+ def name(arg=nil)
82
+ set_or_return(
83
+ :name,
84
+ arg,
85
+ :regex => /^[\-[:alnum:]_]+$/
86
+ )
87
+ end
88
+
89
+ def to_hash
90
+ result = {
91
+ "name" => @name,
92
+ 'json_class' => self.class.name,
93
+ "chef_type" => "data_bag",
94
+ }
95
+ result["_rev"] = @couchdb_rev if @couchdb_rev
96
+ result
97
+ end
98
+
99
+ # Serialize this object as a hash
100
+ def to_json(*a)
101
+ to_hash.to_json(*a)
102
+ end
103
+
104
+ def chef_server_rest
105
+ Chef::REST.new(Chef::Config[:chef_server_url])
106
+ end
107
+
108
+ def self.chef_server_rest
109
+ Chef::REST.new(Chef::Config[:chef_server_url])
110
+ end
111
+
112
+ # Create a Chef::Role from JSON
113
+ def self.json_create(o)
114
+ bag = new
115
+ bag.name(o["name"])
116
+ bag.couchdb_rev = o["_rev"] if o.has_key?("_rev")
117
+ bag.couchdb_id = o["_id"] if o.has_key?("_id")
118
+ bag.index_id = bag.couchdb_id
119
+ bag
120
+ end
121
+
122
+ # List all the Chef::DataBag objects in the CouchDB. If inflate is set to true, you will get
123
+ # the full list of all Roles, fully inflated.
124
+ def self.cdb_list(inflate=false, couchdb=nil)
125
+ rs = (couchdb || Chef::CouchDB.new).list("data_bags", inflate)
126
+ lookup = (inflate ? "value" : "key")
127
+ rs["rows"].collect { |r| r[lookup] }
128
+ end
129
+
130
+ def self.list(inflate=false)
131
+ if inflate
132
+ response = Hash.new
133
+ Chef::Search::Query.new.search(:data) do |n|
134
+ response[n.name] = n
135
+ end
136
+ response
137
+ else
138
+ Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data")
139
+ end
140
+ end
141
+
142
+ # Load a Data Bag by name from CouchDB
143
+ def self.cdb_load(name, couchdb=nil)
144
+ (couchdb || Chef::CouchDB.new).load("data_bag", name)
145
+ end
146
+
147
+ # Load a Data Bag by name via the RESTful API
148
+ def self.load(name)
149
+ Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
150
+ end
151
+
152
+ # Remove this Data Bag from CouchDB
153
+ def cdb_destroy
154
+ removed = @couchdb.delete("data_bag", @name, @couchdb_rev)
155
+ rs = @couchdb.get_view("data_bags", "entries", :include_docs => true, :startkey => @name, :endkey => @name)
156
+ rs["rows"].each do |row|
157
+ row["doc"].couchdb = couchdb
158
+ row["doc"].cdb_destroy
159
+ end
160
+ removed
161
+ end
162
+
163
+ def destroy
164
+ chef_server_rest.delete_rest("data/#{@name}")
165
+ end
166
+
167
+ # Save this Data Bag to the CouchDB
168
+ def cdb_save
169
+ results = @couchdb.store("data_bag", @name, self)
170
+ @couchdb_rev = results["rev"]
171
+ end
172
+
173
+ # Save the Data Bag via RESTful API
174
+ def save
175
+ begin
176
+ chef_server_rest.put_rest("data/#{@name}", self)
177
+ rescue Net::HTTPServerException => e
178
+ raise e unless e.response.code == "404"
179
+ chef_server_rest.post_rest("data", self)
180
+ end
181
+ self
182
+ end
183
+
184
+ #create a data bag via RESTful API
185
+ def create
186
+ chef_server_rest.post_rest("data", self)
187
+ self
188
+ end
189
+
190
+ # List all the items in this Bag from CouchDB
191
+ # The self.load method does this through the REST API
192
+ def list(inflate=false)
193
+ rs = nil
194
+ if inflate
195
+ rs = @couchdb.get_view("data_bags", "entries", :include_docs => true, :startkey => @name, :endkey => @name)
196
+ rs["rows"].collect { |r| r["doc"] }
197
+ else
198
+ rs = @couchdb.get_view("data_bags", "entries", :startkey => @name, :endkey => @name)
199
+ rs["rows"].collect { |r| r["value"] }
200
+ end
201
+ end
202
+
203
+ # Set up our CouchDB design document
204
+ def self.create_design_document(couchdb=nil)
205
+ (couchdb || Chef::CouchDB.new).create_design_document("data_bags", DESIGN_DOCUMENT)
206
+ end
207
+
208
+ # As a string
209
+ def to_s
210
+ "data_bag[#{@name}]"
211
+ end
212
+
213
+ end
214
+ end
215
+