cheffish 1.4.1 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +201 -201
  3. data/README.md +120 -120
  4. data/Rakefile +23 -23
  5. data/lib/chef/provider/chef_acl.rb +439 -439
  6. data/lib/chef/provider/chef_client.rb +53 -53
  7. data/lib/chef/provider/chef_container.rb +55 -55
  8. data/lib/chef/provider/chef_data_bag.rb +55 -55
  9. data/lib/chef/provider/chef_data_bag_item.rb +278 -278
  10. data/lib/chef/provider/chef_environment.rb +83 -83
  11. data/lib/chef/provider/chef_group.rb +83 -83
  12. data/lib/chef/provider/chef_mirror.rb +169 -169
  13. data/lib/chef/provider/chef_node.rb +87 -87
  14. data/lib/chef/provider/chef_organization.rb +155 -155
  15. data/lib/chef/provider/chef_resolved_cookbooks.rb +46 -46
  16. data/lib/chef/provider/chef_role.rb +84 -84
  17. data/lib/chef/provider/chef_user.rb +59 -59
  18. data/lib/chef/provider/private_key.rb +225 -225
  19. data/lib/chef/provider/public_key.rb +88 -88
  20. data/lib/chef/resource/chef_acl.rb +69 -69
  21. data/lib/chef/resource/chef_client.rb +48 -48
  22. data/lib/chef/resource/chef_container.rb +22 -22
  23. data/lib/chef/resource/chef_data_bag.rb +22 -22
  24. data/lib/chef/resource/chef_data_bag_item.rb +121 -121
  25. data/lib/chef/resource/chef_environment.rb +77 -77
  26. data/lib/chef/resource/chef_group.rb +53 -53
  27. data/lib/chef/resource/chef_mirror.rb +52 -52
  28. data/lib/chef/resource/chef_node.rb +22 -22
  29. data/lib/chef/resource/chef_organization.rb +69 -69
  30. data/lib/chef/resource/chef_resolved_cookbooks.rb +35 -35
  31. data/lib/chef/resource/chef_role.rb +110 -110
  32. data/lib/chef/resource/chef_user.rb +56 -56
  33. data/lib/chef/resource/private_key.rb +48 -48
  34. data/lib/chef/resource/public_key.rb +25 -25
  35. data/lib/cheffish/actor_provider_base.rb +131 -131
  36. data/lib/cheffish/basic_chef_client.rb +184 -184
  37. data/lib/cheffish/chef_provider_base.rb +246 -246
  38. data/lib/cheffish/chef_run.rb +162 -162
  39. data/lib/cheffish/chef_run_data.rb +19 -19
  40. data/lib/cheffish/chef_run_listener.rb +30 -30
  41. data/lib/cheffish/key_formatter.rb +113 -113
  42. data/lib/cheffish/merged_config.rb +94 -94
  43. data/lib/cheffish/recipe_dsl.rb +157 -157
  44. data/lib/cheffish/rspec/chef_run_support.rb +83 -83
  45. data/lib/cheffish/rspec/matchers/be_idempotent.rb +16 -16
  46. data/lib/cheffish/rspec/matchers/emit_no_warnings_or_errors.rb +15 -15
  47. data/lib/cheffish/rspec/matchers/have_updated.rb +37 -37
  48. data/lib/cheffish/rspec/matchers/partially_match.rb +63 -63
  49. data/lib/cheffish/rspec/matchers.rb +4 -4
  50. data/lib/cheffish/rspec/recipe_run_wrapper.rb +78 -59
  51. data/lib/cheffish/rspec/repository_support.rb +108 -108
  52. data/lib/cheffish/rspec.rb +8 -8
  53. data/lib/cheffish/server_api.rb +52 -52
  54. data/lib/cheffish/version.rb +3 -3
  55. data/lib/cheffish/with_pattern.rb +21 -21
  56. data/lib/cheffish.rb +235 -235
  57. data/spec/functional/fingerprint_spec.rb +64 -64
  58. data/spec/functional/merged_config_spec.rb +19 -19
  59. data/spec/functional/server_api_spec.rb +13 -13
  60. data/spec/integration/chef_acl_spec.rb +879 -879
  61. data/spec/integration/chef_client_spec.rb +105 -105
  62. data/spec/integration/chef_container_spec.rb +33 -33
  63. data/spec/integration/chef_group_spec.rb +309 -309
  64. data/spec/integration/chef_mirror_spec.rb +491 -491
  65. data/spec/integration/chef_node_spec.rb +786 -786
  66. data/spec/integration/chef_organization_spec.rb +226 -226
  67. data/spec/integration/chef_role_spec.rb +78 -78
  68. data/spec/integration/chef_user_spec.rb +85 -85
  69. data/spec/integration/private_key_spec.rb +399 -399
  70. data/spec/integration/recipe_dsl_spec.rb +28 -28
  71. data/spec/integration/rspec/converge_spec.rb +183 -183
  72. data/spec/support/key_support.rb +29 -29
  73. data/spec/support/spec_support.rb +15 -15
  74. data/spec/unit/get_private_key_spec.rb +131 -131
  75. data/spec/unit/recipe_run_wrapper_spec.rb +37 -37
  76. metadata +3 -2
@@ -1,131 +1,131 @@
1
- require 'cheffish/key_formatter'
2
- require 'cheffish/chef_provider_base'
3
-
4
- class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
5
-
6
- def create_actor
7
- if new_resource.before
8
- new_resource.before.call(new_resource)
9
- end
10
-
11
- # Create or update the client/user
12
- current_public_key = new_json['public_key']
13
- differences = json_differences(current_json, new_json)
14
- if current_resource_exists?
15
- # Update the actor if it's different
16
- if differences.size > 0
17
- description = [ "update #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
18
- converge_by description do
19
- result = rest.put("#{actor_path}/#{new_resource.name}", normalize_for_put(new_json))
20
- current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
21
- end
22
- end
23
- else
24
- # Create the actor if it's missing
25
- if !new_public_key
26
- raise "You must specify a public key to create a #{actor_type}! Use the private_key resource to create a key, and pass it in with source_key_path."
27
- end
28
- description = [ "create #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
29
- converge_by description do
30
- result = rest.post("#{actor_path}", normalize_for_post(new_json))
31
- current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
32
- end
33
- end
34
-
35
- # Write out the public key
36
- if new_resource.output_key_path
37
- # TODO use inline_resource
38
- key_content = Cheffish::KeyFormatter.encode(current_public_key, { :format => new_resource.output_key_format })
39
- if !current_resource.output_key_path
40
- action = 'create'
41
- elsif key_content != IO.read(current_resource.output_key_path)
42
- action = 'overwrite'
43
- else
44
- action = nil
45
- end
46
- if action
47
- converge_by "#{action} public key #{new_resource.output_key_path}" do
48
- IO.write(new_resource.output_key_path, key_content)
49
- end
50
- end
51
- # TODO permissions?
52
- end
53
-
54
- if new_resource.after
55
- new_resource.after.call(self, new_json, server_private_key, server_public_key)
56
- end
57
- end
58
-
59
- def delete_actor
60
- if current_resource_exists?
61
- converge_by "delete #{actor_type} #{new_resource.name} at #{actor_path}" do
62
- rest.delete("#{actor_path}/#{new_resource.name}")
63
- Chef::Log.info("#{new_resource} deleted #{actor_type} #{new_resource.name} at #{rest.url}")
64
- end
65
- end
66
- if current_resource.output_key_path
67
- converge_by "delete public key #{current_resource.output_key_path}" do
68
- ::File.unlink(current_resource.output_key_path)
69
- end
70
- end
71
- end
72
-
73
- def new_public_key
74
- @new_public_key ||= begin
75
- if new_resource.source_key
76
- if new_resource.source_key.is_a?(String)
77
- key, key_format = Cheffish::KeyFormatter.decode(new_resource.source_key)
78
-
79
- if key.private?
80
- key.public_key
81
- else
82
- key
83
- end
84
- elsif new_resource.source_key.private?
85
- new_resource.source_key.public_key
86
- else
87
- new_resource.source_key
88
- end
89
- elsif new_resource.source_key_path
90
- source_key_path = new_resource.source_key_path
91
- if Pathname.new(source_key_path).relative?
92
- source_key_str, source_key_path = Cheffish.get_private_key_with_path(source_key_path, run_context.config)
93
- else
94
- source_key_str = IO.read(source_key_path)
95
- end
96
- source_key, source_key_format = Cheffish::KeyFormatter.decode(source_key_str, new_resource.source_key_pass_phrase, source_key_path)
97
- if source_key.private?
98
- source_key.public_key
99
- else
100
- source_key
101
- end
102
- else
103
- nil
104
- end
105
- end
106
- end
107
-
108
- def augment_new_json(json)
109
- if new_public_key
110
- json['public_key'] = new_public_key.to_pem
111
- end
112
- json
113
- end
114
-
115
- def load_current_resource
116
- begin
117
- json = rest.get("#{actor_path}/#{new_resource.name}")
118
- @current_resource = json_to_resource(json)
119
- rescue Net::HTTPServerException => e
120
- if e.response.code == "404"
121
- @current_resource = not_found_resource
122
- else
123
- raise
124
- end
125
- end
126
-
127
- if new_resource.output_key_path && ::File.exist?(new_resource.output_key_path)
128
- current_resource.output_key_path = new_resource.output_key_path
129
- end
130
- end
131
- end
1
+ require 'cheffish/key_formatter'
2
+ require 'cheffish/chef_provider_base'
3
+
4
+ class Cheffish::ActorProviderBase < Cheffish::ChefProviderBase
5
+
6
+ def create_actor
7
+ if new_resource.before
8
+ new_resource.before.call(new_resource)
9
+ end
10
+
11
+ # Create or update the client/user
12
+ current_public_key = new_json['public_key']
13
+ differences = json_differences(current_json, new_json)
14
+ if current_resource_exists?
15
+ # Update the actor if it's different
16
+ if differences.size > 0
17
+ description = [ "update #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
18
+ converge_by description do
19
+ result = rest.put("#{actor_path}/#{new_resource.name}", normalize_for_put(new_json))
20
+ current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
21
+ end
22
+ end
23
+ else
24
+ # Create the actor if it's missing
25
+ if !new_public_key
26
+ raise "You must specify a public key to create a #{actor_type}! Use the private_key resource to create a key, and pass it in with source_key_path."
27
+ end
28
+ description = [ "create #{actor_type} #{new_resource.name} at #{actor_path}" ] + differences
29
+ converge_by description do
30
+ result = rest.post("#{actor_path}", normalize_for_post(new_json))
31
+ current_public_key, current_public_key_format = Cheffish::KeyFormatter.decode(result['public_key']) if result['public_key']
32
+ end
33
+ end
34
+
35
+ # Write out the public key
36
+ if new_resource.output_key_path
37
+ # TODO use inline_resource
38
+ key_content = Cheffish::KeyFormatter.encode(current_public_key, { :format => new_resource.output_key_format })
39
+ if !current_resource.output_key_path
40
+ action = 'create'
41
+ elsif key_content != IO.read(current_resource.output_key_path)
42
+ action = 'overwrite'
43
+ else
44
+ action = nil
45
+ end
46
+ if action
47
+ converge_by "#{action} public key #{new_resource.output_key_path}" do
48
+ IO.write(new_resource.output_key_path, key_content)
49
+ end
50
+ end
51
+ # TODO permissions?
52
+ end
53
+
54
+ if new_resource.after
55
+ new_resource.after.call(self, new_json, server_private_key, server_public_key)
56
+ end
57
+ end
58
+
59
+ def delete_actor
60
+ if current_resource_exists?
61
+ converge_by "delete #{actor_type} #{new_resource.name} at #{actor_path}" do
62
+ rest.delete("#{actor_path}/#{new_resource.name}")
63
+ Chef::Log.info("#{new_resource} deleted #{actor_type} #{new_resource.name} at #{rest.url}")
64
+ end
65
+ end
66
+ if current_resource.output_key_path
67
+ converge_by "delete public key #{current_resource.output_key_path}" do
68
+ ::File.unlink(current_resource.output_key_path)
69
+ end
70
+ end
71
+ end
72
+
73
+ def new_public_key
74
+ @new_public_key ||= begin
75
+ if new_resource.source_key
76
+ if new_resource.source_key.is_a?(String)
77
+ key, key_format = Cheffish::KeyFormatter.decode(new_resource.source_key)
78
+
79
+ if key.private?
80
+ key.public_key
81
+ else
82
+ key
83
+ end
84
+ elsif new_resource.source_key.private?
85
+ new_resource.source_key.public_key
86
+ else
87
+ new_resource.source_key
88
+ end
89
+ elsif new_resource.source_key_path
90
+ source_key_path = new_resource.source_key_path
91
+ if Pathname.new(source_key_path).relative?
92
+ source_key_str, source_key_path = Cheffish.get_private_key_with_path(source_key_path, run_context.config)
93
+ else
94
+ source_key_str = IO.read(source_key_path)
95
+ end
96
+ source_key, source_key_format = Cheffish::KeyFormatter.decode(source_key_str, new_resource.source_key_pass_phrase, source_key_path)
97
+ if source_key.private?
98
+ source_key.public_key
99
+ else
100
+ source_key
101
+ end
102
+ else
103
+ nil
104
+ end
105
+ end
106
+ end
107
+
108
+ def augment_new_json(json)
109
+ if new_public_key
110
+ json['public_key'] = new_public_key.to_pem
111
+ end
112
+ json
113
+ end
114
+
115
+ def load_current_resource
116
+ begin
117
+ json = rest.get("#{actor_path}/#{new_resource.name}")
118
+ @current_resource = json_to_resource(json)
119
+ rescue Net::HTTPServerException => e
120
+ if e.response.code == "404"
121
+ @current_resource = not_found_resource
122
+ else
123
+ raise
124
+ end
125
+ end
126
+
127
+ if new_resource.output_key_path && ::File.exist?(new_resource.output_key_path)
128
+ current_resource.output_key_path = new_resource.output_key_path
129
+ end
130
+ end
131
+ end
@@ -1,184 +1,184 @@
1
- require 'cheffish/version'
2
- require 'chef/dsl/recipe'
3
- require 'chef/event_dispatch/base'
4
- require 'chef/event_dispatch/dispatcher'
5
- require 'chef/node'
6
- require 'chef/run_context'
7
- require 'chef/runner'
8
- require 'forwardable'
9
- require 'chef/providers'
10
- require 'chef/resources'
11
-
12
- module Cheffish
13
- class BasicChefClient
14
- include Chef::DSL::Recipe
15
-
16
- def initialize(node = nil, events = nil, **chef_config)
17
- if !node
18
- node = Chef::Node.new
19
- node.name 'basic_chef_client'
20
- node.automatic[:platform] = 'basic_chef_client'
21
- node.automatic[:platform_version] = Cheffish::VERSION
22
- end
23
-
24
- # Decide on the config we want for this chef client
25
- @chef_config = chef_config
26
-
27
- with_chef_config do
28
- @cookbook_name = 'basic_chef_client'
29
- @event_catcher = BasicChefClientEvents.new
30
- dispatcher = Chef::EventDispatch::Dispatcher.new(@event_catcher)
31
- case events
32
- when nil
33
- when Array
34
- events.each { |e| dispatcher.register(e) } if events
35
- else
36
- dispatcher.register(events)
37
- end
38
- @run_context = Chef::RunContext.new(node, {}, dispatcher)
39
- @updated = []
40
- @cookbook_name = 'basic_chef_client'
41
- end
42
- end
43
-
44
- extend Forwardable
45
-
46
- # Stuff recipes need
47
- attr_reader :chef_config
48
- attr_reader :run_context
49
- attr_accessor :cookbook_name
50
- attr_accessor :recipe_name
51
- def_delegators :@run_context, :resource_collection, :immediate_notifications, :delayed_notifications
52
-
53
- def add_resource(resource)
54
- with_chef_config do
55
- resource.run_context = run_context
56
- run_context.resource_collection.insert(resource)
57
- end
58
- end
59
-
60
- def load_block(&block)
61
- with_chef_config do
62
- @recipe_name = 'block'
63
- instance_eval(&block)
64
- end
65
- end
66
-
67
- def converge
68
- with_chef_config do
69
- Chef::Runner.new(self).converge
70
- end
71
- end
72
-
73
- def updates
74
- @event_catcher.updates
75
- end
76
-
77
- def updated?
78
- @event_catcher.updates.size > 0
79
- end
80
-
81
- # Builds a resource sans context, which can be later used in a new client's
82
- # add_resource() method.
83
- def self.build_resource(type, name, created_at=nil, &resource_attrs_block)
84
- created_at ||= caller[0]
85
- result = BasicChefClient.new.tap do |client|
86
- client.with_chef_config do
87
- client.build_resource(type, name, created_at, &resource_attrs_block)
88
- end
89
- end
90
- result
91
- end
92
-
93
- def self.inline_resource(provider, provider_action, *resources, &block)
94
- events = ProviderEventForwarder.new(provider, provider_action)
95
- client = BasicChefClient.new(provider.node, events)
96
- client.with_chef_config do
97
- resources.each do |resource|
98
- client.add_resource(resource)
99
- end
100
- end
101
- client.load_block(&block) if block
102
- client.converge
103
- client.updated?
104
- end
105
-
106
- def self.converge_block(node = nil, events = nil, &block)
107
- client = BasicChefClient.new(node, events)
108
- client.load_block(&block)
109
- client.converge
110
- client.updated?
111
- end
112
-
113
- def with_chef_config(&block)
114
- old_chef_config = Chef::Config.save
115
- if chef_config[:log_location]
116
- old_loggers = Chef::Log.loggers
117
- Chef::Log.init(chef_config[:log_location])
118
- end
119
- if chef_config[:log_level]
120
- old_level = Chef::Log.level
121
- Chef::Log.level(chef_config[:log_level])
122
- end
123
- # if chef_config[:stdout]
124
- # old_stdout = $stdout
125
- # $stdout = chef_config[:stdout]
126
- # end
127
- # if chef_config[:stderr]
128
- # old_stderr = $stderr
129
- # $stderr = chef_config[:stderr]
130
- # end
131
- begin
132
- deep_merge_config(chef_config, Chef::Config)
133
- block.call
134
- ensure
135
- # $stdout = old_stdout if chef_config[:stdout]
136
- # $stderr = old_stderr if chef_config[:stderr]
137
- if old_loggers
138
- Chef::Log.logger = old_loggers.shift
139
- old_loggers.each { |l| Chef::Log.loggers.push(l) }
140
- elsif chef_config[:log_level]
141
- Chef::Log.level = old_level
142
- end
143
- Chef::Config.restore(old_chef_config)
144
- end
145
- end
146
-
147
- def deep_merge_config(src, dest)
148
- src.each do |name, value|
149
- if value.is_a?(Hash) && dest[name].is_a?(Hash)
150
- deep_merge_config(value, dest[name])
151
- else
152
- dest[name] = value
153
- end
154
- end
155
- end
156
-
157
- class BasicChefClientEvents < Chef::EventDispatch::Base
158
- def initialize
159
- @updates = []
160
- end
161
-
162
- attr_reader :updates
163
-
164
- # Called after a resource has been completely converged.
165
- def resource_updated(resource, action)
166
- updates << [ resource, action ]
167
- end
168
- end
169
-
170
- class ProviderEventForwarder < Chef::EventDispatch::Base
171
- def initialize(provider, provider_action)
172
- @provider = provider
173
- @provider_action = provider_action
174
- end
175
-
176
- attr_reader :provider
177
- attr_reader :provider_action
178
-
179
- def resource_update_applied(resource, action, update)
180
- provider.run_context.events.resource_update_applied(provider.new_resource, provider_action, update)
181
- end
182
- end
183
- end
184
- end
1
+ require 'cheffish/version'
2
+ require 'chef/dsl/recipe'
3
+ require 'chef/event_dispatch/base'
4
+ require 'chef/event_dispatch/dispatcher'
5
+ require 'chef/node'
6
+ require 'chef/run_context'
7
+ require 'chef/runner'
8
+ require 'forwardable'
9
+ require 'chef/providers'
10
+ require 'chef/resources'
11
+
12
+ module Cheffish
13
+ class BasicChefClient
14
+ include Chef::DSL::Recipe
15
+
16
+ def initialize(node = nil, events = nil, **chef_config)
17
+ if !node
18
+ node = Chef::Node.new
19
+ node.name 'basic_chef_client'
20
+ node.automatic[:platform] = 'basic_chef_client'
21
+ node.automatic[:platform_version] = Cheffish::VERSION
22
+ end
23
+
24
+ # Decide on the config we want for this chef client
25
+ @chef_config = chef_config
26
+
27
+ with_chef_config do
28
+ @cookbook_name = 'basic_chef_client'
29
+ @event_catcher = BasicChefClientEvents.new
30
+ dispatcher = Chef::EventDispatch::Dispatcher.new(@event_catcher)
31
+ case events
32
+ when nil
33
+ when Array
34
+ events.each { |e| dispatcher.register(e) } if events
35
+ else
36
+ dispatcher.register(events)
37
+ end
38
+ @run_context = Chef::RunContext.new(node, {}, dispatcher)
39
+ @updated = []
40
+ @cookbook_name = 'basic_chef_client'
41
+ end
42
+ end
43
+
44
+ extend Forwardable
45
+
46
+ # Stuff recipes need
47
+ attr_reader :chef_config
48
+ attr_reader :run_context
49
+ attr_accessor :cookbook_name
50
+ attr_accessor :recipe_name
51
+ def_delegators :@run_context, :resource_collection, :immediate_notifications, :delayed_notifications
52
+
53
+ def add_resource(resource)
54
+ with_chef_config do
55
+ resource.run_context = run_context
56
+ run_context.resource_collection.insert(resource)
57
+ end
58
+ end
59
+
60
+ def load_block(&block)
61
+ with_chef_config do
62
+ @recipe_name = 'block'
63
+ instance_eval(&block)
64
+ end
65
+ end
66
+
67
+ def converge
68
+ with_chef_config do
69
+ Chef::Runner.new(self).converge
70
+ end
71
+ end
72
+
73
+ def updates
74
+ @event_catcher.updates
75
+ end
76
+
77
+ def updated?
78
+ @event_catcher.updates.size > 0
79
+ end
80
+
81
+ # Builds a resource sans context, which can be later used in a new client's
82
+ # add_resource() method.
83
+ def self.build_resource(type, name, created_at=nil, &resource_attrs_block)
84
+ created_at ||= caller[0]
85
+ result = BasicChefClient.new.tap do |client|
86
+ client.with_chef_config do
87
+ client.build_resource(type, name, created_at, &resource_attrs_block)
88
+ end
89
+ end
90
+ result
91
+ end
92
+
93
+ def self.inline_resource(provider, provider_action, *resources, &block)
94
+ events = ProviderEventForwarder.new(provider, provider_action)
95
+ client = BasicChefClient.new(provider.node, events)
96
+ client.with_chef_config do
97
+ resources.each do |resource|
98
+ client.add_resource(resource)
99
+ end
100
+ end
101
+ client.load_block(&block) if block
102
+ client.converge
103
+ client.updated?
104
+ end
105
+
106
+ def self.converge_block(node = nil, events = nil, &block)
107
+ client = BasicChefClient.new(node, events)
108
+ client.load_block(&block)
109
+ client.converge
110
+ client.updated?
111
+ end
112
+
113
+ def with_chef_config(&block)
114
+ old_chef_config = Chef::Config.save
115
+ if chef_config[:log_location]
116
+ old_loggers = Chef::Log.loggers
117
+ Chef::Log.init(chef_config[:log_location])
118
+ end
119
+ if chef_config[:log_level]
120
+ old_level = Chef::Log.level
121
+ Chef::Log.level(chef_config[:log_level])
122
+ end
123
+ # if chef_config[:stdout]
124
+ # old_stdout = $stdout
125
+ # $stdout = chef_config[:stdout]
126
+ # end
127
+ # if chef_config[:stderr]
128
+ # old_stderr = $stderr
129
+ # $stderr = chef_config[:stderr]
130
+ # end
131
+ begin
132
+ deep_merge_config(chef_config, Chef::Config)
133
+ block.call
134
+ ensure
135
+ # $stdout = old_stdout if chef_config[:stdout]
136
+ # $stderr = old_stderr if chef_config[:stderr]
137
+ if old_loggers
138
+ Chef::Log.logger = old_loggers.shift
139
+ old_loggers.each { |l| Chef::Log.loggers.push(l) }
140
+ elsif chef_config[:log_level]
141
+ Chef::Log.level = old_level
142
+ end
143
+ Chef::Config.restore(old_chef_config)
144
+ end
145
+ end
146
+
147
+ def deep_merge_config(src, dest)
148
+ src.each do |name, value|
149
+ if value.is_a?(Hash) && dest[name].is_a?(Hash)
150
+ deep_merge_config(value, dest[name])
151
+ else
152
+ dest[name] = value
153
+ end
154
+ end
155
+ end
156
+
157
+ class BasicChefClientEvents < Chef::EventDispatch::Base
158
+ def initialize
159
+ @updates = []
160
+ end
161
+
162
+ attr_reader :updates
163
+
164
+ # Called after a resource has been completely converged.
165
+ def resource_updated(resource, action)
166
+ updates << [ resource, action ]
167
+ end
168
+ end
169
+
170
+ class ProviderEventForwarder < Chef::EventDispatch::Base
171
+ def initialize(provider, provider_action)
172
+ @provider = provider
173
+ @provider_action = provider_action
174
+ end
175
+
176
+ attr_reader :provider
177
+ attr_reader :provider_action
178
+
179
+ def resource_update_applied(resource, action, update)
180
+ provider.run_context.events.resource_update_applied(provider.new_resource, provider_action, update)
181
+ end
182
+ end
183
+ end
184
+ end