chef 0.9.8.rc.0 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,13 +17,14 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
 
20
- # Notice:
21
- # This code is imported from deep_merge by Steve Midgley. deep_merge is
22
- # available under the MIT license from
23
- # http://trac.misuse.org/science/wiki/DeepMerge
24
-
25
20
  class Chef
26
21
  module Mixin
22
+ # == Chef::Mixin::DeepMerge
23
+ # Implements a deep merging algorithm for nested data structures.
24
+ # ==== Notice:
25
+ # This code is imported from deep_merge by Steve Midgley. deep_merge is
26
+ # available under the MIT license from
27
+ # http://trac.misuse.org/science/wiki/DeepMerge
27
28
  module DeepMerge
28
29
  def self.merge(first, second)
29
30
  first = Mash.new(first) unless first.kind_of?(Mash)
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Christopher Walters (<cw@opscode.com>)
4
4
  # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
@@ -21,6 +21,7 @@ require 'chef/resource'
21
21
  require 'chef/mixin/convert_to_class_name'
22
22
  require 'chef/mixin/language'
23
23
 
24
+ #--
24
25
  # UGH. this is a circular require that will cause an uninitialized constant
25
26
  # error, but this file really does depend on Chef::Recipe. oh well.
26
27
  # require 'chef/recipe'
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Daniel DeLeo (<dan@opscode.com>)
3
3
  # Copyright:: Copyright (c) 2010 Opscode, Inc.
4
4
  # License:: Apache License, Version 2.0
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Copyright:: Copyright (c) 2008 Opscode, Inc.
4
4
  # License:: Apache License, Version 2.0
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Daniel DeLeo (<dan@opscode.com>)
3
3
  # Copyright:: Copyright (c) 2009 Opscode, Inc.
4
4
  # Copyright:: Copyright (c) 2005 Sam Ruby
@@ -16,7 +16,7 @@
16
16
  # See the License for the specific language governing permissions and
17
17
  # limitations under the License.
18
18
 
19
- #
19
+ #--
20
20
  # Portions of this code are adapted from Sam Ruby's xchar.rb
21
21
  # http://intertwingly.net/stories/2005/09/28/xchar.rb
22
22
  #
@@ -16,11 +16,11 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- # Adds a Dir.glob to Ruby 1.8.5, for compat
20
19
  if RUBY_VERSION < "1.8.6" || RUBY_PLATFORM =~ /mswin|mingw32|windows/
21
20
  class Dir
22
21
  class << self
23
22
  alias_method :glob_, :glob
23
+ # Adds a Dir.glob to Ruby 1.8.5, for compat
24
24
  def glob(pattern, flags=0)
25
25
  raise ArgumentError unless (
26
26
  !pattern.nil? and (
@@ -16,7 +16,8 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- # On ruby 1.9, Strings are aware of multibyte characters, so #size and length
19
+ # == String (Patch)
20
+ # On ruby 1.9, Strings are aware of multibyte characters, so +size+ and +length+
20
21
  # give the actual number of characters. In Chef::REST, we need the bytesize
21
22
  # so we can correctly set the Content-Length headers, but ruby 1.8.6 and lower
22
23
  # don't define String#bytesize. Monkey patching time!
@@ -16,11 +16,15 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
+ # == Tempfile (Patch)
19
20
  # Tempfile has a horrible bug where it causes an IOError: closed stream in its
20
21
  # finalizer, leading to intermittent application crashes with confusing stack
21
22
  # traces. Here we monkey patch the fix into place. You can track the bug on
22
23
  # ruby's redmine: http://redmine.ruby-lang.org/issues/show/3119
23
- class Tempfile
24
+ #
25
+ # The patch is slightly different for Ruby 1.8 and Ruby 1.9, both patches are
26
+ # included here.
27
+ class Tempfile # :nodoc:
24
28
  # Tempfile has changes between 1.8.x and 1.9.x
25
29
  # so we monkey patch separately
26
30
  if RUBY_VERSION =~ /^1\.8/
@@ -18,22 +18,34 @@
18
18
 
19
19
  require 'chef/provider/package'
20
20
  require 'chef/mixin/command'
21
+ require 'chef/mixin/shell_out'
21
22
  require 'chef/resource/package'
23
+ require 'chef/mixin/shell_out'
24
+
22
25
  class Chef
23
26
  class Provider
24
27
  class Package
25
28
  class EasyInstall < Chef::Provider::Package
26
29
 
30
+ include Chef::Mixin::ShellOut
31
+
27
32
  def install_check(name)
28
- command = "python -c \"import sys; print sys.path\""
29
33
  check = false
30
- status = popen4(command) do |pid, stdin, stdout, stderr|
31
- stdout.each do |line|
32
- if line.include? "#{name}"
33
- check = true
34
- end
34
+
35
+ begin
36
+ # first check to see if we can import it
37
+ output = shell_out!("python -c \"import #{name}\"").stderr
38
+ unless output.include? "ImportError"
39
+ check = true
40
+ end
41
+ rescue
42
+ # then check to see if its on the path
43
+ output = shell_out!("python -c \"import sys; print sys.path\"").stdout
44
+ if output.downcase.include? "#{name.downcase}"
45
+ check = true
35
46
  end
36
47
  end
48
+
37
49
  check
38
50
  end
39
51
 
@@ -50,17 +62,19 @@ class Chef
50
62
  # get the currently installed version if installed
51
63
  package_version = nil
52
64
  if install_check(@new_resource.package_name)
53
- command = "python -c \"import #{@new_resource.package_name}; print #{@new_resource.package_name}.__path__\""
54
- status = popen4(command) do |pid, stdin, stdout, stderr|
55
- install_location = stdout.readline
56
- install_location[/\S\S(.*)\/(.*)-(.*)-py(.*).egg\S/]
65
+ begin
66
+ output = shell_out!("python -c \"import #{@new_resource.package_name}; print #{@new_resource.package_name}.__version__\"").stdout
67
+ package_version = output.strip
68
+ rescue
69
+ output = shell_out!("python -c \"import #{@new_resource.package_name}; print #{@new_resource.package_name}.__path__\"").stdout
70
+ output[/\S\S(.*)\/(.*)-(.*)-py(.*).egg\S/]
57
71
  package_version = $3
58
72
  end
59
73
  end
60
74
 
61
75
  if package_version == @new_resource.version
62
76
  Chef::Log.debug("#{@new_resource.package_name} at version #{@new_resource.version}")
63
- @current_resource.version(@new_resource.version)
77
+ @current_resource.version(@new_resource.version)
64
78
  else
65
79
  Chef::Log.debug("#{@new_resource.package_name} at version #{package_version}")
66
80
  @current_resource.version(package_version)
@@ -73,16 +87,9 @@ class Chef
73
87
  return @candidate_version if @candidate_version
74
88
 
75
89
  # do a dry run to get the latest version
76
- command = "#{easy_install_binary_path} -n #{@new_resource.package_name}"
77
- status = popen4(command) do |pid, stdin, stdout, stderr|
78
- dry_run_output = ""
79
- stdout.each do |line|
80
- dry_run_output << line
81
- end
82
- dry_run_output[/(.*)Best match: (.*) (.*)\n/]
83
- @candidate_version = $3
84
- @candidate_version
85
- end
90
+ result = shell_out!("#{easy_install_binary_path} -n #{@new_resource.package_name}", :returns=>[0,1])
91
+ @candidate_version = result.stdout[/(.*)Best match: (.*) (.*)$/, 3]
92
+ @candidate_version
86
93
  end
87
94
 
88
95
  def install_package(name, version)
@@ -104,4 +111,4 @@ class Chef
104
111
  end
105
112
  end
106
113
  end
107
- end
114
+ end
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Daniel DeLeo (<dan@opscode.com>)
4
4
  # Copyright:: Copyright (c) 2008, 2010 Opscode, Inc.
@@ -22,12 +22,6 @@ require 'chef/mixin/template'
22
22
  require 'chef/mixin/checksum'
23
23
  require 'chef/file_access_control'
24
24
 
25
- #require 'chef/mixin/find_preferred_file'
26
- #require 'chef/rest'
27
- #require 'chef/file_cache'
28
- #require 'uri'
29
- #require 'tempfile'
30
-
31
25
  class Chef
32
26
  class Provider
33
27
 
@@ -35,7 +29,6 @@ class Chef
35
29
 
36
30
  include Chef::Mixin::Checksum
37
31
  include Chef::Mixin::Template
38
- #include Chef::Mixin::FindPreferredFile
39
32
 
40
33
  def load_current_resource
41
34
  super
@@ -98,45 +91,8 @@ class Chef
98
91
  @new_resource.updated = access_controls.modified?
99
92
  end
100
93
 
101
- # def locate_or_fetch_template
102
- # Chef::Log.debug("looking for template #{@new_resource.source} in cookbook #{cookbook_name.inspect}")
103
- #
104
- # cache_file_name = "cookbooks/#{cookbook_name}/templates/default/#{@new_resource.source}"
105
- # template_cache_name = "#{cookbook_name}_#{@new_resource.source}"
106
- #
107
- # if @new_resource.local
108
- # cache_file_name = @new_resource.source
109
- # elsif Chef::Config[:solo]
110
- # cache_file_name = solo_cache_file_name
111
- # else
112
- # raw_template_file = fetch_template_via_rest(cache_file_name, template_cache_name)
113
- # end
114
- #
115
- # if template_updated?
116
- # Chef::Log.debug("Updating template for #{@new_resource} in the cache")
117
- # Chef::FileCache.move_to(raw_template_file.path, cache_file_name)
118
- # end
119
- # cache_file_name
120
- # end
121
-
122
94
  private
123
95
 
124
- # def template_updated
125
- # @template_updated = true
126
- # end
127
- #
128
- # def template_not_updated
129
- # @template_updated = false
130
- # end
131
- #
132
- # def template_updated?
133
- # @template_updated
134
- # end
135
- #
136
- # def cookbook_name
137
- # @cookbook_name = (@new_resource.cookbook || @new_resource.cookbook_name)
138
- # end
139
-
140
96
  def render_with_context(template_location, &block)
141
97
  context = {}
142
98
  context.merge!(@new_resource.variables)
@@ -144,55 +100,6 @@ class Chef
144
100
  render_template(IO.read(template_location), context, &block)
145
101
  end
146
102
 
147
- # def solo_cache_file_name
148
- # filename = find_preferred_file(
149
- # cookbook_name,
150
- # :template,
151
- # @new_resource.source,
152
- # node[:fqdn],
153
- # node[:platform],
154
- # node[:platform_version]
155
- # )
156
- # Chef::Log.debug("Using local file for template:#{filename}")
157
- # Pathname.new(filename).relative_path_from(Pathname.new(Chef::Config[:file_cache_path])).to_s
158
- # end
159
- #
160
- # def fetch_template_via_rest(cache_file_name, template_cache_name)
161
- # if node.run_state[:template_cache].has_key?(template_cache_name)
162
- # Chef::Log.debug("I have already fetched the template for #{@new_resource} once this run, not checking again.")
163
- # template_not_updated
164
- # return false
165
- # end
166
- #
167
- # r = Chef::REST.new(Chef::Config[:template_url])
168
- #
169
- # current_checksum = nil
170
- #
171
- # if Chef::FileCache.has_key?(cache_file_name)
172
- # current_checksum = self.checksum(Chef::FileCache.load(cache_file_name, false))
173
- # else
174
- # Chef::Log.debug("Template #{@new_resource} is not in the template cache")
175
- # end
176
- #
177
- # template_url = generate_url(@new_resource.source, "templates", :checksum => current_checksum)
178
- #
179
- # begin
180
- # raw_template_file = r.get_rest(template_url, true)
181
- # template_updated
182
- # rescue Net::HTTPRetriableError
183
- # if e.response.kind_of?(Net::HTTPNotModified)
184
- # Chef::Log.debug("Cached template for #{@new_resource} is unchanged")
185
- # else
186
- # raise
187
- # end
188
- # end
189
- #
190
- # # We have checked the cache for this template this run
191
- # node.run_state[:template_cache][template_cache_name] = true
192
- #
193
- # raw_template_file
194
- # end
195
-
196
103
  end
197
104
  end
198
105
  end
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Christopher Walters (<cw@opscode.com>)
4
4
  # Copyright:: Copyright (c) 2008, 2009 Opscode, Inc.
@@ -26,6 +26,8 @@ require 'chef/mixin/language_include_recipe'
26
26
  require 'chef/mixin/deprecation'
27
27
 
28
28
  class Chef
29
+ # == Chef::Recipe
30
+ # A Recipe object is the context in which Chef recipes are evaluated.
29
31
  class Recipe
30
32
 
31
33
  include Chef::Mixin::FromFile
@@ -42,6 +44,8 @@ class Chef
42
44
  # For example:
43
45
  # "aws::elastic_ip" returns [:aws, "elastic_ip"]
44
46
  # "aws" returns [:aws, "default"]
47
+ #--
48
+ # TODO: Duplicates functionality of RunListItem
45
49
  def self.parse_recipe_name(recipe_name)
46
50
  rmatch = recipe_name.match(/(.+?)::(.+)/)
47
51
  if rmatch
@@ -65,10 +69,10 @@ class Chef
65
69
  run_context.node
66
70
  end
67
71
 
72
+ # Used by the DSL to look up resources when executing in the context of a
73
+ # recipe.
74
+ #--
68
75
  # what does this do? and what is args? TODO 5-14-2010.
69
- #
70
- # We believe this is used by the DSL when it's executing in the
71
- # context of a recipe in order to look up resources.
72
76
  def resources(*args)
73
77
  run_context.resource_collection.find(*args)
74
78
  end
@@ -83,9 +87,9 @@ class Chef
83
87
  #
84
88
  # === Returns
85
89
  # tags<Array>:: The contents of run_context.node[:tags]
86
- def tag(*args)
87
- if args.length > 0
88
- args.each do |tag|
90
+ def tag(*tags)
91
+ if tags.length > 0
92
+ tags.each do |tag|
89
93
  run_context.node[:tags] << tag unless run_context.node[:tags].include?(tag)
90
94
  end
91
95
  run_context.node[:tags]
@@ -94,7 +98,7 @@ class Chef
94
98
  end
95
99
  end
96
100
 
97
- # Returns true if the node is tagged with the supplied list of tags.
101
+ # Returns true if the node is tagged with *all* of the supplied +tags+.
98
102
  #
99
103
  # === Parameters
100
104
  # tags<Array>:: A list of tags
@@ -102,8 +106,8 @@ class Chef
102
106
  # === Returns
103
107
  # true<TrueClass>:: If all the parameters are present
104
108
  # false<FalseClass>:: If any of the parameters are missing
105
- def tagged?(*args)
106
- args.each do |tag|
109
+ def tagged?(*tags)
110
+ tags.each do |tag|
107
111
  return false unless run_context.node[:tags].include?(tag)
108
112
  end
109
113
  true
@@ -116,8 +120,8 @@ class Chef
116
120
  #
117
121
  # === Returns
118
122
  # tags<Array>:: The current list of run_context.node[:tags]
119
- def untag(*args)
120
- args.each do |tag|
123
+ def untag(*tags)
124
+ tags.each do |tag|
121
125
  run_context.node[:tags].delete(tag)
122
126
  end
123
127
  end
@@ -1,4 +1,4 @@
1
- #
1
+ #--
2
2
  # Author:: Adam Jacob (<adam@opscode.com>)
3
3
  # Author:: Thom May (<thom@clearairturbulence.org>)
4
4
  # Author:: Nuo Yan (<nuo@opscode.com>)
@@ -30,10 +30,17 @@ require 'chef/rest/rest_request'
30
30
  require 'chef/monkey_patches/string'
31
31
 
32
32
  class Chef
33
+ # == Chef::REST
34
+ # Chef's custom REST client with built-in JSON support and RSA signed header
35
+ # authentication.
33
36
  class REST
34
37
  attr_reader :auth_credentials
35
38
  attr_accessor :url, :cookies, :sign_on_redirect, :redirect_limit
36
39
 
40
+ # Create a REST client object. The supplied +url+ is used as the base for
41
+ # all subsequent requests. For example, when initialized with a base url
42
+ # http://localhost:4000, a call to +get_rest+ with 'nodes' will make an
43
+ # HTTP GET request to http://localhost:4000/nodes
37
44
  def initialize(url, client_name=Chef::Config[:node_name], signing_key_filename=Chef::Config[:client_key], options={})
38
45
  @url = url
39
46
  @cookies = CookieJar.instance
@@ -90,6 +97,8 @@ class Chef
90
97
 
91
98
  # Send an HTTP GET request to the path
92
99
  #
100
+ # Using this method to +fetch+ a file is considered deprecated.
101
+ #
93
102
  # === Parameters
94
103
  # path:: The path to GET
95
104
  # raw:: Whether you want the raw body returned, or JSON inflated. Defaults
@@ -138,6 +147,9 @@ class Chef
138
147
  auth_credentials.sign_requests? && @sign_request
139
148
  end
140
149
 
150
+ # ==== DEPRECATED
151
+ # Use +api_request+ instead
152
+ #--
141
153
  # Actually run an HTTP request. First argument is the HTTP method,
142
154
  # which should be one of :GET, :PUT, :POST or :DELETE. Next is the
143
155
  # URL, then an object to include in the body (which will be converted with
@@ -190,7 +202,7 @@ class Chef
190
202
  end
191
203
  end
192
204
 
193
- # Similar to #run_request but only supports JSON APIs. File Download not supported.
205
+ # Runs an HTTP request to a JSON API. File Download not supported.
194
206
  def api_request(method, url, headers={}, data=false)
195
207
  json_body = data ? data.to_json : nil
196
208
  headers = build_headers(method, url, headers, json_body)
@@ -219,11 +231,11 @@ class Chef
219
231
  end
220
232
  end
221
233
 
222
- # similar to #run_request but only supports streaming downloads.
223
- # Only supports GET, doesn't speak JSON
234
+ # Makes a streaming download request. <b>Doesn't speak JSON.</b>
224
235
  # Streams the response body to a tempfile. If a block is given, it's
225
- # passed to the tempfile, which means that the tempfile will automatically
236
+ # passed to Tempfile.open(), which means that the tempfile will automatically
226
237
  # be unlinked after the block is executed.
238
+ #
227
239
  # If no block is given, the tempfile is returned, which means it's up to
228
240
  # you to unlink the tempfile when you're done with it.
229
241
  def streaming_request(url, headers, &block)