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,100 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef'
20
+ require 'chef/config'
21
+ require 'chef/mixin/params_validate'
22
+ require 'json'
23
+
24
+ # The client doesn't use this class, so we are cool without having it
25
+ begin
26
+ require 'nanite'
27
+ require 'uuidtools'
28
+ rescue LoadError
29
+ end
30
+
31
+ class Chef
32
+ class Nanite
33
+
34
+ class << self
35
+
36
+ def start_mapper(config={})
37
+ Chef::Log.info("Running the Nanite Mapper")
38
+ ::Nanite::Log.logger = Chef::Log.logger
39
+ identity = get_identity
40
+ ::Nanite.start_mapper(
41
+ :host => Chef::Config[:nanite_host],
42
+ :user => Chef::Config[:nanite_user],
43
+ :pass => Chef::Config[:nanite_pass],
44
+ :vhost => Chef::Config[:nanite_vhost],
45
+ :identity => identity,
46
+ :format => :json,
47
+ :log_level => Chef::Config[:log_level]
48
+ )
49
+ end
50
+
51
+ def get_identity(type="mapper")
52
+ id = nil
53
+ if Chef::Config[:nanite_persistent_mapper]
54
+ if Chef::FileCache.has_key?("nanite-#{type}-identity")
55
+ id = Chef::FileCache.load("nanite-#{type}-identity")
56
+ else
57
+ id = UUIDTools::UUID.random_create.to_s
58
+ Chef::FileCache.store("nanite-#{type}-identity", id)
59
+ end
60
+ else
61
+ id = Chef::Config[:nanite_identity] ? "#{Chef::Config[:nanite_identity]}-#{UUIDTools::UUID.random_create.to_s}" : UUIDTools::UUID.random_create.to_s
62
+ end
63
+ id
64
+ end
65
+
66
+ def request(*args)
67
+ in_event do
68
+ ::Nanite.request(*args)
69
+ end
70
+ end
71
+
72
+ def push(*args)
73
+ in_event do
74
+ ::Nanite.push(*args)
75
+ end
76
+ end
77
+
78
+ def in_event(&block)
79
+ if EM.reactor_running?
80
+ begin
81
+ ::Nanite.ensure_mapper
82
+ rescue ::Nanite::MapperNotRunning
83
+ start_mapper
84
+ end
85
+ block.call
86
+ else
87
+ Chef::Log.warn("Starting Event Machine Loop")
88
+ Thread.new do
89
+ EM.run do
90
+ start_mapper
91
+ block.call
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,463 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/config'
20
+ require 'chef/mixin/check_helper'
21
+ require 'chef/mixin/params_validate'
22
+ require 'chef/mixin/from_file'
23
+ require 'chef/mixin/language_include_attribute'
24
+ require 'chef/couchdb'
25
+ require 'chef/rest'
26
+ require 'chef/run_list'
27
+ require 'chef/node/attribute'
28
+ require 'extlib'
29
+ require 'json'
30
+
31
+ class Chef
32
+ class Node
33
+
34
+ attr_accessor :attribute, :recipe_list, :couchdb_rev, :couchdb_id, :run_state, :run_list, :override_attrs, :default_attrs, :cookbook_loader
35
+
36
+ include Chef::Mixin::CheckHelper
37
+ include Chef::Mixin::FromFile
38
+ include Chef::Mixin::ParamsValidate
39
+ include Chef::Mixin::LanguageIncludeAttribute
40
+
41
+ DESIGN_DOCUMENT = {
42
+ "version" => 9,
43
+ "language" => "javascript",
44
+ "views" => {
45
+ "all" => {
46
+ "map" => <<-EOJS
47
+ function(doc) {
48
+ if (doc.chef_type == "node") {
49
+ emit(doc.name, doc);
50
+ }
51
+ }
52
+ EOJS
53
+ },
54
+ "all_id" => {
55
+ "map" => <<-EOJS
56
+ function(doc) {
57
+ if (doc.chef_type == "node") {
58
+ emit(doc.name, doc.name);
59
+ }
60
+ }
61
+ EOJS
62
+ },
63
+ "status" => {
64
+ "map" => <<-EOJS
65
+ function(doc) {
66
+ if (doc.chef_type == "node") {
67
+ var to_emit = { "name": doc.name };
68
+ if (doc["attributes"]["fqdn"]) {
69
+ to_emit["fqdn"] = doc["attributes"]["fqdn"];
70
+ } else {
71
+ to_emit["fqdn"] = "Undefined";
72
+ }
73
+ if (doc["attributes"]["ipaddress"]) {
74
+ to_emit["ipaddress"] = doc["attributes"]["ipaddress"];
75
+ } else {
76
+ to_emit["ipaddress"] = "Undefined";
77
+ }
78
+ if (doc["attributes"]["ohai_time"]) {
79
+ to_emit["ohai_time"] = doc["attributes"]["ohai_time"];
80
+ } else {
81
+ to_emit["ohai_time"] = "Undefined";
82
+ }
83
+ if (doc["attributes"]["uptime"]) {
84
+ to_emit["uptime"] = doc["attributes"]["uptime"];
85
+ } else {
86
+ to_emit["uptime"] = "Undefined";
87
+ }
88
+ if (doc["attributes"]["platform"]) {
89
+ to_emit["platform"] = doc["attributes"]["platform"];
90
+ } else {
91
+ to_emit["platform"] = "Undefined";
92
+ }
93
+ if (doc["attributes"]["platform_version"]) {
94
+ to_emit["platform_version"] = doc["attributes"]["platform_version"];
95
+ } else {
96
+ to_emit["platform_version"] = "Undefined";
97
+ }
98
+ if (doc["run_list"]) {
99
+ to_emit["run_list"] = doc["run_list"];
100
+ } else {
101
+ to_emit["run_list"] = "Undefined";
102
+ }
103
+ emit(doc.name, to_emit);
104
+ }
105
+ }
106
+ EOJS
107
+ },
108
+ "by_run_list" => {
109
+ "map" => <<-EOJS
110
+ function(doc) {
111
+ if (doc.chef_type == "node") {
112
+ if (doc['run_list']) {
113
+ for (var i=0; i < doc.run_list.length; i++) {
114
+ emit(doc['run_list'][i], doc.name);
115
+ }
116
+ }
117
+ }
118
+ }
119
+ EOJS
120
+ }
121
+ },
122
+ }
123
+
124
+ # Create a new Chef::Node object.
125
+ def initialize
126
+ @name = nil
127
+
128
+ @attribute = Mash.new
129
+ @override_attrs = Mash.new
130
+ @default_attrs = Mash.new
131
+ @run_list = Chef::RunList.new
132
+
133
+ @couchdb_rev = nil
134
+ @couchdb_id = nil
135
+ @couchdb = Chef::CouchDB.new
136
+
137
+ @run_state = {
138
+ :template_cache => Hash.new,
139
+ :seen_recipes => Hash.new,
140
+ :seen_attributes => Hash.new
141
+ }
142
+ end
143
+
144
+ # Find a recipe for this Chef::Node by fqdn. Will search first for
145
+ # Chef::Config["node_path"]/fqdn.rb, then hostname.rb, then default.rb.
146
+ #
147
+ # Returns a new Chef::Node object.
148
+ #
149
+ # Raises an ArgumentError if it cannot find the node.
150
+ def find_file(fqdn)
151
+ node_file = nil
152
+ host_parts = fqdn.split(".")
153
+ hostname = host_parts[0]
154
+
155
+ if File.exists?(File.join(Chef::Config[:node_path], "#{fqdn}.rb"))
156
+ node_file = File.join(Chef::Config[:node_path], "#{fqdn}.rb")
157
+ elsif File.exists?(File.join(Chef::Config[:node_path], "#{hostname}.rb"))
158
+ node_file = File.join(Chef::Config[:node_path], "#{hostname}.rb")
159
+ elsif File.exists?(File.join(Chef::Config[:node_path], "default.rb"))
160
+ node_file = File.join(Chef::Config[:node_path], "default.rb")
161
+ end
162
+ unless node_file
163
+ raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
164
+ end
165
+ self.from_file(node_file)
166
+ end
167
+
168
+ # Set the name of this Node, or return the current name.
169
+ def name(arg=nil)
170
+ if arg != nil
171
+ validate(
172
+ { :name => arg },
173
+ {
174
+ :name => {
175
+ :kind_of => String
176
+ }
177
+ }
178
+ )
179
+ @name = arg
180
+ else
181
+ @name
182
+ end
183
+ end
184
+
185
+ # Return an attribute of this node. Returns nil if the attribute is not found.
186
+ def [](attrib)
187
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
188
+ attrs[attrib]
189
+ end
190
+
191
+ # Set an attribute of this node
192
+ def []=(attrib, value)
193
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
194
+ attrs[attrib] = value
195
+ end
196
+
197
+ def store(attrib, value)
198
+ self[attrib] = value
199
+ end
200
+
201
+ # Set an attribute of this node, but auto-vivifiy any Mashes that might
202
+ # be missing
203
+ def set
204
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
205
+ attrs.auto_vivifiy_on_read = true
206
+ attrs
207
+ end
208
+
209
+ # Set an attribute of this node, auto-vivifiying any mashes that are
210
+ # missing, but if the final value already exists, don't set it
211
+ def set_unless
212
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
213
+ attrs.auto_vivifiy_on_read = true
214
+ attrs.set_unless_value_present = true
215
+ attrs
216
+ end
217
+
218
+ alias_method :default, :set_unless
219
+
220
+ # Return true if this Node has a given attribute, false if not. Takes either a symbol or
221
+ # a string.
222
+ #
223
+ # Only works on the top level. Preferred way is to use the normal [] style
224
+ # lookup and call attribute?()
225
+ def attribute?(attrib)
226
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
227
+ attrs.attribute?(attrib)
228
+ end
229
+
230
+ # Yield each key of the top level to the block.
231
+ def each(&block)
232
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
233
+ attrs.each(&block)
234
+ end
235
+
236
+ # Iterates over each attribute, passing the attribute and value to the block.
237
+ def each_attribute(&block)
238
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
239
+ attrs.each_attribute(&block)
240
+ end
241
+
242
+ # Set an attribute based on the missing method. If you pass an argument, we'll use that
243
+ # to set the attribute values. Otherwise, we'll wind up just returning the attributes
244
+ # value.
245
+ def method_missing(symbol, *args)
246
+ attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
247
+ attrs.send(symbol, *args)
248
+ end
249
+
250
+ # Returns true if this Node expects a given recipe, false if not.
251
+ def recipe?(recipe_name)
252
+ if @run_list.include?(recipe_name)
253
+ true
254
+ else
255
+ if @run_state[:seen_recipes].include?(recipe_name)
256
+ true
257
+ else
258
+ false
259
+ end
260
+ end
261
+ end
262
+
263
+ # Returns an Array of recipes. If you call it with arguments, they will become the new
264
+ # list of recipes.
265
+ def recipes(*args)
266
+ if args.length > 0
267
+ @run_list.reset(args)
268
+ else
269
+ @run_list
270
+ end
271
+ end
272
+
273
+ # Returns true if this Node expects a given role, false if not.
274
+ def role?(role_name)
275
+ @run_list.include?("role[#{role_name}]")
276
+ end
277
+
278
+ # Returns an Array of roles and recipes, in the order they will be applied.
279
+ # If you call it with arguments, they will become the new list of roles and recipes.
280
+ def run_list(*args)
281
+ if args.length > 0
282
+ @run_list.reset(args)
283
+ else
284
+ @run_list
285
+ end
286
+ end
287
+
288
+ # Returns true if this Node expects a given role, false if not.
289
+ def run_list?(item)
290
+ @run_list.detect { |r| r == item } ? true : false
291
+ end
292
+
293
+ def consume_attributes(attrs)
294
+ attrs ||= {}
295
+ Chef::Log.debug("Adding JSON Attributes")
296
+ attrs.each do |key, value|
297
+ if ["recipes", "run_list"].include?(key)
298
+ append_recipes(value)
299
+ else
300
+ Chef::Log.debug("JSON Attribute: #{key} - #{value.inspect}")
301
+ store(key, value)
302
+ end
303
+ end
304
+ self[:tags] = Array.new unless attribute?(:tags)
305
+
306
+ end
307
+
308
+ # Transform the node to a Hash
309
+ def to_hash
310
+ index_hash = Hash.new
311
+ self.each do |k, v|
312
+ index_hash[k] = v
313
+ end
314
+ index_hash["chef_type"] = "node"
315
+ index_hash["name"] = @name
316
+ index_hash["recipe"] = @run_list.recipes if @run_list.recipes.length > 0
317
+ index_hash["role"] = @run_list.roles if @run_list.roles.length > 0
318
+ index_hash["run_list"] = @run_list.run_list if @run_list.run_list.length > 0
319
+ index_hash
320
+ end
321
+
322
+ # Serialize this object as a hash
323
+ def to_json(*a)
324
+ result = {
325
+ "name" => @name,
326
+ 'json_class' => self.class.name,
327
+ "attributes" => @attribute,
328
+ "chef_type" => "node",
329
+ "defaults" => @default_attrs,
330
+ "overrides" => @override_attrs,
331
+ "run_list" => @run_list.run_list,
332
+ }
333
+ result["_rev"] = @couchdb_rev if @couchdb_rev
334
+ result.to_json(*a)
335
+ end
336
+
337
+ # Create a Chef::Node from JSON
338
+ def self.json_create(o)
339
+ node = new
340
+ node.name(o["name"])
341
+ o["attributes"].each do |k,v|
342
+ node[k] = v
343
+ end
344
+ if o.has_key?("defaults")
345
+ node.default_attrs = Mash.new(o["defaults"])
346
+ end
347
+ if o.has_key?("overrides")
348
+ node.override_attrs = Mash.new(o["overrides"])
349
+ end
350
+ if o.has_key?("run_list")
351
+ node.run_list.reset(o["run_list"])
352
+ else
353
+ o["recipes"].each { |r| node.recipes << r }
354
+ end
355
+ node.couchdb_rev = o["_rev"] if o.has_key?("_rev")
356
+ node.couchdb_id = o["_id"] if o.has_key?("_id")
357
+ node
358
+ end
359
+
360
+ # List all the Chef::Node objects in the CouchDB. If inflate is set to true, you will get
361
+ # the full list of all Nodes, fully inflated.
362
+ def self.cdb_list(inflate=false)
363
+ couchdb = Chef::CouchDB.new
364
+ rs = couchdb.list("nodes", inflate)
365
+ if inflate
366
+ rs["rows"].collect { |r| r["value"] }
367
+ else
368
+ rs["rows"].collect { |r| r["key"] }
369
+ end
370
+ end
371
+
372
+ def self.list(inflate=false)
373
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
374
+ if inflate
375
+ response = Hash.new
376
+ Chef::Search::Query.new.search(:node) do |n|
377
+ response[n.name] = n unless n.nil?
378
+ end
379
+ response
380
+ else
381
+ r.get_rest("nodes")
382
+ end
383
+ end
384
+
385
+ # Load a node by name from CouchDB
386
+ def self.cdb_load(name)
387
+ couchdb = Chef::CouchDB.new
388
+ couchdb.load("node", name)
389
+ end
390
+
391
+ # Load a node by name
392
+ def self.load(name)
393
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
394
+ r.get_rest("nodes/#{escape_node_id(name)}")
395
+ end
396
+
397
+ # Remove this node from the CouchDB
398
+ def cdb_destroy
399
+ @couchdb.delete("node", @name, @couchdb_rev)
400
+ end
401
+
402
+ # Remove this node via the REST API
403
+ def destroy
404
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
405
+ r.delete_rest("nodes/#{Chef::Node.escape_node_id(@name)}")
406
+ end
407
+
408
+ # Save this node to the CouchDB
409
+ def cdb_save
410
+ results = @couchdb.store("node", @name, self)
411
+ @couchdb_rev = results["rev"]
412
+ end
413
+
414
+ # Save this node via the REST API
415
+ def save
416
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
417
+ begin
418
+ r.put_rest("nodes/#{Chef::Node.escape_node_id(@name)}", self)
419
+ rescue Net::HTTPServerException => e
420
+ if e.response.code == "404"
421
+ r.post_rest("nodes", self)
422
+ else
423
+ raise e
424
+ end
425
+ end
426
+ self
427
+ end
428
+
429
+ # Create the node via the REST API
430
+ def create
431
+ r = Chef::REST.new(Chef::Config[:chef_server_url])
432
+ r.post_rest("nodes", self)
433
+ self
434
+ end
435
+
436
+ # Set up our CouchDB design document
437
+ def self.create_design_document
438
+ couchdb = Chef::CouchDB.new
439
+ couchdb.create_design_document("nodes", DESIGN_DOCUMENT)
440
+ end
441
+
442
+ # As a string
443
+ def to_s
444
+ "node[#{@name}]"
445
+ end
446
+
447
+ private
448
+
449
+ def append_recipes(recipes_to_append=[])
450
+ recipes_to_append.each do |recipe|
451
+ unless recipes.include?(recipe)
452
+ Chef::Log.debug("Adding recipe #{recipe}")
453
+ recipes << recipe
454
+ end
455
+ end
456
+ end
457
+
458
+ def self.escape_node_id(arg=nil)
459
+ arg.gsub(/\./, '_')
460
+ end
461
+
462
+ end
463
+ end