chef 0.9.8.rc.0 → 0.9.8
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.
- data/README.rdoc +80 -44
- data/lib/chef/checksum.rb +7 -4
- data/lib/chef/client.rb +4 -0
- data/lib/chef/cookbook/cookbook_collection.rb +10 -9
- data/lib/chef/cookbook/file_system_file_vendor.rb +9 -8
- data/lib/chef/cookbook/file_vendor.rb +2 -1
- data/lib/chef/cookbook/metadata.rb +3 -0
- data/lib/chef/cookbook/remote_file_vendor.rb +3 -2
- data/lib/chef/cookbook/syntax_check.rb +8 -0
- data/lib/chef/cookbook_site_streaming_uploader.rb +5 -1
- data/lib/chef/cookbook_version.rb +25 -19
- data/lib/chef/exceptions.rb +3 -0
- data/lib/chef/file_access_control.rb +1 -0
- data/lib/chef/handler.rb +37 -1
- data/lib/chef/mixin/deep_merge.rb +6 -5
- data/lib/chef/mixin/recipe_definition_dsl_core.rb +2 -1
- data/lib/chef/mixin/shell_out.rb +1 -1
- data/lib/chef/mixin/template.rb +1 -1
- data/lib/chef/mixin/xml_escape.rb +2 -2
- data/lib/chef/monkey_patches/dir.rb +1 -1
- data/lib/chef/monkey_patches/string.rb +2 -1
- data/lib/chef/monkey_patches/tempfile.rb +5 -1
- data/lib/chef/provider/package/easy_install.rb +29 -22
- data/lib/chef/provider/template.rb +1 -94
- data/lib/chef/recipe.rb +16 -12
- data/lib/chef/rest.rb +17 -5
- data/lib/chef/run_context.rb +2 -1
- data/lib/chef/run_status.rb +27 -0
- data/lib/chef/runner.rb +5 -3
- data/lib/chef/shef.rb +3 -1
- data/lib/chef/shef/ext.rb +1 -0
- data/lib/chef/shef/model_wrapper.rb +1 -1
- data/lib/chef/shef/shef_rest.rb +1 -1
- data/lib/chef/shef/shef_session.rb +1 -0
- data/lib/chef/shell_out.rb +47 -19
- data/lib/chef/version.rb +1 -1
- metadata +6 -27
@@ -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'
|
data/lib/chef/mixin/shell_out.rb
CHANGED
data/lib/chef/mixin/template.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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
|
-
|
77
|
-
|
78
|
-
|
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
|
data/lib/chef/recipe.rb
CHANGED
@@ -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(*
|
87
|
-
if
|
88
|
-
|
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
|
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?(*
|
106
|
-
|
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(*
|
120
|
-
|
123
|
+
def untag(*tags)
|
124
|
+
tags.each do |tag|
|
121
125
|
run_context.node[:tags].delete(tag)
|
122
126
|
end
|
123
127
|
end
|
data/lib/chef/rest.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
#
|
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
|
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)
|