Class: Bolt::Plugin::Module
  
  
  
  
  
    - Inherits:
- 
      Object
      
        
          - Object
- Bolt::Plugin::Module
 show all
    - Defined in:
- lib/bolt/plugin/module.rb
 
Defined Under Namespace
  
    
  
    
      Classes: InvalidPluginData
    
  
  Instance Attribute Summary collapse
  
  
    
      Class Method Summary
      collapse
    
    
  
    
      Instance Method Summary
      collapse
    
    
      
        - 
  
    
      #extract_task_parameter_schema  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #find_hooks(hook_data)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #hooks  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #initialize(mod:, context:, config:, **_opts)  ⇒ Module 
    
    
  
  
  
    constructor
  
  
  
  
  
  
  
    
A new instance of Module. 
 
- 
  
    
      #load_data  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #name  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #process_params(task, opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #process_schema(schema)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #puppet_library(opts, target, apply_prep)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #resolve_reference(opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
These are all the same but are defined explicitly for clarity. 
 
- 
  
    
      #run_hook(hook_name, opts, value = true)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #run_task(task, opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #secret_createkeys(opts = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #secret_decrypt(opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #secret_encrypt(opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #setup  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
This method interacts with the module on disk so it’s separate from initialize. 
 
- 
  
    
      #validate_config(config, config_schema)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #validate_params(task, params)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #validate_resolve_reference(opts)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
  Constructor Details
  
    
  
  
    #initialize(mod:, context:, config:, **_opts)  ⇒ Module 
  
  
  
  
    
Returns a new instance of Module.
   
 
  
  
    | 
29
30
31
32
33 | # File 'lib/bolt/plugin/module.rb', line 29
def initialize(mod:, context:, config:, **_opts)
  @module = mod
  @config = config
  @context = context
end | 
 
  
 
  
    Instance Attribute Details
    
      
      
      
  
  
    #config  ⇒ Object  
  
  
  
  
    
Returns the value of attribute config.
   
 
  
  
    | 
27
28
29 | # File 'lib/bolt/plugin/module.rb', line 27
def config
  @config
end | 
 
    
   
  
    Class Method Details
    
      
  
  
    .load(name, modules, opts)  ⇒ Object 
  
  
  
  
    | 
15
16
17
18
19
20
21
22
23
24
25 | # File 'lib/bolt/plugin/module.rb', line 15
def self.load(name, modules, opts)
  mod = modules[name]
  if mod&.plugin?
    opts[:mod] = mod
    plugin = Bolt::Plugin::Module.new(opts)
    plugin.setup
    plugin
  else
    raise PluginError::Unknown, name
  end
end | 
 
    
   
  
    Instance Method Details
    
      
  
  
    | 
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 | # File 'lib/bolt/plugin/module.rb', line 166
def 
    type_set = @hook_map.each_with_object({}) do |(_hook, task), acc|
    next unless (schema = task['task'].metadata['parameters'])
    schema.each do |param, scheme|
      next unless scheme['type'].is_a?(String)
      scheme['type'] = Set.new([scheme['type']])
      if acc.dig(param, 'type').is_a?(Set)
        scheme['type'].merge(acc[param]['type'])
      end
    end
    acc.merge!(schema)
  end
    type_set.each do |_param, schema|
    next unless schema['type']
    schema['type'] = if schema['type'].size > 1
                       "Optional[Variant[#{schema['type'].to_a.join(', ')}]]"
                     else
                       "Optional[#{schema['type'].to_a.first}]"
                     end
  end
end | 
 
    
      
  
  
    #find_hooks(hook_data)  ⇒ Object 
  
  
  
  
    | 
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 | # File 'lib/bolt/plugin/module.rb', line 110
def find_hooks(hook_data)
  raise InvalidPluginData.new("'hooks' must be a hash", name) unless hook_data.is_a?(Hash)
  hooks = {}
    hook_data.each do |hook_name, hook_spec|
    unless hook_spec.is_a?(Hash) && hook_spec['task'].is_a?(String)
      msg = "Unexpected hook specification #{hook_spec.to_json} in #{@name} for hook #{hook_name}"
      raise InvalidPluginData.new(msg, name)
    end
    begin
      task = @context.get_validated_task(hook_spec['task'])
    rescue Bolt::Error => e
      msg = if e.kind == 'bolt/unknown-task'
              "Plugin #{name} specified an unkown task '#{hook_spec['task']}' for a hook"
            else
              "Plugin #{name} could not load task '#{hook_spec['task']}': #{e.message}"
            end
      raise InvalidPluginData.new(msg, name)
    end
    hooks[hook_name.to_sym] = { 'task' => task }
  end
    (Set.new(KNOWN_HOOKS.map) - hooks.keys).each do |hook_name|
    task_name = "#{name}::#{hook_name}"
    begin
      task = @context.get_validated_task(task_name)
    rescue Bolt::Error => e
      raise e unless e.kind == 'bolt/unknown-task'
    end
    hooks[hook_name] = { 'task' => task } if task
  end
  Bolt::Util.symbolize_top_level_keys(hooks)
end | 
 
    
      
  
  
    #hooks  ⇒ Object 
  
  
  
  
    | 
58
59
60 | # File 'lib/bolt/plugin/module.rb', line 58
def hooks
  (@hook_map.keys + [:validate_resolve_reference]).uniq
end | 
 
    
      
  
  
    #load_data  ⇒ Object 
  
  
  
  
    | 
62
63
64
65
66 | # File 'lib/bolt/plugin/module.rb', line 62
def load_data
  JSON.parse(File.read(@module.plugin_data_file))
rescue JSON::ParserError => e
  raise InvalidPluginData.new(e.message, name)
end | 
 
    
      
  
  
    #name  ⇒ Object 
  
  
  
  
    | 
54
55
56 | # File 'lib/bolt/plugin/module.rb', line 54
def name
  @module.name
end | 
 
    
      
  
  
    #process_params(task, opts)  ⇒ Object 
  
  
  
  
    | 
153
154
155
156
157
158
159
160
161
162
163
164 | # File 'lib/bolt/plugin/module.rb', line 153
def process_params(task, opts)
        meta, params = opts.partition { |key, _val| key.start_with?('_') }.map(&:to_h)
  params = config.merge(params)
  validate_params(task, params)
  meta['_boltdir'] = @context.boltdir.to_s
  [params, meta]
end | 
 
    
      
  
  
    #process_schema(schema)  ⇒ Object 
  
  
  
  
    | 
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 | # File 'lib/bolt/plugin/module.rb', line 68
def process_schema(schema)
  raise InvalidPluginData.new('config specification is not an object', name) unless schema.is_a?(Hash)
  schema.each do |key, val|
    unless key =~ /\A[a-z][a-z0-9_]*\z/
      raise InvalidPluginData.new("config specification key, '#{key}',  is not allowed", name)
    end
    unless val.is_a?(Hash) && (val['type'] || '').is_a?(String)
      raise InvalidPluginData.new("config specification #{val.to_json} is not allowed", name)
    end
    type_string = val['type'] || 'Any'
    begin
      val['pcore_type'] = Puppet::Pops::Types::TypeParser.singleton.parse(type_string)
      if val['pcore_type'].is_a? Puppet::Pops::Types::PTypeReferenceType
        raise InvalidPluginData.new("Could not find type '#{type_string}' for #{key}", name)
      end
    rescue Puppet::ParseError
      raise InvalidPluginData.new("Could not parse type '#{type_string}' for #{key}", name)
    end
  end
  schema
end | 
 
    
      
  
  
    #puppet_library(opts, target, apply_prep)  ⇒ Object 
  
  
  
  
    | 
254
255
256
257
258
259
260
261
262
263
264
265 | # File 'lib/bolt/plugin/module.rb', line 254
def puppet_library(opts, target, apply_prep)
  task = @hook_map[:puppet_library]['task']
  params, meta_params = process_params(task, opts)
  options = {}
  options[:run_as] = meta_params['_run_as'] if meta_params['_run_as']
  proc do
    apply_prep.run_task([target], task, params, options).first
  end
end | 
 
    
      
  
  
    #resolve_reference(opts)  ⇒ Object 
  
  
  
  
    
These are all the same but are defined explicitly for clarity
   
 
  
  
    | 
238
239
240 | # File 'lib/bolt/plugin/module.rb', line 238
def resolve_reference(opts)
  run_hook(__method__, opts)
end | 
 
    
      
  
  
    #run_hook(hook_name, opts, value = true)  ⇒ Object 
  
  
  
  
    | 
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 | # File 'lib/bolt/plugin/module.rb', line 206
def run_hook(hook_name, opts, value = true)
  hook = @hook_map[hook_name]
    raise PluginError::UnsupportedHook.new(name, hook_name) unless hook
  result = run_task(hook['task'], opts)
  if value
    unless result.include?('value')
      msg = "Plugin #{name} result did not include a value, got #{result}"
      raise Bolt::Plugin::PluginError::ExecutionError.new(msg, name, hook_name)
    end
    result['value']
  end
end | 
 
    
      
  
  
    #run_task(task, opts)  ⇒ Object 
  
  
  
  
    | 
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204 | # File 'lib/bolt/plugin/module.rb', line 190
def run_task(task, opts)
  opts = opts.reject { |key, _val| key.start_with?('_') }
  params, metaparams = process_params(task, opts)
  params = params.merge(metaparams)
    options = { catch_errors: true }
  result = @context.run_local_task(task,
                                   params,
                                   options).first
  raise Bolt::Error.new(result.error_hash['msg'], result.error_hash['kind']) unless result.ok
  result.value
end | 
 
    
      
  
  
    #secret_createkeys(opts = {})  ⇒ Object 
  
  
  
  
    | 
250
251
252 | # File 'lib/bolt/plugin/module.rb', line 250
def secret_createkeys(opts = {})
  run_hook(__method__, opts)
end | 
 
    
      
  
  
    #secret_decrypt(opts)  ⇒ Object 
  
  
  
  
    | 
246
247
248 | # File 'lib/bolt/plugin/module.rb', line 246
def secret_decrypt(opts)
  run_hook(__method__, opts)
end | 
 
    
      
  
  
    #secret_encrypt(opts)  ⇒ Object 
  
  
  
  
    | 
242
243
244 | # File 'lib/bolt/plugin/module.rb', line 242
def secret_encrypt(opts)
  run_hook(__method__, opts)
end | 
 
    
      
  
  
    #setup  ⇒ Object 
  
  
  
  
    
This method interacts with the module on disk so it’s separate from initialize
   
 
  
  
    | 
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 | # File 'lib/bolt/plugin/module.rb', line 36
def setup
  @data = load_data
  @hook_map = find_hooks(@data['hooks'] || {})
  if @data['config']
    msg = <<~MSG.chomp
      Found unsupported key 'config' in bolt_plugin.json. Config for a plugin is inferred
      from task parameters, with config values passed as parameters.
    MSG
    raise InvalidPluginData.new(msg, name)
  end
    @config_schema = process_schema()
  validate_config(@config, @config_schema)
end | 
 
    
      
  
  
    #validate_config(config, config_schema)  ⇒ Object 
  
  
  
  
    | 
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 | # File 'lib/bolt/plugin/module.rb', line 93
def validate_config(config, config_schema)
  config.each_key do |key|
    msg = "Config for #{name} plugin contains unexpected key #{key}"
    raise Bolt::ValidationError, msg unless config_schema.include?(key)
  end
  config_schema.each do |key, spec|
    val = config[key]
    unless spec['pcore_type'].instance?(val)
      raise Bolt::ValidationError, "#{name} plugin expects a #{spec['type']} for key #{key}, got: #{val}"
    end
    val.nil?
  end
  nil
end | 
 
    
      
  
  
    #validate_params(task, params)  ⇒ Object 
  
  
  
  
    | 
149
150
151 | # File 'lib/bolt/plugin/module.rb', line 149
def validate_params(task, params)
  @context.validate_params(task.name, params)
end | 
 
    
      
  
  
    #validate_resolve_reference(opts)  ⇒ Object 
  
  
  
  
    | 
222
223
224
225
226
227
228
229
230
231
232
233
234
235 | # File 'lib/bolt/plugin/module.rb', line 222
def validate_resolve_reference(opts)
    merged = @config.merge(opts)
  params = merged.reject { |k, _v| k.start_with?('_') }
  sig = @hook_map[:resolve_reference]['task']
  if sig
    validate_params(sig, params)
  end
  if @hook_map.include?(:validate_resolve_reference)
    run_hook(:validate_resolve_reference, opts, false)
  end
end |