chef 0.7.10

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.

Files changed (120) 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/lib/chef.rb +49 -0
  6. data/lib/chef/application.rb +98 -0
  7. data/lib/chef/application/agent.rb +18 -0
  8. data/lib/chef/application/client.rb +209 -0
  9. data/lib/chef/application/indexer.rb +141 -0
  10. data/lib/chef/application/server.rb +18 -0
  11. data/lib/chef/application/solo.rb +214 -0
  12. data/lib/chef/client.rb +396 -0
  13. data/lib/chef/compile.rb +138 -0
  14. data/lib/chef/config.rb +141 -0
  15. data/lib/chef/cookbook.rb +144 -0
  16. data/lib/chef/cookbook/metadata.rb +407 -0
  17. data/lib/chef/cookbook/metadata/version.rb +87 -0
  18. data/lib/chef/cookbook_loader.rb +168 -0
  19. data/lib/chef/couchdb.rb +172 -0
  20. data/lib/chef/daemon.rb +170 -0
  21. data/lib/chef/exceptions.rb +36 -0
  22. data/lib/chef/file_cache.rb +205 -0
  23. data/lib/chef/log.rb +39 -0
  24. data/lib/chef/mixin/check_helper.rb +31 -0
  25. data/lib/chef/mixin/checksum.rb +37 -0
  26. data/lib/chef/mixin/command.rb +351 -0
  27. data/lib/chef/mixin/create_path.rb +56 -0
  28. data/lib/chef/mixin/deep_merge.rb +36 -0
  29. data/lib/chef/mixin/find_preferred_file.rb +99 -0
  30. data/lib/chef/mixin/from_file.rb +36 -0
  31. data/lib/chef/mixin/generate_url.rb +48 -0
  32. data/lib/chef/mixin/language.rb +79 -0
  33. data/lib/chef/mixin/params_validate.rb +197 -0
  34. data/lib/chef/mixin/template.rb +84 -0
  35. data/lib/chef/node.rb +406 -0
  36. data/lib/chef/node/attribute.rb +412 -0
  37. data/lib/chef/openid_registration.rb +181 -0
  38. data/lib/chef/platform.rb +253 -0
  39. data/lib/chef/provider.rb +40 -0
  40. data/lib/chef/provider/cron.rb +137 -0
  41. data/lib/chef/provider/directory.rb +72 -0
  42. data/lib/chef/provider/execute.rb +58 -0
  43. data/lib/chef/provider/file.rb +191 -0
  44. data/lib/chef/provider/group.rb +120 -0
  45. data/lib/chef/provider/group/groupadd.rb +92 -0
  46. data/lib/chef/provider/group/pw.rb +88 -0
  47. data/lib/chef/provider/http_request.rb +102 -0
  48. data/lib/chef/provider/ifconfig.rb +131 -0
  49. data/lib/chef/provider/link.rb +157 -0
  50. data/lib/chef/provider/mount.rb +121 -0
  51. data/lib/chef/provider/mount/mount.rb +208 -0
  52. data/lib/chef/provider/package.rb +160 -0
  53. data/lib/chef/provider/package/apt.rb +110 -0
  54. data/lib/chef/provider/package/dpkg.rb +113 -0
  55. data/lib/chef/provider/package/freebsd.rb +153 -0
  56. data/lib/chef/provider/package/macports.rb +105 -0
  57. data/lib/chef/provider/package/portage.rb +124 -0
  58. data/lib/chef/provider/package/rpm.rb +99 -0
  59. data/lib/chef/provider/package/rubygems.rb +130 -0
  60. data/lib/chef/provider/package/yum-dump.py +104 -0
  61. data/lib/chef/provider/package/yum.rb +175 -0
  62. data/lib/chef/provider/remote_directory.rb +126 -0
  63. data/lib/chef/provider/remote_file.rb +134 -0
  64. data/lib/chef/provider/route.rb +118 -0
  65. data/lib/chef/provider/ruby_block.rb +15 -0
  66. data/lib/chef/provider/script.rb +42 -0
  67. data/lib/chef/provider/service.rb +129 -0
  68. data/lib/chef/provider/service/debian.rb +64 -0
  69. data/lib/chef/provider/service/freebsd.rb +157 -0
  70. data/lib/chef/provider/service/gentoo.rb +54 -0
  71. data/lib/chef/provider/service/init.rb +126 -0
  72. data/lib/chef/provider/service/redhat.rb +62 -0
  73. data/lib/chef/provider/template.rb +141 -0
  74. data/lib/chef/provider/user.rb +170 -0
  75. data/lib/chef/provider/user/pw.rb +113 -0
  76. data/lib/chef/provider/user/useradd.rb +107 -0
  77. data/lib/chef/queue.rb +145 -0
  78. data/lib/chef/recipe.rb +210 -0
  79. data/lib/chef/resource.rb +256 -0
  80. data/lib/chef/resource/apt_package.rb +34 -0
  81. data/lib/chef/resource/bash.rb +33 -0
  82. data/lib/chef/resource/cron.rb +143 -0
  83. data/lib/chef/resource/csh.rb +33 -0
  84. data/lib/chef/resource/directory.rb +76 -0
  85. data/lib/chef/resource/dpkg_package.rb +34 -0
  86. data/lib/chef/resource/execute.rb +127 -0
  87. data/lib/chef/resource/file.rb +84 -0
  88. data/lib/chef/resource/gem_package.rb +41 -0
  89. data/lib/chef/resource/group.rb +68 -0
  90. data/lib/chef/resource/http_request.rb +52 -0
  91. data/lib/chef/resource/ifconfig.rb +134 -0
  92. data/lib/chef/resource/link.rb +78 -0
  93. data/lib/chef/resource/macports_package.rb +29 -0
  94. data/lib/chef/resource/mount.rb +135 -0
  95. data/lib/chef/resource/package.rb +80 -0
  96. data/lib/chef/resource/perl.rb +33 -0
  97. data/lib/chef/resource/portage_package.rb +33 -0
  98. data/lib/chef/resource/python.rb +33 -0
  99. data/lib/chef/resource/remote_directory.rb +91 -0
  100. data/lib/chef/resource/remote_file.rb +60 -0
  101. data/lib/chef/resource/route.rb +135 -0
  102. data/lib/chef/resource/ruby.rb +33 -0
  103. data/lib/chef/resource/ruby_block.rb +20 -0
  104. data/lib/chef/resource/script.rb +51 -0
  105. data/lib/chef/resource/service.rb +134 -0
  106. data/lib/chef/resource/template.rb +60 -0
  107. data/lib/chef/resource/user.rb +98 -0
  108. data/lib/chef/resource_collection.rb +176 -0
  109. data/lib/chef/resource_definition.rb +67 -0
  110. data/lib/chef/rest.rb +238 -0
  111. data/lib/chef/role.rb +231 -0
  112. data/lib/chef/run_list.rb +156 -0
  113. data/lib/chef/runner.rb +123 -0
  114. data/lib/chef/search.rb +88 -0
  115. data/lib/chef/search/result.rb +64 -0
  116. data/lib/chef/search_index.rb +77 -0
  117. data/lib/chef/tasks/chef_repo.rake +345 -0
  118. data/lib/chef/util/file_edit.rb +125 -0
  119. data/lib/chef/util/fileedit.rb +121 -0
  120. metadata +262 -0
@@ -0,0 +1,113 @@
1
+ #
2
+ # Author:: Stephen Haynes (<sh@nomitor.com>)
3
+ # Copyright:: Copyright (c) 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/provider/user'
20
+
21
+ class Chef
22
+ class Provider
23
+ class User
24
+ class Pw < Chef::Provider::User
25
+
26
+ def load_current_resource
27
+ super
28
+ raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{@new_resource}" unless ::File.exists?("/usr/sbin/pw")
29
+ end
30
+
31
+ def create_user
32
+ command = "pw useradd"
33
+ command << set_options
34
+ run_command(:command => command)
35
+ modify_password
36
+ end
37
+
38
+ def manage_user
39
+ command = "pw usermod"
40
+ command << set_options
41
+ run_command(:command => command)
42
+ modify_password
43
+ end
44
+
45
+ def remove_user
46
+ command = "pw userdel #{@new_resource.username}"
47
+ command << " -r" if @new_resource.supports[:manage_home]
48
+ run_command(:command => command)
49
+ end
50
+
51
+ def check_lock
52
+ case @current_resource.password
53
+ when /^\*LOCKED\*/
54
+ @locked = true
55
+ else
56
+ @locked = false
57
+ end
58
+ @locked
59
+ end
60
+
61
+ def lock_user
62
+ run_command(:command => "pw lock #{@new_resource.username}")
63
+ end
64
+
65
+ def unlock_user
66
+ run_command(:command => "pw unlock #{@new_resource.username}")
67
+ end
68
+
69
+ def set_options
70
+ opts = " #{@new_resource.username}"
71
+
72
+ field_list = {
73
+ 'comment' => "-c",
74
+ 'home' => "-d",
75
+ 'gid' => "-g",
76
+ 'uid' => "-u",
77
+ 'shell' => "-s"
78
+ }
79
+ field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
80
+ field_symbol = field.to_sym
81
+ if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
82
+ if @new_resource.send(field_symbol)
83
+ Chef::Log.debug("Setting #{@new_resource} #{field} to #{@new_resource.send(field_symbol)}")
84
+ opts << " #{option} '#{@new_resource.send(field_symbol)}'"
85
+ end
86
+ end
87
+ end
88
+ if @new_resource.supports[:manage_home]
89
+ Chef::Log.debug("Managing the home directory for #{@new_resource}")
90
+ opts << " -m"
91
+ end
92
+ opts
93
+ end
94
+
95
+ def modify_password
96
+ if @current_resource.password != @new_resource.password
97
+ Chef::Log.debug("#{new_resource}: updating password")
98
+ command = "pw usermod #{@new_resource.username} -H 0"
99
+ status = popen4(command, :waitlast => true) do |pid, stdin, stdout, stderr|
100
+ stdin.puts "#{@new_resource.password}"
101
+ end
102
+
103
+ unless status.exitstatus == 0
104
+ raise Chef::Exceptions::User, "pw failed - #{status.inspect}!"
105
+ end
106
+ else
107
+ Chef::Log.debug("#{new_resource}: no change needed to password")
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,107 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@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
+
19
+ require 'chef/provider/user'
20
+
21
+ class Chef
22
+ class Provider
23
+ class User
24
+ class Useradd < Chef::Provider::User
25
+ def create_user
26
+ command = "useradd"
27
+ command << set_options
28
+ run_command(:command => command)
29
+ end
30
+
31
+ def manage_user
32
+ command = "usermod"
33
+ command << set_options
34
+ run_command(:command => command)
35
+ end
36
+
37
+ def remove_user
38
+ command = "userdel"
39
+ command << " -r" if @new_resource.supports[:manage_home]
40
+ command << " #{@new_resource.username}"
41
+ run_command(:command => command)
42
+ end
43
+
44
+ def check_lock
45
+ status = popen4("passwd -S #{@new_resource.username}") do |pid, stdin, stdout, stderr|
46
+ status_line = stdout.gets.split(' ')
47
+ case status_line[1]
48
+ when /^P/
49
+ @locked = false
50
+ when /^N/
51
+ @locked = false
52
+ when /^L/
53
+ @locked = true
54
+ end
55
+ end
56
+
57
+ unless status.exitstatus == 0
58
+ raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!"
59
+ end
60
+
61
+ @locked
62
+ end
63
+
64
+ def lock_user
65
+ run_command(:command => "usermod -L #{@new_resource.username}")
66
+ end
67
+
68
+ def unlock_user
69
+ run_command(:command => "usermod -U #{@new_resource.username}")
70
+ end
71
+
72
+ def set_options
73
+ opts = ''
74
+
75
+ field_list = {
76
+ 'comment' => "-c",
77
+ 'gid' => "-g",
78
+ 'uid' => "-u",
79
+ 'shell' => "-s",
80
+ 'password' => "-p"
81
+ }
82
+ field_list.sort{ |a,b| a[0] <=> b[0] }.each do |field, option|
83
+ field_symbol = field.to_sym
84
+ if @current_resource.send(field_symbol) != @new_resource.send(field_symbol)
85
+ if @new_resource.send(field_symbol)
86
+ Chef::Log.debug("Setting #{@new_resource} #{field} to #{@new_resource.send(field_symbol)}")
87
+ opts << " #{option} '#{@new_resource.send(field_symbol)}'"
88
+ end
89
+ end
90
+ end
91
+ if @current_resource.home != @new_resource.home && @new_resource.home
92
+ if @new_resource.supports[:manage_home]
93
+ Chef::Log.debug("Managing the home directory for #{@new_resource}")
94
+ opts << " -d '#{@new_resource.home}' -m"
95
+ else
96
+ Chef::Log.debug("Setting #{@new_resource} home to #{@new_resource.home}")
97
+ opts << " -d '#{@new_resource.home}'"
98
+ end
99
+ end
100
+ opts << " #{@new_resource.username}"
101
+ opts
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+ end
data/lib/chef/queue.rb ADDED
@@ -0,0 +1,145 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@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
+
19
+ require 'chef/mixin/params_validate'
20
+ require 'json'
21
+ require 'stomp'
22
+
23
+ class Chef
24
+ class Queue
25
+
26
+ @client = nil
27
+ @queue_retry_delay = Chef::Config[:queue_retry_delay]
28
+ @queue_retry_count = Chef::Config[:queue_retry_count]
29
+
30
+ class << self
31
+ include Chef::Mixin::ParamsValidate
32
+
33
+ def connect
34
+ queue_user = Chef::Config[:queue_user]
35
+ queue_password = Chef::Config[:queue_password]
36
+ queue_host = Chef::Config[:queue_host]
37
+ queue_port = Chef::Config[:queue_port]
38
+ queue_retries = 1 unless queue_retries
39
+
40
+ # Connection.open(login = "", passcode = "", host='localhost', port=61613, reliable=FALSE, reconnectDelay=5)
41
+ @client = Stomp::Connection.open(queue_user, queue_password, queue_host, queue_port, false)
42
+
43
+ rescue Errno::ECONNREFUSED
44
+ Chef::Log.error("Connection refused connecting to stomp queue at #{queue_host}:#{queue_port}, retry #{queue_retries}/#{@queue_retry_count}")
45
+ sleep(@queue_retry_delay)
46
+ retry if (queue_retries += 1) < @queue_retry_count
47
+ raise Errno::ECONNREFUSED, "Connection refused connecting to stomp queue at #{queue_host}:#{queue_port}, giving up"
48
+ rescue Timeout::Error
49
+ Chef::Log.error("Timeout connecting to stomp queue at #{queue_host}:#{queue_port}, retry #{queue_retries}/#{@queue_retry_count}")
50
+ sleep(@queue_retry_delay)
51
+ retry if (queue_retries += 1) < @queue_retry_count
52
+ raise Timeout::Error, "Timeout connecting to stomp queue at #{queue_host}:#{queue_port}, giving up"
53
+ else
54
+ queue_retries = 1 # reset the number of retries on success
55
+ end
56
+
57
+ def make_url(type, name)
58
+ validate(
59
+ {
60
+ :queue_type => type.to_sym,
61
+ :queue_name => name.to_sym,
62
+ },
63
+ {
64
+ :queue_type => {
65
+ :equal_to => [ :topic, :queue ],
66
+ },
67
+ :queue_name => {
68
+ :kind_of => [ String, Symbol ],
69
+ }
70
+ }
71
+ )
72
+ if Chef::Config[:queue_prefix]
73
+ queue_prefix = Chef::Config[:queue_prefix]
74
+ queue_url = "/#{type}/#{queue_prefix}/chef/#{name}"
75
+ else
76
+ queue_url = "/#{type}/chef/#{name}"
77
+ end
78
+ queue_url
79
+ end
80
+
81
+ def subscribe(type, name)
82
+ queue_url = make_url(type, name)
83
+ Chef::Log.debug("Subscribing to #{queue_url}")
84
+ connect if @client == nil
85
+ @client.subscribe(queue_url)
86
+ end
87
+
88
+ def send_msg(type, name, msg)
89
+ queue_retries = 1 unless queue_retries
90
+ validate(
91
+ {
92
+ :message => msg,
93
+ },
94
+ {
95
+ :message => {
96
+ :respond_to => :to_json
97
+ }
98
+ }
99
+ )
100
+ queue_url = make_url(type, name)
101
+ json = msg.to_json
102
+ connect if @client == nil
103
+ Chef::Log.debug("Sending to #{queue_url}: #{json}")
104
+ begin
105
+ @client.send(queue_url, json)
106
+ rescue Errno::EPIPE
107
+ Chef::Log.debug("Lost connection to stomp queue, reconnecting")
108
+ connect
109
+ retry if (queue_retries += 1) < @queue_retry_count
110
+ raise Errno::EPIPE, "Lost connection to stomp queue, giving up"
111
+ else
112
+ queue_retries = 1 # reset the number of retries on success
113
+ end
114
+ end
115
+
116
+ def receive_msg
117
+ connect if @client == nil
118
+ begin
119
+ raw_msg = @client.receive()
120
+ Chef::Log.debug("Received Message from #{raw_msg.headers["destination"]} containing: #{raw_msg.body}")
121
+ rescue
122
+ Chef::Log.debug("Received nil message from stomp, retrying")
123
+ retry
124
+ end
125
+ msg = JSON.parse(raw_msg.body)
126
+ return msg, raw_msg.headers
127
+ end
128
+
129
+ def poll_msg
130
+ connect if @client == nil
131
+ raw_msg = @client.poll()
132
+ if raw_msg
133
+ msg = JSON.parse(raw_msg.body)
134
+ else
135
+ nil
136
+ end
137
+ end
138
+
139
+ def disconnect
140
+ raise ArgumentError, "You must call connect before you can disconnect!" unless @client
141
+ @client.disconnect
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,210 @@
1
+ #
2
+ # Author:: Adam Jacob (<adam@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
+
19
+ require 'chef/resource'
20
+ Dir[File.join(File.dirname(__FILE__), 'resource/**/*.rb')].sort.each { |lib| require lib }
21
+ require 'chef/mixin/from_file'
22
+ require 'chef/mixin/language'
23
+ require 'chef/resource_collection'
24
+ require 'chef/cookbook_loader'
25
+ require 'chef/rest'
26
+ require 'chef/search/result'
27
+
28
+ class Chef
29
+ class Recipe
30
+
31
+ include Chef::Mixin::FromFile
32
+ include Chef::Mixin::Language
33
+
34
+ attr_accessor :cookbook_name, :recipe_name, :recipe, :node, :collection,
35
+ :definitions, :params, :cookbook_loader
36
+
37
+ def initialize(cookbook_name, recipe_name, node, collection=nil, definitions=nil, cookbook_loader=nil)
38
+ @cookbook_name = cookbook_name
39
+ @recipe_name = recipe_name
40
+ @node = node
41
+
42
+ if collection
43
+ @collection = collection
44
+ else
45
+ @collection = Chef::ResourceCollection.new()
46
+ end
47
+
48
+ if definitions
49
+ @definitions = definitions
50
+ else
51
+ @definitions = Hash.new
52
+ end
53
+
54
+ if cookbook_loader
55
+ @cookbook_loader = cookbook_loader
56
+ else
57
+ @cookbook_loader = Chef::CookbookLoader.new()
58
+ end
59
+
60
+ @params = Hash.new
61
+ end
62
+
63
+ def include_recipe(*args)
64
+ args.flatten.each do |recipe|
65
+ if @node.run_state[:seen_recipes].has_key?(recipe)
66
+ Chef::Log.debug("I am not loading #{recipe}, because I have already seen it.")
67
+ next
68
+ end
69
+
70
+ Chef::Log.debug("Loading Recipe #{recipe} via include_recipe")
71
+ @node.run_state[:seen_recipes][recipe] = true
72
+
73
+ rmatch = recipe.match(/(.+?)::(.+)/)
74
+ if rmatch
75
+ cookbook = @cookbook_loader[rmatch[1]]
76
+ cookbook.load_recipe(rmatch[2], @node, @collection, @definitions, @cookbook_loader)
77
+ else
78
+ cookbook = @cookbook_loader[recipe]
79
+ cookbook.load_recipe("default", @node, @collection, @definitions, @cookbook_loader)
80
+ end
81
+ end
82
+ end
83
+
84
+ def require_recipe(*args)
85
+ include_recipe(*args)
86
+ end
87
+
88
+ def resources(*args)
89
+ @collection.resources(*args)
90
+ end
91
+
92
+ def search(type, query, attributes=[], &block)
93
+ Chef::Log.debug("Searching #{type} index with #{query}")
94
+ r = Chef::REST.new(Chef::Config[:search_url])
95
+
96
+ results = r.get_rest("search/#{type}?q=#{query}&a=#{attributes.join(',')}")
97
+ Chef::Log.debug("Searching #{type} index with #{query} returned #{results.length} entries")
98
+ if block
99
+ results.each do |sr|
100
+ block.call(sr)
101
+ end
102
+ else
103
+ results
104
+ end
105
+ end
106
+
107
+ # Sets a tag, or list of tags, for this node. Syntactic sugar for
108
+ # @node[:tags].
109
+ #
110
+ # With no arguments, returns the list of tags.
111
+ #
112
+ # === Parameters
113
+ # tags<Array>:: A list of tags to add - can be a single string
114
+ #
115
+ # === Returns
116
+ # tags<Array>:: The contents of @node[:tags]
117
+ def tag(*args)
118
+ if args.length > 0
119
+ args.each do |tag|
120
+ @node[:tags] << tag unless @node[:tags].include?(tag)
121
+ end
122
+ @node[:tags]
123
+ else
124
+ @node[:tags]
125
+ end
126
+ end
127
+
128
+ # Returns true if the node is tagged with the supplied list of tags.
129
+ #
130
+ # === Parameters
131
+ # tags<Array>:: A list of tags
132
+ #
133
+ # === Returns
134
+ # true<TrueClass>:: If all the parameters are present
135
+ # false<FalseClass>:: If any of the parameters are missing
136
+ def tagged?(*args)
137
+ args.each do |tag|
138
+ return false unless @node[:tags].include?(tag)
139
+ end
140
+ true
141
+ end
142
+
143
+ # Removes the list of tags from the node.
144
+ #
145
+ # === Parameters
146
+ # tags<Array>:: A list of tags
147
+ #
148
+ # === Returns
149
+ # tags<Array>:: The current list of @node[:tags]
150
+ def untag(*args)
151
+ args.each do |tag|
152
+ @node[:tags].delete(tag)
153
+ end
154
+ end
155
+
156
+ def method_missing(method_symbol, *args, &block)
157
+ resource = nil
158
+ # If we have a definition that matches, we want to use that instead. This should
159
+ # let you do some really crazy over-riding of "native" types, if you really want
160
+ # to.
161
+ if @definitions.has_key?(method_symbol)
162
+ # This dupes the high level object, but we still need to dup the params
163
+ new_def = @definitions[method_symbol].dup
164
+ new_def.params = new_def.params.dup
165
+ new_def.node = @node
166
+ # This sets up the parameter overrides
167
+ new_def.instance_eval(&block) if block
168
+ new_recipe = Chef::Recipe.new(@cookbook_name, @recipe_name, @node, @collection, @definitions, @cookbook_loader)
169
+ new_recipe.params = new_def.params
170
+ new_recipe.params[:name] = args[0]
171
+ new_recipe.instance_eval(&new_def.recipe)
172
+ else
173
+ method_name = method_symbol.to_s
174
+ # Otherwise, we're rocking the regular resource call route.
175
+ rname = nil
176
+ regexp = %r{^(.+?)(_(.+))?$}
177
+
178
+ mn = method_name.match(regexp)
179
+ if mn
180
+ rname = "Chef::Resource::#{mn[1].capitalize}"
181
+
182
+ while mn && mn[3]
183
+ mn = mn[3].match(regexp)
184
+ rname << mn[1].capitalize if mn
185
+ end
186
+ end
187
+
188
+ begin
189
+ args << @collection
190
+ args << @node
191
+ resource = eval(rname).new(*args)
192
+ # If we have a resource like this one, we want to steal it's state
193
+ resource.load_prior_resource
194
+ resource.cookbook_name = @cookbook_name
195
+ resource.recipe_name = @recipe_name
196
+ resource.params = @params
197
+ resource.instance_eval(&block) if block
198
+ rescue Exception => e
199
+ if e.kind_of?(NameError) && e.to_s =~ /Chef::Resource/
200
+ raise NameError, "Cannot find #{rname} for #{method_name}\nOriginal: #{e.to_s}"
201
+ else
202
+ raise e
203
+ end
204
+ end
205
+ @collection << resource
206
+ resource
207
+ end
208
+ end
209
+ end
210
+ end