giraffesoft-chef 0.7.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +135 -0
  3. data/bin/chef-client +26 -0
  4. data/bin/chef-solo +26 -0
  5. data/distro/debian/etc/init.d/chef-client +175 -0
  6. data/distro/debian/etc/init.d/chef-indexer +175 -0
  7. data/distro/debian/etc/init.d/chef-server +120 -0
  8. data/distro/debian/man/man1/chef-indexer.1 +42 -0
  9. data/distro/debian/man/man1/chef-server.1 +108 -0
  10. data/distro/debian/man/man8/chef-client.8 +61 -0
  11. data/distro/debian/man/man8/chef-solo.8 +58 -0
  12. data/distro/redhat/etc/chef/client.rb +16 -0
  13. data/distro/redhat/etc/chef/indexer.rb +10 -0
  14. data/distro/redhat/etc/chef/server.rb +22 -0
  15. data/distro/redhat/etc/init.d/chef-client +74 -0
  16. data/distro/redhat/etc/init.d/chef-indexer +76 -0
  17. data/distro/redhat/etc/init.d/chef-server +77 -0
  18. data/lib/chef.rb +49 -0
  19. data/lib/chef/application.rb +98 -0
  20. data/lib/chef/application/agent.rb +18 -0
  21. data/lib/chef/application/client.rb +209 -0
  22. data/lib/chef/application/indexer.rb +141 -0
  23. data/lib/chef/application/server.rb +18 -0
  24. data/lib/chef/application/solo.rb +214 -0
  25. data/lib/chef/client.rb +421 -0
  26. data/lib/chef/compile.rb +170 -0
  27. data/lib/chef/config.rb +141 -0
  28. data/lib/chef/cookbook.rb +171 -0
  29. data/lib/chef/cookbook/metadata.rb +407 -0
  30. data/lib/chef/cookbook/metadata/version.rb +87 -0
  31. data/lib/chef/cookbook_loader.rb +180 -0
  32. data/lib/chef/couchdb.rb +176 -0
  33. data/lib/chef/daemon.rb +170 -0
  34. data/lib/chef/exceptions.rb +36 -0
  35. data/lib/chef/file_cache.rb +205 -0
  36. data/lib/chef/log.rb +39 -0
  37. data/lib/chef/mixin/check_helper.rb +31 -0
  38. data/lib/chef/mixin/checksum.rb +37 -0
  39. data/lib/chef/mixin/command.rb +386 -0
  40. data/lib/chef/mixin/convert_to_class_name.rb +48 -0
  41. data/lib/chef/mixin/create_path.rb +56 -0
  42. data/lib/chef/mixin/deep_merge.rb +36 -0
  43. data/lib/chef/mixin/find_preferred_file.rb +92 -0
  44. data/lib/chef/mixin/from_file.rb +50 -0
  45. data/lib/chef/mixin/generate_url.rb +49 -0
  46. data/lib/chef/mixin/language.rb +79 -0
  47. data/lib/chef/mixin/params_validate.rb +197 -0
  48. data/lib/chef/mixin/recipe_definition_dsl_core.rb +77 -0
  49. data/lib/chef/mixin/template.rb +84 -0
  50. data/lib/chef/node.rb +406 -0
  51. data/lib/chef/node/attribute.rb +412 -0
  52. data/lib/chef/openid_registration.rb +181 -0
  53. data/lib/chef/platform.rb +254 -0
  54. data/lib/chef/provider.rb +101 -0
  55. data/lib/chef/provider/cron.rb +187 -0
  56. data/lib/chef/provider/deploy.rb +281 -0
  57. data/lib/chef/provider/deploy/revision.rb +70 -0
  58. data/lib/chef/provider/deploy/timestamped.rb +33 -0
  59. data/lib/chef/provider/directory.rb +72 -0
  60. data/lib/chef/provider/execute.rb +58 -0
  61. data/lib/chef/provider/file.rb +191 -0
  62. data/lib/chef/provider/git.rb +198 -0
  63. data/lib/chef/provider/group.rb +120 -0
  64. data/lib/chef/provider/group/gpasswd.rb +50 -0
  65. data/lib/chef/provider/group/groupadd.rb +78 -0
  66. data/lib/chef/provider/group/pw.rb +88 -0
  67. data/lib/chef/provider/group/usermod.rb +57 -0
  68. data/lib/chef/provider/http_request.rb +102 -0
  69. data/lib/chef/provider/ifconfig.rb +131 -0
  70. data/lib/chef/provider/link.rb +157 -0
  71. data/lib/chef/provider/mount.rb +117 -0
  72. data/lib/chef/provider/mount/mount.rb +208 -0
  73. data/lib/chef/provider/package.rb +160 -0
  74. data/lib/chef/provider/package/apt.rb +110 -0
  75. data/lib/chef/provider/package/dpkg.rb +109 -0
  76. data/lib/chef/provider/package/freebsd.rb +153 -0
  77. data/lib/chef/provider/package/macports.rb +105 -0
  78. data/lib/chef/provider/package/portage.rb +124 -0
  79. data/lib/chef/provider/package/rpm.rb +99 -0
  80. data/lib/chef/provider/package/rubygems.rb +136 -0
  81. data/lib/chef/provider/package/yum-dump.py +106 -0
  82. data/lib/chef/provider/package/yum.rb +175 -0
  83. data/lib/chef/provider/remote_directory.rb +126 -0
  84. data/lib/chef/provider/remote_file.rb +141 -0
  85. data/lib/chef/provider/route.rb +118 -0
  86. data/lib/chef/provider/ruby_block.rb +15 -0
  87. data/lib/chef/provider/script.rb +42 -0
  88. data/lib/chef/provider/service.rb +135 -0
  89. data/lib/chef/provider/service/debian.rb +64 -0
  90. data/lib/chef/provider/service/freebsd.rb +157 -0
  91. data/lib/chef/provider/service/gentoo.rb +54 -0
  92. data/lib/chef/provider/service/init.rb +71 -0
  93. data/lib/chef/provider/service/redhat.rb +62 -0
  94. data/lib/chef/provider/service/simple.rb +115 -0
  95. data/lib/chef/provider/subversion.rb +148 -0
  96. data/lib/chef/provider/template.rb +143 -0
  97. data/lib/chef/provider/user.rb +170 -0
  98. data/lib/chef/provider/user/pw.rb +113 -0
  99. data/lib/chef/provider/user/useradd.rb +107 -0
  100. data/lib/chef/queue.rb +145 -0
  101. data/lib/chef/recipe.rb +144 -0
  102. data/lib/chef/resource.rb +380 -0
  103. data/lib/chef/resource/apt_package.rb +34 -0
  104. data/lib/chef/resource/bash.rb +33 -0
  105. data/lib/chef/resource/cron.rb +179 -0
  106. data/lib/chef/resource/csh.rb +33 -0
  107. data/lib/chef/resource/deploy.rb +350 -0
  108. data/lib/chef/resource/deploy_revision.rb +35 -0
  109. data/lib/chef/resource/directory.rb +76 -0
  110. data/lib/chef/resource/dpkg_package.rb +34 -0
  111. data/lib/chef/resource/execute.rb +127 -0
  112. data/lib/chef/resource/file.rb +84 -0
  113. data/lib/chef/resource/gem_package.rb +41 -0
  114. data/lib/chef/resource/git.rb +36 -0
  115. data/lib/chef/resource/group.rb +70 -0
  116. data/lib/chef/resource/http_request.rb +52 -0
  117. data/lib/chef/resource/ifconfig.rb +134 -0
  118. data/lib/chef/resource/link.rb +78 -0
  119. data/lib/chef/resource/macports_package.rb +29 -0
  120. data/lib/chef/resource/mount.rb +135 -0
  121. data/lib/chef/resource/package.rb +80 -0
  122. data/lib/chef/resource/perl.rb +33 -0
  123. data/lib/chef/resource/portage_package.rb +33 -0
  124. data/lib/chef/resource/python.rb +33 -0
  125. data/lib/chef/resource/remote_directory.rb +91 -0
  126. data/lib/chef/resource/remote_file.rb +60 -0
  127. data/lib/chef/resource/route.rb +135 -0
  128. data/lib/chef/resource/ruby.rb +33 -0
  129. data/lib/chef/resource/ruby_block.rb +20 -0
  130. data/lib/chef/resource/scm.rb +129 -0
  131. data/lib/chef/resource/script.rb +51 -0
  132. data/lib/chef/resource/service.rb +134 -0
  133. data/lib/chef/resource/subversion.rb +33 -0
  134. data/lib/chef/resource/template.rb +60 -0
  135. data/lib/chef/resource/timestamped_deploy.rb +31 -0
  136. data/lib/chef/resource/user.rb +98 -0
  137. data/lib/chef/resource_collection.rb +204 -0
  138. data/lib/chef/resource_definition.rb +67 -0
  139. data/lib/chef/rest.rb +238 -0
  140. data/lib/chef/role.rb +231 -0
  141. data/lib/chef/run_list.rb +156 -0
  142. data/lib/chef/runner.rb +130 -0
  143. data/lib/chef/search.rb +88 -0
  144. data/lib/chef/search/result.rb +64 -0
  145. data/lib/chef/search_index.rb +77 -0
  146. data/lib/chef/tasks/chef_repo.rake +347 -0
  147. data/lib/chef/util/file_edit.rb +125 -0
  148. data/lib/chef/util/fileedit.rb +121 -0
  149. metadata +293 -0
@@ -0,0 +1,18 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@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/application'
@@ -0,0 +1,214 @@
1
+ #
2
+ # Author:: AJ Christensen (<aj@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/application'
19
+ require 'chef/client'
20
+ require 'chef/config'
21
+ require 'chef/daemon'
22
+ require 'chef/log'
23
+ require 'net/http'
24
+ require 'open-uri'
25
+ require 'fileutils'
26
+
27
+ class Chef::Application::Solo < Chef::Application
28
+
29
+ option :config_file,
30
+ :short => "-c CONFIG",
31
+ :long => "--config CONFIG",
32
+ :default => "/etc/chef/solo.rb",
33
+ :description => "The configuration file to use"
34
+
35
+ option :log_level,
36
+ :short => "-l LEVEL",
37
+ :long => "--log_level LEVEL",
38
+ :description => "Set the log level (debug, info, warn, error, fatal)",
39
+ :proc => lambda { |l| l.to_sym }
40
+
41
+ option :log_location,
42
+ :short => "-L LOGLOCATION",
43
+ :long => "--logfile LOGLOCATION",
44
+ :description => "Set the log file location, defaults to STDOUT",
45
+ :proc => nil
46
+
47
+ option :help,
48
+ :short => "-h",
49
+ :long => "--help",
50
+ :description => "Show this message",
51
+ :on => :tail,
52
+ :boolean => true,
53
+ :show_options => true,
54
+ :exit => 0
55
+
56
+ option :user,
57
+ :short => "-u USER",
58
+ :long => "--user USER",
59
+ :description => "User to set privilege to",
60
+ :proc => nil
61
+
62
+ option :group,
63
+ :short => "-g GROUP",
64
+ :long => "--group GROUP",
65
+ :description => "Group to set privilege to",
66
+ :proc => nil
67
+
68
+ option :daemonize,
69
+ :short => "-d",
70
+ :long => "--daemonize",
71
+ :description => "Daemonize the process",
72
+ :proc => lambda { |p| true }
73
+
74
+ option :interval,
75
+ :short => "-i SECONDS",
76
+ :long => "--interval SECONDS",
77
+ :description => "Run chef-client periodically, in seconds",
78
+ :proc => lambda { |s| s.to_i }
79
+
80
+ option :json_attribs,
81
+ :short => "-j JSON_ATTRIBS",
82
+ :long => "--json-attributes JSON_ATTRIBS",
83
+ :description => "Load attributes from a JSON file or URL",
84
+ :proc => nil
85
+
86
+ option :node_name,
87
+ :short => "-N NODE_NAME",
88
+ :long => "--node-name NODE_NAME",
89
+ :description => "The node name for this client",
90
+ :proc => nil
91
+
92
+ option :splay,
93
+ :short => "-s SECONDS",
94
+ :long => "--splay SECONDS",
95
+ :description => "The splay time for running at intervals, in seconds",
96
+ :proc => lambda { |s| s.to_i }
97
+
98
+ option :json_attribs,
99
+ :short => "-j JSON_ATTRIBS",
100
+ :long => "--json-attributes JSON_ATTRIBS",
101
+ :description => "Load attributes from a JSON file or URL",
102
+ :proc => nil
103
+
104
+ option :recipe_url,
105
+ :short => "-r RECIPE_URL",
106
+ :long => "--recipe-url RECIPE_URL",
107
+ :description => "Pull down a remote gzipped tarball of recipes and untar it to the cookbook cache.",
108
+ :proc => nil
109
+
110
+ option :version,
111
+ :short => "-v",
112
+ :long => "--version",
113
+ :description => "Show chef version",
114
+ :boolean => true,
115
+ :proc => lambda {|v| puts "Chef: #{::Chef::VERSION}"},
116
+ :exit => 0
117
+
118
+ def initialize
119
+ super
120
+ @chef_solo = nil
121
+ @chef_solo_json = nil
122
+ end
123
+
124
+ def reconfigure
125
+ super
126
+
127
+ Chef::Config.solo true
128
+
129
+ if Chef::Config[:daemonize]
130
+ Chef::Config[:interval] ||= 1800
131
+ end
132
+
133
+ if Chef::Config[:json_attribs]
134
+ begin
135
+ json_io = open(Chef::Config[:json_attribs])
136
+ rescue SocketError => error
137
+ Chef::Application.fatal!("I cannot connect to #{Chef::Config[:json_attribs]}", 2)
138
+ rescue Errno::ENOENT => error
139
+ Chef::Application.fatal!("I cannot find #{Chef::Config[:json_attribs]}", 2)
140
+ rescue Errno::EACCES => error
141
+ Chef::Application.fatal!("Permissions are incorrect on #{Chef::Config[:json_attribs]}. Please chmod a+r #{Chef::Config[:json_attribs]}", 2)
142
+ rescue Exception => error
143
+ Chef::Application.fatal!("Got an unexpected error reading #{Chef::Config[:json_attribs]}: #{error.message}", 2)
144
+ end
145
+
146
+ begin
147
+ @chef_solo_json = JSON.parse(json_io.read)
148
+ rescue JSON::ParserError => error
149
+ Chef::Application.fatal!("Could not parse the provided JSON file (#{Chef::Config[:json_attribs]})!: " + error.message, 2)
150
+ end
151
+ end
152
+
153
+ if Chef::Config[:recipe_url]
154
+ cookbooks_path = Chef::Config[:cookbook_path].detect{|e| e =~ /\/cookbooks\/*$/ }
155
+ recipes_path = File.expand_path(File.join(cookbooks_path, '..'))
156
+ target_file = File.join(recipes_path, 'recipes.tgz')
157
+
158
+ Chef::Log.debug "Creating path #{recipes_path} to extract recipes into"
159
+ FileUtils.mkdir_p recipes_path
160
+ path = File.join(recipes_path, 'recipes.tgz')
161
+ File.open(path, 'wb') do |f|
162
+ open(Chef::Config[:recipe_url]) do |r|
163
+ f.write(r.read)
164
+ end
165
+ end
166
+ Chef::Mixin::Command.run_command(:command => "tar zxvfC #{path} #{recipes_path}")
167
+ end
168
+ end
169
+
170
+ def setup_application
171
+ Chef::Daemon.change_privilege
172
+
173
+ @chef_solo = Chef::Client.new
174
+ @chef_solo.json_attribs = @chef_solo_json
175
+ @chef_solo.node_name = Chef::Config[:node_name]
176
+ end
177
+
178
+ def run_application
179
+ if Chef::Config[:daemonize]
180
+ Chef::Daemon.daemonize("chef-client")
181
+ end
182
+
183
+ loop do
184
+ begin
185
+ if Chef::Config[:splay]
186
+ splay = rand Chef::Config[:splay]
187
+ Chef::Log.debug("Splay sleep #{splay} seconds")
188
+ sleep splay
189
+ end
190
+
191
+ @chef_solo.run_solo
192
+
193
+ if Chef::Config[:interval]
194
+ Chef::Log.debug("Sleeping for #{Chef::Config[:interval]} seconds")
195
+ sleep Chef::Config[:interval]
196
+ else
197
+ Chef::Application.exit! "Exiting", 0
198
+ end
199
+ rescue SystemExit => e
200
+ raise
201
+ rescue Exception => e
202
+ if Chef::Config[:interval]
203
+ Chef::Log.error("#{e.class}")
204
+ Chef::Log.fatal("#{e}\n#{e.backtrace.join("\n")}")
205
+ Chef::Log.fatal("Sleeping for #{Chef::Config[:interval]} seconds before trying again")
206
+ sleep Chef::Config[:interval]
207
+ retry
208
+ else
209
+ raise
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,421 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@opscode.com>)
3
+ # Author:: Christopher Walters (<cw@opscode.com>)
4
+ # Copyright:: Copyright (c) 2008 Opscode, Inc.
5
+ # License:: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+
19
+ require 'chef/config'
20
+ require 'chef/mixin/params_validate'
21
+ require 'chef/mixin/generate_url'
22
+ require 'chef/mixin/checksum'
23
+ require 'chef/log'
24
+ require 'chef/rest'
25
+ require 'chef/platform'
26
+ require 'chef/node'
27
+ require 'chef/role'
28
+ require 'chef/file_cache'
29
+ require 'chef/compile'
30
+ require 'chef/runner'
31
+ require 'ohai'
32
+
33
+ class Chef
34
+ class Client
35
+
36
+ include Chef::Mixin::GenerateURL
37
+ include Chef::Mixin::Checksum
38
+
39
+ attr_accessor :node, :registration, :safe_name, :json_attribs, :validation_token, :node_name, :ohai
40
+
41
+ # Creates a new Chef::Client.
42
+ def initialize()
43
+ @node = nil
44
+ @safe_name = nil
45
+ @validation_token = nil
46
+ @registration = nil
47
+ @json_attribs = nil
48
+ @node_name = nil
49
+ @node_exists = true
50
+ Ohai::Log.logger = Chef::Log.logger
51
+ @ohai = Ohai::System.new
52
+ @rest = Chef::REST.new(Chef::Config[:registration_url])
53
+ end
54
+
55
+ # Do a full run for this Chef::Client. Calls:
56
+ #
57
+ # * build_node - Get the last known state, merge with local changes
58
+ # * register - Make sure we have an openid
59
+ # * authenticate - Authenticate with our openid
60
+ # * sync_library_files - Populate the local cache with all the library files
61
+ # * sync_provider_files - Populate the local cache with all the provider files
62
+ # * sync_resource_files - Populate the local cache with all the resource files
63
+ # * sync_attribute_files - Populate the local cache with all the attribute files
64
+ # * sync_definitions - Populate the local cache with all the definitions
65
+ # * sync_recipes - Populate the local cache with all the recipes
66
+ # * do_attribute_files - Populate the local cache with all attributes, and execute them
67
+ # * save_node - Store the new node configuration
68
+ # * converge - Bring this system up to date, based on the local cache
69
+ # * save_node - Store the node again, in case convergence altered future state
70
+ #
71
+ # === Returns
72
+ # true:: Always returns true.
73
+ def run
74
+ start_time = Time.now
75
+ Chef::Log.info("Starting Chef Run")
76
+
77
+ determine_node_name
78
+ register
79
+ authenticate
80
+ build_node(@node_name)
81
+ save_node
82
+ sync_library_files
83
+ sync_provider_files
84
+ sync_resource_files
85
+ sync_attribute_files
86
+ sync_definitions
87
+ sync_recipes
88
+ save_node
89
+ converge
90
+ save_node
91
+
92
+ end_time = Time.now
93
+ Chef::Log.info("Chef Run complete in #{end_time - start_time} seconds")
94
+ true
95
+ end
96
+
97
+ # Similar to Chef::Client#run, but instead of talking to the Chef server,
98
+ # simply runs in a standalone ("solo") mode.
99
+ #
100
+ # Someday, we'll have chef_chewbacca.
101
+ #
102
+ # === Returns
103
+ # true:: Always returns true.
104
+ def run_solo
105
+ start_time = Time.now
106
+ Chef::Log.info("Starting Chef Solo Run")
107
+
108
+ determine_node_name
109
+ build_node(@node_name, true)
110
+ converge(true)
111
+
112
+ end_time = Time.now
113
+ Chef::Log.info("Chef Run complete in #{end_time - start_time} seconds")
114
+ true
115
+ end
116
+
117
+ def run_ohai
118
+ if @ohai.keys
119
+ @ohai.refresh_plugins
120
+ else
121
+ @ohai.all_plugins
122
+ end
123
+ end
124
+
125
+ def determine_node_name
126
+ run_ohai
127
+ unless safe_name && node_name
128
+ @node_name ||= @ohai[:fqdn] ? @ohai[:fqdn] : @ohai[:hostname]
129
+ @safe_name = @node_name.gsub(/\./, '_')
130
+ end
131
+ @node_name
132
+ end
133
+
134
+ # Builds a new node object for this client. Starts with querying for the FQDN of the current
135
+ # host (unless it is supplied), then merges in the facts from Ohai.
136
+ #
137
+ # === Parameters
138
+ # node_name<String>:: The name of the node to build - defaults to nil
139
+ #
140
+ # === Returns
141
+ # node<Chef::Node>:: Returns the created node object, also stored in @node
142
+ def build_node(node_name=nil, solo=false)
143
+ node_name ||= determine_node_name
144
+ raise RuntimeError, "Unable to determine node name from ohai" unless node_name
145
+ Chef::Log.debug("Building node object for #{@safe_name}")
146
+ unless solo
147
+ begin
148
+ @node = @rest.get_rest("nodes/#{@safe_name}")
149
+ rescue Net::HTTPServerException => e
150
+ unless e.message =~ /^404/
151
+ raise e
152
+ end
153
+ end
154
+ end
155
+ unless @node
156
+ @node_exists = false
157
+ @node ||= Chef::Node.new
158
+ @node.name(node_name)
159
+ end
160
+ if @json_attribs
161
+ Chef::Log.debug("Adding JSON Attributes")
162
+ @json_attribs.each do |key, value|
163
+ if key == "recipes" || key == "run_list"
164
+ value.each do |recipe|
165
+ unless @node.recipes.detect { |r| r == recipe }
166
+ Chef::Log.debug("Adding recipe #{recipe}")
167
+ @node.recipes << recipe
168
+ end
169
+ end
170
+ else
171
+ Chef::Log.debug("JSON Attribute: #{key} - #{value.inspect}")
172
+ @node[key] = value
173
+ end
174
+ end
175
+ end
176
+ ohai.each do |field, value|
177
+ Chef::Log.debug("Ohai Attribute: #{field} - #{value.inspect}")
178
+ @node[field] = value
179
+ end
180
+ platform, version = Chef::Platform.find_platform_and_version(@node)
181
+ Chef::Log.debug("Platform is #{platform} version #{version}")
182
+ @node[:platform] = platform
183
+ @node[:platform_version] = version
184
+ @node[:tags] = Array.new unless @node.attribute?(:tags)
185
+ @node
186
+ end
187
+
188
+ # If this node has been registered before, this method will fetch the current registration
189
+ # data.
190
+ #
191
+ # If it has not, we register it by calling create_registration.
192
+ #
193
+ # === Returns
194
+ # true:: Always returns true
195
+ def register
196
+ determine_node_name unless @node_name
197
+ Chef::Log.debug("Registering #{@safe_name} for an openid")
198
+
199
+ begin
200
+ if @rest.get_rest("registrations/#{@safe_name}")
201
+ @secret = Chef::FileCache.load(File.join("registration", @safe_name))
202
+ end
203
+ rescue Net::HTTPServerException => e
204
+ case e.message
205
+ when /^404/
206
+ create_registration
207
+ else
208
+ raise
209
+ end
210
+ rescue Chef::Exceptions::FileNotFound
211
+ Chef::Application.fatal! "A remote registration already exists for #{@safe_name}, however the local shared secret does not exist." +
212
+ " To remedy this, you could delete the registration via webUI/REST, change the node_name option in config.rb" +
213
+ " (or use the -N/--node-name option to the CLI) or" +
214
+ " copy the old shared secret to #{File.join(Chef::Config[:file_cache_path], 'registration', @safe_name)}", 3
215
+ end
216
+
217
+ true
218
+ end
219
+
220
+ # Generates a random secret, stores it in the Chef::Filestore with the "registration" key,
221
+ # and posts our nodes registration information to the server.
222
+ #
223
+ # === Returns
224
+ # true:: Always returns true
225
+ def create_registration
226
+ @secret = random_password(500)
227
+ Chef::FileCache.store(File.join("registration", @safe_name), @secret)
228
+ @rest.post_rest("registrations", { :id => @safe_name, :password => @secret, :validation_token => @validation_token })
229
+ true
230
+ end
231
+
232
+ # Authenticates the node via OpenID.
233
+ #
234
+ # === Returns
235
+ # true:: Always returns true
236
+ def authenticate
237
+ determine_node_name unless @node_name
238
+ Chef::Log.debug("Authenticating #{@safe_name} via openid")
239
+ response = @rest.post_rest('openid/consumer/start', {
240
+ "openid_identifier" => "#{Chef::Config[:openid_url]}/openid/server/node/#{@safe_name}",
241
+ "submit" => "Verify"
242
+ })
243
+ @rest.post_rest(
244
+ "#{Chef::Config[:openid_url]}#{response["action"]}",
245
+ { "password" => @secret }
246
+ )
247
+ end
248
+
249
+ # Update the file caches for a given cache segment. Takes a segment name
250
+ # and a hash that matches one of the cookbooks/_attribute_files style
251
+ # remote file listings.
252
+ #
253
+ # === Parameters
254
+ # segment<String>:: The cache segment to update
255
+ # remote_list<Hash>:: A cookbooks/_attribute_files style remote file listing
256
+ def update_file_cache(segment, remote_list)
257
+ # We need the list of known good attribute files, so we can delete any that are
258
+ # just laying about.
259
+ file_canonical = Hash.new
260
+
261
+ remote_list.each do |rf|
262
+ cache_file = File.join("cookbooks", rf['cookbook'], segment, rf['name'])
263
+ file_canonical[cache_file] = true
264
+
265
+ # For back-compat between older clients and new chef servers
266
+ rf['checksum'] ||= nil
267
+
268
+ current_checksum = nil
269
+ if Chef::FileCache.has_key?(cache_file)
270
+ current_checksum = checksum(Chef::FileCache.load(cache_file, false))
271
+ end
272
+
273
+ rf_url = generate_cookbook_url(
274
+ rf['name'],
275
+ rf['cookbook'],
276
+ segment,
277
+ @node,
278
+ current_checksum ? { 'checksum' => current_checksum } : nil
279
+ )
280
+ Chef::Log.debug(rf_url)
281
+
282
+ if current_checksum != rf['checksum']
283
+ changed = true
284
+ begin
285
+ raw_file = @rest.get_rest(rf_url, true)
286
+ rescue Net::HTTPRetriableError => e
287
+ if e.response.kind_of?(Net::HTTPNotModified)
288
+ changed = false
289
+ Chef::Log.debug("Cache file #{cache_file} is unchanged")
290
+ else
291
+ raise e
292
+ end
293
+ end
294
+
295
+ if changed
296
+ Chef::Log.info("Storing updated #{cache_file} in the cache.")
297
+ Chef::FileCache.move_to(raw_file.path, cache_file)
298
+ end
299
+ end
300
+ end
301
+
302
+ Chef::FileCache.list.each do |cache_file|
303
+ if cache_file.match("cookbooks/.+?/#{segment}")
304
+ unless file_canonical[cache_file]
305
+ Chef::Log.info("Removing #{cache_file} from the cache; it is no longer on the server.")
306
+ Chef::FileCache.delete(cache_file)
307
+ end
308
+ end
309
+ end
310
+
311
+ end
312
+
313
+ # Gets all the attribute files included in all the cookbooks available on the server,
314
+ # and executes them.
315
+ #
316
+ # === Returns
317
+ # true:: Always returns true
318
+ def sync_attribute_files
319
+ Chef::Log.debug("Synchronizing attributes")
320
+ update_file_cache("attributes", @rest.get_rest("cookbooks/_attribute_files?node=#{@node.name}"))
321
+ true
322
+ end
323
+
324
+ # Gets all the library files included in all the cookbooks available on the server,
325
+ # and loads them.
326
+ #
327
+ # === Returns
328
+ # true:: Always returns true
329
+ def sync_library_files
330
+ Chef::Log.debug("Synchronizing libraries")
331
+ update_file_cache("libraries", @rest.get_rest("cookbooks/_library_files?node=#{@node.name}"))
332
+ true
333
+ end
334
+
335
+ # Gets all the provider files included in all the cookbooks available on the server,
336
+ # and loads them.
337
+ #
338
+ # === Returns
339
+ # true:: Always returns true
340
+ def sync_provider_files
341
+ Chef::Log.debug("Synchronizing providers")
342
+ update_file_cache("providers", @rest.get_rest("cookbooks/_provider_files?node=#{@node.name}"))
343
+ true
344
+ end
345
+
346
+ # Gets all the resource files included in all the cookbooks available on the server,
347
+ # and loads them.
348
+ #
349
+ # === Returns
350
+ # true:: Always returns true
351
+ def sync_resource_files
352
+ Chef::Log.debug("Synchronizing resources")
353
+ update_file_cache("resources", @rest.get_rest("cookbooks/_resource_files?node=#{@node.name}"))
354
+ true
355
+ end
356
+
357
+ # Gets all the definition files included in all the cookbooks available on the server,
358
+ # and loads them.
359
+ #
360
+ # === Returns
361
+ # true:: Always returns true
362
+ def sync_definitions
363
+ Chef::Log.debug("Synchronizing definitions")
364
+ update_file_cache("definitions", @rest.get_rest("cookbooks/_definition_files?node=#{@node.name}"))
365
+ end
366
+
367
+ # Gets all the recipe files included in all the cookbooks available on the server,
368
+ # and loads them.
369
+ #
370
+ # === Returns
371
+ # true:: Always returns true
372
+ def sync_recipes
373
+ Chef::Log.debug("Synchronizing recipes")
374
+ update_file_cache("recipes", @rest.get_rest("cookbooks/_recipe_files?node=#{@node.name}"))
375
+ end
376
+
377
+ # Updates the current node configuration on the server.
378
+ #
379
+ # === Returns
380
+ # true:: Always returns true
381
+ def save_node
382
+ Chef::Log.debug("Saving the current state of node #{@safe_name}")
383
+ if @node_exists
384
+ @node = @rest.put_rest("nodes/#{@safe_name}", @node)
385
+ else
386
+ result = @rest.post_rest("nodes", @node)
387
+ @node = @rest.get_rest(result['uri'])
388
+ @node_exists = true
389
+ end
390
+ true
391
+ end
392
+
393
+ # Compiles the full list of recipes for the server, and passes it to an instance of
394
+ # Chef::Runner.converge.
395
+ #
396
+ # === Returns
397
+ # true:: Always returns true
398
+ def converge(solo=false)
399
+ Chef::Log.debug("Compiling recipes for node #{@safe_name}")
400
+ unless solo
401
+ Chef::Config[:cookbook_path] = File.join(Chef::Config[:file_cache_path], "cookbooks")
402
+ end
403
+ compile = Chef::Compile.new(@node)
404
+
405
+ Chef::Log.debug("Converging node #{@safe_name}")
406
+ cr = Chef::Runner.new(@node, compile.collection, compile.definitions, compile.cookbook_loader)
407
+ cr.converge
408
+ true
409
+ end
410
+
411
+ protected
412
+ # Generates a random password of "len" length.
413
+ def random_password(len)
414
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
415
+ newpass = ""
416
+ 1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
417
+ newpass
418
+ end
419
+
420
+ end
421
+ end