chef 0.7.16 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of chef might be problematic. Click here for more details.
- data/README.rdoc +11 -10
- data/bin/chef-client +2 -2
- data/bin/chef-solo +1 -1
- data/bin/knife +27 -0
- data/bin/shef +49 -0
- data/distro/README +2 -0
- data/distro/{debian → common}/man/man1/chef-indexer.1 +0 -0
- data/distro/{debian → common}/man/man1/chef-server.1 +0 -0
- data/distro/{debian → common}/man/man8/chef-client.8 +0 -0
- data/distro/{debian → common}/man/man8/chef-solo.8 +0 -0
- data/distro/common/man/man8/knife.8 +375 -0
- data/distro/redhat/etc/init.d/chef-client +8 -4
- data/distro/redhat/etc/init.d/chef-server +16 -15
- data/distro/redhat/etc/init.d/chef-server-webui +78 -0
- data/distro/redhat/etc/init.d/chef-solr +76 -0
- data/distro/redhat/etc/init.d/chef-solr-indexer +75 -0
- data/distro/redhat/etc/sysconfig/chef-client +10 -0
- data/distro/redhat/etc/sysconfig/chef-server +10 -0
- data/distro/redhat/etc/sysconfig/chef-server-webui +10 -0
- data/distro/redhat/etc/sysconfig/chef-solr +9 -0
- data/distro/redhat/etc/sysconfig/chef-solr-indexer +7 -0
- data/distro/suse/etc/init.d/chef-client +121 -0
- data/lib/chef.rb +1 -1
- data/lib/chef/api_client.rb +263 -0
- data/lib/chef/application.rb +1 -1
- data/lib/chef/application/client.rb +21 -3
- data/lib/chef/application/knife.rb +144 -0
- data/lib/chef/application/server.rb +2 -1
- data/lib/chef/application/solo.rb +9 -2
- data/lib/chef/cache.rb +61 -0
- data/lib/chef/cache/checksum.rb +70 -0
- data/lib/chef/certificate.rb +154 -0
- data/lib/chef/client.rb +123 -220
- data/lib/chef/compile.rb +9 -21
- data/lib/chef/config.rb +67 -10
- data/lib/chef/cookbook.rb +49 -22
- data/lib/chef/cookbook/metadata.rb +85 -5
- data/lib/chef/cookbook_loader.rb +4 -4
- data/lib/chef/couchdb.rb +99 -30
- data/lib/chef/daemon.rb +1 -1
- data/lib/chef/data_bag.rb +215 -0
- data/lib/chef/data_bag_item.rb +219 -0
- data/lib/chef/exceptions.rb +3 -0
- data/lib/chef/index_queue.rb +29 -0
- data/lib/chef/index_queue/amqp_client.rb +106 -0
- data/lib/chef/index_queue/consumer.rb +76 -0
- data/lib/chef/index_queue/indexable.rb +74 -0
- data/lib/chef/knife.rb +309 -0
- data/lib/chef/knife/client_bulk_delete.rb +40 -0
- data/lib/chef/knife/client_create.rb +62 -0
- data/lib/chef/knife/client_delete.rb +37 -0
- data/lib/chef/knife/client_edit.rb +37 -0
- data/lib/chef/knife/client_list.rb +40 -0
- data/lib/chef/knife/client_reregister.rb +48 -0
- data/lib/chef/knife/client_show.rb +42 -0
- data/lib/chef/knife/configure.rb +123 -0
- data/lib/chef/knife/cookbook_bulk_delete.rb +46 -0
- data/lib/chef/knife/cookbook_delete.rb +41 -0
- data/lib/chef/knife/cookbook_download.rb +57 -0
- data/lib/chef/knife/cookbook_list.rb +41 -0
- data/lib/chef/knife/cookbook_metadata.rb +87 -0
- data/lib/chef/knife/cookbook_show.rb +75 -0
- data/lib/chef/knife/cookbook_upload.rb +179 -0
- data/lib/chef/knife/data_bag_create.rb +43 -0
- data/lib/chef/knife/data_bag_delete.rb +43 -0
- data/lib/chef/knife/data_bag_edit.rb +49 -0
- data/lib/chef/knife/data_bag_list.rb +42 -0
- data/lib/chef/knife/data_bag_show.rb +40 -0
- data/lib/chef/knife/ec2_instance_data.rb +46 -0
- data/lib/chef/knife/index_rebuild.rb +51 -0
- data/lib/chef/knife/node_bulk_delete.rb +43 -0
- data/lib/chef/knife/node_create.rb +39 -0
- data/lib/chef/knife/node_delete.rb +36 -0
- data/lib/chef/knife/node_edit.rb +36 -0
- data/lib/chef/knife/node_from_file.rb +42 -0
- data/lib/chef/knife/node_list.rb +41 -0
- data/lib/chef/knife/node_run_list_add.rb +64 -0
- data/lib/chef/knife/node_run_list_remove.rb +45 -0
- data/lib/chef/knife/node_show.rb +46 -0
- data/lib/chef/knife/role_bulk_delete.rb +44 -0
- data/lib/chef/knife/role_create.rb +44 -0
- data/lib/chef/knife/role_delete.rb +36 -0
- data/lib/chef/knife/role_edit.rb +37 -0
- data/lib/chef/knife/role_from_file.rb +46 -0
- data/lib/chef/knife/role_list.rb +40 -0
- data/lib/chef/knife/role_show.rb +43 -0
- data/lib/chef/knife/search.rb +94 -0
- data/lib/chef/knife/ssh.rb +170 -0
- data/lib/chef/log.rb +30 -8
- data/lib/chef/mixin/checksum.rb +2 -7
- data/lib/chef/mixin/command.rb +32 -13
- data/lib/chef/mixin/convert_to_class_name.rb +15 -0
- data/lib/chef/mixin/deep_merge.rb +199 -11
- data/lib/chef/mixin/generate_url.rb +18 -9
- data/lib/chef/mixin/language.rb +29 -1
- data/lib/chef/mixin/language_include_attribute.rb +56 -0
- data/lib/chef/mixin/language_include_recipe.rb +53 -0
- data/lib/chef/mixin/params_validate.rb +25 -12
- data/lib/chef/mixin/recipe_definition_dsl_core.rb +2 -0
- data/lib/chef/mixin/template.rb +11 -1
- data/lib/chef/mixin/xml_escape.rb +87 -0
- data/lib/chef/node.rb +144 -122
- data/lib/chef/openid_registration.rb +12 -5
- data/lib/chef/platform.rb +89 -47
- data/lib/chef/provider/breakpoint.rb +36 -0
- data/lib/chef/provider/cron.rb +5 -6
- data/lib/chef/provider/deploy.rb +43 -10
- data/lib/chef/provider/deploy/revision.rb +2 -3
- data/lib/chef/provider/erl_call.rb +72 -0
- data/lib/chef/provider/file.rb +8 -4
- data/lib/chef/provider/git.rb +10 -5
- data/lib/chef/provider/group/dscl.rb +128 -0
- data/lib/chef/provider/http_request.rb +6 -2
- data/lib/chef/provider/ifconfig.rb +1 -0
- data/lib/chef/provider/link.rb +1 -1
- data/lib/chef/provider/log.rb +53 -0
- data/lib/chef/provider/mdadm.rb +88 -0
- data/lib/chef/provider/mount/mount.rb +1 -1
- data/lib/chef/provider/package.rb +1 -1
- data/lib/chef/provider/package/easy_install.rb +106 -0
- data/lib/chef/provider/package/pacman.rb +101 -0
- data/lib/chef/provider/package/portage.rb +1 -1
- data/lib/chef/provider/package/rpm.rb +10 -8
- data/lib/chef/provider/package/yum-dump.py +22 -3
- data/lib/chef/provider/package/yum.rb +32 -8
- data/lib/chef/provider/package/zypper.rb +132 -0
- data/lib/chef/provider/remote_directory.rb +58 -49
- data/lib/chef/provider/remote_file.rb +1 -1
- data/lib/chef/provider/route.rb +136 -80
- data/lib/chef/provider/ruby_block.rb +18 -1
- data/lib/chef/provider/service/arch.rb +109 -0
- data/lib/chef/provider/service/freebsd.rb +0 -1
- data/lib/chef/provider/service/simple.rb +2 -3
- data/lib/chef/provider/service/upstart.rb +191 -0
- data/lib/chef/provider/subversion.rb +12 -4
- data/lib/chef/provider/template.rb +85 -53
- data/lib/chef/provider/user.rb +1 -1
- data/lib/chef/provider/user/dscl.rb +277 -0
- data/lib/chef/provider/user/useradd.rb +1 -0
- data/lib/chef/recipe.rb +2 -41
- data/lib/chef/resource.rb +9 -3
- data/lib/chef/resource/breakpoint.rb +35 -0
- data/lib/chef/resource/deploy.rb +16 -2
- data/lib/chef/resource/easy_install_package.rb +41 -0
- data/lib/chef/resource/erl_call.rb +83 -0
- data/lib/chef/resource/freebsd_package.rb +35 -0
- data/lib/chef/resource/log.rb +62 -0
- data/lib/chef/resource/mdadm.rb +82 -0
- data/lib/chef/resource/pacman_package.rb +33 -0
- data/lib/chef/resource/ruby_block.rb +21 -2
- data/lib/chef/resource/scm.rb +8 -0
- data/lib/chef/resource/subversion.rb +1 -0
- data/lib/chef/resource/user.rb +5 -2
- data/lib/chef/resource/yum_package.rb +36 -0
- data/lib/chef/resource_collection.rb +17 -9
- data/lib/chef/resource_collection/stepable_iterator.rb +124 -0
- data/lib/chef/rest.rb +166 -81
- data/lib/chef/role.rb +114 -38
- data/lib/chef/run_list.rb +15 -6
- data/lib/chef/runner.rb +13 -11
- data/lib/chef/search/query.rb +60 -0
- data/lib/chef/shef.rb +220 -0
- data/lib/chef/shef/ext.rb +297 -0
- data/lib/chef/shef/shef_session.rb +175 -0
- data/lib/chef/streaming_cookbook_uploader.rb +187 -0
- data/lib/chef/tasks/chef_repo.rake +53 -155
- data/lib/chef/util/file_edit.rb +94 -96
- data/lib/chef/webui_user.rb +233 -0
- metadata +219 -63
- data/distro/debian/etc/init.d/chef-indexer +0 -175
- data/distro/redhat/etc/chef/client.rb +0 -16
- data/distro/redhat/etc/chef/indexer.rb +0 -10
- data/distro/redhat/etc/chef/server.rb +0 -22
- data/distro/redhat/etc/init.d/chef-indexer +0 -76
- data/lib/chef/application/indexer.rb +0 -141
- data/lib/chef/queue.rb +0 -145
- data/lib/chef/search.rb +0 -88
- data/lib/chef/search/result.rb +0 -64
- data/lib/chef/search_index.rb +0 -77
- data/lib/chef/util/fileedit.rb +0 -121
@@ -30,19 +30,28 @@ class Chef
|
|
30
30
|
else
|
31
31
|
new_url = "cookbooks/#{cookbook}/#{type}?"
|
32
32
|
new_url += "id=#{url}"
|
33
|
-
|
34
|
-
if type == "files" || type == "templates"
|
35
|
-
new_url += "&platform=#{platform}&version=#{version}&fqdn=#{node[:fqdn]}&node_name=#{node.name}"
|
36
|
-
end
|
37
|
-
if args
|
38
|
-
args.each do |key, value|
|
39
|
-
new_url += "&#{key}=#{value}"
|
40
|
-
end
|
41
|
-
end
|
33
|
+
new_url = generate_cookbook_url_from_uri(new_url, node, args)
|
42
34
|
end
|
43
35
|
Chef::Log.debug("generated cookbook url: #{new_url}")
|
44
36
|
return new_url
|
45
37
|
end
|
38
|
+
|
39
|
+
def generate_cookbook_url_from_uri(uri, node, args=nil)
|
40
|
+
platform, version = Chef::Platform.find_platform_and_version(node)
|
41
|
+
uri =~ /cookbooks\/(.+?)\/(.+)\?/
|
42
|
+
cookbook = $1
|
43
|
+
type = $2
|
44
|
+
if type == "files" || type == "templates"
|
45
|
+
uri += "&platform=#{platform}&version=#{version}&fqdn=#{node[:fqdn]}&node_name=#{node.name}"
|
46
|
+
end
|
47
|
+
if args
|
48
|
+
args.each do |key, value|
|
49
|
+
uri += "&#{key}=#{value}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
uri
|
54
|
+
end
|
46
55
|
|
47
56
|
end
|
48
57
|
end
|
data/lib/chef/mixin/language.rb
CHANGED
@@ -16,6 +16,10 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
+
require 'chef/search/query'
|
20
|
+
require 'chef/data_bag'
|
21
|
+
require 'chef/data_bag_item'
|
22
|
+
|
19
23
|
class Chef
|
20
24
|
module Mixin
|
21
25
|
module Language
|
@@ -73,7 +77,31 @@ class Chef
|
|
73
77
|
|
74
78
|
has_platform
|
75
79
|
end
|
76
|
-
|
80
|
+
|
81
|
+
def search(*args, &block)
|
82
|
+
# If you pass a block, or have at least the start argument, do raw result parsing
|
83
|
+
#
|
84
|
+
# Otherwise, do the iteration for the end user
|
85
|
+
if Kernel.block_given? || args.length >= 4
|
86
|
+
Chef::Search::Query.new.search(*args, &block)
|
87
|
+
else
|
88
|
+
results = Array.new
|
89
|
+
Chef::Search::Query.new.search(*args) do |o|
|
90
|
+
results << o
|
91
|
+
end
|
92
|
+
results
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def data_bag(bag)
|
97
|
+
rbag = Chef::DataBag.load(bag)
|
98
|
+
rbag.keys
|
99
|
+
end
|
100
|
+
|
101
|
+
def data_bag_item(bag, item)
|
102
|
+
Chef::DataBagItem.load(bag, item)
|
103
|
+
end
|
104
|
+
|
77
105
|
end
|
78
106
|
end
|
79
107
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008, 2009 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/log'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
module Mixin
|
23
|
+
module LanguageIncludeAttribute
|
24
|
+
|
25
|
+
def include_attribute(*args)
|
26
|
+
if self.kind_of?(Chef::Node)
|
27
|
+
node = self
|
28
|
+
else
|
29
|
+
node = @node
|
30
|
+
end
|
31
|
+
|
32
|
+
args.flatten.each do |attrib|
|
33
|
+
if node.run_state[:seen_attributes].has_key?(attrib)
|
34
|
+
Chef::Log.debug("I am not loading attribute file #{attrib}, because I have already seen it.")
|
35
|
+
next
|
36
|
+
end
|
37
|
+
|
38
|
+
Chef::Log.debug("Loading Attribute #{attrib}")
|
39
|
+
node.run_state[:seen_attributes][attrib] = true
|
40
|
+
|
41
|
+
if amatch = attrib.match(/(.+?)::(.+)/)
|
42
|
+
cookbook = @cookbook_loader[amatch[1].to_sym]
|
43
|
+
cookbook.load_attribute(amatch[2], node)
|
44
|
+
else
|
45
|
+
cookbook = @cookbook_loader[amatch[1].to_sym]
|
46
|
+
cookbook.load_attribute("default", node)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
true
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Copyright:: Copyright (c) 2008, 2009 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/log'
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
module Mixin
|
23
|
+
module LanguageIncludeRecipe
|
24
|
+
|
25
|
+
def include_recipe(*args)
|
26
|
+
args.flatten.each do |recipe|
|
27
|
+
if @node.run_state[:seen_recipes].has_key?(recipe)
|
28
|
+
Chef::Log.debug("I am not loading #{recipe}, because I have already seen it.")
|
29
|
+
next
|
30
|
+
end
|
31
|
+
|
32
|
+
Chef::Log.debug("Loading Recipe #{recipe} via include_recipe")
|
33
|
+
@node.run_state[:seen_recipes][recipe] = true
|
34
|
+
|
35
|
+
rmatch = recipe.match(/(.+?)::(.+)/)
|
36
|
+
if rmatch
|
37
|
+
cookbook = @cookbook_loader[rmatch[1]]
|
38
|
+
cookbook.load_recipe(rmatch[2], @node, @collection, @definitions, @cookbook_loader)
|
39
|
+
else
|
40
|
+
cookbook = @cookbook_loader[recipe]
|
41
|
+
cookbook.load_recipe("default", @node, @collection, @definitions, @cookbook_loader)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def require_recipe(*args)
|
47
|
+
include_recipe(*args)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -80,11 +80,12 @@ class Chef
|
|
80
80
|
map = {
|
81
81
|
symbol => validation
|
82
82
|
}
|
83
|
-
|
83
|
+
|
84
|
+
if arg == nil && self.instance_variable_defined?(iv_symbol) == true
|
84
85
|
self.instance_variable_get(iv_symbol)
|
85
86
|
else
|
86
|
-
validate({ symbol => arg }, { symbol => validation })
|
87
|
-
self.instance_variable_set(iv_symbol,
|
87
|
+
opts = validate({ symbol => arg }, { symbol => validation })
|
88
|
+
self.instance_variable_set(iv_symbol, opts[symbol])
|
88
89
|
end
|
89
90
|
end
|
90
91
|
|
@@ -104,7 +105,8 @@ class Chef
|
|
104
105
|
# Raise an exception if the parameter is not found.
|
105
106
|
def _pv_required(opts, key, is_required=true)
|
106
107
|
if is_required
|
107
|
-
if opts.has_key?(key.to_s)
|
108
|
+
if (opts.has_key?(key.to_s) && opts[key.to_s] != nil) ||
|
109
|
+
(opts.has_key?(key.to_sym) && opts[key.to_sym] != nil)
|
108
110
|
true
|
109
111
|
else
|
110
112
|
raise ArgumentError, "Required argument #{key} is missing!"
|
@@ -166,16 +168,18 @@ class Chef
|
|
166
168
|
# Check a parameter against a regular expression.
|
167
169
|
def _pv_regex(opts, key, regex)
|
168
170
|
value = _pv_opts_lookup(opts, key)
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
if
|
173
|
-
|
171
|
+
if value != nil
|
172
|
+
passes = false
|
173
|
+
[ regex ].flatten.each do |r|
|
174
|
+
if value != nil
|
175
|
+
if r.match(value.to_s)
|
176
|
+
passes = true
|
177
|
+
end
|
174
178
|
end
|
175
179
|
end
|
176
|
-
|
177
|
-
|
178
|
-
|
180
|
+
unless passes
|
181
|
+
raise ArgumentError, "Option #{key}'s value #{value} does not match regular expression #{regex.to_s}"
|
182
|
+
end
|
179
183
|
end
|
180
184
|
end
|
181
185
|
|
@@ -191,6 +195,15 @@ class Chef
|
|
191
195
|
end
|
192
196
|
end
|
193
197
|
end
|
198
|
+
|
199
|
+
# Allow a parameter to default to @name
|
200
|
+
def _pv_name_attribute(opts, key, is_name_attribute=true)
|
201
|
+
if is_name_attribute
|
202
|
+
if opts[key] == nil
|
203
|
+
opts[key] = self.instance_variable_get("@name")
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
194
207
|
end
|
195
208
|
end
|
196
209
|
end
|
@@ -20,12 +20,14 @@
|
|
20
20
|
require 'chef/recipe'
|
21
21
|
require 'chef/resource'
|
22
22
|
require 'chef/mixin/convert_to_class_name'
|
23
|
+
require 'chef/mixin/language'
|
23
24
|
|
24
25
|
class Chef
|
25
26
|
module Mixin
|
26
27
|
module RecipeDefinitionDSLCore
|
27
28
|
|
28
29
|
include Chef::Mixin::ConvertToClassName
|
30
|
+
include Chef::Mixin::Language
|
29
31
|
|
30
32
|
def method_missing(method_symbol, *args, &block)
|
31
33
|
# If we have a definition that matches, we want to use that instead. This should
|
data/lib/chef/mixin/template.rb
CHANGED
@@ -22,7 +22,17 @@ require 'erubis'
|
|
22
22
|
class Chef
|
23
23
|
module Mixin
|
24
24
|
module Template
|
25
|
-
|
25
|
+
|
26
|
+
module ChefContext
|
27
|
+
def node
|
28
|
+
return @node if @node
|
29
|
+
raise "Could not find a value for node. If you are explicitly setting variables in a template, " +
|
30
|
+
"include a node variable if you plan to use it."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
::Erubis::Context.send(:include, ChefContext)
|
35
|
+
|
26
36
|
# Render a template with Erubis. Takes a template as a string, and a
|
27
37
|
# context hash.
|
28
38
|
def render_template(template, context)
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Sam Ruby
|
3
|
+
# Author:: Daniel DeLeo (<dan@opscode.com>)
|
4
|
+
# Copyright:: Copyright (c) 2009 Opscode, Inc.
|
5
|
+
# Copyright:: Copyright (c) 2005 Sam Ruby
|
6
|
+
# License:: Apache License, Version 2.0
|
7
|
+
#
|
8
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
9
|
+
# you may not use this file except in compliance with the License.
|
10
|
+
# You may obtain a copy of the License at
|
11
|
+
#
|
12
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
13
|
+
#
|
14
|
+
# Unless required by applicable law or agreed to in writing, software
|
15
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
16
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
17
|
+
# See the License for the specific language governing permissions and
|
18
|
+
# limitations under the License.
|
19
|
+
|
20
|
+
# Code adapted from Sam Ruby's xchar.rb http://intertwingly.net/stories/2005/09/28/xchar.rb
|
21
|
+
# Thanks, Sam!
|
22
|
+
|
23
|
+
class Chef
|
24
|
+
module Mixin
|
25
|
+
module XMLEscape
|
26
|
+
extend self
|
27
|
+
|
28
|
+
CP1252 = {
|
29
|
+
128 => 8364, # euro sign
|
30
|
+
130 => 8218, # single low-9 quotation mark
|
31
|
+
131 => 402, # latin small letter f with hook
|
32
|
+
132 => 8222, # double low-9 quotation mark
|
33
|
+
133 => 8230, # horizontal ellipsis
|
34
|
+
134 => 8224, # dagger
|
35
|
+
135 => 8225, # double dagger
|
36
|
+
136 => 710, # modifier letter circumflex accent
|
37
|
+
137 => 8240, # per mille sign
|
38
|
+
138 => 352, # latin capital letter s with caron
|
39
|
+
139 => 8249, # single left-pointing angle quotation mark
|
40
|
+
140 => 338, # latin capital ligature oe
|
41
|
+
142 => 381, # latin capital letter z with caron
|
42
|
+
145 => 8216, # left single quotation mark
|
43
|
+
146 => 8217, # right single quotation mark
|
44
|
+
147 => 8220, # left double quotation mark
|
45
|
+
148 => 8221, # right double quotation mark
|
46
|
+
149 => 8226, # bullet
|
47
|
+
150 => 8211, # en dash
|
48
|
+
151 => 8212, # em dash
|
49
|
+
152 => 732, # small tilde
|
50
|
+
153 => 8482, # trade mark sign
|
51
|
+
154 => 353, # latin small letter s with caron
|
52
|
+
155 => 8250, # single right-pointing angle quotation mark
|
53
|
+
156 => 339, # latin small ligature oe
|
54
|
+
158 => 382, # latin small letter z with caron
|
55
|
+
159 => 376 # latin capital letter y with diaeresis
|
56
|
+
} unless defined?(CP1252)
|
57
|
+
|
58
|
+
# http://www.w3.org/TR/REC-xml/#dt-chardata
|
59
|
+
PREDEFINED = {
|
60
|
+
38 => '&', # ampersand
|
61
|
+
60 => '<', # left angle bracket
|
62
|
+
62 => '>' # right angle bracket
|
63
|
+
} unless defined?(PREDEFINED)
|
64
|
+
|
65
|
+
# http://www.w3.org/TR/REC-xml/#charsets
|
66
|
+
VALID = [[0x9, 0xA, 0xD], (0x20..0xD7FF),
|
67
|
+
(0xE000..0xFFFD), (0x10000..0x10FFFF)] unless defined?(VALID)
|
68
|
+
|
69
|
+
def xml_escape(unescaped_str)
|
70
|
+
begin
|
71
|
+
unescaped_str.unpack("U*").map {|char| xml_escape_char!(char)}.join
|
72
|
+
rescue
|
73
|
+
unescaped_str.unpack("C*").map {|char| xml_escape_char!(char)}.join
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def xml_escape_char!(char)
|
80
|
+
char = CP1252[char] || char
|
81
|
+
char = 42 unless VALID.detect {|range| range.include? char}
|
82
|
+
char = PREDEFINED[char] || (char<128 ? char.chr : "&##{char};")
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/chef/node.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#
|
2
2
|
# Author:: Adam Jacob (<adam@opscode.com>)
|
3
|
+
# Author:: Christopher Brown (<cb@opscode.com>)
|
3
4
|
# Copyright:: Copyright (c) 2008 Opscode, Inc.
|
4
5
|
# License:: Apache License, Version 2.0
|
5
6
|
#
|
@@ -20,24 +21,30 @@ require 'chef/config'
|
|
20
21
|
require 'chef/mixin/check_helper'
|
21
22
|
require 'chef/mixin/params_validate'
|
22
23
|
require 'chef/mixin/from_file'
|
24
|
+
require 'chef/mixin/language_include_attribute'
|
23
25
|
require 'chef/couchdb'
|
24
|
-
require 'chef/
|
26
|
+
require 'chef/rest'
|
25
27
|
require 'chef/run_list'
|
26
28
|
require 'chef/node/attribute'
|
29
|
+
require 'chef/index_queue'
|
27
30
|
require 'extlib'
|
28
31
|
require 'json'
|
29
32
|
|
30
33
|
class Chef
|
31
34
|
class Node
|
32
35
|
|
33
|
-
attr_accessor :attribute, :recipe_list, :couchdb_rev, :run_state, :run_list, :
|
36
|
+
attr_accessor :attribute, :recipe_list, :couchdb, :couchdb_rev, :run_state, :run_list, :override_attrs, :default_attrs, :cookbook_loader
|
37
|
+
attr_reader :node
|
38
|
+
attr_reader :couchdb_id
|
34
39
|
|
35
40
|
include Chef::Mixin::CheckHelper
|
36
41
|
include Chef::Mixin::FromFile
|
37
42
|
include Chef::Mixin::ParamsValidate
|
43
|
+
include Chef::Mixin::LanguageIncludeAttribute
|
44
|
+
include Chef::IndexQueue::Indexable
|
38
45
|
|
39
46
|
DESIGN_DOCUMENT = {
|
40
|
-
"version" =>
|
47
|
+
"version" => 9,
|
41
48
|
"language" => "javascript",
|
42
49
|
"views" => {
|
43
50
|
"all" => {
|
@@ -120,22 +127,39 @@ class Chef
|
|
120
127
|
}
|
121
128
|
|
122
129
|
# Create a new Chef::Node object.
|
123
|
-
def initialize()
|
130
|
+
def initialize(couchdb=nil)
|
124
131
|
@name = nil
|
132
|
+
@node = self
|
125
133
|
|
126
134
|
@attribute = Mash.new
|
127
|
-
@
|
128
|
-
@
|
129
|
-
@run_list = Chef::RunList.new
|
135
|
+
@override_attrs = Mash.new
|
136
|
+
@default_attrs = Mash.new
|
137
|
+
@run_list = Chef::RunList.new
|
130
138
|
|
131
139
|
@couchdb_rev = nil
|
132
|
-
@
|
140
|
+
@couchdb_id = nil
|
141
|
+
@couchdb = couchdb || Chef::CouchDB.new
|
142
|
+
|
133
143
|
@run_state = {
|
134
144
|
:template_cache => Hash.new,
|
135
|
-
:seen_recipes => Hash.new
|
145
|
+
:seen_recipes => Hash.new,
|
146
|
+
:seen_attributes => Hash.new
|
136
147
|
}
|
137
148
|
end
|
138
|
-
|
149
|
+
|
150
|
+
def couchdb_id=(value)
|
151
|
+
@couchdb_id = value
|
152
|
+
self.index_id = value
|
153
|
+
end
|
154
|
+
|
155
|
+
def chef_server_rest
|
156
|
+
Chef::REST.new(Chef::Config[:chef_server_url])
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.chef_server_rest
|
160
|
+
Chef::REST.new(Chef::Config[:chef_server_url])
|
161
|
+
end
|
162
|
+
|
139
163
|
# Find a recipe for this Chef::Node by fqdn. Will search first for
|
140
164
|
# Chef::Config["node_path"]/fqdn.rb, then hostname.rb, then default.rb.
|
141
165
|
#
|
@@ -143,21 +167,15 @@ class Chef
|
|
143
167
|
#
|
144
168
|
# Raises an ArgumentError if it cannot find the node.
|
145
169
|
def find_file(fqdn)
|
146
|
-
node_file = nil
|
147
170
|
host_parts = fqdn.split(".")
|
148
171
|
hostname = host_parts[0]
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
end
|
157
|
-
unless node_file
|
158
|
-
raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
|
159
|
-
end
|
160
|
-
self.from_file(node_file)
|
172
|
+
|
173
|
+
[fqdn, hostname, "default"].each { |fname|
|
174
|
+
node_file = File.join(Chef::Config[:node_path], "#{fname.to_s}.rb")
|
175
|
+
return self.from_file(node_file) if File.exists?(node_file)
|
176
|
+
}
|
177
|
+
|
178
|
+
raise ArgumentError, "Cannot find a node matching #{fqdn}, not even with default.rb!"
|
161
179
|
end
|
162
180
|
|
163
181
|
# Set the name of this Node, or return the current name.
|
@@ -179,20 +197,22 @@ class Chef
|
|
179
197
|
|
180
198
|
# Return an attribute of this node. Returns nil if the attribute is not found.
|
181
199
|
def [](attrib)
|
182
|
-
|
183
|
-
attrs[attrib]
|
200
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)[attrib]
|
184
201
|
end
|
185
202
|
|
186
203
|
# Set an attribute of this node
|
187
204
|
def []=(attrib, value)
|
188
|
-
|
189
|
-
|
205
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)[attrib] = value
|
206
|
+
end
|
207
|
+
|
208
|
+
def store(attrib, value)
|
209
|
+
self[attrib] = value
|
190
210
|
end
|
191
211
|
|
192
212
|
# Set an attribute of this node, but auto-vivifiy any Mashes that might
|
193
213
|
# be missing
|
194
214
|
def set
|
195
|
-
attrs = Chef::Node::Attribute.new(@attribute, @
|
215
|
+
attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
|
196
216
|
attrs.auto_vivifiy_on_read = true
|
197
217
|
attrs
|
198
218
|
end
|
@@ -200,7 +220,7 @@ class Chef
|
|
200
220
|
# Set an attribute of this node, auto-vivifiying any mashes that are
|
201
221
|
# missing, but if the final value already exists, don't set it
|
202
222
|
def set_unless
|
203
|
-
attrs = Chef::Node::Attribute.new(@attribute, @
|
223
|
+
attrs = Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs)
|
204
224
|
attrs.auto_vivifiy_on_read = true
|
205
225
|
attrs.set_unless_value_present = true
|
206
226
|
attrs
|
@@ -214,53 +234,31 @@ class Chef
|
|
214
234
|
# Only works on the top level. Preferred way is to use the normal [] style
|
215
235
|
# lookup and call attribute?()
|
216
236
|
def attribute?(attrib)
|
217
|
-
|
218
|
-
attrs.attribute?(attrib)
|
237
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs).attribute?(attrib)
|
219
238
|
end
|
220
239
|
|
221
240
|
# Yield each key of the top level to the block.
|
222
241
|
def each(&block)
|
223
|
-
|
224
|
-
attrs.each(&block)
|
242
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs).each(&block)
|
225
243
|
end
|
226
244
|
|
227
245
|
# Iterates over each attribute, passing the attribute and value to the block.
|
228
246
|
def each_attribute(&block)
|
229
|
-
|
230
|
-
attrs.each_attribute(&block)
|
247
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs).each_attribute(&block)
|
231
248
|
end
|
232
249
|
|
233
250
|
# Set an attribute based on the missing method. If you pass an argument, we'll use that
|
234
251
|
# to set the attribute values. Otherwise, we'll wind up just returning the attributes
|
235
252
|
# value.
|
236
253
|
def method_missing(symbol, *args)
|
237
|
-
|
238
|
-
attrs.send(symbol, *args)
|
254
|
+
Chef::Node::Attribute.new(@attribute, @default_attrs, @override_attrs).send(symbol, *args)
|
239
255
|
end
|
240
256
|
|
241
257
|
# Returns true if this Node expects a given recipe, false if not.
|
242
258
|
def recipe?(recipe_name)
|
243
|
-
|
244
|
-
true
|
245
|
-
else
|
246
|
-
if @run_state[:seen_recipes].include?(recipe_name)
|
247
|
-
true
|
248
|
-
else
|
249
|
-
false
|
250
|
-
end
|
251
|
-
end
|
259
|
+
@run_list.include?(recipe_name) || @run_state[:seen_recipes].include?(recipe_name)
|
252
260
|
end
|
253
261
|
|
254
|
-
# Returns an Array of recipes. If you call it with arguments, they will become the new
|
255
|
-
# list of recipes.
|
256
|
-
def recipes(*args)
|
257
|
-
if args.length > 0
|
258
|
-
@run_list.reset(args)
|
259
|
-
else
|
260
|
-
@run_list
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
262
|
# Returns true if this Node expects a given role, false if not.
|
265
263
|
def role?(role_name)
|
266
264
|
@run_list.include?("role[#{role_name}]")
|
@@ -269,11 +267,12 @@ class Chef
|
|
269
267
|
# Returns an Array of roles and recipes, in the order they will be applied.
|
270
268
|
# If you call it with arguments, they will become the new list of roles and recipes.
|
271
269
|
def run_list(*args)
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
270
|
+
args.length > 0 ? @run_list.reset!(args) : @run_list
|
271
|
+
end
|
272
|
+
|
273
|
+
def recipes(*args)
|
274
|
+
Chef::Log.warn "Chef::Node#recipes method is deprecated. Please use Chef::Node#run_list"
|
275
|
+
run_list(*args)
|
277
276
|
end
|
278
277
|
|
279
278
|
# Returns true if this Node expects a given role, false if not.
|
@@ -281,51 +280,33 @@ class Chef
|
|
281
280
|
@run_list.detect { |r| r == item } ? true : false
|
282
281
|
end
|
283
282
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
def to_index
|
291
|
-
index_hash = {
|
292
|
-
"index_name" => "node",
|
293
|
-
"id" => "node_#{@name}",
|
294
|
-
"name" => @name,
|
295
|
-
}
|
296
|
-
@attribute.each do |key, value|
|
297
|
-
if value.kind_of?(Hash) || value.kind_of?(Mash)
|
298
|
-
index_flatten_hash(key, value).each do |to_index|
|
299
|
-
to_index.each do |nk, nv|
|
300
|
-
index_hash[nk] = nv
|
301
|
-
end
|
302
|
-
end
|
283
|
+
def consume_attributes(attrs)
|
284
|
+
attrs ||= {}
|
285
|
+
Chef::Log.debug("Adding JSON Attributes")
|
286
|
+
attrs.each do |key, value|
|
287
|
+
if ["recipes", "run_list"].include?(key)
|
288
|
+
run_list(value)
|
303
289
|
else
|
304
|
-
|
290
|
+
Chef::Log.debug("JSON Attribute: #{key} - #{value.inspect}")
|
291
|
+
store(key, value)
|
305
292
|
end
|
306
293
|
end
|
307
|
-
|
308
|
-
|
309
|
-
index_hash["run_list"] = @run_list.run_list if @run_list.run_list.length > 0
|
310
|
-
index_hash
|
294
|
+
self[:tags] = Array.new unless attribute?(:tags)
|
295
|
+
|
311
296
|
end
|
312
297
|
|
313
|
-
#
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
# results<Array>:: An array of hashes with one element.
|
319
|
-
def index_flatten_hash(parent_name, hash)
|
320
|
-
results = Array.new
|
321
|
-
hash.each do |k, v|
|
322
|
-
if v.kind_of?(Hash) || v.kind_of?(Mash)
|
323
|
-
results << index_flatten_hash("#{parent_name}_#{k}", v)
|
324
|
-
else
|
325
|
-
results << { "#{parent_name}_#{k}", v }
|
326
|
-
end
|
298
|
+
# Transform the node to a Hash
|
299
|
+
def to_hash
|
300
|
+
index_hash = Hash.new
|
301
|
+
self.each do |k, v|
|
302
|
+
index_hash[k] = v
|
327
303
|
end
|
328
|
-
|
304
|
+
index_hash["chef_type"] = "node"
|
305
|
+
index_hash["name"] = @name
|
306
|
+
index_hash["recipe"] = @run_list.recipes if @run_list.recipes.length > 0
|
307
|
+
index_hash["role"] = @run_list.roles if @run_list.roles.length > 0
|
308
|
+
index_hash["run_list"] = @run_list.run_list if @run_list.run_list.length > 0
|
309
|
+
index_hash
|
329
310
|
end
|
330
311
|
|
331
312
|
# Serialize this object as a hash
|
@@ -335,6 +316,8 @@ class Chef
|
|
335
316
|
'json_class' => self.class.name,
|
336
317
|
"attributes" => @attribute,
|
337
318
|
"chef_type" => "node",
|
319
|
+
"defaults" => @default_attrs,
|
320
|
+
"overrides" => @override_attrs,
|
338
321
|
"run_list" => @run_list.run_list,
|
339
322
|
}
|
340
323
|
result["_rev"] = @couchdb_rev if @couchdb_rev
|
@@ -345,62 +328,101 @@ class Chef
|
|
345
328
|
def self.json_create(o)
|
346
329
|
node = new
|
347
330
|
node.name(o["name"])
|
348
|
-
o["attributes"].each
|
349
|
-
|
350
|
-
|
351
|
-
if o.has_key?("
|
352
|
-
|
353
|
-
end
|
354
|
-
if o.has_key?("overrides")
|
355
|
-
node.override = o["overrides"]
|
356
|
-
end
|
331
|
+
o["attributes"].each { |k,v| node[k] = v }
|
332
|
+
|
333
|
+
node.default_attrs = Mash.new(o["defaults"]) if o.has_key?("defaults")
|
334
|
+
node.override_attrs = Mash.new(o["overrides"]) if o.has_key?("overrides")
|
335
|
+
|
357
336
|
if o.has_key?("run_list")
|
358
|
-
node.run_list.reset(o["run_list"])
|
337
|
+
node.run_list.reset!(o["run_list"])
|
359
338
|
else
|
360
339
|
o["recipes"].each { |r| node.recipes << r }
|
361
340
|
end
|
362
341
|
node.couchdb_rev = o["_rev"] if o.has_key?("_rev")
|
342
|
+
node.couchdb_id = o["_id"] if o.has_key?("_id")
|
343
|
+
node.index_id = node.couchdb_id
|
363
344
|
node
|
364
345
|
end
|
365
346
|
|
366
347
|
# List all the Chef::Node objects in the CouchDB. If inflate is set to true, you will get
|
367
348
|
# the full list of all Nodes, fully inflated.
|
349
|
+
def self.cdb_list(inflate=false, couchdb=nil)
|
350
|
+
rs =(couchdb || Chef::CouchDB.new).list("nodes", inflate)
|
351
|
+
lookup = (inflate ? "value" : "key")
|
352
|
+
rs["rows"].collect { |r| r[lookup] }
|
353
|
+
end
|
354
|
+
|
368
355
|
def self.list(inflate=false)
|
369
|
-
rs = Chef::CouchDB.new.list("nodes", inflate)
|
370
356
|
if inflate
|
371
|
-
|
357
|
+
response = Hash.new
|
358
|
+
Chef::Search::Query.new.search(:node) do |n|
|
359
|
+
response[n.name] = n unless n.nil?
|
360
|
+
end
|
361
|
+
response
|
372
362
|
else
|
373
|
-
|
363
|
+
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes")
|
374
364
|
end
|
375
365
|
end
|
376
366
|
|
377
367
|
# Load a node by name from CouchDB
|
368
|
+
def self.cdb_load(name, couchdb=nil)
|
369
|
+
(couchdb || Chef::CouchDB.new).load("node", name)
|
370
|
+
end
|
371
|
+
|
372
|
+
def self.exists?(nodename, couchdb)
|
373
|
+
begin
|
374
|
+
self.cdb_load(nodename, couchdb)
|
375
|
+
rescue Chef::Exceptions::CouchDBNotFound
|
376
|
+
nil
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Load a node by name
|
378
381
|
def self.load(name)
|
379
|
-
Chef::
|
382
|
+
Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("nodes/#{name}")
|
380
383
|
end
|
381
384
|
|
382
385
|
# Remove this node from the CouchDB
|
383
|
-
def
|
384
|
-
Chef::Queue.send_msg(:queue, :remove, self)
|
386
|
+
def cdb_destroy
|
385
387
|
@couchdb.delete("node", @name, @couchdb_rev)
|
386
388
|
end
|
389
|
+
|
390
|
+
# Remove this node via the REST API
|
391
|
+
def destroy
|
392
|
+
chef_server_rest.delete_rest("nodes/#{@name}")
|
393
|
+
end
|
387
394
|
|
388
395
|
# Save this node to the CouchDB
|
396
|
+
def cdb_save
|
397
|
+
@couchdb_rev = @couchdb.store("node", @name, self)["rev"]
|
398
|
+
end
|
399
|
+
|
400
|
+
# Save this node via the REST API
|
389
401
|
def save
|
390
|
-
|
391
|
-
|
392
|
-
|
402
|
+
begin
|
403
|
+
chef_server_rest.put_rest("nodes/#{@name}", self)
|
404
|
+
rescue Net::HTTPServerException => e
|
405
|
+
raise e unless e.response.code == "404"
|
406
|
+
chef_server_rest.post_rest("nodes", self)
|
407
|
+
end
|
408
|
+
self
|
393
409
|
end
|
394
410
|
|
411
|
+
# Create the node via the REST API
|
412
|
+
def create
|
413
|
+
chef_server_rest.post_rest("nodes", self)
|
414
|
+
self
|
415
|
+
end
|
416
|
+
|
395
417
|
# Set up our CouchDB design document
|
396
|
-
def self.create_design_document
|
397
|
-
Chef::CouchDB.new.create_design_document("nodes", DESIGN_DOCUMENT)
|
418
|
+
def self.create_design_document(couchdb=nil)
|
419
|
+
(couchdb || Chef::CouchDB.new).create_design_document("nodes", DESIGN_DOCUMENT)
|
398
420
|
end
|
399
421
|
|
400
422
|
# As a string
|
401
423
|
def to_s
|
402
424
|
"node[#{@name}]"
|
403
425
|
end
|
404
|
-
|
426
|
+
|
405
427
|
end
|
406
428
|
end
|