1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
#
# Author:: Adam Jacob (<adam@opscode.com>)
# Author:: Christopher Walters (<cw@opscode.com>)
# Author:: Daniel DeLeo (<dan@opscode.com>)
# Copyright:: Copyright (c) 2008-2012 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'chef/provider'
class Chef
class Provider
# == Chef::Provider::LWRPBase
# Base class from which LWRP providers inherit.
class LWRPBase < Provider
# Chef::Provider::LWRPBase::InlineResources
# Implementation of inline resource convergence for LWRP providers. See
# Provider::LWRPBase.use_inline_resources for a longer explanation.
#
# This code is restricted to a module so that it can be selectively
# applied to providers on an opt-in basis.
module InlineResources
# Class methods for InlineResources. Overrides the `action` DSL method
# with one that enables inline resource convergence.
module ClassMethods
# Defines an action method on the provider, using
# recipe_eval_with_update_check to execute the given block.
def action(name, &block)
define_method("action_#{name}") do
recipe_eval_with_update_check(&block)
end
end
end
# Executes the given block in a temporary run_context with its own
# resource collection. After the block is executed, any resources
# declared inside are converged, and if any are updated, the
# new_resource will be marked updated.
def recipe_eval_with_update_check(&block)
saved_run_context = @run_context
temp_run_context = @run_context.dup
@run_context = temp_run_context
@run_context.resource_collection = Chef::ResourceCollection.new
return_value = instance_eval(&block)
Chef::Runner.new(@run_context).converge
return_value
ensure
@run_context = saved_run_context
if temp_run_context.resource_collection.any? {|r| r.updated? }
new_resource.updated_by_last_action(true)
end
end
end
include Chef::DSL::Recipe
# These were previously provided by Chef::Mixin::RecipeDefinitionDSLCore.
# They are not included by its replacment, Chef::DSL::Recipe, but
# they may be used in existing LWRPs.
include Chef::DSL::PlatformIntrospection
include Chef::DSL::DataQuery
# no-op `load_current_resource`. Allows simple LWRP providers to work
# without defining this method explicitly (silences
# Chef::Exceptions::Override exception)
def load_current_resource
end
# class methods
class <<self
include Chef::Mixin::ConvertToClassName
include Chef::Mixin::FromFile
def build_from_file(cookbook_name, filename, run_context)
if LWRPBase.loaded_lwrps[filename]
Chef::Log.info("LWRP provider #{filename} from cookbook #{cookbook_name} has already been loaded! Skipping the reload.")
return loaded_lwrps[filename]
end
resource_name = filename_to_qualified_string(cookbook_name, filename)
# We load the class first to give it a chance to set its own name
provider_class = Class.new(self)
provider_class.provides resource_name.to_sym
provider_class.class_from_file(filename)
# Respect resource_name set inside the LWRP
provider_class.instance_eval do
define_method(:to_s) do
"LWRP provider #{resource_name} from cookbook #{cookbook_name}"
end
define_method(:inspect) { to_s }
end
Chef::Log.debug("Loaded contents of #{filename} into provider #{resource_name} (#{provider_class})")
LWRPBase.loaded_lwrps[filename] = true
Chef::Provider.register_deprecated_lwrp_class(provider_class, convert_to_class_name(resource_name))
provider_class
end
# Enables inline evaluation of resources in provider actions.
#
# Without this option, any resources declared inside the LWRP are added
# to the resource collection after the current position at the time the
# action is executed. Because they are added to the primary resource
# collection for the chef run, they can notify other resources outside
# the LWRP, and potentially be notified by resources outside the LWRP
# (but this is complicated by the fact that they don't exist until the
# provider executes). In this mode, it is impossible to correctly set the
# updated_by_last_action flag on the parent LWRP resource, since it
# executes and returns before its component resources are run.
#
# With this option enabled, each action creates a temporary run_context
# with its own resource collection, evaluates the action's code in that
# context, and then converges the resources created. If any resources
# were updated, then this provider's new_resource will be marked updated.
#
# In this mode, resources created within the LWRP cannot interact with
# external resources via notifies, though notifications to other
# resources within the LWRP will work. Delayed notifications are executed
# at the conclusion of the provider's action, *not* at the end of the
# main chef run.
#
# This mode of evaluation is experimental, but is believed to be a better
# set of tradeoffs than the append-after mode, so it will likely become
# the default in a future major release of Chef.
#
def use_inline_resources
extend InlineResources::ClassMethods
include InlineResources
end
# DSL for defining a provider's actions.
def action(name, &block)
define_method("action_#{name}") do
instance_eval(&block)
end
end
protected
def loaded_lwrps
@loaded_lwrps ||= {}
end
end
end
end
end
|