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.
- 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)
|