app/models/input_template_renderer.rb
class InputTemplateRenderer
class UndefinedInput < ::Foreman::Exception
end
class RenderError < ::Foreman::Exception
end
delegate :logger, to: Rails
attr_accessor :template, :host, :invocation, :template_input_values, :error_message, :templates_stack, :current_user
# takes template object that should be rendered
# host and template invocation arguments are optional
# so we can render values based on parameters, facts or user inputs
def initialize(template, host = nil, invocation = nil, input_values = nil, preview = false, templates_stack = [])
raise Foreman::Exception, N_('Recursive rendering of templates detected') if templates_stack.include?(template)
@host = host
@template = template
@invocation = invocation
@template_input_values = input_values
@preview = preview
@templates_stack = templates_stack + [template]
end
def render
@template_input_values ||= values_from_invocation
@template.validate_unique_inputs!
source = Foreman::Renderer.get_source(
template: template,
host: host
)
@scope = Foreman::Renderer.get_scope(
source: source,
host: host,
klass: renderer_scope,
template_input_values: @template_input_values,
variables: {
host: host,
template: template,
preview: @preview,
invocation: invocation,
input_values: @template_input_values,
templates_stack: templates_stack,
input_template_instance: self,
current_user: User.current.try(:login),
}
)
Foreman::Renderer.render(source, @scope)
rescue => e
self.error_message ||= _('error during rendering: %s') % e.message
Foreman::Logging.exception('Error during rendering of a job template', e)
false
end
def preview
old_preview = @preview
@preview = true
render
ensure
@preview = old_preview
end
private
def values_from_invocation
input_values = @invocation ? Hash[@invocation.input_values.map { |iv| [iv.template_input.name, iv.value] }] : {}
default_values = template.default_input_values(input_values.keys)
result = @preview ? input_values : default_values.merge(input_values)
result.with_indifferent_access
end
def renderer_scope
ForemanRemoteExecution::Renderer::Scope::Input
end
def find_by_name(collection, name)
collection.detect { |i| i.name == name.to_s }
end
end