Class: Bolt::Plugin
- Inherits:
-
Object
- Object
- Bolt::Plugin
- Defined in:
- lib/bolt/plugin.rb,
lib/bolt/plugin/task.rb,
lib/bolt/plugin/module.rb,
lib/bolt/plugin/prompt.rb,
lib/bolt/plugin/env_var.rb,
lib/bolt/plugin/puppetdb.rb
Defined Under Namespace
Classes: EnvVar, Module, PluginContext, PluginError, Prompt, Puppetdb, Task
Constant Summary collapse
- KNOWN_HOOKS =
%i[ puppet_library resolve_reference secret_encrypt secret_decrypt secret_createkeys validate_resolve_reference ].freeze
- RUBY_PLUGINS =
%w[task prompt env_var].freeze
- BUILTIN_PLUGINS =
%w[task terraform pkcs7 prompt vault aws_inventory puppetdb azure_inventory yaml env_var gcloud_inventory].freeze
- DEFAULT_PLUGIN_HOOKS =
{ 'puppet_library' => { 'plugin' => 'puppet_agent', 'stop_service' => true } }.freeze
Instance Attribute Summary collapse
-
#pal ⇒ Object
readonly
Returns the value of attribute pal.
-
#plugin_context ⇒ Object
readonly
Returns the value of attribute plugin_context.
-
#plugin_hooks ⇒ Object
Returns the value of attribute plugin_hooks.
Class Method Summary collapse
Instance Method Summary collapse
- #add_module_plugin(plugin_name) ⇒ Object
-
#add_plugin(plugin) ⇒ Object
Generally this is private.
- #add_ruby_plugin(plugin_name) ⇒ Object
-
#by_name(plugin_name) ⇒ Object
Calling by_name or get_hook will load any module based plugin automatically.
- #config_for_plugin(plugin_name) ⇒ Object
- #get_hook(plugin_name, hook) ⇒ Object
-
#initialize(config, pal, analytics) ⇒ Plugin
constructor
A new instance of Plugin.
- #modules ⇒ Object
-
#reference?(input) ⇒ Boolean
Checks whether a given value is a _plugin reference.
-
#resolve_references(data) ⇒ Object
Evaluate all _plugin references in a data structure.
-
#resolve_top_level_references(data) ⇒ Object
Iteratively resolves “top-level” references until the result no longer has top-level references.
Constructor Details
#initialize(config, pal, analytics) ⇒ Plugin
Returns a new instance of Plugin.
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/bolt/plugin.rb', line 155 def initialize(config, pal, analytics) @config = config @analytics = analytics @plugin_context = PluginContext.new(config, pal, self) @plugins = {} @pal = pal @unknown = Set.new @resolution_stack = [] @unresolved_plugin_configs = config.plugins.dup @plugin_hooks = DEFAULT_PLUGIN_HOOKS.dup end |
Instance Attribute Details
#pal ⇒ Object (readonly)
Returns the value of attribute pal.
150 151 152 |
# File 'lib/bolt/plugin.rb', line 150 def pal @pal end |
#plugin_context ⇒ Object (readonly)
Returns the value of attribute plugin_context.
150 151 152 |
# File 'lib/bolt/plugin.rb', line 150 def plugin_context @plugin_context end |
#plugin_hooks ⇒ Object
Returns the value of attribute plugin_hooks.
151 152 153 |
# File 'lib/bolt/plugin.rb', line 151 def plugin_hooks @plugin_hooks end |
Class Method Details
.setup(config, pal, pdb_client, analytics) ⇒ Object
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/bolt/plugin.rb', line 122 def self.setup(config, pal, pdb_client, analytics) plugins = new(config, pal, analytics) # PDB is special because it needs the PDB client. Since it has no config, # we can just add it first. plugins.add_plugin(Bolt::Plugin::Puppetdb.new(pdb_client)) # Initialize any plugins referenced in plugin config. This will also indirectly # initialize any plugins they depend on. if plugins.reference?(config.plugins) msg = "The 'plugins' setting cannot be set by a plugin reference" raise PluginError.new(msg, 'bolt/plugin-error') end config.plugins.each_key do |plugin| plugins.by_name(plugin) end plugins.plugin_hooks.merge!(plugins.resolve_references(config.plugin_hooks)) plugins end |
Instance Method Details
#add_module_plugin(plugin_name) ⇒ Object
190 191 192 193 194 195 196 197 198 |
# File 'lib/bolt/plugin.rb', line 190 def add_module_plugin(plugin_name) opts = { context: @plugin_context, config: config_for_plugin(plugin_name) } plugin = Bolt::Plugin::Module.load(plugin_name, modules, opts) add_plugin(plugin) end |
#add_plugin(plugin) ⇒ Object
Generally this is private. Puppetdb is special though
172 173 174 |
# File 'lib/bolt/plugin.rb', line 172 def add_plugin(plugin) @plugins[plugin.name] = plugin end |
#add_ruby_plugin(plugin_name) ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/bolt/plugin.rb', line 176 def add_ruby_plugin(plugin_name) cls_name = Bolt::Util.snake_name_to_class_name(plugin_name) filename = "bolt/plugin/#{plugin_name}" require filename cls = Kernel.const_get("Bolt::Plugin::#{cls_name}") opts = { context: @plugin_context, config: config_for_plugin(plugin_name) } plugin = cls.new(**opts) add_plugin(plugin) end |
#by_name(plugin_name) ⇒ Object
Calling by_name or get_hook will load any module based plugin automatically
224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/bolt/plugin.rb', line 224 def by_name(plugin_name) return @plugins[plugin_name] if @plugins.include?(plugin_name) begin if RUBY_PLUGINS.include?(plugin_name) add_ruby_plugin(plugin_name) elsif !@unknown.include?(plugin_name) add_module_plugin(plugin_name) end rescue PluginError::Unknown @unknown << plugin_name nil end end |
#config_for_plugin(plugin_name) ⇒ Object
200 201 202 203 204 205 206 207 208 209 210 211 212 |
# File 'lib/bolt/plugin.rb', line 200 def config_for_plugin(plugin_name) return {} unless @unresolved_plugin_configs.include?(plugin_name) if @resolution_stack.include?(plugin_name) msg = "Configuration for plugin '#{plugin_name}' depends on the plugin itself" raise PluginError.new(msg, 'bolt/plugin-error') else @resolution_stack.push(plugin_name) config = resolve_references(@unresolved_plugin_configs[plugin_name]) @unresolved_plugin_configs.delete(plugin_name) @resolution_stack.pop config end end |
#get_hook(plugin_name, hook) ⇒ Object
214 215 216 217 218 219 220 221 |
# File 'lib/bolt/plugin.rb', line 214 def get_hook(plugin_name, hook) plugin = by_name(plugin_name) raise PluginError::Unknown, plugin_name unless plugin raise PluginError::UnsupportedHook.new(plugin_name, hook) unless plugin.hooks.include?(hook) @analytics.report_bundled_content("Plugin #{hook}", plugin_name) plugin.method(hook) end |
#modules ⇒ Object
167 168 169 |
# File 'lib/bolt/plugin.rb', line 167 def modules @modules ||= Bolt::Module.discover(@pal.modulepath) end |
#reference?(input) ⇒ Boolean
Checks whether a given value is a _plugin reference
303 304 305 |
# File 'lib/bolt/plugin.rb', line 303 def reference?(input) input.is_a?(Hash) && input.key?('_plugin') end |
#resolve_references(data) ⇒ Object
Evaluate all _plugin references in a data structure. Leaves are evaluated and then their parents are evaluated with references replaced by their values. If the result of a reference contains more references, they are resolved again before continuing to ascend the tree. The final result will not contain any references.
243 244 245 246 247 248 249 250 |
# File 'lib/bolt/plugin.rb', line 243 def resolve_references(data) Bolt::Util.postwalk_vals(data) do |value| reference?(value) ? resolve_references(resolve_single_reference(value)) : value end rescue SystemStackError raise Bolt::Error.new("Stack depth exceeded while recursively resolving references.", "bolt/recursive-reference-loop") end |
#resolve_top_level_references(data) ⇒ Object
Iteratively resolves “top-level” references until the result no longer has top-level references. A top-level reference is one which is not contained within another hash. It may be either the actual top-level result or arbitrarily nested within arrays. If parameters of the reference are themselves references, they will be looked. Any remaining references nested inside the result will not be evaluated once the top-level result is not a reference. This is used to resolve the ‘targets` and `groups` keys which are allowed to be references or arrays of references, but which may return data with nested references that should be resolved lazily. The end result will either be a single hash or a flat array of hashes.
263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/bolt/plugin.rb', line 263 def resolve_top_level_references(data) if data.is_a?(Array) data.flat_map { |elem| resolve_top_level_references(elem) } elsif reference?(data) partially_resolved = data.transform_values do |v| resolve_references(v) end fully_resolved = resolve_single_reference(partially_resolved) # The top-level reference may have returned more references, so repeat the process resolve_top_level_references(fully_resolved) else data end end |